mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-19 14:09:22 +01:00
Compare commits
6 Commits
package/an
...
angular-pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6c141221b | ||
|
|
a784e9922c | ||
|
|
1a1843cb2f | ||
|
|
7ced22b514 | ||
|
|
1b72561da4 | ||
|
|
1075461aab |
@@ -95,9 +95,25 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-angular": {
|
"@lucide/angular": {
|
||||||
"order": 6,
|
"order": 6,
|
||||||
"icon": "angular",
|
"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": {
|
||||||
|
"order": 7,
|
||||||
|
"icon": "angular",
|
||||||
"shields": [
|
"shields": [
|
||||||
{
|
{
|
||||||
"alt": "npm",
|
"alt": "npm",
|
||||||
@@ -112,7 +128,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-preact": {
|
"lucide-preact": {
|
||||||
"order": 7,
|
"order": 8,
|
||||||
"icon": "preact",
|
"icon": "preact",
|
||||||
"shields": [
|
"shields": [
|
||||||
{
|
{
|
||||||
@@ -130,7 +146,7 @@
|
|||||||
"@lucide/astro": {
|
"@lucide/astro": {
|
||||||
"docsAlias": "lucide-astro",
|
"docsAlias": "lucide-astro",
|
||||||
"packageDirname": "astro",
|
"packageDirname": "astro",
|
||||||
"order": 8,
|
"order": 9,
|
||||||
"icon": "astro",
|
"icon": "astro",
|
||||||
"iconDark": "astro-dark",
|
"iconDark": "astro-dark",
|
||||||
"shields": [
|
"shields": [
|
||||||
@@ -147,7 +163,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-static": {
|
"lucide-static": {
|
||||||
"order": 9,
|
"order": 10,
|
||||||
"icon": "svg",
|
"icon": "svg",
|
||||||
"shields": [
|
"shields": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,39 +69,39 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
|||||||
link: '/guide/packages/lucide',
|
link: '/guide/packages/lucide',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide React',
|
text: 'React',
|
||||||
link: '/guide/packages/lucide-react',
|
link: '/guide/packages/lucide-react',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Vue',
|
text: 'Vue',
|
||||||
link: '/guide/packages/lucide-vue-next',
|
link: '/guide/packages/lucide-vue-next',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Svelte',
|
text: 'Svelte',
|
||||||
link: '/guide/packages/lucide-svelte',
|
link: '/guide/packages/lucide-svelte',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Solid',
|
text: 'Solid',
|
||||||
link: '/guide/packages/lucide-solid',
|
link: '/guide/packages/lucide-solid',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide React Native',
|
text: 'React Native',
|
||||||
link: '/guide/packages/lucide-react-native',
|
link: '/guide/packages/lucide-react-native',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Angular',
|
text: 'Angular',
|
||||||
link: '/guide/packages/lucide-angular',
|
link: '/guide/packages/angular',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Preact',
|
text: 'Preact',
|
||||||
link: '/guide/packages/lucide-preact',
|
link: '/guide/packages/lucide-preact',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Astro',
|
text: 'Astro',
|
||||||
link: '/guide/packages/lucide-astro',
|
link: '/guide/packages/lucide-astro',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Static',
|
text: 'Static',
|
||||||
link: '/guide/packages/lucide-static',
|
link: '/guide/packages/lucide-static',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const value = computed({
|
|||||||
color: var(--vp-c-text-2);
|
color: var(--vp-c-text-2);
|
||||||
padding: 3px 8px 3px 3px;
|
padding: 3px 8px 3px 3px;
|
||||||
height: auto;
|
height: auto;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
@@ -90,7 +90,7 @@ const value = computed({
|
|||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--vp-c-text-1);
|
color: var(--vp-c-text-1);
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export default {
|
|||||||
label: 'Lucide documentation for Preact',
|
label: 'Lucide documentation for Preact',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'lucide-angular',
|
name: 'angular',
|
||||||
logo: '/framework-logos/angular.svg',
|
logo: '/framework-logos/angular.svg',
|
||||||
label: 'Lucide documentation for Angular',
|
label: 'Lucide documentation for Angular',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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/lucide-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/angular), [Astro](https://lucide.dev/guide/packages/lucide-astro), and [NodeJS](https://lucide.dev/guide/packages/lucide-static#nodejs).
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
|
|||||||
277
docs/guide/packages/angular.md
Normal file
277
docs/guide/packages/angular.md
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
# `@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).
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
# Lucide Angular
|
# Lucide Angular
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
This documentation if 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:**
|
||||||
|
|||||||
@@ -102,16 +102,10 @@ The example below imports all ES Modules, so exercise caution when using it. Imp
|
|||||||
|
|
||||||
### Icon Component Example
|
### Icon Component Example
|
||||||
|
|
||||||
```tsx
|
```jsx
|
||||||
import * as icons from 'lucide-react-native/icons';
|
import { icons } from 'lucide-react-native';
|
||||||
|
|
||||||
interface IconProps {
|
const Icon = ({ name, color, size }) => {
|
||||||
name: keyof typeof icons;
|
|
||||||
color?: string;
|
|
||||||
size?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Icon = ({ name, color, size }: IconProps) => {
|
|
||||||
const LucideIcon = icons[name];
|
const LucideIcon = icons[name];
|
||||||
|
|
||||||
return <LucideIcon color={color} size={size} />;
|
return <LucideIcon color={color} size={size} />;
|
||||||
@@ -122,11 +116,11 @@ export default Icon;
|
|||||||
|
|
||||||
#### Using the Icon Component
|
#### Using the Icon Component
|
||||||
|
|
||||||
```tsx
|
```jsx
|
||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return <Icon name="House" />;
|
return <Icon name="house" />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "../icon.schema.json",
|
|
||||||
"contributors": [
|
|
||||||
"karsa-mistmere"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"toolkit",
|
|
||||||
"tools",
|
|
||||||
"trunk",
|
|
||||||
"chest",
|
|
||||||
"box",
|
|
||||||
"storage",
|
|
||||||
"utility",
|
|
||||||
"utilities",
|
|
||||||
"container",
|
|
||||||
"kit",
|
|
||||||
"set",
|
|
||||||
"repair",
|
|
||||||
"fix",
|
|
||||||
"service",
|
|
||||||
"maintenance",
|
|
||||||
"mechanic",
|
|
||||||
"workshop",
|
|
||||||
"construction",
|
|
||||||
"hardware",
|
|
||||||
"equipment",
|
|
||||||
"gear",
|
|
||||||
"handyman",
|
|
||||||
"engineering",
|
|
||||||
"craft",
|
|
||||||
"diy"
|
|
||||||
],
|
|
||||||
"categories": [
|
|
||||||
"tools",
|
|
||||||
"home"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<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"
|
|
||||||
>
|
|
||||||
<path d="M16 12v4" />
|
|
||||||
<path d="M16 6a2 2 0 0 1 1.414.586l4 4A2 2 0 0 1 22 12v7a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 .586-1.414l4-4A2 2 0 0 1 8 6z" />
|
|
||||||
<path d="M16 6V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2" />
|
|
||||||
<path d="M2 14h20" />
|
|
||||||
<path d="M8 12v4" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 471 B |
4
packages/angular/.vscode/extensions.json
vendored
Normal file
4
packages/angular/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||||
|
"recommendations": ["angular.ng-template"]
|
||||||
|
}
|
||||||
20
packages/angular/.vscode/launch.json
vendored
Normal file
20
packages/angular/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// 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
Normal file
42
packages/angular/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
184
packages/angular/MIGRATION.md
Normal file
184
packages/angular/MIGRATION.md
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
# 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 `provideLucideIcon()`, 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 { LucideAngularModule, AirVent, AlarmClock } from 'lucide-angular';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
LucideAngularModule.pick({ AirVent, AlarmClock }),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Standalone
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { ApplicationConfig } from '@angular/core';
|
||||||
|
|
||||||
|
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(...)`
|
||||||
@@ -27,29 +27,33 @@ Lucide icon library for Angular applications.
|
|||||||
|
|
||||||
# Lucide Angular
|
# Lucide Angular
|
||||||
|
|
||||||
Implementation of the lucide icon library for angular applications.
|
A standalone, signal based, zoneless implementation of the Lucide icon library for Angular applications.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pnpm add lucide-angular
|
pnpm add @lucide/angular
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install lucide-angular
|
npm install @lucide/angular
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yarn add lucide-angular
|
yarn add @lucide/angular
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bun add lucide-angular
|
bun add @lucide/angular
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
For full documentation, visit [lucide.dev](https://lucide.dev/guide/packages/lucide-angular)
|
For full documentation, visit [lucide.dev](https://lucide.dev/guide/packages/angular)
|
||||||
|
|
||||||
|
## Migration guide
|
||||||
|
|
||||||
|
Migrating from `lucide-angular`? Read our [comprehensive migration guide](./MIGRATION.md).
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
{
|
{
|
||||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"newProjectRoot": "projects",
|
"cli": {
|
||||||
|
"packageManager": "pnpm"
|
||||||
|
},
|
||||||
|
"newProjectRoot": ".",
|
||||||
"projects": {
|
"projects": {
|
||||||
"@lucide/angular": {
|
"@lucide/angular": {
|
||||||
"projectType": "library",
|
"projectType": "library",
|
||||||
@@ -44,8 +47,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"cli": {
|
|
||||||
"packageManager": "pnpm"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"build": "pnpm build:ng",
|
"build": "pnpm build:ng",
|
||||||
"copy:license": "cp ../../LICENSE ./LICENSE",
|
"copy:license": "cp ../../LICENSE ./LICENSE",
|
||||||
"clean": "rm -rf dist && rm -rf ./src/icons/*.ts",
|
"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",
|
"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",
|
"build:ng": "ng build --configuration production",
|
||||||
"test": "ng test --no-watch",
|
"test": "ng test --no-watch",
|
||||||
"test:watch": "ng test",
|
"test:watch": "ng test",
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
"@angular/platform-browser": "^21.0.0",
|
"@angular/platform-browser": "^21.0.0",
|
||||||
"@angular/router": "^21.0.0",
|
"@angular/router": "^21.0.0",
|
||||||
"@lucide/build-icons": "workspace:*",
|
"@lucide/build-icons": "workspace:*",
|
||||||
|
"@lucide/helpers": "workspace:*",
|
||||||
"@vitest/browser-playwright": "^4.0.16",
|
"@vitest/browser-playwright": "^4.0.16",
|
||||||
"@vitest/coverage-v8": "^4.0.16",
|
"@vitest/coverage-v8": "^4.0.16",
|
||||||
"angular-eslint": "21.1.0",
|
"angular-eslint": "21.1.0",
|
||||||
@@ -69,7 +70,7 @@
|
|||||||
"vitest": "^4.0.16"
|
"vitest": "^4.0.16"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@angular/common": "13.x - 21.x",
|
"@angular/common": "17.x - 21.x",
|
||||||
"@angular/core": "13.x - 21.x"
|
"@angular/core": "17.x - 21.x"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import base64SVG from '@lucide/build-icons/utils/base64SVG';
|
import base64SVG from '@lucide/build-icons/utils/base64SVG';
|
||||||
import defineExportTemplate from '@lucide/build-icons/utils/defineExportTemplate';
|
import defineExportTemplate from '@lucide/build-icons/utils/defineExportTemplate';
|
||||||
|
import { toPascalCase } from '@lucide/helpers';
|
||||||
|
|
||||||
export default defineExportTemplate(async ({
|
export default defineExportTemplate(async ({
|
||||||
componentName,
|
componentName,
|
||||||
@@ -9,7 +10,6 @@ export default defineExportTemplate(async ({
|
|||||||
deprecated,
|
deprecated,
|
||||||
deprecationReason,
|
deprecationReason,
|
||||||
aliases = [],
|
aliases = [],
|
||||||
toPascalCase,
|
|
||||||
}) => {
|
}) => {
|
||||||
const svgContents = await getSvg();
|
const svgContents = await getSvg();
|
||||||
const svgBase64 = base64SVG(svgContents);
|
const svgBase64 = base64SVG(svgContents);
|
||||||
@@ -49,10 +49,10 @@ import { Component, signal } from '@angular/core';
|
|||||||
standalone: true,
|
standalone: true,
|
||||||
})
|
})
|
||||||
export class ${angularComponentName} extends LucideIconBase {
|
export class ${angularComponentName} extends LucideIconBase {
|
||||||
static iconName = '${iconName}';
|
static readonly iconName = '${iconName}';
|
||||||
static iconData: LucideIconData = ${JSON.stringify(children)};
|
static readonly iconData: LucideIconData = ${JSON.stringify(children)};
|
||||||
override readonly iconName = signal(${angularComponentName}.iconName);
|
protected override readonly iconName = signal(${angularComponentName}.iconName);
|
||||||
override readonly iconData = signal(${angularComponentName}.iconData);
|
protected override readonly iconData = signal(${angularComponentName}.iconData);
|
||||||
}
|
}
|
||||||
|
|
||||||
${aliasComponentNames.map((aliasComponentName) => {
|
${aliasComponentNames.map((aliasComponentName) => {
|
||||||
|
|||||||
@@ -1,18 +1,42 @@
|
|||||||
import { InjectionToken, Provider } from '@angular/core';
|
import { InjectionToken, Provider } from '@angular/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A configuration service for Lucide icon components.
|
* Lucide icon configuration options.
|
||||||
*
|
|
||||||
* You can inject this service, typically in AppComponent, and customize its property values in
|
|
||||||
* order to provide default values for all the icons used in the application.
|
|
||||||
*/
|
*/
|
||||||
export interface LucideConfig {
|
export interface LucideConfig {
|
||||||
|
/**
|
||||||
|
* Stroke color.
|
||||||
|
* @default currentColor
|
||||||
|
*/
|
||||||
color: string;
|
color: string;
|
||||||
|
/**
|
||||||
|
* Width and height.
|
||||||
|
* @default 24
|
||||||
|
*/
|
||||||
size: number;
|
size: number;
|
||||||
|
/**
|
||||||
|
* Stroke width
|
||||||
|
* @default 2
|
||||||
|
*/
|
||||||
strokeWidth: number;
|
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;
|
absoluteStrokeWidth: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default icon configuration options.
|
||||||
|
*/
|
||||||
export const lucideDefaultConfig: LucideConfig = {
|
export const lucideDefaultConfig: LucideConfig = {
|
||||||
color: 'currentColor',
|
color: 'currentColor',
|
||||||
size: 24,
|
size: 24,
|
||||||
@@ -20,13 +44,18 @@ export const lucideDefaultConfig: LucideConfig = {
|
|||||||
absoluteStrokeWidth: false,
|
absoluteStrokeWidth: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LUCIDE_CONFIG = new InjectionToken<LucideConfig>(
|
/**
|
||||||
'Lucide icon config',
|
* Injection token for providing default configuration options.
|
||||||
{
|
*
|
||||||
|
* @internal Use {@link provideLucideConfig}
|
||||||
|
*/
|
||||||
|
export const LUCIDE_CONFIG = new InjectionToken<LucideConfig>('Lucide icon config', {
|
||||||
factory: () => lucideDefaultConfig,
|
factory: () => lucideDefaultConfig,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for default icon configuration options.
|
||||||
|
*/
|
||||||
export function provideLucideConfig(config: Partial<LucideConfig>): Provider {
|
export function provideLucideConfig(config: Partial<LucideConfig>): Provider {
|
||||||
return {
|
return {
|
||||||
provide: LUCIDE_CONFIG,
|
provide: LUCIDE_CONFIG,
|
||||||
|
|||||||
@@ -46,26 +46,61 @@ function transformNumericStringInput(
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
export abstract class LucideIconBase {
|
export abstract class LucideIconBase {
|
||||||
abstract iconName: Signal<Nullable<string>>;
|
protected abstract readonly iconName: Signal<Nullable<string>>;
|
||||||
abstract iconData: Signal<Nullable<LucideIconData>>;
|
protected abstract readonly iconData: Signal<Nullable<LucideIconData>>;
|
||||||
protected readonly iconConfig = inject(LUCIDE_CONFIG);
|
protected readonly iconConfig = inject(LUCIDE_CONFIG);
|
||||||
protected readonly elRef = inject(ElementRef);
|
protected readonly elRef = inject(ElementRef);
|
||||||
protected readonly renderer = inject(Renderer2);
|
protected readonly renderer = inject(Renderer2);
|
||||||
readonly title = input<Nullable<string>>();
|
protected readonly ariaHidden = computed(() => {
|
||||||
readonly ariaHidden = computed(() => {
|
|
||||||
return !this.title();
|
return !this.title();
|
||||||
});
|
});
|
||||||
|
/**
|
||||||
|
* 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, {
|
readonly size = input(this.iconConfig.size, {
|
||||||
transform: (value: Nullable<string | number>) =>
|
transform: (value: Nullable<string | number>) =>
|
||||||
transformNumericStringInput(value, this.iconConfig.size),
|
transformNumericStringInput(value, this.iconConfig.size),
|
||||||
});
|
});
|
||||||
|
/**
|
||||||
|
* Stroke color.
|
||||||
|
* @default currentColor
|
||||||
|
*/
|
||||||
readonly color = input(this.iconConfig.color, {
|
readonly color = input(this.iconConfig.color, {
|
||||||
transform: (value: Nullable<string>) => value ?? this.iconConfig.color,
|
transform: (value: Nullable<string>) => value ?? this.iconConfig.color,
|
||||||
});
|
});
|
||||||
|
/**
|
||||||
|
* Stroke width
|
||||||
|
* @default 2
|
||||||
|
*/
|
||||||
readonly strokeWidth = input(this.iconConfig.strokeWidth, {
|
readonly strokeWidth = input(this.iconConfig.strokeWidth, {
|
||||||
transform: (value: Nullable<string | number>) =>
|
transform: (value: Nullable<string | number>) =>
|
||||||
transformNumericStringInput(value, this.iconConfig.strokeWidth),
|
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, {
|
readonly absoluteStrokeWidth = input(this.iconConfig.absoluteStrokeWidth, {
|
||||||
transform: (value: Nullable<boolean>) => value ?? this.iconConfig.absoluteStrokeWidth,
|
transform: (value: Nullable<boolean>) => value ?? this.iconConfig.absoluteStrokeWidth,
|
||||||
});
|
});
|
||||||
@@ -83,20 +118,20 @@ export abstract class LucideIconBase {
|
|||||||
if (icon) {
|
if (icon) {
|
||||||
const elements = icon.map(([name, attrs]) => {
|
const elements = icon.map(([name, attrs]) => {
|
||||||
const element = this.renderer.createElement(name, 'http://www.w3.org/2000/svg');
|
const element = this.renderer.createElement(name, 'http://www.w3.org/2000/svg');
|
||||||
for (const [name, value] of Object.entries(attrs)) {
|
Object.entries(attrs).forEach(([name, value]) =>
|
||||||
this.renderer.setAttribute(
|
this.renderer.setAttribute(
|
||||||
element,
|
element,
|
||||||
name,
|
name,
|
||||||
typeof value === 'number' ? value.toString(10) : value,
|
typeof value === 'number' ? value.toString(10) : value,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
this.renderer.appendChild(this.elRef.nativeElement, element);
|
this.renderer.appendChild(this.elRef.nativeElement, element);
|
||||||
return element;
|
return element;
|
||||||
});
|
});
|
||||||
onCleanup(() => {
|
onCleanup(() => {
|
||||||
for (const element of elements) {
|
elements.forEach((element) =>
|
||||||
this.renderer.removeChild(this.elRef.nativeElement, element);
|
this.renderer.removeChild(this.elRef.nativeElement, element),
|
||||||
}
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ interface LucideResolvedIcon {
|
|||||||
data: LucideIconData;
|
data: LucideIconData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic icon component for rendering LucideIconData.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'svg[lucideIcon]',
|
selector: 'svg[lucideIcon]',
|
||||||
templateUrl: './lucide-icon.html',
|
templateUrl: './lucide-icon.html',
|
||||||
@@ -24,10 +27,10 @@ export class LucideIcon extends LucideIconBase {
|
|||||||
readonly resolvedIcon = computed<LucideResolvedIcon | null>(() => {
|
readonly resolvedIcon = computed<LucideResolvedIcon | null>(() => {
|
||||||
return this.resolveIcon(this.name(), this.iconInput());
|
return this.resolveIcon(this.name(), this.iconInput());
|
||||||
});
|
});
|
||||||
override readonly iconName = computed(() => {
|
protected override readonly iconName = computed(() => {
|
||||||
return this.resolvedIcon()?.name;
|
return this.resolvedIcon()?.name;
|
||||||
});
|
});
|
||||||
override readonly iconData = computed(() => {
|
protected override readonly iconData = computed(() => {
|
||||||
return this.resolvedIcon()?.data;
|
return this.resolvedIcon()?.data;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,40 @@ import { LucideIconData, LucideIcons } from './types';
|
|||||||
import { isLucideIconComponent, LucideIconComponentType } from './types';
|
import { isLucideIconComponent, LucideIconComponentType } from './types';
|
||||||
import { toKebabCase } from './utils/to-kebab-case';
|
import { toKebabCase } from './utils/to-kebab-case';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection token for providing Lucide icons by name.
|
||||||
|
*
|
||||||
|
* @internal Use {@link provideLucideConfig}
|
||||||
|
*/
|
||||||
export const LUCIDE_ICONS = new InjectionToken<LucideIcons>('Lucide icons', {
|
export const LUCIDE_ICONS = new InjectionToken<LucideIcons>('Lucide icons', {
|
||||||
factory: () => ({}),
|
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(
|
export function provideLucideIcons(
|
||||||
icons: Record<string, LucideIconData | LucideIconComponentType> | Array<LucideIconComponentType>,
|
icons: Record<string, LucideIconData | LucideIconComponentType> | Array<LucideIconComponentType>,
|
||||||
): Provider {
|
): Provider {
|
||||||
|
|||||||
@@ -5,20 +5,27 @@ export type LucideIconNode = readonly [string, HtmlAttributes];
|
|||||||
export type LucideIconData = readonly LucideIconNode[];
|
export type LucideIconData = readonly LucideIconNode[];
|
||||||
export type LucideIcons = { [key: string]: LucideIconData };
|
export type LucideIcons = { [key: string]: LucideIconData };
|
||||||
|
|
||||||
export interface LucideIconComponentInterface {
|
/**
|
||||||
|
* 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<{
|
||||||
iconName: Signal<Nullable<string>>;
|
iconName: Signal<Nullable<string>>;
|
||||||
iconData: Signal<Nullable<LucideIconData>>;
|
iconData: Signal<Nullable<LucideIconData>>;
|
||||||
}
|
}> & {
|
||||||
|
|
||||||
export type LucideIconComponentType = Type<LucideIconComponentInterface> & {
|
|
||||||
iconName: string;
|
iconName: string;
|
||||||
iconData: LucideIconData;
|
iconData: LucideIconData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type guard for {@link LucideIconData}
|
||||||
|
*/
|
||||||
export function isLucideIconData(icon: unknown): icon is LucideIconData {
|
export function isLucideIconData(icon: unknown): icon is LucideIconData {
|
||||||
return Array.isArray(icon);
|
return Array.isArray(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type guard for {@link LucideIconComponentType}
|
||||||
|
*/
|
||||||
export function isLucideIconComponent(icon: unknown): icon is LucideIconComponentType {
|
export function isLucideIconComponent(icon: unknown): icon is LucideIconComponentType {
|
||||||
return (
|
return (
|
||||||
icon instanceof Type &&
|
icon instanceof Type &&
|
||||||
@@ -31,4 +38,7 @@ export function isLucideIconComponent(icon: unknown): icon is LucideIconComponen
|
|||||||
|
|
||||||
export type LucideIconInput = LucideIconComponentType | LucideIconData | string;
|
export type LucideIconInput = LucideIconComponentType | LucideIconData | string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
export type Nullable<T> = T | null | undefined;
|
export type Nullable<T> = T | null | undefined;
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
import { Component } from '@angular/core';
|
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
import { formatFixed, LucideIcon } from './lucide-icon.component';
|
|
||||||
import defaultAttributes from '../icons/constants/default-attributes';
|
|
||||||
import { LucideIconData } from '../icons/types';
|
|
||||||
|
|
||||||
describe('LucideAngularComponent', () => {
|
|
||||||
let testHostComponent: TestHostComponent;
|
|
||||||
let testHostFixture: ComponentFixture<TestHostComponent>;
|
|
||||||
const getSvgAttribute = (attr: string) =>
|
|
||||||
testHostFixture.nativeElement.querySelector('svg').getAttribute(attr);
|
|
||||||
const testIcon: LucideIconData = [['polyline', { points: '1 1 22 22' }]];
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
declarations: [LucideIcon, TestHostComponent],
|
|
||||||
imports: [],
|
|
||||||
}).compileComponents();
|
|
||||||
testHostFixture = TestBed.createComponent(TestHostComponent);
|
|
||||||
testHostComponent = testHostFixture.componentInstance;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
expect(testHostComponent).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add all classes', () => {
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
|
|
||||||
expect(getSvgAttribute('class')).toBe('lucide lucide-demo my-icon');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set color', () => {
|
|
||||||
const color = 'red';
|
|
||||||
testHostComponent.setColor(color);
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke')).toBe(color);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set size', () => {
|
|
||||||
const size = 12;
|
|
||||||
testHostComponent.setSize(size);
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('width')).toBe(size.toString(10));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set stroke width', () => {
|
|
||||||
const strokeWidth = 1.41;
|
|
||||||
testHostComponent.setStrokeWidth(strokeWidth);
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke-width')).toBe(strokeWidth.toString(10));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should adjust stroke width', () => {
|
|
||||||
const strokeWidth = 2;
|
|
||||||
const size = 12;
|
|
||||||
testHostComponent.setStrokeWidth(strokeWidth);
|
|
||||||
testHostComponent.setSize(12);
|
|
||||||
testHostComponent.setAbsoluteStrokeWidth(true);
|
|
||||||
testHostFixture.detectChanges();
|
|
||||||
expect(getSvgAttribute('stroke-width')).toBe(
|
|
||||||
formatFixed(strokeWidth / (size / defaultAttributes.height))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'lucide-spec-host-component',
|
|
||||||
template: ` <i-lucide
|
|
||||||
name="demo"
|
|
||||||
[img]="testIcon"
|
|
||||||
class="my-icon"
|
|
||||||
[color]="color"
|
|
||||||
[size]="size"
|
|
||||||
[strokeWidth]="strokeWidth"
|
|
||||||
[absoluteStrokeWidth]="absoluteStrokeWidth"
|
|
||||||
></i-lucide>`,
|
|
||||||
})
|
|
||||||
class TestHostComponent {
|
|
||||||
color?: string;
|
|
||||||
size?: number;
|
|
||||||
strokeWidth?: number;
|
|
||||||
absoluteStrokeWidth = true;
|
|
||||||
readonly testIcon = testIcon;
|
|
||||||
|
|
||||||
setColor(color: string): void {
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSize(size: number): void {
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
setStrokeWidth(strokeWidth: number): void {
|
|
||||||
this.strokeWidth = strokeWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
setAbsoluteStrokeWidth(absoluteStrokeWidth: boolean): void {
|
|
||||||
this.absoluteStrokeWidth = absoluteStrokeWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
import {
|
|
||||||
ChangeDetectorRef,
|
|
||||||
Component,
|
|
||||||
ElementRef,
|
|
||||||
Inject,
|
|
||||||
Input,
|
|
||||||
OnChanges,
|
|
||||||
OnInit,
|
|
||||||
Renderer2,
|
|
||||||
SimpleChange,
|
|
||||||
Type,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { LucideIconData } from '../icons/types';
|
|
||||||
import defaultAttributes from '../icons/constants/default-attributes';
|
|
||||||
import { LucideIconConfig } from './lucide-icon.config';
|
|
||||||
|
|
||||||
interface TypedChange<T> extends SimpleChange {
|
|
||||||
previousValue: T;
|
|
||||||
currentValue: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
type SvgAttributes = { [key: string]: string | number };
|
|
||||||
|
|
||||||
type LucideAngularComponentChanges = {
|
|
||||||
name?: TypedChange<string | LucideIconData>;
|
|
||||||
icon?: TypedChange<LucideIconData | undefined>;
|
|
||||||
color?: TypedChange<string>;
|
|
||||||
size?: TypedChange<number>;
|
|
||||||
strokeWidth?: TypedChange<number>;
|
|
||||||
absoluteStrokeWidth?: TypedChange<boolean>;
|
|
||||||
class: TypedChange<string>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function formatFixed(number: number, decimals = 3): string {
|
|
||||||
return parseFloat(number.toFixed(decimals)).toString(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LucideIconComponentType = Type<LucideIcon> & { iconData: LucideIconData; name: string };
|
|
||||||
|
|
||||||
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'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
// eslint-disable-next-line @angular-eslint/component-selector
|
|
||||||
selector: 'svg[lucideIcon]',
|
|
||||||
template: '<ng-content></ng-content>',
|
|
||||||
standalone: true,
|
|
||||||
})
|
|
||||||
// eslint-disable-next-line @angular-eslint/component-class-suffix
|
|
||||||
export class LucideIcon implements OnInit, OnChanges {
|
|
||||||
@Input() class?: string;
|
|
||||||
_name?: string;
|
|
||||||
@Input() set name(name: string | undefined) {
|
|
||||||
this._name = name;
|
|
||||||
}
|
|
||||||
get name() {
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
_icon?: LucideIconData | LucideIconComponentType | null;
|
|
||||||
@Input('lucideIcon') set icon(icon: LucideIconData | LucideIconComponentType | null | undefined) {
|
|
||||||
this._icon = icon;
|
|
||||||
}
|
|
||||||
get icon() {
|
|
||||||
return this._icon;
|
|
||||||
}
|
|
||||||
@Input() color?: string;
|
|
||||||
@Input() absoluteStrokeWidth = false;
|
|
||||||
defaultSize: number;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Inject(ElementRef) protected elem: ElementRef,
|
|
||||||
@Inject(Renderer2) protected renderer: Renderer2,
|
|
||||||
@Inject(ChangeDetectorRef) protected changeDetector: ChangeDetectorRef,
|
|
||||||
@Inject(LucideIconConfig) protected iconConfig: LucideIconConfig
|
|
||||||
) {
|
|
||||||
this.defaultSize = defaultAttributes.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
_size?: number;
|
|
||||||
|
|
||||||
get size(): number {
|
|
||||||
return this._size ?? this.iconConfig.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input() set size(value: string | number | undefined) {
|
|
||||||
if (value) {
|
|
||||||
this._size = this.parseNumber(value);
|
|
||||||
} else {
|
|
||||||
delete this._size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_strokeWidth?: number;
|
|
||||||
|
|
||||||
get strokeWidth(): number {
|
|
||||||
return this._strokeWidth ?? this.iconConfig.strokeWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input() set strokeWidth(value: string | number | undefined) {
|
|
||||||
if (value) {
|
|
||||||
this._strokeWidth = this.parseNumber(value);
|
|
||||||
} else {
|
|
||||||
delete this._strokeWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.buildIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnChanges(changes: LucideAngularComponentChanges): void {
|
|
||||||
if (
|
|
||||||
changes.name ||
|
|
||||||
changes.icon ||
|
|
||||||
changes.color ||
|
|
||||||
changes.size ||
|
|
||||||
changes.absoluteStrokeWidth ||
|
|
||||||
changes.strokeWidth ||
|
|
||||||
changes.class
|
|
||||||
) {
|
|
||||||
this.buildIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.changeDetector.markForCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
buildIcon(): void {
|
|
||||||
this.color = this.color ?? this.iconConfig.color;
|
|
||||||
this.size = this.parseNumber(this.size ?? this.iconConfig.size);
|
|
||||||
this.strokeWidth = this.parseNumber(this.strokeWidth ?? this.iconConfig.strokeWidth);
|
|
||||||
this.absoluteStrokeWidth = this.absoluteStrokeWidth ?? this.iconConfig.absoluteStrokeWidth;
|
|
||||||
console.log('Hello, my name is ', this.name, ' my icon is ', this.icon);
|
|
||||||
if (this.icon) {
|
|
||||||
this.replaceElement(isLucideIconComponent(this.icon) ? this.icon.iconData : this.icon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceElement(img: LucideIconData): void {
|
|
||||||
const attributes = {
|
|
||||||
...defaultAttributes,
|
|
||||||
width: this.size,
|
|
||||||
height: this.size,
|
|
||||||
stroke: this.color ?? this.iconConfig.color,
|
|
||||||
'stroke-width': this.absoluteStrokeWidth
|
|
||||||
? formatFixed(this.strokeWidth / (this.size / this.defaultSize))
|
|
||||||
: this.strokeWidth.toString(10),
|
|
||||||
};
|
|
||||||
const icoElement = this.elem.nativeElement;
|
|
||||||
for (const [name, value] of Object.entries(attributes)) {
|
|
||||||
icoElement.setAttribute(name, value);
|
|
||||||
}
|
|
||||||
icoElement.classList.add('lucide');
|
|
||||||
if (typeof this.name === 'string') {
|
|
||||||
icoElement.classList.add(`lucide-${this.name.replace('_', '-')}`);
|
|
||||||
}
|
|
||||||
if (this.class) {
|
|
||||||
icoElement.classList.add(
|
|
||||||
...this.class
|
|
||||||
.split(/ /)
|
|
||||||
.map((a) => a.trim())
|
|
||||||
.filter((a) => a.length > 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for (const child of icoElement.children) {
|
|
||||||
this.renderer.removeChild(this.elem.nativeElement, child);
|
|
||||||
}
|
|
||||||
for (const node of img) {
|
|
||||||
const childElement = this.createElement(node);
|
|
||||||
this.renderer.appendChild(icoElement, childElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected parseNumber(value: string | number): number {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
const parsedValue = parseInt(value, 10);
|
|
||||||
if (isNaN(parsedValue)) {
|
|
||||||
throw new Error(`${value} is not numeric.`);
|
|
||||||
}
|
|
||||||
return parsedValue;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected createElement([tag, attrs, children = []]: readonly [
|
|
||||||
string,
|
|
||||||
SvgAttributes,
|
|
||||||
LucideIconData?
|
|
||||||
]) {
|
|
||||||
const element = this.renderer.createElement(tag, 'http://www.w3.org/2000/svg');
|
|
||||||
|
|
||||||
Object.keys(attrs).forEach((name) => {
|
|
||||||
const attrValue: string =
|
|
||||||
typeof attrs[name] === 'string' ? (attrs[name] as string) : attrs[name].toString(10);
|
|
||||||
this.renderer.setAttribute(element, name, attrValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (children.length) {
|
|
||||||
children.forEach((child) => {
|
|
||||||
const childElement = this.createElement(child);
|
|
||||||
this.renderer.appendChild(element, childElement);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,23 +24,11 @@
|
|||||||
"author": "Eric Fennis",
|
"author": "Eric Fennis",
|
||||||
"amdName": "lucide-react-native",
|
"amdName": "lucide-react-native",
|
||||||
"main": "dist/cjs/lucide-react-native.js",
|
"main": "dist/cjs/lucide-react-native.js",
|
||||||
|
"main:umd": "dist/umd/lucide-react-native.js",
|
||||||
"module": "dist/esm/lucide-react-native.js",
|
"module": "dist/esm/lucide-react-native.js",
|
||||||
|
"unpkg": "dist/umd/lucide-react-native.min.js",
|
||||||
"typings": "dist/lucide-react-native.d.ts",
|
"typings": "dist/lucide-react-native.d.ts",
|
||||||
"react-native": "dist/esm/lucide-react-native.js",
|
"react-native": "dist/esm/lucide-react-native.js",
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"types": "./dist/lucide-react-native.d.ts",
|
|
||||||
"import": "./dist/esm/lucide-react-native.js",
|
|
||||||
"browser": "./dist/esm/lucide-react-native.js",
|
|
||||||
"require": "./dist/cjs/lucide-react-native.js"
|
|
||||||
},
|
|
||||||
"./icons": {
|
|
||||||
"types": "./dist/icons.d.ts",
|
|
||||||
"import": "./dist/esm/icons/index.js",
|
|
||||||
"browser": "./dist/esm/icons/index.js",
|
|
||||||
"require": "./dist/cjs/icons/index.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import pkg from './package.json' with { type: 'json' };
|
|||||||
const packageName = 'LucideReact';
|
const packageName = 'LucideReact';
|
||||||
const outputFileName = 'lucide-react-native';
|
const outputFileName = 'lucide-react-native';
|
||||||
const outputDir = 'dist';
|
const outputDir = 'dist';
|
||||||
const inputs = ['src/lucide-react-native.ts', 'src/icons/index.ts'];
|
const inputs = ['src/lucide-react-native.ts'];
|
||||||
const bundles = [
|
const bundles = [
|
||||||
{
|
{
|
||||||
format: 'cjs',
|
format: 'cjs',
|
||||||
@@ -60,16 +60,6 @@ export default [
|
|||||||
],
|
],
|
||||||
plugins: [dts()],
|
plugins: [dts()],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
input: inputs[1],
|
|
||||||
output: [
|
|
||||||
{
|
|
||||||
file: `dist/icons.d.ts`,
|
|
||||||
format: 'es',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
plugins: [dts()],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
input: `src/${outputFileName}.suffixed.ts`,
|
input: `src/${outputFileName}.suffixed.ts`,
|
||||||
output: [
|
output: [
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ const Icon = forwardRef<SVGSVGElement, IconComponentProps>(
|
|||||||
absoluteStrokeWidth,
|
absoluteStrokeWidth,
|
||||||
children,
|
children,
|
||||||
iconNode,
|
iconNode,
|
||||||
className,
|
|
||||||
...rest
|
...rest
|
||||||
},
|
},
|
||||||
ref,
|
ref,
|
||||||
@@ -47,7 +46,6 @@ const Icon = forwardRef<SVGSVGElement, IconComponentProps>(
|
|||||||
{
|
{
|
||||||
ref,
|
ref,
|
||||||
...defaultAttributes,
|
...defaultAttributes,
|
||||||
className,
|
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
...customAttrs,
|
...customAttrs,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './icons';
|
export * from './icons';
|
||||||
|
export * as icons from './icons';
|
||||||
export * from './aliases/prefixed';
|
export * from './aliases/prefixed';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './icons';
|
export * from './icons';
|
||||||
|
export * as icons from './icons';
|
||||||
export * from './aliases/suffixed';
|
export * from './aliases/suffixed';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './icons';
|
export * from './icons';
|
||||||
|
export * as icons from './icons';
|
||||||
export * from './aliases';
|
export * from './aliases';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
|
|||||||
2700
pnpm-lock.yaml
generated
2700
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,6 @@ async function init() {
|
|||||||
useCSSVars: false,
|
useCSSVars: false,
|
||||||
outSVGReact: false,
|
outSVGReact: false,
|
||||||
outSVGPath: false,
|
outSVGPath: false,
|
||||||
addLigatures: true,
|
|
||||||
svgicons2svgfont: {
|
svgicons2svgfont: {
|
||||||
fontHeight: 1000, // At least 1000 is recommended
|
fontHeight: 1000, // At least 1000 is recommended
|
||||||
normalize: false,
|
normalize: false,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ 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);
|
||||||
|
|
||||||
@@ -25,7 +26,9 @@ export default async function generateExportFile(
|
|||||||
} else if (exportModuleNameCasing === 'pascal') {
|
} else if (exportModuleNameCasing === 'pascal') {
|
||||||
componentName = toPascalCase(iconName);
|
componentName = toPascalCase(iconName);
|
||||||
}
|
}
|
||||||
const importString = `export * from './${iconName}${iconFileExtension}';\n`;
|
const importString = `export ${
|
||||||
|
useDefaultExports ? `{ default as ${componentName} }` : `*`
|
||||||
|
} from './${iconName}${iconFileExtension}';\n`;
|
||||||
return appendFile(importString, fileName, outputDirectory);
|
return appendFile(importString, fileName, outputDirectory);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ function generateIconFiles({
|
|||||||
const {
|
const {
|
||||||
deprecated = false,
|
deprecated = false,
|
||||||
toBeRemovedInVersion = undefined,
|
toBeRemovedInVersion = undefined,
|
||||||
aliases,
|
aliases = [],
|
||||||
} = iconMetaData[iconName];
|
} = iconMetaData[iconName];
|
||||||
const deprecationReason = deprecated
|
const deprecationReason = deprecated
|
||||||
? deprecationReasonTemplate(iconMetaData[iconName]?.deprecationReason ?? '', {
|
? deprecationReasonTemplate(iconMetaData[iconName]?.deprecationReason ?? '', {
|
||||||
@@ -69,7 +69,6 @@ function generateIconFiles({
|
|||||||
deprecated,
|
deprecated,
|
||||||
deprecationReason,
|
deprecationReason,
|
||||||
aliases,
|
aliases,
|
||||||
toPascalCase,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const output = pretty
|
const output = pretty
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -62,6 +63,7 @@ const {
|
|||||||
separateIconFileExportExtension = undefined,
|
separateIconFileExportExtension = undefined,
|
||||||
aliasesFileExtension = '.js',
|
aliasesFileExtension = '.js',
|
||||||
aliasImportFileExtension = '',
|
aliasImportFileExtension = '',
|
||||||
|
useDefaultExports = true,
|
||||||
pretty = true,
|
pretty = true,
|
||||||
} = cliArguments;
|
} = cliArguments;
|
||||||
|
|
||||||
@@ -125,6 +127,7 @@ async function buildIcons() {
|
|||||||
icons,
|
icons,
|
||||||
exportModuleNameCasing,
|
exportModuleNameCasing,
|
||||||
importImportFileExtension,
|
importImportFileExtension,
|
||||||
|
useDefaultExports
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,16 +6,17 @@ 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 type TemplateFunction = (params: {
|
export interface ExportTemplate {
|
||||||
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)[];
|
aliases?: (string | AliasDeprecation)[];
|
||||||
toPascalCase: (value: string) => string;
|
}
|
||||||
}) => Promise<string>;
|
|
||||||
|
export type TemplateFunction = (params: ExportTemplate) => Promise<string>;
|
||||||
|
|
||||||
export type Path = string;
|
export type Path = string;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,4 @@
|
|||||||
import { type IconNode } from '../types.ts';
|
import type { TemplateFunction } from '../types.ts';
|
||||||
|
|
||||||
export interface ExportTemplate {
|
|
||||||
componentName: string;
|
|
||||||
iconName: string;
|
|
||||||
children: IconNode;
|
|
||||||
getSvg: () => Promise<string>;
|
|
||||||
deprecated: boolean;
|
|
||||||
deprecationReason: string;
|
|
||||||
aliases: Array<string | { name: string }>;
|
|
||||||
toPascalCase: (value: string) => 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