UNPKG

@obliczeniowo/elementary

Version:
302 lines (294 loc) 11.4 kB
import * as i1 from '@angular/common/http'; import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import * as i0 from '@angular/core'; import { SecurityContext, DOCUMENT, Inject, Injectable, input, effect, HostBinding, Component, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { of, from } from 'rxjs'; import { map, catchError } from 'rxjs/operators'; import * as i2 from '@angular/platform-browser'; /** * Registering icons service for icon.component * * Registering own: * @example * * constructor(private iconResource: IconResourceService) { * iconResource.registerIcon( * this.sanitizer.bypassSecurityTrustHtml('/assets/icons/your-icon.svg'), * 'icon-name' * ); * } * * @ * Use in html with icon component: * * @example * * <obl-icon [width]="20" name="icon-name"></obl-icon> * * @ To correctly work in library component you need to copy assets folder adding script to npm: * * @example * * "copy-assets": "node ./node_modules/@obliczeniowo/elementary/assets/scripts/copy.js ./src/assets/", * * @ and run in console: * * @example * npm run copy-assets */ class IconResourceService { http; sanitizer; document; icons = new Map(); urls = new Map(); loading = new Map(); base = '/'; constructor(http, sanitizer, document) { this.http = http; this.sanitizer = sanitizer; this.document = document; const base = document.head.querySelector('base'); this.base = base?.href || '/'; if (!this.icons.size) { const icons = [ 'search', 'expand', 'add', 'add-box', 'subtract-box', 'subtract', 'cancel', 'ok', 'down-more', 'up-more', 'up', 'down', 'left-more', 'right-more', 'left', 'right', 'csv-file', 'json-file', 'xlsx-file', 'logout', 'edit', 'pause', 'play', 'move', 'mute', 'voice', 'loop', 'stop', 'pointing', 'asc', 'filter', 'save', 'gear', 'checked', 'unchecked', 'checklist-mixed', 'list', 'file', 'sync-up', 'sync-down', 'link' ]; icons.forEach((icon) => this.registerIcon(this.sanitizer.bypassSecurityTrustHtml(`/assets/obl-icons/${icon}.svg`), icon)); } } /** * Registering own: * @param url SafeHTML object with path to icon in your asset folder * @param name your icon name * * @example * * constructor(private iconResource: IconResourceService) { * iconResource.registerIcon( * this.sanitizer.bypassSecurityTrustHtml('/assets/icons/your-icon.svg'), * 'icon-name' * ); * } * * @ * Use in html with icon component: * * @example * * <obl-icon [width]="20" name="icon-name"></obl-icon> */ registerIcon(url, name) { url.changingThisBreaksApplicationSecurity = this.base + url.changingThisBreaksApplicationSecurity.replace(/^\//, ''); const icon = { url, name, }; this.icons.set(name, icon); } /** * Download once icon from server and keep it in buffer * @param name name of icon * @returns observable with SVGSVGElement or undefined */ getIcon(name) { const icon = this.icons.get(name); if (!icon) { throw new Error(`Can't find icon "${name}" in registered resources. Pleas register it.`); } if (icon.svgString) { return of(this.createSvgFromString(icon.svgString)); } const loading = this.loading.get(name); if (loading) { return from(loading).pipe(map((svg) => (svg ? this.createSvgFromString(svg) : undefined))); } const url = this.sanitizer.sanitize(SecurityContext.HTML, icon.url); if (url) { let resolve; let reject; const exec = (res, rej) => { resolve = res; reject = rej; }; const promise = new Promise(exec); this.loading.set(name, promise); return this._fromUrl(url, (svg) => { icon.svgString = svg; this.icons.set(name, icon); resolve(svg); this.loading.delete(name); }, () => { reject(name); this.loading.delete(url); return this.err(name, url); }); } throw new Error('Icon url was not set'); } /** * Register url to SVG file * @param url url string * @returns SVGSVGElement/undefined or throwing error */ fromUrl(url) { let icon = this.urls.get(url) || {}; if (!icon) { icon = { url: this.sanitizer.bypassSecurityTrustHtml(url), }; } if (icon.svgString) { return of(this.createSvgFromString(icon.svgString)); } return this._fromUrl(url, (svg) => { icon.svgString = svg; this.urls.set(url, icon); }, () => this.err(undefined, url)); } _fromUrl(url, cb, cbError) { return this.http.get(url, { responseType: 'text' }).pipe(map((svg) => { if (cb) { cb(svg); } return this.createSvgFromString(svg); }), catchError((_) => { // eslint-disable-next-line @typescript-eslint/prefer-optional-chain throw (cbError && cbError()) || this.err(undefined, url); })); } ngOnDestroy() { this.icons.clear(); } err(name, url) { return new Error(`Can't download icon "${name}" with url "${url}". Please make sure that asset folder in node_modules of library @obliczeniowo/elementary was copied by adding script: "copy-assets": "node ./node_modules/@obliczeniowo/elementary/assets/scripts/copy.js ./src/assets/", and run it with npm or registered by you icon have proper path to file in your assets folder`); } createSvgFromString(svgString) { const div = this.document.createElement('DIV'); div.innerHTML = svgString; // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style return div.querySelector('svg'); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IconResourceService, deps: [{ token: i1.HttpClient }, { token: i2.DomSanitizer }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IconResourceService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IconResourceService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.DomSanitizer }, { type: Document, decorators: [{ type: Inject, args: [DOCUMENT] }] }] }); /** * Icon component that let you display registered icon with IconResourceService * * @example * * <obl-icon name="search" [size]="20"></obl-icon> */ class IconComponent { iconResource; elementRef; /** * registered icon name */ name = input.required(); /** * Width in px or css like things */ width = input('var(--obl-icon-width, 20px)'); get widthStyle() { return typeof this.width() === 'string' && this.width() || this.width() + 'px'; } constructor(iconResource, elementRef) { this.iconResource = iconResource; this.elementRef = elementRef; effect(() => { this.iconResource.getIcon(this.name()).subscribe((svg) => { if (svg) { while (this.elementRef.nativeElement.firstChild) { this.elementRef.nativeElement.removeChild(this.elementRef.nativeElement.firstChild); } svg.style.fill = 'var(--obl-default-icon-color)'; this.elementRef.nativeElement.appendChild(svg); } }); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IconComponent, deps: [{ token: IconResourceService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: IconComponent, isStandalone: false, selector: "obl-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.width": "this.widthStyle" } }, ngImport: i0, template: "\n", styles: [":host{display:flex;align-items:center}\n"] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IconComponent, decorators: [{ type: Component, args: [{ selector: 'obl-icon', standalone: false, template: "\n", styles: [":host{display:flex;align-items:center}\n"] }] }], ctorParameters: () => [{ type: IconResourceService }, { type: i0.ElementRef }], propDecorators: { widthStyle: [{ type: HostBinding, args: ['style.width'] }] } }); class IconsModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IconsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: IconsModule, declarations: [IconComponent], imports: [CommonModule], exports: [IconComponent] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IconsModule, providers: [provideHttpClient(withInterceptorsFromDi())], imports: [CommonModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IconsModule, decorators: [{ type: NgModule, args: [{ declarations: [ IconComponent ], exports: [ IconComponent ], imports: [CommonModule], providers: [provideHttpClient(withInterceptorsFromDi())] }] }] }); /** * Generated bundle index. Do not edit. */ export { IconComponent, IconResourceService, IconsModule }; //# sourceMappingURL=obliczeniowo-elementary-icons.mjs.map