mirror of
https://github.com/feathericons/feather.git
synced 2023-08-10 21:13:24 +03:00
feat: Update API
BREAKING CHANGE: Each icon in the `feather.icons` object is now an `Icon` object with a `name`, `contents`, `tags` and `attrs` property. ```js /* BEFORE */ feather.icons.x // '<line ... /><line ... />' /* AFTER */ feather.icons.x // { // name: 'x', // contents: '<line ... /><line ... />`, // tags: ['cancel', 'close', 'delete', 'remove'], // attrs: { // class: 'feather feather-x', // 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', // } // } ``` `feather.toSvg()` has been deprecated in favor of `feather.icons[name].toSvg()`: ```js /* BEFORE */ feather.toSvg('x') /* AFTER */ feather.icons.x.toSvg() ``` `feather.replace()` now copies all attributes on the placeholder element (i.e. `<i>`) to the `<svg>` tag instead of just `class` and `id`: ```html <i data-feather="circle" id="my-circle" class="foo bar" stroke-width="1"></i> <!-- <i> will be replaced with: <svg id="my-circle" class="feather feather-circle foo bar" 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"><circle cx="12" cy="12" r="10"></circle></svg> --> ```
This commit is contained in:
parent
0dc2bf5c9d
commit
f243624fbd
5
.babelrc
5
.babelrc
@ -1,5 +1,4 @@
|
||||
{
|
||||
"presets": [
|
||||
"es2015"
|
||||
]
|
||||
"presets": ["es2015"],
|
||||
"plugins": ["transform-object-rest-spread"]
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
{
|
||||
"extends": "airbnb-base",
|
||||
"plugins": [
|
||||
"import"
|
||||
],
|
||||
"plugins": ["import"],
|
||||
"rules": {
|
||||
"no-use-before-define": "off",
|
||||
"arrow-parens": ["error", "as-needed"],
|
||||
"no-console": ["error", { "allow": ["warn", "error"] }],
|
||||
"no-param-reassign": "off",
|
||||
"no-shadow": "off",
|
||||
"no-console": ["error", { "allow": ["warn", "error"] }]
|
||||
"no-use-before-define": "off"
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,6 @@ node_js: 6
|
||||
before_script:
|
||||
- npm prune
|
||||
script:
|
||||
- npm run all
|
||||
- npm start
|
||||
after_success:
|
||||
- npm run semantic-release
|
||||
|
34
Makefile
34
Makefile
@ -1,34 +0,0 @@
|
||||
src_files := src/*.js
|
||||
src_dir := src
|
||||
|
||||
.PHONY: all lint test build
|
||||
|
||||
all: lint test build
|
||||
|
||||
lint: dist/icons.json
|
||||
./node_modules/.bin/eslint .
|
||||
|
||||
test:
|
||||
./node_modules/.bin/jest
|
||||
|
||||
build: dist/feather.js dist/feather.min.js dist/icons
|
||||
|
||||
node_modules:
|
||||
npm install
|
||||
|
||||
dist:
|
||||
mkdir dist
|
||||
|
||||
dist/icons.json: node_modules dist icons icons/*.svg
|
||||
./node_modules/.bin/babel-node bin/build-json.js
|
||||
|
||||
dist/feather.js: dist/icons.json $(src_dir) $(src_files)
|
||||
./node_modules/.bin/webpack --output-filename feather.js
|
||||
|
||||
dist/feather.min.js: dist/icons.json $(src_dir) $(src_files)
|
||||
./node_modules/.bin/webpack --output-filename feather.min.js -p
|
||||
|
||||
dist/icons: dist/icons.json
|
||||
rm -rf dist/icons
|
||||
mkdir -p dist/icons
|
||||
./node_modules/.bin/babel-node bin/build-svgs.js
|
147
README.md
147
README.md
@ -3,12 +3,12 @@
|
||||
[![Travis branch](https://img.shields.io/travis/colebemis/feather/master.svg?style=flat-square)](https://travis-ci.org/colebemis/feather)
|
||||
[![npm](https://img.shields.io/npm/v/feather-icons.svg?style=flat-square)](https://www.npmjs.com/package/feather-icons)
|
||||
[![npm](https://img.shields.io/npm/dm/feather-icons.svg?style=flat-square)](https://npm-stat.com/charts.html?package=feather-icons&from=2017-06-01)
|
||||
[![Code Climate](https://img.shields.io/codeclimate/github/colebemis/feather.svg?style=flat-square)](https://codeclimate.com/github/colebemis/feather)
|
||||
[![CDNJS version](https://img.shields.io/cdnjs/v/feather-icons.svg?style=flat-square)](https://cdnjs.com/libraries/feather-icons)
|
||||
[![Code Climate](https://img.shields.io/codeclimate/github/colebemis/feather.svg?style=flat-square)](https://codeclimate.com/github/colebemis/feather)
|
||||
|
||||
## What is Feather?
|
||||
|
||||
Feather is a collection of **simply beautiful open source icons**. Each icon is designed on a 24x24 grid with an emphasis on simplicity, consistency and readability.
|
||||
Feather is a collection of simply beautiful open source icons. Each icon is designed on a 24x24 grid with an emphasis on simplicity, consistency and readability.
|
||||
|
||||
**[feathericons.com](https://feathericons.com)**
|
||||
|
||||
@ -20,12 +20,13 @@ npm install feather-icons
|
||||
|
||||
* [Quick Start](#quick-start)
|
||||
* [Usage](#usage)
|
||||
* [Client-side JavaScript](#client-side-javascript)
|
||||
* [Client-side](#client-side)
|
||||
* [Node](#node)
|
||||
* [API Reference](#api-reference)
|
||||
* [`feather.icons`](#feathericons)
|
||||
* [`feather.toSvg()`](#feathertosvgkey-options)
|
||||
* [`feather.replace()`](#featherreplaceoptions)
|
||||
* [`feather.icons[name].toSvg()`](#feathericonsnametosvgattrs)
|
||||
* [`feather.replace()`](#featherreplaceattrs)
|
||||
* [[DEPRECATED] `feather.toSvg()`](#deprecated-feathertosvgname-attrs)
|
||||
* [Roadmap](#roadmap)
|
||||
* [Contributing](#contributing)
|
||||
* [Related Projects](#related-projects)
|
||||
@ -60,7 +61,7 @@ At its core, Feather is a collection of [SVG](https://svgontheweb.com/#svg) file
|
||||
|
||||
The following are additional ways you can use Feather.
|
||||
|
||||
### Client-side JavaScript
|
||||
### Client-side
|
||||
|
||||
#### 1. Install
|
||||
|
||||
@ -79,7 +80,7 @@ Or just copy [`feather.js`](https://unpkg.com/feather-icons/dist/feather.js) or
|
||||
Include `feather.js` or `feather.min.js` with a `<script>` tag. These files are located in the `dist` directory of the npm package.
|
||||
|
||||
```html
|
||||
<script src="path/to/dist/feather.min.js"></script>
|
||||
<script src="path/to/dist/feather.js"></script>
|
||||
```
|
||||
|
||||
Or load the script from a CDN provider.
|
||||
@ -104,7 +105,7 @@ See the complete list of icons at [feathericons.com](https://feathericons.com).
|
||||
|
||||
#### 4. Replace
|
||||
|
||||
Call the `feather.replace` method.
|
||||
Call the `feather.replace()` method.
|
||||
|
||||
```html
|
||||
<script>
|
||||
@ -126,44 +127,75 @@ npm install feather-icons --save
|
||||
#### 2. Require
|
||||
|
||||
```javascript
|
||||
var feather = require('feather-icons')
|
||||
const feather = require('feather-icons')
|
||||
```
|
||||
|
||||
#### 3. Use
|
||||
```javascript
|
||||
feather.icons.circle
|
||||
// <circle cx="12" cy="12" r="10"></circle>
|
||||
|
||||
feather.toSvg('circle')
|
||||
// '<svg class="feather feather-circle" 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"><circle cx="12" cy="12" r="10"></circle></svg>'
|
||||
```js
|
||||
feather.icons.x
|
||||
// {
|
||||
// name: 'x',
|
||||
// contents: '<line ... /><line ... />`,
|
||||
// tags: ['cancel', 'close', 'delete', 'remove'],
|
||||
// attrs: {
|
||||
// class: 'feather feather-x',
|
||||
// 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',
|
||||
// }
|
||||
// }
|
||||
|
||||
feather.toSvg('circle', { class: 'my-class', 'stroke-width': 1 })
|
||||
// '<svg class="feather feather-circle my-class" 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"><circle cx="12" cy="12" r="10"></circle></svg>'
|
||||
feather.icons.x.toSvg()
|
||||
// <svg class="feather feather-x" ...><line ... /><line ... /></svg>
|
||||
|
||||
feather.icons.x.toSvg({ class: 'foo bar', 'stroke-width': 1, color: 'red' })
|
||||
// <svg class="feather feather-x foo bar" stroke-width="1" color="red" ...><line ... /><line ... /></svg>
|
||||
```
|
||||
|
||||
See the [API Reference](#api-reference) for more information about the available properties and methods of the `feather` object.
|
||||
|
||||
### Sprite
|
||||
|
||||
*Coming soon*
|
||||
|
||||
## API Reference
|
||||
|
||||
### `feather.icons`
|
||||
|
||||
An object with SVG path information for every icon.
|
||||
An object with information about every icon.
|
||||
|
||||
#### Usage
|
||||
|
||||
```javascript
|
||||
feather.icons.circle
|
||||
// <circle cx="12" cy="12" r="10"></circle>
|
||||
```js
|
||||
feather.icons.x
|
||||
// {
|
||||
// name: 'x',
|
||||
// contents: '<line ... /><line ... />`,
|
||||
// tags: ['cancel', 'close', 'delete', 'remove'],
|
||||
// attrs: {
|
||||
// class: 'feather feather-x',
|
||||
// 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',
|
||||
// }
|
||||
// }
|
||||
|
||||
feather.icons.clock
|
||||
// '<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 15 15"/>'
|
||||
feather.icons.x.toString()
|
||||
// '<line ... /><line ... />`
|
||||
```
|
||||
|
||||
### `feather.toSvg(key, [options])`
|
||||
[View Source](https://github.com/colebemis/feather/blob/master/src/icons.js)
|
||||
|
||||
### `feather.icons[name].toSvg([attrs])`
|
||||
|
||||
Returns an SVG string.
|
||||
|
||||
@ -171,25 +203,24 @@ Returns an SVG string.
|
||||
|
||||
| Name | Type | Description |
|
||||
| --------- | ------ | ----------- |
|
||||
| `key` | string | Icon name |
|
||||
| `options` (optional) | Object | Key-value pairs in the `options` object will be mapped to HTML attributes on the `<svg>` tag (e.g. `{ foo: 'bar' }` maps to `foo="bar"`). All default attributes on the `<svg>` tag can be overridden with the `options` object. |
|
||||
| `attrs` (optional) | Object | Key-value pairs in the `attrs` object will be mapped to HTML attributes on the `<svg>` tag (e.g. `{ foo: 'bar' }` maps to `foo="bar"`). All default attributes on the `<svg>` tag can be overridden with the `attrs` object. |
|
||||
|
||||
#### Usage
|
||||
|
||||
```javascript
|
||||
feather.toSvg('circle')
|
||||
feather.icons.circle.toSvg()
|
||||
// '<svg class="feather feather-circle" 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"><circle cx="12" cy="12" r="10"></circle></svg>'
|
||||
|
||||
feather.toSvg('circle', { 'stroke-width': 1 })
|
||||
feather.icons.circle.toSvg({ 'stroke-width': 1 })
|
||||
// '<svg class="feather feather-circle" 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"><circle cx="12" cy="12" r="10"></circle></svg>'
|
||||
|
||||
feather.toSvg('circle', { class: 'foo bar' })
|
||||
feather.icons.circle.toSvg({ class: 'foo bar' })
|
||||
// '<svg class="feather feather-circle foo bar" 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"><circle cx="12" cy="12" r="10"></circle></svg>'
|
||||
```
|
||||
|
||||
[View Source](https://github.com/colebemis/feather/blob/master/src/to-svg.js)
|
||||
[View Source](https://github.com/colebemis/feather/blob/master/src/icons.js)
|
||||
|
||||
### `feather.replace([options])`
|
||||
### `feather.replace([attrs])`
|
||||
|
||||
Replaces all elements that have a `data-feather` attribute with SVG markup corresponding to the element's `data-feather` attribute value.
|
||||
|
||||
@ -197,7 +228,7 @@ Replaces all elements that have a `data-feather` attribute with SVG markup corre
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---------- | ------ | ----------- |
|
||||
| `options` (optional) | Object | Key-value pairs in the `options` object will be mapped to HTML attributes on the `<svg>` tag (e.g. `{ foo: 'bar' }` maps to `foo="bar"`). All default attributes on the `<svg>` tag can be overridden with the `options` object. |
|
||||
| `attrs` (optional) | Object | Key-value pairs in the `attrs` object will be mapped to HTML attributes on the `<svg>` tag (e.g. `{ foo: 'bar' }` maps to `foo="bar"`). All default attributes on the `<svg>` tag can be overridden with the `attrs` object. |
|
||||
|
||||
#### Usage
|
||||
|
||||
@ -216,7 +247,7 @@ Simple usage:
|
||||
</script>
|
||||
```
|
||||
|
||||
You can pass `feather.replace()` an `options` object:
|
||||
You can pass `feather.replace()` an `attrs` object:
|
||||
```html
|
||||
<i data-feather="circle"></i>
|
||||
<!--
|
||||
@ -229,13 +260,13 @@ You can pass `feather.replace()` an `options` object:
|
||||
</script>
|
||||
```
|
||||
|
||||
The id and classes on a placeholder element (i.e. `<i>`) will be copied to the `<svg>` tag:
|
||||
All attributes on the placeholder element (i.e. `<i>`) will be copied to the `<svg>` tag:
|
||||
|
||||
```html
|
||||
<i id="my-circle-icon" class="foo bar" data-feather="circle"></i>
|
||||
<i data-feather="circle" id="my-circle" class="foo bar" stroke-width="1"></i>
|
||||
<!--
|
||||
<i> will be replaced with:
|
||||
<svg id="my-circle-icon" class="feather feather-circle foo bar" 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"><circle cx="12" cy="12" r="10"></circle></svg>
|
||||
<svg id="my-circle" class="feather feather-circle foo bar" 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"><circle cx="12" cy="12" r="10"></circle></svg>
|
||||
-->
|
||||
|
||||
<script>
|
||||
@ -245,19 +276,43 @@ The id and classes on a placeholder element (i.e. `<i>`) will be copied to the `
|
||||
|
||||
[View Source](https://github.com/colebemis/feather/blob/master/src/replace.js)
|
||||
|
||||
### [DEPRECATED] `feather.toSvg(name, [attrs])`
|
||||
|
||||
> **Note:** `feather.toSvg()` is deprecated. Please use `feather.icons[name].toSvg()` instead.
|
||||
|
||||
Returns an SVG string.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| --------- | ------ | ----------- |
|
||||
| `name` | string | Icon name |
|
||||
| `attrs` (optional) | Object | Key-value pairs in the `attrs` object will be mapped to HTML attributes on the `<svg>` tag (e.g. `{ foo: 'bar' }` maps to `foo="bar"`). All default attributes on the `<svg>` tag can be overridden with the `attrs` object. |
|
||||
|
||||
#### Usage
|
||||
|
||||
```javascript
|
||||
feather.toSvg('circle')
|
||||
// '<svg class="feather feather-circle" 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"><circle cx="12" cy="12" r="10"></circle></svg>'
|
||||
|
||||
feather.toSvg('circle', { 'stroke-width': 1 })
|
||||
// '<svg class="feather feather-circle" 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"><circle cx="12" cy="12" r="10"></circle></svg>'
|
||||
|
||||
feather.toSvg('circle', { class: 'foo bar' })
|
||||
// '<svg class="feather feather-circle foo bar" 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"><circle cx="12" cy="12" r="10"></circle></svg>'
|
||||
```
|
||||
|
||||
[View Source](https://github.com/colebemis/feather/blob/master/src/to-svg.js)
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [x] Write contributing guidelines
|
||||
- [ ] Write icon design guidelines
|
||||
- [ ] Add usage examples
|
||||
- [ ] Add SVG sprite
|
||||
- [ ] Add tests
|
||||
- [ ] Track code coverage
|
||||
- [ ] Use Prettier to enforce consistent code style
|
||||
- [ ] Add search/filter functionality to project website
|
||||
- [ ] Handle icon aliases
|
||||
- [ ] Handle usage of custom icons
|
||||
- [ ] Improve SVG accessibility
|
||||
- [ ] Handle usage of custom icons
|
||||
- [ ] Add usage examples
|
||||
- [ ] Make `<feather-icon>` web component
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
// 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>",
|
||||
}
|
||||
`;
|
17
bin/__tests__/build-icons-object.test.js
Normal file
17
bin/__tests__/build-icons-object.test.js
Normal file
@ -0,0 +1,17 @@
|
||||
/* eslint-env jest */
|
||||
import buildIconsObject from '../build-icons-object';
|
||||
|
||||
const SVG_FILES = {
|
||||
'icon1.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"><line x1="23" y1="1" x2="1" y2="23" /><line x1="1" y1="1" x2="23" y2="23" /></svg>',
|
||||
'icon2.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"><circle cx="12" cy="12" r="11" /></svg>',
|
||||
};
|
||||
|
||||
function getSvg(svgFile) {
|
||||
return SVG_FILES[svgFile];
|
||||
}
|
||||
|
||||
test('builds object correctly', () => {
|
||||
expect(buildIconsObject(Object.keys(SVG_FILES), getSvg)).toMatchSnapshot();
|
||||
});
|
19
bin/build-icons-json.js
Normal file
19
bin/build-icons-json.js
Normal file
@ -0,0 +1,19 @@
|
||||
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}`); // eslint-disable-line no-console
|
||||
|
||||
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));
|
34
bin/build-icons-object.js
Normal file
34
bin/build-icons-object.js
Normal file
@ -0,0 +1,34 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import path from 'path';
|
||||
import cheerio from 'cheerio';
|
||||
|
||||
/**
|
||||
* Build an object in the format: `{ <name>: <contents> }`.
|
||||
* @param {string[]} svgFiles - A list of file names.
|
||||
* @param {Function} getSvg - A function that returns the contents of an SVG file.
|
||||
* @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
|
||||
*/
|
||||
function getSvgContents(svg) {
|
||||
const $ = cheerio.load(svg);
|
||||
return $('svg').html();
|
||||
}
|
||||
|
||||
export default buildIconsObject;
|
@ -1,71 +0,0 @@
|
||||
/**
|
||||
* @file Builds `icons.json` from `icons` directory.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import RSVP from 'rsvp';
|
||||
import Svgo from 'svgo';
|
||||
import parse5 from 'parse5';
|
||||
|
||||
const svgFiles = fs.readdirSync(path.resolve(__dirname, '../icons'))
|
||||
.filter(file => path.extname(file) === '.svg');
|
||||
|
||||
buildIconsObject(svgFiles)
|
||||
.then(icons => {
|
||||
fs.writeFileSync(
|
||||
path.resolve(__dirname, '../dist/icons.json'),
|
||||
JSON.stringify(icons),
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Build an icons object in the format: `{ <icon name>: <svg content> }`.
|
||||
* @param {string[]} svgFiles - A list of file names.
|
||||
* @returns {RSVP.Promise<Object>}
|
||||
*/
|
||||
function buildIconsObject(svgFiles) {
|
||||
const icons = {};
|
||||
|
||||
svgFiles.forEach(svgFile => {
|
||||
const svg = fs.readFileSync(path.resolve(__dirname, '../icons', svgFile), 'utf8');
|
||||
const key = path.basename(svgFile, '.svg');
|
||||
|
||||
icons[key] = optimizeSvg(svg)
|
||||
.then(optimizedSvg => getSvgContent(optimizedSvg));
|
||||
});
|
||||
|
||||
return RSVP.hash(icons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize SVG with `svgo`.
|
||||
* @param {string} svg - An SVG string.
|
||||
* @returns {RSVP.Promise<string>}
|
||||
*/
|
||||
function optimizeSvg(svg) {
|
||||
// configure svgo
|
||||
const svgo = new Svgo({
|
||||
plugins: [
|
||||
{ convertShapeToPath: false },
|
||||
{ mergePaths: false },
|
||||
{ removeAttrs: { attrs: '(fill|stroke.*)' } },
|
||||
],
|
||||
});
|
||||
|
||||
return new RSVP.Promise(resolve => {
|
||||
svgo.optimize(svg, ({ data }) => resolve(data));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content between opening and closing `<svg>` tags.
|
||||
* @param {string} svg - An SVG string.
|
||||
* @returns {string}
|
||||
*/
|
||||
function getSvgContent(svg) {
|
||||
const fragment = parse5.parseFragment(svg);
|
||||
const content = parse5.serialize(fragment.childNodes[0]);
|
||||
return content;
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
* @file Builds `dist/icons` directory.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { icons, toSvg } from '../src';
|
||||
import icons from '../src/icons';
|
||||
|
||||
Object.keys(icons).forEach(icon => {
|
||||
const svg = toSvg(icon);
|
||||
const OUT_DIR = path.resolve(__dirname, '../dist/icons');
|
||||
|
||||
fs.writeFileSync(path.resolve(__dirname, `../dist/icons/${icon}.svg`), svg);
|
||||
console.log(`Building SVGs in ${OUT_DIR}`); // eslint-disable-line no-console
|
||||
|
||||
Object.keys(icons).forEach(name => {
|
||||
const svg = icons[name].toSvg();
|
||||
|
||||
fs.writeFileSync(path.join(OUT_DIR, `${name}.svg`), svg);
|
||||
});
|
||||
|
14
bin/build.sh
Executable file
14
bin/build.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
./node_modules/.bin/babel-node bin/process-svgs.js
|
||||
|
||||
./node_modules/.bin/rimraf dist
|
||||
mkdir dist
|
||||
./node_modules/.bin/babel-node bin/build-icons-json.js
|
||||
|
||||
./node_modules/.bin/rimraf dist/icons
|
||||
mkdir dist/icons
|
||||
./node_modules/.bin/babel-node bin/build-svgs.js
|
||||
|
||||
./node_modules/.bin/webpack --output-filename feather.js
|
||||
./node_modules/.bin/webpack --output-filename feather.min.js -p
|
@ -3,7 +3,7 @@ import Svgo from 'svgo';
|
||||
import cheerio from 'cheerio';
|
||||
import { format } from 'prettier';
|
||||
|
||||
import DEFAULT_ATTRIBUTES from '../src/default-attributes.json';
|
||||
import DEFAULT_ATTRS from '../src/default-attrs.json';
|
||||
|
||||
/**
|
||||
* Process SVG string.
|
||||
@ -13,7 +13,7 @@ import DEFAULT_ATTRIBUTES from '../src/default-attributes.json';
|
||||
function processSvg(svg) {
|
||||
return (
|
||||
optimize(svg)
|
||||
.then(setAttributes)
|
||||
.then(setAttrs)
|
||||
.then(format)
|
||||
// remove semicolon inserted by prettier
|
||||
// because prettier thinks it's formatting JSX not HTML
|
||||
@ -46,11 +46,11 @@ function optimize(svg) {
|
||||
* @param {string} svg - An SVG string.
|
||||
* @returns {string}
|
||||
*/
|
||||
function setAttributes(svg) {
|
||||
function setAttrs(svg) {
|
||||
const $ = cheerio.load(svg);
|
||||
|
||||
Object.keys(DEFAULT_ATTRIBUTES).forEach(key =>
|
||||
$('svg').attr(key, DEFAULT_ATTRIBUTES[key]),
|
||||
Object.keys(DEFAULT_ATTRS).forEach(key =>
|
||||
$('svg').attr(key, DEFAULT_ATTRS[key]),
|
||||
);
|
||||
|
||||
return $('body').html();
|
||||
|
@ -1,15 +1,18 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import processSvg from './process-svg';
|
||||
|
||||
const ICONS_DIR = path.resolve(__dirname, '../icons');
|
||||
const IN_DIR = path.resolve(__dirname, '../icons');
|
||||
|
||||
console.log(`Processing SVGs in ${IN_DIR}`); // eslint-disable-line no-console
|
||||
|
||||
fs
|
||||
.readdirSync(ICONS_DIR)
|
||||
.readdirSync(IN_DIR)
|
||||
.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));
|
||||
const svg = fs.readFileSync(path.join(IN_DIR, svgFile));
|
||||
processSvg(svg).then(svg =>
|
||||
fs.writeFileSync(path.join(IN_DIR, svgFile), svg),
|
||||
);
|
||||
});
|
||||
|
240
package-lock.json
generated
240
package-lock.json
generated
@ -304,12 +304,30 @@
|
||||
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
|
||||
"dev": true
|
||||
},
|
||||
"array-filter": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
|
||||
"integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
|
||||
"dev": true
|
||||
},
|
||||
"array-find-index": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
|
||||
"integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
|
||||
"dev": true
|
||||
},
|
||||
"array-map": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
|
||||
"integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
|
||||
"dev": true
|
||||
},
|
||||
"array-reduce": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
|
||||
"integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
|
||||
"dev": true
|
||||
},
|
||||
"array-union": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
|
||||
@ -889,6 +907,16 @@
|
||||
"regexpu-core": "2.0.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-object-rest-spread": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
|
||||
"integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-plugin-syntax-object-rest-spread": "6.13.0",
|
||||
"babel-runtime": "6.26.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-regenerator": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
|
||||
@ -1417,6 +1445,11 @@
|
||||
"chalk": "1.1.3"
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz",
|
||||
"integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0="
|
||||
},
|
||||
"cli-cursor": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
|
||||
@ -1962,6 +1995,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"define-properties": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
|
||||
"integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"foreach": "2.0.5",
|
||||
"object-keys": "1.0.11"
|
||||
}
|
||||
},
|
||||
"del": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
|
||||
@ -2184,6 +2227,30 @@
|
||||
"is-arrayish": "0.2.1"
|
||||
}
|
||||
},
|
||||
"es-abstract": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz",
|
||||
"integrity": "sha512-kk3IJoKo7A3pWJc0OV8yZ/VEX2oSUytfekrJiqoxBlKJMFAJVJVpGdHClCCTdv+Fn2zHfpDHHIelMFhZVfef3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es-to-primitive": "1.1.1",
|
||||
"function-bind": "1.1.1",
|
||||
"has": "1.0.1",
|
||||
"is-callable": "1.1.3",
|
||||
"is-regex": "1.0.4"
|
||||
}
|
||||
},
|
||||
"es-to-primitive": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
|
||||
"integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-callable": "1.1.3",
|
||||
"is-date-object": "1.0.1",
|
||||
"is-symbol": "1.0.1"
|
||||
}
|
||||
},
|
||||
"es5-ext": {
|
||||
"version": "0.10.35",
|
||||
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.35.tgz",
|
||||
@ -2998,6 +3065,12 @@
|
||||
"for-in": "1.0.2"
|
||||
}
|
||||
},
|
||||
"foreach": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
|
||||
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
|
||||
"dev": true
|
||||
},
|
||||
"foreachasync": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz",
|
||||
@ -4619,6 +4692,12 @@
|
||||
"builtin-modules": "1.1.1"
|
||||
}
|
||||
},
|
||||
"is-callable": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
|
||||
"integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=",
|
||||
"dev": true
|
||||
},
|
||||
"is-ci": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz",
|
||||
@ -4628,6 +4707,12 @@
|
||||
"ci-info": "1.1.1"
|
||||
}
|
||||
},
|
||||
"is-date-object": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
|
||||
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
|
||||
"dev": true
|
||||
},
|
||||
"is-dotfile": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
|
||||
@ -4751,6 +4836,15 @@
|
||||
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-regex": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
|
||||
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has": "1.0.1"
|
||||
}
|
||||
},
|
||||
"is-resolvable": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz",
|
||||
@ -4766,6 +4860,12 @@
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-symbol": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
|
||||
"integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=",
|
||||
"dev": true
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
@ -5827,6 +5927,12 @@
|
||||
"integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==",
|
||||
"dev": true
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz",
|
||||
"integrity": "sha512-xyQpxeWWMKyJps9CuGJYeng6ssI5bpqS9ltQpdVQ90t4ql6NdnxFKh95JcRt2cun/DjMVNrdjniLPuMA69xmCw==",
|
||||
"dev": true
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
@ -6207,6 +6313,12 @@
|
||||
"readable-stream": "2.3.3"
|
||||
}
|
||||
},
|
||||
"memorystream": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
|
||||
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
|
||||
"dev": true
|
||||
},
|
||||
"meow": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
@ -6565,6 +6677,96 @@
|
||||
"slide": "1.1.6"
|
||||
}
|
||||
},
|
||||
"npm-run-all": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.2.tgz",
|
||||
"integrity": "sha512-Z2aRlajMK4SQ8u19ZA75NZZu7wupfCNQWdYosIi8S6FgBdGf/8Y6Hgyjdc8zU2cYmIRVCx1nM80tJPkdEd+UYg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.0",
|
||||
"chalk": "2.3.0",
|
||||
"cross-spawn": "5.1.0",
|
||||
"memorystream": "0.3.1",
|
||||
"minimatch": "3.0.4",
|
||||
"ps-tree": "1.1.0",
|
||||
"read-pkg": "3.0.0",
|
||||
"shell-quote": "1.6.1",
|
||||
"string.prototype.padend": "3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
|
||||
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.0",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"supports-color": "4.5.0"
|
||||
}
|
||||
},
|
||||
"load-json-file": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
||||
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11",
|
||||
"parse-json": "4.0.0",
|
||||
"pify": "3.0.0",
|
||||
"strip-bom": "3.0.0"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"error-ex": "1.3.1",
|
||||
"json-parse-better-errors": "1.0.1"
|
||||
}
|
||||
},
|
||||
"path-type": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
||||
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pify": "3.0.0"
|
||||
}
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"load-json-file": "4.0.0",
|
||||
"normalize-package-data": "2.4.0",
|
||||
"path-type": "3.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
|
||||
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||
@ -6662,6 +6864,12 @@
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
},
|
||||
"object-keys": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
|
||||
"integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=",
|
||||
"dev": true
|
||||
},
|
||||
"object.omit": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
|
||||
@ -7080,6 +7288,15 @@
|
||||
"integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=",
|
||||
"dev": true
|
||||
},
|
||||
"ps-tree": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz",
|
||||
"integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"event-stream": "3.3.4"
|
||||
}
|
||||
},
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
@ -7671,6 +7888,18 @@
|
||||
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
|
||||
"dev": true
|
||||
},
|
||||
"shell-quote": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
|
||||
"integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-filter": "0.0.1",
|
||||
"array-map": "0.0.0",
|
||||
"array-reduce": "0.0.0",
|
||||
"jsonify": "0.0.0"
|
||||
}
|
||||
},
|
||||
"shelljs": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.6.tgz",
|
||||
@ -7897,6 +8126,17 @@
|
||||
"strip-ansi": "3.0.1"
|
||||
}
|
||||
},
|
||||
"string.prototype.padend": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz",
|
||||
"integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"define-properties": "1.1.2",
|
||||
"es-abstract": "1.9.0",
|
||||
"function-bind": "1.1.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
|
16
package.json
16
package.json
@ -7,30 +7,36 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"all": "make",
|
||||
"lint": "make lint",
|
||||
"test": "make test",
|
||||
"build": "make build",
|
||||
"start": "npm-run-all --sequential build lint test",
|
||||
"build": "./bin/build.sh",
|
||||
"lint": "eslint .",
|
||||
"test": "jest",
|
||||
"commitmsg": "validate-commit-msg",
|
||||
"cm": "git-cz",
|
||||
"semantic-release": "semantic-release pre && npm publish && semantic-release post"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-loader": "^7.1.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-register": "^6.24.1",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"commitizen": "^2.9.6",
|
||||
"core-js": "^2.4.1",
|
||||
"cz-conventional-changelog": "^2.0.0",
|
||||
"cz-conventional-changelog": "^2.1.0",
|
||||
"eslint": "^4.0.0",
|
||||
"eslint-config-airbnb-base": "^11.2.0",
|
||||
"eslint-plugin-import": "^2.5.0",
|
||||
"husky": "^0.13.4",
|
||||
"jest": "^21.2.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"parse5": "^3.0.2",
|
||||
"prettier": "^1.8.2",
|
||||
"rimraf": "^2.6.2",
|
||||
"rsvp": "^3.6.0",
|
||||
"semantic-release": "^6.3.6",
|
||||
"svgo": "^0.7.2",
|
||||
|
54
src/__tests__/__snapshots__/icon.test.js.snap
Normal file
54
src/__tests__/__snapshots__/icon.test.js.snap
Normal file
@ -0,0 +1,54 @@
|
||||
// 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>"`;
|
45
src/__tests__/__snapshots__/icons.test.js.snap
Normal file
45
src/__tests__/__snapshots__/icons.test.js.snap
Normal file
@ -0,0 +1,45 @@
|
||||
// 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 [],
|
||||
},
|
||||
}
|
||||
`;
|
13
src/__tests__/__snapshots__/replace.test.js.snap
Normal file
13
src/__tests__/__snapshots__/replace.test.js.snap
Normal file
@ -0,0 +1,13 @@
|
||||
// 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>"`;
|
7
src/__tests__/__snapshots__/to-svg.test.js.snap
Normal file
7
src/__tests__/__snapshots__/to-svg.test.js.snap
Normal file
@ -0,0 +1,7 @@
|
||||
// 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>"`;
|
28
src/__tests__/icon.test.js
Normal file
28
src/__tests__/icon.test.js
Normal file
@ -0,0 +1,28 @@
|
||||
/* 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();
|
||||
});
|
16
src/__tests__/icons.test.js
Normal file
16
src/__tests__/icons.test.js
Normal file
@ -0,0 +1,16 @@
|
||||
/* 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();
|
||||
});
|
8
src/__tests__/index.test.js
Normal file
8
src/__tests__/index.test.js
Normal file
@ -0,0 +1,8 @@
|
||||
/* eslint-env jest */
|
||||
import feather from '../..';
|
||||
|
||||
test('has correct properties', () => {
|
||||
expect(feather).toHaveProperty('icons');
|
||||
expect(feather).toHaveProperty('toSvg');
|
||||
expect(feather).toHaveProperty('replace');
|
||||
});
|
32
src/__tests__/replace.test.js
Normal file
32
src/__tests__/replace.test.js
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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();
|
||||
});
|
21
src/__tests__/to-svg.test.js
Normal file
21
src/__tests__/to-svg.test.js
Normal file
@ -0,0 +1,21 @@
|
||||
/* 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();
|
||||
});
|
55
src/icon.js
Normal file
55
src/icon.js
Normal file
@ -0,0 +1,55 @@
|
||||
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;
|
10
src/icons.js
Normal file
10
src/icons.js
Normal file
@ -0,0 +1,10 @@
|
||||
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,8 +1,4 @@
|
||||
/**
|
||||
* @file Exposes `feather` object.
|
||||
*/
|
||||
|
||||
import icons from '../dist/icons.json';
|
||||
import icons from './icons';
|
||||
import toSvg from './to-svg';
|
||||
import replace from './replace';
|
||||
|
||||
|
@ -1,54 +1,60 @@
|
||||
/**
|
||||
* @file Implements `replace` function.
|
||||
*/
|
||||
/* eslint-env browser */
|
||||
import classnames from 'classnames/dedupe';
|
||||
|
||||
/* global document, DOMParser */
|
||||
|
||||
import icons from '../dist/icons.json';
|
||||
import toSvg from './to-svg';
|
||||
import icons from './icons';
|
||||
|
||||
/**
|
||||
* Replace all elements that have a `data-feather` attribute with SVG markup
|
||||
* Replace all HTML elements that have a `data-feather` attribute with SVG markup
|
||||
* corresponding to the element's `data-feather` attribute value.
|
||||
* @param {Object} options
|
||||
* @param {Object} attrs
|
||||
*/
|
||||
export default function replace(options = {}) {
|
||||
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, options));
|
||||
Array.from(elementsToReplace).forEach(element =>
|
||||
replaceElement(element, attrs),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace single element with SVG markup
|
||||
* Replace a single HTML element with SVG markup
|
||||
* corresponding to the element's `data-feather` attribute value.
|
||||
* @param {Element} element
|
||||
* @param {Object} options
|
||||
* @param {HTMLElement} element
|
||||
* @param {Object} attrs
|
||||
*/
|
||||
function replaceElement(element, options) {
|
||||
const key = element.getAttribute('data-feather');
|
||||
function replaceElement(element, attrs = {}) {
|
||||
const elementAttrs = getAttrs(element);
|
||||
const name = elementAttrs['data-feather'];
|
||||
delete elementAttrs['data-feather'];
|
||||
|
||||
if (!key) {
|
||||
throw new Error('The required `data-feather` attribute has no value.');
|
||||
}
|
||||
|
||||
if (!icons[key]) {
|
||||
throw new Error(`No icon matching '${key}'. See the complete list of icons at https://feathericons.com`);
|
||||
}
|
||||
|
||||
const elementClassAttr = element.getAttribute('class') || '';
|
||||
const elementIdAttr = element.getAttribute('id');
|
||||
const classNames = (
|
||||
options.class ? `${options.class} ${elementClassAttr}` : elementClassAttr
|
||||
const svgString = icons[name].toSvg({
|
||||
...attrs,
|
||||
...elementAttrs,
|
||||
...{ class: classnames(attrs.class, elementAttrs.class) },
|
||||
});
|
||||
const svgDocument = new DOMParser().parseFromString(
|
||||
svgString,
|
||||
'image/svg+xml',
|
||||
);
|
||||
|
||||
const svgOptions = Object.assign({}, options, { class: classNames, id: elementIdAttr });
|
||||
const svgString = toSvg(key, svgOptions);
|
||||
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;
|
||||
|
7
src/tags.json
Normal file
7
src/tags.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"airplay": ["stream"],
|
||||
"bell": ["alarm", "notification"],
|
||||
"settings": ["cog", "edit", "gear", "preferences"],
|
||||
"star": ["bookmark"],
|
||||
"x": ["cancel", "close", "delete", "remove"]
|
||||
}
|
@ -1,66 +1,30 @@
|
||||
/**
|
||||
* @file Implements `toSvg` function.
|
||||
*/
|
||||
|
||||
import icons from '../dist/icons.json';
|
||||
import DEFAULT_ATTRIBUTES from './default-attributes.json';
|
||||
import icons from './icons';
|
||||
|
||||
/**
|
||||
* Create an SVG string.
|
||||
* @param {string} key - Icon name.
|
||||
* @param {Object} options
|
||||
* @deprecated
|
||||
* @param {string} name
|
||||
* @param {Object} attrs
|
||||
* @returns {string}
|
||||
*/
|
||||
export default function toSvg(key, options = {}) {
|
||||
if (!key) {
|
||||
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[key]) {
|
||||
throw new Error(`No icon matching '${key}'. See the complete list of icons at https://feathericons.com`);
|
||||
if (!icons[name]) {
|
||||
throw new Error(
|
||||
`No icon matching '${
|
||||
name
|
||||
}'. See the complete list of icons at https://feathericons.com`,
|
||||
);
|
||||
}
|
||||
|
||||
const combinedOptions = Object.assign({}, DEFAULT_ATTRIBUTES, options);
|
||||
|
||||
combinedOptions.class = addDefaultClassNames(combinedOptions.class, key);
|
||||
|
||||
const attributes = optionsToAttributes(combinedOptions);
|
||||
|
||||
return `<svg ${attributes}>${icons[key]}</svg>`;
|
||||
return icons[name].toSvg(attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default class names.
|
||||
* @param {string} classNames - One or more class names seperated by spaces.
|
||||
* @param {string} key - Icon name.
|
||||
* @returns {string}
|
||||
*/
|
||||
function addDefaultClassNames(classNames, key) {
|
||||
// convert class names string into an array
|
||||
const classNamesArray = classNames ? classNames.trim().split(/\s+/) : [];
|
||||
|
||||
// use Set to avoid duplicate class names
|
||||
const classNamesSet = new Set(classNamesArray);
|
||||
|
||||
// add default class names
|
||||
classNamesSet.add('feather').add(`feather-${key}`);
|
||||
|
||||
return Array.from(classNamesSet).join(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert options object to string of html attributes.
|
||||
* @param {Object} options
|
||||
* @returns {string}
|
||||
*/
|
||||
function optionsToAttributes(options) {
|
||||
const attributes = [];
|
||||
|
||||
Object.keys(options).forEach(key => {
|
||||
if (options[key]) {
|
||||
attributes.push(`${key}="${options[key]}"`);
|
||||
}
|
||||
});
|
||||
|
||||
return attributes.join(' ');
|
||||
}
|
||||
export default toSvg;
|
||||
|
Loading…
Reference in New Issue
Block a user