Add system icon library (#420, #422)

* Add system icon library

* fixes #420

* update changelog
pull/434/head
Cory LaViska 2021-04-20 09:37:19 -04:00 zatwierdzone przez GitHub
rodzic 51d48b6aad
commit af601c6e9c
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
19 zmienionych plików z 140 dodań i 22 usunięć

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,300 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. If you prefer, you can also register a [custom icon library](#icon-libraries).
Shoelace comes bundled with over 1,300 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. These icons are part of the `default` icon library. If you prefer, you can register [custom icon libraries](#icon-libraries) as well.
Click or tap on an icon below to copy its name and use it like this.
@ -64,9 +64,11 @@ Custom icons can be loaded individually with the `src` attribute. Only SVGs on a
## Icon Libraries
Shoelace lets you register additional icons to use with the `<sl-icon>` component through icon libraries. The icon files can exist locally or on a CORS-enabled endpoint (e.g. 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.
You can register additional icons to use with the `<sl-icon>` component through icon libraries. Icon files can exist locally or on a CORS-enabled endpoint (e.g. 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, use the `registerIconLibrary()` function that's exported from `utilities/icon-library.js`. At a minimum, you must provide a name and a resolver function. The resolver function translates an icon name to a URL where the corresponding SVG file exists. Refer to the examples below to better understand how it works.
Shoelace ships with two built-in icon libraries, `default` and `system`. The [default icon library](#customizing-the-default-library) contains all of the icons in the Bootstrap Icons project. The [system icon library](#customizing-the-system-library) contains only a small subset of icons that are used internally by Shoelace components.
To register an additional icon library, use the `registerIconLibrary()` function that's exported from `utilities/icon-library.js`. At a minimum, you must provide a name and a resolver function. The resolver function translates an icon name to a URL where the 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 ideally 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.
@ -431,7 +433,7 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
### Customizing the Default Library
Shoelace comes bundled with over 1,300 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. These are the default icons that display when you use `<sl-icon>` without a `name` attribute. If you prefer to have these icons resolve elsewhere, you can register an icon library with the `default` name and a custom resolver.
The default icon library contains over 1,300 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. These are the icons that display when you use `<sl-icon>` without the `library` attribute. If you prefer to have these icons resolve elsewhere or to a different icon library, register an icon library using the `default` name and a custom resolver.
This example will load the same set of icons from the jsDelivr CDN instead of your local assets folder.
@ -445,6 +447,22 @@ This example will load the same set of icons from the jsDelivr CDN instead of yo
</script>
```
### Customizing the System Library
The system library contains only the icons used internally by Shoelace components. Unlike the default icon library, the system library does not rely on physical assets. Instead, its icons are hard-coded as data URIs into the resolver to ensure their availability.
If you want to change the icons Shoelace uses internally, you can register an icon library using the `system` name and a custom resolver. If you choose to do this, it's your responsibility to provide all of the icons that are required by components. You can reference `src/components/library.system.ts` for a complete list of system icons used by Shoelace.
```html
<script type="module">
import { registerIconLibrary } from '/shoelace/dist/utilities/icon-library.js';
registerIconLibrary('system', {
resolver: name => `/path/to/custom/icons/${name}.svg`
});
</script>
```
<!-- Supporting scripts and styles for the search utility -->
<script>
fetch('/dist/assets/icons/icons.json')

Wyświetl plik

@ -6,6 +6,10 @@ Components with the <sl-badge type="warning" pill>Experimental</sl-badge> badge
_During the beta period, these restrictions may be relaxed in the event of a mission-critical bug._ 🐛
## Next
- Added the `system` icon library and updated all components to use this instead of the default icon library [#420](https://github.com/shoelace-style/shoelace/issues/420)
## 2.0.0-beta.38
- 🚨 BREAKING: `sl-radio` components must be located inside an `sl-radio-group` for proper accessibility [#218](https://github.com/shoelace-style/shoelace/issues/218)

Wyświetl plik

@ -208,6 +208,7 @@ export default class SlAlert extends LitElement {
<sl-icon-button
exportparts="base:close-button"
name="x"
library="system"
@click=${this.handleCloseClick.bind(this)}
></sl-icon-button>
</span>

Wyświetl plik

@ -51,7 +51,7 @@ export default class SlAvatar extends LitElement {
: html`
<div part="icon" class="avatar__icon">
<slot name="icon">
<sl-icon name="person-fill"></sl-icon>
<sl-icon name="person-fill" library="system"></sl-icon>
</slot>
</div>
`}

Wyświetl plik

@ -704,6 +704,7 @@ export default class SlColorPicker extends LitElement {
>
<sl-icon
name="check"
library="system"
class=${classMap({
'color-picker__copy-feedback': true,
'color-picker__copy-feedback--visible': this.showCopyFeedback,

Wyświetl plik

@ -194,7 +194,7 @@ export default class SlDetails extends LitElement {
</div>
<span part="summary-icon" class="details__summary-icon">
<sl-icon name="chevron-right"></sl-icon>
<sl-icon name="chevron-right" library="system"></sl-icon>
</span>
</header>

Wyświetl plik

@ -251,6 +251,7 @@ export default class SlDialog extends LitElement {
exportparts="base:close-button"
class="dialog__close"
name="x"
library="system"
@click="${this.handleCloseClick}"
></sl-icon-button>
</header>

Wyświetl plik

@ -267,6 +267,7 @@ export default class SlDrawer extends LitElement {
exportparts="base:close-button"
class="drawer__close"
name="x"
library="system"
@click=${this.handleCloseClick}
></sl-icon-button>
</header>

Wyświetl plik

@ -0,0 +1,9 @@
import { getBasePath } from '../../utilities/base-path';
import type { IconLibrary } from './library';
const library: IconLibrary = {
name: 'default',
resolver: name => `${getBasePath()}/assets/icons/${name}.svg`
};
export default library;

Wyświetl plik

@ -0,0 +1,83 @@
import type { IconLibrary } from './library';
//
// System icons are a separate library to ensure they're always available, regardless of how the default icon library is
// configured or if its icons resolve properly.
//
// All Shoelace components must use the system library instead of the default library. For visual consistency, system
// icons are a subset of Bootstrap Icons.
//
const icons = {
check: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check" viewBox="0 0 16 16">
<path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z"/>
</svg>
`,
'chevron-down': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>
</svg>
`,
'chevron-left': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>
</svg>
`,
'chevron-right': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"/>
</svg>
`,
eye: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
</svg>
`,
'eye-slash': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye-slash" viewBox="0 0 16 16">
<path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/>
<path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/>
<path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12-.708.708z"/>
</svg>
`,
'grip-vertical': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-grip-vertical" viewBox="0 0 16 16">
<path d="M7 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zM7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>
`,
'person-fill': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-fill" viewBox="0 0 16 16">
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>
</svg>
`,
'star-fill': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
</svg>
`,
x: `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16">
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
</svg>
`,
'x-circle': `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-circle" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
</svg>
`
};
const systemLibrary: IconLibrary = {
name: 'system',
resolver: (name: keyof typeof icons) => {
if (icons[name]) {
return `data:image/svg+xml,${encodeURIComponent(icons[name])}`;
} else {
return '';
}
}
};
export default systemLibrary;

Wyświetl plik

@ -1,21 +1,16 @@
import { SlIcon } from '../../shoelace';
import { getBasePath } from '../../utilities/base-path';
import defaultLibrary from './library.default';
import systemLibrary from './library.system';
export type IconLibraryResolver = (name: string) => string;
export type IconLibraryMutator = (svg: SVGElement) => void;
interface IconLibraryRegistry {
export interface IconLibrary {
name: string;
resolver: IconLibraryResolver;
mutator?: IconLibraryMutator;
}
let registry: IconLibraryRegistry[] = [
{
name: 'default',
resolver: name => `${getBasePath()}/assets/icons/${name}.svg`
}
];
let registry: IconLibrary[] = [defaultLibrary, systemLibrary];
let watchedIcons: SlIcon[] = [];
export function watchIcon(icon: SlIcon) {

Wyświetl plik

@ -128,7 +128,7 @@ export default class SlImageComparer extends LitElement {
tabindex="0"
>
<slot name="handle-icon">
<sl-icon class="image-comparer__handle-icon" name="grip-vertical"></sl-icon>
<sl-icon class="image-comparer__handle-icon" name="grip-vertical" library="system"></sl-icon>
</slot>
</div>
</div>

Wyświetl plik

@ -347,7 +347,7 @@ export default class SlInput extends LitElement {
tabindex="-1"
>
<slot name="clear-icon">
<sl-icon name="x-circle"></sl-icon>
<sl-icon name="x-circle" library="system"></sl-icon>
</slot>
</button>
`
@ -364,13 +364,13 @@ export default class SlInput extends LitElement {
${this.isPasswordVisible
? html`
<slot name="show-password-icon">
<sl-icon name="eye-slash"></sl-icon>
<sl-icon name="eye-slash" library="system"></sl-icon>
</slot>
`
: html`
<slot name="hide-password-icon">
${' '}
<sl-icon name="eye"></sl-icon>
<sl-icon name="eye" library="system"></sl-icon>
</slot>
`}
</button>

Wyświetl plik

@ -83,7 +83,7 @@ export default class SlMenuItem extends LitElement {
@mouseleave=${this.handleMouseLeave}
>
<span part="checked-icon" class="menu-item__check">
<sl-icon name="check" aria-hidden="true"></sl-icon>
<sl-icon name="check" library="system" aria-hidden="true"></sl-icon>
</span>
<span part="prefix" class="menu-item__prefix">

Wyświetl plik

@ -42,7 +42,7 @@ export default class SlRating extends LitElement {
/** The name of the icon to display as the symbol. */
// @ts-ignore
@property() getSymbol = (value?: number) => '<sl-icon name="star-fill"></sl-icon>';
@property() getSymbol = (value?: number) => '<sl-icon name="star-fill" library="system"></sl-icon>';
/** Emitted when the rating's value changes. */
@event('sl-change') slChange: EventEmitter<void>;

Wyświetl plik

@ -452,6 +452,7 @@ export default class SlSelect extends LitElement {
exportparts="base:clear-button"
class="select__clear"
name="x-circle"
library="system"
@click=${this.handleClearClick}
tabindex="-1"
></sl-icon-button>
@ -459,7 +460,7 @@ export default class SlSelect extends LitElement {
: ''}
<span part="icon" class="select__icon" aria-hidden="true">
<sl-icon name="chevron-down"></sl-icon>
<sl-icon name="chevron-down" library="system"></sl-icon>
</span>
<!-- The hidden input tricks the browser's built-in validation so it works as expected. We use an input

Wyświetl plik

@ -344,6 +344,7 @@ export default class SlTabGroup extends LitElement {
class="tab-group__scroll-button tab-group__scroll-button--left"
exportparts="base:scroll-button"
name="chevron-left"
library="system"
@click=${this.handleScrollLeft}
></sl-icon-button>
`
@ -362,6 +363,7 @@ export default class SlTabGroup extends LitElement {
class="tab-group__scroll-button tab-group__scroll-button--right"
exportparts="base:scroll-button"
name="chevron-right"
library="system"
@click=${this.handleScrollRight}
></sl-icon-button>
`

Wyświetl plik

@ -77,6 +77,7 @@ export default class SlTab extends LitElement {
? html`
<sl-icon-button
name="x"
library="system"
exportparts="base:close-button"
class="tab__close-button"
@click=${this.handleCloseClick}

Wyświetl plik

@ -73,6 +73,7 @@ export default class SlTag extends LitElement {
<sl-icon-button
exportparts="base:clear-button"
name="x"
library="system"
class="tag__clear"
@click=${this.handleClearClick}
></sl-icon-button>