js.foresight 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +120 -5
  2. package/dist/{src/types/types.d.ts → index.d.mts} +156 -67
  3. package/dist/index.d.ts +61 -47
  4. package/dist/index.js +2 -6
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +2 -6
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +5 -12
  9. package/dist/Manager/ForesightManager.d.ts +0 -89
  10. package/dist/Manager/ForesightManager.d.ts.map +0 -1
  11. package/dist/Manager/ForesightManager.js +0 -639
  12. package/dist/Manager/ForesightManager.js.map +0 -1
  13. package/dist/Manager/constants.d.ts +0 -23
  14. package/dist/Manager/constants.d.ts.map +0 -1
  15. package/dist/Manager/constants.js +0 -24
  16. package/dist/Manager/constants.js.map +0 -1
  17. package/dist/Manager/helpers/clampNumber.d.ts +0 -2
  18. package/dist/Manager/helpers/clampNumber.d.ts.map +0 -1
  19. package/dist/Manager/helpers/clampNumber.js +0 -10
  20. package/dist/Manager/helpers/clampNumber.js.map +0 -1
  21. package/dist/Manager/helpers/getFocusedElementIndex.d.ts +0 -15
  22. package/dist/Manager/helpers/getFocusedElementIndex.d.ts.map +0 -1
  23. package/dist/Manager/helpers/getFocusedElementIndex.js +0 -27
  24. package/dist/Manager/helpers/getFocusedElementIndex.js.map +0 -1
  25. package/dist/Manager/helpers/getScrollDirection.d.ts +0 -3
  26. package/dist/Manager/helpers/getScrollDirection.d.ts.map +0 -1
  27. package/dist/Manager/helpers/getScrollDirection.js +0 -21
  28. package/dist/Manager/helpers/getScrollDirection.js.map +0 -1
  29. package/dist/Manager/helpers/lineSigmentIntersectsRect.d.ts +0 -12
  30. package/dist/Manager/helpers/lineSigmentIntersectsRect.d.ts.map +0 -1
  31. package/dist/Manager/helpers/lineSigmentIntersectsRect.js +0 -52
  32. package/dist/Manager/helpers/lineSigmentIntersectsRect.js.map +0 -1
  33. package/dist/Manager/helpers/predictNextMousePosition.d.ts +0 -19
  34. package/dist/Manager/helpers/predictNextMousePosition.d.ts.map +0 -1
  35. package/dist/Manager/helpers/predictNextMousePosition.js +0 -43
  36. package/dist/Manager/helpers/predictNextMousePosition.js.map +0 -1
  37. package/dist/Manager/helpers/predictNextScrollPosition.d.ts +0 -6
  38. package/dist/Manager/helpers/predictNextScrollPosition.d.ts.map +0 -1
  39. package/dist/Manager/helpers/predictNextScrollPosition.js +0 -20
  40. package/dist/Manager/helpers/predictNextScrollPosition.js.map +0 -1
  41. package/dist/Manager/helpers/rectAndHitSlop.d.ts +0 -33
  42. package/dist/Manager/helpers/rectAndHitSlop.d.ts.map +0 -1
  43. package/dist/Manager/helpers/rectAndHitSlop.js +0 -66
  44. package/dist/Manager/helpers/rectAndHitSlop.js.map +0 -1
  45. package/dist/Manager/helpers/shouldUpdateSetting.d.ts +0 -11
  46. package/dist/Manager/helpers/shouldUpdateSetting.d.ts.map +0 -1
  47. package/dist/Manager/helpers/shouldUpdateSetting.js +0 -16
  48. package/dist/Manager/helpers/shouldUpdateSetting.js.map +0 -1
  49. package/dist/helpers/shouldRegister.d.ts +0 -8
  50. package/dist/helpers/shouldRegister.d.ts.map +0 -1
  51. package/dist/helpers/shouldRegister.js +0 -31
  52. package/dist/helpers/shouldRegister.js.map +0 -1
  53. package/dist/index.d.ts.map +0 -1
  54. package/dist/src/Manager/ForesightManager.d.ts +0 -89
  55. package/dist/src/Manager/ForesightManager.d.ts.map +0 -1
  56. package/dist/src/Manager/ForesightManager.test.d.ts +0 -2
  57. package/dist/src/Manager/ForesightManager.test.d.ts.map +0 -1
  58. package/dist/src/Manager/constants.d.ts +0 -23
  59. package/dist/src/Manager/constants.d.ts.map +0 -1
  60. package/dist/src/Manager/helpers/clampNumber.d.ts +0 -2
  61. package/dist/src/Manager/helpers/clampNumber.d.ts.map +0 -1
  62. package/dist/src/Manager/helpers/clampNumber.test.d.ts +0 -2
  63. package/dist/src/Manager/helpers/clampNumber.test.d.ts.map +0 -1
  64. package/dist/src/Manager/helpers/getFocusedElementIndex.d.ts +0 -15
  65. package/dist/src/Manager/helpers/getFocusedElementIndex.d.ts.map +0 -1
  66. package/dist/src/Manager/helpers/getFocusedElementIndex.test.d.ts +0 -2
  67. package/dist/src/Manager/helpers/getFocusedElementIndex.test.d.ts.map +0 -1
  68. package/dist/src/Manager/helpers/getScrollDirection.d.ts +0 -3
  69. package/dist/src/Manager/helpers/getScrollDirection.d.ts.map +0 -1
  70. package/dist/src/Manager/helpers/lineSegmentIntersectsRect.test.d.ts +0 -2
  71. package/dist/src/Manager/helpers/lineSegmentIntersectsRect.test.d.ts.map +0 -1
  72. package/dist/src/Manager/helpers/lineSigmentIntersectsRect.d.ts +0 -12
  73. package/dist/src/Manager/helpers/lineSigmentIntersectsRect.d.ts.map +0 -1
  74. package/dist/src/Manager/helpers/predictNextMousePosition.d.ts +0 -19
  75. package/dist/src/Manager/helpers/predictNextMousePosition.d.ts.map +0 -1
  76. package/dist/src/Manager/helpers/predictNextMousePosition.test.d.ts +0 -2
  77. package/dist/src/Manager/helpers/predictNextMousePosition.test.d.ts.map +0 -1
  78. package/dist/src/Manager/helpers/predictNextScrollPosition.d.ts +0 -6
  79. package/dist/src/Manager/helpers/predictNextScrollPosition.d.ts.map +0 -1
  80. package/dist/src/Manager/helpers/rectAndHitSlop.d.ts +0 -33
  81. package/dist/src/Manager/helpers/rectAndHitSlop.d.ts.map +0 -1
  82. package/dist/src/Manager/helpers/rectAndHitSlop.test.d.ts +0 -2
  83. package/dist/src/Manager/helpers/rectAndHitSlop.test.d.ts.map +0 -1
  84. package/dist/src/Manager/helpers/shouldUpdateSetting.d.ts +0 -11
  85. package/dist/src/Manager/helpers/shouldUpdateSetting.d.ts.map +0 -1
  86. package/dist/src/helpers/shouldRegister.d.ts +0 -8
  87. package/dist/src/helpers/shouldRegister.d.ts.map +0 -1
  88. package/dist/src/index.d.ts +0 -3
  89. package/dist/src/index.d.ts.map +0 -1
  90. package/dist/src/types/types.d.ts.map +0 -1
  91. package/dist/test-setup.d.ts +0 -17
  92. package/dist/test-setup.d.ts.map +0 -1
  93. package/dist/tsconfig.tsbuildinfo +0 -1
  94. package/dist/types/types.d.ts +0 -312
  95. package/dist/types/types.d.ts.map +0 -1
  96. package/dist/types/types.js +0 -2
  97. package/dist/types/types.js.map +0 -1
@@ -1,639 +0,0 @@
1
- var __assign = (this && this.__assign) || function () {
2
- __assign = Object.assign || function(t) {
3
- for (var s, i = 1, n = arguments.length; i < n; i++) {
4
- s = arguments[i];
5
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
- t[p] = s[p];
7
- }
8
- return t;
9
- };
10
- return __assign.apply(this, arguments);
11
- };
12
- import { tabbable } from "tabbable";
13
- import { evaluateRegistrationConditions } from "../helpers/shouldRegister";
14
- import { DEFAULT_ENABLE_MOUSE_PREDICTION, DEFAULT_ENABLE_SCROLL_PREDICTION, DEFAULT_ENABLE_TAB_PREDICTION, DEFAULT_HITSLOP, DEFAULT_POSITION_HISTORY_SIZE, DEFAULT_SCROLL_MARGIN, DEFAULT_TAB_OFFSET, DEFAULT_TRAJECTORY_PREDICTION_TIME, MAX_POSITION_HISTORY_SIZE, MAX_SCROLL_MARGIN, MAX_TAB_OFFSET, MAX_TRAJECTORY_PREDICTION_TIME, MIN_POSITION_HISTORY_SIZE, MIN_SCROLL_MARGIN, MIN_TAB_OFFSET, MIN_TRAJECTORY_PREDICTION_TIME, } from "./constants";
15
- import { clampNumber } from "./helpers/clampNumber";
16
- import { lineSegmentIntersectsRect } from "./helpers/lineSigmentIntersectsRect";
17
- import { predictNextMousePosition } from "./helpers/predictNextMousePosition";
18
- import { areRectsEqual, getExpandedRect, isPointInRectangle, normalizeHitSlop, } from "./helpers/rectAndHitSlop";
19
- import { shouldUpdateSetting } from "./helpers/shouldUpdateSetting";
20
- import { getFocusedElementIndex } from "./helpers/getFocusedElementIndex";
21
- import { getScrollDirection } from "./helpers/getScrollDirection";
22
- import { predictNextScrollPosition } from "./helpers/predictNextScrollPosition";
23
- import { PositionObserver } from "position-observer";
24
- /**
25
- * Manages the prediction of user intent based on mouse trajectory and element interactions.
26
- *
27
- * ForesightManager is a singleton class responsible for:
28
- * - Registering HTML elements to monitor.
29
- * - Tracking mouse movements and predicting future cursor positions.
30
- * - Detecting when a predicted trajectory intersects with a registered element's bounds.
31
- * - Invoking callbacks associated with elements upon predicted or actual interaction.
32
- * - Optionally unregistering elements after their callback is triggered.
33
- * - Handling global settings for prediction behavior (e.g., history size, prediction time).
34
- * - Automatically updating element bounds on resize using {@link ResizeObserver}.
35
- * - Automatically unregistering elements removed from the DOM using {@link MutationObserver}.
36
- * - Detecting broader layout shifts via {@link MutationObserver} to update element positions.
37
- *
38
- * It should be initialized once using {@link ForesightManager.initialize} and then
39
- * accessed via the static getter {@link ForesightManager.instance}.
40
- */
41
- var ForesightManager = /** @class */ (function () {
42
- // Never put something in the constructor, use initialize instead
43
- function ForesightManager() {
44
- var _this = this;
45
- this.elements = new Map();
46
- this.isSetup = false;
47
- this._globalCallbackHits = {
48
- mouse: {
49
- hover: 0,
50
- trajectory: 0,
51
- },
52
- tab: {
53
- forwards: 0,
54
- reverse: 0,
55
- },
56
- scroll: {
57
- down: 0,
58
- left: 0,
59
- right: 0,
60
- up: 0,
61
- },
62
- total: 0,
63
- };
64
- this._globalSettings = {
65
- debug: false,
66
- enableMousePrediction: DEFAULT_ENABLE_MOUSE_PREDICTION,
67
- enableScrollPrediction: DEFAULT_ENABLE_SCROLL_PREDICTION,
68
- positionHistorySize: DEFAULT_POSITION_HISTORY_SIZE,
69
- trajectoryPredictionTime: DEFAULT_TRAJECTORY_PREDICTION_TIME,
70
- scrollMargin: DEFAULT_SCROLL_MARGIN,
71
- defaultHitSlop: {
72
- top: DEFAULT_HITSLOP,
73
- left: DEFAULT_HITSLOP,
74
- right: DEFAULT_HITSLOP,
75
- bottom: DEFAULT_HITSLOP,
76
- },
77
- enableTabPrediction: DEFAULT_ENABLE_TAB_PREDICTION,
78
- tabOffset: DEFAULT_TAB_OFFSET,
79
- onAnyCallbackFired: function (_elementData, _managerData) { },
80
- };
81
- this.trajectoryPositions = {
82
- positions: [],
83
- currentPoint: { x: 0, y: 0 },
84
- predictedPoint: { x: 0, y: 0 },
85
- };
86
- this.tabbableElementsCache = [];
87
- this.lastFocusedIndex = null;
88
- this.predictedScrollPoint = null;
89
- this.scrollDirection = null;
90
- this.domObserver = null;
91
- this.positionObserver = null;
92
- // Track the last keydown event to determine if focus change was due to Tab
93
- this.lastKeyDown = null;
94
- // AbortController for managing global event listeners
95
- this.globalListenersController = null;
96
- this.eventListeners = new Map();
97
- this.handleMouseMove = function (e) {
98
- _this.updatePointerState(e);
99
- _this.elements.forEach(function (currentData) {
100
- if (!currentData.isIntersectingWithViewport) {
101
- return;
102
- }
103
- _this.handleCallbackInteraction(currentData);
104
- });
105
- _this.emit({
106
- type: "mouseTrajectoryUpdate",
107
- predictionEnabled: _this._globalSettings.enableMousePrediction,
108
- timestamp: Date.now(),
109
- trajectoryPositions: _this.trajectoryPositions,
110
- });
111
- };
112
- /**
113
- * Detects when registered elements are removed from the DOM and automatically unregisters them to prevent stale references.
114
- *
115
- * @param mutationsList - Array of MutationRecord objects describing the DOM changes
116
- *
117
- */
118
- this.handleDomMutations = function (mutationsList) {
119
- // Invalidate tabbale elements cache
120
- if (mutationsList.length) {
121
- _this.tabbableElementsCache = [];
122
- _this.lastFocusedIndex = null;
123
- }
124
- for (var _i = 0, mutationsList_1 = mutationsList; _i < mutationsList_1.length; _i++) {
125
- var mutation = mutationsList_1[_i];
126
- if (mutation.type === "childList" && mutation.removedNodes.length > 0) {
127
- for (var _a = 0, _b = Array.from(_this.elements.keys()); _a < _b.length; _a++) {
128
- var element = _b[_a];
129
- if (!element.isConnected) {
130
- _this.unregister(element, "disconnected");
131
- }
132
- }
133
- }
134
- }
135
- };
136
- // We store the last key for the FocusIn event, meaning we know if the user is tabbing around the page.
137
- // We dont use handleKeyDown for the full event because of 2 main reasons:
138
- // 1: handleKeyDown e.target returns the target on which the keydown is pressed (meaning we dont know which target got the focus)
139
- // 2: handleKeyUp does return the correct e.target however when holding tab the event doesnt repeat (handleKeyDown does)
140
- this.handleKeyDown = function (e) {
141
- if (e.key === "Tab") {
142
- _this.lastKeyDown = e;
143
- }
144
- };
145
- this.handleFocusIn = function (e) {
146
- if (!_this.lastKeyDown || !_this._globalSettings.enableTabPrediction) {
147
- return;
148
- }
149
- var targetElement = e.target;
150
- if (!(targetElement instanceof HTMLElement)) {
151
- return;
152
- }
153
- // tabbable uses element.GetBoundingClientRect under the hood, to avoid alot of computations we cache its values
154
- if (!_this.tabbableElementsCache.length) {
155
- _this.tabbableElementsCache = tabbable(document.documentElement);
156
- }
157
- // Determine the range of elements to check based on the tab direction and offset
158
- var isReversed = _this.lastKeyDown.shiftKey;
159
- var currentIndex = getFocusedElementIndex(isReversed, _this.lastFocusedIndex, _this.tabbableElementsCache, targetElement);
160
- _this.lastFocusedIndex = currentIndex;
161
- _this.lastKeyDown = null;
162
- var elementsToPredict = [];
163
- for (var i = 0; i <= _this._globalSettings.tabOffset; i++) {
164
- if (isReversed) {
165
- var element = _this.tabbableElementsCache[currentIndex - i];
166
- if (_this.elements.has(element)) {
167
- elementsToPredict.push(element);
168
- }
169
- }
170
- else {
171
- var element = _this.tabbableElementsCache[currentIndex + i];
172
- if (_this.elements.has(element)) {
173
- elementsToPredict.push(element);
174
- }
175
- }
176
- }
177
- elementsToPredict.forEach(function (element) {
178
- _this.callCallback(_this.elements.get(element), {
179
- kind: "tab",
180
- subType: isReversed ? "reverse" : "forwards",
181
- });
182
- });
183
- };
184
- this.handlePositionChange = function (entries) {
185
- for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
186
- var entry = entries_1[_i];
187
- var elementData = _this.elements.get(entry.target);
188
- if (!elementData)
189
- continue;
190
- var wasPreviouslyIntersecting = elementData.isIntersectingWithViewport;
191
- var isNowIntersecting = entry.isIntersecting;
192
- elementData.isIntersectingWithViewport = isNowIntersecting;
193
- if (wasPreviouslyIntersecting !== isNowIntersecting) {
194
- // TODO check if visibility status is changing
195
- _this.emit({
196
- type: "elementDataUpdated",
197
- elementData: elementData,
198
- timestamp: Date.now(),
199
- updatedProp: "visibility",
200
- });
201
- }
202
- if (isNowIntersecting) {
203
- _this.updateElementBounds(entry.boundingClientRect, elementData);
204
- _this.handleScrollPrefetch(elementData, entry.boundingClientRect);
205
- }
206
- }
207
- _this.scrollDirection = null;
208
- _this.predictedScrollPoint = null;
209
- };
210
- }
211
- ForesightManager.initialize = function (props) {
212
- if (!this.isInitiated) {
213
- ForesightManager.manager = new ForesightManager();
214
- }
215
- if (props !== undefined) {
216
- ForesightManager.manager.alterGlobalSettings(props);
217
- }
218
- return ForesightManager.manager;
219
- };
220
- ForesightManager.prototype.addEventListener = function (eventType, listener, options) {
221
- var _this = this;
222
- var _a, _b;
223
- if ((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
224
- return function () { };
225
- }
226
- if (!this.eventListeners.has(eventType)) {
227
- this.eventListeners.set(eventType, []);
228
- }
229
- this.eventListeners.get(eventType).push(listener);
230
- (_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.addEventListener("abort", function () { return _this.removeEventListener(eventType, listener); });
231
- };
232
- ForesightManager.prototype.removeEventListener = function (eventType, listener) {
233
- var listeners = this.eventListeners.get(eventType);
234
- if (listeners) {
235
- var index = listeners.indexOf(listener);
236
- if (index > -1) {
237
- listeners.splice(index, 1);
238
- }
239
- }
240
- };
241
- // Used for debugging only
242
- ForesightManager.prototype.logSubscribers = function () {
243
- var _this = this;
244
- console.log("%c[ForesightManager] Current Subscribers:", "font-weight: bold; color: #3b82f6;");
245
- var eventTypes = Array.from(this.eventListeners.keys());
246
- if (eventTypes.length === 0) {
247
- console.log(" No active subscribers.");
248
- return;
249
- }
250
- eventTypes.forEach(function (eventType) {
251
- var listeners = _this.eventListeners.get(eventType);
252
- if (listeners && listeners.length > 0) {
253
- // Use groupCollapsed so the log isn't too noisy by default.
254
- // The user can expand the events they are interested in.
255
- console.groupCollapsed("Event: %c".concat(eventType), "font-weight: bold;", "(".concat(listeners.length, " listener").concat(listeners.length > 1 ? "s" : "", ")"));
256
- listeners.forEach(function (listener, index) {
257
- console.log("[".concat(index, "]:"), listener);
258
- });
259
- console.groupEnd();
260
- }
261
- });
262
- };
263
- ForesightManager.prototype.emit = function (event) {
264
- var listeners = this.eventListeners.get(event.type);
265
- if (listeners) {
266
- listeners.forEach(function (listener) {
267
- try {
268
- listener(event);
269
- }
270
- catch (error) {
271
- console.error("Error in ForesightManager event listener for ".concat(event.type, ":"), error);
272
- }
273
- });
274
- }
275
- };
276
- Object.defineProperty(ForesightManager.prototype, "getManagerData", {
277
- get: function () {
278
- return {
279
- registeredElements: this.elements,
280
- globalSettings: this._globalSettings,
281
- globalCallbackHits: this._globalCallbackHits,
282
- };
283
- },
284
- enumerable: false,
285
- configurable: true
286
- });
287
- Object.defineProperty(ForesightManager, "isInitiated", {
288
- get: function () {
289
- return !!ForesightManager.manager;
290
- },
291
- enumerable: false,
292
- configurable: true
293
- });
294
- Object.defineProperty(ForesightManager, "instance", {
295
- get: function () {
296
- return this.initialize();
297
- },
298
- enumerable: false,
299
- configurable: true
300
- });
301
- Object.defineProperty(ForesightManager.prototype, "registeredElements", {
302
- get: function () {
303
- return this.elements;
304
- },
305
- enumerable: false,
306
- configurable: true
307
- });
308
- ForesightManager.prototype.register = function (_a) {
309
- var _this = this;
310
- var _b, _c;
311
- var element = _a.element, callback = _a.callback, hitSlop = _a.hitSlop, name = _a.name;
312
- var _d = evaluateRegistrationConditions(), shouldRegister = _d.shouldRegister, isTouchDevice = _d.isTouchDevice, isLimitedConnection = _d.isLimitedConnection;
313
- if (!shouldRegister) {
314
- return {
315
- isLimitedConnection: isLimitedConnection,
316
- isTouchDevice: isTouchDevice,
317
- isRegistered: false,
318
- unregister: function () { },
319
- };
320
- }
321
- // Setup global listeners on every first element added to the manager. It gets removed again when the map is emptied
322
- if (!this.isSetup) {
323
- this.initializeGlobalListeners();
324
- }
325
- var normalizedHitSlop = hitSlop
326
- ? normalizeHitSlop(hitSlop)
327
- : this._globalSettings.defaultHitSlop;
328
- // const elementRect = element.getBoundingClientRect()
329
- var elementData = {
330
- element: element,
331
- callback: callback,
332
- callbackHits: {
333
- mouse: {
334
- hover: 0,
335
- trajectory: 0,
336
- },
337
- tab: {
338
- forwards: 0,
339
- reverse: 0,
340
- },
341
- scroll: {
342
- down: 0,
343
- left: 0,
344
- right: 0,
345
- up: 0,
346
- },
347
- total: 0,
348
- },
349
- elementBounds: {
350
- originalRect: undefined,
351
- expandedRect: { top: 0, left: 0, right: 0, bottom: 0 },
352
- hitSlop: normalizedHitSlop,
353
- },
354
- isHovering: false,
355
- trajectoryHitData: {
356
- isTrajectoryHit: false,
357
- trajectoryHitTime: 0,
358
- trajectoryHitExpirationTimeoutId: undefined,
359
- },
360
- name: (_b = name !== null && name !== void 0 ? name : element.id) !== null && _b !== void 0 ? _b : "",
361
- isIntersectingWithViewport: true,
362
- };
363
- this.elements.set(element, elementData);
364
- (_c = this.positionObserver) === null || _c === void 0 ? void 0 : _c.observe(element);
365
- this.emit({
366
- type: "elementRegistered",
367
- timestamp: Date.now(),
368
- elementData: elementData,
369
- });
370
- return {
371
- isTouchDevice: isTouchDevice,
372
- isLimitedConnection: isLimitedConnection,
373
- isRegistered: true,
374
- unregister: function () { return _this.unregister(element, "apiCall"); },
375
- };
376
- };
377
- ForesightManager.prototype.unregister = function (element, unregisterReason) {
378
- var _a;
379
- if (!this.elements.has(element)) {
380
- return;
381
- }
382
- var foresightElementData = this.elements.get(element);
383
- if (foresightElementData) {
384
- this.emit({
385
- type: "elementUnregistered",
386
- elementData: foresightElementData,
387
- timestamp: Date.now(),
388
- unregisterReason: unregisterReason,
389
- });
390
- }
391
- // Clear any pending trajectory expiration timeout
392
- if (foresightElementData === null || foresightElementData === void 0 ? void 0 : foresightElementData.trajectoryHitData.trajectoryHitExpirationTimeoutId) {
393
- clearTimeout(foresightElementData.trajectoryHitData.trajectoryHitExpirationTimeoutId);
394
- }
395
- (_a = this.positionObserver) === null || _a === void 0 ? void 0 : _a.unobserve(element);
396
- this.elements.delete(element);
397
- if (this.elements.size === 0 && this.isSetup) {
398
- this.removeGlobalListeners();
399
- }
400
- };
401
- ForesightManager.prototype.updateNumericSettings = function (newValue, setting, min, max) {
402
- if (!shouldUpdateSetting(newValue, this._globalSettings[setting])) {
403
- return false;
404
- }
405
- this._globalSettings[setting] = clampNumber(newValue, min, max, setting);
406
- return true;
407
- };
408
- ForesightManager.prototype.updateBooleanSetting = function (newValue, setting) {
409
- if (!shouldUpdateSetting(newValue, this._globalSettings[setting])) {
410
- return false;
411
- }
412
- this._globalSettings[setting] = newValue;
413
- return true;
414
- };
415
- ForesightManager.prototype.alterGlobalSettings = function (props) {
416
- // Call each update function and store whether it made a change.
417
- // This ensures every update function is executed.
418
- var oldPositionHistorySize = this._globalSettings.positionHistorySize;
419
- var positionHistoryChanged = this.updateNumericSettings(props === null || props === void 0 ? void 0 : props.positionHistorySize, "positionHistorySize", MIN_POSITION_HISTORY_SIZE, MAX_POSITION_HISTORY_SIZE);
420
- if (positionHistoryChanged &&
421
- this._globalSettings.positionHistorySize < oldPositionHistorySize) {
422
- if (this.trajectoryPositions.positions.length > this._globalSettings.positionHistorySize) {
423
- this.trajectoryPositions.positions = this.trajectoryPositions.positions.slice(this.trajectoryPositions.positions.length - this._globalSettings.positionHistorySize);
424
- }
425
- }
426
- var trajectoryTimeChanged = this.updateNumericSettings(props === null || props === void 0 ? void 0 : props.trajectoryPredictionTime, "trajectoryPredictionTime", MIN_TRAJECTORY_PREDICTION_TIME, MAX_TRAJECTORY_PREDICTION_TIME);
427
- var scrollMarginChanged = this.updateNumericSettings(props === null || props === void 0 ? void 0 : props.scrollMargin, "scrollMargin", MIN_SCROLL_MARGIN, MAX_SCROLL_MARGIN);
428
- var tabOffsetChanged = this.updateNumericSettings(props === null || props === void 0 ? void 0 : props.tabOffset, "tabOffset", MIN_TAB_OFFSET, MAX_TAB_OFFSET);
429
- var mousePredictionChanged = this.updateBooleanSetting(props === null || props === void 0 ? void 0 : props.enableMousePrediction, "enableMousePrediction");
430
- var scrollPredictionChanged = this.updateBooleanSetting(props === null || props === void 0 ? void 0 : props.enableScrollPrediction, "enableScrollPrediction");
431
- var tabPredictionChanged = this.updateBooleanSetting(props === null || props === void 0 ? void 0 : props.enableTabPrediction, "enableTabPrediction");
432
- if ((props === null || props === void 0 ? void 0 : props.onAnyCallbackFired) !== undefined) {
433
- this._globalSettings.onAnyCallbackFired = props.onAnyCallbackFired;
434
- }
435
- var hitSlopChanged = false;
436
- if ((props === null || props === void 0 ? void 0 : props.defaultHitSlop) !== undefined) {
437
- var normalizedNewHitSlop = normalizeHitSlop(props.defaultHitSlop);
438
- if (!areRectsEqual(this._globalSettings.defaultHitSlop, normalizedNewHitSlop)) {
439
- this._globalSettings.defaultHitSlop = normalizedNewHitSlop;
440
- hitSlopChanged = true;
441
- this.forceUpdateAllElementBounds();
442
- }
443
- }
444
- var settingsActuallyChanged = positionHistoryChanged ||
445
- trajectoryTimeChanged ||
446
- tabOffsetChanged ||
447
- mousePredictionChanged ||
448
- tabPredictionChanged ||
449
- scrollPredictionChanged ||
450
- hitSlopChanged ||
451
- scrollMarginChanged;
452
- if (settingsActuallyChanged) {
453
- this.emit({
454
- type: "managerSettingsChanged",
455
- timestamp: Date.now(),
456
- newSettings: this._globalSettings,
457
- });
458
- }
459
- };
460
- ForesightManager.prototype.forceUpdateAllElementBounds = function () {
461
- var _this = this;
462
- this.elements.forEach(function (_, element) {
463
- var elementData = _this.elements.get(element);
464
- // For performance only update rects that are currently intersecting with the viewport
465
- if (elementData && elementData.isIntersectingWithViewport) {
466
- _this.forceUpdateElementBounds(elementData);
467
- }
468
- });
469
- };
470
- ForesightManager.prototype.updatePointerState = function (e) {
471
- this.trajectoryPositions.currentPoint = { x: e.clientX, y: e.clientY };
472
- this.trajectoryPositions.predictedPoint = this._globalSettings.enableMousePrediction
473
- ? predictNextMousePosition(this.trajectoryPositions.currentPoint, this.trajectoryPositions.positions, // History before the currentPoint was added
474
- this._globalSettings.positionHistorySize, this._globalSettings.trajectoryPredictionTime)
475
- : __assign({}, this.trajectoryPositions.currentPoint);
476
- };
477
- /**
478
- * Processes elements that unregister after a single callback.
479
- *
480
- * This is a "fire-and-forget" handler. Its only goal is to trigger the
481
- * callback once. It does so if the mouse trajectory is predicted to hit the
482
- * element (if prediction is on) OR if the mouse physically hovers over it.
483
- * It does not track state, as the element is immediately unregistered.
484
- *
485
- * @param elementData - The data object for the foresight element.
486
- * @param element - The HTML element being interacted with.
487
- */
488
- ForesightManager.prototype.handleCallbackInteraction = function (elementData) {
489
- var expandedRect = elementData.elementBounds.expandedRect;
490
- // when enable mouse prediction is off, we only check if the mouse is physically hovering over the element
491
- if (!this._globalSettings.enableMousePrediction) {
492
- if (isPointInRectangle(this.trajectoryPositions.currentPoint, expandedRect)) {
493
- this.callCallback(elementData, { kind: "mouse", subType: "hover" });
494
- return;
495
- }
496
- }
497
- else if (lineSegmentIntersectsRect(this.trajectoryPositions.currentPoint, this.trajectoryPositions.predictedPoint, expandedRect)) {
498
- this.callCallback(elementData, { kind: "mouse", subType: "trajectory" });
499
- }
500
- };
501
- ForesightManager.prototype.updateHitCounters = function (elementData, hitType) {
502
- switch (hitType.kind) {
503
- case "mouse":
504
- elementData.callbackHits.mouse[hitType.subType]++;
505
- this._globalCallbackHits.mouse[hitType.subType]++;
506
- break;
507
- case "tab":
508
- elementData.callbackHits.tab[hitType.subType]++;
509
- this._globalCallbackHits.tab[hitType.subType]++;
510
- break;
511
- case "scroll":
512
- elementData.callbackHits.scroll[hitType.subType]++;
513
- this._globalCallbackHits.scroll[hitType.subType]++;
514
- break;
515
- }
516
- elementData.callbackHits.total++;
517
- this._globalCallbackHits.total++;
518
- };
519
- ForesightManager.prototype.callCallback = function (elementData, hitType) {
520
- if (elementData) {
521
- this.updateHitCounters(elementData, hitType);
522
- elementData.callback();
523
- this._globalSettings.onAnyCallbackFired(elementData, this.getManagerData);
524
- this.emit({
525
- type: "callbackFired",
526
- timestamp: Date.now(),
527
- elementData: elementData,
528
- hitType: hitType,
529
- });
530
- this.unregister(elementData.element, "callbackHit");
531
- }
532
- };
533
- /**
534
- * 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.
535
- * We need an observer for that
536
- */
537
- ForesightManager.prototype.forceUpdateElementBounds = function (elementData) {
538
- var newOriginalRect = elementData.element.getBoundingClientRect();
539
- var expandedRect = getExpandedRect(newOriginalRect, elementData.elementBounds.hitSlop);
540
- if (!areRectsEqual(expandedRect, elementData.elementBounds.expandedRect)) {
541
- var updatedElementData = __assign(__assign({}, elementData), { elementBounds: __assign(__assign({}, elementData.elementBounds), { originalRect: newOriginalRect, expandedRect: expandedRect }) });
542
- this.elements.set(elementData.element, updatedElementData);
543
- this.emit({
544
- type: "elementDataUpdated",
545
- timestamp: Date.now(),
546
- elementData: updatedElementData,
547
- updatedProp: "bounds",
548
- });
549
- }
550
- };
551
- ForesightManager.prototype.updateElementBounds = function (newRect, elementData) {
552
- var updatedElementData = __assign(__assign({}, elementData), { elementBounds: __assign(__assign({}, elementData.elementBounds), { originalRect: newRect, expandedRect: getExpandedRect(newRect, elementData.elementBounds.hitSlop) }) });
553
- this.elements.set(elementData.element, updatedElementData);
554
- this.emit({
555
- type: "elementDataUpdated",
556
- timestamp: Date.now(),
557
- elementData: updatedElementData,
558
- updatedProp: "bounds",
559
- });
560
- };
561
- ForesightManager.prototype.handleScrollPrefetch = function (elementData, newRect) {
562
- var _a, _b;
563
- if (this._globalSettings.enableScrollPrediction) {
564
- // This means the foresightmanager is initializing registered elements, we dont want to calc the scroll direction here
565
- if (!elementData.elementBounds.originalRect) {
566
- return;
567
- }
568
- // ONCE per animation frame we decide what the scroll direction is
569
- this.scrollDirection =
570
- (_a = this.scrollDirection) !== null && _a !== void 0 ? _a : getScrollDirection(elementData.elementBounds.originalRect, newRect);
571
- if (this.scrollDirection === "none") {
572
- return;
573
- }
574
- // ONCE per animation frame we decide the predicted scroll point
575
- this.predictedScrollPoint =
576
- (_b = this.predictedScrollPoint) !== null && _b !== void 0 ? _b : predictNextScrollPosition(this.trajectoryPositions.currentPoint, this.scrollDirection, this._globalSettings.scrollMargin);
577
- if (lineSegmentIntersectsRect(this.trajectoryPositions.currentPoint, this.predictedScrollPoint, elementData === null || elementData === void 0 ? void 0 : elementData.elementBounds.expandedRect)) {
578
- this.callCallback(elementData, {
579
- kind: "scroll",
580
- subType: this.scrollDirection,
581
- });
582
- }
583
- this.emit({
584
- type: "scrollTrajectoryUpdate",
585
- timestamp: Date.now(),
586
- currentPoint: this.trajectoryPositions.currentPoint,
587
- predictedPoint: this.predictedScrollPoint,
588
- });
589
- }
590
- else {
591
- if (isPointInRectangle(this.trajectoryPositions.currentPoint, elementData.elementBounds.expandedRect)) {
592
- this.callCallback(elementData, {
593
- kind: "mouse",
594
- subType: "hover",
595
- });
596
- }
597
- }
598
- };
599
- ForesightManager.prototype.initializeGlobalListeners = function () {
600
- if (this.isSetup) {
601
- return;
602
- }
603
- // To avoid setting up listeners while ssr
604
- if (typeof window === "undefined" || typeof document === "undefined") {
605
- return;
606
- }
607
- this.globalListenersController = new AbortController();
608
- var signal = this.globalListenersController.signal;
609
- document.addEventListener("mousemove", this.handleMouseMove); // Dont add signal we still need to emit events even without elements
610
- document.addEventListener("keydown", this.handleKeyDown, { signal: signal });
611
- document.addEventListener("focusin", this.handleFocusIn, { signal: signal });
612
- //Mutation observer is to automatically unregister elements when they leave the DOM. Its a fail-safe for if the user forgets to do it.
613
- this.domObserver = new MutationObserver(this.handleDomMutations);
614
- this.domObserver.observe(document.documentElement, {
615
- childList: true,
616
- subtree: true,
617
- attributes: false,
618
- });
619
- // Handles all position based changes and update the rects of the elements. completely async to avoid dirtying the main thread.
620
- // Handles resize of elements
621
- // Handles resize of viewport
622
- // Handles scrolling
623
- this.positionObserver = new PositionObserver(this.handlePositionChange);
624
- this.isSetup = true;
625
- };
626
- ForesightManager.prototype.removeGlobalListeners = function () {
627
- var _a, _b, _c;
628
- this.isSetup = false;
629
- (_a = this.globalListenersController) === null || _a === void 0 ? void 0 : _a.abort(); // Remove all event listeners only in non debug mode
630
- this.globalListenersController = null;
631
- (_b = this.domObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
632
- this.domObserver = null;
633
- (_c = this.positionObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
634
- this.positionObserver = null;
635
- };
636
- return ForesightManager;
637
- }());
638
- export { ForesightManager };
639
- //# sourceMappingURL=ForesightManager.js.map