diff --git a/packages/astro/src/Icon.astro b/packages/astro/src/Icon.astro index b20d3b835..7d54bedfa 100644 --- a/packages/astro/src/Icon.astro +++ b/packages/astro/src/Icon.astro @@ -21,7 +21,7 @@ const { ...rest } = Astro.props; -const [, builtIconAttributes, builtIconNode] = buildLucideIconNode(icon, { +const [, builtIconAttributes, builtIconNode = []] = buildLucideIconNode(icon, { color, width: width ?? size, height: height ?? size, diff --git a/packages/lucide-preact/src/Icon.ts b/packages/lucide-preact/src/Icon.ts index 3bb74276d..c9c65dcfe 100644 --- a/packages/lucide-preact/src/Icon.ts +++ b/packages/lucide-preact/src/Icon.ts @@ -1,19 +1,18 @@ import { h, toChildArray } from 'preact'; import { buildLucideIconNode, hasA11yProp, mergeClasses } from '@lucide/shared'; -import defaultAttributes from './defaultAttributes'; import type { LucideIconData, LucideIconNode, LucideProps } from './types'; import { useLucideContext } from './context'; type IconComponentProps = LucideProps & ( - | { - iconNode: LucideIconNode; - icon?: never; - } | { icon: LucideIconData; iconNode?: never; } + | { + iconNode: LucideIconNode[]; + icon?: never; + } ); /** @@ -59,7 +58,7 @@ const Icon = ({ class: contextClass = '', } = useLucideContext() ?? {}; - const [name, svgAttributes, builtIconNode] = buildLucideIconNode(icon, { + const [name, svgAttributes, builtIconNode = []] = buildLucideIconNode(icon, { color: color ?? contextColor, width: width ?? size ?? contextSize, height: height ?? size ?? contextSize, diff --git a/packages/lucide-preact/src/types.ts b/packages/lucide-preact/src/types.ts index 6ccc4ad25..15204ae36 100644 --- a/packages/lucide-preact/src/types.ts +++ b/packages/lucide-preact/src/types.ts @@ -2,7 +2,7 @@ import { type FunctionComponent, type JSX } from 'preact'; import type { LucideIconData as SharedLucideIconData, LucideIconNode as SharedLucideIconNode, -} from '@lucide/shared'; +} from '@lucide/shared/types'; export type LucideIconNode = SharedLucideIconNode; diff --git a/packages/lucide-react-native/src/Icon.ts b/packages/lucide-react-native/src/Icon.ts index 0d49ccba9..2ada9234d 100644 --- a/packages/lucide-react-native/src/Icon.ts +++ b/packages/lucide-react-native/src/Icon.ts @@ -81,7 +81,7 @@ const Icon = forwardRef( const hasAccessibleProp = Boolean(children) || hasA11yProp(rest); - const [, svgAttributes, builtIconNode] = buildLucideIconForReact(icon, { + const [, svgAttributes, builtIconNode = []] = buildLucideIconForReact(icon, { color: color ?? contextColor, width: width ?? size ?? contextSize, height: height ?? size ?? contextSize, diff --git a/packages/lucide-react/src/Icon.ts b/packages/lucide-react/src/Icon.ts index ed2de90d6..cf52b9688 100644 --- a/packages/lucide-react/src/Icon.ts +++ b/packages/lucide-react/src/Icon.ts @@ -66,7 +66,7 @@ const Icon = forwardRef( const hasAccessibleProp = Boolean(children) || hasA11yProp(rest); - const [name, svgAttributes, builtIconNode] = buildLucideIconForReact(icon, { + const [name, svgAttributes, builtIconNode = []] = buildLucideIconForReact(icon, { color: color ?? contextColor, width: width ?? size ?? contextSize, height: height ?? size ?? contextSize, diff --git a/packages/lucide-solid/src/Icon.tsx b/packages/lucide-solid/src/Icon.tsx index 2183f4053..d53b00e23 100644 --- a/packages/lucide-solid/src/Icon.tsx +++ b/packages/lucide-solid/src/Icon.tsx @@ -39,7 +39,7 @@ const Icon = (props: LucideProps & IconProps) => { aliases: [], }; - const [, svgAttributes, builtIconNode] = buildLucideIconNode(icon, { + const [, svgAttributes, builtIconNode = []] = buildLucideIconNode(icon, { color: localProps.color ?? globalProps.color, width: localProps.width ?? localProps.size ?? globalProps.size, height: localProps.height ?? localProps.size ?? globalProps.size, diff --git a/packages/shared/src/build/buildLucideIconNode.ts b/packages/shared/src/build/buildLucideIconNode.ts index 6cdb2c940..3ab903c41 100644 --- a/packages/shared/src/build/buildLucideIconNode.ts +++ b/packages/shared/src/build/buildLucideIconNode.ts @@ -17,8 +17,8 @@ function buildLucideIconNode(icon: LucideIconData, params: LucideBuildParams = { const viewBoxHeight = icon.size ?? icon.height ?? defaultAttributes['height']; const aliasClassNames = icon.aliases - ?.filter((alias): alias is string => typeof alias === 'string' && alias.trim() !== '') - .map((alias) => `lucide-${alias}`) ?? []; + ?.filter((alias: string): alias is string => typeof alias === 'string' && alias.trim() !== '') + .map((alias: string) => `lucide-${alias}`) ?? []; const iconClassNames = [...(icon.name ? [`lucide-${icon.name}`] : []), ...aliasClassNames]; const classNamesFromClassName = params.className?.split(' ').filter(Boolean) ?? []; const className = @@ -55,12 +55,14 @@ function buildLucideIconNode(icon: LucideIconData, params: LucideBuildParams = { return [ 'svg', attributes, - icon.node.map(([name, attrs]) => [ - name, - params.nonScalingStroke + icon.node.map((child): LucideIconNode => { + const [name, attrs, children] = child; + const nextAttrs = params.nonScalingStroke ? { [getAttributeName('vector-effect')]: 'non-scaling-stroke', ...attrs } - : attrs, - ]), + : attrs; + + return children ? [name, nextAttrs, children] : [name, nextAttrs]; + }), ]; } diff --git a/packages/shared/src/build/types.ts b/packages/shared/src/build/types.ts index 5844972ba..39a99662f 100644 --- a/packages/shared/src/build/types.ts +++ b/packages/shared/src/build/types.ts @@ -1,4 +1,5 @@ -export type SVGProps = Record; +/* eslint-disable @typescript-eslint/no-explicit-any */ +export type SVGProps = Record; /** * A Lucide icon node (an svgson-like internal format) @@ -70,6 +71,6 @@ export type LucideBuildParams = SVGProps> */ attributeNames?: Record; } & ( - | { size?: string | number; width?: never; height?: never } - | { size?: never; width?: string | number; height?: string | number } + | { size?: string | number | null; width?: never; height?: never } + | { size?: never; width?: string | number | null; height?: string | number | null } ); diff --git a/packages/shared/src/utils/toCamelCase.ts b/packages/shared/src/utils/toCamelCase.ts index 52ade7dbd..6faf1194b 100644 --- a/packages/shared/src/utils/toCamelCase.ts +++ b/packages/shared/src/utils/toCamelCase.ts @@ -4,7 +4,24 @@ * @param {string} string * @returns {string} A camelized string */ -export const toCamelCase = (string: T) => - string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => - p2 ? p2.toUpperCase() : p1.toLowerCase(), - ); +export const toCamelCase = (string: T) => { + let out = ''; + let upperNext = false; + + for (const ch of string) { + if (ch === '-' || ch === '_' || ch <= ' ') { + upperNext = out.length > 0; + continue; + } + + if (out.length === 0) { + out += ch.toLowerCase(); + } else { + out += upperNext ? ch.toUpperCase() : ch; + } + + upperNext = false; + } + + return out as string; +}; diff --git a/packages/svelte/package.json b/packages/svelte/package.json index de071b825..900f5a4ac 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -48,7 +48,7 @@ "scripts": { "build": "pnpm clean && pnpm copy:license && pnpm copy:utils && pnpm build:icons && pnpm build:package && pnpm build:license", "copy:license": "cp ../../LICENSE ./LICENSE", - "copy:utils": "cpy ../../packages/shared/src/build/{buildLucideIconNode.ts,defaultAttributes.ts,types.ts} ../../packages/shared/src/utils/{hasA11yProp.ts,mergeClasses.ts} ./src/utils/", + "copy:utils": "cpy ../../packages/shared/src/build/{buildLucideIconNode.ts,defaultAttributes.ts,types.ts} ../../packages/shared/src/utils/{hasA11yProp.ts,mergeClasses.ts} ./src/utils/ && node ./scripts/patchCopiedUtils.mts", "clean": "rm -rf dist stats ./src/icons/*.{ts,svelte} ./src/aliases/{aliases,prefixed,suffixed}.ts", "build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mts --exportFileName=index.ts --iconFileExtension=.svelte --importImportFileExtension=.svelte --separateIconFileExport --separateIconFileExportExtension=.ts --withAliases --aliasesFileExtension=.ts --separateAliasesFile --separateAliasesFileExtension=.ts --aliasImportFileExtension=.js --pretty=false", "build:package": "svelte-package --input ./src", diff --git a/packages/svelte/scripts/exportTemplate.mts b/packages/svelte/scripts/exportTemplate.mts index e65a57fc1..ef046a584 100644 --- a/packages/svelte/scripts/exportTemplate.mts +++ b/packages/svelte/scripts/exportTemplate.mts @@ -8,8 +8,8 @@ export default defineExportTemplate( const svgBase64 = base64SVG(svgContents); return `\ -