fix(packages): consistent icon name class (#2878)

* fix: consistent icon name class

* merge classes

* fix vue-next

* update test snapshots

* fix vue-next

* fix test

* fix solid

* proper deduplication

* update snapshots

* preact

* refactor

* deprecated

* refactor tests

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
This commit is contained in:
Dante Issaias
2025-03-21 10:35:54 +00:00
committed by GitHub
parent 6d6aa4c4cc
commit 4835ae67a9
16 changed files with 190 additions and 27 deletions

View File

@@ -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('${iconName}', ${JSON.stringify(children)});
export default ${componentName};
`;

View File

@@ -1,5 +1,5 @@
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';
@@ -17,6 +17,7 @@ const createLucideIcon = (iconName: string, iconNode: IconNode): LucideIcon => {
...props,
iconNode,
class: mergeClasses<string | JSX.SignalLike<string | undefined>>(
`lucide-${toKebabCase(toPascalCase(iconName))}`,
`lucide-${toKebabCase(iconName)}`,
classes,
),
@@ -24,7 +25,7 @@ const createLucideIcon = (iconName: string, iconNode: IconNode): LucideIcon => {
children,
);
Component.displayName = `${iconName}`;
Component.displayName = toPascalCase(iconName);
return Component;
};

View File

@@ -27,3 +27,59 @@ exports[`Using createLucideIcon > should create a component from an iconNode 1`]
/>
</svg>
`;
exports[`Using createLucideIcon > should create a component from an iconNode with iconName 1`] = `
<svg
class="lucide lucide-air-vent"
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"
/>
<path
d="M6 8h12"
/>
<path
d="M18.3 17.7a2.5 2.5 0 0 1-3.16 3.83 2.53 2.53 0 0 1-1.14-2V12"
/>
<path
d="M6.6 15.6A2 2 0 1 0 10 17v-5"
/>
</svg>
`;
exports[`Using createLucideIcon > should include backwards compatible className 1`] = `
<svg
class="lucide lucide-layout2 lucide-layout-2"
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"
/>
<path
d="M6 8h12"
/>
<path
d="M18.3 17.7a2.5 2.5 0 0 1-3.16 3.83 2.53 2.53 0 0 1-1.14-2V12"
/>
<path
d="M6.6 15.6A2 2 0 1 0 10 17v-5"
/>
</svg>
`;

View File

@@ -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"
>
<rect width="18"
height="18"
@@ -40,7 +40,7 @@ exports[`Using lucide icon components > 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"
>
<rect width="18"
height="18"
@@ -70,7 +70,7 @@ exports[`Using lucide icon components > 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"
>
<rect width="18"
height="18"

View File

@@ -12,4 +12,22 @@ describe('Using createLucideIcon', () => {
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(<AirVent />);
expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toBeDefined();
});
it('should include backwards compatible className', () => {
const Layout2 = createLucideIcon('layout-2', airVent);
const { container } = render(<Layout2 />);
expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toBeDefined();
});
});

View File

@@ -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('${iconName}', __iconNode);
export default ${componentName};
`;

View File

@@ -1,5 +1,5 @@
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';
@@ -14,12 +14,16 @@ const createLucideIcon = (iconName: string, iconNode: IconNode) => {
createElement(Icon, {
ref,
iconNode,
className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className),
className: mergeClasses(
`lucide-${toKebabCase(toPascalCase(iconName))}`,
`lucide-${iconName}`,
className,
),
...props,
}),
);
Component.displayName = `${iconName}`;
Component.displayName = toPascalCase(iconName);
return Component;
};

View File

@@ -1,6 +1,34 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Using createLucideIcon > should create a component from an iconNode 1`] = `
<svg
class="lucide lucide-air-vent lucide-AirVent"
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"
/>
<path
d="M6 8h12"
/>
<path
d="M18.3 17.7a2.5 2.5 0 0 1-3.16 3.83 2.53 2.53 0 0 1-1.14-2V12"
/>
<path
d="M6.6 15.6A2 2 0 1 0 10 17v-5"
/>
</svg>
`;
exports[`Using createLucideIcon > should create a component from an iconNode with iconName 1`] = `
<svg
class="lucide lucide-air-vent"
fill="none"
@@ -27,3 +55,31 @@ exports[`Using createLucideIcon > should create a component from an iconNode 1`]
/>
</svg>
`;
exports[`Using createLucideIcon > should include backwards compatible className 1`] = `
<svg
class="lucide lucide-layout2 lucide-layout-2"
fill="none"
height="24"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"
/>
<path
d="M6 8h12"
/>
<path
d="M18.3 17.7a2.5 2.5 0 0 1-3.16 3.83 2.53 2.53 0 0 1-1.14-2V12"
/>
<path
d="M6.6 15.6A2 2 0 1 0 10 17v-5"
/>
</svg>
`;

View File

@@ -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"
>
<rect width="18"
height="18"
@@ -40,7 +40,7 @@ exports[`Using lucide icon components > 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"
>
<rect width="18"
height="18"
@@ -70,7 +70,7 @@ exports[`Using lucide icon components > 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"
>
<rect width="18"
height="18"

View File

@@ -12,4 +12,22 @@ describe('Using createLucideIcon', () => {
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(<AirVent />);
expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toBeDefined();
});
it('should include backwards compatible className', () => {
const Layout2 = createLucideIcon('layout-2', airVent);
const { container } = render(<Layout2 />);
expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toBeDefined();
});
});

View File

@@ -30,7 +30,7 @@ const iconNode: IconNode = ${JSON.stringify(children)};
* ${deprecated ? `@deprecated ${deprecationReason}` : ''}
*/
const ${componentName} = (props: LucideProps) => (
<Icon {...props} name="${componentName}" iconNode={iconNode} />
<Icon {...props} iconNode={iconNode} name="${iconName}" />
)
export default ${componentName};

View File

@@ -2,7 +2,7 @@ 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 {
name?: string;
@@ -36,7 +36,12 @@ const Icon = (props: LucideProps & IconProps) => {
class={mergeClasses(
'lucide',
'lucide-icon',
localProps.name != null ? `lucide-${toKebabCase(localProps?.name)}` : undefined,
...(localProps.name != null
? [
`lucide-${toKebabCase(toPascalCase(localProps.name))}`,
`lucide-${toKebabCase(localProps.name)}`,
]
: []),
localProps.class != null ? localProps.class : '',
)}
{...rest}

View File

@@ -10,7 +10,7 @@ exports[`Using lucide icon components > 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-grid3x3 lucide-grid-3x3"
data-testid="grid-icon"
>
<rect width="18"
@@ -50,7 +50,7 @@ exports[`Using lucide icon components > 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-grid3x3 lucide-grid-3x3"
data-testid="grid-icon"
>
<rect width="18"
@@ -90,7 +90,7 @@ exports[`Using lucide icon components > should render a component 1`] = `
height="24"
stroke="currentColor"
stroke-width="2"
class="lucide lucide-icon lucide-grid3x3"
class="lucide lucide-icon lucide-grid3x3 lucide-grid-3x3"
>
<rect width="18"
height="18"

View File

@@ -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('${iconName}', ${JSON.stringify(children)});
export default ${componentName};
`;

View File

@@ -1,5 +1,5 @@
import { type FunctionalComponent, h } from 'vue';
import { toKebabCase } from '@lucide/shared';
import { mergeClasses, toKebabCase, toPascalCase } from '@lucide/shared';
import defaultAttributes from './defaultAttributes';
import { IconNode, LucideProps } from './types';
@@ -20,7 +20,12 @@ const Icon: FunctionalComponent<LucideProps & IconProps> = (
height: size || defaultAttributes.height,
stroke: color || defaultAttributes.stroke,
'stroke-width': absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth,
class: ['lucide', `lucide-${toKebabCase(name ?? 'icon')}`],
class: mergeClasses(
'lucide',
...(name
? [`lucide-${toKebabCase(toPascalCase(name))}-icon`, `lucide-${toKebabCase(name)}`]
: ['lucide-icon']),
),
...props,
},
[...iconNode.map((child) => h(...child)), ...(slots.default ? [slots.default()] : [])],

View File

@@ -3,7 +3,7 @@
exports[`Using lucide icon components > should add a class to the element 1`] = `
<div>
<svg
class="lucide lucide-smile-icon my-icon"
class="lucide lucide-smile-icon lucide-smile my-icon"
fill="none"
height="24"
stroke="currentColor"
@@ -41,7 +41,7 @@ exports[`Using lucide icon components > should add a class to the element 1`] =
exports[`Using lucide icon components > should add a style attribute to the element 1`] = `
<div>
<svg
class="lucide lucide-smile-icon"
class="lucide lucide-smile-icon lucide-smile"
fill="none"
height="24"
stroke="currentColor"
@@ -80,7 +80,7 @@ exports[`Using lucide icon components > should add a style attribute to the elem
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `
<div>
<svg
class="lucide lucide-smile-icon"
class="lucide lucide-smile-icon lucide-smile"
fill="none"
height="48"
stroke="red"
@@ -118,7 +118,7 @@ exports[`Using lucide icon components > should adjust the size, stroke color and
exports[`Using lucide icon components > should pass children to the icon slot 1`] = `
<div>
<svg
class="lucide lucide-smile-icon"
class="lucide lucide-smile-icon lucide-smile"
fill="none"
height="24"
stroke="currentColor"
@@ -161,7 +161,7 @@ exports[`Using lucide icon components > should pass children to the icon slot 1`
exports[`Using lucide icon components > should render an component 1`] = `
<div>
<svg
class="lucide lucide-smile-icon"
class="lucide lucide-smile-icon lucide-smile"
fill="none"
height="24"
stroke="currentColor"