@nrk/core-progress
Advanced tools
Comparing version 2.0.7 to 2.0.8
@@ -168,22 +168,2 @@ 'use strict'; | ||
/** | ||
* closest | ||
* @param {Element} element Element to traverse up from | ||
* @param {String} selector A selector to search for matching parents or element itself | ||
* @return {Element|null} Element which is the closest ancestor matching selector | ||
*/ | ||
var closest = function () { | ||
var proto = typeof window === 'undefined' ? {} : window.Element.prototype; | ||
var match = proto.matches || proto.msMatchesSelector || proto.webkitMatchesSelector; | ||
return proto.closest ? function (el, css) { | ||
return el.closest(css); | ||
} : function (el, css) { | ||
for (; el; el = el.parentElement) { | ||
if (match.call(el, css)) return el; | ||
} | ||
return null; | ||
}; | ||
}(); | ||
/** | ||
* dispatchEvent - with infinite loop prevention | ||
@@ -190,0 +170,0 @@ * @param {Element} elem The target object |
@@ -5,3 +5,3 @@ (function (global, factory) { | ||
(global = global || self, global.CoreProgress = factory(global.React)); | ||
}(this, function (React) { 'use strict'; | ||
}(this, (function (React) { 'use strict'; | ||
@@ -175,22 +175,2 @@ React = React && React.hasOwnProperty('default') ? React['default'] : React; | ||
/** | ||
* closest | ||
* @param {Element} element Element to traverse up from | ||
* @param {String} selector A selector to search for matching parents or element itself | ||
* @return {Element|null} Element which is the closest ancestor matching selector | ||
*/ | ||
var closest = function () { | ||
var proto = typeof window === 'undefined' ? {} : window.Element.prototype; | ||
var match = proto.matches || proto.msMatchesSelector || proto.webkitMatchesSelector; | ||
return proto.closest ? function (el, css) { | ||
return el.closest(css); | ||
} : function (el, css) { | ||
for (; el; el = el.parentElement) { | ||
if (match.call(el, css)) return el; | ||
} | ||
return null; | ||
}; | ||
}(); | ||
/** | ||
* dispatchEvent - with infinite loop prevention | ||
@@ -320,12 +300,12 @@ * @param {Element} elem The target object | ||
var version = "2.0.7"; | ||
var version = "2.0.8"; | ||
/** | ||
* closest | ||
* @param {Element} element Element to traverse up from | ||
* @param {String} selector A selector to search for matching parents or element itself | ||
* @param {Element} el Element to traverse up from | ||
* @param {String} css A selector to search for matching parents or element itself | ||
* @return {Element|null} Element which is the closest ancestor matching selector | ||
*/ | ||
var closest$1 = function () { | ||
var closest = function () { | ||
var proto = typeof window === 'undefined' ? {} : window.Element.prototype; | ||
@@ -347,4 +327,4 @@ var match = proto.matches || proto.msMatchesSelector || proto.webkitMatchesSelector; | ||
* customElementToReact | ||
* @param {Class|Function} elem A custom element definition. | ||
* @param {Array} attr Props and events | ||
* @param {Class|Function} elementClass A custom element definition. | ||
* @param {Array} options Props and custom events | ||
* @return {Object} A React component | ||
@@ -366,4 +346,12 @@ */ | ||
var customEvents = options.customEvents || []; | ||
var skipProps = customProps.concat('forwardRef'); // Keep a copy with forwardRef added | ||
var eventMap = customEvents.reduce(function (map, eventName) { | ||
map[eventName] = "on" + eventName.replace(/(^|\.)./g, function (m) { | ||
return m.slice(-1).toUpperCase(); | ||
}); // input.filter => onInputFilter | ||
return map; | ||
}, {}); | ||
var skipProps = customProps.concat('forwardRef', Object.keys(eventMap).map(function (onEventName) { | ||
return eventMap[onEventName]; | ||
})); | ||
var tagName = (dashCase + "-" + (options.suffix || 'react')).replace(/\W+/g, '-').toLowerCase(); | ||
@@ -375,6 +363,5 @@ return ( | ||
var this$1 = this; | ||
superclass.call(this, props); | ||
superclass.call(this, props); // Register ref prop for accessing custom element https://reactjs.org/docs/refs-and-the-dom.html#callback-refs | ||
this.ref = function (el) { | ||
// Support callback ref https://reactjs.org/docs/refs-and-the-dom.html#callback-refs | ||
if (typeof this$1.props.forwardRef === 'function') { | ||
@@ -387,14 +374,13 @@ this$1.props.forwardRef(el); | ||
return this$1.el = el; | ||
}; | ||
}; // Register event handler on component for each custom event | ||
customEvents.forEach(function (eventName) { | ||
var on = "on" + eventName.replace(/(^|\.)./g, function (m) { | ||
return m.slice(-1).toUpperCase(); | ||
}); // input.filter => onInputFilter | ||
Object.keys(eventMap).forEach(function (eventName) { | ||
var onEventName = eventMap[eventName]; | ||
this$1[eventName] = function (event) { | ||
return this$1.props[on] && closest$1(event.target, this$1.el.nodeName) === this$1.el && this$1.props[on](event); | ||
if (this$1.props[onEventName] && closest(event.target, this$1.el.nodeName) === this$1.el) { | ||
this$1.props[onEventName](event); | ||
} | ||
}; | ||
skipProps.push(on); // Skip props that are customEvents | ||
}); | ||
@@ -408,20 +394,27 @@ } | ||
anonymous.prototype.componentDidMount = function componentDidMount() { | ||
var this$1 = this; // Do not run connectedCallback before after React componentDidMount, to allow React hydration to run first | ||
var this$1 = this; // Run connectedCallback() after React componentDidMount() to allow React hydration to run first | ||
if (!window.customElements.get(tagName)) { | ||
window.customElements.define(tagName, elementClass); | ||
} | ||
} // Populate properties on custom element | ||
customProps.forEach(function (key) { | ||
return key in this$1.props && (this$1.el[key] = this$1.props[key]); | ||
customProps.forEach(function (propName) { | ||
if (propName in this$1.props) { | ||
this$1.el[propName] = this$1.props[propName]; | ||
} | ||
}); // Register events on custom element | ||
customEvents.forEach(function (eventName) { | ||
this$1.el.addEventListener(eventName, this$1[eventName]); | ||
}); | ||
customEvents.forEach(function (key) { | ||
return this$1.el.addEventListener(key, this$1[key]); | ||
}); | ||
}; | ||
anonymous.prototype.componentDidUpdate = function componentDidUpdate(prev) { | ||
var this$1 = this; | ||
customProps.forEach(function (key) { | ||
return prev[key] !== this$1.props[key] && (this$1.el[key] = this$1.props[key]); | ||
var this$1 = this; // Sync prop changes to custom element | ||
customProps.forEach(function (propName) { | ||
if (prev[propName] !== this$1.props[propName]) { | ||
this$1.el[propName] = this$1.props[propName]; | ||
} | ||
}); | ||
@@ -431,5 +424,6 @@ }; | ||
anonymous.prototype.componentWillUnmount = function componentWillUnmount() { | ||
var this$1 = this; | ||
var this$1 = this; // Remove event handlers on custom element on unmount | ||
customEvents.forEach(function (eventName) { | ||
return this$1.el.removeEventListener(eventName, this$1[eventName]); | ||
this$1.el.removeEventListener(eventName, this$1[eventName]); | ||
}); | ||
@@ -441,13 +435,13 @@ }; | ||
return React.createElement(tagName, Object.keys(this.props).reduce(function (thisProps, key) { | ||
if (skipProps.indexOf(key) === -1) { | ||
return React.createElement(tagName, Object.keys(this.props).reduce(function (thisProps, propName) { | ||
if (skipProps.indexOf(propName) === -1) { | ||
// Do not render customEvents and custom props as attributes | ||
if (key === 'className') { | ||
thisProps["class"] = this$1.props[key]; | ||
if (propName === 'className') { | ||
thisProps["class"] = this$1.props[propName]; | ||
} // Fixes className for custom elements | ||
else if (this$1.props[key] === true) { | ||
thisProps[key] = ''; | ||
else if (this$1.props[propName] === true) { | ||
thisProps[propName] = ''; | ||
} // Fixes boolean attributes | ||
else if (this$1.props[key] !== false) { | ||
thisProps[key] = this$1.props[key]; | ||
else if (this$1.props[propName] !== false) { | ||
thisProps[propName] = this$1.props[propName]; | ||
} // Pass only truthy, non-function props | ||
@@ -475,3 +469,3 @@ | ||
})); | ||
}))); | ||
//# sourceMappingURL=core-progress.jsx.js.map |
@@ -1,3 +0,3 @@ | ||
/*! @nrk/core-progress v2.0.7 - Copyright (c) 2017-2019 NRK */ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).coreProgress=e()}(this,function(){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function a(t){return(a=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function c(t,e){return(c=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function i(t,e,n){return(i=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,n){var r=[null];r.push.apply(r,e);var i=new(Function.bind.apply(t,r));return n&&c(i,n.prototype),i}).apply(null,arguments)}function s(t){var r="function"==typeof Map?new Map:void 0;return(s=function(t){if(null===t||(e=t,-1===Function.toString.call(e).indexOf("[native code]")))return t;var e;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==r){if(r.has(t))return r.get(t);r.set(t,n)}function n(){return i(t,arguments,a(this).constructor)}return n.prototype=Object.create(t.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),c(n,t)})(t)}function l(t,e){return!e||"object"!=typeof e&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}var t="undefined"!=typeof window;t&&/(android)/i.test(navigator.userAgent),t&&/iPad|iPhone|iPod/.test(String(navigator.platform));t||global.HTMLElement||(global.HTMLElement=function(){return function t(){o(this,t)}}());var e,n;e="undefined"==typeof window?{}:window.Element.prototype,n=e.matches||e.msMatchesSelector||e.webkitMatchesSelector,e.closest;return function(t){function e(){return o(this,e),l(this,a(e).apply(this,arguments))}var n,r,i;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&c(t,e)}(e,s(HTMLElement)),n=e,i=[{key:"observedAttributes",get:function(){return["type","value","max"]}}],(r=[{key:"connectedCallback",value:function(){var t,e,n,r;this.setAttribute("role","img"),this.setAttribute("aria-label",this.getAttribute("aria-label")||"0%"),this.type=this.type,t=this.nodeName,e="".concat(this.nodeName,"{display:block;fill:none;stroke-width:15}"),n="style-".concat(t.toLowerCase()),r=e.replace(/\/\*[^!][^*]*\*\//g,"").replace(/\s*(^|[:;,{}]|$)\s*/g,"$1"),document.getElementById(n)||document.head.insertAdjacentHTML("afterbegin",'<style id="'.concat(n,'">').concat(r,"</style>"))}},{key:"attributeChangedCallback",value:function(t,e,n){var r=this.parentElement&&"type"===t&&"radial"===n==!this.querySelector("svg"),i=this.indeterminate?100:this.percentage;this.setAttribute("aria-label",this.indeterminate||"".concat(i,"%")),function(t,e){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:!this.hasAttribute(e);!n===t.hasAttribute(e)&&t[n?"setAttribute":"removeAttribute"](e,"")}(this,"indeterminate",this.indeterminate),"linear"===this.type&&(this.style.width="".concat(i,"%")),"radial"===this.type&&(this.style.strokeDashoffset=Math.round((100-i)*Math.PI)),r&&(this.innerHTML="radial"===n?'<svg style="display:block;overflow:hidden;border-radius:100%" width="100%" viewBox="0 0 100 100"><circle cx="50" cy="50" r="50" stroke-dashoffset="0"/><circle cx="50" cy="50" r="50" stroke="currentColor" stroke-dasharray="314.159" transform="rotate(-90 50 50)"/></svg>':""),"value"===t&&Number(n)!==Number(e)&&function(t,e){var n,r=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},i="prevent_recursive_dispatch_maximum_callstack".concat(e);if(t[i])return;t[i]=!0,"function"==typeof window.CustomEvent?n=new window.CustomEvent(e,{bubbles:!0,cancelable:!0,detail:r}):(n=document.createEvent("CustomEvent")).initCustomEvent(e,!0,!0,r);var o=t.dispatchEvent(n);t[i]=null}(this,"change")}},{key:"indeterminate",get:function(){return isNaN(parseFloat(this.getAttribute("value")))&&this.getAttribute("value")}},{key:"percentage",get:function(){return Math.round(this.value/this.max*100)||0}},{key:"value",get:function(){return this.indeterminate||Number(this.getAttribute("value"))},set:function(t){this.setAttribute("value",t)}},{key:"max",get:function(){return Number(this.getAttribute("max"))||1},set:function(t){this.setAttribute("max",t)}},{key:"type",get:function(){return this.getAttribute("type")||"linear"},set:function(t){this.setAttribute("type",t)}}])&&u(n.prototype,r),i&&u(n,i),e}()}),window.customElements.define("core-progress",coreProgress); | ||
/*! @nrk/core-progress v2.0.8 - Copyright (c) 2017-2019 NRK */ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).coreProgress=e()}(this,function(){"use strict";function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function i(t){return(i=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function u(t,e,n){return(u=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,n){var r=[null];r.push.apply(r,e);var i=new(Function.bind.apply(t,r));return n&&o(i,n.prototype),i}).apply(null,arguments)}function a(t){var n="function"==typeof Map?new Map:void 0;return(a=function(t){if(null===t||!function(t){return-1!==Function.toString.call(t).indexOf("[native code]")}(t))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==n){if(n.has(t))return n.get(t);n.set(t,e)}function e(){return u(t,arguments,i(this).constructor)}return e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),o(e,t)})(t)}function n(t,e){return!e||"object"!=typeof e&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}var t="undefined"!=typeof window;t&&/(android)/i.test(navigator.userAgent),t&&/iPad|iPhone|iPod/.test(String(navigator.platform));return t||global.HTMLElement||(global.HTMLElement=function(){return function t(){e(this,t)}}()),function(){function t(){return e(this,t),n(this,i(t).apply(this,arguments))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&o(t,e)}(t,a(HTMLElement)),function(t,e,n){e&&r(t.prototype,e),n&&r(t,n)}(t,[{key:"connectedCallback",value:function(){this.setAttribute("role","img"),this.setAttribute("aria-label",this.getAttribute("aria-label")||"0%"),this.type=this.type,function(t,e){var n="style-".concat(t.toLowerCase()),r=e.replace(/\/\*[^!][^*]*\*\//g,"").replace(/\s*(^|[:;,{}]|$)\s*/g,"$1");document.getElementById(n)||document.head.insertAdjacentHTML("afterbegin",'<style id="'.concat(n,'">').concat(r,"</style>"))}(this.nodeName,"".concat(this.nodeName,"{display:block;fill:none;stroke-width:15}"))}},{key:"attributeChangedCallback",value:function(t,e,n){var r=this.parentElement&&"type"===t&&"radial"===n==!this.querySelector("svg"),i=this.indeterminate?100:this.percentage;this.setAttribute("aria-label",this.indeterminate||"".concat(i,"%")),function(t,e,n){var r=2<arguments.length&&void 0!==n?n:!this.hasAttribute(e);!r===t.hasAttribute(e)&&t[r?"setAttribute":"removeAttribute"](e,"")}(this,"indeterminate",this.indeterminate),"linear"===this.type&&(this.style.width="".concat(i,"%")),"radial"===this.type&&(this.style.strokeDashoffset=Math.round((100-i)*Math.PI)),r&&(this.innerHTML="radial"===n?'<svg style="display:block;overflow:hidden;border-radius:100%" width="100%" viewBox="0 0 100 100"><circle cx="50" cy="50" r="50" stroke-dashoffset="0"/><circle cx="50" cy="50" r="50" stroke="currentColor" stroke-dasharray="314.159" transform="rotate(-90 50 50)"/></svg>':""),"value"===t&&Number(n)!==Number(e)&&function(t,e,n){var r,i=2<arguments.length&&void 0!==n?n:{},o="prevent_recursive_dispatch_maximum_callstack".concat(e);if(t[o])return;t[o]=!0,"function"==typeof window.CustomEvent?r=new window.CustomEvent(e,{bubbles:!0,cancelable:!0,detail:i}):(r=document.createEvent("CustomEvent")).initCustomEvent(e,!0,!0,i);var u=t.dispatchEvent(r);t[o]=null}(this,"change")}},{key:"indeterminate",get:function(){return isNaN(parseFloat(this.getAttribute("value")))&&this.getAttribute("value")}},{key:"percentage",get:function(){return Math.round(this.value/this.max*100)||0}},{key:"value",get:function(){return this.indeterminate||Number(this.getAttribute("value"))},set:function(t){this.setAttribute("value",t)}},{key:"max",get:function(){return Number(this.getAttribute("max"))||1},set:function(t){this.setAttribute("max",t)}},{key:"type",get:function(){return this.getAttribute("type")||"linear"},set:function(t){this.setAttribute("type",t)}}],[{key:"observedAttributes",get:function(){return["type","value","max"]}}]),t}()}),window.customElements.define("core-progress",coreProgress); | ||
//# sourceMappingURL=core-progress.min.js.map |
@@ -1,90 +0,107 @@ | ||
import test from 'ava' | ||
import fs from 'fs' | ||
import path from 'path' | ||
import puppeteer from 'puppeteer' | ||
import { prop, attr } from '../test-utils' | ||
async function withPage (t, run) { | ||
const browser = await puppeteer.launch() | ||
const page = await browser.newPage() | ||
page.on('console', msg => console.log(msg._text)) | ||
await page.addScriptTag({ path: path.join(__dirname, 'core-progress.min.js') }) | ||
try { | ||
await run(t, page) | ||
} finally { | ||
await page.close() | ||
await browser.close() | ||
} | ||
} | ||
const coreProgress = fs.readFileSync(path.resolve(__dirname, 'core-progress.min.js'), 'utf-8') | ||
const customElements = fs.readFileSync(require.resolve('@webcomponents/custom-elements'), 'utf-8') | ||
test('sets up properties', withPage, async (t, page) => { | ||
await page.setContent(`<core-progress></core-progress>`) | ||
t.is(await page.$eval('core-progress', el => el.type), 'linear') | ||
t.is(await page.$eval('core-progress', el => el.value), 0) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('role')), 'img') | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '0%') | ||
}) | ||
describe('core-progress', () => { | ||
beforeEach(async () => { | ||
await browser.refresh() | ||
await browser.executeScript(customElements) | ||
await browser.executeScript(coreProgress) | ||
}) | ||
test('updates label from value', withPage, async (t, page) => { | ||
await page.setContent(`<core-progress value="0.2"></core-progress>`) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '20%') | ||
await page.evaluate(() => (document.querySelector('core-progress').value = 0)) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '0%') | ||
await page.evaluate(() => (document.querySelector('core-progress').value = 1)) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '100%') | ||
}) | ||
it('sets up properties', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-progress></core-progress> | ||
` | ||
}) | ||
await expect(prop('core-progress', 'type')).toEqual('linear') | ||
await expect(prop('core-progress', 'value')).toEqual('0') | ||
await expect(attr('core-progress', 'role')).toEqual('img') | ||
await expect(attr('core-progress', 'aria-label')).toEqual('0%') | ||
}) | ||
test('updates label from value as radial', withPage, async (t, page) => { | ||
await page.setContent(`<core-progress value="0.2" type="radial"></core-progress>`) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '20%') | ||
await page.evaluate(() => (document.querySelector('core-progress').value = 0)) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '0%') | ||
await page.evaluate(() => (document.querySelector('core-progress').value = 1)) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '100%') | ||
}) | ||
it('updates label from value', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-progress value="0.2"></core-progress> | ||
` | ||
}) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('20%') | ||
await browser.executeScript(() => (document.querySelector('core-progress').value = 0)) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('0%') | ||
await browser.executeScript(() => (document.querySelector('core-progress').value = 1)) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('100%') | ||
}) | ||
test('updates label from indeterminate value', withPage, async (t, page) => { | ||
await page.setContent(`<core-progress value="Loading..."></core-progress>`) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), 'Loading...') | ||
}) | ||
it('updates label from value as radial', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-progress value="0.2" type="radial"></core-progress> | ||
` | ||
}) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('20%') | ||
await browser.executeScript(() => (document.querySelector('core-progress').value = 0)) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('0%') | ||
await browser.executeScript(() => (document.querySelector('core-progress').value = 1)) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('100%') | ||
}) | ||
test('calculates percentage from max', withPage, async (t, page) => { | ||
await page.setContent(`<core-progress value="0.5"></core-progress>`) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '50%') | ||
await page.evaluate(() => (document.querySelector('core-progress').max = 10)) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '5%') | ||
await page.evaluate(() => (document.querySelector('core-progress').max = 100)) | ||
t.is(await page.$eval('core-progress', el => el.getAttribute('aria-label')), '1%') | ||
}) | ||
it('updates label from indeterminate value', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-progress value="Loading..."></core-progress> | ||
` | ||
}) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('Loading...') | ||
}) | ||
test('does not trigger change event on max', withPage, async (t, page) => { | ||
await page.setContent(`<core-progress></core-progress>`) | ||
await page.evaluate(() => { | ||
return new Promise((resolve, reject) => { | ||
window.addEventListener('change', reject) | ||
it('calculates percentage relative to max', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-progress value="0.5"></core-progress> | ||
` | ||
}) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('50%') | ||
await browser.executeScript(() => (document.querySelector('core-progress').max = 10)) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('5%') | ||
await browser.executeScript(() => (document.querySelector('core-progress').max = 100)) | ||
await expect(attr('core-progress', 'aria-label')).toEqual('1%') | ||
}) | ||
it('does not trigger change event on max', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-progress></core-progress> | ||
` | ||
document.addEventListener('change', () => (window.triggered = true)) | ||
document.querySelector('core-progress').max = 2 | ||
setTimeout(resolve) | ||
}) | ||
await expect(browser.executeScript(() => window.triggered)).toBeFalsy() | ||
}) | ||
t.pass() | ||
}) | ||
test('triggers change event on value', withPage, async (t, page) => { | ||
await page.setContent(`<core-progress></core-progress>`) | ||
await page.evaluate(() => { | ||
return new Promise((resolve, reject) => { | ||
window.addEventListener('change', resolve) | ||
it('triggers change event on value', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-progress></core-progress> | ||
` | ||
document.addEventListener('change', () => (window.triggered = true)) | ||
document.querySelector('core-progress').value = 2 | ||
}) | ||
await expect(browser.executeScript(() => window.triggered)).toBeTruthy() | ||
}) | ||
t.pass() | ||
}) | ||
test('triggers change event on indeterminate value', withPage, async (t, page) => { | ||
await page.setContent(`<core-progress></core-progress>`) | ||
await page.evaluate(() => { | ||
return new Promise((resolve, reject) => { | ||
window.addEventListener('change', resolve) | ||
it('triggers change event on indeterminate value', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-progress></core-progress> | ||
` | ||
document.addEventListener('change', () => (window.triggered = true)) | ||
document.querySelector('core-progress').value = 'Loading...' | ||
}) | ||
await expect(browser.executeScript(() => window.triggered)).toBeTruthy() | ||
}) | ||
t.pass() | ||
}) |
108
jsx.js
@@ -172,22 +172,2 @@ 'use strict'; | ||
/** | ||
* closest | ||
* @param {Element} element Element to traverse up from | ||
* @param {String} selector A selector to search for matching parents or element itself | ||
* @return {Element|null} Element which is the closest ancestor matching selector | ||
*/ | ||
var closest = function () { | ||
var proto = typeof window === 'undefined' ? {} : window.Element.prototype; | ||
var match = proto.matches || proto.msMatchesSelector || proto.webkitMatchesSelector; | ||
return proto.closest ? function (el, css) { | ||
return el.closest(css); | ||
} : function (el, css) { | ||
for (; el; el = el.parentElement) { | ||
if (match.call(el, css)) return el; | ||
} | ||
return null; | ||
}; | ||
}(); | ||
/** | ||
* dispatchEvent - with infinite loop prevention | ||
@@ -317,12 +297,12 @@ * @param {Element} elem The target object | ||
var version = "2.0.7"; | ||
var version = "2.0.8"; | ||
/** | ||
* closest | ||
* @param {Element} element Element to traverse up from | ||
* @param {String} selector A selector to search for matching parents or element itself | ||
* @param {Element} el Element to traverse up from | ||
* @param {String} css A selector to search for matching parents or element itself | ||
* @return {Element|null} Element which is the closest ancestor matching selector | ||
*/ | ||
var closest$1 = function () { | ||
var closest = function () { | ||
var proto = typeof window === 'undefined' ? {} : window.Element.prototype; | ||
@@ -344,4 +324,4 @@ var match = proto.matches || proto.msMatchesSelector || proto.webkitMatchesSelector; | ||
* customElementToReact | ||
* @param {Class|Function} elem A custom element definition. | ||
* @param {Array} attr Props and events | ||
* @param {Class|Function} elementClass A custom element definition. | ||
* @param {Array} options Props and custom events | ||
* @return {Object} A React component | ||
@@ -363,4 +343,12 @@ */ | ||
var customEvents = options.customEvents || []; | ||
var skipProps = customProps.concat('forwardRef'); // Keep a copy with forwardRef added | ||
var eventMap = customEvents.reduce(function (map, eventName) { | ||
map[eventName] = "on" + eventName.replace(/(^|\.)./g, function (m) { | ||
return m.slice(-1).toUpperCase(); | ||
}); // input.filter => onInputFilter | ||
return map; | ||
}, {}); | ||
var skipProps = customProps.concat('forwardRef', Object.keys(eventMap).map(function (onEventName) { | ||
return eventMap[onEventName]; | ||
})); | ||
var tagName = (dashCase + "-" + (options.suffix || 'react')).replace(/\W+/g, '-').toLowerCase(); | ||
@@ -372,6 +360,5 @@ return ( | ||
var this$1 = this; | ||
superclass.call(this, props); | ||
superclass.call(this, props); // Register ref prop for accessing custom element https://reactjs.org/docs/refs-and-the-dom.html#callback-refs | ||
this.ref = function (el) { | ||
// Support callback ref https://reactjs.org/docs/refs-and-the-dom.html#callback-refs | ||
if (typeof this$1.props.forwardRef === 'function') { | ||
@@ -384,14 +371,13 @@ this$1.props.forwardRef(el); | ||
return this$1.el = el; | ||
}; | ||
}; // Register event handler on component for each custom event | ||
customEvents.forEach(function (eventName) { | ||
var on = "on" + eventName.replace(/(^|\.)./g, function (m) { | ||
return m.slice(-1).toUpperCase(); | ||
}); // input.filter => onInputFilter | ||
Object.keys(eventMap).forEach(function (eventName) { | ||
var onEventName = eventMap[eventName]; | ||
this$1[eventName] = function (event) { | ||
return this$1.props[on] && closest$1(event.target, this$1.el.nodeName) === this$1.el && this$1.props[on](event); | ||
if (this$1.props[onEventName] && closest(event.target, this$1.el.nodeName) === this$1.el) { | ||
this$1.props[onEventName](event); | ||
} | ||
}; | ||
skipProps.push(on); // Skip props that are customEvents | ||
}); | ||
@@ -405,20 +391,27 @@ } | ||
anonymous.prototype.componentDidMount = function componentDidMount() { | ||
var this$1 = this; // Do not run connectedCallback before after React componentDidMount, to allow React hydration to run first | ||
var this$1 = this; // Run connectedCallback() after React componentDidMount() to allow React hydration to run first | ||
if (!window.customElements.get(tagName)) { | ||
window.customElements.define(tagName, elementClass); | ||
} | ||
} // Populate properties on custom element | ||
customProps.forEach(function (key) { | ||
return key in this$1.props && (this$1.el[key] = this$1.props[key]); | ||
customProps.forEach(function (propName) { | ||
if (propName in this$1.props) { | ||
this$1.el[propName] = this$1.props[propName]; | ||
} | ||
}); // Register events on custom element | ||
customEvents.forEach(function (eventName) { | ||
this$1.el.addEventListener(eventName, this$1[eventName]); | ||
}); | ||
customEvents.forEach(function (key) { | ||
return this$1.el.addEventListener(key, this$1[key]); | ||
}); | ||
}; | ||
anonymous.prototype.componentDidUpdate = function componentDidUpdate(prev) { | ||
var this$1 = this; | ||
customProps.forEach(function (key) { | ||
return prev[key] !== this$1.props[key] && (this$1.el[key] = this$1.props[key]); | ||
var this$1 = this; // Sync prop changes to custom element | ||
customProps.forEach(function (propName) { | ||
if (prev[propName] !== this$1.props[propName]) { | ||
this$1.el[propName] = this$1.props[propName]; | ||
} | ||
}); | ||
@@ -428,5 +421,6 @@ }; | ||
anonymous.prototype.componentWillUnmount = function componentWillUnmount() { | ||
var this$1 = this; | ||
var this$1 = this; // Remove event handlers on custom element on unmount | ||
customEvents.forEach(function (eventName) { | ||
return this$1.el.removeEventListener(eventName, this$1[eventName]); | ||
this$1.el.removeEventListener(eventName, this$1[eventName]); | ||
}); | ||
@@ -438,13 +432,13 @@ }; | ||
return React.createElement(tagName, Object.keys(this.props).reduce(function (thisProps, key) { | ||
if (skipProps.indexOf(key) === -1) { | ||
return React.createElement(tagName, Object.keys(this.props).reduce(function (thisProps, propName) { | ||
if (skipProps.indexOf(propName) === -1) { | ||
// Do not render customEvents and custom props as attributes | ||
if (key === 'className') { | ||
thisProps["class"] = this$1.props[key]; | ||
if (propName === 'className') { | ||
thisProps["class"] = this$1.props[propName]; | ||
} // Fixes className for custom elements | ||
else if (this$1.props[key] === true) { | ||
thisProps[key] = ''; | ||
else if (this$1.props[propName] === true) { | ||
thisProps[propName] = ''; | ||
} // Fixes boolean attributes | ||
else if (this$1.props[key] !== false) { | ||
thisProps[key] = this$1.props[key]; | ||
else if (this$1.props[propName] !== false) { | ||
thisProps[propName] = this$1.props[propName]; | ||
} // Pass only truthy, non-function props | ||
@@ -451,0 +445,0 @@ |
@@ -5,3 +5,3 @@ { | ||
"author": "NRK <opensource@nrk.no> (https://www.nrk.no/)", | ||
"version": "2.0.7", | ||
"version": "2.0.8", | ||
"license": "MIT", | ||
@@ -8,0 +8,0 @@ "main": "core-progress.cjs.js", |
@@ -12,2 +12,3 @@ # Core Progress | ||
<!--demo | ||
<script src="https://unpkg.com/@webcomponents/custom-elements"></script> | ||
<script src="core-progress/core-progress.min.js"></script> | ||
@@ -92,2 +93,3 @@ <script src="core-progress/core-progress.jsx.js"></script> | ||
Remember to [polyfill](https://github.com/webcomponents/polyfills#custom-elements) custom elements if needed. | ||
@@ -138,2 +140,4 @@ | ||
indeterminate={Boolean} // Optional. Set indeterminate value | ||
ref={(comp) => {}} // Optional. Get reference to React component | ||
forwardRef={(el) => {}} // Optional. Get reference to underlying DOM custom element | ||
onProgressChange={Function} /> // Optional. Progress change event handler | ||
@@ -140,0 +144,0 @@ </div> |
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
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
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
103059
12
1430
182
2