Skip to content

Commit 71f502f

Browse files
colebemisCole Bemis
authored andcommitted
feat: Add JavaScript library
Add JavaScript library that includes an `icons` object, `toSvg` function and `replace` function.
1 parent ae164db commit 71f502f

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed

src/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @file Exposes `feather` object.
3+
*/
4+
5+
import icons from '../dist/icons.json';
6+
import toSvg from './to-svg';
7+
import replace from './replace';
8+
9+
module.exports = { icons, toSvg, replace };

src/replace.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @file Implements `replace` function.
3+
*/
4+
5+
/* global document, DOMParser */
6+
7+
import icons from '../dist/icons.json';
8+
import toSvg from './to-svg';
9+
10+
/**
11+
* Replace all elements that have a `data-feather` attribute with SVG markup
12+
* corresponding to the element's `data-feather` attribute value.
13+
* @param {Object} options
14+
*/
15+
export default function replace(options = {}) {
16+
if (typeof document === 'undefined') {
17+
throw new Error('`feather.replace()` only works in a browser environment.');
18+
}
19+
20+
const elementsToReplace = document.querySelectorAll('[data-feather]');
21+
22+
Array.from(elementsToReplace).forEach(element => replaceElement(element, options));
23+
}
24+
25+
/**
26+
* Replace single element with SVG markup
27+
* corresponding to the element's `data-feather` attribute value.
28+
* @param {Element} element
29+
* @param {Object} options
30+
*/
31+
function replaceElement(element, options) {
32+
const key = element.getAttribute('data-feather');
33+
34+
if (!key) {
35+
console.error('The required `data-feather` attribute has no value.');
36+
return;
37+
}
38+
39+
if (!icons[key]) {
40+
console.error(`No icon matching '${key}'. See the complete list of icons at https://feathericons.com`);
41+
return;
42+
}
43+
44+
const elementClassAttr = element.getAttribute('class');
45+
const classNames = (
46+
options.class ? `${options.class} ${elementClassAttr}` : elementClassAttr
47+
);
48+
49+
const svgString = toSvg(key, Object.assign({}, options, { class: classNames }));
50+
const svgDocument = new DOMParser().parseFromString(svgString, 'image/svg+xml');
51+
const svgElement = svgDocument.querySelector('svg');
52+
53+
element.parentNode.replaceChild(svgElement, element);
54+
}

src/to-svg.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @file Implements `toSvg` function.
3+
*/
4+
5+
import icons from '../dist/icons.json';
6+
7+
const DEFAULT_OPTIONS = {
8+
xmlns: 'http://www.w3.org/2000/svg',
9+
width: 24,
10+
height: 24,
11+
viewBox: '0 0 24 24',
12+
fill: 'none',
13+
stroke: 'currentColor',
14+
'stroke-width': 2,
15+
'stroke-linecap': 'round',
16+
'stroke-linejoin': 'round',
17+
};
18+
19+
/**
20+
* Create an SVG string.
21+
* @param {string} key - Icon name.
22+
* @param {Object} options
23+
* @returns {string}
24+
*/
25+
export default function toSvg(key, options = {}) {
26+
if (!key) {
27+
throw new Error('The required `key` (icon name) parameter is missing.');
28+
}
29+
30+
if (!icons[key]) {
31+
throw new Error(`No icon matching '${key}'. See the complete list of icons at https://feathericons.com`);
32+
}
33+
34+
const combinedOptions = Object.assign({}, DEFAULT_OPTIONS, options);
35+
36+
combinedOptions.class = addDefaultClassNames(combinedOptions.class, key);
37+
38+
const attributes = optionsToAtrributes(combinedOptions);
39+
40+
return `<svg ${attributes}>${icons[key]}</svg>`;
41+
}
42+
43+
/**
44+
* Add default class names.
45+
* @param {string} classNames - One or more class names seperated by spaces.
46+
* @param {string} key - Icon name.
47+
* @returns {string}
48+
*/
49+
function addDefaultClassNames(classNames, key) {
50+
// convert class names string into an array
51+
const classNamesArray = classNames ? classNames.trim().split(/\s+/) : [];
52+
53+
// use Set to avoid duplicate class names
54+
const classNamesSet = new Set(classNamesArray);
55+
56+
// add default class names
57+
classNamesSet.add('feather').add(`feather-${key}`);
58+
59+
return Array.from(classNamesSet).join(' ');
60+
}
61+
62+
/**
63+
* Convert options object to string of html attributes.
64+
* @param {Object} options
65+
* @returns {string}
66+
*/
67+
function optionsToAtrributes(options) {
68+
const attributes = [];
69+
70+
Object.keys(options).forEach(key => {
71+
attributes.push(`${key}="${options[key]}"`);
72+
});
73+
74+
return attributes.join(' ');
75+
}

0 commit comments

Comments
 (0)