UNPKG

carbon-components-angular

Version:
425 lines (419 loc) 16.5 kB
import * as i0 from '@angular/core'; import { Injectable, Directive, Input, Optional, SkipSelf, NgModule } from '@angular/core'; import { toString, getAttributes } from '@carbon/icon-helpers'; import { CommonModule } from '@angular/common'; import Add16 from '@carbon/icons/es/add/16'; import Add20 from '@carbon/icons/es/add/20'; import Bee16 from '@carbon/icons/es/bee/16'; import Bee20 from '@carbon/icons/es/bee/20'; import Calendar16 from '@carbon/icons/es/calendar/16'; import Carbon16 from '@carbon/icons/es/carbon/16'; import Carbon20 from '@carbon/icons/es/carbon/20'; import CaretDown16 from '@carbon/icons/es/caret--down/16'; import CaretLeft16 from '@carbon/icons/es/caret--left/16'; import CaretRight16 from '@carbon/icons/es/caret--right/16'; import CaretUp16 from '@carbon/icons/es/caret--up/16'; import Checkmark16 from '@carbon/icons/es/checkmark/16'; import CheckmarkFilled16 from '@carbon/icons/es/checkmark--filled/16'; import CheckmarkFilled20 from '@carbon/icons/es/checkmark--filled/20'; import CheckmarkOutline16 from '@carbon/icons/es/checkmark--outline/16'; import Checkbox16 from '@carbon/icons/es/checkbox/16'; import CheckboxCheckedFilled16 from '@carbon/icons/es/checkbox--checked--filled/16'; import ChevronDown16 from '@carbon/icons/es/chevron--down/16'; import ChevronRight16 from '@carbon/icons/es/chevron--right/16'; import CircleDash16 from '@carbon/icons/es/circle-dash/16'; import Close16 from '@carbon/icons/es/close/16'; import Close20 from '@carbon/icons/es/close/20'; import Copy16 from '@carbon/icons/es/copy/16'; import Copy20 from '@carbon/icons/es/copy/20'; import Data216 from '@carbon/icons/es/data--2/16'; import Data220 from '@carbon/icons/es/data--2/20'; import Document16 from '@carbon/icons/es/document/16'; import Document20 from '@carbon/icons/es/document/20'; import Download16 from '@carbon/icons/es/download/16'; import ErrorFilled16 from '@carbon/icons/es/error--filled/16'; import ErrorFilled20 from '@carbon/icons/es/error--filled/20'; import Fade16 from '@carbon/icons/es/fade/16'; import Fade20 from '@carbon/icons/es/fade/20'; import Folder16 from '@carbon/icons/es/folder/16'; import Incomplete16 from '@carbon/icons/es/incomplete/16'; import InformationFilled16 from '@carbon/icons/es/information--filled/16'; import InformationFilled20 from '@carbon/icons/es/information--filled/20'; import InformationSquareFilled20 from '@carbon/icons/es/information--square--filled/20'; import Menu16 from '@carbon/icons/es/menu/16'; import Menu20 from '@carbon/icons/es/menu/20'; import OverflowMenuVertical16 from '@carbon/icons/es/overflow-menu--vertical/16'; import OverflowMenuHorizontal16 from '@carbon/icons/es/overflow-menu--horizontal/16'; import Save16 from '@carbon/icons/es/save/16'; import Search16 from '@carbon/icons/es/search/16'; import Settings16 from '@carbon/icons/es/settings/16'; import SettingsAdjust16 from '@carbon/icons/es/settings--adjust/16'; import Subtract16 from '@carbon/icons/es/subtract/16'; import TrashCan16 from '@carbon/icons/es/trash-can/16'; import Warning16 from '@carbon/icons/es/warning/16'; import WarningFilled16 from '@carbon/icons/es/warning--filled/16'; import WarningFilled20 from '@carbon/icons/es/warning--filled/20'; import WarningAltFilled16 from '@carbon/icons/es/warning--alt--filled/16'; import WarningAltFilled20 from '@carbon/icons/es/warning--alt--filled/20'; import View16 from '@carbon/icons/es/view/16'; import ViewOff16 from '@carbon/icons/es/view--off/16'; /** * Abstract class that represent a cache of icons. * * The actual caching mechanism will be implementation specific, * but it's likely a good idea to key by the icons name and/or size. * Icon name and size will always be strings, and they will be the two consistent * identifiers of an icon. For the purposes of storage additonal descriptor properties may * be used, but the name and size are the only ones guarenteed to be passed for lookup purposes. */ class IconCache { } /** * Custom error for when a name can't be found */ class IconNameNotFoundError extends Error { constructor(name) { super(`Icon ${name} not found`); } } /** * Custom error for when a specific size can't be found */ class IconSizeNotFoundError extends Error { constructor(size, name) { super("Size ${size} for ${name} not found"); } } /** * Concrete implementation of `IconCache` as a simple in memory cache */ class IconMemoryCache extends IconCache { constructor() { super(...arguments); this.iconMap = new Map(); } get(name, size) { if (!this.iconMap.has(name)) { throw new IconNameNotFoundError(name); } const sizeMap = this.iconMap.get(name); if (!sizeMap.has(size)) { throw new IconSizeNotFoundError(size, name); } return sizeMap.get(size); } set(name, size, descriptor) { if (!this.iconMap.has(name)) { this.iconMap.set(name, new Map()); } const sizeMap = this.iconMap.get(name); sizeMap.set(size, descriptor); } } /** * The icon service is a singleton service responsible for registering and retriving icons from `@carbon/icons`. * * It's important to register icons before use. It's reccommended to register your icons early, likely in your app.component. * * To allow for improved tree shaking _do not_ import all the icons from `@carbon/icons` and register them. * Instead register only the icons in use by your application. If your application makes use of lazy loaded * modules you may also lazy load the icons used in that module by registering them early on in that module. * * `ngOnInit` should be sufficiantly early to register icons. * * Example: * ``` * import { Accessibility16 } from "@carbon/icons"; * * // ... * * class MyComponent implements OnInit { * constructor(protected iconService: IconService) {} * * // ... * * ngOnInit() { * this.iconService.register(Accessibility16); * } * * // ... * } * ``` * * If needed it is possible to register an icon under a different name, via `registerAs`. */ class IconService { constructor() { this.iconCache = new IconMemoryCache(); } /** * Registers an array of icons based on the metadata provided by `@carbon/icons` */ registerAll(descriptors) { descriptors.forEach(icon => this.register(icon)); } /** * Registers an icon based on the metadata provided by `@carbon/icons` */ register(descriptor) { const { name } = descriptor; this.registerAs(name, descriptor); } /** * Registers an icon based on a uniqe name and metadata provided by `@carbon/icons` */ registerAs(name, descriptor) { const { size } = descriptor; this.iconCache.set(name, size.toString(), descriptor); } /** * Gets an icon, converts it to a string, and caches the result */ get(name, size) { try { const icon = this.iconCache.get(name, size.toString()); if (!icon.svg) { icon.svg = toString(icon); } return icon; } catch (e) { throw e; } } /** * Configure various service settings (caching strategy ...) */ configure(options) { this.iconCache = options.cache; } } IconService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: IconService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); IconService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: IconService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: IconService, decorators: [{ type: Injectable }] }); /** * A directive for populating a svg element based on the provided carbon icon name. * * Get started with importing the module: * * ```typescript * import { IconModule } from 'carbon-components-angular'; * ``` * * [See demo](../../?path=/story/components-icon--basic) */ class IconDirective { constructor(elementRef, iconService) { this.elementRef = elementRef; this.iconService = iconService; this.cdsIcon = ""; this.size = "16"; this.title = ""; this.ariaLabel = ""; this.ariaLabelledBy = ""; this.ariaHidden = ""; this.isFocusable = false; } /** * @deprecated since v5 - Use `cdsIcon` input property instead */ set ibmIcon(iconName) { this.cdsIcon = iconName; } renderIcon(iconName) { const root = this.elementRef.nativeElement; let icon; try { icon = this.iconService.get(iconName, this.size.toString()); } catch (error) { console.warn(error); // bail out return; } const domParser = new DOMParser(); const rawSVG = icon.svg; const svgElement = domParser.parseFromString(rawSVG, "image/svg+xml").documentElement; let node = root.tagName.toUpperCase() !== "SVG" ? svgElement : svgElement.firstChild; root.innerHTML = ""; // Clear root element while (node) { // importNode makes a clone of the node // this ensures we keep looping over the nodes in the parsed document root.appendChild(root.ownerDocument.importNode(node, true)); // type the node because the angular compiler freaks out if it // ends up thinking it's a `Node` instead of a `ChildNode` node = node.nextSibling; } const svg = root.tagName.toUpperCase() !== "SVG" ? svgElement : root; const xmlns = "http://www.w3.org/2000/svg"; svg.setAttribute("xmlns", xmlns); const attributes = getAttributes({ width: icon.attrs.width, height: icon.attrs.height, viewBox: icon.attrs.viewBox, title: this.title, "aria-label": this.ariaLabel, "aria-labelledby": this.ariaLabelledBy, "aria-hidden": this.ariaHidden, focusable: this.isFocusable.toString(), fill: icon.attrs.fill }); const attrKeys = Object.keys(attributes); for (let i = 0; i < attrKeys.length; i++) { const key = attrKeys[i]; const value = attributes[key]; if (key === "title") { continue; } if (value) { svg.setAttribute(key, value); } } if (attributes["title"]) { const title = document.createElementNS(xmlns, "title"); title.textContent = attributes.title; IconDirective.titleIdCounter++; title.setAttribute("id", `${icon.name}-title-${IconDirective.titleIdCounter}`); // title must be first for screen readers svg.insertBefore(title, svg.firstElementChild); svg.setAttribute("aria-labelledby", `${icon.name}-title-${IconDirective.titleIdCounter}`); } } ngAfterViewInit() { this.renderIcon(this.cdsIcon); } ngOnChanges({ cdsIcon }) { // We want to ignore first change to let the icon register // and add only after view has been initialized if (cdsIcon && !cdsIcon.isFirstChange()) { this.renderIcon(this.cdsIcon); } } } IconDirective.titleIdCounter = 0; IconDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: IconDirective, deps: [{ token: i0.ElementRef }, { token: IconService }], target: i0.ɵɵFactoryTarget.Directive }); IconDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: { ibmIcon: "ibmIcon", cdsIcon: "cdsIcon", size: "size", title: "title", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", ariaHidden: "ariaHidden", isFocusable: "isFocusable" }, usesOnChanges: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: IconDirective, decorators: [{ type: Directive, args: [{ selector: "[cdsIcon], [ibmIcon]" }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: IconService }]; }, propDecorators: { ibmIcon: [{ type: Input }], cdsIcon: [{ type: Input }], size: [{ type: Input }], title: [{ type: Input }], ariaLabel: [{ type: Input }], ariaLabelledBy: [{ type: Input }], ariaHidden: [{ type: Input }], isFocusable: [{ type: Input }] } }); // modules // either provides a new instance of IconService, or returns the parent function ICON_SERVICE_PROVIDER_FACTORY(parentService) { return parentService || new IconService(); } // icon service *must* be a singleton to ensure that icons are accessible globally and not duplicated const ICON_SERVICE_PROVIDER = { provide: IconService, deps: [[new Optional(), new SkipSelf(), IconService]], useFactory: ICON_SERVICE_PROVIDER_FACTORY }; class IconModule { constructor(iconService) { this.iconService = iconService; iconService.registerAll([ Add16, Add20, Bee16, Bee20, Calendar16, Carbon16, Carbon20, CaretDown16, CaretLeft16, CaretRight16, CaretUp16, Checkmark16, CheckmarkFilled16, CheckmarkFilled20, CheckmarkOutline16, Checkbox16, CheckboxCheckedFilled16, ChevronDown16, ChevronRight16, CircleDash16, Close16, Close20, Copy16, Copy20, Data216, Data220, Document16, Document20, Download16, ErrorFilled16, ErrorFilled20, Fade16, Fade20, Folder16, Incomplete16, InformationFilled16, InformationFilled20, InformationSquareFilled20, Menu16, Menu20, OverflowMenuVertical16, OverflowMenuHorizontal16, Save16, Search16, Settings16, SettingsAdjust16, Subtract16, TrashCan16, View16, ViewOff16, Warning16, WarningFilled16, WarningFilled20, WarningAltFilled16, WarningAltFilled20 ]); } } IconModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: IconModule, deps: [{ token: IconService }], target: i0.ɵɵFactoryTarget.NgModule }); IconModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: IconModule, declarations: [IconDirective], imports: [CommonModule], exports: [IconDirective] }); IconModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: IconModule, providers: [ ICON_SERVICE_PROVIDER ], imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: IconModule, decorators: [{ type: NgModule, args: [{ declarations: [ IconDirective ], exports: [ IconDirective ], imports: [ CommonModule ], providers: [ ICON_SERVICE_PROVIDER ] }] }], ctorParameters: function () { return [{ type: IconService }]; } }); /** * Generated bundle index. Do not edit. */ export { ICON_SERVICE_PROVIDER, ICON_SERVICE_PROVIDER_FACTORY, IconCache, IconDirective, IconMemoryCache, IconModule, IconNameNotFoundError, IconService, IconSizeNotFoundError }; //# sourceMappingURL=carbon-components-angular-icon.mjs.map