mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-16 23:47:43 +01:00
Compare commits
23 Commits
v0.148.0
...
v0.1.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d349be0fee | ||
|
|
c7a8ea09d9 | ||
|
|
6fb9593f28 | ||
|
|
2f16a80e6d | ||
|
|
4bdee5a5a2 | ||
|
|
41b9d7637d | ||
|
|
d6b50f942a | ||
|
|
3a44f64098 | ||
|
|
6a0f52daab | ||
|
|
e38ad92be1 | ||
|
|
70b178215b | ||
|
|
bdc4f81aa5 | ||
|
|
018a3af0bd | ||
|
|
c9551388d0 | ||
|
|
4365dddf57 | ||
|
|
ea8bec9320 | ||
|
|
e08eff7dee | ||
|
|
4ac9e0bc37 | ||
|
|
446fd3f852 | ||
|
|
e732f4dd6d | ||
|
|
771cf1d66e | ||
|
|
eee84b0edf | ||
|
|
de6906e242 |
11
.editorconfig
Normal file
11
.editorconfig
Normal file
@@ -0,0 +1,11 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
quote_type = single
|
||||
max_line_length = 100
|
||||
4
.eslintignore
Normal file
4
.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
dist
|
||||
build
|
||||
coverage
|
||||
lib
|
||||
21
.eslintrc.json
Normal file
21
.eslintrc.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": ["airbnb-base", "prettier"],
|
||||
"plugins": ["import", "prettier"],
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"no-param-reassign": "off",
|
||||
"no-shadow": "off",
|
||||
"no-use-before-define": "off",
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,6 +1,10 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
dist
|
||||
build
|
||||
lib
|
||||
sandbox
|
||||
stash
|
||||
coverage
|
||||
coverage
|
||||
stats
|
||||
*.log
|
||||
|
||||
52
README.md
52
README.md
@@ -13,12 +13,64 @@ Featherity is a fork of [Feather Icons](https://github.com/feathericons/feather)
|
||||
* [Contributing](#contributing)
|
||||
* [License](#license)
|
||||
|
||||
## Installation
|
||||
``` bash
|
||||
npm install featherity
|
||||
#or
|
||||
yarn add featherity
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
At its core, Featherity is a collection of [SVG](https://svgontheweb.com/#svg) files. This means that you can use Feather icons in all the same ways you can use SVGs (e.g. `img`, `background-image`, `inline`, `object`, `embed`, `iframe`). Here's a helpful article detailing the many ways SVGs can be used on the web: [SVG on the Web – Implementation Options](https://svgontheweb.com/#implementation)
|
||||
|
||||
The following are additional ways you can use Featherity.
|
||||
|
||||
### ESModule
|
||||
|
||||
``` js
|
||||
import { Camera } from 'featherity';
|
||||
// Returns HTMLElement
|
||||
|
||||
// Usage
|
||||
document.appendChild(Camera);
|
||||
```
|
||||
|
||||
### React
|
||||
|
||||
``` js
|
||||
import { Camera } from 'featherity/react';
|
||||
// Returns ReactComponent
|
||||
|
||||
// Usage
|
||||
const App = () => {
|
||||
return <Camera color="red" size={48}/>
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Vue
|
||||
|
||||
``` vue
|
||||
<template>
|
||||
<div id="app">
|
||||
<Camera color="red" :size="48"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Camera } from 'featherity/vue';
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
components: {
|
||||
Camera
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
### Figma
|
||||
|
||||
You can use the components from [this Figma file](https://www.figma.com/file/g0UipfQlRfGrntKPxZknM7/Featherity).
|
||||
|
||||
28
babel.config.js
Normal file
28
babel.config.js
Normal file
@@ -0,0 +1,28 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@babel/env',
|
||||
{
|
||||
loose: true,
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
// plugins: ['babel-plugin-add-import-extension'],
|
||||
env: {
|
||||
test: {
|
||||
presets: ['@babel/env'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
},
|
||||
dev: {
|
||||
plugins: [
|
||||
[
|
||||
'transform-inline-environment-variables',
|
||||
{
|
||||
include: ['NODE_ENV'],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
60
package.json
60
package.json
@@ -1,9 +1,61 @@
|
||||
{
|
||||
"name": "featherity",
|
||||
"amdName": "featherity",
|
||||
"license": "ISC",
|
||||
"version": "0.1.0-alpha.0",
|
||||
"private": true,
|
||||
"source": "build/featherity.js",
|
||||
"main": "dist/cjs/featherity.js",
|
||||
"main:umd": "dist/umd/featherity.js",
|
||||
"module": "lib/featherity.js",
|
||||
"unpkg": "dist/umd/featherity.min.js",
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"react:compile": "yarn workspace react compile"
|
||||
"start": "babel-watch --watch src",
|
||||
"clean": "rimraf lib && rimraf dist && rimraf build",
|
||||
"build": "yarn clean && yarn build:transpile && yarn build:icons && yarn build:es && yarn build:esbrowser && yarn build:bundles",
|
||||
"build:transpile": "babel src -d build",
|
||||
"build:icons": "npx babel-node ./scripts/buildIcons.js --presets @babel/env",
|
||||
"build:es": "babel build -d lib --source-maps --ignore '**/*.test.js','**/__mocks__'",
|
||||
"build:esbrowser": "BROWSER_COMPAT=true yarn build:es -d dist/esm",
|
||||
"build:bundles": "rollup -c rollup.config.js",
|
||||
"optimize": "npx babel-node ./scripts/optimizeSvgs.js --presets @babel/env"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/react"
|
||||
]
|
||||
"devDependencies": {
|
||||
"@ampproject/rollup-plugin-closure-compiler": "^0.25.2",
|
||||
"@atomico/rollup-plugin-sizes": "^1.1.4",
|
||||
"@babel/cli": "^7.10.5",
|
||||
"@babel/core": "^7.11.1",
|
||||
"@babel/node": "^7.10.5",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"@rollup/plugin-babel": "^5.0.0",
|
||||
"@rollup/plugin-replace": "^2.3.2",
|
||||
"babel-plugin-add-import-extension": "^1.4.3",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-import": "^2.5.0",
|
||||
"eslint-plugin-prettier": "^2.5.0",
|
||||
"html-minifier": "^3.5.8",
|
||||
"lint-staged": "^6.0.0",
|
||||
"microbundle": "^0.12.3",
|
||||
"prettier": "^1.8.2",
|
||||
"rollup": "^2.7.3",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-flow-entry": "^0.3.3",
|
||||
"rollup-plugin-license": "^2.0.0",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-terser": "^5.2.0",
|
||||
"rollup-plugin-visualizer": "^4.1.0",
|
||||
"semantic-release": "^12.2.2",
|
||||
"svgo": "^1.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "3",
|
||||
"htmlparser2": "^4.1.0",
|
||||
"lodash": "^4.17.19",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1"
|
||||
}
|
||||
}
|
||||
|
||||
61
rollup.config.js
Normal file
61
rollup.config.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
import bundleSize from '@atomico/rollup-plugin-sizes';
|
||||
import compiler from '@ampproject/rollup-plugin-closure-compiler';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import visualizer from 'rollup-plugin-visualizer';
|
||||
import license from 'rollup-plugin-license';
|
||||
import resolve from 'rollup-plugin-node-resolve';
|
||||
import commonJS from 'rollup-plugin-commonjs';
|
||||
import pkg from './package.json';
|
||||
|
||||
const outputFileName = pkg.name;
|
||||
|
||||
const inputs = ['build/featherity.js'];
|
||||
const bundles = [
|
||||
{ inputs, format: 'umd', dir: 'dist', minify: true },
|
||||
{ inputs, format: 'umd', dir: 'dist' },
|
||||
{ inputs, format: 'cjs', dir: 'dist' },
|
||||
];
|
||||
|
||||
const configs = bundles
|
||||
.map(({ inputs, dir, format, minify }) =>
|
||||
inputs.map(input => ({
|
||||
input,
|
||||
external: ['lodash/camelCase', 'lodash/upperFirst'],
|
||||
plugins: [
|
||||
format === 'umd' &&
|
||||
replace({
|
||||
__DEV__: minify ? 'false' : 'true',
|
||||
}),
|
||||
babel({ babelHelpers: 'bundled' }),
|
||||
// The two minifiers together seem to procude a smaller bundle 🤷♂️
|
||||
minify && compiler(),
|
||||
minify && terser(),
|
||||
license({ banner: `${pkg.name} v${pkg.version} - ${pkg.license}` }),
|
||||
bundleSize(),
|
||||
resolve(),
|
||||
commonJS({
|
||||
include: 'node_modules/**',
|
||||
}),
|
||||
visualizer({
|
||||
sourcemap: true,
|
||||
filename: `stats/${outputFileName}${minify ? '-min' : ''}.html`,
|
||||
}),
|
||||
].filter(Boolean),
|
||||
output: {
|
||||
name: 'featherity',
|
||||
file: `${dir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`,
|
||||
format,
|
||||
sourcemap: true,
|
||||
exports: 'named',
|
||||
globals: {
|
||||
'lodash/camelCase': 'camelCase',
|
||||
'lodash/upperFirst': 'upperFirst',
|
||||
},
|
||||
},
|
||||
})),
|
||||
)
|
||||
.flat();
|
||||
|
||||
export default configs;
|
||||
23
scripts/build/generateExportsFile.js
Normal file
23
scripts/build/generateExportsFile.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import path from 'path';
|
||||
|
||||
import { generateComponentName, resetFile, writeFile, readFile } from './helpers';
|
||||
|
||||
export default function(inputEntry, outputDirectory, componentGetter, iconNodes) {
|
||||
const fileName = path.basename(inputEntry);
|
||||
|
||||
// Reset file
|
||||
resetFile(fileName, outputDirectory);
|
||||
|
||||
const icons = Object.keys(iconNodes);
|
||||
|
||||
// Generate Import for Icon VNodes
|
||||
icons.forEach(iconName => {
|
||||
const componentName = generateComponentName(iconName);
|
||||
const importString = `export { default as ${componentName} } from './${iconName}';\n`;
|
||||
writeFile(importString, fileName, outputDirectory);
|
||||
});
|
||||
|
||||
writeFile('\n', fileName, outputDirectory);
|
||||
|
||||
console.log(`Successfully generated ${fileName} file`);
|
||||
}
|
||||
27
scripts/build/generateIconFiles.js
Normal file
27
scripts/build/generateIconFiles.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import prettier from 'prettier';
|
||||
import { generateComponentName } from './helpers';
|
||||
|
||||
export default function(iconNode, outputDirectory, template) {
|
||||
const icons = Object.keys(iconNode);
|
||||
const iconsDistDirectory = path.join(outputDirectory, `icons`);
|
||||
|
||||
if (!fs.existsSync(iconsDistDirectory)) {
|
||||
fs.mkdirSync(iconsDistDirectory);
|
||||
}
|
||||
|
||||
icons.forEach(icon => {
|
||||
const location = path.join(iconsDistDirectory, `${icon}.js`);
|
||||
const componentName = generateComponentName(icon);
|
||||
|
||||
const node = JSON.stringify(iconNode[icon]);
|
||||
|
||||
const elementTemplate = template({ componentName, node });
|
||||
|
||||
fs.writeFileSync(location, prettier.format(elementTemplate, { parser: 'babel' }), 'utf-8');
|
||||
|
||||
console.log('Successfully built', componentName);
|
||||
});
|
||||
}
|
||||
37
scripts/build/helpers.js
Normal file
37
scripts/build/helpers.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { upperFirst, camelCase } from 'lodash/string';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Generates a componentName of a String.
|
||||
*
|
||||
* @param {string} iconName
|
||||
*/
|
||||
export const generateComponentName = iconName =>
|
||||
iconName === 'github' ? 'GitHub' : upperFirst(camelCase(iconName));
|
||||
|
||||
/**
|
||||
* Resets the file contents.
|
||||
*
|
||||
* @param {string} fileName
|
||||
* @param {string} outputDirectory
|
||||
*/
|
||||
export const resetFile = (fileName, outputDirectory) =>
|
||||
fs.writeFileSync(path.join(outputDirectory, fileName), '', 'utf-8');
|
||||
|
||||
/**
|
||||
* Reads the file contents.
|
||||
*
|
||||
* @param {string} path
|
||||
*/
|
||||
export const readFile = entry => fs.readFileSync(path.resolve(__dirname, '../../', entry), 'utf-8');
|
||||
|
||||
/**
|
||||
* writes content to a file
|
||||
*
|
||||
* @param {string} content
|
||||
* @param {string} fileName
|
||||
* @param {string} outputDirectory
|
||||
*/
|
||||
export const writeFile = (content, fileName, outputDirectory) =>
|
||||
fs.appendFileSync(path.join(outputDirectory, fileName), content, 'utf-8');
|
||||
43
scripts/buildIcons.js
Normal file
43
scripts/buildIcons.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import renderIconsObject from './render/renderIconsObject';
|
||||
import renderIconNodes from './render/renderIconNodes';
|
||||
import generateIconFiles from './build/generateIconFiles';
|
||||
import generateExportsFile from './build/generateExportsFile';
|
||||
|
||||
const IN_DIR = path.resolve(__dirname, '../icons');
|
||||
const OUTPUT_DIR = path.resolve(__dirname, '../build');
|
||||
const SRC_DIR = path.resolve(__dirname, '../src');
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
|
||||
const svgFiles = fs.readdirSync(IN_DIR).filter(file => path.extname(file) === '.svg');
|
||||
const getSvg = svgFile => fs.readFileSync(path.join(IN_DIR, svgFile));
|
||||
|
||||
const icons = renderIconsObject(svgFiles, getSvg);
|
||||
const iconVNodes = renderIconNodes(icons);
|
||||
|
||||
// Generates iconsNodes files for each icon
|
||||
generateIconFiles(
|
||||
iconVNodes,
|
||||
OUTPUT_DIR,
|
||||
({ componentName, node }) => `
|
||||
import createElement from '../../src/createElement';
|
||||
|
||||
const ${componentName} = ${node};
|
||||
|
||||
export const element = createElement('${componentName}', ${componentName});
|
||||
export default ${componentName};
|
||||
`,
|
||||
);
|
||||
|
||||
// Generates entry files for the compiler filled with icons exports
|
||||
generateExportsFile(
|
||||
path.join(SRC_DIR, 'icons/index.js'),
|
||||
path.join(OUTPUT_DIR, 'icons'),
|
||||
'getElement',
|
||||
iconVNodes,
|
||||
);
|
||||
17
scripts/optimizeSvgs.js
Normal file
17
scripts/optimizeSvgs.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import processSvg from './render/processSvg';
|
||||
|
||||
const ICONS_DIR = path.resolve(__dirname, '../icons');
|
||||
|
||||
console.log(`Optimizing SVGs in ${ICONS_DIR}...`);
|
||||
|
||||
const svgFiles = fs.readdirSync(ICONS_DIR).filter(file => path.extname(file) === '.svg');
|
||||
console.log(svgFiles);
|
||||
|
||||
svgFiles
|
||||
.filter(file => path.extname(file) === '.svg')
|
||||
.forEach(svgFile => {
|
||||
const svg = fs.readFileSync(path.join(ICONS_DIR, svgFile));
|
||||
processSvg(svg).then(svg => fs.writeFileSync(path.join(ICONS_DIR, svgFile), svg));
|
||||
});
|
||||
11
scripts/render/default-attrs.json
Normal file
11
scripts/render/default-attrs.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"xmlns": "http://www.w3.org/2000/svg",
|
||||
"width": 24,
|
||||
"height": 24,
|
||||
"viewBox": "0 0 24 24",
|
||||
"fill": "none",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": 2,
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
}
|
||||
57
scripts/render/processSvg.js
Normal file
57
scripts/render/processSvg.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import Svgo from 'svgo';
|
||||
import cheerio from 'cheerio';
|
||||
import { format } from 'prettier';
|
||||
|
||||
import DEFAULT_ATTRS from './default-attrs.json';
|
||||
|
||||
/**
|
||||
* Process SVG string.
|
||||
* @param {string} svg - An SVG string.
|
||||
* @param {Promise<string>}
|
||||
*/
|
||||
function processSvg(svg) {
|
||||
return (
|
||||
optimize(svg)
|
||||
.then(setAttrs)
|
||||
.then(format)
|
||||
// remove semicolon inserted by prettier
|
||||
// because prettier thinks it's formatting JSX not HTML
|
||||
.then(svg => svg.replace(/;/g, ''))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize SVG with `svgo`.
|
||||
* @param {string} svg - An SVG string.
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
function optimize(svg) {
|
||||
const svgo = new Svgo({
|
||||
plugins: [
|
||||
{ convertShapeToPath: false },
|
||||
{ mergePaths: false },
|
||||
{ removeAttrs: { attrs: '(fill|stroke.*)' } },
|
||||
{ removeTitle: true },
|
||||
],
|
||||
});
|
||||
|
||||
return new Promise(resolve => {
|
||||
svgo.optimize(svg, ({ data }) => resolve(data));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default attibutes on SVG.
|
||||
* @param {string} svg - An SVG string.
|
||||
* @returns {string}
|
||||
*/
|
||||
function setAttrs(svg) {
|
||||
const $ = cheerio.load(svg);
|
||||
|
||||
Object.keys(DEFAULT_ATTRS).forEach(key => $('svg').attr(key, DEFAULT_ATTRS[key]));
|
||||
|
||||
return $('body').html();
|
||||
}
|
||||
|
||||
export default processSvg;
|
||||
29
scripts/render/renderIconNodes.js
Normal file
29
scripts/render/renderIconNodes.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { parseDOM } from 'htmlparser2';
|
||||
import DEFAULT_ATTRS from './default-attrs.json';
|
||||
|
||||
export default iconsObject => {
|
||||
const iconNodes = {};
|
||||
|
||||
Object.keys(iconsObject).forEach(icon => {
|
||||
const svgString = iconsObject[icon];
|
||||
const dom = parseDOM(svgString);
|
||||
|
||||
const children = dom.map(element => [
|
||||
element.name,
|
||||
{
|
||||
...element.attribs,
|
||||
},
|
||||
]);
|
||||
|
||||
iconNodes[icon] = [
|
||||
'svg',
|
||||
{
|
||||
...DEFAULT_ATTRS,
|
||||
},
|
||||
children,
|
||||
];
|
||||
});
|
||||
|
||||
return iconNodes;
|
||||
};
|
||||
34
scripts/render/renderIconsObject.js
Normal file
34
scripts/render/renderIconsObject.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import path from 'path';
|
||||
import cheerio from 'cheerio';
|
||||
import { minify } from 'html-minifier';
|
||||
|
||||
/**
|
||||
* Get contents between opening and closing `<svg>` tags.
|
||||
* @param {string} svg
|
||||
* @returns {string}
|
||||
*/
|
||||
function getSvgContents(svg) {
|
||||
const $ = cheerio.load(svg);
|
||||
|
||||
return minify($('svg').html(), { collapseWhitespace: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an object in the format: `{ <name>: <contents> }`.
|
||||
* @param {string[]} svgFiles - A list of filenames.
|
||||
* @param {Function} getSvg - A function that returns the contents of an SVG file given a filename.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export default (svgFiles, getSvg) =>
|
||||
svgFiles
|
||||
.map(svgFile => {
|
||||
const name = path.basename(svgFile, '.svg');
|
||||
const svg = getSvg(svgFile);
|
||||
const contents = getSvgContents(svg);
|
||||
return { name, contents };
|
||||
})
|
||||
.reduce((icons, icon) => {
|
||||
icons[icon.name] = icon.contents;
|
||||
return icons;
|
||||
}, {});
|
||||
19
src/createElement.js
Normal file
19
src/createElement.js
Normal file
@@ -0,0 +1,19 @@
|
||||
const createElement = (tag, attrs, children = []) => {
|
||||
const element = document.createElement(tag);
|
||||
|
||||
Object.keys(attrs).forEach(name => {
|
||||
element.setAttribute(name, attrs[name]);
|
||||
});
|
||||
|
||||
if (children.length) {
|
||||
children = children.forEach(child => {
|
||||
const childElement = createElement(...child);
|
||||
|
||||
element.appendChild(childElement);
|
||||
});
|
||||
}
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
export default ([tag, attrs, children]) => createElement(tag, attrs, children);
|
||||
5
src/icons/index.js
Normal file
5
src/icons/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
Icons exports.
|
||||
|
||||
Will be generated
|
||||
*/
|
||||
40
src/replaceElement.js
Normal file
40
src/replaceElement.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import camelCase from 'lodash/camelCase';
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import createElement from './createElement';
|
||||
|
||||
/**
|
||||
* Get the attributes of an HTML element.
|
||||
* @param {HTMLElement} element
|
||||
* @returns {Object}
|
||||
*/
|
||||
function getAttrs(element) {
|
||||
return Array.from(element.attributes).reduce((attrs, attr) => {
|
||||
attrs[attr.name] = attr.value;
|
||||
return attrs;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export default (element, { nameAttr, icons, attrs }) => {
|
||||
const iconName = element.getAttribute(nameAttr);
|
||||
const ComponentName = upperFirst(camelCase(iconName));
|
||||
|
||||
const iconNode = icons[ComponentName];
|
||||
|
||||
if (!iconNode) {
|
||||
return console.warn(
|
||||
`${element.outerHTML} icon name was not found in the provided icons object.`,
|
||||
);
|
||||
}
|
||||
|
||||
const [, iconAttrs] = iconNode;
|
||||
|
||||
iconNode[1] = {
|
||||
...iconAttrs,
|
||||
...getAttrs(element),
|
||||
...attrs,
|
||||
};
|
||||
|
||||
const svgElement = createElement(iconNode);
|
||||
|
||||
return element.parentNode.replaceChild(svgElement, element);
|
||||
};
|
||||
Reference in New Issue
Block a user