2018-06-30 01:05:17 +02:00
|
|
|
/* global BUILD */
|
|
|
|
import animationsCss from '../static/css/animations.css';
|
|
|
|
import transformationsCss from '../static/css/transformations.css';
|
|
|
|
|
|
|
|
|
|
|
|
//= ======================================================
|
|
|
|
const CACHE = {}; // iconName: Promise()
|
2018-06-30 14:43:14 +02:00
|
|
|
const CSS_CLASS_PREFIX = 'bx-';
|
2018-06-30 05:33:14 +02:00
|
|
|
const CSS_CLASS_PREFIX_ROTATE = `${CSS_CLASS_PREFIX}rotate-`;
|
|
|
|
const CSS_CLASS_PREFIX_FLIP = `${CSS_CLASS_PREFIX}flip-`;
|
2018-06-30 01:05:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A Custom Element for displaying icon
|
|
|
|
*/
|
|
|
|
export class BoxIconElement extends HTMLElement {
|
|
|
|
static get cdnUrl() {
|
|
|
|
// BUILD.DATA.VERSION is injected by webpack during a build.
|
|
|
|
// Value is same as package.json#version property.
|
|
|
|
return `https://unpkg.com/boxicons@${BUILD.DATA.VERSION}/svg`;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* The html tag name to be use
|
|
|
|
* @type {String}
|
|
|
|
*/
|
|
|
|
static get tagName() { return 'box-icon'; }
|
|
|
|
|
|
|
|
static get observedAttributes() {
|
|
|
|
return [
|
|
|
|
'name',
|
|
|
|
'color',
|
|
|
|
'size',
|
|
|
|
'rotate',
|
|
|
|
'flip',
|
|
|
|
'animation',
|
2018-06-30 05:37:18 +02:00
|
|
|
'shape',
|
2018-06-30 01:05:17 +02:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a promise that should resolve with a string - the svg source.
|
|
|
|
*
|
2018-06-30 14:43:14 +02:00
|
|
|
* @param {String} iconName
|
|
|
|
* The icon name (file name) to the icon that should be loaded.
|
2018-06-30 01:05:17 +02:00
|
|
|
*
|
|
|
|
* @return {Promise<String, Error>}
|
|
|
|
*/
|
2018-06-30 14:43:14 +02:00
|
|
|
static getIconSvg(iconName) {
|
|
|
|
const iconUrl = `${this.cdnUrl}/${iconName}.svg`;
|
2018-06-30 02:12:50 +02:00
|
|
|
if (iconUrl && CACHE[iconUrl]) {
|
|
|
|
return CACHE[iconUrl];
|
|
|
|
}
|
|
|
|
CACHE[iconUrl] = new Promise((resolve, reject) => {
|
|
|
|
const request = new XMLHttpRequest();
|
|
|
|
request.addEventListener('load', function () {
|
|
|
|
if (this.status < 200 || this.status >= 300) {
|
|
|
|
reject(new Error(`${this.status} ${this.responseText}`));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
resolve(this.responseText);
|
|
|
|
});
|
|
|
|
request.onerror = reject;
|
|
|
|
request.onabort = reject;
|
|
|
|
request.open('GET', iconUrl);
|
|
|
|
request.send();
|
|
|
|
});
|
|
|
|
return CACHE[iconUrl];
|
2018-06-30 01:05:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Define (register) the custom element
|
|
|
|
*
|
|
|
|
* @param {String} [tagName=this.tagName]
|
|
|
|
*/
|
|
|
|
static define(tagName) {
|
|
|
|
customElements.define(tagName || this.tagName, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.$ui = this.attachShadow({ mode: 'open' });
|
|
|
|
this.$ui.innerHTML = `
|
|
|
|
<style>
|
|
|
|
:host {
|
|
|
|
display: inline-block;
|
2018-06-30 02:12:50 +02:00
|
|
|
width: 1em;
|
|
|
|
height: 1em;
|
2018-06-30 01:05:17 +02:00
|
|
|
}
|
2018-06-30 02:44:28 +02:00
|
|
|
:host([size=xs]) {
|
|
|
|
width: 0.8rem;
|
|
|
|
height: 0.8rem;
|
|
|
|
}
|
|
|
|
:host([size=sm]) {
|
|
|
|
width: 1.55rem;
|
|
|
|
height: 1.55rem;
|
|
|
|
}
|
|
|
|
:host([size=md]) {
|
|
|
|
width: 2.25rem;
|
|
|
|
height: 2.25rem;
|
|
|
|
}
|
|
|
|
:host([size=lg]) {
|
|
|
|
width: 3.0rem;
|
|
|
|
height: 3.0rem;
|
|
|
|
}
|
2018-06-30 05:37:18 +02:00
|
|
|
:host([shape=square]) {
|
|
|
|
padding: .25em;
|
|
|
|
border: .07em solid rgba(0,0,0,.1);
|
|
|
|
border-radius: .25em;
|
|
|
|
}
|
|
|
|
:host([shape=circle]) {
|
|
|
|
padding: .25em;
|
|
|
|
border: .07em solid rgba(0,0,0,.1);
|
|
|
|
border-radius: 50%;
|
|
|
|
}
|
2018-06-30 01:05:17 +02:00
|
|
|
#icon,
|
|
|
|
svg {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
${animationsCss}
|
|
|
|
${transformationsCss}
|
|
|
|
</style>
|
|
|
|
<div id="icon"></div>`;
|
|
|
|
|
2018-06-30 02:12:50 +02:00
|
|
|
this._state = {
|
|
|
|
$iconHolder: this.$ui.getElementById('icon'),
|
|
|
|
};
|
2018-06-30 01:05:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
attributeChangedCallback(attr, oldVal, newVal) {
|
2018-06-30 14:43:14 +02:00
|
|
|
const $iconHolder = this._state.$iconHolder;
|
2018-06-30 05:33:14 +02:00
|
|
|
|
2018-06-30 02:12:50 +02:00
|
|
|
switch (attr) {
|
|
|
|
case 'name':
|
|
|
|
handleNameChange(this, oldVal, newVal);
|
|
|
|
break;
|
2018-06-30 02:44:28 +02:00
|
|
|
case 'color':
|
2018-06-30 14:43:14 +02:00
|
|
|
$iconHolder.style.fill = newVal || '';
|
2018-06-30 02:44:28 +02:00
|
|
|
break;
|
|
|
|
case 'size':
|
2018-06-30 14:43:14 +02:00
|
|
|
handleSizeChange(this, oldVal, newVal);
|
2018-06-30 02:44:28 +02:00
|
|
|
break;
|
2018-06-30 05:33:14 +02:00
|
|
|
case 'rotate':
|
2018-06-30 14:43:14 +02:00
|
|
|
if (oldVal) {
|
|
|
|
$iconHolder.classList.remove(`${CSS_CLASS_PREFIX_ROTATE}${oldVal}`);
|
|
|
|
}
|
|
|
|
if (newVal) {
|
|
|
|
$iconHolder.classList.add(`${CSS_CLASS_PREFIX_ROTATE}${newVal}`);
|
|
|
|
}
|
2018-06-30 05:33:14 +02:00
|
|
|
break;
|
|
|
|
case 'flip':
|
2018-06-30 14:43:14 +02:00
|
|
|
if (oldVal) {
|
|
|
|
$iconHolder.classList.remove(`${CSS_CLASS_PREFIX_FLIP}${oldVal}`);
|
|
|
|
}
|
|
|
|
if (newVal) {
|
|
|
|
$iconHolder.classList.add(`${CSS_CLASS_PREFIX_FLIP}${newVal}`);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'animation':
|
|
|
|
if (oldVal) {
|
|
|
|
$iconHolder.classList.remove(`${CSS_CLASS_PREFIX}${oldVal}`);
|
|
|
|
}
|
|
|
|
if (newVal) {
|
|
|
|
$iconHolder.classList.add(`${CSS_CLASS_PREFIX}${newVal}`);
|
|
|
|
}
|
2018-06-30 05:33:14 +02:00
|
|
|
break;
|
2018-06-30 02:12:50 +02:00
|
|
|
}
|
2018-06-30 01:05:17 +02:00
|
|
|
}
|
|
|
|
}
|
2018-06-30 02:12:50 +02:00
|
|
|
|
|
|
|
function handleNameChange(inst, oldVal, newVal) {
|
2018-06-30 02:44:28 +02:00
|
|
|
const state = inst._state;
|
|
|
|
state.currentName = newVal;
|
|
|
|
state.$iconHolder.textContent = '';
|
2018-06-30 02:12:50 +02:00
|
|
|
|
|
|
|
if (newVal) {
|
2018-06-30 14:43:14 +02:00
|
|
|
inst.constructor.getIconSvg(newVal)
|
2018-06-30 02:12:50 +02:00
|
|
|
.then((iconData) => {
|
2018-06-30 02:44:28 +02:00
|
|
|
if (state.currentName === newVal) {
|
|
|
|
state.$iconHolder.innerHTML = iconData;
|
2018-06-30 02:12:50 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
2018-06-30 14:43:14 +02:00
|
|
|
console.error(`Failed to load icon: ${newVal + "\n"}${error}`); //eslint-disable-line
|
2018-06-30 02:12:50 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-30 02:44:28 +02:00
|
|
|
function handleSizeChange(inst, oldVal, newVal) {
|
2018-06-30 14:43:14 +02:00
|
|
|
const state = inst._state;
|
2018-06-30 02:44:28 +02:00
|
|
|
|
2018-06-30 14:43:14 +02:00
|
|
|
if (state.size) {
|
|
|
|
state.$iconHolder.style.width = state.$iconHolder.style.height = '';
|
|
|
|
state.size = state.sizeType = null;
|
|
|
|
}
|
2018-06-30 02:44:28 +02:00
|
|
|
|
|
|
|
// If the size is not one of the short-hand ones, then it must be a
|
|
|
|
// css size unit - add it directly to the icon holder.
|
2018-06-30 14:43:14 +02:00
|
|
|
if (newVal && !/^(xs|sm|md|lg)$/.test(state.size)) {
|
|
|
|
state.size = newVal.trim();
|
|
|
|
state.$iconHolder.style.width = state.$iconHolder.style.height = state.size;
|
|
|
|
}
|
2018-06-30 02:44:28 +02:00
|
|
|
}
|
2018-06-30 14:43:14 +02:00
|
|
|
|
|
|
|
export default BoxIconElement;
|