upwwwards 0.1.8-beta.1 → 0.1.9-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.
- package/dist/core/[1]/Event.js +25 -9
- package/dist/core/[1]/Event.js.map +1 -1
- package/dist/{index-DWhRKejo.d.ts → index-Di5rQVjZ.d.ts} +5 -4
- package/dist/index.d.ts +1 -1
- package/dist/initializers/vite.d.ts +1 -1
- package/dist/plugins/@anime/Timeline.js +21 -16
- package/dist/plugins/@anime/Timeline.js.map +1 -1
- package/dist/plugins/Anime.d.ts +1 -1
- package/dist/plugins/Puppeteer.d.ts +1 -1
- package/dist/plugins/Scroll.d.ts +1 -1
- package/dist/plugins/Scroll.js +2 -2
- package/dist/plugins/Scroll.js.map +1 -1
- package/dist/plugins/Synthra.d.ts +1 -1
- package/dist/plugins/Transmitter.d.ts +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/docs/plugins/anime.md +5 -3
- package/package.json +1 -1
package/dist/core/[1]/Event.js
CHANGED
|
@@ -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.#
|
|
18
|
-
["AFTER_NAVIGATE", Event.#
|
|
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
|
|
325
|
+
* Subscribes to adapter navigation hooks (`ON_NAVIGATE` → {@link Event.DEATH}, `AFTER_NAVIGATE` → {@link Event.LIFE} then {@link Event.LOAD}).
|
|
326
326
|
*/
|
|
327
|
-
static #
|
|
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
|
-
*
|
|
433
|
+
* Unsubscribes from adapter navigation hooks (`ON_NAVIGATE` / `AFTER_NAVIGATE`).
|
|
425
434
|
*/
|
|
426
|
-
static #
|
|
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
|
-
// ##
|
|
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 #
|
|
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 #
|
|
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":[]}
|
|
@@ -964,8 +964,8 @@ declare namespace Timeline {
|
|
|
964
964
|
*/
|
|
965
965
|
eLeaveBack?: () => void;
|
|
966
966
|
/**
|
|
967
|
-
*
|
|
968
|
-
*
|
|
967
|
+
* Fires after each ScrollTrigger refresh, once positions, animations and tracks are recomputed
|
|
968
|
+
* (and before any catch-up `eUpdate` when the scrub progress already differs from the last notified value).
|
|
969
969
|
*/
|
|
970
970
|
eRefresh?: () => void;
|
|
971
971
|
/**
|
|
@@ -1379,8 +1379,9 @@ declare class Timeline {
|
|
|
1379
1379
|
*/
|
|
1380
1380
|
addTrack(vars: Timeline.TRACK_VARS): Timeline['addTrack'];
|
|
1381
1381
|
/**
|
|
1382
|
-
*
|
|
1383
|
-
*
|
|
1382
|
+
* Forces a track re-evaluation from the last notified progress to the live ScrollTrigger progress
|
|
1383
|
+
* (e.g. after adding tracks, or when layout changed). Waits for pending fragment updates and for the first
|
|
1384
|
+
* ScrollTrigger refresh — that refresh already catch-ups from `0` when the page was restored mid-scroll.
|
|
1384
1385
|
* Does nothing if the current scroll position (`Up.App.y`) is before the timeline start.
|
|
1385
1386
|
* Logs a warning and returns if the timeline is not configured.
|
|
1386
1387
|
* @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-
|
|
6
|
+
import { P as Plugin } from './index-Di5rQVjZ.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-
|
|
3
|
+
import { P as Plugin } from '../index-Di5rQVjZ.js';
|
|
4
4
|
import { C as Classter } from '../Classter-BvYgmPAa.js';
|
|
5
5
|
import '../symbols/index.js';
|
|
6
6
|
import '../Wait-C8AD49l9.js';
|
|
@@ -39,7 +39,7 @@ class Timeline {
|
|
|
39
39
|
#current = /* @__PURE__ */ new Set();
|
|
40
40
|
#seen = /* @__PURE__ */ new Set();
|
|
41
41
|
#updating = null;
|
|
42
|
-
#
|
|
42
|
+
#updatingResolve = null;
|
|
43
43
|
#getOverflowStart;
|
|
44
44
|
#getOverflowEnd;
|
|
45
45
|
#eRefreshCallback = Up.App.void;
|
|
@@ -96,7 +96,15 @@ class Timeline {
|
|
|
96
96
|
eUpdate = Up.App.void,
|
|
97
97
|
...VARS
|
|
98
98
|
} = config;
|
|
99
|
+
this.#progress = 0;
|
|
99
100
|
this.#name = NAME;
|
|
101
|
+
this.#updating = new Promise((res) => {
|
|
102
|
+
this.#updatingResolve = res;
|
|
103
|
+
});
|
|
104
|
+
this.#getOverflowStart = getOverflowStart;
|
|
105
|
+
this.#getOverflowEnd = getOverflowEnd;
|
|
106
|
+
this.#eRefreshCallback = eRefresh;
|
|
107
|
+
this.#eUpdateCallback = eUpdate;
|
|
100
108
|
this.#ctx = Timeline[BUCKET].gsap.context(() => {
|
|
101
109
|
(this.#timeline = Timeline[BUCKET].gsap.timeline(
|
|
102
110
|
{
|
|
@@ -115,13 +123,6 @@ class Timeline {
|
|
|
115
123
|
}
|
|
116
124
|
)).to(this, { duration: 1 }, 0);
|
|
117
125
|
});
|
|
118
|
-
this.#updating = new Promise((res) => {
|
|
119
|
-
this.#updatingRes = res;
|
|
120
|
-
});
|
|
121
|
-
this.#getOverflowStart = getOverflowStart;
|
|
122
|
-
this.#getOverflowEnd = getOverflowEnd;
|
|
123
|
-
this.#eRefreshCallback = eRefresh;
|
|
124
|
-
this.#eUpdateCallback = eUpdate;
|
|
125
126
|
}
|
|
126
127
|
#setTask() {
|
|
127
128
|
Up.Thread.sub(this.#t$UpdateFragments);
|
|
@@ -382,8 +383,9 @@ class Timeline {
|
|
|
382
383
|
}
|
|
383
384
|
}
|
|
384
385
|
/**
|
|
385
|
-
*
|
|
386
|
-
*
|
|
386
|
+
* Forces a track re-evaluation from the last notified progress to the live ScrollTrigger progress
|
|
387
|
+
* (e.g. after adding tracks, or when layout changed). Waits for pending fragment updates and for the first
|
|
388
|
+
* ScrollTrigger refresh — that refresh already catch-ups from `0` when the page was restored mid-scroll.
|
|
387
389
|
* Does nothing if the current scroll position (`Up.App.y`) is before the timeline start.
|
|
388
390
|
* Logs a warning and returns if the timeline is not configured.
|
|
389
391
|
* @returns Resolves once the update has run or been skipped.
|
|
@@ -420,7 +422,7 @@ class Timeline {
|
|
|
420
422
|
* Called automatically by `Up.Anime.unsub` when the timeline was constructed inside a `sub` callback.
|
|
421
423
|
*/
|
|
422
424
|
destroy() {
|
|
423
|
-
this.#
|
|
425
|
+
this.#resolve();
|
|
424
426
|
this.#destroyTracks();
|
|
425
427
|
this.#destroyVars();
|
|
426
428
|
}
|
|
@@ -430,11 +432,14 @@ class Timeline {
|
|
|
430
432
|
this.#updateFragments(false);
|
|
431
433
|
this.#updateAnimations();
|
|
432
434
|
this.#updateTracks();
|
|
433
|
-
this.#
|
|
435
|
+
this.#resolve();
|
|
436
|
+
this.#eRefreshCallback();
|
|
437
|
+
if (this.#timeline.progress() !== this.#progress) this.#eUpdate(true);
|
|
434
438
|
}
|
|
435
439
|
#eUpdate(force = false) {
|
|
440
|
+
if (this.#updating) return;
|
|
436
441
|
if (this.#seen.size) this.#seen.clear();
|
|
437
|
-
const PREV =
|
|
442
|
+
const PREV = this.#progress;
|
|
438
443
|
this.#progress = this.#timeline.progress();
|
|
439
444
|
if (!force && this.#progress === PREV) return;
|
|
440
445
|
this.#running = this.#progress > 0 && this.#progress < 1;
|
|
@@ -449,9 +454,9 @@ class Timeline {
|
|
|
449
454
|
// ##TASKS
|
|
450
455
|
#t$UpdateFragments = this.#updateFragments.bind(this, true);
|
|
451
456
|
// ##UTILS
|
|
452
|
-
#
|
|
453
|
-
this.#
|
|
454
|
-
this.#
|
|
457
|
+
#resolve() {
|
|
458
|
+
this.#updating = null;
|
|
459
|
+
this.#updatingResolve?.();
|
|
455
460
|
}
|
|
456
461
|
#flush() {
|
|
457
462
|
for (let i = this.#pending.length - 1; i > -1; i--) this.#addAnimation(this.#pending.splice(i, 1)[0]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/plugins/@anime/Timeline.ts"],"sourcesContent":["/* [Timeline] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SYMBOLS\r\nimport { BUCKET } from '../../symbols/index.js'\r\n\r\n // ##CORE\r\nimport Up from '../../core/Up.js'\r\n\r\n // ##SCRIPTS\r\nimport Maths from '../../scripts/Maths.js'\r\nimport Logs from '../../scripts/Logs.js'\r\nimport Trees from '../../scripts/Trees.js'\r\n\r\n // ##TYPES\r\nimport type ScrollTrigger from 'gsap/ScrollTrigger'\r\n\r\nimport type Parser from '../../scripts/Parser.js'\r\n\r\nimport type { AnimeBucket } from '../Anime.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Timeline\r\n{\r\n /**\r\n * Options of the constructor and `set`: GSAP `ScrollTrigger` vars (`trigger`, `scrub`, `pin`, …) plus Upwwwards options.\r\n * `start` / `end` are numbers here (fractions of the trigger height) and the native `onEnter` / `onEnterBack` / `onLeave` /\r\n * `onLeaveBack` / `onRefresh` / `onUpdate` callbacks are forbidden: use `eEnter` / `eEnterBack` / … instead.\r\n *\r\n * The scroll range runs from the moment the `start` point of the trigger reaches the top of the viewport until its `end` point\r\n * reaches the bottom of the viewport (`100lvh` from its top), extended by the optional overflows. The part between the overflows is the main band.\r\n * @note The trigger should be taller than the viewport (`100lvh`), otherwise the range is empty or inverted.\r\n */\r\n export type CONFIG = Parser.Merge<ScrollTrigger.Vars,\r\n {\r\n /**\r\n * Debug name (default `\"Timeline\"`).\r\n */\r\n name?: string,\r\n /**\r\n * Point of the trigger, as a fraction of its height (`0`–`1`, default `0`), that must reach the top of the viewport for the timeline to start.\r\n */\r\n start?: number,\r\n /**\r\n * Point of the trigger, as a fraction of its height (`0`–`1`, default `1`), that must reach the bottom of the viewport for the timeline to end.\r\n */\r\n end?: number,\r\n /**\r\n * Returns the length (px) of the start overflow: extra scroll distance added before the main band. Re-read on every refresh.\r\n */\r\n getOverflowStart?: () => number,\r\n /**\r\n * Returns the length (px) of the end overflow: extra scroll distance added after the main band. Re-read on every refresh.\r\n */\r\n getOverflowEnd?: () => number,\r\n /**\r\n * Passed to ScrollTrigger as `onEnter`: scrolling down into the range.\r\n */\r\n eEnter?: () => void,\r\n /**\r\n * Passed to ScrollTrigger as `onEnterBack`: scrolling up into the range.\r\n */\r\n eEnterBack?: () => void,\r\n /**\r\n * Passed to ScrollTrigger as `onLeave`: scrolling down past the range.\r\n */\r\n eLeave?: () => void,\r\n /**\r\n * Passed to ScrollTrigger as `onLeaveBack`: scrolling up past the start of the range.\r\n */\r\n eLeaveBack?: () => void,\r\n /**\r\n * Intended to fire after each ScrollTrigger refresh, once positions, animations and tracks are recomputed.\r\n * @warning Currently stored but never called by the implementation.\r\n */\r\n eRefresh?: () => void,\r\n /**\r\n * Called with the timeline progress (`0`–`1`) whenever it changes, after the track callbacks.\r\n */\r\n eUpdate ?: (progress: number) => void,\r\n onEnter ?: never,\r\n onEnterBack?: never,\r\n onLeave ?: never,\r\n onLeaveBack?: never,\r\n onRefresh ?: never,\r\n onUpdate ?: never\r\n }>\r\n\r\n /**\r\n * Tween kind: `'F'` = `gsap.from`, `'T'` = `gsap.to`, `'F/T'` = `gsap.fromTo`.\r\n */\r\n export type ANIMATION_TYPE = 'F' | 'T' | 'F/T'\r\n\r\n /**\r\n * GSAP tween vars for a timeline animation. `duration` is forbidden: it is derived from the animation's placement.\r\n * `stagger` and `itemDuration` only apply when the target resolves to several elements (an array or a `NodeList`;\r\n * a selector string counts as one target) and are fractions of a reference span: the fragment when `fragment` is set,\r\n * otherwise the main band plus the overflow parts the animation extends into. The whole staggered sequence still fits between its start and end.\r\n */\r\n export type ANIMATION_UNIVERSAL_VARS = Parser.Merge<gsap.TweenVars,\r\n {\r\n /**\r\n * Debug name (default `\"Animation\"`).\r\n */\r\n name?: string,\r\n /**\r\n * Delay between two consecutive targets, as a fraction of the reference span. Ignored when `itemDuration` is set.\r\n */\r\n stagger?: number,\r\n /**\r\n * Duration of each target, as a fraction of the reference span; the stagger is then computed so the sequence fills the animation. Takes precedence over `stagger`.\r\n */\r\n itemDuration?: number,\r\n duration ?: never\r\n }>\r\n\r\n /**\r\n * Placement of an animation on the timeline, in one of four forms:\r\n * `start` + `end` on the main band (or inside a fragment); `overflowStart` + `end`; `start` + `overflowEnd`; or `overflowStart` + `overflowEnd`.\r\n * Main-band values are fractions of the main band; overflow values are fractions of the corresponding overflow.\r\n */\r\n export type ANIMATION_VARS = Parser.Merge<ANIMATION_UNIVERSAL_VARS,\r\n {\r\n /**\r\n * 1-based fragment index returned by `addFragment`; `start` / `end` are then fractions of that fragment. `0` (default) = no fragment.\r\n */\r\n fragment?: number,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band, or of the fragment when `fragment` is set.\r\n */\r\n start: number,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band, or of the fragment when `fragment` is set.\r\n */\r\n end : number,\r\n overflowStart?: never,\r\n overflowEnd ?: never\r\n }> |\r\n Parser.Merge<ANIMATION_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n start ?: never,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band.\r\n */\r\n end: number,\r\n /**\r\n * How far the animation reaches back into the start overflow, as a fraction of it: `1` starts at the very beginning of the overflow, `0` at the start of the main band.\r\n */\r\n overflowStart: number,\r\n overflowEnd ?: never\r\n }> |\r\n Parser.Merge<ANIMATION_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band.\r\n */\r\n start : number,\r\n end ?: never,\r\n overflowStart?: never,\r\n /**\r\n * How far the animation reaches into the end overflow, as a fraction of it: `1` ends at the very end of the overflow, `0` at the end of the main band.\r\n */\r\n overflowEnd: number\r\n }> |\r\n Parser.Merge<ANIMATION_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n start ?: never,\r\n end ?: never,\r\n /**\r\n * How far the animation reaches back into the start overflow, as a fraction of it: `1` starts at the very beginning of the overflow, `0` at the start of the main band.\r\n */\r\n overflowStart: number,\r\n /**\r\n * How far the animation reaches into the end overflow, as a fraction of it: `1` ends at the very end of the overflow, `0` at the end of the main band.\r\n */\r\n overflowEnd: number\r\n }>\r\n\r\n /**\r\n * Animation record stored by `addAnimation` (resolved and clamped values).\r\n * @internal\r\n */\r\n export type ANIMATION =\r\n {\r\n /**\r\n * Debug name.\r\n */\r\n name: string,\r\n /**\r\n * Tween kind (`'F'`, `'T'` or `'F/T'`).\r\n */\r\n type: ANIMATION_TYPE,\r\n /**\r\n * Resolved GSAP target(s): empty entries of arrays / `NodeList`s removed, a single element unwrapped.\r\n */\r\n target: gsap.TweenTarget,\r\n /**\r\n * Number of resolved targets (`1` for a non-array target such as a selector string).\r\n */\r\n length: number,\r\n /**\r\n * 1-based fragment index, or `0` when not in a fragment.\r\n */\r\n fragment: number,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band or fragment.\r\n */\r\n start: number,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band or fragment.\r\n */\r\n end: number,\r\n /**\r\n * Fraction (`0`–`1`) of the start overflow covered by the animation; `0` when unused.\r\n */\r\n overflowStart: number,\r\n /**\r\n * Fraction (`0`–`1`) of the end overflow covered by the animation; `0` when unused.\r\n */\r\n overflowEnd: number,\r\n /**\r\n * Stagger, as a fraction of the reference span (see {@link Timeline.ANIMATION_UNIVERSAL_VARS}).\r\n */\r\n stagger?: number,\r\n /**\r\n * Per-target duration, as a fraction of the reference span; takes precedence over `stagger`.\r\n */\r\n itemDuration?: number,\r\n /**\r\n * Tween vars without placement keys: `[vars]` for `'F'` / `'T'`, `[fromVars, toVars]` for `'F/T'`.\r\n */\r\n vars: [ANIMATION_UNIVERSAL_VARS] | [ANIMATION_UNIVERSAL_VARS, ANIMATION_UNIVERSAL_VARS],\r\n /**\r\n * GSAP tween on the timeline; created once the timeline is configured and rebuilt on refresh when its timing changes.\r\n */\r\n tween?: gsap.core.Tween\r\n }\r\n\r\n /**\r\n * Name and callbacks shared by every track placement.\r\n * A track is a logical segment of the timeline that has no tween of its own: it reports enter / leave / progress events,\r\n * typically to drive non-GSAP rendering (e.g. Synthra 3D objects).\r\n *\r\n * Every callback receives `priority` and `skipped`:\r\n * - `priority` is `-Infinity` when the change happens during normal playback, meaning \"animate\" (follow the progress).\r\n * Otherwise it is the scroll position (px) of the crossed boundary, negated when scrolling up, so that the highest\r\n * value (the last boundary crossed in the scroll direction) wins when several changes target the same object in one frame.\r\n * - `skipped` is `true` when the track was entered and left within a single update (e.g. a fast scroll jumped over it):\r\n * it still receives its enter, update (`0` or `1`) and leave callbacks, and consumers should apply the final state without animating.\r\n */\r\n export type TRACK_UNIVERSAL_VARS =\r\n {\r\n /**\r\n * Debug name (default `\"Track\"`).\r\n */\r\n name?: string,\r\n /**\r\n * Timeline progress entered the track while scrolling down.\r\n */\r\n eEnter?: (priority: number, skipped: boolean) => void,\r\n /**\r\n * Timeline progress entered the track while scrolling up.\r\n */\r\n eEnterBack?: (priority: number, skipped: boolean) => void,\r\n /**\r\n * Timeline progress left the track by its end while scrolling down.\r\n */\r\n eLeave?: (priority: number, skipped: boolean) => void,\r\n /**\r\n * Timeline progress left the track by its start while scrolling up.\r\n */\r\n eLeaveBack?: (priority: number, skipped: boolean) => void,\r\n /**\r\n * Track progress changed (`0`–`1` within the track).\r\n */\r\n eUpdate?: (progress: number, priority: number, skipped: boolean) => void,\r\n /**\r\n * Called for every track by the timeline's `destroy()`.\r\n */\r\n eDestroy?: () => void\r\n }\r\n\r\n /**\r\n * Placement of a track on the timeline; same four forms and rules as {@link Timeline.ANIMATION_VARS}.\r\n */\r\n export type TRACK_VARS = Parser.Merge<TRACK_UNIVERSAL_VARS,\r\n {\r\n /**\r\n * 1-based fragment index returned by `addFragment`; `start` / `end` are then fractions of that fragment. `0` (default) = no fragment.\r\n */\r\n fragment?: number,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band, or of the fragment when `fragment` is set.\r\n */\r\n start: number,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band, or of the fragment when `fragment` is set.\r\n */\r\n end : number,\r\n overflowStart?: never,\r\n overflowEnd ?: never\r\n }> |\r\n Parser.Merge<TRACK_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n start ?: never,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band.\r\n */\r\n end: number,\r\n /**\r\n * How far the track reaches back into the start overflow, as a fraction of it: `1` starts at the very beginning of the overflow, `0` at the start of the main band.\r\n */\r\n overflowStart: number,\r\n overflowEnd ?: never\r\n }> |\r\n Parser.Merge<TRACK_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band.\r\n */\r\n start : number,\r\n end ?: never,\r\n overflowStart?: never,\r\n /**\r\n * How far the track reaches into the end overflow, as a fraction of it: `1` ends at the very end of the overflow, `0` at the end of the main band.\r\n */\r\n overflowEnd: number\r\n }> |\r\n Parser.Merge<TRACK_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n start ?: never,\r\n end ?: never,\r\n /**\r\n * How far the track reaches back into the start overflow, as a fraction of it: `1` starts at the very beginning of the overflow, `0` at the start of the main band.\r\n */\r\n overflowStart: number,\r\n /**\r\n * How far the track reaches into the end overflow, as a fraction of it: `1` ends at the very end of the overflow, `0` at the end of the main band.\r\n */\r\n overflowEnd: number\r\n }>\r\n\r\n /**\r\n * Track record stored by `addTrack`, with its position resolved on the whole timeline (`0`–`1`, overflows included).\r\n * @internal\r\n */\r\n export type TRACK = Parser.Merge<Required<TRACK_VARS>,\r\n {\r\n /**\r\n * Start on the whole timeline (overflows included), in `[0, 1]`.\r\n */\r\n finalStart: number,\r\n /**\r\n * End on the whole timeline (overflows included), in `[0, 1]`.\r\n */\r\n finalEnd: number,\r\n /**\r\n * `finalEnd - finalStart`, clamped to `≥ 0`.\r\n */\r\n duration: number,\r\n /**\r\n * Last progress sent to `eUpdate` (`-1` until the first update).\r\n */\r\n progress: number\r\n }>\r\n\r\n /**\r\n * Options of `addFragment`.\r\n */\r\n export type FRAGMENT_VARS =\r\n {\r\n /**\r\n * Relative weight of the fragment: the main band is shared between fragments in proportion to their `flex` (must be `> 0`).\r\n */\r\n flex: number\r\n }\r\n\r\n /**\r\n * Fragment record: a flexible portion of the main band (overflows excluded). Fragments are laid out one after another\r\n * from the start of the main band, each sized by its share of the total `flex`.\r\n * @internal\r\n */\r\n export type FRAGMENT = Parser.Merge<Required<FRAGMENT_VARS>,\r\n {\r\n /**\r\n * Start of the fragment on the whole timeline (overflows included), in `[0, 1]`.\r\n */\r\n finalStart: number,\r\n /**\r\n * End of the fragment on the whole timeline (overflows included), in `[0, 1]`.\r\n */\r\n finalEnd: number,\r\n /**\r\n * `finalEnd - finalStart`.\r\n */\r\n duration: number,\r\n /**\r\n * Animations assigned to this fragment.\r\n */\r\n animations: ANIMATION[],\r\n /**\r\n * Tracks assigned to this fragment.\r\n */\r\n tracks: TRACK[]\r\n }>\r\n}\r\n\r\n// #CONSTANTS\r\n\r\n // ##SYMBOLS\r\nconst evaluateTrack = Symbol('evaluateTrack')\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Scroll-driven GSAP timeline backed by a single ScrollTrigger, whose progress (`0`–`1`) is laid out as:\r\n * an optional start overflow, the main band, and an optional end overflow (see {@link Timeline.CONFIG}).\r\n * The main band can be divided into fragments: flexible portions sized by a `flex` weight (see `addFragment`).\r\n *\r\n * Two kinds of content can be placed on it, with positions given as fractions of the main band, of a fragment or of an overflow:\r\n * - animations (`addAnimation`): GSAP tweens whose duration and stagger are derived from their placement;\r\n * - tracks (`addTrack`): logical segments without a tween that report enter / leave / progress events\r\n * (see {@link Timeline.TRACK_UNIVERSAL_VARS}), e.g. to drive 3D objects.\r\n *\r\n * Positions are recomputed on every ScrollTrigger refresh. When constructed inside an `Up.Anime.sub` callback, the timeline\r\n * pushes its `destroy` on the workspace's cleaning stack (the list of destructors run by `Up.Anime.unsub`).\r\n * @note Requires `'ScrollTrigger'` in the Anime config (`plugins: ['ScrollTrigger']`).\r\n * @note Get the class from the Anime bucket (`bucket.Timeline`): it is only usable once Anime has loaded GSAP.\r\n * @example\r\n * ```ts\r\n * Up.Anime.sub(KEY, (bucket: AnimeBucket): void =>\r\n * {\r\n * const TIMELINE = new bucket.Timeline(\r\n * {\r\n * trigger : '.story',\r\n * scrub : true,\r\n * getOverflowStart: (): number => Up.App.lh\r\n * })\r\n *\r\n * const INTRO = TIMELINE.addFragment({ flex: 1 })\r\n * const OUTRO = TIMELINE.addFragment({ flex: 2 })\r\n *\r\n * TIMELINE.addAnimation('F', '.story__title', { autoAlpha: 0, end: 0, overflowStart: 1 })\r\n * ('T', document.querySelectorAll('.story__item'), { x: 100, fragment: INTRO, start: 0, end: 1, stagger: 0.1 })\r\n *\r\n * TIMELINE.addTrack({ fragment: OUTRO, start: 0, end: 1, eUpdate: (progress: number): void => console.log(progress) })\r\n * })\r\n * ```\r\n*/\r\nclass Timeline\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n static #DEFAULT_NAME = 'Timeline'\r\n static #DEFAULT_ANIMATION_NAME = 'Animation'\r\n static #DEFAULT_TRACK_NAME = 'Track'\r\n\r\n /**\r\n * Anime bucket shared by the Anime plugin once GSAP is loaded; includes `ScrollTrigger` when it is in the Anime config.\r\n * @internal\r\n */\r\n static [BUCKET]: AnimeBucket & { ScrollTrigger?: typeof ScrollTrigger }\r\n\r\n // ##PRIVATES\r\n #INTERVAL = new Trees.Interval<Timeline.TRACK>()\r\n\r\n #name = Timeline.#DEFAULT_NAME\r\n\r\n #rise = false\r\n #running = false\r\n\r\n #start = 0\r\n #end = 0\r\n #progressionTrackHeight = 0\r\n #heightRatio = 0\r\n #overflowStartRatio = 0\r\n #overflowEndRatio = 0\r\n #progress = 0\r\n #fragmentTotalFlex = 0\r\n\r\n #timeline: gsap.core.Timeline | null = null\r\n #ctx : gsap.Context | null = null\r\n\r\n #fragments : Timeline.FRAGMENT [] = [] // *Fragments allow you to divide the timeline (does not take overflows into account) into flexible portions (which extend across the entire timeline)\r\n #animations: Timeline.ANIMATION[] = []\r\n #pending : Timeline.ANIMATION[] = []\r\n #tracks : Timeline.TRACK [] = []\r\n #past : Timeline.TRACK [] = []\r\n\r\n #current = new Set<Timeline.TRACK>()\r\n #seen = new Set<Timeline.TRACK>()\r\n\r\n #updating : Promise<void> | null = null\r\n #updatingRes: (() => void) | null = null\r\n\r\n #getOverflowStart?: () => number\r\n #getOverflowEnd ?: () => number\r\n\r\n #eRefreshCallback: NonNullable<Timeline.CONFIG['eRefresh']> = Up.App.void\r\n #eUpdateCallback : NonNullable<Timeline.CONFIG['eUpdate']> = Up.App.void\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##CONSTRUCTOR\r\n /**\r\n * Creates a timeline and, inside a `sub` callback, registers `destroy` on the workspace's cleaning stack.\r\n * Without `config`, the timeline stays unconfigured until `set` is called; animations added meanwhile are queued.\r\n * @param config Optional configuration, applied with `set`.\r\n * @throws If `'ScrollTrigger'` is not in the Anime config.\r\n */\r\n constructor (config?: Timeline.CONFIG)\r\n {\r\n if (!Timeline[BUCKET].ScrollTrigger) Logs.throw('TIMELINE', '\"ScrollTrigger\" (GSAP PLUGIN) IS REQUIRED TO USE THIS CLASS (ADD \"ScrollTrigger\" TO THE \"Anime\" CONFIGURATION).')\r\n\r\n this.#setBindings()\r\n \r\n if (config) this.set(config)\r\n\r\n Timeline[BUCKET].workspace.cleaningStack?.push(this.destroy.bind(this))\r\n }\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n /**\r\n * Debug name of the timeline (`config.name`, default `\"Timeline\"`).\r\n */\r\n get name(): string { return this.#name }\r\n\r\n /**\r\n * Timeline progress in `[0, 1]`, as of the last ScrollTrigger update.\r\n */\r\n get progress(): number { return this.#progress }\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n #setBindings(): void\r\n {\r\n this.addAnimation = this.addAnimation.bind(this)\r\n this.addTrack = this.addTrack.bind(this)\r\n this.addFragment = this.addFragment.bind(this)\r\n this[evaluateTrack] = this[evaluateTrack].bind(this)\r\n }\r\n\r\n #setVars(config: Timeline.CONFIG): void\r\n {\r\n const\r\n {\r\n name : NAME = Timeline.#DEFAULT_NAME,\r\n start: START = 0,\r\n end : END = 1,\r\n getOverflowStart,\r\n getOverflowEnd,\r\n eEnter,\r\n eEnterBack,\r\n eLeave,\r\n eLeaveBack,\r\n eRefresh = Up.App.void,\r\n eUpdate = Up.App.void,\r\n ...VARS\r\n } = config\r\n\r\n this.#name = NAME\r\n this.#ctx = Timeline[BUCKET].gsap.context((): void =>\r\n {\r\n (this.#timeline = Timeline[BUCKET].gsap.timeline(\r\n {\r\n duration : 1,\r\n scrollTrigger:\r\n {\r\n ...VARS,\r\n start: getOverflowStart\r\n ? (): string => `${START * 100}%-=${getOverflowStart()} 0`\r\n : (): string => `${START * 100}% 0`,\r\n end: getOverflowEnd\r\n ? (): string => `${END * 100}%+=${getOverflowEnd()} ${Up.App.lh}`\r\n : (): string => `${END * 100}% ${Up.App.lh}`,\r\n onEnter : eEnter,\r\n onEnterBack: eEnterBack,\r\n onLeave : eLeave,\r\n onLeaveBack: eLeaveBack,\r\n onRefresh : this.#eRefresh.bind(this),\r\n onUpdate : this.#eUpdate.bind(this, false)\r\n }\r\n }))\r\n .to(this, { duration: 1 }, 0)\r\n })\r\n this.#updating = new Promise<void>((res): void => { this.#updatingRes = res })\r\n this.#getOverflowStart = getOverflowStart\r\n this.#getOverflowEnd = getOverflowEnd\r\n this.#eRefreshCallback = eRefresh\r\n this.#eUpdateCallback = eUpdate\r\n }\r\n\r\n #setTask(): void { Up.Thread.sub(this.#t$UpdateFragments) }\r\n\r\n /**\r\n * Configures the timeline: creates the GSAP timeline and its ScrollTrigger, then adds the queued animations.\r\n * Logs a warning and does nothing if the timeline is already configured.\r\n * @note The trigger should be taller than the viewport (`100lvh`), otherwise the scroll range is empty or inverted.\r\n * @param config ScrollTrigger vars plus Upwwwards options (see {@link Timeline.CONFIG}).\r\n */\r\n set(config: Timeline.CONFIG): void\r\n {\r\n if (this.#timeline) return Logs.warn('TIMELINE', 'THE TIMELINE HAS ALREADY BEEN CONFIGURED.')\r\n\r\n this.#setVars(config)\r\n this.#flush()\r\n }\r\n\r\n // ##GET\r\n static #getTargetData(target: gsap.TweenTarget): [target: gsap.TweenTarget, length: number]\r\n {\r\n switch (true)\r\n {\r\n case !target : return [null, 0]\r\n case target instanceof NodeList: target = [...target]\r\n case Array.isArray(target) :\r\n {\r\n const\r\n TARGETS = (target as gsap.TweenTarget[]).filter((t): gsap.TweenTarget => t),\r\n LENGTH = TARGETS.length\r\n\r\n return [LENGTH === 0 ? null : LENGTH === 1 ? TARGETS[0] : TARGETS, LENGTH]\r\n }\r\n default: return [target, 1]\r\n }\r\n }\r\n\r\n static #getDuration(finalStart: number, finalEnd: number): number { return Math.max(finalEnd - finalStart, 0) }\r\n\r\n static #getAnimationVars(animation: Timeline.ANIMATION, duration: number, finalStagger?: number): gsap.TweenVars\r\n {\r\n return {\r\n ...animation.vars[animation.vars.length - 1],\r\n stagger : finalStagger,\r\n duration: finalStagger\r\n ? Math.max(duration - finalStagger * (animation.length - 1), 0) // *Duration per target\r\n : duration\r\n }\r\n }\r\n\r\n #getFragment(fragment: number): Timeline.FRAGMENT { return this.#fragments[fragment - 1] ?? Logs.throw('TIMELINE', `FRAGMENT \"${fragment}\" DOES NOT EXIST.`) }\r\n\r\n #getAnimationClipRatio(animation: Timeline.ANIMATION): number\r\n {\r\n /*\r\n *By default, percentage values are relative to the main portion of the timeline (excluding overflows).\r\n *Certain values, such as \"stagger\" or \"itemDuration\" are not limited to the main portion of the timeline but also include the animation's overflow.\r\n */\r\n\r\n return 1 - this.#overflowStartRatio * (1 - animation.overflowStart) - this.#overflowEndRatio * (1 - animation.overflowEnd)\r\n }\r\n\r\n #getFinalStart(start: number, overflow: number, fragment: number): number\r\n {\r\n /*\r\n *Get the \"finalStart\" in percentage [0; 1] relative to the total \"timeline\" or a \"fragment\".\r\n ?\"Overflow\" is ignored in the case of belonging to a \"fragment\".\r\n */\r\n \r\n if (fragment)\r\n {\r\n const FRAGMENT = this.#getFragment(fragment)\r\n\r\n return FRAGMENT.finalStart + FRAGMENT.duration * start\r\n }\r\n \r\n return this.#heightRatio * start + this.#overflowStartRatio * (1 - overflow)\r\n }\r\n\r\n #getFinalEnd(end: number, overflow: number, fragment: number): number\r\n {\r\n /*\r\n *Get the \"finalEnd\" in percentage [0; 1] relative to the total \"timeline\" or a \"fragment\".\r\n ?\"Overflow\" is ignored in the case of belonging to a \"fragment\".\r\n */\r\n\r\n if (fragment)\r\n {\r\n const FRAGMENT = this.#getFragment(fragment)\r\n\r\n return FRAGMENT.finalStart + FRAGMENT.duration * end\r\n }\r\n \r\n return this.#overflowStartRatio + this.#heightRatio * end + this.#overflowEndRatio * overflow\r\n }\r\n\r\n #getFinalStagger(animation: Timeline.ANIMATION, duration: number): number | undefined\r\n {\r\n /*\r\n *If \"itemDuration\" is present, then the \"stagger\" is calculated.\r\n *\"Stagger\" is relative to the duration of the \"timeline\" or \"fragment\".\r\n */\r\n\r\n if (animation.length > 1) return animation.itemDuration\r\n ? Math.max(duration - (animation.fragment ? this.#getFragment(animation.fragment).duration : this.#getAnimationClipRatio(animation)) * animation.itemDuration, 0) / (animation.length - 1)\r\n : animation.stagger\r\n ? animation.fragment\r\n ? this.#getFragment(animation.fragment).duration * animation.stagger\r\n : this.#getAnimationClipRatio(animation) * animation.stagger\r\n : undefined\r\n }\r\n\r\n #getPriority(boundary: number): number\r\n {\r\n /*\r\n *The \"boundary\" corresponds to \"finalStart\" for the \"eEnter\" and \"eLeaveBack\" events, and corresponds to \"finalEnd\" for the \"eEnterBack\" and \"eLeave\" events.\r\n *For the \"eUpdate\" event, use \"finalEnd\" when \"rise\" is \"true\", otherwise, use \"finalStart\".\r\n */\r\n\r\n return this.#start + this.#progressionTrackHeight * boundary // *Adding \"start\" creates a common starting point for all timelines.\r\n }\r\n\r\n /**\r\n * Returns the scroll position at which the timeline reaches a given point of its main band.\r\n * @note Valid after the first ScrollTrigger refresh; returns `0` before.\r\n * @param point Fraction (`0`–`1`) of the main band (overflows and fragments are not taken into account).\r\n * @returns Scroll position in pixels.\r\n */\r\n getTop(point: number): number { return this.#start + this.#progressionTrackHeight * this.#getFinalStart(point, 0, 0) }\r\n\r\n // ##ADD\r\n #addAnimation(animation: Timeline.ANIMATION): void\r\n {\r\n if (this.#timeline)\r\n {\r\n this.#updateAnimation(animation)\r\n\r\n this.#animations.push(animation)\r\n\r\n if (animation.fragment) this.#getFragment(animation.fragment).animations.push(animation)\r\n }\r\n else this.#pending.push(animation)\r\n }\r\n\r\n #addTrack(track: Timeline.TRACK): void\r\n {\r\n this.#INTERVAL.add(track, track.finalStart, track.finalEnd)\r\n\r\n this.#tracks.push(track)\r\n \r\n if (track.fragment) this.#getFragment(track.fragment).tracks.push(track)\r\n }\r\n\r\n #addPast(track: Timeline.TRACK): void\r\n {\r\n /*\r\n *If the scroll is very fast (> 100 lvh), then it is possible that some tracks will be skipped.\r\n *In this case, they are added to \"current\".\r\n *They will then be notified by one of the \"eLeave\" or \"eLeaveBack\" events and updated to a position (0 or 1).\r\n */\r\n\r\n const KEY = this.#rise ? 'finalEnd' : 'finalStart'\r\n \r\n let i = this.#past.length - 1\r\n\r\n while (i > -1)\r\n if (this.#past[i][KEY] < track[KEY]) break\r\n else i--\r\n\r\n this.#past.splice(i + 1, 0, track)\r\n }\r\n\r\n /**\r\n * Appends a fragment: a flexible portion of the main band (overflows excluded) sized by its share of the total `flex`.\r\n * Fragment bounds, and the animations and tracks placed in fragments, are recomputed on the next Thread frame.\r\n * @param vars Fragment options.\r\n * @returns 1-based fragment index, to pass as `fragment` to `addAnimation` / `addTrack`.\r\n * @throws If `vars.flex` is `≤ 0`.\r\n */\r\n addFragment(vars: Timeline.FRAGMENT_VARS): number\r\n {\r\n if (vars.flex <= 0) Logs.throw('TIMELINE', 'THE \"flex\" PROPERTY CANNOT BE LESS THAN OR EQUAL TO \"0\".')\r\n\r\n this.#fragmentTotalFlex += vars.flex\r\n\r\n const NUMBER = this.#fragments.push(\r\n {\r\n flex : vars.flex,\r\n finalStart: 0,\r\n finalEnd : 0,\r\n duration : 0,\r\n animations: [],\r\n tracks : []\r\n })\r\n\r\n this.#setTask()\r\n\r\n return NUMBER\r\n }\r\n\r\n /**\r\n * Adds a GSAP tween placed on the timeline; its duration (and stagger) is derived from the placement.\r\n * If the timeline is not configured yet, the animation is queued until `set`.\r\n * Out-of-range placement values are clamped to `[0, 1]`. Logs a warning and adds nothing when `target` resolves to no element.\r\n * @template T Tween kind: `'F'`, `'T'` or `'F/T'`.\r\n * @param type Tween kind (see {@link Timeline.ANIMATION_TYPE}).\r\n * @param target GSAP tween target(s); empty entries of arrays / `NodeList`s are ignored.\r\n * @param vars For `'F/T'`: the `from` vars, then the `to` vars with the placement (see {@link Timeline.ANIMATION_VARS});\r\n * otherwise a single object with tween vars and placement.\r\n * @returns The bound `addAnimation` method, so calls can be chained: `timeline.addAnimation(…)(…)`.\r\n * @throws If `fragment` refers to a fragment that does not exist (checked once the timeline is configured).\r\n */\r\n addAnimation<T extends Timeline.ANIMATION_TYPE>(type: T, target: gsap.TweenTarget, ...vars: T extends 'F/T' ? [Timeline.ANIMATION_UNIVERSAL_VARS, Timeline.ANIMATION_VARS] : [Timeline.ANIMATION_VARS]): Timeline['addAnimation']\r\n {\r\n const [TARGET, LENGTH] = Timeline.#getTargetData(target)\r\n\r\n if (LENGTH)\r\n {\r\n const\r\n {\r\n name : NAME = Timeline.#DEFAULT_ANIMATION_NAME,\r\n start : START = 0,\r\n end : END = 1,\r\n overflowStart: OVERFLOW_START = 0,\r\n overflowEnd : OVERFLOW_END = 0,\r\n fragment : FRAGMENT = 0,\r\n stagger : STAGGER,\r\n itemDuration : ITEM_DURATION,\r\n ...VARS\r\n } = vars.pop() as Timeline.ANIMATION_VARS\r\n\r\n this.#addAnimation(\r\n {\r\n name : NAME, \r\n type,\r\n target : TARGET,\r\n length : LENGTH,\r\n fragment : Math.max(FRAGMENT, 0),\r\n start : Maths.range(START, 0, 1),\r\n end : Maths.range(END, 0, 1),\r\n overflowStart: Maths.range(OVERFLOW_START, 0, 1),\r\n overflowEnd : Maths.range(OVERFLOW_END, 0, 1),\r\n stagger : STAGGER,\r\n itemDuration : ITEM_DURATION,\r\n vars : [...vars as [] | [Timeline.ANIMATION_UNIVERSAL_VARS], VARS]\r\n })\r\n }\r\n else Logs.warn('TIMELINE', 'NO TARGET.')\r\n\r\n return this.addAnimation\r\n }\r\n\r\n /**\r\n * Adds a track: a logical segment of the timeline, without a tween, that reports enter / leave / progress events\r\n * (see {@link Timeline.TRACK_UNIVERSAL_VARS} for the `priority` and `skipped` arguments).\r\n * Out-of-range placement values are clamped to `[0, 1]`.\r\n * @param vars Placement and callbacks.\r\n * @returns The bound `addTrack` method, so calls can be chained: `timeline.addTrack(…)(…)`.\r\n * @throws If `fragment` refers to a fragment that does not exist.\r\n */\r\n addTrack(vars: Timeline.TRACK_VARS): Timeline['addTrack']\r\n {\r\n const\r\n FRAGMENT = vars.fragment ?? 0,\r\n START = vars.start == null ? 0 : Maths.range(vars.start, 0, 1),\r\n END = vars.end == null ? 1 : Maths.range(vars.end, 0, 1),\r\n OVERFLOW_START = vars.overflowStart == null ? 0 : Maths.range(vars.overflowStart, 0, 1),\r\n OVERFLOW_END = vars.overflowEnd == null ? 0 : Maths.range(vars.overflowEnd, 0, 1),\r\n FINAL_START = this.#getFinalStart(START, OVERFLOW_START, FRAGMENT),\r\n FINAL_END = this.#getFinalEnd(END, OVERFLOW_END, FRAGMENT)\r\n \r\n this.#addTrack(\r\n {\r\n name : vars.name ?? Timeline.#DEFAULT_TRACK_NAME,\r\n finalStart : FINAL_START,\r\n finalEnd : FINAL_END,\r\n duration : Timeline.#getDuration(FINAL_START, FINAL_END),\r\n progress : -1, // *initialize to -1 to enable calling the \"eUpdate\" callback in \"clearSkipped\"\r\n fragment : FRAGMENT,\r\n start : START,\r\n end : END,\r\n overflowStart: OVERFLOW_START,\r\n overflowEnd : OVERFLOW_END,\r\n eEnter : vars.eEnter ?? Up.App.void,\r\n eEnterBack : vars.eEnterBack ?? Up.App.void,\r\n eLeave : vars.eLeave ?? Up.App.void,\r\n eLeaveBack : vars.eLeaveBack ?? Up.App.void,\r\n eUpdate : vars.eUpdate ?? Up.App.void,\r\n eDestroy : vars.eDestroy ?? Up.App.void\r\n })\r\n\r\n return this.addTrack\r\n }\r\n\r\n // ##UPDATES\r\n #updateVars(): void\r\n {\r\n const\r\n SCROLL_TRIGGER = this.#timeline!.scrollTrigger,\r\n PROGRESSION_TRACK_HEIGHT = SCROLL_TRIGGER && (this.#end = SCROLL_TRIGGER.end) - (this.#start = SCROLL_TRIGGER.start)\r\n\r\n if (PROGRESSION_TRACK_HEIGHT)\r\n {\r\n // TODO: It's a bad idea to separate the end and start points for the trigger (this causes a delay in the calculations and leads to problems when the element is less than 100 lvh in height)\r\n const\r\n OVERFLOW_START = this.#getOverflowStart ? Math.max(this.#getOverflowStart(), 0) : 0,\r\n OVERFLOW_END = this.#getOverflowEnd ? Math.max(this.#getOverflowEnd(), 0) : 0,\r\n FIX_RATIO = Math.min(PROGRESSION_TRACK_HEIGHT / Math.max(OVERFLOW_START + OVERFLOW_END, 1), 1)\r\n\r\n this.#progressionTrackHeight = PROGRESSION_TRACK_HEIGHT\r\n this.#heightRatio = Math.max(PROGRESSION_TRACK_HEIGHT - OVERFLOW_START - OVERFLOW_END, 0) / PROGRESSION_TRACK_HEIGHT\r\n this.#overflowStartRatio = OVERFLOW_START / PROGRESSION_TRACK_HEIGHT * FIX_RATIO\r\n this.#overflowEndRatio = OVERFLOW_END / PROGRESSION_TRACK_HEIGHT * FIX_RATIO\r\n }\r\n else this.#progressionTrackHeight = this.#heightRatio = this.#overflowStartRatio = this.#overflowEndRatio = 0\r\n }\r\n\r\n #updateFragments(deep: boolean): void\r\n {\r\n for (let i = 0, iMax = this.#fragments.length, prevEnd = this.#overflowStartRatio; i < iMax; i++)\r\n {\r\n const\r\n FRAGMENT = this.#fragments[i],\r\n DURATION = FRAGMENT.flex / this.#fragmentTotalFlex * this.#heightRatio\r\n\r\n FRAGMENT.finalStart = prevEnd\r\n FRAGMENT.finalEnd = prevEnd += DURATION\r\n FRAGMENT.duration = DURATION\r\n\r\n if (!deep) continue\r\n\r\n const\r\n ANIMATIONS = FRAGMENT.animations,\r\n TRACKS = FRAGMENT.tracks\r\n\r\n for (let j = 0, jMax = ANIMATIONS.length; j < jMax; j++) this.#updateAnimation(ANIMATIONS[j])\r\n\r\n for (let j = 0, jMax = TRACKS.length; j < jMax; j++)\r\n {\r\n const TRACK = TRACKS[j]\r\n\r\n this.#INTERVAL.remove(TRACK) // TODO: ça serait peut-être mieux de vider et recréer l'arbre\r\n \r\n this.#updateTrack(TRACK)\r\n }\r\n }\r\n }\r\n\r\n #updateAnimation(animation: Timeline.ANIMATION): void\r\n {\r\n const\r\n FINAL_START = this.#getFinalStart(animation.start, animation.overflowStart, animation.fragment),\r\n FINAL_END = this.#getFinalEnd(animation.end, animation.overflowEnd, animation.fragment),\r\n DURATION = Timeline.#getDuration(FINAL_START, FINAL_END),\r\n FINAL_STAGGER = this.#getFinalStagger(animation, DURATION),\r\n TWEEN = animation.tween\r\n\r\n switch (true)\r\n {\r\n case !!TWEEN:\r\n {\r\n this.#timeline!.remove(TWEEN)\r\n\r\n if (TWEEN.vars.duration === DURATION && TWEEN.vars.stagger === FINAL_STAGGER)\r\n {\r\n TWEEN.invalidate()\r\n \r\n break\r\n }\r\n\r\n TWEEN.kill()\r\n }\r\n default: this.#ctx!.add((): void =>\r\n {\r\n animation.tween = animation.type === 'F/T'\r\n ? Timeline[BUCKET].gsap.fromTo(animation.target, animation.vars[0], Timeline.#getAnimationVars(animation, DURATION, FINAL_STAGGER))\r\n : Timeline[BUCKET].gsap[animation.type === 'F' ? 'from' : 'to'](animation.target, Timeline.#getAnimationVars(animation, DURATION, FINAL_STAGGER))\r\n })\r\n }\r\n\r\n this.#timeline!.add(animation.tween!, FINAL_START)\r\n }\r\n\r\n #updateAnimations(): void { for (let i = 0, max = this.#animations.length; i < max; i++) this.#updateAnimation(this.#animations[i]) }\r\n\r\n #updateTrack(track: Timeline.TRACK): void\r\n {\r\n track.duration = Timeline.#getDuration(\r\n track.finalStart = this.#getFinalStart(track.start, track.overflowStart, track.fragment),\r\n track.finalEnd = this.#getFinalEnd(track.end, track.overflowEnd, track.fragment)\r\n )\r\n\r\n this.#INTERVAL.add(track, track.finalStart, track.finalEnd)\r\n }\r\n\r\n #updateTracks(): void\r\n {\r\n this.#INTERVAL.clear()\r\n \r\n for (let i = 0, max = this.#tracks.length; i < max; i++)\r\n {\r\n const TRACK = this.#tracks[i]\r\n\r\n this.#updateTrack(TRACK)\r\n }\r\n }\r\n\r\n /**\r\n * Re-evaluates every track from progress `0` to the current progress, e.g. to sync tracks with a page that is already\r\n * scrolled past the timeline start. Waits for pending fragment updates and for the first ScrollTrigger refresh.\r\n * Does nothing if the current scroll position (`Up.App.y`) is before the timeline start.\r\n * Logs a warning and returns if the timeline is not configured.\r\n * @returns Resolves once the update has run or been skipped.\r\n */\r\n async update(): Promise<void>\r\n {\r\n if (!this.#timeline) return Logs.warn('TIMELINE', 'SET THE TIMELINE BEFORE THE UPDATE!')\r\n\r\n await Up.Thread.wait(this.#t$UpdateFragments) // *Wait for any tasks to be resolved\r\n await this.#updating\r\n\r\n if (this.#timeline.scrollTrigger!.start > Up.App.y) return\r\n\r\n this.#eUpdate(true)\r\n }\r\n\r\n // ##DESTROY\r\n #destroyTracks(): void { for (let i = 0, max = this.#tracks.length; i < max; i++) this.#tracks[i].eDestroy() }\r\n\r\n #destroyVars(): void\r\n {\r\n this.#INTERVAL.clear()\r\n\r\n this.#fragmentTotalFlex = 0\r\n \r\n if (this.#fragments .length) this.#fragments = []\r\n if (this.#animations.length) this.#animations = []\r\n if (this.#pending .length) this.#pending = []\r\n if (this.#tracks .length) this.#tracks = []\r\n\r\n if (this.#current.size) this.#current.clear()\r\n if (this.#seen .size) this.#seen .clear()\r\n \r\n if (this.#ctx)\r\n {\r\n this.#ctx.revert()\r\n \r\n this.#ctx = null\r\n }\r\n\r\n if (this.#timeline) this.#timeline = null\r\n }\r\n\r\n /**\r\n * Calls every track's `eDestroy`, reverts the GSAP timeline, tweens and ScrollTrigger, and removes all fragments, animations and tracks.\r\n * The timeline becomes unconfigured: `set` can be called again.\r\n * Called automatically by `Up.Anime.unsub` when the timeline was constructed inside a `sub` callback.\r\n */\r\n destroy(): void\r\n {\r\n this.#resUpdate()\r\n this.#destroyTracks()\r\n this.#destroyVars()\r\n }\r\n\r\n // ##EVENTS\r\n #eRefresh(): void\r\n {\r\n this.#updateVars()\r\n this.#updateFragments(false) // *Update before animations and tracks (important)\r\n this.#updateAnimations()\r\n this.#updateTracks()\r\n this.#resUpdate()\r\n }\r\n\r\n #eUpdate(force = false): void\r\n {\r\n if (this.#seen.size) this.#seen.clear()\r\n \r\n const PREV = force ? 0 /* *Extend the range to 0, \"rise\" will be equal to \"true\" only if the timeline is not at 0 */ : this.#progress\r\n\r\n this.#progress = this.#timeline!.progress()\r\n\r\n if (!force && this.#progress === PREV) return\r\n \r\n this.#running = this.#progress > 0 && this.#progress < 1\r\n\r\n this.#INTERVAL.each(...((this.#rise = this.#progress > PREV)\r\n ? [PREV, this.#progress] as const\r\n : [this.#progress, PREV] as const\r\n ),\r\n this[evaluateTrack])\r\n \r\n this.#clear()\r\n this.#swap()\r\n this.#eUpdateCallback(this.#progress)\r\n }\r\n\r\n // ##TASKS\r\n #t$UpdateFragments = this.#updateFragments.bind(this, true)\r\n\r\n // ##UTILS\r\n #resUpdate(): void\r\n {\r\n this.#updatingRes?.()\r\n \r\n this.#updating &&= null\r\n }\r\n\r\n #flush(): void { for (let i = this.#pending.length - 1; i > -1; i--) this.#addAnimation(this.#pending.splice(i, 1)[0]) }\r\n\r\n #clear(): void\r\n {\r\n this.#clearPast()\r\n this.#clearCurrent()\r\n }\r\n\r\n #clearPast(): void\r\n {\r\n const LENGTH = this.#past.length\r\n\r\n if (!LENGTH) return\r\n\r\n if (this.#rise) for (let i = 0; i < LENGTH; i++)\r\n {\r\n const\r\n TRACK = this.#past[i],\r\n SKIPPED = !this.#current.delete(TRACK),\r\n PRIORITY = this.#getPriority(TRACK.finalEnd)\r\n\r\n if (SKIPPED) TRACK.eEnter(this.#getPriority(TRACK.finalStart), SKIPPED)\r\n \r\n TRACK.eUpdate(TRACK.progress = 1, PRIORITY, SKIPPED)\r\n TRACK.eLeave(PRIORITY, SKIPPED)\r\n }\r\n else for (let i = LENGTH - 1; i > -1; i--)\r\n {\r\n const\r\n TRACK = this.#past[i],\r\n SKIPPED = !this.#current.delete(TRACK),\r\n PRIORITY = -this.#getPriority(TRACK.finalStart)\r\n\r\n if (SKIPPED) TRACK.eEnterBack(-this.#getPriority(TRACK.finalEnd), SKIPPED)\r\n \r\n TRACK.eUpdate(TRACK.progress = 0, PRIORITY, SKIPPED)\r\n TRACK.eLeaveBack(PRIORITY, SKIPPED)\r\n }\r\n\r\n this.#past = []\r\n }\r\n\r\n #clearCurrent(): void\r\n {\r\n if (!this.#current.size) return\r\n \r\n const [EVENT, PROGRESS] = this.#rise ? ['eLeave', 1] as const : ['eLeaveBack', 0] as const\r\n \r\n for (const TRACK of this.#current)\r\n {\r\n if (TRACK.progress !== PROGRESS) TRACK.eUpdate(TRACK.progress = PROGRESS, -Infinity, false)\r\n \r\n TRACK[EVENT](-Infinity, false)\r\n }\r\n }\r\n\r\n #swap(): void\r\n {\r\n const CURRENT = this.#current\r\n\r\n this.#current = this.#seen\r\n this.#seen = CURRENT\r\n }\r\n\r\n /**\r\n * Interval-tree visitor run on each progress change: fires the enter / update callbacks of a track overlapping the\r\n * scrolled range, or defers it to the past list when the progress is outside it (or the timeline is not playing).\r\n * @param track Track overlapping the scrolled range.\r\n * @internal\r\n */\r\n ;[evaluateTrack](track: Timeline.TRACK): void\r\n {\r\n if (track.finalStart > this.#progress || track.finalEnd < this.#progress) return this.#addPast(track)\r\n\r\n if (!this.#current.delete(track))\r\n {\r\n if (!this.#running) return this.#addPast(track)\r\n\r\n this.#rise ? track.eEnter(-Infinity, false) : track.eEnterBack(-Infinity, false)\r\n }\r\n\r\n if (this.#running) this.#seen.add(track) // *We only add items while the timeline is playing, because the Set \"current\" and \"seen\" are used to indicate which tracks are currently playing, if the timeline has finished, there is nothing left to play\r\n\r\n track.eUpdate(track.progress = Maths.range(track.duration && (this.#progress - track.finalStart) / track.duration, 0, 1), -Infinity, false)\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Timeline\r\n\r\nexport type { Timeline }"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/plugins/@anime/Timeline.ts"],"sourcesContent":["/* [Timeline] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SYMBOLS\r\nimport { BUCKET } from '../../symbols/index.js'\r\n\r\n // ##CORE\r\nimport Up from '../../core/Up.js'\r\n\r\n // ##SCRIPTS\r\nimport Maths from '../../scripts/Maths.js'\r\nimport Logs from '../../scripts/Logs.js'\r\nimport Trees from '../../scripts/Trees.js'\r\n\r\n // ##TYPES\r\nimport type ScrollTrigger from 'gsap/ScrollTrigger'\r\n\r\nimport type Parser from '../../scripts/Parser.js'\r\n\r\nimport type { AnimeBucket } from '../Anime.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Timeline\r\n{\r\n /**\r\n * Options of the constructor and `set`: GSAP `ScrollTrigger` vars (`trigger`, `scrub`, `pin`, …) plus Upwwwards options.\r\n * `start` / `end` are numbers here (fractions of the trigger height) and the native `onEnter` / `onEnterBack` / `onLeave` /\r\n * `onLeaveBack` / `onRefresh` / `onUpdate` callbacks are forbidden: use `eEnter` / `eEnterBack` / … instead.\r\n *\r\n * The scroll range runs from the moment the `start` point of the trigger reaches the top of the viewport until its `end` point\r\n * reaches the bottom of the viewport (`100lvh` from its top), extended by the optional overflows. The part between the overflows is the main band.\r\n * @note The trigger should be taller than the viewport (`100lvh`), otherwise the range is empty or inverted.\r\n */\r\n export type CONFIG = Parser.Merge<ScrollTrigger.Vars,\r\n {\r\n /**\r\n * Debug name (default `\"Timeline\"`).\r\n */\r\n name?: string,\r\n /**\r\n * Point of the trigger, as a fraction of its height (`0`–`1`, default `0`), that must reach the top of the viewport for the timeline to start.\r\n */\r\n start?: number,\r\n /**\r\n * Point of the trigger, as a fraction of its height (`0`–`1`, default `1`), that must reach the bottom of the viewport for the timeline to end.\r\n */\r\n end?: number,\r\n /**\r\n * Returns the length (px) of the start overflow: extra scroll distance added before the main band. Re-read on every refresh.\r\n */\r\n getOverflowStart?: () => number,\r\n /**\r\n * Returns the length (px) of the end overflow: extra scroll distance added after the main band. Re-read on every refresh.\r\n */\r\n getOverflowEnd?: () => number,\r\n /**\r\n * Passed to ScrollTrigger as `onEnter`: scrolling down into the range.\r\n */\r\n eEnter?: () => void,\r\n /**\r\n * Passed to ScrollTrigger as `onEnterBack`: scrolling up into the range.\r\n */\r\n eEnterBack?: () => void,\r\n /**\r\n * Passed to ScrollTrigger as `onLeave`: scrolling down past the range.\r\n */\r\n eLeave?: () => void,\r\n /**\r\n * Passed to ScrollTrigger as `onLeaveBack`: scrolling up past the start of the range.\r\n */\r\n eLeaveBack?: () => void,\r\n /**\r\n * Fires after each ScrollTrigger refresh, once positions, animations and tracks are recomputed\r\n * (and before any catch-up `eUpdate` when the scrub progress already differs from the last notified value).\r\n */\r\n eRefresh?: () => void,\r\n /**\r\n * Called with the timeline progress (`0`–`1`) whenever it changes, after the track callbacks.\r\n */\r\n eUpdate ?: (progress: number) => void,\r\n onEnter ?: never,\r\n onEnterBack?: never,\r\n onLeave ?: never,\r\n onLeaveBack?: never,\r\n onRefresh ?: never,\r\n onUpdate ?: never\r\n }>\r\n\r\n /**\r\n * Tween kind: `'F'` = `gsap.from`, `'T'` = `gsap.to`, `'F/T'` = `gsap.fromTo`.\r\n */\r\n export type ANIMATION_TYPE = 'F' | 'T' | 'F/T'\r\n\r\n /**\r\n * GSAP tween vars for a timeline animation. `duration` is forbidden: it is derived from the animation's placement.\r\n * `stagger` and `itemDuration` only apply when the target resolves to several elements (an array or a `NodeList`;\r\n * a selector string counts as one target) and are fractions of a reference span: the fragment when `fragment` is set,\r\n * otherwise the main band plus the overflow parts the animation extends into. The whole staggered sequence still fits between its start and end.\r\n */\r\n export type ANIMATION_UNIVERSAL_VARS = Parser.Merge<gsap.TweenVars,\r\n {\r\n /**\r\n * Debug name (default `\"Animation\"`).\r\n */\r\n name?: string,\r\n /**\r\n * Delay between two consecutive targets, as a fraction of the reference span. Ignored when `itemDuration` is set.\r\n */\r\n stagger?: number,\r\n /**\r\n * Duration of each target, as a fraction of the reference span; the stagger is then computed so the sequence fills the animation. Takes precedence over `stagger`.\r\n */\r\n itemDuration?: number,\r\n duration ?: never\r\n }>\r\n\r\n /**\r\n * Placement of an animation on the timeline, in one of four forms:\r\n * `start` + `end` on the main band (or inside a fragment); `overflowStart` + `end`; `start` + `overflowEnd`; or `overflowStart` + `overflowEnd`.\r\n * Main-band values are fractions of the main band; overflow values are fractions of the corresponding overflow.\r\n */\r\n export type ANIMATION_VARS = Parser.Merge<ANIMATION_UNIVERSAL_VARS,\r\n {\r\n /**\r\n * 1-based fragment index returned by `addFragment`; `start` / `end` are then fractions of that fragment. `0` (default) = no fragment.\r\n */\r\n fragment?: number,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band, or of the fragment when `fragment` is set.\r\n */\r\n start: number,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band, or of the fragment when `fragment` is set.\r\n */\r\n end : number,\r\n overflowStart?: never,\r\n overflowEnd ?: never\r\n }> |\r\n Parser.Merge<ANIMATION_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n start ?: never,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band.\r\n */\r\n end: number,\r\n /**\r\n * How far the animation reaches back into the start overflow, as a fraction of it: `1` starts at the very beginning of the overflow, `0` at the start of the main band.\r\n */\r\n overflowStart: number,\r\n overflowEnd ?: never\r\n }> |\r\n Parser.Merge<ANIMATION_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band.\r\n */\r\n start : number,\r\n end ?: never,\r\n overflowStart?: never,\r\n /**\r\n * How far the animation reaches into the end overflow, as a fraction of it: `1` ends at the very end of the overflow, `0` at the end of the main band.\r\n */\r\n overflowEnd: number\r\n }> |\r\n Parser.Merge<ANIMATION_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n start ?: never,\r\n end ?: never,\r\n /**\r\n * How far the animation reaches back into the start overflow, as a fraction of it: `1` starts at the very beginning of the overflow, `0` at the start of the main band.\r\n */\r\n overflowStart: number,\r\n /**\r\n * How far the animation reaches into the end overflow, as a fraction of it: `1` ends at the very end of the overflow, `0` at the end of the main band.\r\n */\r\n overflowEnd: number\r\n }>\r\n\r\n /**\r\n * Animation record stored by `addAnimation` (resolved and clamped values).\r\n * @internal\r\n */\r\n export type ANIMATION =\r\n {\r\n /**\r\n * Debug name.\r\n */\r\n name: string,\r\n /**\r\n * Tween kind (`'F'`, `'T'` or `'F/T'`).\r\n */\r\n type: ANIMATION_TYPE,\r\n /**\r\n * Resolved GSAP target(s): empty entries of arrays / `NodeList`s removed, a single element unwrapped.\r\n */\r\n target: gsap.TweenTarget,\r\n /**\r\n * Number of resolved targets (`1` for a non-array target such as a selector string).\r\n */\r\n length: number,\r\n /**\r\n * 1-based fragment index, or `0` when not in a fragment.\r\n */\r\n fragment: number,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band or fragment.\r\n */\r\n start: number,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band or fragment.\r\n */\r\n end: number,\r\n /**\r\n * Fraction (`0`–`1`) of the start overflow covered by the animation; `0` when unused.\r\n */\r\n overflowStart: number,\r\n /**\r\n * Fraction (`0`–`1`) of the end overflow covered by the animation; `0` when unused.\r\n */\r\n overflowEnd: number,\r\n /**\r\n * Stagger, as a fraction of the reference span (see {@link Timeline.ANIMATION_UNIVERSAL_VARS}).\r\n */\r\n stagger?: number,\r\n /**\r\n * Per-target duration, as a fraction of the reference span; takes precedence over `stagger`.\r\n */\r\n itemDuration?: number,\r\n /**\r\n * Tween vars without placement keys: `[vars]` for `'F'` / `'T'`, `[fromVars, toVars]` for `'F/T'`.\r\n */\r\n vars: [ANIMATION_UNIVERSAL_VARS] | [ANIMATION_UNIVERSAL_VARS, ANIMATION_UNIVERSAL_VARS],\r\n /**\r\n * GSAP tween on the timeline; created once the timeline is configured and rebuilt on refresh when its timing changes.\r\n */\r\n tween?: gsap.core.Tween\r\n }\r\n\r\n /**\r\n * Name and callbacks shared by every track placement.\r\n * A track is a logical segment of the timeline that has no tween of its own: it reports enter / leave / progress events,\r\n * typically to drive non-GSAP rendering (e.g. Synthra 3D objects).\r\n *\r\n * Every callback receives `priority` and `skipped`:\r\n * - `priority` is `-Infinity` when the change happens during normal playback, meaning \"animate\" (follow the progress).\r\n * Otherwise it is the scroll position (px) of the crossed boundary, negated when scrolling up, so that the highest\r\n * value (the last boundary crossed in the scroll direction) wins when several changes target the same object in one frame.\r\n * - `skipped` is `true` when the track was entered and left within a single update (e.g. a fast scroll jumped over it):\r\n * it still receives its enter, update (`0` or `1`) and leave callbacks, and consumers should apply the final state without animating.\r\n */\r\n export type TRACK_UNIVERSAL_VARS =\r\n {\r\n /**\r\n * Debug name (default `\"Track\"`).\r\n */\r\n name?: string,\r\n /**\r\n * Timeline progress entered the track while scrolling down.\r\n */\r\n eEnter?: (priority: number, skipped: boolean) => void,\r\n /**\r\n * Timeline progress entered the track while scrolling up.\r\n */\r\n eEnterBack?: (priority: number, skipped: boolean) => void,\r\n /**\r\n * Timeline progress left the track by its end while scrolling down.\r\n */\r\n eLeave?: (priority: number, skipped: boolean) => void,\r\n /**\r\n * Timeline progress left the track by its start while scrolling up.\r\n */\r\n eLeaveBack?: (priority: number, skipped: boolean) => void,\r\n /**\r\n * Track progress changed (`0`–`1` within the track).\r\n */\r\n eUpdate?: (progress: number, priority: number, skipped: boolean) => void,\r\n /**\r\n * Called for every track by the timeline's `destroy()`.\r\n */\r\n eDestroy?: () => void\r\n }\r\n\r\n /**\r\n * Placement of a track on the timeline; same four forms and rules as {@link Timeline.ANIMATION_VARS}.\r\n */\r\n export type TRACK_VARS = Parser.Merge<TRACK_UNIVERSAL_VARS,\r\n {\r\n /**\r\n * 1-based fragment index returned by `addFragment`; `start` / `end` are then fractions of that fragment. `0` (default) = no fragment.\r\n */\r\n fragment?: number,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band, or of the fragment when `fragment` is set.\r\n */\r\n start: number,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band, or of the fragment when `fragment` is set.\r\n */\r\n end : number,\r\n overflowStart?: never,\r\n overflowEnd ?: never\r\n }> |\r\n Parser.Merge<TRACK_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n start ?: never,\r\n /**\r\n * End, as a fraction (`0`–`1`) of the main band.\r\n */\r\n end: number,\r\n /**\r\n * How far the track reaches back into the start overflow, as a fraction of it: `1` starts at the very beginning of the overflow, `0` at the start of the main band.\r\n */\r\n overflowStart: number,\r\n overflowEnd ?: never\r\n }> |\r\n Parser.Merge<TRACK_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n /**\r\n * Start, as a fraction (`0`–`1`) of the main band.\r\n */\r\n start : number,\r\n end ?: never,\r\n overflowStart?: never,\r\n /**\r\n * How far the track reaches into the end overflow, as a fraction of it: `1` ends at the very end of the overflow, `0` at the end of the main band.\r\n */\r\n overflowEnd: number\r\n }> |\r\n Parser.Merge<TRACK_UNIVERSAL_VARS,\r\n {\r\n fragment?: never,\r\n start ?: never,\r\n end ?: never,\r\n /**\r\n * How far the track reaches back into the start overflow, as a fraction of it: `1` starts at the very beginning of the overflow, `0` at the start of the main band.\r\n */\r\n overflowStart: number,\r\n /**\r\n * How far the track reaches into the end overflow, as a fraction of it: `1` ends at the very end of the overflow, `0` at the end of the main band.\r\n */\r\n overflowEnd: number\r\n }>\r\n\r\n /**\r\n * Track record stored by `addTrack`, with its position resolved on the whole timeline (`0`–`1`, overflows included).\r\n * @internal\r\n */\r\n export type TRACK = Parser.Merge<Required<TRACK_VARS>,\r\n {\r\n /**\r\n * Start on the whole timeline (overflows included), in `[0, 1]`.\r\n */\r\n finalStart: number,\r\n /**\r\n * End on the whole timeline (overflows included), in `[0, 1]`.\r\n */\r\n finalEnd: number,\r\n /**\r\n * `finalEnd - finalStart`, clamped to `≥ 0`.\r\n */\r\n duration: number,\r\n /**\r\n * Last progress sent to `eUpdate` (`-1` until the first update).\r\n */\r\n progress: number\r\n }>\r\n\r\n /**\r\n * Options of `addFragment`.\r\n */\r\n export type FRAGMENT_VARS =\r\n {\r\n /**\r\n * Relative weight of the fragment: the main band is shared between fragments in proportion to their `flex` (must be `> 0`).\r\n */\r\n flex: number\r\n }\r\n\r\n /**\r\n * Fragment record: a flexible portion of the main band (overflows excluded). Fragments are laid out one after another\r\n * from the start of the main band, each sized by its share of the total `flex`.\r\n * @internal\r\n */\r\n export type FRAGMENT = Parser.Merge<Required<FRAGMENT_VARS>,\r\n {\r\n /**\r\n * Start of the fragment on the whole timeline (overflows included), in `[0, 1]`.\r\n */\r\n finalStart: number,\r\n /**\r\n * End of the fragment on the whole timeline (overflows included), in `[0, 1]`.\r\n */\r\n finalEnd: number,\r\n /**\r\n * `finalEnd - finalStart`.\r\n */\r\n duration: number,\r\n /**\r\n * Animations assigned to this fragment.\r\n */\r\n animations: ANIMATION[],\r\n /**\r\n * Tracks assigned to this fragment.\r\n */\r\n tracks: TRACK[]\r\n }>\r\n}\r\n\r\n// #CONSTANTS\r\n\r\n // ##SYMBOLS\r\nconst evaluateTrack = Symbol('evaluateTrack')\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Scroll-driven GSAP timeline backed by a single ScrollTrigger, whose progress (`0`–`1`) is laid out as:\r\n * an optional start overflow, the main band, and an optional end overflow (see {@link Timeline.CONFIG}).\r\n * The main band can be divided into fragments: flexible portions sized by a `flex` weight (see `addFragment`).\r\n *\r\n * Two kinds of content can be placed on it, with positions given as fractions of the main band, of a fragment or of an overflow:\r\n * - animations (`addAnimation`): GSAP tweens whose duration and stagger are derived from their placement;\r\n * - tracks (`addTrack`): logical segments without a tween that report enter / leave / progress events\r\n * (see {@link Timeline.TRACK_UNIVERSAL_VARS}), e.g. to drive 3D objects.\r\n *\r\n * Positions are recomputed on every ScrollTrigger refresh. When constructed inside an `Up.Anime.sub` callback, the timeline\r\n * pushes its `destroy` on the workspace's cleaning stack (the list of destructors run by `Up.Anime.unsub`).\r\n * @note Requires `'ScrollTrigger'` in the Anime config (`plugins: ['ScrollTrigger']`).\r\n * @note Get the class from the Anime bucket (`bucket.Timeline`): it is only usable once Anime has loaded GSAP.\r\n * @example\r\n * ```ts\r\n * Up.Anime.sub(KEY, (bucket: AnimeBucket): void =>\r\n * {\r\n * const TIMELINE = new bucket.Timeline(\r\n * {\r\n * trigger : '.story',\r\n * scrub : true,\r\n * getOverflowStart: (): number => Up.App.lh\r\n * })\r\n *\r\n * const INTRO = TIMELINE.addFragment({ flex: 1 })\r\n * const OUTRO = TIMELINE.addFragment({ flex: 2 })\r\n *\r\n * TIMELINE.addAnimation('F', '.story__title', { autoAlpha: 0, end: 0, overflowStart: 1 })\r\n * ('T', document.querySelectorAll('.story__item'), { x: 100, fragment: INTRO, start: 0, end: 1, stagger: 0.1 })\r\n *\r\n * TIMELINE.addTrack({ fragment: OUTRO, start: 0, end: 1, eUpdate: (progress: number): void => console.log(progress) })\r\n * })\r\n * ```\r\n*/\r\nclass Timeline\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n static #DEFAULT_NAME = 'Timeline'\r\n static #DEFAULT_ANIMATION_NAME = 'Animation'\r\n static #DEFAULT_TRACK_NAME = 'Track'\r\n\r\n /**\r\n * Anime bucket shared by the Anime plugin once GSAP is loaded; includes `ScrollTrigger` when it is in the Anime config.\r\n * @internal\r\n */\r\n static [BUCKET]: AnimeBucket & { ScrollTrigger?: typeof ScrollTrigger }\r\n\r\n // ##PRIVATES\r\n #INTERVAL = new Trees.Interval<Timeline.TRACK>()\r\n\r\n #name = Timeline.#DEFAULT_NAME\r\n\r\n #rise = false\r\n #running = false\r\n\r\n #start = 0\r\n #end = 0\r\n #progressionTrackHeight = 0\r\n #heightRatio = 0\r\n #overflowStartRatio = 0\r\n #overflowEndRatio = 0\r\n #progress = 0\r\n #fragmentTotalFlex = 0\r\n\r\n #timeline: gsap.core.Timeline | null = null\r\n #ctx : gsap.Context | null = null\r\n\r\n #fragments : Timeline.FRAGMENT [] = [] // *Fragments allow you to divide the timeline (does not take overflows into account) into flexible portions (which extend across the entire timeline)\r\n #animations: Timeline.ANIMATION[] = []\r\n #pending : Timeline.ANIMATION[] = []\r\n #tracks : Timeline.TRACK [] = []\r\n #past : Timeline.TRACK [] = []\r\n\r\n #current = new Set<Timeline.TRACK>()\r\n #seen = new Set<Timeline.TRACK>()\r\n\r\n #updating : Promise<void> | null = null\r\n #updatingResolve: (() => void) | null = null\r\n\r\n #getOverflowStart?: () => number\r\n #getOverflowEnd ?: () => number\r\n\r\n #eRefreshCallback: NonNullable<Timeline.CONFIG['eRefresh']> = Up.App.void\r\n #eUpdateCallback : NonNullable<Timeline.CONFIG['eUpdate']> = Up.App.void\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##CONSTRUCTOR\r\n /**\r\n * Creates a timeline and, inside a `sub` callback, registers `destroy` on the workspace's cleaning stack.\r\n * Without `config`, the timeline stays unconfigured until `set` is called; animations added meanwhile are queued.\r\n * @param config Optional configuration, applied with `set`.\r\n * @throws If `'ScrollTrigger'` is not in the Anime config.\r\n */\r\n constructor (config?: Timeline.CONFIG)\r\n {\r\n if (!Timeline[BUCKET].ScrollTrigger) Logs.throw('TIMELINE', '\"ScrollTrigger\" (GSAP PLUGIN) IS REQUIRED TO USE THIS CLASS (ADD \"ScrollTrigger\" TO THE \"Anime\" CONFIGURATION).')\r\n\r\n this.#setBindings()\r\n \r\n if (config) this.set(config)\r\n\r\n Timeline[BUCKET].workspace.cleaningStack?.push(this.destroy.bind(this))\r\n }\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n /**\r\n * Debug name of the timeline (`config.name`, default `\"Timeline\"`).\r\n */\r\n get name(): string { return this.#name }\r\n\r\n /**\r\n * Timeline progress in `[0, 1]`, as of the last ScrollTrigger update.\r\n */\r\n get progress(): number { return this.#progress }\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n #setBindings(): void\r\n {\r\n this.addAnimation = this.addAnimation.bind(this)\r\n this.addTrack = this.addTrack.bind(this)\r\n this.addFragment = this.addFragment.bind(this)\r\n this[evaluateTrack] = this[evaluateTrack].bind(this)\r\n }\r\n\r\n #setVars(config: Timeline.CONFIG): void\r\n {\r\n const\r\n {\r\n name : NAME = Timeline.#DEFAULT_NAME,\r\n start: START = 0,\r\n end : END = 1,\r\n getOverflowStart,\r\n getOverflowEnd,\r\n eEnter,\r\n eEnterBack,\r\n eLeave,\r\n eLeaveBack,\r\n eRefresh = Up.App.void,\r\n eUpdate = Up.App.void,\r\n ...VARS\r\n } = config\r\n\r\n this.#progress = 0\r\n this.#name = NAME\r\n this.#updating = new Promise<void>((res): void => { this.#updatingResolve = res })\r\n this.#getOverflowStart = getOverflowStart\r\n this.#getOverflowEnd = getOverflowEnd\r\n this.#eRefreshCallback = eRefresh\r\n this.#eUpdateCallback = eUpdate\r\n this.#ctx = Timeline[BUCKET].gsap.context((): void =>\r\n {\r\n (this.#timeline = Timeline[BUCKET].gsap.timeline(\r\n {\r\n duration : 1,\r\n scrollTrigger:\r\n {\r\n ...VARS,\r\n start: getOverflowStart\r\n ? (): string => `${START * 100}%-=${getOverflowStart()} 0`\r\n : (): string => `${START * 100}% 0`,\r\n end: getOverflowEnd\r\n ? (): string => `${END * 100}%+=${getOverflowEnd()} ${Up.App.lh}`\r\n : (): string => `${END * 100}% ${Up.App.lh}`,\r\n onEnter : eEnter,\r\n onEnterBack: eEnterBack,\r\n onLeave : eLeave,\r\n onLeaveBack: eLeaveBack,\r\n onRefresh : this.#eRefresh.bind(this),\r\n onUpdate : this.#eUpdate.bind(this, false)\r\n }\r\n }))\r\n .to(this, { duration: 1 }, 0)\r\n })\r\n }\r\n\r\n #setTask(): void { Up.Thread.sub(this.#t$UpdateFragments) }\r\n\r\n /**\r\n * Configures the timeline: creates the GSAP timeline and its ScrollTrigger, then adds the queued animations.\r\n * Logs a warning and does nothing if the timeline is already configured.\r\n * @note The trigger should be taller than the viewport (`100lvh`), otherwise the scroll range is empty or inverted.\r\n * @param config ScrollTrigger vars plus Upwwwards options (see {@link Timeline.CONFIG}).\r\n */\r\n set(config: Timeline.CONFIG): void\r\n {\r\n if (this.#timeline) return Logs.warn('TIMELINE', 'THE TIMELINE HAS ALREADY BEEN CONFIGURED.')\r\n\r\n this.#setVars(config)\r\n this.#flush()\r\n }\r\n\r\n // ##GET\r\n static #getTargetData(target: gsap.TweenTarget): [target: gsap.TweenTarget, length: number]\r\n {\r\n switch (true)\r\n {\r\n case !target : return [null, 0]\r\n case target instanceof NodeList: target = [...target]\r\n case Array.isArray(target) :\r\n {\r\n const\r\n TARGETS = (target as gsap.TweenTarget[]).filter((t): gsap.TweenTarget => t),\r\n LENGTH = TARGETS.length\r\n\r\n return [LENGTH === 0 ? null : LENGTH === 1 ? TARGETS[0] : TARGETS, LENGTH]\r\n }\r\n default: return [target, 1]\r\n }\r\n }\r\n\r\n static #getDuration(finalStart: number, finalEnd: number): number { return Math.max(finalEnd - finalStart, 0) }\r\n\r\n static #getAnimationVars(animation: Timeline.ANIMATION, duration: number, finalStagger?: number): gsap.TweenVars\r\n {\r\n return {\r\n ...animation.vars[animation.vars.length - 1],\r\n stagger : finalStagger,\r\n duration: finalStagger\r\n ? Math.max(duration - finalStagger * (animation.length - 1), 0) // *Duration per target\r\n : duration\r\n }\r\n }\r\n\r\n #getFragment(fragment: number): Timeline.FRAGMENT { return this.#fragments[fragment - 1] ?? Logs.throw('TIMELINE', `FRAGMENT \"${fragment}\" DOES NOT EXIST.`) }\r\n\r\n #getAnimationClipRatio(animation: Timeline.ANIMATION): number\r\n {\r\n /*\r\n *By default, percentage values are relative to the main portion of the timeline (excluding overflows).\r\n *Certain values, such as \"stagger\" or \"itemDuration\" are not limited to the main portion of the timeline but also include the animation's overflow.\r\n */\r\n\r\n return 1 - this.#overflowStartRatio * (1 - animation.overflowStart) - this.#overflowEndRatio * (1 - animation.overflowEnd)\r\n }\r\n\r\n #getFinalStart(start: number, overflow: number, fragment: number): number\r\n {\r\n /*\r\n *Get the \"finalStart\" in percentage [0; 1] relative to the total \"timeline\" or a \"fragment\".\r\n ?\"Overflow\" is ignored in the case of belonging to a \"fragment\".\r\n */\r\n \r\n if (fragment)\r\n {\r\n const FRAGMENT = this.#getFragment(fragment)\r\n\r\n return FRAGMENT.finalStart + FRAGMENT.duration * start\r\n }\r\n \r\n return this.#heightRatio * start + this.#overflowStartRatio * (1 - overflow)\r\n }\r\n\r\n #getFinalEnd(end: number, overflow: number, fragment: number): number\r\n {\r\n /*\r\n *Get the \"finalEnd\" in percentage [0; 1] relative to the total \"timeline\" or a \"fragment\".\r\n ?\"Overflow\" is ignored in the case of belonging to a \"fragment\".\r\n */\r\n\r\n if (fragment)\r\n {\r\n const FRAGMENT = this.#getFragment(fragment)\r\n\r\n return FRAGMENT.finalStart + FRAGMENT.duration * end\r\n }\r\n \r\n return this.#overflowStartRatio + this.#heightRatio * end + this.#overflowEndRatio * overflow\r\n }\r\n\r\n #getFinalStagger(animation: Timeline.ANIMATION, duration: number): number | undefined\r\n {\r\n /*\r\n *If \"itemDuration\" is present, then the \"stagger\" is calculated.\r\n *\"Stagger\" is relative to the duration of the \"timeline\" or \"fragment\".\r\n */\r\n\r\n if (animation.length > 1) return animation.itemDuration\r\n ? Math.max(duration - (animation.fragment ? this.#getFragment(animation.fragment).duration : this.#getAnimationClipRatio(animation)) * animation.itemDuration, 0) / (animation.length - 1)\r\n : animation.stagger\r\n ? animation.fragment\r\n ? this.#getFragment(animation.fragment).duration * animation.stagger\r\n : this.#getAnimationClipRatio(animation) * animation.stagger\r\n : undefined\r\n }\r\n\r\n #getPriority(boundary: number): number\r\n {\r\n /*\r\n *The \"boundary\" corresponds to \"finalStart\" for the \"eEnter\" and \"eLeaveBack\" events, and corresponds to \"finalEnd\" for the \"eEnterBack\" and \"eLeave\" events.\r\n *For the \"eUpdate\" event, use \"finalEnd\" when \"rise\" is \"true\", otherwise, use \"finalStart\".\r\n */\r\n\r\n return this.#start + this.#progressionTrackHeight * boundary // *Adding \"start\" creates a common starting point for all timelines.\r\n }\r\n\r\n /**\r\n * Returns the scroll position at which the timeline reaches a given point of its main band.\r\n * @note Valid after the first ScrollTrigger refresh; returns `0` before.\r\n * @param point Fraction (`0`–`1`) of the main band (overflows and fragments are not taken into account).\r\n * @returns Scroll position in pixels.\r\n */\r\n getTop(point: number): number { return this.#start + this.#progressionTrackHeight * this.#getFinalStart(point, 0, 0) }\r\n\r\n // ##ADD\r\n #addAnimation(animation: Timeline.ANIMATION): void\r\n {\r\n if (this.#timeline)\r\n {\r\n this.#updateAnimation(animation)\r\n\r\n this.#animations.push(animation)\r\n\r\n if (animation.fragment) this.#getFragment(animation.fragment).animations.push(animation)\r\n }\r\n else this.#pending.push(animation)\r\n }\r\n\r\n #addTrack(track: Timeline.TRACK): void\r\n {\r\n this.#INTERVAL.add(track, track.finalStart, track.finalEnd)\r\n\r\n this.#tracks.push(track)\r\n \r\n if (track.fragment) this.#getFragment(track.fragment).tracks.push(track)\r\n }\r\n\r\n #addPast(track: Timeline.TRACK): void\r\n {\r\n /*\r\n *If the scroll is very fast (> 100 lvh), then it is possible that some tracks will be skipped.\r\n *In this case, they are added to \"current\".\r\n *They will then be notified by one of the \"eLeave\" or \"eLeaveBack\" events and updated to a position (0 or 1).\r\n */\r\n\r\n const KEY = this.#rise ? 'finalEnd' : 'finalStart'\r\n \r\n let i = this.#past.length - 1\r\n\r\n while (i > -1)\r\n if (this.#past[i][KEY] < track[KEY]) break\r\n else i--\r\n\r\n this.#past.splice(i + 1, 0, track)\r\n }\r\n\r\n /**\r\n * Appends a fragment: a flexible portion of the main band (overflows excluded) sized by its share of the total `flex`.\r\n * Fragment bounds, and the animations and tracks placed in fragments, are recomputed on the next Thread frame.\r\n * @param vars Fragment options.\r\n * @returns 1-based fragment index, to pass as `fragment` to `addAnimation` / `addTrack`.\r\n * @throws If `vars.flex` is `≤ 0`.\r\n */\r\n addFragment(vars: Timeline.FRAGMENT_VARS): number\r\n {\r\n if (vars.flex <= 0) Logs.throw('TIMELINE', 'THE \"flex\" PROPERTY CANNOT BE LESS THAN OR EQUAL TO \"0\".')\r\n\r\n this.#fragmentTotalFlex += vars.flex\r\n\r\n const NUMBER = this.#fragments.push(\r\n {\r\n flex : vars.flex,\r\n finalStart: 0,\r\n finalEnd : 0,\r\n duration : 0,\r\n animations: [],\r\n tracks : []\r\n })\r\n\r\n this.#setTask()\r\n\r\n return NUMBER\r\n }\r\n\r\n /**\r\n * Adds a GSAP tween placed on the timeline; its duration (and stagger) is derived from the placement.\r\n * If the timeline is not configured yet, the animation is queued until `set`.\r\n * Out-of-range placement values are clamped to `[0, 1]`. Logs a warning and adds nothing when `target` resolves to no element.\r\n * @template T Tween kind: `'F'`, `'T'` or `'F/T'`.\r\n * @param type Tween kind (see {@link Timeline.ANIMATION_TYPE}).\r\n * @param target GSAP tween target(s); empty entries of arrays / `NodeList`s are ignored.\r\n * @param vars For `'F/T'`: the `from` vars, then the `to` vars with the placement (see {@link Timeline.ANIMATION_VARS});\r\n * otherwise a single object with tween vars and placement.\r\n * @returns The bound `addAnimation` method, so calls can be chained: `timeline.addAnimation(…)(…)`.\r\n * @throws If `fragment` refers to a fragment that does not exist (checked once the timeline is configured).\r\n */\r\n addAnimation<T extends Timeline.ANIMATION_TYPE>(type: T, target: gsap.TweenTarget, ...vars: T extends 'F/T' ? [Timeline.ANIMATION_UNIVERSAL_VARS, Timeline.ANIMATION_VARS] : [Timeline.ANIMATION_VARS]): Timeline['addAnimation']\r\n {\r\n const [TARGET, LENGTH] = Timeline.#getTargetData(target)\r\n\r\n if (LENGTH)\r\n {\r\n const\r\n {\r\n name : NAME = Timeline.#DEFAULT_ANIMATION_NAME,\r\n start : START = 0,\r\n end : END = 1,\r\n overflowStart: OVERFLOW_START = 0,\r\n overflowEnd : OVERFLOW_END = 0,\r\n fragment : FRAGMENT = 0,\r\n stagger : STAGGER,\r\n itemDuration : ITEM_DURATION,\r\n ...VARS\r\n } = vars.pop() as Timeline.ANIMATION_VARS\r\n\r\n this.#addAnimation(\r\n {\r\n name : NAME, \r\n type,\r\n target : TARGET,\r\n length : LENGTH,\r\n fragment : Math.max(FRAGMENT, 0),\r\n start : Maths.range(START, 0, 1),\r\n end : Maths.range(END, 0, 1),\r\n overflowStart: Maths.range(OVERFLOW_START, 0, 1),\r\n overflowEnd : Maths.range(OVERFLOW_END, 0, 1),\r\n stagger : STAGGER,\r\n itemDuration : ITEM_DURATION,\r\n vars : [...vars as [] | [Timeline.ANIMATION_UNIVERSAL_VARS], VARS]\r\n })\r\n }\r\n else Logs.warn('TIMELINE', 'NO TARGET.')\r\n\r\n return this.addAnimation\r\n }\r\n\r\n /**\r\n * Adds a track: a logical segment of the timeline, without a tween, that reports enter / leave / progress events\r\n * (see {@link Timeline.TRACK_UNIVERSAL_VARS} for the `priority` and `skipped` arguments).\r\n * Out-of-range placement values are clamped to `[0, 1]`.\r\n * @param vars Placement and callbacks.\r\n * @returns The bound `addTrack` method, so calls can be chained: `timeline.addTrack(…)(…)`.\r\n * @throws If `fragment` refers to a fragment that does not exist.\r\n */\r\n addTrack(vars: Timeline.TRACK_VARS): Timeline['addTrack']\r\n {\r\n const\r\n FRAGMENT = vars.fragment ?? 0,\r\n START = vars.start == null ? 0 : Maths.range(vars.start, 0, 1),\r\n END = vars.end == null ? 1 : Maths.range(vars.end, 0, 1),\r\n OVERFLOW_START = vars.overflowStart == null ? 0 : Maths.range(vars.overflowStart, 0, 1),\r\n OVERFLOW_END = vars.overflowEnd == null ? 0 : Maths.range(vars.overflowEnd, 0, 1),\r\n FINAL_START = this.#getFinalStart(START, OVERFLOW_START, FRAGMENT),\r\n FINAL_END = this.#getFinalEnd(END, OVERFLOW_END, FRAGMENT)\r\n \r\n this.#addTrack(\r\n {\r\n name : vars.name ?? Timeline.#DEFAULT_TRACK_NAME,\r\n finalStart : FINAL_START,\r\n finalEnd : FINAL_END,\r\n duration : Timeline.#getDuration(FINAL_START, FINAL_END),\r\n progress : -1, // *initialize to -1 to enable calling the \"eUpdate\" callback in \"clearSkipped\"\r\n fragment : FRAGMENT,\r\n start : START,\r\n end : END,\r\n overflowStart: OVERFLOW_START,\r\n overflowEnd : OVERFLOW_END,\r\n eEnter : vars.eEnter ?? Up.App.void,\r\n eEnterBack : vars.eEnterBack ?? Up.App.void,\r\n eLeave : vars.eLeave ?? Up.App.void,\r\n eLeaveBack : vars.eLeaveBack ?? Up.App.void,\r\n eUpdate : vars.eUpdate ?? Up.App.void,\r\n eDestroy : vars.eDestroy ?? Up.App.void\r\n })\r\n\r\n return this.addTrack\r\n }\r\n\r\n // ##UPDATES\r\n #updateVars(): void\r\n {\r\n const\r\n SCROLL_TRIGGER = this.#timeline!.scrollTrigger,\r\n PROGRESSION_TRACK_HEIGHT = SCROLL_TRIGGER && (this.#end = SCROLL_TRIGGER.end) - (this.#start = SCROLL_TRIGGER.start)\r\n\r\n if (PROGRESSION_TRACK_HEIGHT)\r\n {\r\n // TODO: It's a bad idea to separate the end and start points for the trigger (this causes a delay in the calculations and leads to problems when the element is less than 100 lvh in height)\r\n const\r\n OVERFLOW_START = this.#getOverflowStart ? Math.max(this.#getOverflowStart(), 0) : 0,\r\n OVERFLOW_END = this.#getOverflowEnd ? Math.max(this.#getOverflowEnd(), 0) : 0,\r\n FIX_RATIO = Math.min(PROGRESSION_TRACK_HEIGHT / Math.max(OVERFLOW_START + OVERFLOW_END, 1), 1)\r\n\r\n this.#progressionTrackHeight = PROGRESSION_TRACK_HEIGHT\r\n this.#heightRatio = Math.max(PROGRESSION_TRACK_HEIGHT - OVERFLOW_START - OVERFLOW_END, 0) / PROGRESSION_TRACK_HEIGHT\r\n this.#overflowStartRatio = OVERFLOW_START / PROGRESSION_TRACK_HEIGHT * FIX_RATIO\r\n this.#overflowEndRatio = OVERFLOW_END / PROGRESSION_TRACK_HEIGHT * FIX_RATIO\r\n }\r\n else this.#progressionTrackHeight = this.#heightRatio = this.#overflowStartRatio = this.#overflowEndRatio = 0\r\n }\r\n\r\n #updateFragments(deep: boolean): void\r\n {\r\n for (let i = 0, iMax = this.#fragments.length, prevEnd = this.#overflowStartRatio; i < iMax; i++)\r\n {\r\n const\r\n FRAGMENT = this.#fragments[i],\r\n DURATION = FRAGMENT.flex / this.#fragmentTotalFlex * this.#heightRatio\r\n\r\n FRAGMENT.finalStart = prevEnd\r\n FRAGMENT.finalEnd = prevEnd += DURATION\r\n FRAGMENT.duration = DURATION\r\n\r\n if (!deep) continue\r\n\r\n const\r\n ANIMATIONS = FRAGMENT.animations,\r\n TRACKS = FRAGMENT.tracks\r\n\r\n for (let j = 0, jMax = ANIMATIONS.length; j < jMax; j++) this.#updateAnimation(ANIMATIONS[j])\r\n\r\n for (let j = 0, jMax = TRACKS.length; j < jMax; j++)\r\n {\r\n const TRACK = TRACKS[j]\r\n\r\n this.#INTERVAL.remove(TRACK) // TODO: it might be better to clear the tree and recreate it.\r\n \r\n this.#updateTrack(TRACK)\r\n }\r\n }\r\n }\r\n\r\n #updateAnimation(animation: Timeline.ANIMATION): void\r\n {\r\n const\r\n FINAL_START = this.#getFinalStart(animation.start, animation.overflowStart, animation.fragment),\r\n FINAL_END = this.#getFinalEnd(animation.end, animation.overflowEnd, animation.fragment),\r\n DURATION = Timeline.#getDuration(FINAL_START, FINAL_END),\r\n FINAL_STAGGER = this.#getFinalStagger(animation, DURATION),\r\n TWEEN = animation.tween\r\n\r\n switch (true)\r\n {\r\n case !!TWEEN:\r\n {\r\n this.#timeline!.remove(TWEEN)\r\n\r\n if (TWEEN.vars.duration === DURATION && TWEEN.vars.stagger === FINAL_STAGGER)\r\n {\r\n TWEEN.invalidate()\r\n \r\n break\r\n }\r\n\r\n TWEEN.kill()\r\n }\r\n default: this.#ctx!.add((): void =>\r\n {\r\n animation.tween = animation.type === 'F/T'\r\n ? Timeline[BUCKET].gsap.fromTo(animation.target, animation.vars[0], Timeline.#getAnimationVars(animation, DURATION, FINAL_STAGGER))\r\n : Timeline[BUCKET].gsap[animation.type === 'F' ? 'from' : 'to'](animation.target, Timeline.#getAnimationVars(animation, DURATION, FINAL_STAGGER))\r\n })\r\n }\r\n\r\n this.#timeline!.add(animation.tween!, FINAL_START)\r\n }\r\n\r\n #updateAnimations(): void { for (let i = 0, max = this.#animations.length; i < max; i++) this.#updateAnimation(this.#animations[i]) }\r\n\r\n #updateTrack(track: Timeline.TRACK): void\r\n {\r\n track.duration = Timeline.#getDuration(\r\n track.finalStart = this.#getFinalStart(track.start, track.overflowStart, track.fragment),\r\n track.finalEnd = this.#getFinalEnd(track.end, track.overflowEnd, track.fragment)\r\n )\r\n\r\n this.#INTERVAL.add(track, track.finalStart, track.finalEnd)\r\n }\r\n\r\n #updateTracks(): void\r\n {\r\n this.#INTERVAL.clear()\r\n \r\n for (let i = 0, max = this.#tracks.length; i < max; i++)\r\n {\r\n const TRACK = this.#tracks[i]\r\n\r\n this.#updateTrack(TRACK)\r\n }\r\n }\r\n\r\n /**\r\n * Forces a track re-evaluation from the last notified progress to the live ScrollTrigger progress\r\n * (e.g. after adding tracks, or when layout changed). Waits for pending fragment updates and for the first\r\n * ScrollTrigger refresh — that refresh already catch-ups from `0` when the page was restored mid-scroll.\r\n * Does nothing if the current scroll position (`Up.App.y`) is before the timeline start.\r\n * Logs a warning and returns if the timeline is not configured.\r\n * @returns Resolves once the update has run or been skipped.\r\n */\r\n async update(): Promise<void>\r\n {\r\n if (!this.#timeline) return Logs.warn('TIMELINE', 'SET THE TIMELINE BEFORE THE UPDATE!')\r\n\r\n await Up.Thread.wait(this.#t$UpdateFragments) // *Wait for any tasks to be resolved\r\n await this.#updating\r\n\r\n if (this.#timeline.scrollTrigger!.start > Up.App.y) return\r\n\r\n this.#eUpdate(true)\r\n }\r\n\r\n // ##DESTROY\r\n #destroyTracks(): void { for (let i = 0, max = this.#tracks.length; i < max; i++) this.#tracks[i].eDestroy() }\r\n\r\n #destroyVars(): void\r\n {\r\n this.#INTERVAL.clear()\r\n\r\n this.#fragmentTotalFlex = 0\r\n \r\n if (this.#fragments .length) this.#fragments = []\r\n if (this.#animations.length) this.#animations = []\r\n if (this.#pending .length) this.#pending = []\r\n if (this.#tracks .length) this.#tracks = []\r\n\r\n if (this.#current.size) this.#current.clear()\r\n if (this.#seen .size) this.#seen .clear()\r\n \r\n if (this.#ctx)\r\n {\r\n this.#ctx.revert()\r\n \r\n this.#ctx = null\r\n }\r\n\r\n if (this.#timeline) this.#timeline = null\r\n }\r\n\r\n /**\r\n * Calls every track's `eDestroy`, reverts the GSAP timeline, tweens and ScrollTrigger, and removes all fragments, animations and tracks.\r\n * The timeline becomes unconfigured: `set` can be called again.\r\n * Called automatically by `Up.Anime.unsub` when the timeline was constructed inside a `sub` callback.\r\n */\r\n destroy(): void\r\n {\r\n this.#resolve()\r\n this.#destroyTracks()\r\n this.#destroyVars()\r\n }\r\n\r\n // ##EVENTS\r\n #eRefresh(): void\r\n {\r\n this.#updateVars()\r\n this.#updateFragments(false) // *Update before animations and tracks (important)\r\n this.#updateAnimations()\r\n this.#updateTracks()\r\n this.#resolve()\r\n this.#eRefreshCallback()\r\n\r\n // *GSAP's first refresh can call update() before onRefresh when not batched: #eUpdate is then\r\n // *skipped while #updating is pending, so catch up once track bounds are valid (history restore).\r\n if (this.#timeline!.progress() !== this.#progress) this.#eUpdate(true)\r\n }\r\n\r\n #eUpdate(force = false): void\r\n {\r\n // *Ignore ST updates until the first refresh has rebuilt animation/track bounds. Tracks added\r\n // *before set() sit at [0, 0]; a rise catch-up would treat them as skipped past and fire eLeave.\r\n if (this.#updating) return\r\n\r\n if (this.#seen.size) this.#seen.clear()\r\n \r\n const PREV = this.#progress\r\n\r\n this.#progress = this.#timeline!.progress()\r\n\r\n if (!force && this.#progress === PREV) return\r\n \r\n this.#running = this.#progress > 0 && this.#progress < 1\r\n\r\n this.#INTERVAL.each(...((this.#rise = this.#progress > PREV)\r\n ? [PREV, this.#progress] as const\r\n : [this.#progress, PREV] as const\r\n ),\r\n this[evaluateTrack])\r\n \r\n this.#clear()\r\n this.#swap()\r\n this.#eUpdateCallback(this.#progress)\r\n }\r\n\r\n // ##TASKS\r\n #t$UpdateFragments = this.#updateFragments.bind(this, true)\r\n\r\n // ##UTILS\r\n #resolve(): void\r\n {\r\n this.#updating = null\r\n\r\n this.#updatingResolve?.()\r\n }\r\n\r\n #flush(): void { for (let i = this.#pending.length - 1; i > -1; i--) this.#addAnimation(this.#pending.splice(i, 1)[0]) }\r\n\r\n #clear(): void\r\n {\r\n this.#clearPast()\r\n this.#clearCurrent()\r\n }\r\n\r\n #clearPast(): void\r\n {\r\n const LENGTH = this.#past.length\r\n\r\n if (!LENGTH) return\r\n\r\n if (this.#rise) for (let i = 0; i < LENGTH; i++)\r\n {\r\n const\r\n TRACK = this.#past[i],\r\n SKIPPED = !this.#current.delete(TRACK),\r\n PRIORITY = this.#getPriority(TRACK.finalEnd)\r\n\r\n if (SKIPPED) TRACK.eEnter(this.#getPriority(TRACK.finalStart), SKIPPED)\r\n \r\n TRACK.eUpdate(TRACK.progress = 1, PRIORITY, SKIPPED)\r\n TRACK.eLeave(PRIORITY, SKIPPED)\r\n }\r\n else for (let i = LENGTH - 1; i > -1; i--)\r\n {\r\n const\r\n TRACK = this.#past[i],\r\n SKIPPED = !this.#current.delete(TRACK),\r\n PRIORITY = -this.#getPriority(TRACK.finalStart)\r\n\r\n if (SKIPPED) TRACK.eEnterBack(-this.#getPriority(TRACK.finalEnd), SKIPPED)\r\n \r\n TRACK.eUpdate(TRACK.progress = 0, PRIORITY, SKIPPED)\r\n TRACK.eLeaveBack(PRIORITY, SKIPPED)\r\n }\r\n\r\n this.#past = []\r\n }\r\n\r\n #clearCurrent(): void\r\n {\r\n if (!this.#current.size) return\r\n \r\n const [EVENT, PROGRESS] = this.#rise ? ['eLeave', 1] as const : ['eLeaveBack', 0] as const\r\n \r\n for (const TRACK of this.#current)\r\n {\r\n if (TRACK.progress !== PROGRESS) TRACK.eUpdate(TRACK.progress = PROGRESS, -Infinity, false)\r\n \r\n TRACK[EVENT](-Infinity, false)\r\n }\r\n }\r\n\r\n #swap(): void\r\n {\r\n const CURRENT = this.#current\r\n\r\n this.#current = this.#seen\r\n this.#seen = CURRENT\r\n }\r\n\r\n /**\r\n * Interval-tree visitor run on each progress change: fires the enter / update callbacks of a track overlapping the\r\n * scrolled range, or defers it to the past list when the progress is outside it (or the timeline is not playing).\r\n * @param track Track overlapping the scrolled range.\r\n * @internal\r\n */\r\n ;[evaluateTrack](track: Timeline.TRACK): void\r\n {\r\n if (track.finalStart > this.#progress || track.finalEnd < this.#progress) return this.#addPast(track)\r\n\r\n if (!this.#current.delete(track))\r\n {\r\n if (!this.#running) return this.#addPast(track)\r\n\r\n this.#rise ? track.eEnter(-Infinity, false) : track.eEnterBack(-Infinity, false)\r\n }\r\n\r\n if (this.#running) this.#seen.add(track) // *We only add items while the timeline is playing, because the Set \"current\" and \"seen\" are used to indicate which tracks are currently playing, if the timeline has finished, there is nothing left to play\r\n\r\n track.eUpdate(track.progress = Maths.range(track.duration && (this.#progress - track.finalStart) / track.duration, 0, 1), -Infinity, false)\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Timeline\r\n\r\nexport type { Timeline }"],"mappings":"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","names":[]}
|
package/dist/plugins/Anime.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '../symbols/index.js';
|
|
2
|
-
export { A as Anime, c as AnimeBucket, d as Split, e as Timeline, f as Tweens, A as default } from '../index-
|
|
2
|
+
export { A as Anime, c as AnimeBucket, d as Split, e as Timeline, f as Tweens, A as default } from '../index-Di5rQVjZ.js';
|
|
3
3
|
import 'gsap/all';
|
|
4
4
|
import '../index-BlwaDpQl.js';
|
|
5
5
|
import '../Thread-5NGNyOJb.js';
|
package/dist/plugins/Scroll.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '../symbols/index.js';
|
|
2
|
-
export { S as Scroll, b as ScrollBucket, S as default } from '../index-
|
|
2
|
+
export { S as Scroll, b as ScrollBucket, S as default } from '../index-Di5rQVjZ.js';
|
|
3
3
|
import 'lenis';
|
|
4
4
|
import '../Thread-5NGNyOJb.js';
|
|
5
5
|
import '../index-BlwaDpQl.js';
|
package/dist/plugins/Scroll.js
CHANGED
|
@@ -13,8 +13,8 @@ class Scroll extends Lazy {
|
|
|
13
13
|
* Event subscriptions: `LIFE` triggers the load, `LOAD` registers the Lenis Thread driver.
|
|
14
14
|
*/
|
|
15
15
|
static #EVENT_TICKETS = [
|
|
16
|
-
["LIFE", Scroll.#e$Life],
|
|
17
|
-
["LOAD", Scroll.#e$Load]
|
|
16
|
+
["LIFE", Scroll.#e$Life, { once: true }],
|
|
17
|
+
["LOAD", Scroll.#e$Load, { once: true }]
|
|
18
18
|
];
|
|
19
19
|
/**
|
|
20
20
|
* Whether `stop` was called before Lenis was loaded.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/Scroll.ts"],"sourcesContent":["/* [Scroll] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SYMBOLS\r\nimport { SIGN, BUCKET, set, destroy, load } from '../symbols/index.js'\r\n\r\n // ##CORE\r\nimport Up from '../core/Up.js'\r\n\r\n // ##PLUGINS\r\nimport Lazy from './@/Lazy.js'\r\n\r\n // ##SCRIPTS\r\nimport Logs from '../scripts/Logs.js'\r\n\r\n // ##TYPES\r\nimport type Lenis from 'lenis'\r\nimport type { ScrollToOptions } from 'lenis'\r\n\r\nimport type Event from '../core/[1]/Event.js'\r\nimport type Thread from '../core/[1]/[2]/Thread.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Scroll\r\n{\r\n /**\r\n * Callback receiving the Scroll bucket once Lenis is loaded.\r\n */\r\n export type CALLBACK = (bucket: ScrollBucket) => void\r\n}\r\n\r\n/**\r\n * Object passed to `Up.Scroll.workspace` callbacks once Lenis is loaded.\r\n*/\r\ninterface ScrollBucket\r\n{\r\n /**\r\n * Lenis constructor, from the `lenis` package.\r\n */\r\n Lenis: typeof Lenis,\r\n /**\r\n * Shared Lenis instance, created with `autoRaf: false` and advanced each frame by a {@link Up.Thread} driver.\r\n */\r\n global: Lenis\r\n}\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Smooth scrolling plugin built on [Lenis](https://github.com/darkroomengineering/lenis), loaded lazily (see {@link Lazy}).\r\n * - Lenis is dynamically imported on the first `workspace` call, which the plugin triggers itself on the first `LIFE` event (page entry) of {@link Up.Event}.\r\n * - From the `LOAD` event, a {@link Up.Thread} **driver** advances Lenis each frame (`autoRaf: false`), before modifiers and tasks.\r\n * - On Lenis `scroll`, the plugin {@link Up.Thread.arm|arms} {@link Thread.SCROLL_FLAG} so scroll modifiers (`App.updateScrollVars`, ScrollTrigger, …) run in the same frame.\r\n * - `stop`, `start` and `to` can be called at any time: before Lenis is loaded they use fallbacks, afterwards they call the Lenis instance.\r\n * @note Client-only. Requires the optional peer dependency `lenis` and the plugin enabled in the Vite config.\r\n * @example\r\n * ```ts\r\n * // vite.config.ts\r\n * upwwwards({ adapter: 'Nuxt', plugins: ['Scroll'] })\r\n * ```\r\n *\r\n * ```ts\r\n * Up.Scroll.to('#contact', { offset: -80 })\r\n * Up.Scroll.stop() // e.g. while a modal is open\r\n * Up.Scroll.start()\r\n *\r\n * Up.Scroll.workspace(({ global }): void => { global.on('scroll', console.log) })\r\n * ```\r\n*/\r\nabstract class Scroll extends Lazy\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n /**\r\n * Scroll Thread flag (`32`): armed on Lenis `scroll` so scroll modifiers run after the driver.\r\n */\r\n static #THREAD_FLAG: Thread.SCROLL_FLAG = 32\r\n\r\n /**\r\n * Event subscriptions: `LIFE` triggers the load, `LOAD` registers the Lenis Thread driver.\r\n */\r\n static #EVENT_TICKETS: Event.TICKET[] =\r\n [\r\n ['LIFE', Scroll.#e$Life],\r\n ['LOAD', Scroll.#e$Load]\r\n ]\r\n\r\n /**\r\n * Whether `stop` was called before Lenis was loaded.\r\n */\r\n static #stopped = false\r\n\r\n /**\r\n * Unique identity of the Scroll plugin, stamped on its guards.\r\n * @internal\r\n */\r\n static override readonly [SIGN] = Symbol('Scroll')\r\n\r\n /**\r\n * Plugin name; the plugin is exposed as `Up.Scroll`.\r\n */\r\n static override readonly NAME = 'Scroll'\r\n\r\n /**\r\n * Runtime object passed to `workspace` callbacks (see {@link ScrollBucket}).\r\n * @warning Holds empty placeholders until Lenis is loaded; use `workspace` instead of reading it directly.\r\n * @internal\r\n */\r\n static override readonly [BUCKET]: ScrollBucket =\r\n {\r\n Lenis : {} as typeof Lenis,\r\n global: {} as Lenis\r\n }\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n /**\r\n * {@link Thread.SCROLL_FLAG} (`32`) used when Lenis arms scroll modifiers via {@link Up.Thread.arm}.\r\n * @returns The scroll Thread flag.\r\n */\r\n static get THREAD_FLAG(): Thread.SCROLL_FLAG { return Scroll.#THREAD_FLAG }\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n /**\r\n * Subscribes to the `LIFE` and `LOAD` events.\r\n */\r\n static #setEvents(): void { Up.Event.sub(Scroll.#EVENT_TICKETS) }\r\n\r\n /**\r\n * Registers Lenis `raf` as a Thread driver (runs before modifiers each frame).\r\n */\r\n static #setDriver(): void { Up.Thread.addDriver(Scroll.#d$) }\r\n\r\n /**\r\n * Client-only setup hook: marks the plugin as configured and subscribes to the `LIFE` and `LOAD` events.\r\n * @throws If the plugin is already configured.\r\n * @internal\r\n */\r\n static override [set](): void\r\n {\r\n super[set]()\r\n \r\n Scroll.#setEvents()\r\n }\r\n\r\n // ##DESTROY\r\n /**\r\n * Destroys the Lenis instance.\r\n */\r\n static #destroyVars(): void { Scroll[BUCKET].global?.destroy() }\r\n\r\n /**\r\n * Unsubscribes from the `LIFE` and `LOAD` events.\r\n */\r\n static #destroyEvents(): void { Up.Event.unsub(Scroll.#EVENT_TICKETS) }\r\n\r\n /**\r\n * Unregisters the Lenis Thread driver.\r\n */\r\n static #destroyDriver(): void { Up.Thread.removeDriver(Scroll.#d$) }\r\n\r\n /**\r\n * Client-only teardown hook: destroys the Lenis instance, unsubscribes from events and removes the driver.\r\n * @throws If the plugin is already destroyed.\r\n * @internal\r\n */\r\n static override [destroy](): void\r\n {\r\n super[destroy]()\r\n\r\n Scroll.#destroyVars()\r\n Scroll.#destroyEvents()\r\n Scroll.#destroyDriver()\r\n }\r\n\r\n // ##EVENTS\r\n /**\r\n * `LIFE` handler: triggers the Lenis load (no-op callback once loaded).\r\n */\r\n static #e$Life(): void\r\n {\r\n /*\r\n *Go through `Up.Scroll` so `Up.patch` subclasses keep Lazy STATUS/QUEUE on the live class.\r\n \r\n TODO: Make the auto set optional.\r\n */\r\n\r\n (Up as typeof Up & { Scroll: typeof Scroll }).Scroll.workspace(Up.App.void)\r\n }\r\n\r\n /**\r\n * `LOAD` handler: registers the Lenis Thread driver.\r\n */\r\n static #e$Load(): void { Scroll.#setDriver() }\r\n\r\n // ##DRIVERS\r\n /**\r\n * Thread driver: advances Lenis with {@link Up.Thread.timestamp}.\r\n */\r\n static #d$(): void { Scroll[BUCKET].global.raf(Up.Thread.timestamp) }\r\n\r\n // ##LOADERS\r\n /**\r\n * Load hook: imports `lenis`, creates the shared instance with `autoRaf: false`, rebinds `stop` / `start` / `to`,\r\n * and arms {@link Scroll.THREAD_FLAG} on Lenis `scroll` so Thread scroll modifiers run after the driver.\r\n * If `stop` was called before loading, Lenis starts stopped.\r\n * @throws If the plugin is not configured, already loaded, or destroyed during the import.\r\n * @internal\r\n */\r\n static override async [load](): Promise<void>\r\n {\r\n const\r\n MODULE = await super[load]((): Promise<typeof import('lenis')> => import('lenis')),\r\n LENIS = Scroll[BUCKET].global = new (Scroll[BUCKET].Lenis = MODULE!.default)({ autoRaf: false })\r\n\r\n Scroll.stop = LENIS.stop.bind(LENIS)\r\n Scroll.start = LENIS.start.bind(LENIS)\r\n Scroll.to = LENIS.scrollTo.bind(LENIS)\r\n\r\n LENIS.on('scroll', Up.Thread.arm.bind(null, Scroll.#THREAD_FLAG))\r\n\r\n if (Scroll.#stopped) Scroll.stop()\r\n }\r\n\r\n // ##UTILS\r\n /**\r\n * Runs `callback` with the {@link ScrollBucket} (Lenis constructor and shared instance), loading Lenis first if needed.\r\n * See {@link Lazy.workspace} for the queueing and guard behavior.\r\n * @template T Lazy plugin class.\r\n * @param callback Receives the Scroll bucket.\r\n * @param $guard Optional guard from `Up.Scroll.getGuard`; the call is ignored when `guard.value` is `false`.\r\n * @param lazy When `true`, queue the callback without starting the load.\r\n * @returns The pending load promise while loading, otherwise `undefined`.\r\n * @throws If called on the server.\r\n */\r\n static override workspace<T extends typeof Lazy>(callback: Lazy.CALLBACK, $guard?: Lazy.Guard<T> | null, lazy?: boolean): void | Promise<void>\r\n {\r\n if (!Up.Adapter.BROWSER) Logs.throw('SCROLL', 'SCROLL CAN ONLY BE USED IN THE BROWSER.')\r\n\r\n return super.workspace(callback, $guard, lazy)\r\n }\r\n\r\n /**\r\n * Stops smooth scrolling (calls `Lenis.stop`).\r\n * Before Lenis is loaded, the request is remembered and Lenis starts stopped.\r\n */\r\n static stop(): void { Scroll.#stopped = true }\r\n\r\n /**\r\n * Resumes smooth scrolling (calls `Lenis.start`).\r\n * Before Lenis is loaded, cancels a previous `stop` request.\r\n */\r\n static start(): void { Scroll.#stopped = false }\r\n\r\n /**\r\n * Scrolls the page to a target (calls `Lenis.scrollTo`).\r\n * Before Lenis is loaded, falls back to `window.scrollTo`: selectors and elements are converted to an absolute Y position, smooth unless `options.immediate` is `true`.\r\n * @param target Element, CSS selector, or absolute Y position in px.\r\n * @param options Lenis `scrollTo` options. Before Lenis is loaded, only `immediate` is used, and `offset` only for element and selector targets.\r\n * @note Before Lenis is loaded, a selector that matches nothing logs a warning and does nothing.\r\n */\r\n static to(target: HTMLElement | number | string, options?: ScrollToOptions): void\r\n {\r\n switch (typeof target)\r\n {\r\n case 'string':\r\n {\r\n const TARGET = document.querySelector<HTMLElement>(target)\r\n\r\n if (!TARGET) return Logs.warn('SCROLL', `THE \"${target}\" TARGET WAS NOT FOUND.`)\r\n\r\n target = TARGET\r\n }\r\n case 'object':\r\n {\r\n target = Up.App.y + target.getBoundingClientRect().top\r\n\r\n if (options?.offset) target += options.offset\r\n }\r\n default:\r\n }\r\n\r\n window.scrollTo(\r\n {\r\n top : target,\r\n behavior: options?.immediate ? 'instant' : 'smooth'\r\n })\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Scroll\r\n\r\nexport type {\r\n Scroll,\r\n ScrollBucket\r\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/Scroll.ts"],"sourcesContent":["/* [Scroll] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SYMBOLS\r\nimport { SIGN, BUCKET, set, destroy, load } from '../symbols/index.js'\r\n\r\n // ##CORE\r\nimport Up from '../core/Up.js'\r\n\r\n // ##PLUGINS\r\nimport Lazy from './@/Lazy.js'\r\n\r\n // ##SCRIPTS\r\nimport Logs from '../scripts/Logs.js'\r\n\r\n // ##TYPES\r\nimport type Lenis from 'lenis'\r\nimport type { ScrollToOptions } from 'lenis'\r\n\r\nimport type Event from '../core/[1]/Event.js'\r\nimport type Thread from '../core/[1]/[2]/Thread.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Scroll\r\n{\r\n /**\r\n * Callback receiving the Scroll bucket once Lenis is loaded.\r\n */\r\n export type CALLBACK = (bucket: ScrollBucket) => void\r\n}\r\n\r\n/**\r\n * Object passed to `Up.Scroll.workspace` callbacks once Lenis is loaded.\r\n*/\r\ninterface ScrollBucket\r\n{\r\n /**\r\n * Lenis constructor, from the `lenis` package.\r\n */\r\n Lenis: typeof Lenis,\r\n /**\r\n * Shared Lenis instance, created with `autoRaf: false` and advanced each frame by a {@link Up.Thread} driver.\r\n */\r\n global: Lenis\r\n}\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Smooth scrolling plugin built on [Lenis](https://github.com/darkroomengineering/lenis), loaded lazily (see {@link Lazy}).\r\n * - Lenis is dynamically imported on the first `workspace` call, which the plugin triggers itself on the first `LIFE` event (page entry) of {@link Up.Event}.\r\n * - From the `LOAD` event, a {@link Up.Thread} **driver** advances Lenis each frame (`autoRaf: false`), before modifiers and tasks.\r\n * - On Lenis `scroll`, the plugin {@link Up.Thread.arm|arms} {@link Thread.SCROLL_FLAG} so scroll modifiers (`App.updateScrollVars`, ScrollTrigger, …) run in the same frame.\r\n * - `stop`, `start` and `to` can be called at any time: before Lenis is loaded they use fallbacks, afterwards they call the Lenis instance.\r\n * @note Client-only. Requires the optional peer dependency `lenis` and the plugin enabled in the Vite config.\r\n * @example\r\n * ```ts\r\n * // vite.config.ts\r\n * upwwwards({ adapter: 'Nuxt', plugins: ['Scroll'] })\r\n * ```\r\n *\r\n * ```ts\r\n * Up.Scroll.to('#contact', { offset: -80 })\r\n * Up.Scroll.stop() // e.g. while a modal is open\r\n * Up.Scroll.start()\r\n *\r\n * Up.Scroll.workspace(({ global }): void => { global.on('scroll', console.log) })\r\n * ```\r\n*/\r\nabstract class Scroll extends Lazy\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n /**\r\n * Scroll Thread flag (`32`): armed on Lenis `scroll` so scroll modifiers run after the driver.\r\n */\r\n static #THREAD_FLAG: Thread.SCROLL_FLAG = 32\r\n\r\n /**\r\n * Event subscriptions: `LIFE` triggers the load, `LOAD` registers the Lenis Thread driver.\r\n */\r\n static #EVENT_TICKETS: Event.TICKET[] =\r\n [\r\n ['LIFE', Scroll.#e$Life, { once: true }],\r\n ['LOAD', Scroll.#e$Load, { once: true }]\r\n ]\r\n\r\n /**\r\n * Whether `stop` was called before Lenis was loaded.\r\n */\r\n static #stopped = false\r\n\r\n /**\r\n * Unique identity of the Scroll plugin, stamped on its guards.\r\n * @internal\r\n */\r\n static override readonly [SIGN] = Symbol('Scroll')\r\n\r\n /**\r\n * Plugin name; the plugin is exposed as `Up.Scroll`.\r\n */\r\n static override readonly NAME = 'Scroll'\r\n\r\n /**\r\n * Runtime object passed to `workspace` callbacks (see {@link ScrollBucket}).\r\n * @warning Holds empty placeholders until Lenis is loaded; use `workspace` instead of reading it directly.\r\n * @internal\r\n */\r\n static override readonly [BUCKET]: ScrollBucket =\r\n {\r\n Lenis : {} as typeof Lenis,\r\n global: {} as Lenis\r\n }\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n /**\r\n * {@link Thread.SCROLL_FLAG} (`32`) used when Lenis arms scroll modifiers via {@link Up.Thread.arm}.\r\n * @returns The scroll Thread flag.\r\n */\r\n static get THREAD_FLAG(): Thread.SCROLL_FLAG { return Scroll.#THREAD_FLAG }\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n /**\r\n * Subscribes to the `LIFE` and `LOAD` events.\r\n */\r\n static #setEvents(): void { Up.Event.sub(Scroll.#EVENT_TICKETS) }\r\n\r\n /**\r\n * Registers Lenis `raf` as a Thread driver (runs before modifiers each frame).\r\n */\r\n static #setDriver(): void { Up.Thread.addDriver(Scroll.#d$) }\r\n\r\n /**\r\n * Client-only setup hook: marks the plugin as configured and subscribes to the `LIFE` and `LOAD` events.\r\n * @throws If the plugin is already configured.\r\n * @internal\r\n */\r\n static override [set](): void\r\n {\r\n super[set]()\r\n \r\n Scroll.#setEvents()\r\n }\r\n\r\n // ##DESTROY\r\n /**\r\n * Destroys the Lenis instance.\r\n */\r\n static #destroyVars(): void { Scroll[BUCKET].global?.destroy() }\r\n\r\n /**\r\n * Unsubscribes from the `LIFE` and `LOAD` events.\r\n */\r\n static #destroyEvents(): void { Up.Event.unsub(Scroll.#EVENT_TICKETS) }\r\n\r\n /**\r\n * Unregisters the Lenis Thread driver.\r\n */\r\n static #destroyDriver(): void { Up.Thread.removeDriver(Scroll.#d$) }\r\n\r\n /**\r\n * Client-only teardown hook: destroys the Lenis instance, unsubscribes from events and removes the driver.\r\n * @throws If the plugin is already destroyed.\r\n * @internal\r\n */\r\n static override [destroy](): void\r\n {\r\n super[destroy]()\r\n\r\n Scroll.#destroyVars()\r\n Scroll.#destroyEvents()\r\n Scroll.#destroyDriver()\r\n }\r\n\r\n // ##EVENTS\r\n /**\r\n * `LIFE` handler: triggers the Lenis load (no-op callback once loaded).\r\n */\r\n static #e$Life(): void\r\n {\r\n /*\r\n *Go through `Up.Scroll` so `Up.patch` subclasses keep Lazy STATUS/QUEUE on the live class.\r\n \r\n TODO: Make the auto set optional.\r\n */\r\n\r\n (Up as typeof Up & { Scroll: typeof Scroll }).Scroll.workspace(Up.App.void)\r\n }\r\n\r\n /**\r\n * `LOAD` handler: registers the Lenis Thread driver.\r\n */\r\n static #e$Load(): void { Scroll.#setDriver() }\r\n\r\n // ##DRIVERS\r\n /**\r\n * Thread driver: advances Lenis with {@link Up.Thread.timestamp}.\r\n */\r\n static #d$(): void { Scroll[BUCKET].global.raf(Up.Thread.timestamp) }\r\n\r\n // ##LOADERS\r\n /**\r\n * Load hook: imports `lenis`, creates the shared instance with `autoRaf: false`, rebinds `stop` / `start` / `to`,\r\n * and arms {@link Scroll.THREAD_FLAG} on Lenis `scroll` so Thread scroll modifiers run after the driver.\r\n * If `stop` was called before loading, Lenis starts stopped.\r\n * @throws If the plugin is not configured, already loaded, or destroyed during the import.\r\n * @internal\r\n */\r\n static override async [load](): Promise<void>\r\n {\r\n const\r\n MODULE = await super[load]((): Promise<typeof import('lenis')> => import('lenis')),\r\n LENIS = Scroll[BUCKET].global = new (Scroll[BUCKET].Lenis = MODULE!.default)({ autoRaf: false })\r\n\r\n Scroll.stop = LENIS.stop.bind(LENIS)\r\n Scroll.start = LENIS.start.bind(LENIS)\r\n Scroll.to = LENIS.scrollTo.bind(LENIS)\r\n\r\n LENIS.on('scroll', Up.Thread.arm.bind(null, Scroll.#THREAD_FLAG))\r\n\r\n if (Scroll.#stopped) Scroll.stop()\r\n }\r\n\r\n // ##UTILS\r\n /**\r\n * Runs `callback` with the {@link ScrollBucket} (Lenis constructor and shared instance), loading Lenis first if needed.\r\n * See {@link Lazy.workspace} for the queueing and guard behavior.\r\n * @template T Lazy plugin class.\r\n * @param callback Receives the Scroll bucket.\r\n * @param $guard Optional guard from `Up.Scroll.getGuard`; the call is ignored when `guard.value` is `false`.\r\n * @param lazy When `true`, queue the callback without starting the load.\r\n * @returns The pending load promise while loading, otherwise `undefined`.\r\n * @throws If called on the server.\r\n */\r\n static override workspace<T extends typeof Lazy>(callback: Lazy.CALLBACK, $guard?: Lazy.Guard<T> | null, lazy?: boolean): void | Promise<void>\r\n {\r\n if (!Up.Adapter.BROWSER) Logs.throw('SCROLL', 'SCROLL CAN ONLY BE USED IN THE BROWSER.')\r\n\r\n return super.workspace(callback, $guard, lazy)\r\n }\r\n\r\n /**\r\n * Stops smooth scrolling (calls `Lenis.stop`).\r\n * Before Lenis is loaded, the request is remembered and Lenis starts stopped.\r\n */\r\n static stop(): void { Scroll.#stopped = true }\r\n\r\n /**\r\n * Resumes smooth scrolling (calls `Lenis.start`).\r\n * Before Lenis is loaded, cancels a previous `stop` request.\r\n */\r\n static start(): void { Scroll.#stopped = false }\r\n\r\n /**\r\n * Scrolls the page to a target (calls `Lenis.scrollTo`).\r\n * Before Lenis is loaded, falls back to `window.scrollTo`: selectors and elements are converted to an absolute Y position, smooth unless `options.immediate` is `true`.\r\n * @param target Element, CSS selector, or absolute Y position in px.\r\n * @param options Lenis `scrollTo` options. Before Lenis is loaded, only `immediate` is used, and `offset` only for element and selector targets.\r\n * @note Before Lenis is loaded, a selector that matches nothing logs a warning and does nothing.\r\n */\r\n static to(target: HTMLElement | number | string, options?: ScrollToOptions): void\r\n {\r\n switch (typeof target)\r\n {\r\n case 'string':\r\n {\r\n const TARGET = document.querySelector<HTMLElement>(target)\r\n\r\n if (!TARGET) return Logs.warn('SCROLL', `THE \"${target}\" TARGET WAS NOT FOUND.`)\r\n\r\n target = TARGET\r\n }\r\n case 'object':\r\n {\r\n target = Up.App.y + target.getBoundingClientRect().top\r\n\r\n if (options?.offset) target += options.offset\r\n }\r\n default:\r\n }\r\n\r\n window.scrollTo(\r\n {\r\n top : target,\r\n behavior: options?.immediate ? 'instant' : 'smooth'\r\n })\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Scroll\r\n\r\nexport type {\r\n Scroll,\r\n ScrollBucket\r\n}"],"mappings":"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","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '../symbols/index.js';
|
|
2
|
-
export { B as Basic, h as Package, i as Plugin, j as Spider, k as Synthra, l as SynthraBucket, m as SynthraPlugins, n as SynthraThree, X as X3D, k as default } from '../index-
|
|
2
|
+
export { B as Basic, h as Package, i as Plugin, j as Spider, k as Synthra, l as SynthraBucket, m as SynthraPlugins, n as SynthraThree, X as X3D, k as default } from '../index-Di5rQVjZ.js';
|
|
3
3
|
import 'three';
|
|
4
4
|
import '../Thread-5NGNyOJb.js';
|
|
5
5
|
import '../index-BlwaDpQl.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '../symbols/index.js';
|
|
2
|
-
export { T as Transmitter, a as TransmitterChannels, T as default } from '../index-
|
|
2
|
+
export { T as Transmitter, a as TransmitterChannels, T as default } from '../index-Di5rQVjZ.js';
|
|
3
3
|
import '../index-BlwaDpQl.js';
|
|
4
4
|
import '../Thread-5NGNyOJb.js';
|
|
5
5
|
import 'lenis';
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as Anime, L as Lazy, O as Observer, P as Plugin, g as Puppeteer, o as Screen, S as Scroll, k as Synthra, T as Transmitter } from '../index-
|
|
1
|
+
export { A as Anime, L as Lazy, O as Observer, P as Plugin, g as Puppeteer, o as Screen, S as Scroll, k as Synthra, T as Transmitter } from '../index-Di5rQVjZ.js';
|
|
2
2
|
import '../symbols/index.js';
|
|
3
3
|
import '../index-BlwaDpQl.js';
|
|
4
4
|
import '../Thread-5NGNyOJb.js';
|
package/docs/plugins/anime.md
CHANGED
|
@@ -145,7 +145,7 @@ The trigger should be **taller than the viewport** (`100lvh`); otherwise the ran
|
|
|
145
145
|
| `getOverflowStart` / `getOverflowEnd` | `() => number` px; re-read on refresh |
|
|
146
146
|
| `eEnter` / `eEnterBack` / `eLeave` / `eLeaveBack` | Replaces forbidden native `onEnter` / … |
|
|
147
147
|
| `eUpdate(progress)` | Progress `0`–`1` after track callbacks |
|
|
148
|
-
| `eRefresh` |
|
|
148
|
+
| `eRefresh` | After each ScrollTrigger refresh, once overflows / animations / tracks are recomputed |
|
|
149
149
|
| `name` | Debug label |
|
|
150
150
|
|
|
151
151
|
Native `onEnter` / `onUpdate` / `onRefresh` / … are **typed as `never`** — use the `e*` hooks.
|
|
@@ -167,6 +167,8 @@ Four mutually exclusive forms (fractions `0`–`1`):
|
|
|
167
167
|
|
|
168
168
|
**`addTrack`:** logical segment without a tween (`eEnter` / `eLeave` / `eUpdate` / `eDestroy`). Higher `priority` wins when several tracks update one object; `skipped: true` means the track was jumped — apply final state without animating.
|
|
169
169
|
|
|
170
|
+
**`update()`:** waits for pending fragment updates and the first ScrollTrigger refresh, then forces a track re-evaluation from the **last notified** progress to the live scrub progress (e.g. after adding tracks). Mid-scroll restore catch-up from `0` is done on that first refresh, not by `update()` itself. Does nothing if `Up.App.y` is still before the timeline start. Warns and returns if the timeline is not configured.
|
|
171
|
+
|
|
170
172
|
```ts
|
|
171
173
|
Up.Anime.sub(KEY, ({ Timeline }) => {
|
|
172
174
|
const timeline = new Timeline({
|
|
@@ -210,11 +212,11 @@ With Lenis: [Scroll — Going further](scroll.md#with-anime--scrolltrigger).
|
|
|
210
212
|
- With **Scroll** enabled, Lenis arms flag `32` so ScrollTrigger modifiers stay in sync without a manual Lenis `scroll` listener.
|
|
211
213
|
- `unsub` runs `cleaningStack` in reverse, then `ctx.revert()`.
|
|
212
214
|
- Helpers created inside `sub` push destroyers onto `workspace.cleaningStack`.
|
|
213
|
-
-
|
|
215
|
+
- **`Timeline` refresh gate:** track/`eUpdate` handling is deferred until the first ScrollTrigger `onRefresh` has rebuilt bounds (tracks added before `set()` start at `[0, 0]`). If GSAP already advanced scrub progress during that first refresh, Timeline catch-up runs right after `eRefresh` so skipped leave/enter stay consistent on history restore.
|
|
214
216
|
|
|
215
217
|
---
|
|
216
218
|
|
|
217
219
|
## See also
|
|
218
220
|
|
|
219
221
|
- [Plugins index](../plugins.md)
|
|
220
|
-
- [Core — Event](../core.md) · [Recipes](../recipes.md)
|
|
222
|
+
- [Core — Event](../core.md) · [Recipes](../recipes.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "upwwwards",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9-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>",
|