Finish up library reg

pull/261/head
Cory LaViska 2020-10-01 13:39:38 -04:00
rodzic 043bae13a3
commit fd21e2aac4
3 zmienionych plików z 182 dodań i 19 usunięć

Wyświetl plik

@ -4,7 +4,9 @@
Icons are symbols that can be used to represent or provide context to various options and actions within an application.
Shoelace comes bundled with over 1,100 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. Click or tap on an icon below to copy the name and use it like this.
Shoelace comes bundled with over 1,100 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. If you need more, you can also [register a custom library](#registering-custom-libraries).
Click or tap on an icon below to copy the name and use it like this.
```html
<sl-icon name="icon-name-here"></sl-icon>
@ -54,12 +56,152 @@ Icons are sized relative to the current font size. To change their size, set the
### Custom Icons
Custom icons can be loaded by setting the `src` attribute. Only SVG images are supported
Custom icons can be loaded by setting the `src` attribute. Only SVG images are supported.
```html preview
<sl-icon src="/assets/images/shoe.svg" style="font-size: 8rem;"></sl-icon>
```
## Registering Custom Libraries
You can register custom icon libraries by calling the `registerLibrary()` method on any `<sl-icon>` element. An icon library can exist locally or on a CORS-enabled CDN, and there is no limit to how many you can register. There is no cost associated with registering multiple libraries, as individual icons are only requested when they're used.
The `registerLibrary()` method accepts three arguments: the name of the library, a function that resolves an icon name to an SVG URL, and an optional function that can be used to mutate the SVG element. Once registered, icons can be displayed by setting the icon's `library` prop as shown below.
### Local Registration
This example registers a custom icon library named `my-icons` that serves icons from a local `/public/icons` directory. Additional examples can be found below for some popular open source icon libraries.
```html
<sl-icon library="my-icons" name="smile"></sl-icon>
<script>
const icon = document.querySelector('sl-icon');
icon.registerLibrary('my-icons', name => `/public/icons/${name}.svg`);
</script>
```
?> Calling `registerLibrary()` will register the library for all icons. You don't need to call it more than once for the same library!
### Feather Icons
This example registers and displays a handful of icons from the [Feather Icons](https://feathericons.com/) library using the jsDelivr CDN.
```html preview
<div class="icon-custom-feather" style="font-size: 24px;">
<sl-icon library="feather" name="feather"></sl-icon>
<sl-icon library="feather" name="briefcase"></sl-icon>
<sl-icon library="feather" name="pie-chart"></sl-icon>
<sl-icon library="feather" name="cloud"></sl-icon>
<sl-icon library="feather" name="settings"></sl-icon>
<sl-icon library="feather" name="smile"></sl-icon>
<sl-icon library="feather" name="map-pin"></sl-icon>
<sl-icon library="feather" name="printer"></sl-icon>
<sl-icon library="feather" name="search"></sl-icon>
<sl-icon library="feather" name="shopping-cart"></sl-icon>
</div>
<script>
const container = document.querySelector('.icon-custom-feather');
const icon = container.querySelector('sl-icon');
icon.registerLibrary('feather', name => `https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/icons/${name}.svg`);
</script>
```
### Heroicons
The following example registers the <a href="https://heroicons.com/" rel="noopener" target="_blank">Heroicons</a> library using the jsDelivr CDN.
```html preview
<div class="icon-custom-heroicons" style="font-size: 24px;">
<sl-icon library="heroicons" name="archive"></sl-icon>
<sl-icon library="heroicons" name="badge-check"></sl-icon>
<sl-icon library="heroicons" name="chat"></sl-icon>
<sl-icon library="heroicons" name="cloud"></sl-icon>
<sl-icon library="heroicons" name="cog"></sl-icon>
<sl-icon library="heroicons" name="document-text"></sl-icon>
<sl-icon library="heroicons" name="exclamation"></sl-icon>
<sl-icon library="heroicons" name="gift"></sl-icon>
<sl-icon library="heroicons" name="puzzle"></sl-icon>
<sl-icon library="heroicons" name="volume-up"></sl-icon>
</div>
<script>
const container = document.querySelector('.icon-custom-heroicons');
const icon = container.querySelector('sl-icon');
icon.registerLibrary('heroicons', name => `https://cdn.jsdelivr.net/npm/heroicons@0.4.2/outline/${name}.svg`);
</script>
```
### Ionicons
The following example registers the <a href="https://ionicons.com/" rel="noopener" target="_blank">Ionicons</a> library using the jsDelivr CDN.
```html preview
<div class="icon-custom-ionicons" style="font-size: 24px;">
<sl-icon library="ionicons" name="alarm-outline"></sl-icon>
<sl-icon library="ionicons" name="american-football-outline"></sl-icon>
<sl-icon library="ionicons" name="attach-outline"></sl-icon>
<sl-icon library="ionicons" name="bug-outline"></sl-icon>
<sl-icon library="ionicons" name="chatbubble-outline"></sl-icon>
<sl-icon library="ionicons" name="flask-outline"></sl-icon>
<sl-icon library="ionicons" name="key-outline"></sl-icon>
<sl-icon library="ionicons" name="settings-outline"></sl-icon>
<sl-icon library="ionicons" name="warning-outline"></sl-icon>
<sl-icon library="ionicons" name="wine-outline"></sl-icon>
</div>
<script>
const container = document.querySelector('.icon-custom-ionicons');
const icon = container.querySelector('sl-icon');
icon.registerLibrary(
'ionicons',
name => `https://cdn.jsdelivr.net/npm/ionicons@5.1.2/dist/ionicons/svg/${name}.svg`,
svg => {
svg.setAttribute('fill', 'currentColor');
svg.setAttribute('stroke', 'currentColor');
[...svg.querySelectorAll('.ionicon-fill-none')].map(el => el.setAttribute('fill', 'none'));
[...svg.querySelectorAll('.ionicon-stroke-width')].map(el => el.setAttribute('stroke-width', '32px'));
}
);
</script>
```
### Unicons
The following example registers the <a href="https://iconscout.com/unicons" rel="noopener" target="_blank">Unicons</a> library using the jsDelivr CDN.
```html preview
<div class="icon-custom-unicons" style="font-size: 24px;">
<sl-icon library="unicons" name="bag"></sl-icon>
<sl-icon library="unicons" name="book-alt"></sl-icon>
<sl-icon library="unicons" name="clipboard"></sl-icon>
<sl-icon library="unicons" name="confused"></sl-icon>
<sl-icon library="unicons" name="envelope"></sl-icon>
<sl-icon library="unicons" name="eye"></sl-icon>
<sl-icon library="unicons" name="folder"></sl-icon>
<sl-icon library="unicons" name="heart"></sl-icon>
<sl-icon library="unicons" name="padlock"></sl-icon>
<sl-icon library="unicons" name="rocket"></sl-icon>
</div>
<script>
const container = document.querySelector('.icon-custom-unicons');
const icon = container.querySelector('sl-icon');
icon.registerLibrary(
'unicons',
name => `https://cdn.jsdelivr.net/npm/@iconscout/unicons@3.0.3/svg/line/${name}.svg`,
svg => svg.setAttribute('fill', 'currentColor')
);
</script>
```
<!-- Supporting scripts and styles for the search utility -->
<script>
fetch('/dist/shoelace/icons/icons.json')
.then(res => res.json())

8
src/components.d.ts vendored
Wyświetl plik

@ -481,9 +481,13 @@ export namespace Components {
*/
"name": string;
/**
* Registers a custom icon library.
* Fetches the icon and redraws it. Used internally to handle library registrations.
*/
"registerLibrary": (name: string, getPath: (iconName: string) => string) => Promise<void>;
"redraw": () => Promise<void>;
/**
* Registers a custom icon library. Calling this method will register the library for all icons. You don't need to call it more than once for the same library.
*/
"registerLibrary": (name: string, getPath: (iconName: string) => string, mutate: (svg: SVGElement) => void) => Promise<void>;
/**
* An external URL of an SVG file.
*/

Wyświetl plik

@ -1,13 +1,15 @@
import { Component, Event, EventEmitter, Method, Prop, State, Watch, getAssetPath, h } from '@stencil/core';
import { Component, Element, Event, EventEmitter, Method, Prop, State, Watch, getAssetPath, h } from '@stencil/core';
import { requestIcon } from './request';
interface IconLibrary {
name: string;
getPath: (iconName: string) => string;
mutate?: (svg: SVGElement) => void;
}
const libraries: IconLibrary[] = [];
const parser = new DOMParser();
let connectedIcons: HTMLSlIconElement[] = [];
/**
* @since 2.0
@ -23,6 +25,8 @@ const parser = new DOMParser();
assetsDirs: ['icons']
})
export class Icon {
@Element() host: HTMLSlIconElement;
@State() svg: string;
/** The name of the icon to draw. */
@ -45,28 +49,43 @@ export class Icon {
@Watch('name')
@Watch('src')
@Watch('library')
handleChange() {
this.setIcon();
}
connectedCallback() {
this.handleLibraryRegistration = this.handleLibraryRegistration.bind(this);
connectedIcons.push(this.host);
}
componentDidLoad() {
this.setIcon();
document.addEventListener('slIconLibraryRegistered', this.handleLibraryRegistration);
}
disconnectedCallback() {
document.removeEventListener('slIconLibraryRegistered', this.handleLibraryRegistration);
connectedIcons = connectedIcons.filter(icon => icon !== this.host);
}
/** Registers a custom icon library. */
/**
* Registers a custom icon library. Calling this method will register the library for all icons. You don't need to
* call it more than once for the same library.
*/
@Method()
async registerLibrary(name: string, getPath: (iconName: string) => string) {
libraries.push({ name, getPath });
document.dispatchEvent(new CustomEvent('slIconLibraryRegistered', { detail: { name } }));
async registerLibrary(name: string, getPath: (iconName: string) => string, mutate: (svg: SVGElement) => void) {
libraries.push({ name, getPath, mutate });
// Redraw connected icons
connectedIcons.map(icon => {
if (icon.library === name) {
icon.redraw();
}
});
}
/** Fetches the icon and redraws it. Used internally to handle library registrations. */
@Method()
async redraw() {
this.setIcon();
}
getLabel() {
@ -84,10 +103,10 @@ export class Icon {
}
setIcon() {
const library = this.library ? libraries.filter(lib => lib.name === this.library)[0] : null;
let url = this.src;
if (this.library && this.name) {
const library = libraries.filter(lib => lib.name === this.library)[0];
if (library) {
url = library.getPath(this.name);
} else {
@ -104,6 +123,10 @@ export class Icon {
const doc = parser.parseFromString(source, 'text/html');
const svg = doc.body.querySelector('svg');
if (library && typeof library.mutate === 'function') {
library.mutate(svg);
}
if (svg) {
this.svg = svg.outerHTML;
this.slLoad.emit();
@ -116,12 +139,6 @@ export class Icon {
}
}
handleLibraryRegistration(event: CustomEvent) {
if (event.detail.name === this.library) {
this.setIcon();
}
}
render() {
return <div part="base" class="icon" role="img" aria-label={this.getLabel()} innerHTML={this.svg} />;
}