@forter/icon
Advanced tools
Comparing version 2.0.1 to 2.0.2
31
cache.js
@@ -0,5 +1,8 @@ | ||
import isObject from 'crocks/predicates/isObject'; | ||
/** @typedef {import('lit-html').SVGTemplateResult} Icon */ | ||
/** @typedef {import('./FcIcon').FcIcon} Instance */ | ||
const isMap = x => x instanceof Map; | ||
const DEFAULT_ICON = '__FC_ICON_DEFAULT__'; | ||
/** | ||
@@ -9,2 +12,3 @@ * Map of instances of the component | ||
*/ | ||
const instances = new Map(); | ||
@@ -16,11 +20,22 @@ /** | ||
let cache = new Map(); | ||
let cache = new Map([[DEFAULT_ICON, '']]); | ||
/** | ||
* Empties the canonical cache and replaces it | ||
* with the contents of the passed cache | ||
* @param {Map<String, Icon>} iconCache new icon cache | ||
* @param {Map<String, Icon>} cacheToRegister new icon cache | ||
* @return {Map<String, Icon>} cache | ||
*/ | ||
function registerIconCache(iconCache) { | ||
function registerIconCache(cacheToRegister) { | ||
if (!isMap(cacheToRegister)) { | ||
if (!isObject(cacheToRegister)) { | ||
throw new TypeError('registerIconCache: Map or Object expected'); | ||
} else { | ||
cacheToRegister = new Map(Object.entries(cacheToRegister)); | ||
} | ||
} | ||
if (!cacheToRegister.has(DEFAULT_ICON)) { | ||
cacheToRegister.set(DEFAULT_ICON, ''); | ||
} | ||
/** | ||
@@ -30,2 +45,4 @@ * Updates and instance' cache | ||
*/ | ||
const updateInstanceCache = instance => { | ||
@@ -35,3 +52,3 @@ const { | ||
} = instance; | ||
instance.cache = iconCache; | ||
instance.cache = cacheToRegister; | ||
instance.requestUpdate('cache', oldCache); | ||
@@ -41,3 +58,3 @@ }; // Sets the canonical cache reference to the passed map. | ||
cache = iconCache; // Requests each instance to update it's cache version. | ||
cache = cacheToRegister; // Requests each instance to update it's cache version. | ||
@@ -48,3 +65,3 @@ [...instances.keys()].map(updateInstanceCache); | ||
export { cache, instances, registerIconCache }; | ||
export { DEFAULT_ICON, cache, instances, registerIconCache }; | ||
//# sourceMappingURL=cache.js.map |
@@ -6,2 +6,13 @@ # Change Log | ||
## [2.0.2](https://github.com/forter/web-components/compare/@forter/icon@2.0.1...@forter/icon@2.0.2) (2019-07-17) | ||
### Bug Fixes | ||
* **icon:** show default icon (defaults to blank) when icon is not found ([74c875d](https://github.com/forter/web-components/commit/74c875d)) | ||
## 2.0.1 (2019-07-11) | ||
@@ -8,0 +19,0 @@ |
import { decorate as _decorate, get as _get, getPrototypeOf as _getPrototypeOf } from './_virtual/_rollupPluginBabelHelpers.js'; | ||
import { IsSlottedMixin } from '@forter/helpers/mixins/is-slotted-mixin'; | ||
import { translate } from '@forter/directives'; | ||
import { LitElement, property, html } from 'lit-element'; | ||
import { getPxString as getPxString$1 } from '@forter/helpers/functions/get-px-string'; | ||
import constant from 'crocks/combinators/constant'; | ||
import { LitElement, property, html } from 'lit-element'; | ||
import { styleMap } from 'lit-html/directives/style-map'; | ||
import { translate } from '@forter/directives'; | ||
import { until } from 'lit-html/directives/until'; | ||
import constant from 'crocks/combinators/constant'; | ||
import { cache, DEFAULT_ICON, instances } from './cache.js'; | ||
import { FcIconSizeStyle } from './fc-icon-size-style.css.js'; | ||
import { cache, instances } from './cache.js'; | ||
import FALLBACK_ICON from './icons/forter.svg.js'; | ||
import style from './fc-icon.css.js'; | ||
const isMap = x => x instanceof Map; | ||
const getDefaultExport = module => module.default; | ||
@@ -92,2 +93,13 @@ | ||
decorators: [property({ | ||
type: String | ||
})], | ||
key: "fallbackIcon", | ||
value() { | ||
return DEFAULT_ICON; | ||
} | ||
}, { | ||
kind: "field", | ||
decorators: [property({ | ||
type: String, | ||
@@ -168,2 +180,7 @@ attribute: 'icon' | ||
/** | ||
* The fallback icon key for the instance | ||
* @type {String} | ||
*/ | ||
/** | ||
* The icon key. Used to lookup icon in the cache. Falls back to 'forter' whenever an icon is not found. | ||
@@ -291,3 +308,3 @@ * @type {String} | ||
})}"> | ||
${until(this.getIcon(icon), FALLBACK_ICON)} | ||
${until(this.getIcon(icon), '')} | ||
</div> | ||
@@ -327,3 +344,3 @@ </div> | ||
value: function getIcon(key) { | ||
return this.cache.has(key) ? this.cache.get(key) : import(`./icons/${key}.svg.js`).then(getDefaultExport).then(this.cacheIcon.bind(this, key)).catch(constant(FALLBACK_ICON)); | ||
return !isMap(this.cache) ? '' : this.cache.has(key) ? this.cache.get(key) : import(`./icons/${key}.svg.js`).then(getDefaultExport).then(this.cacheIcon.bind(this, key)).catch(constant(this.cache.get(DEFAULT_ICON) || '')); | ||
} | ||
@@ -330,0 +347,0 @@ /** |
@@ -1,3 +0,2 @@ | ||
export { cache, instances, registerIconCache } from './cache.js'; | ||
export { default as forter } from './icons/forter.svg.js'; | ||
export { DEFAULT_ICON, cache, instances, registerIconCache } from './cache.js'; | ||
import './fc-icon.js'; | ||
@@ -17,2 +16,3 @@ export { default as addNoCircle } from './icons/add-no-circle.svg.js'; | ||
export { default as f2f } from './icons/f2f.svg.js'; | ||
export { default as forter } from './icons/forter.svg.js'; | ||
export { default as group } from './icons/group.svg.js'; | ||
@@ -19,0 +19,0 @@ export { default as microphone } from './icons/microphone.svg.js'; |
{ | ||
"name": "@forter/icon", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"description": "Icon Component from Forter Components", | ||
@@ -50,3 +50,3 @@ "main": "index.js", | ||
}, | ||
"gitHead": "baa864219456b6d832923e4779b36543c4fa78a2" | ||
"gitHead": "126eb8f2b90b20ffc5503b10f238b8dda91f49ec" | ||
} |
/** @typedef {import('lit-html').SVGTemplateResult} Icon */ | ||
/** @typedef {import('./FcIcon').FcIcon} Instance */ | ||
import isObject from 'crocks/predicates/isObject'; | ||
const isMap = x => x instanceof Map; | ||
export const DEFAULT_ICON = '__FC_ICON_DEFAULT__'; | ||
/** | ||
@@ -14,3 +20,3 @@ * Map of instances of the component | ||
*/ | ||
export let cache = new Map(); | ||
export let cache = new Map([[DEFAULT_ICON, '']]); | ||
@@ -20,6 +26,18 @@ /** | ||
* with the contents of the passed cache | ||
* @param {Map<String, Icon>} iconCache new icon cache | ||
* @param {Map<String, Icon>} cacheToRegister new icon cache | ||
* @return {Map<String, Icon>} cache | ||
*/ | ||
export function registerIconCache(iconCache) { | ||
export function registerIconCache(cacheToRegister) { | ||
if (!isMap(cacheToRegister)) { | ||
if (!isObject(cacheToRegister)) { | ||
throw new TypeError('registerIconCache: Map or Object expected'); | ||
} else { | ||
cacheToRegister = new Map(Object.entries(cacheToRegister)); | ||
} | ||
} | ||
if (!cacheToRegister.has(DEFAULT_ICON)) { | ||
cacheToRegister.set(DEFAULT_ICON, ''); | ||
} | ||
/** | ||
@@ -31,3 +49,3 @@ * Updates and instance' cache | ||
const { cache: oldCache } = instance; | ||
instance.cache = iconCache; | ||
instance.cache = cacheToRegister; | ||
instance.requestUpdate('cache', oldCache); | ||
@@ -37,3 +55,3 @@ }; | ||
// Sets the canonical cache reference to the passed map. | ||
cache = iconCache; | ||
cache = cacheToRegister; | ||
@@ -40,0 +58,0 @@ // Requests each instance to update it's cache version. |
@@ -1,44 +0,93 @@ | ||
import { expect, fixture, defineCE } from '@open-wc/testing'; | ||
import { aTimeout, expect } from '@open-wc/testing'; | ||
import { | ||
assertInstantiation, | ||
assertRenderWithHTML, | ||
assertProperties, | ||
setupTestWithInput, | ||
element, | ||
} from '@forter/test-helpers'; | ||
import { FcIcon } from './FcIcon'; | ||
import './fc-icon'; | ||
describe('fc-icon', () => { | ||
const Icon = defineCE(FcIcon); | ||
import { registerIconCache } from './cache'; | ||
it('Instantiates without error', async () => { | ||
const el = await fixture(`<${Icon}></${Icon}>`); | ||
expect(el.localName).to.equal(`${Icon}`); | ||
}); | ||
const getDefaultExport = m => m.default; | ||
describe('size', function() { | ||
it('accepts a size attr as string', async function() { | ||
const el = await fixture(`<${Icon} size="20"></${Icon}>`); | ||
expect(el.size).to.equal('20px'); | ||
}); | ||
const TAG_NAME = 'fc-icon'; | ||
it('converts a number size attr', async function() { | ||
const el = await fixture(`<${Icon} size="20"></${Icon}>`); | ||
expect(el.size).to.equal('20px'); | ||
}); | ||
async function setupTest() { | ||
const tagName = TAG_NAME; | ||
const properties = await import(`../test/${this.test.parent.title}/input.json`) | ||
.then(getDefaultExport) | ||
.catch(() => ({})); | ||
return setupTestWithInput({ properties, tagName }); | ||
} | ||
it('converts a string size attr', async function() { | ||
const el = await fixture(`<${Icon} size="30px"></${Icon}>`); | ||
expect(el.size).to.equal('30px'); | ||
}); | ||
async function assertRender() { | ||
const html = await import(`../test/${this.test.parent.title}/expected.html`) | ||
.then(getDefaultExport) | ||
.catch(() => ''); | ||
return assertRenderWithHTML(html); | ||
} | ||
it('falls back to default for bad size attr', async function() { | ||
const el = await fixture(`<${Icon} size="undefined"></${Icon}>`); | ||
expect(el.size).to.equal('20px'); | ||
describe(TAG_NAME, function() { | ||
it('Instantiates without error', assertInstantiation(TAG_NAME)); | ||
describe('without icon', function() { | ||
beforeEach(setupTest); | ||
it('renders a blank icon', assertRender); | ||
it('should have a cache', function() { | ||
expect(element.cache).to.be.ok; | ||
}); | ||
it('should have a map for cache', function() { | ||
expect(element.cache).to.be.an.instanceof(Map); | ||
}); | ||
}); | ||
it('falls back to default for empty size attr', async function() { | ||
const el = await fixture(`<${Icon} size></${Icon}>`); | ||
expect(el.size).to.equal('20px'); | ||
describe('with size as number', function() { | ||
beforeEach(setupTest); | ||
it('converts attr', assertProperties({ size: '20px' })); | ||
it('renders size', assertRender); | ||
}); | ||
describe('with size as px string', function() { | ||
beforeEach(setupTest); | ||
it('converts attr', assertProperties({ size: '20px' })); | ||
it('renders size', assertRender); | ||
}); | ||
describe('with size as invalid string', function() { | ||
beforeEach(setupTest); | ||
it('converts attr', assertProperties({ size: '20px' })); | ||
it('renders size', assertRender); | ||
}); | ||
describe('with size as empty string', function() { | ||
beforeEach(setupTest); | ||
it('converts attr', assertProperties({ size: '20px' })); | ||
it('renders size', assertRender); | ||
}); | ||
describe('without size', function() { | ||
beforeEach(setupTest); | ||
it('converts attr', assertProperties({ size: '20px' })); | ||
it('renders size', assertRender); | ||
}); | ||
describe('with synchronous cache', function() { | ||
afterEach(function() { | ||
registerIconCache({}); | ||
}); | ||
it('falls back to default for no size attr', async function() { | ||
const el = await fixture(`<${Icon}></${Icon}>`); | ||
expect(el.size).to.equal('20px'); | ||
beforeEach(async function() { | ||
await setupTest.call(this); | ||
registerIconCache({ | ||
foo: 'foo', | ||
bar: 'bar', | ||
}); | ||
await aTimeout(100); | ||
}); | ||
it('renders blank fallback', assertRender); | ||
it('renders icon', assertRender); | ||
}); | ||
}); |
import { IsSlottedMixin } from '@forter/helpers/mixins/is-slotted-mixin'; | ||
import { translate } from '@forter/directives'; | ||
import { LitElement, html, property } from 'lit-element'; | ||
import { getPxString as _getPxString } from '@forter/helpers/functions/get-px-string'; | ||
import constant from 'crocks/combinators/constant'; | ||
import { LitElement, html, property } from 'lit-element'; | ||
import { styleMap } from 'lit-html/directives/style-map'; | ||
import { translate } from '@forter/directives'; | ||
import { until } from 'lit-html/directives/until'; | ||
import constant from 'crocks/combinators/constant'; | ||
import { DEFAULT_ICON, cache, instances } from './cache'; | ||
import { FcIconSizeStyle } from './fc-icon-size-style.css.js'; | ||
import { cache, instances } from './cache'; | ||
import FALLBACK_ICON from './icons/forter.svg.js'; | ||
import style from './fc-icon.css'; | ||
const isMap = x => x instanceof Map; | ||
const getDefaultExport = module => module.default; | ||
@@ -65,2 +63,8 @@ const DEFAULT_SIZE = 20; | ||
/** | ||
* The fallback icon key for the instance | ||
* @type {String} | ||
*/ | ||
@property({ type: String }) fallbackIcon = DEFAULT_ICON; | ||
/** | ||
* The icon key. Used to lookup icon in the cache. Falls back to 'forter' whenever an icon is not found. | ||
@@ -149,3 +153,3 @@ * @type {String} | ||
<div id="content" style="${styleMap({ height, width })}"> | ||
${until(this.getIcon(icon), FALLBACK_ICON)} | ||
${until(this.getIcon(icon), '')} | ||
</div> | ||
@@ -174,8 +178,10 @@ </div> | ||
getIcon(key) { | ||
return this.cache.has(key) | ||
? this.cache.get(key) | ||
return ( | ||
!isMap(this.cache) ? '' | ||
: this.cache.has(key) ? this.cache.get(key) | ||
: import(`./icons/${key}.svg.js`) | ||
.then(getDefaultExport) | ||
.then(this.cacheIcon.bind(this, key)) | ||
.catch(constant(FALLBACK_ICON)); | ||
.catch(constant(this.cache.get(DEFAULT_ICON) || '')) | ||
); | ||
} | ||
@@ -182,0 +188,0 @@ |
import { html } from 'lit-html'; | ||
import { until } from 'lit-html/directives/until'; | ||
import { ifDefined } from 'lit-html/directives/if-defined'; | ||
import { withKnobs, boolean, color, number, select, text } from '@storybook/addon-knobs'; | ||
@@ -12,11 +13,20 @@ import { storiesOf } from '@storybook/polymer'; | ||
function elementProperties() { | ||
function elementProperties({ | ||
size = 24, | ||
originalFill = false, | ||
hoverable = false, | ||
icon = 'forter', | ||
position = 'top', | ||
tooltip = '', | ||
cache, | ||
} = {}) { | ||
return html` | ||
<fc-icon | ||
?hoverable="${boolean('hoverable', false)}" | ||
?original-fill="${boolean('originalFill', false)}" | ||
size="${number('Size', 24, { range: true, min: 10, max: 500 })}px" | ||
icon="${text('icon', '')}" | ||
position="${select('position', ['top', 'bottom'], 'top')}" | ||
tooltip="${text('tooltip', '')}" | ||
.cache="${ifDefined(cache)}" | ||
?hoverable="${boolean('hoverable', hoverable)}" | ||
?original-fill="${boolean('originalFill', originalFill)}" | ||
size="${number('size', size, { range: true, min: 10, max: 500 })}px" | ||
icon="${text('icon', icon)}" | ||
position="${select('position', ['top', 'bottom'], position)}" | ||
tooltip="${text('tooltip', tooltip)}" | ||
></fc-icon> | ||
@@ -27,7 +37,9 @@ `; | ||
function size() { | ||
return html` | ||
<fc-icon size="${number('Size', 24, { range: true, min: 10, max: 500 })}px"></fc-icon> | ||
`; | ||
return elementProperties({ size: 24 }); | ||
} | ||
function noIcon() { | ||
return elementProperties({ icon: null }); | ||
} | ||
function customStyles() { | ||
@@ -40,3 +52,3 @@ return html` | ||
</style> | ||
<fc-icon></fc-icon> | ||
${elementProperties()} | ||
`; | ||
@@ -52,3 +64,3 @@ } | ||
</style> | ||
<fc-icon hoverable></fc-icon> | ||
${elementProperties({ hoverable: true })} | ||
`; | ||
@@ -87,2 +99,3 @@ } | ||
.add('Element Properties', elementProperties, { notes, options }) | ||
.add('No Icon in Cache', noIcon, { notes, options }) | ||
.add('Size', size, { notes, options }) | ||
@@ -89,0 +102,0 @@ .add('Custom Styles', customStyles, { notes, options }) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
162458
143
1982