@nrk/core-datepicker
Advanced tools
Comparing version
@@ -180,2 +180,6 @@ 'use strict'; | ||
} : function (el, css) { | ||
// IE jumps to shadow SVG DOM on clicking an SVG defined by <use>. | ||
// If so, jump back to <use> element and traverse real DOM | ||
if (el.correspondingUseElement) el = el.correspondingUseElement; | ||
for (; el; el = el.parentElement) { | ||
@@ -565,3 +569,3 @@ if (match.call(el, css)) return el; | ||
button.tabIndex = isSelected - 1; | ||
button.setAttribute("data-adjacent", month !== dayMonth); | ||
button.setAttribute('data-adjacent', month !== dayMonth); | ||
button.setAttribute('aria-label', "".concat(dayInMonth, ". ").concat(self.months[dayMonth])); | ||
@@ -568,0 +572,0 @@ button.setAttribute('aria-current', day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear() && 'date'); |
@@ -140,3 +140,3 @@ import { addStyle, closest, dispatchEvent, toggleAttribute, queryAll } from '../utils' | ||
button.tabIndex = isSelected - 1 | ||
button.setAttribute(`data-adjacent`, month !== dayMonth) | ||
button.setAttribute('data-adjacent', month !== dayMonth) | ||
button.setAttribute('aria-label', `${dayInMonth}. ${self.months[dayMonth]}`) | ||
@@ -143,0 +143,0 @@ button.setAttribute('aria-current', day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear() && 'date') |
@@ -5,3 +5,3 @@ (function (global, factory) { | ||
(global = global || self, global.CoreDatepicker = factory(global.React)); | ||
}(this, function (React) { 'use strict'; | ||
}(this, (function (React) { 'use strict'; | ||
@@ -187,2 +187,6 @@ React = React && React.hasOwnProperty('default') ? React['default'] : React; | ||
} : function (el, css) { | ||
// IE jumps to shadow SVG DOM on clicking an SVG defined by <use>. | ||
// If so, jump back to <use> element and traverse real DOM | ||
if (el.correspondingUseElement) el = el.correspondingUseElement; | ||
for (; el; el = el.parentElement) { | ||
@@ -572,3 +576,3 @@ if (match.call(el, css)) return el; | ||
button.tabIndex = isSelected - 1; | ||
button.setAttribute("data-adjacent", month !== dayMonth); | ||
button.setAttribute('data-adjacent', month !== dayMonth); | ||
button.setAttribute('aria-label', "".concat(dayInMonth, ". ").concat(self.months[dayMonth])); | ||
@@ -596,8 +600,8 @@ button.setAttribute('aria-current', day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear() && 'date'); | ||
var version = "3.0.7"; | ||
var version = "3.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 | ||
@@ -623,4 +627,4 @@ */ | ||
* 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 | ||
@@ -642,4 +646,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(); | ||
@@ -651,6 +663,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') { | ||
@@ -663,14 +674,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$1(event.target, this$1.el.nodeName) === this$1.el) { | ||
this$1.props[onEventName](event); | ||
} | ||
}; | ||
skipProps.push(on); // Skip props that are customEvents | ||
}); | ||
@@ -684,20 +694,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]; | ||
} | ||
}); | ||
@@ -707,5 +724,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]); | ||
}); | ||
@@ -717,13 +735,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 | ||
@@ -752,3 +770,3 @@ | ||
})); | ||
}))); | ||
//# sourceMappingURL=core-datepicker.jsx.js.map |
@@ -1,3 +0,3 @@ | ||
/*! @nrk/core-datepicker v3.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).coreDatepicker=e()}(this,function(){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function a(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function u(t){return(u=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 r(t,e,n){return(r=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 i=[null];i.push.apply(i,e);var r=new(Function.bind.apply(t,i));return n&&c(r,n.prototype),r}).apply(null,arguments)}function s(t){var i="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!==i){if(i.has(t))return i.get(t);i.set(t,n)}function n(){return r(t,arguments,u(this).constructor)}return n.prototype=Object.create(t.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),c(n,t)})(t)}function d(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,l=(e="undefined"==typeof window?{}:window.Element.prototype,n=e.matches||e.msMatchesSelector||e.webkitMatchesSelector,e.closest?function(t,e){return t.closest(e)}:function(t,e){for(;t;t=t.parentElement)if(n.call(t,e))return t;return null});function f(t,e){var n,i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},r="prevent_recursive_dispatch_maximum_callstack".concat(e);if(t[r])return!0;t[r]=!0,"function"==typeof window.CustomEvent?n=new window.CustomEvent(e,{bubbles:!0,cancelable:!0,detail:i}):(n=document.createEvent("CustomEvent")).initCustomEvent(e,!0,!0,i);var o=t.dispatchEvent(n);return t[r]=null,o}function h(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:document;if(t){if(t.nodeType)return[t];if("string"==typeof t)return[].slice.call(e.querySelectorAll(t));if(t.length)return[].slice.call(t)}return[]}"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;var i,y=(function(t,e){var g,v,k,w;t.exports=(g={year:"FullYear",month:"Month",week:"Date",day:"Date",hour:"Hours",minute:"Minutes",second:"Seconds"},v=/([+-]\s*\d+)\s*(second|minute|hour|day|week|month|year)|(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)/g,k=/([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,w=/([\dh]+):([\dm]+):?([\ds]+)?/,function(t,e){if(isFinite(t))return new Date(Number(t));var n=String(t).toLowerCase(),r=new Date(isFinite(e)&&-1===n.indexOf("now")?Number(e):Date.now()),i=n.match(k)||[],o=i[1];void 0===o&&(o="y");var a=i[2];void 0===a&&(a="m");var u=i[3];void 0===u&&(u="d");var c=n.match(w)||[],s=c[1];void 0===s&&(s="h");var d=c[2];void 0===d&&(d="m");var l=c[3];void 0===l&&(l="s");var f={year:o,month:a,day:u,hour:s,minute:d,second:l};Object.keys(f).forEach(function(t){var e="month"===t?1:0,i=String(r["get"+g[t]]()+e);f[t]=f[t].replace(/[^-\d]+/g,function(t,e,n){return e?i.substr(i.length-n.length+e,t.length):i.substr(0,Math.max(0,i.length-n.length+t.length))})-e});var h=new Date(f.year,Math.min(12,f.month+1),0).getDate();for(r.setFullYear(f.year,Math.min(11,f.month),Math.max(1,Math.min(h,f.day))),r.setHours(Math.min(24,f.hour),Math.min(59,f.minute),Math.min(59,f.second));null!==(f=v.exec(n));){var y=f[2],m=String(f[1]).replace(/\s/g,"")*("week"===y?7:1),p=f.slice(2).indexOf(f[0]),b=r.getDate();y?r["set"+g[y]](r["get"+g[y]]()+m):r.setDate(r.getDate()-(r.getDay()||7)+p),"month"!==y&&"year"!==y||b===r.getDate()||r.setDate(0)}return r})}(i={exports:{}},i.exports),i.exports),m={year:"*-m-d",month:"y-*-d",day:"y-m-*",hour:"*:m",minute:"h:*",second:"h:m:*",timestamp:"*",null:"*"},p={33:"-1month",34:"+1month",35:"y-m-99",36:"y-m-1",37:"-1day",38:"-1week",39:"+1day",40:"+1week"},b=function(t){function e(){return o(this,e),d(this,u(e).apply(this,arguments))}var n,i,r;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,r=[{key:"observedAttributes",get:function(){return["timestamp","months","days"]}}],(i=[{key:"connectedCallback",value:function(){var t,e,n,i,r=this;this._date=this.date,document.addEventListener("click",this),document.addEventListener("change",this),document.addEventListener("keydown",this),setTimeout(function(){return r.attributeChangedCallback()}),t=this.nodeName,e="".concat(this.nodeName,"{display:block}"),n="style-".concat(t.toLowerCase()),i=e.replace(/\/\*[^!][^*]*\*\//g,"").replace(/\s*(^|[:;,{}]|$)\s*/g,"$1"),document.getElementById(n)||document.head.insertAdjacentHTML("afterbegin",'<style id="'.concat(n,'">').concat(i,"</style>"))}},{key:"disconnectedCallback",value:function(){this._date=this._disabled=null,document.removeEventListener("click",this),document.removeEventListener("change",this),document.removeEventListener("keydown",this)}},{key:"attributeChangedCallback",value:function(){if(this._date){if(this.disabled(this.date)&&!this.disabled(this._date))return this.date=this._date;this.diff(this.date)&&f(this,"datepicker.change",this._date=this.date),v("button",this,k),v("select",this,_),v("input",this,w),v("table",this,E)}}},{key:"handleEvent",value:function(t){if(!(t.defaultPrevented||t.ctrlKey||t.metaKey||t.shiftKey||t.altKey||"keydown"===t.type&&!p[t.keyCode])&&(this.contains(t.target)||l(t.target,'[for="'.concat(this.id,'"]'))))if("change"===t.type)this.date=m[t.target.getAttribute("data-type")].replace("*",t.target.value);else if("click"===t.type){var e=l(t.target,"button[value]"),n=l(t.target,"table");e&&(this.date=e.value),e&&n&&f(this,"datepicker.click.day")}else"keydown"===t.type&&l(t.target,"table")&&(this.date=p[t.keyCode],this.querySelector("[autofocus]").focus(),t.preventDefault())}},{key:"diff",value:function(t){return this.parse(t).getTime()-this.timestamp}},{key:"parse",value:function(t,e){return y(t,e||this._date)}},{key:"disabled",get:function(){return this._disabled||Function.prototype},set:function(e){var n=this;this._disabled="function"==typeof e?function(t){return e(n.parse(t),n)}:function(){return e},this.attributeChangedCallback()}},{key:"timestamp",get:function(){return String(this._date.getTime())}},{key:"year",get:function(){return String(this._date.getFullYear())}},{key:"month",get:function(){return g(this._date.getMonth()+1)}},{key:"day",get:function(){return g(this._date.getDate())}},{key:"hour",get:function(){return g(this._date.getHours())}},{key:"minute",get:function(){return g(this._date.getMinutes())}},{key:"second",get:function(){return g(this._date.getSeconds())}},{key:"date",get:function(){return y(this.getAttribute("timestamp")||this._date||Date.now())},set:function(t){return this.setAttribute("timestamp",this.parse(t).getTime())}},{key:"months",set:function(t){this.setAttribute("months",[].concat(t).join(","))},get:function(){return(this.getAttribute("months")||"januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember").split(/\s*,\s*/)}},{key:"days",set:function(t){this.setAttribute("days",[].concat(t).join(","))},get:function(){return(this.getAttribute("days")||"man,tirs,ons,tors,fre,lør,søn").split(/\s*,\s*/)}}])&&a(n.prototype,i),r&&a(n,r),e}(),g=function(t){return"0".concat(t).slice(-2)},v=function(t,e,n){return[].forEach.call(document.getElementsByTagName(t),function(t){(e.contains(t)||e.id===t.getAttribute(e.external))&&n(e,t)})};function k(t,e){e.value&&(e.type="button",e.disabled=t.disabled(e.value))}function w(t,e){var n=e.getAttribute("data-type")||e.getAttribute("type");"radio"===n||"checkbox"===n?(e.disabled=t.disabled(e.value),e.checked=!t.diff(e.value)):m[n]&&(e.setAttribute("type","number"),e.setAttribute("data-type",n),e.value=t[n])}function E(r,t){t.firstElementChild||(t.innerHTML="\n <caption></caption><thead><tr>".concat(Array(8).join("</th><th>"),"</tr></thead>\n <tbody>").concat(Array(7).join("<tr>".concat(Array(8).join('<td><button type="button"></button></td>'),"</tr>")),"</tbody>"));var o=new Date,a=r.date.getMonth(),u=r.parse("y-m-1 mon");t.caption.textContent="".concat(r.months[a],", ").concat(r.year),h("th",t).forEach(function(t,e){return t.textContent=r.days[e]}),h("button",t).forEach(function(t){var e=!r.diff(u),n=u.getDate(),i=u.getMonth();t.textContent=n,t.value="".concat(u.getFullYear(),"-").concat(i+1,"-").concat(n),t.disabled=r.disabled(u),t.tabIndex=e-1,t.setAttribute("data-adjacent",a!==i),t.setAttribute("aria-label","".concat(n,". ").concat(r.months[i])),t.setAttribute("aria-current",u.getDate()===o.getDate()&&u.getMonth()===o.getMonth()&&u.getFullYear()===o.getFullYear()&&"date"),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,"")}(t,"autofocus",e),u.setDate(n+1)})}function _(n,i){i.firstElementChild||(i._autofill=!0,i.innerHTML=n.months.map(function(t,e){return'<option value="y-'.concat(e+1,'-d"></option>')}).join("")),h(i.children).forEach(function(t,e){i._autofill&&(t.textContent=n.months[e]),t.disabled=n.disabled(t.value),t.selected=!n.diff(t.value)})}return b}),window.customElements.define("core-datepicker",coreDatepicker); | ||
/*! @nrk/core-datepicker v3.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).coreDatepicker=e()}(this,function(){"use strict";function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function r(t){return(r=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 a(t,e,n){return(a=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 i=[null];i.push.apply(i,e);var r=new(Function.bind.apply(t,i));return n&&o(r,n.prototype),r}).apply(null,arguments)}function u(t){var n="function"==typeof Map?new Map:void 0;return(u=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 a(t,arguments,r(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));t||global.HTMLElement||(global.HTMLElement=function(){return function t(){e(this,t)}}());var c,s,d=(c="undefined"==typeof window?{}:window.Element.prototype,s=c.matches||c.msMatchesSelector||c.webkitMatchesSelector,c.closest?function(t,e){return t.closest(e)}:function(t,e){for(t.correspondingUseElement&&(t=t.correspondingUseElement);t;t=t.parentElement)if(s.call(t,e))return t;return null});function l(t,e,n){var i,r=2<arguments.length&&void 0!==n?n:{},o="prevent_recursive_dispatch_maximum_callstack".concat(e);if(t[o])return!0;t[o]=!0,"function"==typeof window.CustomEvent?i=new window.CustomEvent(e,{bubbles:!0,cancelable:!0,detail:r}):(i=document.createEvent("CustomEvent")).initCustomEvent(e,!0,!0,r);var a=t.dispatchEvent(i);return t[o]=null,a}function f(t,e){var n=1<arguments.length&&void 0!==e?e:document;if(t){if(t.nodeType)return[t];if("string"==typeof t)return[].slice.call(n.querySelectorAll(t));if(t.length)return[].slice.call(t)}return[]}"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;var h,y=(function(t,e){var b,v,k,w;t.exports=(b={year:"FullYear",month:"Month",week:"Date",day:"Date",hour:"Hours",minute:"Minutes",second:"Seconds"},v=/([+-]\s*\d+)\s*(second|minute|hour|day|week|month|year)|(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)/g,k=/([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,w=/([\dh]+):([\dm]+):?([\ds]+)?/,function(t,e){if(isFinite(t))return new Date(Number(t));var n=String(t).toLowerCase(),r=new Date(isFinite(e)&&-1===n.indexOf("now")?Number(e):Date.now()),i=n.match(k)||[],o=i[1];void 0===o&&(o="y");var a=i[2];void 0===a&&(a="m");var u=i[3];void 0===u&&(u="d");var c=n.match(w)||[],s=c[1];void 0===s&&(s="h");var d=c[2];void 0===d&&(d="m");var l=c[3];void 0===l&&(l="s");var f={year:o,month:a,day:u,hour:s,minute:d,second:l};Object.keys(f).forEach(function(t){var e="month"===t?1:0,i=String(r["get"+b[t]]()+e);f[t]=f[t].replace(/[^-\d]+/g,function(t,e,n){return e?i.substr(i.length-n.length+e,t.length):i.substr(0,Math.max(0,i.length-n.length+t.length))})-e});var h=new Date(f.year,Math.min(12,f.month+1),0).getDate();for(r.setFullYear(f.year,Math.min(11,f.month),Math.max(1,Math.min(h,f.day))),r.setHours(Math.min(24,f.hour),Math.min(59,f.minute),Math.min(59,f.second));null!==(f=v.exec(n));){var y=f[2],m=String(f[1]).replace(/\s/g,"")*("week"===y?7:1),p=f.slice(2).indexOf(f[0]),g=r.getDate();y?r["set"+b[y]](r["get"+b[y]]()+m):r.setDate(r.getDate()-(r.getDay()||7)+p),"month"!==y&&"year"!==y||g===r.getDate()||r.setDate(0)}return r})}(h={exports:{}},h.exports),h.exports),m={year:"*-m-d",month:"y-*-d",day:"y-m-*",hour:"*:m",minute:"h:*",second:"h:m:*",timestamp:"*",null:"*"},p={33:"-1month",34:"+1month",35:"y-m-99",36:"y-m-1",37:"-1day",38:"-1week",39:"+1day",40:"+1week"},g=function(){function t(){return e(this,t),n(this,r(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,u(HTMLElement)),function(t,e,n){e&&i(t.prototype,e),n&&i(t,n)}(t,[{key:"connectedCallback",value:function(){var t=this;this._date=this.date,document.addEventListener("click",this),document.addEventListener("change",this),document.addEventListener("keydown",this),setTimeout(function(){return t.attributeChangedCallback()}),function(t,e){var n="style-".concat(t.toLowerCase()),i=e.replace(/\/\*[^!][^*]*\*\//g,"").replace(/\s*(^|[:;,{}]|$)\s*/g,"$1");document.getElementById(n)||document.head.insertAdjacentHTML("afterbegin",'<style id="'.concat(n,'">').concat(i,"</style>"))}(this.nodeName,"".concat(this.nodeName,"{display:block}"))}},{key:"disconnectedCallback",value:function(){this._date=this._disabled=null,document.removeEventListener("click",this),document.removeEventListener("change",this),document.removeEventListener("keydown",this)}},{key:"attributeChangedCallback",value:function(){if(this._date){if(this.disabled(this.date)&&!this.disabled(this._date))return this.date=this._date;this.diff(this.date)&&l(this,"datepicker.change",this._date=this.date),v("button",this,k),v("select",this,_),v("input",this,w),v("table",this,E)}}},{key:"handleEvent",value:function(t){if(!(t.defaultPrevented||t.ctrlKey||t.metaKey||t.shiftKey||t.altKey||"keydown"===t.type&&!p[t.keyCode])&&(this.contains(t.target)||d(t.target,'[for="'.concat(this.id,'"]'))))if("change"===t.type)this.date=m[t.target.getAttribute("data-type")].replace("*",t.target.value);else if("click"===t.type){var e=d(t.target,"button[value]"),n=d(t.target,"table");e&&(this.date=e.value),e&&n&&l(this,"datepicker.click.day")}else"keydown"===t.type&&d(t.target,"table")&&(this.date=p[t.keyCode],this.querySelector("[autofocus]").focus(),t.preventDefault())}},{key:"diff",value:function(t){return this.parse(t).getTime()-this.timestamp}},{key:"parse",value:function(t,e){return y(t,e||this._date)}},{key:"disabled",get:function(){return this._disabled||Function.prototype},set:function(e){var n=this;this._disabled="function"==typeof e?function(t){return e(n.parse(t),n)}:function(){return e},this.attributeChangedCallback()}},{key:"timestamp",get:function(){return String(this._date.getTime())}},{key:"year",get:function(){return String(this._date.getFullYear())}},{key:"month",get:function(){return b(this._date.getMonth()+1)}},{key:"day",get:function(){return b(this._date.getDate())}},{key:"hour",get:function(){return b(this._date.getHours())}},{key:"minute",get:function(){return b(this._date.getMinutes())}},{key:"second",get:function(){return b(this._date.getSeconds())}},{key:"date",get:function(){return y(this.getAttribute("timestamp")||this._date||Date.now())},set:function(t){return this.setAttribute("timestamp",this.parse(t).getTime())}},{key:"months",set:function(t){this.setAttribute("months",[].concat(t).join(","))},get:function(){return(this.getAttribute("months")||"januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember").split(/\s*,\s*/)}},{key:"days",set:function(t){this.setAttribute("days",[].concat(t).join(","))},get:function(){return(this.getAttribute("days")||"man,tirs,ons,tors,fre,lør,søn").split(/\s*,\s*/)}}],[{key:"observedAttributes",get:function(){return["timestamp","months","days"]}}]),t}(),b=function(t){return"0".concat(t).slice(-2)},v=function(t,e,n){return[].forEach.call(document.getElementsByTagName(t),function(t){!e.contains(t)&&e.id!==t.getAttribute(e.external)||n(e,t)})};function k(t,e){e.value&&(e.type="button",e.disabled=t.disabled(e.value))}function w(t,e){var n=e.getAttribute("data-type")||e.getAttribute("type");"radio"===n||"checkbox"===n?(e.disabled=t.disabled(e.value),e.checked=!t.diff(e.value)):m[n]&&(e.setAttribute("type","number"),e.setAttribute("data-type",n),e.value=t[n])}function E(r,t){t.firstElementChild||(t.innerHTML="\n <caption></caption><thead><tr>".concat(Array(8).join("</th><th>"),"</tr></thead>\n <tbody>").concat(Array(7).join("<tr>".concat(Array(8).join('<td><button type="button"></button></td>'),"</tr>")),"</tbody>"));var o=new Date,a=r.date.getMonth(),u=r.parse("y-m-1 mon");t.caption.textContent="".concat(r.months[a],", ").concat(r.year),f("th",t).forEach(function(t,e){return t.textContent=r.days[e]}),f("button",t).forEach(function(t){var e=!r.diff(u),n=u.getDate(),i=u.getMonth();t.textContent=n,t.value="".concat(u.getFullYear(),"-").concat(i+1,"-").concat(n),t.disabled=r.disabled(u),t.tabIndex=e-1,t.setAttribute("data-adjacent",a!==i),t.setAttribute("aria-label","".concat(n,". ").concat(r.months[i])),t.setAttribute("aria-current",u.getDate()===o.getDate()&&u.getMonth()===o.getMonth()&&u.getFullYear()===o.getFullYear()&&"date"),function(t,e,n){var i=2<arguments.length&&void 0!==n?n:!this.hasAttribute(e);!i===t.hasAttribute(e)&&t[i?"setAttribute":"removeAttribute"](e,"")}(t,"autofocus",e),u.setDate(n+1)})}function _(n,i){i.firstElementChild||(i._autofill=!0,i.innerHTML=n.months.map(function(t,e){return'<option value="y-'.concat(e+1,'-d"></option>')}).join("")),f(i.children).forEach(function(t,e){i._autofill&&(t.textContent=n.months[e]),t.disabled=n.disabled(t.value),t.selected=!n.diff(t.value)})}return g}),window.customElements.define("core-datepicker",coreDatepicker); | ||
//# sourceMappingURL=core-datepicker.min.js.map |
@@ -1,212 +0,239 @@ | ||
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-datepicker.min.js') }) | ||
try { | ||
await run(t, page) | ||
} finally { | ||
await page.close() | ||
await browser.close() | ||
} | ||
} | ||
const coreDatepicker = fs.readFileSync(path.resolve(__dirname, 'core-datepicker.min.js'), 'utf-8') | ||
const customElements = fs.readFileSync(require.resolve('@webcomponents/custom-elements'), 'utf-8') | ||
const pad = (val) => `0${val}`.slice(-2) | ||
test('sets up properties', withPage, async (t, page) => { | ||
const date = new Date('2019-04-30T10:44:56') | ||
await page.setContent(`<core-datepicker timestamp="${date.getTime()}"></core-datepicker>`) | ||
t.is(await page.$eval('core-datepicker', el => el.year), '2019') | ||
t.is(await page.$eval('core-datepicker', el => el.month), '04') | ||
t.is(await page.$eval('core-datepicker', el => el.day), '30') | ||
t.is(await page.$eval('core-datepicker', el => el.hour), '10') | ||
t.is(await page.$eval('core-datepicker', el => el.minute), '44') | ||
t.is(await page.$eval('core-datepicker', el => el.second), '56') | ||
t.is(await page.$eval('core-datepicker', el => el.date.getTime()), date.getTime()) | ||
t.is(await page.$eval('core-datepicker', el => el.days.join(',')), 'man,tirs,ons,tors,fre,lør,søn') | ||
t.is(await page.$eval('core-datepicker', el => el.months.join(',')), | ||
'januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember') | ||
}) | ||
describe('core-datepicker', () => { | ||
beforeEach(async () => { | ||
await browser.refresh() | ||
await browser.executeScript(customElements) | ||
await browser.executeScript(coreDatepicker) | ||
}) | ||
test('sets input values from timestamp', withPage, async (t, page) => { | ||
const date = new Date('2019-04-30T10:44:56') | ||
await page.setContent(` | ||
<core-datepicker timestamp="${date.getTime()}"> | ||
<input type="year"> | ||
<input type="month"> | ||
<input type="day"> | ||
<input type="hour"> | ||
<input type="minute"> | ||
<input type="second"> | ||
<input type="timestamp"> | ||
</core-datepicker> | ||
`) | ||
t.true(await page.$$eval('core-datepicker input', els => els.every(el => el.type === 'number'))) | ||
t.true(await page.$$eval('core-datepicker input', els => els.every(el => el.hasAttribute('data-type')))) | ||
t.is(await page.$eval('core-datepicker input[data-type="year"]', el => el.value), '2019') | ||
t.is(await page.$eval('core-datepicker input[data-type="month"]', el => el.value), '04') | ||
t.is(await page.$eval('core-datepicker input[data-type="day"]', el => el.value), '30') | ||
t.is(await page.$eval('core-datepicker input[data-type="hour"]', el => el.value), '10') | ||
t.is(await page.$eval('core-datepicker input[data-type="minute"]', el => el.value), '44') | ||
t.is(await page.$eval('core-datepicker input[data-type="second"]', el => el.value), '56') | ||
t.is(await page.$eval('core-datepicker input[data-type="timestamp"]', el => el.value), String(date.getTime())) | ||
}) | ||
it('sets up properties', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker timestamp="${new Date('2019-04-30T12:44:56Z').getTime()}"> | ||
</core-datepicker> | ||
` | ||
}) | ||
await expect(prop('core-datepicker', 'year')).toEqual('2019') | ||
await expect(prop('core-datepicker', 'month')).toEqual('04') | ||
await expect(prop('core-datepicker', 'day')).toEqual('30') | ||
const hour = await browser.executeScript(() => new Date('2019-04-30T12:44:56Z').getHours()) | ||
await expect(prop('core-datepicker', 'hour')).toEqual(pad(String(hour))) | ||
await expect(prop('core-datepicker', 'minute')).toEqual('44') | ||
await expect(prop('core-datepicker', 'second')).toEqual('56') | ||
await expect(prop('core-datepicker', 'days')).toEqual('man,tirs,ons,tors,fre,lør,søn') | ||
await expect(prop('core-datepicker', 'months')).toEqual('januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember') | ||
}) | ||
test('populates empty select with months', withPage, async (t, page) => { | ||
await page.setContent(` | ||
<core-datepicker> | ||
<select></select> | ||
</core-datepicker> | ||
`) | ||
await page.waitFor('core-datepicker select option') | ||
t.is(await page.$eval('core-datepicker select', el => el.childElementCount), 12) | ||
for (let i = 1; i <= 12; i++) { | ||
t.is(await page.$eval(`core-datepicker option:nth-child(${i})`, el => el.value), `y-${i}-d`) | ||
} | ||
t.is(await page.$eval('core-datepicker option:nth-child(1)', el => el.textContent), 'januar') | ||
t.is(await page.$eval('core-datepicker option:nth-child(2)', el => el.textContent), 'februar') | ||
t.is(await page.$eval('core-datepicker option:nth-child(3)', el => el.textContent), 'mars') | ||
t.is(await page.$eval('core-datepicker option:nth-child(4)', el => el.textContent), 'april') | ||
t.is(await page.$eval('core-datepicker option:nth-child(5)', el => el.textContent), 'mai') | ||
t.is(await page.$eval('core-datepicker option:nth-child(6)', el => el.textContent), 'juni') | ||
t.is(await page.$eval('core-datepicker option:nth-child(7)', el => el.textContent), 'juli') | ||
t.is(await page.$eval('core-datepicker option:nth-child(8)', el => el.textContent), 'august') | ||
t.is(await page.$eval('core-datepicker option:nth-child(9)', el => el.textContent), 'september') | ||
t.is(await page.$eval('core-datepicker option:nth-child(10)', el => el.textContent), 'oktober') | ||
t.is(await page.$eval('core-datepicker option:nth-child(11)', el => el.textContent), 'november') | ||
t.is(await page.$eval('core-datepicker option:nth-child(12)', el => el.textContent), 'desember') | ||
}) | ||
it('sets input values from timestamp', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker timestamp="${new Date('2019-04-30T10:44:56Z').getTime()}"> | ||
<input type="year"> | ||
<input type="month"> | ||
<input type="day"> | ||
<input type="hour"> | ||
<input type="minute"> | ||
<input type="second"> | ||
<input type="timestamp"> | ||
</core-datepicker> | ||
` | ||
}) | ||
await expect(prop('input[data-type="year"]', 'value')).toEqual('2019') | ||
await expect(prop('input[data-type="year"]', 'type')).toEqual('number') | ||
await expect(prop('input[data-type="month"]', 'value')).toEqual('04') | ||
await expect(prop('input[data-type="month"]', 'type')).toEqual('number') | ||
await expect(prop('input[data-type="day"]', 'value')).toEqual('30') | ||
await expect(prop('input[data-type="day"]', 'type')).toEqual('number') | ||
const hours = await browser.executeScript(() => new Date('2019-04-30T10:44:56Z').getHours()) | ||
await expect(prop('input[data-type="hour"]', 'value')).toEqual(pad(String(hours))) | ||
await expect(prop('input[data-type="hour"]', 'type')).toEqual('number') | ||
await expect(prop('input[data-type="minute"]', 'value')).toEqual('44') | ||
await expect(prop('input[data-type="minute"]', 'type')).toEqual('number') | ||
await expect(prop('input[data-type="second"]', 'value')).toEqual('56') | ||
await expect(prop('input[data-type="second"]', 'type')).toEqual('number') | ||
const timestamp = await prop('core-datepicker', 'timestamp') | ||
await expect(prop('input[data-type="timestamp"]', 'value')).toEqual(timestamp) | ||
await expect(prop('input[data-type="timestamp"]', 'type')).toEqual('number') | ||
}) | ||
test('re-uses custom select', withPage, async (t, page) => { | ||
await page.setContent(` | ||
<core-datepicker> | ||
<select> | ||
<option>---</option> | ||
<option value="2016-m-d">Set year to 2016</option> | ||
<option value="19yy-1-1">Back 100 years and set to January 1st.</option> | ||
<option value="1985-12-19">December 19, 1985</option> | ||
</select> | ||
</core-datepicker> | ||
`) | ||
t.is(await page.$eval('core-datepicker select', el => el.childElementCount), 4) | ||
t.is(await page.$eval('core-datepicker option:nth-child(1)', el => el.value), '---') | ||
t.is(await page.$eval('core-datepicker option:nth-child(2)', el => el.value), '2016-m-d') | ||
t.is(await page.$eval('core-datepicker option:nth-child(3)', el => el.value), '19yy-1-1') | ||
}) | ||
it('populates empty select with months', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker> | ||
<select></select> | ||
</core-datepicker> | ||
` | ||
}) | ||
await browser.wait(ExpectedConditions.presenceOf($('core-datepicker select option'))) | ||
await expect(prop('core-datepicker select', 'childElementCount')).toEqual('12') | ||
for (let i = 1; i <= 12; i++) { | ||
await expect(prop(`option:nth-child(${i})`, 'value')).toEqual(`y-${i}-d`) | ||
} | ||
await expect(prop('option:nth-child(1)', 'textContent')).toEqual('januar') | ||
await expect(prop('option:nth-child(2)', 'textContent')).toEqual('februar') | ||
await expect(prop('option:nth-child(3)', 'textContent')).toEqual('mars') | ||
await expect(prop('option:nth-child(4)', 'textContent')).toEqual('april') | ||
await expect(prop('option:nth-child(5)', 'textContent')).toEqual('mai') | ||
await expect(prop('option:nth-child(6)', 'textContent')).toEqual('juni') | ||
await expect(prop('option:nth-child(7)', 'textContent')).toEqual('juli') | ||
await expect(prop('option:nth-child(8)', 'textContent')).toEqual('august') | ||
await expect(prop('option:nth-child(9)', 'textContent')).toEqual('september') | ||
await expect(prop('option:nth-child(10)', 'textContent')).toEqual('oktober') | ||
await expect(prop('option:nth-child(11)', 'textContent')).toEqual('november') | ||
await expect(prop('option:nth-child(12)', 'textContent')).toEqual('desember') | ||
}) | ||
test('populates empty table', withPage, async (t, page) => { | ||
const date = new Date('2018-01-01') | ||
await page.setContent(` | ||
<core-datepicker timestamp="${date.getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
`) | ||
await page.waitFor('core-datepicker table button') | ||
const days = await page.$eval('core-datepicker', el => el.days) | ||
t.is(days.length, 7) | ||
for (let i = 1; i <= 7; i++) { | ||
t.is(await page.$eval(`core-datepicker thead tr th:nth-child(${i})`, el => el.textContent), days[i - 1]) | ||
} | ||
t.is(await page.$$eval(`core-datepicker table td button[data-adjacent="false"]`, els => els.length), 31) | ||
t.is(await page.$eval('core-datepicker button[autofocus]', el => el.textContent), '1') | ||
}) | ||
it('re-uses custom select', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker> | ||
<select> | ||
<option>---</option> | ||
<option value="2016-m-d">Set year to 2016</option> | ||
<option value="19yy-1-1">Back 100 years and set to January 1st.</option> | ||
<option value="1985-12-19">December 19, 1985</option> | ||
</select> | ||
</core-datepicker> | ||
` | ||
}) | ||
await expect(prop('select', 'childElementCount')).toEqual('4') | ||
await expect(prop('option:nth-child(1)', 'value')).toEqual('---') | ||
await expect(prop('option:nth-child(2)', 'value')).toEqual('2016-m-d') | ||
await expect(prop('option:nth-child(3)', 'value')).toEqual('19yy-1-1') | ||
}) | ||
test('marks today\'s date in table', withPage, async (t, page) => { | ||
const date = new Date() | ||
await page.setContent(` | ||
<core-datepicker timestamp="${date.getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
`) | ||
await page.waitFor('core-datepicker table button') | ||
t.true(await page.$eval('core-datepicker button[aria-current="date"]', el => el !== null)) | ||
t.is(await page.$eval('core-datepicker button[aria-current="date"]', el => el.textContent), String(date.getDate())) | ||
}) | ||
it('populates empty table', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker timestamp="${new Date('2019-01-01T12:00:00Z').getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
` | ||
}) | ||
await browser.wait(ExpectedConditions.presenceOf($('core-datepicker table button'))) | ||
const days = (await prop('core-datepicker', 'days')).split(',') | ||
await expect(days.length).toEqual(7) | ||
for (let i = 1; i <= 7; i++) { | ||
await expect(prop(`thead tr th:nth-child(${i})`, 'textContent')).toEqual(days[i - 1]) | ||
} | ||
await expect($$('table td button[data-adjacent="false"]').count()).toEqual(31) | ||
await expect(prop('button[autofocus]', 'textContent')).toEqual('1') | ||
}) | ||
test('changes date on day clicked', withPage, async (t, page) => { | ||
const date = new Date('2018-01-01') | ||
await page.setContent(` | ||
<core-datepicker timestamp="${date.getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
`) | ||
await page.waitFor('core-datepicker table button') | ||
t.is(await page.$eval('core-datepicker button[autofocus]', el => el.textContent), '1') | ||
await page.click('core-datepicker tbody tr:nth-child(2) td:nth-child(5) button') | ||
t.is(await page.$eval('core-datepicker button[autofocus]', el => el.textContent), '12') | ||
}) | ||
it('marks today\'s date in table', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker timestamp="${new Date().getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
` | ||
}) | ||
test('changes month names', withPage, async (t, page) => { | ||
const months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'oktober', 'november', 'december'] | ||
await page.setContent(` | ||
<core-datepicker months="${months.join()}"> | ||
<select></select> | ||
</core-datepicker>` | ||
) | ||
await page.waitFor('core-datepicker select option') | ||
t.is(await page.$eval('core-datepicker select', el => el.childElementCount), 12) | ||
for (let i = 1; i <= 12; i++) { | ||
t.is(await page.$eval(`core-datepicker option:nth-child(${i})`, el => el.textContent), months[i - 1]) | ||
} | ||
}) | ||
await browser.wait(ExpectedConditions.presenceOf($('core-datepicker table button'))) | ||
await expect($('button[aria-current="date"]').isPresent()).toEqual(true) | ||
const browserDate = await browser.executeScript(() => new Date().getDate()) | ||
await expect(prop('button[aria-current="date"]', 'textContent')).toEqual(String(browserDate)) | ||
}) | ||
test('changes day names', withPage, async (t, page) => { | ||
const days = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu'] | ||
await page.setContent(` | ||
<core-datepicker days="${days.join()}"> | ||
<table></table> | ||
</core-datepicker>` | ||
) | ||
await page.waitFor('core-datepicker table thead') | ||
t.is(await page.$eval('core-datepicker table thead tr', el => el.childElementCount), 7) | ||
for (let i = 1; i <= 7; i++) { | ||
t.is(await page.$eval(`core-datepicker thead tr th:nth-child(${i})`, el => el.textContent), days[i - 1]) | ||
} | ||
}) | ||
it('changes date on day clicked', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker timestamp="${new Date('2019-01-01T12:00:00Z').getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
` | ||
}) | ||
await browser.wait(ExpectedConditions.presenceOf($('core-datepicker table button'))) | ||
await expect(prop('button[autofocus]', 'textContent')).toEqual('1') | ||
await $('tbody tr:nth-child(2) td:nth-child(5) button').click() | ||
await expect(prop('button[autofocus]', 'textContent')).toEqual('11') | ||
}) | ||
test('disables elements from function', withPage, async (t, page) => { | ||
const date = new Date('2018-01-01') | ||
await page.setContent(` | ||
<core-datepicker timestamp="${date.getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
`) | ||
await page.evaluate(() => (document.querySelector('core-datepicker').disabled = date => date > new Date('2018-01-01'))) | ||
await page.waitFor('core-datepicker table button') | ||
it('changes month names', async () => { | ||
const months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'oktober', 'november', 'december'] | ||
await browser.executeScript((months) => { | ||
document.body.innerHTML = ` | ||
<core-datepicker months="${months.join()}"> | ||
<select></select> | ||
</core-datepicker> | ||
` | ||
}, months) | ||
await browser.wait(ExpectedConditions.presenceOf($('core-datepicker select option'))) | ||
await expect(prop('select', 'childElementCount')).toEqual('12') | ||
for (let i = 1; i <= 12; i++) { | ||
await expect(prop(`option:nth-child(${i})`, 'textContent')).toEqual(months[i - 1]) | ||
} | ||
}) | ||
t.false(await page.$eval('core-datepicker tbody tr:nth-child(1) td:nth-child(1) button', el => el.disabled)) | ||
t.true(await page.$$eval('core-datepicker tbody tr:nth-child(2) button', els => els.every(el => el.disabled))) | ||
t.true(await page.$$eval('core-datepicker tbody tr:nth-child(3) button', els => els.every(el => el.disabled))) | ||
t.true(await page.$$eval('core-datepicker tbody tr:nth-child(4) button', els => els.every(el => el.disabled))) | ||
}) | ||
it('changes day names', async () => { | ||
const days = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu'] | ||
await browser.executeScript((days) => { | ||
document.body.innerHTML = ` | ||
<core-datepicker days="${days.join()}"> | ||
<table></table> | ||
</core-datepicker> | ||
` | ||
}, days) | ||
await browser.wait(ExpectedConditions.presenceOf($('core-datepicker table thead'))) | ||
await expect(prop('table thead tr', 'childElementCount')).toEqual('7') | ||
for (let i = 1; i <= 7; i++) { | ||
await expect(prop(`thead tr th:nth-child(${i})`, 'textContent')).toEqual(days[i - 1]) | ||
} | ||
}) | ||
test('triggers change event', withPage, async (t, page) => { | ||
const date = new Date('2018-01-01') | ||
const expected = new Date('2018-01-02') | ||
await page.setContent(`<core-datepicker timestamp="${date.getTime()}"></core-datepicker>`) | ||
const newDate = await page.evaluate(() => { | ||
return new Promise((resolve, reject) => { | ||
window.addEventListener('datepicker.change', ({ detail }) => resolve(detail.getTime())) | ||
document.querySelector('core-datepicker').date = new Date('2018-01-02') | ||
it('disables elements from function', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker timestamp="${new Date('2019-01-01T12:00:00Z').getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
` | ||
document.querySelector('core-datepicker').disabled = (date) => { | ||
return date > new Date('2019-01-01T12:00:00Z') | ||
} | ||
}) | ||
await browser.wait(ExpectedConditions.presenceOf($('core-datepicker table button'))) | ||
await expect(attr('tbody tr:nth-child(1) td:nth-child(1) button', 'disabled')).toMatch(/(null|false)/i) | ||
// before the date | ||
await expect($('button:not(disabled)[value="2018-12-31"]').isPresent()).toBeTruthy() | ||
await expect($('button:not(disabled)[value="2019-1-1"]').isPresent()).toBeTruthy() | ||
// after | ||
await expect($('button:disabled[value="2019-1-2"]').isPresent()).toBeTruthy() | ||
}) | ||
t.is(newDate, expected.getTime()) | ||
}) | ||
test('triggers click day event', withPage, async (t, page) => { | ||
const date = new Date('2018-01-01') | ||
await page.setContent(` | ||
<core-datepicker timestamp="${date.getTime()}"> | ||
<table></table> | ||
</core-datepicker>` | ||
) | ||
await page.evaluate(() => { | ||
return new Promise((resolve, reject) => { | ||
window.addEventListener('datepicker.click.day', resolve) | ||
it('triggers change event', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker timestamp="${new Date('2019-01-01T12:00:00Z').getTime()}"> | ||
</core-datepicker> | ||
` | ||
document.addEventListener('datepicker.change', (event) => (window.time = event.detail.getTime())) | ||
document.querySelector('core-datepicker').date = new Date('2019-01-02T12:00:00Z') | ||
}) | ||
const time = await browser.executeScript(() => new Date('2019-01-02T12:00:00Z').getTime()) | ||
await expect(browser.executeScript(() => window.time)).toEqual(time) | ||
}) | ||
it('triggers click day event', async () => { | ||
await browser.executeScript(() => { | ||
document.body.innerHTML = ` | ||
<core-datepicker timestamp="${new Date().getTime()}"> | ||
<table></table> | ||
</core-datepicker> | ||
` | ||
}) | ||
await browser.wait(ExpectedConditions.presenceOf($('core-datepicker table button'))) | ||
await browser.executeScript(() => { | ||
document.addEventListener('datepicker.click.day', () => (window.triggered = true)) | ||
document.querySelector('core-datepicker button').click() | ||
}) | ||
await expect(browser.executeScript(() => window.triggered)).toEqual(true) | ||
}) | ||
t.pass() | ||
}) |
92
jsx.js
@@ -184,2 +184,6 @@ 'use strict'; | ||
} : function (el, css) { | ||
// IE jumps to shadow SVG DOM on clicking an SVG defined by <use>. | ||
// If so, jump back to <use> element and traverse real DOM | ||
if (el.correspondingUseElement) el = el.correspondingUseElement; | ||
for (; el; el = el.parentElement) { | ||
@@ -569,3 +573,3 @@ if (match.call(el, css)) return el; | ||
button.tabIndex = isSelected - 1; | ||
button.setAttribute("data-adjacent", month !== dayMonth); | ||
button.setAttribute('data-adjacent', month !== dayMonth); | ||
button.setAttribute('aria-label', "".concat(dayInMonth, ". ").concat(self.months[dayMonth])); | ||
@@ -593,8 +597,8 @@ button.setAttribute('aria-current', day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear() && 'date'); | ||
var version = "3.0.7"; | ||
var version = "3.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 | ||
@@ -620,4 +624,4 @@ */ | ||
* 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 | ||
@@ -639,4 +643,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(); | ||
@@ -648,6 +660,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') { | ||
@@ -660,14 +671,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$1(event.target, this$1.el.nodeName) === this$1.el) { | ||
this$1.props[onEventName](event); | ||
} | ||
}; | ||
skipProps.push(on); // Skip props that are customEvents | ||
}); | ||
@@ -681,20 +691,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]; | ||
} | ||
}); | ||
@@ -704,5 +721,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]); | ||
}); | ||
@@ -714,13 +732,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 | ||
@@ -727,0 +745,0 @@ |
@@ -5,3 +5,3 @@ { | ||
"author": "NRK <opensource@nrk.no> (https://www.nrk.no/)", | ||
"version": "3.0.7", | ||
"version": "3.0.8", | ||
"license": "MIT", | ||
@@ -8,0 +8,0 @@ "main": "core-datepicker.cjs.js", |
@@ -166,3 +166,5 @@ # Core Datepicker | ||
Remember to [polyfill](https://github.com/webcomponents/polyfills#custom-elements) custom elements if needed. | ||
## Usage | ||
@@ -255,2 +257,4 @@ | ||
days={String} // Optional. Comma separated list of custom weekday names to be used ("Man,Tir,Ons,...") | ||
ref={(comp) => {}} // Optional. Get reference to React component | ||
forwardRef={(el) => {}} // Optional. Get reference to underlying DOM custom element | ||
onDatepickerChange={Function} // Optional. See 'datepicker.change' | ||
@@ -257,0 +261,0 @@ onDatepickerClickDay={Function}> // Optional. See 'datepicker.click.day' |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
200941
17.03%12
9.09%2737
27.6%317
1.28%3
200%