├── .babelrc
├── .gitignore
├── .npmignore
├── .storybook
└── config.js
├── .travis.yml
├── LICENSE.txt
├── NOTICE.txt
├── README.md
├── filenameMap.js
├── generate-module.js
├── package-lock.json
├── package.json
├── src
└── util
│ └── createIcon.js
├── stories
└── index.js
├── test.js
└── update.sh
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["@babel/plugin-transform-modules-commonjs"]
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | package/
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | icons
2 | generate-module.js
--------------------------------------------------------------------------------
/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure } from '@storybook/react';
2 |
3 | function loadStories() {
4 | require('../stories');
5 | }
6 |
7 | configure(loadStories, module);
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016-2021 Team Wertarbyte and contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | Material Design Icons license:
2 |
3 | Pictogrammers Free License
4 | --------------------------
5 |
6 | This icon collection is released as free, open source, and GPL friendly by
7 | the [Pictogrammers](http://pictogrammers.com/) icon group. You may use it
8 | for commercial projects, open source projects, or anything really.
9 |
10 | # Icons: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
11 | Some of the icons are redistributed under the Apache 2.0 license. All other
12 | icons are either redistributed under their respective licenses or are
13 | distributed under the Apache 2.0 license.
14 |
15 | # Fonts: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
16 | All web and desktop fonts are distributed under the Apache 2.0 license. Web
17 | and desktop fonts contain some icons that are redistributed under the Apache
18 | 2.0 license. All other icons are either redistributed under their respective
19 | licenses or are distributed under the Apache 2.0 license.
20 |
21 | # Code: MIT (https://opensource.org/licenses/MIT)
22 | The MIT license applies to all non-font and non-icon files.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Material Design Icons for Material-UI
2 |
3 | [](https://github.com/Templarian/MaterialDesign)
4 | [](https://github.com/Templarian/MaterialDesignLight)
5 |
6 | This module provides [Material-UI][material-ui] `` components for all
7 | [Material Design Icons][md-icons]. This is pretty handy if you use React and Material-UI
8 | to build a web app and run out of icons.
9 |
10 | While this module contains wrappers for all icons, alias names are not included. For example, the _plus_ icon is aliased as _add_, but only the _plus_ icon
11 | is exported.
12 |
13 | [materialdesign-webfont-material-ui]: https://github.com/TeamWertarbyte/materialdesign-webfont-material-ui
14 | [material-ui]: http://www.material-ui.com/
15 | [md-icons]: https://materialdesignicons.com/
16 |
17 | ## Installation
18 |
19 | ```shell
20 | npm install mdi-material-ui --save
21 | ```
22 |
23 | There are different major versions of this package, each one for different Material-UI releases. Note that this project does not follow semantic versioning. If Material Design Icons removes or renames icons, it will still be a minor version bump.
24 |
25 | | Material-UI | mdi-material-ui | npm tag |
26 | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------- |
27 | | ^5.0.0, ^6.0.0, ^7.0.0 | [](https://www.npmjs.com/package/mdi-material-ui) | latest |
28 | | ^4.0.0 | [](https://www.npmjs.com/package/mdi-material-ui/v/mui-v4) | mui-v4 |
29 | | ^1.0.0, ^3.0.0 | [](https://www.npmjs.com/package/mdi-material-ui/v/mui-v3) | mui-v3 |
30 | | 0.x | [](https://www.npmjs.com/package/mdi-material-ui/v/legacy) \* | legacy |
31 |
32 | \* mdi-material-ui v4 (for Material-UI v0) is not updated anymore
33 |
34 | ## Usage
35 |
36 | Every icon is exported with its original name in PascalCase. So `coffee` becomes `Coffee`,
37 | `cloud-print-outline` is exported as `CloudPrintOutline` and so on.
38 |
39 | The Material Design _Light_ icons are included in the `/light` subdirectory.
40 |
41 | ### With tree-shaking
42 |
43 | If your environment supports tree-shaking and you are sure that it works fine in your setup, you can simply import the icons as follows:
44 |
45 | ```js
46 | import { Coffee, Food } from 'mdi-material-ui'
47 | import { Camera, Settings } from 'mdi-material-ui/light'
48 |
49 |
50 |
51 |
52 |
53 | ```
54 |
55 | ### Without tree-shaking
56 |
57 | If your environment doesn't support tree-shaking, you should only import the icons that you actually need in order to ensure that you don't end up bundling _all_ icons.
58 |
59 | ```js
60 | import Coffee from 'mdi-material-ui/Coffee'
61 | import Food from 'mdi-material-ui/Food'
62 | import Camera from 'mdi-material-ui/light/Camera'
63 | import Settings from 'mdi-material-ui/light/Settings'
64 |
65 |
66 |
67 |
68 |
69 | ```
70 |
71 | ## License
72 |
73 | The scripts included in this repository are licensed under the MIT license.
74 | The icons are licensed under the MIT license (see [Material Design Icons](https://github.com/Templarian/MaterialDesign-SVG) and the [NOTICE][] file).
75 |
76 | [notice]: https://github.com/TeamWertarbyte/mdi-material-ui/blob/master/NOTICE
77 |
--------------------------------------------------------------------------------
/filenameMap.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | License: "LicenseIcon", // rename License to LicenseIcon to avoid `yarn licenses generate-disclaimer` reading the icon file as license
3 | };
4 |
--------------------------------------------------------------------------------
/generate-module.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const fse = require('fs-extra')
3 | const path = require('path')
4 | const babel = require('@babel/core')
5 | const pick = require('lodash.pick')
6 | const filenameMap = require('./filenameMap')
7 |
8 | function checkNameClashes (icons) {
9 | const caseNameClashes = icons.filter(
10 | (icon) =>
11 | icon.filename == null &&
12 | icons.filter(
13 | (icon2) =>
14 | icon2.filename == null &&
15 | icon2.name.toLowerCase() === icon.name.toLowerCase()
16 | ).length > 1
17 | )
18 | if (caseNameClashes.length > 0) {
19 | throw new Error(
20 | `The following icons have the same file name (case insensitive): ${caseNameClashes
21 | .map((icon) => icon.name)
22 | .join(', ')}`
23 | )
24 | }
25 | }
26 |
27 | (async () => {
28 | const icons = Object.entries(require('@mdi/js'))
29 | .filter(([name]) => name.indexOf('mdi') === 0)
30 | .map(([name, path]) => ({
31 | name: name.substr(3), // remove mdi prefix
32 | filename: filenameMap[name.substr(3)],
33 | svgPath: path
34 | }))
35 | checkNameClashes(icons)
36 |
37 | const lightIcons = Object.entries(require('@mdi/light-js'))
38 | .filter(([name]) => name.indexOf('mdil') === 0)
39 | .map(([name, path]) => ({
40 | name: name.substr(4), // remove mdil prefix
41 | svgPath: path
42 | }))
43 | checkNameClashes(lightIcons)
44 |
45 | fse.removeSync(path.join(__dirname, 'package'))
46 | fse.mkdirpSync(path.join(__dirname, 'package', 'light'))
47 | fse.removeSync(path.join(__dirname, 'package', 'esm'))
48 | fse.mkdirpSync(path.join(__dirname, 'package', 'esm', 'light'))
49 |
50 | for (const { name, filename, svgPath } of icons) {
51 | const code = `
52 | "use client";
53 | import createIcon from './util/createIcon'
54 | export default createIcon('${svgPath}', '${name}')
55 | `
56 |
57 | // es module
58 | fse.writeFileSync(path.join(__dirname, 'package', 'esm', `${filename || name}.js`), babel.transform(code, {
59 | presets: ['@babel/preset-react', ['@babel/preset-env', { modules: false }]],
60 | compact: process.env.NODE_ENV === 'production'
61 | }).code)
62 |
63 | // commonjs module
64 | fse.writeFileSync(path.join(__dirname, 'package', `${filename || name}.js`), babel.transform(code, {
65 | presets: ['@babel/preset-react', '@babel/preset-env'],
66 | compact: process.env.NODE_ENV === 'production'
67 | }).code)
68 |
69 | // typescript definition
70 | fse.writeFileSync(path.join(__dirname, 'package', `${filename || name}.d.ts`), `export { default } from '@mui/material/SvgIcon'
71 | `)
72 | }
73 |
74 | for (const { name, filename, svgPath } of lightIcons) {
75 | const code = `
76 | "use client";
77 | import createIcon from '../util/createIcon'
78 | export default createIcon('${svgPath}', '${name}')
79 | `
80 |
81 | // es module
82 | fse.writeFileSync(path.join(__dirname, 'package', 'esm', 'light', `${filename || name}.js`), babel.transform(code, {
83 | presets: ['@babel/preset-react', ['@babel/preset-env', { modules: false }]],
84 | compact: process.env.NODE_ENV === 'production'
85 | }).code)
86 |
87 | // commonjs module
88 | fse.writeFileSync(path.join(__dirname, 'package', 'light', `${filename || name}.js`), babel.transform(code, {
89 | presets: ['@babel/preset-react', '@babel/preset-env'],
90 | compact: process.env.NODE_ENV === 'production'
91 | }).code)
92 |
93 | // typescript definition
94 | fse.writeFileSync(path.join(__dirname, 'package', 'light', `${filename || name}.d.ts`), `export { default } from '@mui/material/SvgIcon'
95 | `)
96 | }
97 |
98 | const generateIndexFiles = (destination, esmDestination, icons) => {
99 | // es module
100 | const allExports = icons.map(({ name, filename }) => `export { default as ${name} } from './${filename || name}'`).join('\n')
101 | fse.writeFileSync(path.join(esmDestination, 'index.js'), allExports)
102 |
103 | // typescript index definition (looks exactly the same)
104 | fse.writeFileSync(path.join(destination, 'index.d.ts'), allExports)
105 |
106 | // commonjs module
107 | fse.writeFileSync(path.join(destination, 'index.js'), babel.transform(allExports, {
108 | plugins: ['@babel/plugin-transform-modules-commonjs'],
109 | compact: process.env.NODE_ENV === 'production'
110 | }).code)
111 | }
112 |
113 | generateIndexFiles(path.join(__dirname, 'package'), path.join(__dirname, 'package', 'esm'), icons)
114 | generateIndexFiles(path.join(__dirname, 'package', 'light'), path.join(__dirname, 'package', 'esm', 'light'), lightIcons)
115 |
116 | // createIcon function
117 | fse.mkdirSync(path.join(__dirname, 'package', 'util'))
118 | fse.mkdirSync(path.join(__dirname, 'package', 'esm', 'util'))
119 | fse.writeFileSync(
120 | path.join(__dirname, 'package', 'util', 'createIcon.js'),
121 | babel.transform(fse.readFileSync(path.join(__dirname, 'src', 'util', 'createIcon.js')), {
122 | presets: [['@babel/preset-react', { runtime: "automatic" }], '@babel/preset-env'],
123 | compact: process.env.NODE_ENV === 'production'
124 | }).code
125 | )
126 | fse.writeFileSync(
127 | path.join(__dirname, 'package', 'esm', 'util', 'createIcon.js'),
128 | babel.transform(fse.readFileSync(path.join(__dirname, 'src', 'util', 'createIcon.js')), {
129 | presets: [['@babel/preset-react', { runtime: "automatic" }], ['@babel/preset-env', { modules: false }]],
130 | compact: process.env.NODE_ENV === 'production'
131 | }).code
132 | )
133 |
134 | // update readme
135 | const mdiVersion = require(path.join(require.resolve('@mdi/js'), '..', '..', 'package.json')).version
136 | const mdiLightVersion = require(path.join(require.resolve('@mdi/light-js'), '..', '..', 'package.json')).version
137 | let readme = await fse.readFile(path.join(__dirname, 'README.md'), 'utf-8')
138 | readme = readme.replace(/img\.shields\.io\/badge\/mdi-v(.+?)-blue\.svg/g, `img.shields.io/badge/mdi-v${mdiVersion}-blue.svg`)
139 | readme = readme.replace(/img\.shields\.io\/badge\/mdi--light-v(.+?)-blue\.svg/g, `img.shields.io/badge/mdi--light-v${mdiLightVersion}-blue.svg`)
140 | await fse.writeFile(path.join(__dirname, 'README.md'), readme, 'utf-8')
141 |
142 | // copy other files
143 | ;[
144 | 'README.md',
145 | 'NOTICE.txt',
146 | 'LICENSE.txt',
147 | '.npmignore'
148 | ].forEach((file) => fse.copySync(path.join(__dirname, file), path.join(__dirname, 'package', file)))
149 |
150 | const packageJson = require('./package.json')
151 | packageJson.name = 'mdi-material-ui'
152 | fse.writeFileSync(path.join(__dirname, 'package', 'package.json'), JSON.stringify(pick(packageJson, [
153 | 'name',
154 | 'version',
155 | 'description',
156 | 'main',
157 | 'module',
158 | 'jsnext:main',
159 | 'sideEffects',
160 | 'repository',
161 | 'keywords',
162 | 'author',
163 | 'license',
164 | 'bugs',
165 | 'homepage',
166 | 'peerDependencies'
167 | ]), null, 2), 'utf-8')
168 | })()
169 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mdi-material-ui-generator",
3 | "version": "0.0.0",
4 | "description": "Material-UI SvgIcon components for Material Design Icons.",
5 | "main": "./index.js",
6 | "module": "./esm/index.js",
7 | "jsnext:main": "./esm/index.js",
8 | "sideEffects": false,
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/TeamWertarbyte/mdi-material-ui.git"
12 | },
13 | "keywords": [
14 | "material",
15 | "ui",
16 | "icons",
17 | "webfont",
18 | "font",
19 | "react"
20 | ],
21 | "author": "Wertarbyte",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/TeamWertarbyte/mdi-material-ui/issues"
25 | },
26 | "homepage": "https://github.com/TeamWertarbyte/mdi-material-ui#readme",
27 | "devDependencies": {
28 | "@babel/core": "^7.24.5",
29 | "@babel/plugin-transform-modules-commonjs": "^7.24.1",
30 | "@babel/preset-env": "^7.24.5",
31 | "@babel/preset-react": "^7.24.1",
32 | "@emotion/react": "^11.1.5",
33 | "@emotion/styled": "^11.1.5",
34 | "@mdi/js": "^7.4.47",
35 | "@mdi/light-js": "^0.2.63",
36 | "@mui/material": "^7.0.0",
37 | "@storybook/react": "^6.5.6",
38 | "ava": "^3.15.0",
39 | "fs-extra": "^4.0.1",
40 | "lodash.pick": "^4.4.0",
41 | "react": "^18.1.0",
42 | "react-dom": "^18.1.0",
43 | "react-test-renderer": "^18.1.0"
44 | },
45 | "peerDependencies": {
46 | "@mui/material": "^5.0.0 || ^6.0.0 || ^7.0.0",
47 | "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
48 | },
49 | "scripts": {
50 | "storybook": "start-storybook -p 6006",
51 | "build-storybook": "build-storybook",
52 | "build": "NODE_ENV=production node generate-module.js",
53 | "pretest": "node generate-module.js",
54 | "test": "ava"
55 | },
56 | "private": true
57 | }
58 |
--------------------------------------------------------------------------------
/src/util/createIcon.js:
--------------------------------------------------------------------------------
1 | import { createSvgIcon } from "@mui/material/utils";
2 |
3 | export default (path, name) => createSvgIcon(, name);
4 |
--------------------------------------------------------------------------------
/stories/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { storiesOf } from '@storybook/react'
3 | const icons = require('../package/index')
4 | const lightIcons = require('../package/light/index')
5 |
6 | function themed (children) {
7 | return (
8 |
9 | {children}
10 |
11 | )
12 | }
13 |
14 | const iconStories = storiesOf('Material Design Icons', module)
15 | iconStories.add(`all icons (${Object.keys(icons).length.toLocaleString()})`, () => themed(
16 |
17 | {Object.keys(icons).map((icon) => {
18 | const Icon = icons[icon]
19 | return
20 | })}
21 |
22 | ))
23 |
24 | Object.keys(icons).sort().forEach((icon) => {
25 | const Icon = icons[icon]
26 | iconStories.add(icon, () => themed())
27 | })
28 |
29 | const lightIconStories = storiesOf('Material Design Icons Light', module)
30 | lightIconStories.add(`all icons (${Object.keys(lightIcons).length.toLocaleString()})`, () => themed(
31 |
32 | {Object.keys(lightIcons).map((icon) => {
33 | const Icon = lightIcons[icon]
34 | return
35 | })}
36 |
37 | ))
38 |
39 | Object.keys(lightIcons).sort().forEach((icon) => {
40 | const Icon = lightIcons[icon]
41 | lightIconStories.add(icon, () => themed())
42 | })
43 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | const test = require("ava");
2 | const React = require("react");
3 | const renderer = require("react-test-renderer");
4 | const fs = require("fs");
5 | const filenameMap = require("./filenameMap");
6 | const commonjsIcons = require("./package/index");
7 | const commonjsIconsLight = require("./package/light/index");
8 |
9 | test("the npm package", (t) => {
10 | // should set sideEffects to false to allow webpack to optimize re-exports
11 | const packageJson = require("./package/package.json");
12 | t.false(packageJson.sideEffects);
13 | });
14 |
15 | for (const iconName of Object.keys(commonjsIcons)) {
16 | test(`icons > ${iconName}`, (t) => {
17 | const renderedIcon = renderer
18 | .create(React.createElement(commonjsIcons[iconName]))
19 | .toJSON();
20 | // t.is(renderedIcon[0].type, 'style') // generated by emotion
21 | t.is(renderedIcon[1].type, "svg");
22 | t.is(renderedIcon[1].props["data-testid"], `${iconName}Icon`);
23 | });
24 | }
25 |
26 | test("ES module index file", (t) => {
27 | const esmReExports = fs
28 | .readFileSync("./package/esm/index.js", "utf-8")
29 | .split("\n")
30 | .filter((line) => line.length > 0);
31 | t.is(esmReExports.length, Object.keys(commonjsIcons).length);
32 |
33 | for (const line of esmReExports) {
34 | const match = line.match(
35 | /^export \{ default as (.+?) \} from '\.\/(.+?)'$/
36 | );
37 | t.is(filenameMap[match[1]] || match[1], match[2]);
38 | t.truthy(commonjsIcons[match[1]]);
39 | }
40 | });
41 |
42 | for (const iconName of Object.keys(commonjsIconsLight)) {
43 | test(`light icons > ${iconName}`, (t) => {
44 | const renderedIcon = renderer
45 | .create(React.createElement(commonjsIconsLight[iconName]))
46 | .toJSON();
47 | // t.is(renderedIcon[0].type, 'style') // generated by emotion
48 | t.is(renderedIcon[1].type, "svg");
49 | t.is(renderedIcon[1].props["data-testid"], `${iconName}Icon`);
50 | });
51 | }
52 |
53 | test("mdi-light ES module index file", (t) => {
54 | const esmReExports = fs
55 | .readFileSync("./package/esm/light/index.js", "utf-8")
56 | .split("\n")
57 | .filter((line) => line.length > 0);
58 | t.is(esmReExports.length, Object.keys(commonjsIconsLight).length);
59 |
60 | for (const line of esmReExports) {
61 | const match = line.match(
62 | /^export \{ default as (.+?) \} from '\.\/(.+?)'$/
63 | );
64 | t.is(match[1], match[2]);
65 | t.truthy(commonjsIconsLight[match[1]]);
66 | }
67 | });
68 |
--------------------------------------------------------------------------------
/update.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | npm i --save-dev @mdi/js@latest @mdi/light-js@latest
3 | ./generate-module.js
4 | npm test
5 |
6 | VERSION=`cat node_modules/@mdi/js/package.json | jq -r .version`
7 | git add --all
8 | git commit -m "Update to mdi $VERSION."
9 | git push origin master
10 |
--------------------------------------------------------------------------------