mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-16 18:27:41 +01:00
Introducing absoluteStrokeWidth option on Lucide Components (#939)
* Add more music icons and another mic icon (#746)
* Revert "Add more music icons and another mic icon (#746)" (#750)
This reverts commit 57cba6ae0e.
* add scale Stroke width
* Added scaleStrokeWidth prop to all packages
* Add scaleStrokeWidth to types
* Rename scaleStrokeWidth to absoluteStrokeWidth
* Adds common API elements to the Angular package (#949)
* Almost complete rewrite of the Angular package
* Update tsconfig.spec.json
* fixes icon build export file name
* Updates Angular documentation with the new properties + provider injection
* Update lucide-angular.md
* refactored scaleStrokeWidth to be absoluteStrokeWidth to match other packages
* removed codelyzer from devDeps + added flexible angular core dependencies
* Deprecates createElement helper in favour of Renderer2 to support SSR
---------
Co-authored-by: Karsa <karsa@karsa.org>
* Add absoluteStrokeWidth in docs
* update snapshots
* Manual merge of main
* Fixed incorrectly merged pnpm-lock.yaml
* Fixes lucide-angular build
* [lucide-angular] Global configuration for properties + bugfix for legacy icon provider (#1012)
* Almost complete rewrite of the Angular package
* Update tsconfig.spec.json
* fixes icon build export file name
* Updates Angular documentation with the new properties + provider injection
* Update lucide-angular.md
* refactored scaleStrokeWidth to be absoluteStrokeWidth to match other packages
* removed codelyzer from devDeps + added flexible angular core dependencies
* Deprecates createElement helper in favour of Renderer2 to support SSR
* Added global configuration and fixed undefined bug in legacy icon provider. Also updated README.md
* Replaces removed line in README.md
* Fixes merge error
* Updates export template to use the non-deprecated type
* downgrade building to ng-cli@13
* downgrade to es2020
---------
Co-authored-by: Karsa <karsa@karsa.org>
* rename scaleStrokeWidth to absoluteStrokeWidth in readme
---------
Co-authored-by: it-is-not <72697755+it-is-not@users.noreply.github.com>
Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Eric Fennis <eric@dreamteam.nl>
Co-authored-by: Karsa <karsa@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@nac41112.nedap.local>
This commit is contained in:
@@ -8,7 +8,7 @@ nextPage:
|
||||
# Introduction
|
||||
Lucide is an open source icon library for displaying icons and symbols in digital and non-digital projects. It consists of 850+ Vector (svg) files. To use these icons, lucide provides several official packages to make it easier to use these icons in projects.
|
||||
|
||||
Lucide contains icons with different variants and states. With that, designers and developers can choose the right icon for themselves. If a desired icon doesn't exist yet, you're free to open a design request. The Lucide community contributors will help to provide new icons.
|
||||
Lucide contains icons with different variants and states. With that, designers and developers can choose the right icon for themselves. If a desired icon doesn't exist yet, you're free to open a design request. The Lucide community contributors will help to provide new icons.
|
||||
|
||||
With more icons, we simply have more icons to work with in our projects. Also with rising of new applications with specific features, lucide has the goal to provide the complete set for your project.
|
||||
|
||||
@@ -16,7 +16,7 @@ When designing new icons, the community is working with a set of design rules. T
|
||||
|
||||
Beside design, code is also important. Assets like icons in, for example, web projects can increase the bandwidth usage significantly. With the growing internet, lucide has the responsibility to keep their assets as small as possible. To achieve this, lucide uses SVG compression and specific code architecture for tree-shaking abilities. After tree-shaking, you will only ship the icons you used, helps you to keep the software distribution size to a minimum.
|
||||
|
||||
Lucide provides several official packages for: [Web (Vanilla)](https://lucide.dev/docs/lucide), [React](https://lucide.dev/docs/lucide-react), [React Native](https://lucide.dev/docs/lucide-react-native), [Vue](https://lucide.dev/docs/lucide-vue), [Vue 3](https://lucide.dev/docs/lucide-vue-next), [Svelte](https://lucide.dev/docs/lucide-svelte),[Preact](https://lucide.dev/docs/lucide-preact), [Angular](https://lucide.dev/docs/lucide-angular), [NodeJS](https://lucide.dev/docs/lucide-static#nodejs) and [Flutter](https://lucide.dev/docs/lucide-flutter).
|
||||
Lucide provides several official packages for: [Web (Vanilla)](https://lucide.dev/docs/lucide), [React](https://lucide.dev/docs/lucide-react), [React Native](https://lucide.dev/docs/lucide-react-native), [Vue](https://lucide.dev/docs/lucide-vue), [Vue 3](https://lucide.dev/docs/lucide-vue-next), [Svelte](https://lucide.dev/docs/lucide-svelte), [Solid](https://lucide.dev/docs/lucide-solid), [Preact](https://lucide.dev/docs/lucide-preact), [Angular](https://lucide.dev/docs/lucide-angular), [NodeJS](https://lucide.dev/docs/lucide-static#nodejs) and [Flutter](https://lucide.dev/docs/lucide-flutter).
|
||||
|
||||
Any questions about lucide? Ask the community. Active on [GitHub](https://github.com/lucide-icons/lucide) and [Discord](https://discord.gg/EH6nSts).
|
||||
|
||||
|
||||
@@ -1,154 +1,109 @@
|
||||
# Lucide Angular
|
||||
|
||||
Implementation of the lucide icon library for angular applications.
|
||||
Implementation of the lucide icon library for Angular applications.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
```bash
|
||||
yarn add lucide-angular
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```bash
|
||||
npm install lucide-angular
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
There are three ways for use this library.
|
||||
### Step 1: Import `LucideAngularModule`
|
||||
|
||||
### Method 1: createElement
|
||||
|
||||
After install `lucide-angular` change content of file `app.component.html` and `app.component.ts`.
|
||||
|
||||
```html
|
||||
<!-- app.component.html -->
|
||||
<div id="lucide-icon"></div>
|
||||
```
|
||||
In any Angular module you wish to use Lucide icons in, you have to import `LucideAngularModule`, and pick any icons you wish to use:
|
||||
|
||||
```js
|
||||
// app.component.ts
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { createElement } from 'lucide-angular';
|
||||
import { Activity } from 'lucide-angular/icons';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
const div = document.getElementById('lucide-icon');
|
||||
const elm = createElement(Activity);
|
||||
elm.setAttribute('color', 'red'); // or set `width`, `height`, `fill`, `stroke-width`, ...
|
||||
|
||||
if (div) {
|
||||
div.appendChild(elm);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Method 2: User **Tag** with **name** property
|
||||
|
||||
After install `lucide-angular` change content of file `app.component.html`, `app.component.ts`, `app.component.css` and `app.module.ts`.
|
||||
|
||||
```js
|
||||
// app.module.ts
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { LucideAngularModule, AlarmCheck, Edit } from 'lucide-angular';
|
||||
import { LucideAngularModule, File, Home, Menu, UserCheck } from 'lucide-angular';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
LucideAngularModule.pick({ AlarmCheck, Edit }) // add all of icons that is imported.
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
LucideAngularModule.pick({File, Home, Menu, UserCheck})
|
||||
]
|
||||
})
|
||||
export class AppModule {}
|
||||
export class AppModule { }
|
||||
```
|
||||
|
||||
### Step 2: Use the icons in templates
|
||||
|
||||
Within your templates you may now use one of the following component tags to insert an icon:
|
||||
|
||||
```html
|
||||
<!-- app.component.html -->
|
||||
<lucide-icon name="alarm-check" class="myicon"></lucide-icon>
|
||||
<lucide-icon name="edit" class="myicon"></lucide-icon>
|
||||
<lucide-angular name="file" class="my-icon"></lucide-angular>
|
||||
<lucide-icon name="home" class="my-icon"></lucide-icon>
|
||||
<i-lucide name="menu" class="my-icon"></i-lucide>
|
||||
<span-lucide name="user-check" class="my-icon"></span-lucide>
|
||||
```
|
||||
|
||||
### Method 3: User **Tag** with **img** property
|
||||
### Props
|
||||
|
||||
After install `lucide-angular` change content of file `app.component.html`, `app.component.ts`, `app.component.css` and `app.module.ts`.
|
||||
You can pass additional props to adjust the icon appearance.
|
||||
|
||||
```js
|
||||
// app.module.ts
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { LucideAngularModule } from 'lucide-angular';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [BrowserModule, AppRoutingModule, LucideAngularModule.pick({})],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {}
|
||||
```html
|
||||
<i-lucide name="home" [size]="48" color="red" [strokeWidth]="1"></i-lucide>
|
||||
```
|
||||
|
||||
```xml
|
||||
<!-- app.component.html -->
|
||||
<lucide-icon [img]="ico1" class="myicon"></lucide-icon>
|
||||
<lucide-icon [img]="ico2" class="myicon"></lucide-icon>
|
||||
```
|
||||
### Global configuration
|
||||
|
||||
```js
|
||||
// app.component.ts
|
||||
import { Component } from '@angular/core';
|
||||
import { Airplay, Circle } from 'lucide-angular';
|
||||
You can inject the `LucideIconConfig` service in your root component to globally configure the default property values as defined above.
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
ico1 = Airplay;
|
||||
ico2 = Circle;
|
||||
### Styling using a custom CSS class
|
||||
|
||||
Any extra HTML attribute is ignored, but the `class` attribute
|
||||
is passed onto the internal SVG image element and it can be used to style it:
|
||||
|
||||
```css
|
||||
svg.my-icon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
stroke-width: 3;
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
## Injecting multiple icon providers
|
||||
|
||||
### Import all icons
|
||||
|
||||
In `Method 2`: import all icons in `app.module.ts` by:
|
||||
You may provide additional icons using the `LUCIDE_ICONS` injection token,
|
||||
which accepts multiple providers of the interface `LucideIconsProviderInterface`
|
||||
with the utility class `LucideIconsProvider` available for easier usage:
|
||||
|
||||
```js
|
||||
import { LUCIDE_ICONS, LucideIconProvider } from 'lucide-angular';
|
||||
import { MyIcon } from './icons/my-icon';
|
||||
|
||||
const myIcons = {MyIcon};
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
{provide: LUCIDE_ICONS, multi: true, useValue: new LucideIconProvider(myIcons)},
|
||||
]
|
||||
})
|
||||
export class AppModule { }
|
||||
```
|
||||
|
||||
To add custom icons, you will first need to convert them to an [svgson format](https://github.com/elrumordelaluz/svgson).
|
||||
|
||||
## Loading all icons
|
||||
|
||||
> :warning: You may also opt to import all icons if necessary using the following format but be aware that this will significantly increase your application build size.
|
||||
|
||||
```js
|
||||
import { icons } from 'lucide-angular';
|
||||
|
||||
LucideAngularModule.pick(icons)
|
||||
|
||||
...
|
||||
|
||||
LucideAngularModule.pick(icons)
|
||||
```
|
||||
|
||||
### Tags
|
||||
|
||||
You can use the following tags instead of `lucide-icon`:
|
||||
|
||||
- lucide-angular
|
||||
- i-lucide
|
||||
- span-lucide
|
||||
|
||||
All of the above are the same
|
||||
|
||||
@@ -41,11 +41,12 @@ export default App;
|
||||
|
||||
### Props
|
||||
|
||||
| name | type | default |
|
||||
| ------------- | -------- | ------------ |
|
||||
| `size` | _Number_ | 24 |
|
||||
| `color` | _String_ | currentColor |
|
||||
| `strokeWidth` | _Number_ | 2 |
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
### Custom props / svg attributes
|
||||
|
||||
|
||||
@@ -39,11 +39,12 @@ export default App;
|
||||
|
||||
### Props
|
||||
|
||||
| name | type | default |
|
||||
| ------------- | -------- | ------------ |
|
||||
| `size` | _Number_ | 24 |
|
||||
| `color` | _String_ | currentColor |
|
||||
| `strokeWidth` | _Number_ | 2 |
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
### Custom props
|
||||
|
||||
|
||||
@@ -37,11 +37,12 @@ export default App;
|
||||
|
||||
### Props
|
||||
|
||||
| name | type | default |
|
||||
| ------------- | -------- | ------------ |
|
||||
| `size` | _Number_ | 24 |
|
||||
| `color` | _String_ | currentColor |
|
||||
| `strokeWidth` | _Number_ | 2 |
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
### Custom props
|
||||
|
||||
|
||||
79
docs/packages/lucide-solid.md
Normal file
79
docs/packages/lucide-solid.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Lucide Solid
|
||||
|
||||
Implementation of the lucide icon library for solid applications.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add lucide-solid
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
npm install lucide-solid
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
It's build with ESmodules so it's completely tree-shakable.
|
||||
Each icon can be imported as a solid component.
|
||||
|
||||
### Example
|
||||
|
||||
You can pass additional props to adjust the icon.
|
||||
|
||||
```js
|
||||
import { Camera } from 'lucide-solid';
|
||||
// Returns SolidComponent
|
||||
|
||||
// Usage
|
||||
const App = () => {
|
||||
return <Camera color="red" size={48} />;
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Props
|
||||
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
### Custom props / svg attributes
|
||||
|
||||
You can also pass custom props that will be added in the as attributes. With that you can modify the icons look by passing svg attributes.
|
||||
|
||||
```js
|
||||
// Usage
|
||||
const App = () => {
|
||||
return <Camera fill="red" stroke-linejoin="bevel" />;
|
||||
};
|
||||
```
|
||||
|
||||
### One generic icon component
|
||||
|
||||
It is possible to create one generic icon component to load icons.
|
||||
|
||||
> :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
|
||||
|
||||
#### Icon Component Example
|
||||
|
||||
```tsx
|
||||
import * as icons from 'lucide-solid';
|
||||
import type { LucideProps } from 'lucide-solid';
|
||||
import { splitProps } from 'solid-js';
|
||||
import { Dynamic } from 'solid-js/web';
|
||||
|
||||
const Icon = (props: { name: keyof typeof icons } & LucideProps) => {
|
||||
const [local, others] = splitProps(props, ["name"]);
|
||||
|
||||
return <Dynamic component={icons[local.name]} {...others} />
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
@@ -42,12 +42,14 @@ You can pass additional props to adjust the icon.
|
||||
|
||||
### Available props
|
||||
|
||||
| name | type | default |
|
||||
| ------------- | -------- | ------------ |
|
||||
| `size` | _Number_ | 24 |
|
||||
| `color` | _String_ | currentColor |
|
||||
| `strokeWidth` | _Number_ | 2 |
|
||||
| `*<SVGProps>` | _String_ | - |
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
| `*<SVGProps>` | *string* | - |
|
||||
|
||||
|
||||
\* All SVGProps are available to style the svgs. See the list of SVG Presentation Attributes on [MDN](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Presentation)
|
||||
|
||||
|
||||
@@ -42,12 +42,13 @@ import { Camera } from 'lucide-vue-next';
|
||||
|
||||
### Props
|
||||
|
||||
| name | type | default
|
||||
| ------------ | -------- | --------
|
||||
| `size` | *Number* | 24
|
||||
| `color` | *String* | currentColor
|
||||
| `stroke-width`| *Number* | 2
|
||||
| `default-class`| *String* | lucide-icon
|
||||
| name | type | default |
|
||||
| ----------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `stroke-width` | *number* | 2 |
|
||||
| `absolute-stroke-width` | *boolean* | false |
|
||||
| `default-class` | *string* | lucide-icon |
|
||||
|
||||
### Custom props
|
||||
|
||||
@@ -69,7 +70,12 @@ It is possible to create one generic icon component to load icons.
|
||||
|
||||
``` html
|
||||
<template>
|
||||
<component :is="icon" :size="size" :color="color" :stroke-width="strokeWidth" :default-class="defaultClass" />
|
||||
<component
|
||||
:is="icon"
|
||||
:size="size"
|
||||
:color="color"
|
||||
:stroke-width="strokeWidth" :default-class="defaultClass"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
@@ -43,12 +43,13 @@ You can pass additional props to adjust the icon.
|
||||
|
||||
### Props
|
||||
|
||||
| name | type | default |
|
||||
| -------------- | -------- | ------------ |
|
||||
| `size` | _Number_ | 24 |
|
||||
| `color` | _String_ | currentColor |
|
||||
| `strokeWidth` | _Number_ | 2 |
|
||||
| `defaultClass` | _String_ | lucide-icon |
|
||||
| name | type | default |
|
||||
| ----------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `stroke-width` | *number* | 2 |
|
||||
| `absolute-stroke-width` | *boolean* | false |
|
||||
| `default-class` | *string* | lucide-icon |
|
||||
|
||||
### Custom props
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"scripts": {
|
||||
"build": "pnpm -r --filter './packages/**' build",
|
||||
"test": "pnpm -r --filter './packages/**' test",
|
||||
"test:update": "pnpm -r --filter './packages/**' --filter !'./packages/lucide-angular' test -- -u",
|
||||
"lucide": "pnpm --filter lucide",
|
||||
"lucide-angular": "pnpm --filter lucide-angular",
|
||||
"lucide-react": "pnpm --filter lucide-react",
|
||||
|
||||
43
packages/lucide-angular/.eslintrc.js
Normal file
43
packages/lucide-angular/.eslintrc.js
Normal file
@@ -0,0 +1,43 @@
|
||||
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"
|
||||
],
|
||||
"rules": {
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "lucide",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": ["lucide", "i", "span"],
|
||||
"style": "kebab-case"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.html"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
};
|
||||
13
packages/lucide-angular/.gitignore
vendored
13
packages/lucide-angular/.gitignore
vendored
@@ -1,13 +1,13 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
|
||||
# dependencies
|
||||
# Node
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
@@ -23,7 +23,8 @@ speed-measure-plugin*.json
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
# Visual Studio Code
|
||||
/.vscode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
@@ -32,7 +33,7 @@ speed-measure-plugin*.json
|
||||
.history/*
|
||||
.editorconfig
|
||||
|
||||
# misc
|
||||
# Miscellaneous
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
@@ -42,7 +43,7 @@ yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
@@ -51,4 +52,4 @@ package-lock.json
|
||||
src/createElement.js
|
||||
|
||||
# angular cache
|
||||
.angular/cache
|
||||
.angular/cache
|
||||
|
||||
@@ -6,150 +6,106 @@ Implementation of the lucide icon library for angular applications.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
```bash
|
||||
yarn add lucide-angular
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```bash
|
||||
npm install lucide-angular
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
There are three ways for use this library.
|
||||
### Step 1: Import `LucideAngularModule`
|
||||
|
||||
### Method 1: createElement
|
||||
|
||||
After install `lucide-angular` change content of file `app.component.html` and `app.component.ts`.
|
||||
|
||||
```html
|
||||
<!-- app.component.html -->
|
||||
<div id="lucide-icon"></div>
|
||||
```
|
||||
In any Angular module you wish to use Lucide icons in, you have to import `LucideAngularModule`, and pick any icons you wish to use:
|
||||
|
||||
```js
|
||||
// app.component.ts
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { createElement } from 'lucide-angular';
|
||||
import { Activity } from 'lucide-angular/icons';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
const div = document.getElementById('lucide-icon');
|
||||
const elm = createElement(Activity);
|
||||
elm.setAttribute('color', 'red'); // or set `width`, `height`, `fill`, `stroke-width`, ...
|
||||
|
||||
if (div) {
|
||||
div.appendChild(elm);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Method 2: User **Tag** with **name** property
|
||||
|
||||
After install `lucide-angular` change content of file `app.component.html`, `app.component.ts`, `app.component.css` and `app.module.ts`.
|
||||
|
||||
```js
|
||||
// app.module.ts
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { LucideAngularModule, AlarmCheck, Edit } from 'lucide-angular';
|
||||
import { LucideAngularModule, File, Home, Menu, UserCheck } from 'lucide-angular';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
LucideAngularModule.pick({ AlarmCheck, Edit }) // add all of icons that is imported.
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
LucideAngularModule.pick({File, Home, Menu, UserCheck})
|
||||
]
|
||||
})
|
||||
export class AppModule {}
|
||||
export class AppModule { }
|
||||
```
|
||||
|
||||
### Step 2: Use the icons in templates
|
||||
|
||||
Within your templates you may now use one of the following component tags to insert an icon:
|
||||
|
||||
```html
|
||||
<!-- app.component.html -->
|
||||
<lucide-icon name="alarm-check" class="myicon"></lucide-icon>
|
||||
<lucide-icon name="edit" class="myicon"></lucide-icon>
|
||||
<lucide-angular name="file" class="my-icon"></lucide-angular>
|
||||
<lucide-icon name="home" class="my-icon"></lucide-icon>
|
||||
<i-lucide name="menu" class="my-icon"></i-lucide>
|
||||
<span-lucide name="user-check" class="my-icon"></span-lucide>
|
||||
```
|
||||
|
||||
### Method 3: User **Tag** with **img** property
|
||||
### Props
|
||||
|
||||
After install `lucide-angular` change content of file `app.component.html`, `app.component.ts`, `app.component.css` and `app.module.ts`.
|
||||
You can pass additional props to adjust the icon appearance.
|
||||
|
||||
```js
|
||||
// app.module.ts
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
| name | type | default |
|
||||
| ------------------ | --------- | ------------ |
|
||||
| `size` | _number_ | 24 |
|
||||
| `color` | _string_ | currentColor |
|
||||
| `strokeWidth` | _number_ | 2 |
|
||||
| `absoluteStrokeWidth` | _boolean_ | true |
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { LucideAngularModule } from 'lucide-angular';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [BrowserModule, AppRoutingModule, LucideAngularModule.pick({})],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {}
|
||||
```html
|
||||
<i-lucide name="home" [size]="48" color="red" [strokeWidth]="1"></i-lucide>
|
||||
```
|
||||
|
||||
```xml
|
||||
<!-- app.component.html -->
|
||||
<lucide-icon [img]="ico1" class="myicon"></lucide-icon>
|
||||
<lucide-icon [img]="ico2" class="myicon"></lucide-icon>
|
||||
```
|
||||
### Global configuration
|
||||
|
||||
```js
|
||||
// app.component.ts
|
||||
import { Component } from '@angular/core';
|
||||
import { Airplay, Circle } from 'lucide-angular';
|
||||
You can inject the `LucideIconConfig` service in your root component to globally configure the default property values as defined above.
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
ico1 = Airplay;
|
||||
ico2 = Circle;
|
||||
### Styling using a custom CSS class
|
||||
|
||||
Any extra HTML attribute is ignored, but the `class` attribute
|
||||
is passed onto the internal SVG image element and it can be used to style it:
|
||||
|
||||
```css
|
||||
svg.my-icon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
stroke-width: 3;
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
## Injecting multiple icon providers
|
||||
|
||||
### Import all icons
|
||||
|
||||
In `Method 2`: import all icons in `app.module.ts` by:
|
||||
You may provide additional icons using the `LUCIDE_ICONS` injection token,
|
||||
which accepts multiple providers of the interface `LucideIconsProviderInterface`
|
||||
with the utility class `LucideIconsProvider` available for easier usage:
|
||||
|
||||
```js
|
||||
...
|
||||
import { icons } from 'lucide-angular';
|
||||
....
|
||||
LucideAngularModule.pick(icons)
|
||||
....
|
||||
import { LUCIDE_ICONS, LucideIconProvider } from 'lucide-angular';
|
||||
import { MyIcon } from './icons/my-icon';
|
||||
|
||||
const myIcons = {MyIcon};
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
{provide: LUCIDE_ICONS, multi: true, useValue: new LucideIconProvider(myIcons)},
|
||||
]
|
||||
})
|
||||
export class AppModule { }
|
||||
```
|
||||
|
||||
### Tags
|
||||
To add custom icons, you will first need to convert them to an [svgson format](https://github.com/elrumordelaluz/svgson).
|
||||
|
||||
You can use the following tags instead of `lucide-icon`:
|
||||
## Loading all icons
|
||||
|
||||
- lucide-angular
|
||||
- i-lucide
|
||||
- span-lucide
|
||||
> :warning: You may also opt to import all icons if necessary using the following format but be aware that this will significantly increase your application build size.
|
||||
|
||||
All of the above are the same
|
||||
```js
|
||||
import { icons } from 'lucide-angular';
|
||||
|
||||
...
|
||||
|
||||
LucideAngularModule.pick(icons)
|
||||
```
|
||||
|
||||
@@ -5,21 +5,24 @@
|
||||
"projects": {
|
||||
"lucide-angular": {
|
||||
"projectType": "library",
|
||||
"root": "",
|
||||
"root": ".",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "lib",
|
||||
"prefix": "lucide",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "tsconfig.lib.json",
|
||||
"project": "ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "tsconfig.lib.prod.json"
|
||||
},
|
||||
"development": {
|
||||
"tsConfig": "tsconfig.lib.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
@@ -30,19 +33,19 @@
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"tsconfig.lib.json",
|
||||
"tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"packageManager": "pnpm"
|
||||
},
|
||||
"defaultProject": "lucide-angular"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
"$schema": "./node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "dist",
|
||||
"lib": {
|
||||
"entryFile": "src/index.ts"
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,44 +28,56 @@
|
||||
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && 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.mjs --iconFileExtension=.ts --exportFileName=index.ts",
|
||||
"build:ng": "ng build --configuration production",
|
||||
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --iconFileExtension=.ts --exportFileName=lucide-icons.ts",
|
||||
"build:ng": "ng build --configuration production",
|
||||
"test": "ng test --no-watch --no-progress --browsers=ChromeHeadlessCI",
|
||||
"test:watch": "ng test",
|
||||
"lint": "ng lint",
|
||||
"lint": "npx eslint 'src/**/*.{js,jsx,ts,tsx,html,css,scss}' --quiet --fix",
|
||||
"format": "npx prettier 'src/**/*.{js,jsx,ts,tsx,html,css,scss}' --write",
|
||||
"e2e": "ng e2e",
|
||||
"version": "pnpm version --git-tag-version=false"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~14.2.6",
|
||||
"@angular/cli": "~14.2.6",
|
||||
"@angular/common": "~14.2.7",
|
||||
"@angular/compiler": "~14.2.7",
|
||||
"@angular/compiler-cli": "~14.2.7",
|
||||
"@angular/core": "~14.2.7",
|
||||
"@angular/platform-browser": "~14.2.7",
|
||||
"@angular/platform-browser-dynamic": "~14.2.7",
|
||||
"@angular-devkit/build-angular": "~13.3.11",
|
||||
"@angular-eslint/builder": "~13.0.0",
|
||||
"@angular-eslint/eslint-plugin": "~13.0.0",
|
||||
"@angular-eslint/eslint-plugin-template": "~13.0.0",
|
||||
"@angular-eslint/schematics": "~13.0.0",
|
||||
"@angular-eslint/template-parser": "~13.0.0",
|
||||
"@angular/cli": "~13.3.11",
|
||||
"@angular/common": "~13.3.0",
|
||||
"@angular/compiler": "~13.3.0",
|
||||
"@angular/compiler-cli": "~13.3.0",
|
||||
"@angular/core": "~13.3.0",
|
||||
"@angular/platform-browser": "~13.3.0",
|
||||
"@angular/platform-browser-dynamic": "~13.3.0",
|
||||
"@lucide/build-icons": "workspace:*",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"@types/node": "^18.11.4",
|
||||
"codelyzer": "^6.0.2",
|
||||
"jasmine-core": "~3.10.1",
|
||||
"@types/jasmine": "~3.10.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.48.2",
|
||||
"@typescript-eslint/parser": "5.48.2",
|
||||
"eslint": "^8.33.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"jasmine-core": "~4.0.0",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "~6.3.14",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.7.0",
|
||||
"ng-packagr": "^14.2.1",
|
||||
"karma-coverage": "~2.1.0",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"ng-packagr": "^13.3.0",
|
||||
"prettier": "^2.8.4",
|
||||
"protractor": "~7.0.0",
|
||||
"puppeteer": "^8.0.0",
|
||||
"rxjs": "7.5.7",
|
||||
"rxjs": "~7.5.0",
|
||||
"ts-node": "~10.9.1",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.8.4",
|
||||
"zone.js": "^0.11.8"
|
||||
"tslib": "^2.3.0",
|
||||
"typescript": "~4.6.2",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "13.x - 15.x",
|
||||
"@angular/core": "13.x - 15.x"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
export default ({ componentName, children }) => `
|
||||
import { IconData } from './types';
|
||||
import { LucideIconData } from './types';
|
||||
import defaultAttributes from './constants/default-attributes';
|
||||
|
||||
const ${componentName}: IconData = [
|
||||
'svg',
|
||||
defaultAttributes,
|
||||
${JSON.stringify(children)}
|
||||
/* eslint-disable no-shadow-restricted-names */
|
||||
const ${componentName}: LucideIconData = [
|
||||
'svg',
|
||||
defaultAttributes,
|
||||
${JSON.stringify(children)}
|
||||
];
|
||||
|
||||
export default ${componentName};
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { IconData } from '../icons/types'
|
||||
|
||||
/**
|
||||
* Creates a new SVGElement from icon node
|
||||
* @param {string} tag
|
||||
* @param {object} attrs
|
||||
* @param {array} children
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
export const createElement = ([tag, attrs, children = []]: IconData): SVGElement => {
|
||||
const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
||||
|
||||
Object.keys(attrs).forEach(name => {
|
||||
element.setAttribute(name, attrs[name]);
|
||||
});
|
||||
|
||||
if (children.length) {
|
||||
children.forEach((child: IconData) => {
|
||||
const childElement = createElement(child);
|
||||
|
||||
element.appendChild(childElement);
|
||||
});
|
||||
}
|
||||
|
||||
return element;
|
||||
};
|
||||
@@ -1,11 +1,11 @@
|
||||
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',
|
||||
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',
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"ngPackage": {
|
||||
"dest": "dist",
|
||||
"lib": {
|
||||
"entryFile": "./index.ts"
|
||||
"entryFile": "../public-api.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
export type IconNode = readonly [string, object];
|
||||
export type IconData = readonly [string, object, IconNode[]? ];
|
||||
export type Icons = { [key: string]: IconData }
|
||||
type HtmlAttributes = { [key: string]: string | number };
|
||||
export type LucideIconNode = readonly [string, HtmlAttributes];
|
||||
export type LucideIconData = readonly [string, HtmlAttributes, LucideIconNode[]?];
|
||||
export type LucideIcons = { [key: string]: LucideIconData };
|
||||
|
||||
/** @deprecated Use LucideIconData instead. Will be removed in v1.0. */
|
||||
export type IconData = LucideIconData;
|
||||
|
||||
/** @deprecated Use LucideIconNode instead. Will be removed in v1.0. */
|
||||
export type IconNode = LucideIconNode;
|
||||
|
||||
/** @deprecated Use LucideIcons instead. Will be removed in v1.0. */
|
||||
export type Icons = LucideIcons;
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import * as icons from './icons';
|
||||
|
||||
export * from './lib/lucide-angular.component';
|
||||
export * from './lib/lucide-angular.module';
|
||||
export * from './helpers/create-element';
|
||||
export * from './icons';
|
||||
export { icons };
|
||||
3
packages/lucide-angular/src/lib/icons.provider.ts
Executable file → Normal file
3
packages/lucide-angular/src/lib/icons.provider.ts
Executable file → Normal file
@@ -1,3 +1,4 @@
|
||||
/** @deprecated Use the injection token LUCIDE_ICONS instead. Will be removed in v1.0. */
|
||||
export class Icons {
|
||||
constructor(private icons: object) {}
|
||||
constructor(private icons: object) {}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,103 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { LucideAngularModule } from './lucide-angular.module';
|
||||
import { LucideAngularComponent } from './lucide-angular.component';
|
||||
import {Component} from '@angular/core';
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {LucideAngularModule} from './lucide-angular.module';
|
||||
import {formatFixed, LucideAngularComponent} from './lucide-angular.component';
|
||||
import defaultAttributes from '../icons/constants/default-attributes';
|
||||
import {LucideIcons} from '../icons/types';
|
||||
|
||||
describe('LucideAngularComponent', () => {
|
||||
let component: LucideAngularComponent;
|
||||
let fixture: ComponentFixture<LucideAngularComponent>;
|
||||
let testHostComponent: TestHostComponent;
|
||||
let testHostFixture: ComponentFixture<TestHostComponent>;
|
||||
const getSvgAttribute = (attr: string) =>
|
||||
testHostFixture.nativeElement.querySelector('svg').getAttribute(attr);
|
||||
const testIcons: LucideIcons = {
|
||||
Demo: [
|
||||
'svg',
|
||||
defaultAttributes,
|
||||
[['polyline', {points: '1 1 22 22'}]],
|
||||
],
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ LucideAngularComponent ],
|
||||
imports: [
|
||||
LucideAngularModule.pick({ })
|
||||
],
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [LucideAngularComponent, TestHostComponent],
|
||||
imports: [
|
||||
LucideAngularModule.pick(testIcons),
|
||||
]
|
||||
}).compileComponents();
|
||||
testHostFixture = TestBed.createComponent(TestHostComponent);
|
||||
testHostComponent = testHostFixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
testHostFixture.detectChanges();
|
||||
expect(testHostComponent).toBeTruthy();
|
||||
});
|
||||
|
||||
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"
|
||||
[color]="color"
|
||||
[size]="size"
|
||||
[strokeWidth]="strokeWidth"
|
||||
[absoluteStrokeWidth]="absoluteStrokeWidth"
|
||||
></i-lucide>`,
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
class TestHostComponent {
|
||||
color?: string;
|
||||
size?: number;
|
||||
strokeWidth?: number;
|
||||
absoluteStrokeWidth = true;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LucideAngularComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
setColor(color: string): void {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
setSize(size: number): void {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
setStrokeWidth(strokeWidth: number): void {
|
||||
this.strokeWidth = strokeWidth;
|
||||
}
|
||||
|
||||
setAbsoluteStrokeWidth(absoluteStrokeWidth: boolean): void {
|
||||
this.absoluteStrokeWidth = absoluteStrokeWidth;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,72 +1,170 @@
|
||||
import { Component, ElementRef, Input, Inject, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { Icons } from './icons.provider';
|
||||
import { IconData } from '../icons/types';
|
||||
import { createElement } from '../helpers/create-element';
|
||||
import {ChangeDetectorRef, Component, Renderer2, ElementRef, Inject, Input, OnChanges, SimpleChange} from '@angular/core';
|
||||
import {LucideIconData} from '../icons/types';
|
||||
import defaultAttributes from '../icons/constants/default-attributes';
|
||||
import {LUCIDE_ICONS, LucideIconProviderInterface} from './lucide-icon.provider';
|
||||
import {LucideIconConfig} from "./lucide-icon.config";
|
||||
|
||||
interface TypedChange<T> extends SimpleChange {
|
||||
previousValue: T;
|
||||
currentValue: T;
|
||||
}
|
||||
|
||||
type LucideAngularComponentChanges = {
|
||||
name?: TypedChange<string|LucideIconData>;
|
||||
color?: TypedChange<string>;
|
||||
size?: TypedChange<number>;
|
||||
strokeWidth?: TypedChange<number>;
|
||||
absoluteStrokeWidth?: TypedChange<boolean>;
|
||||
};
|
||||
|
||||
export function formatFixed(number: number, decimals = 3): string {
|
||||
return parseFloat(number.toFixed(decimals)).toString(10);
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'lucide-angular, lucide-icon, i-lucide, span-lucide',
|
||||
template: `<ng-content></ng-content>`,
|
||||
styles: [`
|
||||
:host {
|
||||
display: inline-block;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
`]
|
||||
selector: 'lucide-angular, lucide-icon, i-lucide, span-lucide',
|
||||
template: '<ng-content></ng-content>',
|
||||
})
|
||||
|
||||
export class LucideAngularComponent implements OnChanges {
|
||||
@Input() name!: string;
|
||||
@Input() img!: IconData;
|
||||
@Input() class?: string;
|
||||
@Input() name?: string|LucideIconData;
|
||||
@Input() set img(img: LucideIconData) {
|
||||
this.name = img;
|
||||
}
|
||||
@Input() color?: string;
|
||||
_size?: number;
|
||||
get size(): number {
|
||||
return this._size ?? this.iconConfig.size;
|
||||
}
|
||||
|
||||
constructor(
|
||||
@Inject(ElementRef) private elem: ElementRef,
|
||||
@Inject(ChangeDetectorRef) private changeDetector: ChangeDetectorRef,
|
||||
@Inject(Icons) private icons: Icons
|
||||
) { }
|
||||
@Input() set size(value: string | number) {
|
||||
this._size = this.parseNumber(value);
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.name) {
|
||||
// icons are provided as an array of objects because of "multi: true"
|
||||
const icons = Object.assign({}, ...(this.icons as any as object[]));
|
||||
const icoOfName = icons[this.toPascalCase(changes.name.currentValue)] || '';
|
||||
_strokeWidth?: number;
|
||||
get strokeWidth(): number {
|
||||
return this._strokeWidth ?? this.iconConfig.strokeWidth;
|
||||
}
|
||||
|
||||
if (!icoOfName) {
|
||||
console.warn(
|
||||
`Icon not found: ${changes.name.currentValue}\n` +
|
||||
`Please check icon name or \'lucide icon list\'`
|
||||
@Input() set strokeWidth(value: string | number) {
|
||||
this._strokeWidth = this.parseNumber(value);
|
||||
}
|
||||
|
||||
@Input() absoluteStrokeWidth = false;
|
||||
defaultSize: number;
|
||||
|
||||
constructor(
|
||||
@Inject(ElementRef) private elem: ElementRef,
|
||||
@Inject(Renderer2) private renderer: Renderer2,
|
||||
@Inject(ChangeDetectorRef) private changeDetector: ChangeDetectorRef,
|
||||
@Inject(LUCIDE_ICONS) private iconProviders: LucideIconProviderInterface[],
|
||||
@Inject(LucideIconConfig) private iconConfig: LucideIconConfig,
|
||||
) {
|
||||
this.defaultSize = defaultAttributes.height;
|
||||
}
|
||||
|
||||
ngOnChanges(changes: LucideAngularComponentChanges): void {
|
||||
this.color = this.color ?? this.iconConfig.color;
|
||||
this.size = this.parseNumber(this.size ?? this.defaultSize);
|
||||
this.strokeWidth = this.parseNumber(
|
||||
this.strokeWidth ?? this.iconConfig.strokeWidth
|
||||
);
|
||||
} else {
|
||||
const icoElement = createElement(icoOfName);
|
||||
icoElement.setAttribute('stroke-width', 'inherit');
|
||||
icoElement.setAttribute('fill', 'inherit');
|
||||
icoElement.removeAttribute('width');
|
||||
icoElement.removeAttribute('height');
|
||||
this.absoluteStrokeWidth = this.absoluteStrokeWidth ?? false;
|
||||
if (changes.name) {
|
||||
const name = changes.name.currentValue;
|
||||
if (typeof name === 'string') {
|
||||
const icoOfName = this.getIcon(this.toPascalCase(name));
|
||||
if (icoOfName) {
|
||||
this.replaceElement(icoOfName);
|
||||
} else {
|
||||
throw new Error(`The "${name}" icon has not been provided by any available icon providers.`);
|
||||
}
|
||||
} else {
|
||||
this.replaceElement(name);
|
||||
}
|
||||
}
|
||||
|
||||
this.elem.nativeElement.innerHTML = '';
|
||||
this.elem.nativeElement.append(icoElement);
|
||||
}
|
||||
}
|
||||
else if (changes.img) {
|
||||
const icoElement = createElement(changes.img.currentValue);
|
||||
icoElement.setAttribute('stroke-width', 'inherit');
|
||||
icoElement.setAttribute('fill', 'inherit');
|
||||
icoElement.removeAttribute('width');
|
||||
icoElement.removeAttribute('height');
|
||||
|
||||
this.elem.nativeElement.innerHTML = '';
|
||||
this.elem.nativeElement.append(icoElement);
|
||||
this.changeDetector.markForCheck();
|
||||
}
|
||||
|
||||
this.changeDetector.markForCheck();
|
||||
}
|
||||
replaceElement(img: LucideIconData): void {
|
||||
const attributes = {
|
||||
...defaultAttributes,
|
||||
...img[1],
|
||||
width:
|
||||
typeof this.size === 'number'
|
||||
? this.size.toString(10)
|
||||
: this.size,
|
||||
height:
|
||||
typeof this.size === 'number'
|
||||
? this.size.toString(10)
|
||||
: 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.createElement([img[0], attributes, img[2]]);
|
||||
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))
|
||||
}
|
||||
const childElements = this.elem.nativeElement.childNodes;
|
||||
for (let child of childElements) {
|
||||
this.renderer.removeChild(this.elem.nativeElement, child);
|
||||
}
|
||||
this.renderer.appendChild(this.elem.nativeElement, icoElement);
|
||||
}
|
||||
|
||||
toPascalCase(str: string): string {
|
||||
return str.replace(/(\w)([a-z0-9]*)(_|-|\s*)/g, (g0, g1, g2) => g1.toUpperCase() + g2.toLowerCase());
|
||||
}
|
||||
toPascalCase(str: string): string {
|
||||
return str.replace(
|
||||
/(\w)([a-z0-9]*)(_|-|\s*)/g,
|
||||
(g0, g1, g2) => g1.toUpperCase() + g2.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private getIcon(name: string): LucideIconData|null {
|
||||
for (const iconProvider of Array.isArray(this.iconProviders) ? this.iconProviders : [this.iconProviders]) {
|
||||
if (iconProvider.hasIcon(name)) {
|
||||
return iconProvider.getIcon(name);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private createElement([tag, attrs, children = []]: 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: LucideIconData) => {
|
||||
const childElement = this.createElement(child);
|
||||
this.renderer.appendChild(element, childElement);
|
||||
});
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
import { NgModule, ModuleWithProviders, Optional } from '@angular/core';
|
||||
import { LucideAngularComponent } from './lucide-angular.component';
|
||||
import { Icons } from './icons.provider';
|
||||
import { IconData } from '../icons/types';
|
||||
import {ModuleWithProviders, NgModule, Optional} from '@angular/core';
|
||||
import {LucideAngularComponent} from './lucide-angular.component';
|
||||
import {LucideIcons} from '../icons/types';
|
||||
import {LUCIDE_ICONS, LucideIconProvider} from './lucide-icon.provider';
|
||||
import {Icons} from './icons.provider';
|
||||
|
||||
const legacyIconProviderFactory = (icons?: LucideIcons) => {
|
||||
return new LucideIconProvider(icons ?? {});
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [LucideAngularComponent],
|
||||
imports: [
|
||||
],
|
||||
exports: [LucideAngularComponent]
|
||||
declarations: [LucideAngularComponent],
|
||||
imports: [],
|
||||
exports: [LucideAngularComponent],
|
||||
})
|
||||
|
||||
export class LucideAngularModule {
|
||||
constructor(@Optional() private icons: Icons) {
|
||||
if (!this.icons) {
|
||||
throw new Error(
|
||||
`No icon provided. Make sure to use 'LucideAngularModule.pick({ ... })' when importing the module\n`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static pick(icons: { [key: string]: IconData }): ModuleWithProviders<LucideAngularModule> {
|
||||
static pick(icons: LucideIcons): ModuleWithProviders<LucideAngularModule> {
|
||||
return {
|
||||
ngModule: LucideAngularModule,
|
||||
providers: [
|
||||
{ provide: Icons, multi: true, useValue: icons }
|
||||
]
|
||||
{provide: LUCIDE_ICONS, multi: true, useValue: new LucideIconProvider(icons)},
|
||||
{provide: LUCIDE_ICONS, multi: true, useFactory: legacyIconProviderFactory, deps: [[new Optional(), Icons]]},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
16
packages/lucide-angular/src/lib/lucide-icon.config.ts
Normal file
16
packages/lucide-angular/src/lib/lucide-icon.config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import defaultAttributes from "../icons/constants/default-attributes";
|
||||
|
||||
/**
|
||||
* A configuration service for Lucide icon components.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class LucideIconConfig {
|
||||
color: string = defaultAttributes.stroke;
|
||||
size: number = defaultAttributes.width;
|
||||
strokeWidth: number = defaultAttributes["stroke-width"];
|
||||
absoluteStrokeWidth: boolean = false;
|
||||
}
|
||||
22
packages/lucide-angular/src/lib/lucide-icon.provider.ts
Normal file
22
packages/lucide-angular/src/lib/lucide-icon.provider.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import {LucideIconData, LucideIcons} from '../icons/types';
|
||||
import {InjectionToken} from '@angular/core';
|
||||
|
||||
export interface LucideIconProviderInterface {
|
||||
hasIcon(name: string): boolean;
|
||||
getIcon(name: string): LucideIconData|null;
|
||||
}
|
||||
|
||||
export const LUCIDE_ICONS = new InjectionToken<LucideIconProviderInterface>('LucideIcons');
|
||||
|
||||
export class LucideIconProvider implements LucideIconProviderInterface {
|
||||
constructor(private icons: LucideIcons) {
|
||||
}
|
||||
|
||||
getIcon(name: string): LucideIconData|null {
|
||||
return this.hasIcon(name) ? this.icons[name] : null;
|
||||
}
|
||||
|
||||
hasIcon(name: string): boolean {
|
||||
return typeof this.icons === 'object' && name in this.icons;
|
||||
}
|
||||
}
|
||||
7
packages/lucide-angular/src/public-api.ts
Normal file
7
packages/lucide-angular/src/public-api.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import * as icons from './icons/lucide-icons';
|
||||
|
||||
export * from './lib/lucide-angular.component';
|
||||
export * from './lib/lucide-angular.module';
|
||||
export * from './lib/lucide-icon.config';
|
||||
export * from './icons/lucide-icons';
|
||||
export { icons };
|
||||
@@ -1,25 +1,26 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(path: string, deep?: boolean, filter?: RegExp): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
context(path: string, deep?: boolean, filter?: RegExp): {
|
||||
<T>(id: string): T;
|
||||
keys(): string[];
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting(),
|
||||
);
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
|
||||
@@ -4,30 +4,34 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"downlevelIteration": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"paths": {
|
||||
"lucide-angular": [
|
||||
"dist"
|
||||
],
|
||||
"lucide-angular/*": [
|
||||
"dist/*"
|
||||
],
|
||||
]
|
||||
},
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
"target": "es2017",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"es2020",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,10 @@
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"enableResourceInlining": true,
|
||||
"fullTemplateTypeCheck": true
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": true,
|
||||
"compilationMode": "partial"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
{
|
||||
"extends": "tslint:recommended",
|
||||
"rulesDirectory": [
|
||||
"codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"align": {
|
||||
"options": [
|
||||
"parameters",
|
||||
"statements"
|
||||
]
|
||||
},
|
||||
"array-type": false,
|
||||
"arrow-return-shorthand": true,
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warning"
|
||||
},
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"",
|
||||
"kebab-case"
|
||||
],
|
||||
"eofline": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"import-spacing": true,
|
||||
"indent": {
|
||||
"options": [
|
||||
"spaces"
|
||||
]
|
||||
},
|
||||
"max-classes-per-file": false,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-empty": false,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-non-null-assertion": true,
|
||||
"no-redundant-jsdoc": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-key-quotes": [
|
||||
true,
|
||||
"as-needed"
|
||||
],
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"semicolon": {
|
||||
"options": [
|
||||
"always"
|
||||
]
|
||||
},
|
||||
"space-before-function-paren": {
|
||||
"options": {
|
||||
"anonymous": "never",
|
||||
"asyncArrow": "always",
|
||||
"constructor": "never",
|
||||
"method": "never",
|
||||
"named": "never"
|
||||
}
|
||||
},
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature"
|
||||
],
|
||||
"typedef-whitespace": {
|
||||
"options": [
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
},
|
||||
{
|
||||
"call-signature": "onespace",
|
||||
"index-signature": "onespace",
|
||||
"parameter": "onespace",
|
||||
"property-declaration": "onespace",
|
||||
"variable-declaration": "onespace"
|
||||
}
|
||||
]
|
||||
},
|
||||
"variable-name": {
|
||||
"options": [
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"allow-pascal-case"
|
||||
]
|
||||
},
|
||||
"whitespace": {
|
||||
"options": [
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type",
|
||||
"check-typecast"
|
||||
]
|
||||
},
|
||||
"component-class-suffix": true,
|
||||
"contextual-lifecycle": true,
|
||||
"directive-class-suffix": true,
|
||||
"no-conflicting-lifecycle": true,
|
||||
"no-host-metadata-property": true,
|
||||
"no-input-rename": true,
|
||||
"no-inputs-metadata-property": true,
|
||||
"no-output-native": true,
|
||||
"no-output-on-prefix": true,
|
||||
"no-output-rename": true,
|
||||
"no-outputs-metadata-property": true,
|
||||
"template-banana-in-box": true,
|
||||
"template-no-negated-async": true,
|
||||
"use-lifecycle-interface": true,
|
||||
"use-pipe-transform-interface": true
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ interface LucideProps extends Partial<Omit<JSX.SVGAttributes, "ref" | "size">> {
|
||||
color?: string
|
||||
size?: string | number
|
||||
strokeWidth?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
export type LucideIcon = (props: LucideProps) => JSX.Element;
|
||||
|
||||
@@ -7,6 +7,7 @@ interface LucideProps extends Partial<Omit<JSX.SVGAttributes, "ref" | "size">> {
|
||||
color?: string
|
||||
size?: string | number
|
||||
strokeWidth?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -21,7 +22,7 @@ export const toKebabCase = (string: string) => string.replace(/([a-z0-9])([A-Z])
|
||||
|
||||
const createLucideIcon = (iconName: string, iconNode: IconNode): FunctionComponent<LucideProps> => {
|
||||
const Component = (
|
||||
{ color = 'currentColor', size = 24, strokeWidth = 2, children, ...rest }: LucideProps
|
||||
{ color = 'currentColor', size = 24, strokeWidth = 2, absoluteStrokeWidth, children, ...rest }: LucideProps
|
||||
) =>
|
||||
h(
|
||||
'svg' as unknown as ComponentType<Partial<JSX.SVGAttributes<SVGElement> & { 'stroke-width': number | string }>>,
|
||||
@@ -30,7 +31,7 @@ const createLucideIcon = (iconName: string, iconNode: IconNode): FunctionCompone
|
||||
width: String(size),
|
||||
height: size,
|
||||
stroke: color,
|
||||
['stroke-width' as 'strokeWidth']: strokeWidth,
|
||||
['stroke-width' as 'strokeWidth']: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
|
||||
class: `lucide lucide-${toKebabCase(iconName)}`,
|
||||
...rest,
|
||||
},
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
|
||||
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"4\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid\\" data-testid=\\"grid-icon\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid\\" data-testid=\\"grid-icon\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render an component 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-grid\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
@@ -2,6 +2,8 @@ import { describe, it, expect } from 'vitest';
|
||||
import { render, cleanup } from '@testing-library/preact'
|
||||
import { Pen, Edit2, Grid } from '../src/lucide-preact';
|
||||
|
||||
type AttributesAssertion = { attributes: Record<string, { value: string }>}
|
||||
|
||||
describe('Using lucide icon components', () => {
|
||||
it('should render an component', () => {
|
||||
const { container } = render( <Grid/> );
|
||||
@@ -20,7 +22,7 @@ describe('Using lucide icon components', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
const { attributes } = getByTestId(testId);
|
||||
const { attributes } = getByTestId(testId) as unknown as AttributesAssertion;
|
||||
expect(attributes.stroke.value).toBe('red');
|
||||
expect(attributes.width.value).toBe('48');
|
||||
expect(attributes.height.value).toBe('48');
|
||||
@@ -54,4 +56,24 @@ describe('Using lucide icon components', () => {
|
||||
|
||||
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML)
|
||||
});
|
||||
|
||||
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||
const testId = 'grid-icon';
|
||||
const { container, getByTestId } = render(
|
||||
<Grid
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
/>,
|
||||
);
|
||||
|
||||
const { attributes } = getByTestId(testId) as unknown as AttributesAssertion;
|
||||
|
||||
expect(attributes.stroke.value).toBe('red');
|
||||
expect(attributes.width.value).toBe('48');
|
||||
expect(attributes.height.value).toBe('48');
|
||||
expect(attributes['stroke-width'].value).toBe('1');
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -29,6 +29,7 @@ declare module 'lucide-react-native'
|
||||
// Create interface extending SVGProps
|
||||
export interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
|
||||
size?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
export type LucideIcon = (props: LucideProps) => JSX.Element;
|
||||
|
||||
@@ -8,20 +8,21 @@ type IconNode = [elementName: keyof ReactSVG, attrs: Record<string, string>][]
|
||||
|
||||
export interface LucideProps extends SvgProps {
|
||||
size?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
const createLucideIcon = (iconName: string, iconNode: IconNode) => {
|
||||
const Component = forwardRef(
|
||||
({ color = 'currentColor', size = 24, strokeWidth = 2, children, ...rest }: LucideProps, ref) =>
|
||||
({ color = 'currentColor', size = 24, strokeWidth = 2, absoluteStrokeWidth, children, ...rest }: LucideProps, ref) =>
|
||||
createElement(
|
||||
NativeSvg.Svg,
|
||||
NativeSvg.Svg as unknown as string,
|
||||
{
|
||||
ref,
|
||||
...defaultAttributes,
|
||||
width: size,
|
||||
height: size,
|
||||
stroke: color,
|
||||
strokeWidth,
|
||||
strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
|
||||
...rest,
|
||||
},
|
||||
[
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
|
||||
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"4\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" data-testid=\\"grid-icon\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" data-testid=\\"grid-icon\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render an component 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\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render } from '@testing-library/react'
|
||||
import { Grid } from '../src/icons'
|
||||
import { cleanup, render } from '@testing-library/react'
|
||||
import { Edit2, Grid, Pen } from '../src/lucide-react-native'
|
||||
|
||||
vi.mock('react-native-svg')
|
||||
|
||||
@@ -32,4 +32,52 @@ describe('Using lucide icon components', () => {
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the alias icon', () => {
|
||||
const testId = 'pen-icon';
|
||||
const { container } = render(
|
||||
<Pen
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
strokeWidth={4}
|
||||
/>,
|
||||
);
|
||||
|
||||
const PenIconRenderedHTML = container.innerHTML
|
||||
|
||||
cleanup()
|
||||
|
||||
const { container: Edit2Container } = render(
|
||||
<Edit2
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
strokeWidth={4}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML)
|
||||
});
|
||||
|
||||
|
||||
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||
const testId = 'grid-icon';
|
||||
const { container, getByTestId } = render(
|
||||
<Grid
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
/>,
|
||||
);
|
||||
|
||||
const { attributes } = getByTestId(testId) as unknown as{ attributes: Record<string, { value: string }>};
|
||||
expect(attributes.stroke.value).toBe('red');
|
||||
expect(attributes.width.value).toBe('48');
|
||||
expect(attributes.height.value).toBe('48');
|
||||
expect(attributes['stroke-width'].value).toBe('1');
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -29,6 +29,7 @@ declare module 'lucide-react'
|
||||
// Create interface extending SVGProps
|
||||
export interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
|
||||
size?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
export type LucideIcon = (props: LucideProps) => JSX.Element;
|
||||
|
||||
@@ -7,6 +7,7 @@ export type SVGAttributes = Partial<SVGProps<SVGSVGElement>>
|
||||
|
||||
export interface LucideProps extends SVGAttributes {
|
||||
size?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
/**
|
||||
* Converts string to KebabCase
|
||||
@@ -20,7 +21,7 @@ export const toKebabCase = (string: string) => string.replace(/([a-z0-9])([A-Z])
|
||||
|
||||
const createLucideIcon = (iconName: string, iconNode: IconNode) => {
|
||||
const Component = forwardRef<SVGSVGElement, LucideProps>(
|
||||
({ color = 'currentColor', size = 24, strokeWidth = 2, children, ...rest }, ref) =>
|
||||
({ color = 'currentColor', size = 24, strokeWidth = 2, absoluteStrokeWidth, children, ...rest }, ref) =>
|
||||
createElement(
|
||||
'svg',
|
||||
{
|
||||
@@ -29,7 +30,7 @@ const createLucideIcon = (iconName: string, iconNode: IconNode) => {
|
||||
width: size,
|
||||
height: size,
|
||||
stroke: color,
|
||||
strokeWidth,
|
||||
strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
|
||||
className: `lucide lucide-${toKebabCase(iconName)}`,
|
||||
...rest,
|
||||
},
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
|
||||
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"4\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid\\" data-testid=\\"grid-icon\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid\\" data-testid=\\"grid-icon\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render an component 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-grid\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
@@ -30,10 +30,8 @@ describe('Using lucide icon components', () => {
|
||||
});
|
||||
|
||||
it('should render the alias icon', () => {
|
||||
const testId = 'pen-icon';
|
||||
const { container } = render(
|
||||
<Pen
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
strokeWidth={4}
|
||||
@@ -46,7 +44,6 @@ describe('Using lucide icon components', () => {
|
||||
|
||||
const { container: Edit2Container } = render(
|
||||
<Edit2
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
strokeWidth={4}
|
||||
@@ -55,4 +52,25 @@ describe('Using lucide icon components', () => {
|
||||
|
||||
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML)
|
||||
});
|
||||
|
||||
|
||||
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||
const testId = 'grid-icon';
|
||||
const { container, getByTestId } = render(
|
||||
<Grid
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
/>,
|
||||
);
|
||||
|
||||
const { attributes } = getByTestId(testId) as unknown as{ attributes: Record<string, { value: string }>};
|
||||
expect(attributes.stroke.value).toBe('red');
|
||||
expect(attributes.width.value).toBe('48');
|
||||
expect(attributes.height.value).toBe('48');
|
||||
expect(attributes['stroke-width'].value).toBe('1');
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -30,6 +30,7 @@ interface LucideProps extends Partial<JSX.SvgSVGAttributes<SVGSVGElement>> {
|
||||
color?: string
|
||||
size?: string | number
|
||||
strokeWidth?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
class?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ const Icon = (props: LucideProps & IconProps) => {
|
||||
'children',
|
||||
'class',
|
||||
'name',
|
||||
'iconNode'
|
||||
'iconNode',
|
||||
'absoluteStrokeWidth'
|
||||
]);
|
||||
|
||||
return (
|
||||
@@ -35,7 +36,11 @@ const Icon = (props: LucideProps & IconProps) => {
|
||||
width={localProps.size ?? defaultAttributes.width}
|
||||
height={localProps.size ?? defaultAttributes.height}
|
||||
stroke={localProps.color ?? defaultAttributes.stroke}
|
||||
stroke-width={localProps.strokeWidth ?? defaultAttributes['stroke-width']}
|
||||
stroke-width={
|
||||
localProps.absoluteStrokeWidth
|
||||
? Number(localProps.strokeWidth ?? defaultAttributes['stroke-width']) * 24 / (Number(localProps.size))
|
||||
: Number(localProps.strokeWidth ?? defaultAttributes['stroke-width'])
|
||||
}
|
||||
class={`lucide lucide-${toKebabCase(localProps?.name ?? 'icon')} ${
|
||||
localProps.class != null ? localProps.class : ''
|
||||
}`}
|
||||
|
||||
@@ -9,4 +9,5 @@ export interface LucideProps extends SVGAttributes {
|
||||
size?: string | number
|
||||
strokeWidth?: string | number
|
||||
class?: string
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
|
||||
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"4\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" data-testid=\\"grid-icon\\" class=\\"lucide lucide-grid \\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\" key=\\"1m3agn\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\" key=\\"1vqk6q\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\" key=\\"o2sbyz\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\" key=\\"13tij5\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\" key=\\"1hpv9i\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" data-testid=\\"grid-icon\\" class=\\"lucide lucide-grid \\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\" key=\\"1m3agn\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\" key=\\"1vqk6q\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\" key=\\"o2sbyz\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\" key=\\"13tij5\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\" key=\\"1hpv9i\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render an component 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-grid \\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\" key=\\"1m3agn\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\" key=\\"1vqk6q\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\" key=\\"o2sbyz\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\" key=\\"13tij5\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\" key=\\"1hpv9i\\"></line></svg>"`;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { render } from 'solid-testing-library'
|
||||
import { Grid } from '../src/icons'
|
||||
import { cleanup, render } from 'solid-testing-library'
|
||||
import { Edit2, Grid, Pen } from '../src/lucide-solid'
|
||||
|
||||
describe('Using lucide icon components', () => {
|
||||
it('should render an component', () => {
|
||||
const { container } = render(() => <Grid /> );
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
cleanup()
|
||||
});
|
||||
|
||||
it('should adjust the size, stroke color and stroke width', async () => {
|
||||
@@ -26,5 +27,56 @@ describe('Using lucide icon components', () => {
|
||||
expect(attributes.height.value).toBe('48');
|
||||
expect(attributes['stroke-width'].value).toBe('4');
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
cleanup()
|
||||
});
|
||||
|
||||
it('should render the alias icon', () => {
|
||||
const testId = 'pen-icon';
|
||||
const { container } = render(() =>
|
||||
<Pen
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
strokeWidth={4}
|
||||
/>,
|
||||
);
|
||||
|
||||
const PenIconRenderedHTML = container.innerHTML
|
||||
|
||||
cleanup()
|
||||
|
||||
const { container: Edit2Container } = render(() =>
|
||||
<Edit2
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
stroke="red"
|
||||
strokeWidth={4}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML)
|
||||
cleanup()
|
||||
});
|
||||
|
||||
|
||||
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||
const testId = 'grid-icon';
|
||||
const { container, getByTestId } = render(() =>
|
||||
<Grid
|
||||
data-testid={testId}
|
||||
size={48}
|
||||
color="red"
|
||||
absoluteStrokeWidth
|
||||
/>,
|
||||
);
|
||||
|
||||
const { attributes } = getByTestId(testId) as unknown as{ attributes: Record<string, { value: string }>};
|
||||
expect(attributes.stroke.value).toBe('red');
|
||||
expect(attributes.width.value).toBe('48');
|
||||
expect(attributes.height.value).toBe('48');
|
||||
expect(attributes['stroke-width'].value).toBe('1');
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
cleanup()
|
||||
});
|
||||
})
|
||||
|
||||
@@ -31,8 +31,9 @@ import { SvelteComponentTyped } from "svelte";
|
||||
|
||||
interface IconProps extends Partial<svelte.JSX.SVGProps<SVGSVGElement>> {
|
||||
color?: string
|
||||
size?: number|string,
|
||||
strokeWidth?: number|string,
|
||||
size?: number|string
|
||||
strokeWidth?: number|string
|
||||
absoluteStrokeWidth?: boolean
|
||||
class?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
export let name: string
|
||||
export let color = 'currentColor'
|
||||
export let size: number|string = 24
|
||||
export let strokeWidth: number|string = 2
|
||||
export let size: number | string = 24
|
||||
export let strokeWidth: number | string = 2
|
||||
export let absoluteStrokeWidth: boolean = false
|
||||
export let iconNode: IconNode
|
||||
</script>
|
||||
|
||||
@@ -15,7 +16,11 @@
|
||||
width={size}
|
||||
height={size}
|
||||
stroke={color}
|
||||
stroke-width={strokeWidth}
|
||||
stroke-width={
|
||||
absoluteStrokeWidth
|
||||
? Number(strokeWidth) * 24 / Number(size)
|
||||
: strokeWidth
|
||||
}
|
||||
class={`lucide-icon lucide lucide-${name} ${$$props.class ?? ''}`}
|
||||
>
|
||||
{#each iconNode as [tag, attrs]}
|
||||
|
||||
@@ -86,6 +86,8 @@ exports[`Using lucide icon components > should adjust the size, stroke color and
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `"<div><svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" data-testid=\\"smile-icon\\" class=\\"lucide-icon lucide lucide-smile \\"><circle cx=\\"12\\" cy=\\"12\\" r=\\"10\\"></circle><path d=\\"M8 14s1.5 2 4 2 4-2 4-2\\"></path><line x1=\\"9\\" x2=\\"9.01\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"15\\" x2=\\"15.01\\" y1=\\"9\\" y2=\\"9\\"></line></svg></div>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render an component 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { render, cleanup } from '@testing-library/svelte';
|
||||
import { Smile } from '../src/icons'
|
||||
import { render, cleanup, logDOM } from '@testing-library/svelte';
|
||||
import { Smile, Pen, Edit2 } from '../src/lucide-svelte'
|
||||
import TestSlots from './TestSlots.svelte'
|
||||
|
||||
describe('Using lucide icon components', () => {
|
||||
@@ -54,4 +54,34 @@ describe('Using lucide icon components', () => {
|
||||
expect(textElement).toBeInTheDocument();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the alias icon', () => {
|
||||
const { container } = render(Pen);
|
||||
|
||||
const PenIconRenderedHTML = container.innerHTML
|
||||
|
||||
cleanup()
|
||||
|
||||
const { container: Edit2Container } = render(Edit2);
|
||||
|
||||
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML)
|
||||
});
|
||||
|
||||
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||
const testId = 'smile-icon';
|
||||
const { container, getByTestId } = render(Smile, {
|
||||
'data-testid':testId,
|
||||
color: 'red',
|
||||
size: 48,
|
||||
absoluteStrokeWidth: true
|
||||
});
|
||||
|
||||
const { attributes } = getByTestId(testId) as unknown as{ attributes: Record<string, { value: string }>};
|
||||
expect(attributes.stroke.value).toBe('red');
|
||||
expect(attributes.width.value).toBe('48');
|
||||
expect(attributes.height.value).toBe('48');
|
||||
expect(attributes['stroke-width'].value).toBe('1');
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,12 +45,13 @@ export default {
|
||||
|
||||
### Props
|
||||
|
||||
| name | type | default |
|
||||
| -------------- | -------- | ------------ |
|
||||
| `size` | _Number_ | 24 |
|
||||
| `color` | _String_ | currentColor |
|
||||
| `strokeWidth` | _Number_ | 2 |
|
||||
| `defaultClass` | _String_ | lucide-icon |
|
||||
| name | type | default |
|
||||
| ----------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `stroke-width` | *number* | 2 |
|
||||
| `absolute-stroke-width` | *boolean* | false |
|
||||
| `default-class` | *string* | lucide-icon |
|
||||
|
||||
### Custom props
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ declare module 'lucide-vue-next'
|
||||
// Create interface extending SVGAttributes
|
||||
export interface SVGProps extends Partial<SVGAttributes> {
|
||||
size?: 24 | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
export type Icon = (props: SVGProps) => FunctionalComponent<SVGProps>
|
||||
|
||||
@@ -5,6 +5,8 @@ import defaultAttributes from './defaultAttributes';
|
||||
// Create interface extending SVGAttributes
|
||||
export interface SVGProps extends Partial<SVGAttributes> {
|
||||
size?: 24 | number
|
||||
strokeWidth?: number | string
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +23,7 @@ type IconNode = [elementName: string, attrs: Record<string, string>][]
|
||||
export const toKebabCase = (string: string) => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
|
||||
const createLucideIcon = (iconName: string, iconNode: IconNode): FunctionalComponent<SVGProps> => (
|
||||
{ size, color, ...props }, // props
|
||||
{ size, strokeWidth = 2, absoluteStrokeWidth, color, ...props }, // props
|
||||
{ attrs, slots } // context
|
||||
) => {
|
||||
return h(
|
||||
@@ -31,6 +33,7 @@ const createLucideIcon = (iconName: string, iconNode: IconNode): FunctionalCompo
|
||||
width: size || defaultAttributes.width,
|
||||
height: size || defaultAttributes.height,
|
||||
stroke: color || defaultAttributes.stroke,
|
||||
'stroke-width': absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
|
||||
...attrs,
|
||||
class: ['lucide', `lucide-${toKebabCase(iconName)}`, attrs?.class || ''],
|
||||
...props,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import {render, fireEvent, cleanup } from '@testing-library/vue'
|
||||
import { Smile } from '../src/icons'
|
||||
import { Smile, Edit2, Pen } from '../src/lucide-vue-next'
|
||||
|
||||
describe('Using lucide icon components', () => {
|
||||
afterEach(() => cleanup())
|
||||
@@ -89,4 +89,46 @@ describe('Using lucide icon components', () => {
|
||||
expect(textElement).toBeInTheDocument()
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the alias icon', () => {
|
||||
const { container } = render(Pen, {
|
||||
props: {
|
||||
size: 48,
|
||||
color: 'red',
|
||||
'stroke-width': 4
|
||||
}
|
||||
})
|
||||
|
||||
const PenIconRenderedHTML = container.innerHTML
|
||||
|
||||
cleanup()
|
||||
|
||||
const { container: Edit2Container } = render(Edit2, {
|
||||
props: {
|
||||
size: 48,
|
||||
color: 'red',
|
||||
'stroke-width': 4
|
||||
}
|
||||
})
|
||||
|
||||
console.log(PenIconRenderedHTML, Edit2Container.innerHTML)
|
||||
|
||||
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML)
|
||||
})
|
||||
|
||||
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||
render(Pen, {
|
||||
props: {
|
||||
size: 48,
|
||||
color: 'red',
|
||||
absoluteStrokeWidth: true
|
||||
}
|
||||
})
|
||||
|
||||
const [icon] = document.getElementsByClassName('lucide');
|
||||
|
||||
expect(icon.getAttribute('width')).toBe('48')
|
||||
expect(icon.getAttribute('stroke')).toBe('red')
|
||||
expect(icon.getAttribute('stroke-width')).toBe('1')
|
||||
})
|
||||
});
|
||||
|
||||
@@ -45,12 +45,13 @@ export default {
|
||||
|
||||
### Props
|
||||
|
||||
| name | type | default |
|
||||
| -------------- | -------- | ------------ |
|
||||
| `size` | _Number_ | 24 |
|
||||
| `color` | _String_ | currentColor |
|
||||
| `strokeWidth` | _Number_ | 2 |
|
||||
| `defaultClass` | _String_ | lucide-icon |
|
||||
| name | type | default |
|
||||
| ----------------------- | --------- | ------------ |
|
||||
| `size` | *number* | 24 |
|
||||
| `color` | *string* | currentColor |
|
||||
| `stroke-width` | *number* | 2 |
|
||||
| `absolute-stroke-width` | *boolean* | false |
|
||||
| `default-class` | *string* | lucide-icon |
|
||||
|
||||
### Custom props
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@ export default (iconName: string, iconNode: IconNode): Component => ({
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
absoluteStrokeWidth: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
defaultClass: {
|
||||
type: String,
|
||||
default: `lucide-icon lucide lucide-${toKebabCase(iconName).replace('-icon', '')}`,
|
||||
@@ -38,7 +42,7 @@ export default (iconName: string, iconNode: IconNode): Component => ({
|
||||
render(
|
||||
createElement,
|
||||
{
|
||||
props: { color, size, strokeWidth, defaultClass },
|
||||
props: { color, size, strokeWidth, absoluteStrokeWidth, defaultClass },
|
||||
data,
|
||||
children = [],
|
||||
},
|
||||
@@ -54,7 +58,10 @@ export default (iconName: string, iconNode: IconNode): Component => ({
|
||||
width: size,
|
||||
height: size,
|
||||
stroke: color,
|
||||
'stroke-width': strokeWidth,
|
||||
'stroke-width':
|
||||
absoluteStrokeWidth
|
||||
? Number(strokeWidth) * 24 / Number(size)
|
||||
: strokeWidth,
|
||||
...data.attrs,
|
||||
},
|
||||
on: data?.on || {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render, fireEvent, cleanup } from '@testing-library/vue'
|
||||
import { Smile } from '../src/icons'
|
||||
import { Smile, Pen, Edit2 } from '../src/lucide-vue'
|
||||
import { afterEach } from 'vitest';
|
||||
import { VueClass } from '@vue/test-utils';
|
||||
|
||||
@@ -88,4 +88,44 @@ describe('Using lucide icon components', () => {
|
||||
expect(textElement).toBeInTheDocument()
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the alias icon', () => {
|
||||
const { getByText, container } = render(Pen as VueClass<any>, {
|
||||
props: {
|
||||
size: '48',
|
||||
color: 'red',
|
||||
strokeWidth: '4'
|
||||
}
|
||||
})
|
||||
|
||||
const PenIconRenderedHTML = container.innerHTML
|
||||
|
||||
cleanup()
|
||||
|
||||
const { container: Edit2Container } = render(Edit2 as VueClass<any>, {
|
||||
props: {
|
||||
size: '48',
|
||||
color: 'red',
|
||||
strokeWidth: '4'
|
||||
}
|
||||
})
|
||||
|
||||
expect(PenIconRenderedHTML).toBe(Edit2Container.innerHTML)
|
||||
})
|
||||
|
||||
it('should not scale the strokeWidth when absoluteStrokeWidth is set', () => {
|
||||
const { getByText, container } = render(Pen as VueClass<any>, {
|
||||
props: {
|
||||
size: '48',
|
||||
color: 'red',
|
||||
absoluteStrokeWidth: true
|
||||
}
|
||||
})
|
||||
|
||||
const [icon] = document.getElementsByClassName('lucide');
|
||||
|
||||
expect(icon.getAttribute('width')).toBe('48')
|
||||
expect(icon.getAttribute('stroke')).toBe('red')
|
||||
expect(icon.getAttribute('stroke-width')).toBe('1')
|
||||
})
|
||||
});
|
||||
|
||||
12360
pnpm-lock.yaml
generated
12360
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user