diff --git a/packages/lucide-vue-next/src/Icon.ts b/packages/lucide-vue-next/src/Icon.ts index f0a7b5190..73c1037f1 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 { mergeClasses, toKebabCase, toPascalCase } from '@lucide/shared'; +import { mergeClasses, toKebabCase, toPascalCase, isEmptyString } from '@lucide/shared'; import defaultAttributes from './defaultAttributes'; import { IconNode, LucideProps } from './types'; @@ -9,24 +9,43 @@ interface IconProps { } const Icon: FunctionalComponent = ( - { size, strokeWidth = 2, absoluteStrokeWidth, color, iconNode, name, class: classes, ...props }, + { + name, + iconNode, + absoluteStrokeWidth, + 'absolute-stroke-width': absoluteStrokeWidthKebabCase, + strokeWidth, + 'stroke-width': strokeWidthKebabCase, + size = defaultAttributes.width, + color = defaultAttributes.stroke, + ...props + }, { slots }, ) => { return h( 'svg', { ...defaultAttributes, - width: size || defaultAttributes.width, - height: size || defaultAttributes.height, - stroke: color || defaultAttributes.stroke, - 'stroke-width': absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth, + ...props, + width: size, + height: size, + stroke: color, + 'stroke-width': + isEmptyString(absoluteStrokeWidth) || + isEmptyString(absoluteStrokeWidthKebabCase) || + absoluteStrokeWidth === true || + absoluteStrokeWidthKebabCase === true + ? (Number(strokeWidth || strokeWidthKebabCase || defaultAttributes['stroke-width']) * + 24) / + Number(size) + : strokeWidth || strokeWidthKebabCase || defaultAttributes['stroke-width'], class: mergeClasses( 'lucide', + props.class, ...(name ? [`lucide-${toKebabCase(toPascalCase(name))}-icon`, `lucide-${toKebabCase(name)}`] : ['lucide-icon']), ), - ...props, }, [...iconNode.map((child) => h(...child)), ...(slots.default ? [slots.default()] : [])], ); diff --git a/packages/lucide-vue-next/src/createLucideIcon.ts b/packages/lucide-vue-next/src/createLucideIcon.ts index 27c0904f9..10f0ad80e 100644 --- a/packages/lucide-vue-next/src/createLucideIcon.ts +++ b/packages/lucide-vue-next/src/createLucideIcon.ts @@ -13,10 +13,11 @@ import Icon from './Icon'; */ const createLucideIcon = (iconName: string, iconNode: IconNode): FunctionalComponent => - (props, { slots }) => + (props, { slots, attrs }) => h( Icon, { + ...attrs, ...props, iconNode, name: iconName, diff --git a/packages/lucide-vue-next/src/types.ts b/packages/lucide-vue-next/src/types.ts index 638af5b7f..6b3c026a5 100644 --- a/packages/lucide-vue-next/src/types.ts +++ b/packages/lucide-vue-next/src/types.ts @@ -4,6 +4,7 @@ export interface LucideProps extends Partial { size?: 24 | number; strokeWidth?: number | string; absoluteStrokeWidth?: boolean; + 'absolute-stroke-width'?: boolean; } export type IconNode = [elementName: string, attrs: Record][]; diff --git a/packages/lucide-vue-next/tests/__snapshots__/lucide-vue-next.spec.ts.snap b/packages/lucide-vue-next/tests/__snapshots__/lucide-vue-next.spec.ts.snap index 88156ce1b..809afc8b3 100644 --- a/packages/lucide-vue-next/tests/__snapshots__/lucide-vue-next.spec.ts.snap +++ b/packages/lucide-vue-next/tests/__snapshots__/lucide-vue-next.spec.ts.snap @@ -3,7 +3,7 @@ exports[`Using lucide icon components > should add a class to the element 1`] = `
{ expect(icon).toHaveAttribute('stroke', 'red'); expect(icon).toHaveAttribute('stroke-width', '1'); }); + + it('should not scale the strokeWidth when absoluteStrokeWidth is as empty value attribute', () => { + const { container } = render(Pen, { + props: { + size: 48, + color: 'red', + absoluteStrokeWidth: '', + }, + }); + + const icon = container.firstElementChild; + + expect(icon).toHaveAttribute('width', '48'); + expect(icon).toHaveAttribute('stroke', 'red'); + expect(icon).toHaveAttribute('stroke-width', '1'); + }); + + it('should not scale the strokeWidth when absoluteStrokeWidth is written in kebabCase', () => { + const { container } = render(Pen, { + props: { + size: 48, + color: 'red', + 'stroke-width': '2', + 'absolute-stroke-width': '', + }, + }); + + const icon = container.firstElementChild; + + expect(icon).toHaveAttribute('width', '48'); + expect(icon).toHaveAttribute('stroke', 'red'); + expect(icon).toHaveAttribute('stroke-width', '1'); + }); }); diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index 8a6402f40..350bbf935 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -50,6 +50,14 @@ export const mergeClasses = (...classes: .join(' ') .trim(); +/** + * Is empty string + * + * @param {unknown} value + * @returns {boolean} Whether the value is an empty string + */ +export const isEmptyString = (value: unknown): boolean => value === ''; + /** * Check if a component has an accessibility prop *