phase 0.0.5 → 0.0.6

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/README.md CHANGED
@@ -900,40 +900,42 @@ Minimal footprint is a core promise (see [Why phase](#why-phase)). Every export
900
900
  | **Core** | |
901
901
  | `createTicker` | 837 B |
902
902
  | `createSight` | 963 B |
903
- | `createLifecycle` | 1.48 kB |
904
- | `createLoop` | 2.6 kB |
905
- | `createScrollProgress` | 869 B |
903
+ | `createLifecycle` | 1.47 kB |
904
+ | `createLoop` | 2.59 kB |
905
+ | `createScrollProgress` | 857 B |
906
906
  | `createRenderState` | 495 B |
907
907
  | `createDevicePixelRatio` | 544 B |
908
- | `createMutation` | 1.2 kB |
908
+ | `createMutation` | 1.17 kB |
909
+ | `createPointer` | 1.26 kB |
909
910
  | `whenIdle` | 409 B |
910
911
  | `prefersReducedMotion` | 101 B |
911
912
  | **Ease** | |
912
913
  | `ease (all)` | 210 B |
913
914
  | **React** | |
914
915
  | `useLoop` | 2.81 kB |
915
- | `useLifecycle` | 1.68 kB |
916
+ | `useLifecycle` | 1.69 kB |
916
917
  | `useSight` | 1.18 kB |
917
918
  | `useCanvas` | 3.44 kB |
918
- | `useMutation` | 1.38 kB |
919
- | `useTween` | 620 B |
919
+ | `useMutation` | 1.36 kB |
920
+ | `usePointer` | 1.48 kB |
921
+ | `useTween` | 617 B |
920
922
  | `usePresence` | 593 B |
921
- | `useScrollProgress` | 996 B |
922
- | `useSize` | 388 B |
923
- | `useContainerQuery` | 365 B |
923
+ | `useScrollProgress` | 993 B |
924
+ | `useSize` | 384 B |
925
+ | `useContainerQuery` | 356 B |
924
926
  | `useMediaQuery` | 246 B |
925
- | `usePrefersReducedMotion` | 273 B |
927
+ | `usePrefersReducedMotion` | 272 B |
926
928
  | `useDevicePixelRatio` | 231 B |
927
929
  | `useSyncedRef` | 22 B |
928
930
  | `useStableCallback` | 39 B |
929
- | `Presence` | 743 B |
931
+ | `Presence` | 742 B |
930
932
  | `WhenVisible` | 1.44 kB |
931
933
  | `WhenIdle` | 593 B |
932
934
  | `Defer` | 85 B |
933
935
  | `useIdle` | 435 B |
934
936
  | `useWhenIdle` | 449 B |
935
937
  | `useRenderState` | 527 B |
936
- | `Swap` | 1.13 kB |
938
+ | `Swap` | 1.12 kB |
937
939
 
938
940
  <!-- SIZE-TABLE:END -->
939
941
 
@@ -271,5 +271,38 @@ interface Mutation {
271
271
  /** Lifecycle-aware MutationObserver with rAF-coalesced callbacks. */
272
272
  declare function createMutation(options: MutationOptions): Mutation;
273
273
  //#endregion
274
- export { SightReason as A, LifecyclePhase as C, Sight as D, createLifecycle as E, TickerPhase as F, TickerReason as I, createTicker as L, FrameState as M, Ticker as N, SightOptions as O, TickerOptions as P, LifecycleOptions as S, LifecycleReducedMotion as T, LoopReason as _, createMutation as a, createLoop as b, RenderPhase as c, createRenderState as d, DegradedBehavior as f, LoopPhase as g, LoopOptions as h, MutationReason as i, createSight as j, SightPhase as k, RenderState as l, Loop as m, MutationOptions as n, IdleOptions as o, DegradedReason as p, MutationPhase as r, whenIdle as s, Mutation as t, RenderStateOptions as u, Quality as v, LifecycleReason as w, Lifecycle as x, ReducedMotionBehavior as y };
275
- //# sourceMappingURL=index-BynP-ee0.d.ts.map
274
+ //#region src/core/pointer/index.d.ts
275
+ type PointerPhase = 'idle' | 'tracking' | 'stopped';
276
+ type PointerReason = 'initial' | 'enter' | 'leave' | 'sight' | 'disposed';
277
+ interface PointerState {
278
+ /** X position relative to the element's top-left, in CSS pixels. */
279
+ x: number;
280
+ /** Y position relative to the element's top-left, in CSS pixels. */
281
+ y: number;
282
+ /** Whether a pointer is currently over the element. */
283
+ active: boolean;
284
+ }
285
+ interface PointerOptions {
286
+ element: Element;
287
+ /** Called once per rAF frame with the latest pointer position. */
288
+ onPointer: (state: PointerState) => void;
289
+ /** Called on phase transitions (idle, tracking, stopped). */
290
+ onPhaseChange?: (phase: PointerPhase, reason: PointerReason) => void;
291
+ /** Pause when off-screen or ignore visibility. Default `'pause'`. */
292
+ visibility?: 'pause' | 'ignore';
293
+ /** IO options forwarded to the visibility observer. */
294
+ intersectionOptions?: IntersectionObserverInit;
295
+ /** Stops the tracker when aborted. */
296
+ signal?: AbortSignal;
297
+ }
298
+ interface Pointer {
299
+ readonly phase: PointerPhase;
300
+ readonly phaseReason: PointerReason;
301
+ readonly state: Readonly<PointerState>;
302
+ stop(): void;
303
+ }
304
+ /** Lifecycle-aware pointer tracker with rAF-batched `getBoundingClientRect`. */
305
+ declare function createPointer(options: PointerOptions): Pointer;
306
+ //#endregion
307
+ export { LifecycleReason as A, TickerOptions as B, LoopReason as C, Lifecycle as D, createLoop as E, SightPhase as F, TickerReason as H, SightReason as I, createSight as L, createLifecycle as M, Sight as N, LifecycleOptions as O, SightOptions as P, FrameState as R, LoopPhase as S, ReducedMotionBehavior as T, createTicker as U, TickerPhase as V, createRenderState as _, PointerState as a, Loop as b, MutationOptions as c, createMutation as d, IdleOptions as f, RenderStateOptions as g, RenderState as h, PointerReason as i, LifecycleReducedMotion as j, LifecyclePhase as k, MutationPhase as l, RenderPhase as m, PointerOptions as n, createPointer as o, whenIdle as p, PointerPhase as r, Mutation as s, Pointer as t, MutationReason as u, DegradedBehavior as v, Quality as w, LoopOptions as x, DegradedReason as y, Ticker as z };
308
+ //# sourceMappingURL=index-tRHsbTE2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-tRHsbTE2.d.ts","names":[],"sources":["../src/core/tick/index.ts","../src/core/sight/index.ts","../src/core/lifecycle/index.ts","../src/core/loop/index.ts","../src/core/render-state/index.ts","../src/core/idle/index.ts","../src/core/mutation/index.ts","../src/core/pointer/index.ts"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RemapOptions, clamp, clamp01, easeInOutCubic, easeOutBack, easeOutCubic, easeOutQuart, inverseLerp, lerp, linear, remap } from "./ease.js";
2
- import { A as SightReason, C as LifecyclePhase, D as Sight, E as createLifecycle, F as TickerPhase, I as TickerReason, L as createTicker, M as FrameState, N as Ticker, O as SightOptions, P as TickerOptions, S as LifecycleOptions, T as LifecycleReducedMotion, _ as LoopReason, a as createMutation, b as createLoop, c as RenderPhase, d as createRenderState, f as DegradedBehavior, g as LoopPhase, h as LoopOptions, i as MutationReason, j as createSight, k as SightPhase, l as RenderState, m as Loop, n as MutationOptions, o as IdleOptions, p as DegradedReason, r as MutationPhase, s as whenIdle, t as Mutation, u as RenderStateOptions, v as Quality, w as LifecycleReason, x as Lifecycle, y as ReducedMotionBehavior } from "./index-BynP-ee0.js";
2
+ import { A as LifecycleReason, B as TickerOptions, C as LoopReason, D as Lifecycle, E as createLoop, F as SightPhase, H as TickerReason, I as SightReason, L as createSight, M as createLifecycle, N as Sight, O as LifecycleOptions, P as SightOptions, R as FrameState, S as LoopPhase, T as ReducedMotionBehavior, U as createTicker, V as TickerPhase, _ as createRenderState, a as PointerState, b as Loop, c as MutationOptions, d as createMutation, f as IdleOptions, g as RenderStateOptions, h as RenderState, i as PointerReason, j as LifecycleReducedMotion, k as LifecyclePhase, l as MutationPhase, m as RenderPhase, n as PointerOptions, o as createPointer, p as whenIdle, r as PointerPhase, s as Mutation, t as Pointer, u as MutationReason, v as DegradedBehavior, w as Quality, x as LoopOptions, y as DegradedReason, z as Ticker } from "./index-tRHsbTE2.js";
3
3
 
4
4
  //#region src/core/scroll-progress/index.d.ts
5
5
  interface ScrollProgressOptions {
@@ -95,5 +95,5 @@ declare class PhaseError extends Error {
95
95
  /** Check if a value is a PhaseError instance. */
96
96
  declare function isPhaseError(error: unknown): error is PhaseError;
97
97
  //#endregion
98
- export { type DegradedBehavior, type DegradedReason, type DevicePixelRatio, type DevicePixelRatioOptions, type FrameState, type IdleOptions, type Lifecycle, type LifecycleOptions, type LifecyclePhase, type LifecycleReason, type LifecycleReducedMotion, type Loop, type LoopOptions, type LoopPhase, type LoopReason, type Mutation, type MutationOptions, type MutationPhase, type MutationReason, PhaseError, type PhaseErrorCode, type Quality, type ReducedMotionBehavior, type RemapOptions, type RenderPhase, type RenderState, type RenderStateOptions, type ScrollProgress, type ScrollProgressOptions, type Sight, type SightOptions, type SightPhase, type SightReason, type Ticker, type TickerOptions, type TickerPhase, type TickerReason, clamp, clamp01, createDevicePixelRatio, createLifecycle, createLoop, createMutation, createRenderState, createScrollProgress, createSight, createTicker, easeInOutCubic, easeOutBack, easeOutCubic, easeOutQuart, inverseLerp, isPhaseError, lerp, linear, prefersReducedMotion, remap, whenIdle };
98
+ export { type DegradedBehavior, type DegradedReason, type DevicePixelRatio, type DevicePixelRatioOptions, type FrameState, type IdleOptions, type Lifecycle, type LifecycleOptions, type LifecyclePhase, type LifecycleReason, type LifecycleReducedMotion, type Loop, type LoopOptions, type LoopPhase, type LoopReason, type Mutation, type MutationOptions, type MutationPhase, type MutationReason, PhaseError, type PhaseErrorCode, type Pointer, type PointerOptions, type PointerPhase, type PointerReason, type PointerState, type Quality, type ReducedMotionBehavior, type RemapOptions, type RenderPhase, type RenderState, type RenderStateOptions, type ScrollProgress, type ScrollProgressOptions, type Sight, type SightOptions, type SightPhase, type SightReason, type Ticker, type TickerOptions, type TickerPhase, type TickerReason, clamp, clamp01, createDevicePixelRatio, createLifecycle, createLoop, createMutation, createPointer, createRenderState, createScrollProgress, createSight, createTicker, easeInOutCubic, easeOutBack, easeOutCubic, easeOutQuart, inverseLerp, isPhaseError, lerp, linear, prefersReducedMotion, remap, whenIdle };
99
99
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { clamp, clamp01, easeInOutCubic, easeOutBack, easeOutCubic, easeOutQuart, inverseLerp, lerp, linear, remap } from "./ease.js";
2
- import { _ as isPhaseError, a as readDpr, b as linkAbortSignal, c as createScrollProgress, h as PhaseError, i as whenIdle, l as createLoop, m as createTicker, o as subscribeDpr, p as createSight, r as prefersReducedMotion, s as createRenderState, t as createMutation, u as createLifecycle, y as serverContextError } from "./mutation-BDx6r5D3.js";
2
+ import { a as whenIdle, b as serverContextError, c as createRenderState, d as createLifecycle, g as PhaseError, h as createTicker, i as prefersReducedMotion, l as createScrollProgress, m as createSight, n as createMutation, o as readDpr, s as subscribeDpr, t as createPointer, u as createLoop, v as isPhaseError, x as linkAbortSignal } from "./pointer-D5F7_Jjs.js";
3
3
  //#region src/core/device-pixel-ratio/index.ts
4
4
  /**
5
5
  * Track devicePixelRatio changes (e.g. user drags the window between monitors
@@ -42,6 +42,6 @@ function createDevicePixelRatio(options) {
42
42
  };
43
43
  }
44
44
  //#endregion
45
- export { PhaseError, clamp, clamp01, createDevicePixelRatio, createLifecycle, createLoop, createMutation, createRenderState, createScrollProgress, createSight, createTicker, easeInOutCubic, easeOutBack, easeOutCubic, easeOutQuart, inverseLerp, isPhaseError, lerp, linear, prefersReducedMotion, remap, whenIdle };
45
+ export { PhaseError, clamp, clamp01, createDevicePixelRatio, createLifecycle, createLoop, createMutation, createPointer, createRenderState, createScrollProgress, createSight, createTicker, easeInOutCubic, easeOutBack, easeOutCubic, easeOutQuart, inverseLerp, isPhaseError, lerp, linear, prefersReducedMotion, remap, whenIdle };
46
46
 
47
47
  //# sourceMappingURL=index.js.map
@@ -1061,6 +1061,152 @@ function warnReflowStorm(opts) {
1061
1061
  console.warn("[phase] createMutation: observing subtree + attributeFilter including \"style\" or \"class\" fires on every descendant style/class change (animations, hovers, framework churn). Narrow the scope or use a visibility signal instead.");
1062
1062
  }
1063
1063
  //#endregion
1064
- export { isPhaseError as _, readDpr as a, linkAbortSignal as b, createScrollProgress as c, readMediaQuery as d, subscribeMediaQuery as f, invalidDurationError as g, PhaseError as h, whenIdle as i, createLoop as l, createTicker as m, REDUCED_MOTION_QUERY as n, subscribeDpr as o, createSight as p, prefersReducedMotion as r, createRenderState as s, createMutation as t, createLifecycle as u, missingContextError as v, serverContextError as y };
1064
+ //#region src/core/pointer/index.ts
1065
+ /** Lifecycle-aware pointer tracker with rAF-batched `getBoundingClientRect`. */
1066
+ function createPointer(options) {
1067
+ if (typeof document === "undefined") serverContextError("createPointer");
1068
+ const { element, onPointer, onPhaseChange, visibility = "pause", intersectionOptions, signal } = options;
1069
+ if (!element) noElementError("createPointer");
1070
+ let _phase = "idle";
1071
+ let _reason = "initial";
1072
+ let stopped = false;
1073
+ const _state = {
1074
+ x: 0,
1075
+ y: 0,
1076
+ active: false
1077
+ };
1078
+ let rafId = 0;
1079
+ let lastClientX = 0;
1080
+ let lastClientY = 0;
1081
+ let dirty = false;
1082
+ function setPhase(phase, reason) {
1083
+ const prev = _phase;
1084
+ _phase = phase;
1085
+ _reason = reason;
1086
+ if (prev !== phase) onPhaseChange?.(phase, reason);
1087
+ }
1088
+ function flush() {
1089
+ rafId = 0;
1090
+ if (!dirty || stopped) return;
1091
+ dirty = false;
1092
+ const rect = element.getBoundingClientRect();
1093
+ _state.x = lastClientX - rect.left;
1094
+ _state.y = lastClientY - rect.top;
1095
+ onPointer(_state);
1096
+ }
1097
+ function scheduleFlush() {
1098
+ if (rafId !== 0) return;
1099
+ rafId = requestAnimationFrame(flush);
1100
+ }
1101
+ function cancelFlush() {
1102
+ if (rafId !== 0) {
1103
+ cancelAnimationFrame(rafId);
1104
+ rafId = 0;
1105
+ }
1106
+ dirty = false;
1107
+ }
1108
+ function onPointerMove(e) {
1109
+ if (stopped || _phase !== "tracking") return;
1110
+ const pe = e;
1111
+ lastClientX = pe.clientX;
1112
+ lastClientY = pe.clientY;
1113
+ dirty = true;
1114
+ scheduleFlush();
1115
+ }
1116
+ function onPointerEnter() {
1117
+ if (stopped) return;
1118
+ _state.active = true;
1119
+ setPhase("tracking", "enter");
1120
+ }
1121
+ function onPointerLeave() {
1122
+ if (stopped) return;
1123
+ cancelFlush();
1124
+ _state.active = false;
1125
+ setPhase("idle", "leave");
1126
+ onPointer(_state);
1127
+ }
1128
+ let cleanupVisibility;
1129
+ let listenersAttached = false;
1130
+ function attachListeners() {
1131
+ if (listenersAttached) return;
1132
+ listenersAttached = true;
1133
+ element.addEventListener("pointermove", onPointerMove);
1134
+ element.addEventListener("pointerenter", onPointerEnter);
1135
+ element.addEventListener("pointerleave", onPointerLeave);
1136
+ }
1137
+ function detachListeners() {
1138
+ if (!listenersAttached) return;
1139
+ listenersAttached = false;
1140
+ element.removeEventListener("pointermove", onPointerMove);
1141
+ element.removeEventListener("pointerenter", onPointerEnter);
1142
+ element.removeEventListener("pointerleave", onPointerLeave);
1143
+ }
1144
+ if (visibility === "pause") {
1145
+ let elementInView = false;
1146
+ let documentVisible = !document.hidden;
1147
+ function recompute() {
1148
+ if (stopped) return;
1149
+ if (documentVisible && elementInView) attachListeners();
1150
+ else {
1151
+ detachListeners();
1152
+ if (_state.active) {
1153
+ cancelFlush();
1154
+ _state.active = false;
1155
+ setPhase("idle", "sight");
1156
+ }
1157
+ }
1158
+ }
1159
+ function onVisChange() {
1160
+ documentVisible = !document.hidden;
1161
+ recompute();
1162
+ }
1163
+ function onPageShow(event) {
1164
+ if (!event.persisted) return;
1165
+ documentVisible = true;
1166
+ recompute();
1167
+ }
1168
+ document.addEventListener("visibilitychange", onVisChange);
1169
+ window.addEventListener("pageshow", onPageShow);
1170
+ const unobserveIO = observeIntersection({
1171
+ element,
1172
+ onIntersect: (entry) => {
1173
+ elementInView = entry.isIntersecting;
1174
+ recompute();
1175
+ },
1176
+ ...intersectionOptions
1177
+ });
1178
+ cleanupVisibility = () => {
1179
+ document.removeEventListener("visibilitychange", onVisChange);
1180
+ window.removeEventListener("pageshow", onPageShow);
1181
+ unobserveIO();
1182
+ };
1183
+ } else attachListeners();
1184
+ let unlinkAbort;
1185
+ function stop() {
1186
+ if (stopped) return;
1187
+ stopped = true;
1188
+ unlinkAbort?.();
1189
+ cleanupVisibility?.();
1190
+ detachListeners();
1191
+ cancelFlush();
1192
+ _state.active = false;
1193
+ setPhase("stopped", "disposed");
1194
+ }
1195
+ unlinkAbort = linkAbortSignal(signal, stop);
1196
+ return {
1197
+ get phase() {
1198
+ return _phase;
1199
+ },
1200
+ get phaseReason() {
1201
+ return _reason;
1202
+ },
1203
+ get state() {
1204
+ return _state;
1205
+ },
1206
+ stop
1207
+ };
1208
+ }
1209
+ //#endregion
1210
+ export { invalidDurationError as _, whenIdle as a, serverContextError as b, createRenderState as c, createLifecycle as d, readMediaQuery as f, PhaseError as g, createTicker as h, prefersReducedMotion as i, createScrollProgress as l, createSight as m, createMutation as n, readDpr as o, subscribeMediaQuery as p, REDUCED_MOTION_QUERY as r, subscribeDpr as s, createPointer as t, createLoop as u, isPhaseError as v, linkAbortSignal as x, missingContextError as y };
1065
1211
 
1066
- //# sourceMappingURL=mutation-BDx6r5D3.js.map
1212
+ //# sourceMappingURL=pointer-D5F7_Jjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer-D5F7_Jjs.js","names":["pool","createPoolEntry","REDUCED_MOTION_QUERY"],"sources":["../src/core/_internal/abort/index.ts","../src/core/_internal/errors/index.ts","../src/core/tick/index.ts","../src/core/_internal/pool/io-pool.ts","../src/core/sight/index.ts","../src/core/_internal/pool/mql-pool.ts","../src/core/lifecycle/index.ts","../src/core/loop/index.ts","../src/core/scroll-progress/index.ts","../src/core/render-state/index.ts","../src/core/_internal/pool/dpr.ts","../src/core/idle/index.ts","../src/core/reduced-motion/index.ts","../src/core/mutation/index.ts","../src/core/pointer/index.ts"],"sourcesContent":["/**\n * Link an optional `AbortSignal` to a primitive's `stop`/cancel function.\n *\n * When the signal aborts, `stop` runs once. If the signal is already aborted,\n * `stop` runs synchronously. Returns an unlink function that removes the abort\n * listener. Call it from inside `stop` so a manual stop does not leave a\n * dangling listener on a long-lived controller.\n *\n * The listener is registered with `{ once: true }`, so abort and manual stop\n * are safe to interleave: whichever fires first wins, the other is a no-op.\n */\nexport function linkAbortSignal(\n signal: AbortSignal | undefined,\n stop: () => void,\n): () => void {\n if (!signal) return unlinkNoop;\n if (signal.aborted) {\n stop();\n return unlinkNoop;\n }\n signal.addEventListener('abort', stop, { once: true });\n return () => signal.removeEventListener('abort', stop);\n}\n\n/** Shared empty unlink for the no-signal and already-aborted paths. */\nfunction unlinkNoop(): void {\n // No listener was registered, so there is nothing to remove.\n}\n","export type PhaseErrorCode =\n | 'server_context'\n | 'no_element'\n | 'invalid_duration'\n | 'ticker_stopped'\n | 'missing_context';\n\ninterface PhaseErrorOptions {\n code: PhaseErrorCode;\n reason?: string;\n fix?: string;\n link?: string;\n}\n\n/** Lightweight structured error for phase. */\nexport class PhaseError extends Error {\n readonly code: PhaseErrorCode;\n readonly reason: string | undefined;\n readonly fix: string | undefined;\n readonly link: string | undefined;\n\n constructor(message: string, options: PhaseErrorOptions) {\n super(message);\n this.name = 'PhaseError';\n this.code = options.code;\n this.reason = options.reason;\n this.fix = options.fix;\n this.link = options.link;\n }\n}\n\n/** Check if a value is a PhaseError instance. */\nexport function isPhaseError(error: unknown): error is PhaseError {\n return error instanceof PhaseError;\n}\n\nexport function serverContextError(fn: string): never {\n throw new PhaseError(`${fn}() cannot be called on the server.`, {\n code: 'server_context',\n reason: 'Browser APIs are unavailable during SSR.',\n fix: 'Move into a useEffect or client-only module.',\n });\n}\n\nexport function noElementError(fn: string): never {\n throw new PhaseError(`${fn}() requires a DOM element.`, {\n code: 'no_element',\n reason: 'The element was null or undefined.',\n fix: 'Pass a mounted Element, or use the React hook which manages the ref.',\n });\n}\n\nexport function invalidDurationError(fn: string, value: number): never {\n throw new PhaseError(`${fn}() received an invalid duration: ${value}`, {\n code: 'invalid_duration',\n reason: 'Duration must be a finite positive number.',\n fix: 'Pass a positive number (e.g., 300 for 300ms).',\n });\n}\n\nexport function tickerStoppedError(): never {\n throw new PhaseError('Cannot resume a stopped ticker.', {\n code: 'ticker_stopped',\n reason: 'stop() is terminal, so a stopped ticker cannot be resumed.',\n fix: 'Create a new ticker instance instead of resuming a stopped one.',\n });\n}\n\nexport function missingContextError(child: string, parent: string): never {\n throw new PhaseError(`<${child}> must be used inside <${parent}>.`, {\n code: 'missing_context',\n reason: `<${child}> reads from a context that <${parent}> provides.`,\n fix: `Wrap <${child}> with <${parent}>.`,\n });\n}\n","import { linkAbortSignal } from '../_internal/abort';\nimport { serverContextError, tickerStoppedError } from '../_internal/errors';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface FrameState {\n /** Current timestamp from performance.now(). */\n time: number;\n /** Milliseconds since last tick, clamped to 40ms. */\n delta: number;\n /** Milliseconds since start, excluding paused time. */\n elapsed: number;\n /** Frame count since start. */\n frame: number;\n}\n\nexport type TickerPhase = 'idle' | 'running' | 'paused' | 'stopped';\nexport type TickerReason =\n | 'initial'\n | 'started'\n | 'resumed'\n | 'manual'\n | 'disposed';\n\nexport interface TickerOptions {\n /** Cap frame rate. Default: uncapped (display refresh rate). */\n fps?: number;\n /**\n * Called every frame with the current frame state. Write to refs or DOM\n * directly. Never call React `setState` here (60 state updates/sec = 60 re-renders/sec).\n */\n onTick: (frame: FrameState) => void;\n /** Abort signal that stops the ticker when aborted. */\n signal?: AbortSignal;\n}\n\nexport interface Ticker {\n start(): void;\n stop(): void;\n pause(): void;\n resume(): void;\n readonly phase: TickerPhase;\n readonly phaseReason: TickerReason;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Prevents teleportation on resume. Matches motion's maxElapsed. */\nconst MAX_DELTA_MS = 40;\n\n/** Default first-frame delta when no previous tick exists. */\nconst DEFAULT_FIRST_DELTA_MS = 16.67;\n\n// ---------------------------------------------------------------------------\n// Shared frame-locked clock\n//\n// All ticker instances subscribe to a single rAF loop so they read the same\n// timestamp each frame. This prevents visual desync between multiple loops\n// on the same page. The clock starts when the first subscriber joins and\n// stops when the last one leaves.\n// ---------------------------------------------------------------------------\n\nlet sharedTime = 0;\nlet sharedRafId = 0;\nconst sharedSubscribers = new Set<() => void>();\n\nfunction sharedTick(): void {\n sharedTime = performance.now();\n for (const callback of sharedSubscribers) callback();\n if (sharedSubscribers.size > 0) {\n sharedRafId = requestAnimationFrame(sharedTick);\n }\n}\n\nfunction joinSharedClock(callback: () => void): () => void {\n const wasEmpty: boolean = sharedSubscribers.size === 0;\n sharedSubscribers.add(callback);\n\n if (wasEmpty) {\n sharedTime = performance.now();\n sharedRafId = requestAnimationFrame(sharedTick);\n }\n\n return () => {\n sharedSubscribers.delete(callback);\n if (sharedSubscribers.size === 0 && sharedRafId) {\n cancelAnimationFrame(sharedRafId);\n sharedRafId = 0;\n }\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction resetFrameState(state: FrameState): void {\n state.time = 0;\n state.delta = 0;\n state.elapsed = 0;\n state.frame = 0;\n}\n\n// ---------------------------------------------------------------------------\n// createTicker\n// ---------------------------------------------------------------------------\n\n/**\n * Core rAF loop primitive with FPS cap, delta clamping, and strong pause.\n *\n * @remarks\n * `FrameState` is reused across frames. Do not store a reference to it.\n * Read values immediately in your `onTick` callback.\n */\nexport function createTicker(options: TickerOptions): Ticker {\n if (typeof requestAnimationFrame === 'undefined') {\n serverContextError('createTicker');\n }\n\n const { onTick, fps, signal } = options;\n const minFrameTime: number = fps ? 1000 / fps : 0;\n\n let _phase: TickerPhase = 'idle';\n let _reason: TickerReason = 'initial';\n let leaveSharedClock: (() => void) | null = null;\n\n let lastTickTime = 0;\n let pauseStartTime = 0;\n let totalPausedTime = 0;\n let startTime = 0;\n\n // Pre-allocated, mutated in place each frame — zero allocations per tick.\n const frame: FrameState = { time: 0, delta: 0, elapsed: 0, frame: 0 };\n\n function tick(): void {\n const now: number = sharedTime;\n\n // FPS throttle: skip this frame if we're ahead of the target interval.\n if (minFrameTime > 0 && now - lastTickTime < minFrameTime) return;\n\n const rawDelta: number =\n lastTickTime === 0 ? DEFAULT_FIRST_DELTA_MS : now - lastTickTime;\n lastTickTime = now;\n\n frame.time = now;\n frame.delta = rawDelta > MAX_DELTA_MS ? MAX_DELTA_MS : rawDelta;\n frame.elapsed = now - startTime - totalPausedTime;\n frame.frame++;\n\n onTick(frame);\n }\n\n function start(): void {\n if (_phase === 'running') return;\n if (_phase === 'stopped') tickerStoppedError();\n if (_phase === 'paused') {\n resume();\n return;\n }\n\n _phase = 'running';\n _reason = 'started';\n startTime = performance.now();\n lastTickTime = 0;\n totalPausedTime = 0;\n resetFrameState(frame);\n\n leaveSharedClock = joinSharedClock(tick);\n }\n\n function pause(): void {\n if (_phase !== 'running') return;\n\n _phase = 'paused';\n _reason = 'manual';\n pauseStartTime = performance.now();\n\n // Strong pause: cancel rAF subscription entirely — zero CPU while paused.\n leaveSharedClock?.();\n leaveSharedClock = null;\n }\n\n function resume(): void {\n if (_phase === 'stopped') tickerStoppedError();\n if (_phase !== 'paused') return;\n\n totalPausedTime += performance.now() - pauseStartTime;\n // Reset so the first resumed tick gets a clean delta (not the pause gap).\n lastTickTime = 0;\n\n _phase = 'running';\n _reason = 'resumed';\n leaveSharedClock = joinSharedClock(tick);\n }\n\n function stop(): void {\n if (_phase === 'stopped') return;\n\n _phase = 'stopped';\n _reason = _reason === 'initial' ? 'disposed' : 'manual';\n unlinkAbort?.();\n leaveSharedClock?.();\n leaveSharedClock = null;\n }\n\n // Declared before assignment because an already-aborted signal makes\n // linkAbortSignal call stop() synchronously, which reads unlinkAbort.\n let unlinkAbort: (() => void) | undefined;\n unlinkAbort = linkAbortSignal(signal, stop);\n\n return {\n start,\n stop,\n pause,\n resume,\n get phase() {\n return _phase;\n },\n get phaseReason() {\n return _reason;\n },\n };\n}\n","type IOCallback = (entry: IntersectionObserverEntry) => void;\n\nexport interface ObserveIntersectionOptions {\n element: Element;\n onIntersect: IOCallback;\n root?: Element | Document | null;\n rootMargin?: string;\n threshold?: number | number[];\n}\n\ninterface IOPoolEntry {\n observer: IntersectionObserver;\n callbacks: Map<Element, IOCallback>;\n}\n\nconst pool = new Map<string, IOPoolEntry>();\n\n/**\n * Observe an element via a shared IntersectionObserver pool.\n * Elements with identical options share one IO instance.\n *\n * @returns Cleanup function that unobserves the element and removes the IO if empty.\n */\nexport function observeIntersection(\n options: ObserveIntersectionOptions,\n): () => void {\n const { element, onIntersect, root, rootMargin, threshold } = options;\n const ioInit: IntersectionObserverInit = { root, rootMargin, threshold };\n\n const key: string = getPoolKey(ioInit);\n const entry: IOPoolEntry = getOrCreatePoolEntry(key, ioInit);\n\n entry.callbacks.set(element, onIntersect);\n entry.observer.observe(element);\n\n let disposed = false;\n\n return () => {\n if (disposed) return;\n disposed = true;\n\n const poolEntry: IOPoolEntry | undefined = pool.get(key);\n if (!poolEntry) return;\n\n // Only unobserve if our callback is still the registered one.\n // A later subscription on the same element would have overwritten it.\n if (poolEntry.callbacks.get(element) === onIntersect) {\n poolEntry.observer.unobserve(element);\n poolEntry.callbacks.delete(element);\n }\n\n if (poolEntry.callbacks.size === 0) {\n poolEntry.observer.disconnect();\n pool.delete(key);\n }\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Produces a stable string key from IO options to group observers in the pool.\n * IO options are immutable after construction, so identical options can share.\n */\nfunction getPoolKey(opts: IntersectionObserverInit): string {\n const root = opts.root ? 'custom' : 'null';\n const margin = opts.rootMargin ?? '0px';\n const threshold = Array.isArray(opts.threshold)\n ? opts.threshold.join(',')\n : String(opts.threshold ?? 0);\n\n return root + '|' + margin + '|' + threshold;\n}\n\n/** Return an existing pool entry for this key, or create and register a new one. */\nfunction getOrCreatePoolEntry(\n key: string,\n options: IntersectionObserverInit,\n): IOPoolEntry {\n const existing: IOPoolEntry | undefined = pool.get(key);\n if (existing) return existing;\n\n const entry = createPoolEntry(options);\n\n pool.set(key, entry);\n return entry;\n}\n\n/** Create a new pool entry for the given options. */\nconst createPoolEntry = (options: IntersectionObserverInit): IOPoolEntry => {\n const callbacks = new Map<Element, IOCallback>();\n const observer = new IntersectionObserver((entries) => {\n for (const ioEntry of entries) {\n const cb: IOCallback | undefined = callbacks.get(ioEntry.target);\n if (cb) cb(ioEntry);\n }\n }, options);\n\n return { observer, callbacks };\n};\n","import { linkAbortSignal } from '../_internal/abort';\nimport { noElementError, serverContextError } from '../_internal/errors';\nimport { observeIntersection } from '../_internal/pool/io-pool';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type SightPhase = 'unknown' | 'visible' | 'hidden';\nexport type SightReason =\n | 'initial'\n | 'viewport'\n | 'document'\n | 'bfcache'\n | 'all-hidden';\n\nexport interface SightOptions {\n element: Element;\n intersectionOptions?: IntersectionObserverInit;\n onPhaseChange?: (phase: SightPhase, reason: SightReason) => void;\n /** Abort signal that stops the observer when aborted. */\n signal?: AbortSignal;\n}\n\nexport interface Sight {\n readonly phase: SightPhase;\n readonly phaseReason: SightReason;\n stop(): void;\n}\n\n// ---------------------------------------------------------------------------\n// createSight\n// ---------------------------------------------------------------------------\n\n/**\n * Visibility observer combining document focus and viewport intersection.\n *\n * `phase` is `'visible'` only when both the document is visible (not backgrounded)\n * and the element is within the viewport. Uses a shared IntersectionObserver\n * pool. Multiple `createSight` calls with the same options share one observer.\n *\n * @example\n * const sight = createSight({\n * element: el,\n * onPhaseChange: (phase) => phase === 'visible' ? loop.start() : loop.pause(),\n * });\n * // cleanup:\n * sight.stop();\n *\n * @remarks\n * `onPhaseChange` fires only on phase transitions, not on every IntersectionObserver callback.\n */\nexport function createSight(options: SightOptions): Sight {\n if (typeof document === 'undefined') {\n serverContextError('createSight');\n }\n\n const { element, intersectionOptions, onPhaseChange, signal } = options;\n\n if (!element) noElementError('createSight');\n\n let _phase: SightPhase = 'unknown';\n let _reason: SightReason = 'initial';\n let stopped = false;\n\n let documentVisible: boolean = !document.hidden;\n let elementInView = false;\n\n function recompute(trigger: SightReason): void {\n if (stopped) return;\n\n const prev = _phase;\n const next: SightPhase =\n documentVisible && elementInView ? 'visible' : 'hidden';\n\n _reason =\n next === 'hidden' && !documentVisible && !elementInView\n ? 'all-hidden'\n : trigger;\n\n if (next === prev) return;\n _phase = next;\n onPhaseChange?.(_phase, _reason);\n }\n\n // --- Signal handlers ---\n\n function onVisibilityChange(): void {\n documentVisible = !document.hidden;\n recompute('document');\n }\n\n function onPageShow(event: PageTransitionEvent): void {\n if (!event.persisted) return;\n documentVisible = true;\n recompute('bfcache');\n }\n\n function onIntersection(entry: IntersectionObserverEntry): void {\n elementInView = entry.isIntersecting;\n recompute('viewport');\n }\n\n // --- Subscribe ---\n\n document.addEventListener('visibilitychange', onVisibilityChange);\n window.addEventListener('pageshow', onPageShow);\n const unobserveIO: () => void = observeIntersection({\n element,\n onIntersect: onIntersection,\n ...intersectionOptions,\n });\n\n let unlinkAbort: (() => void) | undefined;\n\n function stop(): void {\n if (stopped) return;\n stopped = true;\n unlinkAbort?.();\n document.removeEventListener('visibilitychange', onVisibilityChange);\n window.removeEventListener('pageshow', onPageShow);\n unobserveIO();\n _phase = 'hidden';\n _reason = 'initial';\n }\n\n unlinkAbort = linkAbortSignal(signal, stop);\n\n return {\n get phase() {\n return stopped ? 'hidden' : _phase;\n },\n get phaseReason() {\n return _reason;\n },\n stop,\n };\n}\n","type MQLCallback = (matches: boolean) => void;\n\ninterface MQLPoolEntry {\n mql: MediaQueryList;\n listeners: Set<MQLCallback>;\n handler: (e: MediaQueryListEvent) => void;\n}\n\nconst pool = new Map<string, MQLPoolEntry>();\n\n/**\n * Subscribe to a media query via a shared MediaQueryList pool.\n * Multiple subscribers to the same query share one MQL and one change listener.\n *\n * @returns Cleanup function that removes the subscriber.\n */\nexport function subscribeMediaQuery(\n query: string,\n callback: MQLCallback,\n): () => void {\n const entry: MQLPoolEntry = getOrCreateEntry(query);\n\n entry.listeners.add(callback);\n\n let disposed = false;\n\n return () => {\n if (disposed) return;\n disposed = true;\n\n const poolEntry: MQLPoolEntry | undefined = pool.get(query);\n if (!poolEntry) return;\n poolEntry.listeners.delete(callback);\n\n if (poolEntry.listeners.size === 0) {\n poolEntry.mql.removeEventListener('change', poolEntry.handler);\n pool.delete(query);\n }\n };\n}\n\n/**\n * Synchronous read of a media query via the shared pool.\n * Uses the existing pool entry if available, otherwise reads directly.\n */\nexport function readMediaQuery(query: string): boolean {\n const entry: MQLPoolEntry | undefined = pool.get(query);\n if (entry) return entry.mql.matches;\n return matchMedia(query).matches;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Return an existing pool entry for this query, or create and register a new one. */\nfunction getOrCreateEntry(query: string): MQLPoolEntry {\n const existing: MQLPoolEntry | undefined = pool.get(query);\n if (existing) return existing;\n\n const entry = createPoolEntry(query);\n\n entry.mql.addEventListener('change', entry.handler);\n pool.set(query, entry);\n\n return entry;\n}\n\nconst createPoolEntry = (query: string): MQLPoolEntry => {\n const mql: MediaQueryList = matchMedia(query);\n const listeners = new Set<MQLCallback>();\n\n const handler = (event: MediaQueryListEvent): void => {\n for (const cb of listeners) cb(event.matches);\n };\n return { mql, listeners, handler };\n};\n","import { linkAbortSignal } from '../_internal/abort';\nimport { noElementError, serverContextError } from '../_internal/errors';\nimport {\n readMediaQuery,\n subscribeMediaQuery,\n} from '../_internal/pool/mql-pool';\nimport { createSight } from '../sight';\nimport type { SightPhase } from '../sight';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type LifecyclePhase = 'idle' | 'active' | 'paused' | 'stopped';\nexport type LifecycleReason =\n | 'initial'\n | 'started'\n | 'resumed'\n | 'sight'\n | 'reduced-motion'\n | 'manual'\n | 'disposed';\n\n/** Whether reduced motion pauses the lifecycle. Default `'pause'`. */\nexport type LifecycleReducedMotion = 'pause' | 'ignore';\n\nexport interface LifecycleOptions {\n element: Element;\n reducedMotion?: LifecycleReducedMotion;\n intersectionOptions?: IntersectionObserverInit;\n start?: 'auto' | 'manual';\n onPhaseChange?: (phase: LifecyclePhase, reason: LifecycleReason) => void;\n /** Abort signal that stops the lifecycle when aborted. */\n signal?: AbortSignal;\n}\n\nexport interface Lifecycle {\n /** Begin honoring signals. Called automatically unless `start: 'manual'`. */\n start(): void;\n /** Terminal. Disposes observers and listeners. Cannot be restarted. */\n stop(): void;\n /** Manually pause (e.g. a panel opened over the animation). Lowest priority. */\n pause(): void;\n /** Clear a manual pause. */\n resume(): void;\n readonly phase: LifecyclePhase;\n readonly phaseReason: LifecycleReason;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)';\n\n// ---------------------------------------------------------------------------\n// createLifecycle\n// ---------------------------------------------------------------------------\n\n/**\n * The activation decision for an animation, decoupled from who drives the frames.\n *\n * Composes visibility (`createSight`), reduced motion, and a manual pause into a\n * single `active` / `paused` phase. Use when you own your render loop (WebGL,\n * three.js, a Web Worker, or non-rAF work that should still pause off-screen or\n * under reduced motion). For loops `phase` should drive, use `createLoop` instead.\n *\n * @example\n * const lifecycle = createLifecycle({\n * element: canvas,\n * onPhaseChange: (phase) => {\n * if (phase === 'active') renderer.start();\n * else renderer.stop();\n * },\n * });\n * // cleanup:\n * lifecycle.stop();\n */\nexport function createLifecycle(options: LifecycleOptions): Lifecycle {\n if (typeof document === 'undefined') {\n serverContextError('createLifecycle');\n }\n\n const {\n element,\n reducedMotion = 'pause',\n intersectionOptions,\n start: startMode = 'auto',\n onPhaseChange,\n signal,\n } = options;\n\n if (!element) noElementError('createLifecycle');\n\n let _phase: LifecyclePhase = 'idle';\n let _reason: LifecycleReason = 'initial';\n\n let sightVisible = false;\n let reducedMotionActive = false;\n let manualPaused = false;\n let intentStarted = false;\n let hasBeenActive = false;\n\n function setPhase(phase: LifecyclePhase, reason: LifecycleReason): void {\n if (_phase === phase && _reason === reason) return;\n _phase = phase;\n _reason = reason;\n onPhaseChange?.(phase, reason);\n }\n\n /** Highest-priority active pause signal, or null when nothing should pause. */\n function pauseReason(): LifecycleReason | null {\n if (reducedMotionActive && reducedMotion === 'pause')\n return 'reduced-motion';\n if (!sightVisible) return 'sight';\n if (manualPaused) return 'manual';\n return null;\n }\n\n function reconcile(): void {\n if (_phase === 'stopped' || !intentStarted) return;\n\n const reason = pauseReason();\n if (reason) {\n setPhase('paused', reason);\n return;\n }\n\n setPhase('active', hasBeenActive ? 'resumed' : 'started');\n hasBeenActive = true;\n }\n\n // --- Signal handlers ---\n\n function onSightChange(phase: SightPhase): void {\n sightVisible = phase === 'visible';\n reconcile();\n }\n\n function onReducedMotionChange(matches: boolean): void {\n reducedMotionActive = matches;\n reconcile();\n }\n\n // --- Init subsystems ---\n\n const sight = createSight({\n element,\n intersectionOptions,\n onPhaseChange: onSightChange,\n });\n\n let unsubReducedMotion: (() => void) | null = null;\n if (reducedMotion !== 'ignore') {\n reducedMotionActive = readMediaQuery(REDUCED_MOTION_QUERY);\n unsubReducedMotion = subscribeMediaQuery(\n REDUCED_MOTION_QUERY,\n onReducedMotionChange,\n );\n }\n\n // --- Public API ---\n\n function start(): void {\n if (_phase === 'stopped') return;\n intentStarted = true;\n reconcile();\n }\n\n function stop(): void {\n if (_phase === 'stopped') return;\n unlinkAbort?.();\n sight.stop();\n unsubReducedMotion?.();\n unsubReducedMotion = null;\n setPhase('stopped', 'disposed');\n }\n\n function pause(): void {\n if (manualPaused) return;\n manualPaused = true;\n reconcile();\n }\n\n function resume(): void {\n if (!manualPaused) return;\n manualPaused = false;\n reconcile();\n }\n\n let unlinkAbort: (() => void) | undefined;\n unlinkAbort = linkAbortSignal(signal, stop);\n\n if (startMode === 'auto') {\n start();\n }\n\n return {\n start,\n stop,\n pause,\n resume,\n get phase() {\n return _phase;\n },\n get phaseReason() {\n return _reason;\n },\n };\n}\n","import { linkAbortSignal } from '../_internal/abort';\nimport { noElementError, serverContextError } from '../_internal/errors';\nimport { createLifecycle } from '../lifecycle';\nimport { createTicker } from '../tick';\nimport type { FrameState, Ticker } from '../tick';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type ReducedMotionBehavior = 'pause' | 'complete' | 'ignore';\nexport type DegradedBehavior = 'throttle' | 'pause' | 'ignore';\n\nexport type LoopPhase = 'idle' | 'running' | 'paused' | 'stopped';\nexport type LoopReason =\n | 'initial'\n | 'started'\n | 'resumed'\n | 'sight'\n | 'reduced-motion'\n | 'degraded'\n | 'manual'\n | 'disposed';\n\nexport type Quality = 'full' | 'degraded';\nexport type DegradedReason = 'unfocused' | 'frame-budget';\n\ninterface LoopOptionsBase {\n element: Element;\n /**\n * Called every frame. Write to refs or DOM directly. Never call React\n * `setState` here (60 calls/sec = 60 re-renders/sec).\n */\n onTick: (frame: FrameState) => void;\n fps?: number;\n reducedMotion?: ReducedMotionBehavior;\n intersectionOptions?: IntersectionObserverInit;\n start?: 'auto' | 'manual';\n onPhaseChange?: (phase: LoopPhase, reason: LoopReason) => void;\n /** Abort signal that stops the loop when aborted. */\n signal?: AbortSignal;\n}\n\ntype DegradedOptions =\n | { degraded?: 'throttle'; degradedFps?: number }\n | { degraded: 'pause' }\n | { degraded: 'ignore' };\n\nexport type LoopOptions = LoopOptionsBase & DegradedOptions;\n\nexport interface Loop {\n start(): void;\n stop(): void;\n readonly phase: LoopPhase;\n readonly phaseReason: LoopReason;\n readonly quality: Quality;\n readonly qualityReason: DegradedReason | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** How many consecutive over-budget frames before degrading quality. */\nconst OVER_BUDGET_THRESHOLD = 3;\n\n/** FPS cap applied when quality is degraded (throttle mode). */\nconst DEGRADED_FPS_CAP = 30;\n\n/**\n * In `degraded: 'pause'` mode a frame-budget degrade pauses the loop, so no\n * further frames tick to clear it. Without a timer the loop would stay paused\n * forever after a transient spike. After this delay the loop optimistically\n * un-pauses and re-measures, rescheduling on each subsequent degrade. (Throttle\n * mode keeps ticking, so it does not use this.)\n */\nconst RECOVERY_RETRY_MS = 2000;\n\n// ---------------------------------------------------------------------------\n// createLoop\n// ---------------------------------------------------------------------------\n\n/**\n * Lifecycle-aware animation loop composing ticker, visibility, and reduced motion.\n *\n * Pass an element and get a loop that pauses when the element leaves the viewport\n * or the tab is backgrounded, resumes when it returns, and cleans up with `stop()`.\n *\n * @remarks\n * The loop is signal-driven and exposes only `start()` and `stop()`. There is no\n * imperative `pause()`/`resume()`. Pausing is decided by visibility, reduced\n * motion, and quality, so an imperative pause would compete with those signals.\n * For manual control, use `useLoop`'s `enabled` option (React) or `createLifecycle`,\n * which exposes `pause()`/`resume()` for loops you drive yourself.\n *\n * @example\n * const loop = createLoop({\n * element: el,\n * onTick: (frame) => draw(ctx, frame),\n * });\n * // cleanup:\n * loop.stop();\n */\nexport function createLoop(options: LoopOptions): Loop {\n if (typeof requestAnimationFrame === 'undefined') {\n serverContextError('createLoop');\n }\n\n const {\n element,\n onTick,\n fps: baseFps,\n reducedMotion = 'pause',\n degraded = 'throttle' as DegradedBehavior,\n degradedFps: configuredDegradedFps,\n intersectionOptions,\n start: startMode = 'auto',\n onPhaseChange,\n signal,\n } = options as LoopOptionsBase & {\n degraded?: DegradedBehavior;\n degradedFps?: number;\n signal?: AbortSignal;\n };\n\n if (!element) noElementError('createLoop');\n\n const degradedFps: number | undefined =\n degraded === 'throttle' ? configuredDegradedFps : undefined;\n\n // --- State ---\n\n let _phase: LoopPhase = 'idle';\n let _reason: LoopReason = 'initial';\n let _quality: Quality = 'full';\n let _qualityReason: DegradedReason | undefined;\n\n let intentStarted = false;\n let overBudgetCount = 0;\n let ticker: Ticker | null = null;\n\n // Quality signal flags\n let focusDegraded = false;\n\n // Pending pause-mode frame-budget recovery timer (see RECOVERY_RETRY_MS).\n let recoveryTimer: ReturnType<typeof setTimeout> | null = null;\n\n // --- State transitions ---\n\n function setPhase(phase: LoopPhase, reason: LoopReason): void {\n if (_phase === phase && _reason === reason) return;\n _phase = phase;\n _reason = reason;\n onPhaseChange?.(phase, reason);\n }\n\n function setQuality(quality: Quality, reason?: DegradedReason): void {\n const changed = _quality !== quality;\n _quality = quality;\n _qualityReason = reason;\n\n if (!changed) return;\n\n if (degraded === 'throttle') {\n if (ticker && _phase === 'running') {\n queueMicrotask(rebuildTicker);\n }\n } else if (degraded === 'pause') {\n reconcile();\n }\n }\n\n /** Evaluate all quality signals and pick the highest-priority active one. */\n function reconcileQuality(): void {\n if (focusDegraded) {\n setQuality('degraded', 'unfocused');\n return;\n }\n if (overBudgetCount >= OVER_BUDGET_THRESHOLD) {\n setQuality('degraded', 'frame-budget');\n return;\n }\n setQuality('full');\n }\n\n /**\n * Un-pause and re-measure after a pause-mode frame-budget degrade. If frames\n * are still over budget, the next degrade reschedules this.\n */\n function scheduleBudgetRecovery(): void {\n if (recoveryTimer !== null) return;\n recoveryTimer = setTimeout(() => {\n recoveryTimer = null;\n overBudgetCount = 0;\n reconcileQuality();\n }, RECOVERY_RETRY_MS);\n }\n\n function clearBudgetRecovery(): void {\n if (recoveryTimer === null) return;\n clearTimeout(recoveryTimer);\n recoveryTimer = null;\n }\n\n // --- Ticker lifecycle ---\n\n function getEffectiveFps(): number | undefined {\n if (_quality !== 'degraded') return baseFps;\n const cap: number = degradedFps ?? DEGRADED_FPS_CAP;\n if (baseFps === undefined) return cap;\n return Math.min(baseFps, cap);\n }\n\n function destroyTicker(): void {\n if (!ticker) return;\n ticker.stop();\n ticker = null;\n }\n\n function buildTicker(): void {\n const targetFps: number | undefined = getEffectiveFps();\n const budget: number = 1000 / (targetFps ?? 60);\n\n destroyTicker();\n\n ticker = createTicker({\n fps: targetFps,\n onTick: (frame) => {\n checkFrameBudget(frame.delta, budget);\n onTick(frame);\n },\n });\n ticker.start();\n }\n\n function rebuildTicker(): void {\n if (_phase !== 'running' || !ticker) return;\n buildTicker();\n }\n\n function checkFrameBudget(delta: number, budget: number): void {\n if (delta <= budget * 1.5) {\n overBudgetCount = 0;\n return;\n }\n\n overBudgetCount++;\n if (overBudgetCount < OVER_BUDGET_THRESHOLD) return;\n\n reconcileQuality();\n // Pause mode stops ticking once degraded, so no future frame can clear the\n // degraded state — schedule a timed retry. Throttle keeps running.\n if (degraded === 'pause') scheduleBudgetRecovery();\n }\n\n // --- Reconcile ---\n\n /** Check if any signal requires the loop to be paused. */\n function shouldPause(): LoopReason | null {\n // Visibility + reduced motion are owned by the lifecycle; its paused reasons\n // ('sight' | 'reduced-motion') are a subset of LoopReason.\n if (lifecycle.phase === 'paused')\n return lifecycle.phaseReason as LoopReason;\n // Quality-driven pause stays here — it needs the ticker's frame timing.\n if (degraded === 'pause' && _quality === 'degraded') return 'degraded';\n return null;\n }\n\n /** Evaluate all signals and transition to the correct phase. */\n function reconcile(): void {\n if (_phase === 'stopped' || !intentStarted) return;\n\n const pauseReason = shouldPause();\n\n if (pauseReason) {\n if (ticker && _phase === 'running') ticker.pause();\n setPhase('paused', pauseReason);\n return;\n }\n\n if (!ticker) {\n buildTicker();\n setPhase('running', _reason === 'initial' ? 'started' : 'resumed');\n } else if (_phase === 'paused') {\n ticker.resume();\n setPhase('running', 'resumed');\n }\n }\n\n // --- Signal handlers ---\n\n function onFocusChange(): void {\n focusDegraded = !document.hasFocus();\n reconcileQuality();\n }\n\n // --- Init subsystems ---\n\n // Lifecycle owns the visibility + reduced-motion decision. The loop layers the\n // ticker and quality (frame-budget / focus) on top. Driven manually so it only\n // activates once the loop itself starts.\n const lifecycle = createLifecycle({\n element,\n reducedMotion: reducedMotion === 'pause' ? 'pause' : 'ignore',\n intersectionOptions,\n start: 'manual',\n onPhaseChange: reconcile,\n });\n\n const unsubFocus: () => void = subscribeFocusTracking(onFocusChange);\n\n // --- Public API ---\n\n function start(): void {\n if (_phase === 'stopped') return;\n intentStarted = true;\n lifecycle.start();\n reconcile();\n }\n\n function stop(): void {\n if (_phase === 'stopped') return;\n unlinkAbort?.();\n clearBudgetRecovery();\n destroyTicker();\n lifecycle.stop();\n unsubFocus();\n setPhase('stopped', 'disposed');\n }\n\n // Declared before assignment because an already-aborted signal makes\n // linkAbortSignal call stop() synchronously, which reads unlinkAbort.\n let unlinkAbort: (() => void) | undefined;\n unlinkAbort = linkAbortSignal(signal, stop);\n\n if (startMode === 'auto') {\n start();\n }\n\n return {\n start,\n stop,\n get phase() {\n return _phase;\n },\n get phaseReason() {\n return _reason;\n },\n get quality() {\n return _quality;\n },\n get qualityReason() {\n return _qualityReason;\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction subscribeFocusTracking(onChange: () => void): () => void {\n window.addEventListener('focus', onChange);\n window.addEventListener('blur', onChange);\n return () => {\n window.removeEventListener('focus', onChange);\n window.removeEventListener('blur', onChange);\n };\n}\n","import { linkAbortSignal } from '../_internal/abort';\nimport { noElementError, serverContextError } from '../_internal/errors';\nimport { observeIntersection } from '../_internal/pool/io-pool';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ScrollProgressOptions {\n element: Element;\n /** Called when the intersection ratio changes at a threshold crossing. */\n onProgress: (ratio: number) => void;\n /** Number of evenly-spaced thresholds. Default 20 (~5% granularity). */\n steps?: number;\n root?: Element | Document | null;\n rootMargin?: string;\n /** Abort signal that stops the observer when aborted. */\n signal?: AbortSignal;\n}\n\nexport interface ScrollProgress {\n /** Current intersection ratio (0–1). Synchronous read of the last-reported value. */\n readonly ratio: number;\n stop(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_STEPS = 20;\n\n// ---------------------------------------------------------------------------\n// Threshold cache\n//\n// Most consumers use the same step count. Cache the array so the IO pool\n// receives stable references and identical pool keys without re-allocating.\n// ---------------------------------------------------------------------------\n\nconst thresholdCache = new Map<number, number[]>();\n\nfunction buildThresholds(steps: number): number[] {\n const cached: number[] | undefined = thresholdCache.get(steps);\n if (cached) return cached;\n\n const thresholds: number[] = [];\n for (let i = 0; i <= steps; i++) {\n thresholds.push(i / steps);\n }\n thresholdCache.set(steps, thresholds);\n return thresholds;\n}\n\n// ---------------------------------------------------------------------------\n// createScrollProgress\n// ---------------------------------------------------------------------------\n\n/**\n * Observe what fraction of an element is visible in the viewport (0–1).\n *\n * Uses the shared IntersectionObserver pool with multi-threshold options.\n * Multiple instances with the same `steps` share a single IO.\n *\n * @example\n * const progress = createScrollProgress({\n * element: el,\n * onProgress: (ratio) => {\n * el.style.opacity = String(ratio);\n * },\n * });\n * // cleanup:\n * progress.stop();\n */\nexport function createScrollProgress(\n options: ScrollProgressOptions,\n): ScrollProgress {\n if (typeof IntersectionObserver === 'undefined') {\n serverContextError('createScrollProgress');\n }\n\n const {\n element,\n onProgress,\n steps = DEFAULT_STEPS,\n root,\n rootMargin,\n signal,\n } = options;\n\n if (!element) noElementError('createScrollProgress');\n\n let _ratio = 0;\n let stopped = false;\n\n const threshold: number[] = buildThresholds(steps);\n\n const unobserve: () => void = observeIntersection({\n element,\n onIntersect: (entry: IntersectionObserverEntry) => {\n const newRatio: number = entry.intersectionRatio;\n if (newRatio === _ratio) return;\n _ratio = newRatio;\n onProgress(newRatio);\n },\n root,\n rootMargin,\n threshold,\n });\n\n let unlinkAbort: (() => void) | undefined;\n\n function stop(): void {\n if (stopped) return;\n stopped = true;\n unlinkAbort?.();\n unobserve();\n }\n\n unlinkAbort = linkAbortSignal(signal, stop);\n\n return {\n get ratio(): number {\n return _ratio;\n },\n stop,\n };\n}\n","import { linkAbortSignal } from '../_internal/abort';\nimport { noElementError, serverContextError } from '../_internal/errors';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type RenderPhase = 'rendered' | 'skipped';\n\nexport interface RenderStateOptions {\n element: Element;\n onPhaseChange?: (phase: RenderPhase) => void;\n /** Abort signal that stops the observer when aborted. */\n signal?: AbortSignal;\n}\n\nexport interface RenderState {\n /** Whether the browser is currently rendering the element or skipping it. */\n readonly phase: RenderPhase;\n stop(): void;\n}\n\n// ---------------------------------------------------------------------------\n// createRenderState\n// ---------------------------------------------------------------------------\n\n/**\n * Report whether the browser is rendering an element or skipping it under\n * `content-visibility`. Listens to the `contentvisibilityautostatechange`\n * event, the browser's ground-truth paint decision.\n *\n * Use it to pause raw, non-phase work (a hand-written rAF loop, `setInterval`,\n * expensive effects) when a `Defer` subtree stops painting. phase's own loops\n * already self-pause off-screen, so they do not need this.\n *\n * Listening and reacting has zero layout effect. It never breaks the\n * no-layout-shift guarantee of `content-visibility`.\n *\n * @example\n * const render = createRenderState({\n * element: el,\n * onPhaseChange: (phase) => phase === 'skipped' ? clock.pause() : clock.resume(),\n * });\n * // cleanup:\n * render.stop();\n *\n * @remarks\n * Where `content-visibility` is unsupported, `phase` stays `'rendered'`.\n *\n * Per the CSS Containment spec, `ResizeObserver` callbacks pause for elements\n * inside a skipped `content-visibility: auto` subtree. Use this primitive to\n * detect that transition when your code depends on size observations resuming.\n */\nexport function createRenderState(options: RenderStateOptions): RenderState {\n if (typeof document === 'undefined') {\n serverContextError('createRenderState');\n }\n\n const { element, onPhaseChange, signal } = options;\n\n if (!element) noElementError('createRenderState');\n\n let _phase: RenderPhase = 'rendered';\n let stopped = false;\n\n function onStateChange(event: Event): void {\n if (stopped) return;\n const next: RenderPhase = (event as ContentVisibilityAutoStateChangeEvent)\n .skipped\n ? 'skipped'\n : 'rendered';\n if (next === _phase) return;\n _phase = next;\n onPhaseChange?.(_phase);\n }\n\n element.addEventListener('contentvisibilityautostatechange', onStateChange);\n\n let unlinkAbort: (() => void) | undefined;\n\n function stop(): void {\n if (stopped) return;\n stopped = true;\n unlinkAbort?.();\n element.removeEventListener(\n 'contentvisibilityautostatechange',\n onStateChange,\n );\n }\n\n unlinkAbort = linkAbortSignal(signal, stop);\n\n return {\n get phase() {\n return _phase;\n },\n stop,\n };\n}\n","type DprCallback = (dpr: number) => void;\n\nconst listeners = new Set<DprCallback>();\n\n// Last-bound DPR. Set by bind() before the MQL is created; only meaningful\n// while a subscription is active.\nlet currentDpr = 1;\n\nlet mql: MediaQueryList | null = null;\nlet handler: (() => void) | null = null;\n\n/**\n * Subscribe to devicePixelRatio changes (e.g. user drags window between monitors).\n *\n * Uses a single shared `matchMedia` query that re-subscribes on every DPR change,\n * so chained monitor switches (A -> B -> C) are all caught.\n *\n * @returns Cleanup function that removes the subscriber.\n */\nexport function subscribeDpr(callback: DprCallback): () => void {\n listeners.add(callback);\n\n if (listeners.size === 1) {\n bind();\n }\n\n let disposed = false;\n return () => {\n if (disposed) return;\n disposed = true;\n listeners.delete(callback);\n if (listeners.size === 0) {\n unbind();\n }\n };\n}\n\n/** Read the current devicePixelRatio. */\nexport function readDpr(): number {\n if (typeof window === 'undefined') return 1;\n return window.devicePixelRatio || 1;\n}\n\n// ---------------------------------------------------------------------------\n// Internal: bind/unbind the resolution MQL\n// ---------------------------------------------------------------------------\n\nfunction bind(): void {\n if (typeof matchMedia === 'undefined') return;\n currentDpr = window.devicePixelRatio || 1;\n mql = matchMedia(`(resolution: ${currentDpr}dppx)`);\n handler = onDprChange;\n mql.addEventListener('change', handler);\n}\n\nfunction unbind(): void {\n if (mql && handler) {\n mql.removeEventListener('change', handler);\n }\n mql = null;\n handler = null;\n}\n\nfunction onDprChange(): void {\n const newDpr: number = window.devicePixelRatio || 1;\n if (newDpr === currentDpr) return;\n currentDpr = newDpr;\n\n // Re-subscribe with the new DPR value so the next change is caught.\n unbind();\n bind();\n\n for (const cb of listeners) cb(newDpr);\n}\n","import { linkAbortSignal } from '../_internal/abort';\nimport { serverContextError } from '../_internal/errors';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface IdleOptions {\n /** Max ms to wait before running the callback even if no idle period occurs. */\n timeout?: number;\n /** Abort signal that cancels the scheduled callback when aborted. */\n signal?: AbortSignal;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Fallback delay when `requestIdleCallback` is unavailable (e.g. Safari). */\nconst FALLBACK_DELAY = 1;\n\n// ---------------------------------------------------------------------------\n// whenIdle\n// ---------------------------------------------------------------------------\n\n/**\n * Run a callback once the browser is idle. Wraps `requestIdleCallback`, falling\n * back to a near-immediate `setTimeout` where it is unavailable (Safari).\n *\n * Returns a cancel function. Calling it before the callback runs prevents it.\n *\n * @example\n * const cancel = whenIdle(() => warmCache(), { timeout: 2000 });\n * // later, if no longer needed:\n * cancel();\n */\nexport function whenIdle(\n callback: () => void,\n options?: IdleOptions,\n): () => void {\n if (typeof window === 'undefined') {\n serverContextError('whenIdle');\n }\n\n const { timeout, signal } = options ?? {};\n\n // Already aborted: never schedule, and hand back a no-op cancel.\n if (signal?.aborted) {\n return () => {\n // Nothing was scheduled, so there is nothing to cancel.\n };\n }\n\n let cancel: () => void;\n\n if (typeof window.requestIdleCallback === 'function') {\n // Capture cancelIdleCallback now (bound to window), rather than reading\n // window.cancelIdleCallback inside the returned closure. The cancel may run\n // after the global is swapped out (e.g. test teardown unstubbing globals),\n // and a late lookup would throw \"not a function\". Binding also avoids an\n // illegal-invocation error from calling it detached from window.\n const cancelIdle = window.cancelIdleCallback.bind(window);\n const handle: number = window.requestIdleCallback(\n () => callback(),\n timeout === undefined ? undefined : { timeout },\n );\n cancel = () => cancelIdle(handle);\n } else {\n const handle: ReturnType<typeof setTimeout> = setTimeout(\n callback,\n FALLBACK_DELAY,\n );\n cancel = () => clearTimeout(handle);\n }\n\n const unlinkAbort: () => void = linkAbortSignal(signal, cancel);\n\n return () => {\n unlinkAbort();\n cancel();\n };\n}\n","import { readMediaQuery } from '../_internal/pool/mql-pool';\n\nexport const REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)';\n\n/**\n * Synchronous check for `prefers-reduced-motion: reduce`.\n *\n * Returns `false` on the server (no `matchMedia`). On the client, reads from\n * the shared MQL pool so the underlying `MediaQueryList` is reused across\n * all callers.\n */\nexport function prefersReducedMotion(): boolean {\n if (typeof matchMedia === 'undefined') return false;\n return readMediaQuery(REDUCED_MOTION_QUERY);\n}\n","import { linkAbortSignal } from '../_internal/abort';\nimport { noElementError, serverContextError } from '../_internal/errors';\nimport { observeIntersection } from '../_internal/pool/io-pool';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type MutationPhase = 'observing' | 'paused' | 'stopped';\nexport type MutationReason = 'initial' | 'started' | 'sight' | 'disposed';\n\nexport interface MutationOptions {\n element: Element;\n /** Standard MutationObserver configuration. */\n mutation: MutationObserverInit;\n /** Called once per rAF frame with coalesced records. Never per-record. */\n onMutations: (records: MutationRecord[]) => void;\n /** Called on phase transitions (observing, paused, stopped). */\n onPhaseChange?: (phase: MutationPhase, reason: MutationReason) => void;\n /** Pause when off-screen or ignore visibility. Default `'pause'`. */\n visibility?: 'pause' | 'ignore';\n /** IO options forwarded to the visibility observer. */\n intersectionOptions?: IntersectionObserverInit;\n /** Stops the observer when aborted. */\n signal?: AbortSignal;\n}\n\nexport interface Mutation {\n readonly phase: MutationPhase;\n readonly phaseReason: MutationReason;\n stop(): void;\n}\n\n// ---------------------------------------------------------------------------\n// createMutation\n// ---------------------------------------------------------------------------\n\n/** Lifecycle-aware MutationObserver with rAF-coalesced callbacks. */\nexport function createMutation(options: MutationOptions): Mutation {\n if (typeof document === 'undefined') {\n serverContextError('createMutation');\n }\n\n const {\n element,\n mutation: mutationInit,\n onMutations,\n onPhaseChange,\n visibility = 'pause',\n intersectionOptions,\n signal,\n } = options;\n\n if (!element) noElementError('createMutation');\n\n warnReflowStorm(mutationInit);\n\n let _phase: MutationPhase = 'paused';\n let _reason: MutationReason = 'initial';\n let stopped = false;\n let pendingRecords: MutationRecord[] = [];\n let rafId = 0;\n\n function setPhase(phase: MutationPhase, reason: MutationReason): void {\n const prev = _phase;\n _phase = phase;\n _reason = reason;\n if (prev !== phase) onPhaseChange?.(phase, reason);\n }\n\n function flushRecords(): void {\n rafId = 0;\n if (stopped || pendingRecords.length === 0) return;\n const batch = pendingRecords;\n pendingRecords = [];\n onMutations(batch);\n }\n\n function scheduleFlush(): void {\n if (rafId !== 0) return;\n rafId = requestAnimationFrame(flushRecords);\n }\n\n const mo = new MutationObserver((records) => {\n if (stopped || _phase !== 'observing') return;\n for (let i = 0, len = records.length; i < len; i++) {\n pendingRecords[pendingRecords.length] = records[i] as MutationRecord;\n }\n scheduleFlush();\n });\n\n function startObserving(): void {\n if (stopped || _phase === 'observing') return;\n setPhase('observing', 'started');\n mo.observe(element, mutationInit);\n }\n\n function pauseObserving(reason: MutationReason): void {\n if (stopped || _phase === 'paused') return;\n setPhase('paused', reason);\n mo.disconnect();\n if (rafId !== 0) {\n cancelAnimationFrame(rafId);\n rafId = 0;\n }\n pendingRecords = [];\n }\n\n let cleanupVisibility: (() => void) | undefined;\n\n if (visibility === 'pause') {\n let elementInView = false;\n let documentVisible = !document.hidden;\n\n function recompute(): void {\n if (stopped) return;\n if (documentVisible && elementInView) startObserving();\n else pauseObserving('sight');\n }\n\n function onVisibilityChange(): void {\n documentVisible = !document.hidden;\n recompute();\n }\n\n function onPageShow(event: PageTransitionEvent): void {\n if (!event.persisted) return;\n documentVisible = true;\n recompute();\n }\n\n document.addEventListener('visibilitychange', onVisibilityChange);\n window.addEventListener('pageshow', onPageShow);\n\n const unobserveIO = observeIntersection({\n element,\n onIntersect: (entry) => {\n elementInView = entry.isIntersecting;\n recompute();\n },\n ...intersectionOptions,\n });\n\n cleanupVisibility = () => {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n window.removeEventListener('pageshow', onPageShow);\n unobserveIO();\n };\n } else {\n startObserving();\n }\n\n let unlinkAbort: (() => void) | undefined;\n\n function stop(): void {\n if (stopped) return;\n stopped = true;\n unlinkAbort?.();\n cleanupVisibility?.();\n mo.disconnect();\n if (rafId !== 0) {\n cancelAnimationFrame(rafId);\n rafId = 0;\n }\n pendingRecords = [];\n setPhase('stopped', 'disposed');\n }\n\n unlinkAbort = linkAbortSignal(signal, stop);\n\n return {\n get phase() {\n return _phase;\n },\n get phaseReason() {\n return _reason;\n },\n stop,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst REFLOW_STORM_ATTRIBUTES = new Set(['style', 'class']);\n\nfunction warnReflowStorm(opts: MutationObserverInit): void {\n if (process.env.NODE_ENV === 'production') return;\n if (!opts.subtree) return;\n const filter = opts.attributeFilter;\n if (!filter) return;\n if (!filter.some((attr) => REFLOW_STORM_ATTRIBUTES.has(attr))) return;\n\n console.warn(\n '[phase] createMutation: observing subtree + attributeFilter including ' +\n '\"style\" or \"class\" fires on every descendant style/class change ' +\n '(animations, hovers, framework churn). Narrow the scope or use a ' +\n 'visibility signal instead.',\n );\n}\n","import { linkAbortSignal } from '../_internal/abort';\nimport { noElementError, serverContextError } from '../_internal/errors';\nimport { observeIntersection } from '../_internal/pool/io-pool';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type PointerPhase = 'idle' | 'tracking' | 'stopped';\nexport type PointerReason =\n | 'initial'\n | 'enter'\n | 'leave'\n | 'sight'\n | 'disposed';\n\nexport interface PointerState {\n /** X position relative to the element's top-left, in CSS pixels. */\n x: number;\n /** Y position relative to the element's top-left, in CSS pixels. */\n y: number;\n /** Whether a pointer is currently over the element. */\n active: boolean;\n}\n\nexport interface PointerOptions {\n element: Element;\n /** Called once per rAF frame with the latest pointer position. */\n onPointer: (state: PointerState) => void;\n /** Called on phase transitions (idle, tracking, stopped). */\n onPhaseChange?: (phase: PointerPhase, reason: PointerReason) => void;\n /** Pause when off-screen or ignore visibility. Default `'pause'`. */\n visibility?: 'pause' | 'ignore';\n /** IO options forwarded to the visibility observer. */\n intersectionOptions?: IntersectionObserverInit;\n /** Stops the tracker when aborted. */\n signal?: AbortSignal;\n}\n\nexport interface Pointer {\n readonly phase: PointerPhase;\n readonly phaseReason: PointerReason;\n readonly state: Readonly<PointerState>;\n stop(): void;\n}\n\n// ---------------------------------------------------------------------------\n// createPointer\n// ---------------------------------------------------------------------------\n\n/** Lifecycle-aware pointer tracker with rAF-batched `getBoundingClientRect`. */\nexport function createPointer(options: PointerOptions): Pointer {\n if (typeof document === 'undefined') {\n serverContextError('createPointer');\n }\n\n const {\n element,\n onPointer,\n onPhaseChange,\n visibility = 'pause',\n intersectionOptions,\n signal,\n } = options;\n\n if (!element) noElementError('createPointer');\n\n let _phase: PointerPhase = 'idle';\n let _reason: PointerReason = 'initial';\n let stopped = false;\n const _state: PointerState = { x: 0, y: 0, active: false };\n\n let rafId = 0;\n let lastClientX = 0;\n let lastClientY = 0;\n let dirty = false;\n\n function setPhase(phase: PointerPhase, reason: PointerReason): void {\n const prev = _phase;\n _phase = phase;\n _reason = reason;\n if (prev !== phase) onPhaseChange?.(phase, reason);\n }\n\n function flush(): void {\n rafId = 0;\n if (!dirty || stopped) return;\n dirty = false;\n const rect = element.getBoundingClientRect();\n _state.x = lastClientX - rect.left;\n _state.y = lastClientY - rect.top;\n onPointer(_state);\n }\n\n function scheduleFlush(): void {\n if (rafId !== 0) return;\n rafId = requestAnimationFrame(flush);\n }\n\n function cancelFlush(): void {\n if (rafId !== 0) {\n cancelAnimationFrame(rafId);\n rafId = 0;\n }\n dirty = false;\n }\n\n function onPointerMove(e: Event): void {\n if (stopped || _phase !== 'tracking') return;\n const pe = e as PointerEvent;\n lastClientX = pe.clientX;\n lastClientY = pe.clientY;\n dirty = true;\n scheduleFlush();\n }\n\n function onPointerEnter(): void {\n if (stopped) return;\n _state.active = true;\n setPhase('tracking', 'enter');\n }\n\n function onPointerLeave(): void {\n if (stopped) return;\n cancelFlush();\n _state.active = false;\n setPhase('idle', 'leave');\n onPointer(_state);\n }\n\n let cleanupVisibility: (() => void) | undefined;\n let listenersAttached = false;\n\n function attachListeners(): void {\n if (listenersAttached) return;\n listenersAttached = true;\n element.addEventListener('pointermove', onPointerMove);\n element.addEventListener('pointerenter', onPointerEnter);\n element.addEventListener('pointerleave', onPointerLeave);\n }\n\n function detachListeners(): void {\n if (!listenersAttached) return;\n listenersAttached = false;\n element.removeEventListener('pointermove', onPointerMove);\n element.removeEventListener('pointerenter', onPointerEnter);\n element.removeEventListener('pointerleave', onPointerLeave);\n }\n\n if (visibility === 'pause') {\n let elementInView = false;\n let documentVisible = !document.hidden;\n\n function recompute(): void {\n if (stopped) return;\n if (documentVisible && elementInView) {\n attachListeners();\n } else {\n detachListeners();\n if (_state.active) {\n cancelFlush();\n _state.active = false;\n setPhase('idle', 'sight');\n }\n }\n }\n\n function onVisChange(): void {\n documentVisible = !document.hidden;\n recompute();\n }\n\n function onPageShow(event: PageTransitionEvent): void {\n if (!event.persisted) return;\n documentVisible = true;\n recompute();\n }\n\n document.addEventListener('visibilitychange', onVisChange);\n window.addEventListener('pageshow', onPageShow);\n\n const unobserveIO = observeIntersection({\n element,\n onIntersect: (entry) => {\n elementInView = entry.isIntersecting;\n recompute();\n },\n ...intersectionOptions,\n });\n\n cleanupVisibility = () => {\n document.removeEventListener('visibilitychange', onVisChange);\n window.removeEventListener('pageshow', onPageShow);\n unobserveIO();\n };\n } else {\n attachListeners();\n }\n\n let unlinkAbort: (() => void) | undefined;\n\n function stop(): void {\n if (stopped) return;\n stopped = true;\n unlinkAbort?.();\n cleanupVisibility?.();\n detachListeners();\n cancelFlush();\n _state.active = false;\n setPhase('stopped', 'disposed');\n }\n\n unlinkAbort = linkAbortSignal(signal, stop);\n\n return {\n get phase() {\n return _phase;\n },\n get phaseReason() {\n return _reason;\n },\n get state() {\n return _state;\n },\n stop,\n };\n}\n"],"mappings":"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"}
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as SightReason, C as LifecyclePhase, M as FrameState, T as LifecycleReducedMotion, _ as LoopReason, c as RenderPhase, f as DegradedBehavior, g as LoopPhase, i as MutationReason, k as SightPhase, o as IdleOptions, p as DegradedReason, r as MutationPhase, v as Quality, w as LifecycleReason, y as ReducedMotionBehavior } from "./index-BynP-ee0.js";
1
+ import { A as LifecycleReason, C as LoopReason, F as SightPhase, I as SightReason, R as FrameState, S as LoopPhase, T as ReducedMotionBehavior, a as PointerState, f as IdleOptions, i as PointerReason, j as LifecycleReducedMotion, k as LifecyclePhase, l as MutationPhase, m as RenderPhase, r as PointerPhase, u as MutationReason, v as DegradedBehavior, w as Quality, y as DegradedReason } from "./index-tRHsbTE2.js";
2
2
  import { ComponentProps, ElementType, HTMLAttributes, JSX, ReactNode, Ref, RefObject } from "react";
3
3
 
4
4
  //#region src/react/use-synced-ref/index.d.ts
@@ -451,7 +451,6 @@ declare function useCanvas(options: UseCanvasOptions): UseCanvasResult;
451
451
  //#endregion
452
452
  //#region src/react/use-mutation/index.d.ts
453
453
  type MutationRecordsCallback = (records: MutationRecord[]) => void;
454
- type MutationPhaseCallback = (phase: MutationPhase, phaseReason: MutationReason) => void;
455
454
  interface UseMutationOptions<T extends Element = HTMLDivElement> {
456
455
  /**
457
456
  * Element to observe. When omitted, attach the returned `ref`.
@@ -465,11 +464,6 @@ interface UseMutationOptions<T extends Element = HTMLDivElement> {
465
464
  mutation: MutationObserverInit;
466
465
  /** Called once per rAF frame with coalesced records. Never per-record. */
467
466
  onMutations: MutationRecordsCallback;
468
- /**
469
- * Called on every phase transition. When provided, `phase` and `phaseReason`
470
- * stay at initial values and no re-renders occur (transient mode).
471
- */
472
- onPhaseChange?: MutationPhaseCallback;
473
467
  /** Pause when off-screen or ignore visibility. Default `'pause'`. */
474
468
  visibility?: 'pause' | 'ignore';
475
469
  /** When `false`, tears down the observer entirely. Default `true`. */
@@ -477,7 +471,7 @@ interface UseMutationOptions<T extends Element = HTMLDivElement> {
477
471
  /** IO options forwarded to the visibility observer. */
478
472
  intersectionOptions?: IntersectionObserverInit;
479
473
  }
480
- interface UseMutationReactiveResult<T extends Element = HTMLDivElement> {
474
+ interface UseMutationResult<T extends Element = HTMLDivElement> {
481
475
  ref: RefObject<T | null>;
482
476
  phase: MutationPhase;
483
477
  phaseReason: MutationReason;
@@ -486,25 +480,55 @@ interface UseMutationReactiveResult<T extends Element = HTMLDivElement> {
486
480
  /** Reason via ref. Always current, never triggers re-render. */
487
481
  phaseReasonRef: RefObject<MutationReason>;
488
482
  }
489
- interface UseMutationTransientResult<T extends Element = HTMLDivElement> {
483
+ /**
484
+ * Lifecycle-aware MutationObserver with rAF-coalesced callbacks.
485
+ * Auto-pauses off-screen and tears down on unmount.
486
+ *
487
+ * Records are always delivered imperatively via `onMutations` (never state).
488
+ * Phase transitions (observing/paused) are infrequent, so `phase`/`phaseReason`
489
+ * are reactive state; read `phaseRef`/`phaseReasonRef` for the latest value
490
+ * inside `onMutations` without closure staleness. For synchronous phase
491
+ * reactions, use the core `createMutation` primitive.
492
+ */
493
+ declare function useMutation<T extends Element = HTMLDivElement>(options: UseMutationOptions<T>): UseMutationResult<T>;
494
+ //#endregion
495
+ //#region src/react/use-pointer/index.d.ts
496
+ type PointerCallback = (state: PointerState) => void;
497
+ interface UsePointerOptions<T extends Element = HTMLDivElement> {
498
+ /** Element to track. When omitted, attach the returned `ref`. */
499
+ ref?: RefObject<T | null>;
500
+ /** Called once per rAF frame with the latest pointer position. */
501
+ onPointer: PointerCallback;
502
+ /** Pause when off-screen or ignore visibility. Default `'pause'`. */
503
+ visibility?: 'pause' | 'ignore';
504
+ /** When `false`, tears down the tracker entirely. Default `true`. */
505
+ enabled?: boolean;
506
+ /** IO options forwarded to the visibility observer. */
507
+ intersectionOptions?: IntersectionObserverInit;
508
+ }
509
+ interface UsePointerResult<T extends Element = HTMLDivElement> {
490
510
  ref: RefObject<T | null>;
511
+ phase: PointerPhase;
512
+ phaseReason: PointerReason;
491
513
  /** Phase via ref. Always current, never triggers re-render. */
492
- phaseRef: RefObject<MutationPhase>;
514
+ phaseRef: RefObject<PointerPhase>;
493
515
  /** Reason via ref. Always current, never triggers re-render. */
494
- phaseReasonRef: RefObject<MutationReason>;
516
+ phaseReasonRef: RefObject<PointerReason>;
517
+ /** Latest pointer position via ref. Always current, never triggers re-render. */
518
+ stateRef: RefObject<PointerState>;
495
519
  }
496
- type UseMutationResult<T extends Element = HTMLDivElement> = UseMutationReactiveResult<T>;
497
520
  /**
498
- * Lifecycle-aware MutationObserver with rAF-coalesced callbacks.
521
+ * Lifecycle-aware pointer tracker with rAF-batched `getBoundingClientRect`.
499
522
  * Auto-pauses off-screen and tears down on unmount.
500
523
  *
501
- * Pass `onPhaseChange` for zero-re-render mode (transient). Without it,
502
- * `phase` and `phaseReason` update via state on every transition.
524
+ * Position is always delivered imperatively via `onPointer` (never state) and
525
+ * mirrored in `stateRef` for on-demand reads (e.g. inside a `useLoop` tick).
526
+ * Phase transitions (tracking/idle) are infrequent, so `phase`/`phaseReason`
527
+ * are reactive state; read `phaseRef`/`phaseReasonRef` for the latest value
528
+ * without closure staleness. For synchronous phase reactions, use the core
529
+ * `createPointer` primitive.
503
530
  */
504
- declare function useMutation<T extends Element = HTMLDivElement>(options: UseMutationOptions<T> & {
505
- onPhaseChange: MutationPhaseCallback;
506
- }): UseMutationTransientResult<T>;
507
- declare function useMutation<T extends Element = HTMLDivElement>(options: UseMutationOptions<T>): UseMutationReactiveResult<T>;
531
+ declare function usePointer<T extends Element = HTMLDivElement>(options: UsePointerOptions<T>): UsePointerResult<T>;
508
532
  //#endregion
509
533
  //#region src/react/use-tween/index.d.ts
510
534
  interface UseTweenOptions {
@@ -751,5 +775,5 @@ declare const Swap: typeof SwapRoot & {
751
775
  State: typeof SwapState;
752
776
  };
753
777
  //#endregion
754
- export { type CanvasDrawFn, type ContainerBreakpoint, Defer, type DeferProps, type IdleOptions, type LifecyclePhase, type LifecycleReason, type LifecycleReducedMotion, type LoopTickFn, type MutationPhaseCallback, type MutationRecordsCallback, Presence, type PresenceMode, type PresencePhase, type PresenceProps, type PresenceReason, type RenderPhase, type ScrollProgressCallback, type SightCallback, type Size, type SizeCallback, Swap, type SwapProps, type SwapStateProps, type UseCanvasOptions, type UseCanvasResult, type UseContainerQueryOptions, type UseContainerQueryResult, type UseLifecycleOptions, type UseLifecycleResult, type UseLoopOptions, type UseLoopResult, type UseMutationOptions, type UseMutationReactiveResult, type UseMutationResult, type UseMutationTransientResult, type UsePresenceOptions, type UsePresenceResult, type UseScrollProgressOptions, type UseScrollProgressReactiveResult, type UseScrollProgressResult, type UseScrollProgressTransientResult, type UseSightOptions, type UseSightReactiveResult, type UseSightResult, type UseSightTransientResult, type UseSizeOptions, type UseSizeReactiveResult, type UseSizeResult, type UseSizeTransientResult, type UseTweenOptions, WhenIdle, type WhenIdleProps, WhenVisible, type WhenVisibleProps, useCanvas, useContainerQuery, useDevicePixelRatio, useIdle, useLifecycle, useLoop, useMediaQuery, useMutation, usePrefersReducedMotion, usePresence, useRenderState, useScrollProgress, useSight, useSize, useStableCallback, useSyncedRef, useTween, useWhenIdle };
778
+ export { type CanvasDrawFn, type ContainerBreakpoint, Defer, type DeferProps, type IdleOptions, type LifecyclePhase, type LifecycleReason, type LifecycleReducedMotion, type LoopTickFn, type MutationRecordsCallback, type PointerCallback, Presence, type PresenceMode, type PresencePhase, type PresenceProps, type PresenceReason, type RenderPhase, type ScrollProgressCallback, type SightCallback, type Size, type SizeCallback, Swap, type SwapProps, type SwapStateProps, type UseCanvasOptions, type UseCanvasResult, type UseContainerQueryOptions, type UseContainerQueryResult, type UseLifecycleOptions, type UseLifecycleResult, type UseLoopOptions, type UseLoopResult, type UseMutationOptions, type UseMutationResult, type UsePointerOptions, type UsePointerResult, type UsePresenceOptions, type UsePresenceResult, type UseScrollProgressOptions, type UseScrollProgressReactiveResult, type UseScrollProgressResult, type UseScrollProgressTransientResult, type UseSightOptions, type UseSightReactiveResult, type UseSightResult, type UseSightTransientResult, type UseSizeOptions, type UseSizeReactiveResult, type UseSizeResult, type UseSizeTransientResult, type UseTweenOptions, WhenIdle, type WhenIdleProps, WhenVisible, type WhenVisibleProps, useCanvas, useContainerQuery, useDevicePixelRatio, useIdle, useLifecycle, useLoop, useMediaQuery, useMutation, usePointer, usePrefersReducedMotion, usePresence, useRenderState, useScrollProgress, useSight, useSize, useStableCallback, useSyncedRef, useTween, useWhenIdle };
755
779
  //# sourceMappingURL=react.d.ts.map