mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-16 12:47:41 +01:00
* fix(packages/lucide): replace elements inside `<template>` (#2635) * Added replaceInsideTemplates option * Format code * Simply code and add some documentation * Fix vercel build --------- Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
This commit is contained in:
@@ -93,6 +93,7 @@ In the `createIcons` function you can pass some extra parameters:
|
||||
- you can pass `nameAttr` to adjust the attribute name to replace for
|
||||
- you can pass `attrs` to pass additional custom attributes, for instance CSS classes or stroke options.
|
||||
- you can pass `root` to provide a custom DOM element the icons should be replaced in (useful when manipulating small sections of a large DOM or elements in the shadow DOM)
|
||||
- you can pass `inTemplates: true` to also replace icons inside `<template>` tags.
|
||||
|
||||
Here is a full example:
|
||||
|
||||
@@ -107,6 +108,7 @@ createIcons({
|
||||
},
|
||||
nameAttr: 'data-lucide', // attribute for the icon name.
|
||||
root: element, // DOM element to replace icons in.
|
||||
inTemplates: true // Also replace icons inside <template> tags.
|
||||
});
|
||||
```
|
||||
|
||||
@@ -124,6 +126,34 @@ createIcons({
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Document root
|
||||
|
||||
Apply icons in a custom root element, for instance a shadow DOM root.
|
||||
|
||||
```js
|
||||
import { createIcons } from 'lucide';
|
||||
|
||||
// Custom root element, for instance a shadow DOM root.
|
||||
const shadowRoot = element.attachShadow({ mode: 'open' });
|
||||
|
||||
createIcons({
|
||||
root: shadowRoot
|
||||
});
|
||||
```
|
||||
|
||||
### Apply icons inside `<template>` tags
|
||||
|
||||
By default icons inside `<template>` tags are not added.
|
||||
By setting the `inTemplates` option to `true`, icons inside templates will also be replaced.
|
||||
|
||||
```js
|
||||
import { createIcons } from 'lucide';
|
||||
|
||||
createIcons({
|
||||
inTemplates: true
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Element binding
|
||||
|
||||
```js
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
import replaceElement from './replaceElement';
|
||||
import * as iconAndAliases from './iconsAndAliases';
|
||||
import { Icons, SVGProps } from './types';
|
||||
|
||||
export interface CreateIconsOptions {
|
||||
icons?: Icons;
|
||||
nameAttr?: string;
|
||||
attrs?: SVGProps;
|
||||
root?: Element | Document | DocumentFragment;
|
||||
inTemplates?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all elements with matching nameAttr with the defined icons
|
||||
* @param {{ icons?: object, nameAttr?: string, attrs?: object, root?: Element | Document }} options
|
||||
* @param {CreateIconsOptions} options
|
||||
*/
|
||||
const createIcons = ({
|
||||
icons = {},
|
||||
nameAttr = 'data-lucide',
|
||||
attrs = {},
|
||||
root = document,
|
||||
}: { icons?: object; nameAttr?: string; attrs?: object; root?: Element | Document } = {}) => {
|
||||
inTemplates,
|
||||
}: CreateIconsOptions) => {
|
||||
if (!Object.values(icons).length) {
|
||||
throw new Error(
|
||||
"Please provide an icons object.\nIf you want to use all the icons you can import it like:\n `import { createIcons, icons } from 'lucide';\nlucide.createIcons({icons});`",
|
||||
@@ -21,10 +31,23 @@ const createIcons = ({
|
||||
throw new Error('`createIcons()` only works in a browser environment.');
|
||||
}
|
||||
|
||||
const elementsToReplace = root.querySelectorAll(`[${nameAttr}]`);
|
||||
Array.from(elementsToReplace).forEach((element) =>
|
||||
replaceElement(element, { nameAttr, icons, attrs }),
|
||||
);
|
||||
const elementsToReplace = Array.from(root.querySelectorAll(`[${nameAttr}]`));
|
||||
|
||||
elementsToReplace.forEach((element) => replaceElement(element, { nameAttr, icons, attrs }));
|
||||
|
||||
if (inTemplates) {
|
||||
const templates = Array.from(root.querySelectorAll('template'));
|
||||
|
||||
templates.forEach((template) =>
|
||||
createIcons({
|
||||
icons,
|
||||
nameAttr,
|
||||
attrs,
|
||||
root: template.content,
|
||||
inTemplates,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/** @todo: remove this block in v1.0 */
|
||||
if (nameAttr === 'data-lucide') {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import createElement from './createElement';
|
||||
import defaultAttributes from './defaultAttributes';
|
||||
import { Icons } from './types';
|
||||
import { Icons, SVGProps } from './types';
|
||||
|
||||
export type CustomAttrs = { [attr: string]: any };
|
||||
|
||||
@@ -21,7 +21,7 @@ export const getAttrs = (element: Element): Record<string, string> =>
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getClassNames = (
|
||||
attrs: Record<string, string | string[]> | string,
|
||||
attrs: Record<string, number | string | string[]> | string,
|
||||
): string | string[] => {
|
||||
if (typeof attrs === 'string') return attrs;
|
||||
if (!attrs || !attrs.class) return '';
|
||||
@@ -40,7 +40,7 @@ export const getClassNames = (
|
||||
* @returns {string}
|
||||
*/
|
||||
export const combineClassNames = (
|
||||
arrayOfClassnames: (string | Record<string, string | string[]>)[],
|
||||
arrayOfClassnames: (string | Record<string, number | string | string[]>)[],
|
||||
) => {
|
||||
const classNameArray = arrayOfClassnames.flatMap(getClassNames);
|
||||
|
||||
@@ -57,7 +57,7 @@ const toPascalCase = (string: string): string =>
|
||||
interface ReplaceElementOptions {
|
||||
nameAttr: string;
|
||||
icons: Icons;
|
||||
attrs: Record<string, string>;
|
||||
attrs: SVGProps;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,4 +104,20 @@ describe('createIcons', () => {
|
||||
expect(document.body.innerHTML).toBe(svg);
|
||||
expect(document.body.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should not replace icons inside template elements by default', () => {
|
||||
document.body.innerHTML = `<template><i data-lucide="house"></i></template>`;
|
||||
|
||||
createIcons({ icons });
|
||||
const hasIcon = !!document.querySelector('template')?.content.querySelector('svg');
|
||||
expect(hasIcon).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should replace icons inside template elements when replaceInsideTemplates is true', () => {
|
||||
document.body.innerHTML = `<template><i data-lucide="house"></i></template>`;
|
||||
|
||||
createIcons({ icons, inTemplates: true });
|
||||
const hasIcon = !!document.querySelector('template')?.content.querySelector('svg');
|
||||
expect(hasIcon).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user