mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-23 20:49:24 +01:00
Compare commits
15 Commits
angular-pa
...
package/ic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bb9c9e059 | ||
|
|
3b0c39cf13 | ||
|
|
76861c621f | ||
|
|
4869c6409a | ||
|
|
eae3dc5f94 | ||
|
|
00954a6203 | ||
|
|
d152818621 | ||
|
|
abff584694 | ||
|
|
5d8110882d | ||
|
|
2ea256381c | ||
|
|
b88bcae614 | ||
|
|
1bbcaf8c1c | ||
|
|
68ea9b2736 | ||
|
|
620b478a2e | ||
|
|
6c3bd53c35 |
10
.github/ISSUE_TEMPLATE/02_bug_report.yml
vendored
10
.github/ISSUE_TEMPLATE/02_bug_report.yml
vendored
@@ -13,19 +13,17 @@ body:
|
|||||||
description: Which Lucide packages are affected? You may select more than one.
|
description: Which Lucide packages are affected? You may select more than one.
|
||||||
options:
|
options:
|
||||||
- label: lucide
|
- label: lucide
|
||||||
- label: lucide-angular (old version)
|
- label: lucide-angular
|
||||||
- label: '@lucide/angular (new version)'
|
|
||||||
- label: '@lucide/astro'
|
|
||||||
- label: lucide-flutter
|
- label: lucide-flutter
|
||||||
- label: lucide-preact
|
- label: lucide-preact
|
||||||
- label: lucide-react
|
- label: lucide-react
|
||||||
- label: lucide-react-native
|
- label: lucide-react-native
|
||||||
- label: lucide-solid
|
- label: lucide-solid
|
||||||
- label: lucide-static
|
- label: lucide-svelte
|
||||||
- label: lucide-svelte (old version)
|
|
||||||
- label: '@lucide/svelte (new version)'
|
|
||||||
- label: lucide-vue
|
- label: lucide-vue
|
||||||
- label: lucide-vue-next
|
- label: lucide-vue-next
|
||||||
|
- label: lucide-astro
|
||||||
|
- label: '@lucide/icons'
|
||||||
- label: Figma plugin
|
- label: Figma plugin
|
||||||
- label: source/main
|
- label: source/main
|
||||||
- label: other/not relevant
|
- label: other/not relevant
|
||||||
|
|||||||
11
.github/ISSUE_TEMPLATE/04_feature_request.yml
vendored
11
.github/ISSUE_TEMPLATE/04_feature_request.yml
vendored
@@ -13,23 +13,20 @@ body:
|
|||||||
description: Which Lucide project do you wish this feature were added to? You may select more than one.
|
description: Which Lucide project do you wish this feature were added to? You may select more than one.
|
||||||
options:
|
options:
|
||||||
- label: lucide
|
- label: lucide
|
||||||
- label: lucide-angular (old version)
|
- label: lucide-angular
|
||||||
- label: '@lucide/angular (new version)'
|
|
||||||
- label: '@lucide/astro'
|
|
||||||
- label: lucide-flutter
|
- label: lucide-flutter
|
||||||
- label: lucide-preact
|
- label: lucide-preact
|
||||||
- label: lucide-react
|
- label: lucide-react
|
||||||
- label: lucide-react-native
|
- label: lucide-react-native
|
||||||
- label: lucide-solid
|
- label: lucide-solid
|
||||||
- label: lucide-static
|
- label: lucide-svelte
|
||||||
- label: lucide-svelte (old version)
|
|
||||||
- label: '@lucide/svelte (new version)'
|
|
||||||
- label: lucide-vue
|
- label: lucide-vue
|
||||||
- label: lucide-vue-next
|
- label: lucide-vue-next
|
||||||
|
- label: lucide-astro
|
||||||
|
- label: '@lucide/icons'
|
||||||
- label: Figma plugin
|
- label: Figma plugin
|
||||||
- label: all JS packages
|
- label: all JS packages
|
||||||
- label: site
|
- label: site
|
||||||
- label: other/not relevant
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
7
.github/labeler.yml
vendored
7
.github/labeler.yml
vendored
@@ -59,7 +59,6 @@
|
|||||||
🅰️ angular package:
|
🅰️ angular package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/angular/*'
|
|
||||||
- 'packages/lucide-angular/*'
|
- 'packages/lucide-angular/*'
|
||||||
|
|
||||||
# For changes in the lucide preact package
|
# For changes in the lucide preact package
|
||||||
@@ -86,6 +85,12 @@
|
|||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/astro/*'
|
- 'packages/astro/*'
|
||||||
|
|
||||||
|
# For changes in the @lucide/icons package
|
||||||
|
❇️ lucide-icons:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- 'packages/lucide-icons/*'
|
||||||
|
|
||||||
# For changes in the lucide static package
|
# For changes in the lucide static package
|
||||||
🪨 static package:
|
🪨 static package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
name: Lucide Angular checks
|
name: Lucide Icons Checks
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- packages/angular/**
|
- packages/icons/**
|
||||||
|
- packages/shared/**
|
||||||
- tools/build-icons/**
|
- tools/build-icons/**
|
||||||
|
- tools/rollup-plugins/**
|
||||||
- pnpm-lock.yaml
|
- pnpm-lock.yaml
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -22,7 +24,7 @@ jobs:
|
|||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: pnpm --filter @lucide/angular build
|
run: pnpm --filter @lucide/icons build
|
||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -38,4 +40,4 @@ jobs:
|
|||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: pnpm --filter @lucide/angular test
|
run: pnpm --filter @lucide/icons test
|
||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -58,9 +58,9 @@ jobs:
|
|||||||
'lucide-preact',
|
'lucide-preact',
|
||||||
'lucide-solid',
|
'lucide-solid',
|
||||||
'lucide-svelte',
|
'lucide-svelte',
|
||||||
'@lucide/angular',
|
|
||||||
'@lucide/astro',
|
'@lucide/astro',
|
||||||
'@lucide/svelte',
|
'@lucide/svelte',
|
||||||
|
'@lucide/icons',
|
||||||
'@lucide/vue',
|
'@lucide/vue',
|
||||||
]
|
]
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -87,24 +87,8 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"@lucide/angular": {
|
|
||||||
"order": 6,
|
|
||||||
"icon": "angular",
|
|
||||||
"shields": [
|
|
||||||
{
|
|
||||||
"alt": "npm",
|
|
||||||
"src": "https://img.shields.io/npm/v/@lucide/angular",
|
|
||||||
"href": "https://www.npmjs.com/package/@lucide/angular"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alt": "npm",
|
|
||||||
"src": "https://img.shields.io/npm/dw/@lucide/angular",
|
|
||||||
"href": "https://www.npmjs.com/package/@lucide/angular"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lucide-angular": {
|
"lucide-angular": {
|
||||||
"order": 7,
|
"order": 6,
|
||||||
"icon": "angular",
|
"icon": "angular",
|
||||||
"shields": [
|
"shields": [
|
||||||
{
|
{
|
||||||
@@ -120,7 +104,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-preact": {
|
"lucide-preact": {
|
||||||
"order": 8,
|
"order": 7,
|
||||||
"icon": "preact",
|
"icon": "preact",
|
||||||
"shields": [
|
"shields": [
|
||||||
{
|
{
|
||||||
@@ -138,7 +122,7 @@
|
|||||||
"@lucide/astro": {
|
"@lucide/astro": {
|
||||||
"docsAlias": "lucide-astro",
|
"docsAlias": "lucide-astro",
|
||||||
"packageDirname": "astro",
|
"packageDirname": "astro",
|
||||||
"order": 9,
|
"order": 8,
|
||||||
"icon": "astro",
|
"icon": "astro",
|
||||||
"iconDark": "astro-dark",
|
"iconDark": "astro-dark",
|
||||||
"shields": [
|
"shields": [
|
||||||
@@ -155,7 +139,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-static": {
|
"lucide-static": {
|
||||||
"order": 10,
|
"order": 9,
|
||||||
"icon": "svg",
|
"icon": "svg",
|
||||||
"shields": [
|
"shields": [
|
||||||
{
|
{
|
||||||
@@ -169,5 +153,23 @@
|
|||||||
"href": "https://www.npmjs.com/package/lucide-static"
|
"href": "https://www.npmjs.com/package/lucide-static"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"@lucide/icons": {
|
||||||
|
"docsAlias": "icons",
|
||||||
|
"packageDirname": "icons",
|
||||||
|
"order": 10,
|
||||||
|
"icon": "ts",
|
||||||
|
"shields": [
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/@lucide/icons",
|
||||||
|
"href": "https://www.npmjs.com/package/@lucide/icons"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/@lucide/icons",
|
||||||
|
"href": "https://www.npmjs.com/package/@lucide/icons"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,41 +69,45 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
|||||||
link: '/guide/packages/lucide',
|
link: '/guide/packages/lucide',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'React',
|
text: 'Lucide React',
|
||||||
link: '/guide/packages/lucide-react',
|
link: '/guide/packages/lucide-react',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Vue',
|
text: 'Lucide Vue',
|
||||||
link: '/guide/packages/lucide-vue',
|
link: '/guide/packages/lucide-vue',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Svelte',
|
text: 'Lucide Svelte',
|
||||||
link: '/guide/packages/lucide-svelte',
|
link: '/guide/packages/lucide-svelte',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Solid',
|
text: 'Lucide Solid',
|
||||||
link: '/guide/packages/lucide-solid',
|
link: '/guide/packages/lucide-solid',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'React Native',
|
text: 'Lucide React Native',
|
||||||
link: '/guide/packages/lucide-react-native',
|
link: '/guide/packages/lucide-react-native',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Angular',
|
text: 'Lucide Angular',
|
||||||
link: '/guide/packages/angular',
|
link: '/guide/packages/lucide-angular',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Preact',
|
text: 'Lucide Preact',
|
||||||
link: '/guide/packages/lucide-preact',
|
link: '/guide/packages/lucide-preact',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Astro',
|
text: 'Lucide Astro',
|
||||||
link: '/guide/packages/lucide-astro',
|
link: '/guide/packages/lucide-astro',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Static',
|
text: 'Lucide Static',
|
||||||
link: '/guide/packages/lucide-static',
|
link: '/guide/packages/lucide-static',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: 'Icon data & helpers',
|
||||||
|
link: '/guide/packages/icons',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export default {
|
|||||||
label: 'Lucide documentation for Preact',
|
label: 'Lucide documentation for Preact',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'angular',
|
name: 'lucide-angular',
|
||||||
logo: '/framework-logos/angular.svg',
|
logo: '/framework-logos/angular.svg',
|
||||||
label: 'Lucide documentation for Angular',
|
label: 'Lucide documentation for Angular',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -79,6 +79,16 @@ declare module "lucide-react-native" {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```ts [@lucide-icons]
|
||||||
|
declare module "@lucide/icons" {
|
||||||
|
// Prefixed import names
|
||||||
|
export * from "@lucide/icons/dist/lucide-icons.prefixed";
|
||||||
|
// or
|
||||||
|
// Suffixed import names
|
||||||
|
export * from "@lucide/icons/dist/lucide-icons.suffixed";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Place this in your project root or in a folder where your tsconfig.json is located, or locate it in your defined type directory.
|
Place this in your project root or in a folder where your tsconfig.json is located, or locate it in your defined type directory.
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ However, not everyone can understand them easily. Read more about [how to use Lu
|
|||||||
|
|
||||||
## Official Packages
|
## Official Packages
|
||||||
|
|
||||||
Lucide's official packages are designed to work on different platforms, making it easier for users to integrate icons into their projects. The packages are available for various technologies, including [Web (Vanilla)](https://lucide.dev/guide/packages/lucide), [React](https://lucide.dev/guide/packages/lucide-react), [React Native](https://lucide.dev/guide/packages/lucide-react-native), [Vue](https://lucide.dev/guide/packages/lucide-vue), [Vue 3](https://lucide.dev/guide/packages/lucide-vue-next), [Svelte](https://lucide.dev/guide/packages/lucide-svelte), [Preact](https://lucide.dev/guide/packages/lucide-preact), [Solid](https://lucide.dev/guide/packages/lucide-solid), [Angular](https://lucide.dev/guide/packages/angular), [Astro](https://lucide.dev/guide/packages/lucide-astro), and [NodeJS](https://lucide.dev/guide/packages/lucide-static#nodejs).
|
Lucide's official packages are designed to work on different platforms, making it easier for users to integrate icons into their projects. The packages are available for various technologies, including [Web (Vanilla)](https://lucide.dev/guide/packages/lucide), [React](https://lucide.dev/guide/packages/lucide-react), [React Native](https://lucide.dev/guide/packages/lucide-react-native), [Vue](https://lucide.dev/guide/packages/lucide-vue), [Vue 3](https://lucide.dev/guide/packages/lucide-vue-next), [Svelte](https://lucide.dev/guide/packages/lucide-svelte), [Preact](https://lucide.dev/guide/packages/lucide-preact), [Solid](https://lucide.dev/guide/packages/lucide-solid), [Angular](https://lucide.dev/guide/packages/lucide-angular), [Astro](https://lucide.dev/guide/packages/lucide-astro), and [NodeJS](https://lucide.dev/guide/packages/lucide-static#nodejs).
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
|
|||||||
@@ -1,277 +0,0 @@
|
|||||||
# `@lucide/angular`
|
|
||||||
|
|
||||||
::: warning
|
|
||||||
This documentation is for `@lucide/angular`.
|
|
||||||
|
|
||||||
To learn about our legacy package for Angular, please refer to [`lucide-angular`](./lucide-angular).
|
|
||||||
:::
|
|
||||||
|
|
||||||
A standalone, signal-based, zoneless implementation of Lucide icons for Angular.
|
|
||||||
|
|
||||||
**What you can accomplish:**
|
|
||||||
- Use icons as standalone Angular components with full dependency injection support
|
|
||||||
- Configure icons globally through modern Angular providers
|
|
||||||
- Integrate with Angular's reactive forms and data binding
|
|
||||||
- Build scalable applications with tree-shaken icons and lazy loading support
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
This package requires Angular 17+ and uses standalone components, signals, and zoneless change detection.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
::: code-group
|
|
||||||
|
|
||||||
```sh [pnpm]
|
|
||||||
pnpm add @lucide/angular
|
|
||||||
```
|
|
||||||
|
|
||||||
```sh [yarn]
|
|
||||||
yarn add @lucide/angular
|
|
||||||
```
|
|
||||||
|
|
||||||
```sh [npm]
|
|
||||||
npm install @lucide/angular
|
|
||||||
```
|
|
||||||
|
|
||||||
```sh [bun]
|
|
||||||
bun add @lucide/angular
|
|
||||||
```
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
## How to use
|
|
||||||
|
|
||||||
### Standalone icons
|
|
||||||
|
|
||||||
Every icon can be imported as a ready-to-use standalone component:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<svg lucideFileText></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts{2,7}
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
import { LucideFileText } from '@lucide/angular';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-foobar',
|
|
||||||
templateUrl: './foobar.html',
|
|
||||||
imports: [LucideFileText],
|
|
||||||
})
|
|
||||||
export class Foobar { }
|
|
||||||
```
|
|
||||||
|
|
||||||
::: tip
|
|
||||||
Standalone icon components use the selector `svg[lucide{PascalCaseIconName}]`.
|
|
||||||
|
|
||||||
This ensures minimal bloating of the DOM and the ability to directly manipulate all attributes of the resulting SVG element.
|
|
||||||
:::
|
|
||||||
|
|
||||||
### Dynamic icon component
|
|
||||||
|
|
||||||
You may also use the dynamic `LucideIcon` component to dynamically render icons.
|
|
||||||
|
|
||||||
#### With tree-shaken imports
|
|
||||||
|
|
||||||
You may pass imported icons directly to the component:
|
|
||||||
|
|
||||||
```html{3}
|
|
||||||
@for (item of items) {
|
|
||||||
<a navbarItem [routerLink]="item.routerLink">
|
|
||||||
<svg [lucideIcon]="item.icon"></svg>
|
|
||||||
{{ item.title }}
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts{2,8,14,19}
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
import { LucideIcon, LucideHouse, LucideUsersRound } from '@lucide/angular';
|
|
||||||
import { NavbarItem, NavbarItemModel } from './navbar-item';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-navbar',
|
|
||||||
templateUrl: './navbar.html',
|
|
||||||
imports: [LucideIcon, NavbarItem],
|
|
||||||
})
|
|
||||||
export class Navbar {
|
|
||||||
readonly items: NavbarItemModel[] = [
|
|
||||||
{
|
|
||||||
title: 'Home',
|
|
||||||
icon: LucideHouse,
|
|
||||||
routerLink: [''],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Users',
|
|
||||||
icon: LucideUsersRound,
|
|
||||||
routerLink: ['admin/users'],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### With icons provided via dependency injection
|
|
||||||
|
|
||||||
Alternatively, the component also accepts string inputs.
|
|
||||||
|
|
||||||
To use icons this way, first, you have to provide icons via `provideLucideIcons`:
|
|
||||||
|
|
||||||
:::code-group
|
|
||||||
```ts{7-10} [app.config.ts]
|
|
||||||
import { ApplicationConfig } from '@angular/core';
|
|
||||||
import { provideLucideIcons, LucideCircleCheck, LucideCircleX } from '@lucide/angular';
|
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
|
||||||
providers: [
|
|
||||||
// ...
|
|
||||||
provideLucideIcons([
|
|
||||||
LucideCircleCheck,
|
|
||||||
LucideCircleX,
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
```html [foobar.html]
|
|
||||||
<svg lucideIcon="circle-check"></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts{7} [foobar.ts]
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
import { LucideIcon } from '@lucide/angular';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-foobar',
|
|
||||||
templateUrl: './template-url',
|
|
||||||
imports: [LucideIcon],
|
|
||||||
})
|
|
||||||
export class Foobar { }
|
|
||||||
```
|
|
||||||
:::
|
|
||||||
|
|
||||||
::: tip
|
|
||||||
For optimal bundle size, provide icons at the highest appropriate level in your application.
|
|
||||||
|
|
||||||
Providing all icons at the root level may increase your initial bundle size, while providing them at feature module level enables better code splitting.
|
|
||||||
:::
|
|
||||||
|
|
||||||
::: warning
|
|
||||||
While you may provide your icons at any level of the dependency injection tree, be aware that [Angular's DI system is hierarchical](https://angular.dev/guide/di/defining-dependency-providers#injector-hierarchy-in-angular): `LucideIcon` will only have access to the icons provided closest to it in the tree.
|
|
||||||
:::
|
|
||||||
|
|
||||||
## Accessible labels
|
|
||||||
|
|
||||||
You can use the `title` input property to set the [accessible name element](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/title) on the SVG:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<svg lucideIcon="house" title="Go to dashboard"></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
This will result in the following output:
|
|
||||||
|
|
||||||
```html{2}
|
|
||||||
<svg class="lucide lucide-house" ...>
|
|
||||||
<title>Go to dashboard</title>
|
|
||||||
<!-- SVG paths -->
|
|
||||||
</svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Props
|
|
||||||
|
|
||||||
You can pass additional props to adjust the icon appearance.
|
|
||||||
|
|
||||||
| name | type | default |
|
|
||||||
|-----------------------|-----------|--------------|
|
|
||||||
| `size` | *number* | 24 |
|
|
||||||
| `color` | *string* | currentColor |
|
|
||||||
| `strokeWidth` | *number* | 2 |
|
|
||||||
| `absoluteStrokeWidth` | *boolean* | false |
|
|
||||||
|
|
||||||
```html
|
|
||||||
<svg lucideHouse size="48" color="red" strokeWidth="1"></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Global configuration
|
|
||||||
|
|
||||||
You can use `provideLucideConfig` to configure the default property values as defined above:
|
|
||||||
|
|
||||||
```ts{2,7-9}
|
|
||||||
import { ApplicationConfig } from '@angular/core';
|
|
||||||
import { provideLucideConfig } from '@lucide/angular';
|
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
|
||||||
providers: [
|
|
||||||
// ...
|
|
||||||
provideLucideConfig({
|
|
||||||
strokeWidth: 1.5
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Styling via CSS
|
|
||||||
|
|
||||||
Icons can also be styled by using custom CSS classes:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<svg lucideHousePlus class="my-icon"></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
```css
|
|
||||||
svg.my-icon {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
stroke-width: 3;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## With Lucide lab or custom icons
|
|
||||||
|
|
||||||
[Lucide lab](https://github.com/lucide-icons/lucide-lab) is a collection of icons that are not part of the Lucide main library.
|
|
||||||
|
|
||||||
While they aren't provided as standalone components, they can be still be passed to the `LucideIcon` component the same way as official icons:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- Directly as LucideIconData: -->
|
|
||||||
<svg [lucideIcon]="CoconutIcon"></svg>
|
|
||||||
|
|
||||||
<!-- As a provided icon by name: -->
|
|
||||||
<svg lucideIcon="coconut"></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts{2,6-7,11-12}
|
|
||||||
import { provideLucideIcons } from '@lucide/angular';
|
|
||||||
import { coconut } from '@lucide/lab';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
templateUrl: './foobar.html',
|
|
||||||
// For using by name via provider:
|
|
||||||
providers: [provideLucideIcons({ coconut })],
|
|
||||||
imports: [LucideIcon]
|
|
||||||
})
|
|
||||||
export class Foobar {
|
|
||||||
// For passing directly as LucideIconData:
|
|
||||||
readonly CoconutIcon = coconut;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### The icon is not being displayed
|
|
||||||
If using per-icon-components:
|
|
||||||
1. Ensure that the icon component is being imported, if using per-icon-components
|
|
||||||
2. Check that the icon name matches exactly (case-sensitive)
|
|
||||||
|
|
||||||
If using the dynamic component:
|
|
||||||
1. Ensure the icon is provided via `provideLucideIcons()` if using string names
|
|
||||||
2. Verify the icon is imported from `@lucide/angular` and not the legacy package
|
|
||||||
|
|
||||||
### TypeScript errors?
|
|
||||||
Make sure you're importing from `@lucide/angular` and not `lucide-angular`.
|
|
||||||
|
|
||||||
### Icons render with wrong defaults
|
|
||||||
Ensure `provideLucideConfig()` is used at the right level.
|
|
||||||
|
|
||||||
## Migration guide
|
|
||||||
Migrating from `lucide-angular`? Read our [comprehensive migration guide](https://github.com/lucide-icons/lucide/blob/main/packages/angular/MIGRATION.md).
|
|
||||||
172
docs/guide/packages/icons.md
Normal file
172
docs/guide/packages/icons.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# @lucide/icons
|
||||||
|
|
||||||
|
`@lucide/icons` is a helper library that exports Lucide **icon data** in a tree-shakable format, also providing utilities for dynamic importing icons.
|
||||||
|
|
||||||
|
It intentionally ships **no real rendering logic or components** — other packages (for example [`@lucide/angular`](http://npmjs.com/package/@lucide/angular)) can consume this data to render icons in their respective
|
||||||
|
frameworks. You can also use this package to build third-party integrations for frameworks we don't (yet) support.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
::: code-group
|
||||||
|
|
||||||
|
```sh [pnpm]
|
||||||
|
pnpm install @lucide/icons
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh [yarn]
|
||||||
|
yarn add @lucide/icons
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh [npm]
|
||||||
|
npm install @lucide/icons
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh [bun]
|
||||||
|
bun add @lucide/icons
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Icon data format
|
||||||
|
|
||||||
|
Each icon is described by the following interface:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export type LucideIconData = {
|
||||||
|
name: string;
|
||||||
|
node: LucideIconNode[];
|
||||||
|
} & (
|
||||||
|
| { size: number }
|
||||||
|
| { width: number; height: number; }
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
| name | type | description |
|
||||||
|
|------------------------------|--------------------|--------------------------------------------------------------------|
|
||||||
|
| `name` | `string` | The name of the icon. |
|
||||||
|
| `node` | `LucideIconNode[]` | SVG child nodes as `[tagName, attributes]` tuples. |
|
||||||
|
| `size` or `width` & `height` | `number` | The dimensions of the icon (`size` is shorthand for square icons). |
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
Icons can be imported individually. Only the icons you import end up referenced by your application code — the rest will be eliminated by tree-shaking.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { House } from '@lucide/icons';
|
||||||
|
// House is icon data (not a rendered component).
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building icons
|
||||||
|
|
||||||
|
`@lucide/icons` ships small helpers that convert Lucide icon data into different render-ready outputs.
|
||||||
|
All builders accept the same `params` object (`LucideBuildParams`) to customize the generated SVG.
|
||||||
|
|
||||||
|
### Build parameters
|
||||||
|
|
||||||
|
The following parameters are supported (names reflect the current implementation):
|
||||||
|
|
||||||
|
| param | type | effect |
|
||||||
|
|-----------------------|--------------------------|------------------------------------------------------------------------------------|
|
||||||
|
| `color` | `string` | Sets `stroke` (defaults to `currentColor`). |
|
||||||
|
| `size` | `number` | Sets both `width` and `height` (defaults to 24). |
|
||||||
|
| `width` | `number` | Sets `width` only. |
|
||||||
|
| `height` | `number` | Sets `height` only. |
|
||||||
|
| `strokeWidth` | `number` | Sets `stroke-width` (defaults to 2). |
|
||||||
|
| `absoluteStrokeWidth` | `boolean` | Adds [`vector-effect="non-scaling-stroke"`](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/vector-effect) to child elements. |
|
||||||
|
| `className` | `string` | Appended to the generated `class` attribute. |
|
||||||
|
| `attributes` | `Record<string, string>` | Add or override any generated SVG attributes (including `class`, `viewBox`, etc.). |
|
||||||
|
|
||||||
|
::: info
|
||||||
|
SVG attributes generated by the builders include a default Lucide setup (`xmlns`, `viewBox`, `fill="none"`, `stroke="currentColor"`, `stroke-width="2"`, `stroke-linecap="round"`, `stroke-linejoin="round"`), plus a class string of the form: `lucide lucide-{iconName}`.
|
||||||
|
:::
|
||||||
|
|
||||||
|
### `buildLucideIconNode`
|
||||||
|
|
||||||
|
Creates a root SVG node in an svgson-like format:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { buildLucideIconNode } from '@lucide/icons/builders';
|
||||||
|
import { House } from '@lucide/icons';
|
||||||
|
|
||||||
|
const node = buildLucideIconNode(House, {
|
||||||
|
size: 32,
|
||||||
|
strokeWidth: 1.5,
|
||||||
|
className: 'my-icon',
|
||||||
|
});
|
||||||
|
|
||||||
|
// -> ['svg', attributes, children]
|
||||||
|
```
|
||||||
|
|
||||||
|
This is useful if you want to plug Lucide icons into your own renderer, templating system, or framework integration.
|
||||||
|
|
||||||
|
### `buildLucideSvg`
|
||||||
|
|
||||||
|
Creates an SVG string:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { buildLucideSvg } from '@lucide/icons/builders';
|
||||||
|
import { House } from '@lucide/icons';
|
||||||
|
|
||||||
|
const svg = buildLucideSvg(House, { size: 24, color: '#111' });
|
||||||
|
```
|
||||||
|
|
||||||
|
### `buildLucideIconElement`
|
||||||
|
|
||||||
|
Creates an actual DOM element (SVG) within the provided document:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { buildLucideIconElement } from '@lucide/icons/builders';
|
||||||
|
import { House } from '@lucide/icons';
|
||||||
|
|
||||||
|
const el = buildLucideIconElement(document, House, { size: 24 });
|
||||||
|
document.body.appendChild(el);
|
||||||
|
```
|
||||||
|
|
||||||
|
### `buildLucideDataUri`
|
||||||
|
|
||||||
|
Creates a base64-encoded SVG data URI from a Lucide icon object.
|
||||||
|
|
||||||
|
This helper works in both browsers and Node.js:
|
||||||
|
- In browsers it uses `btoa` (with proper UTF-8 handling)
|
||||||
|
- In Node.js it falls back to `Buffer`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { buildLucideDataUri } from '@lucide/icons/builders';
|
||||||
|
import { House } from '@lucide/icons';
|
||||||
|
|
||||||
|
const uri = buildLucideDataUri(House, { size: 24 });
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned value can be used directly in places such as:
|
||||||
|
- `<img src="...">`
|
||||||
|
- CSS `background-image`
|
||||||
|
- Canvas drawing
|
||||||
|
- Inline data URLs in HTML or SVG
|
||||||
|
|
||||||
|
::: tip Environment notes
|
||||||
|
- The SVG is encoded as UTF-8 before base64 conversion to ensure correct handling of non-ASCII characters.
|
||||||
|
- No runtime configuration is required — the function automatically selects the appropriate encoding strategy.
|
||||||
|
- If neither `btoa` nor `Buffer` is available, an error is thrown.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Dynamic imports
|
||||||
|
|
||||||
|
Dynamic imports are useful when you only know the icon name at runtime (for example, icon names stored in a database or a CMS). For purely static use cases, prefer direct imports for the best tree-shaking results.
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
Validate `iconName` before indexing the map (and provide a fallback icon) to avoid runtime errors.
|
||||||
|
:::
|
||||||
|
## Dynamic imports
|
||||||
|
|
||||||
|
Dynamic imports are useful when the icon name is only known at runtime (for example, icon names stored in a CMS or database). For purely static usage, prefer direct imports for maximum tree-shaking.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { lucideDynamicIconImports } from '@lucide/icons/dynamic';
|
||||||
|
|
||||||
|
const name = 'house';
|
||||||
|
const icon = await lucideDynamicIconImports[name]?.();
|
||||||
|
|
||||||
|
if (!icon) {
|
||||||
|
// handle unknown icon name (fallback)
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,11 +1,5 @@
|
|||||||
# Lucide Angular
|
# Lucide Angular
|
||||||
|
|
||||||
::: warning
|
|
||||||
This documentation is for our legacy package for Angular.
|
|
||||||
|
|
||||||
For our modern, standalone-first implementation, please refer to [`@lucide/angular`](./angular).
|
|
||||||
:::
|
|
||||||
|
|
||||||
Angular components and services for Lucide icons that integrate with Angular's dependency injection and component system. Provides both traditional module-based and modern standalone component approaches for maximum flexibility in Angular applications.
|
Angular components and services for Lucide icons that integrate with Angular's dependency injection and component system. Provides both traditional module-based and modern standalone component approaches for maximum flexibility in Angular applications.
|
||||||
|
|
||||||
**What you can accomplish:**
|
**What you can accomplish:**
|
||||||
|
|||||||
4
docs/public/framework-logos/ts.svg
Normal file
4
docs/public/framework-logos/ts.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path fill="#3178C6" d="M24 0H0v24h24V0Z"/>
|
||||||
|
<path fill="#fff" fill-rule="evenodd" d="M14.11 18.797v2.588c.421.215.918.375 1.49.487a9.45 9.45 0 0 0 1.819.16 8.35 8.35 0 0 0 1.772-.179 4.407 4.407 0 0 0 1.472-.59c.421-.272.75-.628 1.003-1.07.243-.44.365-.983.365-1.63 0-.47-.065-.882-.206-1.238a2.98 2.98 0 0 0-.61-.947 4.48 4.48 0 0 0-.946-.74 11.05 11.05 0 0 0-1.247-.62c-.338-.14-.647-.27-.919-.412a4.124 4.124 0 0 1-.684-.403 1.784 1.784 0 0 1-.44-.44.928.928 0 0 1-.15-.525c0-.178.046-.338.14-.478.093-.141.225-.263.384-.366.169-.103.375-.178.619-.234.244-.057.515-.085.806-.085.216 0 .44.019.684.047.244.028.479.084.722.15.244.066.479.15.713.253.225.103.44.225.637.356v-2.418a6.524 6.524 0 0 0-1.293-.338 10.228 10.228 0 0 0-1.604-.112c-.618 0-1.2.065-1.753.197a4.42 4.42 0 0 0-1.453.618c-.422.282-.75.638-.993 1.07-.244.43-.366.955-.366 1.555 0 .77.225 1.425.666 1.978.45.544 1.125 1.004 2.024 1.388.357.15.685.29.994.431.31.14.572.281.797.44.225.16.403.32.534.498.132.178.197.384.197.61a.921.921 0 0 1-.121.468c-.085.14-.207.262-.366.375-.16.112-.366.187-.619.244a3.957 3.957 0 0 1-.862.084 4.938 4.938 0 0 1-1.67-.3 4.752 4.752 0 0 1-1.537-.872Zm-4.313-6.45h3.328V10.22H3.844v2.128h3.31v9.497h2.633v-9.497h.01Z" clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
9
docs/public/package-logos/icons.svg
Normal file
9
docs/public/package-logos/icons.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="32" fill="none" viewBox="0 0 128 32">
|
||||||
|
<rect width="128" height="32" rx="8" fill="#fff"/>
|
||||||
|
<path fill="#1b1b1f" d="M78.2 22.17a4.5 4.5 0 0 1-2.27-.55 3.7 3.7 0 0 1-1.46-1.55 5.2 5.2 0 0 1-.5-2.38c0-.9.16-1.69.5-2.37a3.87 3.87 0 0 1 3.62-2.16c.54 0 1.05.09 1.53.26s.9.44 1.27.8.66.81.87 1.37c.22.55.32 1.21.32 1.98v.63h-7.15v-1.4h5.18c0-.4-.09-.74-.25-1.05-.17-.3-.4-.55-.7-.73s-.64-.27-1.04-.27a2 2 0 0 0-1.1.3c-.32.2-.57.47-.75.8q-.255.495-.27 1.08v1.2c0 .52.1.95.28 1.31.19.36.45.64.78.83.33.2.72.29 1.17.29.3 0 .57-.04.81-.13.25-.08.46-.21.63-.38.18-.16.32-.37.4-.62l1.93.22a3 3 0 0 1-.7 1.33c-.33.37-.76.67-1.3.87-.52.2-1.12.31-1.8.31zM67.5 22.15a3.3 3.3 0 0 1-3.13-2.06 5.7 5.7 0 0 1-.47-2.44q0-1.455.48-2.46a3.34 3.34 0 0 1 4.39-1.77c.33.17.59.38.78.62.2.24.34.46.45.68h.08v-4.36h2.07V22h-2.03v-1.38H70c-.1.22-.26.44-.46.68a2.53 2.53 0 0 1-2.04.85m.57-1.68c.44 0 .8-.12 1.12-.36.3-.23.54-.57.7-1 .15-.41.23-.9.23-1.47s-.08-1.06-.24-1.48a2.1 2.1 0 0 0-.69-.97 1.8 1.8 0 0 0-1.12-.34c-.46 0-.84.12-1.15.35-.3.24-.53.57-.69 1-.15.41-.23.9-.23 1.44s.08 1.03.23 1.46c.16.42.4.76.7 1 .31.24.7.37 1.14.37M60.09 22v-8.73h2.05V22zm1.03-9.97a1.2 1.2 0 0 1-1.101-.677 1 1 0 0 1-.09-.433c0-.31.12-.57.35-.79q.36-.33.84-.33.495 0 .84.33a1.045 1.045 0 0 1 0 1.58c-.23.22-.5.32-.84.32M54.66 22.17a3.83 3.83 0 0 1-3.68-2.16 5.24 5.24 0 0 1-.5-2.34c0-.89.17-1.67.51-2.35s.82-1.2 1.44-1.59a4.16 4.16 0 0 1 2.22-.57c.7 0 1.33.13 1.88.4a3.21 3.21 0 0 1 1.87 2.74h-1.97a1.88 1.88 0 0 0-.56-1.06q-.45-.42-1.2-.42c-.41 0-.78.11-1.1.34-.32.22-.57.54-.74.96-.18.43-.27.93-.27 1.52 0 .6.1 1.1.27 1.53.17.42.41.75.73.98s.69.34 1.12.34c.3 0 .57-.05.81-.17.24-.11.45-.28.6-.5.17-.22.28-.49.34-.8h1.97a3.23 3.23 0 0 1-1.83 2.76 4.3 4.3 0 0 1-1.9.39zM46.68 18.33v-5.06h2.06V22h-2v-1.55h-.09c-.2.49-.52.89-.97 1.2-.45.3-1 .46-1.65.46a2.64 2.64 0 0 1-2.54-1.5 3.95 3.95 0 0 1-.37-1.78v-5.56h2.06v5.24c0 .55.15 1 .45 1.32.3.33.7.49 1.2.49a1.89 1.89 0 0 0 1.57-.88c.19-.3.28-.67.28-1.11M32.15 22V10.36h2.1v9.87h5.13V22z"/>
|
||||||
|
<path stroke="#1b1b1f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 16a4 4 0 1 0-8 0 8 8 0 0 0 16 0c0-3.55-1.55-6.75-4-8.94"/>
|
||||||
|
<path stroke="#f56565" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 16a4 4 0 1 0 8 0 8 8 0 0 0-16 0c0 3.58 1.57 6.8 4.06 9"/>
|
||||||
|
<path fill="#ddd" d="M92 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4"/>
|
||||||
|
<path fill="#3178c6" d="M122 6h-20v20h20z"/>
|
||||||
|
<path fill="#fff" fill-rule="evenodd" d="M113.758 21.664v2.157q.526.267 1.242.406.751.14 1.516.133c.496.003.991-.047 1.476-.15a3.7 3.7 0 0 0 1.227-.49 2.54 2.54 0 0 0 .836-.893q.303-.55.304-1.358c0-.392-.054-.735-.172-1.032a2.5 2.5 0 0 0-.508-.789 3.7 3.7 0 0 0-.788-.616 9 9 0 0 0-1.04-.517 10 10 0 0 1-.765-.343 3.4 3.4 0 0 1-.57-.336 1.5 1.5 0 0 1-.367-.367.77.77 0 0 1-.125-.437q0-.223.117-.399c.077-.117.187-.219.32-.305.14-.086.312-.148.515-.195q.308-.07.672-.07c.18 0 .367.015.57.039.203.023.399.07.602.125q.303.082.594.21c.187.086.367.188.531.297V14.72a5.5 5.5 0 0 0-1.078-.282 8.5 8.5 0 0 0-1.336-.093q-.771 0-1.461.164a3.7 3.7 0 0 0-1.211.515 2.6 2.6 0 0 0-.828.892c-.203.358-.305.796-.305 1.296 0 .641.188 1.187.555 1.648q.563.678 1.687 1.157c.298.125.571.241.828.359.259.117.477.234.665.367.187.133.335.266.445.415s.164.32.164.508a.76.76 0 0 1-.101.39 1.1 1.1 0 0 1-.305.312 1.4 1.4 0 0 1-.516.204 3.3 3.3 0 0 1-.718.07 4.1 4.1 0 0 1-1.392-.25 4 4 0 0 1-1.28-.727m-3.594-5.375h2.773v-1.772h-7.734v1.773h2.758v7.914h2.195V16.29z" clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
12
package.json
12
package.json
@@ -48,8 +48,6 @@
|
|||||||
"@types/yargs": "^17.0.33",
|
"@types/yargs": "^17.0.33",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"@vitest/coverage-v8": "4.0.12",
|
|
||||||
"@vitest/ui": "4.0.12",
|
|
||||||
"ajv-cli": "^5.0.0",
|
"ajv-cli": "^5.0.0",
|
||||||
"dotenv": "^17.0.0",
|
"dotenv": "^17.0.0",
|
||||||
"eslint": "^8.57.1",
|
"eslint": "^8.57.1",
|
||||||
@@ -61,7 +59,6 @@
|
|||||||
"eslint-import-resolver-typescript": "^3.10.1",
|
"eslint-import-resolver-typescript": "^3.10.1",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"jsdom": "^27.3.0",
|
|
||||||
"lint-staged": "^13.3.0",
|
"lint-staged": "^13.3.0",
|
||||||
"minimist": "^1.2.8",
|
"minimist": "^1.2.8",
|
||||||
"openai": "^5.8.1",
|
"openai": "^5.8.1",
|
||||||
@@ -72,7 +69,6 @@
|
|||||||
"simple-git": "^3.27.0",
|
"simple-git": "^3.27.0",
|
||||||
"svgo": "^3.3.2",
|
"svgo": "^3.3.2",
|
||||||
"svgson": "^5.3.1",
|
"svgson": "^5.3.1",
|
||||||
"vitest": "4.0.12",
|
|
||||||
"yargs": "^17.7.2",
|
"yargs": "^17.7.2",
|
||||||
"zod": "^3.25.67"
|
"zod": "^3.25.67"
|
||||||
},
|
},
|
||||||
@@ -89,13 +85,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"axios": "^1.12.0",
|
|
||||||
"cross-spawn": "7.0.5",
|
"cross-spawn": "7.0.5",
|
||||||
"fast-json-patch": "^3.1.1",
|
|
||||||
"form-data": "^4.0.4",
|
"form-data": "^4.0.4",
|
||||||
|
"fast-json-patch": "^3.1.1",
|
||||||
|
"webpack-dev-middleware": "^5.3.4",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.7.3",
|
||||||
"vite-prerender-plugin": "0.5.12",
|
"axios": "^1.12.0",
|
||||||
"webpack-dev-middleware": "^5.3.4"
|
"vite-prerender-plugin": "0.5.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
root: true,
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['*.ts'],
|
|
||||||
extends: [
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'plugin:@angular-eslint/recommended',
|
|
||||||
'plugin:@angular-eslint/template/process-inline-templates',
|
|
||||||
'prettier',
|
|
||||||
],
|
|
||||||
rules: {
|
|
||||||
'@angular-eslint/directive-selector': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
type: 'attribute',
|
|
||||||
prefix: 'lucide',
|
|
||||||
style: 'camelCase',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@angular-eslint/component-selector': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
type: 'attribute',
|
|
||||||
prefix: ['lucide'],
|
|
||||||
style: 'camelCase',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['*.html'],
|
|
||||||
extends: ['plugin:@angular-eslint/template/recommended'],
|
|
||||||
rules: {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
4
packages/angular/.vscode/extensions.json
vendored
4
packages/angular/.vscode/extensions.json
vendored
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
|
||||||
"recommendations": ["angular.ng-template"]
|
|
||||||
}
|
|
||||||
20
packages/angular/.vscode/launch.json
vendored
20
packages/angular/.vscode/launch.json
vendored
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "ng serve",
|
|
||||||
"type": "chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"preLaunchTask": "npm: start",
|
|
||||||
"url": "http://localhost:4200/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ng test",
|
|
||||||
"type": "chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"preLaunchTask": "npm: test",
|
|
||||||
"url": "http://localhost:9876/debug.html"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
42
packages/angular/.vscode/tasks.json
vendored
42
packages/angular/.vscode/tasks.json
vendored
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"type": "npm",
|
|
||||||
"script": "start",
|
|
||||||
"isBackground": true,
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "typescript",
|
|
||||||
"pattern": "$tsc",
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": {
|
|
||||||
"regexp": "(.*?)"
|
|
||||||
},
|
|
||||||
"endsPattern": {
|
|
||||||
"regexp": "bundle generation complete"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "npm",
|
|
||||||
"script": "test",
|
|
||||||
"isBackground": true,
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "typescript",
|
|
||||||
"pattern": "$tsc",
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": {
|
|
||||||
"regexp": "(.*?)"
|
|
||||||
},
|
|
||||||
"endsPattern": {
|
|
||||||
"regexp": "bundle generation complete"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
# Migrating from `lucide-angular` ⇒ `@lucide/angular`
|
|
||||||
|
|
||||||
## What changed
|
|
||||||
|
|
||||||
`@lucide/angular` moves from a module + single component based API to a more modern Angular approach:
|
|
||||||
|
|
||||||
- The library defines modern signal-based, standalone components, without zone.js based change detection.
|
|
||||||
- Icons are consumed as standalone imports (one component per icon).
|
|
||||||
- Dynamic icon registration is done via `provideLucideIcons()`, not using `NgModule`.
|
|
||||||
- Static icons use per-icon components for better tree-shaking.
|
|
||||||
- Dynamic icons still use a single dynamic component (`svg[lucideIcon]`).
|
|
||||||
- Global defaults are configured via `provideLucideConfig()`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 1 – Update dependencies
|
|
||||||
|
|
||||||
Remove `lucide-angular`, add `@lucide/angular`, see http://lucide.dev/guide/packages/angular#installation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 2 – Replace `LucideAngularModule.pick(...)` with `provideLucideIcons(...)`
|
|
||||||
|
|
||||||
> Notes:
|
|
||||||
> - Old imports like `AirVentIcon` / `AlarmClock` from `lucide-angular` should be replaced with the new per-icon exports `LucideAirVent` and `LucideAlarmClock`.
|
|
||||||
> - If you mostly used static icons, you may not need to provide them **at all**, please refer to Step 3.
|
|
||||||
|
|
||||||
### Before
|
|
||||||
|
|
||||||
#### NgModule based
|
|
||||||
```ts
|
|
||||||
import { BrowserModule, NgModule } from '@angular/core';
|
|
||||||
import { LucideAngularModule, AirVent, AlarmClock } from 'lucide-angular';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
LucideAngularModule.pick({ AirVent, AlarmClock }),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class AppModule {}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Standalone
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { ApplicationConfig } from '@angular/core';
|
|
||||||
import { LucideAngularModule, AirVent, AlarmClock } from 'lucide-angular';
|
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
|
||||||
providers: [
|
|
||||||
// ...
|
|
||||||
importProvidersFrom(LucideAngularModule.pick({ AirVent, AlarmClock })),
|
|
||||||
]
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### After
|
|
||||||
```ts
|
|
||||||
import { ApplicationConfig } from '@angular/core';
|
|
||||||
import { provideLucideIcons, LucideAirVent, LucideAlarmClock } from '@lucide/angular';
|
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
|
||||||
providers: [
|
|
||||||
// ...
|
|
||||||
provideLucideIcons([
|
|
||||||
LucideAirVent,
|
|
||||||
LucideAlarmClock,
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 3 – Replace `<lucide-angular>` / `<lucide-icon>` / `<i-lucide>` / `<span-lucide>`
|
|
||||||
|
|
||||||
The legacy package rendered everything through a single component. All of these selectors must be migrated to `<svg>` usage.
|
|
||||||
|
|
||||||
### A. Static icons by name
|
|
||||||
|
|
||||||
If the icon is known at build time, just use a static import:
|
|
||||||
|
|
||||||
#### Before
|
|
||||||
```html
|
|
||||||
<lucide-angular name="circle-check"></lucide-angular>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### After
|
|
||||||
```html
|
|
||||||
<svg lucideCircleCheck></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
### B. Static icons with icon data binding
|
|
||||||
|
|
||||||
#### Before
|
|
||||||
```ts
|
|
||||||
import { CircleCheck } from 'lucide-angular';
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<lucide-icon [img]="CircleCheck"></lucide-icon>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### After
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { LucideCircleCheck } from '@lucide/angular';
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<svg lucideCircleCheck></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
...and import `LucideCircleCheck` from `@lucide/angular`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### C. Dynamic icons
|
|
||||||
|
|
||||||
If the icon varies at runtime, use the dynamic component:
|
|
||||||
|
|
||||||
#### Before
|
|
||||||
```html
|
|
||||||
<lucide-icon [name]="item.icon"></lucide-icon>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### After
|
|
||||||
```html
|
|
||||||
<svg [lucideIcon]="item.icon"></svg>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 4 – Replace `LucideIconConfig` with `provideLucideConfig()`
|
|
||||||
|
|
||||||
### Before
|
|
||||||
```ts
|
|
||||||
import { inject } from '@angular/core';
|
|
||||||
import { LucideIconConfig } from 'lucide-angular';
|
|
||||||
|
|
||||||
inject(LucideIconConfig).size = 12;
|
|
||||||
```
|
|
||||||
|
|
||||||
### After
|
|
||||||
```ts
|
|
||||||
import { provideLucideConfig } from '@lucide/angular';
|
|
||||||
|
|
||||||
providers: [
|
|
||||||
provideLucideConfig({ size: 12 }),
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Where to place it
|
|
||||||
|
|
||||||
- App-wide: `AppModule.providers` or `bootstrapApplication(...providers)`
|
|
||||||
- Feature-level: feature module providers
|
|
||||||
- Component-level (standalone): component `providers`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### The icon is not being displayed
|
|
||||||
If using per-icon-components:
|
|
||||||
1. Ensure that the icon component is being imported, if using per-icon-components
|
|
||||||
2. Check that the icon name matches exactly (case-sensitive)
|
|
||||||
|
|
||||||
If using the dynamic component:
|
|
||||||
1. Ensure the icon is provided via `provideLucideIcons()` if using string names
|
|
||||||
2. Verify the icon is imported from `@lucide/angular` and not the legacy package
|
|
||||||
|
|
||||||
### TypeScript errors?
|
|
||||||
Make sure you're importing from `@lucide/angular` and not `lucide-angular`.
|
|
||||||
|
|
||||||
### Icons render with wrong defaults
|
|
||||||
Ensure `provideLucideConfig()` is used at the right level.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## TL;DR
|
|
||||||
- `LucideAngularModule` ⇒ static: removed; dynamic: `LucideIcon`
|
|
||||||
- `LucideAngularModule.pick(...)` ⇒ `provideLucideIcons(...)`
|
|
||||||
- `<lucide-angular name="foo-bar">` ⇒ `<svg lucideFooBar>`
|
|
||||||
- `<lucide-icon [name]="expr">` ⇒ `<svg [lucideIcon]="expr">`
|
|
||||||
- `<lucide-icon [img]="expr">` ⇒ `<svg [lucideIcon]="expr">`
|
|
||||||
- `LucideIconConfig` ⇒ `provideLucideConfig(...)`
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
||||||
"version": 1,
|
|
||||||
"cli": {
|
|
||||||
"packageManager": "pnpm"
|
|
||||||
},
|
|
||||||
"newProjectRoot": ".",
|
|
||||||
"projects": {
|
|
||||||
"@lucide/angular": {
|
|
||||||
"projectType": "library",
|
|
||||||
"root": ".",
|
|
||||||
"sourceRoot": "./src",
|
|
||||||
"prefix": "lib",
|
|
||||||
"architect": {
|
|
||||||
"build": {
|
|
||||||
"builder": "@angular/build:ng-packagr",
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"tsConfig": "./tsconfig.lib.prod.json"
|
|
||||||
},
|
|
||||||
"development": {
|
|
||||||
"tsConfig": "./tsconfig.lib.json"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"defaultConfiguration": "production"
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"builder": "@angular/build:unit-test",
|
|
||||||
"options": {
|
|
||||||
"tsConfig": "./tsconfig.spec.json",
|
|
||||||
"coverage": true,
|
|
||||||
"coverageReporters": ["html", "lcov"],
|
|
||||||
"coverageExclude": ["src/icons/*"],
|
|
||||||
"coverageThresholds": {
|
|
||||||
"statements": 80,
|
|
||||||
"branches": 80,
|
|
||||||
"functions": 80,
|
|
||||||
"lines": 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"builder": "@angular-eslint/builder:lint",
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./node_modules/ng-packagr/ng-package.schema.json",
|
|
||||||
"dest": "./dist",
|
|
||||||
"lib": {
|
|
||||||
"entryFile": "./src/public-api.ts"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@lucide/angular",
|
|
||||||
"description": "A Lucide icon library package for Angular applications.",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"author": "SMAH1",
|
|
||||||
"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/angular"
|
|
||||||
},
|
|
||||||
"publishConfig": {
|
|
||||||
"directory": "dist"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"ng": "ng",
|
|
||||||
"watch": "ng build --watch --configuration development",
|
|
||||||
"prebuild": "pnpm clean && pnpm copy:license && pnpm build:icons",
|
|
||||||
"build": "pnpm prebuild && pnpm build:ng",
|
|
||||||
"copy:license": "cp ../../LICENSE ./LICENSE",
|
|
||||||
"clean": "rm -rf dist && rm -rf ./src/icons/*.ts",
|
|
||||||
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mts --renderUniqueKey --iconFileExtension=.ts --exportFileName=lucide-angular.ts --useDefaultExports=0",
|
|
||||||
"build:ng": "ng build --configuration production",
|
|
||||||
"test": "pnpm prebuild && ng test --no-watch",
|
|
||||||
"test:watch": "ng test",
|
|
||||||
"lint": "npx eslint 'src/**/*.{js,jsx,ts,tsx,html,css,scss}' --quiet --fix",
|
|
||||||
"e2e": "ng e2e",
|
|
||||||
"version": "pnpm version --git-tag-version=false"
|
|
||||||
},
|
|
||||||
"prettier": {
|
|
||||||
"printWidth": 100,
|
|
||||||
"singleQuote": true,
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": "*.html",
|
|
||||||
"options": {
|
|
||||||
"parser": "angular"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"private": true,
|
|
||||||
"devDependencies": {
|
|
||||||
"@angular-eslint/builder": "~21.1.0",
|
|
||||||
"@angular-eslint/eslint-plugin": "~21.1.0",
|
|
||||||
"@angular-eslint/eslint-plugin-template": "~21.1.0",
|
|
||||||
"@angular-eslint/schematics": "~21.1.0",
|
|
||||||
"@angular-eslint/template-parser": "~21.1.0",
|
|
||||||
"@angular/build": "^21.0.3",
|
|
||||||
"@angular/cli": "^21.0.3",
|
|
||||||
"@angular/common": "^21.0.0",
|
|
||||||
"@angular/compiler": "^21.0.0",
|
|
||||||
"@angular/compiler-cli": "^21.0.0",
|
|
||||||
"@angular/core": "^21.0.0",
|
|
||||||
"@angular/forms": "^21.0.0",
|
|
||||||
"@angular/platform-browser": "^21.0.0",
|
|
||||||
"@angular/router": "^21.0.0",
|
|
||||||
"@lucide/build-icons": "workspace:*",
|
|
||||||
"@lucide/helpers": "workspace:*",
|
|
||||||
"@vitest/browser-playwright": "^4.0.12",
|
|
||||||
"angular-eslint": "21.1.0",
|
|
||||||
"ng-packagr": "^21.0.0",
|
|
||||||
"rxjs": "~7.8.0",
|
|
||||||
"tslib": "^2.3.0",
|
|
||||||
"typescript": "~5.9.2"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@angular/common": "17.x - 21.x",
|
|
||||||
"@angular/core": "17.x - 21.x"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import base64SVG from '@lucide/build-icons/utils/base64SVG';
|
|
||||||
import defineExportTemplate from '@lucide/build-icons/utils/defineExportTemplate';
|
|
||||||
import { toPascalCase } from '@lucide/helpers';
|
|
||||||
|
|
||||||
export default defineExportTemplate(async ({
|
|
||||||
componentName,
|
|
||||||
iconName,
|
|
||||||
children,
|
|
||||||
getSvg,
|
|
||||||
deprecated,
|
|
||||||
deprecationReason,
|
|
||||||
aliases = [],
|
|
||||||
}) => {
|
|
||||||
const svgContents = await getSvg();
|
|
||||||
const svgBase64 = base64SVG(svgContents);
|
|
||||||
const angularComponentName = `Lucide${componentName}`;
|
|
||||||
const selectors = [`svg[lucide${toPascalCase(iconName)}]`];
|
|
||||||
const aliasComponentNames: string[] = [];
|
|
||||||
for (const alias of aliases) {
|
|
||||||
const aliasName = typeof alias === 'string' ? alias : alias.name;
|
|
||||||
const aliasComponentName = `Lucide${toPascalCase(aliasName)}`;
|
|
||||||
const aliasSelector = `svg[lucide${toPascalCase(aliasName)}]`;
|
|
||||||
if (!selectors.includes(aliasSelector)) {
|
|
||||||
selectors.push(aliasSelector);
|
|
||||||
}
|
|
||||||
if (aliasComponentName !== angularComponentName && !aliasComponentNames.includes(aliasComponentName)) {
|
|
||||||
aliasComponentNames.push(aliasComponentName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return `\
|
|
||||||
import { LucideIconData } from '../types';
|
|
||||||
import { LucideIconBase } from '../lucide-icon-base';
|
|
||||||
import { Component, signal } from '@angular/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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/angular - Documentation
|
|
||||||
*
|
|
||||||
* @param {Object} props - Lucide icons props and any valid SVG attribute
|
|
||||||
* ${deprecated ? `@deprecated ${deprecationReason}` : ''}
|
|
||||||
*/
|
|
||||||
@Component({
|
|
||||||
selector: '${selectors.join(', ')}',
|
|
||||||
templateUrl: '../lucide-icon.html',
|
|
||||||
standalone: true,
|
|
||||||
})
|
|
||||||
export class ${angularComponentName} extends LucideIconBase {
|
|
||||||
static readonly iconName = '${iconName}';
|
|
||||||
static readonly iconData: LucideIconData = ${JSON.stringify(children)};
|
|
||||||
protected override readonly iconName = signal(${angularComponentName}.iconName);
|
|
||||||
protected override readonly iconData = signal(${angularComponentName}.iconData);
|
|
||||||
}
|
|
||||||
|
|
||||||
${aliasComponentNames.map((aliasComponentName) => {
|
|
||||||
return `
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* @see ${angularComponentName}
|
|
||||||
*/
|
|
||||||
export const ${aliasComponentName} = ${angularComponentName};
|
|
||||||
`;
|
|
||||||
}).join(`\n\n`)}
|
|
||||||
`;
|
|
||||||
});
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
export default {
|
|
||||||
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',
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
import { LUCIDE_CONFIG, lucideDefaultConfig, provideLucideConfig } from './lucide-config';
|
|
||||||
|
|
||||||
describe('Lucide config', () => {
|
|
||||||
describe('LUCIDE_CONFIG', () => {
|
|
||||||
it('should use default', () => {
|
|
||||||
expect(TestBed.inject(LUCIDE_CONFIG)).toBe(lucideDefaultConfig);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('provideLucideConfig', () => {
|
|
||||||
it('should use defaults', () => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [
|
|
||||||
provideLucideConfig({
|
|
||||||
size: 18,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
expect(TestBed.inject(LUCIDE_CONFIG)).toEqual({
|
|
||||||
...lucideDefaultConfig,
|
|
||||||
size: 18,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import { InjectionToken, Provider } from '@angular/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lucide icon configuration options.
|
|
||||||
*/
|
|
||||||
export interface LucideConfig {
|
|
||||||
/**
|
|
||||||
* Stroke color.
|
|
||||||
* @default currentColor
|
|
||||||
*/
|
|
||||||
color: string;
|
|
||||||
/**
|
|
||||||
* Width and height.
|
|
||||||
* @default 24
|
|
||||||
*/
|
|
||||||
size: number;
|
|
||||||
/**
|
|
||||||
* Stroke width
|
|
||||||
* @default 2
|
|
||||||
*/
|
|
||||||
strokeWidth: number;
|
|
||||||
/**
|
|
||||||
* Whether stroke width should be scaled to appear uniform regardless of icon size.
|
|
||||||
* @default false
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Use CSS to set on SVG paths instead:
|
|
||||||
* ```css
|
|
||||||
* .lucide * {
|
|
||||||
* vector-effect: non-scaling-stroke;
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
absoluteStrokeWidth: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default icon configuration options.
|
|
||||||
*/
|
|
||||||
export const lucideDefaultConfig: LucideConfig = {
|
|
||||||
color: 'currentColor',
|
|
||||||
size: 24,
|
|
||||||
strokeWidth: 2,
|
|
||||||
absoluteStrokeWidth: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injection token for providing default configuration options.
|
|
||||||
*
|
|
||||||
* @internal Use {@link provideLucideConfig}
|
|
||||||
*/
|
|
||||||
export const LUCIDE_CONFIG = new InjectionToken<LucideConfig>('Lucide icon config', {
|
|
||||||
factory: () => lucideDefaultConfig,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provider for default icon configuration options.
|
|
||||||
*/
|
|
||||||
export function provideLucideConfig(config: Partial<LucideConfig>): Provider {
|
|
||||||
return {
|
|
||||||
provide: LUCIDE_CONFIG,
|
|
||||||
useValue: {
|
|
||||||
...lucideDefaultConfig,
|
|
||||||
...config,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
import {
|
|
||||||
Component,
|
|
||||||
computed,
|
|
||||||
effect,
|
|
||||||
ElementRef,
|
|
||||||
inject,
|
|
||||||
input,
|
|
||||||
Renderer2,
|
|
||||||
Signal,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { LUCIDE_CONFIG } from './lucide-config';
|
|
||||||
import { LucideIconData, Nullable } from './types';
|
|
||||||
import defaultAttributes from './default-attributes';
|
|
||||||
import { formatFixed } from './utils/format-fixed';
|
|
||||||
import { toKebabCase } from './utils/to-kebab-case';
|
|
||||||
|
|
||||||
function transformNumericStringInput(
|
|
||||||
value: Nullable<string | number>,
|
|
||||||
defaultValue: number,
|
|
||||||
): number {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
const parsedValue = parseInt(value, 10);
|
|
||||||
if (isNaN(parsedValue)) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
return parsedValue;
|
|
||||||
}
|
|
||||||
return value ?? defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
@Component({
|
|
||||||
// eslint-disable-next-line @angular-eslint/component-selector
|
|
||||||
selector: 'svg[lucideIcon]',
|
|
||||||
templateUrl: './lucide-icon.html',
|
|
||||||
host: {
|
|
||||||
...defaultAttributes,
|
|
||||||
class: 'lucide',
|
|
||||||
'[attr.width]': 'size().toString(10)',
|
|
||||||
'[attr.height]': 'size().toString(10)',
|
|
||||||
'[attr.stroke]': 'color()',
|
|
||||||
'[attr.stroke-width]': 'computedStrokeWidth()',
|
|
||||||
'[attr.aria-hidden]': '!title()',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export abstract class LucideIconBase {
|
|
||||||
protected abstract readonly iconName: Signal<Nullable<string>>;
|
|
||||||
protected abstract readonly iconData: Signal<Nullable<LucideIconData>>;
|
|
||||||
protected readonly iconConfig = inject(LUCIDE_CONFIG);
|
|
||||||
protected readonly elRef = inject(ElementRef);
|
|
||||||
protected readonly renderer = inject(Renderer2);
|
|
||||||
/**
|
|
||||||
* An optional accessible label for the icon.
|
|
||||||
* - If provided, it will add the title as an [`<svg:title>` element](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/title).
|
|
||||||
* - If not provided, the component will add an `aria-hidden="true"` attribute automatically.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Please refer to our [Accessibility guide](https://lucide.dev/guide/advanced/accessibility) regarding this matter.
|
|
||||||
* Adding accessible labels to icons is normally not necessary:
|
|
||||||
* - If your icon is decorative (as most icons are) just leave it as hidden from screen readers.
|
|
||||||
* - If your icon is interactive, it should be contained within an interactive element (e.g. button), and you should probably set your accessible label on that element.
|
|
||||||
* - If your icon is functional (e.g. used in place of a label), feel free to use this property.
|
|
||||||
*/
|
|
||||||
readonly title = input<Nullable<string>>();
|
|
||||||
/**
|
|
||||||
* Width and height.
|
|
||||||
* @default 24
|
|
||||||
*/
|
|
||||||
readonly size = input(this.iconConfig.size, {
|
|
||||||
transform: (value: Nullable<string | number>) =>
|
|
||||||
transformNumericStringInput(value, this.iconConfig.size),
|
|
||||||
});
|
|
||||||
/**
|
|
||||||
* Stroke color.
|
|
||||||
* @default currentColor
|
|
||||||
*/
|
|
||||||
readonly color = input(this.iconConfig.color, {
|
|
||||||
transform: (value: Nullable<string>) => value ?? this.iconConfig.color,
|
|
||||||
});
|
|
||||||
/**
|
|
||||||
* Stroke width
|
|
||||||
* @default 2
|
|
||||||
*/
|
|
||||||
readonly strokeWidth = input(this.iconConfig.strokeWidth, {
|
|
||||||
transform: (value: Nullable<string | number>) =>
|
|
||||||
transformNumericStringInput(value, this.iconConfig.strokeWidth),
|
|
||||||
});
|
|
||||||
/**
|
|
||||||
* Whether stroke width should be scaled to appear uniform regardless of icon size.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Use CSS to set on SVG paths instead:
|
|
||||||
* ```css
|
|
||||||
* .lucide * {
|
|
||||||
* vector-effect: non-scaling-stroke;
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
readonly absoluteStrokeWidth = input(this.iconConfig.absoluteStrokeWidth, {
|
|
||||||
transform: (value: Nullable<boolean>) => value ?? this.iconConfig.absoluteStrokeWidth,
|
|
||||||
});
|
|
||||||
protected readonly computedStrokeWidth = computed(() => {
|
|
||||||
const strokeWidth = this.strokeWidth();
|
|
||||||
const size = this.size();
|
|
||||||
return this.absoluteStrokeWidth()
|
|
||||||
? formatFixed(strokeWidth / (size / 24))
|
|
||||||
: strokeWidth.toString(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
effect((onCleanup) => {
|
|
||||||
const icon = this.iconData();
|
|
||||||
if (icon) {
|
|
||||||
const elements = icon.map(([name, attrs]) => {
|
|
||||||
const element = this.renderer.createElement(name, 'http://www.w3.org/2000/svg');
|
|
||||||
Object.entries(attrs).forEach(([name, value]) =>
|
|
||||||
this.renderer.setAttribute(
|
|
||||||
element,
|
|
||||||
name,
|
|
||||||
typeof value === 'number' ? value.toString(10) : value,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
this.renderer.appendChild(this.elRef.nativeElement, element);
|
|
||||||
return element;
|
|
||||||
});
|
|
||||||
onCleanup(() => {
|
|
||||||
elements.forEach((element) =>
|
|
||||||
this.renderer.removeChild(this.elRef.nativeElement, element),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
effect((onCleanup) => {
|
|
||||||
const name = this.iconName();
|
|
||||||
if (name) {
|
|
||||||
const cssClass = `lucide-${toKebabCase(name)}`;
|
|
||||||
this.renderer.addClass(this.elRef.nativeElement, cssClass);
|
|
||||||
onCleanup(() => {
|
|
||||||
this.renderer.removeClass(this.elRef.nativeElement, cssClass);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
@if (title(); as titleValue) {
|
|
||||||
<title>{{ titleValue }}</title>
|
|
||||||
}
|
|
||||||
<ng-content />
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
import { Component, input, inputBinding, signal, WritableSignal } from '@angular/core';
|
|
||||||
import { LucideIcon } from './lucide-icon';
|
|
||||||
import { LucideIconData, LucideIconInput } from './types';
|
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
import { provideLucideIcons } from './lucide-icons';
|
|
||||||
import { LucideActivity } from './icons/activity';
|
|
||||||
import { By } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
template: `@if (icon(); as iconData) {
|
|
||||||
<svg [lucideIcon]="iconData">
|
|
||||||
<rect x="1" y="1" width="22" height="22" />
|
|
||||||
</svg>
|
|
||||||
}`,
|
|
||||||
imports: [LucideIcon],
|
|
||||||
})
|
|
||||||
class TestHostComponent {
|
|
||||||
readonly icon = input<LucideIconData>();
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('LucideIcon', () => {
|
|
||||||
let component: LucideIcon;
|
|
||||||
let fixture: ComponentFixture<LucideIcon>;
|
|
||||||
let icon: WritableSignal<LucideIconInput | null | undefined>;
|
|
||||||
let name: WritableSignal<string | undefined>;
|
|
||||||
let title: WritableSignal<string | undefined>;
|
|
||||||
let color: WritableSignal<string | undefined>;
|
|
||||||
let size: WritableSignal<string | number | undefined>;
|
|
||||||
let strokeWidth: WritableSignal<string | number | undefined>;
|
|
||||||
let absoluteStrokeWidth: WritableSignal<boolean | undefined>;
|
|
||||||
const getSvgAttribute = (attr: string) => fixture.nativeElement.getAttribute(attr);
|
|
||||||
const testIcon: LucideIconData = [['polyline', { points: '1 1 22 22' }]];
|
|
||||||
const testIcon2: LucideIconData = [
|
|
||||||
['circle', { cx: 12, cy: 12, r: 8 }],
|
|
||||||
['polyline', { points: '1 1 22 22' }],
|
|
||||||
];
|
|
||||||
beforeEach(async () => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [provideLucideIcons({ demo: testIcon })],
|
|
||||||
});
|
|
||||||
icon = signal('demo');
|
|
||||||
name = signal(undefined);
|
|
||||||
title = signal(undefined);
|
|
||||||
color = signal(undefined);
|
|
||||||
size = signal(undefined);
|
|
||||||
strokeWidth = signal(undefined);
|
|
||||||
absoluteStrokeWidth = signal(undefined);
|
|
||||||
fixture = TestBed.createComponent(LucideIcon, {
|
|
||||||
inferTagName: true,
|
|
||||||
bindings: [
|
|
||||||
inputBinding('lucideIcon', icon),
|
|
||||||
inputBinding('name', name),
|
|
||||||
inputBinding('title', title),
|
|
||||||
inputBinding('color', color),
|
|
||||||
inputBinding('size', size),
|
|
||||||
inputBinding('strokeWidth', strokeWidth),
|
|
||||||
inputBinding('absoluteStrokeWidth', absoluteStrokeWidth),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render children', () => {
|
|
||||||
icon.set(testIcon2);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(fixture.nativeElement.innerHTML).toBe(
|
|
||||||
'<!--container--><circle cx="12" cy="12" r="8"></circle><polyline points="1 1 22 22"></polyline>',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should remove children on change', () => {
|
|
||||||
icon.set(null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(fixture.nativeElement.innerHTML).toBe('<!--container-->');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('iconInput', () => {
|
|
||||||
it('should support LucideIconData input', () => {
|
|
||||||
icon.set(testIcon);
|
|
||||||
name.set('custom-name');
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(component['iconData']()).toBe(testIcon);
|
|
||||||
expect(component['iconName']()).toBe('custom-name');
|
|
||||||
expect(fixture.nativeElement.innerHTML).toBe(
|
|
||||||
'<!--container--><polyline points="1 1 22 22"></polyline>',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('should support LucideIconComponentType input', () => {
|
|
||||||
icon.set(LucideActivity);
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(component['iconData']()).toBe(LucideActivity.iconData);
|
|
||||||
expect(component['iconName']()).toBe(LucideActivity.iconName);
|
|
||||||
});
|
|
||||||
it('should support string icon name', () => {
|
|
||||||
icon.set('demo');
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(component['iconData']()).toBe(testIcon);
|
|
||||||
expect(component['iconName']()).toBe('demo');
|
|
||||||
});
|
|
||||||
it('should throw error if no icon founds', () => {
|
|
||||||
icon.set('invalid');
|
|
||||||
expect(() => fixture.detectChanges()).toThrowError(`Unable to resolve icon 'invalid'`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('class', () => {
|
|
||||||
it('should add all classes', () => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('class')).toBe('lucide lucide-demo');
|
|
||||||
});
|
|
||||||
it('should add class from name, even if icon has name', () => {
|
|
||||||
icon.set(LucideActivity);
|
|
||||||
name.set('custom-name');
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(getSvgAttribute('class')).toBe('lucide lucide-custom-name');
|
|
||||||
});
|
|
||||||
it('should add class icon if available', () => {
|
|
||||||
icon.set(LucideActivity);
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(getSvgAttribute('class')).toBe('lucide lucide-activity');
|
|
||||||
});
|
|
||||||
it('should remove class on change', () => {
|
|
||||||
icon.set(null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('class')).toBe('lucide');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('color', () => {
|
|
||||||
it('should default to currentColor', () => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke')).toBe('currentColor');
|
|
||||||
});
|
|
||||||
it('should set color', () => {
|
|
||||||
color.set('red');
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke')).toBe('red');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('size', () => {
|
|
||||||
it('should default to 24', () => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('width')).toBe('24');
|
|
||||||
expect(getSvgAttribute('height')).toBe('24');
|
|
||||||
});
|
|
||||||
it('should set size', () => {
|
|
||||||
size.set(12);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('width')).toBe('12');
|
|
||||||
expect(getSvgAttribute('height')).toBe('12');
|
|
||||||
});
|
|
||||||
it('should allow string size', () => {
|
|
||||||
size.set('18');
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('width')).toBe('18');
|
|
||||||
expect(getSvgAttribute('height')).toBe('18');
|
|
||||||
});
|
|
||||||
it('should use default on invalid string', () => {
|
|
||||||
size.set('large');
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('width')).toBe('24');
|
|
||||||
expect(getSvgAttribute('height')).toBe('24');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('strokeWidth', () => {
|
|
||||||
it('should default to 2', () => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke-width')).toBe('2');
|
|
||||||
});
|
|
||||||
it('should set stroke width', () => {
|
|
||||||
strokeWidth.set(1.41);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke-width')).toBe('1.41');
|
|
||||||
});
|
|
||||||
it('should allow string stroke width', () => {
|
|
||||||
strokeWidth.set('1px');
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke-width')).toBe('1');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('absoluteStrokeWidth', () => {
|
|
||||||
it('should not adjust stroke width', () => {
|
|
||||||
strokeWidth.set(2);
|
|
||||||
size.set(12);
|
|
||||||
absoluteStrokeWidth.set(false);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke-width')).toBe('2');
|
|
||||||
});
|
|
||||||
it('should adjust stroke width', () => {
|
|
||||||
strokeWidth.set(2);
|
|
||||||
size.set(12);
|
|
||||||
absoluteStrokeWidth.set(true);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke-width')).toBe('4');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('title', () => {
|
|
||||||
it('should set title if provided', () => {
|
|
||||||
title.set('Foobar');
|
|
||||||
fixture.detectChanges();
|
|
||||||
const titleEl = fixture.debugElement.query(By.css('title')).nativeElement;
|
|
||||||
expect(titleEl).toBeDefined();
|
|
||||||
expect(titleEl.textContent).toBe('Foobar');
|
|
||||||
});
|
|
||||||
it('should not set aria-hidden when title is set', () => {
|
|
||||||
title.set('Foobar');
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('aria-hidden')).toBe('false');
|
|
||||||
});
|
|
||||||
it('should set aria-hidden if no title is provided', () => {
|
|
||||||
title.set(undefined);
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('aria-hidden')).toBe('true');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('content projection', () => {
|
|
||||||
it('should project content', () => {
|
|
||||||
const hostFixture = TestBed.createComponent(TestHostComponent);
|
|
||||||
hostFixture.componentRef.setInput('icon', testIcon);
|
|
||||||
hostFixture.detectChanges();
|
|
||||||
hostFixture.componentRef.setInput('icon', testIcon2);
|
|
||||||
hostFixture.detectChanges();
|
|
||||||
const rect = hostFixture.debugElement.query(By.css('rect')).nativeElement;
|
|
||||||
expect(rect).toBeInstanceOf(SVGElement);
|
|
||||||
expect(rect.outerHTML).toBe('<rect x="1" y="1" width="22" height="22"></rect>');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import { Component, computed, inject, input } from '@angular/core';
|
|
||||||
import { isLucideIconComponent, isLucideIconData, LucideIconInput } from './types';
|
|
||||||
import { LucideIconBase } from './lucide-icon-base';
|
|
||||||
import { LUCIDE_ICONS } from './lucide-icons';
|
|
||||||
import { LucideIconData } from './types';
|
|
||||||
import { toKebabCase } from './utils/to-kebab-case';
|
|
||||||
|
|
||||||
interface LucideResolvedIcon {
|
|
||||||
name?: string | null;
|
|
||||||
data: LucideIconData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic icon component for rendering LucideIconData.
|
|
||||||
*/
|
|
||||||
@Component({
|
|
||||||
selector: 'svg[lucideIcon]',
|
|
||||||
templateUrl: './lucide-icon.html',
|
|
||||||
standalone: true,
|
|
||||||
})
|
|
||||||
export class LucideIcon extends LucideIconBase {
|
|
||||||
protected readonly icons = inject(LUCIDE_ICONS);
|
|
||||||
readonly name = input<string | null>();
|
|
||||||
readonly iconInput = input.required<LucideIconInput | null>({
|
|
||||||
alias: 'lucideIcon',
|
|
||||||
});
|
|
||||||
readonly resolvedIcon = computed<LucideResolvedIcon | null>(() => {
|
|
||||||
return this.resolveIcon(this.name(), this.iconInput());
|
|
||||||
});
|
|
||||||
protected override readonly iconName = computed(() => {
|
|
||||||
return this.resolvedIcon()?.name;
|
|
||||||
});
|
|
||||||
protected override readonly iconData = computed(() => {
|
|
||||||
return this.resolvedIcon()?.data;
|
|
||||||
});
|
|
||||||
|
|
||||||
protected resolveIcon(
|
|
||||||
name: string | null | undefined,
|
|
||||||
icon: LucideIconInput | null | undefined,
|
|
||||||
): LucideResolvedIcon | null {
|
|
||||||
if (isLucideIconData(icon)) {
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
data: icon,
|
|
||||||
};
|
|
||||||
} else if (isLucideIconComponent(icon)) {
|
|
||||||
return {
|
|
||||||
name: name ?? icon.iconName,
|
|
||||||
data: icon.iconData,
|
|
||||||
};
|
|
||||||
} else if (typeof icon === 'string') {
|
|
||||||
const name = toKebabCase(icon);
|
|
||||||
if (name in this.icons) {
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
data: this.icons[name],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
throw new Error(`Unable to resolve icon '${icon}'`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
import { LUCIDE_ICONS, provideLucideIcons } from './lucide-icons';
|
|
||||||
import { LucideIconData } from './types';
|
|
||||||
import { LucideActivity } from './icons/activity';
|
|
||||||
import { LucideCircle } from './icons/circle';
|
|
||||||
import { LucideSquareX } from './icons/square-x';
|
|
||||||
|
|
||||||
describe('Lucide icons', () => {
|
|
||||||
describe('LUCIDE_ICONS', () => {
|
|
||||||
it('should default to empty map', () => {
|
|
||||||
expect(TestBed.inject(LUCIDE_ICONS)).toEqual({});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('provideLucideIcons', () => {
|
|
||||||
const mockIcon: LucideIconData = [['polyline', { points: '1 1 22 22' }]];
|
|
||||||
const mockIcon2: LucideIconData = [['circle', { cx: 12, cy: 12, r: 8 }]];
|
|
||||||
it('should accept dictionary of icons', () => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [
|
|
||||||
provideLucideIcons({
|
|
||||||
DemoIcon: mockIcon,
|
|
||||||
MockIcon: mockIcon2,
|
|
||||||
TestIcon: LucideActivity,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
expect(TestBed.inject(LUCIDE_ICONS)).toEqual({
|
|
||||||
'demo-icon': mockIcon,
|
|
||||||
'mock-icon': mockIcon2,
|
|
||||||
[LucideActivity.iconName]: LucideActivity.iconData,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should accept list of icon components', () => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
providers: [provideLucideIcons([LucideActivity, LucideSquareX, LucideCircle])],
|
|
||||||
});
|
|
||||||
expect(TestBed.inject(LUCIDE_ICONS)).toEqual({
|
|
||||||
[LucideActivity.iconName]: LucideActivity.iconData,
|
|
||||||
[LucideSquareX.iconName]: LucideSquareX.iconData,
|
|
||||||
[LucideCircle.iconName]: LucideCircle.iconData,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import { InjectionToken, Provider } from '@angular/core';
|
|
||||||
import { LucideIconData, LucideIcons } from './types';
|
|
||||||
import { isLucideIconComponent, LucideIconComponentType } from './types';
|
|
||||||
import { toKebabCase } from './utils/to-kebab-case';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injection token for providing Lucide icons by name.
|
|
||||||
*
|
|
||||||
* @internal Use {@link provideLucideIcons}
|
|
||||||
*/
|
|
||||||
export const LUCIDE_ICONS = new InjectionToken<LucideIcons>('Lucide icons', {
|
|
||||||
factory: () => ({}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide Lucide icons by name.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Warning! This provider will convert dictionary keys to lower-kebab-case.
|
|
||||||
*
|
|
||||||
* @param icons Either a dictionary of icons or a list of Angular icon components.
|
|
||||||
*
|
|
||||||
* @usage
|
|
||||||
* ```ts
|
|
||||||
* import { provideLucideIcons, SquareCheck } from '@lucide/angular';
|
|
||||||
* import { MyCustomIcon } from './custom-icons/circle-check';
|
|
||||||
*
|
|
||||||
* providers: [
|
|
||||||
* provideLucideIcons({
|
|
||||||
* SquareCheck,
|
|
||||||
* MyCustomIcon, // LucideIconData
|
|
||||||
* }),
|
|
||||||
* ]
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* ```html
|
|
||||||
* <svg lucideIcon="my-custom-icon" />
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export function provideLucideIcons(
|
|
||||||
icons: Record<string, LucideIconData | LucideIconComponentType> | Array<LucideIconComponentType>,
|
|
||||||
): Provider {
|
|
||||||
if (Array.isArray(icons)) {
|
|
||||||
return {
|
|
||||||
provide: LUCIDE_ICONS,
|
|
||||||
useValue: icons.reduce((acc, icon) => {
|
|
||||||
acc[toKebabCase(icon.iconName)] = icon.iconData;
|
|
||||||
return acc;
|
|
||||||
}, {} as LucideIcons),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
provide: LUCIDE_ICONS,
|
|
||||||
useValue: Object.entries(icons).reduce((acc, [name, icon]) => {
|
|
||||||
if (isLucideIconComponent(icon)) {
|
|
||||||
acc[icon.iconName] = icon.iconData;
|
|
||||||
} else {
|
|
||||||
acc[toKebabCase(name)] = icon;
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {} as LucideIcons),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import * as icons from './icons/lucide-angular';
|
|
||||||
|
|
||||||
export * from './lucide-config';
|
|
||||||
export * from './lucide-icon';
|
|
||||||
export * from './lucide-icons';
|
|
||||||
export * from './types';
|
|
||||||
export * from './icons/lucide-angular';
|
|
||||||
export { icons };
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import { Signal, Type } from '@angular/core';
|
|
||||||
|
|
||||||
type HtmlAttributes = { [key: string]: string | number };
|
|
||||||
export type LucideIconNode = readonly [string, HtmlAttributes];
|
|
||||||
export type LucideIconData = readonly LucideIconNode[];
|
|
||||||
export type LucideIcons = { [key: string]: LucideIconData };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a Lucide icon component that has `iconName` and `iconData` signals inherited from `LucideIconBase` and respective static members accessible without instantiating the component.
|
|
||||||
*/
|
|
||||||
export type LucideIconComponentType = Type<{
|
|
||||||
title: Signal<Nullable<string>>;
|
|
||||||
size: Signal<Nullable<number>>;
|
|
||||||
color: Signal<Nullable<string>>;
|
|
||||||
strokeWidth: Signal<Nullable<number>>;
|
|
||||||
absoluteStrokeWidth: Signal<Nullable<boolean>>;
|
|
||||||
}> & {
|
|
||||||
iconName: string;
|
|
||||||
iconData: LucideIconData;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type guard for {@link LucideIconData}
|
|
||||||
*/
|
|
||||||
export function isLucideIconData(icon: unknown): icon is LucideIconData {
|
|
||||||
return Array.isArray(icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type guard for {@link LucideIconComponentType}
|
|
||||||
*/
|
|
||||||
export function isLucideIconComponent(icon: unknown): icon is LucideIconComponentType {
|
|
||||||
return (
|
|
||||||
icon instanceof Type &&
|
|
||||||
'iconData' in icon &&
|
|
||||||
Array.isArray(icon.iconData) &&
|
|
||||||
'iconName' in icon &&
|
|
||||||
typeof icon.iconName === 'string'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LucideIconInput = LucideIconComponentType | LucideIconData | string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export type Nullable<T> = T | null | undefined;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export function formatFixed(number: number, decimals = 3): string {
|
|
||||||
return parseFloat(number.toFixed(decimals)).toString(10);
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export const toKebabCase = (name: string) =>
|
|
||||||
name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
|
||||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
|
||||||
{
|
|
||||||
"compileOnSave": false,
|
|
||||||
"compilerOptions": {
|
|
||||||
"paths": {
|
|
||||||
"@lucide/angular": ["./dist"],
|
|
||||||
},
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitOverride": true,
|
|
||||||
"noPropertyAccessFromIndexSignature": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"declaration": false,
|
|
||||||
"downlevelIteration": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"importHelpers": true,
|
|
||||||
"target": "ES2022",
|
|
||||||
"module": "preserve",
|
|
||||||
},
|
|
||||||
"angularCompilerOptions": {
|
|
||||||
"enableI18nLegacyMessageIdFormat": false,
|
|
||||||
"strictInjectionParameters": true,
|
|
||||||
"strictInputAccessModifiers": true,
|
|
||||||
"strictTemplates": true,
|
|
||||||
},
|
|
||||||
"files": [],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.lib.json",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.spec.json",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
|
||||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
|
||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "./out-tsc/lib",
|
|
||||||
"declaration": true,
|
|
||||||
"declarationMap": true,
|
|
||||||
"inlineSources": true,
|
|
||||||
"types": []
|
|
||||||
},
|
|
||||||
"include": ["src/**/*.ts"],
|
|
||||||
"exclude": ["**/*.spec.ts"]
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
|
||||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
|
||||||
{
|
|
||||||
"extends": "./tsconfig.lib.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"declarationMap": false
|
|
||||||
},
|
|
||||||
"angularCompilerOptions": {
|
|
||||||
"compilationMode": "partial"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
|
||||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
|
||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "./out-tsc/spec",
|
|
||||||
"types": ["vitest/globals"]
|
|
||||||
},
|
|
||||||
"include": ["src/**/*.d.ts", "src/**/*.spec.ts"]
|
|
||||||
}
|
|
||||||
@@ -56,6 +56,7 @@
|
|||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^6.3.6",
|
"vite": "^6.3.6",
|
||||||
|
"vitest": "^4.0.12",
|
||||||
"astro": "^5.16.0"
|
"astro": "^5.16.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
10
packages/icons/.npmignore
Normal file
10
packages/icons/.npmignore
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
stats
|
||||||
|
node_modules
|
||||||
|
tests
|
||||||
|
scripts
|
||||||
|
build
|
||||||
|
src
|
||||||
|
babel.config.js
|
||||||
|
jest.config.js
|
||||||
|
rollup.config.js
|
||||||
|
yarn.error.log
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/lucide-icons/lucide">
|
<a href="https://github.com/lucide-icons/lucide">
|
||||||
<img src="https://lucide.dev/package-logos/lucide-angular.svg" alt="Lucide icon library for Angular applications." width="540">
|
<img src="https://lucide.dev/package-logos/icons.svg" alt="" width="540">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Lucide icon library for Angular applications.
|
Lucide helper library that exports icon data.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
[](https://www.npmjs.com/package/@lucide/icons)
|
||||||
[](https://www.npmjs.com/package/@lucide/angular)
|

|
||||||

|
|
||||||
[](https://lucide.dev/license)
|
[](https://lucide.dev/license)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -20,40 +19,46 @@ Lucide icon library for Angular applications.
|
|||||||
·
|
·
|
||||||
<a href="https://lucide.dev/icons/">Icons</a>
|
<a href="https://lucide.dev/icons/">Icons</a>
|
||||||
·
|
·
|
||||||
<a href="https://lucide.dev/guide/packages/angular">Documentation</a>
|
<a href="https://lucide.dev/guide/packages/lucide">Documentation</a>
|
||||||
·
|
·
|
||||||
<a href="https://lucide.dev/license">License</a>
|
<a href="https://lucide.dev/license">License</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# Lucide Angular
|
# @lucide/icons
|
||||||
|
|
||||||
A standalone, signal based, zoneless implementation of the Lucide icon library for Angular applications.
|
A helper library that exports Lucide icon data in a tree-shakable format, also providing utilities for dynamic importing icons.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pnpm add @lucide/angular
|
pnpm add @lucide/icons
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install @lucide/angular
|
npm install @lucide/icons
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn add @lucide/angular
|
yarn add @lucide/icons
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bun add @lucide/angular
|
bun add @lucide/icons
|
||||||
|
```
|
||||||
|
|
||||||
|
### CDN
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Development version -->
|
||||||
|
<script src="https://unpkg.com/@lucide/icons@latest/dist/umd/lucide.js"></script>
|
||||||
|
|
||||||
|
<!-- Production version -->
|
||||||
|
<script src="https://unpkg.com/@lucide/icons@latest"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
For full documentation, visit [lucide.dev](https://lucide.dev/guide/packages/angular)
|
For full documentation, visit [lucide.dev](https://lucide.dev/guide/packages/icons)
|
||||||
|
|
||||||
## Migration guide
|
|
||||||
|
|
||||||
Migrating from `lucide-angular`? Read our [comprehensive migration guide](./MIGRATION.md).
|
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
@@ -74,4 +79,4 @@ Lucide is licensed under the ISC license. See [LICENSE](https://lucide.dev/licen
|
|||||||
### Awesome backers 🍺
|
### 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://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>
|
<a href="https://github.com/pdfme/pdfme"><img src="../../docs/public/sponsors/pdfme.svg" width="180" alt="pdfme sponsor badge" /></a>
|
||||||
77
packages/icons/package.json
Normal file
77
packages/icons/package.json
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"name": "@lucide/icons",
|
||||||
|
"description": "A Lucide icon library that contains icon data in a standard Lucide format.",
|
||||||
|
"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/lucide"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"Lucide",
|
||||||
|
"HTML",
|
||||||
|
"Feather",
|
||||||
|
"Icons",
|
||||||
|
"Icon",
|
||||||
|
"SVG",
|
||||||
|
"Feather Icons"
|
||||||
|
],
|
||||||
|
"amdName": "lucide-icons",
|
||||||
|
"source": "src/lucide-icons.ts",
|
||||||
|
"main": "dist/cjs/lucide-icons.cjs",
|
||||||
|
"module": "dist/esm/lucide-icons.mjs",
|
||||||
|
"types": "dist/esm/lucide-icons.d.ts",
|
||||||
|
"sideEffects": false,
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/esm/lucide-icons.d.ts",
|
||||||
|
"import": "./dist/esm/lucide-icons.mjs",
|
||||||
|
"require": "./dist/cjs/lucide-icons.cjs",
|
||||||
|
"default": "./dist/esm/lucide-icons.mjs"
|
||||||
|
},
|
||||||
|
"./icons/*": {
|
||||||
|
"import": "./dist/esm/icons/*.mjs",
|
||||||
|
"default": "./dist/esm/icons/*.mjs"
|
||||||
|
},
|
||||||
|
"./dynamic": {
|
||||||
|
"types": "./dist/esm/dynamic.d.ts",
|
||||||
|
"import": "./dist/esm/dynamic.mjs",
|
||||||
|
"require": "./dist/cjs/dynamic.cjs",
|
||||||
|
"default": "./dist/esm/dynamic.mjs"
|
||||||
|
},
|
||||||
|
"./build": {
|
||||||
|
"types": "./dist/esm/build.d.ts",
|
||||||
|
"import": "./dist/esm/build.mjs",
|
||||||
|
"require": "./dist/cjs/build.cjs",
|
||||||
|
"default": "./dist/esm/build.mjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --withAliases --withDynamicImports --separateAliasesFile --aliasesFileExtension=.ts --iconFileExtension=.ts --exportFileName=index.ts",
|
||||||
|
"build:bundle": "rollup -c rollup.config.mjs",
|
||||||
|
"test": "pnpm build:icons && vitest run",
|
||||||
|
"test:watch": "vitest watch",
|
||||||
|
"test:update": "vitest -u",
|
||||||
|
"version": "pnpm version --git-tag-version=false"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@lucide/build-icons": "workspace:*",
|
||||||
|
"@lucide/helpers": "^1.0.0",
|
||||||
|
"@lucide/rollup-plugins": "workspace:*",
|
||||||
|
"@rollup/plugin-replace": "^6.0.2",
|
||||||
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
|
"jest-serializer-html": "^7.1.0",
|
||||||
|
"rollup": "^4.53.3",
|
||||||
|
"rollup-plugin-dts": "^6.2.3",
|
||||||
|
"rollup-plugin-preserve-directives": "^0.4.0",
|
||||||
|
"typescript": "^5.8.3",
|
||||||
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
87
packages/icons/rollup.config.mjs
Normal file
87
packages/icons/rollup.config.mjs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import plugins from '@lucide/rollup-plugins';
|
||||||
|
import pkg from './package.json' with { type: 'json' };
|
||||||
|
import dts from 'rollup-plugin-dts';
|
||||||
|
|
||||||
|
const packageName = '@lucide/icons';
|
||||||
|
const outputFileName = 'lucide-icons';
|
||||||
|
const inputs = [`src/lucide-icons.ts`];
|
||||||
|
const bundles = [
|
||||||
|
{
|
||||||
|
format: 'cjs',
|
||||||
|
inputs,
|
||||||
|
extension: 'cjs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: 'esm',
|
||||||
|
inputs: [...inputs, './src/dynamic.ts', './src/build.ts'],
|
||||||
|
preserveModules: true,
|
||||||
|
extension: 'mjs',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const configs = bundles
|
||||||
|
.map(
|
||||||
|
({
|
||||||
|
inputs,
|
||||||
|
outputDir = 'dist',
|
||||||
|
outputFile,
|
||||||
|
format,
|
||||||
|
minify,
|
||||||
|
preserveModules,
|
||||||
|
entryFileNames,
|
||||||
|
external = [],
|
||||||
|
paths,
|
||||||
|
extension = 'js',
|
||||||
|
}) =>
|
||||||
|
inputs.map((input) => ({
|
||||||
|
input,
|
||||||
|
plugins: [...plugins({ pkg, minify })],
|
||||||
|
external,
|
||||||
|
output: {
|
||||||
|
name: packageName,
|
||||||
|
entryFileNames,
|
||||||
|
...(preserveModules
|
||||||
|
? {
|
||||||
|
dir: `${outputDir}/${format}`,
|
||||||
|
entryFileNames: `[name].${extension}`,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
file:
|
||||||
|
outputFile ??
|
||||||
|
`${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.${extension}`,
|
||||||
|
}),
|
||||||
|
paths,
|
||||||
|
format,
|
||||||
|
sourcemap: true,
|
||||||
|
preserveModules,
|
||||||
|
exports: 'named',
|
||||||
|
globals: {},
|
||||||
|
preserveModulesRoot: 'src',
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...[
|
||||||
|
outputFileName,
|
||||||
|
`${outputFileName}.prefixed`,
|
||||||
|
`${outputFileName}.suffixed`,
|
||||||
|
'dynamic',
|
||||||
|
'build',
|
||||||
|
].map((filename) => ({
|
||||||
|
input: `./src/${filename}.ts`,
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
file: `dist/esm/${filename}.d.ts`,
|
||||||
|
format: 'esm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
file: `dist/cjs/${filename}.d.cts`,
|
||||||
|
format: 'cjs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
plugins: [dts()],
|
||||||
|
})),
|
||||||
|
...configs,
|
||||||
|
];
|
||||||
36
packages/icons/scripts/exportTemplate.mjs
Normal file
36
packages/icons/scripts/exportTemplate.mjs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import base64SVG from '@lucide/build-icons/utils/base64SVG';
|
||||||
|
|
||||||
|
export default async ({
|
||||||
|
componentName,
|
||||||
|
iconName,
|
||||||
|
children,
|
||||||
|
getSvg,
|
||||||
|
deprecated,
|
||||||
|
deprecationReason,
|
||||||
|
}) => {
|
||||||
|
const svgContents = await getSvg();
|
||||||
|
const svgBase64 = base64SVG(svgContents);
|
||||||
|
|
||||||
|
return `
|
||||||
|
import type { LucideIcon } from '../types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ${iconName}
|
||||||
|
* @description Lucide SVG icon node.
|
||||||
|
*
|
||||||
|
* @preview  - https://lucide.dev/icons/${iconName}
|
||||||
|
* @see https://lucide.dev/guide/packages/lucide - Documentation
|
||||||
|
*
|
||||||
|
* @returns {Array}
|
||||||
|
* ${deprecated ? `@deprecated ${deprecationReason}` : ''}
|
||||||
|
*/
|
||||||
|
const ${componentName}: LucideIcon = ${JSON.stringify({
|
||||||
|
name: iconName,
|
||||||
|
size: 24,
|
||||||
|
node: children,
|
||||||
|
})}
|
||||||
|
|
||||||
|
export default ${componentName};
|
||||||
|
`;
|
||||||
|
};
|
||||||
3
packages/icons/src/aliases/index.ts
Normal file
3
packages/icons/src/aliases/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './aliases';
|
||||||
|
export * from './prefixed';
|
||||||
|
export * from './suffixed';
|
||||||
4
packages/icons/src/build.ts
Normal file
4
packages/icons/src/build.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export { default as buildLucideIconNode } from './buildLucideIconNode';
|
||||||
|
export { default as buildLucideDataUri } from './buildLucideDataUri';
|
||||||
|
export { default as buildLucideIconElement } from './buildLucideIconElement';
|
||||||
|
export { default as buildLucideSvg } from './buildLucideSvg';
|
||||||
30
packages/icons/src/buildLucideDataUri.ts
Normal file
30
packages/icons/src/buildLucideDataUri.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { LucideBuildParams, LucideIcon } from './types';
|
||||||
|
import buildLucideSvg from './buildLucideSvg';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a base64 encoded data URI from a Lucide icon object.
|
||||||
|
*
|
||||||
|
* @param icon The icon to build.
|
||||||
|
* @param params Additional build parameters.
|
||||||
|
*/
|
||||||
|
function buildLucideDataUri(icon: LucideIcon, params: LucideBuildParams = {}) {
|
||||||
|
const svg = buildLucideSvg(icon, params);
|
||||||
|
|
||||||
|
// Browser
|
||||||
|
if (typeof btoa === 'function') {
|
||||||
|
// Ensure proper UTF-8 handling before base64
|
||||||
|
const utf8Bytes = new TextEncoder().encode(svg);
|
||||||
|
let binary = '';
|
||||||
|
for (const element of utf8Bytes) binary += String.fromCodePoint(element);
|
||||||
|
return `data:image/svg+xml;base64,${btoa(binary)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node.js (and other JS runtimes with Buffer)
|
||||||
|
if (typeof Buffer !== 'undefined') {
|
||||||
|
return `data:image/svg+xml;base64,${Buffer.from(svg, 'utf8').toString('base64')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('No base64 encoder available in this environment.');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default buildLucideDataUri;
|
||||||
34
packages/icons/src/buildLucideIconElement.ts
Normal file
34
packages/icons/src/buildLucideIconElement.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { LucideBuildParams, LucideIcon, LucideIconNode } from './types';
|
||||||
|
import buildLucideIconNode from './buildLucideIconNode';
|
||||||
|
|
||||||
|
const buildDomElement = (
|
||||||
|
document: Document,
|
||||||
|
[tagName, attributes, children = []]: LucideIconNode,
|
||||||
|
): Element => {
|
||||||
|
const element = document.createElementNS('http://www.w3.org/2000/svg', tagName);
|
||||||
|
for (const [attrName, value] of Object.entries(attributes)) {
|
||||||
|
element.setAttribute(attrName, value);
|
||||||
|
}
|
||||||
|
for (const node of children) {
|
||||||
|
const childNode = buildDomElement(document, node);
|
||||||
|
element.appendChild(childNode);
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SvgElement from a Lucide icon object.
|
||||||
|
*
|
||||||
|
* @param document The document to create the Element in.
|
||||||
|
* @param icon The icon to build.
|
||||||
|
* @param params Additional build parameters.
|
||||||
|
*/
|
||||||
|
function buildLucideIconElement(
|
||||||
|
document: Document,
|
||||||
|
icon: LucideIcon,
|
||||||
|
params: LucideBuildParams = {},
|
||||||
|
) {
|
||||||
|
return buildDomElement(document, buildLucideIconNode(icon, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default buildLucideIconElement;
|
||||||
50
packages/icons/src/buildLucideIconNode.ts
Normal file
50
packages/icons/src/buildLucideIconNode.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { LucideBuildParams, LucideIcon, LucideIconNode } from './types';
|
||||||
|
|
||||||
|
const defaultAttributes = {
|
||||||
|
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',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Lucide icon node (an svgson-like format) from a Lucide icon object.
|
||||||
|
*
|
||||||
|
* @param icon The icon to build.
|
||||||
|
* @param params Additional build parameters.
|
||||||
|
*/
|
||||||
|
function buildLucideIconNode(icon: LucideIcon, params: LucideBuildParams = {}): LucideIconNode {
|
||||||
|
const viewBoxWidth = ('size' in icon ? icon.size : icon.width) ?? defaultAttributes.width;
|
||||||
|
const viewBoxHeight = ('size' in icon ? icon.size : icon.height) ?? defaultAttributes.height;
|
||||||
|
const attributes = {
|
||||||
|
...defaultAttributes,
|
||||||
|
...('color' in params && { stroke: params['color'] }),
|
||||||
|
...('size' in params &&
|
||||||
|
params['size'] && {
|
||||||
|
width: params['size'].toString(10),
|
||||||
|
height: params['size'].toString(10),
|
||||||
|
}),
|
||||||
|
...('width' in params && params['width'] && { width: params['width'].toString(10) }),
|
||||||
|
...('height' in params && params['height'] && { height: params['height'].toString(10) }),
|
||||||
|
...('strokeWidth' in params &&
|
||||||
|
params['strokeWidth'] && { 'stroke-width': params['strokeWidth'].toString(10) }),
|
||||||
|
class: `lucide lucide-${icon.name} ${params['className'] ?? ''}`.trim(),
|
||||||
|
viewBox: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
|
||||||
|
...('attributes' in params && params.attributes),
|
||||||
|
};
|
||||||
|
return [
|
||||||
|
'svg',
|
||||||
|
attributes,
|
||||||
|
icon.node.map(([name, attrs]) => [
|
||||||
|
name,
|
||||||
|
params['absoluteStrokeWidth'] ? { 'vector-effect': 'non-scaling-stroke', ...attrs } : attrs,
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default buildLucideIconNode;
|
||||||
19
packages/icons/src/buildLucideSvg.ts
Normal file
19
packages/icons/src/buildLucideSvg.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { LucideBuildParams, LucideIcon, LucideIconNode } from './types';
|
||||||
|
import buildLucideIconNode from './buildLucideIconNode';
|
||||||
|
|
||||||
|
const buildDomNode = ([tagName, attributes, children = []]: LucideIconNode): string =>
|
||||||
|
`<${tagName} ${Object.entries(attributes)
|
||||||
|
.map(([attrName, value]) => `${attrName}="${value}"`)
|
||||||
|
.join(' ')}>${children?.map((child) => buildDomNode(child)).join('')}</${tagName}>`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an SVG string from a Lucide icon object.
|
||||||
|
*
|
||||||
|
* @param icon The icon to build.
|
||||||
|
* @param params Additional build parameters.
|
||||||
|
*/
|
||||||
|
function buildLucideSvg(icon: LucideIcon, params: LucideBuildParams = {}) {
|
||||||
|
return buildDomNode(buildLucideIconNode(icon, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default buildLucideSvg;
|
||||||
2
packages/icons/src/dynamic.ts
Normal file
2
packages/icons/src/dynamic.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { lucideIconNames, type LucideIconName } from './dynamicIcon';
|
||||||
|
export { default as lucideDynamicIconImports } from './dynamicIconImports';
|
||||||
8
packages/icons/src/dynamicIcon.ts
Normal file
8
packages/icons/src/dynamicIcon.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import dynamicIconImports from './dynamicIconImports';
|
||||||
|
|
||||||
|
export type LucideIconName = keyof typeof dynamicIconImports;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of available Lucide icon names.
|
||||||
|
*/
|
||||||
|
export const lucideIconNames = Object.keys(dynamicIconImports) as Array<LucideIconName>;
|
||||||
1
packages/icons/src/icons/.gitkeep
Normal file
1
packages/icons/src/icons/.gitkeep
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Folder for generated icons
|
||||||
5
packages/icons/src/lucide-icons.prefixed.ts
Normal file
5
packages/icons/src/lucide-icons.prefixed.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export * as icons from './icons';
|
||||||
|
export * from './aliases/prefixed';
|
||||||
|
export * from './types';
|
||||||
|
|
||||||
|
export * from './build';
|
||||||
3
packages/icons/src/lucide-icons.suffixed.ts
Normal file
3
packages/icons/src/lucide-icons.suffixed.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * as icons from './icons';
|
||||||
|
export * from './aliases/suffixed';
|
||||||
|
export * from './types';
|
||||||
4
packages/icons/src/lucide-icons.ts
Normal file
4
packages/icons/src/lucide-icons.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export * as icons from './icons';
|
||||||
|
export * from './icons';
|
||||||
|
export * from './aliases/index';
|
||||||
|
export * from './types';
|
||||||
42
packages/icons/src/types.ts
Normal file
42
packages/icons/src/types.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
export type SVGProps = Record<string, string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Lucide icon node (an svgson-like internal format)
|
||||||
|
*/
|
||||||
|
export type LucideIconNode =
|
||||||
|
| [attrName: string, attributes: SVGProps]
|
||||||
|
| [attrName: string, attributes: SVGProps, children: LucideIconNode[]];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Lucide icon object that fully describes an icon to be displayed.
|
||||||
|
*/
|
||||||
|
export type LucideIcon = {
|
||||||
|
name: string;
|
||||||
|
node: LucideIconNode[];
|
||||||
|
} & ({ size: number } | { width: number; height: number });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build parameters for creating a Lucide icon instance for display.
|
||||||
|
*/
|
||||||
|
export type LucideBuildParams = {
|
||||||
|
/**
|
||||||
|
* The color of the icon.
|
||||||
|
*/
|
||||||
|
color?: string;
|
||||||
|
/**
|
||||||
|
* The stroke width.
|
||||||
|
*/
|
||||||
|
strokeWidth?: number;
|
||||||
|
/**
|
||||||
|
* Adds [`vector-effect="non-scaling-stroke"`](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/vector-effect) to child elements.
|
||||||
|
*/
|
||||||
|
absoluteStrokeWidth?: boolean;
|
||||||
|
/**
|
||||||
|
* Extra CSS class names to pass to the SVG element.
|
||||||
|
*/
|
||||||
|
className?: string;
|
||||||
|
/**
|
||||||
|
* Any extra attributes to pass to the SVG element.
|
||||||
|
*/
|
||||||
|
attributes?: SVGProps;
|
||||||
|
} & ({ size?: number } | { width?: number; height?: number });
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`buildLucideIconElement > should match the snapshot 1`] = `
|
||||||
|
<svg 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"
|
||||||
|
class="lucide lucide-house"
|
||||||
|
>
|
||||||
|
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"
|
||||||
|
key="5wwlr5"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
<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"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`buildLucideIconNode > should match the snapshot 1`] = `"{"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","class":"lucide lucide-house"}"`;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`buildLucideSvg > should match the snapshot 1`] = `
|
||||||
|
<svg 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"
|
||||||
|
class="lucide lucide-house"
|
||||||
|
>
|
||||||
|
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"
|
||||||
|
key="5wwlr5"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
<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"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`buildLucideSvgDataUri > should match the snapshot 1`] = `"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWhvdXNlIj48cGF0aCBkPSJNMTUgMjF2LThhMSAxIDAgMCAwLTEtMWgtNGExIDEgMCAwIDAtMSAxdjgiIGtleT0iNXd3bHI1Ij48L3BhdGg+PHBhdGggZD0iTTMgMTBhMiAyIDAgMCAxIC43MDktMS41MjhsNy02YTIgMiAwIDAgMSAyLjU4MiAwbDcgNkEyIDIgMCAwIDEgMjEgMTB2OWEyIDIgMCAwIDEtMiAySDVhMiAyIDAgMCAxLTItMnoiIGtleT0icjZuc3MxIj48L3BhdGg+PC9zdmc+"`;
|
||||||
44
packages/icons/tests/buildLucideIconElement.spec.ts
Normal file
44
packages/icons/tests/buildLucideIconElement.spec.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { House } from '../src/lucide-icons';
|
||||||
|
import { getOriginalSvg, removeKeys } from './helpers';
|
||||||
|
import buildLucideIconElement from '../src/buildLucideIconElement';
|
||||||
|
|
||||||
|
describe('buildLucideIconElement', () => {
|
||||||
|
it('should create SVG Element', () => {
|
||||||
|
const HomeSVG = buildLucideIconElement(document, House);
|
||||||
|
|
||||||
|
expect(HomeSVG.tagName).toBe('svg');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should match the snapshot', () => {
|
||||||
|
const HomeSVG = buildLucideIconElement(document, House);
|
||||||
|
|
||||||
|
expect(HomeSVG.outerHTML).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create SVG Element with attributes', () => {
|
||||||
|
const HomeSVG = buildLucideIconElement(document, House, { attributes: { fill: 'red' } });
|
||||||
|
|
||||||
|
expect(HomeSVG.getAttribute('fill')).toBe('red');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create SVG Element with class name', () => {
|
||||||
|
const HomeSVG = buildLucideIconElement(document, House, { attributes: { class: 'icon' } });
|
||||||
|
|
||||||
|
expect(HomeSVG.getAttribute('class')).toBe('icon');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should merge classes', () => {
|
||||||
|
const HomeSVG = buildLucideIconElement(document, House, { className: 'icon' });
|
||||||
|
|
||||||
|
expect(HomeSVG.getAttribute('class')).toBe('lucide lucide-house icon');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the correct svg element', () => {
|
||||||
|
const HomeSVG = buildLucideIconElement(document, House);
|
||||||
|
|
||||||
|
const svg = getOriginalSvg('house', undefined, true);
|
||||||
|
|
||||||
|
expect(removeKeys(HomeSVG.outerHTML)).toBe(svg);
|
||||||
|
});
|
||||||
|
});
|
||||||
86
packages/icons/tests/buildLucideIconNode.spec.ts
Normal file
86
packages/icons/tests/buildLucideIconNode.spec.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { House } from '../src/lucide-icons';
|
||||||
|
import buildLucideIconNode from '../src/buildLucideIconNode';
|
||||||
|
|
||||||
|
describe('buildLucideIconNode', () => {
|
||||||
|
it('should create icon node', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House);
|
||||||
|
|
||||||
|
expect(HouseSVG.at(0)).toBe('svg');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should match the snapshot', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House);
|
||||||
|
|
||||||
|
expect(JSON.stringify(HouseSVG.at(1))).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override dimensions, but not viewBox', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { size: 12 });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['width']).toBe('12');
|
||||||
|
expect(HouseSVG[1]['height']).toBe('12');
|
||||||
|
expect(HouseSVG[1]['viewBox']).toBe('0 0 24 24');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override width, but not height', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { width: 12 });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['width']).toBe('12');
|
||||||
|
expect(HouseSVG[1]['height']).toBe('24');
|
||||||
|
expect(HouseSVG[1]['viewBox']).toBe('0 0 24 24');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override height, but not width', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { height: 12 });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['width']).toBe('24');
|
||||||
|
expect(HouseSVG[1]['height']).toBe('12');
|
||||||
|
expect(HouseSVG[1]['viewBox']).toBe('0 0 24 24');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override color', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { color: 'pink' });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['stroke']).toBe('pink');
|
||||||
|
expect(HouseSVG[1]['fill']).toBe('none');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override stroke width', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { strokeWidth: 12 });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['stroke-width']).toBe('12');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set non-scaling-stroke to child nodes', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { absoluteStrokeWidth: true });
|
||||||
|
|
||||||
|
for (const node of HouseSVG[2]!) {
|
||||||
|
expect(node[1]['vector-effect']).toBe('non-scaling-stroke');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set non-scaling-stroke', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { absoluteStrokeWidth: false });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['vector-effect']).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create icon node with attributes', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { attributes: { fill: 'red' } });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['fill']).toBe('red');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create icon node with class name', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { attributes: { class: 'icon' } });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['class']).toBe('icon');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should merge classes', () => {
|
||||||
|
const HouseSVG = buildLucideIconNode(House, { className: 'icon' });
|
||||||
|
|
||||||
|
expect(HouseSVG[1]['class']).toBe('lucide lucide-house icon');
|
||||||
|
});
|
||||||
|
});
|
||||||
29
packages/icons/tests/buildLucideSvg.spec.ts
Normal file
29
packages/icons/tests/buildLucideSvg.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { House } from '../src/lucide-icons';
|
||||||
|
import { getOriginalSvg, removeKeys } from './helpers';
|
||||||
|
import buildLucideSvg from '../src/buildLucideSvg';
|
||||||
|
import buildLucideDataUri from '../src/buildLucideDataUri';
|
||||||
|
|
||||||
|
describe('buildLucideSvg', () => {
|
||||||
|
it('should match the snapshot', () => {
|
||||||
|
const HouseSVG = buildLucideSvg(House);
|
||||||
|
|
||||||
|
expect(HouseSVG).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the correct svg element', () => {
|
||||||
|
const HouseSVG = buildLucideSvg(House);
|
||||||
|
|
||||||
|
const svg = getOriginalSvg('house', undefined, true);
|
||||||
|
|
||||||
|
expect(removeKeys(HouseSVG)).toBe(svg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('buildLucideSvgDataUri', () => {
|
||||||
|
it('should match the snapshot', () => {
|
||||||
|
const HouseDataUri = buildLucideDataUri(House);
|
||||||
|
|
||||||
|
expect(HouseDataUri).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
18
packages/icons/tests/helpers.ts
Normal file
18
packages/icons/tests/helpers.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { parseSync, stringify } from 'svgson';
|
||||||
|
|
||||||
|
const ICONS_DIR = path.resolve(__dirname, '../../../icons');
|
||||||
|
|
||||||
|
export const getOriginalSvg = (iconName: string, aliasName?: string, setAttrs = true) => {
|
||||||
|
const svgContent = fs.readFileSync(path.join(ICONS_DIR, `${iconName}.svg`), 'utf8');
|
||||||
|
const svgParsed = parseSync(svgContent);
|
||||||
|
|
||||||
|
if (setAttrs) {
|
||||||
|
svgParsed.attributes['class'] = `lucide lucide-${aliasName ?? iconName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringify(svgParsed, { selfClose: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeKeys = (svg: string) => svg.replaceAll(/ key="[^"]+"/g, '');
|
||||||
10
packages/icons/tests/lucide-icons.spec.ts
Normal file
10
packages/icons/tests/lucide-icons.spec.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { House } from '../src/lucide-icons';
|
||||||
|
|
||||||
|
describe('lucide-icons', () => {
|
||||||
|
it('should init', () => {
|
||||||
|
const HouseSVG = House;
|
||||||
|
|
||||||
|
expect(House).toMatchObject(House);
|
||||||
|
});
|
||||||
|
});
|
||||||
5
packages/icons/tests/setupVitest.js
Normal file
5
packages/icons/tests/setupVitest.js
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);
|
||||||
22
packages/icons/tsconfig.json
Normal file
22
packages/icons/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"declaration": false,
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"module": "ESNext",
|
||||||
|
"target": "ESNext",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"lib": ["esnext", "dom"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
},
|
||||||
|
"exclude": ["**/node_modules"],
|
||||||
|
}
|
||||||
9
packages/icons/vitest.config.mts
Normal file
9
packages/icons/vitest.config.mts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
setupFiles: './tests/setupVitest.js',
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -51,7 +51,8 @@
|
|||||||
"rollup": "^4.53.3",
|
"rollup": "^4.53.3",
|
||||||
"rollup-plugin-dts": "^6.2.3",
|
"rollup-plugin-dts": "^6.2.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^7.2.4"
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"preact": "^10.27.2"
|
"preact": "^10.27.2"
|
||||||
|
|||||||
@@ -71,7 +71,8 @@
|
|||||||
"rollup": "^4.53.3",
|
"rollup": "^4.53.3",
|
||||||
"rollup-plugin-dts": "^6.2.3",
|
"rollup-plugin-dts": "^6.2.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^7.2.4"
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
|||||||
@@ -63,7 +63,8 @@
|
|||||||
"rollup-plugin-dts": "^6.2.3",
|
"rollup-plugin-dts": "^6.2.3",
|
||||||
"rollup-plugin-preserve-directives": "^0.4.0",
|
"rollup-plugin-preserve-directives": "^0.4.0",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^7.2.4"
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^7.2.4",
|
"vite": "^7.2.4",
|
||||||
"vite-plugin-solid": "^2.11.6",
|
"vite-plugin-solid": "^2.11.6",
|
||||||
|
"vitest": "^4.0.12",
|
||||||
"esbuild": "^0.25.0"
|
"esbuild": "^0.25.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:package && pnpm build:license",
|
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:package && pnpm build:license",
|
||||||
"copy:license": "cp ../../LICENSE ./LICENSE",
|
"copy:license": "cp ../../LICENSE ./LICENSE",
|
||||||
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.svelte && rm -rf ./src/icons/*.ts && rm -f index.js",
|
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.svelte && rm -f index.js",
|
||||||
"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: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",
|
"build:package": "svelte-package --input ./src",
|
||||||
"build:license": "node ./scripts/appendBlockComments.mts",
|
"build:license": "node ./scripts/appendBlockComments.mts",
|
||||||
@@ -65,11 +65,13 @@
|
|||||||
"@testing-library/svelte": "^4.0.2",
|
"@testing-library/svelte": "^4.0.2",
|
||||||
"@tsconfig/svelte": "^5.0.0",
|
"@tsconfig/svelte": "^5.0.0",
|
||||||
"jest-serializer-html": "^7.1.0",
|
"jest-serializer-html": "^7.1.0",
|
||||||
|
"jsdom": "^20.0.3",
|
||||||
"svelte": "^4.2.19",
|
"svelte": "^4.2.19",
|
||||||
"svelte-check": "^3.4.4",
|
"svelte-check": "^3.4.4",
|
||||||
"svelte-preprocess": "^5.0.4",
|
"svelte-preprocess": "^5.0.4",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^7.2.4"
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"svelte": "^3 || ^4 || ^5.0.0-next.42"
|
"svelte": "^3 || ^4 || ^5.0.0-next.42"
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
"rollup": "^4.53.3",
|
"rollup": "^4.53.3",
|
||||||
"rollup-plugin-dts": "^6.2.3",
|
"rollup-plugin-dts": "^6.2.3",
|
||||||
"vite": "^7.2.4",
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12",
|
||||||
"vue": "^3.4.21"
|
"vue": "^3.4.21"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
"rollup": "^4.53.3",
|
"rollup": "^4.53.3",
|
||||||
"rollup-plugin-dts": "^6.2.3",
|
"rollup-plugin-dts": "^6.2.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^7.2.4"
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"test:watch": "vitest watch"
|
"test:watch": "vitest watch"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"vite": "^7.2.4"
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,11 +65,13 @@
|
|||||||
"@testing-library/svelte": "^5.2.7",
|
"@testing-library/svelte": "^5.2.7",
|
||||||
"@tsconfig/svelte": "^5.0.4",
|
"@tsconfig/svelte": "^5.0.4",
|
||||||
"jest-serializer-html": "^7.1.0",
|
"jest-serializer-html": "^7.1.0",
|
||||||
|
"jsdom": "^20.0.3",
|
||||||
"svelte": "^5.20.5",
|
"svelte": "^5.20.5",
|
||||||
"svelte-check": "^4.1.4",
|
"svelte-check": "^4.1.4",
|
||||||
"svelte-preprocess": "^6.0.3",
|
"svelte-preprocess": "^6.0.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^6.3.6"
|
"vite": "^6.3.6",
|
||||||
|
"vitest": "^4.0.12"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"svelte": "^5"
|
"svelte": "^5"
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
"rollup-plugin-dts": "^6.1.0",
|
"rollup-plugin-dts": "^6.1.0",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^7.2.4",
|
"vite": "^7.2.4",
|
||||||
|
"vitest": "^4.0.12",
|
||||||
"vue": "^3.4.21"
|
"vue": "^3.4.21"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
4527
pnpm-lock.yaml
generated
4527
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,6 @@ export default async function generateExportFile(
|
|||||||
iconNodes: Record<string, INode>,
|
iconNodes: Record<string, INode>,
|
||||||
exportModuleNameCasing: 'camel' | 'pascal',
|
exportModuleNameCasing: 'camel' | 'pascal',
|
||||||
iconFileExtension = '',
|
iconFileExtension = '',
|
||||||
useDefaultExports = true,
|
|
||||||
) {
|
) {
|
||||||
const fileName = path.basename(inputEntry);
|
const fileName = path.basename(inputEntry);
|
||||||
|
|
||||||
@@ -26,9 +25,7 @@ export default async function generateExportFile(
|
|||||||
} else if (exportModuleNameCasing === 'pascal') {
|
} else if (exportModuleNameCasing === 'pascal') {
|
||||||
componentName = toPascalCase(iconName);
|
componentName = toPascalCase(iconName);
|
||||||
}
|
}
|
||||||
const importString = `export ${
|
const importString = `export { default as ${componentName} } from './${iconName}${iconFileExtension}';\n`;
|
||||||
useDefaultExports ? `{ default as ${componentName} }` : `*`
|
|
||||||
} from './${iconName}${iconFileExtension}';\n`;
|
|
||||||
return appendFile(importString, fileName, outputDirectory);
|
return appendFile(importString, fileName, outputDirectory);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,7 @@ function generateIconFiles({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const getSvg = () => readSvg(`${iconName}.svg`, iconsDir);
|
const getSvg = () => readSvg(`${iconName}.svg`, iconsDir);
|
||||||
const {
|
const { deprecated = false, toBeRemovedInVersion = undefined } = iconMetaData[iconName];
|
||||||
deprecated = false,
|
|
||||||
toBeRemovedInVersion = undefined,
|
|
||||||
aliases = [],
|
|
||||||
} = iconMetaData[iconName];
|
|
||||||
const deprecationReason = deprecated
|
const deprecationReason = deprecated
|
||||||
? deprecationReasonTemplate(iconMetaData[iconName]?.deprecationReason ?? '', {
|
? deprecationReasonTemplate(iconMetaData[iconName]?.deprecationReason ?? '', {
|
||||||
componentName,
|
componentName,
|
||||||
@@ -68,7 +64,6 @@ function generateIconFiles({
|
|||||||
getSvg,
|
getSvg,
|
||||||
deprecated,
|
deprecated,
|
||||||
deprecationReason,
|
deprecationReason,
|
||||||
aliases,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const output = pretty
|
const output = pretty
|
||||||
@@ -76,7 +71,7 @@ function generateIconFiles({
|
|||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
trailingComma: 'all',
|
trailingComma: 'all',
|
||||||
printWidth: 100,
|
printWidth: 100,
|
||||||
parser: iconFileExtension.endsWith('.ts') ? 'babel-ts' : 'babel',
|
parser: 'babel',
|
||||||
})
|
})
|
||||||
: elementTemplate;
|
: elementTemplate;
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ interface CliArguments {
|
|||||||
separateIconFileExportExtension?: string;
|
separateIconFileExportExtension?: string;
|
||||||
aliasesFileExtension?: string;
|
aliasesFileExtension?: string;
|
||||||
aliasImportFileExtension?: string;
|
aliasImportFileExtension?: string;
|
||||||
useDefaultExports?: boolean;
|
|
||||||
pretty?: boolean;
|
pretty?: boolean;
|
||||||
output: string | undefined;
|
output: string | undefined;
|
||||||
}
|
}
|
||||||
@@ -63,7 +62,6 @@ const {
|
|||||||
separateIconFileExportExtension = undefined,
|
separateIconFileExportExtension = undefined,
|
||||||
aliasesFileExtension = '.js',
|
aliasesFileExtension = '.js',
|
||||||
aliasImportFileExtension = '',
|
aliasImportFileExtension = '',
|
||||||
useDefaultExports = true,
|
|
||||||
pretty = true,
|
pretty = true,
|
||||||
} = cliArguments;
|
} = cliArguments;
|
||||||
|
|
||||||
@@ -127,7 +125,6 @@ async function buildIcons() {
|
|||||||
icons,
|
icons,
|
||||||
exportModuleNameCasing,
|
exportModuleNameCasing,
|
||||||
importImportFileExtension,
|
importImportFileExtension,
|
||||||
useDefaultExports,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,17 +6,14 @@ export type IconNode = [tag: string, attrs: SVGProps][];
|
|||||||
|
|
||||||
export type IconNodeWithChildren = [tag: string, attrs: SVGProps, children: IconNode];
|
export type IconNodeWithChildren = [tag: string, attrs: SVGProps, children: IconNode];
|
||||||
|
|
||||||
export interface ExportTemplate {
|
export type TemplateFunction = (params: {
|
||||||
componentName: string;
|
componentName: string;
|
||||||
iconName: string;
|
iconName: string;
|
||||||
children: IconNode;
|
children: IconNode;
|
||||||
getSvg: () => Promise<string>;
|
getSvg: () => Promise<string>;
|
||||||
deprecated: boolean;
|
deprecated?: boolean;
|
||||||
deprecationReason: string;
|
deprecationReason?: string;
|
||||||
aliases?: (string | AliasDeprecation)[];
|
}) => Promise<string>;
|
||||||
}
|
|
||||||
|
|
||||||
export type TemplateFunction = (params: ExportTemplate) => Promise<string>;
|
|
||||||
|
|
||||||
export type Path = string;
|
export type Path = string;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,15 @@
|
|||||||
import type { TemplateFunction } from '../types.ts';
|
import { type IconNode } from '../types.ts';
|
||||||
|
|
||||||
|
export interface ExportTemplate {
|
||||||
|
componentName: string;
|
||||||
|
iconName: string;
|
||||||
|
children: IconNode;
|
||||||
|
getSvg: () => Promise<string>;
|
||||||
|
deprecated: boolean;
|
||||||
|
deprecationReason: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TemplateFunction = (params: ExportTemplate) => Promise<string>;
|
||||||
|
|
||||||
const defineExportTemplate = (exportFunction: TemplateFunction) => exportFunction;
|
const defineExportTemplate = (exportFunction: TemplateFunction) => exportFunction;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user