upwwwards 0.1.6-beta.1 → 0.1.7-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -298,8 +298,8 @@ class Event {
298
298
  if (config.enhance) Event.#constructData(config.enhance);
299
299
  }
300
300
  for (const [KEY, DATA] of Event.#DATA) {
301
- const CALLSTACK = [], caller = Event.#caller.bind(null, CALLSTACK), callback = DATA.crushed ? caller : DATA.callback.bind(null, caller);
302
- Event.#MANAGER.set(KEY, CALLSTACK);
301
+ const WRAPPERS = [], caller = Event.#caller.bind(null, WRAPPERS), callback = DATA.crushed ? caller : DATA.callback.bind(null, caller);
302
+ Event.#MANAGER.set(KEY, WRAPPERS);
303
303
  if (DATA.forever) {
304
304
  Event.Thread.markForever(callback);
305
305
  Event.#getThreadSubscription(KEY, callback, DATA.threadFlag)();
@@ -359,18 +359,26 @@ class Event {
359
359
  static #getWaiter(task, waitState) {
360
360
  return waitState > 0 ? Wait.debounce(task, waitState, false) : Wait.throttle(task, waitState * -1, true, false);
361
361
  }
362
+ static #getIndex(wrappers, callback) {
363
+ for (let i = 0, max = wrappers.length; i < max; i++) if (wrappers[i].original === callback) return i;
364
+ return -1;
365
+ }
362
366
  // ##ADD
363
367
  /**
364
368
  * Adds `callback` to the callstack of `key` (no duplicates), or calls it immediately (see {@link Event.sub}).
365
369
  */
366
- static #add(key, callback) {
367
- if (key === "LOAD" && Event.#status & Event.#PRE_LOAD) {
370
+ static #add(key, callback, options) {
371
+ const WRAPPERS = Event.#MANAGER.get(key);
372
+ if (!WRAPPERS || key === "LOAD" && Event.#status & Event.#PRE_LOAD) {
368
373
  callback();
369
374
  return;
370
- }
371
- const CALLSTACK = Event.#MANAGER.get(key);
372
- if (!CALLSTACK) callback();
373
- else if (!CALLSTACK.includes(callback)) CALLSTACK.push(callback);
375
+ } else if (~Event.#getIndex(WRAPPERS, callback)) return;
376
+ let original = callback;
377
+ if (options?.once) callback = (...args) => {
378
+ Event.#remove(key, original);
379
+ return original(...args);
380
+ };
381
+ WRAPPERS.push({ original, callback });
374
382
  }
375
383
  // ##REMOVE
376
384
  /**
@@ -378,10 +386,10 @@ class Event {
378
386
  */
379
387
  static #remove(key, callback) {
380
388
  Wait.cancel(callback);
381
- const CALLSTACK = Event.#MANAGER.get(key);
382
- if (!CALLSTACK) return;
383
- const INDEX = CALLSTACK.indexOf(callback);
384
- if (~INDEX) CALLSTACK.splice(INDEX, 1);
389
+ const WRAPPERS = Event.#MANAGER.get(key);
390
+ if (!WRAPPERS) return;
391
+ const INDEX = Event.#getIndex(WRAPPERS, callback);
392
+ if (~INDEX) WRAPPERS.splice(INDEX, 1);
385
393
  }
386
394
  // ##UPDATES
387
395
  /**
@@ -530,20 +538,28 @@ class Event {
530
538
  }
531
539
  // ##UTILS
532
540
  /**
533
- * Subscribes one or several tickets.
534
- * Without `subscriber`, each `[key, callback]` ticket ({@link Event.TICKET}) is added to the Event manager.
535
- * Subscribing the same callback twice to the same key has no effect, and subscribers of an event run in reverse subscription order.
536
- * With `subscriber`, each `[key, callback, options?]` ticket ({@link Event.TICKET_CUSTOM}) is passed to `subscriber.addEventListener`.
537
- * @note Without `subscriber`, the callback is called once immediately, with no arguments, and is not stored when:
538
- * the key is unknown or not registered (including on the server), or the key is `LOAD` and the current `LOAD` phase has already started.
541
+ * Subscribes one or several handlers.
542
+ *
543
+ * **Event manager** (no second argument) — pass {@link Event.TICKET} tuples:
544
+ * - `['LIFE', onLife]`
545
+ * - `['LOAD', onLoad, { once: true }]` — runs once for that key, then auto-unsubscribes
546
+ *
547
+ * Same handler twice on the same key is ignored. Handlers for a given key run in **reverse** subscription order.
548
+ *
549
+ * **DOM target** — pass a `subscriber` (`window`, `document`, an element, …) and {@link Event.TICKET_CUSTOM}
550
+ * tuples; the third field is native `AddEventListenerOptions` (`passive`, DOM `once`, …).
551
+ *
552
+ * @note Without a `subscriber`, the handler is called **immediately** (no args) and **not stored** when:
553
+ * the key is unknown / not registered (including on the server), or the key is `LOAD` and the current `LOAD`
554
+ * phase has already started.
539
555
  * @param pass A ticket or an array of tickets.
540
- * @param subscriber Optional listener target (`window`, `document`, an `Element`, …).
556
+ * @param subscriber Optional listener target for DOM (or DOM-like) events.
541
557
  * @example
542
558
  * ```ts
543
559
  * const onResize = (): void => console.log(Up.App.w, Up.App.h)
544
560
  * const onClick = (e: MouseEvent): void => console.log(e.clientX)
545
561
  *
546
- * Up.Event.sub([['LOAD', () => console.log('Page ready')], ['resize', onResize]])
562
+ * Up.Event.sub([['LOAD', () => console.log('Page ready'), { once: true }], ['resize', onResize]])
547
563
  * Up.Event.sub(['click', onClick, Up.Event.PASSIVE], document.body)
548
564
  * ```
549
565
  */
@@ -554,8 +570,9 @@ class Event {
554
570
  );
555
571
  }
556
572
  /**
557
- * Unsubscribes one or several tickets previously passed to {@link Event.sub}.
558
- * Callbacks are matched by reference, so pass the same function (and the same `subscriber`) used to subscribe.
573
+ * Unsubscribes handlers previously passed to {@link Event.sub}.
574
+ * Match by **function reference** (and the same `subscriber` if you used one).
575
+ * For Event-manager tickets, pass the same handler you subscribed — including when it was registered with `{ once: true }`.
559
576
  * @param pass A ticket or an array of tickets.
560
577
  * @param subscriber The listener target used when subscribing, if any.
561
578
  * @example
@@ -572,11 +589,12 @@ class Event {
572
589
  }
573
590
  // ##GENERATORS
574
591
  /**
575
- * Calls each subscriber of `callstack` with `args`, from last to first, yielding after each call.
592
+ * Invokes each subscriber with `args`, from last to first, yielding after each call.
593
+ * @internal
576
594
  */
577
- static *#caller(callstack, ...args) {
578
- for (let i = callstack.length - 1; i > -1; i--) {
579
- callstack[i](...args);
595
+ static *#caller(wrappers, ...args) {
596
+ for (let i = wrappers.length - 1; i > -1; i--) {
597
+ wrappers[i].callback(...args);
580
598
  yield;
581
599
  }
582
600
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/%5B1%5D/Event.ts"],"sourcesContent":["/* [Event] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SYMBOLS\r\nimport { INHERITANCE, construct, set, destroy, start, stop } from '../../symbols/index.js'\r\n\r\n // ##SCRIPTS\r\nimport Parser from '../../scripts/Parser.js'\r\nimport Wait from '../../scripts/Wait.js'\r\n\r\n // ##THIS\r\nimport Thread from './[2]/Thread.js'\r\n\r\n // ##TYPES\r\nimport type Adapter from '../../adapters/@/Adapter.js'\r\n\r\nimport type App from './[2]/[3]/App.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Event\r\n{\r\n /**\r\n * Event module configuration, declared in `up.event` of the Vite initializer and applied by `Up[construct]`.\r\n */\r\n export type CONFIG =\r\n {\r\n /**\r\n * Extra events to register alongside the built-ins, so they can be used with {@link Event.sub}.\r\n * A string registers a DOM event on `window`, with no wait and the default Thread flag ({@link Event.THREAD_FLAG}).\r\n * An object allows customization:\r\n * - `key`: real DOM event name (e.g. `\"click\"`, `\"mousemove\"`).\r\n * - `on`: `\"window\"` (default), `\"document\"` or `\"independent\"` (no DOM listener).\r\n * - `forever`: run subscribers every frame as a Thread forever task.\r\n * - `waitType` + `waitDelay`: debounce or throttle the event by `waitDelay` ms.\r\n * - `threadFlag`: Thread priority flag; `0` runs subscribers inline instead of through the Thread (not allowed with `forever`).\r\n * - `argsTypes`: TypeScript tuple, as a string, typing subscriber arguments in the generated declarations (e.g. `\"[e: MouseEvent]\"`).\r\n * @note DOM listeners are always registered as passive.\r\n */\r\n enhance?: (CUSTOM_KEY |\r\n {\r\n forever : true,\r\n key : CUSTOM_KEY,\r\n on ?: ON,\r\n waitType ?: never, // *Wait.frame or forever task\r\n threadFlag?: Thread.FLAG,\r\n argsTypes ?: `[${string}]`\r\n } |\r\n {\r\n forever ?: false,\r\n key : CUSTOM_KEY,\r\n on ?: ON,\r\n waitType ?: never, // *Wait.frame or forever task\r\n threadFlag?: 0 | Thread.FLAG,\r\n argsTypes ?: `[${string}]`\r\n } |\r\n {\r\n forever ?: false,\r\n key : CUSTOM_KEY,\r\n on ?: ON,\r\n waitType : 'debounce' | 'throttle',\r\n waitDelay : number,\r\n threadFlag?: 0 | Thread.FLAG,\r\n argsTypes ?: `[${string}]`\r\n }\r\n )[],\r\n /**\r\n * Options for the static-file wait (images, media, …) performed before each `LOAD` event.\r\n * Shallow-merged onto the defaults, where `eagerOnly`, `viewportOnly` and `emptySizeOnly` are `true`.\r\n * `limiter` cannot be set: it is set at runtime to `Adapter.root` (falls back to `document.body` when `null`).\r\n * @see {@link Wait.STATIC_FILES_CONFIG}\r\n */\r\n staticFilesConfig?: Omit<Wait.STATIC_FILES_CONFIG, 'limiter'>\r\n }\r\n\r\n /**\r\n * Status bit (`1`): the `DEATH` phase has started (the app is about to navigate away from the current page).\r\n * Setting it clears all other status bits.\r\n */\r\n export type PRE_DEATH = 1\r\n\r\n /**\r\n * Status bit (`2`): all `DEATH` subscribers have run.\r\n */\r\n export type AFTER_DEATH = 2\r\n\r\n /**\r\n * Status bit (`4`): the `LIFE` phase has started (navigation to a new page has completed).\r\n * Setting it clears all other status bits.\r\n */\r\n export type PRE_LIFE = 4\r\n\r\n /**\r\n * Status bit (`8`): all `LIFE` subscribers have run.\r\n */\r\n export type AFTER_LIFE = 8\r\n\r\n /**\r\n * Status bit (`16`): the `LOAD` phase has started (static files and `App.wait` have resolved).\r\n */\r\n export type PRE_LOAD = 16\r\n\r\n /**\r\n * Status bit (`32`): all `LOAD` subscribers have run.\r\n */\r\n export type AFTER_LOAD = 32\r\n\r\n /**\r\n * Default listener target for enhanced events (`\"window\"`).\r\n */\r\n export type DEFAULT_ON = 'window'\r\n\r\n /**\r\n * Where an event listener is attached: `\"window\"`, `\"document\"`, or `\"independent\"` (no DOM listener, triggered by the runtime itself).\r\n */\r\n export type ON = DEFAULT_ON | 'document' | 'independent'\r\n\r\n /**\r\n * Name of an event known to the Event manager: a built-in key ({@link EventData}) or an enhanced one from {@link Event.CONFIG.enhance}.\r\n */\r\n export type KEY = keyof EventData\r\n\r\n /**\r\n * DOM event name (or any string) used by enhanced events and custom subscribers.\r\n */\r\n export type CUSTOM_KEY = keyof GlobalEventHandlersEventMap | string & {}\r\n\r\n /**\r\n * Subscriber callback stored in an event callstack.\r\n */\r\n export type CALLBACK = (...args: any) => any\r\n\r\n /**\r\n * Function that returns a generator calling every subscriber of an event with the given arguments, one per `next()`.\r\n * Built-in runners that need custom argument handling (`TICK`, `DEATH`, `visibilitychange`) receive it as first parameter.\r\n */\r\n export type CALLER = (...args: any) => Thread.GENERATOR\r\n\r\n /**\r\n * Subscription tuple `[key, callback]` for an event known to the Event manager; callback arguments are inferred from the key.\r\n */\r\n export type TICKET = Ticket<KEY>\r\n\r\n /**\r\n * Subscription tuple `[key, callback, options?]` forwarded as is to `addEventListener` / `removeEventListener` on a custom subscriber.\r\n */\r\n export type TICKET_CUSTOM = [key: CUSTOM_KEY, callback: (e: any) => any, options?: AddEventListenerOptions]\r\n\r\n /**\r\n * Any object exposing `addEventListener` / `removeEventListener` (`window`, `document`, an `Element`, …).\r\n */\r\n export type SUBSCRIBER =\r\n {\r\n addEventListener : (key: string, callback: CALLBACK, ...args: any) => any,\r\n removeEventListener: (key: string, callback: CALLBACK, ...args: any) => any\r\n }\r\n\r\n /**\r\n * Runtime descriptor of any registered event (built-in or enhanced).\r\n */\r\n export type DATA = Data<ON, boolean, number, 0 | Thread.FLAG | null, (keyof typeof Event & symbol) | Thread.TASK | null>\r\n\r\n /**\r\n * Typed descriptor of one event entry: listener target, scheduling mode, wait state, Thread flag and runner.\r\n * A \"crushed\" event calls its subscribers directly with the runner's arguments; a non-crushed one goes through\r\n * a built-in runner that receives a {@link Event.CALLER} and decides how subscribers are called.\r\n * @template T Listener target ({@link Event.ON}).\r\n * @template U `true` for a forever event (runs every frame).\r\n * @template V Wait state: `0` (none), `> 0` (debounce delay in ms) or `< 0` (throttle delay in ms). Always `0` for forever events.\r\n * @template W Thread flag: `null` / `undefined` (default {@link Thread.EVENT_FLAG}), `0` (run inline, not allowed for forever events) or a {@link Thread.FLAG}.\r\n * @template X Runner: a symbol-keyed method of `Event`, a task signature, or `null` (generic callback).\r\n */\r\n export type Data<\r\n T extends ON = DEFAULT_ON,\r\n U extends boolean = false,\r\n V extends U extends true ? 0 : number = 0,\r\n W extends U extends true ? Thread.FLAG | null | undefined : 0 | Thread.FLAG | null | undefined = null,\r\n X extends (keyof typeof Event & symbol) | Thread.TASK | null | undefined = null\r\n >\r\n = X extends symbol\r\n ? X extends keyof typeof Event\r\n ? (typeof Event)[X] extends Thread.TASK\r\n ? _Data<T, U, V, W, (typeof Event)[X], X>\r\n : never\r\n : never\r\n : X extends Thread.TASK\r\n ? _Data<T, U, V, W, X, null>\r\n : _Data<T, U, V, W, (...args: any) => void, null>\r\n\r\n type _Data<\r\n T extends ON,\r\n U extends boolean,\r\n V extends number,\r\n W extends 0 | Thread.FLAG | null | undefined,\r\n X extends Thread.TASK,\r\n Y extends symbol | null\r\n >\r\n = boolean extends U\r\n ? __Data<T, true, 0, W, X, Y> | __Data<T, false, V, W, X, Y>\r\n : __Data<T, U, V, W, X, Y>\r\n\r\n type __Data<\r\n T extends ON,\r\n U extends true | false,\r\n V extends number,\r\n W extends 0 | Thread.FLAG | null | undefined,\r\n X extends Thread.TASK,\r\n Y extends symbol | null\r\n >\r\n = Y extends symbol\r\n ? U extends true\r\n ? {\r\n method : Y,\r\n forever : true,\r\n crushed : IsCrushed<X>,\r\n on : T,\r\n threadFlag: W extends 0 | null | undefined ? Thread.EVENT_FLAG : W,\r\n callback : X\r\n }\r\n : {\r\n method : Y,\r\n forever : false,\r\n crushed : IsCrushed<X>,\r\n on : T,\r\n waitState : V,\r\n threadFlag: W extends null | undefined ? Thread.EVENT_FLAG : W,\r\n callback : X\r\n }\r\n : U extends true\r\n ? {\r\n forever : true,\r\n crushed : true,\r\n on : T,\r\n threadFlag: W extends 0 | null | undefined ? Thread.EVENT_FLAG : W,\r\n callback : X\r\n }\r\n : {\r\n forever : false,\r\n crushed : true,\r\n on : T,\r\n waitState : V,\r\n threadFlag: W extends null | undefined ? Thread.EVENT_FLAG : W,\r\n callback : X\r\n }\r\n\r\n /**\r\n * Tuple `[key, callback]` whose callback arguments are inferred from the event runner.\r\n * @template T Event key (distributed over unions).\r\n */\r\n export type Ticket<T extends KEY> = T extends T ? [T, (...args: Args<EventData[T]['callback']>) => any] : never\r\n\r\n /**\r\n * Argument accepted by {@link Event.sub} / {@link Event.unsub}: one ticket or an array of tickets.\r\n * Tickets are {@link Event.TICKET} without a subscriber and {@link Event.TICKET_CUSTOM} with one.\r\n * @template T Subscriber type, or `undefined` for the Event manager.\r\n */\r\n export type Pass<T extends SUBSCRIBER | undefined> = T extends SUBSCRIBER ? TICKET_CUSTOM | TICKET_CUSTOM[] : TICKET | TICKET[]\r\n\r\n /**\r\n * Whether an event runner is \"crushed\": `false` when its first parameter is a {@link Event.CALLER}\r\n * (subscribers are driven by that runner); `true` otherwise (subscribers receive the runner's arguments directly).\r\n * @template T Runner task signature to inspect.\r\n */\r\n export type IsCrushed<T extends Thread.TASK> = T extends (caller: infer U, ...args: any) => any\r\n ? U extends Event.CALLER\r\n ? false\r\n : true\r\n : true\r\n\r\n /**\r\n * Arguments passed to subscribers for a given runner: strips a leading {@link Event.CALLER} when present,\r\n * otherwise keeps the full parameter list (all made `Required`).\r\n * Used by {@link Event.Ticket} to type ticket callbacks.\r\n * @template T Runner task signature to inspect.\r\n */\r\n export type Args<T extends Thread.TASK> = T extends (...args: infer U) => any\r\n ? U extends [Event.CALLER, ...infer V]\r\n ? Required<V>\r\n : Required<U>\r\n : []\r\n}\r\n\r\n/**\r\n * Registry of built-in events. Its keys are the event names accepted by `Event.sub` / `Event.unsub`.\r\n * Unless stated otherwise, subscribers run inside the Thread (see {@link Thread}) with the listed flag, possibly spread over several frames.\r\n*/\r\ninterface EventData\r\n{\r\n /**\r\n * Runs every frame as a Thread forever task (flag `128`). Subscribers receive the current `Thread.timestamp` (ms).\r\n */\r\n TICK: Event.Data<'independent', true, 0, Thread.EVENT_FLAG, typeof eTick>,\r\n /**\r\n * Fired after each successful navigation (`Up.Adapter` `AFTER_NAVIGATE`, flag `128`).\r\n * Use it to bring the new page to life (enter animations, bind UI, …).\r\n * Subscribers receive a promise that resolves once every `LIFE` subscriber has run.\r\n */\r\n LIFE: Event.Data<'independent', false, 0, Thread.EVENT_FLAG, typeof eLife>,\r\n /**\r\n * Fired when a client-side navigation is committed (`Up.Adapter` `ON_NAVIGATE`), before the old page is torn down.\r\n * Use it to leave the current page (exit animations, unbind, dispose). Runs synchronously (not through the Thread).\r\n * Not fired for cancelled navigations that never reach `ON_NAVIGATE`. If a committed navigation later fails,\r\n * listen to `Up.Adapter` `ABORTED` to restore state — `LIFE` will not run for that attempt.\r\n */\r\n DEATH: Event.Data<'independent', false, 0, 0, typeof eDeath>,\r\n /**\r\n * Fired after `LIFE` once the framework has updated, static files are ready ({@link Event.CONFIG.staticFilesConfig})\r\n * and `App.wait` has resolved (flag `128`). Subscribers receive a promise that resolves once every `LOAD` subscriber has run.\r\n */\r\n LOAD: Event.Data<'independent', false, 0, Thread.EVENT_FLAG, typeof eLoad>,\r\n /**\r\n * Size changes of the app root (`Adapter.root`, or `document.body`) observed with a `ResizeObserver` on the content box,\r\n * debounced by 50 ms (flag `2`). Subscribers receive the `ResizeObserverEntry[]`.\r\n */\r\n EARTHQUAKE: Event.Data<'independent', false, 50, Thread.EARTHQUAKE_FLAG, typeof eEarthquake>,\r\n /**\r\n * Native `document` `\"visibilitychange\"` event. Pauses the Thread when the page is hidden and resumes it when visible,\r\n * then calls subscribers synchronously with `document.hidden`.\r\n */\r\n visibilitychange: Event.Data<'document', false, 0, 0, typeof eVisibilitychange>,\r\n /**\r\n * Native `window` `\"resize\"` event, debounced by 50 ms (flag `8`). Subscribers receive the DOM event.\r\n */\r\n resize: Event.Data<'window', false, 50, Thread.RESIZE_FLAG, typeof eResize>,\r\n /**\r\n * Native `window` `\"scroll\"` event (flag `32`). Subscribers receive the DOM event.\r\n */\r\n scroll: Event.Data<'window', false, 0, Thread.SCROLL_FLAG, typeof eScroll>\r\n}\r\n\r\n// #CONSTANTS\r\n\r\n // ##SYMBOLS\r\nconst\r\neTick = Symbol('eTick'),\r\neLife = Symbol('eLife'),\r\neDeath = Symbol('eDeath'),\r\neLoad = Symbol('eLoad'),\r\neEarthquake = Symbol('eEarthquake'),\r\neVisibilitychange = Symbol('eVisibilitychange'),\r\neResize = Symbol('eResize'),\r\neScroll = Symbol('eScroll')\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Event manager of the runtime. It dispatches page lifecycle events and a small set of DOM events to subscribers,\r\n * scheduling them through the {@link Thread} with debounce / throttle when configured.\r\n *\r\n * Page lifecycle (driven by `Up.Adapter` navigation phases), in order on a successful change:\r\n * `DEATH` (leave current page, on `ON_NAVIGATE`) → `LIFE` (enter new page, on `AFTER_NAVIGATE`) →\r\n * `LOAD` (after framework tick, static readiness and `App.wait`).\r\n *\r\n * Subscribe with `Up.Event.sub([['DEATH', handler], ['LIFE', handler], …])`. See {@link EventData} for built-in keys\r\n * and {@link Event.CONFIG} to register more.\r\n * @note Client-only: on the server no event is registered.\r\n*/\r\nabstract class Event\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n static #PRE_DEATH : Event.PRE_DEATH = 1\r\n static #AFTER_DEATH: Event.AFTER_DEATH = 2\r\n static #PRE_LIFE : Event.PRE_LIFE = 4\r\n static #AFTER_LIFE : Event.AFTER_LIFE = 8\r\n static #PRE_LOAD : Event.PRE_LOAD = 16\r\n static #AFTER_LOAD : Event.AFTER_LOAD = 32\r\n\r\n static #THREAD_FLAG: Thread.EVENT_FLAG = 128\r\n\r\n static #ADAPTER_TICKETS: Adapter.TICKET[] =\r\n [\r\n ['ON_NAVIGATE' , Event.#eOnNavigate],\r\n ['AFTER_NAVIGATE', Event.#eAfterNavigate]\r\n ]\r\n\r\n static #PASSIVE = { passive: true } as const\r\n static #IMPASSIVE = { passive: false } as const\r\n\r\n static #STATIC_FILES_CONFIG: Wait.STATIC_FILES_CONFIG =\r\n {\r\n eagerOnly : true,\r\n viewportOnly : true,\r\n emptySizeOnly: true\r\n }\r\n\r\n static #DATA = new Map<Event.KEY, EventData[Event.KEY]>(\r\n [\r\n [\r\n 'TICK',\r\n {\r\n method : eTick,\r\n forever : true,\r\n crushed : false,\r\n on : 'independent',\r\n threadFlag: Event.#THREAD_FLAG,\r\n callback : Event[eTick]\r\n }\r\n ],\r\n [\r\n 'LIFE',\r\n {\r\n method : eLife,\r\n forever : false,\r\n crushed : true,\r\n on : 'independent',\r\n waitState : 0,\r\n threadFlag: Event.#THREAD_FLAG,\r\n callback : Event[eLife]\r\n }\r\n ],\r\n [\r\n 'DEATH',\r\n {\r\n method : eDeath,\r\n forever : false,\r\n crushed : false,\r\n on : 'independent',\r\n waitState : 0,\r\n threadFlag: 0,\r\n callback : Event[eDeath]\r\n }\r\n ],\r\n [\r\n 'LOAD',\r\n {\r\n method : eLoad,\r\n forever : false,\r\n crushed : true,\r\n on : 'independent',\r\n waitState : 0,\r\n threadFlag: Event.#THREAD_FLAG,\r\n callback : Event[eLoad]\r\n }\r\n ],\r\n [\r\n 'EARTHQUAKE',\r\n {\r\n method : eEarthquake,\r\n forever : false,\r\n crushed : true,\r\n on : 'independent',\r\n waitState : 50,\r\n threadFlag: 2,\r\n callback : Event[eEarthquake]\r\n }\r\n ],\r\n [\r\n 'visibilitychange',\r\n {\r\n method : eVisibilitychange,\r\n forever : false,\r\n crushed : false,\r\n on : 'document',\r\n waitState : 0,\r\n threadFlag: 0,\r\n callback : Event[eVisibilitychange]\r\n }\r\n ],\r\n [\r\n 'resize',\r\n {\r\n method : eResize,\r\n forever : false,\r\n crushed : true,\r\n on : 'window',\r\n waitState : 50,\r\n threadFlag: 8,\r\n callback : Event[eResize]\r\n }\r\n ],\r\n [\r\n 'scroll',\r\n {\r\n method : eScroll,\r\n forever : false,\r\n crushed : true,\r\n on : 'window',\r\n waitState : 0,\r\n threadFlag: 32,\r\n callback : Event[eScroll]\r\n }\r\n ]\r\n ])\r\n static #THREAD_TICKETS = new Map<Event.KEY, [task: Thread.TASK, flag: Thread.FLAG][]>()\r\n static #MANAGER = new Map<Event.KEY, Event.CALLBACK[]>()\r\n\r\n /**\r\n * Shared HRT stack after hydrating `Thread` (`[Adapter, App, Thread]`); `Up` later appends `Event`.\r\n * Same array as `Thread[INHERITANCE]` — does not include `Event` itself.\r\n * @internal\r\n */\r\n static [INHERITANCE] = Thread.App.HRT.hydrate<(typeof Thread)[typeof INHERITANCE], [typeof Thread]>(Thread)\r\n\r\n static #status = 0\r\n static #lifeIn = -1\r\n static #deathIn = -1\r\n\r\n static #resizeObserver: ResizeObserver | null = null\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n /**\r\n * Active framework adapter (same as {@link Up.Adapter}).\r\n * @returns The adapter class.\r\n */\r\n static get Adapter(): typeof Adapter { return Thread[INHERITANCE][0] }\r\n /**\r\n * Application runtime (same as {@link Up.App}).\r\n * @returns The {@link App} class.\r\n */\r\n static get App(): typeof App { return Thread[INHERITANCE][1] }\r\n /**\r\n * Frame scheduler (same as {@link Up.Thread}).\r\n * @returns The {@link Thread} class.\r\n */\r\n static get Thread(): typeof Thread { return Thread }\r\n\r\n /**\r\n * Status bit set when the `DEATH` phase starts ({@link Event.PRE_DEATH}).\r\n * @returns `1`.\r\n */\r\n static get PRE_DEATH(): Event.PRE_DEATH { return Event.#PRE_DEATH }\r\n /**\r\n * Status bit set once all `DEATH` subscribers have run ({@link Event.AFTER_DEATH}).\r\n * @returns `2`.\r\n */\r\n static get AFTER_DEATH(): Event.AFTER_DEATH { return Event.#AFTER_DEATH }\r\n /**\r\n * Status bit set when the `LIFE` phase starts ({@link Event.PRE_LIFE}).\r\n * @returns `4`.\r\n */\r\n static get PRE_LIFE(): Event.PRE_LIFE { return Event.#PRE_LIFE }\r\n /**\r\n * Status bit set once all `LIFE` subscribers have run ({@link Event.AFTER_LIFE}).\r\n * @returns `8`.\r\n */\r\n static get AFTER_LIFE(): Event.AFTER_LIFE { return Event.#AFTER_LIFE }\r\n /**\r\n * Status bit set when the `LOAD` phase starts ({@link Event.PRE_LOAD}).\r\n * @returns `16`.\r\n */\r\n static get PRE_LOAD(): Event.PRE_LOAD { return Event.#PRE_LOAD }\r\n /**\r\n * Status bit set once all `LOAD` subscribers have run ({@link Event.AFTER_LOAD}).\r\n * @returns `32`.\r\n */\r\n static get AFTER_LOAD(): Event.AFTER_LOAD { return Event.#AFTER_LOAD }\r\n\r\n /**\r\n * Default Thread flag of event tasks (`TICK`, `LIFE`, `LOAD` and enhanced events without `threadFlag`).\r\n * @returns `128` ({@link Thread.EVENT_FLAG}).\r\n */\r\n static get THREAD_FLAG(): Thread.EVENT_FLAG { return Event.#THREAD_FLAG }\r\n\r\n /**\r\n * Shared listener options for passive DOM listeners.\r\n * @returns `{ passive: true }`.\r\n */\r\n static get PASSIVE(): { passive: true } { return Event.#PASSIVE }\r\n /**\r\n * Shared listener options for DOM listeners that need to call `preventDefault`.\r\n * @returns `{ passive: false }`.\r\n */\r\n static get IMPASSIVE(): { passive: false } { return Event.#IMPASSIVE }\r\n\r\n /**\r\n * Current lifecycle status, a bitmask of the `PRE_*` / `AFTER_*` bits. `0` until the first navigation hook runs.\r\n * @returns The status bitmask.\r\n * @example\r\n * ```ts\r\n * if (Up.Event.status & Up.Event.AFTER_LOAD) console.log('Page fully loaded')\r\n * ```\r\n */\r\n static get status(): number { return Event.#status }\r\n /**\r\n * Time (`performance.now()`, ms) at which the current `LIFE` phase started.\r\n * @returns The timestamp, or `-1` before the first `LIFE`.\r\n */\r\n static get lifeIn(): number { return Event.#lifeIn }\r\n /**\r\n * Time (`performance.now()`, ms) at which the latest `DEATH` phase started.\r\n * @returns The timestamp, or `-1` before the first `DEATH`.\r\n */\r\n static get deathIn(): number { return Event.#deathIn }\r\n\r\n// #METHODS\r\n\r\n // ##CONSTRUCT\r\n /**\r\n * Adds enhanced event descriptors from {@link Event.CONFIG.enhance} to the registry.\r\n */\r\n static #constructData(enhance: NonNullable<Event.CONFIG['enhance']>): void\r\n {\r\n for (let i = 0, max = enhance.length; i < max; i++)\r\n {\r\n const DATA = enhance[i]\r\n\r\n if (typeof DATA === 'string') (Event.#DATA as Map<string, Event.DATA>).set(DATA,\r\n {\r\n forever : false,\r\n crushed : true,\r\n on : 'window',\r\n waitState : 0,\r\n threadFlag: Event.#THREAD_FLAG,\r\n callback : Event.App.void\r\n })\r\n else (Event.#DATA as Map<string, Event.DATA>).set(DATA.key,\r\n {\r\n crushed : true,\r\n on : DATA.on ?? 'window',\r\n callback: Event.App.void,\r\n ...(DATA.forever\r\n ? {\r\n forever : true,\r\n threadFlag: DATA.threadFlag || Event.#THREAD_FLAG\r\n }\r\n : {\r\n forever : false,\r\n waitState: 'waitDelay' in DATA && DATA.waitDelay > 0\r\n ? DATA.waitType === 'debounce'\r\n ? DATA.waitDelay\r\n : DATA.waitType === 'throttle'\r\n ? -DATA.waitDelay\r\n : 0\r\n : 0,\r\n threadFlag: DATA.threadFlag ?? Event.#THREAD_FLAG,\r\n }\r\n )\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Builds the event registry and subscriber callstacks, wraps each runner with its Thread flag and debounce / throttle,\r\n * and starts the `TICK` forever task. Merges `staticFilesConfig` onto the defaults when provided.\r\n * Does nothing outside the browser.\r\n * @internal\r\n * @param config Optional {@link Event.CONFIG}.\r\n */\r\n static [construct](config?: Event.CONFIG): void\r\n {\r\n if (!Event.Adapter.BROWSER) return\r\n\r\n if (config)\r\n {\r\n if (config.staticFilesConfig) Parser.copy(Event.#STATIC_FILES_CONFIG, config.staticFilesConfig)\r\n\r\n if (config.enhance) Event.#constructData(config.enhance)\r\n }\r\n \r\n for (const [KEY, DATA] of Event.#DATA as Map<Event.KEY, Event.DATA>)\r\n {\r\n const\r\n CALLSTACK: Event.CALLBACK[] = [],\r\n caller = Event.#caller.bind(null, CALLSTACK),\r\n callback = DATA.crushed\r\n ? caller\r\n : (DATA.callback as (caller: Event.CALLER, ...args: any) => void | Thread.GENERATOR).bind(null, caller)\r\n\r\n Event.#MANAGER.set(KEY, CALLSTACK)\r\n\r\n if (DATA.forever)\r\n {\r\n Event.Thread.markForever(callback)\r\n Event.#getThreadSubscription(KEY, callback, DATA.threadFlag)() // *Let's call him directly\r\n\r\n DATA.callback = callback\r\n }\r\n else if (DATA.threadFlag)\r\n {\r\n DATA.callback = Event.#getThreadSubscription(KEY, callback, DATA.threadFlag)\r\n\r\n if (DATA.waitState)\r\n {\r\n // *It is essential to return the generator to the thread in order to take advantage of its benefits and, most importantly, to be able to execute the generators.\r\n // *The \"waiters\" take us out of the thread, and we can't put them ahead of the task because we have modifiers that are waiting for real-time updates.\r\n // *To solve the problem, we break it down into two separate tasks.\r\n \r\n DATA.callback = Event.#getThreadSubscription(KEY, Event.#getWaiter(DATA.callback, DATA.waitState), DATA.threadFlag)\r\n }\r\n }\r\n else DATA.callback = DATA.waitState ? Event.#getWaiter(callback, DATA.waitState) : callback // *Do not use \"Wait.frame\"\r\n\r\n if ('method' in DATA && DATA.method) Event[DATA.method] = DATA.callback as any\r\n }\r\n }\r\n\r\n // ##SET\r\n /**\r\n * Sets the static-file root and creates the `ResizeObserver`.\r\n */\r\n static #setVars(): void\r\n {\r\n Event.#STATIC_FILES_CONFIG.limiter = Event.Adapter.root\r\n\r\n Event.#resizeObserver = new ResizeObserver(Event.#oResize)\r\n }\r\n\r\n /**\r\n * Subscribes to adapter navigation hooks and attaches DOM listeners.\r\n */\r\n static #setEvents(): void\r\n {\r\n Event.Adapter.sub(Event.#ADAPTER_TICKETS)\r\n\r\n for (const [KEY, DATA] of Event.#DATA)\r\n if (DATA.on !== 'independent') (DATA.on === 'window' ? window : document).addEventListener(KEY, DATA.callback as () => void, Event.#PASSIVE)\r\n }\r\n\r\n /**\r\n * Observes the app root (or `document.body`) for `EARTHQUAKE`.\r\n */\r\n static #setObservers(): void { Event.#resizeObserver!.observe(Event.Adapter.root ?? document.body, { box: 'content-box' }) }\r\n\r\n /**\r\n * Attaches navigation hooks, DOM listeners and the `ResizeObserver`. Called from `Up.set` in the browser.\r\n * @internal\r\n */\r\n static [set](): void\r\n {\r\n Event.#setVars()\r\n Event.#setEvents()\r\n Event.#setObservers()\r\n }\r\n\r\n // ##GET\r\n /**\r\n * Records `task` for teardown and returns a function scheduling it on the Thread with `flag`.\r\n */\r\n static #getThreadSubscription(key: keyof EventData, task: Thread.TASK, flag: Thread.FLAG): (...args: any) => void\r\n {\r\n const TICKETS = Event.#THREAD_TICKETS.get(key)\r\n\r\n TICKETS\r\n ? TICKETS.push([task, flag])\r\n : Event.#THREAD_TICKETS.set(key, [[task, flag]])\r\n\r\n return Event.Thread.sub.bind(null, task, flag)\r\n }\r\n\r\n /**\r\n * Wraps `task` with a trailing debounce (`waitState > 0`) or a trailing throttle (`waitState < 0`).\r\n */\r\n static #getWaiter(task: Thread.TASK, waitState: number): Thread.TASK\r\n {\r\n return waitState > 0\r\n ? Wait.debounce(task, waitState, false)\r\n : Wait.throttle(task, waitState * -1, true, false)\r\n }\r\n\r\n // ##ADD\r\n /**\r\n * Adds `callback` to the callstack of `key` (no duplicates), or calls it immediately (see {@link Event.sub}).\r\n */\r\n static #add(key: Event.KEY, callback: Event.CALLBACK): void\r\n {\r\n if (key === 'LOAD' && Event.#status & Event.#PRE_LOAD)\r\n {\r\n callback()\r\n\r\n return\r\n }\r\n\r\n const CALLSTACK = Event.#MANAGER.get(key)\r\n\r\n if (!CALLSTACK) callback()\r\n else if (!CALLSTACK.includes(callback)) CALLSTACK.push(callback)\r\n }\r\n\r\n // ##REMOVE\r\n /**\r\n * Removes `callback` from the callstack of `key`.\r\n */\r\n static #remove(key: Event.KEY, callback: Event.CALLBACK): void\r\n {\r\n Wait.cancel(callback)\r\n \r\n const CALLSTACK = Event.#MANAGER.get(key)\r\n\r\n if (!CALLSTACK) return\r\n \r\n const INDEX = CALLSTACK.indexOf(callback)\r\n\r\n if (~INDEX) CALLSTACK.splice(INDEX, 1)\r\n }\r\n\r\n // ##UPDATES\r\n /**\r\n * Applies `action` to one ticket or to each ticket of an array.\r\n */\r\n static #update(pass: Event.Pass<Event.SUBSCRIBER | undefined>, action: (...ticket: Event.TICKET | Event.TICKET_CUSTOM) => void): void\r\n {\r\n if (typeof pass[0] === 'string') return action(...pass)\r\n\r\n for (let i = 0, max = pass.length; i < max; i++) action(...pass[i])\r\n }\r\n\r\n // ##DESTROY\r\n /**\r\n * Clears callstacks and disconnects the `ResizeObserver`.\r\n */\r\n static #destroyVars(): void\r\n {\r\n if (Event.#MANAGER.size) Event.#MANAGER.clear()\r\n \r\n if (Event.#resizeObserver)\r\n {\r\n Event.#resizeObserver.disconnect()\r\n\r\n Event.#resizeObserver = null\r\n }\r\n }\r\n\r\n /**\r\n * Unsubscribes and cancels every Thread task created for events.\r\n */\r\n static #destroyTasks(): void\r\n {\r\n for (const [_, TICKETS] of Event.#THREAD_TICKETS) for (let i = 0, max = TICKETS.length; i < max; i++)\r\n {\r\n const task = TICKETS[i][0]\r\n \r\n Event.Thread.unsub(task)\r\n Wait.cancel(task)\r\n }\r\n }\r\n\r\n /**\r\n * Detaches navigation hooks and DOM listeners and cancels pending waits.\r\n */\r\n static #destroyEvents(): void\r\n {\r\n Event.Adapter.unsub(Event.#ADAPTER_TICKETS)\r\n \r\n for (const [KEY, DATA] of Event.#DATA)\r\n {\r\n if (DATA.on !== 'independent') (DATA.on === 'window' ? window : document).removeEventListener(KEY, DATA.callback as () => void)\r\n\r\n Wait.cancel(DATA.callback)\r\n }\r\n }\r\n\r\n /**\r\n * Removes all subscribers, listeners, observers and event tasks. Called from `Up.destroy` in the browser.\r\n * @internal\r\n */\r\n static [destroy](): void\r\n {\r\n Event.#destroyVars()\r\n Event.#destroyTasks()\r\n Event.#destroyEvents()\r\n }\r\n\r\n // ##EVENTS\r\n /**\r\n * Adapter `ON_NAVIGATE` hook: runs the `DEATH` phase (leave current page once navigation is committed).\r\n */\r\n static #eOnNavigate(): void\r\n {\r\n Event.#status = Event.#PRE_DEATH\r\n Event.#deathIn = performance.now()\r\n\r\n ;(Event[eDeath] as any)()\r\n\r\n Event.#status |= Event.#AFTER_DEATH\r\n }\r\n\r\n /**\r\n * Adapter `AFTER_NAVIGATE` hook: runs the `LIFE` phase, waits for readiness, then runs the `LOAD` phase.\r\n */\r\n static async #eAfterNavigate(): Promise<void>\r\n {\r\n let res = Event.App.void\r\n \r\n Event.#status = Event.#PRE_LIFE\r\n Event.#lifeIn = performance.now()\r\n \r\n Event[eLife](new Promise((r): void => { res = r }))\r\n\r\n await Event.Thread.wait(Event.#THREAD_TICKETS.get('LIFE')![0][0])\r\n\r\n Event.#status |= Event.#AFTER_LIFE\r\n\r\n res()\r\n\r\n await Event.Adapter.tick() // *Wait for updates brought by the \"LIFE\" event\r\n await Wait.staticFiles(Event.#STATIC_FILES_CONFIG) // *Static readiness before LOAD (see CONFIG.staticFilesConfig / #STATIC_FILES_CONFIG)\r\n await Event.App.wait\r\n\r\n Event.#status |= Event.#PRE_LOAD\r\n\r\n Event[eLoad](new Promise((r): void => { res = r }))\r\n\r\n await Event.Thread.wait(Event.#THREAD_TICKETS.get('LOAD')![0][0])\r\n\r\n Event.#status |= Event.#AFTER_LOAD\r\n\r\n res()\r\n }\r\n\r\n /**\r\n * `TICK` runner: calls subscribers with the current frame timestamp.\r\n * @internal\r\n */\r\n static [eTick](caller: Event.CALLER, timestamp = Event.Thread.timestamp): Thread.GENERATOR { return caller(timestamp) }\r\n\r\n /**\r\n * `LIFE` trigger (signature placeholder, replaced by the scheduled runner in `[construct]`).\r\n * @internal\r\n */\r\n static [eLife](promise: Promise<void>): void {}\r\n\r\n /**\r\n * `DEATH` runner: calls every subscriber synchronously.\r\n * @internal\r\n */\r\n static [eDeath](caller: Event.CALLER): void\r\n {\r\n const GEN = caller()\r\n\r\n while (!GEN.next().done) {}\r\n }\r\n\r\n /**\r\n * `LOAD` trigger (signature placeholder, replaced by the scheduled runner in `[construct]`).\r\n * @internal\r\n */\r\n static [eLoad](promise: Promise<void>): void {}\r\n\r\n /**\r\n * `EARTHQUAKE` trigger (signature placeholder, replaced by the scheduled runner in `[construct]`).\r\n * @internal\r\n */\r\n static [eEarthquake](o: ResizeObserverEntry[]): void {}\r\n\r\n /**\r\n * `visibilitychange` runner: pauses or resumes the Thread, then calls every subscriber synchronously with `document.hidden`.\r\n * @internal\r\n */\r\n static [eVisibilitychange](caller: Event.CALLER): void\r\n {\r\n Event.Thread[document.hidden ? stop : start]()\r\n\r\n const GEN = caller(document.hidden)\r\n\r\n while (!GEN.next().done) {}\r\n }\r\n\r\n /**\r\n * `resize` trigger (signature placeholder, replaced by the DOM listener in `[construct]`).\r\n * @internal\r\n */\r\n static [eResize](e: Event): void {}\r\n\r\n /**\r\n * `scroll` trigger (signature placeholder, replaced by the DOM listener in `[construct]`).\r\n * @internal\r\n */\r\n static [eScroll](e: Event): void {}\r\n\r\n // ##OBSERVERS\r\n /**\r\n * `ResizeObserver` callback forwarding entries to `EARTHQUAKE`.\r\n */\r\n static #oResize(o: ResizeObserverEntry[]): void\r\n {\r\n // TODO: Earthquake ne devrait peut-être pas être un événements mais avoir un Plugin dédié permettant de fragmenter l'app en zone observable.\r\n // *Ici les earthquake se déclenchent aussi sur la largeur.\r\n Event[eEarthquake](o)\r\n }\r\n\r\n // ##UTILS\r\n /**\r\n * Subscribes one or several tickets.\r\n * Without `subscriber`, each `[key, callback]` ticket ({@link Event.TICKET}) is added to the Event manager.\r\n * Subscribing the same callback twice to the same key has no effect, and subscribers of an event run in reverse subscription order.\r\n * With `subscriber`, each `[key, callback, options?]` ticket ({@link Event.TICKET_CUSTOM}) is passed to `subscriber.addEventListener`.\r\n * @note Without `subscriber`, the callback is called once immediately, with no arguments, and is not stored when:\r\n * the key is unknown or not registered (including on the server), or the key is `LOAD` and the current `LOAD` phase has already started.\r\n * @param pass A ticket or an array of tickets.\r\n * @param subscriber Optional listener target (`window`, `document`, an `Element`, …).\r\n * @example\r\n * ```ts\r\n * const onResize = (): void => console.log(Up.App.w, Up.App.h)\r\n * const onClick = (e: MouseEvent): void => console.log(e.clientX)\r\n *\r\n * Up.Event.sub([['LOAD', () => console.log('Page ready')], ['resize', onResize]])\r\n * Up.Event.sub(['click', onClick, Up.Event.PASSIVE], document.body)\r\n * ```\r\n */\r\n static sub<T extends undefined | Event.SUBSCRIBER = undefined>(pass: Event.Pass<T>, subscriber?: T): void\r\n {\r\n Event.#update(pass, (\r\n subscriber\r\n ? subscriber.addEventListener.bind(subscriber)\r\n : Event.#add as any\r\n )\r\n )\r\n }\r\n\r\n /**\r\n * Unsubscribes one or several tickets previously passed to {@link Event.sub}.\r\n * Callbacks are matched by reference, so pass the same function (and the same `subscriber`) used to subscribe.\r\n * @param pass A ticket or an array of tickets.\r\n * @param subscriber The listener target used when subscribing, if any.\r\n * @example\r\n * ```ts\r\n * Up.Event.unsub(['resize', onResize])\r\n * Up.Event.unsub(['click', onClick], document.body)\r\n * ```\r\n */\r\n static unsub<T extends undefined | Event.SUBSCRIBER = undefined>(pass: Event.Pass<T>, subscriber?: T): void\r\n {\r\n Event.#update(pass, (\r\n subscriber\r\n ? subscriber.removeEventListener.bind(subscriber)\r\n : Event.#remove as any\r\n )\r\n )\r\n }\r\n\r\n // ##GENERATORS\r\n /**\r\n * Calls each subscriber of `callstack` with `args`, from last to first, yielding after each call.\r\n */\r\n static *#caller(callstack: Event.CALLBACK[], ...args: any[]): Thread.GENERATOR\r\n {\r\n // ?The call starts at the end because the stack can be modified.\r\n for (let i = callstack.length - 1; i > -1; i--)\r\n {\r\n callstack[i](...args)\r\n\r\n yield\r\n }\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Event\r\n\r\nexport type {\r\n Event,\r\n EventData\r\n}"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/%5B1%5D/Event.ts"],"sourcesContent":["/* [Event] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SYMBOLS\r\nimport { INHERITANCE, construct, set, destroy, start, stop } from '../../symbols/index.js'\r\n\r\n // ##SCRIPTS\r\nimport Parser from '../../scripts/Parser.js'\r\nimport Wait from '../../scripts/Wait.js'\r\n\r\n // ##THIS\r\nimport Thread from './[2]/Thread.js'\r\n\r\n // ##TYPES\r\nimport type Adapter from '../../adapters/@/Adapter.js'\r\n\r\nimport type App from './[2]/[3]/App.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Event\r\n{\r\n /**\r\n * Event module configuration, declared in `up.event` of the Vite initializer and applied by `Up[construct]`.\r\n */\r\n export type CONFIG =\r\n {\r\n /**\r\n * Extra events to register alongside the built-ins, so they can be used with {@link Event.sub}.\r\n * A string registers a DOM event on `window`, with no wait and the default Thread flag ({@link Event.THREAD_FLAG}).\r\n * An object allows customization:\r\n * - `key`: real DOM event name (e.g. `\"click\"`, `\"mousemove\"`).\r\n * - `on`: `\"window\"` (default), `\"document\"` or `\"independent\"` (no DOM listener).\r\n * - `forever`: run subscribers every frame as a Thread forever task.\r\n * - `waitType` + `waitDelay`: debounce or throttle the event by `waitDelay` ms.\r\n * - `threadFlag`: Thread priority flag; `0` runs subscribers inline instead of through the Thread (not allowed with `forever`).\r\n * - `argsTypes`: TypeScript tuple, as a string, typing subscriber arguments in the generated declarations (e.g. `\"[e: MouseEvent]\"`).\r\n * @note DOM listeners are always registered as passive.\r\n */\r\n enhance?: (CUSTOM_KEY |\r\n {\r\n forever : true,\r\n key : CUSTOM_KEY,\r\n on ?: ON,\r\n waitType ?: never, // *Wait.frame or forever task\r\n threadFlag?: Thread.FLAG,\r\n argsTypes ?: `[${string}]`\r\n } |\r\n {\r\n forever ?: false,\r\n key : CUSTOM_KEY,\r\n on ?: ON,\r\n waitType ?: never, // *Wait.frame or forever task\r\n threadFlag?: 0 | Thread.FLAG,\r\n argsTypes ?: `[${string}]`\r\n } |\r\n {\r\n forever ?: false,\r\n key : CUSTOM_KEY,\r\n on ?: ON,\r\n waitType : 'debounce' | 'throttle',\r\n waitDelay : number,\r\n threadFlag?: 0 | Thread.FLAG,\r\n argsTypes ?: `[${string}]`\r\n }\r\n )[],\r\n /**\r\n * Options for the static-file wait (images, media, …) performed before each `LOAD` event.\r\n * Shallow-merged onto the defaults, where `eagerOnly`, `viewportOnly` and `emptySizeOnly` are `true`.\r\n * `limiter` cannot be set: it is set at runtime to `Adapter.root` (falls back to `document.body` when `null`).\r\n * @see {@link Wait.STATIC_FILES_CONFIG}\r\n */\r\n staticFilesConfig?: Omit<Wait.STATIC_FILES_CONFIG, 'limiter'>\r\n }\r\n\r\n /**\r\n * Status bit (`1`): the `DEATH` phase has started (the app is about to navigate away from the current page).\r\n * Setting it clears all other status bits.\r\n */\r\n export type PRE_DEATH = 1\r\n\r\n /**\r\n * Status bit (`2`): all `DEATH` subscribers have run.\r\n */\r\n export type AFTER_DEATH = 2\r\n\r\n /**\r\n * Status bit (`4`): the `LIFE` phase has started (navigation to a new page has completed).\r\n * Setting it clears all other status bits.\r\n */\r\n export type PRE_LIFE = 4\r\n\r\n /**\r\n * Status bit (`8`): all `LIFE` subscribers have run.\r\n */\r\n export type AFTER_LIFE = 8\r\n\r\n /**\r\n * Status bit (`16`): the `LOAD` phase has started (static files and `App.wait` have resolved).\r\n */\r\n export type PRE_LOAD = 16\r\n\r\n /**\r\n * Status bit (`32`): all `LOAD` subscribers have run.\r\n */\r\n export type AFTER_LOAD = 32\r\n\r\n /**\r\n * Default listener target for enhanced events (`\"window\"`).\r\n */\r\n export type DEFAULT_ON = 'window'\r\n\r\n /**\r\n * Where an event listener is attached: `\"window\"`, `\"document\"`, or `\"independent\"` (no DOM listener, triggered by the runtime itself).\r\n */\r\n export type ON = DEFAULT_ON | 'document' | 'independent'\r\n\r\n /**\r\n * Name of an event known to the Event manager: a built-in key ({@link EventData}) or an enhanced one from {@link Event.CONFIG.enhance}.\r\n */\r\n export type KEY = keyof EventData\r\n\r\n /**\r\n * DOM event name (or any string) used by enhanced events and custom subscribers.\r\n */\r\n export type CUSTOM_KEY = keyof GlobalEventHandlersEventMap | string & {}\r\n\r\n /**\r\n * Handler passed to {@link Event.sub} / {@link Event.unsub}.\r\n */\r\n export type CALLBACK = (...args: any) => any\r\n\r\n /**\r\n * Options for {@link Event.sub} when targeting the Event manager (no DOM `subscriber`).\r\n * Pass `{ once: true }` so the handler runs **one time** for that key, then unsubscribes itself.\r\n */\r\n export type OPTIONS = { once?: boolean }\r\n\r\n /**\r\n * @internal Stored subscriber entry (`original` = user handler; `callback` may wrap it when `once` is set).\r\n */\r\n export type WRAPPER =\r\n {\r\n original: CALLBACK,\r\n callback: CALLBACK\r\n }\r\n\r\n /**\r\n * Function that returns a generator calling every subscriber of an event with the given arguments, one per `next()`.\r\n * Built-in runners that need custom argument handling (`TICK`, `DEATH`, `visibilitychange`) receive it as first parameter.\r\n */\r\n export type CALLER = (...args: any) => Thread.GENERATOR\r\n\r\n /**\r\n * Ticket for the Event manager: `[key, handler]` or `[key, handler, { once?: boolean }]`.\r\n * Handler argument types follow the event key.\r\n */\r\n export type TICKET = Ticket<KEY>\r\n\r\n /**\r\n * Ticket for a DOM (or DOM-like) target: `[key, handler, options?]` where `options` is\r\n * {@link https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener#options | AddEventListenerOptions}\r\n * (native `once`, `passive`, …) — not {@link Event.OPTIONS}.\r\n */\r\n export type TICKET_CUSTOM = [key: CUSTOM_KEY, callback: (e: any) => any, options?: AddEventListenerOptions]\r\n\r\n /**\r\n * Any object exposing `addEventListener` / `removeEventListener` (`window`, `document`, an `Element`, …).\r\n */\r\n export type SUBSCRIBER =\r\n {\r\n addEventListener : (key: string, callback: CALLBACK, ...args: any) => any,\r\n removeEventListener: (key: string, callback: CALLBACK, ...args: any) => any\r\n }\r\n\r\n /**\r\n * Runtime descriptor of any registered event (built-in or enhanced).\r\n */\r\n export type DATA = Data<ON, boolean, number, 0 | Thread.FLAG | null, (keyof typeof Event & symbol) | Thread.TASK | null>\r\n\r\n /**\r\n * Typed descriptor of one event entry: listener target, scheduling mode, wait state, Thread flag and runner.\r\n * A \"crushed\" event calls its subscribers directly with the runner's arguments; a non-crushed one goes through\r\n * a built-in runner that receives a {@link Event.CALLER} and decides how subscribers are called.\r\n * @template T Listener target ({@link Event.ON}).\r\n * @template U `true` for a forever event (runs every frame).\r\n * @template V Wait state: `0` (none), `> 0` (debounce delay in ms) or `< 0` (throttle delay in ms). Always `0` for forever events.\r\n * @template W Thread flag: `null` / `undefined` (default {@link Thread.EVENT_FLAG}), `0` (run inline, not allowed for forever events) or a {@link Thread.FLAG}.\r\n * @template X Runner: a symbol-keyed method of `Event`, a task signature, or `null` (generic callback).\r\n */\r\n export type Data<\r\n T extends ON = DEFAULT_ON,\r\n U extends boolean = false,\r\n V extends U extends true ? 0 : number = 0,\r\n W extends U extends true ? Thread.FLAG | null | undefined : 0 | Thread.FLAG | null | undefined = null,\r\n X extends (keyof typeof Event & symbol) | Thread.TASK | null | undefined = null\r\n >\r\n = X extends symbol\r\n ? X extends keyof typeof Event\r\n ? (typeof Event)[X] extends Thread.TASK\r\n ? _Data<T, U, V, W, (typeof Event)[X], X>\r\n : never\r\n : never\r\n : X extends Thread.TASK\r\n ? _Data<T, U, V, W, X, null>\r\n : _Data<T, U, V, W, (...args: any) => void, null>\r\n\r\n type _Data<\r\n T extends ON,\r\n U extends boolean,\r\n V extends number,\r\n W extends 0 | Thread.FLAG | null | undefined,\r\n X extends Thread.TASK,\r\n Y extends symbol | null\r\n >\r\n = boolean extends U\r\n ? __Data<T, true, 0, W, X, Y> | __Data<T, false, V, W, X, Y>\r\n : __Data<T, U, V, W, X, Y>\r\n\r\n type __Data<\r\n T extends ON,\r\n U extends true | false,\r\n V extends number,\r\n W extends 0 | Thread.FLAG | null | undefined,\r\n X extends Thread.TASK,\r\n Y extends symbol | null\r\n >\r\n = Y extends symbol\r\n ? U extends true\r\n ? {\r\n method : Y,\r\n forever : true,\r\n crushed : IsCrushed<X>,\r\n on : T,\r\n threadFlag: W extends 0 | null | undefined ? Thread.EVENT_FLAG : W,\r\n callback : X\r\n }\r\n : {\r\n method : Y,\r\n forever : false,\r\n crushed : IsCrushed<X>,\r\n on : T,\r\n waitState : V,\r\n threadFlag: W extends null | undefined ? Thread.EVENT_FLAG : W,\r\n callback : X\r\n }\r\n : U extends true\r\n ? {\r\n forever : true,\r\n crushed : true,\r\n on : T,\r\n threadFlag: W extends 0 | null | undefined ? Thread.EVENT_FLAG : W,\r\n callback : X\r\n }\r\n : {\r\n forever : false,\r\n crushed : true,\r\n on : T,\r\n waitState : V,\r\n threadFlag: W extends null | undefined ? Thread.EVENT_FLAG : W,\r\n callback : X\r\n }\r\n\r\n /**\r\n * Builds an Event-manager ticket for key `T`: `[key, handler, options?]`.\r\n * @template T Event key (distributed over unions).\r\n */\r\n export type Ticket<T extends KEY> = T extends T ? [T, (...args: Args<EventData[T]['callback']>) => any, options?: OPTIONS] : never\r\n\r\n /**\r\n * What you pass to {@link Event.sub} / {@link Event.unsub}: one ticket or an array of tickets.\r\n * Without a DOM `subscriber` → {@link Event.TICKET}; with one → {@link Event.TICKET_CUSTOM}.\r\n * @template T Subscriber type, or `undefined` for the Event manager.\r\n */\r\n export type Pass<T extends SUBSCRIBER | undefined> = T extends SUBSCRIBER ? TICKET_CUSTOM | TICKET_CUSTOM[] : TICKET | TICKET[]\r\n\r\n /**\r\n * Whether an event runner is \"crushed\": `false` when its first parameter is a {@link Event.CALLER}\r\n * (subscribers are driven by that runner); `true` otherwise (subscribers receive the runner's arguments directly).\r\n * @template T Runner task signature to inspect.\r\n */\r\n export type IsCrushed<T extends Thread.TASK> = T extends (caller: infer U, ...args: any) => any\r\n ? U extends Event.CALLER\r\n ? false\r\n : true\r\n : true\r\n\r\n /**\r\n * Arguments passed to subscribers for a given runner: strips a leading {@link Event.CALLER} when present,\r\n * otherwise keeps the full parameter list (all made `Required`).\r\n * Used by {@link Event.Ticket} to type ticket callbacks.\r\n * @template T Runner task signature to inspect.\r\n */\r\n export type Args<T extends Thread.TASK> = T extends (...args: infer U) => any\r\n ? U extends [Event.CALLER, ...infer V]\r\n ? Required<V>\r\n : Required<U>\r\n : []\r\n}\r\n\r\n/**\r\n * Registry of built-in events. Its keys are the event names accepted by `Event.sub` / `Event.unsub`.\r\n * Unless stated otherwise, subscribers run inside the Thread (see {@link Thread}) with the listed flag, possibly spread over several frames.\r\n*/\r\ninterface EventData\r\n{\r\n /**\r\n * Runs every frame as a Thread forever task (flag `128`). Subscribers receive the current `Thread.timestamp` (ms).\r\n */\r\n TICK: Event.Data<'independent', true, 0, Thread.EVENT_FLAG, typeof eTick>,\r\n /**\r\n * Fired after each successful navigation (`Up.Adapter` `AFTER_NAVIGATE`, flag `128`).\r\n * Use it to bring the new page to life (enter animations, bind UI, …).\r\n * Subscribers receive a promise that resolves once every `LIFE` subscriber has run.\r\n */\r\n LIFE: Event.Data<'independent', false, 0, Thread.EVENT_FLAG, typeof eLife>,\r\n /**\r\n * Fired when a client-side navigation is committed (`Up.Adapter` `ON_NAVIGATE`), before the old page is torn down.\r\n * Use it to leave the current page (exit animations, unbind, dispose). Runs synchronously (not through the Thread).\r\n * Not fired for cancelled navigations that never reach `ON_NAVIGATE`. If a committed navigation later fails,\r\n * listen to `Up.Adapter` `ABORTED` to restore state — `LIFE` will not run for that attempt.\r\n */\r\n DEATH: Event.Data<'independent', false, 0, 0, typeof eDeath>,\r\n /**\r\n * Fired after `LIFE` once the framework has updated, static files are ready ({@link Event.CONFIG.staticFilesConfig})\r\n * and `App.wait` has resolved (flag `128`). Subscribers receive a promise that resolves once every `LOAD` subscriber has run.\r\n */\r\n LOAD: Event.Data<'independent', false, 0, Thread.EVENT_FLAG, typeof eLoad>,\r\n /**\r\n * Size changes of the app root (`Adapter.root`, or `document.body`) observed with a `ResizeObserver` on the content box,\r\n * debounced by 50 ms (flag `2`). Subscribers receive the `ResizeObserverEntry[]`.\r\n */\r\n EARTHQUAKE: Event.Data<'independent', false, 50, Thread.EARTHQUAKE_FLAG, typeof eEarthquake>,\r\n /**\r\n * Native `document` `\"visibilitychange\"` event. Pauses the Thread when the page is hidden and resumes it when visible,\r\n * then calls subscribers synchronously with `document.hidden`.\r\n */\r\n visibilitychange: Event.Data<'document', false, 0, 0, typeof eVisibilitychange>,\r\n /**\r\n * Native `window` `\"resize\"` event, debounced by 50 ms (flag `8`). Subscribers receive the DOM event.\r\n */\r\n resize: Event.Data<'window', false, 50, Thread.RESIZE_FLAG, typeof eResize>,\r\n /**\r\n * Native `window` `\"scroll\"` event (flag `32`). Subscribers receive the DOM event.\r\n */\r\n scroll: Event.Data<'window', false, 0, Thread.SCROLL_FLAG, typeof eScroll>\r\n}\r\n\r\n// #CONSTANTS\r\n\r\n // ##SYMBOLS\r\nconst\r\neTick = Symbol('eTick'),\r\neLife = Symbol('eLife'),\r\neDeath = Symbol('eDeath'),\r\neLoad = Symbol('eLoad'),\r\neEarthquake = Symbol('eEarthquake'),\r\neVisibilitychange = Symbol('eVisibilitychange'),\r\neResize = Symbol('eResize'),\r\neScroll = Symbol('eScroll')\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Event manager of the runtime. It dispatches page lifecycle events and a small set of DOM events to subscribers,\r\n * scheduling them through the {@link Thread} with debounce / throttle when configured.\r\n *\r\n * Page lifecycle (driven by `Up.Adapter` navigation phases), in order on a successful change:\r\n * `DEATH` (leave current page, on `ON_NAVIGATE`) → `LIFE` (enter new page, on `AFTER_NAVIGATE`) →\r\n * `LOAD` (after framework tick, static readiness and `App.wait`).\r\n *\r\n * Subscribe with `Up.Event.sub([['DEATH', handler], ['LIFE', handler], …])`.\r\n * Optional third ticket field `{ once: true }` runs a handler once then unsubscribes it.\r\n * See {@link EventData} for built-in keys and {@link Event.CONFIG} to register more.\r\n * @note Client-only: on the server no event is registered.\r\n*/\r\nabstract class Event\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n static #PRE_DEATH : Event.PRE_DEATH = 1\r\n static #AFTER_DEATH: Event.AFTER_DEATH = 2\r\n static #PRE_LIFE : Event.PRE_LIFE = 4\r\n static #AFTER_LIFE : Event.AFTER_LIFE = 8\r\n static #PRE_LOAD : Event.PRE_LOAD = 16\r\n static #AFTER_LOAD : Event.AFTER_LOAD = 32\r\n\r\n static #THREAD_FLAG: Thread.EVENT_FLAG = 128\r\n\r\n static #ADAPTER_TICKETS: Adapter.TICKET[] =\r\n [\r\n ['ON_NAVIGATE' , Event.#eOnNavigate],\r\n ['AFTER_NAVIGATE', Event.#eAfterNavigate]\r\n ]\r\n\r\n static #PASSIVE = { passive: true } as const\r\n static #IMPASSIVE = { passive: false } as const\r\n\r\n static #STATIC_FILES_CONFIG: Wait.STATIC_FILES_CONFIG =\r\n {\r\n eagerOnly : true,\r\n viewportOnly : true,\r\n emptySizeOnly: true\r\n }\r\n\r\n static #DATA = new Map<Event.KEY, EventData[Event.KEY]>(\r\n [\r\n [\r\n 'TICK',\r\n {\r\n method : eTick,\r\n forever : true,\r\n crushed : false,\r\n on : 'independent',\r\n threadFlag: Event.#THREAD_FLAG,\r\n callback : Event[eTick]\r\n }\r\n ],\r\n [\r\n 'LIFE',\r\n {\r\n method : eLife,\r\n forever : false,\r\n crushed : true,\r\n on : 'independent',\r\n waitState : 0,\r\n threadFlag: Event.#THREAD_FLAG,\r\n callback : Event[eLife]\r\n }\r\n ],\r\n [\r\n 'DEATH',\r\n {\r\n method : eDeath,\r\n forever : false,\r\n crushed : false,\r\n on : 'independent',\r\n waitState : 0,\r\n threadFlag: 0,\r\n callback : Event[eDeath]\r\n }\r\n ],\r\n [\r\n 'LOAD',\r\n {\r\n method : eLoad,\r\n forever : false,\r\n crushed : true,\r\n on : 'independent',\r\n waitState : 0,\r\n threadFlag: Event.#THREAD_FLAG,\r\n callback : Event[eLoad]\r\n }\r\n ],\r\n [\r\n 'EARTHQUAKE',\r\n {\r\n method : eEarthquake,\r\n forever : false,\r\n crushed : true,\r\n on : 'independent',\r\n waitState : 50,\r\n threadFlag: 2,\r\n callback : Event[eEarthquake]\r\n }\r\n ],\r\n [\r\n 'visibilitychange',\r\n {\r\n method : eVisibilitychange,\r\n forever : false,\r\n crushed : false,\r\n on : 'document',\r\n waitState : 0,\r\n threadFlag: 0,\r\n callback : Event[eVisibilitychange]\r\n }\r\n ],\r\n [\r\n 'resize',\r\n {\r\n method : eResize,\r\n forever : false,\r\n crushed : true,\r\n on : 'window',\r\n waitState : 50,\r\n threadFlag: 8,\r\n callback : Event[eResize]\r\n }\r\n ],\r\n [\r\n 'scroll',\r\n {\r\n method : eScroll,\r\n forever : false,\r\n crushed : true,\r\n on : 'window',\r\n waitState : 0,\r\n threadFlag: 32,\r\n callback : Event[eScroll]\r\n }\r\n ]\r\n ])\r\n static #THREAD_TICKETS = new Map<Event.KEY, [task: Thread.TASK, flag: Thread.FLAG][]>()\r\n static #MANAGER = new Map<Event.KEY, Event.WRAPPER[]>()\r\n\r\n /**\r\n * Shared HRT stack after hydrating `Thread` (`[Adapter, App, Thread]`); `Up` later appends `Event`.\r\n * Same array as `Thread[INHERITANCE]` — does not include `Event` itself.\r\n * @internal\r\n */\r\n static [INHERITANCE] = Thread.App.HRT.hydrate<(typeof Thread)[typeof INHERITANCE], [typeof Thread]>(Thread)\r\n\r\n static #status = 0\r\n static #lifeIn = -1\r\n static #deathIn = -1\r\n\r\n static #resizeObserver: ResizeObserver | null = null\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n /**\r\n * Active framework adapter (same as {@link Up.Adapter}).\r\n * @returns The adapter class.\r\n */\r\n static get Adapter(): typeof Adapter { return Thread[INHERITANCE][0] }\r\n /**\r\n * Application runtime (same as {@link Up.App}).\r\n * @returns The {@link App} class.\r\n */\r\n static get App(): typeof App { return Thread[INHERITANCE][1] }\r\n /**\r\n * Frame scheduler (same as {@link Up.Thread}).\r\n * @returns The {@link Thread} class.\r\n */\r\n static get Thread(): typeof Thread { return Thread }\r\n\r\n /**\r\n * Status bit set when the `DEATH` phase starts ({@link Event.PRE_DEATH}).\r\n * @returns `1`.\r\n */\r\n static get PRE_DEATH(): Event.PRE_DEATH { return Event.#PRE_DEATH }\r\n /**\r\n * Status bit set once all `DEATH` subscribers have run ({@link Event.AFTER_DEATH}).\r\n * @returns `2`.\r\n */\r\n static get AFTER_DEATH(): Event.AFTER_DEATH { return Event.#AFTER_DEATH }\r\n /**\r\n * Status bit set when the `LIFE` phase starts ({@link Event.PRE_LIFE}).\r\n * @returns `4`.\r\n */\r\n static get PRE_LIFE(): Event.PRE_LIFE { return Event.#PRE_LIFE }\r\n /**\r\n * Status bit set once all `LIFE` subscribers have run ({@link Event.AFTER_LIFE}).\r\n * @returns `8`.\r\n */\r\n static get AFTER_LIFE(): Event.AFTER_LIFE { return Event.#AFTER_LIFE }\r\n /**\r\n * Status bit set when the `LOAD` phase starts ({@link Event.PRE_LOAD}).\r\n * @returns `16`.\r\n */\r\n static get PRE_LOAD(): Event.PRE_LOAD { return Event.#PRE_LOAD }\r\n /**\r\n * Status bit set once all `LOAD` subscribers have run ({@link Event.AFTER_LOAD}).\r\n * @returns `32`.\r\n */\r\n static get AFTER_LOAD(): Event.AFTER_LOAD { return Event.#AFTER_LOAD }\r\n\r\n /**\r\n * Default Thread flag of event tasks (`TICK`, `LIFE`, `LOAD` and enhanced events without `threadFlag`).\r\n * @returns `128` ({@link Thread.EVENT_FLAG}).\r\n */\r\n static get THREAD_FLAG(): Thread.EVENT_FLAG { return Event.#THREAD_FLAG }\r\n\r\n /**\r\n * Shared listener options for passive DOM listeners.\r\n * @returns `{ passive: true }`.\r\n */\r\n static get PASSIVE(): { passive: true } { return Event.#PASSIVE }\r\n /**\r\n * Shared listener options for DOM listeners that need to call `preventDefault`.\r\n * @returns `{ passive: false }`.\r\n */\r\n static get IMPASSIVE(): { passive: false } { return Event.#IMPASSIVE }\r\n\r\n /**\r\n * Current lifecycle status, a bitmask of the `PRE_*` / `AFTER_*` bits. `0` until the first navigation hook runs.\r\n * @returns The status bitmask.\r\n * @example\r\n * ```ts\r\n * if (Up.Event.status & Up.Event.AFTER_LOAD) console.log('Page fully loaded')\r\n * ```\r\n */\r\n static get status(): number { return Event.#status }\r\n /**\r\n * Time (`performance.now()`, ms) at which the current `LIFE` phase started.\r\n * @returns The timestamp, or `-1` before the first `LIFE`.\r\n */\r\n static get lifeIn(): number { return Event.#lifeIn }\r\n /**\r\n * Time (`performance.now()`, ms) at which the latest `DEATH` phase started.\r\n * @returns The timestamp, or `-1` before the first `DEATH`.\r\n */\r\n static get deathIn(): number { return Event.#deathIn }\r\n\r\n// #METHODS\r\n\r\n // ##CONSTRUCT\r\n /**\r\n * Adds enhanced event descriptors from {@link Event.CONFIG.enhance} to the registry.\r\n */\r\n static #constructData(enhance: NonNullable<Event.CONFIG['enhance']>): void\r\n {\r\n for (let i = 0, max = enhance.length; i < max; i++)\r\n {\r\n const DATA = enhance[i]\r\n\r\n if (typeof DATA === 'string') (Event.#DATA as Map<string, Event.DATA>).set(DATA,\r\n {\r\n forever : false,\r\n crushed : true,\r\n on : 'window',\r\n waitState : 0,\r\n threadFlag: Event.#THREAD_FLAG,\r\n callback : Event.App.void\r\n })\r\n else (Event.#DATA as Map<string, Event.DATA>).set(DATA.key,\r\n {\r\n crushed : true,\r\n on : DATA.on ?? 'window',\r\n callback: Event.App.void,\r\n ...(DATA.forever\r\n ? {\r\n forever : true,\r\n threadFlag: DATA.threadFlag || Event.#THREAD_FLAG\r\n }\r\n : {\r\n forever : false,\r\n waitState: 'waitDelay' in DATA && DATA.waitDelay > 0\r\n ? DATA.waitType === 'debounce'\r\n ? DATA.waitDelay\r\n : DATA.waitType === 'throttle'\r\n ? -DATA.waitDelay\r\n : 0\r\n : 0,\r\n threadFlag: DATA.threadFlag ?? Event.#THREAD_FLAG,\r\n }\r\n )\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Builds the event registry and subscriber callstacks, wraps each runner with its Thread flag and debounce / throttle,\r\n * and starts the `TICK` forever task. Merges `staticFilesConfig` onto the defaults when provided.\r\n * Does nothing outside the browser.\r\n * @internal\r\n * @param config Optional {@link Event.CONFIG}.\r\n */\r\n static [construct](config?: Event.CONFIG): void\r\n {\r\n if (!Event.Adapter.BROWSER) return\r\n\r\n if (config)\r\n {\r\n if (config.staticFilesConfig) Parser.copy(Event.#STATIC_FILES_CONFIG, config.staticFilesConfig)\r\n\r\n if (config.enhance) Event.#constructData(config.enhance)\r\n }\r\n \r\n for (const [KEY, DATA] of Event.#DATA as Map<Event.KEY, Event.DATA>)\r\n {\r\n const\r\n WRAPPERS: Event.WRAPPER[] = [],\r\n caller = Event.#caller.bind(null, WRAPPERS),\r\n callback = DATA.crushed\r\n ? caller\r\n : (DATA.callback as (caller: Event.CALLER, ...args: any) => void | Thread.GENERATOR).bind(null, caller)\r\n\r\n Event.#MANAGER.set(KEY, WRAPPERS)\r\n\r\n if (DATA.forever)\r\n {\r\n Event.Thread.markForever(callback)\r\n Event.#getThreadSubscription(KEY, callback, DATA.threadFlag)() // *Let's call him directly\r\n\r\n DATA.callback = callback\r\n }\r\n else if (DATA.threadFlag)\r\n {\r\n DATA.callback = Event.#getThreadSubscription(KEY, callback, DATA.threadFlag)\r\n\r\n if (DATA.waitState)\r\n {\r\n // *It is essential to return the generator to the thread in order to take advantage of its benefits and, most importantly, to be able to execute the generators.\r\n // *The \"waiters\" take us out of the thread, and we can't put them ahead of the task because we have modifiers that are waiting for real-time updates.\r\n // *To solve the problem, we break it down into two separate tasks.\r\n \r\n DATA.callback = Event.#getThreadSubscription(KEY, Event.#getWaiter(DATA.callback, DATA.waitState), DATA.threadFlag)\r\n }\r\n }\r\n else DATA.callback = DATA.waitState ? Event.#getWaiter(callback, DATA.waitState) : callback // *Do not use \"Wait.frame\"\r\n\r\n if ('method' in DATA && DATA.method) Event[DATA.method] = DATA.callback as any\r\n }\r\n }\r\n\r\n // ##SET\r\n /**\r\n * Sets the static-file root and creates the `ResizeObserver`.\r\n */\r\n static #setVars(): void\r\n {\r\n Event.#STATIC_FILES_CONFIG.limiter = Event.Adapter.root\r\n\r\n Event.#resizeObserver = new ResizeObserver(Event.#oResize)\r\n }\r\n\r\n /**\r\n * Subscribes to adapter navigation hooks and attaches DOM listeners.\r\n */\r\n static #setEvents(): void\r\n {\r\n Event.Adapter.sub(Event.#ADAPTER_TICKETS)\r\n\r\n for (const [KEY, DATA] of Event.#DATA)\r\n if (DATA.on !== 'independent') (DATA.on === 'window' ? window : document).addEventListener(KEY, DATA.callback as () => void, Event.#PASSIVE)\r\n }\r\n\r\n /**\r\n * Observes the app root (or `document.body`) for `EARTHQUAKE`.\r\n */\r\n static #setObservers(): void { Event.#resizeObserver!.observe(Event.Adapter.root ?? document.body, { box: 'content-box' }) }\r\n\r\n /**\r\n * Attaches navigation hooks, DOM listeners and the `ResizeObserver`. Called from `Up.set` in the browser.\r\n * @internal\r\n */\r\n static [set](): void\r\n {\r\n Event.#setVars()\r\n Event.#setEvents()\r\n Event.#setObservers()\r\n }\r\n\r\n // ##GET\r\n /**\r\n * Records `task` for teardown and returns a function scheduling it on the Thread with `flag`.\r\n */\r\n static #getThreadSubscription(key: keyof EventData, task: Thread.TASK, flag: Thread.FLAG): (...args: any) => void\r\n {\r\n const TICKETS = Event.#THREAD_TICKETS.get(key)\r\n\r\n TICKETS\r\n ? TICKETS.push([task, flag])\r\n : Event.#THREAD_TICKETS.set(key, [[task, flag]])\r\n\r\n return Event.Thread.sub.bind(null, task, flag)\r\n }\r\n\r\n /**\r\n * Wraps `task` with a trailing debounce (`waitState > 0`) or a trailing throttle (`waitState < 0`).\r\n */\r\n static #getWaiter(task: Thread.TASK, waitState: number): Thread.TASK\r\n {\r\n return waitState > 0\r\n ? Wait.debounce(task, waitState, false)\r\n : Wait.throttle(task, waitState * -1, true, false)\r\n }\r\n\r\n static #getIndex(wrappers: Event.WRAPPER[], callback: Event.CALLBACK): number\r\n {\r\n for (let i = 0, max = wrappers.length; i < max; i++) if (wrappers[i].original === callback) return i\r\n\r\n return -1\r\n }\r\n\r\n // ##ADD\r\n /**\r\n * Adds `callback` to the callstack of `key` (no duplicates), or calls it immediately (see {@link Event.sub}).\r\n */\r\n static #add(key: Event.KEY, callback: Event.CALLBACK, options?: Event.OPTIONS): void\r\n {\r\n const WRAPPERS = Event.#MANAGER.get(key)\r\n\r\n if (!WRAPPERS || key === 'LOAD' && Event.#status & Event.#PRE_LOAD)\r\n {\r\n callback()\r\n\r\n return\r\n }\r\n else if (~Event.#getIndex(WRAPPERS, callback)) return\r\n\r\n let original = callback\r\n\r\n if (options?.once) callback = (...args: any): any =>\r\n {\r\n Event.#remove(key, original)\r\n\r\n return original(...args)\r\n }\r\n\r\n WRAPPERS.push({original, callback})\r\n }\r\n\r\n // ##REMOVE\r\n /**\r\n * Removes `callback` from the callstack of `key`.\r\n */\r\n static #remove(key: Event.KEY, callback: Event.CALLBACK): void\r\n {\r\n Wait.cancel(callback)\r\n \r\n const WRAPPERS = Event.#MANAGER.get(key)\r\n\r\n if (!WRAPPERS) return\r\n \r\n const INDEX = Event.#getIndex(WRAPPERS, callback)\r\n\r\n if (~INDEX) WRAPPERS.splice(INDEX, 1)\r\n }\r\n\r\n // ##UPDATES\r\n /**\r\n * Applies `action` to one ticket or to each ticket of an array.\r\n */\r\n static #update(pass: Event.Pass<Event.SUBSCRIBER | undefined>, action: (...ticket: Event.TICKET | Event.TICKET_CUSTOM) => void): void\r\n {\r\n if (typeof pass[0] === 'string') return action(...pass)\r\n\r\n for (let i = 0, max = pass.length; i < max; i++) action(...pass[i])\r\n }\r\n\r\n // ##DESTROY\r\n /**\r\n * Clears callstacks and disconnects the `ResizeObserver`.\r\n */\r\n static #destroyVars(): void\r\n {\r\n if (Event.#MANAGER.size) Event.#MANAGER.clear()\r\n \r\n if (Event.#resizeObserver)\r\n {\r\n Event.#resizeObserver.disconnect()\r\n\r\n Event.#resizeObserver = null\r\n }\r\n }\r\n\r\n /**\r\n * Unsubscribes and cancels every Thread task created for events.\r\n */\r\n static #destroyTasks(): void\r\n {\r\n for (const [_, TICKETS] of Event.#THREAD_TICKETS) for (let i = 0, max = TICKETS.length; i < max; i++)\r\n {\r\n const task = TICKETS[i][0]\r\n \r\n Event.Thread.unsub(task)\r\n Wait.cancel(task)\r\n }\r\n }\r\n\r\n /**\r\n * Detaches navigation hooks and DOM listeners and cancels pending waits.\r\n */\r\n static #destroyEvents(): void\r\n {\r\n Event.Adapter.unsub(Event.#ADAPTER_TICKETS)\r\n \r\n for (const [KEY, DATA] of Event.#DATA)\r\n {\r\n if (DATA.on !== 'independent') (DATA.on === 'window' ? window : document).removeEventListener(KEY, DATA.callback as () => void)\r\n\r\n Wait.cancel(DATA.callback)\r\n }\r\n }\r\n\r\n /**\r\n * Removes all subscribers, listeners, observers and event tasks. Called from `Up.destroy` in the browser.\r\n * @internal\r\n */\r\n static [destroy](): void\r\n {\r\n Event.#destroyVars()\r\n Event.#destroyTasks()\r\n Event.#destroyEvents()\r\n }\r\n\r\n // ##EVENTS\r\n /**\r\n * Adapter `ON_NAVIGATE` hook: runs the `DEATH` phase (leave current page once navigation is committed).\r\n */\r\n static #eOnNavigate(): void\r\n {\r\n Event.#status = Event.#PRE_DEATH\r\n Event.#deathIn = performance.now()\r\n\r\n ;(Event[eDeath] as any)()\r\n\r\n Event.#status |= Event.#AFTER_DEATH\r\n }\r\n\r\n /**\r\n * Adapter `AFTER_NAVIGATE` hook: runs the `LIFE` phase, waits for readiness, then runs the `LOAD` phase.\r\n */\r\n static async #eAfterNavigate(): Promise<void>\r\n {\r\n let res = Event.App.void\r\n \r\n Event.#status = Event.#PRE_LIFE\r\n Event.#lifeIn = performance.now()\r\n \r\n Event[eLife](new Promise((r): void => { res = r }))\r\n\r\n await Event.Thread.wait(Event.#THREAD_TICKETS.get('LIFE')![0][0])\r\n\r\n Event.#status |= Event.#AFTER_LIFE\r\n\r\n res()\r\n\r\n await Event.Adapter.tick() // *Wait for updates brought by the \"LIFE\" event\r\n await Wait.staticFiles(Event.#STATIC_FILES_CONFIG) // *Static readiness before LOAD (see CONFIG.staticFilesConfig / #STATIC_FILES_CONFIG)\r\n await Event.App.wait\r\n\r\n Event.#status |= Event.#PRE_LOAD\r\n\r\n Event[eLoad](new Promise((r): void => { res = r }))\r\n\r\n await Event.Thread.wait(Event.#THREAD_TICKETS.get('LOAD')![0][0])\r\n\r\n Event.#status |= Event.#AFTER_LOAD\r\n\r\n res()\r\n }\r\n\r\n /**\r\n * `TICK` runner: calls subscribers with the current frame timestamp.\r\n * @internal\r\n */\r\n static [eTick](caller: Event.CALLER, timestamp = Event.Thread.timestamp): Thread.GENERATOR { return caller(timestamp) }\r\n\r\n /**\r\n * `LIFE` trigger (signature placeholder, replaced by the scheduled runner in `[construct]`).\r\n * @internal\r\n */\r\n static [eLife](promise: Promise<void>): void {}\r\n\r\n /**\r\n * `DEATH` runner: calls every subscriber synchronously.\r\n * @internal\r\n */\r\n static [eDeath](caller: Event.CALLER): void\r\n {\r\n const GEN = caller()\r\n\r\n while (!GEN.next().done) {}\r\n }\r\n\r\n /**\r\n * `LOAD` trigger (signature placeholder, replaced by the scheduled runner in `[construct]`).\r\n * @internal\r\n */\r\n static [eLoad](promise: Promise<void>): void {}\r\n\r\n /**\r\n * `EARTHQUAKE` trigger (signature placeholder, replaced by the scheduled runner in `[construct]`).\r\n * @internal\r\n */\r\n static [eEarthquake](o: ResizeObserverEntry[]): void {}\r\n\r\n /**\r\n * `visibilitychange` runner: pauses or resumes the Thread, then calls every subscriber synchronously with `document.hidden`.\r\n * @internal\r\n */\r\n static [eVisibilitychange](caller: Event.CALLER): void\r\n {\r\n Event.Thread[document.hidden ? stop : start]()\r\n\r\n const GEN = caller(document.hidden)\r\n\r\n while (!GEN.next().done) {}\r\n }\r\n\r\n /**\r\n * `resize` trigger (signature placeholder, replaced by the DOM listener in `[construct]`).\r\n * @internal\r\n */\r\n static [eResize](e: Event): void {}\r\n\r\n /**\r\n * `scroll` trigger (signature placeholder, replaced by the DOM listener in `[construct]`).\r\n * @internal\r\n */\r\n static [eScroll](e: Event): void {}\r\n\r\n // ##OBSERVERS\r\n /**\r\n * `ResizeObserver` callback forwarding entries to `EARTHQUAKE`.\r\n */\r\n static #oResize(o: ResizeObserverEntry[]): void\r\n {\r\n // TODO: Earthquake ne devrait peut-être pas être un événements mais avoir un Plugin dédié permettant de fragmenter l'app en zone observable.\r\n // *Ici les earthquake se déclenchent aussi sur la largeur.\r\n Event[eEarthquake](o)\r\n }\r\n\r\n // ##UTILS\r\n /**\r\n * Subscribes one or several handlers.\r\n *\r\n * **Event manager** (no second argument) — pass {@link Event.TICKET} tuples:\r\n * - `['LIFE', onLife]`\r\n * - `['LOAD', onLoad, { once: true }]` — runs once for that key, then auto-unsubscribes\r\n *\r\n * Same handler twice on the same key is ignored. Handlers for a given key run in **reverse** subscription order.\r\n *\r\n * **DOM target** — pass a `subscriber` (`window`, `document`, an element, …) and {@link Event.TICKET_CUSTOM}\r\n * tuples; the third field is native `AddEventListenerOptions` (`passive`, DOM `once`, …).\r\n *\r\n * @note Without a `subscriber`, the handler is called **immediately** (no args) and **not stored** when:\r\n * the key is unknown / not registered (including on the server), or the key is `LOAD` and the current `LOAD`\r\n * phase has already started.\r\n * @param pass A ticket or an array of tickets.\r\n * @param subscriber Optional listener target for DOM (or DOM-like) events.\r\n * @example\r\n * ```ts\r\n * const onResize = (): void => console.log(Up.App.w, Up.App.h)\r\n * const onClick = (e: MouseEvent): void => console.log(e.clientX)\r\n *\r\n * Up.Event.sub([['LOAD', () => console.log('Page ready'), { once: true }], ['resize', onResize]])\r\n * Up.Event.sub(['click', onClick, Up.Event.PASSIVE], document.body)\r\n * ```\r\n */\r\n static sub<T extends undefined | Event.SUBSCRIBER = undefined>(pass: Event.Pass<T>, subscriber?: T): void\r\n {\r\n Event.#update(pass, (\r\n subscriber\r\n ? subscriber.addEventListener.bind(subscriber)\r\n : Event.#add as any\r\n )\r\n )\r\n }\r\n\r\n /**\r\n * Unsubscribes handlers previously passed to {@link Event.sub}.\r\n * Match by **function reference** (and the same `subscriber` if you used one).\r\n * For Event-manager tickets, pass the same handler you subscribed — including when it was registered with `{ once: true }`.\r\n * @param pass A ticket or an array of tickets.\r\n * @param subscriber The listener target used when subscribing, if any.\r\n * @example\r\n * ```ts\r\n * Up.Event.unsub(['resize', onResize])\r\n * Up.Event.unsub(['click', onClick], document.body)\r\n * ```\r\n */\r\n static unsub<T extends undefined | Event.SUBSCRIBER = undefined>(pass: Event.Pass<T>, subscriber?: T): void\r\n {\r\n Event.#update(pass, (\r\n subscriber\r\n ? subscriber.removeEventListener.bind(subscriber)\r\n : Event.#remove as any\r\n )\r\n )\r\n }\r\n\r\n // ##GENERATORS\r\n /**\r\n * Invokes each subscriber with `args`, from last to first, yielding after each call.\r\n * @internal\r\n */\r\n static *#caller(wrappers: Event.WRAPPER[], ...args: any[]): Thread.GENERATOR\r\n {\r\n // ?The call starts at the end because the stack can be modified.\r\n for (let i = wrappers.length - 1; i > -1; i--)\r\n {\r\n wrappers[i].callback(...args)\r\n\r\n yield\r\n }\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Event\r\n\r\nexport type {\r\n Event,\r\n EventData\r\n}"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -155,20 +155,37 @@ declare namespace Event {
155
155
  */
156
156
  export type CUSTOM_KEY = keyof GlobalEventHandlersEventMap | string & {};
157
157
  /**
158
- * Subscriber callback stored in an event callstack.
158
+ * Handler passed to {@link Event.sub} / {@link Event.unsub}.
159
159
  */
160
160
  export type CALLBACK = (...args: any) => any;
161
+ /**
162
+ * Options for {@link Event.sub} when targeting the Event manager (no DOM `subscriber`).
163
+ * Pass `{ once: true }` so the handler runs **one time** for that key, then unsubscribes itself.
164
+ */
165
+ export type OPTIONS = {
166
+ once?: boolean;
167
+ };
168
+ /**
169
+ * @internal Stored subscriber entry (`original` = user handler; `callback` may wrap it when `once` is set).
170
+ */
171
+ export type WRAPPER = {
172
+ original: CALLBACK;
173
+ callback: CALLBACK;
174
+ };
161
175
  /**
162
176
  * Function that returns a generator calling every subscriber of an event with the given arguments, one per `next()`.
163
177
  * Built-in runners that need custom argument handling (`TICK`, `DEATH`, `visibilitychange`) receive it as first parameter.
164
178
  */
165
179
  export type CALLER = (...args: any) => Thread.GENERATOR;
166
180
  /**
167
- * Subscription tuple `[key, callback]` for an event known to the Event manager; callback arguments are inferred from the key.
181
+ * Ticket for the Event manager: `[key, handler]` or `[key, handler, { once?: boolean }]`.
182
+ * Handler argument types follow the event key.
168
183
  */
169
184
  export type TICKET = Ticket<KEY>;
170
185
  /**
171
- * Subscription tuple `[key, callback, options?]` forwarded as is to `addEventListener` / `removeEventListener` on a custom subscriber.
186
+ * Ticket for a DOM (or DOM-like) target: `[key, handler, options?]` where `options` is
187
+ * {@link https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener#options | AddEventListenerOptions}
188
+ * (native `once`, `passive`, …) — not {@link Event.OPTIONS}.
172
189
  */
173
190
  export type TICKET_CUSTOM = [key: CUSTOM_KEY, callback: (e: any) => any, options?: AddEventListenerOptions];
174
191
  /**
@@ -224,13 +241,13 @@ declare namespace Event {
224
241
  callback: X;
225
242
  };
226
243
  /**
227
- * Tuple `[key, callback]` whose callback arguments are inferred from the event runner.
244
+ * Builds an Event-manager ticket for key `T`: `[key, handler, options?]`.
228
245
  * @template T Event key (distributed over unions).
229
246
  */
230
- export type Ticket<T extends KEY> = T extends T ? [T, (...args: Args<EventData[T]['callback']>) => any] : never;
247
+ export type Ticket<T extends KEY> = T extends T ? [T, (...args: Args<EventData[T]['callback']>) => any, options?: OPTIONS] : never;
231
248
  /**
232
- * Argument accepted by {@link Event.sub} / {@link Event.unsub}: one ticket or an array of tickets.
233
- * Tickets are {@link Event.TICKET} without a subscriber and {@link Event.TICKET_CUSTOM} with one.
249
+ * What you pass to {@link Event.sub} / {@link Event.unsub}: one ticket or an array of tickets.
250
+ * Without a DOM `subscriber` → {@link Event.TICKET}; with one → {@link Event.TICKET_CUSTOM}.
234
251
  * @template T Subscriber type, or `undefined` for the Event manager.
235
252
  */
236
253
  export type Pass<T extends SUBSCRIBER | undefined> = T extends SUBSCRIBER ? TICKET_CUSTOM | TICKET_CUSTOM[] : TICKET | TICKET[];
@@ -257,8 +274,9 @@ declare namespace Event {
257
274
  * `DEATH` (leave current page, on `ON_NAVIGATE`) → `LIFE` (enter new page, on `AFTER_NAVIGATE`) →
258
275
  * `LOAD` (after framework tick, static readiness and `App.wait`).
259
276
  *
260
- * Subscribe with `Up.Event.sub([['DEATH', handler], ['LIFE', handler], …])`. See {@link EventData} for built-in keys
261
- * and {@link Event.CONFIG} to register more.
277
+ * Subscribe with `Up.Event.sub([['DEATH', handler], ['LIFE', handler], …])`.
278
+ * Optional third ticket field `{ once: true }` runs a handler once then unsubscribes it.
279
+ * See {@link EventData} for built-in keys and {@link Event.CONFIG} to register more.
262
280
  * @note Client-only: on the server no event is registered.
263
281
  */
264
282
  declare abstract class Event {
@@ -411,27 +429,36 @@ declare abstract class Event {
411
429
  */
412
430
  static [eScroll](e: Event): void;
413
431
  /**
414
- * Subscribes one or several tickets.
415
- * Without `subscriber`, each `[key, callback]` ticket ({@link Event.TICKET}) is added to the Event manager.
416
- * Subscribing the same callback twice to the same key has no effect, and subscribers of an event run in reverse subscription order.
417
- * With `subscriber`, each `[key, callback, options?]` ticket ({@link Event.TICKET_CUSTOM}) is passed to `subscriber.addEventListener`.
418
- * @note Without `subscriber`, the callback is called once immediately, with no arguments, and is not stored when:
419
- * the key is unknown or not registered (including on the server), or the key is `LOAD` and the current `LOAD` phase has already started.
432
+ * Subscribes one or several handlers.
433
+ *
434
+ * **Event manager** (no second argument) — pass {@link Event.TICKET} tuples:
435
+ * - `['LIFE', onLife]`
436
+ * - `['LOAD', onLoad, { once: true }]` — runs once for that key, then auto-unsubscribes
437
+ *
438
+ * Same handler twice on the same key is ignored. Handlers for a given key run in **reverse** subscription order.
439
+ *
440
+ * **DOM target** — pass a `subscriber` (`window`, `document`, an element, …) and {@link Event.TICKET_CUSTOM}
441
+ * tuples; the third field is native `AddEventListenerOptions` (`passive`, DOM `once`, …).
442
+ *
443
+ * @note Without a `subscriber`, the handler is called **immediately** (no args) and **not stored** when:
444
+ * the key is unknown / not registered (including on the server), or the key is `LOAD` and the current `LOAD`
445
+ * phase has already started.
420
446
  * @param pass A ticket or an array of tickets.
421
- * @param subscriber Optional listener target (`window`, `document`, an `Element`, …).
447
+ * @param subscriber Optional listener target for DOM (or DOM-like) events.
422
448
  * @example
423
449
  * ```ts
424
450
  * const onResize = (): void => console.log(Up.App.w, Up.App.h)
425
451
  * const onClick = (e: MouseEvent): void => console.log(e.clientX)
426
452
  *
427
- * Up.Event.sub([['LOAD', () => console.log('Page ready')], ['resize', onResize]])
453
+ * Up.Event.sub([['LOAD', () => console.log('Page ready'), { once: true }], ['resize', onResize]])
428
454
  * Up.Event.sub(['click', onClick, Up.Event.PASSIVE], document.body)
429
455
  * ```
430
456
  */
431
457
  static sub<T extends undefined | Event.SUBSCRIBER = undefined>(pass: Event.Pass<T>, subscriber?: T): void;
432
458
  /**
433
- * Unsubscribes one or several tickets previously passed to {@link Event.sub}.
434
- * Callbacks are matched by reference, so pass the same function (and the same `subscriber`) used to subscribe.
459
+ * Unsubscribes handlers previously passed to {@link Event.sub}.
460
+ * Match by **function reference** (and the same `subscriber` if you used one).
461
+ * For Event-manager tickets, pass the same handler you subscribed — including when it was registered with `{ once: true }`.
435
462
  * @param pass A ticket or an array of tickets.
436
463
  * @param subscriber The listener target used when subscribing, if any.
437
464
  * @example
package/docs/core.md CHANGED
@@ -69,9 +69,15 @@ Up.Event.unsub([
69
69
  ])
70
70
  ```
71
71
 
72
+ Optional third field `{ once: true }` — the handler runs **once** for that key, then unsubscribes itself (still `unsub` with the same function if you tear down early):
73
+
74
+ ```ts
75
+ Up.Event.sub(['LOAD', () => console.log('ready'), { once: true }])
76
+ ```
77
+
72
78
  `LIFE` / `LOAD` subscribers receive a **Promise** that resolves when every subscriber for that phase has finished. `DEATH` runs synchronously and takes no args.
73
79
 
74
- Always **unsub** with the same function references when the component goes away. Event listeners are **client-only**.
80
+ Always **unsub** with the same function references when the component goes away (including handlers registered with `once`). Event listeners are **client-only**.
75
81
 
76
82
  ### Wire the host — `Up.set` and `Up.Adapter`
77
83
 
@@ -187,7 +193,7 @@ Up.Event.sub(['click', onClick, Up.Event.PASSIVE], document.body)
187
193
  Up.Event.unsub(['click', onClick], document.body)
188
194
  ```
189
195
 
190
- `Up.Event.PASSIVE` / `IMPASSIVE` are ready-made options objects.
196
+ `Up.Event.PASSIVE` / `IMPASSIVE` are ready-made **DOM** options objects (`AddEventListenerOptions`). They are not the Event-manager `{ once: true }` ticket option — that third field only applies when you omit the DOM `subscriber`.
191
197
 
192
198
  ### Extra App metrics and cache notes
193
199
 
@@ -251,7 +257,8 @@ Budgets: [initializers — `up.thread`](initializers.md#upthread).
251
257
  ### Event subtleties
252
258
 
253
259
  - Subscribers of a given key run in **reverse subscription order**. Duplicate `(key, callback)` pairs are ignored.
254
- - **Immediate one-shot (not stored):** if you `sub` an unknown / unregistered key, or `LOAD` after the current `LOAD` phase has already started, the callback runs **once** with no args and is **not** kept.
260
+ - **`{ once: true }`:** runs once for that key, then auto-unsubscribes. Unrelated to the bullet below.
261
+ - **Immediate one-shot (not stored):** if you `sub` an unknown / unregistered key, or `LOAD` after the current `LOAD` phase has already started, the callback runs **immediately** with no args and is **not** kept.
255
262
  - `LIFE` / `LOAD` Promise args are useful for chaining; you can ignore them.
256
263
 
257
264
  ---
package/docs/faq.md CHANGED
@@ -90,7 +90,11 @@ Expected: default tasks are **flow** (one-shot). For every frame, `Up.Thread.mar
90
90
 
91
91
  ### Memory leaks after navigation
92
92
 
93
- Always **unsub** with the **same function references** you passed to `Event.sub` / `Adapter.sub` / `Thread.sub` / `Observer.sub` / `Anime.unsub(key)`. Cancel `Wait.throttle` / `debounce` wrappers with `Wait.cancel`.
93
+ Always **unsub** with the **same function references** you passed to `Event.sub` / `Adapter.sub` / `Thread.sub` / `Observer.sub` / `Anime.unsub(key)` — including Event handlers registered with `{ once: true }` if you tear down early. Cancel `Wait.throttle` / `debounce` wrappers with `Wait.cancel`.
94
+
95
+ ### How do I run an Event handler only once?
96
+
97
+ `Up.Event.sub(['LOAD', handler, { once: true }])` — fires once for that key, then unsubscribes. (DOM targets use native `AddEventListenerOptions.once` instead.) — [core](core.md#page-cues--upevent).
94
98
 
95
99
  ### Can I use scripts without the Vite plugin?
96
100
 
package/docs/recipes.md CHANGED
@@ -32,6 +32,16 @@ Up.Event.sub([
32
32
 
33
33
  `LOAD` also waits on static files after `LIFE`. Options: `up.event.staticFilesConfig` in [initializers](initializers.md).
34
34
 
35
+ ### Run a handler once
36
+
37
+ ```ts
38
+ Up.Event.sub(['LOAD', () => {
39
+ /* first ready only — then auto-unsub */
40
+ }, { once: true }])
41
+ ```
42
+
43
+ Same function reference for a manual `unsub` if you leave before it fires. Details: [core — Event](core.md#page-cues--upevent).
44
+
35
45
  ### Component-scoped subscriptions (Nuxt / Vue)
36
46
 
37
47
  ```vue
package/llms.txt CHANGED
@@ -72,6 +72,8 @@ API docs (core, adapters, initializers, contexts, plugins, scripts, classter, sy
72
72
 
73
73
  - `Up.Thread.sub(task)` is one-shot (flow) by default; flag default is `4096` (`MAX_FLAG`)
74
74
  - Forever: `markForever(task)` then `sub`, or prefer `Up.Event.sub(['TICK', …])`
75
+ - Event ticket `{ once: true }` (third field, Event manager only): run once per key then auto-unsub; unsub still uses the same function ref
76
+ - DOM `Event.sub(..., element)` third field is `AddEventListenerOptions`, not Event `{ once: true }`
75
77
  - `Up.destroy()` is irreversible (no second `Up.set`)
76
78
  - Screen cookie: `up::plugins::screen::format`
77
79
 
@@ -79,4 +81,4 @@ API docs (core, adapters, initializers, contexts, plugins, scripts, classter, sy
79
81
 
80
82
  - Republish or rebrand as a competing package
81
83
  - Assume MIT/Apache rights
82
- - Call `Up.set` more than once (no-op after first)
84
+ - Call `Up.set` more than once (no-op after first)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "upwwwards",
3
- "version": "0.1.6-beta.1",
3
+ "version": "0.1.7-beta.1",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "Shared page lifecycle, frame loop, and opt-in plugins (GSAP, Lenis, Three.js) for Nuxt 4 and SvelteKit 2.",
6
6
  "author": "Morgan LE THUAUT <morgan@upwwwards.com>",