├── projects ├── demo │ ├── src │ │ ├── styles.scss │ │ ├── favicon.ico │ │ ├── app │ │ │ ├── app.config.ts │ │ │ ├── testing │ │ │ │ ├── icon-library.component.ts │ │ │ │ ├── explicit-reference.component.ts │ │ │ │ ├── explicit-reference.component.spec.ts │ │ │ │ └── icon-library.component.spec.ts │ │ │ ├── app.config.server.ts │ │ │ ├── app.component.scss │ │ │ ├── alternate-prefix.component.html │ │ │ ├── alternate-prefix.component.ts │ │ │ ├── app.component.ts │ │ │ └── app.component.html │ │ ├── main.ts │ │ ├── main.server.ts │ │ ├── index.html │ │ └── server.ts │ ├── tsconfig.spec.json │ ├── tsconfig.app.json │ ├── e2e │ │ ├── tsconfig.json │ │ ├── src │ │ │ ├── app.page.ts │ │ │ └── app.e2e-spec.ts │ │ └── protractor.conf.js │ ├── karma.conf.js │ └── .eslintrc.json └── schematics │ ├── src │ ├── ng-add │ │ ├── versions.ts │ │ ├── schema.ts │ │ ├── index.ts │ │ ├── schema.json │ │ └── index.spec.ts │ └── collection.json │ └── tsconfig.json ├── .yarnrc.yml ├── .prettierrc.json ├── testing ├── ng-package.json └── src │ ├── public_api.ts │ ├── config.ts │ ├── icon │ ├── mock-icon-library.service.spec.ts │ └── mock-icon-library.service.ts │ ├── testing.module.ts │ └── testing.module.spec.ts ├── src ├── lib │ ├── shared │ │ ├── errors │ │ │ ├── warn-if-icon-spec-missing.ts │ │ │ ├── warn-if-icon-html-missing.ts │ │ │ └── warn-if-parent-not-exist.ts │ │ ├── utils │ │ │ ├── is-icon-lookup.util.ts │ │ │ ├── normalize-icon-spec.util.ts │ │ │ ├── classlist.util.ts │ │ │ └── css.ts │ │ └── models │ │ │ └── props.model.ts │ ├── config.spec.ts │ ├── stack │ │ ├── stack.component.ts │ │ ├── stack-item-size.directive.ts │ │ ├── stack-item-size.directive.spec.ts │ │ └── stack.component.spec.ts │ ├── public_api.ts │ ├── fontawesome.module.ts │ ├── types.ts │ ├── layers │ │ ├── layers-text.component.spec.ts │ │ ├── layers.component.ts │ │ ├── layers-counter.component.spec.ts │ │ ├── layers-counter.component.ts │ │ ├── layers-text.component.ts │ │ └── layers.component.spec.ts │ ├── icon-library.ts │ ├── config.ts │ ├── icon-library.spec.ts │ └── icon │ │ ├── duotone-icon.component.ts │ │ ├── duotone-icon.component.spec.ts │ │ └── icon.component.ts └── testing │ └── helpers.ts ├── tsconfig.lib.prod.json ├── .editorconfig ├── tasks └── build-schematics.ts ├── tsconfig.spec.json ├── ng-package.json ├── tsconfig.lib.json ├── docs ├── upgrading │ ├── 0.9.0-0.10.0.md │ ├── 0.11.0-0.12.0.md │ ├── v4.md │ ├── 1.0.0-2.0.0.md │ ├── 0.5.0-0.6.0.md │ ├── 0.4.0-0.5.0.md │ ├── 0.1.0-0.1.0-6.md │ └── 0.14.0-0.15.0.md ├── faq.md ├── guide │ ├── storybook.md │ ├── styling-icon-internals.md │ ├── compatibility.md │ ├── adding-css.md │ ├── custom-icons.md │ ├── advanced-uses.md │ └── testing.md ├── usage.md └── usage │ ├── explicit-reference.md │ ├── icon-library.md │ ├── using-other-styles.md │ └── features.md ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── check.yml ├── .gitignore ├── UPGRADING.md ├── .yarn └── patches │ └── @angular-devkit-build-angular-npm-19.0.0-131974ef98.patch ├── LICENSE ├── karma.conf.js ├── tsconfig.json ├── .eslintrc.json ├── DEVELOPER.md ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md ├── package.json ├── angular.json └── README.md /projects/demo/src/styles.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "trailingComma": "all" 5 | } 6 | -------------------------------------------------------------------------------- /projects/demo/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FortAwesome/angular-fontawesome/HEAD/projects/demo/src/favicon.ico -------------------------------------------------------------------------------- /projects/demo/src/app/app.config.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationConfig } from '@angular/core'; 2 | 3 | export const appConfig: ApplicationConfig = { 4 | providers: [], 5 | }; 6 | -------------------------------------------------------------------------------- /testing/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../node_modules/ng-packagr/ng-entrypoint.schema.json", 3 | "lib": { 4 | "entryFile": "src/public_api.ts" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/shared/errors/warn-if-icon-spec-missing.ts: -------------------------------------------------------------------------------- 1 | export const faWarnIfIconSpecMissing = () => { 2 | throw new Error('Property `icon` is required for `fa-icon`/`fa-duotone-icon` components.'); 3 | }; 4 | -------------------------------------------------------------------------------- /testing/src/public_api.ts: -------------------------------------------------------------------------------- 1 | export { FontAwesomeTestingModule } from './testing.module'; 2 | export { MockFaIconLibrary } from './icon/mock-icon-library.service'; 3 | export { FaTestingConfig } from './config'; 4 | -------------------------------------------------------------------------------- /projects/demo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": ["jasmine"] 6 | }, 7 | "include": ["src/**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "compilationMode": "partial" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /projects/demo/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/app", 5 | "types": [] 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "exclude": ["src/**/*.spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | indent_size = 4 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /tasks/build-schematics.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | 3 | fs.copyFileSync('projects/schematics/src/collection.json', 'dist/angular-fontawesome/schematics/collection.json'); 4 | fs.copyFileSync('projects/schematics/src/ng-add/schema.json', 'dist/angular-fontawesome/schematics/ng-add/schema.json'); 5 | -------------------------------------------------------------------------------- /projects/demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import { bootstrapApplication, provideClientHydration } from '@angular/platform-browser'; 2 | import { AppComponent } from './app/app.component'; 3 | 4 | bootstrapApplication(AppComponent, { 5 | providers: [provideClientHydration()], 6 | }).catch((err) => console.error(err)); 7 | -------------------------------------------------------------------------------- /projects/demo/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es2018", 7 | "types": ["jasmine", "jasminewd2", "node"] 8 | }, 9 | "include": ["src/**/*.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/shared/utils/is-icon-lookup.util.ts: -------------------------------------------------------------------------------- 1 | import { IconLookup, IconProp } from '../../types'; 2 | 3 | /** 4 | * Returns if is IconLookup or not. 5 | */ 6 | export const isIconLookup = (i: IconProp): i is IconLookup => 7 | (i as IconLookup).prefix !== undefined && (i as IconLookup).iconName !== undefined; 8 | -------------------------------------------------------------------------------- /projects/schematics/src/ng-add/versions.ts: -------------------------------------------------------------------------------- 1 | export const angularFontawesomeVersion = '^4.0.0'; 2 | 3 | export const iconPackVersionMap: Record = { 4 | '7': { iconPackVersion: '^7.1.0' }, 5 | '6': { iconPackVersion: '^6.7.2' }, 6 | '5': { iconPackVersion: '^5.15.4' }, 7 | }; 8 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": ["jasmine"], 6 | "paths": { 7 | "@fortawesome/angular-fontawesome": ["src/lib/public_api.ts"] 8 | } 9 | }, 10 | "include": ["src/**/*.ts", "testing/**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/shared/errors/warn-if-icon-html-missing.ts: -------------------------------------------------------------------------------- 1 | import { IconLookup } from '../../types'; 2 | 3 | export const faWarnIfIconDefinitionMissing = (iconSpec: IconLookup) => { 4 | throw new Error( 5 | `Could not find icon with iconName=${iconSpec.iconName} and prefix=${iconSpec.prefix} in the icon library.`, 6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /src/lib/shared/errors/warn-if-parent-not-exist.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Warns if parent component not existing. 3 | */ 4 | export const faWarnIfParentNotExist = (parent: any, parentName: string, childName: string) => { 5 | if (!parent) { 6 | throw new Error(`${childName} should be used as child of ${parentName} only.`); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/ng-packagr/ng-package.schema.json", 3 | "lib": { 4 | "entryFile": "src/lib/public_api.ts", 5 | "flatModuleFile": "angular-fontawesome" 6 | }, 7 | "dest": "./dist/angular-fontawesome", 8 | "allowedNonPeerDependencies": ["@fortawesome/fontawesome-svg-core"] 9 | } 10 | -------------------------------------------------------------------------------- /projects/demo/src/app/testing/icon-library.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FaIconComponent } from '@fortawesome/angular-fontawesome'; 3 | 4 | @Component({ 5 | selector: 'app-regular-icon-library', 6 | imports: [FaIconComponent], 7 | template: '', 8 | }) 9 | export class IconLibraryComponent {} 10 | -------------------------------------------------------------------------------- /projects/demo/src/main.server.ts: -------------------------------------------------------------------------------- 1 | import { bootstrapApplication, BootstrapContext } from '@angular/platform-browser'; 2 | import { AppComponent } from './app/app.component'; 3 | import { config } from './app/app.config.server'; 4 | 5 | const bootstrap = (context: BootstrapContext) => bootstrapApplication(AppComponent, config, context); 6 | 7 | export default bootstrap; 8 | -------------------------------------------------------------------------------- /projects/demo/e2e/src/app.page.ts: -------------------------------------------------------------------------------- 1 | import { $, $$, browser } from 'protractor'; 2 | 3 | export class AppPage { 4 | readonly icons = $$('svg'); 5 | readonly styles = $$('style'); 6 | 7 | readonly appRoot = $('app-root'); 8 | 9 | async navigateTo() { 10 | await browser.get(browser.baseUrl); 11 | } 12 | } 13 | 14 | export const appPage = new AppPage(); 15 | -------------------------------------------------------------------------------- /projects/schematics/src/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json", 3 | "schematics": { 4 | "ng-add": { 5 | "description": "Adds Font Awesome to the application without affecting any templates.", 6 | "factory": "./ng-add/index", 7 | "schema": "./ng-add/schema.json" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/lib", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "include": ["src/**/*.ts", "testing/src/**/*.ts"], 11 | "exclude": ["src/testing/*.ts", "src/**/*.spec.ts", "testing/src/**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/config.spec.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core/testing'; 2 | import { FaConfig } from './config'; 3 | 4 | describe('FaConfig', () => { 5 | it('should be created with a default value', inject([FaConfig], (service: FaConfig) => { 6 | expect(service).toBeTruthy(); 7 | expect(service.defaultPrefix).toEqual('fas'); 8 | expect(service.fixedWidth).toBeFalsy(); 9 | })); 10 | }); 11 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.config.server.ts: -------------------------------------------------------------------------------- 1 | import { mergeApplicationConfig, ApplicationConfig } from '@angular/core'; 2 | import { provideServerRendering } from '@angular/platform-server'; 3 | import { appConfig } from './app.config'; 4 | 5 | const serverConfig: ApplicationConfig = { 6 | providers: [provideServerRendering()], 7 | }; 8 | 9 | export const config = mergeApplicationConfig(appConfig, serverConfig); 10 | -------------------------------------------------------------------------------- /projects/demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | angular-fontawesome 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/demo/src/app/testing/explicit-reference.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FaIconComponent } from '@fortawesome/angular-fontawesome'; 3 | import { faUser } from '@fortawesome/free-solid-svg-icons'; 4 | 5 | @Component({ 6 | selector: 'app-explicit-reference', 7 | imports: [FaIconComponent], 8 | template: '', 9 | }) 10 | export class ExplicitReferenceComponent { 11 | faUser = faUser; 12 | } 13 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | font-family: Tahoma, Geneva, sans-serif; 3 | } 4 | 5 | .wrapper { 6 | display: grid; 7 | grid-template-columns: repeat(3, 1fr); 8 | grid-gap: 10px; 9 | grid-auto-rows: minmax(100px, auto); 10 | width: 40%; 11 | justify-content: flex-start !important; 12 | } 13 | 14 | select { 15 | font-size: 15px; 16 | font-family: Tahoma, Geneva, sans-serif; 17 | } 18 | 19 | .green-icon { 20 | color: green; 21 | } 22 | -------------------------------------------------------------------------------- /src/testing/helpers.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture } from '@angular/core/testing'; 2 | import { IconDefinition } from '../lib/types'; 3 | 4 | export const queryByCss = (fixture: ComponentFixture, cssSelector: string): HTMLElement => 5 | fixture.nativeElement.querySelector(cssSelector); 6 | 7 | export const faDummy: IconDefinition = { 8 | prefix: 'fad', 9 | iconName: 'dummy', 10 | icon: [512, 512, [], '', ['M50 50 H412 V250 H50 Z', 'M50 262 H412 V462 H50 Z']], 11 | }; 12 | -------------------------------------------------------------------------------- /projects/demo/src/app/alternate-prefix.component.html: -------------------------------------------------------------------------------- 1 | 2 |

Example of setting the default icon prefix

3 |

4 | The default icon prefix is usually fas but can be adjusted by injecting the FaConfig and 5 | changing the defaultPrefix property. 6 |

7 | 8 | 9 | 10 |
11 | -------------------------------------------------------------------------------- /docs/upgrading/0.9.0-0.10.0.md: -------------------------------------------------------------------------------- 1 | # Upgrading 0.9.0 to 0.10.0 2 | 3 | ## Migrate from global icon library to FaIconLibrary 4 | 5 | Support for the deprecated icon library from `@fortawesome/fontawesome-svg-core` (referred as *global icon library*) was removed together with the corresponding deprecated configuration property (`FaConfig.globalLibrary`). Make sure to remove any usage of the above prior to upgrading. 6 | 7 | See the [deprecation announcement](https://github.com/FortAwesome/angular-fontawesome/blob/master/docs/upgrading/0.4.0-0.5.0.md#migrate-from-global-icon-library-to-faiconlibrary) for more details. 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | ### Describe the problem 8 | 9 | 10 | 11 | ### What did you expect? 12 | 13 | 14 | 15 | ### Reproducible test case 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/lib/shared/utils/normalize-icon-spec.util.ts: -------------------------------------------------------------------------------- 1 | import { IconDefinition, IconLookup, IconPrefix, IconProp } from '../../types'; 2 | import { isIconLookup } from './is-icon-lookup.util'; 3 | 4 | /** 5 | * Normalizing icon spec. 6 | */ 7 | export const faNormalizeIconSpec = ( 8 | iconSpec: IconProp | IconDefinition, 9 | defaultPrefix: IconPrefix, 10 | ): IconLookup | IconDefinition => { 11 | if (isIconLookup(iconSpec)) { 12 | return iconSpec; 13 | } 14 | 15 | if (Array.isArray(iconSpec) && iconSpec.length === 2) { 16 | return { prefix: iconSpec[0], iconName: iconSpec[1] }; 17 | } 18 | 19 | return { prefix: defaultPrefix, iconName: iconSpec }; 20 | }; 21 | -------------------------------------------------------------------------------- /docs/upgrading/0.11.0-0.12.0.md: -------------------------------------------------------------------------------- 1 | # Upgrading 0.11.0 to 0.12.0 2 | 3 | ## Remove usage of the deprecated `styles` and `classes` inputs 4 | 5 | `styles` and `classes` inputs in all components are deprecated for removal in the next release. These inputs don't work the way one would expect and cause a lot of confusion. For majority of the cases, one should use regular [class and style bindings](https://angular.io/guide/class-binding) provided by Angular. For those rare cases, when it is not enough, there is a guide on how one can style component's internal elements at their own risk - [Styling icon internals](https://github.com/FortAwesome/angular-fontawesome/blob/master/docs/guide/styling-icon-internals.md). 6 | -------------------------------------------------------------------------------- /testing/src/config.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root', 5 | }) 6 | export class FaTestingConfig { 7 | /** 8 | * What to do when `addIcons()` or `addIconPacks()` is invoked on 9 | * the FaIconLibrary provided by the FontAwesomeTestingModule. 10 | * 11 | * Possible values are: 12 | * - `'throwError'` - Throw an error. 13 | * - `'logWarning'` - Write a warning to the console. 14 | * - `'noop'` - Do nothing. 15 | * 16 | * Note that in any case the icon will not be added to the library. 17 | * 18 | * @default 'throwError' 19 | */ 20 | whenAddingIcons: 'throwError' | 'logWarning' | 'noop' = 'throwError'; 21 | } 22 | -------------------------------------------------------------------------------- /testing/src/icon/mock-icon-library.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { dummyIcon, MockFaIconLibrary } from './mock-icon-library.service'; 4 | 5 | describe('MockFaIconLibrary', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service = TestBed.inject(MockFaIconLibrary); 10 | expect(service).toBeTruthy(); 11 | }); 12 | 13 | it('should return a stubbed icon when getIconDefinition is called regardless of input', () => { 14 | const service = TestBed.inject(MockFaIconLibrary); 15 | expect(service.getIconDefinition('fas', '500px')).toEqual(dummyIcon); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /docs/upgrading/v4.md: -------------------------------------------------------------------------------- 1 | # Upgrading from Font Awesome 4 or older 2 | 3 | If you've used Font Awesome in the past (version 4 or older) there are some 4 | things that you should learn before you dive in. 5 | 6 | > https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4 7 | 8 | ## Learn about our new SVG implementation 9 | 10 | This package, under the hood, uses SVG with JS and the 11 | `@fortawesome/fontawesome-svg-core` library. This implementation differs 12 | drastically from the web fonts implementation that was used in version 4 and 13 | older of Font Awesome. You might head over there to learn about how it works. 14 | 15 | > https://fontawesome.com/how-to-use/on-the-web/advanced/svg-javascript-core 16 | -------------------------------------------------------------------------------- /src/lib/shared/models/props.model.ts: -------------------------------------------------------------------------------- 1 | import { FlipProp, PullProp, RotateProp, SizeProp } from '@fortawesome/fontawesome-svg-core'; 2 | 3 | /** 4 | * Fontawesome props. 5 | */ 6 | export interface FaProps { 7 | className?: string; 8 | animation?: AnimationProp; 9 | border?: boolean; 10 | fixedWidth?: boolean; 11 | counter?: boolean; 12 | inverse?: boolean; 13 | flip?: FlipProp; 14 | size?: SizeProp; 15 | pull?: PullProp; 16 | rotate?: RotateProp | string; 17 | stackItemSize?: '1x' | '2x'; 18 | } 19 | 20 | export type AnimationProp = 21 | | 'beat' 22 | | 'fade' 23 | | 'beat-fade' 24 | | 'bounce' 25 | | 'flip' 26 | | 'shake' 27 | | 'spin' 28 | | 'spin-reverse' 29 | | 'spin-pulse' 30 | | 'spin-pulse-reverse'; 31 | -------------------------------------------------------------------------------- /projects/schematics/src/ng-add/schema.ts: -------------------------------------------------------------------------------- 1 | export interface Schema { 2 | /** Name of the project. */ 3 | project?: string; 4 | 5 | /** The FontAwesome version to install. */ 6 | version?: '5' | '6' | '7'; 7 | 8 | /** The icon packages to install */ 9 | iconPackages?: ( 10 | | 'free-solid' 11 | | 'free-regular' 12 | | 'free-brands' 13 | | 'pro-solid' 14 | | 'pro-regular' 15 | | 'pro-light' 16 | | 'pro-thin' 17 | | 'pro-duotone' 18 | | 'duotone-regular' 19 | | 'duotone-light' 20 | | 'duotone-thin' 21 | | 'sharp-solid' 22 | | 'sharp-regular' 23 | | 'sharp-light' 24 | | 'sharp-thin' 25 | | 'sharp-duotone-solid' 26 | | 'sharp-duotone-regular' 27 | | 'sharp-duotone-light' 28 | | 'sharp-duotone-thin' 29 | )[]; 30 | } 31 | -------------------------------------------------------------------------------- /projects/schematics/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "../../dist/angular-fontawesome/schematics", 4 | "baseUrl": ".", 5 | "lib": ["es2018", "dom"], 6 | "declaration": true, 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "noEmitOnError": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "noImplicitAny": true, 12 | "noImplicitThis": true, 13 | "noUnusedParameters": true, 14 | "noUnusedLocals": true, 15 | "rootDir": "src/", 16 | "skipDefaultLibCheck": true, 17 | "skipLibCheck": true, 18 | "sourceMap": true, 19 | "strict": true, 20 | "target": "es6", 21 | "types": ["jasmine", "node"] 22 | }, 23 | "include": ["src/**/*"], 24 | "exclude": ["src/*/files/**/*", "src/**/*.spec.ts"] 25 | } 26 | -------------------------------------------------------------------------------- /projects/demo/src/app/testing/explicit-reference.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { ExplicitReferenceComponent } from './explicit-reference.component'; 3 | 4 | describe('ExplicitReferenceComponent', () => { 5 | let component: ExplicitReferenceComponent; 6 | let fixture: ComponentFixture; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | imports: [ExplicitReferenceComponent], 11 | }); 12 | }); 13 | 14 | beforeEach(() => { 15 | fixture = TestBed.createComponent(ExplicitReferenceComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /projects/demo/src/app/alternate-prefix.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { FaConfig, FaIconComponent, FaIconLibrary } from '@fortawesome/angular-fontawesome'; 3 | import { faBellSlash, faHandPaper, faUser } from '@fortawesome/free-regular-svg-icons'; 4 | 5 | @Component({ 6 | selector: 'app-alternate-prefix', 7 | imports: [FaIconComponent], 8 | templateUrl: './alternate-prefix.component.html', 9 | providers: [FaConfig], 10 | }) 11 | export class AlternatePrefixComponent { 12 | constructor() { 13 | const faConfig = inject(FaConfig); 14 | const library = inject(FaIconLibrary); 15 | 16 | // Setting the defaultPrefix to far 17 | faConfig.defaultPrefix = 'far'; 18 | // Adding dynamic icons to library for use 19 | library.addIcons(faUser, faHandPaper, faBellSlash); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist/ 5 | /dist/* 6 | /tmp 7 | /out-tsc 8 | 9 | # dependencies 10 | /node_modules 11 | 12 | # IDEs and editors 13 | /.idea 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | *.sublime-workspace 20 | 21 | # IDE - VSCode 22 | .vscode/ 23 | .vscode/* 24 | !.vscode/settings.json 25 | !.vscode/tasks.json 26 | !.vscode/launch.json 27 | !.vscode/extensions.json 28 | 29 | # misc 30 | /.angular/cache 31 | /.sass-cache 32 | /connect.lock 33 | /coverage 34 | /libpeerconnection.log 35 | npm-debug.log 36 | testem.log 37 | yarn-error.log 38 | yarn.lock 39 | package-lock.json 40 | /typings 41 | 42 | # System Files 43 | .DS_Store 44 | Thumbs.db 45 | /*.iml 46 | /*.ipr 47 | /*.iws 48 | 49 | # Yarn 50 | /.yarn/* 51 | !/.yarn/releases 52 | !/.yarn/plugins 53 | !/.yarn/sdks 54 | !/.yarn/versions 55 | !/.yarn/patches 56 | -------------------------------------------------------------------------------- /src/lib/stack/stack.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, input, computed, ChangeDetectionStrategy } from '@angular/core'; 2 | import { SizeProp } from '@fortawesome/fontawesome-svg-core'; 3 | 4 | @Component({ 5 | selector: 'fa-stack', 6 | template: ``, 7 | host: { 8 | '[class]': 'classes()', 9 | }, 10 | changeDetection: ChangeDetectionStrategy.OnPush, 11 | }) 12 | export class FaStackComponent { 13 | /** 14 | * Size of the stacked icon. 15 | * Note that stacked icon is by default 2 times bigger, than non-stacked icon. 16 | * You'll need to set size using custom CSS to align stacked icon with a 17 | * simple one. E.g. `fa-stack { font-size: 0.5em; }`. 18 | */ 19 | readonly size = input(); 20 | 21 | readonly classes = computed(() => { 22 | const sizeValue = this.size(); 23 | const sizeClass = sizeValue ? { [`fa-${sizeValue}`]: true } : {}; 24 | return { 25 | ...sizeClass, 26 | 'fa-stack': true, 27 | }; 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrading Guide 2 | 3 | See the [CHANGELOG.md](CHANGELOG.md) for detailed information about what has changed between versions. 4 | 5 | This guide is useful to figure out what you need to do between breaking changes. 6 | 7 | As always, [submit issues](https://github.com/FortAwesome/angular-fontawesome/issues/new) that you run into with this guide or with these upgrades to us. 8 | 9 | You might also be interested in the larger umbrella project [upgrade guide](https://github.com/FortAwesome/Font-Awesome/blob/master/UPGRADING.md) 10 | 11 | 12 | ## Version Specific Guides 13 | * [Font Awesome 4 or older](docs/upgrading/v4.md) 14 | * [0.1.0 to 0.1.0-6](docs/upgrading/0.1.0-0.1.0-6.md) 15 | * [0.4.0 to 0.5.0](docs/upgrading/0.4.0-0.5.0.md) 16 | * [0.5.0 to 0.6.0](docs/upgrading/0.5.0-0.6.0.md) 17 | * [0.9.0 to 0.10.0](docs/upgrading/0.9.0-0.10.0.md) 18 | * [0.11.0 to 0.12.0](docs/upgrading/0.11.0-0.12.0.md) 19 | * [0.14.0 to 0.15.0](docs/upgrading/0.14.0-0.15.0.md) 20 | * [1.0.0 to 2.0.0](docs/upgrading/1.0.0-2.0.0.md) 21 | -------------------------------------------------------------------------------- /src/lib/stack/stack-item-size.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, effect, input } from '@angular/core'; 2 | import { SizeProp } from '@fortawesome/fontawesome-svg-core'; 3 | import { FaStackComponent } from './stack.component'; 4 | 5 | @Directive({ 6 | // eslint-disable-next-line @angular-eslint/directive-selector 7 | selector: 'fa-icon[stackItemSize],fa-duotone-icon[stackItemSize]', 8 | }) 9 | export class FaStackItemSizeDirective { 10 | /** 11 | * Specify whether icon inside {@link FaStackComponent} should be rendered in 12 | * regular size (1x) or as a larger icon (2x). 13 | */ 14 | readonly stackItemSize = input<'1x' | '2x'>('1x'); 15 | 16 | /** 17 | * @internal 18 | */ 19 | readonly size = input(); 20 | 21 | _effect = effect(() => { 22 | const size = this.size(); 23 | if (size) { 24 | throw new Error( 25 | 'fa-icon is not allowed to customize size when used inside fa-stack. ' + 26 | 'Set size on the enclosing fa-stack instead: ....', 27 | ); 28 | } 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /.yarn/patches/@angular-devkit-build-angular-npm-19.0.0-131974ef98.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/builders/protractor/index.js b/src/builders/protractor/index.js 2 | index c3175770fe275393ea2d997c627469c898339754..55a8316756931c22e6d32b471304cb944bebee63 100755 3 | --- a/src/builders/protractor/index.js 4 | +++ b/src/builders/protractor/index.js 5 | @@ -108,17 +108,7 @@ async function execute(options, context) { 6 | const serverOptions = await context.getTargetOptions(target); 7 | const overrides = { 8 | watch: false, 9 | - liveReload: false, 10 | }; 11 | - if (options.host !== undefined) { 12 | - overrides.host = options.host; 13 | - } 14 | - else if (typeof serverOptions.host === 'string') { 15 | - options.host = serverOptions.host; 16 | - } 17 | - else { 18 | - options.host = overrides.host = 'localhost'; 19 | - } 20 | if (options.port !== undefined) { 21 | overrides.port = options.port; 22 | } 23 | -------------------------------------------------------------------------------- /src/lib/public_api.ts: -------------------------------------------------------------------------------- 1 | export { FontAwesomeModule } from './fontawesome.module'; 2 | export type { AnimationProp, FaProps } from './shared/models/props.model'; 3 | export { FaIconComponent } from './icon/icon.component'; 4 | export { FaDuotoneIconComponent } from './icon/duotone-icon.component'; 5 | export { FaConfig } from './config'; 6 | export { FaLayersComponent } from './layers/layers.component'; 7 | export { FaLayersTextComponent } from './layers/layers-text.component'; 8 | export { FaLayersCounterComponent } from './layers/layers-counter.component'; 9 | export { FaStackComponent } from './stack/stack.component'; 10 | export { FaStackItemSizeDirective } from './stack/stack-item-size.directive'; 11 | export { FaIconLibrary, type FaIconLibraryInterface } from './icon-library'; 12 | export type { IconPrefix, IconName, IconLookup, IconDefinition, IconPack } from './types'; 13 | 14 | export type { 15 | IconParams, 16 | CounterParams, 17 | TextParams, 18 | FaSymbol, 19 | FlipProp, 20 | PullProp, 21 | RotateProp, 22 | SizeProp, 23 | Transform, 24 | } from '@fortawesome/fontawesome-svg-core'; 25 | -------------------------------------------------------------------------------- /src/lib/fontawesome.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { FaDuotoneIconComponent } from './icon/duotone-icon.component'; 3 | import { FaIconComponent } from './icon/icon.component'; 4 | import { FaLayersCounterComponent } from './layers/layers-counter.component'; 5 | import { FaLayersTextComponent } from './layers/layers-text.component'; 6 | import { FaLayersComponent } from './layers/layers.component'; 7 | import { FaStackItemSizeDirective } from './stack/stack-item-size.directive'; 8 | import { FaStackComponent } from './stack/stack.component'; 9 | 10 | @NgModule({ 11 | imports: [ 12 | FaIconComponent, 13 | FaDuotoneIconComponent, 14 | FaLayersComponent, 15 | FaLayersTextComponent, 16 | FaLayersCounterComponent, 17 | FaStackComponent, 18 | FaStackItemSizeDirective, 19 | ], 20 | exports: [ 21 | FaIconComponent, 22 | FaDuotoneIconComponent, 23 | FaLayersComponent, 24 | FaLayersTextComponent, 25 | FaLayersCounterComponent, 26 | FaStackComponent, 27 | FaStackItemSizeDirective, 28 | ], 29 | }) 30 | export class FontAwesomeModule {} 31 | -------------------------------------------------------------------------------- /testing/src/testing.module.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders, NgModule } from '@angular/core'; 2 | import { FaIconLibrary, FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 3 | import { FaTestingConfig } from './config'; 4 | import { MockFaIconLibrary } from './icon/mock-icon-library.service'; 5 | 6 | @NgModule({ 7 | exports: [FontAwesomeModule], 8 | providers: [{ provide: FaIconLibrary, useExisting: MockFaIconLibrary }], 9 | }) 10 | export class FontAwesomeTestingModule { 11 | /** 12 | * Use this method to configure the module’s behaviour when trying to add icons 13 | * and icon packs to the mock icon library. 14 | */ 15 | static forRoot(config: Partial = {}): ModuleWithProviders { 16 | return { 17 | ngModule: FontAwesomeTestingModule, 18 | providers: [ 19 | { 20 | provide: FaIconLibrary, 21 | useExisting: MockFaIconLibrary, 22 | }, 23 | { 24 | provide: FaTestingConfig, 25 | useFactory: () => Object.assign(new FaTestingConfig(), config), 26 | }, 27 | ], 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Fonticons, Inc. and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /projects/demo/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | chromeDriver: require(`chromedriver/lib/chromedriver`).path, 12 | allScriptsTimeout: 11000, 13 | specs: ['./src/**/*.e2e-spec.ts'], 14 | capabilities: { 15 | browserName: 'chrome', 16 | 'goog:chromeOptions': { 17 | args: ['--headless'], 18 | }, 19 | }, 20 | directConnect: true, 21 | baseUrl: 'http://localhost:4200/', 22 | SELENIUM_PROMISE_MANAGER: false, 23 | framework: 'jasmine', 24 | jasmineNodeOpts: { 25 | showColors: true, 26 | defaultTimeoutInterval: 30000, 27 | print: function () {}, 28 | }, 29 | onPrepare() { 30 | require('ts-node').register({ 31 | project: require('path').join(__dirname, './tsconfig.json'), 32 | }); 33 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: StacktraceOption.PRETTY } })); 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import { IconName as CoreIconName, IconPrefix as CoreIconPrefix } from '@fortawesome/fontawesome-svg-core'; 2 | 3 | // Currently, when a union type of a primitive type is combined with literal 4 | // types, TypeScript loses all information about the combined literals. Thus, 5 | // when such type is used in an IDE with autocompletion, no suggestions are 6 | // made for the declared literals. 7 | // Below types use a workaround from [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729). 8 | 9 | export type IconPrefix = CoreIconPrefix | (string & {}); 10 | 11 | export type IconName = CoreIconName | (string & {}); 12 | 13 | export interface IconLookup { 14 | prefix: IconPrefix; 15 | iconName: IconName; 16 | } 17 | 18 | export interface IconDefinition { 19 | prefix: IconPrefix; 20 | iconName: IconName; 21 | icon: [ 22 | number, // width 23 | number, // height 24 | string[], // ligatures 25 | string, // unicode 26 | string | string[], // svgPathData 27 | ]; 28 | } 29 | 30 | export interface IconPack { 31 | [key: string]: IconDefinition; 32 | } 33 | 34 | export type IconProp = IconName | [IconPrefix, IconName] | IconLookup; 35 | -------------------------------------------------------------------------------- /docs/upgrading/1.0.0-2.0.0.md: -------------------------------------------------------------------------------- 1 | # Upgrading 1.0.0 to 2.0.0 2 | 3 | Below approaches have changed 4 | 5 | ## To create `FaIconComponent` dynamically: 6 | 7 | ```diff 8 | @Component({ 9 | selector: 'fa-host', 10 | template: ` 11 | 14 |
15 | 16 | ` 17 | }) 18 | class HostComponent { 19 | readonly container = viewChild('host', { read: ViewContainerRef }); 20 | 21 | createIcon() { 22 | const componentRef = this.container().createComponent(FaIconComponent); 23 | - componentRef.instance.icon = faUser; 24 | - componentRef.instance.render(); 25 | 26 | + componentRef.setInput('icon', faUser); 27 | } 28 | } 29 | ``` 30 | 31 | ## To update `FaIconComponent` programmatically: 32 | 33 | ```diff 34 | @Component({ 35 | selector: 'fa-host', 36 | template: '' 37 | }) 38 | class HostComponent { 39 | readonly faUser = faUser; 40 | readonly iconComponent = viewChild(FaIconComponent); 41 | 42 | spinIcon() { 43 | const iconComponent = this.iconComponent(); 44 | - iconComponent.animation = 'spin'; 45 | + iconComponent.animation.set('spin'); 46 | } 47 | } 48 | ``` -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | ], 14 | client: { 15 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 16 | }, 17 | coverageReporter: { 18 | dir: require('path').join(__dirname, 'coverage/angular-fontawesome'), 19 | subdir: '.', 20 | reporters: [{ type: 'html' }, { type: 'text-summary' }], 21 | }, 22 | reporters: ['progress', 'kjhtml'], 23 | port: 9876, 24 | colors: true, 25 | logLevel: config.LOG_INFO, 26 | autoWatch: true, 27 | browsers: ['Chrome'], 28 | singleRun: false, 29 | restartOnFileChange: true, 30 | customLaunchers: { 31 | ChromeCI: { 32 | base: `${process.env['CI'] ? 'ChromeHeadless' : 'Chrome'}`, 33 | flags: process.env['CI'] ? ['--no-sandbox'] : [], 34 | }, 35 | }, 36 | }); 37 | }; 38 | -------------------------------------------------------------------------------- /projects/demo/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | ], 14 | client: { 15 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 16 | }, 17 | coverageReporter: { 18 | dir: require('path').join(__dirname, '../../coverage/demo'), 19 | subdir: '.', 20 | reporters: [{ type: 'html' }, { type: 'text-summary' }], 21 | }, 22 | reporters: ['progress', 'kjhtml'], 23 | port: 9876, 24 | colors: true, 25 | logLevel: config.LOG_INFO, 26 | autoWatch: true, 27 | browsers: ['Chrome'], 28 | singleRun: false, 29 | restartOnFileChange: true, 30 | customLaunchers: { 31 | ChromeCI: { 32 | base: `${process.env['CI'] ? 'ChromeHeadless' : 'Chrome'}`, 33 | flags: process.env['CI'] ? ['--no-sandbox'] : [], 34 | }, 35 | }, 36 | }); 37 | }; 38 | -------------------------------------------------------------------------------- /src/lib/layers/layers-text.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, inputBinding } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { queryByCss } from '../../testing/helpers'; 4 | import { FaLayersComponent } from './layers.component'; 5 | import { FaLayersTextComponent } from './layers-text.component'; 6 | 7 | describe('FaLayersTextComponent', () => { 8 | it('should render text layer', () => { 9 | @Component({ 10 | selector: 'fa-host', 11 | imports: [FaLayersComponent, FaLayersTextComponent], 12 | template: ` 13 | 14 | 15 | 16 | `, 17 | }) 18 | class HostComponent {} 19 | 20 | const fixture = TestBed.createComponent(HostComponent); 21 | fixture.detectChanges(); 22 | expect(queryByCss(fixture, 'fa-layers-text > span')).toBeTruthy(); 23 | }); 24 | 25 | it('should throw an error if text layer is used outside of fa-layers', () => { 26 | expect(() => 27 | TestBed.createComponent(FaLayersTextComponent, { bindings: [inputBinding('content', () => 'Test')] }), 28 | ).toThrow(new Error('FaLayersTextComponent should be used as child of FaLayersComponent only.')); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | ### Describe the problem you'd like to see solved or task you'd like to see made easier 7 | 8 | 9 | 10 | ### Is this in relation to an existing part of angular-fontawesome or something new? 11 | 12 | 13 | 14 | ### What is 1 thing that we can do when building this feature that will guarantee that it is awesome? 15 | 16 | 17 | 18 | ### Why would other angular-fontawesome users care about this? 19 | 20 | 21 | 22 | ### On a scale of 1 (sometime in the future) to 10 (absolutely right now), how soon would you recommend we make this feature? 23 | 24 | 25 | 26 | ### Feature request checklist 27 | 28 | - [ ] This is a single feature (i.e. not a re-write of all of Font Awesome) 29 | - [ ] The title starts with "Feature request: " and is followed by a clear feature name (Ex: `Feature request: moar cowbell`) 30 | - [ ] I have [searched for existing issues](https://github.com/FortAwesome/angular-fontawesome/issues) and to the best of my knowledge this is not a duplicate 31 | -------------------------------------------------------------------------------- /testing/src/icon/mock-icon-library.service.ts: -------------------------------------------------------------------------------- 1 | import { inject, Injectable } from '@angular/core'; 2 | import { FaIconLibraryInterface, IconDefinition, IconName, IconPrefix } from '@fortawesome/angular-fontawesome'; 3 | import { FaTestingConfig } from '../config'; 4 | 5 | export const dummyIcon: IconDefinition = { 6 | prefix: 'fad', 7 | iconName: 'dummy', 8 | icon: [512, 512, [], '', 'M50 50 H462 V462 H50 Z'], 9 | }; 10 | 11 | export const ADD_ICON_MESSAGE = 'Attempt to add an icon to the MockFaIconLibrary.'; 12 | 13 | @Injectable({ 14 | providedIn: 'root', 15 | }) 16 | export class MockFaIconLibrary implements FaIconLibraryInterface { 17 | private config = inject(FaTestingConfig); 18 | 19 | addIcons() { 20 | if (this.config.whenAddingIcons === 'throwError') { 21 | throw new Error(ADD_ICON_MESSAGE); 22 | } 23 | if (this.config.whenAddingIcons === 'logWarning') { 24 | console.warn(ADD_ICON_MESSAGE); 25 | } 26 | } 27 | 28 | addIconPacks() { 29 | if (this.config.whenAddingIcons === 'throwError') { 30 | throw new Error(ADD_ICON_MESSAGE); 31 | } 32 | if (this.config.whenAddingIcons === 'logWarning') { 33 | console.warn(ADD_ICON_MESSAGE); 34 | } 35 | } 36 | 37 | getIconDefinition(prefix: IconPrefix, name: IconName): IconDefinition { 38 | return dummyIcon; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/lib/layers/layers.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject, OnInit, input, computed, ChangeDetectionStrategy, DOCUMENT } from '@angular/core'; 2 | import { SizeProp } from '@fortawesome/fontawesome-svg-core'; 3 | import { FaConfig } from '../config'; 4 | import { ensureCss } from '../shared/utils/css'; 5 | 6 | /** 7 | * Fontawesome layers. 8 | */ 9 | @Component({ 10 | selector: 'fa-layers', 11 | template: ``, 12 | host: { 13 | '[class]': 'classes()', 14 | }, 15 | changeDetection: ChangeDetectionStrategy.OnPush, 16 | }) 17 | export class FaLayersComponent implements OnInit { 18 | readonly size = input(); 19 | readonly fixedWidth = input(); 20 | readonly faFw = computed(() => { 21 | const fixedWidth = this.fixedWidth(); 22 | return typeof fixedWidth === 'boolean' ? fixedWidth : this.config.fixedWidth; 23 | }); 24 | readonly classes = computed(() => { 25 | const sizeValue = this.size(); 26 | const sizeClass = sizeValue ? { [`fa-${sizeValue}`]: true } : {}; 27 | return { 28 | ...sizeClass, 29 | 'fa-fw': this.faFw(), 30 | 'fa-layers': true, 31 | }; 32 | }); 33 | 34 | private readonly document = inject(DOCUMENT); 35 | private readonly config = inject(FaConfig); 36 | 37 | ngOnInit() { 38 | ensureCss(this.document, this.config); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "sourceMap": true, 12 | "isolatedModules": true, 13 | "experimentalDecorators": true, 14 | "importHelpers": true, 15 | "target": "ES2022", 16 | "module": "preserve", 17 | "stripInternal": true, 18 | "paths": { 19 | "@fortawesome/angular-fontawesome": ["dist/angular-fontawesome"], 20 | "@fortawesome/angular-fontawesome/testing": ["dist/angular-fontawesome/testing"] 21 | } 22 | }, 23 | "angularCompilerOptions": { 24 | "enableI18nLegacyMessageIdFormat": false, 25 | "strictInjectionParameters": true, 26 | "strictInputAccessModifiers": true, 27 | "typeCheckHostBindings": true, 28 | "strictTemplates": true 29 | }, 30 | "files": [], 31 | "references": [ 32 | { 33 | "path": "./tsconfig.lib.json" 34 | }, 35 | { 36 | "path": "./tsconfig.spec.json" 37 | }, 38 | { 39 | "path": "./projects/demo/tsconfig.app.json" 40 | }, 41 | { 42 | "path": "./projects/demo/tsconfig.spec.json" 43 | }, 44 | { 45 | "path": "./projects/demo/e2e/tsconfig.json" 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /src/lib/icon-library.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { IconDefinition, IconName, IconPack, IconPrefix } from './types'; 3 | 4 | export interface FaIconLibraryInterface { 5 | addIcons(...icons: IconDefinition[]): void; 6 | addIconPacks(...packs: IconPack[]): void; 7 | getIconDefinition(prefix: IconPrefix, name: IconName): IconDefinition | null; 8 | } 9 | 10 | @Injectable({ providedIn: 'root' }) 11 | export class FaIconLibrary implements FaIconLibraryInterface { 12 | private definitions: { [prefix: string]: { [name: string]: IconDefinition } } = {}; 13 | 14 | addIcons(...icons: IconDefinition[]) { 15 | for (const icon of icons) { 16 | if (!(icon.prefix in this.definitions)) { 17 | this.definitions[icon.prefix] = {}; 18 | } 19 | this.definitions[icon.prefix][icon.iconName] = icon; 20 | for (const alias of icon.icon[2]) { 21 | if (typeof alias === 'string') { 22 | this.definitions[icon.prefix][alias] = icon; 23 | } 24 | } 25 | } 26 | } 27 | 28 | addIconPacks(...packs: IconPack[]) { 29 | for (const pack of packs) { 30 | const icons = Object.keys(pack).map((key) => pack[key]); 31 | this.addIcons(...icons); 32 | } 33 | } 34 | 35 | getIconDefinition(prefix: IconPrefix, name: IconName): IconDefinition | null { 36 | if (prefix in this.definitions && name in this.definitions[prefix]) { 37 | return this.definitions[prefix][name]; 38 | } 39 | return null; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | # Frequently asked questions 2 | 3 | ## Should I use this library? 4 | 5 | There are multiple ways to add FontAwesome icons to your Angular project, to name a few: 6 | 7 | 1. An Angular component which aims to offer the best Angular experience: `ng add`, type checking, etc. 8 | 2. FontAwesome SVG Core which Angular component uses under the hood. It is more flexible in some situations, but does 9 | not offer the above features. 10 | 3. FontAwesome Free/Pro. 11 | 4. [Font Awesome Kits](https://fontawesome.com/kits). 12 | 13 | Depending on your needs, you may want to use this library or another method. 14 | 15 | For an average Angular project we recommend this library. It would feel the most natural. If occasionally you need more 16 | flexibility, it can be achieved 17 | following [this guide](https://github.com/FortAwesome/angular-fontawesome/blob/master/docs/guide/advanced-uses.md#replace-i-tags-with-icons-in-the-arbitrary-html). 18 | 19 | For a project where most of the icons are dynamic (e.g. a CMS project) and come in `` form, you may have better luck 20 | to give up on type-checking and go with FontAwesome SVG Core or FontAwesome Free/Pro (in particular if you need some 21 | rarely used features only available to Web Fonts). 22 | 23 | If you're a Pro-user, you can also use the [Font Awesome Kits](https://fontawesome.com/kits) (specifically Kit NPM 24 | packages) with this library. This way you reduce the footprint of the icons in the `node_modules`, reduce work spent on 25 | removing unused icons from the bundle and get a convenient way to manage your custom icons. However, it will come with 26 | the cost of managing icons separately from the codebase. 27 | -------------------------------------------------------------------------------- /src/lib/config.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { config } from '@fortawesome/fontawesome-svg-core'; 3 | import { IconDefinition, IconPrefix } from './types'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class FaConfig { 7 | /** 8 | * Default prefix to use, when one is not provided with the icon name. 9 | * 10 | * @default 'fas' 11 | */ 12 | defaultPrefix: IconPrefix = 'fas'; 13 | 14 | /** 15 | * Provides a fallback icon to use whilst main icon is being loaded asynchronously. 16 | * When value is null, then fa-icon component will throw an error if icon input is missing. 17 | * When value is not null, then the provided icon will be used as a fallback icon if icon input is missing. 18 | * 19 | * @default null 20 | */ 21 | fallbackIcon: IconDefinition | null = null; 22 | 23 | /** 24 | * Set icons to the same fixed width. 25 | * 26 | * @see {@link: https://fontawesome.com/how-to-use/on-the-web/styling/fixed-width-icons} 27 | * @default false 28 | */ 29 | fixedWidth?: boolean; 30 | 31 | /** 32 | * Automatically add Font Awesome styles to the document when icon is rendered. 33 | * 34 | * For the majority of the cases the automatically added CSS is sufficient, 35 | * please refer to the linked guide for more information on when to disable 36 | * this feature. 37 | * 38 | * @see {@link: https://github.com/FortAwesome/angular-fontawesome/blob/main/docs/guide/adding-css.md} 39 | * @default true 40 | */ 41 | set autoAddCss(value: boolean) { 42 | config.autoAddCss = value; 43 | this._autoAddCss = value; 44 | } 45 | 46 | get autoAddCss() { 47 | return this._autoAddCss; 48 | } 49 | 50 | private _autoAddCss = true; 51 | } 52 | -------------------------------------------------------------------------------- /docs/guide/storybook.md: -------------------------------------------------------------------------------- 1 | # Storybook 2 | 3 | This guide explains how to use Font Awesome within storybook. 4 | 5 | --- 6 | 7 | We can use Angular's `APP_INITIALIZER` function to execute arbitrary code when Storybook loads: 8 | 9 | ```typescript 10 | import { FaIconLibrary, FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 11 | import { faHome, faTimes } from '@fortawesome/free-solid-svg-icons'; 12 | 13 | export default { 14 | title: 'Components/Actions/Button', 15 | component: MyButton, 16 | decorators: [ 17 | moduleMetadata({ 18 | imports: [FontAwesomeModule], 19 | providers: [ 20 | { 21 | provide: APP_INITIALIZER, 22 | useFactory: (iconLibrary: FaIconLibrary) => async() => { 23 | // Add any icons needed here: 24 | iconLibrary.addIcons(faHome); 25 | iconLibrary.addIcons(faTimes); 26 | }, 27 | // When using a factory provider you need to explicitly specify its dependencies. 28 | deps: [FaIconLibrary], 29 | multi: true, 30 | }, 31 | ], 32 | }), 33 | ], 34 | }; 35 | 36 | export const iconStory = () => ({ 37 | template: ` 38 | 42 | 43 | 47 | `, 48 | // Provide the icons as props: 49 | props: { 50 | homeIcon: faHome, 51 | closeIcon: faTimes, 52 | }, 53 | }); 54 | ``` 55 | 56 | Many thanks to [yaroslav-admin][so-user] who first [posted][so-post] about this solution. 57 | 58 | [so-post]: https://stackoverflow.com/a/58672268/722367 59 | [so-user]: https://stackoverflow.com/users/1377864/yaroslav-admin 60 | -------------------------------------------------------------------------------- /docs/guide/styling-icon-internals.md: -------------------------------------------------------------------------------- 1 | # Styling icon internals 2 | 3 | **DISCLAIMER:** Styling icon internals is not recommended as it relies on the component's implementation details and may silently break after any library update. 4 | 5 | For the majority of the cases, styling the icon with regular `style` and `class` properties as shown in [Custom styles](../usage/features.md#custom-styles) should be used. However, sometimes one has to attach style to one of the internal elements of the component. To achieve this, one would need to overcome the Angular [view encapsulation](https://angular.io/guide/view-encapsulation). This guide explains how to do that. 6 | 7 | ## Use global styles 8 | 9 | As global styles are not subject to the view encapsulation, one can add styles for the `fa-icon` internals to the global `styles.css` and use it everywhere in the application. 10 | 11 | ```css 12 | /* styles.css */ 13 | fa-icon.fancy svg path { 14 | fill: #ffffff; 15 | stroke: #ff0000; 16 | stroke-width: 10; 17 | } 18 | ``` 19 | 20 | ```angular2html 21 | 22 | 23 | ``` 24 | 25 | ## Use `::ng-deep` pseudo-class selector 26 | 27 | Another options is to use `:ng-deep` pseudo-class selector. This has the benefit that styles are local to the component and won't accidentally affect `fa-icon` usage in other components of the application. 28 | 29 | ```ts 30 | import { Component } from '@angular/core'; 31 | 32 | @Component({ 33 | selector: 'app-root', 34 | template: '', 35 | styles: [` 36 | fa-icon.fancy ::ng-deep svg path { 37 | fill: #ffffff; 38 | stroke: #ff0000; 39 | stroke-width: 10; 40 | } 41 | `], 42 | }) 43 | export class AppComponent {} 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/guide/compatibility.md: -------------------------------------------------------------------------------- 1 | # Version compatibility 2 | 3 | | @fortawesome/angular-fontawesome | Angular | Font Awesome | ng-add | 4 | |----------------------------------|------------|-------------------|---------------| 5 | | 0.1.x | 5.x | 5.x | not supported | 6 | | 0.2.x | 6.x | 5.x | not supported | 7 | | 0.3.x | 6.x && 7.x | 5.x | not supported | 8 | | 0.4.x, 0.5.x | 8.x | 5.x | not supported | 9 | | 0.6.x | 9.x | 5.x | supported | 10 | | 0.7.x | 10.x | 5.x | supported | 11 | | 0.8.x | 11.x | 5.x | supported | 12 | | 0.9.x | 12.x | 5.x | supported | 13 | | 0.10.x | 13.x | 5.x && 6.x | supported | 14 | | 0.11.x | 14.x | 5.x && 6.x | supported | 15 | | 0.12.x | 15.x | 5.x && 6.x | supported | 16 | | 0.13.x | 16.x | 5.x && 6.x | supported | 17 | | 0.14.x | 17.x | 5.x && 6.x | supported | 18 | | 0.15.x | 18.x | 5.x && 6.x | supported | 19 | | 1.x | 19.x | 5.x && 6.x | supported | 20 | | 2.x | 20.x | 5.x && 6.x | supported | 21 | | 3.x | 20.x | 5.x && 6.x && 7.x | supported | 22 | | 4.x | 21.x | 5.x && 6.x && 7.x | supported | 23 | -------------------------------------------------------------------------------- /src/lib/layers/layers-counter.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, inputBinding } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { queryByCss } from '../../testing/helpers'; 4 | import { FaLayersComponent } from './layers.component'; 5 | import { FaLayersCounterComponent } from './layers-counter.component'; 6 | 7 | describe('FaLayersCounterComponent', () => { 8 | it('should render counter layer', () => { 9 | @Component({ 10 | selector: 'fa-host', 11 | imports: [FaLayersComponent, FaLayersCounterComponent], 12 | template: ` 13 | 14 | 15 | 16 | `, 17 | }) 18 | class HostComponent {} 19 | 20 | const fixture = TestBed.createComponent(HostComponent); 21 | fixture.detectChanges(); 22 | expect(queryByCss(fixture, 'fa-layers-counter > span')).toBeTruthy(); 23 | }); 24 | 25 | it('should throw an error if counter layer is used outside of fa-layers', () => { 26 | expect(() => 27 | TestBed.createComponent(FaLayersCounterComponent, { bindings: [inputBinding('content', () => 300)] }), 28 | ).toThrow(new Error('FaLayersCounterComponent should be used as child of FaLayersComponent only.')); 29 | }); 30 | 31 | it('should include position class', () => { 32 | @Component({ 33 | selector: 'fa-host', 34 | imports: [FaLayersComponent, FaLayersCounterComponent], 35 | template: ` 36 | 37 | 38 | 39 | `, 40 | }) 41 | class HostComponent {} 42 | 43 | const fixture = TestBed.createComponent(HostComponent); 44 | fixture.detectChanges(); 45 | expect(queryByCss(fixture, '.fa-layers-bottom-left')).toBeTruthy(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/lib/layers/layers-counter.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, computed, DOCUMENT, inject, input } from '@angular/core'; 2 | import { DomSanitizer } from '@angular/platform-browser'; 3 | import { counter, CounterParams } from '@fortawesome/fontawesome-svg-core'; 4 | import { FaConfig } from '../config'; 5 | import { faWarnIfParentNotExist } from '../shared/errors/warn-if-parent-not-exist'; 6 | import { ensureCss } from '../shared/utils/css'; 7 | import { FaLayersComponent } from './layers.component'; 8 | 9 | @Component({ 10 | selector: 'fa-layers-counter', 11 | template: '', 12 | host: { 13 | class: 'ng-fa-layers-counter', 14 | '[innerHTML]': 'renderedHTML()', 15 | }, 16 | changeDetection: ChangeDetectionStrategy.OnPush, 17 | }) 18 | export class FaLayersCounterComponent { 19 | readonly content = input.required(); 20 | readonly title = input(); 21 | readonly position = input<'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'>(); 22 | 23 | readonly renderedHTML = computed(() => { 24 | const params = this.buildParams(); 25 | return this.updateContent(params); 26 | }); 27 | 28 | private document = inject(DOCUMENT); 29 | private config = inject(FaConfig); 30 | private parent = inject(FaLayersComponent, { optional: true }); 31 | private sanitizer = inject(DomSanitizer); 32 | 33 | constructor() { 34 | faWarnIfParentNotExist(this.parent, 'FaLayersComponent', 'FaLayersCounterComponent'); 35 | } 36 | 37 | protected buildParams(): CounterParams { 38 | const position = this.position(); 39 | return { 40 | title: this.title(), 41 | classes: position != null ? [`fa-layers-${position}`] : undefined, 42 | }; 43 | } 44 | 45 | private updateContent(params: CounterParams) { 46 | ensureCss(this.document, this.config); 47 | return this.sanitizer.bypassSecurityTrustHtml(counter(this.content() || '', params).html.join('')); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /projects/demo/src/server.ts: -------------------------------------------------------------------------------- 1 | import { APP_BASE_HREF } from '@angular/common'; 2 | import { CommonEngine } from '@angular/ssr/node'; 3 | import express from 'express'; 4 | import { dirname, join, resolve } from 'node:path'; 5 | import { fileURLToPath } from 'node:url'; 6 | import bootstrap from './main.server'; 7 | 8 | // The Express app is exported so that it can be used by serverless Functions. 9 | export function app(): express.Express { 10 | const server = express(); 11 | const serverDistFolder = dirname(fileURLToPath(import.meta.url)); 12 | const browserDistFolder = resolve(serverDistFolder, '../browser'); 13 | const indexHtml = join(serverDistFolder, 'index.server.html'); 14 | 15 | const commonEngine = new CommonEngine(); 16 | 17 | server.set('view engine', 'html'); 18 | server.set('views', browserDistFolder); 19 | 20 | // Example Express Rest API endpoints 21 | // server.get('/api/**', (req, res) => { }); 22 | // Serve static files from /browser 23 | server.get( 24 | '**', 25 | express.static(browserDistFolder, { 26 | maxAge: '1y', 27 | index: 'index.html', 28 | }), 29 | ); 30 | 31 | // All regular routes use the Angular engine 32 | server.get('**', (req, res, next) => { 33 | const { protocol, originalUrl, baseUrl, headers } = req; 34 | 35 | commonEngine 36 | .render({ 37 | bootstrap, 38 | documentFilePath: indexHtml, 39 | url: `${protocol}://${headers.host}${originalUrl}`, 40 | publicPath: browserDistFolder, 41 | providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }], 42 | }) 43 | .then((html) => res.send(html)) 44 | .catch((err) => next(err)); 45 | }); 46 | 47 | return server; 48 | } 49 | 50 | function run(): void { 51 | const port = process.env['PORT'] || 4000; 52 | 53 | // Start up the Node server 54 | const server = app(); 55 | server.listen(port, () => { 56 | console.log(`Node Express server listening on http://localhost:${port}`); 57 | }); 58 | } 59 | 60 | run(); 61 | -------------------------------------------------------------------------------- /projects/demo/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { browser, logging } from 'protractor'; 2 | import { appPage } from './app.page'; 3 | 4 | describe('Angular FontAwesome demo', () => { 5 | beforeEach(async () => { 6 | // TODO: Migrate off Protractor as wait for Angular does not seem to work in the standalone mode 7 | browser.waitForAngularEnabled(false); 8 | await appPage.navigateTo(); 9 | await browser.sleep(1000); 10 | }); 11 | 12 | it('should render all icons', async () => { 13 | expect(await appPage.icons.count()).toBe(47); 14 | }); 15 | 16 | it('should only add styles once', async () => { 17 | const styles: string[] = await appPage.styles.map((style) => style!.getAttribute('innerHTML')); 18 | const fontAwesomeStyles = styles.filter((style) => style.includes('.svg-inline--fa')); 19 | 20 | expect(fontAwesomeStyles.length).toBe(1); 21 | }); 22 | 23 | it('should include styles in the server-side-rendered page', async () => { 24 | const context = await appPage.appRoot.getAttribute('ng-server-context'); 25 | if (context !== 'ssg') { 26 | // Skip the test if the page is not server-side rendered. 27 | console.warn('Skipping test as the page is not server-side rendered.'); 28 | return; 29 | } 30 | 31 | const render1 = await fetch(browser.baseUrl); 32 | const text1 = await render1.text(); 33 | expect(text1).toContain('.svg-inline--fa'); 34 | 35 | // Repeated second time to make sure that second render also includes the styles. 36 | // To achieve it we use WeakSet instead of a simple global variable. 37 | const render2 = await fetch(browser.baseUrl); 38 | const text2 = await render2.text(); 39 | expect(text2).toContain('.svg-inline--fa'); 40 | }); 41 | 42 | afterEach(async () => { 43 | // Assert that there are no errors emitted from the browser 44 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 45 | expect(logs).not.toContain(jasmine.objectContaining({ level: logging.Level.SEVERE })); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/lib/shared/utils/classlist.util.ts: -------------------------------------------------------------------------------- 1 | import { RotateProp } from '@fortawesome/fontawesome-svg-core'; 2 | import { FaProps } from '../models/props.model'; 3 | 4 | export const isKnownRotateValue = (rotate: RotateProp | string | undefined) => 5 | rotate != null && 6 | (rotate === 90 || rotate === 180 || rotate === 270 || rotate === '90' || rotate === '180' || rotate === '270'); 7 | 8 | /** 9 | * Fontawesome class list. 10 | * Returns classes array by props. 11 | */ 12 | export const faClassList = (props: FaProps): string[] => { 13 | const knownRotateValue = isKnownRotateValue(props.rotate); 14 | 15 | const classes = { 16 | [`fa-${props.animation}`]: props.animation != null && !props.animation.startsWith('spin'), 17 | 'fa-spin': props.animation === 'spin' || props.animation === 'spin-reverse', 18 | 'fa-spin-pulse': props.animation === 'spin-pulse' || props.animation === 'spin-pulse-reverse', 19 | 'fa-spin-reverse': props.animation === 'spin-reverse' || props.animation === 'spin-pulse-reverse', 20 | // According to https://fontawesome.com/docs/web/style/animate#spin fa-pulse 21 | // class is deprecated, remove the below line when Font Awesome 5 support 22 | // is dropped. 23 | 'fa-pulse': props.animation === 'spin-pulse' || props.animation === 'spin-pulse-reverse', 24 | 'fa-fw': props.fixedWidth, 25 | 'fa-border': props.border, 26 | 'fa-inverse': props.inverse, 27 | 'fa-layers-counter': props.counter, 28 | 'fa-flip-horizontal': props.flip === 'horizontal' || props.flip === 'both', 29 | 'fa-flip-vertical': props.flip === 'vertical' || props.flip === 'both', 30 | [`fa-${props.size}`]: props.size !== null, 31 | [`fa-rotate-${props.rotate}`]: knownRotateValue, 32 | 'fa-rotate-by': props.rotate != null && !knownRotateValue, 33 | [`fa-pull-${props.pull}`]: props.pull !== null, 34 | [`fa-stack-${props.stackItemSize}`]: props.stackItemSize != null, 35 | }; 36 | 37 | return Object.keys(classes) 38 | .map((key) => (classes[key] ? key : null)) 39 | .filter((key): key is string => key != null); 40 | }; 41 | -------------------------------------------------------------------------------- /docs/guide/adding-css.md: -------------------------------------------------------------------------------- 1 | # Adding CSS 2 | 3 | For Font Awesome icon to render properly, it needs global Font Awesome styles to be added to the page. By default, the library will automatically add the necessary styles to the page before rendering an icon. 4 | 5 | If you have issues with this approach, you can disable it by setting `FaConfig.autoAddCss` to `false`: 6 | 7 | ```typescript 8 | import { inject } from '@angular/core'; 9 | import { FaConfig } from '@fortawesome/angular-fontawesome'; 10 | 11 | export class AppComponent { 12 | constructor() { 13 | const faConfig = inject(FaConfig); 14 | faConfig.autoAddCss = false; 15 | } 16 | } 17 | ``` 18 | 19 | And instead add the styles manually to your application. You can find the necessary styles in the `node_modules/@fortawesome/fontawesome-svg-core/styles.css` file. Then add them to the application global styles in the `angular.json` file: 20 | 21 | ```json 22 | { 23 | "projects": { 24 | "your-project-name": { 25 | "architect": { 26 | "build": { 27 | "options": { 28 | "styles": [ 29 | "node_modules/@fortawesome/fontawesome-svg-core/styles.css", 30 | "src/styles.css" 31 | ] 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | ``` 39 | 40 | One common case when this is necessary is when using Shadow DOM. Angular includes [certain non-trivial logic](https://angular.io/guide/view-encapsulation#mixing-encapsulation-modes) to ensure that global styles work as expected inside the shadow root which can't be applied when styles are added automatically. 41 | 42 | ## Size concerns 43 | 44 | If you are concerned about the size of the Font Awesome global styles, you may extract only the necessary styles from the `node_modules/@fortawesome/fontawesome-svg-core/styles.css` file and add them instead. This way, you can reduce the size of the global styles to only what is necessary for your application. But be aware that this is not officially supported and may break with future updates to Font Awesome. Make sure to revisit the manually extracted styles every time the library is updated or a new Font Awesome feature is used. 45 | -------------------------------------------------------------------------------- /projects/demo/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc.json", 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "parserOptions": { 8 | "project": [ 9 | "projects/demo/tsconfig.app.json", 10 | "projects/demo/tsconfig.spec.json", 11 | "projects/demo/e2e/tsconfig.json" 12 | ], 13 | "createDefaultProgram": true 14 | }, 15 | "rules": { 16 | "@angular-eslint/component-class-suffix": [ 17 | "error", 18 | { 19 | "suffixes": ["Component"] 20 | } 21 | ], 22 | "@angular-eslint/component-max-inline-declarations": [ 23 | "error", 24 | { 25 | "template": 6 26 | } 27 | ], 28 | "@angular-eslint/component-selector": [ 29 | "error", 30 | { 31 | "type": "element", 32 | "prefix": "app", 33 | "style": "kebab-case" 34 | } 35 | ], 36 | "@angular-eslint/directive-class-suffix": [ 37 | "error", 38 | { 39 | "suffixes": ["Directive"] 40 | } 41 | ], 42 | "@angular-eslint/directive-selector": [ 43 | "error", 44 | { 45 | "type": "attribute", 46 | "prefix": "app", 47 | "style": "camelCase" 48 | } 49 | ], 50 | "@angular-eslint/no-host-metadata-property": "off", 51 | "@angular-eslint/no-queries-metadata-property": "error", 52 | "@typescript-eslint/array-type": [ 53 | "error", 54 | { 55 | "default": "array" 56 | } 57 | ], 58 | "@typescript-eslint/explicit-member-accessibility": [ 59 | "error", 60 | { 61 | "accessibility": "no-public" 62 | } 63 | ], 64 | "@typescript-eslint/no-empty-function": "error", 65 | "@typescript-eslint/no-var-requires": "error", 66 | "no-empty": "error", 67 | "no-fallthrough": "off", 68 | "arrow-body-style": ["error", "as-needed"] 69 | } 70 | }, 71 | { 72 | "files": ["*.html"], 73 | "rules": {} 74 | } 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /src/lib/stack/stack-item-size.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, signal, Type } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { queryByCss } from '../../testing/helpers'; 4 | import { faCircle, faUser } from '@fortawesome/free-solid-svg-icons'; 5 | import { FaIconComponent } from '../icon/icon.component'; 6 | import { FaStackItemSizeDirective } from './stack-item-size.directive'; 7 | import { FaStackComponent } from './stack.component'; 8 | 9 | const imports: Type[] = [FaStackComponent, FaStackItemSizeDirective, FaIconComponent]; 10 | 11 | describe('FaStackItemSizeDirective', () => { 12 | it('should attach fa-stack-1x or fa-stack-2x classes to icons', () => { 13 | @Component({ 14 | selector: 'fa-host', 15 | imports, 16 | template: ` 17 | 18 | 19 | 20 | 21 | `, 22 | }) 23 | class HostComponent { 24 | faUser = signal(faUser); 25 | faCircle = signal(faCircle); 26 | } 27 | 28 | const fixture = TestBed.createComponent(HostComponent); 29 | fixture.detectChanges(); 30 | expect(queryByCss(fixture, '.fa-stack-1x')).toBeTruthy(); 31 | expect(queryByCss(fixture, '.fa-stack-2x')).toBeTruthy(); 32 | }); 33 | 34 | it('should throw an error when setting size input together with stackItemSize', () => { 35 | @Component({ 36 | selector: 'fa-host', 37 | imports, 38 | template: ` 39 | 40 | 41 | 42 | 43 | `, 44 | }) 45 | class HostComponent { 46 | faUser = signal(faUser); 47 | faCircle = signal(faCircle); 48 | } 49 | 50 | const fixture = TestBed.createComponent(HostComponent); 51 | 52 | expect(() => fixture.detectChanges()).toThrow( 53 | new Error( 54 | 'fa-icon is not allowed to customize size when used inside fa-stack. ' + 55 | 'Set size on the enclosing fa-stack instead: ....', 56 | ), 57 | ); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /src/lib/icon-library.spec.ts: -------------------------------------------------------------------------------- 1 | import { inject } from '@angular/core/testing'; 2 | import { far, faSun as farSun, faUser as farUser, faFileAlt } from '@fortawesome/free-regular-svg-icons'; 3 | import { fas, faSun, faUser } from '@fortawesome/free-solid-svg-icons'; 4 | import { FaIconLibrary } from './icon-library'; 5 | 6 | describe('FaIconLibrary', () => { 7 | it('should be possible to add an icon', inject([FaIconLibrary], (library: FaIconLibrary) => { 8 | library.addIcons(faUser); 9 | expect(library.getIconDefinition('fas', 'user')).toBe(faUser); 10 | })); 11 | 12 | it('should be possible to add multiple icons', inject([FaIconLibrary], (library: FaIconLibrary) => { 13 | library.addIcons(faUser, farUser); 14 | expect(library.getIconDefinition('fas', 'user')).toBe(faUser); 15 | expect(library.getIconDefinition('far', 'user')).toBe(farUser); 16 | })); 17 | 18 | it('should be possible to add an icon pack', inject([FaIconLibrary], (library: FaIconLibrary) => { 19 | library.addIconPacks(far); 20 | expect(library.getIconDefinition('far', 'user')).toBe(farUser); 21 | })); 22 | 23 | it('should be possible to add multiple icon packs', inject([FaIconLibrary], (library: FaIconLibrary) => { 24 | library.addIconPacks(far, fas); 25 | expect(library.getIconDefinition('fas', 'sun')).toBe(faSun); 26 | expect(library.getIconDefinition('far', 'sun')).toBe(farSun); 27 | })); 28 | 29 | it('should be possible to get an icon', inject([FaIconLibrary], (library: FaIconLibrary) => { 30 | library.addIcons(faUser); 31 | expect(library.getIconDefinition('fas', 'user')).toBe(faUser); 32 | })); 33 | 34 | it('should return null if icon prefix was not registered', inject([FaIconLibrary], (library: FaIconLibrary) => { 35 | expect(library.getIconDefinition('fas', 'user')).toBeNull(); 36 | })); 37 | 38 | it('should return null if icon name is not registered', inject([FaIconLibrary], (library: FaIconLibrary) => { 39 | library.addIcons(faUser); 40 | expect(library.getIconDefinition('fas', 'sun')).toBeNull(); 41 | })); 42 | 43 | it('should be possible to look up icon by alias (FA6 feature)', inject([FaIconLibrary], (library: FaIconLibrary) => { 44 | library.addIcons(faFileAlt); 45 | expect(library.getIconDefinition('far', 'file-alt')).toBe(faFileAlt); 46 | })); 47 | }); 48 | -------------------------------------------------------------------------------- /docs/upgrading/0.5.0-0.6.0.md: -------------------------------------------------------------------------------- 1 | # Upgrading 0.5.0 to 0.6.0 2 | 3 | ## Migrate from global icon library to FaIconLibrary 4 | 5 | See [upgrade instructions](https://github.com/FortAwesome/angular-fontawesome/blob/master/docs/upgrading/0.4.0-0.5.0.md#migrate-from-global-icon-library-to-faiconlibrary) for the previous release. 6 | 7 | ## `FaIcon.icon` and `FaDuotoneIcon.icon` inputs are now required 8 | 9 | `icon` input of these components is now required and will throw an error if it is missing or set to `null` or `underfined`. Review your application for unexpected errors and ensure that `fa-icon` component always has a meaningful `icon` input. 10 | 11 | When using `AsyncPipe` with `icon` input you have 3 options: 12 | 13 | - Do not render `fa-icon` component until icon is loaded 14 | 15 | ```html 16 | 17 | ``` 18 | 19 | - Render a placeholder icon while icon is loaded 20 | 21 | ```typescript 22 | // loadIcon() is your custom function to load icon definition asynchronously. 23 | loadIcon() { 24 | return of(faUser); 25 | } 26 | 27 | // Use `startsWith()` from RxJS to provide placeholder icon. 28 | this.icon$ = this.loadIcon().pipe(startsWith(defaultIcon)); 29 | ``` 30 | 31 | - Provide a fallback icon to be used instead of any missing icon in the application 32 | 33 | ```typescript 34 | import { FaConfig } from '@fortawesome/angular-fontawesome'; 35 | import { faBan } from '@fortawesome/free-solid-svg-icons'; 36 | 37 | export class AppModule { 38 | constructor(config: FaConfig) { 39 | config.fallbackIcon = faBan; 40 | } 41 | } 42 | ``` 43 | 44 | ## Icon definition missing from the icon library is now hard error 45 | 46 | Previously attempt to render an icon, which is missing from the icon library was logging a soft warning. In this release the warning was changed to a hard error to improve discoverability of such bugs. Review your application for unexpected errors and ensure that all used icons are added to the icon library. 47 | 48 | Also refer to the [testing documentation](https://github.com/FortAwesome/angular-fontawesome/blob/master/docs/guide/testing.md#test-components-using-icon-library) to learn how to test components using icon library without getting missing icon errors. 49 | -------------------------------------------------------------------------------- /src/lib/shared/utils/css.ts: -------------------------------------------------------------------------------- 1 | import { dom } from '@fortawesome/fontawesome-svg-core'; 2 | import { FaConfig } from '../../config'; 3 | 4 | const cssInserted = new WeakSet(); 5 | export const autoCssId = 'fa-auto-css'; 6 | 7 | /** 8 | * Ensure that Font Awesome CSS is inserted into the page. 9 | * 10 | * SVG Core has the same logic to insert the same styles into the page, however 11 | * it's not aware of Angular SSR and therefore styles won't be added in that 12 | * context leading to https://github.com/FortAwesome/angular-fontawesome/issues/48. 13 | * That's why the same logic is duplicated here. 14 | * 15 | * @param document - Document. 16 | * @param config - Font Awesome configuration. 17 | */ 18 | export function ensureCss(document: Document, config: FaConfig): void { 19 | if (!config.autoAddCss) { 20 | return; 21 | } 22 | 23 | if (cssInserted.has(document)) { 24 | return; 25 | } 26 | 27 | // Prevent adding the same styles again after hydration. 28 | if (document.getElementById(autoCssId) != null) { 29 | config.autoAddCss = false; 30 | cssInserted.add(document); 31 | return; 32 | } 33 | 34 | const style = document.createElement('style'); 35 | style.setAttribute('type', 'text/css'); 36 | style.setAttribute('id', autoCssId); 37 | style.innerHTML = dom.css(); 38 | const headChildren = document.head.childNodes; 39 | let beforeChild = null; 40 | 41 | for (let i = headChildren.length - 1; i > -1; i--) { 42 | const child = headChildren[i]; 43 | const tagName = child.nodeName.toUpperCase(); 44 | 45 | if (['STYLE', 'LINK'].indexOf(tagName) > -1) { 46 | beforeChild = child; 47 | } 48 | } 49 | 50 | document.head.insertBefore(style, beforeChild); 51 | 52 | // Prevent SVG Core from adding the same styles. 53 | // 54 | // As the logic is present in two places and SVG Core is not aware about 55 | // this library, it may lead to styles being added twice. This can only 56 | // occur when icon is rendered by SVG Core before the Angular component 57 | // and should not have any significant negative impact. This is a rare 58 | // use case, and it's tricky to prevent, so we accept this behavior. Consumer 59 | // can choose to disable `FaConfig.autoAddCss` and add styles manually to 60 | // prevent this from happening. 61 | config.autoAddCss = false; 62 | cssInserted.add(document); 63 | } 64 | -------------------------------------------------------------------------------- /docs/guide/custom-icons.md: -------------------------------------------------------------------------------- 1 | # Custom icons 2 | 3 | This guide explains how to use custom icons with `angular-fontawesome`. 4 | 5 | First of all, you'll need a valid SVG file containing the icon you want to use. Please refer to 6 | the [Icon Design Guidelines](https://docs.fontawesome.com/web/add-icons/upload-icons/icon-design) 7 | and [Prep Icons for Upload](https://docs.fontawesome.com/web/add-icons/upload-icons/prep-icons) to learn how to create 8 | an SVG icon which can be used with Font Awesome. 9 | 10 | ## Icon definition 11 | 12 | To use a custom icon in the project, you need to define an object specified by the `IconDefinition` type. All icons are 13 | defined using the same structure, so you can refer to existing icons as examples. The object should contain the 14 | following properties: 15 | 16 | ```typescript 17 | export interface IconDefinition { 18 | prefix: string; // prefix of the icon 19 | iconName: string; // name of the icon 20 | icon: [ 21 | number, // viewBox width 22 | number, // viewBox height 23 | string[], // ligatures (not used in `angular-fontawesome`) 24 | string, // unicode (not used in `angular-fontawesome`) 25 | string | string[], // single path for a simple icon or array of two paths for a duotone icon 26 | ]; 27 | } 28 | ``` 29 | 30 | Knowing the icon structure, you can easily convert the SVG file to the `IconDefinition` object by picking up the 31 | relevant parts. Given an example SVG file: 32 | 33 | ```xml 34 | 35 | 36 | 37 | 38 | ``` 39 | 40 | The icon definition will look like the following: 41 | 42 | ```typescript 43 | import { IconDefinition } from '@fortawesome/angular-fontawesome'; 44 | 45 | const myIcon: IconDefinition = { 46 | prefix: 'fac', 47 | iconName: 'my-icon', 48 | icon: [ 49 | 512, 50 | 512, 51 | [], 52 | '', 53 | 'M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z', 54 | ], 55 | }; 56 | ``` 57 | 58 | You can also use a [Font Awesome Kit](https://fontawesome.com/kits) to upload your custom icons or pick only the icons 59 | you'd like to use. 60 | 61 | ## Use custom icon 62 | 63 | To use a custom icon is no different from a Font Awesome icon. You can either add it to 64 | the [icon library](./icon-library.md) or use an [explicit references](./explicit-reference.md) approach. 65 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["projects/**/*"], 4 | "parser": "@typescript-eslint/parser", 5 | "plugins": ["@typescript-eslint"], 6 | "overrides": [ 7 | { 8 | "files": ["*.ts"], 9 | "parserOptions": { 10 | "project": ["tsconfig.lib.json", "tsconfig.spec.json"], 11 | "createDefaultProgram": true 12 | }, 13 | "extends": [ 14 | "plugin:@angular-eslint/recommended", 15 | "plugin:@angular-eslint/template/process-inline-templates", 16 | "prettier" 17 | ], 18 | "rules": { 19 | "@angular-eslint/component-class-suffix": [ 20 | "error", 21 | { 22 | "suffixes": ["Component"] 23 | } 24 | ], 25 | "@angular-eslint/component-max-inline-declarations": [ 26 | "error", 27 | { 28 | "template": 6 29 | } 30 | ], 31 | "@angular-eslint/component-selector": [ 32 | "error", 33 | { 34 | "type": "element", 35 | "prefix": "fa", 36 | "style": "kebab-case" 37 | } 38 | ], 39 | "@angular-eslint/directive-class-suffix": [ 40 | "error", 41 | { 42 | "suffixes": ["Directive"] 43 | } 44 | ], 45 | "@angular-eslint/directive-selector": [ 46 | "error", 47 | { 48 | "type": "attribute", 49 | "prefix": "fa", 50 | "style": "camelCase" 51 | } 52 | ], 53 | "@angular-eslint/no-host-metadata-property": "off", 54 | "@angular-eslint/no-queries-metadata-property": "error", 55 | "@typescript-eslint/array-type": [ 56 | "error", 57 | { 58 | "default": "array" 59 | } 60 | ], 61 | "@typescript-eslint/explicit-member-accessibility": [ 62 | "error", 63 | { 64 | "accessibility": "no-public" 65 | } 66 | ], 67 | "@typescript-eslint/no-empty-function": "error", 68 | "@typescript-eslint/no-var-requires": "error", 69 | "no-empty": "error", 70 | "no-fallthrough": "off", 71 | "arrow-body-style": ["error", "as-needed"] 72 | } 73 | }, 74 | { 75 | "files": ["*.spec.ts"], 76 | "rules": { 77 | "@angular-eslint/prefer-standalone": "off" 78 | } 79 | }, 80 | { 81 | "files": ["*.html"], 82 | "extends": ["plugin:@angular-eslint/template/recommended"], 83 | "rules": {} 84 | } 85 | ] 86 | } 87 | -------------------------------------------------------------------------------- /docs/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ## Approaches 4 | There are two approaches for using `angular-fontawesome`. Each has its own pros and cons, so we leave it to you to decide how you'd like to use the library. 5 | 6 | * [Explicit Reference](./usage/explicit-reference.md) 7 | * [Icon Library](./usage/icon-library.md) 8 | 9 | Whichever approach you choose only the icons you have imported will end up in the bundle, and the remaining ones will be tree-shaken away. 10 | 11 | ## Using Additional Styles 12 | Take advantage of the other FontAwesome icon styles. 13 | 14 | * [Brand](./usage/using-other-styles.md#brand-icons) 15 | * [Regular](./usage/using-other-styles.md#regular-icons) 16 | * [Light (Pro Only)](./usage/using-other-styles.md#pro-only-light-icons) 17 | * [Duotone (Pro Only)](./usage/using-other-styles.md#pro-only-duotone-icons) 18 | 19 | ## Features 20 | Utilize core FontAwesome features 21 | 22 | * [Size](./usage/features.md#size) 23 | * [Fixed Width](./usage/features.md#fixed-width) 24 | * [Rotate](./usage/features.md#rotate) 25 | * [Flip](./usage/features.md#flip) 26 | * [Animations](./usage/features.md#animations) 27 | * [Border](./usage/features.md#border) 28 | * [Pull](./usage/features.md#pull) 29 | * [Custom styles](./usage/features.md#custom-styles) 30 | 31 | ## Features specific for Duotone icons 32 | Additional features available for Duotone icons 33 | 34 | * [Basic use](./usage/features.md#basic-use) 35 | * [Swap layers opacity](./usage/features.md#swap-layers-opacity) 36 | * [Customize layers opacity](./usage/features.md#customize-layers-opacity) 37 | * [Customize layers color](./usage/features.md#customize-layers-color) 38 | 39 | ## Advanced Features 40 | Take your icons to the next level with these advanced features. 41 | 42 | * [Mask](./usage/features.md#mask) 43 | * [Transform](./usage/features.md#transform) 44 | * [Stateful Animations](./usage/features.md#stateful-animations) 45 | * [Transform within binding](./usage/features.md#transform-within-binding) 46 | * [Stacked icons](./usage/features.md#stacked-icons) 47 | * [Layers](./usage/features.md#layers) 48 | * [Layers with text](./usage/features.md#layers-with-text) 49 | * [Layers with counter](./usage/features.md#layers-with-counter) 50 | * [Programmatic API](./usage/features.md#programmatic-api) 51 | 52 | ## Guides 53 | Guides on specific topics or use cases. 54 | 55 | * [Testing](./guide/testing.md) 56 | * [Custom icons](./guide/custom-icons.md) 57 | * [Storybook](./guide/storybook.md) 58 | * [Advanced uses](./guide/advanced-uses.md) 59 | * [Styling icon internals](./guide/styling-icon-internals.md) 60 | * [Adding CSS](./guide/adding-css.md) 61 | -------------------------------------------------------------------------------- /projects/demo/src/app/testing/icon-library.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { inject, NgModule } from '@angular/core'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { FaIconLibrary, FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 4 | import { FontAwesomeTestingModule } from '@fortawesome/angular-fontawesome/testing'; 5 | import { faUser } from '@fortawesome/free-solid-svg-icons'; 6 | import { IconLibraryComponent } from './icon-library.component'; 7 | 8 | describe('IconLibraryComponent', () => { 9 | let component: IconLibraryComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(() => { 13 | TestBed.configureTestingModule({ 14 | imports: [IconLibraryComponent], 15 | }); 16 | }); 17 | 18 | beforeEach(() => { 19 | // Use TestBed.get(FaIconLibrary) if you use Angular < 9. 20 | const library = TestBed.inject(FaIconLibrary); // <-- 21 | library.addIcons(faUser); // <-- 22 | 23 | fixture = TestBed.createComponent(IconLibraryComponent); 24 | component = fixture.componentInstance; 25 | fixture.detectChanges(); 26 | }); 27 | 28 | it('should create', () => { 29 | expect(component).toBeTruthy(); 30 | }); 31 | }); 32 | 33 | describe('IconLibraryComponent', () => { 34 | let component: IconLibraryComponent; 35 | let fixture: ComponentFixture; 36 | 37 | beforeEach(() => { 38 | TestBed.configureTestingModule({ 39 | imports: [FontAwesomeTestingModule, IconLibraryComponent], // <-- 40 | }); 41 | }); 42 | 43 | beforeEach(() => { 44 | fixture = TestBed.createComponent(IconLibraryComponent); 45 | component = fixture.componentInstance; 46 | fixture.detectChanges(); 47 | }); 48 | 49 | it('should create', () => { 50 | expect(component).toBeTruthy(); 51 | }); 52 | }); 53 | 54 | @NgModule({ 55 | imports: [FontAwesomeModule], 56 | exports: [FontAwesomeModule], 57 | }) 58 | class FontAwesomeIconsModule { 59 | constructor() { 60 | const library = inject(FaIconLibrary); 61 | library.addIcons(faUser); 62 | } 63 | } 64 | 65 | describe('IconLibraryComponent', () => { 66 | let component: IconLibraryComponent; 67 | let fixture: ComponentFixture; 68 | 69 | beforeEach(() => { 70 | TestBed.configureTestingModule({ 71 | imports: [FontAwesomeIconsModule, IconLibraryComponent], // <-- 72 | }); 73 | }); 74 | 75 | beforeEach(() => { 76 | fixture = TestBed.createComponent(IconLibraryComponent); 77 | component = fixture.componentInstance; 78 | fixture.detectChanges(); 79 | }); 80 | 81 | it('should create', () => { 82 | expect(component).toBeTruthy(); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /src/lib/stack/stack.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, signal, Type } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { faCircle, faUser } from '@fortawesome/free-solid-svg-icons'; 4 | import { faDummy, queryByCss } from '../../testing/helpers'; 5 | import { FaIconComponent } from '../icon/icon.component'; 6 | import { FaDuotoneIconComponent } from '../icon/duotone-icon.component'; 7 | import { FaStackItemSizeDirective } from './stack-item-size.directive'; 8 | import { FaStackComponent } from './stack.component'; 9 | 10 | const imports: Type[] = [FaStackComponent, FaStackItemSizeDirective, FaIconComponent]; 11 | 12 | describe('FaStackComponent', () => { 13 | it('should render stack icon', () => { 14 | @Component({ 15 | selector: 'fa-host', 16 | imports, 17 | template: ` 18 | 19 | 20 | 21 | 22 | `, 23 | }) 24 | class HostComponent { 25 | faUser = signal(faUser); 26 | faCircle = signal(faCircle); 27 | } 28 | 29 | const fixture = TestBed.createComponent(HostComponent); 30 | fixture.detectChanges(); 31 | expect(fixture.nativeElement).toBeTruthy(); 32 | }); 33 | 34 | it('should work with duotone icons', () => { 35 | @Component({ 36 | selector: 'fa-host', 37 | imports: [...imports, FaDuotoneIconComponent], 38 | template: ` 39 | 40 | 41 | 42 | 43 | `, 44 | }) 45 | class HostComponent { 46 | dummyDuotoneIcon = signal(faDummy); 47 | faCircle = signal(faCircle); 48 | } 49 | 50 | const fixture = TestBed.createComponent(HostComponent); 51 | fixture.detectChanges(); 52 | expect(queryByCss(fixture, 'fa-duotone-icon')).toBeTruthy(); 53 | }); 54 | 55 | it('should include size class', () => { 56 | @Component({ 57 | selector: 'fa-host', 58 | imports, 59 | template: ` 60 | 61 | 62 | 63 | 64 | `, 65 | }) 66 | class HostComponent { 67 | faUser = signal(faUser); 68 | faCircle = signal(faCircle); 69 | } 70 | 71 | const fixture = TestBed.createComponent(HostComponent); 72 | fixture.detectChanges(); 73 | expect(queryByCss(fixture, '.fa-2x')).toBeTruthy(); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Check 2 | on: pull_request 3 | jobs: 4 | check5: 5 | name: Font Awesome 5 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - uses: actions/setup-node@v4 10 | with: 11 | node-version: '20' 12 | - uses: actions/cache@v4 13 | with: 14 | path: .yarn/cache 15 | key: ${{ hashFiles('yarn.lock') }} 16 | - run: corepack enable 17 | - run: yarn 18 | - run: yarn add -D @fortawesome/free-regular-svg-icons@5.15.4 @fortawesome/free-solid-svg-icons@5.15.4 19 | - run: yarn format:enforce 20 | - run: yarn lint 21 | - run: yarn test 22 | - run: yarn test:schematics 23 | - run: yarn build 24 | - run: yarn build:schematics 25 | - run: yarn build:demo 26 | - run: yarn test:demo 27 | - run: yarn add -D chromedriver@~`google-chrome --version | awk '{print $3}' | awk -F. '{print $1}'` 28 | - run: yarn test:integration 29 | - run: yarn test:integration:ssr 30 | check6: 31 | name: Font Awesome 6 32 | runs-on: ubuntu-latest 33 | steps: 34 | - uses: actions/checkout@v4 35 | - uses: actions/setup-node@v4 36 | with: 37 | node-version: '20' 38 | - uses: actions/cache@v4 39 | with: 40 | path: .yarn/cache 41 | key: ${{ hashFiles('yarn.lock') }} 42 | - run: corepack enable 43 | - run: yarn 44 | - run: yarn add -D @fortawesome/free-regular-svg-icons@6.7.2 @fortawesome/free-solid-svg-icons@6.7.2 45 | - run: yarn format:enforce 46 | - run: yarn lint 47 | - run: yarn test 48 | - run: yarn test:schematics 49 | - run: yarn build 50 | - run: yarn build:schematics 51 | - run: yarn build:demo 52 | - run: yarn test:demo 53 | - run: yarn add -D chromedriver@~`google-chrome --version | awk '{print $3}' | awk -F. '{print $1}'` 54 | - run: yarn test:integration 55 | - run: yarn test:integration:ssr 56 | check7: 57 | name: Font Awesome 7 58 | runs-on: ubuntu-latest 59 | steps: 60 | - uses: actions/checkout@v4 61 | - uses: actions/setup-node@v4 62 | with: 63 | node-version: '20' 64 | - uses: actions/cache@v4 65 | with: 66 | path: .yarn/cache 67 | key: ${{ hashFiles('yarn.lock') }} 68 | - run: corepack enable 69 | - run: yarn 70 | - run: yarn format:enforce 71 | - run: yarn lint 72 | - run: yarn test 73 | - run: yarn test:schematics 74 | - run: yarn build 75 | - run: yarn build:schematics 76 | - run: yarn build:demo 77 | - run: yarn test:demo 78 | - run: yarn add -D chromedriver@~`google-chrome --version | awk '{print $3}' | awk -F. '{print $1}'` 79 | - run: yarn test:integration 80 | - run: yarn test:integration:ssr 81 | -------------------------------------------------------------------------------- /DEVELOPER.md: -------------------------------------------------------------------------------- 1 | # Developer Documentation 2 | 3 | Thanks for taking the time to consider contributing to the project. You will find documentation here that will help you get a local environment setup for contributing to the project as well as some helpful guidance on how you can help keep `angular-fontawesome` going. 4 | 5 | ## Prerequisites 6 | 7 | * [git](https://git-scm.com/downloads) 8 | * [node 18+](https://nodejs.org/en/download/) 9 | 10 | ## Setting up the local environment 11 | 12 | 1. `git clone https://github.com/FortAwesome/angular-fontawesome` 13 | 1. `cd angular-fontawesome` 14 | 1. `corepack enable` - to get the global `yarn` command 15 | 1. `yarn` - install dependencies 16 | 1. `yarn build:watch` (in terminal 1) - build the library and keep watching for changes 17 | 1. `yarn start` (in terminal 2) - start sample application using library distribution from the previous step 18 | 1. Visit http://localhost:4200 and observe sample application running 19 | 20 | ## Make changes 21 | 22 | 1. Modify the code. You can use sample application from the previous step to check that your changes behave as intended. 23 | 2. Once you're done with the implementation add relevant tests and ensure that `yarn lint` and `yarn test` pass. 24 | 3. Submit a pull request. 25 | 26 | ## Development tasks 27 | 28 | Development tasks are managed as `scripts` inside of `package.json`. Below are the description of the common tasks: 29 | 30 | Command | Purpose 31 | --- | --- 32 | `yarn format` | Format codebase using Prettier 33 | `yarn lint` | Verify code style 34 | `yarn test` | Execute unit tests 35 | `yarn test:schematics` | Execute unit tests for schematics 36 | `yarn test:demo` | Execute unit tests of the demo project 37 | `yarn test:integration` | Execute integration tests 38 | `yarn start` | Run development server for the demo application 39 | `yarn build` | Build library 40 | `yarn build:schematics` | Build schematics (should be run after the library build) 41 | 42 | ## Releasing 43 | 44 | 1. Bump version in `package.json` 45 | 1. Update versions in `projects/schematics/src/ng-add/versions.ts` to align with the published release. 46 | 1. Add contributors to `README.md` 47 | 1. Update Compatibility table in `README.md` and `docs/guide/compatibility.md` 48 | 1. Update the `CHANGELOG.md` 49 | 1. Update the `UPGRADING.md` if necessary 50 | 1. `yarn build && yarn build:schematics` 51 | 1. `cd dist/angular-fontawesome` 52 | 1. `npm publish` - publish to public registry 53 | 1. `npm publish --registry https://npm.fontawesome.com` - publish to Pro registry 54 | 1. `git commit -a -m 'Release VERSION'` 55 | 1. `git tag && git push upstream && git push upstream --tags` - create a tag and push all changes to GitHub 56 | 1. Create a [new release](https://github.com/FortAwesome/angular-fontawesome/releases/new) with CHANGELOG details 57 | 1. Update StackBlitz sample projects: [one](https://stackblitz.com/edit/angular-ivy-7jrcne) and [two](https://stackblitz.com/edit/angular-ivy-9mvggg) 58 | -------------------------------------------------------------------------------- /docs/usage/explicit-reference.md: -------------------------------------------------------------------------------- 1 | # Explicit reference approach 2 | 3 | The explicit reference approach involves explicitly importing the icon definition from the npm package, assigning it to the component's property and then binding this property to the `icon` input of the `fa-icon` component. 4 | 5 | While this approach is more verbose than the [icon library](./icon-library.md) approach, it makes it much easier to figure out where or whether the given icon is used. For example, with Find usages feature of the IDE. Another benefit of this approach is that it will produce a compile-time error if an icon is missing. 6 | 7 | `src/app/app.component.html` 8 | 9 | ```html 10 |
11 | 12 |
13 | ``` 14 | 15 | `src/app/app.component.ts` 16 | 17 | 1. Import `{ FontAwesomeModule } from '@fortawesome/angular-fontawesome'`. 18 | 1. Add `FontAwesomeModule` to `imports`. 19 | 20 | Note that you need to add `FontAwesomeModule` to the `imports` of every module/component where you want to use `fa-icon` component, because of Angular module encapsulation. You can read more about it in [this blog post](https://indepth.dev/posts/1056/avoiding-common-confusions-with-modules-in-angular#module-encapsulation). 21 | 1. Import an icon like `{ faCoffee } from '@fortawesome/free-solid-svg-icons'`. 22 | 1. Assign icon to the component property using `faCoffee = faCoffee`. 23 | 24 | ```typescript 25 | import { Component } from '@angular/core'; 26 | import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 27 | import { faCoffee } from '@fortawesome/free-solid-svg-icons'; 28 | 29 | @Component({ 30 | selector: 'app-root', 31 | imports: [FontAwesomeModule], 32 | templateUrl: './app.component.html', 33 | }) 34 | export class AppComponent { 35 | faCoffee = faCoffee; 36 | } 37 | ``` 38 | 39 | You can also use a [Font Awesome Kit](https://fontawesome.com/kits). With a Kit 40 | you can upload your own icons or pick only the icons you'd like to use. 41 | 42 | [Find out more about Kits and how you can use them in JavaScript projects](https://fontawesome.com/docs/web/setup/use-kit) 43 | 44 | ```typescript 45 | import { Component } from '@angular/core'; 46 | import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 47 | import { faCoffee } from '@awesome.me/kit-KIT_CODE/icons/classic/solid'; // KIT_CODE is a unique identifier for you Pro Kit 48 | 49 | @Component({ 50 | selector: 'app-root', 51 | imports: [FontAwesomeModule], 52 | templateUrl: './app.component.html', 53 | }) 54 | export class AppComponent { 55 | faCoffee = faCoffee; 56 | } 57 | ``` 58 | 59 | Kit packages use a [subpath exports](https://nodejs.org/api/packages.html#subpath-exports) feature of Node.js. If you 60 | get an error like `Cannot find module '@awesome.me/kit-KIT_CODE/icons/classic/solid' or its corresponding type 61 | declartions.`, you may need to update your `tsconfig.json` to set `moduleResolution` to `bundler`: 62 | 63 | ```json 64 | { 65 | "compilerOptions": { 66 | "moduleResolution": "bundler" 67 | } 68 | } 69 | ``` 70 | 71 | -------------------------------------------------------------------------------- /docs/upgrading/0.4.0-0.5.0.md: -------------------------------------------------------------------------------- 1 | # Upgrading 0.4.0 to 0.5.0 2 | 3 | ## Migrate from global icon library to FaIconLibrary 4 | 5 | Icon library from `@fortawesome/fontawesome-svg-core` (referred as *global icon library*) is deprecated in favour of `FaIconLibrary` provided by `@fortawesome/angular-fontawesome` and managed by Angular (referred as *icon library*). 6 | 7 | The library will emit a warning when icon definition from a global icon library is used, so to migrate you'll need to replace all usages of the global icon library. 8 | 9 | ```diff 10 | import { NgModule } from '@angular/core'; 11 | import { BrowserModule } from '@angular/platform-browser'; 12 | -import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 13 | -import { library } from '@fortawesome/fontawesome-svg-core'; 14 | +import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; 15 | import { faCoffee, fas } from '@fortawesome/free-solid-svg-icons'; 16 | import { AppComponent } from './app.component'; 17 | 18 | @NgModule({ 19 | declarations: [AppComponent], 20 | imports: [BrowserModule, FontAwesomeModule], 21 | bootstrap: [AppComponent] 22 | }) 23 | export class AppModule { 24 | - constructor() { 25 | + constructor(library: FaIconLibrary) { 26 | - library.add(fas, faCoffee); 27 | + library.addIconPacks(fas); 28 | + library.addIcons(faCoffee); 29 | } 30 | } 31 | ``` 32 | 33 | You can also use `FaConfig.globalLibrary` property to change the warning into the hard error or suppress warnings altogether (not recommended). 34 | 35 | Note 1: `@fortawesome/fontawesome-svg-core` package is still used internally by the components, so you should not remove it from the dependencies and should use version 1.2.21 or newer as it is required by the peer dependency of `@fortawesome/angular-fontawesome` package. 36 | 37 | Note 2: `FaIconLibrary` is only used by components provided by `angular-fontawesome` and won't work for `dom.watch()`. To make it work you'll need to register icons in both libraries. We actually don't recommend using `angular-fontawesome` together with `dom.watch()` and thinking to deprecated it. If you currently utilize it, please, drop by into https://github.com/FortAwesome/angular-fontawesome/issues/171 and share your use case. 38 | 39 | ## Changed semantics of FaIconComponent.icon property 40 | 41 | `FaIconComponent.icon` property used to have type `Icon` (rendered icon object), which was changed to `IconProp` as it is now an input property to specify the icon definition. No replacement is provided. 42 | 43 | If you were working with `FaIconComponent` programmatically you should switch from setting `FaIconComponent.iconProp` to `FaIconComponent.icon` as former is deprecated. 44 | 45 | ## FaIconComponent.listItem is deprecated 46 | 47 | The input was not working and we don't want to support this pattern in angular-fontawesome. 48 | 49 | You can use `fixedWidth=true` and custom CSS to achieve similar behavior: 50 | 51 | ```css 52 | ul { 53 | list-style-type: none; 54 | padding-left: 20px; 55 | } 56 | ``` 57 | 58 | Demo: https://stackblitz.com/edit/angular-z8v4ux-o2yduf 59 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This is the repository for the _official_ Font Awesome Angular component, _initialized_ by the team behind Font Awesome, but intended to evolve over time with _community_ contributions. 2 | 3 | # Ways to Contribute 4 | 5 | ## Ask a Question 6 | 7 | Trying to figure out how to make it work? Or how to use it in your scenario? 8 | 9 | 1. Review the [README](README.md) 10 | 2. Get familiar with the documentation for the [SVG with JavaScript](https://fontawesome.com/how-to-use/svg-with-js) implementation, the framework upon which this component is built. Sometimes the answers you need may be there. 11 | 3. Post any remaining questions on [StackOverflow](https://stackoverflow.com/questions/tagged/angular-fontawesome) with the tag `angular-fontawesome`. 12 | 13 | ## Report a Bug 14 | 15 | 1. Create a test case that reproduces the unexpected behavior using [this StackBlitz template](https://stackblitz.com/edit/angular-ivy-9mvggg) 16 | 2. [Open a new issue with this template](https://github.com/FortAwesome/angular-fontawesome/issues/new?template=bug-report.md), and be sure to include a link to the reproduction you made with StackBlitz. 17 | 18 | ## Submit a Pull Request 19 | 20 | Add tests if you add code. 21 | 22 | ## Everything Else 23 | 24 | - [Request a feature](https://github.com/FortAwesome/angular-fontawesome/issues/new??title=Feature%20request:feature-name&template=feature-request.md) 25 | - [Request a new icon](https://github.com/FortAwesome/Font-Awesome/issues/new?title=Icon%20request:%20icon-name&template=icon-request.md) 26 | 27 | # Project Goals 28 | 29 | 1. Achieve and maintain feature parity with Font Awesome's [SVG with JavaScript](https://fontawesome.com/how-to-use/svg-with-js) method. 30 | 31 | 2. Keep with best practices in the Angular development community. 32 | 33 | 3. Stay current with major developments in Angular and Angular-CLI 34 | 35 | 4. Maintain a reasonable level of consistency between this component and the other Font Awesome official JavaScript framework components ([Vue](https://github.com/FortAwesome/vue-fontawesome), [React](https://github.com/FortAwesome/react-fontawesome), [Ember](https://github.com/FortAwesome/ember-fontawesome)) 36 | 37 | 5. Sharing responsibility: The Font Awesome team will continue to be involved in ongoing development, hoping to _propel_ the project's momentum as we make _our_ contributions, while minimizing any bottle-necking that may happen as we balance our own priorities across various projects. Ideally, members of the community will enjoy lending a hand to help keep the project moving forward by responding to issues, answering questions on StackOverflow, reviewing and merging pull requests, and publishing npm updates. 38 | 39 | # Code of Conduct 40 | 41 | We'll contribute according to the [Code of Conduct](CODE_OF_CONDUCT.md). 42 | 43 | # Wanted: Core Contributors 44 | 45 | We're seeking core contributors to help drive this project. Core contributors: 46 | 47 | 1. Share these goals 48 | 2. Demonstrate competence through contributions 49 | 3. Contribute with conduct fitting with our code of conduct 50 | 4. Want to make this project awesome 51 | -------------------------------------------------------------------------------- /src/lib/layers/layers-text.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, computed, DOCUMENT, inject, input } from '@angular/core'; 2 | import { DomSanitizer } from '@angular/platform-browser'; 3 | import { 4 | FlipProp, 5 | parse, 6 | PullProp, 7 | RotateProp, 8 | SizeProp, 9 | Styles, 10 | text, 11 | TextParams, 12 | Transform, 13 | } from '@fortawesome/fontawesome-svg-core'; 14 | import { FaConfig } from '../config'; 15 | import { faWarnIfParentNotExist } from '../shared/errors/warn-if-parent-not-exist'; 16 | import { FaProps } from '../shared/models/props.model'; 17 | import { faClassList, isKnownRotateValue } from '../shared/utils/classlist.util'; 18 | import { ensureCss } from '../shared/utils/css'; 19 | import { FaLayersComponent } from './layers.component'; 20 | 21 | @Component({ 22 | selector: 'fa-layers-text', 23 | template: '', 24 | host: { 25 | class: 'ng-fa-layers-text', 26 | '[innerHTML]': 'renderedHTML()', 27 | }, 28 | changeDetection: ChangeDetectionStrategy.OnPush, 29 | }) 30 | export class FaLayersTextComponent { 31 | readonly content = input.required(); 32 | readonly title = input(); 33 | readonly flip = input(); 34 | readonly size = input(); 35 | readonly pull = input(); 36 | readonly border = input(); 37 | readonly inverse = input(); 38 | readonly rotate = input(); 39 | readonly fixedWidth = input(); 40 | readonly transform = input(); 41 | 42 | readonly renderedHTML = computed(() => { 43 | const params = this.buildParams(); 44 | return this.updateContent(params); 45 | }); 46 | 47 | private readonly document = inject(DOCUMENT); 48 | private readonly config = inject(FaConfig); 49 | private readonly parent = inject(FaLayersComponent, { optional: true }); 50 | private readonly sanitizer = inject(DomSanitizer); 51 | 52 | constructor() { 53 | faWarnIfParentNotExist(this.parent, 'FaLayersComponent', 'FaLayersTextComponent'); 54 | } 55 | 56 | /** 57 | * Updating params by component props. 58 | */ 59 | protected buildParams(): TextParams { 60 | const classOpts: FaProps = { 61 | flip: this.flip(), 62 | border: this.border(), 63 | inverse: this.inverse(), 64 | size: this.size(), 65 | pull: this.pull(), 66 | rotate: this.rotate(), 67 | fixedWidth: this.fixedWidth(), 68 | }; 69 | 70 | const transform = this.transform(); 71 | const parsedTransform = typeof transform === 'string' ? parse.transform(transform) : transform; 72 | 73 | const styles: Styles = {}; 74 | if (classOpts.rotate != null && !isKnownRotateValue(classOpts.rotate)) { 75 | styles['--fa-rotate-angle'] = `${classOpts.rotate}`; 76 | } 77 | 78 | return { 79 | transform: parsedTransform, 80 | classes: faClassList(classOpts), 81 | title: this.title(), 82 | styles, 83 | }; 84 | } 85 | 86 | private updateContent(params: TextParams) { 87 | ensureCss(this.document, this.config); 88 | return this.sanitizer.bypassSecurityTrustHtml(text(this.content() || '', params).html.join('\n')); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: https://contributor-covenant.org 46 | [version]: https://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { DecimalPipe } from '@angular/common'; 2 | import { Component, inject } from '@angular/core'; 3 | import { FaConfig, FaIconLibrary, FontAwesomeModule, IconDefinition } from '@fortawesome/angular-fontawesome'; 4 | import { faFlag, faUser as regularUser } from '@fortawesome/free-regular-svg-icons'; 5 | import { 6 | faAdjust, 7 | faBatteryQuarter, 8 | faBell, 9 | faCircle, 10 | faCoffee, 11 | faCog, 12 | faEllipsisH, 13 | faFighterJet, 14 | faHeart, 15 | faMagic, 16 | faSpinner, 17 | faSquare, 18 | faTimes, 19 | faUser, 20 | faFlag as solidFlag, 21 | } from '@fortawesome/free-solid-svg-icons'; 22 | import { AlternatePrefixComponent } from './alternate-prefix.component'; 23 | 24 | @Component({ 25 | selector: 'app-root', 26 | imports: [DecimalPipe, FontAwesomeModule, AlternatePrefixComponent], 27 | templateUrl: './app.component.html', 28 | styleUrls: ['./app.component.scss'], 29 | }) 30 | export class AppComponent { 31 | faBell = faBell; 32 | faCog = faCog; 33 | faFlag = faFlag; 34 | solidFlag = solidFlag; 35 | faTimes = faTimes; 36 | faMagic = faMagic; 37 | faAdjust = faAdjust; 38 | faCircle = faCircle; 39 | faCoffee = faCoffee; 40 | faSquare = faSquare; 41 | regularUser = regularUser; 42 | faEllipsisH = faEllipsisH; 43 | faFighterJet = faFighterJet; 44 | faBatteryQuarter = faBatteryQuarter; 45 | faHeart = faHeart; 46 | faSpinner = faSpinner; 47 | 48 | faDummy: IconDefinition = { 49 | prefix: 'fad', 50 | iconName: 'dummy', 51 | icon: [512, 512, [], '', ['M50 50 H412 V250 H50 Z', 'M50 262 H412 V462 H50 Z']], 52 | }; 53 | 54 | notificationsCounter = 1000; 55 | isAnimated = true; 56 | magicLevel = 0; 57 | 58 | selectedPosition: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' = 'bottom-right'; 59 | 60 | constructor() { 61 | // Notice that we're adding two different icon objects to the library. 62 | // Each of them within their respective icon npm packages are exported as faUser, 63 | // but we've renamed the second one in order to disambiguate the two objects within 64 | // this JavaScript module. Internally, these objects are different, even though they have the same iconName. 65 | // They have different prefixes: faUser has a prefix of fas, since it came from free-solid-svg-icons; 66 | // regularUser has a prefix of far, since it came from free-regular-svg-icons. 67 | // And of course, they also have different SVG content, resulting in different appearances. 68 | // So they really are totally different icons. However, they share the same iconName: user. 69 | // So in the template, the only way to reference the non-default (fas) icon is to either 70 | // use the array syntax that specifies [prefix, iconName], like this: 71 | // 72 | // 73 | // 74 | // Or we could make the regularUser object available to the template and simply 75 | // reference it as an object, like this: 76 | // 77 | // 78 | // 79 | // You don't specify the prefix in that case, because the icon object knows its own prefix. 80 | inject(FaIconLibrary).addIcons(faUser, regularUser); 81 | inject(FaConfig).fallbackIcon = faMagic; 82 | } 83 | 84 | onChange(event: any) { 85 | this.selectedPosition = event.target.value; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /docs/upgrading/0.1.0-0.1.0-6.md: -------------------------------------------------------------------------------- 1 | ## Upgrading 0.1.0-x to >= 0.1.0-6 2 | 3 | ### Renamed packages 4 | 5 | The following packages have been renamed as part of 5.1.0 of Font Awesome. 6 | 7 | _All packages are in the [@fortawesome NPM scope](https://www.npmjs.com/search?q=scope:fortawesome&page=1&ranking=optimal)_ 8 | 9 | | Old package(1) | New package | 10 | |--------------------------|------------------------| 11 | | fontawesome | fontawesome-svg-core | 12 | | fontawesome-free-solid | free-solid-svg-icons | 13 | | fontawesome-free-regular | free-regular-svg-icons | 14 | | fontawesome-free-brands | free-brands-svg-icons | 15 | | fontawesome-pro-solid | pro-solid-svg-icons | 16 | | fontawesome-pro-regular | pro-regular-svg-icons | 17 | | fontawesome-pro-light | pro-light-svg-icons | 18 | 19 | (1) Old packages have now been deprecated. They are still available but will only receive high priority patch release fixes. 20 | 21 | **You'll need to update your package.json file with the renamed packages and new versions.** 22 | 23 | How does your Angular usage change? 24 | 25 | ~~Old way:~~ 26 | 27 | ```javascript 28 | import { Component } from '@angular/core'; 29 | import { faCoffee } from '@fortawesome/fontawesome-free-solid'; 30 | import { faUser as regularUser } from '@fortawesome/fontawesome-free-regular'; 31 | import { library } from '@fortawesome/fontawesome'; 32 | 33 | @Component({ 34 | selector: 'example-root', 35 | templateUrl: './example.component.html', 36 | styleUrls: [] 37 | }) 38 | export class ExampleComponent { 39 | faCoffee = faCoffee; 40 | regularUser = regularUser; 41 | } 42 | ``` 43 | 44 | New way: 45 | 46 | ```javascript 47 | import { Component } from '@angular/core'; 48 | import { faCoffee } from '@fortawesome/free-solid-svg-icons'; 49 | import { faUser as regularUser } from '@fortawesome/free-regular-svg-icons'; 50 | import { library } from '@fortawesome/fontawesome-svg-core'; 51 | 52 | @Component({ 53 | selector: 'example-root', 54 | templateUrl: './example.component.html', 55 | styleUrls: [] 56 | }) 57 | export class ExampleComponent { 58 | faCoffee = faCoffee; 59 | regularUser = regularUser; 60 | } 61 | ``` 62 | 63 | ### Improved support for tree shaking 64 | 65 | Tree shaking is now functional by default and no additional configuration is required to make it work. 66 | 67 | The `shakable.es.js` module has been removed and is no longer needed. 68 | 69 | If you've previously configured tree shaking by modifying your `tsconfig.json` you can safely remove this. 70 | 71 | ```javascript 72 | { 73 | "compilerOptions": { 74 | "paths": { 75 | "@fortawesome/fontawesome-free-solid": ["node_modules/@fortawesome/fontawesome-free-solid/shakable.es.js"], 76 | "@fortawesome/fontawesome-free-brands": ["node_modules/@fortawesome/fontawesome-free-brands/shakable.es.js"] 77 | } 78 | } 79 | } 80 | ``` 81 | 82 | **We recommend that you check your bundle size after upgrading an ensure that file sizes are as you would expect.** 83 | 84 | ### Mixed modes with automatic replacement of `` tags to `` 85 | 86 | If you were previously relying on Font Awesome to replace any `` tags in 87 | your page or app with `` you'll need to explicitly control that now. 88 | 89 | ```javascript 90 | import { dom } from '@fortawesome/fontawesome-svg-core' 91 | 92 | dom.watch() // This will kick of the replacement of i tags and configure a MutationObserver 93 | ``` 94 | -------------------------------------------------------------------------------- /projects/schematics/src/ng-add/index.ts: -------------------------------------------------------------------------------- 1 | import { workspaces } from '@angular-devkit/core'; 2 | import { chain, Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics'; 3 | import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; 4 | import { 5 | createSourceFile, 6 | ScriptTarget, 7 | } from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; 8 | import { addImportToModule } from '@schematics/angular/utility/ast-utils'; 9 | import { InsertChange } from '@schematics/angular/utility/change'; 10 | import { addPackageJsonDependency, NodeDependencyType } from '@schematics/angular/utility/dependencies'; 11 | import { getAppModulePath, isStandaloneApp } from '@schematics/angular/utility/ng-ast-utils'; 12 | import { getMainFilePath } from '@schematics/angular/utility/standalone/util'; 13 | import { getWorkspace } from '@schematics/angular/utility/workspace'; 14 | import { Schema } from './schema'; 15 | import { angularFontawesomeVersion, iconPackVersionMap } from './versions'; 16 | 17 | export default function (options: Schema): Rule { 18 | return chain([ 19 | (tree: Tree, context: SchematicContext) => { 20 | addPackageJsonDependency(tree, { 21 | type: NodeDependencyType.Default, 22 | name: '@fortawesome/angular-fontawesome', 23 | version: angularFontawesomeVersion, 24 | }); 25 | 26 | const iconPackages = options.iconPackages != null ? options.iconPackages : ['free-solid']; 27 | for (const pack of iconPackages) { 28 | addPackageJsonDependency(tree, { 29 | type: NodeDependencyType.Default, 30 | name: `@fortawesome/${pack}-svg-icons`, 31 | version: iconPackVersionMap[options.version as string].iconPackVersion, 32 | }); 33 | } 34 | 35 | context.addTask(new NodePackageInstallTask()); 36 | 37 | return tree; 38 | }, 39 | addModule(options), 40 | ]); 41 | } 42 | 43 | function addModule(options: Schema): Rule { 44 | return async (host: Tree) => { 45 | const workspace = await getWorkspace(host); 46 | const projectName = options.project as string; 47 | const project = workspace.projects.get(projectName); 48 | if (project == null) { 49 | throw new SchematicsException(`Project with name ${projectName} does not exist.`); 50 | } 51 | const mainPath = await getMainFilePath(host, projectName); 52 | if (!isStandaloneApp(host, mainPath)) { 53 | const modulePath = getAppModulePath(host, mainPath); 54 | const moduleSource = getSourceFile(host, modulePath); 55 | const changes = addImportToModule( 56 | moduleSource, 57 | modulePath, 58 | 'FontAwesomeModule', 59 | '@fortawesome/angular-fontawesome', 60 | ); 61 | const recorder = host.beginUpdate(modulePath); 62 | changes.forEach((change) => { 63 | if (change instanceof InsertChange) { 64 | recorder.insertLeft(change.pos, change.toAdd); 65 | } 66 | }); 67 | host.commitUpdate(recorder); 68 | } 69 | }; 70 | } 71 | 72 | function getSourceFile(host: Tree, path: string) { 73 | const buffer = host.read(path); 74 | if (!buffer) { 75 | throw new SchematicsException(`Could not find ${path}.`); 76 | } 77 | const content = buffer.toString('utf-8'); 78 | return createSourceFile(path, content, ScriptTarget.Latest, true); 79 | } 80 | 81 | export function getProjectTargetOptions(project: workspaces.ProjectDefinition, buildTarget: string) { 82 | const buildTargetObject = project.targets.get(buildTarget); 83 | if (buildTargetObject && buildTargetObject.options) { 84 | return buildTargetObject.options; 85 | } 86 | 87 | throw new SchematicsException(`Cannot determine project target configuration for: ${buildTarget}.`); 88 | } 89 | -------------------------------------------------------------------------------- /src/lib/icon/duotone-icon.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, input } from '@angular/core'; 2 | import { IconDefinition as CoreIconDefinition, IconParams } from '@fortawesome/fontawesome-svg-core'; 3 | import { IconDefinition, IconProp } from '../types'; 4 | import { FaIconComponent } from './icon.component'; 5 | 6 | @Component({ 7 | selector: 'fa-duotone-icon', 8 | template: ``, 9 | changeDetection: ChangeDetectionStrategy.OnPush, 10 | }) 11 | export class FaDuotoneIconComponent extends FaIconComponent { 12 | /** 13 | * Swap the default opacity of each duotone icon’s layers. This will make an 14 | * icon’s primary layer have the default opacity of 40% rather than its 15 | * secondary layer. 16 | * 17 | * @default false 18 | */ 19 | readonly swapOpacity = input<'true' | 'false' | boolean>(); 20 | 21 | /** 22 | * Customize the opacity of the primary icon layer. 23 | * Valid values are in range [0, 1.0]. 24 | * 25 | * @default 1.0 26 | */ 27 | readonly primaryOpacity = input(); 28 | 29 | /** 30 | * Customize the opacity of the secondary icon layer. 31 | * Valid values are in range [0, 1.0]. 32 | * 33 | * @default 0.4 34 | */ 35 | readonly secondaryOpacity = input(); 36 | 37 | /** 38 | * Customize the color of the primary icon layer. 39 | * Accepts any valid CSS color value. 40 | * 41 | * @default CSS inherited color 42 | */ 43 | readonly primaryColor = input(); 44 | 45 | /** 46 | * Customize the color of the secondary icon layer. 47 | * Accepts any valid CSS color value. 48 | * 49 | * @default CSS inherited color 50 | */ 51 | readonly secondaryColor = input(); 52 | 53 | protected override findIconDefinition(i: IconProp | IconDefinition): CoreIconDefinition | null { 54 | const definition = super.findIconDefinition(i); 55 | 56 | if (definition != null && !Array.isArray(definition.icon[4])) { 57 | throw new Error( 58 | 'The specified icon does not appear to be a Duotone icon. ' + 59 | 'Check that you specified the correct style: ' + 60 | ` ` + 61 | `or use: instead.`, 62 | ); 63 | } 64 | 65 | return definition; 66 | } 67 | 68 | protected override buildParams(): IconParams { 69 | const params = super.buildParams(); 70 | 71 | const swapOpacity = this.swapOpacity(); 72 | if (swapOpacity === true || swapOpacity === 'true') { 73 | if (Array.isArray(params.classes)) { 74 | params.classes.push('fa-swap-opacity'); 75 | } else if (typeof params.classes === 'string') { 76 | params.classes = [params.classes, 'fa-swap-opacity']; 77 | } else { 78 | params.classes = ['fa-swap-opacity']; 79 | } 80 | } 81 | 82 | if (params.styles == null) { 83 | params.styles = {}; 84 | } 85 | const primaryOpacity = this.primaryOpacity(); 86 | if (primaryOpacity != null) { 87 | params.styles['--fa-primary-opacity'] = primaryOpacity.toString(); 88 | } 89 | const secondaryOpacity = this.secondaryOpacity(); 90 | if (secondaryOpacity != null) { 91 | params.styles['--fa-secondary-opacity'] = secondaryOpacity.toString(); 92 | } 93 | const primaryColor = this.primaryColor(); 94 | if (primaryColor != null) { 95 | params.styles['--fa-primary-color'] = primaryColor; 96 | } 97 | const secondaryColor = this.secondaryColor(); 98 | if (secondaryColor != null) { 99 | params.styles['--fa-secondary-color'] = secondaryColor; 100 | } 101 | 102 | return params; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /docs/upgrading/0.14.0-0.15.0.md: -------------------------------------------------------------------------------- 1 | # Upgrading 0.14.0 to 0.15.0 2 | 3 | ## Remove usage of the `spin` and `pulse` inputs 4 | 5 | Previously deprecated `spin` and `pulse` inputs in all components were removed. The usage should be replaced with a generic `animation` input which supports more animations. See [Animating icons](https://fontawesome.com/docs/web/style/animate) for a reference. 6 | 7 | Dynamic animation can be achieved by binding the `animation` input to `undefined`: 8 | 9 | ```diff 10 | - 11 | + 12 | ``` 13 | 14 | ## Remove usage of the `styles` and `classes` inputs 15 | 16 | Previously deprecated `styles` and `classes` inputs in all components were removed. These inputs don't work the way one would expect and cause a lot of confusion. For the majority of the cases, one should use regular [class and style bindings](https://angular.io/guide/class-binding) provided by Angular. For those rare cases, when it is not enough, there is a guide on how one can style component's internal elements at their own risk - [Styling icon internals](https://github.com/FortAwesome/angular-fontawesome/blob/master/docs/guide/styling-icon-internals.md). 17 | 18 | ## Styles are correctly added in the SSR context 19 | 20 | Previously, the library didn't correctly add global styles in the SSR context. If you have added global styles to your application to work around issues like [#407](https://github.com/FortAwesome/angular-fontawesome/issues/407), [#18](https://github.com/FortAwesome/angular-fontawesome/issues/18) or [#48](https://github.com/FortAwesome/angular-fontawesome/issues/48), you can either remove the workaround or alternatively, disable automatic styles injection by setting `FaConfig.autoAddCss` to `false`: 21 | 22 | ```typescript 23 | import { FaConfig } from '@fortawesome/angular-fontawesome'; 24 | 25 | export class AppComponent { 26 | constructor(faConfig: FaConfig) { 27 | faConfig.autoAddCss = false; 28 | } 29 | } 30 | ``` 31 | 32 | Not doing this should not cause any issues, but it will lead to same styles being added twice to the page. 33 | 34 | ## @fortawesome/fontawesome-svg-core became a regular dependency 35 | 36 | Previously, `@fortawesome/fontawesome-svg-core` was a peer dependency. Now it is a regular dependency. This means that you don't have to add it to your `package.json` file anymore. Unless you use it directly for [advanced cases](https://github.com/FortAwesome/angular-fontawesome/blob/main/docs/guide/advanced-uses.md), you can remove the dependency: 37 | 38 | ```bash 39 | $ npm uninstall @fortawesome/fontawesome-svg-core 40 | ``` 41 | 42 | And import types from `@fortawesome/angular-fontawesome` instead of `@fortawesome/fontawesome-svg-core`, e.g: 43 | 44 | ```diff 45 | -import { IconDefinition } from '@fortawesome/fontawesome-svg-core'; 46 | +import { IconDefinition } from '@fortawesome/angular-fontawesome'; 47 | ``` 48 | 49 | ## Icon inputs are now more permissive 50 | 51 | Previously, `icon` input had a very restrictive type, which only allowed to specify icon pack and icon name values which exist in the Font Awesome icon packages. Now, the type is more permissive and allows to specify any string while retaining code completion for potentially available Font Awesome icon packs and icon names. 52 | 53 | No changes are needed in the code, but consumers should be aware that the `` component will no longer fail compilation if the icon name is not one of the Font Awesome icons, thus allowing to use [custom icons](../guide/custom-icons.md). 54 | 55 | Refer to https://github.com/FortAwesome/angular-fontawesome/pull/436 for more details on the change. 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fortawesome/angular-fontawesome", 3 | "version": "4.0.0", 4 | "description": "Angular Fontawesome, an Angular library", 5 | "scripts": { 6 | "ng": "ng", 7 | "test": "ng test angular-fontawesome --watch=false --browsers=ChromeCI", 8 | "test:schematics": "ts-node --project projects/schematics/tsconfig.json node_modules/.bin/jasmine projects/schematics/src/**/*.spec.ts", 9 | "test:demo": "ng test demo --watch=false --browsers=ChromeCI", 10 | "test:integration": "ng e2e demo", 11 | "test:integration:ssr": "ng e2e demo --configuration production-ssr", 12 | "lint": "ng lint", 13 | "start": "ng serve demo", 14 | "start:ssr": "ng serve demo --configuration development-ssr", 15 | "build": "ng build angular-fontawesome", 16 | "build:demo": "ng build demo", 17 | "build:watch": "ng build angular-fontawesome -c development --watch", 18 | "build:schematics": "tsc -p projects/schematics/tsconfig.json && ts-node -O '{\"module\":\"commonjs\"}' tasks/build-schematics.ts", 19 | "format": "prettier --write --ignore-path .gitignore '**/*.{js,ts,json,html}'", 20 | "format:enforce": "prettier --check --ignore-path .gitignore '**/*.{js,ts,json,html}'" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/FortAwesome/angular-fontawesome" 25 | }, 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/FortAwesome/angular-fontawesome/issues" 29 | }, 30 | "homepage": "https://github.com/FortAwesome/angular-fontawesome", 31 | "devDependencies": { 32 | "@angular-devkit/build-angular": "patch:@angular-devkit/build-angular@npm%3A21.0.0#~/.yarn/patches/@angular-devkit-build-angular-npm-19.0.0-131974ef98.patch", 33 | "@angular-devkit/core": "^21.0.0", 34 | "@angular-devkit/schematics": "^21.0.0", 35 | "@angular/animations": "^21.0.0", 36 | "@angular/build": "^21.0.0", 37 | "@angular/cli": "^21.0.0", 38 | "@angular/common": "^21.0.0", 39 | "@angular/compiler": "^21.0.0", 40 | "@angular/compiler-cli": "^21.0.0", 41 | "@angular/core": "^21.0.0", 42 | "@angular/language-service": "^21.0.0", 43 | "@angular/platform-browser": "^21.0.0", 44 | "@angular/platform-browser-dynamic": "^21.0.0", 45 | "@angular/platform-server": "^21.0.0", 46 | "@angular/router": "^21.0.0", 47 | "@angular/ssr": "^21.0.0", 48 | "@fortawesome/free-regular-svg-icons": "^7.1.0", 49 | "@fortawesome/free-solid-svg-icons": "^7.1.0", 50 | "@types/express": "^4.17.25", 51 | "@types/jasmine": "~4.3.6", 52 | "@types/node": "~22.9.4", 53 | "@typescript-eslint/eslint-plugin": "^8.48.0", 54 | "@typescript-eslint/parser": "^8.48.0", 55 | "angular-eslint": "^21.0.1", 56 | "browser-sync": "^3.0.4", 57 | "chromedriver": "~142.0.3", 58 | "eslint": "^9.39.1", 59 | "eslint-config-prettier": "^10.1.8", 60 | "eslint-plugin-import": "2.32.0", 61 | "eslint-plugin-jsdoc": "^61.4.1", 62 | "eslint-plugin-prefer-arrow": "1.2.3", 63 | "express": "^4.21.2", 64 | "jasmine-core": "~4.5.0", 65 | "jasmine-spec-reporter": "~7.0.0", 66 | "karma": "~6.4.4", 67 | "karma-chrome-launcher": "~3.2.0", 68 | "karma-coverage": "~2.2.1", 69 | "karma-jasmine": "~5.1.0", 70 | "karma-jasmine-html-reporter": "^2.1.0", 71 | "ng-packagr": "^21.0.0", 72 | "prettier": "3.6.2", 73 | "protractor": "~7.0.0", 74 | "rxjs": "^7.8.2", 75 | "ts-node": "~10.9.2", 76 | "typescript": "^5.9.3", 77 | "typescript-eslint": "^8.48.0", 78 | "zone.js": "~0.15.1" 79 | }, 80 | "dependencies": { 81 | "@fortawesome/fontawesome-svg-core": "^7.1.0", 82 | "tslib": "^2.8.1" 83 | }, 84 | "keywords": [ 85 | "angular", 86 | "font", 87 | "awesome", 88 | "fontawesome", 89 | "icon", 90 | "svg" 91 | ], 92 | "peerDependencies": { 93 | "@angular/core": "^21.0.0" 94 | }, 95 | "schematics": "./schematics/collection.json", 96 | "packageManager": "yarn@4.9.2" 97 | } 98 | -------------------------------------------------------------------------------- /src/lib/icon/duotone-icon.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, inputBinding, viewChild, ViewContainerRef } from '@angular/core'; 2 | import { TestBed } from '@angular/core/testing'; 3 | import { faUser } from '@fortawesome/free-solid-svg-icons'; 4 | import { faDummy, queryByCss } from '../../testing/helpers'; 5 | import { FaDuotoneIconComponent } from './duotone-icon.component'; 6 | 7 | describe('FaDuotoneIconComponent', () => { 8 | it('should render the duotone icon', () => { 9 | const fixture = TestBed.createComponent(FaDuotoneIconComponent, { 10 | bindings: [inputBinding('icon', () => faDummy)], 11 | }); 12 | fixture.detectChanges(); 13 | expect(queryByCss(fixture, 'svg')).toBeTruthy(); 14 | }); 15 | 16 | it('should allow to swap opacity of the layers', () => { 17 | const fixture = TestBed.createComponent(FaDuotoneIconComponent, { 18 | bindings: [inputBinding('icon', () => faDummy), inputBinding('swapOpacity', () => true)], 19 | }); 20 | fixture.detectChanges(); 21 | expect(queryByCss(fixture, 'svg').classList.contains('fa-swap-opacity')).toBeTruthy(); 22 | }); 23 | 24 | it('should allow to customize opacity of the primary layer', () => { 25 | const fixture = TestBed.createComponent(FaDuotoneIconComponent, { 26 | bindings: [inputBinding('icon', () => faDummy), inputBinding('primaryOpacity', () => 0.1)], 27 | }); 28 | fixture.detectChanges(); 29 | expect(queryByCss(fixture, 'svg').style.getPropertyValue('--fa-primary-opacity')).toBe('0.1'); 30 | }); 31 | 32 | it('should allow to customize opacity of the secondary layer', () => { 33 | const fixture = TestBed.createComponent(FaDuotoneIconComponent, { 34 | bindings: [inputBinding('icon', () => faDummy), inputBinding('secondaryOpacity', () => 0.9)], 35 | }); 36 | fixture.detectChanges(); 37 | expect(queryByCss(fixture, 'svg').style.getPropertyValue('--fa-secondary-opacity')).toBe('0.9'); 38 | }); 39 | 40 | it('should allow to customize color of the primary layer', () => { 41 | const fixture = TestBed.createComponent(FaDuotoneIconComponent, { 42 | bindings: [inputBinding('icon', () => faDummy), inputBinding('primaryColor', () => 'red')], 43 | }); 44 | fixture.detectChanges(); 45 | expect(queryByCss(fixture, 'svg').style.getPropertyValue('--fa-primary-color')).toBe('red'); 46 | }); 47 | 48 | it('should allow to customize color of the secondary layer', () => { 49 | const fixture = TestBed.createComponent(FaDuotoneIconComponent, { 50 | bindings: [inputBinding('icon', () => faDummy), inputBinding('secondaryColor', () => 'red')], 51 | }); 52 | fixture.detectChanges(); 53 | expect(queryByCss(fixture, 'svg').style.getPropertyValue('--fa-secondary-color')).toBe('red'); 54 | }); 55 | 56 | it('should throw if specified icon is not a Duotone icon', () => { 57 | const fixture = TestBed.createComponent(FaDuotoneIconComponent, { bindings: [inputBinding('icon', () => faUser)] }); 58 | expect(() => fixture.detectChanges()).toThrow( 59 | new Error( 60 | 'The specified icon does not appear to be a Duotone icon. ' + 61 | "Check that you specified the correct style: " + 62 | 'or use: instead.', 63 | ), 64 | ); 65 | }); 66 | 67 | it('should be able to create component dynamically', () => { 68 | @Component({ 69 | selector: 'fa-host', 70 | template: '', 71 | }) 72 | class HostComponent { 73 | container = viewChild('host', { read: ViewContainerRef }); 74 | 75 | createIcon() { 76 | const componentRef = this.container()!.createComponent(FaDuotoneIconComponent); 77 | componentRef.setInput('icon', faDummy); 78 | } 79 | } 80 | 81 | const fixture = TestBed.createComponent(HostComponent); 82 | fixture.detectChanges(); 83 | expect(queryByCss(fixture, 'svg')).toBeFalsy(); 84 | 85 | fixture.componentInstance.createIcon(); 86 | fixture.detectChanges(); 87 | expect(queryByCss(fixture, 'svg')).toBeTruthy(); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /docs/guide/advanced-uses.md: -------------------------------------------------------------------------------- 1 | # Advanced uses 2 | 3 | While `` component provides a convenient way to render a Font Awesome icon in the Angular app, there are situations where you can't use it. This guide describes such situations and how to use Font Awesome JavaScript API to deal with them. 4 | 5 | The Font Awesome JavaScript API is distributed as the [`@fortawesome/fontawesome-svg-core`](https://www.npmjs.com/package/@fortawesome/fontawesome-svg-core) package. The [documentation](https://fontawesome.com/docs/apis/javascript/get-started) for the JavaScript API is available on the official website. 6 | 7 | ## Replace `` tags with icons in the arbitrary HTML 8 | 9 | **Problem:** You have an Angular application, but you need to replace `` tags used by the vanilla Font Awesome in the arbitrary markup, which is not part of the Angular templates. This often happens when the custom HTML markup is loaded from the backend and inserted into the page with `innerHTML`. 10 | 11 | In this case, markup is not part of the Angular template, and you can't use `` component outside the Angular template (see [this SO answer](https://stackoverflow.com/a/41089093/1377864) for more details). Because of this limitation, the `angular-fontawesome` library is not really useful. 12 | 13 | The first step is to add all icons which need to be replaced to the library used by the `fontawesome-svg-core` package. This should be done early to make sure that icons are in the library by the time you attempt to replace `` tags. For example, you can choose to put the below code in the `main.ts`: 14 | 15 | ```ts 16 | import { library } from '@fortawesome/fontawesome-svg-core' 17 | import { faCamera } from '@fortawesome/free-solid-svg-icons' 18 | 19 | library.add(faCamera) 20 | ``` 21 | 22 | Once icons are added to the library you have two options: 23 | 24 | 1. When custom markup is inserted into the page in a controlled way, it is better to call [`dom.i2svg()`](https://fontawesome.com/v5.15/how-to-use/javascript-api/methods/dom-i2svg) method once the custom markup has been added to the page. It will replace all `` tags with the icon `` elements. 25 | 26 | This approach is more performant. 27 | 2. When custom markup is inserted into the page in multiple places or by the third-party code (so you can't hook into it), then you can use [`dom.watch()`](https://fontawesome.com/v5.15/how-to-use/javascript-api/methods/dom-watch) method, which will utilize [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to listen to any markup changes and replace `` tags with the icon `` elements. 28 | 29 | Note that depending on the size of the application, this option may cause performance problems as the dynamic Angular application will trigger a lot of events even when icons don't need to be re-rendered. Also, note that in some situations `MutationObserver` may cause an infinite change detection loop (observed as a frozen application). To prevent this from happening, you should call `dom.watch()` outside of Angular zone by either putting it in the `main.ts` or wrapping it into [`NgZone.runOutsideAngular()`](https://angular.io/api/core/NgZone#runOutsideAngular) call. 30 | 31 | ## Include icon in the markup passed as a string to a JavaScript library 32 | 33 | **Problem:** You have an Angular application where you use some library, which accepts custom markup as a string parameter and injects it somewhere in the DOM (tooltip, Google Maps, etc). You want to include Font Awesome icon in this custom markup and tried to include `` component, but it didn't work. 34 | 35 | Such markup is not part of the Angular template, and you can't use `` component outside the Angular template (see [this SO answer](https://stackoverflow.com/a/41089093/1377864) for more details). Because of this limitation, the `angular-fontawesome` library is not really useful. 36 | 37 | While you can use `dom.i2svg()` or `dom.watch()` calls described in the previous scenario to handle this, it's often an overkill. As you control the markup, you can render icons into SVG strings using [`icon()`](https://fontawesome.com/v5.15/how-to-use/javascript-api/methods/icon) function and concatenate them with the rest of the markup. See the below example. 38 | 39 | ```ts 40 | import { icon } from '@fortawesome/fontawesome-svg-core'; 41 | import { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons'; 42 | 43 | myTooltipLib({ 44 | content: `

Hint: You can navigate items with ${icon(faChevronLeft).html.join('')} and ${icon(faChevronRight).html.join('')} buttons.

` 45 | }) 46 | ``` 47 | -------------------------------------------------------------------------------- /projects/schematics/src/ng-add/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "angular-fontawesome-ng-add", 4 | "title": "Font Awesome ng-add schematic", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The name of the project.", 10 | "$default": { 11 | "$source": "projectName" 12 | } 13 | }, 14 | "version": { 15 | "description": "The FontAwesome version to install.", 16 | "type": "string", 17 | "default": "7", 18 | "x-prompt": { 19 | "message": "Choose Font Awesome version you would like to use:", 20 | "type": "list", 21 | "items": [ 22 | { 23 | "value": "7", 24 | "label": "Font Awesome 7" 25 | }, 26 | { 27 | "value": "6", 28 | "label": "Font Awesome 6" 29 | }, 30 | { 31 | "value": "5", 32 | "label": "Font Awesome 5" 33 | } 34 | ] 35 | } 36 | }, 37 | "iconPackages": { 38 | "description": "The icon packages to install.", 39 | "type": "array", 40 | "items": { 41 | "type": "string", 42 | "enum": [ 43 | "free-solid", 44 | "free-regular", 45 | "free-brands", 46 | "pro-solid", 47 | "pro-regular", 48 | "pro-light", 49 | "pro-thin", 50 | "pro-duotone", 51 | "duotone-regular", 52 | "duotone-light", 53 | "duotone-thin", 54 | "sharp-solid", 55 | "sharp-regular", 56 | "sharp-light", 57 | "sharp-thin", 58 | "sharp-duotone-solid", 59 | "sharp-duotone-regular", 60 | "sharp-duotone-light", 61 | "sharp-duotone-thin" 62 | ] 63 | }, 64 | "default": ["free-solid"], 65 | "x-prompt": { 66 | "message": "Choose Font Awesome icon packages you would like to use:", 67 | "type": "list", 68 | "multiselect": true, 69 | "items": [ 70 | { 71 | "value": "free-solid", 72 | "label": "Free Solid Icons" 73 | }, 74 | { 75 | "value": "free-regular", 76 | "label": "Free Regular Icons" 77 | }, 78 | { 79 | "value": "free-brands", 80 | "label": "Free Brands Icons" 81 | }, 82 | { 83 | "value": "pro-solid", 84 | "label": "Pro Solid Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 85 | }, 86 | { 87 | "value": "pro-regular", 88 | "label": "Pro Regular Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 89 | }, 90 | { 91 | "value": "pro-light", 92 | "label": "Pro Light Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 93 | }, 94 | { 95 | "value": "pro-thin", 96 | "label": "Pro Thin Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 97 | }, 98 | { 99 | "value": "pro-duotone", 100 | "label": "Pro Duotone Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 101 | }, 102 | { 103 | "value": "duotone-regular", 104 | "label": "Duotone Regular Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 105 | }, 106 | { 107 | "value": "duotone-light", 108 | "label": "Duotone Light Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 109 | }, 110 | { 111 | "value": "duotone-thin", 112 | "label": "Duotone Thin Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 113 | }, 114 | { 115 | "value": "sharp-solid", 116 | "label": "Sharp Solid Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 117 | }, 118 | { 119 | "value": "sharp-regular", 120 | "label": "Sharp Regular Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 121 | }, 122 | { 123 | "value": "sharp-light", 124 | "label": "Sharp Light Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 125 | }, 126 | { 127 | "value": "sharp-thin", 128 | "label": "Sharp Thin Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 129 | }, 130 | { 131 | "value": "sharp-duotone-solid", 132 | "label": "Sharp Duotone Solid Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 133 | }, 134 | { 135 | "value": "sharp-duotone-regular", 136 | "label": "Sharp Duotone Regular Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 137 | }, 138 | { 139 | "value": "sharp-duotone-light", 140 | "label": "Sharp Duotone Light Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 141 | }, 142 | { 143 | "value": "sharp-duotone-thin", 144 | "label": "Sharp Duotone Thin Icons [ Requires Pro plan: https://fontawesome.com/plans ]" 145 | } 146 | ] 147 | } 148 | } 149 | }, 150 | "required": [], 151 | "additionalProperties": false 152 | } 153 | -------------------------------------------------------------------------------- /docs/usage/icon-library.md: -------------------------------------------------------------------------------- 1 | # Icon library approach 2 | 3 | The icon library approach provides convenient usage in the templates, but the icons have to be managed separately from the components. This has long-term maintenance implications, specifically, this means that there is no easy way to tell if any given icon is in use. Therefore, if someone accidentally removes an icon from the icon library, the application will build just fine, but the component that needs this icon will break at runtime. 4 | 5 | Icons should be registered only once in the `AppComponent`'s constructor using `FaIconLibrary.addIcons()` or `FaIconLibrary.addIconPacks()` calls. Icons added to the library will be available everywhere in the application and can be referenced just by their name. This eliminates the need to explicitly import icons and assign them to a property of every individual component to be able to use them in the template as with the [explicit reference](./explicit-reference.md) approach. 6 | 7 | `src/app/app.component.html` 8 | 9 | ```html 10 | 11 | 12 | 13 | 14 | ``` 15 | 16 | `src/app/app.component.ts` 17 | 18 | 1. Import `{ FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'`. 19 | 1. Add `FontAwesomeModule` to `imports`. 20 | 21 | Note that you need to add `FontAwesomeModule` to the `imports` of every module/component where you want to use `fa-icon` component, because of Angular module encapsulation. You can read more about it in [this blog post](https://indepth.dev/posts/1056/avoiding-common-confusions-with-modules-in-angular#module-encapsulation). 22 | 1. Inject `FaIconLibrary` into constructor of the `AppComponent`. 23 | 1. Import an icon like `{ faCoffee } from '@fortawesome/free-solid-svg-icons'`. 24 | 1. Add icon to the library with `library.addIcons(faCoffee)`. 25 | 26 | ```typescript 27 | import { Component, inject } from '@angular/core'; 28 | import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; 29 | import { faCoffee } from '@fortawesome/free-solid-svg-icons'; 30 | 31 | @Component({ 32 | selector: 'app-root', 33 | imports: [FontAwesomeModule], 34 | templateUrl: './app.component.html', 35 | }) 36 | export class AppComponent { 37 | constructor() { 38 | // Add an icon to the library for convenient access in other components 39 | const library = inject(FaIconLibrary); 40 | library.addIcons(faCoffee); 41 | } 42 | } 43 | ``` 44 | 45 | You can also import entire icon styles. But be careful! This way of importing icons does not support tree-shaking, so all icons from the imported package will end up in the bundle. 46 | 47 | ```typescript 48 | import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; 49 | import { fas } from '@fortawesome/free-solid-svg-icons'; 50 | import { far } from '@fortawesome/free-regular-svg-icons'; 51 | 52 | export class AppComponent { 53 | constructor() { 54 | const library = inject(FaIconLibrary); 55 | library.addIconPacks(fas, far); 56 | } 57 | } 58 | ``` 59 | 60 | A better way can be to use a [Font Awesome Kit](https://fontawesome.com/kits) to only include the icons you choose. You can even upload your own icons. 61 | 62 | [Find out more about Kits and how you can use them in JavaScript projects](https://fontawesome.com/docs/web/setup/use-kit) 63 | 64 | _In these examples, you would replace "KIT_CODE" with the unique identifier for your Pro Kit_ 65 | 66 | ```typescript 67 | import { Component, inject } from '@angular/core'; 68 | import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; 69 | import { all } from '@awesome.me/kit-KIT_CODE/icons'; 70 | 71 | @Component({ 72 | selector: 'app-root', 73 | imports: [FontAwesomeModule], 74 | templateUrl: './app.component.html', 75 | }) 76 | export class AppComponent { 77 | constructor() { 78 | // Add an icon to the library for convenient access in other components 79 | const library = inject(FaIconLibrary); 80 | library.addIcons(...all); 81 | } 82 | } 83 | ``` 84 | 85 | Kit packages use a [subpath exports](https://nodejs.org/api/packages.html#subpath-exports) feature of Node.js. If you 86 | get an error like `Cannot find module '@awesome.me/kit-KIT_CODE/icons' or its corresponding type declartions.`, you may 87 | need to update your `tsconfig.json` to set `moduleResolution` to `bundler`: 88 | 89 | ```json 90 | { 91 | "compilerOptions": { 92 | "moduleResolution": "bundler" 93 | } 94 | } 95 | ``` 96 | 97 | ## Changing the default prefix 98 | 99 | The default prefix, `fas`, can be adjusted by injecting the `FaConfig` and modifying the `defaultPrefix` property. 100 | 101 | ```typescript 102 | import { FaConfig } from '@fortawesome/angular-fontawesome'; 103 | 104 | export class AppComponent { 105 | constructor() { 106 | const faConfig = inject(FaConfig); 107 | faConfig.defaultPrefix = 'far'; 108 | } 109 | } 110 | ``` 111 | 112 | ## Apply fixed width by default 113 | 114 | The fixed width class, `fa-fw`, can be applied globally by injecting the `FaConfig` and modifying the `fixedWidth` property. 115 | 116 | ```ts 117 | import { FaConfig } from '@fortawesome/angular-fontawesome'; 118 | 119 | export class AppComponent { 120 | constructor() { 121 | const faConfig = inject(FaConfig); 122 | faConfig.fixedWidth = true; 123 | } 124 | } 125 | ``` 126 | -------------------------------------------------------------------------------- /docs/usage/using-other-styles.md: -------------------------------------------------------------------------------- 1 | # Using other styles 2 | 3 | Font Awesome icons are separated into styles, which are shipped in separate packages to meet different needs and to reduce individual packages size. To use an icon you'll need to install a package which contains it. 4 | 5 | The general workflow of adding a new icon: 6 | 7 | 1. Visit [fontawesome.com/icons](https://fontawesome.com/icons) to browse icons. 8 | 1. Open the icon page to find out which style it belongs to. 9 | 1. Install a package containing the icon if not already installed (use style name from the previous step and see full package names below). 10 | 1. Import the icon from the installed package and use it in your application using either [icon library](./icon-library.md) or [explicit references](./explicit-reference.md) approach. 11 | 12 | Packages prefixed with `free` are available for everybody, but other packages require a [Font Awesome Pro](https://fontawesome.com/plans) subscription and [additional configuration](https://fontawesome.com/docs/web/setup/packages#_1-configure-access). 13 | 14 | ## Solid Icons 15 | 16 | ```bash 17 | $ yarn add @fortawesome/free-solid-svg-icons 18 | # or 19 | $ yarn add @fortawesome/pro-solid-svg-icons 20 | ``` 21 | 22 | ```javascript 23 | import { faClock } from '@fortawesome/free-solid-svg-icons'; 24 | ``` 25 | 26 | ## Brand Icons 27 | 28 | ``` 29 | $ yarn add @fortawesome/free-brands-svg-icons 30 | ``` 31 | 32 | ```javascript 33 | import { faTwitter } from '@fortawesome/free-brands-svg-icons'; 34 | ``` 35 | 36 | ## Regular Icons 37 | 38 | ```bash 39 | $ yarn add @fortawesome/free-regular-svg-icons 40 | # or 41 | $ yarn add @fortawesome/pro-regular-svg-icons 42 | ``` 43 | 44 | ```javascript 45 | import { faCalendar } from '@fortawesome/free-regular-svg-icons'; 46 | ``` 47 | 48 | ## Pro-only Icons 49 | 50 | ```bash 51 | npm install --save @fortawesome/free-brands-svg-icons 52 | npm install --save @fortawesome/pro-solid-svg-icons 53 | npm install --save @fortawesome/pro-regular-svg-icons 54 | npm install --save @fortawesome/pro-light-svg-icons 55 | npm install --save @fortawesome/pro-thin-svg-icons 56 | npm install --save @fortawesome/pro-duotone-svg-icons 57 | npm install --save @fortawesome/duotone-regular-svg-icons 58 | npm install --save @fortawesome/duotone-light-svg-icons 59 | npm install --save @fortawesome/duotone-thin-svg-icons 60 | npm install --save @fortawesome/sharp-solid-svg-icons 61 | npm install --save @fortawesome/sharp-regular-svg-icons 62 | npm install --save @fortawesome/sharp-light-svg-icons 63 | npm install --save @fortawesome/sharp-thin-svg-icons 64 | npm install --save @fortawesome/sharp-duotone-solid-svg-icons 65 | npm install --save @fortawesome/sharp-duotone-regular-svg-icons 66 | npm install --save @fortawesome/sharp-duotone-light-svg-icons 67 | npm install --save @fortawesome/sharp-duotone-thin-svg-icons 68 | ``` 69 | 70 | ```bash 71 | yarn add @fortawesome/free-brands-svg-icons 72 | yarn add @fortawesome/pro-solid-svg-icons 73 | yarn add @fortawesome/pro-regular-svg-icons 74 | yarn add @fortawesome/pro-light-svg-icons 75 | yarn add @fortawesome/pro-thin-svg-icons 76 | yarn add @fortawesome/pro-duotone-svg-icons 77 | yarn add @fortawesome/duotone-regular-svg-icons 78 | yarn add @fortawesome/duotone-light-svg-icons 79 | yarn add @fortawesome/duotone-thin-svg-icons 80 | yarn add @fortawesome/sharp-solid-svg-icons 81 | yarn add @fortawesome/sharp-regular-svg-icons 82 | yarn add @fortawesome/sharp-light-svg-icons 83 | yarn add @fortawesome/sharp-thin-svg-icons 84 | yarn add @fortawesome/sharp-duotone-solid-svg-icons 85 | yarn add @fortawesome/sharp-duotone-regular-svg-icons 86 | yarn add @fortawesome/sharp-duotone-light-svg-icons 87 | yarn add @fortawesome/sharp-duotone-thin-svg-icons 88 | ``` 89 | 90 | Example using the Light style: 91 | 92 | ```javascript 93 | import { faArrowAltRight } from '@fortawesome/pro-light-svg-icons'; 94 | ``` 95 | 96 | ## Pro-only Kit 97 | 98 | You can now use your [Font Awesome Kit](https://fontawesome.com/kits) with angular-fontawesome. With a Kit you can upload your own icons or pick only the icons you'd like to use. 99 | 100 | [Find out more about Kits and how you can use them in JavaScript projects](https://fontawesome.com/docs/web/setup/use-kit) 101 | 102 | _In these examples, you would replace "KIT_CODE" with the unique identifier for your Pro Kit_ 103 | 104 | ```bash 105 | npm install --save @awesome.me/kit-KIT_CODE 106 | # or 107 | yarn add @awesome.me/kit-KIT_CODE 108 | ``` 109 | 110 | ```javascript 111 | import { faArrowAltRight } from '@awesome.me/kit-KIT_CODE/icons/classic/solid'; 112 | import { faMyIcon } from '@awesome.me/kit-KIT_CODE/icons/kit/custom'; 113 | ``` 114 | 115 | ## Same Icon from Multiple Styles 116 | 117 | To use the same icon from the multiple styles you'll need to use import aliases to avoid the name conflicts: 118 | 119 | ```javascript 120 | import { faStar as farStar } from '@fortawesome/free-regular-svg-icons'; 121 | import { faStar as fasStar } from '@fortawesome/free-solid-svg-icons'; 122 | 123 | // Add icons to the library for convenient access in other components 124 | import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; 125 | 126 | export class AppModule { 127 | constructor() { 128 | // Add multiple icons to the library 129 | const library = inject(FaIconLibrary); 130 | library.addIcons(fasStar, farStar); 131 | } 132 | } 133 | ``` 134 | 135 | ```html 136 | 137 | 138 | ``` 139 | -------------------------------------------------------------------------------- /projects/schematics/src/ng-add/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { Tree } from '@angular-devkit/schematics'; 2 | import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; 3 | import * as path from 'path'; 4 | import { Schema } from './schema'; 5 | import { angularFontawesomeVersion, iconPackVersionMap } from './versions'; 6 | 7 | const collectionPath = path.join(__dirname, '../collection.json'); 8 | 9 | describe('ng-add', () => { 10 | it('adds v7 dependencies to package.json', async () => { 11 | const { runner, appTree } = await setup(); 12 | 13 | const tree = await runner.runSchematic('ng-add', { project: 'test-app' }, appTree); 14 | 15 | const packageJson = JSON.parse(tree.readContent('package.json')); 16 | expect(packageJson.dependencies).toBeDefined(); 17 | 18 | const dependencies = packageJson.dependencies; 19 | 20 | expect(dependencies['@fortawesome/free-solid-svg-icons']).toBe(iconPackVersionMap['7'].iconPackVersion); 21 | expect(dependencies['@fortawesome/angular-fontawesome']).toBe(angularFontawesomeVersion); 22 | }); 23 | 24 | it('adds v6 dependencies to package.json', async () => { 25 | const { runner, appTree } = await setup(); 26 | 27 | const tree = await runner.runSchematic('ng-add', { project: 'test-app', version: '6' }, appTree); 28 | 29 | const packageJson = JSON.parse(tree.readContent('package.json')); 30 | expect(packageJson.dependencies).toBeDefined(); 31 | 32 | const dependencies = packageJson.dependencies; 33 | 34 | expect(dependencies['@fortawesome/free-solid-svg-icons']).toBe(iconPackVersionMap['6'].iconPackVersion); 35 | expect(dependencies['@fortawesome/angular-fontawesome']).toBe(angularFontawesomeVersion); 36 | }); 37 | 38 | it('adds v5 dependencies to package.json', async () => { 39 | const { runner, appTree } = await setup(); 40 | 41 | const tree = await runner.runSchematic('ng-add', { project: 'test-app', version: '5' }, appTree); 42 | 43 | const packageJson = JSON.parse(tree.readContent('package.json')); 44 | expect(packageJson.dependencies).toBeDefined(); 45 | 46 | const dependencies = packageJson.dependencies; 47 | 48 | expect(dependencies['@fortawesome/free-solid-svg-icons']).toBe(iconPackVersionMap['5'].iconPackVersion); 49 | expect(dependencies['@fortawesome/angular-fontawesome']).toBe(angularFontawesomeVersion); 50 | }); 51 | 52 | it('adds FontAwesomeModule import to the AppModule when standalone=false', async () => { 53 | const { runner, appTree } = await setup(false); 54 | 55 | const tree = await runner.runSchematic('ng-add', { project: 'test-app' }, appTree); 56 | 57 | const contents = tree.readContent('src/app/app-module.ts'); 58 | 59 | expect(contents).toContain('import { FontAwesomeModule }'); 60 | }); 61 | 62 | it('does not attempt to add FontAwesomeModule import to the AppModule when standalone=true', async () => { 63 | const { runner, appTree } = await setup(); 64 | 65 | const tree = await runner.runSchematic('ng-add', { project: 'test-app' }, appTree); 66 | 67 | expect(tree.files).not.toContain('/src/app/app.module.ts'); 68 | }); 69 | 70 | it('installs @fortawesome/free-solid-svg-icons package by default', async () => { 71 | const { runner, appTree } = await setup(); 72 | 73 | const tree = await runner.runSchematic('ng-add', { project: 'test-app' }, appTree); 74 | 75 | const packageJson = JSON.parse(tree.readContent('package.json')); 76 | expect(packageJson.dependencies).toBeDefined(); 77 | 78 | const dependencies = packageJson.dependencies; 79 | expect(dependencies['@fortawesome/free-solid-svg-icons']).toBeDefined(); 80 | }); 81 | 82 | it('allows to install several @fortawesome/*-svg-icons packages', async () => { 83 | const { runner, appTree } = await setup(); 84 | 85 | const tree = await runner.runSchematic( 86 | 'ng-add', 87 | { 88 | project: 'test-app', 89 | iconPackages: ['free-solid', 'free-brands', 'free-regular'], 90 | }, 91 | appTree, 92 | ); 93 | const packageJson = JSON.parse(tree.readContent('package.json')); 94 | expect(packageJson.dependencies).toBeDefined(); 95 | 96 | const dependencies = packageJson.dependencies; 97 | expect(dependencies['@fortawesome/free-solid-svg-icons']).toBeDefined(); 98 | expect(dependencies['@fortawesome/free-brands-svg-icons']).toBeDefined(); 99 | expect(dependencies['@fortawesome/free-regular-svg-icons']).toBeDefined(); 100 | }); 101 | 102 | it('allows to install no icon packages', async () => { 103 | const { runner, appTree } = await setup(); 104 | 105 | const tree = await runner.runSchematic( 106 | 'ng-add', 107 | { 108 | project: 'test-app', 109 | iconPackages: [], 110 | }, 111 | appTree, 112 | ); 113 | const packageJson = JSON.parse(tree.readContent('package.json')); 114 | expect(packageJson.dependencies).toBeDefined(); 115 | 116 | const dependencies = packageJson.dependencies; 117 | expect(dependencies['@fortawesome/free-solid-svg-icons']).not.toBeDefined(); 118 | }); 119 | }); 120 | 121 | const setup = async (standalone?: boolean) => { 122 | const runner = new SchematicTestRunner('schematics', collectionPath); 123 | 124 | const appTree = await runner.runExternalSchematic( 125 | '@schematics/angular', 126 | 'ng-new', 127 | { 128 | name: 'test-app', 129 | version: '9.0.0-rc.6', 130 | directory: '.', 131 | standalone, 132 | }, 133 | Tree.empty(), 134 | ); 135 | 136 | return { runner, appTree }; 137 | }; 138 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-fontawesome": { 7 | "projectType": "library", 8 | "root": "", 9 | "sourceRoot": ".", 10 | "prefix": "fa", 11 | "architect": { 12 | "build": { 13 | "builder": "@angular/build:ng-packagr", 14 | "options": { 15 | "tsConfig": "tsconfig.lib.json", 16 | "project": "ng-package.json" 17 | }, 18 | "configurations": { 19 | "production": { 20 | "tsConfig": "tsconfig.lib.prod.json" 21 | }, 22 | "development": {} 23 | }, 24 | "defaultConfiguration": "production" 25 | }, 26 | "test": { 27 | "builder": "@angular/build:karma", 28 | "options": { 29 | "include": ["src/**/*.spec.ts", "testing/src/**/*.spec.ts"], 30 | "polyfills": ["zone.js", "zone.js/testing"], 31 | "tsConfig": "tsconfig.spec.json", 32 | "karmaConfig": "karma.conf.js" 33 | } 34 | }, 35 | "lint": { 36 | "builder": "@angular-eslint/builder:lint", 37 | "options": { 38 | "lintFilePatterns": ["src/**/*.ts", "src/**/*.html", "testing/src/**/*.ts", "testing/src/**/*.html"] 39 | } 40 | } 41 | } 42 | }, 43 | "demo": { 44 | "projectType": "application", 45 | "schematics": { 46 | "@schematics/angular:component": { 47 | "inlineStyle": true, 48 | "style": "scss" 49 | } 50 | }, 51 | "root": "projects/demo", 52 | "sourceRoot": "projects/demo/src", 53 | "prefix": "app", 54 | "architect": { 55 | "build": { 56 | "builder": "@angular/build:application", 57 | "options": { 58 | "outputPath": { 59 | "base": "dist/demo" 60 | }, 61 | "index": "projects/demo/src/index.html", 62 | "polyfills": ["zone.js"], 63 | "tsConfig": "projects/demo/tsconfig.app.json", 64 | "assets": ["projects/demo/src/favicon.ico", "projects/demo/src/assets"], 65 | "styles": ["projects/demo/src/styles.scss"], 66 | "scripts": [], 67 | "extractLicenses": false, 68 | "sourceMap": true, 69 | "optimization": false, 70 | "namedChunks": true, 71 | "browser": "projects/demo/src/main.ts", 72 | "server": "projects/demo/src/main.server.ts" 73 | }, 74 | "configurations": { 75 | "production": { 76 | "optimization": true, 77 | "outputHashing": "all", 78 | "sourceMap": false, 79 | "namedChunks": false, 80 | "extractLicenses": true 81 | }, 82 | "development": {}, 83 | "production-ssr": { 84 | "optimization": true, 85 | "outputHashing": "all", 86 | "sourceMap": false, 87 | "namedChunks": false, 88 | "extractLicenses": true, 89 | "ssr": { 90 | "entry": "projects/demo/src/server.ts" 91 | } 92 | }, 93 | "development-ssr": { 94 | "ssr": { 95 | "entry": "projects/demo/src/server.ts" 96 | } 97 | } 98 | }, 99 | "defaultConfiguration": "production" 100 | }, 101 | "serve": { 102 | "builder": "@angular/build:dev-server", 103 | "options": {}, 104 | "configurations": { 105 | "production": { 106 | "buildTarget": "demo:build:production" 107 | }, 108 | "development": { 109 | "buildTarget": "demo:build:development" 110 | }, 111 | "production-ssr": { 112 | "buildTarget": "demo:build:production-ssr" 113 | }, 114 | "development-ssr": { 115 | "buildTarget": "demo:build:development-ssr" 116 | } 117 | }, 118 | "defaultConfiguration": "development" 119 | }, 120 | "test": { 121 | "builder": "@angular/build:karma", 122 | "options": { 123 | "polyfills": ["zone.js", "zone.js/testing"], 124 | "tsConfig": "projects/demo/tsconfig.spec.json", 125 | "karmaConfig": "projects/demo/karma.conf.js", 126 | "assets": ["projects/demo/src/favicon.ico", "projects/demo/src/assets"], 127 | "styles": ["projects/demo/src/styles.scss"], 128 | "scripts": [] 129 | } 130 | }, 131 | "lint": { 132 | "builder": "@angular-eslint/builder:lint", 133 | "options": { 134 | "lintFilePatterns": ["projects/demo/**/*.ts", "projects/demo/**/*.html"] 135 | } 136 | }, 137 | "e2e": { 138 | "builder": "@angular-devkit/build-angular:private-protractor", 139 | "options": { 140 | "protractorConfig": "projects/demo/e2e/protractor.conf.js" 141 | }, 142 | "configurations": { 143 | "production": { 144 | "devServerTarget": "demo:serve:production", 145 | "webdriverUpdate": false 146 | }, 147 | "production-ssr": { 148 | "devServerTarget": "demo:serve:production-ssr", 149 | "webdriverUpdate": false 150 | } 151 | }, 152 | "defaultConfiguration": "production" 153 | } 154 | } 155 | } 156 | }, 157 | "cli": { 158 | "analytics": false 159 | }, 160 | "schematics": { 161 | "@angular-eslint/schematics:application": { 162 | "setParserOptionsProject": true 163 | }, 164 | "@angular-eslint/schematics:library": { 165 | "setParserOptionsProject": true 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/lib/icon/icon.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, computed, DOCUMENT, inject, model } from '@angular/core'; 2 | import { DomSanitizer } from '@angular/platform-browser'; 3 | import { 4 | Attributes, 5 | FaSymbol, 6 | FlipProp, 7 | icon, 8 | IconDefinition as CoreIconDefinition, 9 | IconParams, 10 | parse, 11 | PullProp, 12 | RotateProp, 13 | SizeProp, 14 | Styles, 15 | Transform, 16 | } from '@fortawesome/fontawesome-svg-core'; 17 | import { FaConfig } from '../config'; 18 | import { FaIconLibrary } from '../icon-library'; 19 | import { faWarnIfIconDefinitionMissing } from '../shared/errors/warn-if-icon-html-missing'; 20 | import { faWarnIfIconSpecMissing } from '../shared/errors/warn-if-icon-spec-missing'; 21 | import { AnimationProp, FaProps } from '../shared/models/props.model'; 22 | import { faClassList, isKnownRotateValue } from '../shared/utils/classlist.util'; 23 | import { ensureCss } from '../shared/utils/css'; 24 | import { faNormalizeIconSpec } from '../shared/utils/normalize-icon-spec.util'; 25 | import { FaStackItemSizeDirective } from '../stack/stack-item-size.directive'; 26 | import { FaStackComponent } from '../stack/stack.component'; 27 | import { IconDefinition, IconProp } from '../types'; 28 | 29 | @Component({ 30 | selector: 'fa-icon', 31 | template: ``, 32 | host: { 33 | class: 'ng-fa-icon', 34 | '[attr.title]': 'title() ?? undefined', 35 | '[innerHTML]': 'renderedIconHTML()', 36 | }, 37 | changeDetection: ChangeDetectionStrategy.OnPush, 38 | }) 39 | export class FaIconComponent { 40 | readonly icon = model(); 41 | 42 | /** 43 | * Specify a title for the icon. 44 | * 45 | * This text will be displayed in a tooltip on hover and presented to the 46 | * screen readers. 47 | */ 48 | readonly title = model(); 49 | 50 | /** 51 | * Icon animation. 52 | * 53 | * Most of the animations are only available when using Font Awesome 6. With 54 | * Font Awesome 5, only 'spin' and 'spin-pulse' are supported. 55 | */ 56 | readonly animation = model(); 57 | 58 | readonly mask = model(); 59 | readonly flip = model(); 60 | readonly size = model(); 61 | readonly pull = model(); 62 | readonly border = model(); 63 | readonly inverse = model(); 64 | readonly symbol = model(); 65 | readonly rotate = model(); 66 | readonly fixedWidth = model(); 67 | readonly transform = model(); 68 | 69 | /** 70 | * Specify the `role` attribute for the rendered element. 71 | * 72 | * @default 'img' 73 | */ 74 | readonly a11yRole = model(); 75 | 76 | readonly renderedIconHTML = computed(() => { 77 | const iconValue = this.icon() ?? this.config.fallbackIcon; 78 | if (!iconValue) { 79 | faWarnIfIconSpecMissing(); 80 | return ''; 81 | } 82 | 83 | const iconDefinition = this.findIconDefinition(iconValue); 84 | if (!iconDefinition) { 85 | return ''; 86 | } 87 | const params = this.buildParams(); 88 | ensureCss(this.document, this.config); 89 | const renderedIcon = icon(iconDefinition, params); 90 | return this.sanitizer.bypassSecurityTrustHtml(renderedIcon.html.join('\n')); 91 | }); 92 | 93 | private readonly document = inject(DOCUMENT); 94 | private readonly sanitizer = inject(DomSanitizer); 95 | private readonly config = inject(FaConfig); 96 | private readonly iconLibrary = inject(FaIconLibrary); 97 | private readonly stackItem = inject(FaStackItemSizeDirective, { optional: true }); 98 | private readonly stack = inject(FaStackComponent, { optional: true }); 99 | 100 | constructor() { 101 | if (this.stack != null && this.stackItem == null) { 102 | console.error( 103 | 'FontAwesome: fa-icon and fa-duotone-icon elements must specify stackItemSize attribute when wrapped into ' + 104 | 'fa-stack. Example: .', 105 | ); 106 | } 107 | } 108 | 109 | protected findIconDefinition(i: IconProp | IconDefinition): CoreIconDefinition | null { 110 | const lookup = faNormalizeIconSpec(i, this.config.defaultPrefix); 111 | if ('icon' in lookup) { 112 | return lookup as CoreIconDefinition; 113 | } 114 | 115 | const definition = this.iconLibrary.getIconDefinition(lookup.prefix, lookup.iconName); 116 | if (definition != null) { 117 | return definition as CoreIconDefinition; 118 | } 119 | 120 | faWarnIfIconDefinitionMissing(lookup); 121 | return null; 122 | } 123 | 124 | protected buildParams(): IconParams { 125 | const fixedWidth = this.fixedWidth(); 126 | const classOpts: FaProps = { 127 | flip: this.flip(), 128 | animation: this.animation(), 129 | border: this.border(), 130 | inverse: this.inverse(), 131 | size: this.size(), 132 | pull: this.pull(), 133 | rotate: this.rotate(), 134 | fixedWidth: typeof fixedWidth === 'boolean' ? fixedWidth : this.config.fixedWidth, 135 | stackItemSize: this.stackItem != null ? this.stackItem.stackItemSize() : undefined, 136 | }; 137 | 138 | const transform = this.transform(); 139 | const parsedTransform = typeof transform === 'string' ? parse.transform(transform) : transform; 140 | 141 | const mask = this.mask(); 142 | const maskIconDefinition = mask != null ? this.findIconDefinition(mask) : null; 143 | 144 | const attributes: Attributes = {}; 145 | const a11yRole = this.a11yRole(); 146 | if (a11yRole != null) { 147 | attributes['role'] = a11yRole; 148 | } 149 | 150 | const styles: Styles = {}; 151 | if (classOpts.rotate != null && !isKnownRotateValue(classOpts.rotate)) { 152 | styles['--fa-rotate-angle'] = `${classOpts.rotate}`; 153 | } 154 | 155 | return { 156 | title: this.title(), 157 | transform: parsedTransform, 158 | classes: faClassList(classOpts), 159 | mask: maskIconDefinition ?? undefined, 160 | symbol: this.symbol(), 161 | attributes, 162 | styles, 163 | }; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/lib/layers/layers.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, inputBinding, signal } from '@angular/core'; 2 | import { NgClass } from '@angular/common'; 3 | import { TestBed } from '@angular/core/testing'; 4 | import { By } from '@angular/platform-browser'; 5 | import { SizeProp } from '@fortawesome/fontawesome-svg-core'; 6 | import { faCoffee, faUser } from '@fortawesome/free-solid-svg-icons'; 7 | import { faDummy, queryByCss } from '../../testing/helpers'; 8 | import { FaConfig } from '../config'; 9 | import { FaLayersComponent } from './layers.component'; 10 | import { FaLayersTextComponent } from './layers-text.component'; 11 | import { FaIconComponent } from '../icon/icon.component'; 12 | import { FaDuotoneIconComponent } from '../icon/duotone-icon.component'; 13 | 14 | describe('FaLayersComponent', () => { 15 | it('should render layers icon', () => { 16 | @Component({ 17 | selector: 'fa-host', 18 | imports: [FaLayersComponent, FaIconComponent, FaLayersTextComponent], 19 | template: ` 20 | 21 | 22 | 23 | 24 | 25 | `, 26 | }) 27 | class HostComponent { 28 | faUser = signal(faUser); 29 | faCoffee = signal(faCoffee); 30 | } 31 | 32 | const fixture = TestBed.createComponent(HostComponent); 33 | fixture.detectChanges(); 34 | expect(queryByCss(fixture, 'svg')).toBeTruthy(); 35 | }); 36 | 37 | it('should include size class', () => { 38 | @Component({ 39 | selector: 'fa-host', 40 | imports: [FaLayersComponent, FaIconComponent, FaLayersTextComponent], 41 | template: ` 42 | 43 | 44 | 45 | 46 | 47 | `, 48 | }) 49 | class HostComponent { 50 | faUser = signal(faUser); 51 | faCoffee = signal(faCoffee); 52 | } 53 | 54 | const fixture = TestBed.createComponent(HostComponent); 55 | fixture.detectChanges(); 56 | expect(queryByCss(fixture, '.fa-2x')).toBeTruthy(); 57 | }); 58 | 59 | it('should include fixed width when set explicitly', () => { 60 | const fixture = TestBed.createComponent(FaLayersComponent, { bindings: [inputBinding('fixedWidth', () => true)] }); 61 | const config = TestBed.inject(FaConfig); 62 | config.fixedWidth = false; 63 | fixture.detectChanges(); 64 | expect(fixture.nativeElement.classList.contains('fa-fw')).toBeTrue(); 65 | }); 66 | 67 | it('should include fixed width when set with global config', () => { 68 | const fixture = TestBed.createComponent(FaLayersComponent); 69 | const config = TestBed.inject(FaConfig); 70 | config.fixedWidth = true; 71 | fixture.detectChanges(); 72 | expect(fixture.nativeElement.classList.contains('fa-fw')).toBeTrue(); 73 | }); 74 | 75 | it('should not include fixed width when set explicitly', () => { 76 | @Component({ 77 | selector: 'fa-host', 78 | imports: [FaLayersComponent, FaIconComponent, FaLayersTextComponent], 79 | template: ` 80 | 81 | 82 | 83 | 84 | 85 | `, 86 | }) 87 | class HostComponent { 88 | faUser = signal(faUser); 89 | faCoffee = signal(faCoffee); 90 | } 91 | 92 | const fixture = TestBed.createComponent(HostComponent); 93 | const config = TestBed.inject(FaConfig); 94 | config.fixedWidth = true; 95 | fixture.detectChanges(); 96 | expect(queryByCss(fixture, 'fa-layers.fa-fw')).toBeFalsy(); 97 | }); 98 | 99 | it('should allow setting custom class on the host element', () => { 100 | @Component({ 101 | selector: 'fa-host', 102 | imports: [FaLayersComponent, NgClass], 103 | template: ` 104 | 105 | 106 | 107 | 108 | 109 | 110 | `, 111 | }) 112 | class HostComponent { 113 | fixedWidth = signal(true); 114 | size = signal('4x'); 115 | } 116 | 117 | const fixture = TestBed.createComponent(HostComponent); 118 | 119 | fixture.detectChanges(); 120 | const elements = fixture.debugElement.queryAll(By.css('fa-layers')); 121 | for (const element of elements) { 122 | expect(element.nativeElement.className).toContain('custom-class'); 123 | expect(element.nativeElement.className).toContain('fa-layers'); 124 | expect(element.nativeElement.className).toContain('fa-fw'); 125 | expect(element.nativeElement.className).toContain('fa-4x'); 126 | } 127 | }); 128 | 129 | it('should support duotone icons', () => { 130 | @Component({ 131 | selector: 'fa-host', 132 | imports: [FaLayersComponent, FaDuotoneIconComponent, FaLayersTextComponent], 133 | template: ` 134 | 135 | 136 | 137 | 138 | `, 139 | }) 140 | class HostComponent { 141 | faDummy = signal(faDummy); 142 | } 143 | 144 | const fixture = TestBed.createComponent(HostComponent); 145 | fixture.detectChanges(); 146 | expect(queryByCss(fixture, 'fa-duotone-icon')).toBeTruthy(); 147 | }); 148 | 149 | it('should support icons wrapped into ng-container', () => { 150 | @Component({ 151 | selector: 'fa-host', 152 | imports: [FaLayersComponent, FaIconComponent, FaLayersTextComponent], 153 | template: ` 154 | 155 | 156 | 157 | 158 | 159 | 160 | `, 161 | }) 162 | class HostComponent { 163 | faUser = signal(faUser); 164 | } 165 | 166 | const fixture = TestBed.createComponent(HostComponent); 167 | fixture.detectChanges(); 168 | expect(queryByCss(fixture, 'fa-icon')).toBeTruthy(); 169 | }); 170 | }); 171 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

Font Awesome examples

2 | 3 |

Icon as Object (with title attribute—inspect the DOM to see it)

4 | 5 | 6 |

Icon looked up in library by name

7 |

8 | Possible after adding the faUser icon from the free-solid-svg-icons package to the library. 9 |

10 |

The default prefix of fas is assumed. Also, add a border.

11 | 12 | 13 |

Duotone icons

14 | 15 |

Swap layer opacity.

16 | 17 |

Custom primary or secondary layer opacity.

18 | 19 |

Custom primary or secondary layer color.

20 | 21 | 22 |

Icon with Non-default Style Prefix Using [prefix, iconName]

23 |

icon should be set equal to an array object with two string elements: the prefix and the icon name.

24 |

25 | Using a string for an icon name also requires that this icon has been added to the library with 26 | library.add() 27 |

28 | 29 | 30 |

Icon as Object with non-Default Prefix

31 |

The icon object knows its own prefix, so the prefix is not specified in this case.

32 | 33 | 34 |

With Mask and Transform

35 | 36 | 37 |

Change Size

38 | 39 | 40 |

Change color

41 | 42 |

Using custom style:

43 |

Using custom class:

44 | 45 |

Rotate

46 | 47 |

48 | 49 |

50 | 51 |

Animations

52 | 53 | 54 | 55 |

56 |   57 |   58 | 59 |

60 | 61 |

62 |   63 |   64 |

65 | 66 |

67 |   68 |   73 |   74 |

75 | 76 |

 

77 | 78 |

79 |   80 |   85 |

86 | 87 |

 

88 | 89 |

90 |   91 |   92 |   93 |   94 |

95 | 96 |

Slide to turn up the magic.

97 | 98 | 99 | 100 |

Stack

101 |

Stack multiple icons into one.

102 | 103 | 104 | 105 | 106 | 107 |

Layers

108 |

Custom icons created with multiple layers.

109 |
110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 |
125 |

Using text as one of the layers.

126 |
127 | 128 | 129 | 130 | 131 |
132 | 133 |
134 |
135 |

Slide and increase the number.

136 | 143 |
144 |
145 |

Select a position.

146 | 152 |
153 |
154 | 155 |
156 | 157 | 158 | 163 | 164 |
165 | 166 | 167 | 168 |

Fallback icon

169 |

170 | Icon uses a fallback icon when the main icon parameter is not specified. Useful for when the icon is loaded 171 | asynchronously. If no fallback icon is specified, the icon will not appear. (Not shown in this example.) 172 |

173 | 174 | -------------------------------------------------------------------------------- /docs/guide/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | This guide explains how to test components, which use Font Awesome icons. 4 | 5 | ## Test components using [explicit reference](../usage/explicit-reference.md) 6 | 7 | Testing components using explicit reference does not require any special setup. You only need to add `FontAwesomeModule` to the `imports` of the testing module to be able to use `angular-fontawesome` components in the tests. 8 | 9 | ```typescript 10 | import { Component } from '@angular/core'; 11 | import { faUser } from '@fortawesome/free-solid-svg-icons'; 12 | 13 | @Component({ 14 | selector: 'app-explicit-reference', 15 | template: '', 16 | }) 17 | export class ExplicitReferenceComponent { 18 | faUser = faUser; 19 | } 20 | ``` 21 | 22 | ```typescript 23 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 24 | import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 25 | import { ExplicitReferenceComponent } from './explicit-reference.component'; 26 | 27 | describe('ExplicitReferenceComponent', () => { 28 | let component: ExplicitReferenceComponent; 29 | let fixture: ComponentFixture; 30 | 31 | beforeEach(() => { 32 | TestBed.configureTestingModule({ 33 | imports: [FontAwesomeModule], // <-- 34 | declarations: [ExplicitReferenceComponent], 35 | }); 36 | }); 37 | 38 | beforeEach(() => { 39 | fixture = TestBed.createComponent(ExplicitReferenceComponent); 40 | component = fixture.componentInstance; 41 | fixture.detectChanges(); 42 | }); 43 | 44 | it('should create', () => { 45 | expect(component).toBeTruthy(); 46 | }); 47 | }); 48 | 49 | ``` 50 | 51 | ## Test components using [icon library](../usage/icon-library.md) 52 | 53 | When it comes to testing components using icon library you'll need to setup the icon library in one way or another otherwise component will throw because of the missing icon definition. The icon library setup is needed because most likely `AppModule` where you normally add icons to the library is not part of the tested component spec and therefore icons added there are not available. 54 | 55 | There are several options how to deal with the icon library in the tests: 56 | 57 | - (recommended) define a wrapper module for `FontAwesomeModule` to configure an icon library in a single place 58 | - configure regular `FaIconLibrary` in each spec with icons used by the component 59 | - use `FontAwesomeTestingModule`, which will mock `FaIconLibrary` and render stub icons instead of the real ones 60 | 61 | ### Define a wrapper module for `FontAwesomeModule` 62 | 63 | With this approach you would define a new module, which wraps `FontAwesomeModule` and configures an icon library. Then this module can be used instead of `FontAwesomeModule` both in the `AppModule` and test code thus the icon library configuration is shared between application and tests. Below is the example of such wrapper module: 64 | 65 | ```typescript 66 | import { inject, NgModule } from '@angular/core'; 67 | import { FaIconLibrary, FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 68 | import { faUser } from '@fortawesome/free-solid-svg-icons'; 69 | 70 | @NgModule({ 71 | imports: [FontAwesomeModule], 72 | exports: [FontAwesomeModule], 73 | }) 74 | class FontAwesomeIconsModule { 75 | constructor() { 76 | const library = inject(FaIconLibrary); 77 | library.addIcons(faUser); 78 | } 79 | } 80 | ``` 81 | 82 | And here is how it should be used in test code: 83 | 84 | ```typescript 85 | import { Component } from '@angular/core'; 86 | 87 | @Component({ 88 | selector: 'app-regular-icon-library', 89 | template: '', 90 | }) 91 | export class IconLibraryComponent {} 92 | ``` 93 | 94 | ```typescript 95 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 96 | import { IconLibraryComponent } from './icon-library.component'; 97 | 98 | describe('IconLibraryComponent', () => { 99 | let component: IconLibraryComponent; 100 | let fixture: ComponentFixture; 101 | 102 | beforeEach(() => { 103 | TestBed.configureTestingModule({ 104 | imports: [FontAwesomeIconsModule], // <-- 105 | declarations: [IconLibraryComponent], 106 | }); 107 | }); 108 | 109 | beforeEach(() => { 110 | fixture = TestBed.createComponent(IconLibraryComponent); 111 | component = fixture.componentInstance; 112 | fixture.detectChanges(); 113 | }); 114 | 115 | it('should create', () => { 116 | expect(component).toBeTruthy(); 117 | }); 118 | }); 119 | ``` 120 | 121 | *This approach was [initially suggested by 1FpGLLjZSZMx6k on StackOverflow](https://stackoverflow.com/a/58380192/1377864).* 122 | 123 | ### Configure regular `FaIconLibrary` 124 | 125 | To use this approach you'll need to add `FontAwesomeModule` to the `imports` of the testing module to be able to use `angular-fontawesome` components in the tests and also inject `FaIconLibrary` in `beforeEach` hook and add icons used by the tested component. 126 | 127 | ```typescript 128 | import { Component } from '@angular/core'; 129 | 130 | @Component({ 131 | selector: 'app-regular-icon-library', 132 | template: '', 133 | }) 134 | export class IconLibraryComponent {} 135 | ``` 136 | 137 | ```typescript 138 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 139 | import { FaIconLibrary, FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 140 | import { faUser } from '@fortawesome/free-solid-svg-icons'; 141 | import { IconLibraryComponent } from './icon-library.component'; 142 | 143 | describe('IconLibraryComponent', () => { 144 | let component: IconLibraryComponent; 145 | let fixture: ComponentFixture; 146 | 147 | beforeEach(() => { 148 | TestBed.configureTestingModule({ 149 | imports: [FontAwesomeModule], // <-- 150 | declarations: [IconLibraryComponent], 151 | }); 152 | }); 153 | 154 | beforeEach(() => { 155 | // Use TestBed.get(FaIconLibrary) if you use Angular < 9. 156 | const library = TestBed.inject(FaIconLibrary); // <-- 157 | library.addIcons(faUser); // <-- 158 | 159 | fixture = TestBed.createComponent(IconLibraryComponent); 160 | component = fixture.componentInstance; 161 | fixture.detectChanges(); 162 | }); 163 | 164 | it('should create', () => { 165 | expect(component).toBeTruthy(); 166 | }); 167 | }); 168 | ``` 169 | 170 | ### Use `FontAwesomeTestingModule` to mock icon library 171 | 172 | `FontAwesomeTestingModule` provides a mocked `FaIconLibrary` and renders stub icons instead of the real ones. This approach allows to reduce boilerplate when testing components with a lot of icons. To use this approach you need to import `FontAwesomeTestingModule` instead of the regular `FontAwesomeModule` and don't need to explicitly configure `FaIconLibrary` as in the previous approach. 173 | 174 | ```typescript 175 | import { Component } from '@angular/core'; 176 | 177 | @Component({ 178 | selector: 'app-regular-icon-library', 179 | template: '', 180 | }) 181 | export class IconLibraryComponent {} 182 | ``` 183 | 184 | ```typescript 185 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 186 | import { FontAwesomeTestingModule } from '@fortawesome/angular-fontawesome/testing'; 187 | import { IconLibraryComponent } from './icon-library.component'; 188 | 189 | describe('IconLibraryComponent', () => { 190 | let component: IconLibraryComponent; 191 | let fixture: ComponentFixture; 192 | 193 | beforeEach(() => { 194 | TestBed.configureTestingModule({ 195 | imports: [FontAwesomeTestingModule], // <-- 196 | declarations: [IconLibraryComponent], 197 | }); 198 | }); 199 | 200 | beforeEach(() => { 201 | fixture = TestBed.createComponent(IconLibraryComponent); 202 | component = fixture.componentInstance; 203 | fixture.detectChanges(); 204 | }); 205 | 206 | it('should create', () => { 207 | expect(component).toBeTruthy(); 208 | }); 209 | }); 210 | ``` 211 | -------------------------------------------------------------------------------- /testing/src/testing.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { FaIconLibrary } from '@fortawesome/angular-fontawesome'; 4 | import { faUser } from '@fortawesome/free-solid-svg-icons'; 5 | import { ADD_ICON_MESSAGE } from './icon/mock-icon-library.service'; 6 | import { FontAwesomeTestingModule } from './testing.module'; 7 | 8 | @Component({ 9 | selector: 'fa-host', 10 | standalone: false, 11 | template: '', 12 | }) 13 | class HostComponent {} 14 | 15 | describe('Using the `FontAwesomeTestingModule', () => { 16 | describe('Providing no configuration', () => { 17 | // This describe block asserts that the behaviour of versions <= 0.14.1 is maintained 18 | 19 | let component: HostComponent; 20 | let fixture: ComponentFixture; 21 | 22 | beforeEach(() => { 23 | TestBed.configureTestingModule({ 24 | imports: [FontAwesomeTestingModule], 25 | declarations: [HostComponent], 26 | }); 27 | 28 | fixture = TestBed.createComponent(HostComponent); 29 | component = fixture.componentInstance; 30 | fixture.detectChanges(); 31 | }); 32 | 33 | it('should allow you to import the module without errors', () => { 34 | expect(component).toBeTruthy(); 35 | }); 36 | 37 | it('should throw on attempt to add an icon to the mocked icon library', () => { 38 | const service = TestBed.inject(FaIconLibrary); 39 | expect(() => service.addIcons(faUser)).toThrow(new Error(ADD_ICON_MESSAGE)); 40 | }); 41 | 42 | it('should throw on attempt to add an icon pack to the mocked icon library', () => { 43 | const service = TestBed.inject(FaIconLibrary); 44 | expect(() => service.addIcons(faUser)).toThrow(new Error(ADD_ICON_MESSAGE)); 45 | }); 46 | }); 47 | 48 | describe('Providing an empty configuration object', () => { 49 | // This describe block asserts that a partial configuration object 50 | // is correctly filled up to the ‘full’ internal object. 51 | // The used configuration should mimic the default values for ‘no configuration’. 52 | 53 | let component: HostComponent; 54 | let fixture: ComponentFixture; 55 | 56 | beforeEach(() => { 57 | TestBed.configureTestingModule({ 58 | imports: [FontAwesomeTestingModule.forRoot({})], 59 | declarations: [HostComponent], 60 | }); 61 | }); 62 | 63 | beforeEach(() => { 64 | fixture = TestBed.createComponent(HostComponent); 65 | component = fixture.componentInstance; 66 | fixture.detectChanges(); 67 | }); 68 | 69 | it('should allow you to import the module without errors', () => { 70 | expect(component).toBeTruthy(); 71 | }); 72 | 73 | it('should throw on attempt to add an icon to the mocked icon library', () => { 74 | const service = TestBed.inject(FaIconLibrary); 75 | expect(() => service.addIcons(faUser)).toThrow(new Error(ADD_ICON_MESSAGE)); 76 | }); 77 | 78 | it('should throw on attempt to add an icon pack to the mocked icon library', () => { 79 | const service = TestBed.inject(FaIconLibrary); 80 | expect(() => service.addIcons(faUser)).toThrow(new Error(ADD_ICON_MESSAGE)); 81 | }); 82 | }); 83 | 84 | describe('Providing {addIcons: "throwError"}', () => { 85 | // This describe block asserts that feature request 86 | // https://github.com/FortAwesome/angular-fontawesome/issues/440 87 | // is implemented correctly. 88 | 89 | let component: HostComponent; 90 | let fixture: ComponentFixture; 91 | 92 | beforeEach(() => { 93 | TestBed.configureTestingModule({ 94 | imports: [FontAwesomeTestingModule.forRoot({ whenAddingIcons: 'throwError' })], 95 | declarations: [HostComponent], 96 | }); 97 | }); 98 | 99 | beforeEach(() => { 100 | fixture = TestBed.createComponent(HostComponent); 101 | component = fixture.componentInstance; 102 | fixture.detectChanges(); 103 | }); 104 | 105 | it('should allow you to import the module without errors', () => { 106 | expect(component).toBeTruthy(); 107 | }); 108 | 109 | it('should throw on attempt to add an icon to the mocked icon library', () => { 110 | const service = TestBed.inject(FaIconLibrary); 111 | expect(() => service.addIcons(faUser)).toThrow(new Error('Attempt to add an icon to the MockFaIconLibrary.')); 112 | }); 113 | 114 | it('should throw on attempt to add an icon pack to the mocked icon library', () => { 115 | const service = TestBed.inject(FaIconLibrary); 116 | expect(() => service.addIcons(faUser)).toThrow(new Error('Attempt to add an icon to the MockFaIconLibrary.')); 117 | }); 118 | }); 119 | 120 | describe('Providing {addIcons: "logWarning"}', () => { 121 | // This describe block asserts that feature request 122 | // https://github.com/FortAwesome/angular-fontawesome/issues/440 123 | // is implemented correctly. 124 | 125 | let component: HostComponent; 126 | let fixture: ComponentFixture; 127 | 128 | beforeEach(() => { 129 | TestBed.configureTestingModule({ 130 | imports: [FontAwesomeTestingModule.forRoot({ whenAddingIcons: 'logWarning' })], 131 | declarations: [HostComponent], 132 | }); 133 | }); 134 | 135 | beforeEach(() => { 136 | fixture = TestBed.createComponent(HostComponent); 137 | component = fixture.componentInstance; 138 | fixture.detectChanges(); 139 | }); 140 | 141 | it('should allow you to import the module without errors', () => { 142 | expect(component).toBeTruthy(); 143 | }); 144 | 145 | it('should call console.warn on attempt to add an icon to the mocked icon library', () => { 146 | const service = TestBed.inject(FaIconLibrary); 147 | spyOn(console, 'warn'); 148 | expect(() => service.addIcons(faUser)).not.toThrow(); 149 | expect(console.warn).toHaveBeenCalledOnceWith(ADD_ICON_MESSAGE); 150 | }); 151 | 152 | it('should call console.warn on attempt to add an icon pack to the mocked icon library', () => { 153 | const service = TestBed.inject(FaIconLibrary); 154 | spyOn(console, 'warn'); 155 | expect(() => service.addIcons(faUser)).not.toThrow(); 156 | expect(console.warn).toHaveBeenCalledOnceWith(ADD_ICON_MESSAGE); 157 | }); 158 | }); 159 | 160 | describe('Providing {addIcons: "noop"}', () => { 161 | // This describe block asserts that feature request 162 | // https://github.com/FortAwesome/angular-fontawesome/issues/440 163 | // is implemented correctly. 164 | 165 | let component: HostComponent; 166 | let fixture: ComponentFixture; 167 | 168 | beforeEach(() => { 169 | TestBed.configureTestingModule({ 170 | imports: [FontAwesomeTestingModule.forRoot({ whenAddingIcons: 'noop' })], 171 | declarations: [HostComponent], 172 | }); 173 | }); 174 | 175 | beforeEach(() => { 176 | fixture = TestBed.createComponent(HostComponent); 177 | component = fixture.componentInstance; 178 | fixture.detectChanges(); 179 | }); 180 | 181 | it('should allow you to import the module without errors', () => { 182 | expect(component).toBeTruthy(); 183 | }); 184 | 185 | it('should ignore attempts to add an icon to the mocked icon library', () => { 186 | const service = TestBed.inject(FaIconLibrary); 187 | spyOn(console, 'warn'); 188 | expect(() => service.addIcons(faUser)).not.toThrow(); 189 | expect(console.warn).not.toHaveBeenCalledOnceWith(ADD_ICON_MESSAGE); 190 | }); 191 | 192 | it('should ignore attempts to add an icon pack to the mocked icon library', () => { 193 | const service = TestBed.inject(FaIconLibrary); 194 | spyOn(console, 'warn'); 195 | expect(() => service.addIcons(faUser)).not.toThrow(); 196 | expect(console.warn).not.toHaveBeenCalledOnceWith(ADD_ICON_MESSAGE); 197 | }); 198 | }); 199 | }); 200 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Official Javascript Component 3 | 4 | 5 | # angular-fontawesome 6 | 7 | [![npm](https://img.shields.io/npm/v/@fortawesome/angular-fontawesome.svg?style=flat-square)](https://www.npmjs.com/package/@fortawesome/angular-fontawesome) 8 | 9 | Official Angular component for Font Awesome 5+ 10 | 11 | ## Installation 12 | 13 | If you have [FontAwesome Pro](https://fontawesome.com/plans) subscription, make sure to [configure access](https://fontawesome.com/docs/web/setup/packages#_1-configure-access) before following the installation instructions. 14 | 15 | > **Note:** Pro+ Icons are only available in Kit Packages 16 | > Along with a Pro+ Plan, you'll need to install a downloaded Kit package to use any of our Pro+ Icons — they are not available in any other packages. 17 | > [Read more](https://docs.fontawesome.com/web/setup/use-kit#using-kit-packages). 18 | 19 | 20 | Using `ng add`: 21 | 22 | ``` 23 | # See Compatibility table below to choose a correct version 24 | $ ng add @fortawesome/angular-fontawesome@ 25 | ``` 26 | 27 | Using [Yarn](https://yarnpkg.com) 28 | ``` 29 | $ yarn add @fortawesome/free-solid-svg-icons 30 | # See Compatibility table below to choose a correct version 31 | $ yarn add @fortawesome/angular-fontawesome@ 32 | ``` 33 | 34 | Using [NPM](https://www.npmjs.com/) 35 | ``` 36 | $ npm install @fortawesome/free-solid-svg-icons 37 | # See Compatibility table below to choose a correct version 38 | $ npm install @fortawesome/angular-fontawesome@ 39 | ``` 40 | 41 | ### Compatibility table 42 | 43 | | @fortawesome/angular-fontawesome | Angular | Font Awesome | 44 | |----------------------------------|---------|-------------------| 45 | | 4.x | 21.x | 5.x && 6.x && 7.x | 46 | | 3.x | 20.x | 5.x && 6.x && 7.x | 47 | | 2.x | 20.x | 5.x && 6.x | 48 | 49 | See [the compatibility page](./docs/guide/compatibility.md) for older versions. 50 | 51 | ## Usage 52 | 53 | To get up and running using Font Awesome with Angular follow the below steps: 54 | 55 | 1. Add `FontAwesomeModule` to the `imports` and tie the icon to the property in your component 56 | `src/app/app.component.ts`: 57 | 58 | ```typescript 59 | import { Component } from '@angular/core'; 60 | import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; 61 | import { faCoffee } from '@fortawesome/free-solid-svg-icons'; 62 | 63 | // Import from Kit Packages (Pro+ Icons) 64 | // import {faCloud} from "@awesome.me/kit-/icons/slab/regular"; 65 | 66 | 67 | @Component({ 68 | selector: 'app-root', 69 | imports: [FontAwesomeModule], // alternatively, individual components can be imported 70 | templateUrl: './app.component.html' 71 | }) 72 | export class AppComponent { 73 | faCoffee = faCoffee; 74 | } 75 | ``` 76 | 77 | 1. Use the icon in the template 78 | `src/app/app.component.html`: 79 | 80 | ```html 81 | 82 | ``` 83 | 84 | ## Documentation 85 | 86 | * [In-depth usage guide](./docs/usage.md) 87 | * [Using other styles](./docs/usage/using-other-styles.md) 88 | * [Full feature list](./docs/usage/features.md) 89 | * [Upgrading instructions](UPGRADING.md) 90 | * [Frequency asked questions](./docs/faq.md) 91 | 92 | ## Examples 93 | 94 | ### Stackblitz 95 | Here's a [StackBlitz Starter Sample](https://stackblitz.com/edit/angular-ivy-7jrcne) on how to display Solid, Regular, and Brand icons [using the Icon Library](./docs/usage/icon-library.md#using-the-icon-library). 96 | 97 | 98 | ### Demo application 99 | You can find examples in the `projects/demo` directory. You can follow [the docs to run the demo app](./DEVELOPER.md#setting-up-the-local-environment) on your own machine. 100 | 101 | ## Contributing 102 | `angular-fontawesome` is a product of the community, you can take a look at the [developer docs](./DEVELOPER.md) to find about more on how to contribute back to the project. 103 | 104 | ## Contributors 105 | 106 | The following contributors have either helped to start this project, have contributed 107 | code, are actively maintaining it (including documentation), or in other ways 108 | being awesome contributors to this project. **We'd like to take a moment to recognize them.** 109 | 110 | [devoto13](https://github.com/devoto13) 111 | [zeevkatz](https://github.com/zeevkatz) 112 | [scttcper](https://github.com/scttcper) 113 | [DavidePastore](https://github.com/DavidePastore) 114 | [donmckenna](https://github.com/donmckenna) 115 | [paustint](https://github.com/paustint) 116 | [mzellho](https://github.com/mzellho) 117 | [elebitzero](https://github.com/elebitzero) 118 | [mcenkar](https://github.com/mcenkar) 119 | [SiddAjmera](https://github.com/SiddAjmera) 120 | [stephaniepurvis](https://github.com/stephaniepurvis) 121 | [loicgasser](https://github.com/loicgasser) 122 | [damienwebdev](https://github.com/damienwebdev) 123 | [ronniebarker](https://github.com/ronniebarker) 124 | [bhanuhiteshi](https://github.com/bhanuhiteshi) 125 | [MrSuttonmann](https://github.com/MrSuttonmann) 126 | [ej2](https://github.com/ej2) 127 | [peterblazejewicz](https://github.com/peterblazejewicz) 128 | [arjenbrandenburgh](https://github.com/arjenbrandenburgh) 129 | [athisun](https://github.com/athisun) 130 | [madebyjeffrey](https://github.com/madebyjeffrey) 131 | [benjamincharity](https://github.com/benjamincharity) 132 | [NayeBeckham](https://github.com/NayeBeckham) 133 | [Nosfistis](https://github.com/Nosfistis) 134 | [bleistift-zwei](https://github.com/bleistift-zwei) 135 | [igorls](https://github.com/igorls) 136 | [jasonlundien](https://github.com/jasonlundien) 137 | [Font Awesome Team](https://github.com/orgs/FortAwesome/people) 138 | [pankajparkar](https://github.com/pankajparkar) 139 | [medbenmakhlouf](https://github.com/medbenmakhlouf) 140 | [Stoffel-KT](https://github.com/Stoffel-KT) 141 | [Ionaru](https://github.com/Ionaru) 142 | 143 | If we've missed someone (which is quite likely) submit a Pull Request to us and we'll get it resolved. 144 | -------------------------------------------------------------------------------- /docs/usage/features.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | The following features are available as part of Font Awesome. Note that the syntax is different from our general web-use documentation. 4 | 5 | ## Basic 6 | 7 | ### Size 8 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/sizing-icons) 9 | ```html 10 | 11 | 12 | 13 | ``` 14 | 15 | ### Fixed Width 16 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/fixed-width-icons): 17 | 18 | ```html 19 | 20 | ``` 21 | 22 | ### Rotate 23 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/rotating-icons): 24 | 25 | ```html 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | ### Flip 34 | * horizontally, vertically, or both 35 | 36 | ```html 37 | 38 | 39 | 40 | ``` 41 | 42 | ### Animations 43 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/animating-icons) 44 | 45 | ```html 46 | 47 | 48 | 49 | ``` 50 | 51 | ### Border 52 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/bordered-pulled-icons): 53 | 54 | ```html 55 | 56 | ``` 57 | 58 | ### Pull 59 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/bordered-pulled-icons): 60 | 61 | ```html 62 | 63 | ``` 64 | 65 | ### Custom styles 66 | 67 | Simple styles can be applied using usual [class and style bindings](https://angular.io/guide/class-binding): 68 | 69 | ```css 70 | .red-icon { 71 | color: red; 72 | } 73 | ``` 74 | 75 | ```html 76 | 77 | ``` 78 | 79 | For more advanced styling, see [Styling icon internals](../guide/styling-icon-internals.md). 80 | 81 | ## Duotone icons 82 | 83 | ### Basic use 84 | 85 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/duotone-icons#basic-use): 86 | 87 | ```html 88 | 89 | ``` 90 | 91 | ### Swap layers opacity 92 | 93 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/duotone-icons#swapping-layers): 94 | 95 | ```html 96 | 97 | ``` 98 | 99 | ### Customize layers opacity 100 | 101 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/duotone-icons#changing-opacity): 102 | 103 | ```html 104 | 105 | 106 | ``` 107 | 108 | ### Customize layers color 109 | 110 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/duotone-icons#coloring): 111 | 112 | ```html 113 | 114 | 115 | ``` 116 | 117 | ## Advanced Usage 118 | 119 | ### Mask 120 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/masking) 121 | ```html 122 | 123 | ``` 124 | 125 | ### Transform 126 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/power-transforms) 127 | 128 | ```html 129 | 130 | ``` 131 | 132 | ### Stateful Animations 133 | ```html 134 | 139 | ``` 140 | 141 | ### Transform within binding: 142 | 143 | ```html 144 | 145 | 146 | ``` 147 | (Slide input range to "turn up the magic") 148 | 149 | ### Stacked icons 150 | 151 | Each `` declared inside an `` element **must** include the `stackItemSize` input parameter, otherwise the icon will not render. 152 | 153 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/stacking-icons): 154 | 155 | ```html 156 | 157 | 158 | 159 | 160 | ``` 161 | 162 | When using standalone components, make sure to also add `FaStackItemSizeDirective` to the imports alongside with the `FaStackComponent`. Without the directive, the stacked icon will not render correctly. 163 | 164 | ### Layers 165 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/layering): 166 | 167 | ```html 168 | 169 | 170 | 171 | 172 | ``` 173 | 174 | ### Layers with text 175 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/layering): 176 | 177 | ```html 178 | 179 | 180 | 181 | 182 | ``` 183 | 184 | ### Layers with counter 185 | [FontAwesome Spec](https://fontawesome.com/how-to-use/on-the-web/styling/layering): 186 | 187 | ```html 188 | 189 | 190 | 191 | 192 | ``` 193 | 194 | ### Programmatic API 195 | 196 | #### v2.0.0 Onwards 197 | 198 | To create `FaIconComponent` dynamically: 199 | 200 | ```ts 201 | @Component({ 202 | selector: 'fa-host', 203 | template: ` 204 | 207 |
208 | 209 | ` 210 | }) 211 | class HostComponent { 212 | readonly container = viewChild('host', { read: ViewContainerRef }); 213 | 214 | createIcon() { 215 | const componentRef = this.countainer().createComponent(FaIconComponent); 216 | componentRef.setInput('icon', faUser); 217 | } 218 | } 219 | ``` 220 | 221 | To update `FaIconComponent` programmatically: 222 | 223 | ```ts 224 | @Component({ 225 | selector: 'fa-host', 226 | template: '', 227 | }) 228 | class HostComponent { 229 | readonly faUser = faUser; 230 | readonly iconComponent = viewChild(FaIconComponent); 231 | 232 | spinIcon() { 233 | this.iconComponent().animation.set('spin'); 234 | } 235 | } 236 | ``` 237 | 238 | #### Upto v1.0.0 239 | 240 | To create `FaIconComponent` dynamically: 241 | 242 | ```ts 243 | @Component({ 244 | selector: 'fa-host', 245 | template: '
' 246 | }) 247 | class HostComponent { 248 | @ViewChild('host', {static: true, read: ViewContainerRef}) container: ViewContainerRef; 249 | 250 | createIcon() { 251 | const componentRef = this.container.createComponent(FaIconComponent); 252 | componentRef.instance.icon = faUser; 253 | // Note that FaIconComponent.render() should be called to update the 254 | // rendered SVG after setting/updating component inputs. 255 | componentRef.instance.render(); 256 | } 257 | } 258 | ``` 259 | 260 | To update `FaIconComponent` programmatically: 261 | 262 | ```ts 263 | @Component({ 264 | selector: 'fa-host', 265 | template: '' 266 | }) 267 | class HostComponent { 268 | faUser = faUser; 269 | 270 | @ViewChild(FaIconComponent, {static: true}) iconComponent: FaIconComponent; 271 | 272 | spinIcon() { 273 | this.iconComponent.animation = 'spin'; 274 | // Note that FaIconComponent.render() should be called to update the 275 | // rendered SVG after setting/updating component inputs. 276 | this.iconComponent.render(); 277 | } 278 | } 279 | ``` 280 | --------------------------------------------------------------------------------