From f8e7d35649c87a5c88582e9bf6ad847fc0a3b4de Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 01:08:31 +0000 Subject: [PATCH 01/13] fix: consistent icon name class --- .../lucide-react/scripts/exportTemplate.mjs | 2 +- packages/lucide-react/src/createLucideIcon.ts | 9 +++++---- .../lucide-solid/scripts/exportTemplate.mjs | 2 +- packages/lucide-solid/src/Icon.tsx | 11 ++++++++--- packages/lucide-vue-next/src/Icon.ts | 17 ++++++++++++++--- packages/lucide-vue/scripts/exportTemplate.mjs | 2 +- packages/lucide-vue/src/createLucideIcon.ts | 6 +++--- 7 files changed, 33 insertions(+), 16 deletions(-) diff --git a/packages/lucide-react/scripts/exportTemplate.mjs b/packages/lucide-react/scripts/exportTemplate.mjs index e39cf0a6fee..b0d404cf480 100644 --- a/packages/lucide-react/scripts/exportTemplate.mjs +++ b/packages/lucide-react/scripts/exportTemplate.mjs @@ -29,7 +29,7 @@ export const __iconNode: IconNode = ${JSON.stringify(children)} * @returns {JSX.Element} JSX Element * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ -const ${componentName} = createLucideIcon('${componentName}', __iconNode); +const ${componentName} = createLucideIcon('${componentName}', __iconNode, '${iconName}'); export default ${componentName}; `; diff --git a/packages/lucide-react/src/createLucideIcon.ts b/packages/lucide-react/src/createLucideIcon.ts index b209293824a..74a0988472e 100644 --- a/packages/lucide-react/src/createLucideIcon.ts +++ b/packages/lucide-react/src/createLucideIcon.ts @@ -5,21 +5,22 @@ import Icon from './Icon'; /** * Create a Lucide icon component - * @param {string} iconName + * @param {string} componentName * @param {array} iconNode + * @param {string} iconName * @returns {ForwardRefExoticComponent} LucideIcon */ -const createLucideIcon = (iconName: string, iconNode: IconNode) => { +const createLucideIcon = (componentName: string, iconNode: IconNode, iconName: string) => { const Component = forwardRef(({ className, ...props }, ref) => createElement(Icon, { ref, iconNode, - className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className), + className: mergeClasses(`lucide-${toKebabCase(componentName)} lucide-${iconName}`, className), ...props, }), ); - Component.displayName = `${iconName}`; + Component.displayName = `${componentName}`; return Component; }; diff --git a/packages/lucide-solid/scripts/exportTemplate.mjs b/packages/lucide-solid/scripts/exportTemplate.mjs index 116b257b5c4..4f9ecd4b947 100644 --- a/packages/lucide-solid/scripts/exportTemplate.mjs +++ b/packages/lucide-solid/scripts/exportTemplate.mjs @@ -30,7 +30,7 @@ const iconNode: IconNode = ${JSON.stringify(children)}; * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ const ${componentName} = (props: LucideProps) => ( - + ) export default ${componentName}; diff --git a/packages/lucide-solid/src/Icon.tsx b/packages/lucide-solid/src/Icon.tsx index d805f72ca4a..a40014cb47f 100644 --- a/packages/lucide-solid/src/Icon.tsx +++ b/packages/lucide-solid/src/Icon.tsx @@ -5,8 +5,9 @@ import { IconNode, LucideProps } from './types'; import { mergeClasses, toKebabCase } from '@lucide/shared'; interface IconProps { - name?: string; + componentName?: string; iconNode: IconNode; + iconName: string; } const Icon = (props: LucideProps & IconProps) => { @@ -16,7 +17,8 @@ const Icon = (props: LucideProps & IconProps) => { 'strokeWidth', 'children', 'class', - 'name', + 'componentName', + 'iconName', 'iconNode', 'absoluteStrokeWidth', ]); @@ -36,7 +38,10 @@ const Icon = (props: LucideProps & IconProps) => { class={mergeClasses( 'lucide', 'lucide-icon', - localProps.name != null ? `lucide-${toKebabCase(localProps?.name)}` : undefined, + localProps.componentName != null + ? `lucide-${toKebabCase(localProps?.componentName)}` + : undefined, + `lucide-${localProps.iconName}`, localProps.class != null ? localProps.class : '', )} {...rest} diff --git a/packages/lucide-vue-next/src/Icon.ts b/packages/lucide-vue-next/src/Icon.ts index 3b33bc18948..98f3cebef35 100644 --- a/packages/lucide-vue-next/src/Icon.ts +++ b/packages/lucide-vue-next/src/Icon.ts @@ -5,11 +5,22 @@ import { IconNode, LucideProps } from './types'; interface IconProps { iconNode: IconNode; - name: string; + componentName: string; + iconName: string; } const Icon: FunctionalComponent = ( - { size, strokeWidth = 2, absoluteStrokeWidth, color, iconNode, name, class: classes, ...props }, + { + size, + strokeWidth = 2, + absoluteStrokeWidth, + color, + iconNode, + componentName, + iconName, + class: classes, + ...props + }, { slots }, ) => { return h( @@ -20,7 +31,7 @@ const Icon: FunctionalComponent = ( height: size || defaultAttributes.height, stroke: color || defaultAttributes.stroke, 'stroke-width': absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth, - class: ['lucide', `lucide-${toKebabCase(name ?? 'icon')}`], + class: ['lucide', `lucide-${toKebabCase(componentName ?? 'icon')}`, `lucide-${iconName}`], ...props, }, [...iconNode.map((child) => h(...child)), ...(slots.default ? [slots.default()] : [])], diff --git a/packages/lucide-vue/scripts/exportTemplate.mjs b/packages/lucide-vue/scripts/exportTemplate.mjs index 2116f0893b0..49f38a1daff 100644 --- a/packages/lucide-vue/scripts/exportTemplate.mjs +++ b/packages/lucide-vue/scripts/exportTemplate.mjs @@ -26,7 +26,7 @@ import createLucideIcon from '../createLucideIcon'; * @returns {Component} Vue Component * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ -const ${componentName} = createLucideIcon('${componentName}Icon', ${JSON.stringify(children)}); +const ${componentName} = createLucideIcon('${componentName}Icon', ${JSON.stringify(children)}, '${iconName}'); export default ${componentName}; `; diff --git a/packages/lucide-vue/src/createLucideIcon.ts b/packages/lucide-vue/src/createLucideIcon.ts index bb1fc24c506..5f879f83958 100644 --- a/packages/lucide-vue/src/createLucideIcon.ts +++ b/packages/lucide-vue/src/createLucideIcon.ts @@ -6,8 +6,8 @@ var showDeprecationWarning = true; type IconNode = [elementName: string, attrs: Record][]; -export default (iconName: string, iconNode: IconNode): Component => ({ - name: iconName, +export default (componentName: string, iconNode: IconNode, iconName: string): Component => ({ + name: componentName, functional: true, props: { color: { @@ -28,7 +28,7 @@ export default (iconName: string, iconNode: IconNode): Component => ({ }, defaultClass: { type: String, - default: `lucide-icon lucide lucide-${toKebabCase(iconName).replace('-icon', '')}`, + default: `lucide-icon lucide lucide-${toKebabCase(componentName).replace('-icon', '')} lucide-${iconName}`, }, }, render( From aa24fc8404a01cd3bb2e44f01b4d3952cde5e22c Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 01:12:18 +0000 Subject: [PATCH 02/13] merge classes --- packages/lucide-vue-next/src/Icon.ts | 6 ++++-- packages/lucide-vue/src/createLucideIcon.ts | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/lucide-vue-next/src/Icon.ts b/packages/lucide-vue-next/src/Icon.ts index 98f3cebef35..dcb3d81ad61 100644 --- a/packages/lucide-vue-next/src/Icon.ts +++ b/packages/lucide-vue-next/src/Icon.ts @@ -1,5 +1,5 @@ import { type FunctionalComponent, h } from 'vue'; -import { toKebabCase } from '@lucide/shared'; +import { mergeClasses, toKebabCase } from '@lucide/shared'; import defaultAttributes from './defaultAttributes'; import { IconNode, LucideProps } from './types'; @@ -31,7 +31,9 @@ const Icon: FunctionalComponent = ( height: size || defaultAttributes.height, stroke: color || defaultAttributes.stroke, 'stroke-width': absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth, - class: ['lucide', `lucide-${toKebabCase(componentName ?? 'icon')}`, `lucide-${iconName}`], + class: mergeClasses( + `lucide lucide-${toKebabCase(componentName ?? 'icon')} lucide-${iconName}`, + ), ...props, }, [...iconNode.map((child) => h(...child)), ...(slots.default ? [slots.default()] : [])], diff --git a/packages/lucide-vue/src/createLucideIcon.ts b/packages/lucide-vue/src/createLucideIcon.ts index 5f879f83958..974ac9ce3cf 100644 --- a/packages/lucide-vue/src/createLucideIcon.ts +++ b/packages/lucide-vue/src/createLucideIcon.ts @@ -1,6 +1,6 @@ import { Component } from 'vue'; import defaultAttributes from './defaultAttributes'; -import { toKebabCase } from '@lucide/shared'; +import { mergeClasses, toKebabCase } from '@lucide/shared'; var showDeprecationWarning = true; @@ -28,7 +28,9 @@ export default (componentName: string, iconNode: IconNode, iconName: string): Co }, defaultClass: { type: String, - default: `lucide-icon lucide lucide-${toKebabCase(componentName).replace('-icon', '')} lucide-${iconName}`, + default: mergeClasses( + `lucide-icon lucide lucide-${toKebabCase(componentName).replace('-icon', '')} lucide-${iconName}`, + ), }, }, render( From 3475f3d010a91bbb372ce11141f3ed6aa951d252 Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 01:17:48 +0000 Subject: [PATCH 03/13] fix vue-next --- packages/lucide-vue-next/scripts/exportTemplate.mjs | 2 +- packages/lucide-vue-next/src/createLucideIcon.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/lucide-vue-next/scripts/exportTemplate.mjs b/packages/lucide-vue-next/scripts/exportTemplate.mjs index e7550a667fd..7e645ba3eb3 100644 --- a/packages/lucide-vue-next/scripts/exportTemplate.mjs +++ b/packages/lucide-vue-next/scripts/exportTemplate.mjs @@ -26,7 +26,7 @@ import createLucideIcon from '../createLucideIcon'; * @returns {FunctionalComponent} Vue component * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ -const ${componentName} = createLucideIcon('${componentName}Icon', ${JSON.stringify(children)}); +const ${componentName} = createLucideIcon('${componentName}Icon', ${JSON.stringify(children)}, '${iconName}'); export default ${componentName}; `; diff --git a/packages/lucide-vue-next/src/createLucideIcon.ts b/packages/lucide-vue-next/src/createLucideIcon.ts index 27c0904f984..1a77571c18b 100644 --- a/packages/lucide-vue-next/src/createLucideIcon.ts +++ b/packages/lucide-vue-next/src/createLucideIcon.ts @@ -7,19 +7,21 @@ import Icon from './Icon'; /** * Create a Lucide icon component - * @param {string} iconName + * @param {string} componentName * @param {array} iconNode + * @param {string} iconName * @returns {FunctionalComponent} LucideIcon */ const createLucideIcon = - (iconName: string, iconNode: IconNode): FunctionalComponent => + (componentName: string, iconNode: IconNode, iconName: string): FunctionalComponent => (props, { slots }) => h( Icon, { ...props, iconNode, - name: iconName, + componentName, + iconName, }, slots, ); From 1408badb9806ed35d92cf406086b47d37d85149b Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 01:18:35 +0000 Subject: [PATCH 04/13] update test snapshots --- .../tests/__snapshots__/createLucideIcon.spec.tsx.snap | 2 +- .../tests/__snapshots__/dynamicImports.spec.tsx.snap | 2 +- .../tests/__snapshots__/lucide-react.spec.tsx.snap | 6 +++--- .../tests/__snapshots__/Icon.spec.tsx.snap | 2 +- .../tests/__snapshots__/lucide-solid.spec.tsx.snap | 9 ++++++--- .../tests/__snapshots__/Icon.spec.ts.snap | 2 +- .../tests/__snapshots__/lucide-vue-next.spec.ts.snap | 10 +++++----- .../tests/__snapshots__/lucide-vue.spec.ts.snap | 10 +++++----- 8 files changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap b/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap index acf4f973908..bf18cebd10b 100644 --- a/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap +++ b/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap @@ -2,7 +2,7 @@ exports[`Using createLucideIcon > should create a component from an iconNode 1`] = ` should render icons dynamically by using the dyn stroke-width="1" stroke-linecap="round" stroke-linejoin="round" - class="lucide lucide-smile" + class="lucide lucide-smile lucide-smile" aria-label="smile" > should adjust the size, stroke color and stroke-width="4" stroke-linecap="round" stroke-linejoin="round" - class="lucide lucide-grid3x3" + class="lucide lucide-grid3x3 lucide-grid-3x3" > should not scale the strokeWidth when ab stroke-width="1" stroke-linecap="round" stroke-linejoin="round" - class="lucide lucide-grid3x3" + class="lucide lucide-grid3x3 lucide-grid-3x3" > should render an component 1`] = ` stroke-width="2" stroke-linecap="round" stroke-linejoin="round" - class="lucide lucide-grid3x3" + class="lucide lucide-grid3x3 lucide-grid-3x3" > should render icon and match snapshot 1`] = ` should adjust the size, stroke color and height="48" stroke="red" stroke-width="4" - class="lucide lucide-icon lucide-grid3x3" + class="lucide lucide-icon lucide-grid-3x3" data-testid="grid-icon" + name="Grid3x3" > should not scale the strokeWidth when ab height="48" stroke="red" stroke-width="1" - class="lucide lucide-icon lucide-grid3x3" + class="lucide lucide-icon lucide-grid-3x3" data-testid="grid-icon" + name="Grid3x3" > should render a component 1`] = ` height="24" stroke="currentColor" stroke-width="2" - class="lucide lucide-icon lucide-grid3x3" + class="lucide lucide-icon lucide-grid-3x3" + name="Grid3x3" > should render icon and match snapshot 1`] = ` should add a class to the element 1`] = `
should add a class to the element 1`] = exports[`Using lucide icon components > should add a style attribute to the element 1`] = `
should add a style attribute to the elem exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `
should adjust the size, stroke color and exports[`Using lucide icon components > should pass children to the icon slot 1`] = `
should pass children to the icon slot 1` exports[`Using lucide icon components > should render an component 1`] = `
should add a class to the element 1`] = `
should add a class to the element 1`] = exports[`Using lucide icon components > should add a style attribute to the element 1`] = `
should add a style attribute to the elem exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `
should adjust the size, stroke color and exports[`Using lucide icon components > should pass children to the icon slot 1`] = `
should pass children to the icon slot 1` exports[`Using lucide icon components > should render an component 1`] = `
Date: Sat, 8 Mar 2025 01:23:45 +0000 Subject: [PATCH 05/13] fix vue-next --- packages/lucide-vue-next/src/Icon.ts | 3 ++- packages/lucide-vue-next/tests/__snapshots__/Icon.spec.ts.snap | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/lucide-vue-next/src/Icon.ts b/packages/lucide-vue-next/src/Icon.ts index dcb3d81ad61..bbf7ac58784 100644 --- a/packages/lucide-vue-next/src/Icon.ts +++ b/packages/lucide-vue-next/src/Icon.ts @@ -32,7 +32,8 @@ const Icon: FunctionalComponent = ( stroke: color || defaultAttributes.stroke, 'stroke-width': absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth, class: mergeClasses( - `lucide lucide-${toKebabCase(componentName ?? 'icon')} lucide-${iconName}`, + `lucide lucide-${toKebabCase(componentName ?? 'icon')}`, + iconName && `lucide-${iconName}`, ), ...props, }, diff --git a/packages/lucide-vue-next/tests/__snapshots__/Icon.spec.ts.snap b/packages/lucide-vue-next/tests/__snapshots__/Icon.spec.ts.snap index 25584c7183e..5e38eec073c 100644 --- a/packages/lucide-vue-next/tests/__snapshots__/Icon.spec.ts.snap +++ b/packages/lucide-vue-next/tests/__snapshots__/Icon.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Using Icon Component > should render icon and match snapshot 1`] = ` Date: Sat, 8 Mar 2025 01:27:47 +0000 Subject: [PATCH 06/13] fix test --- packages/lucide-react/tests/createLucideIcon.spec.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lucide-react/tests/createLucideIcon.spec.tsx b/packages/lucide-react/tests/createLucideIcon.spec.tsx index 7c1b5e475bd..9adc9bf7c03 100644 --- a/packages/lucide-react/tests/createLucideIcon.spec.tsx +++ b/packages/lucide-react/tests/createLucideIcon.spec.tsx @@ -5,7 +5,7 @@ import { render } from '@testing-library/react'; describe('Using createLucideIcon', () => { it('should create a component from an iconNode', () => { - const AirVent = createLucideIcon('AirVent', airVent); + const AirVent = createLucideIcon('AirVent', airVent, 'air-vent'); const { container } = render(); From 44c9016fe50fc0cc90b2b66ec7db518af60d6a88 Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 01:28:47 +0000 Subject: [PATCH 07/13] fix solid --- packages/lucide-solid/src/Icon.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lucide-solid/src/Icon.tsx b/packages/lucide-solid/src/Icon.tsx index a40014cb47f..8825e97ce72 100644 --- a/packages/lucide-solid/src/Icon.tsx +++ b/packages/lucide-solid/src/Icon.tsx @@ -6,8 +6,8 @@ import { mergeClasses, toKebabCase } from '@lucide/shared'; interface IconProps { componentName?: string; + iconName?: string; iconNode: IconNode; - iconName: string; } const Icon = (props: LucideProps & IconProps) => { @@ -41,7 +41,7 @@ const Icon = (props: LucideProps & IconProps) => { localProps.componentName != null ? `lucide-${toKebabCase(localProps?.componentName)}` : undefined, - `lucide-${localProps.iconName}`, + localProps.iconName && `lucide-${localProps.iconName}`, localProps.class != null ? localProps.class : '', )} {...rest} From b81e92c6c326e2fc5321c6e3c12ca7174ad5724d Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 01:30:52 +0000 Subject: [PATCH 08/13] proper deduplication --- packages/lucide-react/src/createLucideIcon.ts | 6 +++++- packages/lucide-vue/src/createLucideIcon.ts | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/lucide-react/src/createLucideIcon.ts b/packages/lucide-react/src/createLucideIcon.ts index 74a0988472e..d60a06fcdeb 100644 --- a/packages/lucide-react/src/createLucideIcon.ts +++ b/packages/lucide-react/src/createLucideIcon.ts @@ -15,7 +15,11 @@ const createLucideIcon = (componentName: string, iconNode: IconNode, iconName: s createElement(Icon, { ref, iconNode, - className: mergeClasses(`lucide-${toKebabCase(componentName)} lucide-${iconName}`, className), + className: mergeClasses( + `lucide-${toKebabCase(componentName)}`, + `lucide-${iconName}`, + className, + ), ...props, }), ); diff --git a/packages/lucide-vue/src/createLucideIcon.ts b/packages/lucide-vue/src/createLucideIcon.ts index 974ac9ce3cf..cc543d1f9e8 100644 --- a/packages/lucide-vue/src/createLucideIcon.ts +++ b/packages/lucide-vue/src/createLucideIcon.ts @@ -29,7 +29,9 @@ export default (componentName: string, iconNode: IconNode, iconName: string): Co defaultClass: { type: String, default: mergeClasses( - `lucide-icon lucide lucide-${toKebabCase(componentName).replace('-icon', '')} lucide-${iconName}`, + `lucide-icon lucide`, + `lucide-${toKebabCase(componentName).replace('-icon', '')}`, + `lucide-${iconName}`, ), }, }, From b0df4259f659ac4cbce13fd841876f8182663f4a Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 01:31:51 +0000 Subject: [PATCH 09/13] update snapshots --- .../tests/__snapshots__/createLucideIcon.spec.tsx.snap | 2 +- .../tests/__snapshots__/dynamicImports.spec.tsx.snap | 2 +- .../tests/__snapshots__/Icon.spec.tsx.snap | 2 +- .../tests/__snapshots__/lucide-vue.spec.ts.snap | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap b/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap index bf18cebd10b..acf4f973908 100644 --- a/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap +++ b/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap @@ -2,7 +2,7 @@ exports[`Using createLucideIcon > should create a component from an iconNode 1`] = ` should render icons dynamically by using the dyn stroke-width="1" stroke-linecap="round" stroke-linejoin="round" - class="lucide lucide-smile lucide-smile" + class="lucide lucide-smile" aria-label="smile" > should render icon and match snapshot 1`] = ` should add a class to the element 1`] = `
should add a class to the element 1`] = exports[`Using lucide icon components > should add a style attribute to the element 1`] = `
should add a style attribute to the elem exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `
should adjust the size, stroke color and exports[`Using lucide icon components > should pass children to the icon slot 1`] = `
should pass children to the icon slot 1` exports[`Using lucide icon components > should render an component 1`] = `
Date: Sat, 8 Mar 2025 01:34:13 +0000 Subject: [PATCH 10/13] preact --- packages/lucide-preact/scripts/exportTemplate.mjs | 2 +- packages/lucide-preact/src/createLucideIcon.ts | 14 ++++++++++---- .../__snapshots__/lucide-preact.spec.tsx.snap | 6 +++--- .../lucide-preact/tests/createLucideIcon.spec.tsx | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/lucide-preact/scripts/exportTemplate.mjs b/packages/lucide-preact/scripts/exportTemplate.mjs index 42a9be1ffac..ba2de929731 100644 --- a/packages/lucide-preact/scripts/exportTemplate.mjs +++ b/packages/lucide-preact/scripts/exportTemplate.mjs @@ -26,7 +26,7 @@ import createLucideIcon from '../createLucideIcon'; * @returns {JSX.Element} JSX Element * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ -const ${componentName} = createLucideIcon('${componentName}', ${JSON.stringify(children)}); +const ${componentName} = createLucideIcon('${componentName}', ${JSON.stringify(children)}, '${iconName}'); export default ${componentName}; `; diff --git a/packages/lucide-preact/src/createLucideIcon.ts b/packages/lucide-preact/src/createLucideIcon.ts index 2ba13086f3f..0e2d3b40cfa 100644 --- a/packages/lucide-preact/src/createLucideIcon.ts +++ b/packages/lucide-preact/src/createLucideIcon.ts @@ -5,11 +5,16 @@ import type { IconNode, LucideIcon, LucideProps } from './types'; /** * Create a Lucide icon component - * @param {string} iconName + * @param {string} componentName * @param {array} iconNode + * @param {string} iconName * @returns {FunctionComponent} LucideIcon */ -const createLucideIcon = (iconName: string, iconNode: IconNode): LucideIcon => { +const createLucideIcon = ( + componentName: string, + iconNode: IconNode, + iconName: string, +): LucideIcon => { const Component = ({ class: classes = '', children, ...props }: LucideProps) => h( Icon, @@ -17,14 +22,15 @@ const createLucideIcon = (iconName: string, iconNode: IconNode): LucideIcon => { ...props, iconNode, class: mergeClasses>( - `lucide-${toKebabCase(iconName)}`, + `lucide-${toKebabCase(componentName)}`, + `lucide-${iconName}`, classes, ), }, children, ); - Component.displayName = `${iconName}`; + Component.displayName = `${componentName}`; return Component; }; diff --git a/packages/lucide-preact/tests/__snapshots__/lucide-preact.spec.tsx.snap b/packages/lucide-preact/tests/__snapshots__/lucide-preact.spec.tsx.snap index a3cc0865779..eacfae32021 100644 --- a/packages/lucide-preact/tests/__snapshots__/lucide-preact.spec.tsx.snap +++ b/packages/lucide-preact/tests/__snapshots__/lucide-preact.spec.tsx.snap @@ -10,7 +10,7 @@ exports[`Using lucide icon components > should adjust the size, stroke color and stroke-width="4" stroke-linecap="round" stroke-linejoin="round" - class="lucide lucide-grid3x3" + class="lucide lucide-grid3x3 lucide-grid-3x3" > should not scale the strokeWidth when ab stroke-width="1" stroke-linecap="round" stroke-linejoin="round" - class="lucide lucide-grid3x3" + class="lucide lucide-grid3x3 lucide-grid-3x3" > should render an component 1`] = ` stroke-width="2" stroke-linecap="round" stroke-linejoin="round" - class="lucide lucide-grid3x3" + class="lucide lucide-grid3x3 lucide-grid-3x3" > { it('should create a component from an iconNode', () => { - const AirVent = createLucideIcon('AirVent', airVent); + const AirVent = createLucideIcon('AirVent', airVent, 'air-vent'); const { container } = render(); From 767fa12c9f7d0cc9c6db1ea54e13689e57f7d138 Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 11:28:01 +0000 Subject: [PATCH 11/13] refactor --- .../lucide-preact/scripts/exportTemplate.mjs | 2 +- .../lucide-preact/src/createLucideIcon.ts | 17 +++++--------- .../tests/createLucideIcon.spec.tsx | 2 +- .../lucide-react/scripts/exportTemplate.mjs | 2 +- packages/lucide-react/src/createLucideIcon.ts | 11 ++++----- .../tests/createLucideIcon.spec.tsx | 2 +- .../lucide-solid/scripts/exportTemplate.mjs | 2 +- packages/lucide-solid/src/Icon.tsx | 18 +++++++-------- .../__snapshots__/lucide-solid.spec.tsx.snap | 9 +++----- .../scripts/exportTemplate.mjs | 2 +- packages/lucide-vue-next/src/Icon.ts | 23 ++++++------------- .../lucide-vue-next/src/createLucideIcon.ts | 8 +++---- packages/lucide-vue/src/createLucideIcon.ts | 2 +- 13 files changed, 40 insertions(+), 60 deletions(-) diff --git a/packages/lucide-preact/scripts/exportTemplate.mjs b/packages/lucide-preact/scripts/exportTemplate.mjs index ba2de929731..1608ac7b774 100644 --- a/packages/lucide-preact/scripts/exportTemplate.mjs +++ b/packages/lucide-preact/scripts/exportTemplate.mjs @@ -26,7 +26,7 @@ import createLucideIcon from '../createLucideIcon'; * @returns {JSX.Element} JSX Element * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ -const ${componentName} = createLucideIcon('${componentName}', ${JSON.stringify(children)}, '${iconName}'); +const ${componentName} = createLucideIcon('${iconName}', ${JSON.stringify(children)}); export default ${componentName}; `; diff --git a/packages/lucide-preact/src/createLucideIcon.ts b/packages/lucide-preact/src/createLucideIcon.ts index 0e2d3b40cfa..b2e2fb3009b 100644 --- a/packages/lucide-preact/src/createLucideIcon.ts +++ b/packages/lucide-preact/src/createLucideIcon.ts @@ -1,20 +1,15 @@ import { h, type JSX } from 'preact'; -import { mergeClasses, toKebabCase } from '@lucide/shared'; +import { mergeClasses, toKebabCase, toPascalCase } from '@lucide/shared'; import Icon from './Icon'; import type { IconNode, LucideIcon, LucideProps } from './types'; /** * Create a Lucide icon component - * @param {string} componentName - * @param {array} iconNode * @param {string} iconName + * @param {array} iconNode * @returns {FunctionComponent} LucideIcon */ -const createLucideIcon = ( - componentName: string, - iconNode: IconNode, - iconName: string, -): LucideIcon => { +const createLucideIcon = (iconName: string, iconNode: IconNode): LucideIcon => { const Component = ({ class: classes = '', children, ...props }: LucideProps) => h( Icon, @@ -22,15 +17,15 @@ const createLucideIcon = ( ...props, iconNode, class: mergeClasses>( - `lucide-${toKebabCase(componentName)}`, - `lucide-${iconName}`, + `lucide-${toKebabCase(toPascalCase(iconName))}`, + `lucide-${toKebabCase(iconName)}`, classes, ), }, children, ); - Component.displayName = `${componentName}`; + Component.displayName = toPascalCase(iconName); return Component; }; diff --git a/packages/lucide-preact/tests/createLucideIcon.spec.tsx b/packages/lucide-preact/tests/createLucideIcon.spec.tsx index 4e6dfb11649..fd8e56aac25 100644 --- a/packages/lucide-preact/tests/createLucideIcon.spec.tsx +++ b/packages/lucide-preact/tests/createLucideIcon.spec.tsx @@ -5,7 +5,7 @@ import { render } from '@testing-library/preact'; describe('Using createLucideIcon', () => { it('should create a component from an iconNode', () => { - const AirVent = createLucideIcon('AirVent', airVent, 'air-vent'); + const AirVent = createLucideIcon('air-vent', airVent); const { container } = render(); diff --git a/packages/lucide-react/scripts/exportTemplate.mjs b/packages/lucide-react/scripts/exportTemplate.mjs index b0d404cf480..167d858a0be 100644 --- a/packages/lucide-react/scripts/exportTemplate.mjs +++ b/packages/lucide-react/scripts/exportTemplate.mjs @@ -29,7 +29,7 @@ export const __iconNode: IconNode = ${JSON.stringify(children)} * @returns {JSX.Element} JSX Element * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ -const ${componentName} = createLucideIcon('${componentName}', __iconNode, '${iconName}'); +const ${componentName} = createLucideIcon('${iconName}', __iconNode); export default ${componentName}; `; diff --git a/packages/lucide-react/src/createLucideIcon.ts b/packages/lucide-react/src/createLucideIcon.ts index d60a06fcdeb..bc453af84fb 100644 --- a/packages/lucide-react/src/createLucideIcon.ts +++ b/packages/lucide-react/src/createLucideIcon.ts @@ -1,22 +1,21 @@ import { createElement, forwardRef } from 'react'; -import { mergeClasses, toKebabCase } from '@lucide/shared'; +import { mergeClasses, toKebabCase, toPascalCase } from '@lucide/shared'; import { IconNode, LucideProps } from './types'; import Icon from './Icon'; /** * Create a Lucide icon component - * @param {string} componentName - * @param {array} iconNode * @param {string} iconName + * @param {array} iconNode * @returns {ForwardRefExoticComponent} LucideIcon */ -const createLucideIcon = (componentName: string, iconNode: IconNode, iconName: string) => { +const createLucideIcon = (iconName: string, iconNode: IconNode) => { const Component = forwardRef(({ className, ...props }, ref) => createElement(Icon, { ref, iconNode, className: mergeClasses( - `lucide-${toKebabCase(componentName)}`, + `lucide-${toKebabCase(toPascalCase(iconName))}`, `lucide-${iconName}`, className, ), @@ -24,7 +23,7 @@ const createLucideIcon = (componentName: string, iconNode: IconNode, iconName: s }), ); - Component.displayName = `${componentName}`; + Component.displayName = toPascalCase(iconName); return Component; }; diff --git a/packages/lucide-react/tests/createLucideIcon.spec.tsx b/packages/lucide-react/tests/createLucideIcon.spec.tsx index 9adc9bf7c03..d3b5f8c7ee0 100644 --- a/packages/lucide-react/tests/createLucideIcon.spec.tsx +++ b/packages/lucide-react/tests/createLucideIcon.spec.tsx @@ -5,7 +5,7 @@ import { render } from '@testing-library/react'; describe('Using createLucideIcon', () => { it('should create a component from an iconNode', () => { - const AirVent = createLucideIcon('AirVent', airVent, 'air-vent'); + const AirVent = createLucideIcon('air-vent', airVent); const { container } = render(); diff --git a/packages/lucide-solid/scripts/exportTemplate.mjs b/packages/lucide-solid/scripts/exportTemplate.mjs index 4f9ecd4b947..5c1a4a68691 100644 --- a/packages/lucide-solid/scripts/exportTemplate.mjs +++ b/packages/lucide-solid/scripts/exportTemplate.mjs @@ -30,7 +30,7 @@ const iconNode: IconNode = ${JSON.stringify(children)}; * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ const ${componentName} = (props: LucideProps) => ( - + ) export default ${componentName}; diff --git a/packages/lucide-solid/src/Icon.tsx b/packages/lucide-solid/src/Icon.tsx index 8825e97ce72..fb3f077133c 100644 --- a/packages/lucide-solid/src/Icon.tsx +++ b/packages/lucide-solid/src/Icon.tsx @@ -2,11 +2,10 @@ import { For, splitProps } from 'solid-js'; import { Dynamic } from 'solid-js/web'; import defaultAttributes from './defaultAttributes'; import { IconNode, LucideProps } from './types'; -import { mergeClasses, toKebabCase } from '@lucide/shared'; +import { mergeClasses, toKebabCase, toPascalCase } from '@lucide/shared'; interface IconProps { - componentName?: string; - iconName?: string; + name?: string; iconNode: IconNode; } @@ -17,8 +16,7 @@ const Icon = (props: LucideProps & IconProps) => { 'strokeWidth', 'children', 'class', - 'componentName', - 'iconName', + 'name', 'iconNode', 'absoluteStrokeWidth', ]); @@ -38,10 +36,12 @@ const Icon = (props: LucideProps & IconProps) => { class={mergeClasses( 'lucide', 'lucide-icon', - localProps.componentName != null - ? `lucide-${toKebabCase(localProps?.componentName)}` - : undefined, - localProps.iconName && `lucide-${localProps.iconName}`, + ...(localProps.name != null + ? [ + `lucide-${toKebabCase(toPascalCase(localProps.name))}`, + `lucide-${toKebabCase(localProps.name)}`, + ] + : []), localProps.class != null ? localProps.class : '', )} {...rest} diff --git a/packages/lucide-solid/tests/__snapshots__/lucide-solid.spec.tsx.snap b/packages/lucide-solid/tests/__snapshots__/lucide-solid.spec.tsx.snap index 33504f56bb8..73f49add462 100644 --- a/packages/lucide-solid/tests/__snapshots__/lucide-solid.spec.tsx.snap +++ b/packages/lucide-solid/tests/__snapshots__/lucide-solid.spec.tsx.snap @@ -10,9 +10,8 @@ exports[`Using lucide icon components > should adjust the size, stroke color and height="48" stroke="red" stroke-width="4" - class="lucide lucide-icon lucide-grid-3x3" + class="lucide lucide-icon lucide-grid3x3 lucide-grid-3x3" data-testid="grid-icon" - name="Grid3x3" > should not scale the strokeWidth when ab height="48" stroke="red" stroke-width="1" - class="lucide lucide-icon lucide-grid-3x3" + class="lucide lucide-icon lucide-grid3x3 lucide-grid-3x3" data-testid="grid-icon" - name="Grid3x3" > should render a component 1`] = ` height="24" stroke="currentColor" stroke-width="2" - class="lucide lucide-icon lucide-grid-3x3" - name="Grid3x3" + class="lucide lucide-icon lucide-grid3x3 lucide-grid-3x3" > = ( - { - size, - strokeWidth = 2, - absoluteStrokeWidth, - color, - iconNode, - componentName, - iconName, - class: classes, - ...props - }, + { size, strokeWidth = 2, absoluteStrokeWidth, color, iconNode, name, class: classes, ...props }, { slots }, ) => { return h( @@ -32,8 +21,10 @@ const Icon: FunctionalComponent = ( stroke: color || defaultAttributes.stroke, 'stroke-width': absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth, class: mergeClasses( - `lucide lucide-${toKebabCase(componentName ?? 'icon')}`, - iconName && `lucide-${iconName}`, + 'lucide', + ...(name + ? [`lucide-${toKebabCase(toPascalCase(name))}-icon`, `lucide-${toKebabCase(name)}`] + : ['lucide-icon']), ), ...props, }, diff --git a/packages/lucide-vue-next/src/createLucideIcon.ts b/packages/lucide-vue-next/src/createLucideIcon.ts index 1a77571c18b..27c0904f984 100644 --- a/packages/lucide-vue-next/src/createLucideIcon.ts +++ b/packages/lucide-vue-next/src/createLucideIcon.ts @@ -7,21 +7,19 @@ import Icon from './Icon'; /** * Create a Lucide icon component - * @param {string} componentName - * @param {array} iconNode * @param {string} iconName + * @param {array} iconNode * @returns {FunctionalComponent} LucideIcon */ const createLucideIcon = - (componentName: string, iconNode: IconNode, iconName: string): FunctionalComponent => + (iconName: string, iconNode: IconNode): FunctionalComponent => (props, { slots }) => h( Icon, { ...props, iconNode, - componentName, - iconName, + name: iconName, }, slots, ); diff --git a/packages/lucide-vue/src/createLucideIcon.ts b/packages/lucide-vue/src/createLucideIcon.ts index cc543d1f9e8..807d90600e4 100644 --- a/packages/lucide-vue/src/createLucideIcon.ts +++ b/packages/lucide-vue/src/createLucideIcon.ts @@ -29,7 +29,7 @@ export default (componentName: string, iconNode: IconNode, iconName: string): Co defaultClass: { type: String, default: mergeClasses( - `lucide-icon lucide`, + 'lucide-icon lucide', `lucide-${toKebabCase(componentName).replace('-icon', '')}`, `lucide-${iconName}`, ), From 9a599f2cc6c08779c35591e811a73102fb88ada0 Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 11:31:05 +0000 Subject: [PATCH 12/13] deprecated --- packages/lucide-vue/scripts/exportTemplate.mjs | 2 +- packages/lucide-vue/src/createLucideIcon.ts | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/lucide-vue/scripts/exportTemplate.mjs b/packages/lucide-vue/scripts/exportTemplate.mjs index 49f38a1daff..2116f0893b0 100644 --- a/packages/lucide-vue/scripts/exportTemplate.mjs +++ b/packages/lucide-vue/scripts/exportTemplate.mjs @@ -26,7 +26,7 @@ import createLucideIcon from '../createLucideIcon'; * @returns {Component} Vue Component * ${deprecated ? `@deprecated ${deprecationReason}` : ''} */ -const ${componentName} = createLucideIcon('${componentName}Icon', ${JSON.stringify(children)}, '${iconName}'); +const ${componentName} = createLucideIcon('${componentName}Icon', ${JSON.stringify(children)}); export default ${componentName}; `; diff --git a/packages/lucide-vue/src/createLucideIcon.ts b/packages/lucide-vue/src/createLucideIcon.ts index 807d90600e4..bb1fc24c506 100644 --- a/packages/lucide-vue/src/createLucideIcon.ts +++ b/packages/lucide-vue/src/createLucideIcon.ts @@ -1,13 +1,13 @@ import { Component } from 'vue'; import defaultAttributes from './defaultAttributes'; -import { mergeClasses, toKebabCase } from '@lucide/shared'; +import { toKebabCase } from '@lucide/shared'; var showDeprecationWarning = true; type IconNode = [elementName: string, attrs: Record][]; -export default (componentName: string, iconNode: IconNode, iconName: string): Component => ({ - name: componentName, +export default (iconName: string, iconNode: IconNode): Component => ({ + name: iconName, functional: true, props: { color: { @@ -28,11 +28,7 @@ export default (componentName: string, iconNode: IconNode, iconName: string): Co }, defaultClass: { type: String, - default: mergeClasses( - 'lucide-icon lucide', - `lucide-${toKebabCase(componentName).replace('-icon', '')}`, - `lucide-${iconName}`, - ), + default: `lucide-icon lucide lucide-${toKebabCase(iconName).replace('-icon', '')}`, }, }, render( From 3ef56bf9b3f822f0fa46466470f0fd2ed8c82679 Mon Sep 17 00:00:00 2001 From: Dante Issaias Date: Sat, 8 Mar 2025 11:47:51 +0000 Subject: [PATCH 13/13] refactor tests --- .../createLucideIcon.spec.tsx.snap | 56 +++++++++++++++++++ .../tests/createLucideIcon.spec.tsx | 18 ++++++ .../createLucideIcon.spec.tsx.snap | 56 +++++++++++++++++++ .../tests/createLucideIcon.spec.tsx | 18 ++++++ 4 files changed, 148 insertions(+) diff --git a/packages/lucide-preact/tests/__snapshots__/createLucideIcon.spec.tsx.snap b/packages/lucide-preact/tests/__snapshots__/createLucideIcon.spec.tsx.snap index acf4f973908..aeb02b39527 100644 --- a/packages/lucide-preact/tests/__snapshots__/createLucideIcon.spec.tsx.snap +++ b/packages/lucide-preact/tests/__snapshots__/createLucideIcon.spec.tsx.snap @@ -27,3 +27,59 @@ exports[`Using createLucideIcon > should create a component from an iconNode 1`] /> `; + +exports[`Using createLucideIcon > should create a component from an iconNode with iconName 1`] = ` + + + + + + +`; + +exports[`Using createLucideIcon > should include backwards compatible className 1`] = ` + + + + + + +`; diff --git a/packages/lucide-preact/tests/createLucideIcon.spec.tsx b/packages/lucide-preact/tests/createLucideIcon.spec.tsx index fd8e56aac25..bab081ff065 100644 --- a/packages/lucide-preact/tests/createLucideIcon.spec.tsx +++ b/packages/lucide-preact/tests/createLucideIcon.spec.tsx @@ -5,6 +5,15 @@ import { render } from '@testing-library/preact'; describe('Using createLucideIcon', () => { it('should create a component from an iconNode', () => { + const AirVent = createLucideIcon('AirVent', airVent); + + const { container } = render(); + + expect(container.firstChild).toMatchSnapshot(); + expect(container.firstChild).toBeDefined(); + }); + + it('should create a component from an iconNode with iconName', () => { const AirVent = createLucideIcon('air-vent', airVent); const { container } = render(); @@ -12,4 +21,13 @@ describe('Using createLucideIcon', () => { expect(container.firstChild).toMatchSnapshot(); expect(container.firstChild).toBeDefined(); }); + + it('should include backwards compatible className', () => { + const Layout2 = createLucideIcon('layout-2', airVent); + + const { container } = render(); + + expect(container.firstChild).toMatchSnapshot(); + expect(container.firstChild).toBeDefined(); + }); }); diff --git a/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap b/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap index acf4f973908..a1f9dc728ba 100644 --- a/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap +++ b/packages/lucide-react/tests/__snapshots__/createLucideIcon.spec.tsx.snap @@ -1,6 +1,34 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Using createLucideIcon > should create a component from an iconNode 1`] = ` + + + + + + +`; + +exports[`Using createLucideIcon > should create a component from an iconNode with iconName 1`] = ` should create a component from an iconNode 1`] /> `; + +exports[`Using createLucideIcon > should include backwards compatible className 1`] = ` + + + + + + +`; diff --git a/packages/lucide-react/tests/createLucideIcon.spec.tsx b/packages/lucide-react/tests/createLucideIcon.spec.tsx index d3b5f8c7ee0..051bc579ebb 100644 --- a/packages/lucide-react/tests/createLucideIcon.spec.tsx +++ b/packages/lucide-react/tests/createLucideIcon.spec.tsx @@ -5,6 +5,15 @@ import { render } from '@testing-library/react'; describe('Using createLucideIcon', () => { it('should create a component from an iconNode', () => { + const AirVent = createLucideIcon('AirVent', airVent); + + const { container } = render(); + + expect(container.firstChild).toMatchSnapshot(); + expect(container.firstChild).toBeDefined(); + }); + + it('should create a component from an iconNode with iconName', () => { const AirVent = createLucideIcon('air-vent', airVent); const { container } = render(); @@ -12,4 +21,13 @@ describe('Using createLucideIcon', () => { expect(container.firstChild).toMatchSnapshot(); expect(container.firstChild).toBeDefined(); }); + + it('should include backwards compatible className', () => { + const Layout2 = createLucideIcon('layout-2', airVent); + + const { container } = render(); + + expect(container.firstChild).toMatchSnapshot(); + expect(container.firstChild).toBeDefined(); + }); });