mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-08-29 09:38:26 +02:00
Setup solid 2
This commit is contained in:
87
packages/solid/README.md
Normal file
87
packages/solid/README.md
Normal file
@@ -0,0 +1,87 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/lucide-icons/lucide">
|
||||
<img src="https://lucide.dev/package-logos/lucide-solid.svg" alt="Lucide icon library for Solid applications." width="540">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Lucide icon library for Solid v2 applications.
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://www.npmjs.com/package/lucide-solid)
|
||||

|
||||
[](https://lucide.dev/license)
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://lucide.dev/guide/">About</a>
|
||||
·
|
||||
<a href="https://lucide.dev/icons/">Icons</a>
|
||||
·
|
||||
<a href="https://lucide.dev/guide/solid">Documentation</a>
|
||||
·
|
||||
<a href="https://lucide.dev/license">License</a>
|
||||
</p>
|
||||
|
||||
# Lucide Solid
|
||||
|
||||
Implementation of the Lucide icon library for solid applications.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
pnpm add @lucide/solid
|
||||
```
|
||||
|
||||
```sh
|
||||
npm install @lucide/solid
|
||||
```
|
||||
|
||||
```sh
|
||||
yarn add @lucide/solid
|
||||
```
|
||||
|
||||
```sh
|
||||
bun add @lucide/solid
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
For full documentation, visit [lucide.dev](https://lucide.dev/guide/packages/lucide-solid)
|
||||
|
||||
## Community
|
||||
|
||||
Join the [Discord server](https://discord.gg/EH6nSts) to chat with the maintainers and other users.
|
||||
|
||||
## License
|
||||
|
||||
Lucide is licensed under the ISC license. See [LICENSE](https://lucide.dev/license).
|
||||
|
||||
[//]: <> (Sponsors)
|
||||
|
||||
## Sponsors
|
||||
|
||||
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss">
|
||||
<img src="https://lucide.dev/vercel.svg" alt="Powered by Vercel" width="200" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.digitalocean.com/?refcode=b0877a2caebd&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge"><img src="https://lucide.dev/digitalocean.svg" width="200" alt="DigitalOcean Referral Badge" /></a>
|
||||
|
||||
### Hero backers 🦸
|
||||
|
||||
<a href="https://zephyr-cloud.io/"><img src="https://lucide.dev/sponsors/zephyr-cloud.svg" width="180" alt="Zephyr Cloud – From idea to prod: fast micro-frontend delivery!" /></a>
|
||||
|
||||
### Awesome backers 🍺
|
||||
|
||||
<a href="https://github.com/pdfme/pdfme"><img src="https://lucide.dev/sponsors/pdfme.svg" width="180" alt="pdfme – Open-source PDF generation library built with TypeScript and React." /></a>
|
||||
<a href="https://www.paxhistoria.co/"><img src="https://lucide.dev/sponsors/paxhistoria.svg?" width="180" alt="Pax Historia – An alternate history sandbox game" /></a>
|
||||
|
||||
### Backers ☕
|
||||
|
||||
<a href="https://www.fina.money/"><img src="https://lucide.dev/sponsors/fina-money.png" width="180" alt="Fina Money – Modular Finance Tracker" /></a>
|
||||
|
||||
### Other contributors 💸
|
||||
|
||||
You can find all our past and non-recurring financial contributors at [our Open Collective page](https://opencollective.com/lucide-icons).
|
||||
94
packages/solid/package.json
Normal file
94
packages/solid/package.json
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"name": "@lucide/solid",
|
||||
"description": "A Lucide icon library package for Solid v2 applications.",
|
||||
"version": "0.0.1",
|
||||
"license": "ISC",
|
||||
"homepage": "https://lucide.dev",
|
||||
"bugs": "https://github.com/lucide-icons/lucide/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lucide-icons/lucide.git",
|
||||
"directory": "packages/solid"
|
||||
},
|
||||
"keywords": [
|
||||
"Lucide",
|
||||
"Solid",
|
||||
"SolidJS",
|
||||
"Feather",
|
||||
"Icons",
|
||||
"Icon",
|
||||
"SVG",
|
||||
"Feather Icons",
|
||||
"Fontawesome",
|
||||
"Font Awesome"
|
||||
],
|
||||
"author": "Eric Fennis",
|
||||
"source": "src/lucide-solid.ts",
|
||||
"main": "dist/cjs/lucide-solid.js",
|
||||
"module": "dist/esm/lucide-solid.mjs",
|
||||
"types": "dist/types/lucide-solid.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/types/lucide-solid.d.ts",
|
||||
"solid": "./dist/source/lucide-solid.jsx",
|
||||
"import": "./dist/esm/lucide-solid.mjs",
|
||||
"browser": "./dist/esm/lucide-solid.mjs",
|
||||
"require": "./dist/cjs/lucide-solid.js"
|
||||
},
|
||||
"./icons": {
|
||||
"types": "./dist/types/lucide-solid.d.ts",
|
||||
"solid": "./dist/source/lucide-solid.jsx",
|
||||
"import": "./dist/esm/lucide-solid.mjs",
|
||||
"browser": "./dist/esm/lucide-solid.mjs",
|
||||
"require": "./dist/cjs/lucide-solid.js"
|
||||
},
|
||||
"./icons/*": {
|
||||
"types": "./dist/types/icons/*.d.ts",
|
||||
"solid": "./dist/source/icons/*.jsx",
|
||||
"import": "./dist/esm/icons/*.mjs",
|
||||
"browser": "./dist/esm/icons/*.mjs",
|
||||
"require": "./dist/cjs/icons/*.js"
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:bundle",
|
||||
"copy:license": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.ts",
|
||||
"build:transpile": "tsc --jsx preserve -t es2020 --rootDir src --outDir dist --noEmit false",
|
||||
"build:version": "node ./scripts/replaceVersion.mjs",
|
||||
"build:bundle": "rollup -c rollup.config.mjs",
|
||||
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mts --renderUniqueKey --withAliases --separateAliasesFile --separateAliasesFileIgnore=fingerprint --aliasesFileExtension=.ts --iconFileExtension=.tsx --exportFileName=index.ts",
|
||||
"typecheck": "tsc",
|
||||
"typecheck:watch": "tsc -w",
|
||||
"test": "pnpm build:icons && vitest run",
|
||||
"test:watch": "vitest watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.9",
|
||||
"@babel/preset-env": "^7.23.9",
|
||||
"@babel/preset-typescript": "^7.23.3",
|
||||
"@lucide/build-icons": "workspace:*",
|
||||
"@lucide/rollup-plugins": "workspace:*",
|
||||
"@lucide/shared": "workspace:*",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@solidjs/testing-library": "1.0.0-beta.2",
|
||||
"@solidjs/web": "2.0.0-beta.16",
|
||||
"@testing-library/jest-dom": "^6.8.0",
|
||||
"babel-preset-solid": "2.0.0-beta.16",
|
||||
"esbuild": "^0.28.1",
|
||||
"jest-serializer-html": "^7.1.0",
|
||||
"rollup": "^4.59.0",
|
||||
"solid-js": "2.0.0-beta.16",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^7.2.4",
|
||||
"vite-plugin-solid": "^2.11.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"solid-js": "2.0.0-beta.16",
|
||||
"@solidjs/web": "2.0.0-beta.16"
|
||||
}
|
||||
}
|
||||
135
packages/solid/rollup.config.mjs
Normal file
135
packages/solid/rollup.config.mjs
Normal file
@@ -0,0 +1,135 @@
|
||||
import path from 'path';
|
||||
import { babel } from '@rollup/plugin-babel';
|
||||
import esbuild from 'esbuild';
|
||||
import plugins from '@lucide/rollup-plugins';
|
||||
import ts from 'typescript';
|
||||
|
||||
import pkg from './package.json' with { type: 'json' };
|
||||
|
||||
const packageName = 'LucideSolid';
|
||||
const outputFileName = 'lucide-solid';
|
||||
const outputDir = 'dist';
|
||||
const inputs = ['src/lucide-solid.ts'];
|
||||
|
||||
const bundles = [
|
||||
{
|
||||
format: 'cjs',
|
||||
inputs,
|
||||
outputDir,
|
||||
preserveModules: true,
|
||||
},
|
||||
{
|
||||
format: 'esm',
|
||||
inputs,
|
||||
outputDir,
|
||||
preserveModules: true,
|
||||
extension: 'mjs',
|
||||
},
|
||||
];
|
||||
|
||||
const configs = bundles
|
||||
.map(({ inputs, outputDir, format, preserveModules, extension = 'js' }) =>
|
||||
inputs.map((input) => ({
|
||||
input,
|
||||
plugins: [
|
||||
babel({
|
||||
extensions: ['.ts', '.tsx', '.js', '.jsx'],
|
||||
babelHelpers: 'bundled',
|
||||
presets: [
|
||||
'babel-preset-solid',
|
||||
'@babel/preset-typescript',
|
||||
['@babel/preset-env', { bugfixes: true, targets: 'last 2 years' }],
|
||||
],
|
||||
}),
|
||||
...plugins({
|
||||
pkg,
|
||||
withEsbuild: false,
|
||||
}),
|
||||
format === 'esm'
|
||||
? {
|
||||
name: 'ts',
|
||||
buildEnd() {
|
||||
// Transpile typescript to './dist/source'
|
||||
esbuild.build({
|
||||
entryPoints: ['./src/**/*.tsx', './src/**/*.ts'],
|
||||
outdir: './dist/source',
|
||||
outExtension: {
|
||||
'.js': '.jsx',
|
||||
},
|
||||
loader: {
|
||||
'.js': 'jsx',
|
||||
},
|
||||
jsx: 'preserve',
|
||||
jsxImportSource: 'solid-js',
|
||||
bundle: true,
|
||||
format: 'esm',
|
||||
sourcemap: true,
|
||||
target: ['esnext'],
|
||||
banner: {
|
||||
js: `/**
|
||||
* @license ${pkg.name} v${pkg.version} - ${pkg.license}
|
||||
*
|
||||
* This source code is licensed under the ${pkg.license} license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/`,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
name: 'externalize-everything-except-own-dependencies',
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /(.*)/ }, (args) => {
|
||||
const modulePath = path.join(args.resolveDir, args.path);
|
||||
if (
|
||||
args.kind === 'import-statement' &&
|
||||
args.path !== '@lucide/shared' &&
|
||||
!modulePath.includes('packages/shared')
|
||||
) {
|
||||
return { path: args.path, external: true };
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
external: ['solid-js'],
|
||||
});
|
||||
|
||||
// Generate types
|
||||
const program = ts.createProgram([pkg.source], {
|
||||
target: ts.ScriptTarget.ESNext,
|
||||
module: ts.ModuleKind.ESNext,
|
||||
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
||||
jsx: ts.JsxEmit.Preserve,
|
||||
jsxImportSource: 'solid-js',
|
||||
allowSyntheticDefaultImports: true,
|
||||
esModuleInterop: true,
|
||||
declarationDir: `dist/types`,
|
||||
declaration: true,
|
||||
emitDeclarationOnly: true,
|
||||
});
|
||||
program.emit();
|
||||
},
|
||||
}
|
||||
: null,
|
||||
],
|
||||
external: ['solid-js', '@solidjs/web', 'solid-js/store'],
|
||||
output: {
|
||||
name: packageName,
|
||||
...(preserveModules
|
||||
? {
|
||||
dir: `${outputDir}/${format}`,
|
||||
exports: 'auto',
|
||||
entryFileNames: `[name].${extension}`,
|
||||
}
|
||||
: {
|
||||
file: `${outputDir}/${format}/${outputFileName}.${extension}`,
|
||||
}),
|
||||
format: format === 'source' ? 'esm' : format,
|
||||
preserveModules,
|
||||
preserveModulesRoot: 'src',
|
||||
sourcemap: true,
|
||||
},
|
||||
})),
|
||||
)
|
||||
.flat();
|
||||
|
||||
export default configs;
|
||||
38
packages/solid/scripts/exportTemplate.mts
Normal file
38
packages/solid/scripts/exportTemplate.mts
Normal file
@@ -0,0 +1,38 @@
|
||||
import base64SVG from '@lucide/build-icons/utils/base64SVG';
|
||||
import defineExportTemplate from '@lucide/build-icons/utils/defineExportTemplate';
|
||||
|
||||
export default defineExportTemplate(async ({
|
||||
componentName,
|
||||
iconName,
|
||||
children,
|
||||
getSvg,
|
||||
deprecated,
|
||||
deprecationReason,
|
||||
}) => {
|
||||
const svgContents = await getSvg();
|
||||
const svgBase64 = base64SVG(svgContents);
|
||||
|
||||
return `
|
||||
import Icon from '../Icon';
|
||||
import type { IconNode, LucideProps } from '../types';
|
||||
|
||||
const iconNode: IconNode = ${JSON.stringify(children)};
|
||||
|
||||
/**
|
||||
* @component @name ${componentName}
|
||||
* @description Lucide SVG icon component, renders SVG Element with children.
|
||||
*
|
||||
* @preview  - https://lucide.dev/icons/${iconName}
|
||||
* @see https://lucide.dev/guide/packages/lucide-solid - Documentation
|
||||
*
|
||||
* @param {Object} props - Lucide icons props and any valid SVG attribute
|
||||
* @returns {JSX.Element} JSX Element
|
||||
* ${deprecated ? `@deprecated ${deprecationReason}` : ''}
|
||||
*/
|
||||
const ${componentName} = (props: LucideProps) => (
|
||||
<Icon {...props} iconNode={iconNode} name="${iconName}" />
|
||||
)
|
||||
|
||||
export default ${componentName};
|
||||
`;
|
||||
});
|
||||
78
packages/solid/src/Icon.tsx
Normal file
78
packages/solid/src/Icon.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import { For, omit, useContext } from 'solid-js';
|
||||
import { Dynamic } from '@solidjs/web';
|
||||
import defaultAttributes from './defaultAttributes';
|
||||
import { IconNode, LucideProps } from './types';
|
||||
import { LucideContext } from './context';
|
||||
import { hasA11yProp, mergeClasses, toKebabCase, toPascalCase } from '@lucide/shared';
|
||||
import { JSX } from '@solidjs/web';
|
||||
|
||||
interface IconProps {
|
||||
name?: string;
|
||||
iconNode: IconNode;
|
||||
}
|
||||
|
||||
const Icon = (props: LucideProps & IconProps) => {
|
||||
const [localProps, rest] = omit(props, [
|
||||
'color',
|
||||
'size',
|
||||
'strokeWidth',
|
||||
'children',
|
||||
'class',
|
||||
'name',
|
||||
'iconNode',
|
||||
'absoluteStrokeWidth',
|
||||
]);
|
||||
|
||||
const globalProps = useContext(LucideContext);
|
||||
|
||||
return (
|
||||
<svg
|
||||
{...defaultAttributes}
|
||||
width={localProps.size ?? globalProps.size ?? defaultAttributes.width}
|
||||
height={localProps.size ?? globalProps.size ?? defaultAttributes.height}
|
||||
stroke={localProps.color ?? globalProps.color ?? defaultAttributes.stroke}
|
||||
stroke-width={
|
||||
(localProps.absoluteStrokeWidth ?? globalProps.absoluteStrokeWidth) === true
|
||||
? (Number(
|
||||
localProps.strokeWidth ??
|
||||
globalProps.strokeWidth ??
|
||||
defaultAttributes['stroke-width'],
|
||||
) *
|
||||
24) /
|
||||
Number(localProps.size ?? globalProps.size)
|
||||
: Number(
|
||||
localProps.strokeWidth ??
|
||||
globalProps.strokeWidth ??
|
||||
defaultAttributes['stroke-width'],
|
||||
)
|
||||
}
|
||||
class={mergeClasses(
|
||||
'lucide',
|
||||
'lucide-icon',
|
||||
globalProps.class,
|
||||
...(localProps.name != null
|
||||
? [
|
||||
`lucide-${toKebabCase(toPascalCase(localProps.name))}`,
|
||||
`lucide-${toKebabCase(localProps.name)}`,
|
||||
]
|
||||
: []),
|
||||
localProps.class,
|
||||
)}
|
||||
aria-hidden={!localProps.children && !hasA11yProp(rest) ? 'true' : undefined}
|
||||
{...rest}
|
||||
>
|
||||
<For each={localProps.iconNode}>
|
||||
{([elementName, attrs]) => {
|
||||
return (
|
||||
<Dynamic
|
||||
component={elementName}
|
||||
{...attrs}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
3
packages/solid/src/aliases/index.ts
Normal file
3
packages/solid/src/aliases/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './aliases';
|
||||
export * from './prefixed';
|
||||
export * from './suffixed';
|
||||
37
packages/solid/src/context.tsx
Normal file
37
packages/solid/src/context.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createContext, omit } from 'solid-js';
|
||||
import { type JSX } from '@solidjs/web';
|
||||
|
||||
export const LucideContext = createContext<{
|
||||
size?: number;
|
||||
color?: string;
|
||||
strokeWidth?: number;
|
||||
absoluteStrokeWidth?: boolean;
|
||||
class?: string;
|
||||
}>({
|
||||
size: 24,
|
||||
color: 'currentColor',
|
||||
strokeWidth: 2,
|
||||
absoluteStrokeWidth: false,
|
||||
class: '',
|
||||
});
|
||||
|
||||
interface LucideProviderProps {
|
||||
children: JSX.Element;
|
||||
size?: number;
|
||||
color?: string;
|
||||
strokeWidth?: number;
|
||||
absoluteStrokeWidth?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
export function LucideProvider(props: LucideProviderProps) {
|
||||
const [value, rest] = omit(props, [
|
||||
'size',
|
||||
'color',
|
||||
'strokeWidth',
|
||||
'absoluteStrokeWidth',
|
||||
'class',
|
||||
]);
|
||||
|
||||
return <LucideContext.Provider value={value}>{rest.children}</LucideContext.Provider>;
|
||||
}
|
||||
15
packages/solid/src/defaultAttributes.ts
Normal file
15
packages/solid/src/defaultAttributes.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { type SVGAttributes } from './types';
|
||||
|
||||
const defaultAttributes: SVGAttributes = {
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
width: 24,
|
||||
height: 24,
|
||||
viewBox: '0 0 24 24',
|
||||
fill: 'none',
|
||||
stroke: 'currentColor',
|
||||
'stroke-width': 2,
|
||||
'stroke-linecap': 'round',
|
||||
'stroke-linejoin': 'round',
|
||||
};
|
||||
|
||||
export default defaultAttributes;
|
||||
1
packages/solid/src/icons/.gitkeep
Normal file
1
packages/solid/src/icons/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
Folder for generated icons
|
||||
7
packages/solid/src/lucide-solid.ts
Normal file
7
packages/solid/src/lucide-solid.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export * from './icons';
|
||||
export * as icons from './icons';
|
||||
export * from './aliases';
|
||||
export * from './types';
|
||||
export * from './context';
|
||||
|
||||
export { default as Icon } from './Icon';
|
||||
15
packages/solid/src/types.ts
Normal file
15
packages/solid/src/types.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { type JSX } from '@solidjs/web';
|
||||
|
||||
export type IconNode = [elementName: keyof JSX.IntrinsicElements, attrs: Record<string, string>][];
|
||||
export type SVGAttributes = Partial<JSX.SvgSVGAttributes<SVGSVGElement>>;
|
||||
|
||||
export interface LucideProps extends SVGAttributes {
|
||||
key?: string | number;
|
||||
class?: string;
|
||||
size?: string | number;
|
||||
color?: string;
|
||||
strokeWidth?: string | number;
|
||||
absoluteStrokeWidth?: boolean;
|
||||
}
|
||||
|
||||
export type LucideIcon = (props: LucideProps) => JSX.Element;
|
||||
106
packages/solid/tests/Icon.spec.tsx
Normal file
106
packages/solid/tests/Icon.spec.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { render } from '@solidjs/testing-library';
|
||||
|
||||
import { airVent } from './testIconNodes';
|
||||
import { Icon } from '../src/lucide-solid';
|
||||
|
||||
describe('Using Icon Component', () => {
|
||||
it('should render icon based on a iconNode', async () => {
|
||||
const { container } = render(() => (
|
||||
<Icon
|
||||
iconNode={airVent}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
/>
|
||||
));
|
||||
|
||||
expect(container.firstChild).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render icon and match snapshot', async () => {
|
||||
const { container } = render(() => (
|
||||
<Icon
|
||||
iconNode={airVent}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
/>
|
||||
));
|
||||
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Icon Component Accessibility', () => {
|
||||
it('should have aria-hidden prop when no aria prop is present', async () => {
|
||||
const { container } = render(() => (
|
||||
<Icon
|
||||
iconNode={airVent}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
/>
|
||||
));
|
||||
|
||||
expect(container.firstChild).toHaveAttribute('aria-hidden', 'true');
|
||||
});
|
||||
|
||||
it('should not have aria-hidden prop when aria prop is present', async () => {
|
||||
const { container } = render(() => (
|
||||
<Icon
|
||||
iconNode={airVent}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
aria-label="Air conditioning"
|
||||
/>
|
||||
));
|
||||
|
||||
expect(container.firstChild).not.toHaveAttribute('aria-hidden');
|
||||
});
|
||||
|
||||
it('should not have aria-hidden prop when title prop is present', async () => {
|
||||
const { container } = render(() => (
|
||||
<Icon
|
||||
iconNode={airVent}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
// @ts-expect-error
|
||||
title="Air conditioning"
|
||||
/>
|
||||
));
|
||||
|
||||
expect(container.firstChild).not.toHaveAttribute('aria-hidden');
|
||||
});
|
||||
|
||||
it('should not have aria-hidden prop when there are children that could be a <title> element', async () => {
|
||||
const { container } = render(() => (
|
||||
<Icon
|
||||
iconNode={airVent}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
>
|
||||
<title>Some title</title>
|
||||
</Icon>
|
||||
));
|
||||
|
||||
expect(container.firstChild).not.toHaveAttribute('aria-hidden');
|
||||
});
|
||||
|
||||
it('should never override aria-hidden prop', async () => {
|
||||
const { container } = render(() => (
|
||||
<Icon
|
||||
iconNode={airVent}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
aria-hidden={false}
|
||||
/>
|
||||
));
|
||||
|
||||
expect(container.firstChild).toHaveAttribute('aria-hidden', 'false');
|
||||
});
|
||||
});
|
||||
34
packages/solid/tests/__snapshots__/Icon.spec.tsx.snap
Normal file
34
packages/solid/tests/__snapshots__/Icon.spec.tsx.snap
Normal file
@@ -0,0 +1,34 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Using Icon Component > should render icon and match snapshot 1`] = `
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="lucide lucide-icon"
|
||||
fill="none"
|
||||
height="48"
|
||||
stroke="red"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1"
|
||||
viewBox="0 0 24 24"
|
||||
width="48"
|
||||
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"
|
||||
key="larmp2"
|
||||
/>
|
||||
<path
|
||||
d="M6 8h12"
|
||||
key="6g4wlu"
|
||||
/>
|
||||
<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"
|
||||
key="1bo8pg"
|
||||
/>
|
||||
<path
|
||||
d="M6.6 15.6A2 2 0 1 0 10 17v-5"
|
||||
key="t9h90c"
|
||||
/>
|
||||
</svg>
|
||||
`;
|
||||
26
packages/solid/tests/__snapshots__/context.spec.tsx.snap
Normal file
26
packages/solid/tests/__snapshots__/context.spec.tsx.snap
Normal file
@@ -0,0 +1,26 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Using LucideProvider > should render the icon with LucideProvider 1`] = `
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="lucide lucide-icon lucide-house"
|
||||
fill="none"
|
||||
height="48"
|
||||
stroke="red"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
width="48"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"
|
||||
key="5wwlr5"
|
||||
/>
|
||||
<path
|
||||
d="M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"
|
||||
key="r6nss1"
|
||||
/>
|
||||
</svg>
|
||||
`;
|
||||
123
packages/solid/tests/__snapshots__/lucide-solid.spec.tsx.snap
Normal file
123
packages/solid/tests/__snapshots__/lucide-solid.spec.tsx.snap
Normal file
@@ -0,0 +1,123 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
width="48"
|
||||
height="48"
|
||||
stroke="red"
|
||||
stroke-width="4"
|
||||
class="lucide lucide-icon lucide-grid3x3 lucide-grid-3x3"
|
||||
aria-hidden="true"
|
||||
data-testid="grid-icon"
|
||||
>
|
||||
<rect width="18"
|
||||
height="18"
|
||||
x="3"
|
||||
y="3"
|
||||
rx="2"
|
||||
key="afitv7"
|
||||
>
|
||||
</rect>
|
||||
<path d="M3 9h18"
|
||||
key="1pudct"
|
||||
>
|
||||
</path>
|
||||
<path d="M3 15h18"
|
||||
key="5xshup"
|
||||
>
|
||||
</path>
|
||||
<path d="M9 3v18"
|
||||
key="fh3hqa"
|
||||
>
|
||||
</path>
|
||||
<path d="M15 3v18"
|
||||
key="14nvp0"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
width="48"
|
||||
height="48"
|
||||
stroke="red"
|
||||
stroke-width="1"
|
||||
class="lucide lucide-icon lucide-grid3x3 lucide-grid-3x3"
|
||||
aria-hidden="true"
|
||||
data-testid="grid-icon"
|
||||
>
|
||||
<rect width="18"
|
||||
height="18"
|
||||
x="3"
|
||||
y="3"
|
||||
rx="2"
|
||||
key="afitv7"
|
||||
>
|
||||
</rect>
|
||||
<path d="M3 9h18"
|
||||
key="1pudct"
|
||||
>
|
||||
</path>
|
||||
<path d="M3 15h18"
|
||||
key="5xshup"
|
||||
>
|
||||
</path>
|
||||
<path d="M9 3v18"
|
||||
key="fh3hqa"
|
||||
>
|
||||
</path>
|
||||
<path d="M15 3v18"
|
||||
key="14nvp0"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
exports[`Using lucide icon components > should render a component 1`] = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
viewbox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
width="24"
|
||||
height="24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
class="lucide lucide-icon lucide-grid3x3 lucide-grid-3x3"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<rect width="18"
|
||||
height="18"
|
||||
x="3"
|
||||
y="3"
|
||||
rx="2"
|
||||
key="afitv7"
|
||||
>
|
||||
</rect>
|
||||
<path d="M3 9h18"
|
||||
key="1pudct"
|
||||
>
|
||||
</path>
|
||||
<path d="M3 15h18"
|
||||
key="5xshup"
|
||||
>
|
||||
</path>
|
||||
<path d="M9 3v18"
|
||||
key="fh3hqa"
|
||||
>
|
||||
</path>
|
||||
<path d="M15 3v18"
|
||||
key="14nvp0"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
`;
|
||||
102
packages/solid/tests/context.spec.tsx
Normal file
102
packages/solid/tests/context.spec.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import { render } from '@solidjs/testing-library';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { House, LucideProvider } from '../src/lucide-solid';
|
||||
|
||||
describe('Using LucideProvider', () => {
|
||||
it('should render the icon with LucideProvider', () => {
|
||||
const { container } = render(() => (
|
||||
<LucideProvider
|
||||
size={48}
|
||||
color="red"
|
||||
>
|
||||
<House />
|
||||
</LucideProvider>
|
||||
));
|
||||
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the icon with default props when no provider is used', () => {
|
||||
const { container } = render(() => <House />);
|
||||
|
||||
const IconComponent = container.firstElementChild;
|
||||
|
||||
expect(IconComponent).toHaveAttribute('width', '24');
|
||||
expect(IconComponent).toHaveAttribute('height', '24');
|
||||
expect(IconComponent).toHaveAttribute('stroke', 'currentColor');
|
||||
expect(IconComponent).toHaveAttribute('stroke-width', '2');
|
||||
});
|
||||
|
||||
it('should render the icon with LucideProvider and custom strokeWidth', () => {
|
||||
const { container } = render(() => (
|
||||
<LucideProvider
|
||||
size={48}
|
||||
color="red"
|
||||
strokeWidth={4}
|
||||
>
|
||||
<House />
|
||||
</LucideProvider>
|
||||
));
|
||||
|
||||
const IconComponent = container.firstElementChild;
|
||||
|
||||
expect(IconComponent).toHaveAttribute('width', '48');
|
||||
expect(IconComponent).toHaveAttribute('height', '48');
|
||||
expect(IconComponent).toHaveAttribute('stroke', 'red');
|
||||
expect(IconComponent).toHaveAttribute('stroke-width', '4');
|
||||
});
|
||||
|
||||
it('should render the icon with LucideProvider and custom absoluteStrokeWidth', () => {
|
||||
const { container } = render(() => (
|
||||
<LucideProvider
|
||||
size={48}
|
||||
color="red"
|
||||
absoluteStrokeWidth
|
||||
>
|
||||
<House />
|
||||
</LucideProvider>
|
||||
));
|
||||
|
||||
const IconComponent = container.firstElementChild;
|
||||
|
||||
expect(IconComponent).toHaveAttribute('stroke-width', '1');
|
||||
});
|
||||
|
||||
it("should override the provider's global props when passing props to the icon", () => {
|
||||
const { container } = render(() => (
|
||||
<LucideProvider
|
||||
size={48}
|
||||
color="red"
|
||||
strokeWidth={4}
|
||||
>
|
||||
<House
|
||||
size={24}
|
||||
color="blue"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
</LucideProvider>
|
||||
));
|
||||
|
||||
const IconComponent = container.firstElementChild;
|
||||
|
||||
expect(IconComponent).toHaveAttribute('width', '24');
|
||||
expect(IconComponent).toHaveAttribute('height', '24');
|
||||
expect(IconComponent).toHaveAttribute('stroke', 'blue');
|
||||
expect(IconComponent).toHaveAttribute('stroke-width', '2');
|
||||
});
|
||||
|
||||
it('should merge className from provider and icon', () => {
|
||||
const { container } = render(() => (
|
||||
<LucideProvider class="provider-class">
|
||||
<House class="icon-class" />
|
||||
</LucideProvider>
|
||||
));
|
||||
|
||||
const IconComponent = container.firstElementChild;
|
||||
|
||||
expect(IconComponent).toHaveAttribute(
|
||||
'class',
|
||||
'lucide lucide-icon provider-class lucide-house icon-class',
|
||||
);
|
||||
});
|
||||
});
|
||||
90
packages/solid/tests/lucide-solid.spec.tsx
Normal file
90
packages/solid/tests/lucide-solid.spec.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { render, cleanup } from '@solidjs/testing-library';
|
||||
import { Edit2, Grid, Pen, Droplet } from '../src/lucide-solid';
|
||||
|
||||
describe('Using lucide icon components', () => {
|
||||
it('should render a component', () => {
|
||||
const { container } = render(() => <Grid />);
|
||||
|
||||
expect(container.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should adjust the size, stroke color and stroke width', async () => {
|
||||
const testId = 'grid-icon';
|
||||
const { container, getByTestId } = render(() => (
|
||||
<Grid
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
color="red"
|
||||
strokeWidth={4}
|
||||
/>
|
||||
));
|
||||
|
||||
const { attributes } = (await getByTestId(testId)) as unknown as {
|
||||
attributes: Record<string, { value: string }>;
|
||||
};
|
||||
expect(attributes.stroke.value).toBe('red');
|
||||
expect(attributes.width.value).toBe('48');
|
||||
expect(attributes.height.value).toBe('48');
|
||||
expect(attributes['stroke-width'].value).toBe('4');
|
||||
expect(container.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the alias icon', () => {
|
||||
const testId = 'pen-icon';
|
||||
const { container } = render(() => (
|
||||
<Pen
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
strokeWidth={4}
|
||||
/>
|
||||
));
|
||||
|
||||
const PenIconRenderedHTML = container.innerHTML;
|
||||
|
||||
cleanup();
|
||||
|
||||
const { container: Edit2Container } = render(() => (
|
||||
<Edit2
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
strokeWidth={4}
|
||||
/>
|
||||
));
|
||||
|
||||
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML);
|
||||
});
|
||||
|
||||
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||
const testId = 'grid-icon';
|
||||
const { container, getByTestId } = render(() => (
|
||||
<Grid
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
color="red"
|
||||
absoluteStrokeWidth
|
||||
/>
|
||||
));
|
||||
|
||||
const { attributes } = getByTestId(testId) as unknown as {
|
||||
attributes: Record<string, { value: string }>;
|
||||
};
|
||||
expect(attributes.stroke.value).toBe('red');
|
||||
expect(attributes.width.value).toBe('48');
|
||||
expect(attributes.height.value).toBe('48');
|
||||
expect(attributes['stroke-width'].value).toBe('1');
|
||||
|
||||
expect(container.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should add all classes to the element', () => {
|
||||
const testClass = 'my-class';
|
||||
const { container } = render(() => <Droplet class={testClass} />);
|
||||
|
||||
expect(container.firstChild).toHaveClass(testClass);
|
||||
expect(container.firstChild).toHaveClass('lucide');
|
||||
expect(container.firstChild).toHaveClass('lucide-droplet');
|
||||
});
|
||||
});
|
||||
10
packages/solid/tests/setupVitest.js
Normal file
10
packages/solid/tests/setupVitest.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { expect, afterEach } from 'vitest';
|
||||
import { cleanup } from '@solidjs/testing-library';
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
import htmlSerializer from 'jest-serializer-html';
|
||||
|
||||
expect.addSnapshotSerializer(htmlSerializer);
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
22
packages/solid/tests/testIconNodes.ts
Normal file
22
packages/solid/tests/testIconNodes.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { IconNode } from '../src/types';
|
||||
|
||||
export const airVent: IconNode = [
|
||||
[
|
||||
'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',
|
||||
key: 'larmp2',
|
||||
},
|
||||
],
|
||||
['path', { d: 'M6 8h12', key: '6g4wlu' }],
|
||||
['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', key: '1bo8pg' }],
|
||||
['path', { d: 'M6.6 15.6A2 2 0 1 0 10 17v-5', key: 't9h90c' }],
|
||||
];
|
||||
|
||||
export const coffee: IconNode = [
|
||||
['path', { d: 'M17 8h1a4 4 0 1 1 0 8h-1', key: 'jx4kbh' }],
|
||||
['path', { d: 'M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z', key: '1bxrl0' }],
|
||||
['line', { x1: '6', x2: '6', y1: '2', y2: '4', key: '1cr9l3' }],
|
||||
['line', { x1: '10', x2: '10', y1: '2', y2: '4', key: '170wym' }],
|
||||
['line', { x1: '14', x2: '14', y1: '2', y2: '4', key: '1c5f70' }],
|
||||
];
|
||||
18
packages/solid/tsconfig.json
Normal file
18
packages/solid/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "@solidjs/web",
|
||||
"types": ["vite/client", "@testing-library/jest-dom"],
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"outDir": "./dist",
|
||||
"declarationDir": "./dist",
|
||||
"declaration": true,
|
||||
},
|
||||
}
|
||||
13
packages/solid/vitest.config.mts
Normal file
13
packages/solid/vitest.config.mts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import solidPlugin from 'vite-plugin-solid';
|
||||
|
||||
export default defineConfig({
|
||||
// TODO: Remove this when Solid testing library has support for Vitest 1.0, see: https://github.com/solidjs/solid-testing-library/issues/52
|
||||
// @ts-ignore
|
||||
plugins: [solidPlugin()],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
setupFiles: './tests/setupVitest.js',
|
||||
},
|
||||
});
|
||||
1355
pnpm-lock.yaml
generated
1355
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user