From a0fe6e325709d1abeb160b3f169b2f4fbc748c17 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Tue, 29 Sep 2020 16:52:16 -0400 Subject: [PATCH] Prototype to register custom libraries on sl-icon --- docs/components/alert.md | 13 ++++++ src/components.d.ts | 12 ++++++ src/components/icon/icon.tsx | 77 ++++++++++++++++++++++++++++-------- 3 files changed, 86 insertions(+), 16 deletions(-) diff --git a/docs/components/alert.md b/docs/components/alert.md index b5076bda..50256592 100644 --- a/docs/components/alert.md +++ b/docs/components/alert.md @@ -4,6 +4,19 @@ Alerts are used to display important messages either inline or as toast notifications. +```html preview +
+ +
+ + +``` + ```html preview diff --git a/src/components.d.ts b/src/components.d.ts index 123426b3..d3a42c0a 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -472,10 +472,18 @@ export namespace Components { * An alternative description to use for accessibility. If omitted, the name or src will be used to generate it. */ "label": string; + /** + * The name of a custom registered icon library. + */ + "library": string; /** * The name of the icon to draw. */ "name": string; + /** + * Registers a custom icon library. + */ + "registerLibrary": (name: string, getPath: (iconName: string) => string) => Promise; /** * An external URL of an SVG file. */ @@ -1919,6 +1927,10 @@ declare namespace LocalJSX { * An alternative description to use for accessibility. If omitted, the name or src will be used to generate it. */ "label"?: string; + /** + * The name of a custom registered icon library. + */ + "library"?: string; /** * The name of the icon to draw. */ diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx index 517939ca..d818560e 100644 --- a/src/components/icon/icon.tsx +++ b/src/components/icon/icon.tsx @@ -1,7 +1,12 @@ -import { Component, Event, EventEmitter, Prop, State, Watch, getAssetPath, h } from '@stencil/core'; - +import { Component, Event, EventEmitter, Method, Prop, State, Watch, getAssetPath, h } from '@stencil/core'; import { requestIcon } from './request'; +interface IconLibrary { + name: string; + getPath: (iconName: string) => string; +} + +const libraries: IconLibrary[] = []; const parser = new DOMParser(); /** @@ -29,6 +34,9 @@ export class Icon { /** An alternative description to use for accessibility. If omitted, the name or src will be used to generate it. */ @Prop() label: string; + /** The name of a custom registered icon library. */ + @Prop() library: string; + /** Emitted when the icon has loaded. */ @Event() slLoad: EventEmitter; @@ -41,8 +49,24 @@ export class Icon { this.setIcon(); } + connectedCallback() { + this.handleLibraryRegistration = this.handleLibraryRegistration.bind(this); + } + componentDidLoad() { this.setIcon(); + document.addEventListener('slIconLibraryRegistered', this.handleLibraryRegistration); + } + + disconnectedCallback() { + document.removeEventListener('slIconLibraryRegistered', this.handleLibraryRegistration); + } + + /** Registers a custom icon library. */ + @Method() + async registerLibrary(name: string, getPath: (iconName: string) => string) { + libraries.push({ name, getPath }); + document.dispatchEvent(new CustomEvent('slIconLibraryRegistered', { detail: { name } })); } getLabel() { @@ -60,21 +84,42 @@ export class Icon { } setIcon() { - const url = this.name ? getAssetPath(`./icons/${this.name}.svg`) : this.src; - requestIcon(url) - .then(source => { - const doc = parser.parseFromString(source, 'text/html'); - const svg = doc.body.querySelector('svg'); + let url = this.src; - if (svg) { - this.svg = svg.outerHTML; - this.slLoad.emit(); - } else { - this.svg = ''; - this.slError.emit(); - } - }) - .catch(error => this.slError.emit(error)); + if (this.library && this.name) { + const library = libraries.filter(lib => lib.name === this.library)[0]; + if (library) { + url = library.getPath(this.name); + } else { + // The library hasn't been registered yet + return; + } + } else if (this.name) { + url = getAssetPath(`./icons/${this.name}.svg`); + } + + if (url) { + requestIcon(url) + .then(source => { + const doc = parser.parseFromString(source, 'text/html'); + const svg = doc.body.querySelector('svg'); + + if (svg) { + this.svg = svg.outerHTML; + this.slLoad.emit(); + } else { + this.svg = ''; + this.slError.emit(); + } + }) + .catch(error => this.slError.emit(error)); + } + } + + handleLibraryRegistration(event: CustomEvent) { + if (event.detail.name === this.library) { + this.setIcon(); + } } render() {