js.foresight 3.5.0 → 4.1.0
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/LICENSE +21 -0
- package/README.md +14 -46
- package/dist/BaseForesightModule-CJzWVlF2.mjs +2 -0
- package/dist/BaseForesightModule-CJzWVlF2.mjs.map +1 -0
- package/dist/DesktopHandler-CR9nLuzu.mjs +2 -0
- package/dist/DesktopHandler-CR9nLuzu.mjs.map +1 -0
- package/dist/ElementObservingModule-QE8ZBcnz.mjs +2 -0
- package/dist/ElementObservingModule-QE8ZBcnz.mjs.map +1 -0
- package/dist/ScrollPredictor-ZHRqX0lh.mjs +2 -0
- package/dist/ScrollPredictor-ZHRqX0lh.mjs.map +1 -0
- package/dist/TabPredictor-C2zyaEQZ.mjs +2 -0
- package/dist/TabPredictor-C2zyaEQZ.mjs.map +1 -0
- package/dist/TouchDeviceHandler-BPzPdr-z.mjs +2 -0
- package/dist/TouchDeviceHandler-BPzPdr-z.mjs.map +1 -0
- package/dist/TouchStartPredictor-r7R_E74t.mjs +2 -0
- package/dist/TouchStartPredictor-r7R_E74t.mjs.map +1 -0
- package/dist/ViewportPredictor-aTE2EmU2.mjs +2 -0
- package/dist/ViewportPredictor-aTE2EmU2.mjs.map +1 -0
- package/dist/index.d.mts +594 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lineSegmentIntersectsRect-x9nicliA.mjs +2 -0
- package/dist/lineSegmentIntersectsRect-x9nicliA.mjs.map +1 -0
- package/dist/rectAndHitSlop-T7Z3PZlb.mjs +2 -0
- package/dist/rectAndHitSlop-T7Z3PZlb.mjs.map +1 -0
- package/package.json +27 -28
- package/dist/DesktopHandler-BOXAW4XX.js +0 -1
- package/dist/ScrollPredictor-Y7NELMBI.js +0 -1
- package/dist/TabPredictor-HA2SV3CY.js +0 -1
- package/dist/TouchDeviceHandler-JWBQ2YOV.js +0 -1
- package/dist/TouchStartPredictor-ZH3KJG2C.js +0 -1
- package/dist/ViewportPredictor-H3GLDETY.js +0 -1
- package/dist/chunk-44N4MCQB.js +0 -1
- package/dist/chunk-AODZNE3S.js +0 -1
- package/dist/chunk-PAYO6NXN.js +0 -1
- package/dist/index.d.ts +0 -531
- package/dist/index.js +0 -1
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
//#region src/helpers/CircularBuffer.d.ts
|
|
2
|
+
declare class CircularBuffer<T> {
|
|
3
|
+
private buffer;
|
|
4
|
+
private head;
|
|
5
|
+
private count;
|
|
6
|
+
private capacity;
|
|
7
|
+
constructor(capacity: number);
|
|
8
|
+
add(item: T): void;
|
|
9
|
+
getFirst(): T | undefined;
|
|
10
|
+
getLast(): T | undefined;
|
|
11
|
+
getFirstLast(): [T | undefined, T | undefined];
|
|
12
|
+
resize(newCapacity: number): void;
|
|
13
|
+
private getAllItems;
|
|
14
|
+
clear(): void;
|
|
15
|
+
get length(): number;
|
|
16
|
+
get size(): number;
|
|
17
|
+
get isFull(): boolean;
|
|
18
|
+
get isEmpty(): boolean;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/types/types.d.ts
|
|
22
|
+
type Rect = {
|
|
23
|
+
top: number;
|
|
24
|
+
left: number;
|
|
25
|
+
right: number;
|
|
26
|
+
bottom: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* A callback function that is executed when a foresight interaction
|
|
30
|
+
* (e.g., hover, trajectory hit) occurs on a registered element.
|
|
31
|
+
*/
|
|
32
|
+
type ForesightCallback = (state: ForesightElementState) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Represents the HTML element that is being tracked by the ForesightManager.
|
|
35
|
+
* This is typically a standard DOM `Element`.
|
|
36
|
+
*/
|
|
37
|
+
type ForesightElement = Element;
|
|
38
|
+
/**
|
|
39
|
+
* Represents a mouse position captured at a specific point in time.
|
|
40
|
+
* Used for tracking mouse movement history.
|
|
41
|
+
*/
|
|
42
|
+
type MousePosition = {
|
|
43
|
+
/** The (x, y) coordinates of the mouse. */point: Point; /** The timestamp (e.g., from `performance.now()`) when this position was recorded. */
|
|
44
|
+
time: number;
|
|
45
|
+
};
|
|
46
|
+
type Point = {
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
};
|
|
50
|
+
type TrajectoryPositions = {
|
|
51
|
+
positions: CircularBuffer<MousePosition>;
|
|
52
|
+
currentPoint: Point;
|
|
53
|
+
predictedPoint: Point;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Immutable geometry snapshot for a registered element. Replaced (never mutated)
|
|
57
|
+
* whenever the element's position or size changes, which happens on every
|
|
58
|
+
* scroll/resize tick for visible elements.
|
|
59
|
+
*/
|
|
60
|
+
type ElementBounds = {
|
|
61
|
+
/** The expanded rectangle, including hitSlop, used for interaction detection. */expandedRect: Readonly<Rect>; /** The original bounding rectangle of the element, as returned by `getBoundingClientRect()`. */
|
|
62
|
+
originalRect: DOMRectReadOnly;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Immutable, flat state snapshot for a registered element.
|
|
66
|
+
* The reference is replaced (never mutated) on every change so it can be used
|
|
67
|
+
* with `useSyncExternalStore` and Vue's `shallowRef`.
|
|
68
|
+
*/
|
|
69
|
+
type ForesightElementState = {
|
|
70
|
+
/** Unique identifier assigned during registration. */id: string; /** Human-readable name for debugging. */
|
|
71
|
+
name: string; /** Arbitrary user-supplied metadata. */
|
|
72
|
+
meta: Record<string, unknown>;
|
|
73
|
+
/** The normalized hit slop applied to this element. The element's rects live in
|
|
74
|
+
* {@link ElementBounds} (see `getBounds`/`subscribeToBounds`), not in this snapshot. */
|
|
75
|
+
hitSlop: Exclude<HitSlop, number>; /** Whether the user has connection limitations (network slower than minimum connection type (default: 3g) or data saver enabled) that prevent prefetching. */
|
|
76
|
+
isLimitedConnection: boolean; /** Whether the element is currently intersecting the viewport. */
|
|
77
|
+
isIntersectingWithViewport: boolean;
|
|
78
|
+
/** Whether the element is currently tracked by the manager. Stays `true` from
|
|
79
|
+
* registration until it is explicitly unregistered (via the returned `unregister`).
|
|
80
|
+
* Detaching the element from the DOM does NOT unregister it - it is parked inactive
|
|
81
|
+
* and resumes when it reconnects. On a limited connection it is also registered but
|
|
82
|
+
* inactive - check `isLimitedConnection` / `isActive`. */
|
|
83
|
+
isRegistered: boolean;
|
|
84
|
+
/** Whether the element is currently eligible to fire its callback. False when the
|
|
85
|
+
* element is disabled (`isEnabled: false`), on a limited connection, or temporarily
|
|
86
|
+
* detached from the DOM (see `isParked`). */
|
|
87
|
+
isActive: boolean;
|
|
88
|
+
/** Whether the element is detached from the DOM and parked: kept registered but
|
|
89
|
+
* inactive until it reconnects, at which point it resumes automatically. */
|
|
90
|
+
isParked: boolean;
|
|
91
|
+
/** Whether prediction is enabled for this element. When `false` the element
|
|
92
|
+
* stays registered but inactive. Note: an enabled element is still inactive on a
|
|
93
|
+
* limited connection (see `isLimitedConnection`). */
|
|
94
|
+
isEnabled: boolean; /** True once the element's callback has been triggered by a prediction hit. Stays true until the element is reactivated or unregistered. */
|
|
95
|
+
isPredicted: boolean; /** True while the callback is executing (between invocation and completion). The callback is awaited, so this stays true for async callbacks until they resolve or reject. */
|
|
96
|
+
isCallbackRunning: boolean; /** Number of times the callback has fired for this element. */
|
|
97
|
+
hitCount: number; /** Number of times this element has been (re)registered. */
|
|
98
|
+
registerCount: number; /** Duration in ms of the most recent callback run. */
|
|
99
|
+
durationMs: number | undefined; /** Status of the most recently completed callback. */
|
|
100
|
+
status: callbackStatus; /** Error message from the most recently completed callback. */
|
|
101
|
+
error: string | null; /** Time in ms after which the callback can be fired again (Infinity = never). */
|
|
102
|
+
reactivateAfter: number;
|
|
103
|
+
};
|
|
104
|
+
type ForesightRegisterResult = ForesightElementState & {
|
|
105
|
+
/** Function to unregister the element
|
|
106
|
+
*/
|
|
107
|
+
unregister: () => void;
|
|
108
|
+
/**
|
|
109
|
+
* Subscribe to logical state changes for this element. Never fires for
|
|
110
|
+
* geometry-only changes (scroll/resize), use `subscribeToBounds` for those.
|
|
111
|
+
* Returns an unsubscribe function.
|
|
112
|
+
*/
|
|
113
|
+
subscribe: (listener: () => void) => () => void;
|
|
114
|
+
/**
|
|
115
|
+
* Returns the current immutable state snapshot for this element.
|
|
116
|
+
* The reference only changes when logical state changes - never on scroll.
|
|
117
|
+
*/
|
|
118
|
+
getSnapshot: () => ForesightElementState;
|
|
119
|
+
/**
|
|
120
|
+
* Subscribe to geometry changes for this element (position/size, fired on
|
|
121
|
+
* every scroll/resize tick while visible). Returns an unsubscribe function.
|
|
122
|
+
*/
|
|
123
|
+
subscribeToBounds: (listener: () => void) => () => void;
|
|
124
|
+
/**
|
|
125
|
+
* Returns the current immutable geometry snapshot for this element.
|
|
126
|
+
*/
|
|
127
|
+
getBounds: () => ElementBounds;
|
|
128
|
+
};
|
|
129
|
+
type callbackStatus = "error" | "success" | undefined;
|
|
130
|
+
type MouseCallbackCounts = {
|
|
131
|
+
hover: number;
|
|
132
|
+
trajectory: number;
|
|
133
|
+
};
|
|
134
|
+
type TabCallbackCounts = {
|
|
135
|
+
reverse: number;
|
|
136
|
+
forwards: number;
|
|
137
|
+
};
|
|
138
|
+
type ScrollDirection = "down" | "up" | "left" | "right" | "none";
|
|
139
|
+
type ScrollCallbackCounts = Record<`${Exclude<ScrollDirection, "none">}`, number>;
|
|
140
|
+
type CallbackHits = {
|
|
141
|
+
total: number;
|
|
142
|
+
mouse: MouseCallbackCounts;
|
|
143
|
+
tab: TabCallbackCounts;
|
|
144
|
+
scroll: ScrollCallbackCounts;
|
|
145
|
+
touch: number;
|
|
146
|
+
viewport: number;
|
|
147
|
+
};
|
|
148
|
+
type CallbackHitType = {
|
|
149
|
+
kind: "mouse";
|
|
150
|
+
subType: keyof MouseCallbackCounts;
|
|
151
|
+
} | {
|
|
152
|
+
kind: "tab";
|
|
153
|
+
subType: keyof TabCallbackCounts;
|
|
154
|
+
} | {
|
|
155
|
+
kind: "scroll";
|
|
156
|
+
subType: keyof ScrollCallbackCounts;
|
|
157
|
+
} | {
|
|
158
|
+
kind: "touch";
|
|
159
|
+
subType?: string;
|
|
160
|
+
} | {
|
|
161
|
+
kind: "viewport";
|
|
162
|
+
subType?: string;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Snapshot of the current ForesightManager state
|
|
166
|
+
*/
|
|
167
|
+
type ForesightManagerData = {
|
|
168
|
+
registeredElements: ReadonlyMap<ForesightElement, ForesightElementState>;
|
|
169
|
+
globalSettings: Readonly<ForesightManagerSettings>;
|
|
170
|
+
globalCallbackHits: Readonly<CallbackHits>;
|
|
171
|
+
eventListeners: ReadonlyMap<keyof ForesightEventMap, ForesightEventListener[]>;
|
|
172
|
+
currentDeviceStrategy: CurrentDeviceStrategy;
|
|
173
|
+
activeElementCount: number;
|
|
174
|
+
parkedElementCount: number;
|
|
175
|
+
loadedModules: ForesightModules;
|
|
176
|
+
};
|
|
177
|
+
type ForesightModules = {
|
|
178
|
+
desktopHandler: boolean;
|
|
179
|
+
touchHandler: boolean;
|
|
180
|
+
predictors: {
|
|
181
|
+
mouse: boolean;
|
|
182
|
+
tab: boolean;
|
|
183
|
+
scroll: boolean;
|
|
184
|
+
viewport: boolean;
|
|
185
|
+
touchStart: boolean;
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
type TouchDeviceStrategy = "none" | "viewport" | "onTouchStart";
|
|
189
|
+
type MinimumConnectionType = "slow-2g" | "2g" | "3g" | "4g";
|
|
190
|
+
type BaseForesightManagerSettings = {
|
|
191
|
+
/**
|
|
192
|
+
* Number of mouse positions to keep in history for trajectory calculation.
|
|
193
|
+
* A higher number might lead to smoother but slightly delayed predictions.
|
|
194
|
+
*
|
|
195
|
+
*
|
|
196
|
+
* @link https://foresightjs.com/docs/getting_started/config#available-global-settings
|
|
197
|
+
*
|
|
198
|
+
*
|
|
199
|
+
* **This value is clamped between 2 and 30.**
|
|
200
|
+
* @default 8
|
|
201
|
+
*/
|
|
202
|
+
positionHistorySize: number;
|
|
203
|
+
/**
|
|
204
|
+
*
|
|
205
|
+
* Logs basic information about the ForesightManager and its handlers that doesn't have a dedicated event.
|
|
206
|
+
*
|
|
207
|
+
* Mostly used by the maintainers of ForesightJS to debug the manager. But might be useful for implementers aswell.
|
|
208
|
+
*
|
|
209
|
+
* This is not the same as logging events, this can be done with the actual developer tools.
|
|
210
|
+
* @link https://foresightjs.com/docs/debugging/devtools
|
|
211
|
+
*/
|
|
212
|
+
enableManagerLogging: boolean;
|
|
213
|
+
/**
|
|
214
|
+
* How far ahead (in milliseconds) to predict the mouse trajectory.
|
|
215
|
+
* A larger value means the prediction extends further into the future. (meaning it will trigger callbacks sooner)
|
|
216
|
+
*
|
|
217
|
+
* @link https://foresightjs.com/docs/getting_started/config#available-global-settings
|
|
218
|
+
*
|
|
219
|
+
* **This value is clamped between 10 and 200.**
|
|
220
|
+
* @default 120
|
|
221
|
+
*/
|
|
222
|
+
trajectoryPredictionTime: number;
|
|
223
|
+
/**
|
|
224
|
+
* Whether to enable mouse trajectory prediction.
|
|
225
|
+
* If false, only direct hover/interaction is considered.
|
|
226
|
+
* @link https://foresightjs.com/docs/getting_started/config#available-global-settings
|
|
227
|
+
* @default true
|
|
228
|
+
*/
|
|
229
|
+
enableMousePrediction: boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Toggles whether keyboard prediction is on
|
|
232
|
+
*
|
|
233
|
+
* @link https://foresightjs.com/docs/getting_started/config#available-global-settings
|
|
234
|
+
* @default true
|
|
235
|
+
*/
|
|
236
|
+
enableTabPrediction: boolean;
|
|
237
|
+
/**
|
|
238
|
+
* Sets the pixel distance to check from the mouse position in the scroll direction.
|
|
239
|
+
*
|
|
240
|
+
* @link https://foresightjs.com/docs/getting_started/config#available-global-settings
|
|
241
|
+
*
|
|
242
|
+
* **This value is clamped between 30 and 300.**
|
|
243
|
+
* @default 150
|
|
244
|
+
*/
|
|
245
|
+
scrollMargin: number;
|
|
246
|
+
/**
|
|
247
|
+
* Toggles whether scroll prediction is on
|
|
248
|
+
* @link https://foresightjs.com/docs/getting_started/config#available-global-settings
|
|
249
|
+
* @default true
|
|
250
|
+
*/
|
|
251
|
+
enableScrollPrediction: boolean;
|
|
252
|
+
/**
|
|
253
|
+
* Tab stops away from an element to trigger callback. Only works when @argument enableTabPrediction is true
|
|
254
|
+
*
|
|
255
|
+
* **This value is clamped between 0 and 20.**
|
|
256
|
+
* @default 2
|
|
257
|
+
*/
|
|
258
|
+
tabOffset: number;
|
|
259
|
+
/**
|
|
260
|
+
* The prefetch strategy used for touch devices.
|
|
261
|
+
* - `viewport`: Prefetching is done based on the viewport, meaning elements in the viewport are preloaded.
|
|
262
|
+
* - `onTouchStart`: Prefetching is done when the user touches the element
|
|
263
|
+
* @default onTouchStart
|
|
264
|
+
*/
|
|
265
|
+
touchDeviceStrategy: TouchDeviceStrategy;
|
|
266
|
+
/**
|
|
267
|
+
* Network effective connection types that should be considered as limited connections.
|
|
268
|
+
* When the user's network matches any of these types, ForesightJS will disable prefetching
|
|
269
|
+
* to avoid consuming data on slow or expensive connections.
|
|
270
|
+
*
|
|
271
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType
|
|
272
|
+
* @default 3g
|
|
273
|
+
*/
|
|
274
|
+
minimumConnectionType: MinimumConnectionType;
|
|
275
|
+
};
|
|
276
|
+
type CurrentDeviceStrategy = "mouse" | "touch" | "pen";
|
|
277
|
+
/**
|
|
278
|
+
* Configuration options for the ForesightManager
|
|
279
|
+
* @link https://foresightjs.com/docs/getting_started/config#available-global-settings
|
|
280
|
+
*/
|
|
281
|
+
type ForesightManagerSettings = BaseForesightManagerSettings & {
|
|
282
|
+
defaultHitSlop: Exclude<HitSlop, number>;
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* Update options for the ForesightManager
|
|
286
|
+
* @link https://foresightjs.com/docs/getting_started/config#available-global-settings
|
|
287
|
+
*/
|
|
288
|
+
type UpdateForsightManagerSettings = BaseForesightManagerSettings & {
|
|
289
|
+
defaultHitSlop: HitSlop;
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Type used to register elements to the foresight manager
|
|
293
|
+
*/
|
|
294
|
+
type ForesightRegisterOptions = ForesightRegisterOptionsWithoutElement & {
|
|
295
|
+
element: ForesightElement;
|
|
296
|
+
};
|
|
297
|
+
type ForesightRegisterNodeListOptions = ForesightRegisterOptionsWithoutElement & {
|
|
298
|
+
element: NodeListOf<ForesightElement>;
|
|
299
|
+
};
|
|
300
|
+
/**
|
|
301
|
+
* Use full for if you want to create a custom button component in a modern framework (for example React).
|
|
302
|
+
* And you want to have the ForesightRegisterOptions used in ForesightManager.instance.register({})
|
|
303
|
+
* without the element as the element will be the ref of the component.
|
|
304
|
+
*
|
|
305
|
+
* @link https://foresightjs.com/docs/getting_started/typescript#foresightregisteroptionswithoutelement
|
|
306
|
+
*/
|
|
307
|
+
type ForesightRegisterOptionsWithoutElement = {
|
|
308
|
+
callback: ForesightCallback;
|
|
309
|
+
hitSlop?: HitSlop;
|
|
310
|
+
name?: string;
|
|
311
|
+
/**
|
|
312
|
+
* If set by user, stores additional information about the registered element
|
|
313
|
+
*/
|
|
314
|
+
meta?: Record<string, unknown>;
|
|
315
|
+
/**
|
|
316
|
+
* Time in milliseconds after which the callback can be fired again and we reactivate the element.
|
|
317
|
+
* Set to Infinity to prevent callback from firing again after first execution.
|
|
318
|
+
* @default Infinity
|
|
319
|
+
*/
|
|
320
|
+
reactivateAfter?: number;
|
|
321
|
+
/**
|
|
322
|
+
* When `false` the element stays registered but inactive: excluded from
|
|
323
|
+
* prediction and never fires its callback.
|
|
324
|
+
* @default true
|
|
325
|
+
*/
|
|
326
|
+
enabled?: boolean;
|
|
327
|
+
};
|
|
328
|
+
/**
|
|
329
|
+
* Fully invisible "slop" around the element.
|
|
330
|
+
* Basically increases the hover hitbox
|
|
331
|
+
*/
|
|
332
|
+
type HitSlop = Rect | number;
|
|
333
|
+
interface ForesightEventMap {
|
|
334
|
+
elementRegistered: ElementRegisteredEvent;
|
|
335
|
+
elementUnregistered: ElementUnregisteredEvent;
|
|
336
|
+
callbackInvoked: CallbackInvokedEvent;
|
|
337
|
+
callbackCompleted: CallbackCompletedEvent;
|
|
338
|
+
mouseTrajectoryUpdate: MouseTrajectoryUpdateEvent;
|
|
339
|
+
scrollTrajectoryUpdate: ScrollTrajectoryUpdateEvent;
|
|
340
|
+
managerSettingsChanged: ManagerSettingsChangedEvent;
|
|
341
|
+
deviceStrategyChanged: DeviceStrategyChangedEvent;
|
|
342
|
+
}
|
|
343
|
+
type ForesightEvent = "elementRegistered" | "elementUnregistered" | "callbackInvoked" | "callbackCompleted" | "mouseTrajectoryUpdate" | "scrollTrajectoryUpdate" | "managerSettingsChanged" | "deviceStrategyChanged";
|
|
344
|
+
interface DeviceStrategyChangedEvent extends ForesightBaseEvent {
|
|
345
|
+
type: "deviceStrategyChanged";
|
|
346
|
+
newStrategy: CurrentDeviceStrategy;
|
|
347
|
+
oldStrategy: CurrentDeviceStrategy;
|
|
348
|
+
}
|
|
349
|
+
interface ElementRegisteredEvent extends ForesightBaseEvent {
|
|
350
|
+
type: "elementRegistered";
|
|
351
|
+
element: ForesightElement;
|
|
352
|
+
state: ForesightElementState;
|
|
353
|
+
}
|
|
354
|
+
interface ElementUnregisteredEvent extends ForesightBaseEvent {
|
|
355
|
+
type: "elementUnregistered";
|
|
356
|
+
element: ForesightElement;
|
|
357
|
+
state: ForesightElementState;
|
|
358
|
+
unregisterReason: ElementUnregisteredReason;
|
|
359
|
+
wasLastRegisteredElement: boolean;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* The reason an element was unregistered from ForesightManager's tracking.
|
|
363
|
+
* - `callbackHit`: The element was automatically unregistered after its callback fired.
|
|
364
|
+
* - `disconnected`: No longer emitted. Elements detached from the DOM are now parked
|
|
365
|
+
* (kept registered but inactive) and resumed on reconnect, rather than unregistered.
|
|
366
|
+
* - `apiCall`: The developer manually called the `unregister()` function for the element.
|
|
367
|
+
* - `devtools`: When clicking the trash icon in the devtools element tab
|
|
368
|
+
* - any other string
|
|
369
|
+
*/
|
|
370
|
+
type ElementUnregisteredReason = "disconnected" | "apiCall" | "devtools" | (string & {});
|
|
371
|
+
interface CallbackInvokedEvent extends ForesightBaseEvent {
|
|
372
|
+
type: "callbackInvoked";
|
|
373
|
+
element: ForesightElement;
|
|
374
|
+
state: ForesightElementState;
|
|
375
|
+
hitType: CallbackHitType;
|
|
376
|
+
}
|
|
377
|
+
interface CallbackCompletedEventBase extends ForesightBaseEvent {
|
|
378
|
+
type: "callbackCompleted";
|
|
379
|
+
element: ForesightElement;
|
|
380
|
+
state: ForesightElementState;
|
|
381
|
+
hitType: CallbackHitType;
|
|
382
|
+
elapsed: number;
|
|
383
|
+
wasLastActiveElement: boolean;
|
|
384
|
+
}
|
|
385
|
+
type CallbackCompletedEvent = CallbackCompletedEventBase & {
|
|
386
|
+
status: callbackStatus;
|
|
387
|
+
errorMessage: string | null;
|
|
388
|
+
};
|
|
389
|
+
interface MouseTrajectoryUpdateEvent extends Omit<ForesightBaseEvent, "timestamp"> {
|
|
390
|
+
type: "mouseTrajectoryUpdate";
|
|
391
|
+
trajectoryPositions: TrajectoryPositions;
|
|
392
|
+
predictionEnabled: boolean;
|
|
393
|
+
}
|
|
394
|
+
interface ScrollTrajectoryUpdateEvent extends Omit<ForesightBaseEvent, "timestamp"> {
|
|
395
|
+
type: "scrollTrajectoryUpdate";
|
|
396
|
+
currentPoint: Point;
|
|
397
|
+
predictedPoint: Point;
|
|
398
|
+
scrollDirection: ScrollDirection;
|
|
399
|
+
}
|
|
400
|
+
interface ManagerSettingsChangedEvent extends ForesightBaseEvent {
|
|
401
|
+
type: "managerSettingsChanged";
|
|
402
|
+
managerData: ForesightManagerData;
|
|
403
|
+
updatedSettings: UpdatedManagerSetting[];
|
|
404
|
+
}
|
|
405
|
+
type UpdatedManagerSetting = { [K in keyof ForesightManagerSettings]: {
|
|
406
|
+
setting: K;
|
|
407
|
+
newValue: ForesightManagerSettings[K];
|
|
408
|
+
oldValue: ForesightManagerSettings[K];
|
|
409
|
+
} }[keyof ForesightManagerSettings];
|
|
410
|
+
type ForesightEventListener<K extends ForesightEvent = ForesightEvent> = (event: ForesightEventMap[K]) => void;
|
|
411
|
+
interface ForesightBaseEvent {
|
|
412
|
+
type: ForesightEvent;
|
|
413
|
+
timestamp: number;
|
|
414
|
+
}
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/managers/ForesightManager.d.ts
|
|
417
|
+
/**
|
|
418
|
+
* Manages the prediction of user intent based on mouse trajectory and element interactions.
|
|
419
|
+
*
|
|
420
|
+
* ForesightManager is a singleton class responsible for:
|
|
421
|
+
* - Registering HTML elements to monitor.
|
|
422
|
+
* - Tracking mouse movements and predicting future cursor positions.
|
|
423
|
+
* - Detecting when a predicted trajectory intersects with a registered element's bounds.
|
|
424
|
+
* - Invoking callbacks associated with elements upon predicted or actual interaction.
|
|
425
|
+
* - Deactivating elements after their callback completes, with optional reactivation via `reactivateAfter`.
|
|
426
|
+
* - Handling global settings for prediction behavior (e.g., history size, prediction time).
|
|
427
|
+
* - Delegating element bounds observation to device handlers ({@link DesktopHandler}, {@link TouchDeviceHandler}).
|
|
428
|
+
* - Automatically unregistering elements removed from the DOM using {@link MutationObserver}.
|
|
429
|
+
* - Detecting broader layout shifts via {@link MutationObserver} to update element positions.
|
|
430
|
+
*
|
|
431
|
+
* It should be initialized once using {@link ForesightManager.initialize} and then
|
|
432
|
+
* accessed via the static getter {@link ForesightManager.instance}.
|
|
433
|
+
*/
|
|
434
|
+
declare class ForesightManager {
|
|
435
|
+
private static manager;
|
|
436
|
+
/** Internal entries containing full element data, callbacks, and subscribers. */
|
|
437
|
+
private elementEntries;
|
|
438
|
+
/** Public read-only view exposing only external state, derived from {@link elementEntries}. */
|
|
439
|
+
readonly registeredElements: ReadonlyMap<ForesightElement, ForesightElementState>;
|
|
440
|
+
private idCounter;
|
|
441
|
+
private activeElementCount;
|
|
442
|
+
private parkedElementCount;
|
|
443
|
+
private desktopHandler;
|
|
444
|
+
private touchDeviceHandler;
|
|
445
|
+
private currentlyActiveHandler;
|
|
446
|
+
private handlerDependencies;
|
|
447
|
+
private isSetup;
|
|
448
|
+
private pendingPointerEvent;
|
|
449
|
+
private rafId;
|
|
450
|
+
private domObserver;
|
|
451
|
+
private currentDeviceStrategy;
|
|
452
|
+
private eventEmitter;
|
|
453
|
+
private _globalCallbackHits;
|
|
454
|
+
private _globalSettings;
|
|
455
|
+
private constructor();
|
|
456
|
+
private getOrCreateDesktopHandler;
|
|
457
|
+
private getOrCreateTouchHandler;
|
|
458
|
+
static initialize(props?: Partial<UpdateForsightManagerSettings>): ForesightManager;
|
|
459
|
+
static get isInitiated(): Readonly<boolean>;
|
|
460
|
+
static get instance(): ForesightManager;
|
|
461
|
+
private generateId;
|
|
462
|
+
private get isUsingDesktopHandler();
|
|
463
|
+
addEventListener<K extends ForesightEvent>(eventType: K, listener: ForesightEventListener<K>, options?: {
|
|
464
|
+
signal?: AbortSignal;
|
|
465
|
+
}): void;
|
|
466
|
+
removeEventListener<K extends ForesightEvent>(eventType: K, listener: ForesightEventListener<K>): void;
|
|
467
|
+
hasListeners<K extends ForesightEvent>(eventType: K): boolean;
|
|
468
|
+
/**
|
|
469
|
+
* Subscribe to logical state changes for a specific element.
|
|
470
|
+
* The listener is called (with no arguments) whenever the element's
|
|
471
|
+
* immutable state snapshot is replaced. Never fires for geometry-only
|
|
472
|
+
* changes (scroll/resize) - see {@link subscribeToElementBounds}.
|
|
473
|
+
* Use {@link registeredElements} to read the latest state inside the listener.
|
|
474
|
+
*
|
|
475
|
+
* @returns An unsubscribe function, or `undefined` if the element is not registered.
|
|
476
|
+
*/
|
|
477
|
+
subscribeToElement(element: ForesightElement, listener: () => void): (() => void) | undefined;
|
|
478
|
+
/**
|
|
479
|
+
* Subscribe to geometry changes for a specific element (position/size, fired
|
|
480
|
+
* on every scroll/resize tick while visible). Use {@link getElementBounds}
|
|
481
|
+
* to read the latest geometry inside the listener.
|
|
482
|
+
*
|
|
483
|
+
* @returns An unsubscribe function, or `undefined` if the element is not registered.
|
|
484
|
+
*/
|
|
485
|
+
subscribeToElementBounds(element: ForesightElement, listener: () => void): (() => void) | undefined;
|
|
486
|
+
/**
|
|
487
|
+
* Returns the current immutable geometry snapshot for a registered element,
|
|
488
|
+
* or `undefined` if the element is not registered.
|
|
489
|
+
*/
|
|
490
|
+
getElementBounds(element: ForesightElement): ElementBounds | undefined;
|
|
491
|
+
get getManagerData(): Readonly<ForesightManagerData>;
|
|
492
|
+
private getLoadedModulesSnapshot;
|
|
493
|
+
register(options: ForesightRegisterNodeListOptions): ForesightRegisterResult[];
|
|
494
|
+
register(options: ForesightRegisterOptions): ForesightRegisterResult;
|
|
495
|
+
private registerElement;
|
|
496
|
+
/**
|
|
497
|
+
* Updates the options of an already-registered element.
|
|
498
|
+
* Only the provided fields are updated; omitted fields keep their current values.
|
|
499
|
+
* If a reactivation timeout is pending and reactivateAfter changed, the timeout is rescheduled.
|
|
500
|
+
*
|
|
501
|
+
* @throws Error if the element is not registered.
|
|
502
|
+
*/
|
|
503
|
+
updateElementOptions(element: ForesightElement, options: Partial<ForesightRegisterOptionsWithoutElement>): ForesightElementState;
|
|
504
|
+
/**
|
|
505
|
+
* Create a subscribe function for a listener set (state or bounds subscribers).
|
|
506
|
+
* Returns an unsubscribe callback when called.
|
|
507
|
+
*/
|
|
508
|
+
private makeSubscribe;
|
|
509
|
+
/**
|
|
510
|
+
* Replace the immutable state ref for an element and notify subscribers.
|
|
511
|
+
* No-op when every patch value already matches current state - preserves the
|
|
512
|
+
* stable-reference contract relied on by useSyncExternalStore and shallowRef.
|
|
513
|
+
*/
|
|
514
|
+
private updateElementState;
|
|
515
|
+
/**
|
|
516
|
+
* Replace the immutable geometry ref for an element and notify bounds
|
|
517
|
+
* subscribers. No-op when both rects are content-equal. Preserves the
|
|
518
|
+
* stable-reference contract, mirroring {@link updateElementState}.
|
|
519
|
+
*
|
|
520
|
+
* When a single trigger changes both geometry and logical state (position
|
|
521
|
+
* change, hitSlop update), bounds must be updated BEFORE the state patch so
|
|
522
|
+
* state subscribers always read fresh geometry.
|
|
523
|
+
*/
|
|
524
|
+
private updateElementBounds;
|
|
525
|
+
unregister(element: ForesightElement | NodeListOf<ForesightElement>, unregisterReason?: ElementUnregisteredReason): void;
|
|
526
|
+
private unregisterElement;
|
|
527
|
+
reactivate(element: ForesightElement | NodeListOf<ForesightElement>): void;
|
|
528
|
+
private reactivateElement;
|
|
529
|
+
/**
|
|
530
|
+
* Toggle prediction for a registered element without unregistering it.
|
|
531
|
+
* Disabling deactivates and stops observing; enabling reactivates it.
|
|
532
|
+
*/
|
|
533
|
+
private setElementEnabled;
|
|
534
|
+
private clearReactivateTimeout;
|
|
535
|
+
private callCallback;
|
|
536
|
+
private markElementAsRunning;
|
|
537
|
+
private executeCallbackAsync;
|
|
538
|
+
private finalizeCallback;
|
|
539
|
+
private updateHitCounters;
|
|
540
|
+
private setDeviceStrategy;
|
|
541
|
+
private handlePointerMove;
|
|
542
|
+
private initializeGlobalListeners;
|
|
543
|
+
private removeGlobalListeners;
|
|
544
|
+
private handleDomMutations;
|
|
545
|
+
/**
|
|
546
|
+
* Deactivate an element that was detached from the DOM. It is kept in
|
|
547
|
+
* {@link elementEntries} (still registered) and flagged `isParked` so it can be
|
|
548
|
+
* resumed when it reconnects.
|
|
549
|
+
*/
|
|
550
|
+
private parkDisconnected;
|
|
551
|
+
/**
|
|
552
|
+
* Re-activate a previously parked element once it is back in the DOM. Mirrors
|
|
553
|
+
* the activation rules used everywhere else: disabled / limited connections stay
|
|
554
|
+
* inactive, and an element that already fired its callback stays inactive too
|
|
555
|
+
* (it resumes the same state it had before it detached).
|
|
556
|
+
*/
|
|
557
|
+
private resumeReconnected;
|
|
558
|
+
/**
|
|
559
|
+
* Tear down global listeners only when nothing needs them: no active elements
|
|
560
|
+
* to predict on, and no parked elements waiting to reconnect (which need the
|
|
561
|
+
* MutationObserver to detect their return).
|
|
562
|
+
*/
|
|
563
|
+
private removeGlobalListenersIfIdle;
|
|
564
|
+
alterGlobalSettings(props?: Partial<UpdateForsightManagerSettings>): void;
|
|
565
|
+
private forceUpdateAllElementBounds;
|
|
566
|
+
/**
|
|
567
|
+
* ONLY use this function when you want to change the rect bounds via code, if the rects are changing because of updates in the DOM do not use this function.
|
|
568
|
+
* We need an observer for that
|
|
569
|
+
*/
|
|
570
|
+
private forceUpdateElementBounds;
|
|
571
|
+
private devLog;
|
|
572
|
+
}
|
|
573
|
+
//#endregion
|
|
574
|
+
//#region src/helpers/createInitialState.d.ts
|
|
575
|
+
/**
|
|
576
|
+
* Snapshot of the flat state shape for an element that is not (yet) tracked by the
|
|
577
|
+
* manager. Reuses the same fields as a registered element so consumers don't need
|
|
578
|
+
* to special-case `null`.
|
|
579
|
+
*
|
|
580
|
+
* Used in two situations:
|
|
581
|
+
* 1. The manager refuses to register the element (touch device, limited connection,
|
|
582
|
+
* etc.) - pass `isLimitedConnection` to reflect that.
|
|
583
|
+
* 2. Framework wrappers (React, Vue) need an initial snapshot before `register()`
|
|
584
|
+
* has run. `register()` requires a real DOM element, which only exists after
|
|
585
|
+
* the consumer's first render commits, so the wrapper returns this snapshot
|
|
586
|
+
* during that brief window. Pass `isLimitedConnection: false` for this case.
|
|
587
|
+
*/
|
|
588
|
+
declare const createUnregisteredSnapshot: (isLimitedConnection: boolean) => ForesightElementState;
|
|
589
|
+
//#endregion
|
|
590
|
+
//#region src/core/BaseForesightModule.d.ts
|
|
591
|
+
type HasListenersFunction = <K extends ForesightEvent>(eventType: K) => boolean;
|
|
592
|
+
//#endregion
|
|
593
|
+
export { type CallbackCompletedEvent, type CallbackHitType, type CallbackHits, type CallbackInvokedEvent, type DeviceStrategyChangedEvent, type ElementBounds, type ElementRegisteredEvent, type ElementUnregisteredEvent, type ForesightCallback, type ForesightElement, type ForesightElementState, type ForesightEvent, type ForesightEventMap, ForesightManager, type ForesightManagerData, type ForesightManagerSettings, type Point as ForesightPoint, type Rect as ForesightRect, type ForesightRegisterNodeListOptions, type ForesightRegisterOptions, type ForesightRegisterOptionsWithoutElement, type ForesightRegisterResult, type HasListenersFunction, type HitSlop, type ManagerSettingsChangedEvent, type MinimumConnectionType, type MouseTrajectoryUpdateEvent, type ScrollDirection, type ScrollTrajectoryUpdateEvent, type TouchDeviceStrategy, type UpdateForsightManagerSettings, type UpdatedManagerSetting, createUnregisteredSnapshot };
|
|
594
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/helpers/CircularBuffer.ts","../src/types/types.ts","../src/managers/ForesightManager.ts","../src/helpers/createInitialState.ts","../src/core/BaseForesightModule.ts"],"mappings":";cAAa,cAAA;EAAA,QACH,MAAA;EAAA,QACA,IAAA;EAAA,QACA,KAAA;EAAA,QACA,QAAA;cAEI,QAAA;EASZ,GAAA,CAAI,IAAA,EAAM,CAAA;EASV,QAAA,CAAA,GAAY,CAAA;EAYZ,OAAA,CAAA,GAAW,CAAA;EAcX,YAAA,CAAA,IAAiB,CAAA,cAAe,CAAA;EAiBhC,MAAA,CAAO,WAAA;EAAA,QA2BC,WAAA;EAsBR,KAAA,CAAA;EAAA,IAKI,MAAA,CAAA;EAAA,IAIA,IAAA,CAAA;EAAA,IAIA,MAAA,CAAA;EAAA,IAIA,OAAA,CAAA;AAAA;;;KCnIM,IAAA;EACV,GAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;AAAA;;;;;KAOU,iBAAA,IAAqB,KAAA,EAAO,qBAAA;;;;;KAM5B,gBAAA,GAAmB,OAAA;;;;;KAMnB,aAAA;EDDE,2CCGZ,KAAA,EAAO,KAAA,EDSI;ECPX,IAAA;AAAA;AAAA,KAGU,KAAA;EACV,CAAA;EACA,CAAA;AAAA;AAAA,KAGU,mBAAA;EACV,SAAA,EAAW,cAAA,CAAe,aAAA;EAC1B,YAAA,EAAc,KAAA;EACd,cAAA,EAAgB,KAAA;AAAA;;;;;;KAQN,aAAA;EA9CI,iFAgDd,YAAA,EAAc,QAAA,CAAS,IAAA,GAhDT;EAkDd,YAAA,EAAc,eAAA;AAAA;;;;;AAvChB;KA+CY,qBAAA;wDAEV,EAAA,UAjD2D;EAmD3D,IAAA,UA7C0B;EA+C1B,IAAA,EAAM,MAAA;EA/CuB;;EAkD7B,OAAA,EAAS,OAAA,CAAQ,OAAA,WA5CM;EA8CvB,mBAAA,WA5CY;EA8CZ,0BAAA;EA9CO;;;;AAKT;EA+CE,YAAA;;;;EAIA,QAAA;EA9C6B;;EAiD7B,QAAA;EAhDW;;;EAoDX,SAAA,WAlDqB;EAoDrB,WAAA,WAtDW;EAwDX,iBAAA,WAvDA;EAyDA,QAAA,UAxDA;EA0DA,aAAA,UA1DqB;EA4DrB,UAAA,sBApDU;EAsDV,MAAA,EAAQ,cAAA;EAER,KAAA,iBAtDc;EAwDd,eAAA;AAAA;AAAA,KAGU,uBAAA,GAA0B,qBAAA;EA3DpC;;EA8DA,UAAA;EA5DA;;;;AAQF;EA0DE,SAAA,GAAY,QAAA;;;;;EAKZ,WAAA,QAAmB,qBAAA;EArBG;;;;EA0BtB,iBAAA,GAAoB,QAAA;EA9Dd;;;EAkEN,SAAA,QAAiB,aAAA;AAAA;AAAA,KA4BP,cAAA;AAAA,KAEP,mBAAA;EACH,KAAA;EACA,UAAA;AAAA;AAAA,KAGG,iBAAA;EACH,OAAA;EACA,QAAA;AAAA;AAAA,KAGU,eAAA;AAAA,KACP,oBAAA,GAAuB,MAAA,IAAU,OAAA,CAAQ,eAAA;AAAA,KAElC,YAAA;EACV,KAAA;EACA,KAAA,EAAO,mBAAA;EACP,GAAA,EAAK,iBAAA;EACL,MAAA,EAAQ,oBAAA;EACR,KAAA;EACA,QAAA;AAAA;AAAA,KAGU,eAAA;EACN,IAAA;EAAe,OAAA,QAAe,mBAAA;AAAA;EAC9B,IAAA;EAAa,OAAA,QAAe,iBAAA;AAAA;EAC5B,IAAA;EAAgB,OAAA,QAAe,oBAAA;AAAA;EAC/B,IAAA;EAAe,OAAA;AAAA;EACf,IAAA;EAAkB,OAAA;AAAA;;;;KAKZ,oBAAA;EACV,kBAAA,EAAoB,WAAA,CAAY,gBAAA,EAAkB,qBAAA;EAClD,cAAA,EAAgB,QAAA,CAAS,wBAAA;EACzB,kBAAA,EAAoB,QAAA,CAAS,YAAA;EAC7B,cAAA,EAAgB,WAAA,OAAkB,iBAAA,EAAmB,sBAAA;EACrD,qBAAA,EAAuB,qBAAA;EACvB,kBAAA;EACA,kBAAA;EACA,aAAA,EAAe,gBAAA;AAAA;AAAA,KAGL,gBAAA;EACV,cAAA;EACA,YAAA;EACA,UAAA;IACE,KAAA;IACA,GAAA;IACA,MAAA;IACA,QAAA;IACA,UAAA;EAAA;AAAA;AAAA,KAIQ,mBAAA;AAAA,KACA,qBAAA;AAAA,KAEP,4BAAA;EAvCK;;AAGV;;;;;;;;;EAgDE,mBAAA;EA/CkC;;;;;;;;;EA0DlC,oBAAA;EAtDsB;;;AAKxB;;;;;;EA2DE,wBAAA;EAzDgB;;;;;;EAiEhB,qBAAA;EA3De;;;;;;EAmEf,mBAAA;EAzEA;;;;;;;;EAmFA,YAAA;EAjFqD;;;;;EAwFrD,sBAAA;EApFe;;;AAGjB;;;EAyFE,SAAA;EAxFA;;;;;;EAgGA,mBAAA,EAAqB,mBAAA;EAzFnB;;;AAIJ;;;;;EA+FE,qBAAA,EAAuB,qBAAA;AAAA;AAAA,KAGb,qBAAA;;;AAjGsD;;KAuGtD,wBAAA,GAA2B,4BAAA;EACrC,cAAA,EAAgB,OAAA,CAAQ,OAAA;AAAA;;;;;KAOd,6BAAA,GAAgC,4BAAA;EAC1C,cAAA,EAAgB,OAAA;AAAA;;;;KAMN,wBAAA,GAA2B,sCAAA;EACrC,OAAA,EAAS,gBAAA;AAAA;AAAA,KAGC,gCAAA,GAAmC,sCAAA;EAC7C,OAAA,EAAS,UAAA,CAAW,gBAAA;AAAA;;;AApBtB;;;;;KA8BY,sCAAA;EACV,QAAA,EAAU,iBAAA;EACV,OAAA,GAAU,OAAA;EACV,IAAA;EAhCA;;;EAoCA,IAAA,GAAO,MAAA;EApCwB;AAOjC;;;;EAmCE,eAAA;EAlCA;;;;AAMF;EAkCE,OAAA;AAAA;;;;;KAOU,OAAA,GAAU,IAAA;AAAA,UAqBL,iBAAA;EACf,iBAAA,EAAmB,sBAAA;EACnB,mBAAA,EAAqB,wBAAA;EACrB,eAAA,EAAiB,oBAAA;EACjB,iBAAA,EAAmB,sBAAA;EACnB,qBAAA,EAAuB,0BAAA;EACvB,sBAAA,EAAwB,2BAAA;EACxB,sBAAA,EAAwB,2BAAA;EACxB,qBAAA,EAAuB,0BAAA;AAAA;AAAA,KAGb,cAAA;AAAA,UAUK,0BAAA,SAAmC,kBAAA;EAClD,IAAA;EACA,WAAA,EAAa,qBAAA;EACb,WAAA,EAAa,qBAAA;AAAA;AAAA,UAGE,sBAAA,SAA+B,kBAAA;EAC9C,IAAA;EACA,OAAA,EAAS,gBAAA;EACT,KAAA,EAAO,qBAAA;AAAA;AAAA,UAGQ,wBAAA,SAAiC,kBAAA;EAChD,IAAA;EACA,OAAA,EAAS,gBAAA;EACT,KAAA,EAAO,qBAAA;EACP,gBAAA,EAAkB,yBAAA;EAClB,wBAAA;AAAA;;;;;;;;;;KAYU,yBAAA;AAAA,UAEK,oBAAA,SAA6B,kBAAA;EAC5C,IAAA;EACA,OAAA,EAAS,gBAAA;EACT,KAAA,EAAO,qBAAA;EACP,OAAA,EAAS,eAAA;AAAA;AAAA,UAGD,0BAAA,SAAmC,kBAAA;EAC3C,IAAA;EACA,OAAA,EAAS,gBAAA;EACT,KAAA,EAAO,qBAAA;EACP,OAAA,EAAS,eAAA;EACT,OAAA;EACA,oBAAA;AAAA;AAAA,KAGU,sBAAA,GAAyB,0BAAA;EACnC,MAAA,EAAQ,cAAA;EACR,YAAA;AAAA;AAAA,UAGe,0BAAA,SAAmC,IAAA,CAAK,kBAAA;EACvD,IAAA;EACA,mBAAA,EAAqB,mBAAA;EACrB,iBAAA;AAAA;AAAA,UAGe,2BAAA,SAAoC,IAAA,CAAK,kBAAA;EACxD,IAAA;EACA,YAAA,EAAc,KAAA;EACd,cAAA,EAAgB,KAAA;EAChB,eAAA,EAAiB,eAAA;AAAA;AAAA,UAGF,2BAAA,SAAoC,kBAAA;EACnD,IAAA;EACA,WAAA,EAAa,oBAAA;EACb,eAAA,EAAiB,qBAAA;AAAA;AAAA,KAGP,qBAAA,iBACE,wBAAA;EACV,OAAA,EAAS,CAAA;EACT,QAAA,EAAU,wBAAA,CAAyB,CAAA;EACnC,QAAA,EAAU,wBAAA,CAAyB,CAAA;AAAA,UAE/B,wBAAA;AAAA,KAGI,sBAAA,WAAiC,cAAA,GAAiB,cAAA,KAC5D,KAAA,EAAO,iBAAA,CAAkB,CAAA;AAAA,UAIjB,kBAAA;EACR,IAAA,EAAM,cAAA;EACN,SAAA;AAAA;;;AD1fF;;;;;;;;;;;;;;;;;AAAA,cEqDa,gBAAA;EAAA,eACI,OAAA;EFvCX;EAAA,QE0CI,cAAA;EFjCI;EAAA,SEmCI,kBAAA,EAAoB,WAAA,CAAY,gBAAA,EAAkB,qBAAA;EAAA,QAG1D,SAAA;EAAA,QACA,kBAAA;EAAA,QACA,kBAAA;EAAA,QAEA,cAAA;EAAA,QACA,kBAAA;EAAA,QACA,sBAAA;EAAA,QACA,mBAAA;EAAA,QAEA,OAAA;EAAA,QACA,mBAAA;EAAA,QACA,KAAA;EAAA,QACA,WAAA;EAAA,QACA,qBAAA;EAAA,QAEA,YAAA;EAAA,QACA,mBAAA;EAAA,QACA,eAAA;EAAA,QAED,WAAA,CAAA;EAAA,QAoBO,yBAAA;EAAA,QAUA,uBAAA;EAAA,OAUA,UAAA,CAAW,KAAA,GAAQ,OAAA,CAAQ,6BAAA,IAAiC,gBAAA;EAAA,WAQxD,WAAA,CAAA,GAAe,QAAA;EAAA,WAIf,QAAA,CAAA,GAAY,gBAAA;EAAA,QAItB,UAAA;EAAA,YAII,qBAAA,CAAA;EAIL,gBAAA,WAA2B,cAAA,CAAA,CAChC,SAAA,EAAW,CAAA,EACX,QAAA,EAAU,sBAAA,CAAuB,CAAA,GACjC,OAAA;IAAY,MAAA,GAAS,WAAA;EAAA;EAKhB,mBAAA,WAA8B,cAAA,CAAA,CACnC,SAAA,EAAW,CAAA,EACX,QAAA,EAAU,sBAAA,CAAuB,CAAA;EAK5B,YAAA,WAAuB,cAAA,CAAA,CAAgB,SAAA,EAAW,CAAA;EDnJ9B;;;;AAM7B;;;;;EC0JS,kBAAA,CACL,OAAA,EAAS,gBAAA,EACT,QAAA;EDtJqB;;;;;;;ECuKhB,wBAAA,CACL,OAAA,EAAS,gBAAA,EACT,QAAA;EDlKQ;;;;ECgLH,gBAAA,CAAiB,OAAA,EAAS,gBAAA,GAAmB,aAAA;EAAA,IAIzC,cAAA,CAAA,GAAkB,QAAA,CAAS,oBAAA;EAAA,QAa9B,wBAAA;EAiBD,QAAA,CAAS,OAAA,EAAS,gCAAA,GAAmC,uBAAA;EACrD,QAAA,CAAS,OAAA,EAAS,wBAAA,GAA2B,uBAAA;EAAA,QAa5C,eAAA;EDzNM;;;;;;;ECoSP,oBAAA,CACL,OAAA,EAAS,gBAAA,EACT,OAAA,EAAS,OAAA,CAAQ,sCAAA,IAChB,qBAAA;EDvSW;;;;EAAA,QCkWN,aAAA;EDzVE;;;;;EAAA,QCwWF,kBAAA;EDpWqB;;;;;;;;;EAAA,QC4YrB,mBAAA;EAqBD,UAAA,CACL,OAAA,EAAS,gBAAA,GAAmB,UAAA,CAAW,gBAAA,GACvC,gBAAA,GAAmB,yBAAA;EAAA,QASb,iBAAA;EAgDD,UAAA,CAAW,OAAA,EAAS,gBAAA,GAAmB,UAAA,CAAW,gBAAA;EAAA,QAQjD,iBAAA;EDndC;;;;EAAA,QC4eD,iBAAA;EAAA,QA0CA,sBAAA;EAAA,QAKA,YAAA;EAAA,QASA,oBAAA;EAAA,QAYM,oBAAA;EAAA,QA4BN,gBAAA;EAAA,QA8CA,iBAAA;EAAA,QAuBM,iBAAA;EAAA,QAkBN,iBAAA;EAAA,QAmCA,yBAAA;EAAA,QAoBA,qBAAA;EAAA,QAoBA,kBAAA;EDztBR;;;;;EAAA,QCiwBQ,gBAAA;EDrvBR;;;;;;EAAA,QC4wBQ,iBAAA;EDrwByB;;;;;EAAA,QCqyBzB,2BAAA;EAQD,mBAAA,CAAoB,KAAA,GAAQ,OAAA,CAAQ,6BAAA;EAAA,QA2CnC,2BAAA;EDr1BR;;;;EAAA,QCi2BQ,wBAAA;EAAA,QASA,MAAA;AAAA;;;;;;;;;;;;;;;;cCv1BG,0BAAA,GAA8B,mBAAA,cAA+B,qBAAA;;;KCjH9D,oBAAA,cAAkC,cAAA,EAAgB,SAAA,EAAW,CAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e,i as t,n,o as r,t as i}from"./rectAndHitSlop-T7Z3PZlb.mjs";var a=class{constructor(e,t){this.source=e,this.derive=t}get size(){return this.source.size}get(e){let t=this.source.get(e);return t===void 0?void 0:this.derive(t)}has(e){return this.source.has(e)}forEach(e){this.source.forEach((t,n)=>e(this.derive(t),n,this))}*entries(){for(let[e,t]of this.source)yield[e,this.derive(t)]}*values(){for(let e of this.source.values())yield this.derive(e)}keys(){return this.source.keys()}[Symbol.iterator](){return this.entries()}get[Symbol.toStringTag](){return`DerivedMapView`}};const o=e=>{let t=s(),n=c(e);return{isTouchDevice:t,isLimitedConnection:n,shouldRegister:!n}},s=()=>typeof window>`u`||typeof navigator>`u`?!1:window.matchMedia(`(pointer: coarse)`).matches&&navigator.maxTouchPoints>0,c=e=>{let t=navigator.connection;if(!t)return!1;let n=[`slow-2g`,`2g`,`3g`,`4g`];return n.indexOf(t.effectiveType)<n.indexOf(e)||t.saveData},l=e=>{if(typeof window>`u`||typeof document>`u`)return!1;let t=window.innerWidth||document.documentElement.clientWidth,n=window.innerHeight||document.documentElement.clientHeight;return e.top<n&&e.bottom>0&&e.left<t&&e.right>0},u=()=>({mouse:{hover:0,trajectory:0},tab:{forwards:0,reverse:0},scroll:{down:0,left:0,right:0,up:0},touch:0,viewport:0,total:0}),d=()=>({enableManagerLogging:!1,enableMousePrediction:!0,enableScrollPrediction:!0,positionHistorySize:8,trajectoryPredictionTime:120,scrollMargin:150,defaultHitSlop:{top:0,left:0,right:0,bottom:0},enableTabPrediction:!0,tabOffset:2,touchDeviceStrategy:`onTouchStart`,minimumConnectionType:`3g`}),f=(e,r,i,a)=>{let{element:o,callback:s,hitSlop:c,name:u,meta:d,reactivateAfter:f,enabled:p}=e,m=o.getBoundingClientRect(),h=c===void 0?i:t(c),g=p!==!1;return{state:{id:r,name:u||o.id||`unnamed`,meta:d??{},hitSlop:h,isLimitedConnection:a,isIntersectingWithViewport:l(m),isRegistered:!0,isActive:g&&!a,isParked:!1,isEnabled:g,isPredicted:!1,isCallbackRunning:!1,hitCount:0,registerCount:1,durationMs:void 0,status:void 0,error:null,reactivateAfter:f??1/0},bounds:{originalRect:m,expandedRect:n(m,h)},invokedAt:void 0,completedAt:void 0,element:o,callback:s,reactivateTimeoutId:void 0,subscribers:new Set,boundsSubscribers:new Set}},p=e=>({id:``,name:``,meta:{},hitSlop:{top:0,left:0,right:0,bottom:0},isLimitedConnection:e,isIntersectingWithViewport:!1,isRegistered:!1,isActive:!1,isParked:!1,isEnabled:!1,isPredicted:!1,isCallbackRunning:!1,hitCount:0,registerCount:0,durationMs:void 0,status:void 0,error:null,reactivateAfter:r});var m=class{constructor(){this.eventListeners=new Map}addEventListener(e,t,n){if(n?.signal?.aborted)return;let r=this.eventListeners.get(e)??[];r.push(t),this.eventListeners.set(e,r),n?.signal?.addEventListener(`abort`,()=>this.removeEventListener(e,t))}removeEventListener(e,t){let n=this.eventListeners.get(e);if(!n)return;let r=n.indexOf(t);r>-1&&n.splice(r,1)}emit(e){let t=this.eventListeners.get(e.type);if(!(!t||t.length===0))for(let n=0;n<t.length;n++)try{let r=t[n];r&&r(e)}catch(t){console.error(`Error in ForesightManager event listener ${n} for ${e.type}:`,t)}}hasListeners(e){let t=this.eventListeners.get(e);return t!==void 0&&t.length>0}getEventListeners(){return this.eventListeners}};const h=(e,t)=>e!==void 0&&t!==e,g={trajectoryPredictionTime:{min:10,max:200},positionHistorySize:{min:2,max:30},scrollMargin:{min:30,max:300},tabOffset:{min:0,max:20}},_=(t,n,r)=>{if(!h(r,t[n]))return!1;let{min:i,max:a}=g[n];return t[n]=e(r,i,a,n),!0},v=(e,t,n)=>h(n,e[t])?(e[t]=n,!0):!1,y=(e,n)=>{_(e,`trajectoryPredictionTime`,n.trajectoryPredictionTime),_(e,`positionHistorySize`,n.positionHistorySize),_(e,`scrollMargin`,n.scrollMargin),_(e,`tabOffset`,n.tabOffset),v(e,`enableMousePrediction`,n.enableMousePrediction),v(e,`enableScrollPrediction`,n.enableScrollPrediction),v(e,`enableTabPrediction`,n.enableTabPrediction),v(e,`enableManagerLogging`,n.enableManagerLogging),n.defaultHitSlop!==void 0&&(e.defaultHitSlop=t(n.defaultHitSlop)),n.touchDeviceStrategy!==void 0&&(e.touchDeviceStrategy=n.touchDeviceStrategy),n.minimumConnectionType!==void 0&&(e.minimumConnectionType=n.minimumConnectionType)},b=(e,n)=>{let r=[],a=!1,o=!1,s=!1,c=!1,l=!1;if(!n)return{changedSettings:r,positionHistorySizeChanged:a,scrollPredictionChanged:o,tabPredictionChanged:s,hitSlopChanged:c,touchStrategyChanged:l};for(let t of[`trajectoryPredictionTime`,`positionHistorySize`,`scrollMargin`,`tabOffset`]){let i=e[t];_(e,t,n[t])&&(r.push({setting:t,oldValue:i,newValue:e[t]}),t===`positionHistorySize`&&(a=!0))}for(let t of[`enableMousePrediction`,`enableScrollPrediction`,`enableTabPrediction`]){let i=e[t];v(e,t,n[t])&&(r.push({setting:t,oldValue:i,newValue:e[t]}),t===`enableScrollPrediction`&&(o=!0),t===`enableTabPrediction`&&(s=!0))}if(n.defaultHitSlop!==void 0){let a=e.defaultHitSlop,o=t(n.defaultHitSlop);i(a,o)||(e.defaultHitSlop=o,r.push({setting:`defaultHitSlop`,oldValue:a,newValue:o}),c=!0)}if(n.touchDeviceStrategy!==void 0){let t=e.touchDeviceStrategy;e.touchDeviceStrategy=n.touchDeviceStrategy,r.push({setting:`touchDeviceStrategy`,oldValue:t,newValue:n.touchDeviceStrategy}),l=!0}if(n.minimumConnectionType!==void 0){let t=e.minimumConnectionType;e.minimumConnectionType=n.minimumConnectionType,r.push({setting:`minimumConnectionType`,oldValue:t,newValue:n.minimumConnectionType})}return{changedSettings:r,positionHistorySizeChanged:a,scrollPredictionChanged:o,tabPredictionChanged:s,hitSlopChanged:c,touchStrategyChanged:l}};var x=class e{constructor(e){this.elementEntries=new Map,this.registeredElements=new a(this.elementEntries,e=>e.state),this.idCounter=0,this.activeElementCount=0,this.parkedElementCount=0,this.desktopHandler=null,this.touchDeviceHandler=null,this.currentlyActiveHandler=null,this.isSetup=!1,this.pendingPointerEvent=null,this.rafId=null,this.domObserver=null,this.currentDeviceStrategy=s()?`touch`:`mouse`,this.eventEmitter=new m,this._globalCallbackHits=u(),this._globalSettings=d(),this.handlePointerMove=e=>{this.pendingPointerEvent=e,e.pointerType!==this.currentDeviceStrategy&&(this.eventEmitter.emit({type:`deviceStrategyChanged`,timestamp:Date.now(),newStrategy:e.pointerType,oldStrategy:this.currentDeviceStrategy}),this.currentDeviceStrategy=e.pointerType,this.setDeviceStrategy(this.currentDeviceStrategy)),!this.rafId&&(this.rafId=requestAnimationFrame(()=>{if(!this.isUsingDesktopHandler){this.rafId=null;return}this.pendingPointerEvent&&this.desktopHandler?.processMouseMovement(this.pendingPointerEvent),this.rafId=null}))},this.handleDomMutations=e=>{if(!e.length)return;this.desktopHandler?.invalidateTabCache();let t=!1;for(let n=0;n<e.length;n++){let r=e[n];if(r&&r.type===`childList`&&(r.removedNodes.length>0||r.addedNodes.length>0)){t=!0;break}}if(t)for(let e of this.elementEntries.values())e.state.isParked?e.element.isConnected&&this.resumeReconnected(e):e.element.isConnected||this.parkDisconnected(e)},e!==void 0&&y(this._globalSettings,e),this.handlerDependencies={elements:this.elementEntries,callCallback:this.callCallback.bind(this),emit:this.eventEmitter.emit.bind(this.eventEmitter),hasListeners:this.eventEmitter.hasListeners.bind(this.eventEmitter),updateElementState:this.updateElementState.bind(this),updateElementBounds:this.updateElementBounds.bind(this),settings:this._globalSettings},this.devLog(`ForesightManager initialized with device strategy: ${this.currentDeviceStrategy}`),this.initializeGlobalListeners()}async getOrCreateDesktopHandler(){if(!this.desktopHandler){let{DesktopHandler:e}=await import(`./DesktopHandler-CR9nLuzu.mjs`);this.desktopHandler=new e(this.handlerDependencies),this.devLog(`DesktopHandler lazy loaded`)}return this.desktopHandler}async getOrCreateTouchHandler(){if(!this.touchDeviceHandler){let{TouchDeviceHandler:e}=await import(`./TouchDeviceHandler-BPzPdr-z.mjs`);this.touchDeviceHandler=new e(this.handlerDependencies),this.devLog(`TouchDeviceHandler lazy loaded`)}return this.touchDeviceHandler}static initialize(t){return this.isInitiated||(e.manager=new e(t)),e.manager}static get isInitiated(){return!!e.manager}static get instance(){return this.initialize()}generateId(){return`foresight-${++this.idCounter}`}get isUsingDesktopHandler(){return this.currentDeviceStrategy===`mouse`||this.currentDeviceStrategy===`pen`}addEventListener(e,t,n){this.eventEmitter.addEventListener(e,t,n)}removeEventListener(e,t){this.eventEmitter.removeEventListener(e,t)}hasListeners(e){return this.eventEmitter.hasListeners(e)}subscribeToElement(e,t){let n=this.elementEntries.get(e);if(n)return this.makeSubscribe(n.subscribers)(t)}subscribeToElementBounds(e,t){let n=this.elementEntries.get(e);if(n)return this.makeSubscribe(n.boundsSubscribers)(t)}getElementBounds(e){return this.elementEntries.get(e)?.bounds}get getManagerData(){return{registeredElements:this.registeredElements,globalSettings:this._globalSettings,globalCallbackHits:this._globalCallbackHits,eventListeners:this.eventEmitter.getEventListeners(),currentDeviceStrategy:this.currentDeviceStrategy,activeElementCount:this.activeElementCount,parkedElementCount:this.parkedElementCount,loadedModules:this.getLoadedModulesSnapshot()}}getLoadedModulesSnapshot(){let e=this.desktopHandler?.loadedPredictors,t=this.touchDeviceHandler?.loadedPredictors;return{desktopHandler:this.desktopHandler!==null,touchHandler:this.touchDeviceHandler!==null,predictors:{mouse:e?.mouse??!1,tab:e?.tab??!1,scroll:e?.scroll??!1,viewport:t?.viewport??!1,touchStart:t?.touchStart??!1}}}register(e){let{element:t,...n}=e;return t instanceof NodeList?Array.from(t,e=>this.registerElement({...n,element:e})):this.registerElement({...n,element:t})}registerElement(e){let{isLimitedConnection:t}=o(this._globalSettings.minimumConnectionType),n=this.elementEntries.get(e.element);if(n)return this.updateElementOptions(e.element,e),this.updateElementState(n,{registerCount:n.state.registerCount+1}),{...n.state,unregister:()=>{this.unregister(e.element)},subscribe:this.makeSubscribe(n.subscribers),getSnapshot:()=>n.state,subscribeToBounds:this.makeSubscribe(n.boundsSubscribers),getBounds:()=>n.bounds};this.isSetup||this.initializeGlobalListeners();let r=f(e,this.generateId(),this._globalSettings.defaultHitSlop,t);return this.elementEntries.set(e.element,r),r.state.isActive&&(this.activeElementCount++,this.currentlyActiveHandler?.observeElement(e.element)),this.eventEmitter.emit({type:`elementRegistered`,timestamp:Date.now(),element:e.element,state:r.state}),{...r.state,unregister:()=>{this.unregister(e.element)},subscribe:this.makeSubscribe(r.subscribers),getSnapshot:()=>r.state,subscribeToBounds:this.makeSubscribe(r.boundsSubscribers),getBounds:()=>r.bounds}}updateElementOptions(e,r){let a=this.elementEntries.get(e);if(!a)throw Error(`Cannot update options: element is not registered.`);r.callback&&(a.callback=r.callback),r.enabled!==void 0&&this.setElementEnabled(a,e,r.enabled!==!1);let o=a.state.hitSlop;if(r.hitSlop!==void 0){let s=t(r.hitSlop);if(!i(s,o)){o=s;let t=e.getBoundingClientRect();this.updateElementBounds(a,{originalRect:t,expandedRect:n(t,o)})}}let s=a.state.reactivateAfter,c=r.reactivateAfter??s,l=this.updateElementState(a,{name:r.name||a.state.name,meta:r.meta??a.state.meta,reactivateAfter:c,hitSlop:o});return c!==s&&(a.reactivateTimeoutId!==void 0&&this.clearReactivateTimeout(a),c!==1/0&&l.isPredicted&&(a.reactivateTimeoutId=setTimeout(()=>{this.reactivate(e)},c))),l}makeSubscribe(e){return t=>(e.add(t),()=>{e.delete(t)})}updateElementState(e,t){let n=e.state,r=!1;for(let e in t)if(t[e]!==n[e]){r=!0;break}if(!r)return n;let i={...n,...t};e.state=i;for(let t of e.subscribers)try{t()}catch(e){console.error(`Error in element subscriber for ${i.name}:`,e)}return i}updateElementBounds(e,t){let n=e.bounds;if(i(t.originalRect,n.originalRect)&&i(t.expandedRect,n.expandedRect))return n;e.bounds=t;for(let t of e.boundsSubscribers)try{t()}catch(t){console.error(`Error in element bounds subscriber for ${e.state.name}:`,t)}return t}unregister(e,t){e instanceof NodeList?e.forEach(e=>this.unregisterElement(e,t)):this.unregisterElement(e,t)}unregisterElement(e,t){let n=this.elementEntries.get(e);if(!n)return;this.clearReactivateTimeout(n),this.currentlyActiveHandler?.unobserveElement(e),n.state.isActive&&this.activeElementCount--,n.state.isParked&&this.parkedElementCount--;let r=this.updateElementState(n,{isRegistered:!1,isActive:!1,isParked:!1,isPredicted:!1,isCallbackRunning:!1});this.elementEntries.delete(e),n.subscribers.clear(),n.boundsSubscribers.clear();let i=this.elementEntries.size===0&&this.isSetup;i&&(this.devLog(`All elements unregistered, removing global listeners`),this.removeGlobalListeners()),this.eventEmitter.emit({type:`elementUnregistered`,element:e,state:r,timestamp:Date.now(),unregisterReason:t??`by user`,wasLastRegisteredElement:i})}reactivate(e){e instanceof NodeList?e.forEach(e=>this.reactivateElement(e)):this.reactivateElement(e)}reactivateElement(e){let t=this.elementEntries.get(e);!t||!t.state.isEnabled||(this.isSetup||this.initializeGlobalListeners(),this.clearReactivateTimeout(t),!(t.state.isCallbackRunning||t.state.isActive)&&(this.updateElementState(t,{isActive:!0,isPredicted:!1}),this.activeElementCount++,this.currentlyActiveHandler?.observeElement(e)))}setElementEnabled(e,t,n){if(e.state.isEnabled===n)return;let r=n&&!e.state.isLimitedConnection&&!e.state.isParked;r?(this.isSetup||this.initializeGlobalListeners(),this.activeElementCount++,this.currentlyActiveHandler?.observeElement(t)):(this.clearReactivateTimeout(e),this.currentlyActiveHandler?.unobserveElement(t),e.state.isActive&&this.activeElementCount--),this.updateElementState(e,{isEnabled:n,isActive:r,isPredicted:!1,isCallbackRunning:!1}),this.removeGlobalListenersIfIdle()}clearReactivateTimeout(e){clearTimeout(e.reactivateTimeoutId),e.reactivateTimeoutId=void 0}callCallback(e,t){e.state.isPredicted||!e.state.isActive||(this.markElementAsRunning(e),this.executeCallbackAsync(e,t))}markElementAsRunning(e){this.clearReactivateTimeout(e),e.invokedAt=Date.now(),this.updateElementState(e,{isPredicted:!0,isCallbackRunning:!0,hitCount:e.state.hitCount+1})}async executeCallbackAsync(e,t){this.updateHitCounters(t),this.eventEmitter.emit({type:`callbackInvoked`,timestamp:Date.now(),element:e.element,state:e.state,hitType:t});let n=performance.now(),r=null;try{await e.callback(e.state)}catch(t){r=t instanceof Error?t.message:String(t),console.error(`Error in callback for element ${e.state.name}:`,t)}let i=r===null?`success`:`error`;this.finalizeCallback(e,t,n,i,r)}finalizeCallback(e,t,n,r,i){let a=performance.now()-n;e.state.isActive&&this.activeElementCount--,this.currentlyActiveHandler?.unobserveElement(e.element),e.completedAt=Date.now();let o=this.updateElementState(e,{isCallbackRunning:!1,isActive:!1,durationMs:a,status:r,error:i});o.reactivateAfter!==1/0&&(e.reactivateTimeoutId=setTimeout(()=>{this.reactivate(e.element)},o.reactivateAfter));let s=this.activeElementCount===0;this.removeGlobalListenersIfIdle(),this.eventEmitter.emit({type:`callbackCompleted`,timestamp:Date.now(),element:e.element,state:o,hitType:t,elapsed:a,status:r,errorMessage:i,wasLastActiveElement:s})}updateHitCounters(e){switch(e.kind){case`mouse`:this._globalCallbackHits.mouse[e.subType]++;break;case`tab`:this._globalCallbackHits.tab[e.subType]++;break;case`scroll`:this._globalCallbackHits.scroll[e.subType]++;break;case`touch`:this._globalCallbackHits.touch++;break;case`viewport`:this._globalCallbackHits.viewport++;break;default:}this._globalCallbackHits.total++}async setDeviceStrategy(e){let t=this.currentDeviceStrategy;t!==e&&this.devLog(`Switching device strategy from ${t} to ${e}`),this.currentlyActiveHandler?.disconnect(),this.currentlyActiveHandler=e===`mouse`||e===`pen`?await this.getOrCreateDesktopHandler():await this.getOrCreateTouchHandler(),this.currentlyActiveHandler.connect()}initializeGlobalListeners(){this.isSetup||typeof document>`u`||(this.devLog(`Initializing global listeners (pointermove, MutationObserver)`),this.setDeviceStrategy(this.currentDeviceStrategy),document.addEventListener(`pointermove`,this.handlePointerMove),this.domObserver=new MutationObserver(this.handleDomMutations),this.domObserver.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!1}),this.isSetup=!0)}removeGlobalListeners(){typeof document>`u`||(this.isSetup=!1,this.domObserver?.disconnect(),this.domObserver=null,document.removeEventListener(`pointermove`,this.handlePointerMove),this.currentlyActiveHandler?.disconnect(),this.rafId&&=(cancelAnimationFrame(this.rafId),null),this.pendingPointerEvent=null)}parkDisconnected(e){this.clearReactivateTimeout(e),this.currentlyActiveHandler?.unobserveElement(e.element),e.state.isActive&&this.activeElementCount--,this.parkedElementCount++,this.updateElementState(e,{isActive:!1,isCallbackRunning:!1,isParked:!0})}resumeReconnected(e){this.parkedElementCount--;let t=e.state.isEnabled&&!e.state.isLimitedConnection,n=t&&!e.state.isPredicted;n&&(this.isSetup||this.initializeGlobalListeners(),this.activeElementCount++,this.currentlyActiveHandler?.observeElement(e.element)),this.updateElementState(e,{isActive:n,isParked:!1}),t&&e.state.isPredicted&&e.state.reactivateAfter!==1/0&&(e.reactivateTimeoutId=setTimeout(()=>{this.reactivate(e.element)},e.state.reactivateAfter))}removeGlobalListenersIfIdle(){this.activeElementCount>0||this.parkedElementCount>0||this.removeGlobalListeners()}alterGlobalSettings(e){let t=b(this._globalSettings,e);t.positionHistorySizeChanged&&this.desktopHandler&&this.desktopHandler.trajectoryPositions.positions.resize(this._globalSettings.positionHistorySize),t.scrollPredictionChanged&&this.isUsingDesktopHandler&&this.desktopHandler&&(this._globalSettings.enableScrollPrediction?this.desktopHandler.connectScrollPredictor():this.desktopHandler.disconnectScrollPredictor()),t.tabPredictionChanged&&this.isUsingDesktopHandler&&this.desktopHandler&&(this._globalSettings.enableTabPrediction?this.desktopHandler.connectTabPredictor():this.desktopHandler.disconnectTabPredictor()),t.hitSlopChanged&&this.forceUpdateAllElementBounds(),t.touchStrategyChanged&&!this.isUsingDesktopHandler&&this.touchDeviceHandler&&this.touchDeviceHandler.setTouchPredictor(),t.changedSettings.length>0&&this.eventEmitter.emit({type:`managerSettingsChanged`,timestamp:Date.now(),managerData:this.getManagerData,updatedSettings:t.changedSettings})}forceUpdateAllElementBounds(){for(let e of this.elementEntries.values())e.state.isIntersectingWithViewport&&this.forceUpdateElementBounds(e)}forceUpdateElementBounds(e){let t=e.element.getBoundingClientRect();this.updateElementBounds(e,{originalRect:t,expandedRect:n(t,e.state.hitSlop)})}devLog(e){this._globalSettings.enableManagerLogging&&console.log(`%c🛠️ ForesightManager: ${e}`,`color: #16a34a; font-weight: bold;`)}};export{x as ForesightManager,p as createUnregisteredSnapshot};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|