Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@nrk/core-datepicker

Package Overview
Dependencies
Maintainers
128
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nrk/core-datepicker - npm Package Compare versions

Comparing version 2.1.0 to 3.0.0

.DS_Store

625

core-datepicker.cjs.js
'use strict';
var name = "@nrk/core-datepicker";
var version = "2.0.3";
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
return true;
} catch (e) {
return false;
}
}
function _construct(Parent, args, Class) {
if (isNativeReflectConstruct()) {
_construct = Reflect.construct;
} else {
_construct = function _construct(Parent, args, Class) {
var a = [null];
a.push.apply(a, args);
var Constructor = Function.bind.apply(Parent, a);
var instance = new Constructor();
if (Class) _setPrototypeOf(instance, Class.prototype);
return instance;
};
}
return _construct.apply(null, arguments);
}
function _isNativeFunction(fn) {
return Function.toString.call(fn).indexOf("[native code]") !== -1;
}
function _wrapNativeSuper(Class) {
var _cache = typeof Map === "function" ? new Map() : undefined;
_wrapNativeSuper = function _wrapNativeSuper(Class) {
if (Class === null || !_isNativeFunction(Class)) return Class;
if (typeof Class !== "function") {
throw new TypeError("Super expression must either be null or a function");
}
if (typeof _cache !== "undefined") {
if (_cache.has(Class)) return _cache.get(Class);
_cache.set(Class, Wrapper);
}
function Wrapper() {
return _construct(Class, arguments, _getPrototypeOf(this).constructor);
}
Wrapper.prototype = Object.create(Class.prototype, {
constructor: {
value: Wrapper,
enumerable: false,
writable: true,
configurable: true
}
});
return _setPrototypeOf(Wrapper, Class);
};
return _wrapNativeSuper(Class);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _possibleConstructorReturn(self, call) {
if (call && (typeof call === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
var IS_BROWSER = typeof window !== 'undefined';
var IS_ANDROID = IS_BROWSER && /(android)/i.test(navigator.userAgent); // Bad, but needed
var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(String(navigator.platform));
var HAS_EVENT_OPTIONS = (function (has) {
if ( has === void 0 ) has = false;
try { window.addEventListener('test', null, { get passive () { has = true; } }); } catch (e) {}
return has
})();
var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(String(navigator.platform)); // Polyfill toggleAttribute for IE
if (IS_BROWSER && !window.Element.prototype.toggleAttribute) {
window.Element.prototype.toggleAttribute = function (name) {
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : !this.hasAttribute(name);
if (!force === this.hasAttribute(name)) this[force ? 'setAttribute' : 'removeAttribute'](name, '');
return force;
};
}
/**
* addEvent
* @param {String} uuid An unique ID of the event to bind - ensurnes single instance
* @param {String} type The type of event to bind
* @param {Function} handler The function to call on event
* @param {Boolean|Object} options useCapture or options object for addEventListener. Defaults to false
* addStyle
* @param {String} nodeName An unique ID of the event to bind - ensurnes single instance
* @param {String} css The css to inject
*/
function addEvent (uuid, type, handler, options) {
if ( options === void 0 ) options = false;
if (typeof window === 'undefined' || window[uuid = uuid + "-" + type]) { return } // Ensure single instance
if (!HAS_EVENT_OPTIONS && typeof options === 'object') { options = Boolean(options.capture); } // Fix unsupported options
var node = (type === 'resize' || type === 'load') ? window : document;
node.addEventListener(window[uuid] = type, handler, options);
function addStyle(nodeName, css) {
var key = "style-".concat(nodeName.toLowerCase());
var min = css.replace(/\/\*[^!][^*]*\*\//g, '').replace(/\s*(^|[:;,{}]|$)\s*/g, '$1');
document.getElementById(key) || document.head.insertAdjacentHTML('afterbegin', "<style id=\"".concat(key, "\">").concat(min, "</style>"));
}
/**

@@ -37,7 +168,36 @@ * escapeHTML

*/
var ESCAPE_MAP = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', '/': '&#x2F;', '\'': '&#x27;' };
function escapeHTML (str) {
return String(str || '').replace(/[&<>"'/]/g, function (char) { return ESCAPE_MAP[char]; })
var ESCAPE_MAP = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'/': '&#x2F;',
'\'': '&#x27;'
};
function escapeHTML(str) {
return String(str || '').replace(/[&<>"'/]/g, function (_char) {
return ESCAPE_MAP[_char];
});
}
/**
* 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;
};
}();
/**

@@ -50,26 +210,28 @@ * dispatchEvent - with infinite loop prevention

*/
var IGNORE = 'prevent_recursive_dispatch_maximum_callstack';
function dispatchEvent (element, name, detail) {
if ( detail === void 0 ) detail = {};
var ignore = "" + IGNORE + name;
function dispatchEvent(element, name) {
var detail = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var ignore = "prevent_recursive_dispatch_maximum_callstack".concat(name);
var event;
if (element[ignore]) return true; // We are already processing this event, so skip sending a new one
else element[ignore] = true; // Add name to dispatching ignore
if (element[ignore]) { return true } // We are already processing this event, so skip sending a new one
else { element[ignore] = true; } // Add name to dispatching ignore
if (typeof window.CustomEvent === 'function') {
event = new window.CustomEvent(name, { bubbles: true, cancelable: true, detail: detail });
event = new window.CustomEvent(name, {
bubbles: true,
cancelable: true,
detail: detail
});
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(name, true, true, detail);
}
// IE reports incorrect event.defaultPrevented
} // IE reports incorrect event.defaultPrevented
// but correct return value on element.dispatchEvent
var result = element.dispatchEvent(event);
element[ignore] = null; // Remove name from dispatching ignore
return result // Follow W3C standard for return value
return result; // Follow W3C standard for return value
}
/**

@@ -80,14 +242,16 @@ * queryAll

*/
function queryAll (elements, context) {
if ( context === void 0 ) context = document;
function queryAll(elements) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;
if (elements) {
if (elements.nodeType) { return [elements] }
if (typeof elements === 'string') { return [].slice.call(context.querySelectorAll(elements)) }
if (elements.length) { return [].slice.call(elements) }
if (elements.nodeType) return [elements];
if (typeof elements === 'string') return [].slice.call(context.querySelectorAll(elements));
if (elements.length) return [].slice.call(elements);
}
return []
return [];
}
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

@@ -99,121 +263,304 @@ function createCommonjsModule(fn, module) {

var index_min = createCommonjsModule(function (module, exports) {
!function(e,t){module.exports=t();}(commonjsGlobal,function(){var D={year:"FullYear",month:"Month",week:"Date",day:"Date",hour:"Hours",minute:"Minutes",second:"Seconds"},w=/([+-]\s*\d+)\s*(second|minute|hour|day|week|month|year)|(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)/g,M=/([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,p=/([\dh]+):([\dm]+):?([\ds]+)?/;return function(e,t){if(isFinite(e)){ return new Date(Number(e)); }var n=String(e).toLowerCase(),r=new Date(isFinite(t)&&-1===n.indexOf("now")?Number(t):Date.now()),a=n.match(M)||[],o=a[1];void 0===o&&(o="y");var i=a[2];void 0===i&&(i="m");var s=a[3];void 0===s&&(s="d");var d=n.match(p)||[],u=d[1];void 0===u&&(u="h");var h=d[2];void 0===h&&(h="m");var m=d[3];void 0===m&&(m="s");var c={year:o,month:i,day:s,hour:u,minute:h,second:m};Object.keys(c).forEach(function(e){var t="month"===e?1:0,a=String(r["get"+D[e]]()+t);c[e]=c[e].replace(/[^-\d]+/g,function(e,t,n){return t?a.substr(a.length-n.length+t,e.length):a.substr(0,Math.max(0,a.length-n.length+e.length))})-t;});var f=new Date(c.year,Math.min(12,c.month+1),0).getDate();for(r.setFullYear(c.year,Math.min(11,c.month),Math.max(1,Math.min(f,c.day))),r.setHours(Math.min(24,c.hour),Math.min(59,c.minute),Math.min(59,c.second));null!==(c=w.exec(n));){var g=c[2],l=String(c[1]).replace(/\s/g,"")*("week"===g?7:1),v=c.slice(2).indexOf(c[0]),y=r.getDate();g?r["set"+D[g]](r["get"+D[g]]()+l):r.setDate(r.getDate()-(r.getDay()||7)+v),"month"!==g&&"year"!==g||y===r.getDate()||r.setDate(0);}return r}});
!function (e, t) {
module.exports = t();
}(commonjsGlobal, function () {
var D = {
year: "FullYear",
month: "Month",
week: "Date",
day: "Date",
hour: "Hours",
minute: "Minutes",
second: "Seconds"
},
w = /([+-]\s*\d+)\s*(second|minute|hour|day|week|month|year)|(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)/g,
M = /([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,
p = /([\dh]+):([\dm]+):?([\ds]+)?/;
return function (e, t) {
if (isFinite(e)) return new Date(Number(e));
var n = String(e).toLowerCase(),
r = new Date(isFinite(t) && -1 === n.indexOf("now") ? Number(t) : Date.now()),
a = n.match(M) || [],
o = a[1];
void 0 === o && (o = "y");
var i = a[2];
void 0 === i && (i = "m");
var s = a[3];
void 0 === s && (s = "d");
var d = n.match(p) || [],
u = d[1];
void 0 === u && (u = "h");
var h = d[2];
void 0 === h && (h = "m");
var m = d[3];
void 0 === m && (m = "s");
var c = {
year: o,
month: i,
day: s,
hour: u,
minute: h,
second: m
};
Object.keys(c).forEach(function (e) {
var t = "month" === e ? 1 : 0,
a = String(r["get" + D[e]]() + t);
c[e] = c[e].replace(/[^-\d]+/g, function (e, t, n) {
return t ? a.substr(a.length - n.length + t, e.length) : a.substr(0, Math.max(0, a.length - n.length + e.length));
}) - t;
});
var f = new Date(c.year, Math.min(12, c.month + 1), 0).getDate();
for (r.setFullYear(c.year, Math.min(11, c.month), Math.max(1, Math.min(f, c.day))), r.setHours(Math.min(24, c.hour), Math.min(59, c.minute), Math.min(59, c.second)); null !== (c = w.exec(n));) {
var g = c[2],
l = String(c[1]).replace(/\s/g, "") * ("week" === g ? 7 : 1),
v = c.slice(2).indexOf(c[0]),
y = r.getDate();
g ? r["set" + D[g]](r["get" + D[g]]() + l) : r.setDate(r.getDate() - (r.getDay() || 7) + v), "month" !== g && "year" !== g || y === r.getDate() || r.setDate(0);
}
return r;
};
});
});
var ATTR = 'data-core-datepicker';
var UUID = ("data-" + name + "-" + version).replace(/\W+/g, '-'); // Strip invalid attribute characters
var KEY_CODES = { 33: '-1month', 34: '+1month', 35: 'y-m-99', 36: 'y-m-1', 37: '-1day', 38: '-1week', 39: '+1day', 40: '+1week' };
var MASK = { year: '*-m-d', month: 'y-*-d', day: 'y-m-*', hour: '*:m', minute: 'h:*', second: 'h:m:*', timestamp: '*' };
var MS_IN_MINUTES = 60000;
var MASK = {
year: '*-m-d',
month: 'y-*-d',
day: 'y-m-*',
hour: '*:m',
minute: 'h:*',
second: 'h:m:*',
timestamp: '*',
"null": '*'
};
var KEYS = {
33: '-1month',
34: '+1month',
35: 'y-m-99',
36: 'y-m-1',
37: '-1day',
38: '-1week',
39: '+1day',
40: '+1week'
};
var MONTHS = 'januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember';
var DAYS = 'man,tirs,ons,tors,fre,lør,søn';
function datepicker (elements, date) { // date can be String, Timestamp or Date
return queryAll(elements).map(function (element) {
var prevDate = index_min(element.getAttribute(UUID) || date);
var nextDate = index_min(typeof date === 'undefined' ? prevDate : date, prevDate);
var disable = function () { return false; };
var CoreDatepicker =
/*#__PURE__*/
function (_HTMLElement) {
_inherits(CoreDatepicker, _HTMLElement);
dispatchEvent(element, 'datepicker.render', { nextDate: nextDate, prevDate: prevDate, disable: function (fn) { return (disable = fn); } });
if (disable(nextDate)) { nextDate = prevDate; } // Jump back to prev date if next is disabled
function CoreDatepicker() {
_classCallCheck(this, CoreDatepicker);
var isUpdate = prevDate.getTime() === nextDate.getTime() || dispatchEvent(element, 'datepicker.change', { prevDate: prevDate, nextDate: nextDate });
var next = isUpdate ? nextDate : index_min(element.getAttribute(UUID) || Date.now()); // dispatchEvent can change attributes to parse prevDate again
var json = new Date(next.getTime() - next.getTimezoneOffset() * MS_IN_MINUTES).toJSON().match(/\d+/g);
var unit = { year: next.getFullYear(), month: json[1], day: json[2], hour: json[3], minute: json[4], second: json[5], timestamp: next.getTime() };
return _possibleConstructorReturn(this, _getPrototypeOf(CoreDatepicker).apply(this, arguments));
}
element.setAttribute(UUID, unit.timestamp);
queryAll('button').forEach(function (el) { return button(el, next, disable, element); });
queryAll('select', element).concat(queryAll(("select[" + ATTR + "=\"" + (element.id) + "\"]"))).forEach(function (el) { return select(el, next, disable); });
queryAll('input', element).concat(queryAll(("input[" + ATTR + "=\"" + (element.id) + "\"]"))).forEach(function (el) { return input(el, next, disable, unit); });
queryAll('table', element).concat(queryAll(("table[" + ATTR + "=\"" + (element.id) + "\"]"))).forEach(function (el) { return table(el, next, disable); });
_createClass(CoreDatepicker, [{
key: "connectedCallback",
value: function connectedCallback() {
var _this = this;
return element
})
}
this._date = this.date; // Store for later comparison and speeding up things
// Expose API and config
datepicker.parse = index_min;
datepicker.months = ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'];
datepicker.days = ['man', 'tirs', 'ons', 'tors', 'fre', 'lør', 'søn'];
document.addEventListener('click', this);
document.addEventListener('change', this);
document.addEventListener('keydown', this);
setTimeout(function () {
return _this.attributeChangedCallback();
}); // Render after children is parsed
addEvent(UUID, 'change', onChange);
addEvent(UUID, 'click', function (ref) {
var target = ref.target;
addStyle(this.nodeName, "".concat(this.nodeName, "{display:block}")); // default to display block
}
}, {
key: "disconnectedCallback",
value: function disconnectedCallback() {
this._date = this._disabled = null; // Garbage collection
for (var el = target; el; el = el.parentElement) {
if (el.nodeName === 'BUTTON') { return onChange({ target: el }) }
}
});
addEvent(UUID, 'keydown', function (event) {
if (event.ctrlKey || event.metaKey || event.shitKey || event.altKey || !KEY_CODES[event.keyCode]) { return }
for (var el = event.target, table = (void 0); el; el = el.parentElement) {
if (!table && el.nodeName === 'TABLE') { table = el; } // Store table while traversing DOM parents
if (table && el.hasAttribute(UUID)) { // Only listen to keyCodes inside table inside datepicker
datepicker(el, KEY_CODES[event.keyCode]);
table.querySelector(("[" + ATTR + "-selected=\"true\"]")).focus();
event.preventDefault();
break
document.removeEventListener('click', this);
document.removeEventListener('change', this);
document.removeEventListener('keydown', this);
}
}
});
}, {
key: "attributeChangedCallback",
value: function attributeChangedCallback() {
if (!this._date) return; // Only render after connectedCallback
function onChange (ref) {
var target = ref.target;
if (this.disabled(this.date) && !this.disabled(this._date)) return this.date = this._date; // Jump back
for (var el = target, table = (void 0); el; el = el.parentElement) {
var elem = document.getElementById(el.getAttribute(ATTR)) || el;
var mask = elem.hasAttribute(UUID) && (MASK[target.getAttribute((UUID + "-type"))] || '*');
if (this.diff(this.date)) dispatchEvent(this, 'datepicker.change', this._date = this.date);
forEach('button', this, button);
forEach('select', this, select);
forEach('input', this, input);
forEach('table', this, table);
}
}, {
key: "handleEvent",
value: function handleEvent(event) {
if (event.defaultPrevented || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey || event.type === 'keydown' && !KEYS[event.keyCode]) return;
if (!this.contains(event.target) && !closest(event.target, "[for=\"".concat(this.id, "\"]"))) return;
if (event.type === 'change') this.date = MASK[event.target.getAttribute('data-type')].replace('*', event.target.value);else if (event.type === 'click') {
var _button = closest(event.target, 'button[value]');
if (!table && el.nodeName === 'TABLE') { table = el; } // Store table while traversing DOM parents
if (mask) {
var nextDate = mask.replace('*', target.value);
var isUpdate = !elem.contains(table) || dispatchEvent(elem, 'datepicker.click.day', {
currentTarget: target,
relatedTarget: table,
prevDate: index_min(elem.getAttribute(UUID)),
nextDate: index_min(nextDate)
});
var _table = closest(event.target, 'table');
return isUpdate && datepicker(elem, nextDate)
if (_button) this.date = _button.value;
if (_button && _table) dispatchEvent(this, 'datepicker.click.day');
} else if (event.type === 'keydown' && closest(event.target, 'table')) {
this.date = KEYS[event.keyCode];
this.querySelector('[autofocus]').focus();
event.preventDefault(); // Prevent scrolling
}
}
}
}, {
key: "diff",
value: function diff(val) {
return this.parse(val).getTime() - this.timestamp;
}
}, {
key: "parse",
value: function parse(val, from) {
return index_min(val, from || this._date);
}
}, {
key: "disabled",
get: function get() {
return this._disabled || Function.prototype;
},
set: function set(fn) {
var _this2 = this;
this._disabled = typeof fn === 'function' ? function (val) {
return fn(_this2.parse(val), _this2);
} : function () {
return fn;
}; // Auto parse dates
this.attributeChangedCallback(); // Re-render
}
}, {
key: "timestamp",
get: function get() {
return String(this._date.getTime());
}
}, {
key: "year",
get: function get() {
return String(this._date.getFullYear());
} // Stringify for consistency and for truthy '0'
}, {
key: "month",
get: function get() {
return pad(this._date.getMonth() + 1);
}
}, {
key: "day",
get: function get() {
return pad(this._date.getDate());
}
}, {
key: "hour",
get: function get() {
return pad(this._date.getHours());
}
}, {
key: "minute",
get: function get() {
return pad(this._date.getMinutes());
}
}, {
key: "second",
get: function get() {
return pad(this._date.getSeconds());
}
}, {
key: "date",
get: function get() {
return index_min(this.getAttribute('timestamp') || this._date || Date.now());
},
set: function set(val) {
return this.setAttribute('timestamp', this.parse(val).getTime());
}
}, {
key: "months",
set: function set(val) {
this.setAttribute('months', [].concat(val).join(','));
},
get: function get() {
return (this.getAttribute('months') || MONTHS).split(/\s*,\s*/);
}
}, {
key: "days",
set: function set(val) {
this.setAttribute('days', [].concat(val).join(','));
},
get: function get() {
return (this.getAttribute('days') || DAYS).split(/\s*,\s*/);
}
}], [{
key: "observedAttributes",
get: function get() {
return ['timestamp', 'months', 'days'];
}
}]);
return CoreDatepicker;
}(_wrapNativeSuper(HTMLElement));
var pad = function pad(val) {
return "0".concat(val).slice(-2);
};
var forEach = function forEach(css, self, fn) {
return [].forEach.call(document.getElementsByTagName(css), function (el) {
if (self.contains(el) || self.id === el.getAttribute(self.external)) fn(self, el, self._date);
});
};
function button(self, el) {
el.disabled = self.disabled(el.value);
}
function input (el, date, disable, unit) {
var type = el.getAttribute((UUID + "-type")) || el.getAttribute('type');
function input(self, el) {
var type = el.getAttribute('data-type') || el.getAttribute('type');
if (type === 'radio' || type === 'checkbox') {
var val = index_min(el.value, date);
el.disabled = disable(val);
el.checked = val.getTime() === date.getTime();
} else if (unit[type]) {
el.disabled = self.disabled(el.value);
el.checked = !self.diff(el.value);
} else if (MASK[type]) {
el.setAttribute('type', 'number'); // Set input type to number
el.setAttribute((UUID + "-type"), type); // And store original input type
el.value = unit[type];
el.setAttribute('data-type', type); // And store original type
el.value = self[type];
}
}
function table (table, date, disable) {
function table(self, table) {
if (!table.firstElementChild) {
table.innerHTML = "\n <caption></caption><thead><tr><th>" + (datepicker.days.map(escapeHTML).join('</th><th>')) + "</th></tr></thead>\n <tbody>" + (Array(7).join(("<tr>" + (Array(8).join("<td><button type=\"button\"></button></td>")) + "</tr>"))) + "</tbody>";
table.innerHTML = "\n <caption></caption><thead><tr><th>".concat(self.days.map(escapeHTML).join('</th><th>'), "</th></tr></thead>\n <tbody>").concat(Array(7).join("<tr>".concat(Array(8).join('<td><button type="button"></button></td>'), "</tr>")), "</tbody>");
}
var today = new Date();
var day = index_min('y-m-1 mon', date); // Monday in first week of month
table.caption.textContent = (escapeHTML(datepicker.months[date.getMonth()])) + ", " + (date.getFullYear());
var month = self.date.getMonth();
var day = self.parse('y-m-1 mon'); // Monday in first week of month
table.caption.textContent = "".concat(self.months[month], ", ").concat(self.year);
queryAll('button', table).forEach(function (button) {
var isToday = day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear();
var isSelected = day.getTime() === date.getTime();
var isSelected = !self.diff(day);
var dayInMonth = day.getDate();
var month = day.getMonth();
var dayMonth = day.getMonth();
button.textContent = dayInMonth; // Set textContent instead of innerHTML avoids reflow
button.textContent = dayInMonth; // Set textContent instead of innerHTML avoids reflow
button.value = (day.getFullYear()) + "-" + (month + 1) + "-" + dayInMonth;
button.disabled = disable(day);
button.setAttribute('tabindex', isSelected - 1);
button.setAttribute((ATTR + "-selected"), isSelected);
button.setAttribute((ATTR + "-adjacent"), date.getMonth() !== month);
button.setAttribute('aria-label', (dayInMonth + ". " + (datepicker.months[month])));
button[isToday ? 'setAttribute' : 'removeAttribute']('aria-current', 'date');
button[isSelected ? 'setAttribute' : 'removeAttribute']('autofocus', '');
button.value = "".concat(day.getFullYear(), "-").concat(dayMonth + 1, "-").concat(dayInMonth);
button.disabled = self.disabled(day);
button.tabIndex = isSelected - 1;
button.setAttribute("data-adjacent", month !== dayMonth);
button.setAttribute('aria-label', "".concat(dayInMonth, ". ").concat(self.months[dayMonth]));
button.setAttribute('aria-current', day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear() && 'date');
button.toggleAttribute('autofocus', isSelected);
day.setDate(dayInMonth + 1);

@@ -223,21 +570,15 @@ });

function button (el, date, disable, picker) {
if (el.getAttribute(ATTR) === picker.id || picker.contains(el)) {
el.disabled = disable(index_min(el.value, date));
}
}
function select (select, date, disable) {
function select(self, select) {
if (!select.firstElementChild) {
select.innerHTML = datepicker.months.map(function (name, month) { return ("<option value=\"y-" + (month + 1) + "-d\">" + (escapeHTML(name)) + "</option>"); }
).join('');
select.innerHTML = self.months.map(function (name, month) {
return "<option value=\"y-".concat(month + 1, "-d\">").concat(escapeHTML(name), "</option>");
}).join('');
}
queryAll(select.children).forEach(function (option) {
var val = index_min(option.value, date);
option.disabled = disable(val);
option.selected = val.getTime() === date.getTime();
option.disabled = self.disabled(option.value);
option.selected = !self.diff(option.value);
});
}
module.exports = datepicker;
module.exports = CoreDatepicker;

@@ -1,118 +0,122 @@

import { name, version } from './package.json'
import { addEvent, escapeHTML, dispatchEvent, queryAll } from '../utils'
import { addStyle, closest, escapeHTML, dispatchEvent, queryAll } from '../utils'
import parse from '@nrk/simple-date-parse'
const ATTR = 'data-core-datepicker'
const UUID = `data-${name}-${version}`.replace(/\W+/g, '-') // Strip invalid attribute characters
const KEY_CODES = { 33: '-1month', 34: '+1month', 35: 'y-m-99', 36: 'y-m-1', 37: '-1day', 38: '-1week', 39: '+1day', 40: '+1week' }
const MASK = { year: '*-m-d', month: 'y-*-d', day: 'y-m-*', hour: '*:m', minute: 'h:*', second: 'h:m:*', timestamp: '*' }
const MS_IN_MINUTES = 60000
const MASK = { year: '*-m-d', month: 'y-*-d', day: 'y-m-*', hour: '*:m', minute: 'h:*', second: 'h:m:*', timestamp: '*', null: '*' }
const KEYS = { 33: '-1month', 34: '+1month', 35: 'y-m-99', 36: 'y-m-1', 37: '-1day', 38: '-1week', 39: '+1day', 40: '+1week' }
const MONTHS = 'januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember'
const DAYS = 'man,tirs,ons,tors,fre,lør,søn'
export default function datepicker (elements, date) { // date can be String, Timestamp or Date
return queryAll(elements).map((element) => {
const prevDate = parse(element.getAttribute(UUID) || date)
let nextDate = parse(typeof date === 'undefined' ? prevDate : date, prevDate)
let disable = () => false
export default class CoreDatepicker extends HTMLElement {
static get observedAttributes () { return ['timestamp', 'months', 'days'] }
dispatchEvent(element, 'datepicker.render', { nextDate, prevDate, disable: (fn) => (disable = fn) })
if (disable(nextDate)) nextDate = prevDate // Jump back to prev date if next is disabled
connectedCallback () {
this._date = this.date // Store for later comparison and speeding up things
document.addEventListener('click', this)
document.addEventListener('change', this)
document.addEventListener('keydown', this)
setTimeout(() => this.attributeChangedCallback()) // Render after children is parsed
addStyle(this.nodeName, `${this.nodeName}{display:block}`) // default to display block
}
disconnectedCallback () {
this._date = this._disabled = null // Garbage collection
document.removeEventListener('click', this)
document.removeEventListener('change', this)
document.removeEventListener('keydown', this)
}
attributeChangedCallback () {
if (!this._date) return // Only render after connectedCallback
if (this.disabled(this.date) && !this.disabled(this._date)) return (this.date = this._date) // Jump back
if (this.diff(this.date)) dispatchEvent(this, 'datepicker.change', this._date = this.date)
const isUpdate = prevDate.getTime() === nextDate.getTime() || dispatchEvent(element, 'datepicker.change', { prevDate, nextDate })
const next = isUpdate ? nextDate : parse(element.getAttribute(UUID) || Date.now()) // dispatchEvent can change attributes to parse prevDate again
const json = new Date(next.getTime() - next.getTimezoneOffset() * MS_IN_MINUTES).toJSON().match(/\d+/g)
const unit = { year: next.getFullYear(), month: json[1], day: json[2], hour: json[3], minute: json[4], second: json[5], timestamp: next.getTime() }
forEach('button', this, button)
forEach('select', this, select)
forEach('input', this, input)
forEach('table', this, table)
}
handleEvent (event) {
if (event.defaultPrevented || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey || (event.type === 'keydown' && !KEYS[event.keyCode])) return
if (!this.contains(event.target) && !closest(event.target, `[for="${this.id}"]`)) return
if (event.type === 'change') this.date = MASK[event.target.getAttribute('data-type')].replace('*', event.target.value)
else if (event.type === 'click') {
const button = closest(event.target, 'button[value]')
const table = closest(event.target, 'table')
if (button) this.date = button.value
if (button && table) dispatchEvent(this, 'datepicker.click.day')
} else if (event.type === 'keydown' && closest(event.target, 'table')) {
this.date = KEYS[event.keyCode]
this.querySelector('[autofocus]').focus()
event.preventDefault() // Prevent scrolling
}
}
diff (val) { return this.parse(val).getTime() - this.timestamp }
parse (val, from) { return parse(val, from || this._date) }
element.setAttribute(UUID, unit.timestamp)
queryAll('button').forEach((el) => button(el, next, disable, element))
queryAll('select', element).concat(queryAll(`select[${ATTR}="${element.id}"]`)).forEach((el) => select(el, next, disable))
queryAll('input', element).concat(queryAll(`input[${ATTR}="${element.id}"]`)).forEach((el) => input(el, next, disable, unit))
queryAll('table', element).concat(queryAll(`table[${ATTR}="${element.id}"]`)).forEach((el) => table(el, next, disable))
get disabled () { return this._disabled || Function.prototype }
set disabled (fn) {
this._disabled = typeof fn === 'function' ? (val) => fn(this.parse(val), this) : () => fn // Auto parse dates
this.attributeChangedCallback() // Re-render
}
return element
})
get timestamp () { return String(this._date.getTime()) }
get year () { return String(this._date.getFullYear()) } // Stringify for consistency and for truthy '0'
get month () { return pad(this._date.getMonth() + 1) }
get day () { return pad(this._date.getDate()) }
get hour () { return pad(this._date.getHours()) }
get minute () { return pad(this._date.getMinutes()) }
get second () { return pad(this._date.getSeconds()) }
get date () { return parse(this.getAttribute('timestamp') || this._date || Date.now()) }
set date (val) { return this.setAttribute('timestamp', this.parse(val).getTime()) }
set months (val) { this.setAttribute('months', [].concat(val).join(',')) }
get months () { return (this.getAttribute('months') || MONTHS).split(/\s*,\s*/) }
set days (val) { this.setAttribute('days', [].concat(val).join(',')) }
get days () { return (this.getAttribute('days') || DAYS).split(/\s*,\s*/) }
}
// Expose API and config
datepicker.parse = parse
datepicker.months = ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember']
datepicker.days = ['man', 'tirs', 'ons', 'tors', 'fre', 'lør', 'søn']
addEvent(UUID, 'change', onChange)
addEvent(UUID, 'click', ({ target }) => {
for (let el = target; el; el = el.parentElement) {
if (el.nodeName === 'BUTTON') return onChange({ target: el })
}
const pad = (val) => `0${val}`.slice(-2)
const forEach = (css, self, fn) => [].forEach.call(document.getElementsByTagName(css), (el) => {
if (self.contains(el) || self.id === el.getAttribute(self.external)) fn(self, el, self._date)
})
addEvent(UUID, 'keydown', (event) => {
if (event.ctrlKey || event.metaKey || event.shitKey || event.altKey || !KEY_CODES[event.keyCode]) return
for (let el = event.target, table; el; el = el.parentElement) {
if (!table && el.nodeName === 'TABLE') table = el // Store table while traversing DOM parents
if (table && el.hasAttribute(UUID)) { // Only listen to keyCodes inside table inside datepicker
datepicker(el, KEY_CODES[event.keyCode])
table.querySelector(`[${ATTR}-selected="true"]`).focus()
event.preventDefault()
break
}
}
})
function onChange ({ target }) {
for (let el = target, table; el; el = el.parentElement) {
const elem = document.getElementById(el.getAttribute(ATTR)) || el
const mask = elem.hasAttribute(UUID) && (MASK[target.getAttribute(`${UUID}-type`)] || '*')
function button (self, el) {
el.disabled = self.disabled(el.value)
}
if (!table && el.nodeName === 'TABLE') table = el // Store table while traversing DOM parents
if (mask) {
const nextDate = mask.replace('*', target.value)
const isUpdate = !elem.contains(table) || dispatchEvent(elem, 'datepicker.click.day', {
currentTarget: target,
relatedTarget: table,
prevDate: parse(elem.getAttribute(UUID)),
nextDate: parse(nextDate)
})
function input (self, el) {
const type = el.getAttribute('data-type') || el.getAttribute('type')
return isUpdate && datepicker(elem, nextDate)
}
}
}
function input (el, date, disable, unit) {
const type = el.getAttribute(`${UUID}-type`) || el.getAttribute('type')
if (type === 'radio' || type === 'checkbox') {
const val = parse(el.value, date)
el.disabled = disable(val)
el.checked = val.getTime() === date.getTime()
} else if (unit[type]) {
el.disabled = self.disabled(el.value)
el.checked = !self.diff(el.value)
} else if (MASK[type]) {
el.setAttribute('type', 'number') // Set input type to number
el.setAttribute(`${UUID}-type`, type) // And store original input type
el.value = unit[type]
el.setAttribute('data-type', type) // And store original type
el.value = self[type]
}
}
function table (table, date, disable) {
function table (self, table) {
if (!table.firstElementChild) {
table.innerHTML = `
<caption></caption><thead><tr><th>${datepicker.days.map(escapeHTML).join('</th><th>')}</th></tr></thead>
<tbody>${Array(7).join(`<tr>${Array(8).join(`<td><button type="button"></button></td>`)}</tr>`)}</tbody>`
<caption></caption><thead><tr><th>${self.days.map(escapeHTML).join('</th><th>')}</th></tr></thead>
<tbody>${Array(7).join(`<tr>${Array(8).join('<td><button type="button"></button></td>')}</tr>`)}</tbody>`
}
const today = new Date()
let day = parse('y-m-1 mon', date) // Monday in first week of month
table.caption.textContent = `${escapeHTML(datepicker.months[date.getMonth()])}, ${date.getFullYear()}`
const month = self.date.getMonth()
const day = self.parse('y-m-1 mon') // Monday in first week of month
table.caption.textContent = `${self.months[month]}, ${self.year}`
queryAll('button', table).forEach((button) => {
const isToday = day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear()
const isSelected = day.getTime() === date.getTime()
const isSelected = !self.diff(day)
const dayInMonth = day.getDate()
const month = day.getMonth()
const dayMonth = day.getMonth()
button.textContent = dayInMonth // Set textContent instead of innerHTML avoids reflow
button.value = `${day.getFullYear()}-${month + 1}-${dayInMonth}`
button.disabled = disable(day)
button.setAttribute('tabindex', isSelected - 1)
button.setAttribute(`${ATTR}-selected`, isSelected)
button.setAttribute(`${ATTR}-adjacent`, date.getMonth() !== month)
button.setAttribute('aria-label', `${dayInMonth}. ${datepicker.months[month]}`)
button[isToday ? 'setAttribute' : 'removeAttribute']('aria-current', 'date')
button[isSelected ? 'setAttribute' : 'removeAttribute']('autofocus', '')
button.value = `${day.getFullYear()}-${dayMonth + 1}-${dayInMonth}`
button.disabled = self.disabled(day)
button.tabIndex = isSelected - 1
button.setAttribute(`data-adjacent`, month !== dayMonth)
button.setAttribute('aria-label', `${dayInMonth}. ${self.months[dayMonth]}`)
button.setAttribute('aria-current', day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear() && 'date')
button.toggleAttribute('autofocus', isSelected)
day.setDate(dayInMonth + 1)

@@ -122,11 +126,5 @@ })

function button (el, date, disable, picker) {
if (el.getAttribute(ATTR) === picker.id || picker.contains(el)) {
el.disabled = disable(parse(el.value, date))
}
}
function select (select, date, disable) {
function select (self, select) {
if (!select.firstElementChild) {
select.innerHTML = datepicker.months.map((name, month) =>
select.innerHTML = self.months.map((name, month) =>
`<option value="y-${month + 1}-d">${escapeHTML(name)}</option>`

@@ -137,6 +135,5 @@ ).join('')

queryAll(select.children).forEach((option) => {
const val = parse(option.value, date)
option.disabled = disable(val)
option.selected = val.getTime() === date.getTime()
option.disabled = self.disabled(option.value)
option.selected = !self.diff(option.value)
})
}

@@ -1,51 +0,4 @@

import React from 'react'
import PropTypes from 'prop-types'
import coreDatepicker from './core-datepicker'
import { exclude } from '../utils'
import CoreDatepicker from './core-datepicker.js'
import { elementToReact } from '../utils.js'
export default class Datepicker extends React.Component {
static get defaultProps () { return { date: null, disable: null, onRender: null, onChange: null, onClickDay: null } }
static set months (months) { coreDatepicker.months = months }
static set days (days) { coreDatepicker.days = days }
static get months () { return coreDatepicker.months }
static get days () { return coreDatepicker.days }
static parse (...args) { return coreDatepicker.parse(...args) }
constructor (props) {
super(props)
this.onClickDay = this.onClickDay.bind(this)
this.onChange = this.onChange.bind(this)
this.onRender = this.onRender.bind(this)
}
componentDidMount () {
this.el.addEventListener('datepicker.click.day', this.onClickDay)
this.el.addEventListener('datepicker.change', this.onChange)
this.el.addEventListener('datepicker.render', this.onRender)
coreDatepicker(this.el, this.props.date)
}
componentDidUpdate () { coreDatepicker(this.el, this.props.date) }
componentWillUnmount () {
this.el.removeEventListener('datepicker.click.day', this.onClickDay)
this.el.removeEventListener('datepicker.change', this.onChange)
this.el.removeEventListener('datepicker.render', this.onRender)
}
onClickDay (event) { this.props.onClickDay && this.props.onClickDay(event) }
onChange (event) { this.props.onChange && this.props.onChange(event) }
onRender (event) { this.props.disable && event.detail.disable(this.props.disable) }
render () {
const props = exclude(this.props, Datepicker.defaultProps, { ref: el => (this.el = el) })
return React.createElement('div', props, this.props.children)
}
}
Datepicker.propTypes = {
disable: PropTypes.func,
onRender: PropTypes.func,
onChange: PropTypes.func,
onClickDay: PropTypes.func,
date: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Date)
])
}
export default elementToReact(CoreDatepicker, 'datepicker.change', 'datepicker.click.day', 'disabled', 'months', 'days')

@@ -1,3 +0,683 @@

/*! @nrk/core-datepicker v2.0.3 - Copyright (c) 2017-2019 NRK */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("react"),require("prop-types")):"function"==typeof define&&define.amd?define(["react","prop-types"],t):(e=e||self).CoreDatepicker=t(e.React,e.PropTypes)}(this,function(a,e){"use strict";a=a&&a.hasOwnProperty("default")?a.default:a,e=e&&e.hasOwnProperty("default")?e.default:e;var t="undefined"!=typeof window,o=(t&&/(android)/i.test(navigator.userAgent),t&&/iPad|iPhone|iPod/.test(String(navigator.platform)),function(e){void 0===e&&(e=!1);try{window.addEventListener("test",null,{get passive(){e=!0}})}catch(e){}return e}());function n(e,t,n,r){(void 0===r&&(r=!1),"undefined"==typeof window||window[e=e+"-"+t])||(o||"object"!=typeof r||(r=Boolean(r.capture)),("resize"===t||"load"===t?window:document).addEventListener(window[e]=t,n,r))}var r={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","/":"&#x2F;","'":"&#x27;"};function s(e){return String(e||"").replace(/[&<>"'/]/g,function(e){return r[e]})}var u="prevent_recursive_dispatch_maximum_callstack";function d(e,t,n){void 0===n&&(n={});var r,o=""+u+t;if(e[o])return!0;e[o]=!0,"function"==typeof window.CustomEvent?r=new window.CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n}):(r=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,n);var i=e.dispatchEvent(r);return e[o]=null,i}function c(e,t){if(void 0===t&&(t=document),e){if(e.nodeType)return[e];if("string"==typeof e)return[].slice.call(t.querySelectorAll(e));if(e.length)return[].slice.call(e)}return[]}"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;var i,l=(function(e,t){var v,b,k,w;e.exports=(v={year:"FullYear",month:"Month",week:"Date",day:"Date",hour:"Hours",minute:"Minutes",second:"Seconds"},b=/([+-]\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(e,t){if(isFinite(e))return new Date(Number(e));var n=String(e).toLowerCase(),o=new Date(isFinite(t)&&-1===n.indexOf("now")?Number(t):Date.now()),r=n.match(k)||[],i=r[1];void 0===i&&(i="y");var a=r[2];void 0===a&&(a="m");var u=r[3];void 0===u&&(u="d");var d=n.match(w)||[],s=d[1];void 0===s&&(s="h");var c=d[2];void 0===c&&(c="m");var l=d[3];void 0===l&&(l="s");var p={year:i,month:a,day:u,hour:s,minute:c,second:l};Object.keys(p).forEach(function(e){var t="month"===e?1:0,r=String(o["get"+v[e]]()+t);p[e]=p[e].replace(/[^-\d]+/g,function(e,t,n){return t?r.substr(r.length-n.length+t,e.length):r.substr(0,Math.max(0,r.length-n.length+e.length))})-t});var h=new Date(p.year,Math.min(12,p.month+1),0).getDate();for(o.setFullYear(p.year,Math.min(11,p.month),Math.max(1,Math.min(h,p.day))),o.setHours(Math.min(24,p.hour),Math.min(59,p.minute),Math.min(59,p.second));null!==(p=b.exec(n));){var f=p[2],m=String(p[1]).replace(/\s/g,"")*("week"===f?7:1),y=p.slice(2).indexOf(p[0]),g=o.getDate();f?o["set"+v[f]](o["get"+v[f]]()+m):o.setDate(o.getDate()-(o.getDay()||7)+y),"month"!==f&&"year"!==f||g===o.getDate()||o.setDate(0)}return o})}(i={exports:{}},i.exports),i.exports),p="data-core-datepicker",h="data-@nrk/core-datepicker-2.0.3".replace(/\W+/g,"-"),f={33:"-1month",34:"+1month",35:"y-m-99",36:"y-m-1",37:"-1day",38:"-1week",39:"+1day",40:"+1week"},m={year:"*-m-d",month:"y-*-d",day:"y-m-*",hour:"*:m",minute:"h:*",second:"h:m:*",timestamp:"*"},y=6e4;function g(e,o){return c(e).map(function(i){var e=l(i.getAttribute(h)||o),t=l(void 0===o?e:o,e),a=function(){return!1};d(i,"datepicker.render",{nextDate:t,prevDate:e,disable:function(e){return a=e}}),a(t)&&(t=e);var u=e.getTime()===t.getTime()||d(i,"datepicker.change",{prevDate:e,nextDate:t})?t:l(i.getAttribute(h)||Date.now()),n=new Date(u.getTime()-u.getTimezoneOffset()*y).toJSON().match(/\d+/g),r={year:u.getFullYear(),month:n[1],day:n[2],hour:n[3],minute:n[4],second:n[5],timestamp:u.getTime()};return i.setAttribute(h,r.timestamp),c("button").forEach(function(e){return n=u,r=a,o=i,void(((t=e).getAttribute(p)===o.id||o.contains(t))&&(t.disabled=r(l(t.value,n))));var t,n,r,o}),c("select",i).concat(c("select["+p+'="'+i.id+'"]')).forEach(function(e){return function(e,n,r){e.firstElementChild||(e.innerHTML=g.months.map(function(e,t){return'<option value="y-'+(t+1)+'-d">'+s(e)+"</option>"}).join(""));c(e.children).forEach(function(e){var t=l(e.value,n);e.disabled=r(t),e.selected=t.getTime()===n.getTime()})}(e,u,a)}),c("input",i).concat(c("input["+p+'="'+i.id+'"]')).forEach(function(e){return function(e,t,n,r){var o=e.getAttribute(h+"-type")||e.getAttribute("type");if("radio"===o||"checkbox"===o){var i=l(e.value,t);e.disabled=n(i),e.checked=i.getTime()===t.getTime()}else r[o]&&(e.setAttribute("type","number"),e.setAttribute(h+"-type",o),e.value=r[o])}(e,u,a,r)}),c("table",i).concat(c("table["+p+'="'+i.id+'"]')).forEach(function(e){return function(e,i,a){e.firstElementChild||(e.innerHTML="\n <caption></caption><thead><tr><th>"+g.days.map(s).join("</th><th>")+"</th></tr></thead>\n <tbody>"+Array(7).join("<tr>"+Array(8).join('<td><button type="button"></button></td>')+"</tr>")+"</tbody>");var u=new Date,d=l("y-m-1 mon",i);e.caption.textContent=s(g.months[i.getMonth()])+", "+i.getFullYear(),c("button",e).forEach(function(e){var t=d.getDate()===u.getDate()&&d.getMonth()===u.getMonth()&&d.getFullYear()===u.getFullYear(),n=d.getTime()===i.getTime(),r=d.getDate(),o=d.getMonth();e.textContent=r,e.value=d.getFullYear()+"-"+(o+1)+"-"+r,e.disabled=a(d),e.setAttribute("tabindex",n-1),e.setAttribute(p+"-selected",n),e.setAttribute(p+"-adjacent",i.getMonth()!==o),e.setAttribute("aria-label",r+". "+g.months[o]),e[t?"setAttribute":"removeAttribute"]("aria-current","date"),e[n?"setAttribute":"removeAttribute"]("autofocus",""),d.setDate(r+1)})}(e,u,a)}),i})}function v(e){for(var t=e.target,n=t,r=void 0;n;n=n.parentElement){var o=document.getElementById(n.getAttribute(p))||n,i=o.hasAttribute(h)&&(m[t.getAttribute(h+"-type")]||"*");if(r||"TABLE"!==n.nodeName||(r=n),i){var a=i.replace("*",t.value);return(!o.contains(r)||d(o,"datepicker.click.day",{currentTarget:t,relatedTarget:r,prevDate:l(o.getAttribute(h)),nextDate:l(a)}))&&g(o,a)}}}g.parse=l,g.months=["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],g.days=["man","tirs","ons","tors","fre","lør","søn"],n(h,"change",v),n(h,"click",function(e){for(var t=e.target;t;t=t.parentElement)if("BUTTON"===t.nodeName)return v({target:t})}),n(h,"keydown",function(e){if(!(e.ctrlKey||e.metaKey||e.shitKey||e.altKey)&&f[e.keyCode])for(var t=e.target,n=void 0;t;t=t.parentElement)if(n||"TABLE"!==t.nodeName||(n=t),n&&t.hasAttribute(h)){g(t,f[e.keyCode]),n.querySelector("["+p+'-selected="true"]').focus(),e.preventDefault();break}});var b=function(t){function i(e){t.call(this,e),this.onClickDay=this.onClickDay.bind(this),this.onChange=this.onChange.bind(this),this.onRender=this.onRender.bind(this)}t&&(i.__proto__=t),(i.prototype=Object.create(t&&t.prototype)).constructor=i;var e={defaultProps:{configurable:!0},months:{configurable:!0},days:{configurable:!0}};return e.defaultProps.get=function(){return{date:null,disable:null,onRender:null,onChange:null,onClickDay:null}},e.months.set=function(e){g.months=e},e.days.set=function(e){g.days=e},e.months.get=function(){return g.months},e.days.get=function(){return g.days},i.parse=function(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];return g.parse.apply(g,e)},i.prototype.componentDidMount=function(){this.el.addEventListener("datepicker.click.day",this.onClickDay),this.el.addEventListener("datepicker.change",this.onChange),this.el.addEventListener("datepicker.render",this.onRender),g(this.el,this.props.date)},i.prototype.componentDidUpdate=function(){g(this.el,this.props.date)},i.prototype.componentWillUnmount=function(){this.el.removeEventListener("datepicker.click.day",this.onClickDay),this.el.removeEventListener("datepicker.change",this.onChange),this.el.removeEventListener("datepicker.render",this.onRender)},i.prototype.onClickDay=function(e){this.props.onClickDay&&this.props.onClickDay(e)},i.prototype.onChange=function(e){this.props.onChange&&this.props.onChange(e)},i.prototype.onRender=function(e){this.props.disable&&e.detail.disable(this.props.disable)},i.prototype.render=function(){var n,r,e,t=this,o=(n=this.props,r=i.defaultProps,void 0===(e={ref:function(e){return t.el=e}})&&(e={}),Object.keys(n).reduce(function(e,t){return r.hasOwnProperty(t)||(e[t]=n[t]),e},e));return a.createElement("div",o,this.props.children)},Object.defineProperties(i,e),i}(a.Component);return b.propTypes={disable:e.func,onRender:e.func,onChange:e.func,onClickDay:e.func,date:e.oneOfType([e.string,e.number,e.instanceOf(Date)])},b});
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) :
typeof define === 'function' && define.amd ? define(['react'], factory) :
(global = global || self, global.CoreDatepicker = factory(global.React));
}(this, function (React) { 'use strict';
React = React && React.hasOwnProperty('default') ? React['default'] : React;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
return true;
} catch (e) {
return false;
}
}
function _construct(Parent, args, Class) {
if (isNativeReflectConstruct()) {
_construct = Reflect.construct;
} else {
_construct = function _construct(Parent, args, Class) {
var a = [null];
a.push.apply(a, args);
var Constructor = Function.bind.apply(Parent, a);
var instance = new Constructor();
if (Class) _setPrototypeOf(instance, Class.prototype);
return instance;
};
}
return _construct.apply(null, arguments);
}
function _isNativeFunction(fn) {
return Function.toString.call(fn).indexOf("[native code]") !== -1;
}
function _wrapNativeSuper(Class) {
var _cache = typeof Map === "function" ? new Map() : undefined;
_wrapNativeSuper = function _wrapNativeSuper(Class) {
if (Class === null || !_isNativeFunction(Class)) return Class;
if (typeof Class !== "function") {
throw new TypeError("Super expression must either be null or a function");
}
if (typeof _cache !== "undefined") {
if (_cache.has(Class)) return _cache.get(Class);
_cache.set(Class, Wrapper);
}
function Wrapper() {
return _construct(Class, arguments, _getPrototypeOf(this).constructor);
}
Wrapper.prototype = Object.create(Class.prototype, {
constructor: {
value: Wrapper,
enumerable: false,
writable: true,
configurable: true
}
});
return _setPrototypeOf(Wrapper, Class);
};
return _wrapNativeSuper(Class);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _possibleConstructorReturn(self, call) {
if (call && (typeof call === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
var IS_BROWSER = typeof window !== 'undefined';
var IS_ANDROID = IS_BROWSER && /(android)/i.test(navigator.userAgent); // Bad, but needed
var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(String(navigator.platform)); // Polyfill toggleAttribute for IE
if (IS_BROWSER && !window.Element.prototype.toggleAttribute) {
window.Element.prototype.toggleAttribute = function (name) {
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : !this.hasAttribute(name);
if (!force === this.hasAttribute(name)) this[force ? 'setAttribute' : 'removeAttribute'](name, '');
return force;
};
}
/**
* addStyle
* @param {String} nodeName An unique ID of the event to bind - ensurnes single instance
* @param {String} css The css to inject
*/
function addStyle(nodeName, css) {
var key = "style-".concat(nodeName.toLowerCase());
var min = css.replace(/\/\*[^!][^*]*\*\//g, '').replace(/\s*(^|[:;,{}]|$)\s*/g, '$1');
document.getElementById(key) || document.head.insertAdjacentHTML('afterbegin', "<style id=\"".concat(key, "\">").concat(min, "</style>"));
}
/**
* escapeHTML
* @param {String} str A string with potential html tokens
* @return {String} Escaped HTML string according to OWASP recommendation
*/
var ESCAPE_MAP = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'/': '&#x2F;',
'\'': '&#x27;'
};
function escapeHTML(str) {
return String(str || '').replace(/[&<>"'/]/g, function (_char) {
return ESCAPE_MAP[_char];
});
}
/**
* 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
* @param {Element} elem The target object
* @param {String} name The source object(s)
* @param {Object} detail Detail object (bubbles and cancelable is set to true)
* @return {Boolean} Whether the event was canceled
*/
function dispatchEvent(element, name) {
var detail = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var ignore = "prevent_recursive_dispatch_maximum_callstack".concat(name);
var event;
if (element[ignore]) return true; // We are already processing this event, so skip sending a new one
else element[ignore] = true; // Add name to dispatching ignore
if (typeof window.CustomEvent === 'function') {
event = new window.CustomEvent(name, {
bubbles: true,
cancelable: true,
detail: detail
});
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(name, true, true, detail);
} // IE reports incorrect event.defaultPrevented
// but correct return value on element.dispatchEvent
var result = element.dispatchEvent(event);
element[ignore] = null; // Remove name from dispatching ignore
return result; // Follow W3C standard for return value
}
function elementToReact(elementClass) {
for (var _len = arguments.length, attr = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
attr[_key - 1] = arguments[_key];
}
var name = elementClass.name || String(elementClass).match(/function ([^(]+)/)[1]; // String match for IE11
var tag = "".concat(name.replace(/\W+/, '-'), "-").concat(getUUID()).toLowerCase();
if (IS_BROWSER && !window.customElements.get(tag)) window.customElements.define(tag, elementClass);
return (
/*#__PURE__*/
function (_React$Component) {
_inherits(_class, _React$Component);
function _class(props) {
var _this;
_classCallCheck(this, _class);
_this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, props));
_this.ref = function (el) {
return _this.el = el;
};
attr.forEach(function (k) {
var on = "on".concat(k.replace(/(^|\.)./g, function (m) {
return m.slice(-1).toUpperCase();
})); // input.filter => onInputFilter
_this[k] = function (event) {
return _this.props[on] && _this.props[on](event);
};
});
return _this;
}
_createClass(_class, [{
key: "componentDidMount",
value: function componentDidMount() {
var _this2 = this;
attr.forEach(function (k) {
return _this2.props[k] ? _this2.el[k] = _this2.props[k] : _this2.el.addEventListener(k, _this2[k]);
});
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prev) {
var _this3 = this;
attr.forEach(function (k) {
return prev[k] !== _this3.props[k] && (_this3.el[k] = _this3.props[k]);
});
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var _this4 = this;
attr.forEach(function (k) {
return _this4.el.removeEventListener(k, _this4[k]);
});
}
}, {
key: "render",
value: function render() {
var _this5 = this;
// Convert React props to CustomElement props https://github.com/facebook/react/issues/12810
return React.createElement(tag, Object.keys(this.props).reduce(function (props, k) {
if (k === 'className') props["class"] = _this5.props[k]; // Fixes className for custom elements
else if (_this5.props[k] === true) props[k] = ''; // Fixes boolean attributes
else if (_this5.props[k] !== false) props[k] = _this5.props[k];
return props;
}, {
ref: this.ref
}));
}
}]);
return _class;
}(React.Component)
);
}
/**
* getUUID
* @return {String} A generated unique ID
*/
function getUUID() {
return Date.now().toString(36) + Math.random().toString(36).slice(2, 5);
}
/**
* queryAll
* @param {String|NodeList|Array|Element} elements A CSS selector string, nodeList, element array, or single element
* @return {Element[]} Array of elements
*/
function queryAll(elements) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;
if (elements) {
if (elements.nodeType) return [elements];
if (typeof elements === 'string') return [].slice.call(context.querySelectorAll(elements));
if (elements.length) return [].slice.call(elements);
}
return [];
}
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var index_min = createCommonjsModule(function (module, exports) {
!function (e, t) {
module.exports = t();
}(commonjsGlobal, function () {
var D = {
year: "FullYear",
month: "Month",
week: "Date",
day: "Date",
hour: "Hours",
minute: "Minutes",
second: "Seconds"
},
w = /([+-]\s*\d+)\s*(second|minute|hour|day|week|month|year)|(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)/g,
M = /([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,
p = /([\dh]+):([\dm]+):?([\ds]+)?/;
return function (e, t) {
if (isFinite(e)) return new Date(Number(e));
var n = String(e).toLowerCase(),
r = new Date(isFinite(t) && -1 === n.indexOf("now") ? Number(t) : Date.now()),
a = n.match(M) || [],
o = a[1];
void 0 === o && (o = "y");
var i = a[2];
void 0 === i && (i = "m");
var s = a[3];
void 0 === s && (s = "d");
var d = n.match(p) || [],
u = d[1];
void 0 === u && (u = "h");
var h = d[2];
void 0 === h && (h = "m");
var m = d[3];
void 0 === m && (m = "s");
var c = {
year: o,
month: i,
day: s,
hour: u,
minute: h,
second: m
};
Object.keys(c).forEach(function (e) {
var t = "month" === e ? 1 : 0,
a = String(r["get" + D[e]]() + t);
c[e] = c[e].replace(/[^-\d]+/g, function (e, t, n) {
return t ? a.substr(a.length - n.length + t, e.length) : a.substr(0, Math.max(0, a.length - n.length + e.length));
}) - t;
});
var f = new Date(c.year, Math.min(12, c.month + 1), 0).getDate();
for (r.setFullYear(c.year, Math.min(11, c.month), Math.max(1, Math.min(f, c.day))), r.setHours(Math.min(24, c.hour), Math.min(59, c.minute), Math.min(59, c.second)); null !== (c = w.exec(n));) {
var g = c[2],
l = String(c[1]).replace(/\s/g, "") * ("week" === g ? 7 : 1),
v = c.slice(2).indexOf(c[0]),
y = r.getDate();
g ? r["set" + D[g]](r["get" + D[g]]() + l) : r.setDate(r.getDate() - (r.getDay() || 7) + v), "month" !== g && "year" !== g || y === r.getDate() || r.setDate(0);
}
return r;
};
});
});
var MASK = {
year: '*-m-d',
month: 'y-*-d',
day: 'y-m-*',
hour: '*:m',
minute: 'h:*',
second: 'h:m:*',
timestamp: '*',
"null": '*'
};
var KEYS = {
33: '-1month',
34: '+1month',
35: 'y-m-99',
36: 'y-m-1',
37: '-1day',
38: '-1week',
39: '+1day',
40: '+1week'
};
var MONTHS = 'januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember';
var DAYS = 'man,tirs,ons,tors,fre,lør,søn';
var CoreDatepicker =
/*#__PURE__*/
function (_HTMLElement) {
_inherits(CoreDatepicker, _HTMLElement);
function CoreDatepicker() {
_classCallCheck(this, CoreDatepicker);
return _possibleConstructorReturn(this, _getPrototypeOf(CoreDatepicker).apply(this, arguments));
}
_createClass(CoreDatepicker, [{
key: "connectedCallback",
value: function connectedCallback() {
var _this = this;
this._date = this.date; // Store for later comparison and speeding up things
document.addEventListener('click', this);
document.addEventListener('change', this);
document.addEventListener('keydown', this);
setTimeout(function () {
return _this.attributeChangedCallback();
}); // Render after children is parsed
addStyle(this.nodeName, "".concat(this.nodeName, "{display:block}")); // default to display block
}
}, {
key: "disconnectedCallback",
value: function disconnectedCallback() {
this._date = this._disabled = null; // Garbage collection
document.removeEventListener('click', this);
document.removeEventListener('change', this);
document.removeEventListener('keydown', this);
}
}, {
key: "attributeChangedCallback",
value: function attributeChangedCallback() {
if (!this._date) return; // Only render after connectedCallback
if (this.disabled(this.date) && !this.disabled(this._date)) return this.date = this._date; // Jump back
if (this.diff(this.date)) dispatchEvent(this, 'datepicker.change', this._date = this.date);
forEach('button', this, button);
forEach('select', this, select);
forEach('input', this, input);
forEach('table', this, table);
}
}, {
key: "handleEvent",
value: function handleEvent(event) {
if (event.defaultPrevented || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey || event.type === 'keydown' && !KEYS[event.keyCode]) return;
if (!this.contains(event.target) && !closest(event.target, "[for=\"".concat(this.id, "\"]"))) return;
if (event.type === 'change') this.date = MASK[event.target.getAttribute('data-type')].replace('*', event.target.value);else if (event.type === 'click') {
var _button = closest(event.target, 'button[value]');
var _table = closest(event.target, 'table');
if (_button) this.date = _button.value;
if (_button && _table) dispatchEvent(this, 'datepicker.click.day');
} else if (event.type === 'keydown' && closest(event.target, 'table')) {
this.date = KEYS[event.keyCode];
this.querySelector('[autofocus]').focus();
event.preventDefault(); // Prevent scrolling
}
}
}, {
key: "diff",
value: function diff(val) {
return this.parse(val).getTime() - this.timestamp;
}
}, {
key: "parse",
value: function parse(val, from) {
return index_min(val, from || this._date);
}
}, {
key: "disabled",
get: function get() {
return this._disabled || Function.prototype;
},
set: function set(fn) {
var _this2 = this;
this._disabled = typeof fn === 'function' ? function (val) {
return fn(_this2.parse(val), _this2);
} : function () {
return fn;
}; // Auto parse dates
this.attributeChangedCallback(); // Re-render
}
}, {
key: "timestamp",
get: function get() {
return String(this._date.getTime());
}
}, {
key: "year",
get: function get() {
return String(this._date.getFullYear());
} // Stringify for consistency and for truthy '0'
}, {
key: "month",
get: function get() {
return pad(this._date.getMonth() + 1);
}
}, {
key: "day",
get: function get() {
return pad(this._date.getDate());
}
}, {
key: "hour",
get: function get() {
return pad(this._date.getHours());
}
}, {
key: "minute",
get: function get() {
return pad(this._date.getMinutes());
}
}, {
key: "second",
get: function get() {
return pad(this._date.getSeconds());
}
}, {
key: "date",
get: function get() {
return index_min(this.getAttribute('timestamp') || this._date || Date.now());
},
set: function set(val) {
return this.setAttribute('timestamp', this.parse(val).getTime());
}
}, {
key: "months",
set: function set(val) {
this.setAttribute('months', [].concat(val).join(','));
},
get: function get() {
return (this.getAttribute('months') || MONTHS).split(/\s*,\s*/);
}
}, {
key: "days",
set: function set(val) {
this.setAttribute('days', [].concat(val).join(','));
},
get: function get() {
return (this.getAttribute('days') || DAYS).split(/\s*,\s*/);
}
}], [{
key: "observedAttributes",
get: function get() {
return ['timestamp', 'months', 'days'];
}
}]);
return CoreDatepicker;
}(_wrapNativeSuper(HTMLElement));
var pad = function pad(val) {
return "0".concat(val).slice(-2);
};
var forEach = function forEach(css, self, fn) {
return [].forEach.call(document.getElementsByTagName(css), function (el) {
if (self.contains(el) || self.id === el.getAttribute(self.external)) fn(self, el, self._date);
});
};
function button(self, el) {
el.disabled = self.disabled(el.value);
}
function input(self, el) {
var type = el.getAttribute('data-type') || el.getAttribute('type');
if (type === 'radio' || type === 'checkbox') {
el.disabled = self.disabled(el.value);
el.checked = !self.diff(el.value);
} else if (MASK[type]) {
el.setAttribute('type', 'number'); // Set input type to number
el.setAttribute('data-type', type); // And store original type
el.value = self[type];
}
}
function table(self, table) {
if (!table.firstElementChild) {
table.innerHTML = "\n <caption></caption><thead><tr><th>".concat(self.days.map(escapeHTML).join('</th><th>'), "</th></tr></thead>\n <tbody>").concat(Array(7).join("<tr>".concat(Array(8).join('<td><button type="button"></button></td>'), "</tr>")), "</tbody>");
}
var today = new Date();
var month = self.date.getMonth();
var day = self.parse('y-m-1 mon'); // Monday in first week of month
table.caption.textContent = "".concat(self.months[month], ", ").concat(self.year);
queryAll('button', table).forEach(function (button) {
var isSelected = !self.diff(day);
var dayInMonth = day.getDate();
var dayMonth = day.getMonth();
button.textContent = dayInMonth; // Set textContent instead of innerHTML avoids reflow
button.value = "".concat(day.getFullYear(), "-").concat(dayMonth + 1, "-").concat(dayInMonth);
button.disabled = self.disabled(day);
button.tabIndex = isSelected - 1;
button.setAttribute("data-adjacent", month !== dayMonth);
button.setAttribute('aria-label', "".concat(dayInMonth, ". ").concat(self.months[dayMonth]));
button.setAttribute('aria-current', day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear() && 'date');
button.toggleAttribute('autofocus', isSelected);
day.setDate(dayInMonth + 1);
});
}
function select(self, select) {
if (!select.firstElementChild) {
select.innerHTML = self.months.map(function (name, month) {
return "<option value=\"y-".concat(month + 1, "-d\">").concat(escapeHTML(name), "</option>");
}).join('');
}
queryAll(select.children).forEach(function (option) {
option.disabled = self.disabled(option.value);
option.selected = !self.diff(option.value);
});
}
var coreDatepicker = elementToReact(CoreDatepicker, 'datepicker.change', 'datepicker.click.day', 'disabled', 'months', 'days');
return coreDatepicker;
}));
//# sourceMappingURL=core-datepicker.jsx.js.map

@@ -1,3 +0,3 @@

/*! @nrk/core-datepicker v2.0.3 - Copyright (c) 2017-2019 NRK */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).coreDatepicker=t()}(this,function(){"use strict";var e="undefined"!=typeof window,a=(e&&/(android)/i.test(navigator.userAgent),e&&/iPad|iPhone|iPod/.test(String(navigator.platform)),function(e){void 0===e&&(e=!1);try{window.addEventListener("test",null,{get passive(){e=!0}})}catch(e){}return e}());function t(e,t,n,r){(void 0===r&&(r=!1),"undefined"==typeof window||window[e=e+"-"+t])||(a||"object"!=typeof r||(r=Boolean(r.capture)),("resize"===t||"load"===t?window:document).addEventListener(window[e]=t,n,r))}var n={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","/":"&#x2F;","'":"&#x27;"};function c(e){return String(e||"").replace(/[&<>"'/]/g,function(e){return n[e]})}var o="prevent_recursive_dispatch_maximum_callstack";function d(e,t,n){void 0===n&&(n={});var r,a=""+o+t;if(e[a])return!0;e[a]=!0,"function"==typeof window.CustomEvent?r=new window.CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n}):(r=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,n);var i=e.dispatchEvent(r);return e[a]=null,i}function s(e,t){if(void 0===t&&(t=document),e){if(e.nodeType)return[e];if("string"==typeof e)return[].slice.call(t.querySelectorAll(e));if(e.length)return[].slice.call(e)}return[]}"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;var r,l=(function(e,t){var y,b,w,D;e.exports=(y={year:"FullYear",month:"Month",week:"Date",day:"Date",hour:"Hours",minute:"Minutes",second:"Seconds"},b=/([+-]\s*\d+)\s*(second|minute|hour|day|week|month|year)|(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)/g,w=/([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,D=/([\dh]+):([\dm]+):?([\ds]+)?/,function(e,t){if(isFinite(e))return new Date(Number(e));var n=String(e).toLowerCase(),a=new Date(isFinite(t)&&-1===n.indexOf("now")?Number(t):Date.now()),r=n.match(w)||[],i=r[1];void 0===i&&(i="y");var o=r[2];void 0===o&&(o="m");var u=r[3];void 0===u&&(u="d");var d=n.match(D)||[],c=d[1];void 0===c&&(c="h");var s=d[2];void 0===s&&(s="m");var l=d[3];void 0===l&&(l="s");var m={year:i,month:o,day:u,hour:c,minute:s,second:l};Object.keys(m).forEach(function(e){var t="month"===e?1:0,r=String(a["get"+y[e]]()+t);m[e]=m[e].replace(/[^-\d]+/g,function(e,t,n){return t?r.substr(r.length-n.length+t,e.length):r.substr(0,Math.max(0,r.length-n.length+e.length))})-t});var f=new Date(m.year,Math.min(12,m.month+1),0).getDate();for(a.setFullYear(m.year,Math.min(11,m.month),Math.max(1,Math.min(f,m.day))),a.setHours(Math.min(24,m.hour),Math.min(59,m.minute),Math.min(59,m.second));null!==(m=b.exec(n));){var h=m[2],g=String(m[1]).replace(/\s/g,"")*("week"===h?7:1),v=m.slice(2).indexOf(m[0]),p=a.getDate();h?a["set"+y[h]](a["get"+y[h]]()+g):a.setDate(a.getDate()-(a.getDay()||7)+v),"month"!==h&&"year"!==h||p===a.getDate()||a.setDate(0)}return a})}(r={exports:{}},r.exports),r.exports),m="data-core-datepicker",f="data-@nrk/core-datepicker-2.0.3".replace(/\W+/g,"-"),i={33:"-1month",34:"+1month",35:"y-m-99",36:"y-m-1",37:"-1day",38:"-1week",39:"+1day",40:"+1week"},u={year:"*-m-d",month:"y-*-d",day:"y-m-*",hour:"*:m",minute:"h:*",second:"h:m:*",timestamp:"*"},h=6e4;function g(e,a){return s(e).map(function(i){var e=l(i.getAttribute(f)||a),t=l(void 0===a?e:a,e),o=function(){return!1};d(i,"datepicker.render",{nextDate:t,prevDate:e,disable:function(e){return o=e}}),o(t)&&(t=e);var u=e.getTime()===t.getTime()||d(i,"datepicker.change",{prevDate:e,nextDate:t})?t:l(i.getAttribute(f)||Date.now()),n=new Date(u.getTime()-u.getTimezoneOffset()*h).toJSON().match(/\d+/g),r={year:u.getFullYear(),month:n[1],day:n[2],hour:n[3],minute:n[4],second:n[5],timestamp:u.getTime()};return i.setAttribute(f,r.timestamp),s("button").forEach(function(e){return n=u,r=o,a=i,void(((t=e).getAttribute(m)===a.id||a.contains(t))&&(t.disabled=r(l(t.value,n))));var t,n,r,a}),s("select",i).concat(s("select["+m+'="'+i.id+'"]')).forEach(function(e){return function(e,n,r){e.firstElementChild||(e.innerHTML=g.months.map(function(e,t){return'<option value="y-'+(t+1)+'-d">'+c(e)+"</option>"}).join(""));s(e.children).forEach(function(e){var t=l(e.value,n);e.disabled=r(t),e.selected=t.getTime()===n.getTime()})}(e,u,o)}),s("input",i).concat(s("input["+m+'="'+i.id+'"]')).forEach(function(e){return function(e,t,n,r){var a=e.getAttribute(f+"-type")||e.getAttribute("type");if("radio"===a||"checkbox"===a){var i=l(e.value,t);e.disabled=n(i),e.checked=i.getTime()===t.getTime()}else r[a]&&(e.setAttribute("type","number"),e.setAttribute(f+"-type",a),e.value=r[a])}(e,u,o,r)}),s("table",i).concat(s("table["+m+'="'+i.id+'"]')).forEach(function(e){return function(e,i,o){e.firstElementChild||(e.innerHTML="\n <caption></caption><thead><tr><th>"+g.days.map(c).join("</th><th>")+"</th></tr></thead>\n <tbody>"+Array(7).join("<tr>"+Array(8).join('<td><button type="button"></button></td>')+"</tr>")+"</tbody>");var u=new Date,d=l("y-m-1 mon",i);e.caption.textContent=c(g.months[i.getMonth()])+", "+i.getFullYear(),s("button",e).forEach(function(e){var t=d.getDate()===u.getDate()&&d.getMonth()===u.getMonth()&&d.getFullYear()===u.getFullYear(),n=d.getTime()===i.getTime(),r=d.getDate(),a=d.getMonth();e.textContent=r,e.value=d.getFullYear()+"-"+(a+1)+"-"+r,e.disabled=o(d),e.setAttribute("tabindex",n-1),e.setAttribute(m+"-selected",n),e.setAttribute(m+"-adjacent",i.getMonth()!==a),e.setAttribute("aria-label",r+". "+g.months[a]),e[t?"setAttribute":"removeAttribute"]("aria-current","date"),e[n?"setAttribute":"removeAttribute"]("autofocus",""),d.setDate(r+1)})}(e,u,o)}),i})}function v(e){for(var t=e.target,n=t,r=void 0;n;n=n.parentElement){var a=document.getElementById(n.getAttribute(m))||n,i=a.hasAttribute(f)&&(u[t.getAttribute(f+"-type")]||"*");if(r||"TABLE"!==n.nodeName||(r=n),i){var o=i.replace("*",t.value);return(!a.contains(r)||d(a,"datepicker.click.day",{currentTarget:t,relatedTarget:r,prevDate:l(a.getAttribute(f)),nextDate:l(o)}))&&g(a,o)}}}return g.parse=l,g.months=["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],g.days=["man","tirs","ons","tors","fre","lør","søn"],t(f,"change",v),t(f,"click",function(e){for(var t=e.target;t;t=t.parentElement)if("BUTTON"===t.nodeName)return v({target:t})}),t(f,"keydown",function(e){if(!(e.ctrlKey||e.metaKey||e.shitKey||e.altKey)&&i[e.keyCode])for(var t=e.target,n=void 0;t;t=t.parentElement)if(n||"TABLE"!==t.nodeName||(n=t),n&&t.hasAttribute(f)){g(t,i[e.keyCode]),n.querySelector("["+m+'-selected="true"]').focus(),e.preventDefault();break}}),g});
/*! @nrk/core-datepicker v3.0.0 - 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){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 u(t,e){return(u=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&&u(i,n.prototype),i}).apply(null,arguments)}function c(t){var r="function"==typeof Map?new Map:void 0;return(c=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}}),u(n,t)})(t)}function s(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&&!window.Element.prototype.toggleAttribute&&(window.Element.prototype.toggleAttribute=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:!this.hasAttribute(t);return!e===this.hasAttribute(t)&&this[e?"setAttribute":"removeAttribute"](t,""),e});var e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","/":"&#x2F;","'":"&#x27;"};function n(t){return String(t||"").replace(/[&<>"'/]/g,function(t){return e[t]})}var r,d,l=(r="undefined"==typeof window?{}:window.Element.prototype,d=r.matches||r.msMatchesSelector||r.webkitMatchesSelector,r.closest?function(t,e){return t.closest(e)}:function(t,e){for(;t;t=t.parentElement)if(d.call(t,e))return t;return null});function f(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!0;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);return t[i]=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 y,p=(function(t,e){var b,v,w,k;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,w=/([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,k=/([\dh]+):([\dm]+):?([\ds]+)?/,function(t,e){if(isFinite(t))return new Date(Number(t));var n=String(t).toLowerCase(),i=new Date(isFinite(e)&&-1===n.indexOf("now")?Number(e):Date.now()),r=n.match(w)||[],o=r[1];void 0===o&&(o="y");var a=r[2];void 0===a&&(a="m");var u=r[3];void 0===u&&(u="d");var c=n.match(k)||[],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,r=String(i["get"+b[t]]()+e);f[t]=f[t].replace(/[^-\d]+/g,function(t,e,n){return e?r.substr(r.length-n.length+e,t.length):r.substr(0,Math.max(0,r.length-n.length+t.length))})-e});var h=new Date(f.year,Math.min(12,f.month+1),0).getDate();for(i.setFullYear(f.year,Math.min(11,f.month),Math.max(1,Math.min(h,f.day))),i.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],p=String(f[1]).replace(/\s/g,"")*("week"===y?7:1),m=f.slice(2).indexOf(f[0]),g=i.getDate();y?i["set"+b[y]](i["get"+b[y]]()+p):i.setDate(i.getDate()-(i.getDay()||7)+m),"month"!==y&&"year"!==y||g===i.getDate()||i.setDate(0)}return i})}(y={exports:{}},y.exports),y.exports),m={year:"*-m-d",month:"y-*-d",day:"y-m-*",hour:"*:m",minute:"h:*",second:"h:m:*",timestamp:"*",null:"*"},g={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 function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),s(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&&u(t,e)}(e,c(HTMLElement)),n=e,i=[{key:"observedAttributes",get:function(){return["timestamp","months","days"]}}],(r=[{key:"connectedCallback",value:function(){var t,e,n,r,i=this;this._date=this.date,document.addEventListener("click",this),document.addEventListener("change",this),document.addEventListener("keydown",this),setTimeout(function(){return i.attributeChangedCallback()}),t=this.nodeName,e="".concat(this.nodeName,"{display:block}"),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:"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),w("button",this,k),w("select",this,A),w("input",this,E),w("table",this,_)}}},{key:"handleEvent",value:function(t){if(!(t.defaultPrevented||t.ctrlKey||t.metaKey||t.shiftKey||t.altKey||"keydown"===t.type&&!g[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=g[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 p(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 v(this._date.getMonth()+1)}},{key:"day",get:function(){return v(this._date.getDate())}},{key:"hour",get:function(){return v(this._date.getHours())}},{key:"minute",get:function(){return v(this._date.getMinutes())}},{key:"second",get:function(){return v(this._date.getSeconds())}},{key:"date",get:function(){return p(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*/)}}])&&o(n.prototype,r),i&&o(n,i),e}(),v=function(t){return"0".concat(t).slice(-2)},w=function(t,e,n){return[].forEach.call(document.getElementsByTagName(t),function(t){(e.contains(t)||e.id===t.getAttribute(e.external))&&n(e,t,e._date)})};function k(t,e){e.disabled=t.disabled(e.value)}function E(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 _(i,t){t.firstElementChild||(t.innerHTML="\n <caption></caption><thead><tr><th>".concat(i.days.map(n).join("</th><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=i.date.getMonth(),u=i.parse("y-m-1 mon");t.caption.textContent="".concat(i.months[a],", ").concat(i.year),h("button",t).forEach(function(t){var e=!i.diff(u),n=u.getDate(),r=u.getMonth();t.textContent=n,t.value="".concat(u.getFullYear(),"-").concat(r+1,"-").concat(n),t.disabled=i.disabled(u),t.tabIndex=e-1,t.setAttribute("data-adjacent",a!==r),t.setAttribute("aria-label","".concat(n,". ").concat(i.months[r])),t.setAttribute("aria-current",u.getDate()===o.getDate()&&u.getMonth()===o.getMonth()&&u.getFullYear()===o.getFullYear()&&"date"),t.toggleAttribute("autofocus",e),u.setDate(n+1)})}function A(e,t){t.firstElementChild||(t.innerHTML=e.months.map(function(t,e){return'<option value="y-'.concat(e+1,'-d">').concat(n(t),"</option>")}).join("")),h(t.children).forEach(function(t){t.disabled=e.disabled(t.value),t.selected=!e.diff(t.value)})}return b}),window.customElements.define("core-datepicker",coreDatepicker);
//# sourceMappingURL=core-datepicker.min.js.map

@@ -1,241 +0,212 @@

const coreDatepicker = require('./core-datepicker.min')
import test from 'ava'
import path from 'path'
import puppeteer from 'puppeteer'
const standardHTML = `
<div class="my-datepicker">
<input type="timestamp" />
<select></select>
<table></table>
</div>
`
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 customSelectHTML = `
<div class="my-datepicker">
<input type="timestamp" />
<select>
<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>
<select></select>
<table></table>
</div>
`
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(() => {
coreDatepicker.months = ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember']
coreDatepicker.days = ['man', 'tirs', 'ons', 'tors', 'fre', 'lør', 'søn']
})
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('should exists', () => {
expect(coreDatepicker).toBeInstanceOf(Function)
})
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('should dispatch render when datepicker is initialized ', () => {
document.body.innerHTML = standardHTML
const callback = jest.fn()
const datepickerEl = document.querySelector('.my-datepicker')
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')
})
datepickerEl.addEventListener('datepicker.render', callback)
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')
})
coreDatepicker(datepickerEl)
expect(callback).toBeCalled()
})
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('should set selected date if date parameter is set', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const now = new Date()
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')
})
coreDatepicker(datepickerEl, now.getTime())
expect(Number(datepickerEl.querySelector('input').value)).toEqual(now.getTime())
})
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])
}
})
it('should change month names in select when replacing months property', () => {
document.body.innerHTML = standardHTML
const monthsEn = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'oktober', 'november', 'december']
const datepickerEl = document.querySelector('.my-datepicker')
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])
}
})
coreDatepicker.months = monthsEn
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')
coreDatepicker(datepickerEl)
datepickerEl.querySelectorAll('select option').forEach((option, index) => {
expect(option.textContent).toEqual(monthsEn[index])
})
})
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('should change days names in table when replacing days property', () => {
document.body.innerHTML = standardHTML
const daysTest = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu']
const datepickerEl = document.querySelector('.my-datepicker')
coreDatepicker.days = daysTest
coreDatepicker(datepickerEl)
datepickerEl.querySelectorAll('thead tr th').forEach((option, index) => {
expect(option.textContent).toEqual(daysTest[index])
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')
})
})
t.is(newDate, expected.getTime())
})
describe('<input />', () => {
it('should set selected year if input is type year', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const inputEl = datepickerEl.querySelector('input')
const now = new Date()
// Test year type
inputEl.type = 'year'
coreDatepicker(datepickerEl, now.getTime())
expect(Number(inputEl.value)).toEqual(now.getFullYear())
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)
document.querySelector('core-datepicker button').click()
})
it('should set selected month if input is type month', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const inputEl = datepickerEl.querySelector('input')
const now = new Date()
// Test month type
inputEl.type = 'month'
coreDatepicker(datepickerEl, now.getTime())
expect(Number(inputEl.value)).toEqual(now.getMonth() + 1)
})
it('should set selected day if input is type day', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const inputEl = datepickerEl.querySelector('input')
const now = new Date()
// Test day type
inputEl.type = 'day'
coreDatepicker(datepickerEl, now.getTime())
expect(Number(inputEl.value)).toEqual(now.getDate())
})
it('should set selected hour if input is type hour', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const inputEl = datepickerEl.querySelector('input')
const now = new Date()
// Test hour type
inputEl.type = 'hour'
coreDatepicker(datepickerEl, now.getTime())
expect(Number(inputEl.value)).toEqual(now.getHours())
})
it('should set selected minute if input is type minute', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const inputEl = datepickerEl.querySelector('input')
const now = new Date()
// Test minute type
inputEl.type = 'minute'
coreDatepicker(datepickerEl, now.getTime())
expect(Number(inputEl.value)).toEqual(now.getMinutes())
})
it('should set selected second if input is type second', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const inputEl = datepickerEl.querySelector('input')
const now = new Date()
// Test second type
inputEl.type = 'second'
coreDatepicker(datepickerEl, now.getTime())
expect(Number(inputEl.value)).toEqual(now.getSeconds())
})
})
describe('<select>', () => {
it('should use custom select if specified and not overwrite options', () => {
document.body.innerHTML = customSelectHTML
const datepickerEl = document.querySelector('.my-datepicker')
const selectEl = datepickerEl.querySelector('select')
coreDatepicker(datepickerEl)
expect(selectEl.childElementCount).toEqual(3)
expect(selectEl.children[0].value).toEqual('2016-m-d')
expect(selectEl.children[0].textContent).toEqual('Set year to 2016')
})
it('should support multiple select (one custom and one default)', () => {
document.body.innerHTML = customSelectHTML
const datepickerEl = document.querySelector('.my-datepicker')
const selectsEl = datepickerEl.querySelectorAll('select')
coreDatepicker(datepickerEl)
expect(selectsEl.length).toEqual(2)
expect(selectsEl[0].children[0].textContent).toEqual('Set year to 2016')
expect(selectsEl[1].children[0].textContent).toEqual(coreDatepicker.months[0])
})
})
describe('<table>', () => {
it('should show days of the week in header', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
coreDatepicker(datepickerEl)
const tableHeaders = datepickerEl.querySelectorAll('table th')
expect(tableHeaders.length).toEqual(7)
tableHeaders.forEach((el, i) => expect(el.textContent).toEqual(coreDatepicker.days[i]))
})
it('should display the current month with all dates', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const nowJan = new Date('2018-01-01') // So we know the months has 31 days and starts on monday
coreDatepicker(datepickerEl, nowJan)
expect(datepickerEl.querySelectorAll('table button')[30].textContent).toEqual('31')
})
it('should change date if a day is clicked', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const tableEl = datepickerEl.querySelector('table')
// Fri Jan 12 2018
const current = new Date(1515774608994)
coreDatepicker(datepickerEl, current)
const jan1Btn = tableEl.querySelector('tbody tr td button')
const jan12Btn = tableEl.querySelector('tbody tr:nth-child(2) td:nth-child(5) button')
jan1Btn.click()
expect(jan1Btn.getAttribute('data-core-datepicker-selected')).toEqual('true')
expect(jan12Btn.getAttribute('data-core-datepicker-selected')).toEqual('false')
})
it('should disable the dates specified by disable method', () => {
document.body.innerHTML = standardHTML
const datepickerEl = document.querySelector('.my-datepicker')
const tableEl = datepickerEl.querySelector('table')
// Fri Jan 12 2018
const current = new Date(1515774608994)
datepickerEl.addEventListener('datepicker.render', (event) => {
event.detail.disable((date) => date > current)
})
coreDatepicker(datepickerEl, current)
const currentBtn = tableEl.querySelector('tbody tr:nth-child(2) td:nth-child(5) button')
const prevBtn = tableEl.querySelector('tbody tr:nth-child(2) td:nth-child(4) button')
const nextBtn = tableEl.querySelector('tbody tr:nth-child(2) td:nth-child(6) button')
expect(currentBtn.hasAttribute('disabled')).toBe(false)
expect(prevBtn.hasAttribute('disabled')).toBe(false)
expect(nextBtn.hasAttribute('disabled')).toBe(true)
tableEl.querySelectorAll('tbody tr:nth-child(3) td')
.forEach((td) => expect(td.children[0].hasAttribute('disabled')).toEqual(true))
})
})
t.pass()
})

@@ -6,33 +6,163 @@ 'use strict';

var React = _interopDefault(require('react'));
var PropTypes = _interopDefault(require('prop-types'));
var name = "@nrk/core-datepicker";
var version = "2.0.3";
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
return true;
} catch (e) {
return false;
}
}
function _construct(Parent, args, Class) {
if (isNativeReflectConstruct()) {
_construct = Reflect.construct;
} else {
_construct = function _construct(Parent, args, Class) {
var a = [null];
a.push.apply(a, args);
var Constructor = Function.bind.apply(Parent, a);
var instance = new Constructor();
if (Class) _setPrototypeOf(instance, Class.prototype);
return instance;
};
}
return _construct.apply(null, arguments);
}
function _isNativeFunction(fn) {
return Function.toString.call(fn).indexOf("[native code]") !== -1;
}
function _wrapNativeSuper(Class) {
var _cache = typeof Map === "function" ? new Map() : undefined;
_wrapNativeSuper = function _wrapNativeSuper(Class) {
if (Class === null || !_isNativeFunction(Class)) return Class;
if (typeof Class !== "function") {
throw new TypeError("Super expression must either be null or a function");
}
if (typeof _cache !== "undefined") {
if (_cache.has(Class)) return _cache.get(Class);
_cache.set(Class, Wrapper);
}
function Wrapper() {
return _construct(Class, arguments, _getPrototypeOf(this).constructor);
}
Wrapper.prototype = Object.create(Class.prototype, {
constructor: {
value: Wrapper,
enumerable: false,
writable: true,
configurable: true
}
});
return _setPrototypeOf(Wrapper, Class);
};
return _wrapNativeSuper(Class);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _possibleConstructorReturn(self, call) {
if (call && (typeof call === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
var IS_BROWSER = typeof window !== 'undefined';
var IS_ANDROID = IS_BROWSER && /(android)/i.test(navigator.userAgent); // Bad, but needed
var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(String(navigator.platform));
var HAS_EVENT_OPTIONS = (function (has) {
if ( has === void 0 ) has = false;
try { window.addEventListener('test', null, { get passive () { has = true; } }); } catch (e) {}
return has
})();
var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(String(navigator.platform)); // Polyfill toggleAttribute for IE
if (IS_BROWSER && !window.Element.prototype.toggleAttribute) {
window.Element.prototype.toggleAttribute = function (name) {
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : !this.hasAttribute(name);
if (!force === this.hasAttribute(name)) this[force ? 'setAttribute' : 'removeAttribute'](name, '');
return force;
};
}
/**
* addEvent
* @param {String} uuid An unique ID of the event to bind - ensurnes single instance
* @param {String} type The type of event to bind
* @param {Function} handler The function to call on event
* @param {Boolean|Object} options useCapture or options object for addEventListener. Defaults to false
* addStyle
* @param {String} nodeName An unique ID of the event to bind - ensurnes single instance
* @param {String} css The css to inject
*/
function addEvent (uuid, type, handler, options) {
if ( options === void 0 ) options = false;
if (typeof window === 'undefined' || window[uuid = uuid + "-" + type]) { return } // Ensure single instance
if (!HAS_EVENT_OPTIONS && typeof options === 'object') { options = Boolean(options.capture); } // Fix unsupported options
var node = (type === 'resize' || type === 'load') ? window : document;
node.addEventListener(window[uuid] = type, handler, options);
function addStyle(nodeName, css) {
var key = "style-".concat(nodeName.toLowerCase());
var min = css.replace(/\/\*[^!][^*]*\*\//g, '').replace(/\s*(^|[:;,{}]|$)\s*/g, '$1');
document.getElementById(key) || document.head.insertAdjacentHTML('afterbegin', "<style id=\"".concat(key, "\">").concat(min, "</style>"));
}
/**

@@ -43,22 +173,36 @@ * escapeHTML

*/
var ESCAPE_MAP = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', '/': '&#x2F;', '\'': '&#x27;' };
function escapeHTML (str) {
return String(str || '').replace(/[&<>"'/]/g, function (char) { return ESCAPE_MAP[char]; })
var ESCAPE_MAP = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'/': '&#x2F;',
'\'': '&#x27;'
};
function escapeHTML(str) {
return String(str || '').replace(/[&<>"'/]/g, function (_char) {
return ESCAPE_MAP[_char];
});
}
/**
* exclude
* @param {Object} target The target object
* @param {Object} exclude The source to exclude keys from
* @return {Object} The target object without keys found in source
* 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
*/
function exclude (target, exclude, include) {
if ( include === void 0 ) include = {};
return Object.keys(target).reduce(function (acc, key) {
if (!exclude.hasOwnProperty(key)) { acc[key] = target[key]; }
return acc
}, include)
}
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;
};
}();
/**

@@ -71,27 +215,122 @@ * dispatchEvent - with infinite loop prevention

*/
var IGNORE = 'prevent_recursive_dispatch_maximum_callstack';
function dispatchEvent (element, name, detail) {
if ( detail === void 0 ) detail = {};
var ignore = "" + IGNORE + name;
function dispatchEvent(element, name) {
var detail = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var ignore = "prevent_recursive_dispatch_maximum_callstack".concat(name);
var event;
if (element[ignore]) return true; // We are already processing this event, so skip sending a new one
else element[ignore] = true; // Add name to dispatching ignore
if (element[ignore]) { return true } // We are already processing this event, so skip sending a new one
else { element[ignore] = true; } // Add name to dispatching ignore
if (typeof window.CustomEvent === 'function') {
event = new window.CustomEvent(name, { bubbles: true, cancelable: true, detail: detail });
event = new window.CustomEvent(name, {
bubbles: true,
cancelable: true,
detail: detail
});
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(name, true, true, detail);
}
// IE reports incorrect event.defaultPrevented
} // IE reports incorrect event.defaultPrevented
// but correct return value on element.dispatchEvent
var result = element.dispatchEvent(event);
element[ignore] = null; // Remove name from dispatching ignore
return result // Follow W3C standard for return value
return result; // Follow W3C standard for return value
}
function elementToReact(elementClass) {
for (var _len = arguments.length, attr = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
attr[_key - 1] = arguments[_key];
}
var name = elementClass.name || String(elementClass).match(/function ([^(]+)/)[1]; // String match for IE11
var tag = "".concat(name.replace(/\W+/, '-'), "-").concat(getUUID()).toLowerCase();
if (IS_BROWSER && !window.customElements.get(tag)) window.customElements.define(tag, elementClass);
return (
/*#__PURE__*/
function (_React$Component) {
_inherits(_class, _React$Component);
function _class(props) {
var _this;
_classCallCheck(this, _class);
_this = _possibleConstructorReturn(this, _getPrototypeOf(_class).call(this, props));
_this.ref = function (el) {
return _this.el = el;
};
attr.forEach(function (k) {
var on = "on".concat(k.replace(/(^|\.)./g, function (m) {
return m.slice(-1).toUpperCase();
})); // input.filter => onInputFilter
_this[k] = function (event) {
return _this.props[on] && _this.props[on](event);
};
});
return _this;
}
_createClass(_class, [{
key: "componentDidMount",
value: function componentDidMount() {
var _this2 = this;
attr.forEach(function (k) {
return _this2.props[k] ? _this2.el[k] = _this2.props[k] : _this2.el.addEventListener(k, _this2[k]);
});
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prev) {
var _this3 = this;
attr.forEach(function (k) {
return prev[k] !== _this3.props[k] && (_this3.el[k] = _this3.props[k]);
});
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var _this4 = this;
attr.forEach(function (k) {
return _this4.el.removeEventListener(k, _this4[k]);
});
}
}, {
key: "render",
value: function render() {
var _this5 = this;
// Convert React props to CustomElement props https://github.com/facebook/react/issues/12810
return React.createElement(tag, Object.keys(this.props).reduce(function (props, k) {
if (k === 'className') props["class"] = _this5.props[k]; // Fixes className for custom elements
else if (_this5.props[k] === true) props[k] = ''; // Fixes boolean attributes
else if (_this5.props[k] !== false) props[k] = _this5.props[k];
return props;
}, {
ref: this.ref
}));
}
}]);
return _class;
}(React.Component)
);
}
/**
* getUUID
* @return {String} A generated unique ID
*/
function getUUID() {
return Date.now().toString(36) + Math.random().toString(36).slice(2, 5);
}
/**
* queryAll

@@ -101,14 +340,16 @@ * @param {String|NodeList|Array|Element} elements A CSS selector string, nodeList, element array, or single element

*/
function queryAll (elements, context) {
if ( context === void 0 ) context = document;
function queryAll(elements) {
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;
if (elements) {
if (elements.nodeType) { return [elements] }
if (typeof elements === 'string') { return [].slice.call(context.querySelectorAll(elements)) }
if (elements.length) { return [].slice.call(elements) }
if (elements.nodeType) return [elements];
if (typeof elements === 'string') return [].slice.call(context.querySelectorAll(elements));
if (elements.length) return [].slice.call(elements);
}
return []
return [];
}
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

@@ -120,121 +361,304 @@ function createCommonjsModule(fn, module) {

var index_min = createCommonjsModule(function (module, exports) {
!function(e,t){module.exports=t();}(commonjsGlobal,function(){var D={year:"FullYear",month:"Month",week:"Date",day:"Date",hour:"Hours",minute:"Minutes",second:"Seconds"},w=/([+-]\s*\d+)\s*(second|minute|hour|day|week|month|year)|(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)/g,M=/([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,p=/([\dh]+):([\dm]+):?([\ds]+)?/;return function(e,t){if(isFinite(e)){ return new Date(Number(e)); }var n=String(e).toLowerCase(),r=new Date(isFinite(t)&&-1===n.indexOf("now")?Number(t):Date.now()),a=n.match(M)||[],o=a[1];void 0===o&&(o="y");var i=a[2];void 0===i&&(i="m");var s=a[3];void 0===s&&(s="d");var d=n.match(p)||[],u=d[1];void 0===u&&(u="h");var h=d[2];void 0===h&&(h="m");var m=d[3];void 0===m&&(m="s");var c={year:o,month:i,day:s,hour:u,minute:h,second:m};Object.keys(c).forEach(function(e){var t="month"===e?1:0,a=String(r["get"+D[e]]()+t);c[e]=c[e].replace(/[^-\d]+/g,function(e,t,n){return t?a.substr(a.length-n.length+t,e.length):a.substr(0,Math.max(0,a.length-n.length+e.length))})-t;});var f=new Date(c.year,Math.min(12,c.month+1),0).getDate();for(r.setFullYear(c.year,Math.min(11,c.month),Math.max(1,Math.min(f,c.day))),r.setHours(Math.min(24,c.hour),Math.min(59,c.minute),Math.min(59,c.second));null!==(c=w.exec(n));){var g=c[2],l=String(c[1]).replace(/\s/g,"")*("week"===g?7:1),v=c.slice(2).indexOf(c[0]),y=r.getDate();g?r["set"+D[g]](r["get"+D[g]]()+l):r.setDate(r.getDate()-(r.getDay()||7)+v),"month"!==g&&"year"!==g||y===r.getDate()||r.setDate(0);}return r}});
!function (e, t) {
module.exports = t();
}(commonjsGlobal, function () {
var D = {
year: "FullYear",
month: "Month",
week: "Date",
day: "Date",
hour: "Hours",
minute: "Minutes",
second: "Seconds"
},
w = /([+-]\s*\d+)\s*(second|minute|hour|day|week|month|year)|(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)/g,
M = /([-\dy]+)[-/.]([\dm]+)[-/.]([\dd]+)/,
p = /([\dh]+):([\dm]+):?([\ds]+)?/;
return function (e, t) {
if (isFinite(e)) return new Date(Number(e));
var n = String(e).toLowerCase(),
r = new Date(isFinite(t) && -1 === n.indexOf("now") ? Number(t) : Date.now()),
a = n.match(M) || [],
o = a[1];
void 0 === o && (o = "y");
var i = a[2];
void 0 === i && (i = "m");
var s = a[3];
void 0 === s && (s = "d");
var d = n.match(p) || [],
u = d[1];
void 0 === u && (u = "h");
var h = d[2];
void 0 === h && (h = "m");
var m = d[3];
void 0 === m && (m = "s");
var c = {
year: o,
month: i,
day: s,
hour: u,
minute: h,
second: m
};
Object.keys(c).forEach(function (e) {
var t = "month" === e ? 1 : 0,
a = String(r["get" + D[e]]() + t);
c[e] = c[e].replace(/[^-\d]+/g, function (e, t, n) {
return t ? a.substr(a.length - n.length + t, e.length) : a.substr(0, Math.max(0, a.length - n.length + e.length));
}) - t;
});
var f = new Date(c.year, Math.min(12, c.month + 1), 0).getDate();
for (r.setFullYear(c.year, Math.min(11, c.month), Math.max(1, Math.min(f, c.day))), r.setHours(Math.min(24, c.hour), Math.min(59, c.minute), Math.min(59, c.second)); null !== (c = w.exec(n));) {
var g = c[2],
l = String(c[1]).replace(/\s/g, "") * ("week" === g ? 7 : 1),
v = c.slice(2).indexOf(c[0]),
y = r.getDate();
g ? r["set" + D[g]](r["get" + D[g]]() + l) : r.setDate(r.getDate() - (r.getDay() || 7) + v), "month" !== g && "year" !== g || y === r.getDate() || r.setDate(0);
}
return r;
};
});
});
var ATTR = 'data-core-datepicker';
var UUID = ("data-" + name + "-" + version).replace(/\W+/g, '-'); // Strip invalid attribute characters
var KEY_CODES = { 33: '-1month', 34: '+1month', 35: 'y-m-99', 36: 'y-m-1', 37: '-1day', 38: '-1week', 39: '+1day', 40: '+1week' };
var MASK = { year: '*-m-d', month: 'y-*-d', day: 'y-m-*', hour: '*:m', minute: 'h:*', second: 'h:m:*', timestamp: '*' };
var MS_IN_MINUTES = 60000;
var MASK = {
year: '*-m-d',
month: 'y-*-d',
day: 'y-m-*',
hour: '*:m',
minute: 'h:*',
second: 'h:m:*',
timestamp: '*',
"null": '*'
};
var KEYS = {
33: '-1month',
34: '+1month',
35: 'y-m-99',
36: 'y-m-1',
37: '-1day',
38: '-1week',
39: '+1day',
40: '+1week'
};
var MONTHS = 'januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember';
var DAYS = 'man,tirs,ons,tors,fre,lør,søn';
function datepicker (elements, date) { // date can be String, Timestamp or Date
return queryAll(elements).map(function (element) {
var prevDate = index_min(element.getAttribute(UUID) || date);
var nextDate = index_min(typeof date === 'undefined' ? prevDate : date, prevDate);
var disable = function () { return false; };
var CoreDatepicker =
/*#__PURE__*/
function (_HTMLElement) {
_inherits(CoreDatepicker, _HTMLElement);
dispatchEvent(element, 'datepicker.render', { nextDate: nextDate, prevDate: prevDate, disable: function (fn) { return (disable = fn); } });
if (disable(nextDate)) { nextDate = prevDate; } // Jump back to prev date if next is disabled
function CoreDatepicker() {
_classCallCheck(this, CoreDatepicker);
var isUpdate = prevDate.getTime() === nextDate.getTime() || dispatchEvent(element, 'datepicker.change', { prevDate: prevDate, nextDate: nextDate });
var next = isUpdate ? nextDate : index_min(element.getAttribute(UUID) || Date.now()); // dispatchEvent can change attributes to parse prevDate again
var json = new Date(next.getTime() - next.getTimezoneOffset() * MS_IN_MINUTES).toJSON().match(/\d+/g);
var unit = { year: next.getFullYear(), month: json[1], day: json[2], hour: json[3], minute: json[4], second: json[5], timestamp: next.getTime() };
return _possibleConstructorReturn(this, _getPrototypeOf(CoreDatepicker).apply(this, arguments));
}
element.setAttribute(UUID, unit.timestamp);
queryAll('button').forEach(function (el) { return button(el, next, disable, element); });
queryAll('select', element).concat(queryAll(("select[" + ATTR + "=\"" + (element.id) + "\"]"))).forEach(function (el) { return select(el, next, disable); });
queryAll('input', element).concat(queryAll(("input[" + ATTR + "=\"" + (element.id) + "\"]"))).forEach(function (el) { return input(el, next, disable, unit); });
queryAll('table', element).concat(queryAll(("table[" + ATTR + "=\"" + (element.id) + "\"]"))).forEach(function (el) { return table(el, next, disable); });
_createClass(CoreDatepicker, [{
key: "connectedCallback",
value: function connectedCallback() {
var _this = this;
return element
})
}
this._date = this.date; // Store for later comparison and speeding up things
// Expose API and config
datepicker.parse = index_min;
datepicker.months = ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'];
datepicker.days = ['man', 'tirs', 'ons', 'tors', 'fre', 'lør', 'søn'];
document.addEventListener('click', this);
document.addEventListener('change', this);
document.addEventListener('keydown', this);
setTimeout(function () {
return _this.attributeChangedCallback();
}); // Render after children is parsed
addEvent(UUID, 'change', onChange);
addEvent(UUID, 'click', function (ref) {
var target = ref.target;
addStyle(this.nodeName, "".concat(this.nodeName, "{display:block}")); // default to display block
}
}, {
key: "disconnectedCallback",
value: function disconnectedCallback() {
this._date = this._disabled = null; // Garbage collection
for (var el = target; el; el = el.parentElement) {
if (el.nodeName === 'BUTTON') { return onChange({ target: el }) }
}
});
addEvent(UUID, 'keydown', function (event) {
if (event.ctrlKey || event.metaKey || event.shitKey || event.altKey || !KEY_CODES[event.keyCode]) { return }
for (var el = event.target, table = (void 0); el; el = el.parentElement) {
if (!table && el.nodeName === 'TABLE') { table = el; } // Store table while traversing DOM parents
if (table && el.hasAttribute(UUID)) { // Only listen to keyCodes inside table inside datepicker
datepicker(el, KEY_CODES[event.keyCode]);
table.querySelector(("[" + ATTR + "-selected=\"true\"]")).focus();
event.preventDefault();
break
document.removeEventListener('click', this);
document.removeEventListener('change', this);
document.removeEventListener('keydown', this);
}
}
});
}, {
key: "attributeChangedCallback",
value: function attributeChangedCallback() {
if (!this._date) return; // Only render after connectedCallback
function onChange (ref) {
var target = ref.target;
if (this.disabled(this.date) && !this.disabled(this._date)) return this.date = this._date; // Jump back
for (var el = target, table = (void 0); el; el = el.parentElement) {
var elem = document.getElementById(el.getAttribute(ATTR)) || el;
var mask = elem.hasAttribute(UUID) && (MASK[target.getAttribute((UUID + "-type"))] || '*');
if (this.diff(this.date)) dispatchEvent(this, 'datepicker.change', this._date = this.date);
forEach('button', this, button);
forEach('select', this, select);
forEach('input', this, input);
forEach('table', this, table);
}
}, {
key: "handleEvent",
value: function handleEvent(event) {
if (event.defaultPrevented || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey || event.type === 'keydown' && !KEYS[event.keyCode]) return;
if (!this.contains(event.target) && !closest(event.target, "[for=\"".concat(this.id, "\"]"))) return;
if (event.type === 'change') this.date = MASK[event.target.getAttribute('data-type')].replace('*', event.target.value);else if (event.type === 'click') {
var _button = closest(event.target, 'button[value]');
if (!table && el.nodeName === 'TABLE') { table = el; } // Store table while traversing DOM parents
if (mask) {
var nextDate = mask.replace('*', target.value);
var isUpdate = !elem.contains(table) || dispatchEvent(elem, 'datepicker.click.day', {
currentTarget: target,
relatedTarget: table,
prevDate: index_min(elem.getAttribute(UUID)),
nextDate: index_min(nextDate)
});
var _table = closest(event.target, 'table');
return isUpdate && datepicker(elem, nextDate)
if (_button) this.date = _button.value;
if (_button && _table) dispatchEvent(this, 'datepicker.click.day');
} else if (event.type === 'keydown' && closest(event.target, 'table')) {
this.date = KEYS[event.keyCode];
this.querySelector('[autofocus]').focus();
event.preventDefault(); // Prevent scrolling
}
}
}
}, {
key: "diff",
value: function diff(val) {
return this.parse(val).getTime() - this.timestamp;
}
}, {
key: "parse",
value: function parse(val, from) {
return index_min(val, from || this._date);
}
}, {
key: "disabled",
get: function get() {
return this._disabled || Function.prototype;
},
set: function set(fn) {
var _this2 = this;
this._disabled = typeof fn === 'function' ? function (val) {
return fn(_this2.parse(val), _this2);
} : function () {
return fn;
}; // Auto parse dates
this.attributeChangedCallback(); // Re-render
}
}, {
key: "timestamp",
get: function get() {
return String(this._date.getTime());
}
}, {
key: "year",
get: function get() {
return String(this._date.getFullYear());
} // Stringify for consistency and for truthy '0'
}, {
key: "month",
get: function get() {
return pad(this._date.getMonth() + 1);
}
}, {
key: "day",
get: function get() {
return pad(this._date.getDate());
}
}, {
key: "hour",
get: function get() {
return pad(this._date.getHours());
}
}, {
key: "minute",
get: function get() {
return pad(this._date.getMinutes());
}
}, {
key: "second",
get: function get() {
return pad(this._date.getSeconds());
}
}, {
key: "date",
get: function get() {
return index_min(this.getAttribute('timestamp') || this._date || Date.now());
},
set: function set(val) {
return this.setAttribute('timestamp', this.parse(val).getTime());
}
}, {
key: "months",
set: function set(val) {
this.setAttribute('months', [].concat(val).join(','));
},
get: function get() {
return (this.getAttribute('months') || MONTHS).split(/\s*,\s*/);
}
}, {
key: "days",
set: function set(val) {
this.setAttribute('days', [].concat(val).join(','));
},
get: function get() {
return (this.getAttribute('days') || DAYS).split(/\s*,\s*/);
}
}], [{
key: "observedAttributes",
get: function get() {
return ['timestamp', 'months', 'days'];
}
}]);
return CoreDatepicker;
}(_wrapNativeSuper(HTMLElement));
var pad = function pad(val) {
return "0".concat(val).slice(-2);
};
var forEach = function forEach(css, self, fn) {
return [].forEach.call(document.getElementsByTagName(css), function (el) {
if (self.contains(el) || self.id === el.getAttribute(self.external)) fn(self, el, self._date);
});
};
function button(self, el) {
el.disabled = self.disabled(el.value);
}
function input (el, date, disable, unit) {
var type = el.getAttribute((UUID + "-type")) || el.getAttribute('type');
function input(self, el) {
var type = el.getAttribute('data-type') || el.getAttribute('type');
if (type === 'radio' || type === 'checkbox') {
var val = index_min(el.value, date);
el.disabled = disable(val);
el.checked = val.getTime() === date.getTime();
} else if (unit[type]) {
el.disabled = self.disabled(el.value);
el.checked = !self.diff(el.value);
} else if (MASK[type]) {
el.setAttribute('type', 'number'); // Set input type to number
el.setAttribute((UUID + "-type"), type); // And store original input type
el.value = unit[type];
el.setAttribute('data-type', type); // And store original type
el.value = self[type];
}
}
function table (table, date, disable) {
function table(self, table) {
if (!table.firstElementChild) {
table.innerHTML = "\n <caption></caption><thead><tr><th>" + (datepicker.days.map(escapeHTML).join('</th><th>')) + "</th></tr></thead>\n <tbody>" + (Array(7).join(("<tr>" + (Array(8).join("<td><button type=\"button\"></button></td>")) + "</tr>"))) + "</tbody>";
table.innerHTML = "\n <caption></caption><thead><tr><th>".concat(self.days.map(escapeHTML).join('</th><th>'), "</th></tr></thead>\n <tbody>").concat(Array(7).join("<tr>".concat(Array(8).join('<td><button type="button"></button></td>'), "</tr>")), "</tbody>");
}
var today = new Date();
var day = index_min('y-m-1 mon', date); // Monday in first week of month
table.caption.textContent = (escapeHTML(datepicker.months[date.getMonth()])) + ", " + (date.getFullYear());
var month = self.date.getMonth();
var day = self.parse('y-m-1 mon'); // Monday in first week of month
table.caption.textContent = "".concat(self.months[month], ", ").concat(self.year);
queryAll('button', table).forEach(function (button) {
var isToday = day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear();
var isSelected = day.getTime() === date.getTime();
var isSelected = !self.diff(day);
var dayInMonth = day.getDate();
var month = day.getMonth();
var dayMonth = day.getMonth();
button.textContent = dayInMonth; // Set textContent instead of innerHTML avoids reflow
button.textContent = dayInMonth; // Set textContent instead of innerHTML avoids reflow
button.value = (day.getFullYear()) + "-" + (month + 1) + "-" + dayInMonth;
button.disabled = disable(day);
button.setAttribute('tabindex', isSelected - 1);
button.setAttribute((ATTR + "-selected"), isSelected);
button.setAttribute((ATTR + "-adjacent"), date.getMonth() !== month);
button.setAttribute('aria-label', (dayInMonth + ". " + (datepicker.months[month])));
button[isToday ? 'setAttribute' : 'removeAttribute']('aria-current', 'date');
button[isSelected ? 'setAttribute' : 'removeAttribute']('autofocus', '');
button.value = "".concat(day.getFullYear(), "-").concat(dayMonth + 1, "-").concat(dayInMonth);
button.disabled = self.disabled(day);
button.tabIndex = isSelected - 1;
button.setAttribute("data-adjacent", month !== dayMonth);
button.setAttribute('aria-label', "".concat(dayInMonth, ". ").concat(self.months[dayMonth]));
button.setAttribute('aria-current', day.getDate() === today.getDate() && day.getMonth() === today.getMonth() && day.getFullYear() === today.getFullYear() && 'date');
button.toggleAttribute('autofocus', isSelected);
day.setDate(dayInMonth + 1);

@@ -244,83 +668,17 @@ });

function button (el, date, disable, picker) {
if (el.getAttribute(ATTR) === picker.id || picker.contains(el)) {
el.disabled = disable(index_min(el.value, date));
}
}
function select (select, date, disable) {
function select(self, select) {
if (!select.firstElementChild) {
select.innerHTML = datepicker.months.map(function (name, month) { return ("<option value=\"y-" + (month + 1) + "-d\">" + (escapeHTML(name)) + "</option>"); }
).join('');
select.innerHTML = self.months.map(function (name, month) {
return "<option value=\"y-".concat(month + 1, "-d\">").concat(escapeHTML(name), "</option>");
}).join('');
}
queryAll(select.children).forEach(function (option) {
var val = index_min(option.value, date);
option.disabled = disable(val);
option.selected = val.getTime() === date.getTime();
option.disabled = self.disabled(option.value);
option.selected = !self.diff(option.value);
});
}
var Datepicker = /*@__PURE__*/(function (superclass) {
function Datepicker (props) {
superclass.call(this, props);
this.onClickDay = this.onClickDay.bind(this);
this.onChange = this.onChange.bind(this);
this.onRender = this.onRender.bind(this);
}
var coreDatepicker = elementToReact(CoreDatepicker, 'datepicker.change', 'datepicker.click.day', 'disabled', 'months', 'days');
if ( superclass ) Datepicker.__proto__ = superclass;
Datepicker.prototype = Object.create( superclass && superclass.prototype );
Datepicker.prototype.constructor = Datepicker;
var staticAccessors = { defaultProps: { configurable: true },months: { configurable: true },days: { configurable: true } };
staticAccessors.defaultProps.get = function () { return { date: null, disable: null, onRender: null, onChange: null, onClickDay: null } };
staticAccessors.months.set = function (months) { datepicker.months = months; };
staticAccessors.days.set = function (days) { datepicker.days = days; };
staticAccessors.months.get = function () { return datepicker.months };
staticAccessors.days.get = function () { return datepicker.days };
Datepicker.parse = function parse () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return datepicker.parse.apply(datepicker, args) };
Datepicker.prototype.componentDidMount = function componentDidMount () {
this.el.addEventListener('datepicker.click.day', this.onClickDay);
this.el.addEventListener('datepicker.change', this.onChange);
this.el.addEventListener('datepicker.render', this.onRender);
datepicker(this.el, this.props.date);
};
Datepicker.prototype.componentDidUpdate = function componentDidUpdate () { datepicker(this.el, this.props.date); };
Datepicker.prototype.componentWillUnmount = function componentWillUnmount () {
this.el.removeEventListener('datepicker.click.day', this.onClickDay);
this.el.removeEventListener('datepicker.change', this.onChange);
this.el.removeEventListener('datepicker.render', this.onRender);
};
Datepicker.prototype.onClickDay = function onClickDay (event) { this.props.onClickDay && this.props.onClickDay(event); };
Datepicker.prototype.onChange = function onChange (event) { this.props.onChange && this.props.onChange(event); };
Datepicker.prototype.onRender = function onRender (event) { this.props.disable && event.detail.disable(this.props.disable); };
Datepicker.prototype.render = function render () {
var this$1 = this;
var props = exclude(this.props, Datepicker.defaultProps, { ref: function (el) { return (this$1.el = el); } });
return React.createElement('div', props, this.props.children)
};
Object.defineProperties( Datepicker, staticAccessors );
return Datepicker;
}(React.Component));
Datepicker.propTypes = {
disable: PropTypes.func,
onRender: PropTypes.func,
onChange: PropTypes.func,
onClickDay: PropTypes.func,
date: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Date)
])
};
module.exports = Datepicker;
module.exports = coreDatepicker;

@@ -5,3 +5,3 @@ {

"author": "NRK <opensource@nrk.no> (https://www.nrk.no/)",
"version": "2.1.0",
"version": "3.0.0",
"license": "MIT",

@@ -15,6 +15,3 @@ "main": "core-datepicker.cjs.js",

"@nrk/simple-date-parse": "1.0.3"
},
"dependencies": {
"prop-types": "15.7.2"
}
}
# Core Datepicker
> `@nrk/core-datepicker` enhances all child `input`, `select` `table` and `button` elements with keyboard accessible functionality for selecting both dates and times. The interface and granularity of date refinement can easily be altered through markup.
> `@nrk/core-datepicker` enhances all child `input`, `select` `table` and `button` elements with keyboard accessible functionality
> for selecting both dates and times. The interface and granularity of date refinement can easily be altered through markup.
## Installation
```bash
npm install @nrk/core-datepicker --save-exact
```
```js
import coreDatepicker from '@nrk/core-datepicker' // Vanilla JS
import CoreDatepicker from '@nrk/core-datepicker/jsx' // React/Preact JSX
```
<!-- <script src="https://unpkg.com/preact"></script>
<script src="https://unpkg.com/preact-compat"></script>
<script>
window.React = preactCompat
window.ReactDOM = preactCompat
</script> -->
<!--demo
<script src="https://unpkg.com/@webcomponents/custom-elements"></script>
<script src="core-toggle/core-toggle.min.js"></script>

@@ -22,6 +19,6 @@ <script src="core-toggle/core-toggle.jsx.js"></script>

<style>
.my-datepicker { position: absolute; z-index: 3; padding: 1rem; background: #fff; box-shadow: 0 5px 9px rgba(0,0,0,.4) }
.my-popup:not([hidden]) { display: block; position: absolute; z-index: 3; padding: 1rem; background: #fff; box-shadow: 0 5px 9px rgba(0,0,0,.4) }
button[aria-current="date"] { border: 1px dashed }
button[data-core-datepicker-adjacent="true"] { opacity: .3 }
button[data-core-datepicker-selected="true"] { border: 2px solid }
button[data-adjacent="true"] { opacity: .3 }
button[autofocus] { border: 2px solid }
:disabled { filter: brightness(.7) sepia(1) hue-rotate(-50deg) }

@@ -31,3 +28,3 @@ </style>

## Demo
## Example

@@ -37,61 +34,65 @@ ```html

<button class="my-toggle">Velg dato</button>
<div class="my-datepicker" id="my-datepicker" hidden>
<input type="timestamp">
<fieldset>
<legend>Navigasjon</legend>
<button value="now">I dag</button>
<button value="now - 1 day">I går</button>
<button value="now + 1 day">I morgen</button>
<button value="- 1 week">Tilbake en uke</button>
<button value="+ 1 week">Fremover en uke</button>
<button value="now tuesday - 1 week">Tirsdag sist uke</button>
<button value="now + 10 years">Om ti år</button>
<button value="yy00-01-01 - 100 years">Forrige århundre</button>
</fieldset>
<label>
År
<select>
<option value="2016-m-d">2016</option>
<option value="2017-m-d">2017</option>
<option value="2018-m-d">2018</option>
<option value="2019-m-d">2019</option>
</select>
</label>
<label>Måned<select></select></label>
<fieldset>
<legend>Måned</legend>
<label><input type="radio" name="my-months" value="y-1-d">Jan</label>
<label><input type="radio" name="my-months" value="y-2-d">Feb</label>
<label><input type="radio" name="my-months" value="y-3-d">Mars</label>
<label><input type="radio" name="my-months" value="y-4-d">April</label>
<label><input type="radio" name="my-months" value="y-5-d">Mai</label>
<label><input type="radio" name="my-months" value="y-6-d">Juni</label>
<label><input type="radio" name="my-months" value="y-7-d">Juli</label>
<label><input type="radio" name="my-months" value="y-8-d">Aug</label>
<label><input type="radio" name="my-months" value="y-9-d">Sep</label>
<label><input type="radio" name="my-months" value="y-10-d">Okt</label>
<label><input type="radio" name="my-months" value="y-11-d">Nov</label>
<label><input type="radio" name="my-months" value="y-12-d">Des</label>
</fieldset>
<label><span>År</span><input type="year"></label>
<label><span>Måned</span><input type="month"></label>
<fieldset>
<legend>Klokke</legend>
<label>Time<input type="hour"></label>
<label>Minutt<input type="minute"></label>
<core-toggle popup hidden class="my-popup">
<core-datepicker id="my-datepicker"
days="Mon,Tue,Wed,Thu,Fri,Sat,Sun"
months="January,Febuary,March,April,May,June,July,August,September,October,November,December">
<input type="timestamp">
<fieldset>
<legend>Navigasjon</legend>
<button value="now">I dag</button>
<button value="now - 1 day">I går</button>
<button value="now + 1 day">I morgen</button>
<button value="- 1 week">Tilbake en uke</button>
<button value="+ 1 week">Fremover en uke</button>
<button value="now tuesday - 1 week">Tirsdag sist uke</button>
<button value="now + 10 years">Om ti år</button>
<button value="yy00-01-01 - 100 years">Forrige århundre</button>
</fieldset>
<label>
<span>Time</span>
År
<select>
<option>--</option>
<option value="11:m">11</option>
<option value="12:m">12</option>
<option value="13:m">13</option>
<option value="2016-m-d">2016</option>
<option value="2017-m-d">2017</option>
<option value="2018-m-d">2018</option>
<option value="2019-m-d">2019</option>
</select>
</label>
</fieldset>
<table></table>
</div>
<button data-core-datepicker="my-datepicker" value="now">Nå</button>
<button data-core-datepicker="my-datepicker" value="+1 week">Neste uke</button>
<select data-core-datepicker="my-datepicker">
<label>Måned<select></select></label>
<fieldset>
<legend>Måned</legend>
<label><input type="radio" name="my-months" value="y-1-d">Jan</label>
<label><input type="radio" name="my-months" value="y-2-d">Feb</label>
<label><input type="radio" name="my-months" value="y-3-d">Mars</label>
<label><input type="radio" name="my-months" value="y-4-d">April</label>
<label><input type="radio" name="my-months" value="y-5-d">Mai</label>
<label><input type="radio" name="my-months" value="y-6-d">Juni</label>
<label><input type="radio" name="my-months" value="y-7-d">Juli</label>
<label><input type="radio" name="my-months" value="y-8-d">Aug</label>
<label><input type="radio" name="my-months" value="y-9-d">Sep</label>
<label><input type="radio" name="my-months" value="y-10-d">Okt</label>
<label><input type="radio" name="my-months" value="y-11-d">Nov</label>
<label><input type="radio" name="my-months" value="y-12-d">Des</label>
</fieldset>
<label><span>År</span><input type="year"></label>
<label><span>Måned</span><input type="month"></label>
<fieldset>
<legend>Klokke</legend>
<label>Time<input type="hour"></label>
<label>Minutt<input type="minute"></label>
<label>
<span>Time</span>
<select>
<option>--</option>
<option value="11:m">11</option>
<option value="12:m">12</option>
<option value="13:m">13</option>
</select>
</label>
</fieldset>
<table></table>
</core-datepicker>
</core-toggle>
<button for="my-datepicker" value="now">Nå</button>
<button for="my-datepicker" value="+1 week">Neste uke</button>
<select for="my-datepicker">
<option>Tid</option>

@@ -102,15 +103,10 @@ <option value="11:m">11</option>

</select>
<table data-core-datepicker="my-datepicker"></table>
<table for="my-datepicker"></table>
<input type="text" id="my-datepicker-output">
<script>
// Change labels of months
coreDatepicker.months = ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
// Update GUI
document.getElementById('my-datepicker').disabled = (date) => date > Date.now()
// Change labels of days
//coreDatepicker.days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
// Update GUI
document.addEventListener('datepicker.render', function (event) {
if (event.target.id !== 'my-datepicker') return
event.detail.disable(function (date) { return date > Date.now() })
document.addEventListener('datepicker.click.day', function (event) {
console.log(event)
})

@@ -121,8 +117,5 @@

if (event.target.id !== 'my-datepicker') return
document.getElementById('my-datepicker-output').value = event.detail.nextDate.toLocaleString()
console.log(event)
document.getElementById('my-datepicker-output').value = event.target.date.toLocaleString()
})
// Initialize
coreDatepicker('#my-datepicker')
coreToggle('.my-toggle', {popup: true}) // Make popup
</script>

@@ -135,31 +128,28 @@ ```

<script type="text/jsx">
// Change labels
CoreDatepicker.months = ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
CoreDatepicker.days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
class MyDate extends React.Component {
constructor (props) {
super(props)
this.today = CoreDatepicker.parse('00:00')
this.state = {date: new Date()}
this.today = Date.now() - Date.now() % 864e3
this.state = { date: new Date() }
this.onNow = this.onNow.bind(this)
this.onChange = this.onChange.bind(this)
}
onNow () { this.setState({date: CoreDatepicker.parse('now')}) }
onChange (event) { this.setState({date: event.detail.nextDate}) }
onNow () { this.setState({ date: new Date() }) }
onChange (event) { this.setState({ date: event.target.date }) }
render () {
return <CoreToggle popup={true}>
return <div>
<button>Velg dato JSX</button>
<CoreDatepicker
date={this.state.date}
disable={(date) => date < this.today}
onChange={this.onChange}
className="my-datepicker">
<label>År<input type="year" /></label>
<label>Måned<select></select></label>
<table></table>
</CoreDatepicker>
<CoreToggle hidden popup className="my-popup">
<CoreDatepicker
timestamp={this.state.date.getTime()}
disabled={(date) => date <= this.today}
onDatepickerChange={this.onChange}>
<label>År<input type="year" /></label>
<label>Måned<select></select></label>
<table></table>
</CoreDatepicker>
</CoreToggle>
<button onClick={this.onNow}>I dag JSX</button>
<input type="text" readOnly value={this.state.date.toLocaleDateString()} />
</CoreToggle>
</div>
}

@@ -172,4 +162,18 @@ }

## Installation
Using NPM provides own element namespace and extensibility.
Recommended:
```bash
npm install @nrk/core-datepicker # Using NPM
```
Using static registers the custom element with default name automatically:
```html
<script src="https://static.nrk.no/core-components/major/5/core-datepicker/core-datepicker.min.js"></script> <!-- Using static -->
```
## Usage

@@ -182,56 +186,73 @@

```html
<div class="my-datepicker">
<!-- There are different behaviours depending on the type of <input>. -->
<!-- When 'radio' or 'checkbox' is used, core-datepicker checks the value field -->
<!-- to see if the date specified is matching the values of the <input>s. -->
<!-- When any other type is used, core-datepicker sets the type to number -->
<!-- and sets the date specified in the value field. -->
<!-- NOTE: Other input types are not handled by core-datepicker to allow -->
<!-- more customizability with other elements inside core-datepicker container -->
<input type="radio|checkbox|year|month|day|hour|minute|second|timestamp"/>
<core-datepicker
timestamp="{String}" <!-- Optional. Sets date from UNIX timestamp -->
months="{String}" <!-- Optional. Comma separated list of custom month names to be used. ("Jan,Feb,...") -->
days="{String}"> <!-- Optional. Comma separated list of custom weekday names to be used ("Man,Tir,Ons,...") -->
<!-- There are different behaviours depending on the type of <input>. -->
<!-- When 'radio' or 'checkbox' is used, core-datepicker checks the value field -->
<!-- to see if the date specified is matching the values of the <input>s. -->
<!-- When any other type is used, core-datepicker sets the type to number -->
<!-- and sets the date specified in the value field. -->
<!-- NOTE: Other input types are not handled by core-datepicker to allow -->
<!-- more customizability with other elements inside core-datepicker container -->
<input type="radio|checkbox|year|month|day|hour|minute|second|timestamp"/>
<!-- If an empty <select> is provided, core-datepicker will populate the select -->
<!-- with months and automatically handle the date state when an option is chosen -->
<select></select>
<!-- If an empty <select> is provided, core-datepicker will populate the select -->
<!-- with months and automatically handle the date state when an option is chosen -->
<select></select>
<!-- If you use a <select> that is already populated, core-datepicker will not -->
<!-- modify it, but handle the dates specified in values -->
<select>
<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>
<!-- If you use a <select> that is already populated, core-datepicker will not -->
<!-- modify it, but handle the dates specified in values -->
<select>
<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>
<!-- If an empty <table> is provided, core-datepicker will display all dates -->
<!-- for the current/chosen month -->
<table></table>
<!-- If an empty <table> is provided, core-datepicker will display all dates -->
<!-- for the current/chosen month -->
<table></table>
<!-- It is also possible to extend the datepicker with more features -->
<!-- As shown in the example, it is possible to provide buttons that moves -->
<!-- the date a certain amount of time -->
<fieldset>
<legend>Navigasjon</legend>
<!-- Dates relative to today/now by using the keyword 'now' -->
<button value="now">I dag</button>
<button value="now - 1 day|week|month|year">I går/forrige uke/måned/år</button>
<button value="now + 1 day|week|month|year">I morgen/neste uke/måned/år</button>
<!-- It is also possible to extend the datepicker with more features -->
<!-- As shown in the example, it is possible to provide buttons that moves -->
<!-- the date a certain amount of time -->
<fieldset>
<legend>Navigasjon</legend>
<!-- Dates relative to today/now by using the keyword 'now' -->
<button value="now">I dag</button>
<button value="now - 1 day|week|month|year">I går/forrige uke/måned/år</button>
<button value="now + 1 day|week|month|year">I morgen/neste uke/måned/år</button>
<!-- Semi-specific dates -->
<!-- Will use the first two digits of the current year and set the two last -->
<!-- digits of the year 0. Will set the date to 1st of January -->
<button value="yy00-01-01">Start of current century</button>
</fieldset>
</div>
<!-- Semi-specific dates -->
<!-- Will use the first two digits of the current year and set the two last -->
<!-- digits of the year 0. Will set the date to 1st of January -->
<button value="yy00-01-01">Start of current century</button>
</fieldset>
</core-datepicker>
```
```js
import coreDatepicker from '@nrk/core-datepicker'
import CoreDatepicker from '@nrk/core-datepicker' // Using NPM
window.customElements.define('core-datepicker', CoreProgress) // Using NPM. Replace 'core-datepicker' with 'my-datepicker' to namespace
coreDatepicker(
String|Element|Elements, // Accepts a selector string, NodeList, Element or array of Elements
String|Date // Specify the date which coreDatepicker should use.
// e.g:
'now + 2 days' // Will set the date to the day after tomorrow
})
const myDatepicker = document.querySelector('core-datepicker')
// Getters
myDatepicker.date // Get date object
myDatepicker.timestamp // Get timestamp
myDatepicker.year // Get year
myDatepicker.month // Get month
myDatepicker.day // Get day
myDatepicker.hour // Get hour
myDatepicker.minute // Get minute
myDatepicker.second // Get second
// Setters
myDatepicker.date = 'now' // Set date. Accepts simple-date-parse format or Date object
myDatepicker.months = ['Jan', 'Feb', ...] // Set list of custom month names to be used
myDatepicker.days = ['Man', 'Tir', ...] // Set list of custom weekday names to be used
myDatepicker.disabled = Function|Boolean // Disable dates. If true disable all dates. Function receives each date, returns a boolean.
// Methods
myDatepicker.parse('fri') // Utility function for parsing time and dates. Really just @nrk/simple-date-parse
```

@@ -244,7 +265,11 @@

<CoreDatepicker date={String|Date} onChange={function () {}} >
<input type="radio|checkbox|year|month|day|hour|minute|second|timestamp"/> /* Same as with vanilla js */
<select></select> /* Same as with vanilla js */
<table></table> /* Same as with vanilla js */
<CoreDatepicker>
<CoreDatepicker timestamp={String} // Optional. Sets date from timestamp
months={String} // Optional. Comma separated list of custom month names to be used ("Jan,Feb,...")
days={String}> // Optional. Comma separated list of custom weekday names to be used ("Man,Tir,Ons,...")
onDatepickerChange={Function}> // Optional. See 'datepicker.change'
onDatepickerClickDay={Function}> // Optional. See 'datepicker.click.day'
<input type="radio|checkbox|year|month|day|hour|minute|second|timestamp"/> // Same as with vanilla js
<select></select> // Same as with vanilla js
<table></table> // Same as with vanilla js
</CoreDatepicker>
```

@@ -255,28 +280,11 @@

## Events
Events run in the order `datepicker.click.day`\* &rarr; `datepicker.render` &rarr; `datepicker.change`
<br><small>\* datepicker.click.day only fires if user clicked inside the month days grid</small>
### datepicker.render
`'datepicker.render'` event is fired on every render. The `datepicker.render` can be used to disable specific dates or limit timespan (read: max/min). The bubbles and can therefore be detected both from button element itself, or any parent element (read event delegation):
```js
document.addEventListener('datepicker.render', (event) => {
event.target // The datepicker container
event.detail.nextDate // The new date that triggered change
event.detail.prevDate // The previous/current date
event.detail.disable(function) // Pass a fuction to the disable parameter to visually dates
// Example, disable all future dates: event.detail.disable((date) => date > Date.now())
})
```
### datepicker.change
`'datepicker.change'` event is fired when date is changed by user or programatically (both for VanillaJS and React/Preact components). The `datepicker.change` event is cancelable, meaning you can use `event.preventDefault()` to cancel change. The event also bubbles, and can therefore be detected both from button element itself, or any parent element (read event delegation):
Fired when date is changed by user or programatically:
```js
document.addEventListener('datepicker.change', (event) => {
event.target // The datepicker container
event.detail.nextDate // The new date that triggered change
event.detail.prevDate // The previous/current date
event.target // The datepicker
event.detail // The new date that triggered change
})

@@ -287,24 +295,10 @@ ```

`'datepicker.click.day'` event is fired if the user clicks a day in the month days grid. The `datepicker.click.day` runs before `datepicker.change`. The event is cancelable, meaning you can use `event.preventDefault()`. The event also bubbles, and can therefore be detected both from button element itself, or any parent element (read event delegation):
Fired if the user clicks a day in the month days grid. The `datepicker.click.day` runs before `datepicker.change`:
```js
document.addEventListener('datepicker.click.day', (event) => {
event.target // The datepicker container
event.detail.currentTarget // The button clicked
event.detail.relatedTarget // The table containing the button
event.detail.nextDate // The new date that triggered change
event.detail.prevDate // The previous/current date
event.target // The datepicker
})
```
## Methods
### datepicker.parse
A utility function for parsing time and dates. It's really just [`@nrk/simple-date-parse`](https://github.com/nrkno/simple-date-parse):
```js
coreDatepicker.parse('fri')
```
## Properties

@@ -315,11 +309,9 @@

```js
//JS
coreDatepicker.days = ['man', 'tir', 'ons', 'tor', 'fre', 'lør', 'søn'] // Change name of days
coreDatepicker.months = ['jan', 'feb', ...] // Change name of months
//JSX
CoreDatepicker.days = ['man', 'tir', 'ons', 'tor', 'fre', 'lør', 'søn'] // Change name of days
CoreDatepicker.months = ['jan', 'feb', ...] // Change name of months
myDatepicker.days = ['man', 'tir', 'ons', 'tor', 'fre', 'lør', 'søn'] // Change name of days
myDatepicker.months = ['jan', 'feb', ...] // Change name of months
myDatepicker.disabled = (date) => date > Date.now() // Disable future dates
myDatepicker.disabled = false // Enable all dates
```
## Styling

@@ -330,9 +322,10 @@

```css
.my-datepicker /* Target datepicker container */
.my-datepicker input:checked /* Target selected checkbox/radio dates */
.my-datepicker input:disabled /* Target disabled checkbox/radio dates */
.my-datepicker button:disabled /* Target disabled dates */
.my-datepicker button[aria-current="date"] /* Target current date (today) in month view */
.my-datepicker button[data-core-datepicker-adjacent="true"] /* Target dates from next or previous month in the month view */
.my-datepicker button[data-core-datepicker-selected="true"] /* Target the chosen date in month view */
.my-datepicker /* Target datepicker container */
.my-datepicker input:checked /* Target selected checkbox/radio dates */
.my-datepicker input:disabled /* Target disabled checkbox/radio dates */
.my-datepicker button:disabled /* Target disabled dates */
.my-datepicker button[autofocus] /* Target the chosen date in month view */
.my-datepicker button[aria-current="date"] /* Target current date (today) in month view */
.my-datepicker button[data-adjacent="false"] /* Target date in current month in the month view */
.my-datepicker button[data-adjacent="true"] /* Target date in next or previous month in the month view */
```

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc