diff --git a/README.md b/README.md
index 9c122e22f..df786025a 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ We're trying to expanding the icon set as much as possible while keeping it nice
* [Web](#web)
* [React](#react)
* [Vue](#vue)
+ * [Angular](#angular)
* [Figma](#figma)
* [Contributing](#contributing)
* [Community](#community)
@@ -82,6 +83,18 @@ npm install lucide-vue
For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue#lucide-vue).
+### Angular
+
+```sh
+yarn add lucide-angular
+
+# or
+
+npm install lucide-angular
+```
+
+For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/packages/lucide-angular/projects/lucide-angular#lucide-angular).
+
### Figma
The lucide figma plugin.
diff --git a/package.json b/package.json
index c2372f385..f11861ccb 100644
--- a/package.json
+++ b/package.json
@@ -1,13 +1,25 @@
{
"private": true,
- "workspaces": [
- "packages/*",
- "site"
- ],
+ "workspaces": {
+ "packages": [
+ "packages/*",
+ "site"
+ ],
+ "nohoist": [
+ "**/jest", "**/jest/**",
+ "**/jasmine", "**/jasmine/**",
+ "**/react", "**/react/**",
+ "**/testing-library__jest-dom", "**/testing-library__jest-dom/**",
+ "**/testing-library__react-hooks", "**/testing-library__react-hooks/**",
+ "**/react-dom", "**/react-dom/**",
+ "**/react-test-renderer", "**/react-test-renderer/**"
+ ]
+ },
"scripts": {
"build": "yarn lucide build && yarn lucide-react build && yarn lucide-vue build",
"test": "yarn lucide build:icons && yarn lucide-react build:icons && yarn lucide-vue build:icons && jest",
"lucide": "yarn workspace lucide",
+ "lucide-angular": "yarn workspace lucide-angular",
"lucide-react": "yarn workspace lucide-react",
"lucide-vue": "yarn workspace lucide-vue",
"build:icons": "babel-node ./scripts/buildIcons.js --presets @babel/env",
diff --git a/packages/lucide-angular/.gitignore b/packages/lucide-angular/.gitignore
new file mode 100644
index 000000000..5d67e7fda
--- /dev/null
+++ b/packages/lucide-angular/.gitignore
@@ -0,0 +1,51 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# compiled output
+/dist
+/tmp
+/out-tsc
+# Only exists if Bazel was run
+/bazel-out
+
+# dependencies
+/node_modules
+
+# profiling files
+chrome-profiler-events*.json
+speed-measure-plugin*.json
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# IDE - VSCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+.editorconfig
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage
+/libpeerconnection.log
+npm-debug.log
+yarn-error.log
+testem.log
+/typings
+
+# System Files
+.DS_Store
+Thumbs.db
+
+#npm-yarn
+package-lock.json
+yarn.lock
diff --git a/packages/lucide-angular/angular.json b/packages/lucide-angular/angular.json
new file mode 100644
index 000000000..059734448
--- /dev/null
+++ b/packages/lucide-angular/angular.json
@@ -0,0 +1,48 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "lucide-angular": {
+ "projectType": "library",
+ "root": "projects/lucide-angular",
+ "sourceRoot": "projects/lucide-angular/src",
+ "prefix": "lib",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:ng-packagr",
+ "options": {
+ "tsConfig": "projects/lucide-angular/tsconfig.lib.json",
+ "project": "projects/lucide-angular/ng-package.json"
+ },
+ "configurations": {
+ "production": {
+ "tsConfig": "projects/lucide-angular/tsconfig.lib.prod.json"
+ }
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "projects/lucide-angular/src/test.ts",
+ "tsConfig": "projects/lucide-angular/tsconfig.spec.json",
+ "karmaConfig": "projects/lucide-angular/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "projects/lucide-angular/tsconfig.lib.json",
+ "projects/lucide-angular/tsconfig.spec.json"
+ ],
+ "exclude": [
+ "**/node_modules/**"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "defaultProject": "lucide-angular"
+}
diff --git a/packages/lucide-angular/package.json b/packages/lucide-angular/package.json
new file mode 100644
index 000000000..0274cdd71
--- /dev/null
+++ b/packages/lucide-angular/package.json
@@ -0,0 +1,65 @@
+{
+ "name": "lucide-angular",
+ "description": "Lucide Angular package, Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
+ "version": "0.15.0",
+ "author": "SMAH1",
+ "license": "ISC",
+ "homepage": "https://lucide.dev",
+ "bugs": "https://github.com/lucide-icons/lucide/issues",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/lucide-icons/lucide.git",
+ "directory": "packages/lucide-vue"
+ },
+ "keywords": [
+ "Lucide",
+ "Angular",
+ "Feather",
+ "Icons",
+ "Icon",
+ "Feather Icons",
+ "Fontawesome",
+ "Font Awesome"
+ ],
+ "scripts": {
+ "build": "yarn clean && yarn build:js && yarn build:icons && yarn build:iconsindex && yarn build:ng",
+ "clean": "rm -rf dist && rm -rf projects/lucide-angular/build",
+ "build:js": "mkdir -p projects/lucide-angular/build && cp -av ../lucide/src/createElement.js projects/lucide-angular/build/",
+ "build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-angular/projects/lucide-angular/build --templateSrc=../packages/lucide-angular/scripts/exportTemplate && for f in projects/lucide-angular/build/icons/*.js; do mv -- \"$f\" \"${f%.js}.ts\"; done",
+ "build:iconsindex": "yarn --cwd ../../ babel-node packages/lucide-angular/scripts/buildIconsIndex.js",
+ "build:ng": "ng build --prod",
+ "test:headless": "ng test --no-watch --no-progress --browsers=ChromeHeadlessCI",
+ "test": "ng test",
+ "lint": "ng lint",
+ "e2e": "ng e2e"
+ },
+ "dependencies": {
+ "@angular/common": "~11.2.6",
+ "@angular/compiler": "~11.2.6",
+ "@angular/core": "~11.2.6",
+ "@angular/platform-browser": "~11.2.6",
+ "@angular/platform-browser-dynamic": "~11.2.6",
+ "tslib": "^2.0.0"
+ },
+ "devDependencies": {
+ "@angular-devkit/build-angular": "~0.1102.5",
+ "@angular/cli": "~11.2.5",
+ "@angular/compiler-cli": "~11.2.6",
+ "@types/jasmine": "~3.6.0",
+ "@types/node": "^12.11.1",
+ "codelyzer": "^6.0.0",
+ "jasmine-core": "~3.6.0",
+ "jasmine-spec-reporter": "~5.0.0",
+ "karma": "~6.1.0",
+ "karma-chrome-launcher": "~3.1.0",
+ "karma-coverage": "~2.0.3",
+ "karma-jasmine": "~4.0.0",
+ "karma-jasmine-html-reporter": "^1.5.0",
+ "ng-packagr": "^11.0.0",
+ "protractor": "~7.0.0",
+ "puppeteer": "^8.0.0",
+ "ts-node": "~8.3.0",
+ "tslint": "~6.1.0",
+ "typescript": "~4.1.5"
+ }
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/README.md b/packages/lucide-angular/projects/lucide-angular/README.md
new file mode 100644
index 000000000..4c3b21878
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/README.md
@@ -0,0 +1,191 @@
+# Lucide Angular
+
+Implementation of the lucide icon library for angular applications.
+
+> What is lucide? Read it [here](https://github.com/lucide-icons/lucide#what-is-lucide).
+
+## Installation
+
+``` sh
+yarn add lucide-angular
+
+# or
+
+npm install lucide-angular
+```
+
+## How to use
+
+There are three ways for use this library.
+
+### Method 1: createElement
+
+After install `lucide-angular` change content of file `app.component.html` and `app.component.ts`.
+
+``` xml
+
+
+```
+
+``` 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('ico');
+ const elm = createElement(Activity);
+ elm.setAttribute('color', 'red'); // or set `width`, `height`, `fill`, `stroke-width`, ...
+ 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 } from 'lucide-angular';
+import { AlarmCheck, Edit } from 'lucide-angular/icons'; // or import other icons
+
+@NgModule({
+ declarations: [
+ AppComponent
+ ],
+ imports: [
+ BrowserModule,
+ AppRoutingModule,
+ LucideAngularModule.pick({ AlarmCheck, Edit }) // add all of icons that is imported.
+ ],
+ providers: [],
+ bootstrap: [AppComponent]
+})
+export class AppModule { }
+```
+
+``` css
+/* app.component.css */
+.myicon {
+ /* Be sure to set these values */
+ width: 48px;
+ height: 48px;
+ /* or other properties like `color`, `fill`, `stroke-width` */
+}
+```
+
+``` xml
+
+
+
+```
+
+``` js
+// app.component.ts
+
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+
+}
+```
+
+### Method 3: User __Tag__ with __img__ 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 } from 'lucide-angular';
+
+@NgModule({
+ declarations: [
+ AppComponent
+ ],
+ imports: [
+ BrowserModule,
+ AppRoutingModule,
+ LucideAngularModule.pick({ })
+ ],
+ providers: [],
+ bootstrap: [AppComponent]
+})
+export class AppModule { }
+```
+
+``` css
+/* app.component.css */
+.myicon {
+ /* Be sure to set these values */
+ width: 48px;
+ height: 48px;
+ /* or other properties like `color`, `fill`, `stroke-width` */
+}
+```
+
+``` xml
+
+
+
+```
+
+``` js
+// app.component.ts
+import { Component } from '@angular/core';
+import { Airplay, Circle } from 'lucide-angular/icons';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.css']
+})
+export class AppComponent {
+ ico1 = Airplay;
+ ico2 = Circle;
+}
+```
+
+## Notes
+
+### Import all icons
+
+In `Method 2`: import all icons in `app.module.ts` by:
+``` js
+...
+import { icons } from 'lucide-angular/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
diff --git a/packages/lucide-angular/projects/lucide-angular/default-attributes.ts b/packages/lucide-angular/projects/lucide-angular/default-attributes.ts
new file mode 100644
index 000000000..8ae7d46ea
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/default-attributes.ts
@@ -0,0 +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',
+};
diff --git a/packages/lucide-angular/projects/lucide-angular/icons-index.ts b/packages/lucide-angular/projects/lucide-angular/icons-index.ts
new file mode 100644
index 000000000..9b54f0f0b
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/icons-index.ts
@@ -0,0 +1,4 @@
+export * from './build/icons-index';
+
+import * as icons from './build/icons-index';
+export { icons };
diff --git a/packages/lucide-angular/projects/lucide-angular/icons/package.json b/packages/lucide-angular/projects/lucide-angular/icons/package.json
new file mode 100644
index 000000000..84efc25d1
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/icons/package.json
@@ -0,0 +1,7 @@
+{
+ "ngPackage": {
+ "lib": {
+ "entryFile": "../icons-index.ts"
+ }
+ }
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/karma.conf.js b/packages/lucide-angular/projects/lucide-angular/karma.conf.js
new file mode 100644
index 000000000..5fe10e39f
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/karma.conf.js
@@ -0,0 +1,51 @@
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+process.env.CHROME_BIN = require('puppeteer').executablePath();
+
+module.exports = function (config) {
+ config.set({
+ basePath: '',
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-chrome-launcher'),
+ require('karma-jasmine-html-reporter'),
+ require('karma-coverage'),
+ require('@angular-devkit/build-angular/plugins/karma')
+ ],
+ client: {
+ jasmine: {
+ // you can add configuration options for Jasmine here
+ // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
+ // for example, you can disable the random execution with `random: false`
+ // or set a specific seed with `seed: 4321`
+ },
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
+ },
+ jasmineHtmlReporter: {
+ suppressAll: true // removes the duplicated traces
+ },
+ coverageReporter: {
+ dir: require('path').join(__dirname, '../../coverage/lucide-angular'),
+ subdir: '.',
+ reporters: [
+ { type: 'html' },
+ { type: 'text-summary' }
+ ]
+ },
+ reporters: ['progress', 'kjhtml'],
+ port: 9876,
+ colors: true,
+ logLevel: config.LOG_INFO,
+ autoWatch: true,
+ browsers: ['ChromeHeadlessCI'],
+ customLaunchers: {
+ ChromeHeadlessCI: {
+ base: 'ChromeHeadless',
+ flags: ['--no-sandbox']
+ }
+ },
+ singleRun: false,
+ restartOnFileChange: true
+ });
+};
diff --git a/packages/lucide-angular/projects/lucide-angular/lib-index.ts b/packages/lucide-angular/projects/lucide-angular/lib-index.ts
new file mode 100644
index 000000000..74e83bebf
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/lib-index.ts
@@ -0,0 +1,4 @@
+
+export * from './src/lib/lucide-angular.component';
+export * from './src/lib/lucide-angular.module';
+export * from './lucide';
diff --git a/packages/lucide-angular/projects/lucide-angular/lucide.ts b/packages/lucide-angular/projects/lucide-angular/lucide.ts
new file mode 100644
index 000000000..dd773b473
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/lucide.ts
@@ -0,0 +1,10 @@
+export type IconNode = readonly [string, object];
+export type IconData = readonly [string, object, IconNode[] ];
+
+export declare const icons: { [key: string]: IconData };
+
+import { default as createElementTmp } from './build/createElement';
+
+export function createElement(ico: IconData): HTMLElement {
+ return createElementTmp(ico as any);
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/ng-package.json b/packages/lucide-angular/projects/lucide-angular/ng-package.json
new file mode 100644
index 000000000..3b1643920
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/ng-package.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
+ "dest": "../../dist/lucide-angular",
+ "lib": {
+ "entryFile": "./lib-index.ts"
+ }
+}
\ No newline at end of file
diff --git a/packages/lucide-angular/projects/lucide-angular/package.json b/packages/lucide-angular/projects/lucide-angular/package.json
new file mode 100644
index 000000000..2f36465a4
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "lucide-angular",
+ "description": "Lucide Angular package, Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
+ "version": "0.15.0",
+ "author": "SMAH1",
+ "license": "ISC",
+ "homepage": "https://lucide.dev",
+ "bugs": "https://github.com/lucide-icons/lucide/issues",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/lucide-icons/lucide.git",
+ "directory": "packages/lucide-vue"
+ },
+ "keywords": [
+ "Lucide",
+ "Angular",
+ "Feather",
+ "Icons",
+ "Icon",
+ "Feather Icons",
+ "Fontawesome",
+ "Font Awesome"
+ ],
+ "peerDependencies": {
+ "@angular/common": "^11.2.6",
+ "@angular/core": "^11.2.6"
+ },
+ "dependencies": {
+ "tslib": "^2.0.0"
+ }
+}
\ No newline at end of file
diff --git a/packages/lucide-angular/projects/lucide-angular/src/lib/icons.provider.ts b/packages/lucide-angular/projects/lucide-angular/src/lib/icons.provider.ts
new file mode 100755
index 000000000..e1d765d8b
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/src/lib/icons.provider.ts
@@ -0,0 +1,3 @@
+export class Icons {
+ constructor(private icons: object) {}
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.component.spec.ts b/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.component.spec.ts
new file mode 100644
index 000000000..6fea47079
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.component.spec.ts
@@ -0,0 +1,29 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { LucideAngularModule } from './lucide-angular.module';
+
+import { LucideAngularComponent } from './lucide-angular.component';
+
+describe('LucideAngularComponent', () => {
+ let component: LucideAngularComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ LucideAngularComponent ],
+ imports: [
+ LucideAngularModule.pick({ })
+ ],
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LucideAngularComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.component.ts b/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.component.ts
new file mode 100644
index 000000000..065a21964
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.component.ts
@@ -0,0 +1,68 @@
+import { Component, ElementRef, Input, Inject, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';
+import { Icons } from './icons.provider';
+import { createElement, IconData } from '../../lucide';
+
+@Component({
+ selector: 'lucide-angular, lucide-icon, i-lucide, span-lucide',
+ template: ``,
+ styles: [`
+ :host {
+ display: inline-block;
+ fill: none;
+ stroke: inherit;
+ stroke-width: inherit;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ }
+ `]
+})
+export class LucideAngularComponent implements OnChanges {
+ @Input() name!: string;
+ @Input() img!: IconData;
+
+ constructor(
+ @Inject(ElementRef) private elem: ElementRef,
+ @Inject(ChangeDetectorRef) private changeDetector: ChangeDetectorRef,
+ @Inject(Icons) private icons: Icons
+ ) { }
+
+ 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)] || '';
+
+ if (!icoOfName) {
+ console.warn(
+ `Icon not found: ${changes.name.currentValue}\n` +
+ `Please check icon name or \'lucide icon list\'`
+ );
+ } else {
+ const icoElement = createElement(icoOfName);
+ icoElement.setAttribute('stroke-width', 'inherit');
+ icoElement.setAttribute('fill', 'inherit');
+ icoElement.removeAttribute('width');
+ icoElement.removeAttribute('height');
+
+ 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();
+ }
+
+ toPascalCase(str: string): string {
+ return str.replace(/(\w)([a-z0-9]*)(_|-|\s*)/g, (g0, g1, g2) => g1.toUpperCase() + g2.toLowerCase());
+ }
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.module.ts b/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.module.ts
new file mode 100644
index 000000000..40cfa629b
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/src/lib/lucide-angular.module.ts
@@ -0,0 +1,27 @@
+import { NgModule, ModuleWithProviders, Optional } from '@angular/core';
+import { LucideAngularComponent } from './lucide-angular.component';
+import { Icons } from './icons.provider';
+import { IconData } from '../../lucide';
+
+@NgModule({
+ declarations: [LucideAngularComponent],
+ 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 {
+ return {
+ ngModule: LucideAngularModule,
+ providers: [
+ { provide: Icons, multi: true, useValue: icons }
+ ]
+ };
+ }
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/src/test.ts b/packages/lucide-angular/projects/lucide-angular/src/test.ts
new file mode 100644
index 000000000..303b32a22
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/src/test.ts
@@ -0,0 +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 { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: {
+ context(path: string, deep?: boolean, filter?: RegExp): {
+ keys(): string[];
+ (id: string): T;
+ };
+};
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/packages/lucide-angular/projects/lucide-angular/tsconfig.lib.json b/packages/lucide-angular/projects/lucide-angular/tsconfig.lib.json
new file mode 100644
index 000000000..16fc7bfef
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/tsconfig.lib.json
@@ -0,0 +1,26 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "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
+ },
+ "exclude": [
+ "src/test.ts",
+ "**/*.spec.ts"
+ ]
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/tsconfig.lib.prod.json b/packages/lucide-angular/projects/lucide-angular/tsconfig.lib.prod.json
new file mode 100644
index 000000000..5615c27df
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/tsconfig.lib.prod.json
@@ -0,0 +1,10 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "extends": "./tsconfig.lib.json",
+ "compilerOptions": {
+ "declarationMap": false
+ },
+ "angularCompilerOptions": {
+ "enableIvy": false
+ }
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/tsconfig.spec.json b/packages/lucide-angular/projects/lucide-angular/tsconfig.spec.json
new file mode 100644
index 000000000..715dd0a5d
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/tsconfig.spec.json
@@ -0,0 +1,17 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../out-tsc/spec",
+ "types": [
+ "jasmine"
+ ]
+ },
+ "files": [
+ "src/test.ts"
+ ],
+ "include": [
+ "**/*.spec.ts",
+ "**/*.d.ts"
+ ]
+}
diff --git a/packages/lucide-angular/projects/lucide-angular/tslint.json b/packages/lucide-angular/projects/lucide-angular/tslint.json
new file mode 100644
index 000000000..920be84fc
--- /dev/null
+++ b/packages/lucide-angular/projects/lucide-angular/tslint.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tslint.json",
+ "rules": {
+ "directive-selector": [
+ true,
+ "attribute",
+ "lib",
+ "camelCase"
+ ],
+ "component-selector": [
+ true,
+ "element",
+ "",
+ "kebab-case"
+ ]
+ }
+}
diff --git a/packages/lucide-angular/scripts/buildIconsIndex.js b/packages/lucide-angular/scripts/buildIconsIndex.js
new file mode 100644
index 000000000..84a6cc483
--- /dev/null
+++ b/packages/lucide-angular/scripts/buildIconsIndex.js
@@ -0,0 +1,39 @@
+import path from 'path';
+
+import {
+ writeFile,
+ resetFile,
+ appendFile,
+ readSvgDirectory,
+} from '../../../scripts/helpers';
+
+const TARGET_DIR = path.join(__dirname, '../projects/lucide-angular/build');
+const ICONS_DIR = path.resolve(__dirname, '../../../icons');
+const TYPES_FILE_NAME = 'icons-index.ts';
+
+// Generates header of d.ts file include some types and functions
+const typeDefinitions = `\
+export type IconNode = readonly [string, object];
+export type IconData = readonly [string, object, IconNode[] ];
+
+export declare const icons: { [key: string]: IconData };
+
+// Generated icons
+`;
+
+resetFile(TYPES_FILE_NAME, TARGET_DIR);
+writeFile(typeDefinitions, TYPES_FILE_NAME, TARGET_DIR);
+
+const svgFiles = readSvgDirectory(ICONS_DIR);
+
+svgFiles.forEach(svgFile => {
+ const kebab = path.basename(svgFile, '.svg');
+
+ appendFile(
+ `export * from './icons/${kebab}';\n`,
+ TYPES_FILE_NAME,
+ TARGET_DIR,
+ );
+});
+
+console.log(`Generated ${TYPES_FILE_NAME} file with`, svgFiles.length, 'icons');
diff --git a/packages/lucide-angular/scripts/exportTemplate.js b/packages/lucide-angular/scripts/exportTemplate.js
new file mode 100644
index 000000000..0687be845
--- /dev/null
+++ b/packages/lucide-angular/scripts/exportTemplate.js
@@ -0,0 +1,10 @@
+export default ({ componentName, children }) => `
+import { IconData } from '../../lucide';
+import defaultAttributes from '../../default-attributes';
+
+export const ${componentName}: IconData = [
+ 'svg',
+ defaultAttributes,
+ ${JSON.stringify(children)}
+];
+`;
diff --git a/packages/lucide-angular/tsconfig.json b/packages/lucide-angular/tsconfig.json
new file mode 100644
index 000000000..0f0bbfdaa
--- /dev/null
+++ b/packages/lucide-angular/tsconfig.json
@@ -0,0 +1,31 @@
+/* To learn more about this file see: https://angular.io/config/tsconfig. */
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "baseUrl": "./",
+ "outDir": "./dist/out-tsc",
+ "sourceMap": true,
+ "declaration": true,
+ "downlevelIteration": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "allowJs": true,
+ "paths": {
+ "lucide-angular": [
+ "dist/lucide-angular/lucide-angular",
+ "dist/lucide-angular"
+ ]
+ },
+ "moduleResolution": "node",
+ "importHelpers": true,
+ "target": "es2015",
+ "module": "es2020",
+ "lib": [
+ "es2018",
+ "dom"
+ ]
+ },
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false
+ }
+}
diff --git a/packages/lucide-angular/tslint.json b/packages/lucide-angular/tslint.json
new file mode 100644
index 000000000..733008b75
--- /dev/null
+++ b/packages/lucide-angular/tslint.json
@@ -0,0 +1,140 @@
+{
+ "extends": "tslint:recommended",
+ "rulesDirectory": [
+ "codelyzer"
+ ],
+ "rules": {
+ "align": {
+ "options": [
+ "parameters",
+ "statements"
+ ]
+ },
+ "array-type": false,
+ "arrow-return-shorthand": true,
+ "curly": true,
+ "deprecation": {
+ "severity": "warning"
+ },
+ "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
+ }
+}