upwwwards 0.1.8-beta.1 → 0.1.10-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.
@@ -14,8 +14,8 @@ class Event {
14
14
  static #AFTER_LOAD = 32;
15
15
  static #THREAD_FLAG = 128;
16
16
  static #ADAPTER_TICKETS = [
17
- ["ON_NAVIGATE", Event.#eOnNavigate],
18
- ["AFTER_NAVIGATE", Event.#eAfterNavigate]
17
+ ["ON_NAVIGATE", Event.#n$OnNavigate],
18
+ ["AFTER_NAVIGATE", Event.#n$AfterNavigate]
19
19
  ];
20
20
  static #PASSIVE = { passive: true };
21
21
  static #IMPASSIVE = { passive: false };
@@ -322,10 +322,15 @@ class Event {
322
322
  Event.#resizeObserver = new ResizeObserver(Event.#oResize);
323
323
  }
324
324
  /**
325
- * Subscribes to adapter navigation hooks and attaches DOM listeners.
325
+ * Subscribes to adapter navigation hooks (`ON_NAVIGATE` → {@link Event.DEATH}, `AFTER_NAVIGATE` → {@link Event.LIFE} then {@link Event.LOAD}).
326
326
  */
327
- static #setEvents() {
327
+ static #setNavigation() {
328
328
  Event.Adapter.sub(Event.#ADAPTER_TICKETS);
329
+ }
330
+ /**
331
+ * Attaches DOM listeners for built-in window / document events (`resize`, `scroll`, `visibilitychange`, …).
332
+ */
333
+ static #setEvents() {
329
334
  for (const [KEY, DATA] of Event.#DATA)
330
335
  if (DATA.on !== "independent") (DATA.on === "window" ? window : document).addEventListener(KEY, DATA.callback, Event.#PASSIVE);
331
336
  }
@@ -341,6 +346,7 @@ class Event {
341
346
  */
342
347
  static [set]() {
343
348
  Event.#setVars();
349
+ Event.#setNavigation();
344
350
  Event.#setEvents();
345
351
  Event.#setObservers();
346
352
  }
@@ -359,6 +365,9 @@ class Event {
359
365
  static #getWaiter(task, waitState) {
360
366
  return waitState > 0 ? Wait.debounce(task, waitState, false) : Wait.throttle(task, waitState * -1, true, false);
361
367
  }
368
+ /**
369
+ * Index of `callback` in `wrappers` (matched on `original`), or `-1` if absent.
370
+ */
362
371
  static #getIndex(wrappers, callback) {
363
372
  for (let i = 0, max = wrappers.length; i < max; i++) if (wrappers[i].original === callback) return i;
364
373
  return -1;
@@ -421,10 +430,15 @@ class Event {
421
430
  }
422
431
  }
423
432
  /**
424
- * Detaches navigation hooks and DOM listeners and cancels pending waits.
433
+ * Unsubscribes from adapter navigation hooks (`ON_NAVIGATE` / `AFTER_NAVIGATE`).
425
434
  */
426
- static #destroyEvents() {
435
+ static #destroyNavigation() {
427
436
  Event.Adapter.unsub(Event.#ADAPTER_TICKETS);
437
+ }
438
+ /**
439
+ * Detaches DOM listeners for built-in window / document events and cancels their pending waits.
440
+ */
441
+ static #destroyEvents() {
428
442
  for (const [KEY, DATA] of Event.#DATA) {
429
443
  if (DATA.on !== "independent") (DATA.on === "window" ? window : document).removeEventListener(KEY, DATA.callback);
430
444
  Wait.cancel(DATA.callback);
@@ -437,13 +451,14 @@ class Event {
437
451
  static [destroy]() {
438
452
  Event.#destroyVars();
439
453
  Event.#destroyTasks();
454
+ Event.#destroyNavigation();
440
455
  Event.#destroyEvents();
441
456
  }
442
- // ##EVENTS
457
+ // ##NAVIGATION
443
458
  /**
444
459
  * Adapter `ON_NAVIGATE` hook: runs the `DEATH` phase (leave current page once navigation is committed).
445
460
  */
446
- static #eOnNavigate() {
461
+ static #n$OnNavigate() {
447
462
  Event.#status = Event.#PRE_DEATH;
448
463
  Event.#deathIn = performance.now();
449
464
  Event[eDeath]();
@@ -452,7 +467,7 @@ class Event {
452
467
  /**
453
468
  * Adapter `AFTER_NAVIGATE` hook: runs the `LIFE` phase, waits for readiness, then runs the `LOAD` phase.
454
469
  */
455
- static async #eAfterNavigate() {
470
+ static async #n$AfterNavigate() {
456
471
  let res = Event.App.void;
457
472
  Event.#status = Event.#PRE_LIFE;
458
473
  Event.#lifeIn = performance.now();
@@ -473,6 +488,7 @@ class Event {
473
488
  Event.#status |= Event.#AFTER_LOAD;
474
489
  res();
475
490
  }
491
+ // ##EVENTS
476
492
  /**
477
493
  * `TICK` runner: calls subscribers with the current frame timestamp.
478
494
  * @internal
@@ -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 * 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":[]}
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.#n$OnNavigate],\r\n ['AFTER_NAVIGATE', Event.#n$AfterNavigate]\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 (`ON_NAVIGATE` → {@link Event.DEATH}, `AFTER_NAVIGATE` → {@link Event.LIFE} then {@link Event.LOAD}).\r\n */\r\n static #setNavigation(): void { Event.Adapter.sub(Event.#ADAPTER_TICKETS) }\r\n\r\n /**\r\n * Attaches DOM listeners for built-in window / document events (`resize`, `scroll`, `visibilitychange`, …).\r\n */\r\n static #setEvents(): void\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.#setNavigation()\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 /**\r\n * Index of `callback` in `wrappers` (matched on `original`), or `-1` if absent.\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 * Unsubscribes from adapter navigation hooks (`ON_NAVIGATE` / `AFTER_NAVIGATE`).\r\n */\r\n static #destroyNavigation(): void { Event.Adapter.unsub(Event.#ADAPTER_TICKETS) }\r\n\r\n /**\r\n * Detaches DOM listeners for built-in window / document events and cancels their pending waits.\r\n */\r\n static #destroyEvents(): void\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.#destroyNavigation()\r\n Event.#destroyEvents()\r\n }\r\n\r\n // ##NAVIGATION\r\n /**\r\n * Adapter `ON_NAVIGATE` hook: runs the `DEATH` phase (leave current page once navigation is committed).\r\n */\r\n static #n$OnNavigate(): 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 #n$AfterNavigate(): 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 // ##EVENTS\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":[]}
@@ -783,11 +783,48 @@ declare abstract class Scroll extends Lazy {
783
783
  static to(target: HTMLElement | number | string, options?: ScrollToOptions): void;
784
784
  }
785
785
 
786
+ declare namespace Split {
787
+ /**
788
+ * Options for {@link Split.add}: GSAP `SplitText.Vars`, plus an optional `reconstruct` flag.
789
+ * By default, each target keeps one cached {@link Split.SPLIT}: a later `add` that only needs a
790
+ * **subset** of already split types (and a compatible `mask`) returns that same object; if new types
791
+ * or a new `mask` are required, types are **merged** and the existing `SplitText` is re-split in place.
792
+ * Set `reconstruct: true` to **replace** the cached types / mask with this call’s values and re-split
793
+ * (no merge). `reconstruct` is upwwwards-only and is not passed to GSAP.
794
+ */
795
+ type VARS = SplitText.Vars & {
796
+ reconstruct?: boolean;
797
+ };
798
+ /**
799
+ * A split kind accepted in `vars.type` (`'chars'`, `'lines'`, or `'words'`).
800
+ */
801
+ type TYPE = 'chars' | 'lines' | 'words';
802
+ /**
803
+ * Result of {@link Split.add}: one stable object per `target` on this helper.
804
+ * `chars` / `lines` / `words` / `masks` are the same array references across calls; their contents are
805
+ * updated in place when the underlying `SplitText` is re-split. `types` / `mask` reflect the current
806
+ * split definition; `splitText` is the single GSAP instance for that target.
807
+ */
808
+ type SPLIT = {
809
+ types: TYPE[];
810
+ mask: TYPE | undefined;
811
+ chars: Element[];
812
+ lines: Element[];
813
+ words: Element[];
814
+ masks: Element[];
815
+ splitText: SplitText;
816
+ };
817
+ }
786
818
  /**
787
- * Collection of GSAP `SplitText` instances owned by a private GSAP context, reverted together by `destroy`
788
- * (which restores the original markup).
819
+ * Helper that owns one GSAP `SplitText` per target in a private GSAP context, reverted together by {@link Split.destroy}
820
+ * (restoring the original markup).
821
+ * On the **same target**, {@link Split.add} returns the same {@link Split.SPLIT}: subset requests reuse it as-is;
822
+ * wider requests (or a new `mask`) merge into the cached types and call `splitText.split(…)`. Pass
823
+ * `reconstruct: true` to replace the definition instead of merging. Element arrays on the `SPLIT` are kept by
824
+ * reference and refreshed in place after a re-split — prefer that object over holding individual node refs across
825
+ * a reconstruct / expand (tweens already targeting old nodes stay stale).
789
826
  * When constructed inside an `Up.Anime.sub` callback, the instance pushes its `destroy` on the workspace's cleaning stack
790
- * (the list of destructors run by `Up.Anime.unsub`), so it is cleaned up automatically.
827
+ * (run by `Up.Anime.unsub`), so it is cleaned up automatically.
791
828
  * @note Requires `'SplitText'` in the Anime config (`plugins: ['SplitText']`).
792
829
  * @note Get the class from the Anime bucket (`bucket.Split`): it is only usable once Anime has loaded GSAP.
793
830
  * @example
@@ -816,15 +853,28 @@ declare class Split {
816
853
  */
817
854
  constructor();
818
855
  /**
819
- * Splits `target` with `SplitText.create` inside the managed context, so `destroy` reverts it.
820
- * @param target Element(s) to split.
821
- * @param vars `SplitText` options.
822
- * @returns The created `SplitText` instance.
856
+ * Splits `target` according to `vars.type` (and optional `mask`). Work is recorded in the managed GSAP context
857
+ * so {@link Split.destroy} can revert it.
858
+ * **Same target, default:** if the cached split already covers the requested types and `mask`, returns that
859
+ * {@link Split.SPLIT} unchanged; otherwise merges the new types (and updates `mask` when provided), re-splits
860
+ * via `splitText.split(…)`, and refreshes `chars` / `lines` / `words` / `masks` in place.
861
+ * **`reconstruct: true`:** replaces the cached types / mask with this call’s values, re-splits, then refreshes
862
+ * the arrays (still the same `SPLIT` object / `splitText` instance). Unknown tokens in `type` are ignored.
863
+ * @param target Element(s) to split (Map key for the per-target cache).
864
+ * @param vars GSAP `SplitText` options; `type` is required. Optional `reconstruct` is upwwwards-only and is not passed to GSAP.
865
+ * @returns The cached {@link Split.SPLIT} for `target` (created on first `add`).
866
+ * @example
867
+ * ```ts
868
+ * const lines = split.add('.title', { type: 'lines' })
869
+ * const both = split.add('.title', { type: 'lines,words' }) // same object; union + re-split
870
+ * const words = split.add('.title', { type: 'words' }) // same object; subset → no re-split
871
+ * const only = split.add('.title', { type: 'words', reconstruct: true }) // same object; replace + re-split
872
+ * ```
823
873
  */
824
- add(target: gsap.DOMTarget, vars?: SplitText.Vars): SplitText;
874
+ add(target: gsap.DOMTarget, { reconstruct, ...vars }: Split.VARS): Split.SPLIT;
825
875
  /**
826
- * Reverts every `SplitText` instance created through this helper, then starts over with an empty context.
827
- * The instance stays usable afterwards.
876
+ * Clears the per-target cache, reverts every `SplitText` owned by this helper, and starts over with an empty context.
877
+ * The instance stays usable afterwards (new `add` calls behave like on a fresh `Split`).
828
878
  */
829
879
  destroy(): void;
830
880
  }
@@ -964,8 +1014,8 @@ declare namespace Timeline {
964
1014
  */
965
1015
  eLeaveBack?: () => void;
966
1016
  /**
967
- * Intended to fire after each ScrollTrigger refresh, once positions, animations and tracks are recomputed.
968
- * @warning Currently stored but never called by the implementation.
1017
+ * Fires after each ScrollTrigger refresh, once positions, animations and tracks are recomputed
1018
+ * (and before any catch-up `eUpdate` when the scrub progress already differs from the last notified value).
969
1019
  */
970
1020
  eRefresh?: () => void;
971
1021
  /**
@@ -1379,8 +1429,9 @@ declare class Timeline {
1379
1429
  */
1380
1430
  addTrack(vars: Timeline.TRACK_VARS): Timeline['addTrack'];
1381
1431
  /**
1382
- * Re-evaluates every track from progress `0` to the current progress, e.g. to sync tracks with a page that is already
1383
- * scrolled past the timeline start. Waits for pending fragment updates and for the first ScrollTrigger refresh.
1432
+ * Forces a track re-evaluation from the last notified progress to the live ScrollTrigger progress
1433
+ * (e.g. after adding tracks, or when layout changed). Waits for pending fragment updates and for the first
1434
+ * ScrollTrigger refresh — that refresh already catch-ups from `0` when the page was restored mid-scroll.
1384
1435
  * Does nothing if the current scroll position (`Up.App.y`) is before the timeline start.
1385
1436
  * Logs a warning and returns if the timeline is not configured.
1386
1437
  * @returns Resolves once the update has run or been skipped.
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { W as Wait } from './Wait-C8AD49l9.js';
3
3
  import { T as Thread, a as App } from './Thread-5NGNyOJb.js';
4
4
  export { b as AppCache } from './Thread-5NGNyOJb.js';
5
5
  import { A as Adapter, a as AdapterConfig } from './index-BlwaDpQl.js';
6
- import { P as Plugin } from './index-DWhRKejo.js';
6
+ import { P as Plugin } from './index-ymMzfIlh.js';
7
7
  import 'lenis';
8
8
  import 'gsap/SplitText';
9
9
  import 'gsap/ScrollTrigger';
@@ -1,6 +1,6 @@
1
1
  import { Plugin as Plugin$1 } from 'vite';
2
2
  import { Up } from '../index.js';
3
- import { P as Plugin } from '../index-DWhRKejo.js';
3
+ import { P as Plugin } from '../index-ymMzfIlh.js';
4
4
  import { C as Classter } from '../Classter-BvYgmPAa.js';
5
5
  import '../symbols/index.js';
6
6
  import '../Wait-C8AD49l9.js';
@@ -4,12 +4,17 @@ import Logs from "../../scripts/Logs.js";
4
4
  class Split {
5
5
  // #PROPS
6
6
  // ##STATICS
7
+ static #RGX_TYPE = /\s*,\s*/;
8
+ static #TYPES = ["chars", "lines", "words"];
9
+ static #PROPS = [...Split.#TYPES, "masks"];
10
+ static #PROPS_LENGTH = Split.#PROPS.length;
7
11
  /**
8
12
  * Anime bucket shared by the Anime plugin once GSAP is loaded; includes `SplitText` when it is in the Anime config.
9
13
  * @internal
10
14
  */
11
15
  static [BUCKET];
12
16
  // ##PRIVATES
17
+ #CACHE = /* @__PURE__ */ new Map();
13
18
  #ctx = Split[BUCKET].gsap.context(Up.App.void);
14
19
  // ##PUBLICS
15
20
  // #MANAGERS
@@ -29,23 +34,75 @@ class Split {
29
34
  // ##GET
30
35
  // ##ADD
31
36
  /**
32
- * Splits `target` with `SplitText.create` inside the managed context, so `destroy` reverts it.
33
- * @param target Element(s) to split.
34
- * @param vars `SplitText` options.
35
- * @returns The created `SplitText` instance.
37
+ * Splits `target` according to `vars.type` (and optional `mask`). Work is recorded in the managed GSAP context
38
+ * so {@link Split.destroy} can revert it.
39
+ * **Same target, default:** if the cached split already covers the requested types and `mask`, returns that
40
+ * {@link Split.SPLIT} unchanged; otherwise merges the new types (and updates `mask` when provided), re-splits
41
+ * via `splitText.split(…)`, and refreshes `chars` / `lines` / `words` / `masks` in place.
42
+ * **`reconstruct: true`:** replaces the cached types / mask with this call’s values, re-splits, then refreshes
43
+ * the arrays (still the same `SPLIT` object / `splitText` instance). Unknown tokens in `type` are ignored.
44
+ * @param target Element(s) to split (Map key for the per-target cache).
45
+ * @param vars GSAP `SplitText` options; `type` is required. Optional `reconstruct` is upwwwards-only and is not passed to GSAP.
46
+ * @returns The cached {@link Split.SPLIT} for `target` (created on first `add`).
47
+ * @example
48
+ * ```ts
49
+ * const lines = split.add('.title', { type: 'lines' })
50
+ * const both = split.add('.title', { type: 'lines,words' }) // same object; union + re-split
51
+ * const words = split.add('.title', { type: 'words' }) // same object; subset → no re-split
52
+ * const only = split.add('.title', { type: 'words', reconstruct: true }) // same object; replace + re-split
53
+ * ```
36
54
  */
37
- add(target, vars) {
38
- return this.#ctx.add(() => Split[BUCKET].SplitText.create(target, vars));
55
+ add(target, { reconstruct, ...vars }) {
56
+ return this.#ctx.add(() => {
57
+ const TYPES = vars.type.trim().split(Split.#RGX_TYPE);
58
+ for (let i = TYPES.length - 1; i > -1; i--) if (!Split.#TYPES.includes(TYPES[i])) TYPES.splice(i, 1);
59
+ let split = this.#CACHE.get(target);
60
+ if (split) {
61
+ if (reconstruct) {
62
+ split.types = TYPES;
63
+ split.mask = vars.mask;
64
+ vars.type = TYPES.join(",");
65
+ } else {
66
+ if (Split.#isIncluded(split.types, TYPES) && (!vars.mask || split.mask === vars.mask)) return split;
67
+ for (let i = 0, max = TYPES.length; i < max; i++) if (!split.types.includes(TYPES[i])) split.types.push(TYPES[i]);
68
+ vars.type = split.types.join(",");
69
+ if (vars.mask) split.mask = vars.mask;
70
+ }
71
+ split.splitText.split(vars);
72
+ } else this.#CACHE.set(target, split = {
73
+ types: TYPES,
74
+ mask: vars.mask,
75
+ chars: [],
76
+ lines: [],
77
+ words: [],
78
+ masks: [],
79
+ splitText: Split[BUCKET].SplitText.create(target, vars)
80
+ });
81
+ for (let i = 0; i < Split.#PROPS_LENGTH; i++) {
82
+ const TARGET = split[Split.#PROPS[i]], SOURCE = split.splitText[Split.#PROPS[i]], LENGTH = SOURCE.length;
83
+ TARGET.length = LENGTH;
84
+ for (let j = 0; j < LENGTH; j++) TARGET[j] = SOURCE[j];
85
+ }
86
+ return split;
87
+ });
39
88
  }
40
89
  // ##DESTROY
41
90
  /**
42
- * Reverts every `SplitText` instance created through this helper, then starts over with an empty context.
43
- * The instance stays usable afterwards.
91
+ * Clears the per-target cache, reverts every `SplitText` owned by this helper, and starts over with an empty context.
92
+ * The instance stays usable afterwards (new `add` calls behave like on a fresh `Split`).
44
93
  */
45
94
  destroy() {
95
+ if (this.#CACHE.size) this.#CACHE.clear();
46
96
  this.#ctx.revert();
47
97
  this.#ctx = Split[BUCKET].gsap.context(Up.App.void);
48
98
  }
99
+ // ##IS
100
+ static #isIncluded(target, source) {
101
+ const LENGTH = source.length;
102
+ if (LENGTH > target.length) return false;
103
+ for (let i = 0; i < LENGTH; i++) if (!target.includes(source[i])) return false;
104
+ return true;
105
+ }
49
106
  }
50
107
  var Split_default = Split;
51
108
  export {