diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..354f5a0 --- /dev/null +++ b/src/index.js @@ -0,0 +1,9 @@ +/** + * @file Exposes `feather` object. + */ + +import icons from '../dist/icons.json'; +import toSvg from './to-svg'; +import replace from './replace'; + +module.exports = { icons, toSvg, replace }; diff --git a/src/replace.js b/src/replace.js new file mode 100644 index 0000000..43026cc --- /dev/null +++ b/src/replace.js @@ -0,0 +1,54 @@ +/** + * @file Implements `replace` function. + */ + +/* global document, DOMParser */ + +import icons from '../dist/icons.json'; +import toSvg from './to-svg'; + +/** + * Replace all elements that have a `data-feather` attribute with SVG markup + * corresponding to the element's `data-feather` attribute value. + * @param {Object} options + */ +export default function replace(options = {}) { + 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)); +} + +/** + * Replace single element with SVG markup + * corresponding to the element's `data-feather` attribute value. + * @param {Element} element + * @param {Object} options + */ +function replaceElement(element, options) { + const key = element.getAttribute('data-feather'); + + if (!key) { + console.error('The required `data-feather` attribute has no value.'); + return; + } + + if (!icons[key]) { + console.error(`No icon matching '${key}'. See the complete list of icons at https://feathericons.com`); + return; + } + + const elementClassAttr = element.getAttribute('class'); + const classNames = ( + options.class ? `${options.class} ${elementClassAttr}` : elementClassAttr + ); + + const svgString = toSvg(key, Object.assign({}, options, { class: classNames })); + const svgDocument = new DOMParser().parseFromString(svgString, 'image/svg+xml'); + const svgElement = svgDocument.querySelector('svg'); + + element.parentNode.replaceChild(svgElement, element); +} diff --git a/src/to-svg.js b/src/to-svg.js new file mode 100644 index 0000000..253cc51 --- /dev/null +++ b/src/to-svg.js @@ -0,0 +1,75 @@ +/** + * @file Implements `toSvg` function. + */ + +import icons from '../dist/icons.json'; + +const DEFAULT_OPTIONS = { + 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', +}; + +/** + * Create an SVG string. + * @param {string} key - Icon name. + * @param {Object} options + * @returns {string} + */ +export default function toSvg(key, options = {}) { + if (!key) { + 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`); + } + + const combinedOptions = Object.assign({}, DEFAULT_OPTIONS, options); + + combinedOptions.class = addDefaultClassNames(combinedOptions.class, key); + + const attributes = optionsToAtrributes(combinedOptions); + + return `${icons[key]}`; +} + +/** + * 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 optionsToAtrributes(options) { + const attributes = []; + + Object.keys(options).forEach(key => { + attributes.push(`${key}="${options[key]}"`); + }); + + return attributes.join(' '); +}