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
package/README.md CHANGED
@@ -1,12 +1,34 @@
1
- # js.foresight
1
+ # [ForesightJS](https://foresightjs.com/)
2
2
 
3
- The core ForesightJS library package.
3
+ [![npm version](https://img.shields.io/npm/v/js.foresight.svg)](https://www.npmjs.com/package/js.foresight)
4
+ [![npm downloads](https://img.shields.io/npm/dt/js.foresight.svg)](https://www.npmjs.com/package/js.foresight)
5
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/js.foresight)](https://bundlephobia.com/package/js.foresight)
6
+ [![GitHub stars](https://img.shields.io/github/stars/spaansba/ForesightJS.svg?style=social&label=Star)](https://github.com/spaansba/ForesightJS)
7
+ [![GitHub last commit](https://img.shields.io/github/last-commit/spaansba/ForesightJS)](https://github.com/spaansba/ForesightJS/commits)
4
8
 
5
- A lightweight JavaScript/TypeScript library that predicts user intent based on mouse movements, scroll behavior, and keyboard navigation. Published as `js.foresight` on npm.
9
+ [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+ [![Demo](https://img.shields.io/badge/demo-live-blue)](https://foresightjs.com#playground)
6
12
 
7
- **For complete documentation, usage examples, and API reference, see the [main README](../../README.md).**
13
+ ForesightJS is a lightweight JavaScript library with full TypeScript support that predicts user intent based on mouse movements, scroll and keyboard navigation. By analyzing cursor/scroll trajectory and tab sequences, it anticipates which elements a user is likely to interact with, allowing developers to trigger actions before the actual hover or click occurs (for example prefetching).
8
14
 
9
- ## Installation
15
+ ### Understanding ForesightJS's Role:
16
+
17
+ When you over simplify prefetching it exists of three parts.
18
+
19
+ - **What** resource or data to load
20
+ - **How** the loading method and caching strategy is
21
+ - **When** the optimal moment to start fetching is
22
+
23
+ ForesightJS takes care of the **When** by predicting user intent with mouse trajectory and tab navigation.
24
+ You supply the **What** and **How** inside your `callback` when you register an element.
25
+
26
+ ### [Playground](https://foresightjs.com/)
27
+
28
+ ![](https://github.com/user-attachments/assets/36c81a82-fee7-43d6-ba1e-c48214136f90)
29
+ _In the GIF above, the [ForesightJS DevTools](https://foresightjs.com/docs/getting_started/development_tools) are enabled. Normally, users won't see anything that ForesightJS does except the increased perceived speed from early prefetching._
30
+
31
+ ## Download
10
32
 
11
33
  ```bash
12
34
  pnpm add js.foresight
@@ -15,3 +37,96 @@ npm install js.foresight
15
37
  # or
16
38
  yarn add js.foresight
17
39
  ```
40
+
41
+ ## Which problems does ForesightJS solve?
42
+
43
+ ### Problem 1: On-Hover Prefetching Still Has Latency
44
+
45
+ Traditional hover-based prefetching only triggers after the user's cursor reaches an element. This approach wastes the critical 100-200ms window between when a user begins moving toward a target and when the hover event actually fires.
46
+
47
+ ### Problem 2: Viewport-Based Prefetching is Wasteful
48
+
49
+ Many modern frameworks (like Next.js) automatically prefetch resources for all links that enter the viewport. While well-intentioned, this creates significant overhead since users typically interact with only a small fraction of visible elements. Simply scrolling up and down the Next.js homepage can trigger **_1.59MB_** of unnecessary prefetch requests.
50
+
51
+ ### Problem 3: Hover-Based Prefetching Excludes Keyboard Users
52
+
53
+ Many routers rely on hover-based prefetching, but this approach completely excludes keyboard users since keyboard navigation never triggers hover events. This means keyboard users miss out on the performance benefits that mouse users get from hover-based prefetching.
54
+
55
+ ### The ForesightJS Solution
56
+
57
+ ForesightJS bridges the gap between wasteful viewport prefetching and basic hover prefetching. The `ForesightManager` predicts user interactions by analyzing mouse trajectory patterns, scroll direction and keyboard navigation sequences. This allows you to prefetch resources at the optimal time to improve performance, but targeted enough to avoid waste.
58
+
59
+ ## Basic Usage Example
60
+
61
+ This basic example is in vanilla JS, ofcourse most people will use ForesightJS with a framework. You can read about framework integrations in the [docs](https://foresightjs.com/docs/integrations).
62
+
63
+ ```javascript
64
+ import { ForesightManager } from "foresightjs"
65
+
66
+ // Initialize the manager if you want custom global settings (do this once at app startup)
67
+ ForesightManager.initialize({
68
+ // Optional props (see configuration)
69
+ })
70
+
71
+ // Register an element to be tracked
72
+ const myButton = document.getElementById("my-button")
73
+
74
+ const { isTouchDevice, unregister } = ForesightManager.instance.register({
75
+ element: myButton,
76
+ callback: () => {
77
+ // This is where your prefetching logic goes
78
+ },
79
+ hitSlop: 20, // Optional: "hit slop" in pixels. Overwrites defaultHitSlop
80
+ // other optional props (see configuration)
81
+ })
82
+
83
+ // Later, when done with this element:
84
+ unregister()
85
+ ```
86
+
87
+ ## Integrations
88
+
89
+ Since ForesightJS is framework agnostic, it can be integrated with any JavaScript framework. While I haven't yet built [integrations](https://foresightjs.com/docs/integrations) for every framework, ready-to-use implementations for [Next.js](https://foresightjs.com/docs/integrations/react/nextjs) and [React Router](https://foresightjs.com/docs/integrations/react/react-router) are already available. Sharing integrations for other frameworks/packages is highly appreciated!
90
+
91
+ ## Configuration
92
+
93
+ ForesightJS can be used bare-bones but also can be configured. For all configuration possibilities you can reference the [docs](https://foresightjs.com/docs/getting_started/config).
94
+
95
+ ## Development Tools
96
+
97
+ ForesightJS has dedicated [Development Tools](https://github.com/spaansba/ForesightJS-DevTools) created with [Foresight Events](https://foresightjs.com/docs/getting_started/events) that help you understand and tune how foresight is working in your application. This standalone development package provides real-time visualization of mouse trajectory predictions, element bounds, and callback execution. It's particularly helpful when setting up ForesightJS for the first time or when fine-tuning for specific UI components.
98
+
99
+ ```bash
100
+ npm install js.foresight-devtools
101
+ ```
102
+
103
+ See the [development tools documentation](https://foresightjs.com/docs/getting_started/debug) for more details.
104
+
105
+ ## What About Touch Devices and Slow Connections?
106
+
107
+ Since ForesightJS relies on the keyboard/mouse it will not register elements for touch devices. For limited connections (2G or data-saver mode), we respect the user's preference to minimize data usage and skip registration aswell.
108
+
109
+ The `ForesightManager.instance.register()` method returns these properties:
110
+
111
+ - `isTouchDevice` - true if user is on a touch device
112
+ - `isLimitedConnection` - true when user is on a 2G connection or has data-saver enabled
113
+ - `isRegistered` - true if element was actually registered
114
+
115
+ With these properties you could create your own fallback prefetching methods if required. For example if the user is on a touch device you could prefetch based on viewport.
116
+ An example of this can be found in the [Next.js](https://foresightjs.com/docs/integrations/react/nextjs) or [React Router](https://foresightjs.com/docs/integrations/react/react-router) ForesightLink components.
117
+
118
+ ## How Does ForesightJS Work?
119
+
120
+ For a detailed technical explanation of its prediction algorithms and internal architecture, see the **[Behind the Scenes documentation](https://foresightjs.com/docs/Behind_the_Scenes)**.
121
+
122
+ ## Providing Context to AI Tools
123
+
124
+ ForesightJS is a newer library, so most AI assistants and LLMs may not have much built-in knowledge about it. To improve their responses, you can provide the following context:
125
+
126
+ - Use [llms.txt](https://foresightjs.com/llms.txt) for a concise overview of the API and usage patterns.
127
+ - Use [llms-full.txt](https://foresightjs.com/llms-full.txt) for a full markdown version of the docs, ideal for AI tools that support context injection or uploads.
128
+ - All documentation pages are also available in markdown. You can view them by adding .md to the end of any URL, for example: https://foresightjs.com/docs/getting_started.md.
129
+
130
+ # Contributing
131
+
132
+ Please see the [contributing guidelines](/CONTRIBUTING.md)
@@ -1,4 +1,4 @@
1
- export type Rect = {
1
+ type Rect = {
2
2
  top: number;
3
3
  left: number;
4
4
  right: number;
@@ -8,27 +8,27 @@ export type Rect = {
8
8
  * A callback function that is executed when a foresight interaction
9
9
  * (e.g., hover, trajectory hit) occurs on a registered element.
10
10
  */
11
- export type ForesightCallback = () => void;
11
+ type ForesightCallback = () => void;
12
12
  /**
13
13
  * Represents the HTML element that is being tracked by the ForesightManager.
14
14
  * This is typically a standard DOM `Element`.
15
15
  */
16
- export type ForesightElement = Element;
16
+ type ForesightElement = Element;
17
17
  /**
18
18
  * Represents a mouse position captured at a specific point in time.
19
19
  * Used for tracking mouse movement history.
20
20
  */
21
- export type MousePosition = {
21
+ type MousePosition = {
22
22
  /** The (x, y) coordinates of the mouse. */
23
23
  point: Point;
24
24
  /** The timestamp (e.g., from `performance.now()`) when this position was recorded. */
25
25
  time: number;
26
26
  };
27
- export type Point = {
27
+ type Point = {
28
28
  x: number;
29
29
  y: number;
30
30
  };
31
- export type TrajectoryPositions = {
31
+ type TrajectoryPositions = {
32
32
  positions: MousePosition[];
33
33
  currentPoint: Point;
34
34
  predictedPoint: Point;
@@ -37,18 +37,18 @@ export type TrajectoryPositions = {
37
37
  * Internal type representing the calculated boundaries of a foresight element,
38
38
  * including its original dimensions and the expanded hit area.
39
39
  */
40
- export type ElementBounds = {
40
+ type ElementBounds = {
41
41
  /** The expanded rectangle, including hitSlop, used for interaction detection. */
42
- expandedRect: Rect;
42
+ expandedRect: Readonly<Rect>;
43
43
  /** The original bounding rectangle of the element, as returned by `getBoundingClientRect()`. */
44
- originalRect?: DOMRectReadOnly | undefined;
44
+ originalRect: DOMRectReadOnly;
45
45
  /** The hit slop values applied to this element. */
46
46
  hitSlop: Exclude<HitSlop, number>;
47
47
  };
48
48
  /**
49
49
  * Represents trajectory hit related data for a foresight element.
50
50
  */
51
- export type TrajectoryHitData = {
51
+ type TrajectoryHitData = {
52
52
  /** True if the predicted mouse trajectory has intersected the element's expanded bounds. */
53
53
  isTrajectoryHit: boolean;
54
54
  /** The timestamp when the last trajectory hit occurred. */
@@ -56,7 +56,7 @@ export type TrajectoryHitData = {
56
56
  /** Timeout ID for expiring the trajectory hit state. */
57
57
  trajectoryHitExpirationTimeoutId?: ReturnType<typeof setTimeout>;
58
58
  };
59
- export type ForesightRegisterResult = {
59
+ type ForesightRegisterResult = {
60
60
  /** Whether the current device is a touch device. This is important as ForesightJS only works based on cursor movement. If the user is using a touch device you should handle prefetching differently */
61
61
  isTouchDevice: boolean;
62
62
  /** Whether the user has connection limitations (slow network (2g) or data saver enabled) that should prevent prefetching */
@@ -69,7 +69,7 @@ export type ForesightRegisterResult = {
69
69
  /**
70
70
  * Represents the data associated with a registered foresight element.
71
71
  */
72
- export type ForesightElementData = Required<Pick<ForesightRegisterOptions, "callback" | "name">> & {
72
+ type ForesightElementData = Required<Pick<ForesightRegisterOptions, "callback" | "name">> & {
73
73
  /** The boundary information for the element. */
74
74
  elementBounds: ElementBounds;
75
75
  /** True if the mouse cursor is currently hovering over the element's expanded bounds. */
@@ -80,30 +80,39 @@ export type ForesightElementData = Required<Pick<ForesightRegisterOptions, "call
80
80
  trajectoryHitData: TrajectoryHitData;
81
81
  /**
82
82
  * Is the element intersecting with the viewport, usefull to track which element we should observe or not
83
+ * Can be @undefined in the split second the element is registering
83
84
  */
84
85
  isIntersectingWithViewport: boolean;
85
86
  /**
86
87
  * The element you registered
87
88
  */
88
89
  element: ForesightElement;
90
+ /**
91
+ * If the element is currently running its callback
92
+ */
93
+ isRunningCallback: boolean;
94
+ /**
95
+ * For debugging, check if you are registering the same element multiple times.
96
+ */
97
+ registerCount: number;
89
98
  };
90
- export type MouseCallbackCounts = {
99
+ type MouseCallbackCounts = {
91
100
  hover: number;
92
101
  trajectory: number;
93
102
  };
94
- export type TabCallbackCounts = {
103
+ type TabCallbackCounts = {
95
104
  reverse: number;
96
105
  forwards: number;
97
106
  };
98
- export type ScrollDirection = "down" | "up" | "left" | "right" | "none";
99
- export type ScrollCallbackCounts = Record<`${Exclude<ScrollDirection, "none">}`, number>;
100
- export type CallbackHits = {
107
+ type ScrollDirection = "down" | "up" | "left" | "right" | "none";
108
+ type ScrollCallbackCounts = Record<`${Exclude<ScrollDirection, "none">}`, number>;
109
+ type CallbackHits = {
101
110
  total: number;
102
111
  mouse: MouseCallbackCounts;
103
112
  tab: TabCallbackCounts;
104
113
  scroll: ScrollCallbackCounts;
105
114
  };
106
- export type HitType = {
115
+ type CallbackHitType = {
107
116
  kind: "mouse";
108
117
  subType: keyof MouseCallbackCounts;
109
118
  } | {
@@ -116,10 +125,11 @@ export type HitType = {
116
125
  /**
117
126
  * Snapshot of the current ForesightManager state
118
127
  */
119
- export type ForesightManagerData = {
128
+ type ForesightManagerData = {
120
129
  registeredElements: ReadonlyMap<ForesightElement, ForesightElementData>;
121
130
  globalSettings: Readonly<ForesightManagerSettings>;
122
131
  globalCallbackHits: Readonly<CallbackHits>;
132
+ eventListeners: ReadonlyMap<keyof ForesightEventMap, ForesightEventListener[]>;
123
133
  };
124
134
  type BaseForesightManagerSettings = {
125
135
  /**
@@ -187,33 +197,25 @@ type BaseForesightManagerSettings = {
187
197
  * @default 2
188
198
  */
189
199
  tabOffset: number;
190
- /**
191
- * A global callback that runs whenever a callback is fired for any
192
- * registered element, just after the element's specific callback is fired.
193
- *
194
- * @param elementData - The ForesightTarget object for the element that triggered the event.
195
- * @param managerData - Data about the ForesightManager
196
- */
197
- onAnyCallbackFired: (elementData: ForesightElementData, managerData: ForesightManagerData) => void;
198
200
  };
199
201
  /**
200
202
  * Configuration options for the ForesightManager
201
203
  * @link https://foresightjs.com/docs/getting_started/config#available-global-settings
202
204
  */
203
- export type ForesightManagerSettings = BaseForesightManagerSettings & {
205
+ type ForesightManagerSettings = BaseForesightManagerSettings & {
204
206
  defaultHitSlop: Exclude<HitSlop, number>;
205
207
  };
206
208
  /**
207
209
  * Update options for the ForesightManager
208
210
  * @link https://foresightjs.com/docs/getting_started/config#available-global-settings
209
211
  */
210
- export type UpdateForsightManagerSettings = BaseForesightManagerSettings & {
212
+ type UpdateForsightManagerSettings = BaseForesightManagerSettings & {
211
213
  defaultHitSlop: HitSlop;
212
214
  };
213
215
  /**
214
216
  * Type used to register elements to the foresight manager
215
217
  */
216
- export type ForesightRegisterOptions = {
218
+ type ForesightRegisterOptions = {
217
219
  element: ForesightElement;
218
220
  callback: ForesightCallback;
219
221
  hitSlop?: HitSlop;
@@ -230,43 +232,28 @@ export type ForesightRegisterOptions = {
230
232
  *
231
233
  * @link https://foresightjs.com/docs/getting_started/typescript#foresightregisteroptionswithoutelement
232
234
  */
233
- export type ForesightRegisterOptionsWithoutElement = Omit<ForesightRegisterOptions, "element">;
235
+ type ForesightRegisterOptionsWithoutElement = Omit<ForesightRegisterOptions, "element">;
234
236
  /**
235
237
  * Fully invisible "slop" around the element.
236
238
  * Basically increases the hover hitbox
237
239
  */
238
- export type HitSlop = Rect | number;
239
- /**
240
- * Get all keys in UpdateForsightManagerSettings that are numeric
241
- */
242
- export type NumericSettingKeys = {
243
- [K in keyof UpdateForsightManagerSettings]: UpdateForsightManagerSettings[K] extends number ? K : never;
244
- }[keyof UpdateForsightManagerSettings];
245
- /**
246
- * Get all keys in UpdateForsightManagerSettings that are boolean
247
- */
248
- export type ManagerBooleanSettingKeys = {
249
- [K in keyof UpdateForsightManagerSettings]: UpdateForsightManagerSettings[K] extends boolean ? K : never;
250
- }[keyof UpdateForsightManagerSettings];
251
- export interface ForesightEventMap {
240
+ type HitSlop = Rect | number;
241
+ interface ForesightEventMap {
252
242
  elementRegistered: ElementRegisteredEvent;
253
243
  elementUnregistered: ElementUnregisteredEvent;
254
244
  elementDataUpdated: ElementDataUpdatedEvent;
255
- callbackFired: CallbackFiredEvent;
245
+ callbackInvoked: CallbackInvokedEvent;
246
+ callbackCompleted: CallbackCompletedEvent;
256
247
  mouseTrajectoryUpdate: MouseTrajectoryUpdateEvent;
257
248
  scrollTrajectoryUpdate: ScrollTrajectoryUpdateEvent;
258
249
  managerSettingsChanged: ManagerSettingsChangedEvent;
259
250
  }
260
- export type ForesightEventType = keyof ForesightEventMap;
261
- export interface ForesightEvent {
262
- type: ForesightEventType;
263
- timestamp: number;
264
- }
265
- export interface ElementRegisteredEvent extends ForesightEvent {
251
+ type ForesightEvent = "elementRegistered" | "elementUnregistered" | "elementDataUpdated" | "callbackInvoked" | "callbackCompleted" | "mouseTrajectoryUpdate" | "scrollTrajectoryUpdate" | "managerSettingsChanged";
252
+ interface ElementRegisteredEvent extends ForesightBaseEvent {
266
253
  type: "elementRegistered";
267
254
  elementData: ForesightElementData;
268
255
  }
269
- export interface ElementUnregisteredEvent extends ForesightEvent {
256
+ interface ElementUnregisteredEvent extends ForesightBaseEvent {
270
257
  type: "elementUnregistered";
271
258
  elementData: ForesightElementData;
272
259
  unregisterReason: ElementUnregisteredReason;
@@ -277,33 +264,135 @@ export interface ElementUnregisteredEvent extends ForesightEvent {
277
264
  * - `disconnected`: The element was automatically unregistered because it was removed from the DOM.
278
265
  * - `apiCall`: The developer manually called the `unregister()` function for the element.
279
266
  */
280
- export type ElementUnregisteredReason = "callbackHit" | "disconnected" | "apiCall";
281
- export interface ElementDataUpdatedEvent extends ForesightEvent {
267
+ type ElementUnregisteredReason = "callbackHit" | "disconnected" | "apiCall";
268
+ interface ElementDataUpdatedEvent extends Omit<ForesightBaseEvent, "timestamp"> {
282
269
  type: "elementDataUpdated";
283
270
  elementData: ForesightElementData;
284
- updatedProp: "bounds" | "visibility";
271
+ updatedProps: UpdatedDataPropertyNames[];
285
272
  }
286
- export interface CallbackFiredEvent extends ForesightEvent {
287
- type: "callbackFired";
273
+ type UpdatedDataPropertyNames = "bounds" | "visibility";
274
+ interface CallbackInvokedEvent extends ForesightBaseEvent {
275
+ type: "callbackInvoked";
288
276
  elementData: ForesightElementData;
289
- hitType: HitType;
290
- managerData: ForesightManagerData;
277
+ hitType: CallbackHitType;
278
+ }
279
+ interface CallbackCompletedEventBase extends ForesightBaseEvent {
280
+ type: "callbackCompleted";
281
+ elementData: ForesightElementData;
282
+ hitType: CallbackHitType;
283
+ elapsed: number;
291
284
  }
292
- export interface MouseTrajectoryUpdateEvent extends ForesightEvent {
285
+ type CallbackCompletedEvent = CallbackCompletedEventBase & ({
286
+ status: "success";
287
+ } | {
288
+ status: "error";
289
+ errorMessage: string;
290
+ });
291
+ interface MouseTrajectoryUpdateEvent extends Omit<ForesightBaseEvent, "timestamp"> {
293
292
  type: "mouseTrajectoryUpdate";
294
293
  trajectoryPositions: TrajectoryPositions;
295
294
  predictionEnabled: boolean;
296
295
  }
297
- export interface ScrollTrajectoryUpdateEvent extends ForesightEvent {
296
+ interface ScrollTrajectoryUpdateEvent extends Omit<ForesightBaseEvent, "timestamp"> {
298
297
  type: "scrollTrajectoryUpdate";
299
298
  currentPoint: Point;
300
299
  predictedPoint: Point;
300
+ scrollDirection: ScrollDirection;
301
301
  }
302
- export interface ManagerSettingsChangedEvent extends ForesightEvent {
302
+ interface ManagerSettingsChangedEvent extends ForesightBaseEvent {
303
303
  type: "managerSettingsChanged";
304
304
  managerData: ForesightManagerData;
305
+ updatedSettings: UpdatedManagerSetting[];
306
+ }
307
+ type UpdatedManagerSetting = {
308
+ [K in keyof ForesightManagerSettings]: {
309
+ setting: K;
310
+ newValue: ForesightManagerSettings[K];
311
+ oldValue: ForesightManagerSettings[K];
312
+ };
313
+ }[keyof ForesightManagerSettings];
314
+ type ForesightEventListener<K extends ForesightEvent = ForesightEvent> = (event: ForesightEventMap[K]) => void;
315
+ interface ForesightBaseEvent {
316
+ type: ForesightEvent;
317
+ timestamp: number;
318
+ }
319
+
320
+ /**
321
+ * Manages the prediction of user intent based on mouse trajectory and element interactions.
322
+ *
323
+ * ForesightManager is a singleton class responsible for:
324
+ * - Registering HTML elements to monitor.
325
+ * - Tracking mouse movements and predicting future cursor positions.
326
+ * - Detecting when a predicted trajectory intersects with a registered element's bounds.
327
+ * - Invoking callbacks associated with elements upon predicted or actual interaction.
328
+ * - Optionally unregistering elements after their callback is triggered.
329
+ * - Handling global settings for prediction behavior (e.g., history size, prediction time).
330
+ * - Automatically updating element bounds on resize using {@link ResizeObserver}.
331
+ * - Automatically unregistering elements removed from the DOM using {@link MutationObserver}.
332
+ * - Detecting broader layout shifts via {@link MutationObserver} to update element positions.
333
+ *
334
+ * It should be initialized once using {@link ForesightManager.initialize} and then
335
+ * accessed via the static getter {@link ForesightManager.instance}.
336
+ */
337
+ declare class ForesightManager {
338
+ private static manager;
339
+ private elements;
340
+ private isSetup;
341
+ private _globalCallbackHits;
342
+ private _globalSettings;
343
+ private trajectoryPositions;
344
+ private tabbableElementsCache;
345
+ private lastFocusedIndex;
346
+ private predictedScrollPoint;
347
+ private scrollDirection;
348
+ private domObserver;
349
+ private positionObserver;
350
+ private lastKeyDown;
351
+ private globalListenersController;
352
+ private rafId;
353
+ private pendingMouseEvent;
354
+ private eventListeners;
355
+ private constructor();
356
+ static initialize(props?: Partial<UpdateForsightManagerSettings>): ForesightManager;
357
+ addEventListener<K extends ForesightEvent>(eventType: K, listener: ForesightEventListener<K>, options?: {
358
+ signal?: AbortSignal;
359
+ }): (() => void) | undefined;
360
+ removeEventListener<K extends ForesightEvent>(eventType: K, listener: ForesightEventListener<K>): void;
361
+ private emit;
362
+ get getManagerData(): Readonly<ForesightManagerData>;
363
+ static get isInitiated(): Readonly<boolean>;
364
+ static get instance(): ForesightManager;
365
+ get registeredElements(): ReadonlyMap<ForesightElement, ForesightElementData>;
366
+ register({ element, callback, hitSlop, name, }: ForesightRegisterOptions): ForesightRegisterResult;
367
+ private unregister;
368
+ private updateNumericSettings;
369
+ private updateBooleanSetting;
370
+ alterGlobalSettings(props?: Partial<UpdateForsightManagerSettings>): void;
371
+ private forceUpdateAllElementBounds;
372
+ private updatePointerState;
373
+ private handleMouseMove;
374
+ private processMouseMovement;
375
+ /**
376
+ * Detects when registered elements are removed from the DOM and automatically unregisters them to prevent stale references.
377
+ *
378
+ * @param mutationsList - Array of MutationRecord objects describing the DOM changes
379
+ *
380
+ */
381
+ private handleDomMutations;
382
+ private handleKeyDown;
383
+ private handleFocusIn;
384
+ private updateHitCounters;
385
+ private callCallback;
386
+ /**
387
+ * 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.
388
+ * We need an observer for that
389
+ */
390
+ private forceUpdateElementBounds;
391
+ private handlePositionChange;
392
+ private handlePositionChangeDataUpdates;
393
+ private handleScrollPrefetch;
394
+ private initializeGlobalListeners;
395
+ private removeGlobalListeners;
305
396
  }
306
- export type ForesightEventData = ElementRegisteredEvent | ElementUnregisteredEvent | ElementDataUpdatedEvent | CallbackFiredEvent | MouseTrajectoryUpdateEvent | ScrollTrajectoryUpdateEvent | ManagerSettingsChangedEvent;
307
- export type ForesightEventListener = (event: ForesightEventData) => void;
308
- export {};
309
- //# sourceMappingURL=types.d.ts.map
397
+
398
+ export { type CallbackCompletedEvent, type CallbackHitType, type CallbackHits, type CallbackInvokedEvent, type ElementDataUpdatedEvent, type ElementRegisteredEvent, type ElementUnregisteredEvent, type ForesightElement, type ForesightElementData, type ForesightEvent, ForesightManager, type ForesightManagerSettings, type Rect as ForesightRect, type ForesightRegisterOptions, type ForesightRegisterOptionsWithoutElement, type ForesightRegisterResult, type HitSlop, type ManagerSettingsChangedEvent, type MouseTrajectoryUpdateEvent, type ScrollTrajectoryUpdateEvent, type UpdateForsightManagerSettings, type UpdatedManagerSetting };