UNPKG

flowbite-angular

Version:

<div align="center"> <h1>:construction: flowbite-angular (unreleased) :construction:</h1> <p> <a href="https://flowbite.com"> <img alt="Flowbite - Tailwind CSS components" width="350" src="https://flowbite.s3.amazonaws.com/github/logo-github

255 lines (249 loc) 10.5 kB
import { DOCUMENT, isPlatformBrowser } from '@angular/common'; import { HttpClient } from '@angular/common/http'; import * as i0 from '@angular/core'; import { inject, PLATFORM_ID, SecurityContext, Injectable, ElementRef, model, effect, Component, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { of, throwError, map, tap, finalize, share, take } from 'rxjs'; import { BaseComponent } from 'flowbite-angular'; /** * Thanks to Angular Material for Icon part of this library : https://github.com/angular/components */ let policy; function getPolicy() { if (!policy) { if (typeof window !== 'undefined') { const tWindow = window; if (tWindow.trustedTypes !== undefined) { policy = tWindow.trustedTypes.createPolicy('angular#components', { createHTML: (s) => s, }); } } } return policy; } function trustedHTMLFromString(raw) { return getPolicy()?.createHTML(raw) || raw; } /** * Thanks to Angular Material for Icon part of this library : https://github.com/angular/components */ function getSvgIconFromNamedError(iconName) { return Error(`Unable to find icon with name ${iconName}`); } function getSvgIconFailedToSanitizeRawError(raw) { return Error(`The raw provided to IconRegistry was not trusted as safe HTML by ANGULAR's DOMSanitizer. Attempted raw was : ${raw}`); } function getSvgIconFailedToSanitizeUrlError(url) { return Error(`The URL provided to IconRegistry was not trusted as a resource URL via Angular's DOMSanitizer. Attempted URL was : ${url}`); } function getSvgIconNoHttpClientProvidedError() { return Error(`Could not fid HttpClient provider for use with flowbite-angular icons. Please include the HttpClientModule from @angular/common/http in your app imports`); } class SvgIconConfig { constructor(url, svgText, options) { this.url = url; this.svgText = svgText; this.options = options; this.svgElement = null; } } class IconRegistry { constructor() { this.platformId = inject(PLATFORM_ID); this._httpClient = inject(HttpClient, { optional: true }); this._sanitizer = inject(DomSanitizer); this._document = inject(DOCUMENT); this._svgIconConfig = new Map(); this._cachedSvgIconByUrl = new Map(); this._inProgressSvgIconFetch = new Map(); } addSvgIcon(iconName, url, options) { return this.addSvgIconInNamespace('', iconName, url, options); } addRawSvgIcon(iconName, raw, options) { return this.addRawSvgIconInNamepsace('', iconName, raw, options); } addSvgIconInNamespace(namespace, iconName, url, options) { return this._addSvgIconConfig(namespace, iconName, new SvgIconConfig(url, undefined, options)); } addRawSvgIconInNamepsace(namespace, iconName, raw, options) { const cleanRaw = this._sanitizer.sanitize(SecurityContext.HTML, raw); if (!cleanRaw) { throw getSvgIconFailedToSanitizeRawError(raw); } const trustedRaw = trustedHTMLFromString(cleanRaw); return this._addSvgIconConfig(namespace, iconName, new SvgIconConfig('', trustedRaw, options)); } getSvgIconFromUrl(safeUrl) { const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl); if (!url) { throw getSvgIconFailedToSanitizeUrlError(safeUrl); } const cachedIcon = this._cachedSvgIconByUrl.get(url); if (cachedIcon) { return of(cloneSvg(cachedIcon)); } return this._loadSvgIconFromConfig(new SvgIconConfig(safeUrl, undefined)); } getSvgIconFromName(iconName, namespace) { const key = iconKey(namespace, iconName); const config = this._svgIconConfig.get(key); if (config) { return this._getSvgIconFromConfig(config); } return throwError(() => getSvgIconFromNamedError(key)); } ngOnDestroy() { this._svgIconConfig.clear(); this._cachedSvgIconByUrl.clear(); } _addSvgIconConfig(namespace, iconName, config) { this._svgIconConfig.set(iconKey(namespace, iconName), config); return this; } _getSvgIconFromConfig(config) { if (config.svgText) { return of(cloneSvg(this._svgElementFromConfig(config))); } else { return this._loadSvgIconFromConfig(config).pipe(map((svg) => cloneSvg(svg))); } } _loadSvgIconFromConfig(config) { return this._fetchIcon(config).pipe(tap((svgText) => (config.svgText = svgText)), map(() => this._svgElementFromConfig(config))); } _setSvgAttributes(svg, options) { svg.setAttribute('fit', ''); svg.setAttribute('height', '100%'); svg.setAttribute('width', '100%'); svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); svg.setAttribute('focusable', 'false'); if (options?.viewBox) { svg.setAttribute('viewBox', options.viewBox); } return svg; } _svgElementFromConfig(config) { if (!config.svgElement) { const svg = this._svgElementFromString(config.svgText); this._setSvgAttributes(svg, config.options); config.svgElement = svg; } return config.svgElement; } _svgElementFromString(str) { const div = this._document.createElement('div'); div.innerHTML = str; const svg = div.querySelector('svg'); return svg; } _fetchIcon(iconConfig) { if (isPlatformBrowser(this.platformId)) { if (!this._httpClient) { throw getSvgIconNoHttpClientProvidedError(); } const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, iconConfig.url); if (!url) { throw getSvgIconFailedToSanitizeUrlError(iconConfig.url); } const inProgressFetch = this._inProgressSvgIconFetch.get(url); if (inProgressFetch) { return inProgressFetch; } const req = this._httpClient.get(url, { responseType: 'text' }).pipe(map((svg) => { return trustedHTMLFromString(svg); }), finalize(() => this._inProgressSvgIconFetch.delete(url)), share()); this._inProgressSvgIconFetch.set(url, req); return req; } else { return of(trustedHTMLFromString('<svg></svg>')); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: IconRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: IconRegistry, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: IconRegistry, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); function cloneSvg(svg) { return svg.cloneNode(true); } function iconKey(namespace, iconName) { return `${namespace}:${iconName}`; } /** * Thanks to Angular Material for Icon part of this library : https://github.com/angular/components */ class IconComponent extends BaseComponent { constructor() { super(...arguments); this._elementRef = inject((ElementRef)); this._iconRegistry = inject(IconRegistry); this.svgIcon = model.required(); } init() { effect(() => { this._updateSvgIcon(); }, { injector: this.injector }); } fetchClass() { return { rootClass: '' }; } _splitIconName(iconName) { if (!iconName) { return ['', '']; } const parts = iconName.split(':'); switch (parts.length) { case 1: return ['', parts[0]]; case 2: return parts; default: throw Error(`Invalid icon name: "${iconName}"`); } } _updateSvgIcon() { const [namespace, iconName] = this._splitIconName(this.svgIcon()); this._iconRegistry .getSvgIconFromName(iconName, namespace) .pipe(take(1)) .subscribe((svg) => this._setSvgElement(svg)); } _setSvgElement(svg) { this._clearSvgElements(); this._elementRef.nativeElement.appendChild(svg); } _clearSvgElements() { const layoutElement = this._elementRef.nativeElement; let childCount = layoutElement.childNodes.length; while (childCount--) { const child = layoutElement.childNodes[childCount]; if (child.nodeType !== 1 || child.nodeName.toLowerCase() === 'svg') { child.remove(); } } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: IconComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.4", type: IconComponent, isStandalone: true, selector: "flowbite-icon", inputs: { svgIcon: { classPropertyName: "svgIcon", publicName: "svgIcon", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { svgIcon: "svgIconChange" }, usesInheritance: true, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: IconComponent, decorators: [{ type: Component, args: [{ standalone: true, selector: 'flowbite-icon', template: `<ng-content />`, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }] }] }); /** * Generated bundle index. Do not edit. */ export { IconComponent, IconRegistry, SvgIconConfig, getSvgIconFailedToSanitizeRawError, getSvgIconFailedToSanitizeUrlError, getSvgIconFromNamedError, getSvgIconNoHttpClientProvidedError, trustedHTMLFromString }; //# sourceMappingURL=flowbite-angular-icon.mjs.map