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.
- package/README.md +120 -5
- package/dist/{src/types/types.d.ts → index.d.mts} +156 -67
- package/dist/index.d.ts +61 -47
- package/dist/index.js +2 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -12
- package/dist/Manager/ForesightManager.d.ts +0 -89
- package/dist/Manager/ForesightManager.d.ts.map +0 -1
- package/dist/Manager/ForesightManager.js +0 -639
- package/dist/Manager/ForesightManager.js.map +0 -1
- package/dist/Manager/constants.d.ts +0 -23
- package/dist/Manager/constants.d.ts.map +0 -1
- package/dist/Manager/constants.js +0 -24
- package/dist/Manager/constants.js.map +0 -1
- package/dist/Manager/helpers/clampNumber.d.ts +0 -2
- package/dist/Manager/helpers/clampNumber.d.ts.map +0 -1
- package/dist/Manager/helpers/clampNumber.js +0 -10
- package/dist/Manager/helpers/clampNumber.js.map +0 -1
- package/dist/Manager/helpers/getFocusedElementIndex.d.ts +0 -15
- package/dist/Manager/helpers/getFocusedElementIndex.d.ts.map +0 -1
- package/dist/Manager/helpers/getFocusedElementIndex.js +0 -27
- package/dist/Manager/helpers/getFocusedElementIndex.js.map +0 -1
- package/dist/Manager/helpers/getScrollDirection.d.ts +0 -3
- package/dist/Manager/helpers/getScrollDirection.d.ts.map +0 -1
- package/dist/Manager/helpers/getScrollDirection.js +0 -21
- package/dist/Manager/helpers/getScrollDirection.js.map +0 -1
- package/dist/Manager/helpers/lineSigmentIntersectsRect.d.ts +0 -12
- package/dist/Manager/helpers/lineSigmentIntersectsRect.d.ts.map +0 -1
- package/dist/Manager/helpers/lineSigmentIntersectsRect.js +0 -52
- package/dist/Manager/helpers/lineSigmentIntersectsRect.js.map +0 -1
- package/dist/Manager/helpers/predictNextMousePosition.d.ts +0 -19
- package/dist/Manager/helpers/predictNextMousePosition.d.ts.map +0 -1
- package/dist/Manager/helpers/predictNextMousePosition.js +0 -43
- package/dist/Manager/helpers/predictNextMousePosition.js.map +0 -1
- package/dist/Manager/helpers/predictNextScrollPosition.d.ts +0 -6
- package/dist/Manager/helpers/predictNextScrollPosition.d.ts.map +0 -1
- package/dist/Manager/helpers/predictNextScrollPosition.js +0 -20
- package/dist/Manager/helpers/predictNextScrollPosition.js.map +0 -1
- package/dist/Manager/helpers/rectAndHitSlop.d.ts +0 -33
- package/dist/Manager/helpers/rectAndHitSlop.d.ts.map +0 -1
- package/dist/Manager/helpers/rectAndHitSlop.js +0 -66
- package/dist/Manager/helpers/rectAndHitSlop.js.map +0 -1
- package/dist/Manager/helpers/shouldUpdateSetting.d.ts +0 -11
- package/dist/Manager/helpers/shouldUpdateSetting.d.ts.map +0 -1
- package/dist/Manager/helpers/shouldUpdateSetting.js +0 -16
- package/dist/Manager/helpers/shouldUpdateSetting.js.map +0 -1
- package/dist/helpers/shouldRegister.d.ts +0 -8
- package/dist/helpers/shouldRegister.d.ts.map +0 -1
- package/dist/helpers/shouldRegister.js +0 -31
- package/dist/helpers/shouldRegister.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/src/Manager/ForesightManager.d.ts +0 -89
- package/dist/src/Manager/ForesightManager.d.ts.map +0 -1
- package/dist/src/Manager/ForesightManager.test.d.ts +0 -2
- package/dist/src/Manager/ForesightManager.test.d.ts.map +0 -1
- package/dist/src/Manager/constants.d.ts +0 -23
- package/dist/src/Manager/constants.d.ts.map +0 -1
- package/dist/src/Manager/helpers/clampNumber.d.ts +0 -2
- package/dist/src/Manager/helpers/clampNumber.d.ts.map +0 -1
- package/dist/src/Manager/helpers/clampNumber.test.d.ts +0 -2
- package/dist/src/Manager/helpers/clampNumber.test.d.ts.map +0 -1
- package/dist/src/Manager/helpers/getFocusedElementIndex.d.ts +0 -15
- package/dist/src/Manager/helpers/getFocusedElementIndex.d.ts.map +0 -1
- package/dist/src/Manager/helpers/getFocusedElementIndex.test.d.ts +0 -2
- package/dist/src/Manager/helpers/getFocusedElementIndex.test.d.ts.map +0 -1
- package/dist/src/Manager/helpers/getScrollDirection.d.ts +0 -3
- package/dist/src/Manager/helpers/getScrollDirection.d.ts.map +0 -1
- package/dist/src/Manager/helpers/lineSegmentIntersectsRect.test.d.ts +0 -2
- package/dist/src/Manager/helpers/lineSegmentIntersectsRect.test.d.ts.map +0 -1
- package/dist/src/Manager/helpers/lineSigmentIntersectsRect.d.ts +0 -12
- package/dist/src/Manager/helpers/lineSigmentIntersectsRect.d.ts.map +0 -1
- package/dist/src/Manager/helpers/predictNextMousePosition.d.ts +0 -19
- package/dist/src/Manager/helpers/predictNextMousePosition.d.ts.map +0 -1
- package/dist/src/Manager/helpers/predictNextMousePosition.test.d.ts +0 -2
- package/dist/src/Manager/helpers/predictNextMousePosition.test.d.ts.map +0 -1
- package/dist/src/Manager/helpers/predictNextScrollPosition.d.ts +0 -6
- package/dist/src/Manager/helpers/predictNextScrollPosition.d.ts.map +0 -1
- package/dist/src/Manager/helpers/rectAndHitSlop.d.ts +0 -33
- package/dist/src/Manager/helpers/rectAndHitSlop.d.ts.map +0 -1
- package/dist/src/Manager/helpers/rectAndHitSlop.test.d.ts +0 -2
- package/dist/src/Manager/helpers/rectAndHitSlop.test.d.ts.map +0 -1
- package/dist/src/Manager/helpers/shouldUpdateSetting.d.ts +0 -11
- package/dist/src/Manager/helpers/shouldUpdateSetting.d.ts.map +0 -1
- package/dist/src/helpers/shouldRegister.d.ts +0 -8
- package/dist/src/helpers/shouldRegister.d.ts.map +0 -1
- package/dist/src/index.d.ts +0 -3
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/types/types.d.ts.map +0 -1
- package/dist/test-setup.d.ts +0 -17
- package/dist/test-setup.d.ts.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/types/types.d.ts +0 -312
- package/dist/types/types.d.ts.map +0 -1
- package/dist/types/types.js +0 -2
- 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
|