lion/packages/icon/src/LionIcon.js

119 lines
2.5 KiB
JavaScript

import { html, css, render, unsafeHTML, until } from '@lion/core';
import { LionLitElement } from '@lion/core/src/LionLitElement.js';
const isDefinedPromise = action => typeof action === 'object' && Promise.resolve(action) === action;
/**
* Custom element for rendering SVG icons
* @polymerElement
*/
export class LionIcon extends LionLitElement {
static get properties() {
return {
svg: {
type: String,
},
role: {
type: String,
attribute: 'role',
reflect: true,
},
ariaLabel: {
type: String,
attribute: 'aria-label',
reflect: true,
},
};
}
static get styles() {
return [
css`
:host {
box-sizing: border-box;
display: inline-block;
width: 1em;
height: 1em;
}
:host:first-child {
margin-left: 0;
}
:host:last-child {
margin-right: 0;
}
::slotted(svg) {
display: block;
width: 100%;
height: 100%;
}
`,
];
}
constructor() {
super();
this.role = 'img';
}
update(changedProperties) {
super.update(changedProperties);
if (changedProperties.has('svg')) {
if (isDefinedPromise(this.svg)) {
this._setDynamicSvg();
} else {
this._setSvg();
}
}
if (changedProperties.has('ariaLabel')) {
this._onLabelChanged(changedProperties);
}
}
render() {
return html`
<slot></slot>
`;
}
connectedCallback() {
// ensures that aria-hidden is set if there is no aria-label attribute
this._onLabelChanged();
super.connectedCallback();
}
/**
* On IE11, svgs without focusable false appear in the tab order
* so make sure to have <svg focusable="false"> in svg files
*/
_setSvg() {
this.innerHTML = this.svg;
}
// TODO: find a better way to render dynamic icons without the need for unsafeHTML
_setDynamicSvg() {
const template = html`
${until(
this.svg.then(_svg => {
// If the export was not made explicit, take the default
if (typeof _svg !== 'string') {
return unsafeHTML(_svg.default);
}
return unsafeHTML(_svg);
}),
)}
`;
render(template, this);
}
_onLabelChanged() {
if (this.ariaLabel) {
this.setAttribute('aria-hidden', 'false');
} else {
this.setAttribute('aria-hidden', 'true');
this.removeAttribute('aria-label');
}
}
}