UNPKG

@pqina/flip

Version:

A Beautifully Animated Flip Clock

2,060 lines (1,649 loc) 149 kB
(function() { 'use strict'; if (!Array.prototype.fill) { Object.defineProperty(Array.prototype, 'fill', { value: function(value) { // Steps 1-2. if (this == null) { throw new TypeError('this is null or not defined'); } var O = Object(this); // Steps 3-5. var len = O.length >>> 0; // Steps 6-7. var start = arguments[1]; var relativeStart = start >> 0; // Step 8. var k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); // Steps 9-10. var end = arguments[2]; var relativeEnd = end === undefined ? len : end >> 0; // Step 11. var final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len); // Step 12. while (k < final) { O[k] = value; k++; } // Step 13. return O; } }); } if (!Array.prototype.find) { Object.defineProperty(Array.prototype, 'find', { value: function (predicate) { if (this == null) { throw new TypeError('Array.prototype.find called on null or undefined'); } if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } var list = Object(this); var length = list.length >>> 0; var thisArg = arguments[1]; for (var i = 0; i !== length; i++) { if (predicate.call(thisArg, this[i], i, list)) { return this[i]; } } return undefined; } }); } // Production steps of ECMA-262, Edition 6, 22.1.2.1 if (!Array.from) { Array.from = (function () { var toStr = Object.prototype.toString; var isCallable = function (fn) { return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; }; var toInteger = function (value) { var number = Number(value); if (isNaN(number)) { return 0; } if (number === 0 || !isFinite(number)) { return number; } return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); }; var maxSafeInteger = Math.pow(2, 53) - 1; var toLength = function (value) { var len = toInteger(value); return Math.min(Math.max(len, 0), maxSafeInteger); }; // The length property of the from method is 1. return function from(arrayLike/*, mapFn, thisArg */) { // 1. Let C be the this value. var C = this; // 2. Let items be ToObject(arrayLike). var items = Object(arrayLike); // 3. ReturnIfAbrupt(items). if (arrayLike == null) { throw new TypeError("Array.from requires an array-like object - not null or undefined"); } // 4. If mapfn is undefined, then let mapping be false. var mapFn = arguments.length > 1 ? arguments[1] : void undefined; var T; if (typeof mapFn !== 'undefined') { // 5. else // 5. a If IsCallable(mapfn) is false, throw a TypeError exception. if (!isCallable(mapFn)) { throw new TypeError('Array.from: when provided, the second argument must be a function'); } // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 2) { T = arguments[2]; } } // 10. Let lenValue be Get(items, "length"). // 11. Let len be ToLength(lenValue). var len = toLength(items.length); // 13. If IsConstructor(C) is true, then // 13. a. Let A be the result of calling the [[Construct]] internal method // of C with an argument list containing the single item len. // 14. a. Else, Let A be ArrayCreate(len). var A = isCallable(C) ? Object(new C(len)) : new Array(len); // 16. Let k be 0. var k = 0; // 17. Repeat, while k < len… (also steps a - h) var kValue; while (k < len) { kValue = items[k]; if (mapFn) { A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); } else { A[k] = kValue; } k += 1; } // 18. Let putStatus be Put(A, "length", len, true). A.length = len; // 20. Return A. return A; }; }()); } Array.prototype.includes = Array.prototype.includes||function(searchElement , fromIndex) { if (!this) { throw new TypeError('Array.prototype.includes called on null or undefined'); } if (fromIndex===undefined){ var i = this.length; while(i--){ if (this[i]===searchElement){return true} } } else { var i = fromIndex, len=this.length; while(i++!==len){ // Addittion on hardware will perform as fast as, if not faster than subtraction if (this[i]===searchElement){return true} } } return false; }; // These polyfills are required for using Tick on IE 11 if (typeof Object.assign != 'function') { Object.assign = function (target, varArgs) { // .length of function is 2 if (target == null) { // TypeError if undefined or null throw new TypeError('Cannot convert undefined or null to object'); } var to = Object(target); for (var index = 1; index < arguments.length; index++) { var nextSource = arguments[index]; if (nextSource != null) { // Skip over if undefined or null for (var nextKey in nextSource) { // Avoid bugs when hasOwnProperty is shadowed if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }; } // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys if (!Object.keys) { Object.keys = (function() { var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ], dontEnumsLength = dontEnums.length; return function(obj) { if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { throw new TypeError('Object.keys called on non-object'); } var result = [], prop, i; for (prop in obj) { if (hasOwnProperty.call(obj, prop)) { result.push(prop); } } if (hasDontEnumBug) { for (i = 0; i < dontEnumsLength; i++) { if (hasOwnProperty.call(obj, dontEnums[i])) { result.push(dontEnums[i]); } } } return result; }; }()); } }()); /* eslint-disable */ /* * @pqina/flip v1.8.3 - A Beautifully Animated Flip Clock * Copyright (c) 2023 PQINA - https://pqina.nl/flip/ */ (function(root, undefined) { 'use strict'; // only create tick extensions queue if not already available if (!root.Tick) { root.Tick = []; } // add this extension root.Tick.push(['view', 'flip', (function() { if (!module) { var module = {}; } 'use strict'; var asyncGenerator = function () { function AwaitValue(value) { this.value = value; } function AsyncGenerator(gen) { var front, back; function send(key, arg) { return new Promise(function (resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; if (back) { back = back.next = request; } else { front = back = request; resume(key, arg); } }); } function resume(key, arg) { try { var result = gen[key](arg); var value = result.value; if (value instanceof AwaitValue) { Promise.resolve(value.value).then(function (arg) { resume("next", arg); }, function (arg) { resume("throw", arg); }); } else { settle(result.done ? "return" : "normal", result.value); } } catch (err) { settle("throw", err); } } function settle(type, value) { switch (type) { case "return": front.resolve({ value: value, done: true }); break; case "throw": front.reject(value); break; default: front.resolve({ value: value, done: false }); break; } front = front.next; if (front) { resume(front.key, front.arg); } else { back = null; } } this._invoke = send; if (typeof gen.return !== "function") { this.return = undefined; } } if (typeof Symbol === "function" && Symbol.asyncIterator) { AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; }; } AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); }; AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); }; AsyncGenerator.prototype.return = function (arg) { return this._invoke("return", arg); }; return { wrap: function (fn) { return function () { return new AsyncGenerator(fn.apply(this, arguments)); }; }, await: function (value) { return new AwaitValue(value); } }; }(); var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var index = (function (_ref) { var DOM = _ref.DOM, animate = _ref.Animation.animate, Extension = _ref.Extension, performance = _ref.Date.performance, _ref$View = _ref.View, rooter = _ref$View.rooter, destroyer = _ref$View.destroyer, drawer = _ref$View.drawer, updater = _ref$View.updater, styler = _ref$View.styler; var easeOutCubic = Extension.getExtension(Extension.Type.EASING_FUNCTION, 'ease-out-cubic'); var easeOutSine = Extension.getExtension(Extension.Type.EASING_FUNCTION, 'ease-out-sine'); var draw = function draw(state) { // create cards if not already created if (state.isInitialValue()) { // clear current content state.root.textContent = ''; // value spacer state.spacer = DOM.create('span', 'tick-flip-spacer'); state.root.appendChild(state.spacer); // shaders var shadowTop = DOM.create('span', 'tick-flip-shadow-top tick-flip-shadow tick-flip-front'); var shadowBottom = DOM.create('span', 'tick-flip-shadow-bottom tick-flip-shadow tick-flip-back'); state.root.appendChild(shadowTop); state.root.appendChild(shadowBottom); // create shadow element state.shadowCard = DOM.create('span', 'tick-flip-card-shadow'); state.root.appendChild(state.shadowCard); } // set spacer value state.spacer.textContent = state.value; // don't animate when invisible to the user if (!state.isInitialValue() && !DOM.visible(state.root)) { state.cards.forEach(function (card) { card.back = state.value; card.front = state.value; }); return; } // get previous card var turningCard = state.cards[state.cards.length - 1]; if (turningCard) { turningCard.waiting = false; turningCard.offset = performance(); turningCard.back = state.value; } // create a quick flipped initial card and then exit if (state.isInitialValue()) { // create flipped state (bottom) var initialBottomCard = new FlipCard(); initialBottomCard.back = state.value; initialBottomCard.offset = null; initialBottomCard.progress = 1; state.root.insertBefore(initialBottomCard.root, state.root.firstChild); state.cards.push(initialBottomCard); } // create a new card var topCard = new FlipCard(); topCard.offset = null; topCard.progress = 0; topCard.visual_progress = 0; topCard.waiting = true; topCard.front = state.value; topCard.rotate(0); // topCard.rotate(-1); // prevents slight anti-aliasing issues on Safari / Firefox state.root.insertBefore(topCard.root, state.root.firstChild); state.cards.push(topCard); if (!state.animating) { state.animating = true; var ease = Extension.getExtension(Extension.Type.EASING_FUNCTION, state.style.flipEasing); var tick = function tick() { // find cards that require animation var cardsToAnimate = state.cards.filter(function (card) { return !card.done && !card.waiting; }); if (cardsToAnimate.length === 0) { state.animating = false; return; } // calculate card progress cardsToAnimate.forEach(function (card) { if (card.offset !== null) { card.progress = (performance() - card.offset) / state.style.flipDuration; } if (card.progress >= 1) { card.progress = 1; card.done = true; } card.visual_progress = ease(card.progress); }); // sort var cardDistance = 0.01; cardsToAnimate.reverse().forEach(function (card, index) { var previousCard = cardsToAnimate[index - 1]; if (previousCard && card.visual_progress <= previousCard.visual_progress) { card.visual_progress = previousCard.visual_progress + cardDistance; } }); cardsToAnimate.reverse(); // update shadows state.cards.forEach(function (card, index) { // set default shadow and highlight levels based on visual animation progress var shadowFrontProgress = 1 - Math.abs(card.visual_progress - .5) * 2; var highlightBackProgress = 1 - (card.visual_progress - .5) / .5; card.shadowFront = shadowFrontProgress; card.highlightBack = highlightBackProgress; // recalculate levels based on other card positions var cardAbove = state.cards[index + 1]; // if there's a card above me, my back is visible, and the above card is falling if (cardAbove && card.visual_progress > .5 && card.visual_progress > 0) { card.shadowBack = easeOutCubic(cardAbove.visual_progress); } }); // update and animate cards cardsToAnimate.forEach(function (card, index) { var p = card.visual_progress; if (p > .5 && !card.done) { card.root.style.zIndex = 10 + index; } else { card.root.style.removeProperty('z-index'); } card.rotate(p * -180); }); // handle card stack shadow var shadowProgress = 0; var dist = 1; cardsToAnimate.forEach(function (card) { var d = Math.abs(card.visual_progress - .5); if (d < dist) { dist = d; shadowProgress = card.visual_progress; } }); var s = shadowProgress < .5 ? easeOutSine(shadowProgress / .5) : easeOutSine((1 - shadowProgress) / .5); state.shadowCard.style.opacity = s; DOM.transform(state.shadowCard, 'scaleY', s); // clean up cards that finished animating state.cards.filter(function (card) { return card.done; }) // gather all done cards .slice(0, -1) // don't delete the last one .forEach(function (card) { // let's delete them // remove predecessor from cards array state.cards = state.cards.filter(function (c) { return c !== card; }); // remove predecessor from the DOM if (card.root.parentNode) { state.root.removeChild(card.root); } }); requestAnimationFrame(tick); }; tick(); } }; var FlipCard = function () { function FlipCard() { classCallCheck(this, FlipCard); this._root = DOM.create('span', 'tick-flip-card'); // card front var front = DOM.create('span', 'tick-flip-panel-front tick-flip-front tick-flip-panel'); var textFront = DOM.create('span', 'tick-flip-panel-front-text'); var textFrontWrapper = DOM.create('span', 'tick-flip-panel-text-wrapper'); textFront.appendChild(textFrontWrapper); var shadowFront = DOM.create('span', 'tick-flip-panel-front-shadow'); front.appendChild(textFront); front.appendChild(shadowFront); var back = DOM.create('span', 'tick-flip-panel-back tick-flip-back tick-flip-panel'); var textBack = DOM.create('span', 'tick-flip-panel-back-text'); var textBackWrapper = DOM.create('span', 'tick-flip-panel-text-wrapper'); textBack.appendChild(textBackWrapper); var highlightBack = DOM.create('span', 'tick-flip-panel-back-highlight'); var shadowBack = DOM.create('span', 'tick-flip-panel-back-shadow'); back.appendChild(textBack); back.appendChild(highlightBack); back.appendChild(shadowBack); // create card this._root.appendChild(front); this._root.appendChild(back); // references for animation this._front = front; this._back = back; this._shadowFront = shadowFront; this._shadowBack = shadowBack; this._highlightBack = highlightBack; // back this._textBack = textBackWrapper; this._textFront = textFrontWrapper; // front and back values this._frontValue = null; this._backValue = null; } createClass(FlipCard, [{ key: 'rotate', value: function rotate(degrees) { this._front.style.transform = 'rotateX(' + degrees + 'deg)'; this._back.style.transform = 'rotateX(' + (-180 + degrees) + 'deg)'; } }, { key: 'root', get: function get$$1() { return this._root; } }, { key: 'front', set: function set$$1(value) { this._frontValue = value; this._textFront.textContent = value; }, get: function get$$1() { return this._frontValue; } }, { key: 'back', set: function set$$1(value) { this._backValue = value; this._textBack.textContent = value; }, get: function get$$1() { return this._backValue; } }, { key: 'highlightBack', set: function set$$1(value) { this._highlightBack.style.opacity = value; } }, { key: 'shadowBack', set: function set$$1(value) { this._shadowBack.style.opacity = value; } }, { key: 'shadowFront', set: function set$$1(value) { this._shadowFront.style.opacity = value; } }]); return FlipCard; }(); /** * Expose */ return function (root) { var state = { cards: [], lastCard: null, initialCard: null, shadowAbove: null, shadowBelow: null, shadowCard: null, currentValue: null, lastValue: null, front: null, back: null }; return Object.assign({}, rooter(state, root, 'flip'), updater(state), styler(state, { flipDuration: 800, flipEasing: 'ease-out-bounce' }), drawer(state, draw), destroyer(state)); }; }); module.exports = index; module.exports.identifier = { name:'flip', type:'view' }; return module.exports; }())]); }(window)); /* eslint-disable */ /* * @pqina/tick v1.8.2 - Counters Made Easy * Copyright (c) 2023 PQINA - https://github.com/pqina/tick/ */ (function(root, plugins, undefined) { 'use strict'; // Cut the mustard for really old browsers if (!root || !('MutationObserver' in root) || !('requestAnimationFrame' in root)) { return; } // private library reference var Tick = (function() { if (!module) { var module = {}; } 'use strict'; // Available extension types var ExtensionType = { FONT: 'font', VIEW: 'view', TRANSFORM: 'transform', EASING_FUNCTION: 'easing-function', TRANSITION: 'transition' }; // Registered extension collection var Extensions = {}; Extensions[ExtensionType.FONT] = {}; Extensions[ExtensionType.VIEW] = {}; Extensions[ExtensionType.TRANSFORM] = {}; Extensions[ExtensionType.EASING_FUNCTION] = {}; Extensions[ExtensionType.TRANSITION] = {}; /** * Adds multiple extensions in one go * @param type * @param extensions * @returns {null} */ var addExtensions = function addExtensions(type, extensions) { // type does not exist if (!Extensions[type]) { return null; } for (var name in extensions) { if (!extensions.hasOwnProperty(name)) { continue; } // name already exists if (Extensions[type][name]) { return null; } // register Extensions[type][name] = extensions[name]; } }; /** * Adds an extension function by type * @param type * @param name * @param fn * @returns {null} */ var addExtension = function addExtension(type, name, fn) { // type does not exist if (!Extensions[type]) { throw 'Can\'t add extension with type of "' + type + '", "' + type + '" is not a valid extension type. The following types are valid: ' + keysToList(Extensions); } // if is invalid name if (!/^[-a-z]+$/.test(name)) { throw 'Can\'t add extension with name "' + name + '", "' + name + '" is contains invalid characters. Only lowercase alphabetical characters and dashes are allowed.'; } // name in type already exists if (Extensions[type][name]) { throw 'Can\'t add extension with name "' + name + '", "' + name + '" is already added.'; } // add Extensions[type][name] = fn; }; /** * Returns an extension function by name and type * @param type * @param name * @returns {*} */ var getExtension = function getExtension(type, name) { // type does not exist if (!Extensions[type]) { throw 'Can\'t get extension with type of "' + type + '", "' + type + '" is not a valid extension type. The following types are available: ' + keysToList(Extensions); } // name in type does not exist if (!Extensions[type][name]) { throw 'Can\'t get extension with name "' + name + '", "' + name + '" is not available. The following extensions are available: ' + keysToList(Extensions[type]); } return Extensions[type][name]; }; var MILLISECOND = 1; var SECOND = 1000; var MINUTE = 60000; var HOUR = 3600000; var DAY = 86400000; var WEEK = 604800000; var MONTH = 2628000000; var YEAR = 31536000000; var TimeUnit = { 'Week': WEEK, 'Day': DAY, 'Hour': HOUR, 'Minute': MINUTE, 'Second': SECOND, 'Millisecond': MILLISECOND, 'Month': MONTH, 'Year': YEAR }; var Months = ['Januari', 'Februari', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; for (var key in TimeUnit) { if (!TimeUnit.hasOwnProperty(key)) { continue; } var val = TimeUnit[key]; if (val === MILLISECOND) { TimeUnit['mi'] = val; TimeUnit['ms'] = val; } else if (val === MONTH) { TimeUnit['M'] = val; } else { TimeUnit[key.charAt(0).toLowerCase()] = val; } TimeUnit[key.toLowerCase()] = val; TimeUnit[key.toLowerCase() + 's'] = val; } var Days = { Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6, Sunday: 0 }; var MonthFactor = { 'M': 1, 'y': 12 }; var serverDate = function serverDate(cb) { var xhr = new XMLHttpRequest(); var now = Date.now(); xhr.open('HEAD', window.location + '?noCache=' + now); xhr.setRequestHeader('Content-Type', 'text/html'); xhr.setRequestHeader('Cache-Control', 'no-cache'); xhr.onload = function () { var correction = (now - Date.now()) * .5; var responseDate = new Date(xhr.getResponseHeader('Date')); cb(new Date(responseDate.getTime() + correction)); }; xhr.send(); }; var isDate = function isDate(date) { return date instanceof Date; }; var setTime = function setTime(date, time) { date.setHours(time[0] || 0, time[1] || 0, time[2] || 0, time[3] || 0); return date; }; var setDay = function setDay(date, day) { var current = date.getDay(); var dist = day - current; date.setDate(date.getDate() + dist); return date; }; var setDayOfMonth = function setDayOfMonth(date, day) { var totalDays = daysInMonth(date.getMonth() + 1, date.getFullYear()); day = day === 'last' ? totalDays : Math.max(1, Math.min(totalDays, day)); date.setDate(day); return date; }; var setMonth = function setMonth(date, month) { date.setMonth(Months.map(function (m) { return m.toLowerCase(); }).indexOf(month)); return date; }; /* Z ±hh:mm ±hhmm ±hh */ var toTimezoneOffset = function toTimezoneOffset(ISO8601Timezone) { var current = new Date().getTimezoneOffset() * 60000; if (ISO8601Timezone === 'Z') { return current; } var parts = ISO8601Timezone.match(/\+|-|[\d]{2}|[\d]{2}/g); var multiplier = parts.shift() === '-' ? -1 : 1; var hours = parseInt(parts[0], 10); var minutes = parseInt(parts[1], 10); // calculate zone offset plus our current zone offset, all in milliseconds return multiplier * (hours * 3600000 + minutes * 60000) + current; }; var offsetDate = function offsetDate(offset) { return new Date(Date.now() + offset); }; var timezoneDate = function timezoneDate(date, offset) { return new Date(date.getTime() + offset); }; // same date (day) var sameDate = function sameDate(a, b) { return a.toDateString() === b.toDateString(); }; // exact same date and time var sameTime = function sameTime(a, b) { return a.getTime() === b.getTime(); }; var daysInMonth = function daysInMonth(month, year) { return new Date(year, month, 0).getDate(); }; var dateFromISO = function dateFromISO(iso) { // use existing timezone if (iso.match(/(Z)|([+\-][0-9]{2}:?[0-9]*$)/g)) { return new Date(iso); } // add local timezone iso += iso.indexOf('T') !== -1 ? 'Z' : ''; return dateToLocal(new Date(iso)); }; var dateToLocal = function dateToLocal(date) { return new Date(date.getTime() + date.getTimezoneOffset() * 60000); }; var timeDuration = function timeDuration(milliseconds, components) { return components.map(function (key) { var requiredMilliseconds = TimeUnit[key]; var count = Math.max(0, Math.floor(milliseconds / requiredMilliseconds)); milliseconds = milliseconds % requiredMilliseconds; return count; }); }; // makes use of time duration for everything expect years and months var dateDiff = function dateDiff(a, b, components) { // do calculations var diff = b - a; var swapped = false; if (diff < 0) { diff = a - b; var _ref = [b, a]; a = _ref[0]; b = _ref[1]; swapped = true; } // set default components if (!components) { components = ['d', 'h', 'm']; } // correct month uppercase M if set to lower case var mIndex = components.indexOf('m'); if (mIndex >= 0 && (components[mIndex - 1] === 'y' || components[mIndex + 1] === 'd')) { components[mIndex].key = 'M'; } var anchor = void 0; var monthsRemaining = void 0; var months = void 0; var presentsYears = components.includes('y'); var presentsMonths = components.includes('M'); if (presentsMonths || presentsYears) { anchor = new Date(a.valueOf() + diff); monthsRemaining = diffInMonths(anchor, a); months = presentsMonths ? Math.floor(monthsRemaining) : Math.floor(monthsRemaining / 12) * 12; diff = anchor.valueOf() - addMonths(clone$1(a), months).valueOf(); } var output = components.map(function (key) { // if is month or year if (key === 'y' || key === 'M') { var _count = Math.max(0, Math.floor(monthsRemaining / MonthFactor[key])); monthsRemaining -= _count * MonthFactor[key]; return _count; } var requiredMilliseconds = TimeUnit[key]; var count = Math.max(0, Math.floor(diff / requiredMilliseconds)); diff = diff % requiredMilliseconds; return count; }); return swapped ? output.map(function (v) { return v > 0 ? -v : v; }) : output; }; /** * Tick.helper.duration(10, 'seconds') -> milliseconds * Tick.helper.duration(a, b, format, cascade) -> [0, 10, 20, 4, 0]; * @param args * @returns {*} */ var duration = function duration() { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } // if is countdown x amount of milliseconds if (typeof args[0] === 'number' && typeof args[1] === 'string') { if (!TimeUnit[args[1]]) { throw '"' + args[1] + '" is not a valid amount.'; } return args[0] * TimeUnit[args[1]]; } // is date diff if (isDate(args[0])) { return dateDiff.apply(undefined, args); } // is duration in milliseconds if (typeof args[0] === 'number' && Array.isArray(args[1])) { return timeDuration.apply(undefined, args); } return null; }; /** * Returns current date */ var now$1 = function now() { return new Date(); }; /** * Clones the given date object * @param date * @returns {Date} */ var clone$1 = function clone(date) { return new Date(date.valueOf()); }; /** * Adds x amount of months to date * @param date * @param months * @returns {*} */ var addMonths = function addMonths(date, months) { date.setMonth(date.getMonth() + months); return date; }; /** * Difference in months between date `a` and date `b` * @param a * @param b * @returns {number} */ var diffInMonths = function diffInMonths(a, b) { var wholeMonthDiff = (b.getFullYear() - a.getFullYear()) * 12 + (b.getMonth() - a.getMonth()); var anchor = addMonths(clone$1(a), wholeMonthDiff); var anchor2 = void 0; var adjust = void 0; if (b - anchor < 0) { anchor2 = addMonths(clone$1(a), wholeMonthDiff - 1); adjust = (b - anchor) / (anchor - anchor2); } else { anchor2 = addMonths(clone$1(a), wholeMonthDiff + 1); adjust = (b - anchor) / (anchor2 - anchor); } return -(wholeMonthDiff + adjust); }; /** * Destroyer * @param state */ var destroyer = (function (state) { return { destroy: function destroy() { state.destroyed = true; if (state.frame) { cancelAnimationFrame(state.frame); } if (state.styleObserver) { state.styleObserver.disconnect(); } if (state.didResizeWindow) { window.removeEventListener('resize', state.didResizeWindow); } if (state.root && state.root.parentNode) { state.root.parentNode.removeChild(state.root); } } }; }); /** * Rooter * @param state * @param root * @param name */ var rooter = (function (state) { var root = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.createElement('span'); var name = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; state.root = root; state.aligned = null; state.destroyed = false; if (root && name) { state.root.classList.add('tick-' + name); state.root.setAttribute('data-view', name); } if (root && root.dataset.layout) { state.align = (root.dataset.layout.match(/left|right|center/) || [])[0] || 'left'; } return { appendTo: function appendTo(element) { var location = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'last'; // if no root or already attached -> exit if (!state.root || state.root && state.root.parentNode) { return; } if (location === 'last') { // place before last text node if found if (element.childNodes.length && element.childNodes[element.childNodes.length - 1].nodeType === Node.TEXT_NODE) { element.insertBefore(state.root, element.childNodes[element.childNodes.length - 1]); } else { // else just append element.appendChild(state.root); } return; } if (location === 'first') { // no elements and no text if (element.childNodes.length === 0) { element.appendChild(state.root); } // no elements but does contain text else if (element.children.length === 0 && element.childNodes.length) { element.insertBefore(state.root, element.childNodes[element.childNodes.length - 1]); } // elements! else { element.insertBefore(state.root, element.children[0]); } } if (typeof location !== 'string') { element.insertBefore(state.root, location); } } }; }); /** * Grouper * @param state * @param definition */ var grouper = (function (state, definition) { state.definition = definition; return { setDefinition: function setDefinition(definition) { state.definition = definition; } }; }); /** * Drawer * @param state * @param draw * @param present * @param drawViews */ var drawer = (function (state, _draw, drawViews, present) { return { draw: function draw() { // not dirty, might need to draw subviews if (!state.dirty) { if (drawViews) { // draw sub views var redrawn = drawViews(state); if (redrawn) { // let's fit it! (if necessary) fit(state); } } return false; } // draw everything _draw(state, present); // let's fit this view (if necessary) fit(state); // no longer dirty state.dirty = false; return true; } }; }); var fit = function fit(state) { if (!state.fit) { // nope if (!state.root || !(state.root.getAttribute('data-layout') || '').match(/fit/)) { state.fit = false; return; } // create fit info object var style = window.getComputedStyle(state.root, null); state.fit = true; state.fitInfo = { currentFontSize: parseInt(style.getPropertyValue('font-size'), 10) }; } // get available width from parent node state.fitInfo.availableWidth = state.root.parentNode.clientWidth; // the space our target element uses state.fitInfo.currentWidth = state.root.scrollWidth; // let's calculate the new font size var newFontSize = Math.min(Math.max(4, state.fitInfo.availableWidth / state.fitInfo.currentWidth * state.fitInfo.currentFontSize), 1024); // size has not changed enough? var dist = Math.abs(newFontSize - state.fitInfo.currentFontSize); // prevents flickering on firefox / safari / ie by not redrawing tiny font size changes if (dist <= 1) return; state.fitInfo.currentFontSize = newFontSize; state.root.style.fontSize = state.fitInfo.currentFontSize + 'px'; // redraw once more to quickly create better fit if (state.fitInfo.currentWidth / state.fitInfo.availableWidth < 0.5) { requestAnimationFrame(function () { return fit(state); }); } }; var updater = (function (state) { state.dirty = true; state.value = null; state.valueUpdateCount = 0; state.isInitialValue = function () { return state.valueUpdateCount <= 1; }; return { reset: function reset() { state.dirty = true; state.value = null; state.valueUpdateCount = 0; }, update: function update(value) { // don't update on same value if (equal(state.value, value)) { return; } state.value = value; state.valueUpdateCount++; state.dirty = true; } }; }); /** * Resizer * @param state */ var resizer = (function (state) { state.didResizeWindow = function () { state.dirty = true; }; window.addEventListener('resize', state.didResizeWindow); }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var asyncGenerator = function () { function AwaitValue(value) { this.value = value; } function AsyncGenerator(gen) { var front, back; function send(key, arg) { return new Promise(function (resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; if (back) { back = back.next = request; } else { front = back = request; resume(key, arg); } }); } function resume(key, arg) { try { var result = gen[key](arg); var value = result.value; if (value instanceof AwaitValue) { Promise.resolve(value.value).then(function (arg) { resume("next", arg); }, function (arg) { resume("throw", arg); }); } else { settle(result.done ? "return" : "normal", result.value); } } catch (err) { settle("throw", err); } } function settle(type, value) { switch (type) { case "return": front.resolve({ value: value, done: true }); break; case "throw": front.reject(value); break; default: front.resolve({ value: value, done: false }); break; } front = front.next; if (front) { resume(front.key, front.arg); } else { back = null; } } this._invoke = send; if (typeof gen.return !== "function") { this.return = undefined; } } if (typeof Symbol === "function" && Symbol.asyncIterator) { AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; }; } AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); }; AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); }; AsyncGenerator.prototype.return = function (arg) { return this._invoke("return", arg); }; return { wrap: function (fn) { return function () { return new AsyncGenerator(fn.apply(this, arguments)); }; }, await: function (value) { return new AwaitValue(value); } }; }(); var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; var draw = function draw(state, present) { var views = (state.definition || []).concat(); if (state.align === 'right') { views.reverse(); } var value = Array.isArray(state.value) ? state.value.concat() : _typeof(state.value) === 'object' ? clone(state.value) : state.value; views.forEach(function (view) { if (!view.presenter) { state.update = present(view); if (!view.presenter) { return; } view.presenter.appendTo(state.root); } }); views.filter(function (view) { return view.presenter !== undefined; }).forEach(function (view) { if (Array.isArray(value) && state.valueMapping) { // if set to indexes divide values over views, else (must be "none") just pass array state.update(view, state.valueMapping === 'indexes' ? state.align === 'right' ? value.pop() : value.shift() : value); } else if (view.key && value[view.key] !== undefined) { // view expects a key so value should be object state.update(view, value[view.key]); } else { // just pass on value to all sub views state.update(view, value); } }); state.views = views; // also draw subviews drawViews(state); }; var drawViews = function drawViews(state) { var redrawn = false; state.views.filter(function (view) { return view.presenter !== undefined; }).forEach(function (view) { if (view.presenter.draw()) { redrawn = true; } }); return redrawn; }; var createRoot = (function (root, definition, present) { var state = { valueMapping: null // "none" or "indexes" }; if (root && root.dataset.valueMapping) { var allowed = ['none', 'indexes']; var mapping = root.dataset.valueMapping; state.valueMapping = allowed.indexOf(mapping) !== -1 ? mapping : null; } return Object.assign({}, rooter(state, root), resizer(state), updater(state), grouper(state, definition), drawer(state, draw, drawViews, present), destroyer(state)); }); var draw$1 = function draw(state, present, ready) { // if value is not in form of array force to array var value = copyArray(Array.isArray(state.value) ? state.value : (state.value + '').split('')); // if we're aligned to the right we will append items differently so view updating is less jumpy if (state.align === 'right') { value.reverse(); } // clean up presenters if too much presenters if (state.definitions.length > value.length) { while (state.definitions.length > value.length) { var def = state.definitions.pop(); def.presenter.destroy(); } } // setup presenters value.forEach(function (value, index) { var def = state.definitions[index]; if (!def) { def = state.definitions[index] = cloneDefinition(state.definition); state.update = present(def); def.presenter.appendTo(state.root, state.align === 'right' ? 'first' : 'last'); } }); // let's update all subs (possibly sets dirty flag) value.forEach(function (value, index) { return state.update(state.definitions[index], value); }); state.views = value; // also draw subviews drawViews$1(state); }; var drawViews$1 = function drawViews(state) { var redrawn = false; state.views.forEach(function (view, index) { if (state.definitions[index].presenter.draw()) { redrawn = true; } }); return redrawn; }; var createRepeater = (function (root, definition, present) { var state = { definitions: [] }; return Object.assign({}, rooter(state, root), updater(state), grouper(state, definition), drawer(state, draw$1, drawViews$1, present), destroyer(state)); }); var VENDOR_PREFIX = typeof document === 'undefined' ? null : function () { var VENDORS = ['webkit', 'Moz', 'ms', 'O']; var i = 0; var l = VENDORS.length; var transform = void 0; var elementStyle = document.createElement('div').style; for (; i < l; i++) { transform = VENDORS[i] + 'Transform'; if (transform in elementStyle) { return VENDORS[i]; } } return null; }(); var text = function text(node, value) { var textNode = node.childNodes[0]; if (!textNode) { textNode = document.createTextNode(value); node.appendChild(textNode); } else if (value !== textNode.nodeValue) { textNode.nodeValue = value; } }; var create$1 = function create(name, className) { var el = document.createElement(name); if (className) { el.className = className; } return el; }; var observeAttributes = function observeAttributes(element, attributes, cb) { var observer = new MutationObserver(function (mutations) { attributes.forEach(function (attr) { if (mutations.filter(function (mutation) { return attributes.includes(mutation.attributeName); }).length) { cb(element.getAttribute(attr)); } }); }); observer.observe(element, { attributes: true }); return observer; }; var isHTMLElement = function isHTMLElement(value) { return value instanceof HTMLElement; }; /** * Element Transform Origin * @param element * @param value */ var setTransformOrigin = function setTransformOrigin(element, value) { element.style.transformOrigin = value; }; /** * Element Transforms * @param element * @param name * @param value * @param unit */ var setTransform = function setTransform(element, name, value) { var unit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ''; if (!element.transforms) { element.transforms = []; } var t = element.transforms.find(function (t) { return t.name === name; }); if (t) { t.value = value; } else { element.transforms.push({ name: name, value: value, unit: unit }); } setTransformStyle(element, element.transforms); }; var setTransformStyle = function setTransformStyle(element, transforms) { element.style.transform = transforms.map(function (t) { return t.name + '(' + t.value + t.unit + ')'; }).join(' '); }; var isVisible = function isVisible(element) { var elementRect = element.getBoundingClientRect(); // is above top of the page if (elementRect.bottom < 0) { return false; } // is below bottom of page if (elementRect.top > window.scrollY + window.innerHeight) { return false; } return true; }; /** * @param value { * } */ var toBoolean$1 = function toBoolean(value) { return typeof value === 'string' ? value === 'true' : value; }; /** * @param string { string } */ var capitalizeFirstLetter$1 = function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); }; /** * @param string { string } */ var trim$1 = function trim(string) { return string.trim(); }; var CACHE = {}; var cache = (function (value, fn) { var fns = fn.toString(); if (!CACHE[fns]) { CACHE[fns] = {}; } if (!CACHE[fns][value]) { CACHE[fns][value] = fn(value); } return CACHE[fns][value]; }); var isInt = new RegExp("^[0-9]+$"); var isBoolean$1 = new RegExp("^(true|false)$"); var isFloat = new RegExp("^[0-9.]+$"); var isColor = new RegExp("color"); var isShadow = new RegExp("shadow"); var isGradient = new RegExp("^(follow-gradient|horizontal-gradient|vertical-gradient)"); var isDuration = new RegExp("^[.0-9]+(?:ms|s){1}$"); var isTransition = new RegExp("^transition-?(?:in|out)?$"); var isURL = new RegExp("^url\\("); var toDuration = function toDuration(string) { return string ? parseFloat(string) * (/ms$/.test(string) ? 1 : 1000) : 0; }; var toTransition = function toTransition(string) { return string.match(/[a-z]+(?:\(.*?\))?\s?(?:origin\(.*?\))?\s?(?:[a-z]+\(.*?\))?[ .a-z-0-9]*/g).map(toTransitionPartial); }; var toTransitionPartial = function toTransitionPartial(string) { var parts = string.match(/([a-z]+(?:\(.*?\))?)\s?(?:origin\((.*?)\))?\s?([a-z]+(?:\(.*?\))?)?\s?(?:([.0-9ms]+)?\s?(?:(ease-[a-z-]+))?\s?([.0-9ms]+)?)?/); // get transition function definition var fn = toFunctionOutline(parts[1]); // get duration and easing var origin = undefined; var duration = undefined; var ease = undefined; var delay = undefined; var resolver = undefined; // skip function and figure out what other parts are parts.slice(2).filter(function (part) { return typeof part !== "undefined"; }).forEach(function (part) { // is either duration or delay if (isDuration.test(part)) { if (typeof duration === "undefined") { duration = toDuration(part); } else { delay = toDuration(part); } } // is origin if contains a space else if (/ /.test(part)) { origin = part; } // should be ease else if (/^ease-[a-z-]+$/.test(part)) { ease = part; } // should be transform else if (/^[a-z]+/.test(part)) { resolver = toFunctionOutline(part); } }); // reset easing and duration when transform is defined, these settings don't work together if (resolver) { duration = undefined; ease = undefined; } // return transition object return { name: fn.name, parameters: fn.parameters, duration: duration, ease: ease, delay: delay, origin: origin, resolver: resolver }; }; /** * toGradient * @param string { string } - string should be in format <type>(color, color) * @returns { {type: *, colors: *} } */ var toGradient = function toGradient(string) { var type = string.match(/follow-gradient|horizontal-gradient|vertical-gradient/)[0]; var colors = string.substring(type.length).match(/(?:transparent|rgb\(.*?\)|hsl\(.*?\)|hsla\(.*?\)|rgba\(.*?\)|[a-z]+|#[abcdefABCDEF\d]+)\s?(?:[\d]{1,3}%?)?/g).map(toGradientColor); return { type: type, colors: colors }; }; var gradientOffsetRegex = /\s([\d]{1,3})%?$/; var toGradientColor = function toGradientColor(string) { var offset = string.match(gradientOffsetRegex); return { offset: offset ? parseFloat(offset[1]) / 100 : null, value: toColor(string.replace(gradientOffsetRegex, "")) }; }; /** * Returns the pixels amount for the given value */ var pipetteCache = []; var getPipette = function getPipette(id, root) { if (!pipetteCache[id]) { return null; } return pipetteCache[id].find(function (p) { return p.node.parentNode === root; }); }; var setPipette = function setPipette(id, pipette) { if (!pipetteCache[id]) { pipetteCache[id] = []; } pipetteCache[id].push(pipette); }; var toPixels = typeof document === "undefined" ? function (value) { return 0; } : function (value) { var root = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.body; var id = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; if (value == 0) { return 0; } if (id) { var _pipette = getPipette(id, root) || {}; if (!_pipette.node) { _pipette.node = document.createElement("span"); _pipette.node.style.cssText = "position:absolute;padding:0;visibility:hidden;"; root.appendChild(_pipette.node); } // update value _pipette.node.style.marginTop = value; // compute style for first time if (!_pipette.style) { _pipette.style = window.getComputedStyle(_pipette.node); } setPipette(id, _pipette); return parseInt(_pipette.style.marginTop, 10); } // old method var pipette = document.createElement("span"); pipette.style.cssText = "pos