mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-11-12 13:38:32 +00:00
fix(lucide): Lucide create element function returning SVG Element (#2816)
* Fix create element function * Formatting * Adjust documentation
This commit is contained in:
@@ -126,11 +126,23 @@ import { createElement, Menu } from 'lucide';
|
||||
|
||||
const menuIcon = createElement(Menu); // Returns HTMLElement (svg)
|
||||
|
||||
// set custom attributes with browser native functions
|
||||
menuIcon.setAttribute('stroke', '#333');
|
||||
menuIcon.classList.add('my-icon-class');
|
||||
// Append HTMLElement in the DOM
|
||||
const myApp = document.getElementById('app');
|
||||
myApp.appendChild(menuIcon);
|
||||
```
|
||||
|
||||
// Append HTMLElement in webpage
|
||||
#### Custom Element binding with custom attributes
|
||||
|
||||
```js
|
||||
import { createElement, Menu } from 'lucide';
|
||||
|
||||
const menuIcon = createElement(Menu, {
|
||||
class: ['my-custom-class', 'icon'],
|
||||
'stroke-width': 1,
|
||||
stroke: '#333'
|
||||
}); // Returns HTMLElement (svg)
|
||||
|
||||
// Append HTMLElement in the DOM
|
||||
const myApp = document.getElementById('app');
|
||||
myApp.appendChild(menuIcon);
|
||||
```
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import defaultAttributes from './defaultAttributes';
|
||||
import { IconNode, SVGProps } from './types';
|
||||
|
||||
type CreateElementParams = [tag: string, attrs: SVGProps, children?: IconNode];
|
||||
type CreateSVGElementParams = [tag: string, attrs: SVGProps, children?: IconNode];
|
||||
|
||||
/**
|
||||
* Creates a new HTMLElement from icon node
|
||||
* @param {string} tag
|
||||
* @param {object} attrs
|
||||
* @param {array} children
|
||||
* @returns {HTMLElement}
|
||||
* Creates a new SVGElement
|
||||
* @param {string} tag - Tag name of the element
|
||||
* @param {object} attrs - Attributes of the element
|
||||
* @param {array} children - Children of the element
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
const createElement = ([tag, attrs, children]: CreateElementParams) => {
|
||||
const createSVGElement = ([tag, attrs, children]: CreateSVGElementParams) => {
|
||||
const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
||||
|
||||
Object.keys(attrs).forEach((name) => {
|
||||
@@ -18,7 +19,7 @@ const createElement = ([tag, attrs, children]: CreateElementParams) => {
|
||||
|
||||
if (children?.length) {
|
||||
children.forEach((child) => {
|
||||
const childElement = createElement(child);
|
||||
const childElement = createSVGElement(child);
|
||||
|
||||
element.appendChild(childElement);
|
||||
});
|
||||
@@ -27,4 +28,20 @@ const createElement = ([tag, attrs, children]: CreateElementParams) => {
|
||||
return element;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new HTMLElement from icon node
|
||||
* @param {array} iconNode - Icon node to be converted to an element
|
||||
* @param {object} customAttrs - Custom attributes to be added to the element
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
const createElement = (iconNode: IconNode, customAttrs: SVGProps = {}) => {
|
||||
const tag = 'svg';
|
||||
const attrs = {
|
||||
...defaultAttributes,
|
||||
...customAttrs,
|
||||
};
|
||||
|
||||
return createSVGElement([tag, attrs, iconNode]);
|
||||
};
|
||||
|
||||
export default createElement;
|
||||
|
||||
@@ -98,7 +98,7 @@ const replaceElement = (element: Element, { nameAttr, icons, attrs }: ReplaceEle
|
||||
});
|
||||
}
|
||||
|
||||
const svgElement = createElement(['svg', iconAttrs, iconNode]);
|
||||
const svgElement = createElement(iconNode, iconAttrs);
|
||||
|
||||
return element.parentNode?.replaceChild(svgElement, element);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`createElement > should match the snapshot 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"
|
||||
>
|
||||
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8">
|
||||
</path>
|
||||
<path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z">
|
||||
</path>
|
||||
</svg>
|
||||
`;
|
||||
@@ -0,0 +1,37 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { House, createElement } from '../src/lucide';
|
||||
import { getOriginalSvg } from './helpers';
|
||||
|
||||
describe('createElement', () => {
|
||||
it('should create SVG Element', () => {
|
||||
const HomeSVG = createElement(House);
|
||||
|
||||
expect(HomeSVG.tagName).toBe('svg');
|
||||
});
|
||||
|
||||
it('should match the snapshot', () => {
|
||||
const HomeSVG = createElement(House);
|
||||
|
||||
expect(HomeSVG.outerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should create SVG Element with attributes', () => {
|
||||
const HomeSVG = createElement(House, { fill: 'red' });
|
||||
|
||||
expect(HomeSVG.getAttribute('fill')).toBe('red');
|
||||
});
|
||||
|
||||
it('should create SVG Element with class name', () => {
|
||||
const HomeSVG = createElement(House, { class: 'icon' });
|
||||
|
||||
expect(HomeSVG.getAttribute('class')).toBe('icon');
|
||||
});
|
||||
|
||||
it('should create the correct svg element', () => {
|
||||
const HomeSVG = createElement(House);
|
||||
|
||||
const svg = getOriginalSvg('house', undefined, false);
|
||||
|
||||
expect(HomeSVG.outerHTML).toBe(svg);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { parseSync, stringify } from 'svgson';
|
||||
|
||||
const ICONS_DIR = path.resolve(__dirname, '../../../icons');
|
||||
|
||||
export const getOriginalSvg = (iconName: string, aliasName?: string, setAttrs = true) => {
|
||||
const svgContent = fs.readFileSync(path.join(ICONS_DIR, `${iconName}.svg`), 'utf8');
|
||||
const svgParsed = parseSync(svgContent);
|
||||
|
||||
if (setAttrs) {
|
||||
svgParsed.attributes['data-lucide'] = aliasName ?? iconName;
|
||||
svgParsed.attributes['class'] = `lucide lucide-${aliasName ?? iconName}`;
|
||||
}
|
||||
|
||||
return stringify(svgParsed, { selfClose: false });
|
||||
};
|
||||
@@ -1,20 +1,6 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createIcons, icons } from '../src/lucide';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { parseSync, stringify } from 'svgson';
|
||||
|
||||
const ICONS_DIR = path.resolve(__dirname, '../../../icons');
|
||||
|
||||
const getOriginalSvg = (iconName: string, aliasName?: string) => {
|
||||
const svgContent = fs.readFileSync(path.join(ICONS_DIR, `${iconName}.svg`), 'utf8');
|
||||
const svgParsed = parseSync(svgContent);
|
||||
|
||||
svgParsed.attributes['data-lucide'] = aliasName ?? iconName;
|
||||
svgParsed.attributes['class'] = `lucide lucide-${aliasName ?? iconName}`;
|
||||
|
||||
return stringify(svgParsed, { selfClose: false });
|
||||
};
|
||||
import { getOriginalSvg } from './helpers';
|
||||
|
||||
describe('createIcons', () => {
|
||||
it('should read elements from DOM and replace it with icons', () => {
|
||||
|
||||
Reference in New Issue
Block a user