mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-16 22:47:42 +01:00
feat(@lucide/svelte): Lucide svelte 5 package (#2753)
* Lucide svelte (#1) * Update peerDependencies to support Svelte 5 * Bump svelte version * Bump @testing-library/svelte version * Remove alias in vitest.config.ts that causes tests to fail due to deprecated svelte/internal API * Convert to svelte 5 syntax * Bump vite & @sveltejs/vite-plugin-svelte version * Fix error during render when children prop is missing & fix components being mounted on the server during tests * Update test snapshots to reflect the differences in the html generated by svelte 5 * Convert class attribute to new array syntax with built-in clsx * Convert export template to svelte 5 syntax * Move svelte 5 to separate directory * Update snapshots * Update docs * fix(icon): change variable declaration from let to const in Icon.svelte * Lucide svelte (#1) (#2727) * Update peerDependencies to support Svelte 5 * Bump svelte version * Bump @testing-library/svelte version * Remove alias in vitest.config.ts that causes tests to fail due to deprecated svelte/internal API * Convert to svelte 5 syntax * Bump vite & @sveltejs/vite-plugin-svelte version * Fix error during render when children prop is missing & fix components being mounted on the server during tests * Update test snapshots to reflect the differences in the html generated by svelte 5 * Convert class attribute to new array syntax with built-in clsx * Convert export template to svelte 5 syntax * Revert changes in lucide-svelte library * Update package lock * Update test files * Formatting * Update clean command * Fix build * Update packages * update deps * Fix export script * Format code * Revert version number change in package json * Update workflows --------- Co-authored-by: Aurélien Richard <56389380+aurelienrichard@users.noreply.github.com>
This commit is contained in:
41
.github/workflows/lucide-svelte-5.yml
vendored
Normal file
41
.github/workflows/lucide-svelte-5.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: Lucide Svelte 5 checks
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- packages/svelte/**
|
||||||
|
- packages/shared/**
|
||||||
|
- tools/build-icons/**
|
||||||
|
- tools/rollup-plugins/**
|
||||||
|
- pnpm-lock.yaml
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: pnpm/action-setup@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
cache: 'pnpm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: pnpm --filter @lucide/svelte build
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: pnpm/action-setup@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
cache: 'pnpm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: pnpm --filter @lucide/svelte test
|
||||||
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -52,6 +52,7 @@ jobs:
|
|||||||
'lucide-preact',
|
'lucide-preact',
|
||||||
'lucide-solid',
|
'lucide-solid',
|
||||||
'lucide-svelte',
|
'lucide-svelte',
|
||||||
|
'@lucide/svelte',
|
||||||
]
|
]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -7,22 +7,22 @@ Implementation of the lucide icon library for svelte applications.
|
|||||||
::: code-group
|
::: code-group
|
||||||
|
|
||||||
```sh [pnpm]
|
```sh [pnpm]
|
||||||
pnpm add lucide-svelte
|
pnpm add @lucide/svelte
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh [yarn]
|
```sh [yarn]
|
||||||
yarn add lucide-svelte
|
yarn add @lucide/svelte
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh [npm]
|
```sh [npm]
|
||||||
npm install lucide-svelte
|
npm install @lucide/svelte
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh [bun]
|
```sh [bun]
|
||||||
bun add lucide-svelte
|
bun add @lucide/svelte
|
||||||
```
|
```
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
> `@lucide/svelte` is only for Svelte 5, for Svelte 4 use the `lucide-svelte` package.
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ Default usage:
|
|||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script>
|
<script>
|
||||||
import { Skull } from 'lucide-svelte';
|
import { Skull } from '@lucide/svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Skull />
|
<Skull />
|
||||||
@@ -46,17 +46,17 @@ Additional props can be passed to adjust the icon:
|
|||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script>
|
<script>
|
||||||
import { Camera } from 'lucide-svelte';
|
import { Camera } from '@lucide/svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Camera color="#ff3e98" />
|
<Camera color="#ff3e98" />
|
||||||
```
|
```
|
||||||
|
|
||||||
For faster builds and load times, you can import icons directly from the `lucide-svelte/icons` directory:
|
For faster builds and load times, you can import icons directly from the `@lucide/svelte/icons` directory:
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script>
|
<script>
|
||||||
import CircleAlert from 'lucide-svelte/icons/circle-alert';
|
import CircleAlert from '@lucide/svelte/icons/circle-alert';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CircleAlert color="#ff3e98" />
|
<CircleAlert color="#ff3e98" />
|
||||||
@@ -77,7 +77,7 @@ To customize the appearance of an icon, you can pass custom properties as props
|
|||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script>
|
<script>
|
||||||
import { Phone } from 'lucide-svelte';
|
import { Phone } from '@lucide/svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Phone fill="#333" />
|
<Phone fill="#333" />
|
||||||
@@ -91,53 +91,11 @@ The package includes type definitions for all icons. This is useful if you want
|
|||||||
|
|
||||||
### TypeScript Example
|
### TypeScript Example
|
||||||
|
|
||||||
#### Svelte 4
|
::: code-group
|
||||||
|
|
||||||
```svelte
|
```svelte [Svelte 5]
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Home, Library, Cog, type Icon } from 'lucide-svelte';
|
import { Home, Library, Cog, type Icon as IconType } from '@lucide/svelte';
|
||||||
import type { ComponentType } from 'svelte';
|
|
||||||
|
|
||||||
type MenuItem = {
|
|
||||||
name: string;
|
|
||||||
href: string;
|
|
||||||
icon: ComponentType<Icon>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const menuItems: MenuItem[] = [
|
|
||||||
{
|
|
||||||
name: 'Home',
|
|
||||||
href: '/',
|
|
||||||
icon: Home
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Blog',
|
|
||||||
href: '/blog',
|
|
||||||
icon: Library
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Projects',
|
|
||||||
href: '/projects',
|
|
||||||
icon: Cog
|
|
||||||
}
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#each menuItems as item}
|
|
||||||
<a href={item.href}>
|
|
||||||
<svelte:component this={item.icon} />
|
|
||||||
<span>{item.name}</span>
|
|
||||||
</a>
|
|
||||||
{/each}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### Svelte 5
|
|
||||||
Some changes are required since Svelte 5 [deprecates](https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes-Component-typing-changes) the `ComponentType` typescript type.
|
|
||||||
|
|
||||||
```svelte
|
|
||||||
<script lang="ts">
|
|
||||||
import { Home, Library, Cog, type Icon as IconType } from 'lucide-svelte';
|
|
||||||
|
|
||||||
type MenuItem = {
|
type MenuItem = {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -173,19 +131,98 @@ Some changes are required since Svelte 5 [deprecates](https://svelte.dev/docs/sv
|
|||||||
{/each}
|
{/each}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```svelte [Svelte 4]
|
||||||
|
<script lang="ts">
|
||||||
|
import { Home, Library, Cog, type Icon } from '@lucide/svelte';
|
||||||
|
import type { ComponentType } from 'svelte';
|
||||||
|
|
||||||
|
type MenuItem = {
|
||||||
|
name: string;
|
||||||
|
href: string;
|
||||||
|
icon: ComponentType<Icon>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const menuItems: MenuItem[] = [
|
||||||
|
{
|
||||||
|
name: 'Home',
|
||||||
|
href: '/',
|
||||||
|
icon: Home
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Blog',
|
||||||
|
href: '/blog',
|
||||||
|
icon: Library
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Projects',
|
||||||
|
href: '/projects',
|
||||||
|
icon: Cog
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each menuItems as item}
|
||||||
|
<a href={item.href}>
|
||||||
|
<svelte:component this={item.icon} />
|
||||||
|
<span>{item.name}</span>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
### JSDoc Example
|
### JSDoc Example
|
||||||
|
|
||||||
#### Svelte 4
|
::: code-group
|
||||||
|
|
||||||
```svelte
|
```svelte [Svelte 5]
|
||||||
<script>
|
<script>
|
||||||
import { Home, Library, Cog } from 'lucide-svelte';
|
import { Home, Library, Cog } from '@lucide/svelte';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} MenuItem
|
* @typedef {Object} MenuItem
|
||||||
* @property {string} name
|
* @property {string} name
|
||||||
* @property {string} href
|
* @property {string} href
|
||||||
* @property {import('svelte').ComponentType<import('lucide-svelte').Icon>} icon
|
* @property {typeof import('@lucide/svelte').Icon} icon
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {MenuItem[]} */
|
||||||
|
const menuItems = [
|
||||||
|
{
|
||||||
|
name: 'Home',
|
||||||
|
href: '/',
|
||||||
|
icon: Home
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Blog',
|
||||||
|
href: '/blog',
|
||||||
|
icon: Library
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Projects',
|
||||||
|
href: '/projects',
|
||||||
|
icon: Cog
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each menuItems as item}
|
||||||
|
{@const Icon = item.icon}
|
||||||
|
<a href={item.href}>
|
||||||
|
<Icon />
|
||||||
|
<span>{item.name}</span>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
```
|
||||||
|
|
||||||
|
```svelte [Svelte 4]
|
||||||
|
<script>
|
||||||
|
import { Home, Library, Cog } from '@lucide/svelte';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} MenuItem
|
||||||
|
* @property {string} name
|
||||||
|
* @property {string} href
|
||||||
|
* @property {import('svelte').ComponentType<import('@lucide/svelte').Icon>} icon
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @type {MenuItem[]} */
|
/** @type {MenuItem[]} */
|
||||||
@@ -216,49 +253,7 @@ Some changes are required since Svelte 5 [deprecates](https://svelte.dev/docs/sv
|
|||||||
{/each}
|
{/each}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
#### Svelte 5
|
|
||||||
|
|
||||||
```svelte
|
|
||||||
<script>
|
|
||||||
import { Home, Library, Cog } from 'lucide-svelte';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} MenuItem
|
|
||||||
* @property {string} name
|
|
||||||
* @property {string} href
|
|
||||||
* @property {typeof import('lucide-svelte').Icon} icon
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @type {MenuItem[]} */
|
|
||||||
const menuItems = [
|
|
||||||
{
|
|
||||||
name: 'Home',
|
|
||||||
href: '/',
|
|
||||||
icon: Home
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Blog',
|
|
||||||
href: '/blog',
|
|
||||||
icon: Library
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Projects',
|
|
||||||
href: '/projects',
|
|
||||||
icon: Cog
|
|
||||||
}
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#each menuItems as item}
|
|
||||||
{@const Icon = item.icon}
|
|
||||||
<a href={item.href}>
|
|
||||||
<Icon />
|
|
||||||
<span>{item.name}</span>
|
|
||||||
</a>
|
|
||||||
{/each}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
For more details about typing the `svelte:component` directive, see the [Svelte documentation](https://svelte.dev/docs/typescript#types-componenttype).
|
For more details about typing the `svelte:component` directive, see the [Svelte documentation](https://svelte.dev/docs/typescript#types-componenttype).
|
||||||
|
|
||||||
@@ -275,7 +270,7 @@ This creates a single icon based on the iconNode passed and renders a Lucide ico
|
|||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script>
|
<script>
|
||||||
import { Icon } from 'lucide-svelte';
|
import { Icon } from '@lucide/svelte';
|
||||||
import { burger, sausage } from '@lucide/lab';
|
import { burger, sausage } from '@lucide/lab';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -293,22 +288,11 @@ The example below imports all ES Modules, so exercise caution when using it. Imp
|
|||||||
|
|
||||||
### Icon Component Example
|
### Icon Component Example
|
||||||
|
|
||||||
#### Svelte 4
|
::: code-group
|
||||||
|
|
||||||
```svelte
|
```svelte [Svelte 5]
|
||||||
<script>
|
<script>
|
||||||
import * as icons from 'lucide-svelte';
|
import * as icons from '@lucide/svelte';
|
||||||
export let name;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:component this={icons[name]} {...$$props} />
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Svelte 5
|
|
||||||
|
|
||||||
```svelte
|
|
||||||
<script>
|
|
||||||
import * as icons from 'lucide-svelte';
|
|
||||||
let { name } = $props();
|
let { name } = $props();
|
||||||
|
|
||||||
const Icon = icons[name];
|
const Icon = icons[name];
|
||||||
@@ -317,6 +301,17 @@ The example below imports all ES Modules, so exercise caution when using it. Imp
|
|||||||
<Icon {...props} />
|
<Icon {...props} />
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```svelte [Svelte 4]
|
||||||
|
<script>
|
||||||
|
import * as icons from '@lucide/svelte';
|
||||||
|
export let name;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:component this={icons[name]} {...$$props} />
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
#### Using the Icon Component
|
#### Using the Icon Component
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`Using Icon Component > should render icon and match snapshot 1`] = `
|
exports[`Using Icon Component > should render icon and match snapshot 1`] = `
|
||||||
<div>
|
<svg
|
||||||
<svg
|
|
||||||
class="lucide-icon lucide"
|
class="lucide-icon lucide"
|
||||||
fill="none"
|
fill="none"
|
||||||
height="48"
|
height="48"
|
||||||
@@ -13,7 +12,7 @@ exports[`Using Icon Component > should render icon and match snapshot 1`] = `
|
|||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
width="48"
|
width="48"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<path
|
<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"
|
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"
|
||||||
/>
|
/>
|
||||||
@@ -31,6 +30,5 @@ exports[`Using Icon Component > should render icon and match snapshot 1`] = `
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ exports[`Using lucide icon components > should add a class to the element 1`] =
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `
|
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `
|
||||||
<body>
|
<div>
|
||||||
<div>
|
|
||||||
<svg
|
<svg
|
||||||
class="lucide-icon lucide lucide-smile"
|
class="lucide-icon lucide lucide-smile"
|
||||||
fill="none"
|
fill="none"
|
||||||
@@ -82,13 +81,11 @@ exports[`Using lucide icon components > should adjust the size, stroke color and
|
|||||||
|
|
||||||
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `
|
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `
|
||||||
<div>
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="48"
|
width="48"
|
||||||
height="48"
|
height="48"
|
||||||
viewbox="0 0 24 24"
|
viewbox="0 0 24 24"
|
||||||
@@ -99,7 +96,7 @@ exports[`Using lucide icon components > should not scale the strokeWidth when ab
|
|||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
data-testid="smile-icon"
|
data-testid="smile-icon"
|
||||||
class="lucide-icon lucide lucide-smile"
|
class="lucide-icon lucide lucide-smile"
|
||||||
>
|
>
|
||||||
<circle cx="12"
|
<circle cx="12"
|
||||||
cy="12"
|
cy="12"
|
||||||
r="10"
|
r="10"
|
||||||
@@ -119,13 +116,11 @@ exports[`Using lucide icon components > should not scale the strokeWidth when ab
|
|||||||
y2="9"
|
y2="9"
|
||||||
>
|
>
|
||||||
</line>
|
</line>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Using lucide icon components > should render an component 1`] = `
|
exports[`Using lucide icon components > should render an component 1`] = `
|
||||||
<body>
|
<div>
|
||||||
<div>
|
|
||||||
<svg
|
<svg
|
||||||
class="lucide-icon lucide lucide-smile"
|
class="lucide-icon lucide lucide-smile"
|
||||||
fill="none"
|
fill="none"
|
||||||
@@ -164,13 +159,11 @@ exports[`Using lucide icon components > should render an component 1`] = `
|
|||||||
|
|
||||||
|
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Using lucide icon components > should render an icon slot 1`] = `
|
exports[`Using lucide icon components > should render an icon slot 1`] = `
|
||||||
<body>
|
<div>
|
||||||
<div>
|
|
||||||
<svg
|
<svg
|
||||||
class="lucide-icon lucide lucide-smile"
|
class="lucide-icon lucide lucide-smile"
|
||||||
fill="none"
|
fill="none"
|
||||||
@@ -212,6 +205,5 @@ exports[`Using lucide icon components > should render an icon slot 1`] = `
|
|||||||
Test
|
Test
|
||||||
</text>
|
</text>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
2
packages/svelte/.gitignore
vendored
Normal file
2
packages/svelte/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
src/icons/*.svelte
|
||||||
|
.svelte-kit
|
||||||
73
packages/svelte/README.md
Normal file
73
packages/svelte/README.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/lucide-icons/lucide">
|
||||||
|
<img src="https://lucide.dev/package-logos/lucide-svelte.svg" alt="Lucide icon library for Svelte 5 applications." width="540">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
Lucide icon library for Svelte 5 applications.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://www.npmjs.com/package/lucide-svelte)
|
||||||
|

|
||||||
|
[](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/packages/lucide-svelte">Documentation</a>
|
||||||
|
·
|
||||||
|
<a href="https://lucide.dev/license">License</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# Lucide Svelte
|
||||||
|
|
||||||
|
Implementation of the lucide icon library for svelte applications.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm add @lucide/svelte
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install @lucide/svelte
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add @lucide/svelte
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bun add @lucide/svelte
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
For full documentation, visit [lucide.dev](https://lucide.dev/guide/packages/lucide-svelte)
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
### Awesome backers 🍺
|
||||||
|
|
||||||
|
<a href="https://www.scipress.io?utm_source=lucide"><img src="https://lucide.dev/sponsors/scipress.svg" width="180" alt="Scipress sponsor badge" /></a>
|
||||||
|
<a href="https://github.com/pdfme/pdfme"><img src="https://lucide.dev/sponsors/pdfme.svg" width="180" alt="pdfme sponsor badge" /></a>
|
||||||
79
packages/svelte/package.json
Normal file
79
packages/svelte/package.json
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"name": "@lucide/svelte",
|
||||||
|
"description": "A Lucide icon library package for Svelte applications",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"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/svelte"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"Lucide",
|
||||||
|
"Svelte",
|
||||||
|
"Feather",
|
||||||
|
"Icons",
|
||||||
|
"Icon",
|
||||||
|
"SVG",
|
||||||
|
"Feather Icons",
|
||||||
|
"Fontawesome",
|
||||||
|
"Font Awesome"
|
||||||
|
],
|
||||||
|
"author": "Eric Fennis",
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/lucide-svelte.js",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/lucide-svelte.d.ts",
|
||||||
|
"svelte": "./dist/lucide-svelte.js",
|
||||||
|
"default": "./dist/lucide-svelte.js"
|
||||||
|
},
|
||||||
|
"./icons": {
|
||||||
|
"types": "./dist/lucide-svelte.d.ts",
|
||||||
|
"svelte": "./dist/lucide-svelte.js"
|
||||||
|
},
|
||||||
|
"./icons/*": {
|
||||||
|
"types": "./dist/icons/*.svelte.d.ts",
|
||||||
|
"svelte": "./dist/icons/*.js",
|
||||||
|
"default": "./dist/icons/*.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"typings": "dist/lucide-svelte.d.ts",
|
||||||
|
"sideEffects": false,
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:package && pnpm build:license",
|
||||||
|
"copy:license": "cp ../../LICENSE ./LICENSE",
|
||||||
|
"clean": "rm -rf dist stats ./src/icons/*.{ts,svelte} ./src/aliases/{aliases,prefixed,suffixed}.ts",
|
||||||
|
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --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",
|
||||||
|
"build:license": "node ./scripts/appendBlockComments.mjs",
|
||||||
|
"test": "pnpm copy:license && pnpm build:icons && vitest run",
|
||||||
|
"test:watch": "vitest watch",
|
||||||
|
"version": "pnpm version --git-tag-version=false"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@lucide/build-icons": "workspace:*",
|
||||||
|
"@lucide/helpers": "workspace:*",
|
||||||
|
"@sveltejs/package": "^2.3.10",
|
||||||
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
|
"@testing-library/jest-dom": "^6.1.4",
|
||||||
|
"@testing-library/svelte": "^5.2.7",
|
||||||
|
"@tsconfig/svelte": "^5.0.4",
|
||||||
|
"jest-serializer-html": "^7.1.0",
|
||||||
|
"jsdom": "^20.0.3",
|
||||||
|
"svelte": "^5.20.5",
|
||||||
|
"svelte-check": "^4.1.4",
|
||||||
|
"svelte-preprocess": "^6.0.3",
|
||||||
|
"typescript": "^5.1.6",
|
||||||
|
"vite": "6.0.7",
|
||||||
|
"vitest": "^1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
64
packages/svelte/scripts/appendBlockComments.mjs
Normal file
64
packages/svelte/scripts/appendBlockComments.mjs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { lstatSync } from 'fs';
|
||||||
|
import { readdir, readFile, writeFile } from 'fs/promises';
|
||||||
|
import path from 'path';
|
||||||
|
import { getCurrentDirPath } from '@lucide/helpers';
|
||||||
|
import { getJSBanner } from './license.mjs';
|
||||||
|
|
||||||
|
const currentDir = getCurrentDirPath(import.meta.url);
|
||||||
|
const targetDirectory = path.join(currentDir, '../dist');
|
||||||
|
|
||||||
|
const files = await readdir(targetDirectory, {
|
||||||
|
recursive: true,
|
||||||
|
encoding: 'utf-8',
|
||||||
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
for (const file of files) {
|
||||||
|
const filepath = path.join(targetDirectory, file);
|
||||||
|
const filestat = lstatSync(filepath);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
if (filestat.isFile() === false || filestat.isDirectory()) continue;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const contents = await readFile(filepath, { encoding: 'utf-8' });
|
||||||
|
let newContents = contents;
|
||||||
|
const ext = path.extname(filepath);
|
||||||
|
let license;
|
||||||
|
|
||||||
|
if (/\.(js|mjs|cjs|ts)/.test(ext)) {
|
||||||
|
license = getJSBanner();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (license) {
|
||||||
|
newContents = license + contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Places icon block comment at the top of the Svelte component class
|
||||||
|
if (/icons\/(.*?)\.svelte\.d\.ts/.test(filepath)) {
|
||||||
|
const svelteFilepath = filepath.replace('.d.ts', '');
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const svelteFileContents = await readFile(svelteFilepath, { encoding: 'utf-8' });
|
||||||
|
|
||||||
|
const blockCommentRegex = /\/\*\*\n\s\*\s(@component\s@name)[\s\S]*?\*\//;
|
||||||
|
const blockCommentMatch = blockCommentRegex.exec(svelteFileContents);
|
||||||
|
|
||||||
|
if (blockCommentMatch !== null) {
|
||||||
|
const blockComment = blockCommentMatch[0];
|
||||||
|
|
||||||
|
const exportClassRegex = /export default class (\w+) extends SvelteComponentTyped<(.*?)> {/;
|
||||||
|
|
||||||
|
if (exportClassRegex.test(newContents)) {
|
||||||
|
newContents = newContents.replace(
|
||||||
|
exportClassRegex,
|
||||||
|
`${blockComment}\nexport default class $1 extends SvelteComponentTyped<$2> {`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newContents !== contents) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await writeFile(filepath, newContents, { encoding: 'utf-8' });
|
||||||
|
}
|
||||||
|
}
|
||||||
43
packages/svelte/scripts/exportTemplate.mjs
Normal file
43
packages/svelte/scripts/exportTemplate.mjs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
|
||||||
|
import { getJSBanner } from './license.mjs';
|
||||||
|
|
||||||
|
export default async ({
|
||||||
|
iconName,
|
||||||
|
children,
|
||||||
|
componentName,
|
||||||
|
getSvg,
|
||||||
|
deprecated,
|
||||||
|
deprecationReason,
|
||||||
|
}) => {
|
||||||
|
const svgContents = await getSvg();
|
||||||
|
const svgBase64 = base64SVG(svgContents);
|
||||||
|
|
||||||
|
return `\
|
||||||
|
<script lang="ts">
|
||||||
|
${getJSBanner()}
|
||||||
|
import Icon from '../Icon.svelte';
|
||||||
|
import type { IconNode, IconProps } from '../types.js';
|
||||||
|
|
||||||
|
let props: IconProps = $props();
|
||||||
|
|
||||||
|
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-svelte - Documentation
|
||||||
|
*
|
||||||
|
* @param {Object} props - Lucide icons props and any valid SVG attribute
|
||||||
|
* @returns {FunctionalComponent} Svelte component
|
||||||
|
* ${deprecated ? `@deprecated ${deprecationReason}` : ''}
|
||||||
|
*/
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Icon name="${iconName}" {...props} iconNode={iconNode}>
|
||||||
|
{@render props.children?.()}
|
||||||
|
</Icon>
|
||||||
|
`;
|
||||||
|
};
|
||||||
13
packages/svelte/scripts/license.mjs
Normal file
13
packages/svelte/scripts/license.mjs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import pkg from '../package.json' with { type: 'json' };
|
||||||
|
|
||||||
|
const license = fs.readFileSync('LICENSE', 'utf-8');
|
||||||
|
|
||||||
|
export function getJSBanner() {
|
||||||
|
return `/**
|
||||||
|
* @license ${pkg.name} v${pkg.version} - ${pkg.license}
|
||||||
|
*
|
||||||
|
* ${license.split('\n').join('\n * ')}
|
||||||
|
*/
|
||||||
|
`;
|
||||||
|
}
|
||||||
33
packages/svelte/src/Icon.svelte
Normal file
33
packages/svelte/src/Icon.svelte
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import defaultAttributes from './defaultAttributes';
|
||||||
|
import type { IconProps } from './types';
|
||||||
|
|
||||||
|
const {
|
||||||
|
name,
|
||||||
|
color = 'currentColor',
|
||||||
|
size = 24,
|
||||||
|
strokeWidth = 2,
|
||||||
|
absoluteStrokeWidth = false,
|
||||||
|
iconNode = [],
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: IconProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
{...defaultAttributes}
|
||||||
|
{...props}
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
stroke={color}
|
||||||
|
stroke-width={absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth}
|
||||||
|
class={['lucide-icon lucide', name && `lucide-${name}`, props.class]}
|
||||||
|
>
|
||||||
|
{#each iconNode as [tag, attrs]}
|
||||||
|
<svelte:element
|
||||||
|
this={tag}
|
||||||
|
{...attrs}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
{@render children?.()}
|
||||||
|
</svg>
|
||||||
3
packages/svelte/src/aliases/index.ts
Normal file
3
packages/svelte/src/aliases/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './aliases';
|
||||||
|
export * from './prefixed';
|
||||||
|
export * from './suffixed';
|
||||||
15
packages/svelte/src/defaultAttributes.ts
Normal file
15
packages/svelte/src/defaultAttributes.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import type { Attrs } from './types.js';
|
||||||
|
|
||||||
|
const defaultAttributes: Attrs = {
|
||||||
|
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/svelte/src/icons/.gitkeep
Normal file
1
packages/svelte/src/icons/.gitkeep
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Folder for generated icons
|
||||||
6
packages/svelte/src/lucide-svelte.ts
Normal file
6
packages/svelte/src/lucide-svelte.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export * from './icons/index';
|
||||||
|
export * as icons from './icons/index';
|
||||||
|
export * from './aliases';
|
||||||
|
export { default as defaultAttributes } from './defaultAttributes';
|
||||||
|
export * from './types';
|
||||||
|
export { default as Icon } from './Icon.svelte';
|
||||||
24
packages/svelte/src/types.ts
Normal file
24
packages/svelte/src/types.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import type { SVGAttributes, SvelteHTMLElements } from 'svelte/elements';
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
|
||||||
|
export type Attrs = SVGAttributes<SVGSVGElement>;
|
||||||
|
|
||||||
|
export type IconNode = [elementName: keyof SvelteHTMLElements, attrs: Attrs][];
|
||||||
|
|
||||||
|
export interface IconProps extends Attrs {
|
||||||
|
name?: string;
|
||||||
|
color?: string;
|
||||||
|
size?: number | string;
|
||||||
|
strokeWidth?: number | string;
|
||||||
|
absoluteStrokeWidth?: boolean;
|
||||||
|
iconNode?: IconNode;
|
||||||
|
children?: Snippet;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IconEvents = {
|
||||||
|
[evt: string]: CustomEvent<any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IconSlots = {
|
||||||
|
default: {};
|
||||||
|
};
|
||||||
8
packages/svelte/svelte.config.js
Normal file
8
packages/svelte/svelte.config.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
|
import sveltePreprocess from 'svelte-preprocess';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: sveltePreprocess({
|
||||||
|
typescript: true,
|
||||||
|
}),
|
||||||
|
};
|
||||||
33
packages/svelte/tests/Icon.spec.ts
Normal file
33
packages/svelte/tests/Icon.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { render } from '@testing-library/svelte';
|
||||||
|
import { Icon } from '../src/lucide-svelte';
|
||||||
|
|
||||||
|
import { airVent } from './testIconNodes';
|
||||||
|
|
||||||
|
describe('Using Icon Component', () => {
|
||||||
|
it('should render icon based on a iconNode', async () => {
|
||||||
|
const { container } = render(Icon, {
|
||||||
|
props: {
|
||||||
|
iconNode: airVent,
|
||||||
|
size: 48,
|
||||||
|
color: 'red',
|
||||||
|
absoluteStrokeWidth: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.firstChild).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render icon and match snapshot', async () => {
|
||||||
|
const { container } = render(Icon, {
|
||||||
|
props: {
|
||||||
|
iconNode: airVent,
|
||||||
|
size: 48,
|
||||||
|
color: 'red',
|
||||||
|
absoluteStrokeWidth: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.firstChild).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
7
packages/svelte/tests/TestSlots.svelte
Normal file
7
packages/svelte/tests/TestSlots.svelte
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Smile from '../src/icons/smile.svelte'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Smile>
|
||||||
|
<text>Test</text>
|
||||||
|
</Smile>
|
||||||
47
packages/svelte/tests/__snapshots__/Icon.spec.ts.snap
Normal file
47
packages/svelte/tests/__snapshots__/Icon.spec.ts.snap
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`Using Icon Component > should render icon and match snapshot 1`] = `
|
||||||
|
<svg
|
||||||
|
class="lucide-icon lucide"
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<path
|
||||||
|
d="M6 8h12"
|
||||||
|
>
|
||||||
|
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<path
|
||||||
|
d="M6.6 15.6A2 2 0 1 0 10 17v-5"
|
||||||
|
>
|
||||||
|
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
272
packages/svelte/tests/__snapshots__/lucide-svelte.spec.ts.snap
Normal file
272
packages/svelte/tests/__snapshots__/lucide-svelte.spec.ts.snap
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`Using lucide icon components > should add a class to the element 1`] = `
|
||||||
|
<svg
|
||||||
|
class="lucide-icon lucide lucide-smile my-icon"
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
<!---->
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
>
|
||||||
|
|
||||||
|
</circle>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<path
|
||||||
|
d="M8 14s1.5 2 4 2 4-2 4-2"
|
||||||
|
>
|
||||||
|
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<line
|
||||||
|
x1="9"
|
||||||
|
x2="9.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
|
||||||
|
</line>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<line
|
||||||
|
x1="15"
|
||||||
|
x2="15.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
|
||||||
|
</line>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `
|
||||||
|
<div>
|
||||||
|
<svg
|
||||||
|
class="lucide-icon lucide lucide-smile"
|
||||||
|
fill="none"
|
||||||
|
height="48"
|
||||||
|
stroke="red"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="4"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="48"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<!---->
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
>
|
||||||
|
|
||||||
|
</circle>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<path
|
||||||
|
d="M8 14s1.5 2 4 2 4-2 4-2"
|
||||||
|
>
|
||||||
|
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<line
|
||||||
|
x1="9"
|
||||||
|
x2="9.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
|
||||||
|
</line>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<line
|
||||||
|
x1="15"
|
||||||
|
x2="15.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
|
||||||
|
</line>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
viewbox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="red"
|
||||||
|
stroke-width="1"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
data-testid="smile-icon"
|
||||||
|
class="lucide-icon lucide lucide-smile"
|
||||||
|
>
|
||||||
|
<circle cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
>
|
||||||
|
</circle>
|
||||||
|
<path d="M8 14s1.5 2 4 2 4-2 4-2">
|
||||||
|
</path>
|
||||||
|
<line x1="9"
|
||||||
|
x2="9.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
</line>
|
||||||
|
<line x1="15"
|
||||||
|
x2="15.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
</line>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Using lucide icon components > should render an component 1`] = `
|
||||||
|
<div>
|
||||||
|
<svg
|
||||||
|
class="lucide-icon lucide lucide-smile"
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
<!---->
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
>
|
||||||
|
|
||||||
|
</circle>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<path
|
||||||
|
d="M8 14s1.5 2 4 2 4-2 4-2"
|
||||||
|
>
|
||||||
|
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<line
|
||||||
|
x1="9"
|
||||||
|
x2="9.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
|
||||||
|
</line>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<line
|
||||||
|
x1="15"
|
||||||
|
x2="15.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
|
||||||
|
</line>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Using lucide icon components > should render an icon slot 1`] = `
|
||||||
|
<div>
|
||||||
|
<svg
|
||||||
|
class="lucide-icon lucide lucide-smile"
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
<!---->
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
>
|
||||||
|
|
||||||
|
</circle>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<path
|
||||||
|
d="M8 14s1.5 2 4 2 4-2 4-2"
|
||||||
|
>
|
||||||
|
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<line
|
||||||
|
x1="9"
|
||||||
|
x2="9.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
|
||||||
|
</line>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<line
|
||||||
|
x1="15"
|
||||||
|
x2="15.01"
|
||||||
|
y1="9"
|
||||||
|
y2="9"
|
||||||
|
>
|
||||||
|
|
||||||
|
</line>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<text>
|
||||||
|
Test
|
||||||
|
</text>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
92
packages/svelte/tests/lucide-svelte.spec.ts
Normal file
92
packages/svelte/tests/lucide-svelte.spec.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { describe, it, expect, afterEach } from 'vitest';
|
||||||
|
import { render, cleanup } from '@testing-library/svelte';
|
||||||
|
import { Smile, Pen, Edit2 } from '../src/lucide-svelte';
|
||||||
|
import TestSlots from './TestSlots.svelte';
|
||||||
|
|
||||||
|
describe('Using lucide icon components', () => {
|
||||||
|
afterEach(() => cleanup());
|
||||||
|
it('should render an component', () => {
|
||||||
|
const { container } = render(Smile);
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should adjust the size, stroke color and stroke width', () => {
|
||||||
|
const { container } = render(Smile, {
|
||||||
|
props: {
|
||||||
|
size: 48,
|
||||||
|
color: 'red',
|
||||||
|
strokeWidth: 4,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add a class to the element', () => {
|
||||||
|
const testClass = 'my-icon';
|
||||||
|
render(Smile, {
|
||||||
|
props: {
|
||||||
|
class: testClass,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [icon] = document.getElementsByClassName(testClass);
|
||||||
|
|
||||||
|
expect(icon).toBeInTheDocument();
|
||||||
|
expect(icon).toMatchSnapshot();
|
||||||
|
expect(icon).toHaveClass(testClass);
|
||||||
|
expect(icon).toHaveClass('lucide');
|
||||||
|
expect(icon).toHaveClass('lucide-smile');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add a style attribute to the element', () => {
|
||||||
|
render(Smile, {
|
||||||
|
props: {
|
||||||
|
style: 'position: absolute;',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const [icon] = document.getElementsByClassName('lucide');
|
||||||
|
|
||||||
|
expect(icon.getAttribute('style')).toContain('position: absolute');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render an icon slot', () => {
|
||||||
|
const { container, getByText } = render(TestSlots);
|
||||||
|
|
||||||
|
const textElement = getByText('Test');
|
||||||
|
expect(textElement).toBeInTheDocument();
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the alias icon', () => {
|
||||||
|
const { container } = render(Pen);
|
||||||
|
|
||||||
|
const PenIconRenderedHTML = container.innerHTML;
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
const { container: Edit2Container } = render(Edit2);
|
||||||
|
|
||||||
|
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||||
|
const testId = 'smile-icon';
|
||||||
|
const { container, getByTestId } = render(Smile, {
|
||||||
|
'data-testid': testId,
|
||||||
|
color: 'red',
|
||||||
|
size: 48,
|
||||||
|
absoluteStrokeWidth: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
5
packages/svelte/tests/setupVitest.ts
Normal file
5
packages/svelte/tests/setupVitest.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { expect } from 'vitest';
|
||||||
|
import '@testing-library/jest-dom/vitest';
|
||||||
|
import htmlSerializer from 'jest-serializer-html';
|
||||||
|
|
||||||
|
expect.addSnapshotSerializer(htmlSerializer);
|
||||||
21
packages/svelte/tests/testIconNodes.ts
Normal file
21
packages/svelte/tests/testIconNodes.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { IconNode } from '../src/lucide-svelte';
|
||||||
|
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['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' }],
|
||||||
|
];
|
||||||
|
|
||||||
|
export const coffee: IconNode = [
|
||||||
|
['path', { d: 'M17 8h1a4 4 0 1 1 0 8h-1' }],
|
||||||
|
['path', { d: 'M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z' }],
|
||||||
|
['line', { x1: '6', x2: '6', y1: '2', y2: '4' }],
|
||||||
|
['line', { x1: '10', x2: '10', y1: '2', y2: '4' }],
|
||||||
|
['line', { x1: '14', x2: '14', y1: '2', y2: '4' }],
|
||||||
|
];
|
||||||
14
packages/svelte/tsconfig.json
Normal file
14
packages/svelte/tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"types": ["@testing-library/jest-dom"],
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte", "tests/**/*.ts"],
|
||||||
|
}
|
||||||
19
packages/svelte/vitest.config.ts
Normal file
19
packages/svelte/vitest.config.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
// @ts-expect-error - type mismatch
|
||||||
|
export default defineConfig(({ mode }) => ({
|
||||||
|
plugins: [
|
||||||
|
svelte({
|
||||||
|
compilerOptions: { hmr: false },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
conditions: mode === 'test' ? ['browser'] : [],
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
setupFiles: './tests/setupVitest.ts',
|
||||||
|
},
|
||||||
|
}));
|
||||||
2581
pnpm-lock.yaml
generated
2581
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ function pascalToKebabNextJSFlavour(str) {
|
|||||||
const currentDir = getCurrentDirPath(import.meta.url);
|
const currentDir = getCurrentDirPath(import.meta.url);
|
||||||
const ICONS_DIR = path.resolve(currentDir, '../icons');
|
const ICONS_DIR = path.resolve(currentDir, '../icons');
|
||||||
|
|
||||||
const svgFiles = readSvgDirectory(ICONS_DIR);
|
const svgFiles = await readSvgDirectory(ICONS_DIR);
|
||||||
|
|
||||||
const iconNames = svgFiles.map((icon) => icon.split('.')[0]).reverse();
|
const iconNames = svgFiles.map((icon) => icon.split('.')[0]).reverse();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user