mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-16 19:47:41 +01:00
Hotfix Lucide npm package, fix security issues (#84)
* adjust npmignore
* 📦 Fix security issues
* update font workflow
* identation
* update, package.json
* Add description
* Add shields
This commit is contained in:
35
.github/workflows/font.yml
vendored
35
.github/workflows/font.yml
vendored
@@ -1,63 +1,48 @@
|
||||
name: Build Featherity
|
||||
name: Build Lucide
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
Build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
|
||||
- name: Clone 'Featherity'
|
||||
- name: Clone 'Lucide'
|
||||
uses: actions/checkout@v2
|
||||
|
||||
|
||||
- name: Install FontForge
|
||||
run: sudo apt-get install zlib1g-dev fontforge woff2
|
||||
|
||||
|
||||
- name: Clone sfnt2woff-zopfli repo
|
||||
run: git clone https://github.com/bramstein/sfnt2woff-zopfli.git sfnt2woff-zopfli
|
||||
|
||||
|
||||
|
||||
- name: Install and move sfnt2woff-zopfli
|
||||
run: |
|
||||
cd sfnt2woff-zopfli
|
||||
make
|
||||
sudo mv sfnt2woff-zopfli /usr/local/bin/sfnt2woff
|
||||
|
||||
|
||||
- name: Clone woff2
|
||||
run: git clone --recursive https://github.com/google/woff2.git
|
||||
|
||||
|
||||
- name: Install woff2
|
||||
run: |
|
||||
cd woff2
|
||||
sudo make clean all
|
||||
sudo mv woff2_compress /usr/local/bin/ && sudo mv woff2_decompress /usr/local/bin/
|
||||
|
||||
|
||||
|
||||
|
||||
- name: Install Font Custom dependency
|
||||
run: sudo gem install fontcustom
|
||||
|
||||
- name: Build 'Featherity'
|
||||
|
||||
- name: Build 'Lucide'
|
||||
run: echo "Building Featherity font" && fontcustom compile ./icons -h -n Featherity -o build -F
|
||||
|
||||
|
||||
- name: Zip 'Featherity'
|
||||
|
||||
- name: Zip 'Lucide'
|
||||
run: zip -r Featherity.zip build
|
||||
|
||||
|
||||
|
||||
- name: 'Upload to Artifacts'
|
||||
uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: Featherity
|
||||
path: build
|
||||
|
||||
name: Lucide
|
||||
path: build
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
.github
|
||||
packages
|
||||
stats
|
||||
build
|
||||
node_modules
|
||||
tests
|
||||
scripts
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Lucide
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/lucide)
|
||||
[](https://discord.gg/EH6nSts)
|
||||
|
||||
## What is Lucide?
|
||||
|
||||
|
Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 329 B |
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "lucide",
|
||||
"description": "Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
|
||||
"version": "0.1.1",
|
||||
"license": "ISC",
|
||||
"amdName": "lucide",
|
||||
"homepage": "https://featherity.netlify.app",
|
||||
"url": "https://github.com/owner/project/issues",
|
||||
"repository": "github:lucide-icons/lucide",
|
||||
"url" : "https://github.com/owner/project/issues",
|
||||
"license": "ISC",
|
||||
"version": "0.1.0",
|
||||
"source": "build/lucide.js",
|
||||
"main": "dist/cjs/lucide.js",
|
||||
"main:umd": "dist/umd/lucide.js",
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"browsers": ["last 2 versions"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-2"
|
||||
]
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
dist
|
||||
coverage
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": ["airbnb-base", "prettier"],
|
||||
"plugins": ["import", "prettier"],
|
||||
"rules": {
|
||||
"no-console": ["error", { "allow": ["warn", "error"] }],
|
||||
"no-param-reassign": "off",
|
||||
"no-shadow": "off",
|
||||
"no-use-before-define": "off",
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`builds object correctly 1`] = `
|
||||
Object {
|
||||
"icon1": "<line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\"></line><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\"></line>",
|
||||
"icon2": "<circle cx=\\"12\\" cy=\\"12\\" r=\\"11\\"></circle>",
|
||||
}
|
||||
`;
|
||||
@@ -1,3 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`builds sprite correctly 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\"><defs><symbol id=\\"icon1\\" viewBox=\\"0 0 24 24\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\"></line><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\"></line></symbol><symbol id=\\"icon2\\" viewBox=\\"0 0 24 24\\"><circle cx=\\"12\\" cy=\\"12\\" r=\\"11\\"></circle></symbol></defs></svg>"`;
|
||||
@@ -1,26 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`processes SVG correctly 1`] = `
|
||||
"<svg
|
||||
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\\"
|
||||
>
|
||||
<line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" />
|
||||
<line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" />
|
||||
</svg>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`rejects when passed unparsable SVG string 1`] = `
|
||||
[Error: Error in parsing SVG: Unclosed root tag
|
||||
Line: 0
|
||||
Column: 10
|
||||
Char: ]
|
||||
`;
|
||||
@@ -1,17 +0,0 @@
|
||||
/* eslint-env jest */
|
||||
import buildIconsObject from '../build-icons-object';
|
||||
|
||||
const SVG_FILES = {
|
||||
'icon1.svg':
|
||||
'<svg\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n>\n <line x1="23" y1="1" x2="1" y2="23" />\n <line x1="1" y1="1" x2="23" y2="23" />\n</svg>',
|
||||
'icon2.svg':
|
||||
'<svg\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n>\n <circle cx="12" cy="12" r="11" />\n</svg>',
|
||||
};
|
||||
|
||||
function getSvg(svgFile) {
|
||||
return SVG_FILES[svgFile];
|
||||
}
|
||||
|
||||
test('builds object correctly', () => {
|
||||
expect(buildIconsObject(Object.keys(SVG_FILES), getSvg)).toMatchSnapshot();
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
/* eslint-env jest */
|
||||
import buildSpriteString from '../build-sprite-string';
|
||||
|
||||
const icons = {
|
||||
icon1:
|
||||
'<line x1="23" y1="1" x2="1" y2="23"></line><line x1="1" y1="1" x2="23" y2="23"></line>',
|
||||
icon2: '<circle cx="12" cy="12" r="11"></circle>',
|
||||
};
|
||||
|
||||
test('builds sprite correctly', () => {
|
||||
expect(buildSpriteString(icons)).toMatchSnapshot();
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
/* eslint-env jest */
|
||||
import processSvg from '../process-svg';
|
||||
|
||||
test('processes SVG correctly', () => {
|
||||
const SVG =
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><title>Title</title><line x1="23" y1="1" x2="1" y2="23" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><line x1="1" y1="1" x2="23" y2="23" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>';
|
||||
|
||||
expect(processSvg(SVG)).resolves.toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('rejects when passed unparsable SVG string', () => {
|
||||
const UNPARSABLE_SVG = '<svg></svg';
|
||||
|
||||
expect(processSvg(UNPARSABLE_SVG)).rejects.toMatchSnapshot();
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import buildIconsObject from './build-icons-object';
|
||||
|
||||
const IN_DIR = path.resolve(__dirname, '../icons');
|
||||
const OUT_FILE = path.resolve(__dirname, '../dist/icons.json');
|
||||
|
||||
console.log(`Building ${OUT_FILE}...`);
|
||||
|
||||
const svgFiles = fs
|
||||
.readdirSync(IN_DIR)
|
||||
.filter(file => path.extname(file) === '.svg');
|
||||
|
||||
const getSvg = svgFile => fs.readFileSync(path.join(IN_DIR, svgFile));
|
||||
|
||||
const icons = buildIconsObject(svgFiles, getSvg);
|
||||
|
||||
fs.writeFileSync(OUT_FILE, JSON.stringify(icons));
|
||||
@@ -1,35 +0,0 @@
|
||||
import path from 'path';
|
||||
import cheerio from 'cheerio';
|
||||
import { minify } from 'html-minifier';
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
function buildIconsObject(svgFiles, getSvg) {
|
||||
return 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;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 });
|
||||
}
|
||||
|
||||
export default buildIconsObject;
|
||||
@@ -1,28 +0,0 @@
|
||||
import DEFAULT_ATTRS from '../src/default-attrs.json';
|
||||
|
||||
/**
|
||||
* Build an SVG sprite string containing SVG symbols.
|
||||
* @param {Object} icons
|
||||
* @returns {string}
|
||||
*/
|
||||
function buildSpriteString(icons) {
|
||||
const symbols = Object.keys(icons)
|
||||
.map(icon => toSvgSymbol(icon, icons[icon]))
|
||||
.join('');
|
||||
|
||||
return `<svg xmlns="${DEFAULT_ATTRS.xmlns}"><defs>${symbols}</defs></svg>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SVG symbol string.
|
||||
* @param {string} name - Icon name
|
||||
* @param {string} contents - SVG contents
|
||||
* @returns {string}
|
||||
*/
|
||||
function toSvgSymbol(name, contents) {
|
||||
return `<symbol id="${name}" viewBox="${DEFAULT_ATTRS.viewBox}">${
|
||||
contents
|
||||
}</symbol>`;
|
||||
}
|
||||
|
||||
export default buildSpriteString;
|
||||
@@ -1,10 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import icons from '../dist/icons.json';
|
||||
import buildSpriteString from './build-sprite-string';
|
||||
|
||||
const OUT_FILE = path.resolve(__dirname, '../dist/feather-sprite.svg');
|
||||
|
||||
console.log(`Building ${OUT_FILE}...`);
|
||||
|
||||
fs.writeFileSync(OUT_FILE, buildSpriteString(icons));
|
||||
@@ -1,13 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import icons from '../src/icons';
|
||||
|
||||
const OUT_DIR = path.resolve(__dirname, '../dist/icons');
|
||||
|
||||
console.log(`Building SVGs in ${OUT_DIR}...`);
|
||||
|
||||
Object.keys(icons).forEach(name => {
|
||||
const svg = icons[name].toSvg();
|
||||
|
||||
fs.writeFileSync(path.join(OUT_DIR, `${name}.svg`), svg);
|
||||
});
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Process SVG files
|
||||
npx babel-node bin/process-svgs.js
|
||||
|
||||
# Create dist directory
|
||||
npx rimraf dist
|
||||
mkdir dist
|
||||
|
||||
# Build icons.json
|
||||
npx babel-node bin/build-icons-json.js
|
||||
|
||||
# Build SVG sprite
|
||||
npx babel-node bin/build-sprite.js
|
||||
|
||||
# Create dist/icons directory
|
||||
npx rimraf dist/icons
|
||||
mkdir dist/icons
|
||||
|
||||
# Build SVG icons
|
||||
npx babel-node bin/build-svgs.js
|
||||
|
||||
# Build JavaScript library
|
||||
npx webpack --output-filename feather.js --mode development
|
||||
npx webpack --output-filename feather.min.js --mode production
|
||||
@@ -1,58 +0,0 @@
|
||||
import Svgo from 'svgo';
|
||||
import cheerio from 'cheerio';
|
||||
import { format } from 'prettier';
|
||||
|
||||
import DEFAULT_ATTRS from '../src/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;
|
||||
@@ -1,18 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import processSvg from './process-svg';
|
||||
|
||||
const IN_DIR = path.resolve(__dirname, '../icons');
|
||||
|
||||
console.log(`Processing SVGs in ${IN_DIR}...`);
|
||||
|
||||
fs
|
||||
.readdirSync(IN_DIR)
|
||||
.filter(file => path.extname(file) === '.svg')
|
||||
.forEach(svgFile => {
|
||||
const svg = fs.readFileSync(path.join(IN_DIR, svgFile));
|
||||
processSvg(svg).then(svg =>
|
||||
fs.writeFileSync(path.join(IN_DIR, svgFile), svg),
|
||||
);
|
||||
});
|
||||
@@ -1,73 +0,0 @@
|
||||
import algolia from 'algoliasearch';
|
||||
import icons from '../dist/icons.json';
|
||||
import tags from '../src/tags.json';
|
||||
|
||||
const ALGOLIA_APP_ID = '5EEOG744D0';
|
||||
|
||||
if (
|
||||
process.env.TRAVIS_PULL_REQUEST === 'false' &&
|
||||
process.env.TRAVIS_BRANCH === 'master'
|
||||
) {
|
||||
syncAlgolia();
|
||||
} else {
|
||||
console.log('Skipped Algolia sync.');
|
||||
}
|
||||
|
||||
function syncAlgolia() {
|
||||
// ALGOLIA_ADMIN_KEY must be added as an environment variable in Travis CI
|
||||
const client = algolia(ALGOLIA_APP_ID, process.env.ALGOLIA_ADMIN_KEY);
|
||||
|
||||
console.log('Initializing target and temporary indexes...');
|
||||
const index = client.initIndex('icons');
|
||||
const indexTmp = client.initIndex('icons_tmp');
|
||||
|
||||
console.log(
|
||||
"Copying target index's settings, synonyms and rules into temporary index...",
|
||||
);
|
||||
scopedCopyIndex(client, index.indexName, indexTmp.indexName)
|
||||
.then(() => {
|
||||
const objects = Object.keys(icons).map(name => ({
|
||||
name,
|
||||
tags: tags[name] || [],
|
||||
}));
|
||||
|
||||
console.log('Adding objects to the temporary index...');
|
||||
return addObjects(indexTmp, objects);
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Moving temporary index to target index...');
|
||||
return moveIndex(client, indexTmp.indexName, index.indexName);
|
||||
});
|
||||
}
|
||||
|
||||
function scopedCopyIndex(
|
||||
client,
|
||||
indexNameSrc,
|
||||
indexNameDest,
|
||||
scope = ['settings', 'synonyms', 'rules'],
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.copyIndex(indexNameSrc, indexNameDest, scope, (error, contents) => {
|
||||
if (error) reject(error);
|
||||
resolve(contents);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addObjects(index, objects) {
|
||||
return new Promise((resolve, reject) => {
|
||||
index.addObjects(objects, (error, contents) => {
|
||||
if (error) reject(error);
|
||||
resolve(contents);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function moveIndex(client, indexNameSrc, indexNameDest) {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.moveIndex(indexNameSrc, indexNameDest, (error, contents) => {
|
||||
if (error) reject(error);
|
||||
resolve(contents);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
{
|
||||
"name": "feather-icons",
|
||||
"version": "0.0.0-development",
|
||||
"description": "Simply beautiful open source icons",
|
||||
"main": "dist/feather.js",
|
||||
"unpkg": "dist/feather.min.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"all": "npm-run-all --sequential build lint test:coverage",
|
||||
"build": "./bin/build.sh",
|
||||
"lint": "eslint .",
|
||||
"test": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
"cm": "git-cz",
|
||||
"precommit": "lint-staged",
|
||||
"commitmsg": "commitlint --edit"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "cz-conventional-changelog"
|
||||
}
|
||||
},
|
||||
"jest": {
|
||||
"collectCoverageFrom": [
|
||||
"src/**/*.js"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5",
|
||||
"core-js": "^3.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^5.2.5",
|
||||
"@commitlint/config-conventional": "^6.1.3",
|
||||
"algoliasearch": "^3.27.1",
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-loader": "^7.1.1",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-stage-2": "^6.24.1",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"commitizen": "^2.9.6",
|
||||
"cz-conventional-changelog": "^2.1.0",
|
||||
"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",
|
||||
"husky": "^0.14.3",
|
||||
"jest": "^22.4.4",
|
||||
"lint-staged": "^6.0.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.8.2",
|
||||
"semantic-release": "^12.2.2",
|
||||
"svgo": "^0.7.2",
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-cli": "^2.1.3"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/feathericons/feather.git"
|
||||
},
|
||||
"author": "Cole Bemis <cole@colebemis.com> (http://colebemis.com)",
|
||||
"license": "MIT"
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`constructs icon object correctly 1`] = `
|
||||
Icon {
|
||||
"attrs": Object {
|
||||
"class": "feather feather-test",
|
||||
"fill": "none",
|
||||
"height": 24,
|
||||
"stroke": "currentColor",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
"stroke-width": 2,
|
||||
"viewBox": "0 0 24 24",
|
||||
"width": 24,
|
||||
"xmlns": "http://www.w3.org/2000/svg",
|
||||
},
|
||||
"contents": "<line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" />",
|
||||
"name": "test",
|
||||
"tags": Array [
|
||||
"hello",
|
||||
"world",
|
||||
"foo",
|
||||
"bar",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`constructs icon object correctly 2`] = `
|
||||
Icon {
|
||||
"attrs": Object {
|
||||
"class": "feather feather-test",
|
||||
"fill": "none",
|
||||
"height": 24,
|
||||
"stroke": "currentColor",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
"stroke-width": 2,
|
||||
"viewBox": "0 0 24 24",
|
||||
"width": 24,
|
||||
"xmlns": "http://www.w3.org/2000/svg",
|
||||
},
|
||||
"contents": "<line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" />",
|
||||
"name": "test",
|
||||
"tags": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`toString() returns correct string 1`] = `"<line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" />"`;
|
||||
|
||||
exports[`toSvg() returns correct string 1`] = `"<svg 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\\" class=\\"feather feather-test\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" /></svg>"`;
|
||||
|
||||
exports[`toSvg() returns correct string 2`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"feather feather-test\\" color=\\"red\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" /></svg>"`;
|
||||
|
||||
exports[`toSvg() returns correct string 3`] = `"<svg 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\\" class=\\"feather feather-test foo bar\\" color=\\"red\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" /></svg>"`;
|
||||
@@ -1,45 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`exports correct object 1`] = `
|
||||
Object {
|
||||
"icon1": Icon {
|
||||
"attrs": Object {
|
||||
"class": "feather feather-icon1",
|
||||
"fill": "none",
|
||||
"height": 24,
|
||||
"stroke": "currentColor",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
"stroke-width": 2,
|
||||
"viewBox": "0 0 24 24",
|
||||
"width": 24,
|
||||
"xmlns": "http://www.w3.org/2000/svg",
|
||||
},
|
||||
"contents": "<line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" />",
|
||||
"name": "icon1",
|
||||
"tags": Array [
|
||||
"foo",
|
||||
"bar",
|
||||
"hello",
|
||||
"world",
|
||||
],
|
||||
},
|
||||
"icon2": Icon {
|
||||
"attrs": Object {
|
||||
"class": "feather feather-icon2",
|
||||
"fill": "none",
|
||||
"height": 24,
|
||||
"stroke": "currentColor",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
"stroke-width": 2,
|
||||
"viewBox": "0 0 24 24",
|
||||
"width": 24,
|
||||
"xmlns": "http://www.w3.org/2000/svg",
|
||||
},
|
||||
"contents": "<circle cx=\\"12\\" cy=\\"12\\" r=\\"11\\" />",
|
||||
"name": "icon2",
|
||||
"tags": Array [],
|
||||
},
|
||||
}
|
||||
`;
|
||||
@@ -1,3 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`throws an error when run in node environment 1`] = `"\`feather.replace()\` only works in a browser environment."`;
|
||||
@@ -1,13 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`copies placeholder element attributes to <svg> tag 1`] = `"<i data-feather=\\"icon1\\" id=\\"test\\" class=\\"foo bar\\" stroke-width=\\"1\\"></i>"`;
|
||||
|
||||
exports[`copies placeholder element attributes to <svg> tag 2`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"feather feather-icon1 foo bar\\" id=\\"test\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\"></line><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\"></line></svg>"`;
|
||||
|
||||
exports[`replaces [data-feather] elements with SVG markup 1`] = `"<i data-feather=\\"icon1\\"></i><span data-feather=\\"icon2\\"></span>"`;
|
||||
|
||||
exports[`replaces [data-feather] elements with SVG markup 2`] = `"<svg 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\\" class=\\"feather feather-icon1\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\"></line><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\"></line></svg><svg 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\\" class=\\"feather feather-icon2\\"><circle cx=\\"12\\" cy=\\"12\\" r=\\"11\\"></circle></svg>"`;
|
||||
|
||||
exports[`sets attributes passed as parameters 1`] = `"<i data-feather=\\"icon1\\" id=\\"test\\" class=\\"foo bar\\" stroke-width=\\"1\\"></i>"`;
|
||||
|
||||
exports[`sets attributes passed as parameters 2`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"feather feather-icon1 foo bar hello\\" color=\\"salmon\\" id=\\"test\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\"></line><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\"></line></svg>"`;
|
||||
@@ -1,7 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`returns correct string 1`] = `"<svg 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\\" class=\\"feather feather-icon1\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" /></svg>"`;
|
||||
|
||||
exports[`returns correct string 2`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"feather feather-icon1\\" color=\\"red\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" /></svg>"`;
|
||||
|
||||
exports[`returns correct string 3`] = `"<svg 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\\" class=\\"feather feather-icon1 foo bar\\" color=\\"red\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\" /><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\" /></svg>"`;
|
||||
@@ -1,28 +0,0 @@
|
||||
/* eslint-env jest */
|
||||
import Icon from '../icon';
|
||||
|
||||
const icon1 = new Icon(
|
||||
'test',
|
||||
'<line x1="23" y1="1" x2="1" y2="23" /><line x1="1" y1="1" x2="23" y2="23" />',
|
||||
['hello', 'world', 'foo', 'bar'],
|
||||
);
|
||||
|
||||
const icon2 = new Icon(
|
||||
'test',
|
||||
'<line x1="23" y1="1" x2="1" y2="23" /><line x1="1" y1="1" x2="23" y2="23" />',
|
||||
);
|
||||
|
||||
test('constructs icon object correctly', () => {
|
||||
expect(icon1).toMatchSnapshot();
|
||||
expect(icon2).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('toSvg() returns correct string', () => {
|
||||
expect(icon1.toSvg()).toMatchSnapshot();
|
||||
expect(icon1.toSvg({ 'stroke-width': 1, color: 'red' })).toMatchSnapshot();
|
||||
expect(icon1.toSvg({ class: 'foo bar', color: 'red' })).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('toString() returns correct string', () => {
|
||||
expect(icon1.toString()).toMatchSnapshot();
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
/* eslint-env jest */
|
||||
import icons from '../icons';
|
||||
|
||||
jest.mock('../../dist/icons.json', () => ({
|
||||
icon1:
|
||||
'<line x1="23" y1="1" x2="1" y2="23" /><line x1="1" y1="1" x2="23" y2="23" />',
|
||||
icon2: '<circle cx="12" cy="12" r="11" />',
|
||||
}));
|
||||
|
||||
jest.mock('../tags.json', () => ({
|
||||
icon1: ['foo', 'bar', 'hello', 'world'],
|
||||
}));
|
||||
|
||||
test('exports correct object', () => {
|
||||
expect(icons).toMatchSnapshot();
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
/* eslint-env jest */
|
||||
import feather from '../index';
|
||||
|
||||
test('has correct properties', () => {
|
||||
expect(feather).toHaveProperty('icons');
|
||||
expect(feather).toHaveProperty('toSvg');
|
||||
expect(feather).toHaveProperty('replace');
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* @jest-environment node
|
||||
*/
|
||||
|
||||
/* eslint-env jest */
|
||||
import replace from '../replace';
|
||||
|
||||
test('throws an error when run in node environment', () => {
|
||||
expect(replace).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
/* eslint-env jest, browser */
|
||||
import replace from '../replace';
|
||||
|
||||
jest.mock('../../dist/icons.json', () => ({
|
||||
icon1:
|
||||
'<line x1="23" y1="1" x2="1" y2="23" /><line x1="1" y1="1" x2="23" y2="23" />',
|
||||
icon2: '<circle cx="12" cy="12" r="11" />',
|
||||
}));
|
||||
|
||||
test('replaces [data-feather] elements with SVG markup', () => {
|
||||
document.body.innerHTML =
|
||||
'<i data-feather="icon1"></i><span data-feather="icon2"></i>';
|
||||
expect(document.body.innerHTML).toMatchSnapshot();
|
||||
replace();
|
||||
expect(document.body.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('copies placeholder element attributes to <svg> tag', () => {
|
||||
document.body.innerHTML =
|
||||
'<i data-feather="icon1" id="test" class="foo bar" stroke-width="1"></i>';
|
||||
expect(document.body.innerHTML).toMatchSnapshot();
|
||||
replace();
|
||||
expect(document.body.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sets attributes passed as parameters', () => {
|
||||
document.body.innerHTML =
|
||||
'<i data-feather="icon1" id="test" class="foo bar" stroke-width="1"></i>';
|
||||
expect(document.body.innerHTML).toMatchSnapshot();
|
||||
replace({ class: 'foo bar hello', 'stroke-width': 1.5, color: 'salmon' });
|
||||
expect(document.body.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
@@ -1,21 +0,0 @@
|
||||
/* eslint-env jest */
|
||||
import toSvg from '../to-svg';
|
||||
|
||||
jest.mock('../../dist/icons.json', () => ({
|
||||
icon1:
|
||||
'<line x1="23" y1="1" x2="1" y2="23" /><line x1="1" y1="1" x2="23" y2="23" />',
|
||||
}));
|
||||
|
||||
test('returns correct string', () => {
|
||||
expect(toSvg('icon1')).toMatchSnapshot();
|
||||
expect(toSvg('icon1', { 'stroke-width': 1, color: 'red' })).toMatchSnapshot();
|
||||
expect(toSvg('icon1', { class: 'foo bar', color: 'red' })).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('throws error when `name` parameter is undefined', () => {
|
||||
expect(() => toSvg()).toThrow();
|
||||
});
|
||||
|
||||
test('throws error when passed unknown icon name', () => {
|
||||
expect(() => toSvg('foo')).toThrow();
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import classnames from 'classnames/dedupe';
|
||||
|
||||
import DEFAULT_ATTRS from './default-attrs.json';
|
||||
|
||||
class Icon {
|
||||
constructor(name, contents, tags = []) {
|
||||
this.name = name;
|
||||
this.contents = contents;
|
||||
this.tags = tags;
|
||||
this.attrs = {
|
||||
...DEFAULT_ATTRS,
|
||||
...{ class: `feather feather-${name}` },
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SVG string.
|
||||
* @param {Object} attrs
|
||||
* @returns {string}
|
||||
*/
|
||||
toSvg(attrs = {}) {
|
||||
const combinedAttrs = {
|
||||
...this.attrs,
|
||||
...attrs,
|
||||
...{ class: classnames(this.attrs.class, attrs.class) },
|
||||
};
|
||||
|
||||
return `<svg ${attrsToString(combinedAttrs)}>${this.contents}</svg>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string representation of an `Icon`.
|
||||
*
|
||||
* Added for backward compatibility. If old code expects `feather.icons.<name>`
|
||||
* to be a string, `toString()` will get implicitly called.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
toString() {
|
||||
return this.contents;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert attributes object to string of HTML attributes.
|
||||
* @param {Object} attrs
|
||||
* @returns {string}
|
||||
*/
|
||||
function attrsToString(attrs) {
|
||||
return Object.keys(attrs)
|
||||
.map(key => `${key}="${attrs[key]}"`)
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
export default Icon;
|
||||
@@ -1,10 +0,0 @@
|
||||
import Icon from './icon';
|
||||
import icons from '../dist/icons.json';
|
||||
import tags from './tags.json';
|
||||
|
||||
export default Object.keys(icons)
|
||||
.map(key => new Icon(key, icons[key], tags[key]))
|
||||
.reduce((object, icon) => {
|
||||
object[icon.name] = icon;
|
||||
return object;
|
||||
}, {});
|
||||
@@ -1,5 +0,0 @@
|
||||
import icons from './icons';
|
||||
import toSvg from './to-svg';
|
||||
import replace from './replace';
|
||||
|
||||
module.exports = { icons, toSvg, replace };
|
||||
@@ -1,60 +0,0 @@
|
||||
/* eslint-env browser */
|
||||
import classnames from 'classnames/dedupe';
|
||||
|
||||
import icons from './icons';
|
||||
|
||||
/**
|
||||
* Replace all HTML elements that have a `data-feather` attribute with SVG markup
|
||||
* corresponding to the element's `data-feather` attribute value.
|
||||
* @param {Object} attrs
|
||||
*/
|
||||
function replace(attrs = {}) {
|
||||
if (typeof document === 'undefined') {
|
||||
throw new Error('`feather.replace()` only works in a browser environment.');
|
||||
}
|
||||
|
||||
const elementsToReplace = document.querySelectorAll('[data-feather]');
|
||||
|
||||
Array.from(elementsToReplace).forEach(element =>
|
||||
replaceElement(element, attrs),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace a single HTML element with SVG markup
|
||||
* corresponding to the element's `data-feather` attribute value.
|
||||
* @param {HTMLElement} element
|
||||
* @param {Object} attrs
|
||||
*/
|
||||
function replaceElement(element, attrs = {}) {
|
||||
const elementAttrs = getAttrs(element);
|
||||
const name = elementAttrs['data-feather'];
|
||||
delete elementAttrs['data-feather'];
|
||||
|
||||
const svgString = icons[name].toSvg({
|
||||
...attrs,
|
||||
...elementAttrs,
|
||||
...{ class: classnames(attrs.class, elementAttrs.class) },
|
||||
});
|
||||
const svgDocument = new DOMParser().parseFromString(
|
||||
svgString,
|
||||
'image/svg+xml',
|
||||
);
|
||||
const svgElement = svgDocument.querySelector('svg');
|
||||
|
||||
element.parentNode.replaceChild(svgElement, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 replace;
|
||||
@@ -1,30 +0,0 @@
|
||||
import icons from './icons';
|
||||
|
||||
/**
|
||||
* Create an SVG string.
|
||||
* @deprecated
|
||||
* @param {string} name
|
||||
* @param {Object} attrs
|
||||
* @returns {string}
|
||||
*/
|
||||
function toSvg(name, attrs = {}) {
|
||||
console.warn(
|
||||
'feather.toSvg() is deprecated. Please use feather.icons[name].toSvg() instead.',
|
||||
);
|
||||
|
||||
if (!name) {
|
||||
throw new Error('The required `key` (icon name) parameter is missing.');
|
||||
}
|
||||
|
||||
if (!icons[name]) {
|
||||
throw new Error(
|
||||
`No icon matching '${
|
||||
name
|
||||
}'. See the complete list of icons at https://feathericons.com`,
|
||||
);
|
||||
}
|
||||
|
||||
return icons[name].toSvg(attrs);
|
||||
}
|
||||
|
||||
export default toSvg;
|
||||
@@ -1,23 +0,0 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: ['core-js/es/array/from', path.resolve(__dirname, 'src/index.js')],
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
libraryTarget: 'umd',
|
||||
library: 'feather',
|
||||
// Prevents webpack from referencing `window` in the UMD build
|
||||
// Source: https://git.io/vppgU
|
||||
globalObject: "typeof self !== 'undefined' ? self : this",
|
||||
},
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user