Add sl-icon-library

pull/261/head
Cory LaViska 2020-10-07 09:34:05 -04:00
rodzic 2578215c28
commit c152f89cce
12 zmienionych plików z 531 dodań i 208 usunięć

Wyświetl plik

@ -23,6 +23,7 @@
- [Form](/components/form.md)
- [Icon](/components/icon.md)
- [Icon Button](/components/icon-button.md)
- [Icon Library](/components/icon-library.md)
- [Image Comparer](/components/image-comparer.md)
- [Input](/components/input.md)
- [Menu](/components/menu.md)

Wyświetl plik

@ -0,0 +1,370 @@
# Icon Library
[component-header:sl-icon-library]
Icon libraries let you register additional icons to use with the `<sl-icon>` component.
An icon library is a renderless component that registers a custom set of SVG icons. The icon files can exist locally or on a CORS-enabled endpoint (i.e. a CDN). There is no limit to how many icon libraries you can register and there is no cost associated with registering them, as individual icons are only requested when they're used.
To register an icon library, create an `<sl-icon-library>` element with a name and resolver function. The resolver function translates an icon name to a URL where its corresponding SVG file exists. Refer to the examples below to better understand how it works.
If necessary, a mutator function can be used to mutate the SVG element before rendering. This is necessary for some libraries due to the many possible ways SVGs are crafted. For example, icons should inherit the current text color via `currentColor`, so you may need to apply `fill="currentColor` or `stroke="currentColor"` to the SVG element using this function.
Here's an example that registers an icon library located in the `/assets/icons` directory.
```html
<!-- Create a library named "my-icons" -->
<sl-icon-library name="my-icons"></sl-icon>
<script>
// Get a reference to the library element
const library = document.querySelector('sl-icon-library[name="my-icons"]');
// Add a resolver function to translate icon names to URLs
library.resolver = name => `/assets/icons/${name}.svg`;
// Apply an optional mutator function to modify the SVG before it renders
library.mutator = svg => svg.setAttribute('fill', 'currentColor');
</script>
```
To display an icon, set the `library` and `name` attributes of an `<sl-icon>` element.
```html
<!-- This will show the icon located at /assets/icons/smile.svg -->
<sl-icon library="my-icons" name="smile"></sl-icon>
```
The location of the icon library in the DOM doesn't matter as long as it's within the `<body>` element. If an icon is used before registration, it will be empty until registration has completed. It's perfectly acceptable to place all `<sl-icon-library>` elements before the `</body>` tag if you prefer to organize them that way.
## Examples
The following examples demonstrate how to register a number of popular, open source icon libraries via CDN. Feel free to adapt the code as you see fit to use your own origin or naming conventions.
### Boxicons
This will register the [Boxicons](https://boxicons.com/) library using the jsDelivr CDN. This library has three variations: regular (`bx-*`), solid (`bxs-*`), and logos (`bxl-*`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Creative Commons 4.0 License](https://github.com/atisawd/boxicons#license).
```html preview
<sl-icon-library name="boxicons"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="boxicons"]');
library.resolver = name => {
let folder = 'regular';
if (name.substring(0, 4) === 'bxs-') folder = 'solid';
if (name.substring(0, 4) === 'bxl-') folder = 'logos';
return `https://cdn.jsdelivr.net/npm/boxicons@2.0.5/svg/${folder}/${name}.svg`;
};
library.mutator = svg => svg.setAttribute('fill', 'currentColor');
</script>
<div style="font-size: 24px;">
<sl-icon library="boxicons" name="bx-bot"></sl-icon>
<sl-icon library="boxicons" name="bx-cookie"></sl-icon>
<sl-icon library="boxicons" name="bx-joystick"></sl-icon>
<sl-icon library="boxicons" name="bx-save"></sl-icon>
<sl-icon library="boxicons" name="bx-server"></sl-icon>
<sl-icon library="boxicons" name="bx-wine"></sl-icon>
<br>
<sl-icon library="boxicons" name="bxs-bot"></sl-icon>
<sl-icon library="boxicons" name="bxs-cookie"></sl-icon>
<sl-icon library="boxicons" name="bxs-joystick"></sl-icon>
<sl-icon library="boxicons" name="bxs-save"></sl-icon>
<sl-icon library="boxicons" name="bxs-server"></sl-icon>
<sl-icon library="boxicons" name="bxs-wine"></sl-icon>
<br>
<sl-icon library="boxicons" name="bxl-apple"></sl-icon>
<sl-icon library="boxicons" name="bxl-chrome"></sl-icon>
<sl-icon library="boxicons" name="bxl-edge"></sl-icon>
<sl-icon library="boxicons" name="bxl-firefox"></sl-icon>
<sl-icon library="boxicons" name="bxl-opera"></sl-icon>
<sl-icon library="boxicons" name="bxl-microsoft"></sl-icon>
</div>
```
### Feather Icons
This will register the [Feather Icons](https://feathericons.com/) library using the jsDelivr CDN.
Icons in this library are licensed under the [MIT License](https://github.com/feathericons/feather/blob/master/LICENSE).
```html preview
<sl-icon-library name="feather"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="feather"]');
library.resolver = name => `https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/icons/${name}.svg`;
</script>
<div style="font-size: 24px;">
<sl-icon library="feather" name="feather"></sl-icon>
<sl-icon library="feather" name="pie-chart"></sl-icon>
<sl-icon library="feather" name="settings"></sl-icon>
<sl-icon library="feather" name="map-pin"></sl-icon>
<sl-icon library="feather" name="printer"></sl-icon>
<sl-icon library="feather" name="shopping-cart"></sl-icon>
</div>
```
### Font Awesome
This will register the [Font Awesome Free](https://fontawesome.com/) library using the jsDelivr CDN. This library has three variations: regular (`far-*`), solid (`fas-*`), and brands (`fab-*`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Font Awesome Free License](https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt). Some of the icons that appear on the Font Awesome website require a license and are therefore not available in the CDN.
```html preview
<sl-icon-library name="fa"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="fa"]');
library.resolver = name => {
const filename = name.replace(/^fa[rbs]-/, '');
let folder = 'regular';
if (name.substring(0, 4) === 'fas-') folder = 'solid';
if (name.substring(0, 4) === 'fab-') folder = 'brands';
return `https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.1/svgs/${folder}/${filename}.svg`;
};
library.mutator = svg => svg.setAttribute('fill', 'currentColor');
</script>
<div style="font-size: 24px;">
<sl-icon library="fa" name="far-bell"></sl-icon>
<sl-icon library="fa" name="far-comment"></sl-icon>
<sl-icon library="fa" name="far-hand-point-right"></sl-icon>
<sl-icon library="fa" name="far-hdd"></sl-icon>
<sl-icon library="fa" name="far-heart"></sl-icon>
<sl-icon library="fa" name="far-star"></sl-icon>
<br>
<sl-icon library="fa" name="fas-archive"></sl-icon>
<sl-icon library="fa" name="fas-book"></sl-icon>
<sl-icon library="fa" name="fas-chess-knight"></sl-icon>
<sl-icon library="fa" name="fas-dice"></sl-icon>
<sl-icon library="fa" name="fas-pizza-slice"></sl-icon>
<sl-icon library="fa" name="fas-scroll"></sl-icon>
<br>
<sl-icon library="fa" name="fab-apple"></sl-icon>
<sl-icon library="fa" name="fab-chrome"></sl-icon>
<sl-icon library="fa" name="fab-edge"></sl-icon>
<sl-icon library="fa" name="fab-firefox"></sl-icon>
<sl-icon library="fa" name="fab-opera"></sl-icon>
<sl-icon library="fa" name="fab-microsoft"></sl-icon>
</div>
```
### Heroicons
This will register the [Heroicons](https://heroicons.com/) library using the jsDelivr CDN.
Icons in this library are licensed under the [MIT License](https://github.com/tailwindlabs/heroicons/blob/master/LICENSE).
```html preview
<sl-icon-library name="heroicons"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="heroicons"]');
library.resolver = name => `https://cdn.jsdelivr.net/npm/heroicons@0.4.2/outline/${name}.svg`;
</script>
<div style="font-size: 24px;">
<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="gift"></sl-icon>
<sl-icon library="heroicons" name="volume-up"></sl-icon>
</div>
```
### Ionicons
This will register the [Ionicons](https://ionicons.com/) library using the jsDelivr CDN. This library has three variations: outline (default), filled (`*-filled`), and sharp (`*-sharp`). A mutator function is required to polyfill a handful of styles we're not including.
Icons in this library are licensed under the [MIT License](https://github.com/ionic-team/ionicons/blob/master/LICENSE).
```html preview
<sl-icon-library name="ionicons"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="ionicons"]');
library.resolver = name => `https://cdn.jsdelivr.net/npm/ionicons@5.1.2/dist/ionicons/svg/${name}.svg`;
library.mutator = 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>
<div style="font-size: 24px;">
<sl-icon library="ionicons" name="alarm"></sl-icon>
<sl-icon library="ionicons" name="american-football"></sl-icon>
<sl-icon library="ionicons" name="bug"></sl-icon>
<sl-icon library="ionicons" name="chatbubble"></sl-icon>
<sl-icon library="ionicons" name="settings"></sl-icon>
<sl-icon library="ionicons" name="warning"></sl-icon>
<br>
<sl-icon library="ionicons" name="alarm-outline"></sl-icon>
<sl-icon library="ionicons" name="american-football-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="settings-outline"></sl-icon>
<sl-icon library="ionicons" name="warning-outline"></sl-icon>
<br>
<sl-icon library="ionicons" name="alarm-sharp"></sl-icon>
<sl-icon library="ionicons" name="american-football-sharp"></sl-icon>
<sl-icon library="ionicons" name="bug-sharp"></sl-icon>
<sl-icon library="ionicons" name="chatbubble-sharp"></sl-icon>
<sl-icon library="ionicons" name="settings-sharp"></sl-icon>
<sl-icon library="ionicons" name="warning-sharp"></sl-icon>
</div>
```
### Jam Icons
This will register the [Jam Icons](https://jam-icons.com/) library using the jsDelivr CDN. This library has two variations: regular (default) and filled (`*-f`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [MIT License](https://github.com/michaelampr/jam/blob/master/LICENSE).
```html preview
<sl-icon-library name="jam"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="jam"]');
library.resolver = name => `https://cdn.jsdelivr.net/npm/jam-icons@2.0.0/svg/${name}.svg`;
library.mutator = svg => svg.setAttribute('fill', 'currentColor');
</script>
<div style="font-size: 24px;">
<sl-icon library="jam" name="calendar"></sl-icon>
<sl-icon library="jam" name="camera"></sl-icon>
<sl-icon library="jam" name="filter"></sl-icon>
<sl-icon library="jam" name="leaf"></sl-icon>
<sl-icon library="jam" name="picture"></sl-icon>
<sl-icon library="jam" name="set-square"></sl-icon>
<br>
<sl-icon library="jam" name="calendar-f"></sl-icon>
<sl-icon library="jam" name="camera-f"></sl-icon>
<sl-icon library="jam" name="filter-f"></sl-icon>
<sl-icon library="jam" name="leaf-f"></sl-icon>
<sl-icon library="jam" name="picture-f"></sl-icon>
<sl-icon library="jam" name="set-square-f"></sl-icon>
</div>
```
### Material Icons
This will register the [Material Icons](https://material.io/resources/icons/?style=baseline) library using the jsDelivr CDN. This library has three variations: outline (default), round (`*_round`), and sharp (`*_sharp`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Apache 2.0 License](https://github.com/google/material-design-icons/blob/master/LICENSE).
```html preview
<sl-icon-library name="material"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="material"]');
library.resolver = name => {
const match = name.match(/^(.*?)(_(round|sharp))?$/);
return `https://cdn.jsdelivr.net/npm/@material-icons/svg@1.0.5/svg/${match[1]}/${match[3] || 'outline'}.svg`;
};
library.mutator = svg => svg.setAttribute('fill', 'currentColor');
</script>
<div style="font-size: 24px;">
<sl-icon library="material" name="notifications"></sl-icon>
<sl-icon library="material" name="email"></sl-icon>
<sl-icon library="material" name="delete"></sl-icon>
<sl-icon library="material" name="volume_up"></sl-icon>
<sl-icon library="material" name="settings"></sl-icon>
<sl-icon library="material" name="shopping_basket"></sl-icon>
<br>
<sl-icon library="material" name="notifications_round"></sl-icon>
<sl-icon library="material" name="email_round"></sl-icon>
<sl-icon library="material" name="delete_round"></sl-icon>
<sl-icon library="material" name="volume_up_round"></sl-icon>
<sl-icon library="material" name="settings_round"></sl-icon>
<sl-icon library="material" name="shopping_basket_round"></sl-icon>
<br>
<sl-icon library="material" name="notifications_sharp"></sl-icon>
<sl-icon library="material" name="email_sharp"></sl-icon>
<sl-icon library="material" name="delete_sharp"></sl-icon>
<sl-icon library="material" name="volume_up_sharp"></sl-icon>
<sl-icon library="material" name="settings_sharp"></sl-icon>
<sl-icon library="material" name="shopping_basket_sharp"></sl-icon>
</div>
```
### Remix Icon
This will register the [Remix Icon](https://remixicon.com/) library using the jsDelivr CDN. This library has two variations: line (default) and fill (`*-fill`). It also groups icons by categories, so the name must include the category and icon separated by a slash. A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Apache 2.0 License](https://github.com/Remix-Design/RemixIcon/blob/master/License).
```html preview
<sl-icon-library name="remixicon"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="remixicon"]');
library.resolver = name => {
const match = name.match(/^(.*?)\/(.*?)(-(fill))?$/);
match[1] = match[1].charAt(0).toUpperCase() + match[1].slice(1);
return `https://cdn.jsdelivr.net/npm/remixicon@2.5.0/icons/${match[1]}/${match[2]}${match[3] || '-line'}.svg`;
};
library.mutator = svg => svg.setAttribute('fill', 'currentColor');
</script>
<div style="font-size: 24px;">
<sl-icon library="remixicon" name="business/cloud"></sl-icon>
<sl-icon library="remixicon" name="design/brush"></sl-icon>
<sl-icon library="remixicon" name="business/pie-chart"></sl-icon>
<sl-icon library="remixicon" name="development/bug"></sl-icon>
<sl-icon library="remixicon" name="media/image"></sl-icon>
<sl-icon library="remixicon" name="system/alert"></sl-icon>
<br>
<sl-icon library="remixicon" name="business/cloud-fill"></sl-icon>
<sl-icon library="remixicon" name="design/brush-fill"></sl-icon>
<sl-icon library="remixicon" name="business/pie-chart-fill"></sl-icon>
<sl-icon library="remixicon" name="development/bug-fill"></sl-icon>
<sl-icon library="remixicon" name="media/image-fill"></sl-icon>
<sl-icon library="remixicon" name="system/alert-fill"></sl-icon>
</div>
```
### Unicons
This will register the [Unicons](https://iconscout.com/unicons) library using the jsDelivr CDN. This library has two variations: line (default) and solid (`*-s`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Apache 2.0 License](https://github.com/Iconscout/unicons/blob/master/LICENSE). Some of the icons that appear on the Unicons website, particularly many of the solid variations, require a license and are therefore not available in the CDN.
```html preview
<sl-icon-library name="unicons"></sl-icon-library>
<script>
const library = document.querySelector('sl-icon-library[name="unicons"]');
library.resolver = name => {
const match = name.match(/^(.*?)(-s)?$/);
return `https://cdn.jsdelivr.net/npm/@iconscout/unicons@3.0.3/svg/${match[2] === '-s' ? 'solid' : 'line'}/${match[1]}.svg`;
};
library.mutator = svg => svg.setAttribute('fill', 'currentColor');
</script>
<div style="font-size: 24px;">
<sl-icon library="unicons" name="clock"></sl-icon>
<sl-icon library="unicons" name="graph-bar"></sl-icon>
<sl-icon library="unicons" name="padlock"></sl-icon>
<sl-icon library="unicons" name="polygon"></sl-icon>
<sl-icon library="unicons" name="rocket"></sl-icon>
<sl-icon library="unicons" name="star"></sl-icon>
<br>
<sl-icon library="unicons" name="clock-s"></sl-icon>
<sl-icon library="unicons" name="graph-bar-s"></sl-icon>
<sl-icon library="unicons" name="padlock-s"></sl-icon>
<sl-icon library="unicons" name="polygon-s"></sl-icon>
<sl-icon library="unicons" name="rocket-s"></sl-icon>
<sl-icon library="unicons" name="star-s"></sl-icon>
</div>
```
[component-metadata:sl-icon-library]

Wyświetl plik

@ -4,7 +4,7 @@
Icons are symbols that can be used to represent various options within an application.
Shoelace comes bundled with over 1,100 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. If you prefer, you can also [register custom libraries](#registering-custom-libraries).
Shoelace comes bundled with over 1,100 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. If you prefer, you can also register [custom icon libraries](/components/icon-library.md).
Click or tap on an icon below to copy its name and use it like this.
@ -56,168 +56,12 @@ Icons are sized relative to the current font size. To change their size, set the
### Custom Icons
Custom icons can be loaded individually with the `src` attribute. Only SVG icons are supported.
Custom icons can be loaded individually with the `src` attribute. Only SVGs on a local or CORS-enabled endpoint are supported. If you're using more than one custom icon, it might make sense to register a [custom icon library](/components/icon-library.md).
```html preview
<sl-icon src="/assets/images/shoe.svg" style="font-size: 8rem;"></sl-icon>
```
## Registering Custom Libraries
You can register custom SVG icon libraries with the `registerIconLibrary()` utility. The import syntax will vary depending on how you're consuming Shoelace.
If you're using the CDN, the import will look like this:
```html
<!-- The script type must be "module" -->
<script type="module">
import { registerIconLibrary } from 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%';
</script>
```
If you're using a bundler such as webpack or Rollup, the import will look like this:
```js
import { registerIconLibrary } from '@shoelace-style/shoelace';
```
Icon libraries can be present locally or on a CORS-enabled CDN. There is no limit to how many libraries you can register and there is no cost associated with registering them, as individual icons are requested only when they're used.
The `registerIconLibrary()` method accepts three arguments: the name of the library, a function that resolves an icon name to a URL, and an optional function that can be used to mutate the SVG element.
Once registered, icons can be displayed using the `library` and `name` attributes.
```html
<script type="module">
import { registerIconLibrary } from 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%';
registerIconLibrary('my-icons', name => `/public/icons/${name}.svg`);
</script>
<!-- Shows the icon located at /public/icons/smile.svg -->
<sl-icon library="my-icons" name="smile"></sl-icon>
```
For your convenience, registration functions for a handful of open source icon libraries are demonstrated below.
### Feather Icons
This example registers the [Feather Icons](https://feathericons.com/) library. The registration function maps the name of the icon to its location on the CDN.
```html preview
<script type="module">
// See above for the correct import to use in your application
import { registerIconLibrary } from '/dist/shoelace/index.esm.js';
registerIconLibrary('feather', name => `https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/icons/${name}.svg`);
</script>
<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>
```
### Heroicons
This example registers the [Heroicons](https://heroicons.com/) library. The registration function maps the name of the icon to its location on the CDN.
```html preview
<script type="module">
// See above for the correct import to use in your application
import { registerIconLibrary } from '/dist/shoelace/index.esm.js';
registerIconLibrary('heroicons', name => `https://cdn.jsdelivr.net/npm/heroicons@0.4.2/outline/${name}.svg`);
</script>
<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>
```
### Ionicons
This example registers the [Ionicons](https://ionicons.com/) library. The registration function maps the name of the icon to its location on the CDN. This library also requires some SVG mutations due to the way it uses a stylesheet that we're not importing.
```html preview
<script type="module">
// See above for the correct import to use in your application
import { registerIconLibrary } from '/dist/shoelace/index.esm.js';
registerIconLibrary(
'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>
<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>
```
### Unicons
This example registers the [Unicons](https://iconscout.com/unicons) library. The registration function maps the name of the icon to its location on the CDN. This library also requires an SVG mutation to set the `fill` to `currentColor`.
```html preview
<script type="module">
// See above for the correct import to use in your application
import { registerIconLibrary } from '/dist/shoelace/index.esm.js';
registerIconLibrary(
'unicons',
name => `https://cdn.jsdelivr.net/npm/@iconscout/unicons@3.0.3/svg/line/${name}.svg`,
svg => svg.setAttribute('fill', 'currentColor')
);
</script>
<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="smile"></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>
```
<!-- Supporting scripts and styles for the search utility -->
<script>
fetch('/dist/shoelace/icons/icons.json')

Wyświetl plik

@ -10,6 +10,8 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
- Added support for dropdowns and non-icon elements to `sl-input`
- Added `spellcheck` prop to `sl-input`
- Added `sl-icon-library` to allow custom icon library registration
- Added `library` prop to `sl-icon` and `sl-icon-button`
- Fixed a bug where `sl-progress-ring` rendered incorrectly when zoomed in Safari [#227](https://github.com/shoelace-style/shoelace/issues/227)
- Fixed a bug where tabbing into slotted elements closes `sl-dropdown` when used in a shadow root [#223](https://github.com/shoelace-style/shoelace/issues/223)
- Fixed a bug where scroll anchoring caused undesirable scrolling when `sl-details` are grouped

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

@ -5,6 +5,7 @@
* It contains typing information for all components that exist in this project.
*/
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { IconLibraryMutator, IconLibraryResolver } from "./components/icon-library/icon-library-registry";
export namespace Components {
interface SlAlert {
/**
@ -473,7 +474,7 @@ export namespace Components {
*/
"label": string;
/**
* The name of a custom registered icon library.
* The name of a registered custom icon library.
*/
"library": string;
/**
@ -496,7 +497,11 @@ export namespace Components {
*/
"label": string;
/**
* The name of the icon to draw. See the icon component for a full list of icons.
* The name of a registered custom icon library.
*/
"library": string;
/**
* The name of the icon to draw.
*/
"name": string;
/**
@ -504,6 +509,20 @@ export namespace Components {
*/
"src": string;
}
interface SlIconLibrary {
/**
* A function that mutates the SVG element before it renders.
*/
"mutator": IconLibraryMutator;
/**
* The name of the icon library.
*/
"name": string;
/**
* A function that translates an icon name to a URL where the corresponding SVG file exists The URL can be local or a CORS-enabled endpoint.
*/
"resolver": IconLibraryResolver;
}
interface SlImageComparer {
/**
* The position of the divider as a percentage.
@ -1255,6 +1274,12 @@ declare global {
prototype: HTMLSlIconButtonElement;
new (): HTMLSlIconButtonElement;
};
interface HTMLSlIconLibraryElement extends Components.SlIconLibrary, HTMLStencilElement {
}
var HTMLSlIconLibraryElement: {
prototype: HTMLSlIconLibraryElement;
new (): HTMLSlIconLibraryElement;
};
interface HTMLSlImageComparerElement extends Components.SlImageComparer, HTMLStencilElement {
}
var HTMLSlImageComparerElement: {
@ -1405,6 +1430,7 @@ declare global {
"sl-format-bytes": HTMLSlFormatBytesElement;
"sl-icon": HTMLSlIconElement;
"sl-icon-button": HTMLSlIconButtonElement;
"sl-icon-library": HTMLSlIconLibraryElement;
"sl-image-comparer": HTMLSlImageComparerElement;
"sl-input": HTMLSlInputElement;
"sl-menu": HTMLSlMenuElement;
@ -1929,7 +1955,7 @@ declare namespace LocalJSX {
*/
"label"?: string;
/**
* The name of a custom registered icon library.
* The name of a registered custom icon library.
*/
"library"?: string;
/**
@ -1959,7 +1985,11 @@ declare namespace LocalJSX {
*/
"label"?: string;
/**
* The name of the icon to draw. See the icon component for a full list of icons.
* The name of a registered custom icon library.
*/
"library"?: string;
/**
* The name of the icon to draw.
*/
"name"?: string;
/**
@ -1967,6 +1997,20 @@ declare namespace LocalJSX {
*/
"src"?: string;
}
interface SlIconLibrary {
/**
* A function that mutates the SVG element before it renders.
*/
"mutator"?: IconLibraryMutator;
/**
* The name of the icon library.
*/
"name"?: string;
/**
* A function that translates an icon name to a URL where the corresponding SVG file exists The URL can be local or a CORS-enabled endpoint.
*/
"resolver"?: IconLibraryResolver;
}
interface SlImageComparer {
/**
* Emitted when the slider position changes.
@ -2624,6 +2668,7 @@ declare namespace LocalJSX {
"sl-format-bytes": SlFormatBytes;
"sl-icon": SlIcon;
"sl-icon-button": SlIconButton;
"sl-icon-library": SlIconLibrary;
"sl-image-comparer": SlImageComparer;
"sl-input": SlInput;
"sl-menu": SlMenu;
@ -2669,6 +2714,7 @@ declare module "@stencil/core" {
"sl-format-bytes": LocalJSX.SlFormatBytes & JSXBase.HTMLAttributes<HTMLSlFormatBytesElement>;
"sl-icon": LocalJSX.SlIcon & JSXBase.HTMLAttributes<HTMLSlIconElement>;
"sl-icon-button": LocalJSX.SlIconButton & JSXBase.HTMLAttributes<HTMLSlIconButtonElement>;
"sl-icon-library": LocalJSX.SlIconLibrary & JSXBase.HTMLAttributes<HTMLSlIconLibraryElement>;
"sl-image-comparer": LocalJSX.SlImageComparer & JSXBase.HTMLAttributes<HTMLSlImageComparerElement>;
"sl-input": LocalJSX.SlInput & JSXBase.HTMLAttributes<HTMLSlInputElement>;
"sl-menu": LocalJSX.SlMenu & JSXBase.HTMLAttributes<HTMLSlMenuElement>;

Wyświetl plik

@ -16,9 +16,12 @@ import { focusVisible } from '../../utilities/focus-visible';
export class IconButton {
button: HTMLButtonElement;
/** The name of the icon to draw. See the icon component for a full list of icons. */
/** The name of the icon to draw. */
@Prop({ reflect: true }) name: string;
/** The name of a registered custom icon library. */
@Prop({ reflect: true }) library: string;
/** An external URL of an SVG file. */
@Prop({ reflect: true }) src: string;
@ -47,7 +50,7 @@ export class IconButton {
}}
type="button"
>
<sl-icon name={this.name} src={this.src} label={this.label} />
<sl-icon library={this.library} name={this.name} src={this.src} label={this.label} />
</button>
);
}

Wyświetl plik

@ -0,0 +1,38 @@
export type IconLibraryResolver = (name: string) => string;
export type IconLibraryMutator = (svg: SVGElement) => void;
interface IconLibraryRegistry {
name: string;
resolver: IconLibraryResolver;
mutator?: IconLibraryMutator;
}
let registry: IconLibraryRegistry[] = [];
let watchedIcons: HTMLSlIconElement[] = [];
export function watchIcon(icon: HTMLSlIconElement) {
watchedIcons.push(icon);
}
export function unwatchIcon(icon: HTMLSlIconElement) {
watchedIcons = watchedIcons.filter(el => el !== icon);
}
export function getLibrary(name?: string) {
return registry.filter(lib => lib.name === name)[0];
}
export function registerLibrary(name: string, resolver: IconLibraryResolver, mutator?: IconLibraryMutator) {
unregisterLibrary(name);
registry.push({ name, resolver, mutator });
// Redraw watched icons
watchedIcons.map(icon => {
if (icon.library === name) {
icon.redraw();
}
});
}
export function unregisterLibrary(name: string) {
registry = registry.filter(lib => lib.name !== name);
}

Wyświetl plik

@ -0,0 +1,3 @@
:host {
display: none;
}

Wyświetl plik

@ -0,0 +1,53 @@
import { Component, Prop, Watch } from '@stencil/core';
import { registerLibrary, unregisterLibrary, IconLibraryResolver, IconLibraryMutator } from './icon-library-registry';
/**
* @since 2.0
* @status stable
*/
@Component({
tag: 'sl-icon-library',
styleUrl: 'icon-library.scss',
shadow: true
})
export class IconLibrary {
/** The name of the icon library. */
@Prop() name: string;
/**
* A function that translates an icon name to a URL where the corresponding SVG file exists The URL can be local or a
* CORS-enabled endpoint.
*/
@Prop() resolver: IconLibraryResolver;
/** A function that mutates the SVG element before it renders. */
@Prop() mutator: IconLibraryMutator;
@Watch('name')
@Watch('resolver')
@Watch('mutator')
handleUpdate() {
// Subsequent registrations with the same name will invalidate existing ones
this.register();
}
connectedCallback() {
if (this.name && this.resolver) {
this.register();
}
}
disconnectedCallback() {
unregisterLibrary(this.name);
}
register() {
const { name, resolver, mutator } = this;
registerLibrary(name, resolver, mutator);
}
render() {
return null;
}
}

Wyświetl plik

@ -1,35 +0,0 @@
interface IconLibrary {
name: string;
getPath: (iconName: string) => string;
mutate?: (svg: SVGElement) => void;
}
const iconLibrary: IconLibrary[] = [];
let watchedIcons: HTMLSlIconElement[] = [];
export function watchIcon(icon: HTMLSlIconElement) {
watchedIcons.push(icon);
}
export function unwatchIcon(icon: HTMLSlIconElement) {
watchedIcons = watchedIcons.filter(el => el !== icon);
}
export function getLibrary(name?: string) {
return iconLibrary.filter(lib => lib.name === name)[0];
}
export function registerLibrary(
name: string,
getPath: (iconName: string) => string,
mutate?: (svg: SVGElement) => void
) {
iconLibrary.push({ name, getPath, mutate });
// Redraw watched icons
watchedIcons.map(icon => {
if (icon.library === name) {
icon.redraw();
}
});
}

Wyświetl plik

@ -1,5 +1,5 @@
import { Component, Element, Event, EventEmitter, Method, Prop, State, Watch, getAssetPath, h } from '@stencil/core';
import { getLibrary, watchIcon, unwatchIcon } from './icon-library';
import { getLibrary, watchIcon, unwatchIcon } from '../icon-library/icon-library-registry';
import { requestIcon } from './request';
const parser = new DOMParser();
@ -31,7 +31,7 @@ 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. */
/** The name of a registered custom icon library. */
@Prop() library: string;
/** Emitted when the icon has loaded. */
@ -85,7 +85,7 @@ export class Icon {
if (this.library && this.name) {
if (library) {
url = library.getPath(this.name);
url = library.resolver(this.name);
} else {
// The library hasn't been registered yet
return;
@ -100,11 +100,11 @@ 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) {
if (library && library.mutator) {
library.mutator(svg);
}
this.svg = svg.outerHTML;
this.slLoad.emit();
} else {

Wyświetl plik

@ -1,3 +1 @@
export { Components, JSX } from './components';
export { registerLibrary as registerIconLibrary } from './components/icon/icon-library';