diff --git a/packages/icon/README.md b/packages/icon/README.md
index b9acb2712..ea02c1a11 100644
--- a/packages/icon/README.md
+++ b/packages/icon/README.md
@@ -32,6 +32,19 @@ Use it in your lit-html template:
```
+### Icon format
+
+Icon file is an ES module with an extension `.svg.js` which exports a function like this:
+
+```js
+// bug.svg.js
+export default tag => tag`
+
+`;
+```
+
+Make sure you have `focusable="false"` in the icon file to prevent bugs in IE/Edge when the icon appears in tab-order.
+
### Accessibiltiy
You may add an `aria-label` to provide information to visually impaired users:
diff --git a/packages/icon/src/LionIcon.js b/packages/icon/src/LionIcon.js
index 1d492511a..200a60460 100644
--- a/packages/icon/src/LionIcon.js
+++ b/packages/icon/src/LionIcon.js
@@ -1,4 +1,4 @@
-import { html, css, LitElement } from '@lion/core';
+import { html, nothing, TemplateResult, css, render, LitElement } from '@lion/core';
const isPromise = action => typeof action === 'object' && Promise.resolve(action) === action;
@@ -11,7 +11,7 @@ export class LionIcon extends LitElement {
return {
// svg is a property to ensure the setter is called if the property is set before upgrading
svg: {
- type: String,
+ type: Object,
},
role: {
type: String,
@@ -84,17 +84,17 @@ export class LionIcon extends LitElement {
set svg(svg) {
this.__svg = svg;
if (svg === undefined) {
- this._renderSvg('');
+ this._renderSvg(nothing);
} else if (isPromise(svg)) {
- this._renderSvg(''); // show nothing before resolved
+ this._renderSvg(nothing); // show nothing before resolved
svg.then(resolvedSvg => {
// render only if it is still the same and was not replaced after loading started
if (svg === this.__svg) {
- this._renderSvg(resolvedSvg);
+ this._renderSvg(this.constructor.__unwrapSvg(resolvedSvg));
}
});
} else {
- this._renderSvg(svg);
+ this._renderSvg(this.constructor.__unwrapSvg(svg));
}
}
@@ -111,8 +111,22 @@ export class LionIcon extends LitElement {
}
}
- _renderSvg(svgOrModule) {
- const svg = svgOrModule && svgOrModule.default ? svgOrModule.default : svgOrModule;
- this.innerHTML = svg;
+ _renderSvg(svgObject) {
+ this.constructor.__validateSvg(svgObject);
+ render(svgObject, this);
+ }
+
+ static __unwrapSvg(wrappedSvgObject) {
+ const svgObject =
+ wrappedSvgObject && wrappedSvgObject.default ? wrappedSvgObject.default : wrappedSvgObject;
+ return typeof svgObject === 'function' ? svgObject(html) : svgObject;
+ }
+
+ static __validateSvg(svg) {
+ if (!(svg === nothing || svg instanceof TemplateResult)) {
+ throw new Error(
+ 'icon accepts only lit-html templates or functions like "tag => tag``"',
+ );
+ }
}
}
diff --git a/packages/icon/stories/icons/bugs/bug01.svg.js b/packages/icon/stories/icons/bugs/bug01.svg.js
index c57d889b2..db8f6cde2 100644
--- a/packages/icon/stories/icons/bugs/bug01.svg.js
+++ b/packages/icon/stories/icons/bugs/bug01.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/bugs/bug02.svg.js b/packages/icon/stories/icons/bugs/bug02.svg.js
index 5211c1e8f..e8c81e7b2 100644
--- a/packages/icon/stories/icons/bugs/bug02.svg.js
+++ b/packages/icon/stories/icons/bugs/bug02.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/bugs/bug05.svg.js b/packages/icon/stories/icons/bugs/bug05.svg.js
index 33fe059b4..b9272d231 100644
--- a/packages/icon/stories/icons/bugs/bug05.svg.js
+++ b/packages/icon/stories/icons/bugs/bug05.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/bugs/bug06.svg.js b/packages/icon/stories/icons/bugs/bug06.svg.js
index 8d5caf285..ba57ae18d 100644
--- a/packages/icon/stories/icons/bugs/bug06.svg.js
+++ b/packages/icon/stories/icons/bugs/bug06.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/bugs/bug08.svg.js b/packages/icon/stories/icons/bugs/bug08.svg.js
index d2c7c504e..dd2f9073c 100644
--- a/packages/icon/stories/icons/bugs/bug08.svg.js
+++ b/packages/icon/stories/icons/bugs/bug08.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/bugs/bug12.svg.js b/packages/icon/stories/icons/bugs/bug12.svg.js
index 9a42c96c2..7f0679de4 100644
--- a/packages/icon/stories/icons/bugs/bug12.svg.js
+++ b/packages/icon/stories/icons/bugs/bug12.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/bugs/bug19.svg.js b/packages/icon/stories/icons/bugs/bug19.svg.js
index 832aebafa..ec4055a35 100644
--- a/packages/icon/stories/icons/bugs/bug19.svg.js
+++ b/packages/icon/stories/icons/bugs/bug19.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/bugs/bug23.svg.js b/packages/icon/stories/icons/bugs/bug23.svg.js
index 330716eaa..0c76bdf37 100644
--- a/packages/icon/stories/icons/bugs/bug23.svg.js
+++ b/packages/icon/stories/icons/bugs/bug23.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/bugs/bug24.svg.js b/packages/icon/stories/icons/bugs/bug24.svg.js
index 7e77f6b9b..b604f065a 100644
--- a/packages/icon/stories/icons/bugs/bug24.svg.js
+++ b/packages/icon/stories/icons/bugs/bug24.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/aliens-spaceship.svg.js b/packages/icon/stories/icons/space/aliens-spaceship.svg.js
index a6cd30a53..9438a9317 100644
--- a/packages/icon/stories/icons/space/aliens-spaceship.svg.js
+++ b/packages/icon/stories/icons/space/aliens-spaceship.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/meteor.svg.js b/packages/icon/stories/icons/space/meteor.svg.js
index 40770e093..197133816 100644
--- a/packages/icon/stories/icons/space/meteor.svg.js
+++ b/packages/icon/stories/icons/space/meteor.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/moon-flag.svg.js b/packages/icon/stories/icons/space/moon-flag.svg.js
index 2be77c6b9..9283c4010 100644
--- a/packages/icon/stories/icons/space/moon-flag.svg.js
+++ b/packages/icon/stories/icons/space/moon-flag.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/moon.svg.js b/packages/icon/stories/icons/space/moon.svg.js
index ac5cf1c1d..dbfb92b1c 100644
--- a/packages/icon/stories/icons/space/moon.svg.js
+++ b/packages/icon/stories/icons/space/moon.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/night.svg.js b/packages/icon/stories/icons/space/night.svg.js
index 8528f3dc2..ba258dac1 100644
--- a/packages/icon/stories/icons/space/night.svg.js
+++ b/packages/icon/stories/icons/space/night.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/orbit.svg.js b/packages/icon/stories/icons/space/orbit.svg.js
index 9819d763f..e3f26ebb0 100644
--- a/packages/icon/stories/icons/space/orbit.svg.js
+++ b/packages/icon/stories/icons/space/orbit.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/planet.svg.js b/packages/icon/stories/icons/space/planet.svg.js
index 2364e9af8..2d0283f43 100644
--- a/packages/icon/stories/icons/space/planet.svg.js
+++ b/packages/icon/stories/icons/space/planet.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/robot.svg.js b/packages/icon/stories/icons/space/robot.svg.js
index fa6609620..73dd887fd 100644
--- a/packages/icon/stories/icons/space/robot.svg.js
+++ b/packages/icon/stories/icons/space/robot.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/rocket.svg.js b/packages/icon/stories/icons/space/rocket.svg.js
index 68dae39d7..6d7a1fdc6 100644
--- a/packages/icon/stories/icons/space/rocket.svg.js
+++ b/packages/icon/stories/icons/space/rocket.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/satellite.svg.js b/packages/icon/stories/icons/space/satellite.svg.js
index 0291c2f02..363059924 100644
--- a/packages/icon/stories/icons/space/satellite.svg.js
+++ b/packages/icon/stories/icons/space/satellite.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/signal.svg.js b/packages/icon/stories/icons/space/signal.svg.js
index e7e1dbb6f..8613b0e1f 100644
--- a/packages/icon/stories/icons/space/signal.svg.js
+++ b/packages/icon/stories/icons/space/signal.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/space-helmet.svg.js b/packages/icon/stories/icons/space/space-helmet.svg.js
index 45300e92f..4b7b539ef 100644
--- a/packages/icon/stories/icons/space/space-helmet.svg.js
+++ b/packages/icon/stories/icons/space/space-helmet.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/sun.svg.js b/packages/icon/stories/icons/space/sun.svg.js
index 134f315a6..11a341845 100644
--- a/packages/icon/stories/icons/space/sun.svg.js
+++ b/packages/icon/stories/icons/space/sun.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/stories/icons/space/telescope.svg.js b/packages/icon/stories/icons/space/telescope.svg.js
index 498c6f8b6..4fdffb02c 100644
--- a/packages/icon/stories/icons/space/telescope.svg.js
+++ b/packages/icon/stories/icons/space/telescope.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/test/hammer.svg.js b/packages/icon/test/hammer.svg.js
index aa6130703..1d909b91e 100644
--- a/packages/icon/test/hammer.svg.js
+++ b/packages/icon/test/hammer.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/test/heart.svg.js b/packages/icon/test/heart.svg.js
index 05f2b801a..0272044f0 100644
--- a/packages/icon/test/heart.svg.js
+++ b/packages/icon/test/heart.svg.js
@@ -1 +1,2 @@
-export default '';
+export default tag =>
+ tag``;
diff --git a/packages/icon/test/lion-icon.test.js b/packages/icon/test/lion-icon.test.js
index 675c4002b..316c4db9b 100644
--- a/packages/icon/test/lion-icon.test.js
+++ b/packages/icon/test/lion-icon.test.js
@@ -6,6 +6,47 @@ import hammerSvg from './hammer.svg.js';
import '../lion-icon.js';
describe('lion-icon', () => {
+ it('supports svg icon as a function which recieves a tag function as an argument and returns a tagged template literal', async () => {
+ const iconFunction = tag => tag``;
+ const el = await fixture(
+ html`
+
+ `,
+ );
+ expect(el.children[0].getAttribute('data-test-id')).to.equal('svg');
+ });
+
+ it('supports svg icon as a lit-html template', async () => {
+ const icon = html`
+
+ `;
+ const el = await fixture(
+ html`
+
+ `,
+ );
+ expect(el.children[0].getAttribute('data-test-id')).to.equal('svg');
+ });
+
+ it('does not support string svg icon', async () => {
+ const errorMessage =
+ 'icon accepts only lit-html templates or functions like "tag => tag``"';
+ expect(() => {
+ fixtureSync(
+ html`
+ '}>
+ `,
+ );
+ }).to.throw(Error, errorMessage);
+ expect(() => {
+ fixtureSync(
+ html`
+ ''}>
+ `,
+ );
+ }).to.throw(Error, errorMessage);
+ });
+
it('displays an svg icon with an aria label attribute', async () => {
const el = await fixture(
html`
@@ -135,7 +176,7 @@ describe('lion-icon', () => {
dispatchEvent(new CustomEvent('importDone'));
return e.default;
}),
- '',
+ html``,
)}
aria-label="Love"
>
@@ -159,7 +200,7 @@ describe('lion-icon', () => {
await el.updateComplete;
el.svg = undefined;
await el.updateComplete;
- expect(el.innerHTML).to.equal('');
+ expect(el.innerHTML).to.equal(''); // don't use lightDom.to.equal(''), it gives false positives
});
describe('race conditions with dynamic promisified icons', () => {