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
JavaScript
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