UNPKG

@nent/core

Version:

Functional elements to add routing, data-binding, dynamic HTML, declarative actions, audio, video, and so much more. Supercharge static HTML files into web apps without script or builds.

214 lines (209 loc) 6.88 kB
/*! * NENT 2022 */ import { proxyCustomElement, HTMLElement, createEvent, Build, h, Host } from '@stencil/core/internal/client'; import { E as EventEmitter, e as eventBus } from './index2.js'; import { R as ROUTE_EVENTS } from './interfaces4.js'; import { s as state } from './state4.js'; import { T as TIMER_EVENTS } from './interfaces8.js'; import { g as getTimeDetails } from './time.js'; import { f as debugIf } from './logging.js'; import { t as throttle } from './promises.js'; /* It's a timer that uses the browser's animation frame to emit events at a given interval */ class FrameTimer extends EventEmitter { /** * It creates a new timer object that will fire an event every `interval` milliseconds, and will fire * a final event when the timer has run for `durationSeconds` * @param {AnimationFrameProvider} provider - AnimationFrameProvider * @param {number} interval - The interval at which to emit the current time. * @param {number} durationSeconds - The duration of the timer in seconds. * @param getStart - () => number = performance.now, * @param {null | (() => void)} [onInterval=null] - a callback that will be called every interval * milliseconds. * @param {boolean} [debug=false] - boolean - if true, will log to console.log */ constructor(provider, interval, durationSeconds, getStart = performance.now, onInterval = null, debug = false) { super(); this.provider = provider; this.interval = interval; this.durationSeconds = durationSeconds; this.getStart = getStart; this.onInterval = onInterval; this.debug = debug; this.timer = 0; this.start = 0; this.durationMs = 0; this.durationMs = this.durationSeconds * 1000; debugIf(this.debug, `presentation-timer: starting timer w/ ${this.durationSeconds} duration`); this.currentTime = getTimeDetails(this.start, this.start, this.durationMs); if (this.interval > 0) this.debouncedInterval = throttle(this.interval, () => { this.timer = this.provider.requestAnimationFrame(current => { this.doInterval(current); }); }, true, true); else this.debouncedInterval = () => { this.timer = this.provider.requestAnimationFrame(current => { this.doInterval(current); }); }; } /** * We start the timer by setting the start time, and then we call the `doInterval` function */ begin() { if (this.timer) this.stop(); this.start = this.getStart(); this.currentTime = getTimeDetails(this.start, this.start, this.durationMs); this.provider.requestAnimationFrame(async (current) => { await this.doInterval(current); }); } /** * It stops the animation by cancelling the requestAnimationFrame */ stop() { this.provider.cancelAnimationFrame(this.timer); } async doInterval(time) { var _a; this.currentTime = getTimeDetails(this.start, time, this.durationMs); if (this.currentTime.ended) { this.stop(); this.emit(TIMER_EVENTS.OnEnd, this.currentTime); } else { this.emit(TIMER_EVENTS.OnInterval, this.currentTime); await this.debouncedInterval(); } (_a = this.onInterval) === null || _a === void 0 ? void 0 : _a.call(this); } /** * It stops the timer and removes all listeners. */ destroy() { this.stop(); this.removeAllListeners(); } } const PresentationTimer = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement { constructor() { super(); this.__registerHost(); this.ready = createEvent(this, "ready", 7); this.elapsed = 0; /** * To debug timed elements, set this value to true. */ this.debug = false; /** * Duration before the timer stops and raises * the ended event (seconds). 0 = never */ this.duration = 0; /** * Interval in milliseconds to request * between the getAnimationFrame. This * affects the precision. */ this.interval = 200; /** * Display elapsed seconds */ this.display = false; /** * If set, disables auto-starting the timer * on render. This will be removed if in a view, * when the view is activated or when the start * method is called. */ this.deferLoad = false; this.now = Build.isTesting || Build.isServer ? () => new Date().getTime() : () => performance.now(); } get currentRoute() { var _a; const parent = this.el.closest('n-view-prompt') || this.el.closest('n-view'); if (parent) return parent.route; return ((_a = state.router) === null || _a === void 0 ? void 0 : _a.exactRoute) || null; } /** * Begin the timer. This is called automatically * by the presentation element. */ async begin() { this.timer.begin(); } /** * Stop the timer. */ async stop() { this.timer.stop(); } componentWillLoad() { this.timer = new FrameTimer(window, this.interval, this.duration, () => this.now(), () => { this.elapsed = this.timer.currentTime.elapsedSeconds; }, this.debug); } render() { return h(Host, null, this.display ? this.elapsed : null); } componentDidLoad() { var _a, _b; this.ready.emit(true); if (this.currentRoute) { debugIf(this.debug, `n-presentation-timer: syncing to route ${this.currentRoute.path}`); if ((_b = (_a = this.currentRoute) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.isExact) { this.timer.begin(); } this.navigationSubscription = eventBus.on(ROUTE_EVENTS.RouteChanged, () => { var _a, _b; if ((_b = (_a = this.currentRoute) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.isExact) { this.timer.begin(); } else { this.timer.stop(); } }); } else { this.timer.begin(); } } disconnectedCallback() { var _a; this.timer.destroy(); (_a = this.navigationSubscription) === null || _a === void 0 ? void 0 : _a.call(this); } get el() { return this; } }, [0, "n-presentation-timer", { "debug": [4], "timer": [1040], "duration": [2], "interval": [2], "display": [4], "deferLoad": [1028, "defer-load"], "elapsed": [32], "begin": [64], "stop": [64] }]); function defineCustomElement$1() { if (typeof customElements === "undefined") { return; } const components = ["n-presentation-timer"]; components.forEach(tagName => { switch (tagName) { case "n-presentation-timer": if (!customElements.get(tagName)) { customElements.define(tagName, PresentationTimer); } break; } }); } const NPresentationTimer = PresentationTimer; const defineCustomElement = defineCustomElement$1; export { NPresentationTimer, defineCustomElement };