@noriginmedia/norigin-spatial-navigation-core 3.0.0 → 3.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { debounce, sortBy, findKey, throttle, forOwn, filter, first, difference, forEach } from 'lodash-es';
1
+ import { findKey, sortBy, assign, throttle, filter, first, difference, forEach, debounce, forOwn } from 'lodash-es';
2
2
 
3
3
  /******************************************************************************
4
4
  Copyright (c) Microsoft Corporation.
@@ -16,6 +16,20 @@ PERFORMANCE OF THIS SOFTWARE.
16
16
  ***************************************************************************** */
17
17
  /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
18
18
 
19
+ var extendStatics = function(d, b) {
20
+ extendStatics = Object.setPrototypeOf ||
21
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
22
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
23
+ return extendStatics(d, b);
24
+ };
25
+
26
+ function __extends(d, b) {
27
+ if (typeof b !== "function" && b !== null)
28
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
29
+ extendStatics(d, b);
30
+ function __() { this.constructor = d; }
31
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
32
+ }
19
33
 
20
34
  var __assign = function() {
21
35
  __assign = Object.assign || function __assign(t) {
@@ -28,6 +42,44 @@ var __assign = function() {
28
42
  return __assign.apply(this, arguments);
29
43
  };
30
44
 
45
+ function __awaiter(thisArg, _arguments, P, generator) {
46
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
47
+ return new (P || (P = Promise))(function (resolve, reject) {
48
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
49
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
50
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
51
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
52
+ });
53
+ }
54
+
55
+ function __generator(thisArg, body) {
56
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
57
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
58
+ function verb(n) { return function (v) { return step([n, v]); }; }
59
+ function step(op) {
60
+ if (f) throw new TypeError("Generator is already executing.");
61
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
62
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
63
+ if (y = 0, t) op = [op[0] & 2, t.value];
64
+ switch (op[0]) {
65
+ case 0: case 1: t = op; break;
66
+ case 4: _.label++; return { value: op[1], done: false };
67
+ case 5: _.label++; y = op[1]; op = [0]; continue;
68
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
69
+ default:
70
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
71
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
72
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
73
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
74
+ if (t[2]) _.ops.pop();
75
+ _.trys.pop(); continue;
76
+ }
77
+ op = body.call(thisArg, _);
78
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
79
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
80
+ }
81
+ }
82
+
31
83
  function __spreadArray(to, from, pack) {
32
84
  if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
33
85
  if (ar || !(i in from)) {
@@ -43,79 +95,6 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
43
95
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
44
96
  };
45
97
 
46
- var WritingDirection;
47
- (function (WritingDirection) {
48
- WritingDirection[WritingDirection["LTR"] = 0] = "LTR";
49
- WritingDirection[WritingDirection["RTL"] = 1] = "RTL";
50
- })(WritingDirection || (WritingDirection = {}));
51
- var WritingDirection$1 = WritingDirection;
52
-
53
- // We'll make VisualDebugger no-op for any environments lacking a DOM (e.g. SSR and React Native non-web platforms).
54
- var hasDOM = typeof window !== 'undefined' && window.document;
55
- var WIDTH = hasDOM ? window.innerWidth : 0;
56
- var HEIGHT = hasDOM ? window.innerHeight : 0;
57
- var VisualDebugger = /** @class */ (function () {
58
- function VisualDebugger(writingDirection) {
59
- if (hasDOM) {
60
- this.debugCtx = VisualDebugger.createCanvas('sn-debug', '1010', writingDirection);
61
- this.layoutsCtx = VisualDebugger.createCanvas('sn-layouts', '1000', writingDirection);
62
- this.writingDirection = writingDirection;
63
- }
64
- }
65
- VisualDebugger.createCanvas = function (id, zIndex, writingDirection) {
66
- var canvas = document.querySelector("#".concat(id)) || document.createElement('canvas');
67
- canvas.setAttribute('id', id);
68
- canvas.setAttribute('dir', writingDirection === WritingDirection$1.LTR ? 'ltr' : 'rtl');
69
- var ctx = canvas.getContext('2d');
70
- canvas.style.zIndex = zIndex;
71
- canvas.style.position = 'fixed';
72
- canvas.style.top = '0';
73
- canvas.style.left = '0';
74
- document.body.appendChild(canvas);
75
- canvas.width = WIDTH;
76
- canvas.height = HEIGHT;
77
- return ctx;
78
- };
79
- VisualDebugger.prototype.clear = function () {
80
- if (!hasDOM) {
81
- return;
82
- }
83
- this.debugCtx.clearRect(0, 0, WIDTH, HEIGHT);
84
- };
85
- VisualDebugger.prototype.clearLayouts = function () {
86
- if (!hasDOM) {
87
- return;
88
- }
89
- this.layoutsCtx.clearRect(0, 0, WIDTH, HEIGHT);
90
- };
91
- VisualDebugger.prototype.drawLayout = function (layout, focusKey, parentFocusKey) {
92
- if (!hasDOM) {
93
- return;
94
- }
95
- this.layoutsCtx.strokeStyle = 'green';
96
- this.layoutsCtx.strokeRect(layout.left, layout.top, layout.width, layout.height);
97
- this.layoutsCtx.font = '8px monospace';
98
- this.layoutsCtx.fillStyle = 'red';
99
- var horizontalStartDirection = this.writingDirection === WritingDirection$1.LTR ? 'left' : 'right';
100
- var horizontalStartCoordinate = layout[horizontalStartDirection];
101
- this.layoutsCtx.fillText(focusKey, horizontalStartCoordinate, layout.top + 10);
102
- this.layoutsCtx.fillText(parentFocusKey, horizontalStartCoordinate, layout.top + 25);
103
- this.layoutsCtx.fillText("".concat(horizontalStartDirection, ": ").concat(horizontalStartCoordinate), horizontalStartCoordinate, layout.top + 40);
104
- this.layoutsCtx.fillText("top: ".concat(layout.top), horizontalStartCoordinate, layout.top + 55);
105
- };
106
- VisualDebugger.prototype.drawPoint = function (x, y, color, size) {
107
- if (color === void 0) { color = 'blue'; }
108
- if (size === void 0) { size = 10; }
109
- if (!hasDOM) {
110
- return;
111
- }
112
- this.debugCtx.strokeStyle = color;
113
- this.debugCtx.lineWidth = 3;
114
- this.debugCtx.strokeRect(x - size / 2, y - size / 2, size, size);
115
- };
116
- return VisualDebugger;
117
- }());
118
-
119
98
  var ELEMENT_NODE = 1;
120
99
  var getRect = function (node) {
121
100
  var offsetParent = node.offsetParent;
@@ -198,6 +177,241 @@ var getBoundingClientRect = function (node) {
198
177
  };
199
178
  };
200
179
 
180
+ var getKeyCode = function (event) {
181
+ return event.keyCode || event.code || event.key;
182
+ };
183
+ var BaseWebAdapter = /** @class */ (function () {
184
+ function BaseWebAdapter(service) {
185
+ var _this = this;
186
+ this.service = service;
187
+ this.measureLayout = function (component) { return __awaiter(_this, void 0, void 0, function () {
188
+ return __generator(this, function (_a) {
189
+ return [2 /*return*/, (__assign(__assign({}, measureLayout(component.node)), { node: component.node }))];
190
+ });
191
+ }); };
192
+ this.blurNode = function (component) {
193
+ var _a, _b;
194
+ if (component.node && _this.service.options.shouldFocusDOMNode) {
195
+ (_b = (_a = component.node) === null || _a === void 0 ? void 0 : _a.removeAttribute) === null || _b === void 0 ? void 0 : _b.call(_a, 'data-focused');
196
+ }
197
+ };
198
+ this.focusNode = function (component) {
199
+ var _a, _b;
200
+ if (component.node && _this.service.options.shouldFocusDOMNode) {
201
+ component.node.focus(_this.service.options.domNodeFocusOptions);
202
+ }
203
+ (_b = (_a = component.node) === null || _a === void 0 ? void 0 : _a.setAttribute) === null || _b === void 0 ? void 0 : _b.call(_a, 'data-focused', 'true');
204
+ };
205
+ }
206
+ BaseWebAdapter.prototype.addEventListeners = function (_a) {
207
+ var _this = this;
208
+ var keyDown = _a.keyDown, keyUp = _a.keyUp;
209
+ this.keyDownEventListener = function (event) {
210
+ var keyCode = getKeyCode(event);
211
+ var key = findKey(_this.service.getKeyMap(), function (codeList) {
212
+ return codeList.includes(keyCode);
213
+ });
214
+ if (!key) {
215
+ return;
216
+ }
217
+ if (!_this.service.options.shouldUseNativeEvents) {
218
+ event.preventDefault();
219
+ event.stopPropagation();
220
+ }
221
+ keyDown === null || keyDown === void 0 ? void 0 : keyDown(key, event);
222
+ };
223
+ this.keyUpEventListener = function (event) {
224
+ var keyCode = getKeyCode(event);
225
+ var key = findKey(_this.service.getKeyMap(), function (codeList) {
226
+ return codeList.includes(keyCode);
227
+ });
228
+ if (!key) {
229
+ return;
230
+ }
231
+ keyUp === null || keyUp === void 0 ? void 0 : keyUp(key);
232
+ };
233
+ window.addEventListener('keyup', this.keyUpEventListener);
234
+ window.addEventListener('keydown', this.keyDownEventListener);
235
+ };
236
+ BaseWebAdapter.prototype.removeEventListeners = function () {
237
+ window.removeEventListener('keyup', this.keyUpEventListener);
238
+ window.removeEventListener('keydown', this.keyDownEventListener);
239
+ };
240
+ return BaseWebAdapter;
241
+ }());
242
+
243
+ var GetBoundingClientRectAdapter = /** @class */ (function (_super) {
244
+ __extends(GetBoundingClientRectAdapter, _super);
245
+ function GetBoundingClientRectAdapter() {
246
+ var _this = _super !== null && _super.apply(this, arguments) || this;
247
+ _this.measureLayout = function (component) { return __awaiter(_this, void 0, void 0, function () {
248
+ return __generator(this, function (_a) {
249
+ return [2 /*return*/, (__assign(__assign({}, getBoundingClientRect(component.node)), { node: component.node }))];
250
+ });
251
+ }); };
252
+ return _this;
253
+ }
254
+ return GetBoundingClientRectAdapter;
255
+ }(BaseWebAdapter));
256
+
257
+ var WritingDirection;
258
+ (function (WritingDirection) {
259
+ WritingDirection[WritingDirection["LTR"] = 0] = "LTR";
260
+ WritingDirection[WritingDirection["RTL"] = 1] = "RTL";
261
+ })(WritingDirection || (WritingDirection = {}));
262
+ var WritingDirection$1 = WritingDirection;
263
+
264
+ // We'll make VisualDebugger no-op for any environments lacking a DOM (e.g. SSR and React Native non-web platforms).
265
+ var hasDOM = typeof window !== 'undefined' && window.document;
266
+ var WIDTH = hasDOM ? window.innerWidth : 0;
267
+ var HEIGHT = hasDOM ? window.innerHeight : 0;
268
+ var VisualDebugger = /** @class */ (function () {
269
+ function VisualDebugger(writingDirection) {
270
+ if (hasDOM) {
271
+ this.debugCtx = VisualDebugger.createCanvas('sn-debug', '1010', writingDirection);
272
+ this.layoutsCtx = VisualDebugger.createCanvas('sn-layouts', '1000', writingDirection);
273
+ this.writingDirection = writingDirection;
274
+ }
275
+ }
276
+ VisualDebugger.createCanvas = function (id, zIndex, writingDirection) {
277
+ var canvas = document.querySelector("#".concat(id)) || document.createElement('canvas');
278
+ canvas.setAttribute('id', id);
279
+ canvas.setAttribute('dir', writingDirection === WritingDirection$1.LTR ? 'ltr' : 'rtl');
280
+ var ctx = canvas.getContext('2d');
281
+ canvas.style.zIndex = zIndex;
282
+ canvas.style.position = 'fixed';
283
+ canvas.style.top = '0';
284
+ canvas.style.left = '0';
285
+ document.body.appendChild(canvas);
286
+ canvas.width = WIDTH;
287
+ canvas.height = HEIGHT;
288
+ return ctx;
289
+ };
290
+ VisualDebugger.prototype.clear = function () {
291
+ if (!hasDOM) {
292
+ return;
293
+ }
294
+ this.debugCtx.clearRect(0, 0, WIDTH, HEIGHT);
295
+ };
296
+ VisualDebugger.prototype.clearLayouts = function () {
297
+ if (!hasDOM) {
298
+ return;
299
+ }
300
+ this.layoutsCtx.clearRect(0, 0, WIDTH, HEIGHT);
301
+ };
302
+ VisualDebugger.prototype.drawLayout = function (layout, focusKey, parentFocusKey) {
303
+ if (!hasDOM) {
304
+ return;
305
+ }
306
+ this.layoutsCtx.strokeStyle = 'green';
307
+ this.layoutsCtx.strokeRect(layout.left, layout.top, layout.width, layout.height);
308
+ this.layoutsCtx.font = '8px monospace';
309
+ this.layoutsCtx.fillStyle = 'red';
310
+ var horizontalStartDirection = this.writingDirection === WritingDirection$1.LTR ? 'left' : 'right';
311
+ var horizontalStartCoordinate = layout[horizontalStartDirection];
312
+ this.layoutsCtx.fillText(focusKey, horizontalStartCoordinate, layout.top + 10);
313
+ this.layoutsCtx.fillText(parentFocusKey, horizontalStartCoordinate, layout.top + 25);
314
+ this.layoutsCtx.fillText("".concat(horizontalStartDirection, ": ").concat(horizontalStartCoordinate), horizontalStartCoordinate, layout.top + 40);
315
+ this.layoutsCtx.fillText("top: ".concat(layout.top), horizontalStartCoordinate, layout.top + 55);
316
+ };
317
+ VisualDebugger.prototype.drawPoint = function (x, y, color, size) {
318
+ if (color === void 0) { color = 'blue'; }
319
+ if (size === void 0) { size = 10; }
320
+ if (!hasDOM) {
321
+ return;
322
+ }
323
+ this.debugCtx.strokeStyle = color;
324
+ this.debugCtx.lineWidth = 3;
325
+ this.debugCtx.strokeRect(x - size / 2, y - size / 2, size, size);
326
+ };
327
+ return VisualDebugger;
328
+ }());
329
+
330
+ /**
331
+ * Scheduler provides a simple way to queue and execute tasks in a strict sequence.
332
+ * - Regular tasks are run one after another; if a new task is scheduled before the current one starts, it replaces the pending next task.
333
+ * - Priority tasks are added to a separate queue and will be executed before any remaining regular tasks.
334
+ */
335
+ var Scheduler = /** @class */ (function () {
336
+ function Scheduler() {
337
+ this.nextPriorityTasks = [];
338
+ }
339
+ Scheduler.prototype.tick = function () {
340
+ return __awaiter(this, void 0, void 0, function () {
341
+ var _this = this;
342
+ var _a;
343
+ return __generator(this, function (_b) {
344
+ switch (_b.label) {
345
+ case 0:
346
+ _b.trys.push([0, , 2, 8]);
347
+ return [4 /*yield*/, ((_a = this.currentTask) === null || _a === void 0 ? void 0 : _a.call(this))];
348
+ case 1:
349
+ _b.sent();
350
+ return [3 /*break*/, 8];
351
+ case 2:
352
+ if (!(this.nextPriorityTasks.length > 0)) return [3 /*break*/, 4];
353
+ this.currentTask = function () {
354
+ return Promise.all(_this.nextPriorityTasks.map(function (task) { return task(); }));
355
+ };
356
+ this.nextPriorityTasks = [];
357
+ return [4 /*yield*/, this.tick()];
358
+ case 3:
359
+ _b.sent();
360
+ return [3 /*break*/, 7];
361
+ case 4:
362
+ if (!this.nextTask) return [3 /*break*/, 6];
363
+ this.currentTask = this.nextTask;
364
+ this.nextTask = undefined;
365
+ return [4 /*yield*/, this.tick()];
366
+ case 5:
367
+ _b.sent();
368
+ return [3 /*break*/, 7];
369
+ case 6:
370
+ this.currentTask = undefined;
371
+ _b.label = 7;
372
+ case 7: return [7 /*endfinally*/];
373
+ case 8: return [2 /*return*/];
374
+ }
375
+ });
376
+ });
377
+ };
378
+ Scheduler.prototype.bind = function (fn, context) {
379
+ var _this = this;
380
+ return function () {
381
+ var args = [];
382
+ for (var _i = 0; _i < arguments.length; _i++) {
383
+ args[_i] = arguments[_i];
384
+ }
385
+ return __awaiter(_this, void 0, void 0, function () {
386
+ var _this = this;
387
+ return __generator(this, function (_a) {
388
+ return [2 /*return*/, this.schedulePriority(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
389
+ return [2 /*return*/, fn.bind(context).apply(void 0, args)];
390
+ }); }); })];
391
+ });
392
+ });
393
+ };
394
+ };
395
+ Scheduler.prototype.schedule = function (task) {
396
+ if (this.currentTask) {
397
+ this.nextTask = task;
398
+ }
399
+ else {
400
+ this.currentTask = task;
401
+ this.tick();
402
+ }
403
+ };
404
+ Scheduler.prototype.schedulePriority = function (task) {
405
+ if (this.currentTask) {
406
+ this.nextPriorityTasks.push(task);
407
+ }
408
+ else {
409
+ task();
410
+ }
411
+ };
412
+ return Scheduler;
413
+ }());
414
+
201
415
  var _a;
202
416
  var DIRECTION_LEFT = 'left';
203
417
  var DIRECTION_RIGHT = 'right';
@@ -223,6 +437,7 @@ var DIAGONAL_SLICE_WEIGHT = 1;
223
437
  */
224
438
  var MAIN_COORDINATE_WEIGHT = 5;
225
439
  var AUTO_RESTORE_FOCUS_DELAY = 300;
440
+ var LAYOUT_STALE_TIME = 16; // 60fps
226
441
  var DEBUG_FN_COLORS = ['#0FF', '#FF0', '#F0F'];
227
442
  var THROTTLE_OPTIONS = {
228
443
  leading: true,
@@ -253,8 +468,16 @@ var normalizeKeyMap = function (keyMap) {
253
468
  });
254
469
  return newKeyMap;
255
470
  };
471
+ var DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS = {
472
+ debug: false,
473
+ throttle: 0,
474
+ throttleKeypresses: false,
475
+ domNodeFocusOptions: {},
476
+ shouldUseNativeEvents: false,
477
+ distanceCalculationMethod: 'corners'};
256
478
  var SpatialNavigationService = /** @class */ (function () {
257
479
  function SpatialNavigationService() {
480
+ this.scheduler = new Scheduler();
258
481
  /**
259
482
  * Storage for all focusable components
260
483
  */
@@ -270,10 +493,8 @@ var SpatialNavigationService = /** @class */ (function () {
270
493
  this.parentsHavingFocusedChild = [];
271
494
  this.domNodeFocusOptions = {};
272
495
  this.enabled = false;
273
- this.nativeMode = false;
274
496
  this.throttle = 0;
275
497
  this.throttleKeypresses = false;
276
- this.useGetBoundingClientRect = false;
277
498
  this.shouldFocusDOMNode = false;
278
499
  this.shouldUseNativeEvents = false;
279
500
  this.writingDirection = WritingDirection$1.LTR;
@@ -289,8 +510,10 @@ var SpatialNavigationService = /** @class */ (function () {
289
510
  this.pause = this.pause.bind(this);
290
511
  this.resume = this.resume.bind(this);
291
512
  this.setFocus = this.setFocus.bind(this);
292
- this.updateAllLayouts = this.updateAllLayouts.bind(this);
293
- this.navigateByDirection = this.navigateByDirection.bind(this);
513
+ this.updateAllLayouts = this.scheduler.bind(this.updateAllLayouts, this);
514
+ this.navigateByDirection = this.scheduler.bind(this.navigateByDirection, this);
515
+ this.addFocusable = this.scheduler.bind(this.addFocusable, this);
516
+ this.removeFocusable = this.scheduler.bind(this.removeFocusable, this);
294
517
  this.init = this.init.bind(this);
295
518
  this.setThrottle = this.setThrottle.bind(this);
296
519
  this.destroy = this.destroy.bind(this);
@@ -307,6 +530,17 @@ var SpatialNavigationService = /** @class */ (function () {
307
530
  this.logIndex = 0;
308
531
  this.distanceCalculationMethod = 'corners';
309
532
  }
533
+ Object.defineProperty(SpatialNavigationService.prototype, "options", {
534
+ get: function () {
535
+ return {
536
+ shouldFocusDOMNode: this.shouldFocusDOMNode,
537
+ domNodeFocusOptions: this.domNodeFocusOptions,
538
+ shouldUseNativeEvents: this.shouldUseNativeEvents
539
+ };
540
+ },
541
+ enumerable: false,
542
+ configurable: true
543
+ });
310
544
  /**
311
545
  * Used to determine the coordinate that will be used to filter items that are over the "edge"
312
546
  */
@@ -495,56 +729,73 @@ var SpatialNavigationService = /** @class */ (function () {
495
729
  };
496
730
  SpatialNavigationService.prototype.init = function (_a) {
497
731
  var _this = this;
498
- var _b = _a === void 0 ? {} : _a, _c = _b.debug, debug = _c === void 0 ? false : _c, _d = _b.visualDebug, visualDebug = _d === void 0 ? false : _d, _e = _b.nativeMode, nativeMode = _e === void 0 ? false : _e, _f = _b.throttle, throttleParam = _f === void 0 ? 0 : _f, _g = _b.throttleKeypresses, throttleKeypresses = _g === void 0 ? false : _g, _h = _b.useGetBoundingClientRect, useGetBoundingClientRect = _h === void 0 ? false : _h, _j = _b.shouldFocusDOMNode, shouldFocusDOMNode = _j === void 0 ? false : _j, _k = _b.domNodeFocusOptions, domNodeFocusOptions = _k === void 0 ? {} : _k, _l = _b.shouldUseNativeEvents, shouldUseNativeEvents = _l === void 0 ? false : _l, _m = _b.rtl, rtl = _m === void 0 ? false : _m, _o = _b.distanceCalculationMethod, distanceCalculationMethod = _o === void 0 ? 'corners' : _o, _p = _b.customDistanceCalculationFunction, customDistanceCalculationFunction = _p === void 0 ? undefined : _p;
732
+ var _b = _a === void 0 ? {} : _a, debug = _b.debug, visualDebug = _b.visualDebug, throttleParam = _b.throttle, throttleKeypresses = _b.throttleKeypresses, useGetBoundingClientRect = _b.useGetBoundingClientRect, layoutAdapter = _b.layoutAdapter, shouldFocusDOMNode = _b.shouldFocusDOMNode, domNodeFocusOptions = _b.domNodeFocusOptions, shouldUseNativeEvents = _b.shouldUseNativeEvents, rtl = _b.rtl, distanceCalculationMethod = _b.distanceCalculationMethod, _c = _b.customDistanceCalculationFunction, customDistanceCalculationFunction = _c === void 0 ? undefined : _c;
499
733
  if (!this.enabled) {
500
- this.domNodeFocusOptions = domNodeFocusOptions;
501
- this.enabled = true;
502
- this.nativeMode = nativeMode;
503
- this.throttleKeypresses = throttleKeypresses;
504
- this.useGetBoundingClientRect = useGetBoundingClientRect;
505
- this.shouldFocusDOMNode = shouldFocusDOMNode && !nativeMode;
506
- this.shouldUseNativeEvents = shouldUseNativeEvents;
734
+ this.domNodeFocusOptions =
735
+ domNodeFocusOptions !== null && domNodeFocusOptions !== void 0 ? domNodeFocusOptions : DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS.domNodeFocusOptions;
736
+ this.throttleKeypresses =
737
+ throttleKeypresses !== null && throttleKeypresses !== void 0 ? throttleKeypresses : DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS.throttleKeypresses;
738
+ /*
739
+ * If layoutAdapter is a constructor, create a new instance of the class
740
+ * If it's an object, merge it with the default adapter
741
+ */
742
+ if (typeof layoutAdapter === 'function') {
743
+ var LayoutAdapterClass = layoutAdapter;
744
+ this.layoutAdapter = new LayoutAdapterClass(this);
745
+ }
746
+ else {
747
+ if (useGetBoundingClientRect) {
748
+ console.warn('useGetBoundingClientRect is deprecated. Please use layoutAdapter API instead.');
749
+ this.layoutAdapter = new GetBoundingClientRectAdapter(this);
750
+ }
751
+ else {
752
+ this.layoutAdapter = new BaseWebAdapter(this);
753
+ }
754
+ // Override specific methods
755
+ if (layoutAdapter) {
756
+ assign(this.layoutAdapter, layoutAdapter);
757
+ }
758
+ }
759
+ this.shouldFocusDOMNode = shouldFocusDOMNode;
760
+ this.shouldUseNativeEvents =
761
+ shouldUseNativeEvents !== null && shouldUseNativeEvents !== void 0 ? shouldUseNativeEvents : DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS.shouldUseNativeEvents;
507
762
  this.writingDirection = rtl ? WritingDirection$1.RTL : WritingDirection$1.LTR;
508
- this.distanceCalculationMethod = distanceCalculationMethod;
763
+ this.distanceCalculationMethod =
764
+ distanceCalculationMethod !== null && distanceCalculationMethod !== void 0 ? distanceCalculationMethod : DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS.distanceCalculationMethod;
509
765
  this.customDistanceCalculationFunction =
510
766
  customDistanceCalculationFunction;
511
- this.debug = debug;
512
- if (!this.nativeMode) {
513
- if (Number.isInteger(throttleParam) && throttleParam > 0) {
514
- this.throttle = throttleParam;
515
- }
516
- this.bindEventHandlers();
517
- if (visualDebug) {
518
- this.visualDebugger = new VisualDebugger(this.writingDirection);
519
- var draw_1 = function () {
520
- requestAnimationFrame(function () {
521
- _this.visualDebugger.clearLayouts();
522
- forOwn(_this.focusableComponents, function (component, focusKey) {
523
- _this.visualDebugger.drawLayout(component.layout, focusKey, component.parentFocusKey);
524
- });
525
- draw_1();
767
+ this.debug = debug !== null && debug !== void 0 ? debug : DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS.debug;
768
+ this.throttle =
769
+ throttleParam !== null && throttleParam !== void 0 ? throttleParam : DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS.throttle;
770
+ this.bindEventHandlers();
771
+ if (visualDebug) {
772
+ this.visualDebugger = new VisualDebugger(this.writingDirection);
773
+ var draw_1 = function () {
774
+ requestAnimationFrame(function () {
775
+ _this.visualDebugger.clearLayouts();
776
+ forOwn(_this.focusableComponents, function (component, focusKey) {
777
+ _this.visualDebugger.drawLayout(component.layout, focusKey, component.parentFocusKey);
526
778
  });
527
- };
528
- draw_1();
529
- }
779
+ draw_1();
780
+ });
781
+ };
782
+ draw_1();
530
783
  }
784
+ this.enabled = true;
531
785
  }
532
786
  };
533
787
  SpatialNavigationService.prototype.setThrottle = function (_a) {
534
- var _b = _a === void 0 ? {} : _a, _c = _b.throttle, throttleParam = _c === void 0 ? 0 : _c, _d = _b.throttleKeypresses, throttleKeypresses = _d === void 0 ? false : _d;
788
+ var _b = _a === void 0 ? {} : _a, _c = _b.throttle, throttleParam = _c === void 0 ? DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS.throttle : _c, _d = _b.throttleKeypresses, throttleKeypresses = _d === void 0 ? DEFAULT_SPATIAL_NAVIGATION_SERVICE_OPTIONS.throttleKeypresses : _d;
535
789
  this.throttleKeypresses = throttleKeypresses;
536
- if (!this.nativeMode) {
537
- this.unbindEventHandlers();
538
- if (Number.isInteger(throttleParam)) {
539
- this.throttle = throttleParam;
540
- }
541
- this.bindEventHandlers();
790
+ this.unbindEventHandlers();
791
+ if (Number.isInteger(throttleParam)) {
792
+ this.throttle = throttleParam;
542
793
  }
794
+ this.bindEventHandlers();
543
795
  };
544
796
  SpatialNavigationService.prototype.destroy = function () {
545
797
  if (this.enabled) {
546
798
  this.enabled = false;
547
- this.nativeMode = false;
548
799
  this.throttle = 0;
549
800
  this.throttleKeypresses = false;
550
801
  this.focusKey = null;
@@ -558,92 +809,78 @@ var SpatialNavigationService = /** @class */ (function () {
558
809
  SpatialNavigationService.prototype.getEventType = function (keyCode) {
559
810
  return findKey(this.getKeyMap(), function (codeList) { return codeList.includes(keyCode); });
560
811
  };
561
- SpatialNavigationService.getKeyCode = function (event) {
562
- return event.keyCode || event.code || event.key;
563
- };
564
812
  SpatialNavigationService.prototype.bindEventHandlers = function () {
565
813
  var _this = this;
566
- // We check both because the React Native remote debugger implements window, but not window.addEventListener.
567
- if (typeof window !== 'undefined' && window.addEventListener) {
568
- this.keyDownEventListener = function (event) {
569
- if (_this.paused === true) {
570
- return;
571
- }
572
- if (_this.debug) {
573
- _this.logIndex += 1;
574
- }
575
- var keyCode = SpatialNavigationService.getKeyCode(event);
576
- var eventType = _this.getEventType(keyCode);
577
- if (!eventType) {
578
- return;
579
- }
580
- _this.pressedKeys[eventType] = _this.pressedKeys[eventType]
581
- ? _this.pressedKeys[eventType] + 1
582
- : 1;
583
- if (!_this.shouldUseNativeEvents) {
584
- event.preventDefault();
585
- event.stopPropagation();
586
- }
587
- var keysDetails = {
588
- pressedKeys: _this.pressedKeys
589
- };
590
- if (eventType === KEY_ENTER && _this.focusKey) {
591
- _this.onEnterPress(keysDetails);
592
- return;
593
- }
594
- var preventDefaultNavigation = _this.onArrowPress(eventType, keysDetails) === false;
595
- if (_this.visualDebugger) {
596
- _this.visualDebugger.clear();
597
- }
598
- if (preventDefaultNavigation) {
599
- _this.log('keyDownEventListener', 'default navigation prevented');
600
- }
601
- else {
602
- var direction = findKey(_this.getKeyMap(), function (codeList) {
603
- return codeList.includes(keyCode);
604
- });
605
- _this.smartNavigate(direction, null, { event: event });
606
- }
607
- };
608
- // Apply throttle only if the option we got is > 0 to avoid limiting the listener to every animation frame
609
- if (this.throttle) {
610
- this.keyDownEventListenerThrottled = throttle(this.keyDownEventListener.bind(this), this.throttle, THROTTLE_OPTIONS);
611
- }
612
- // When throttling then make sure to only throttle key down and cancel any queued functions in case of key up
613
- this.keyUpEventListener = function (event) {
614
- var keyCode = SpatialNavigationService.getKeyCode(event);
615
- var eventType = _this.getEventType(keyCode);
616
- delete _this.pressedKeys[eventType];
814
+ this.keyDownEventListener = function (key, event) {
815
+ _this.scheduler.schedule(function () { return __awaiter(_this, void 0, void 0, function () {
816
+ var preventDefaultNavigation;
817
+ return __generator(this, function (_a) {
818
+ switch (_a.label) {
819
+ case 0:
820
+ if (this.paused === true) {
821
+ return [2 /*return*/];
822
+ }
823
+ if (this.debug) {
824
+ this.logIndex += 1;
825
+ }
826
+ this.pressedKeys[key] = this.pressedKeys[key]
827
+ ? this.pressedKeys[key] + 1
828
+ : 1;
829
+ if (key === KEY_ENTER && this.focusKey) {
830
+ this.onEnterPress({ pressedKeys: this.pressedKeys });
831
+ return [2 /*return*/];
832
+ }
833
+ preventDefaultNavigation = this.onArrowPress(key, { pressedKeys: this.pressedKeys }) === false;
834
+ if (this.visualDebugger) {
835
+ this.visualDebugger.clear();
836
+ }
837
+ if (!preventDefaultNavigation) return [3 /*break*/, 1];
838
+ this.log('keyDownEventListener', 'default navigation prevented');
839
+ return [3 /*break*/, 3];
840
+ case 1: return [4 /*yield*/, this.smartNavigate(key, null, { event: event })];
841
+ case 2:
842
+ _a.sent();
843
+ _a.label = 3;
844
+ case 3: return [2 /*return*/];
845
+ }
846
+ });
847
+ }); });
848
+ };
849
+ // Apply throttle only if the option we got is > 0 to avoid limiting the listener to every animation frame
850
+ if (this.throttle) {
851
+ this.keyDownEventListenerThrottled = throttle(this.keyDownEventListener.bind(this), this.throttle, THROTTLE_OPTIONS);
852
+ }
853
+ // When throttling then make sure to only throttle key down and cancel any queued functions in case of key up
854
+ this.keyUpEventListener = function (key) {
855
+ _this.scheduler.schedule(function () {
856
+ delete _this.pressedKeys[key];
617
857
  if (_this.throttle && !_this.throttleKeypresses) {
618
858
  _this.keyDownEventListenerThrottled.cancel();
619
859
  }
620
- if (eventType === KEY_ENTER && _this.focusKey) {
860
+ if (key === KEY_ENTER && _this.focusKey) {
621
861
  _this.onEnterRelease();
622
862
  }
623
- if (_this.focusKey && (eventType === DIRECTION_LEFT ||
624
- eventType === DIRECTION_RIGHT ||
625
- eventType === DIRECTION_UP ||
626
- eventType === DIRECTION_DOWN)) {
627
- _this.onArrowRelease(eventType);
863
+ if (_this.focusKey &&
864
+ (key === DIRECTION_LEFT ||
865
+ key === DIRECTION_RIGHT ||
866
+ key === DIRECTION_UP ||
867
+ key === DIRECTION_DOWN)) {
868
+ _this.onArrowRelease(key);
628
869
  }
629
- };
630
- window.addEventListener('keyup', this.keyUpEventListener);
631
- window.addEventListener('keydown', this.throttle
870
+ });
871
+ };
872
+ this.layoutAdapter.addEventListeners({
873
+ keyDown: this.throttle
632
874
  ? this.keyDownEventListenerThrottled
633
- : this.keyDownEventListener);
634
- }
875
+ : this.keyDownEventListener,
876
+ keyUp: this.keyUpEventListener
877
+ });
635
878
  };
636
879
  SpatialNavigationService.prototype.unbindEventHandlers = function () {
637
- // We check both because the React Native remote debugger implements window, but not window.removeEventListener.
638
- if (typeof window !== 'undefined' && window.removeEventListener) {
639
- window.removeEventListener('keyup', this.keyUpEventListener);
640
- this.keyUpEventListener = null;
641
- var listener = this.throttle
642
- ? this.keyDownEventListenerThrottled
643
- : this.keyDownEventListener;
644
- window.removeEventListener('keydown', listener);
645
- this.keyDownEventListener = null;
646
- }
880
+ this.layoutAdapter.removeEventListeners();
881
+ this.keyUpEventListener = null;
882
+ this.keyDownEventListener = null;
883
+ this.keyDownEventListenerThrottled = null;
647
884
  };
648
885
  SpatialNavigationService.prototype.onEnterPress = function (keysDetails) {
649
886
  var component = this.focusableComponents[this.focusKey];
@@ -713,107 +950,135 @@ var SpatialNavigationService = /** @class */ (function () {
713
950
  * navigateByDirection('right') // The focus is moved to right
714
951
  */
715
952
  SpatialNavigationService.prototype.navigateByDirection = function (direction, focusDetails) {
716
- if (this.paused === true || !this.enabled || this.nativeMode) {
717
- return;
718
- }
719
- var validDirections = [
720
- DIRECTION_DOWN,
721
- DIRECTION_UP,
722
- DIRECTION_LEFT,
723
- DIRECTION_RIGHT
724
- ];
725
- if (validDirections.includes(direction)) {
726
- this.log('navigateByDirection', 'direction', direction);
727
- this.smartNavigate(direction, null, focusDetails);
728
- }
729
- else {
730
- this.log('navigateByDirection', "Invalid direction. You passed: `".concat(direction, "`, but you can use only these: "), validDirections);
731
- }
953
+ return __awaiter(this, void 0, void 0, function () {
954
+ var validDirections;
955
+ return __generator(this, function (_a) {
956
+ switch (_a.label) {
957
+ case 0:
958
+ if (this.paused === true || !this.enabled) {
959
+ return [2 /*return*/];
960
+ }
961
+ validDirections = [
962
+ DIRECTION_DOWN,
963
+ DIRECTION_UP,
964
+ DIRECTION_LEFT,
965
+ DIRECTION_RIGHT
966
+ ];
967
+ if (!validDirections.includes(direction)) return [3 /*break*/, 2];
968
+ this.log('navigateByDirection', 'direction', direction);
969
+ return [4 /*yield*/, this.smartNavigate(direction, null, focusDetails)];
970
+ case 1:
971
+ _a.sent();
972
+ return [3 /*break*/, 3];
973
+ case 2:
974
+ this.log('navigateByDirection', "Invalid direction. You passed: `".concat(direction, "`, but you can use only these: "), validDirections);
975
+ _a.label = 3;
976
+ case 3: return [2 /*return*/];
977
+ }
978
+ });
979
+ });
732
980
  };
733
981
  /**
734
982
  * This function navigates between siblings OR goes up by the Tree
735
983
  * Based on the Direction
736
984
  */
737
985
  SpatialNavigationService.prototype.smartNavigate = function (direction, fromParentFocusKey, focusDetails) {
738
- var _this = this;
739
- if (this.nativeMode) {
740
- return;
741
- }
742
- var isVerticalDirection = direction === DIRECTION_DOWN || direction === DIRECTION_UP;
743
- var isIncrementalDirection = direction === DIRECTION_DOWN ||
744
- (this.writingDirection === WritingDirection$1.LTR
745
- ? direction === DIRECTION_RIGHT
746
- : direction === DIRECTION_LEFT);
747
- this.log('smartNavigate', 'direction', direction);
748
- this.log('smartNavigate', 'fromParentFocusKey', fromParentFocusKey);
749
- this.log('smartNavigate', 'this.focusKey', this.focusKey);
750
- if (!fromParentFocusKey) {
751
- forOwn(this.focusableComponents, function (component) {
752
- // eslint-disable-next-line no-param-reassign
753
- component.layoutUpdated = false;
754
- });
755
- }
756
- var currentComponent = this.focusableComponents[fromParentFocusKey || this.focusKey];
757
- /**
758
- * When there's no currently focused component, an attempt is made, to force focus one of
759
- * the Focusable Containers, that have "forceFocus" flag enabled.
760
- */
761
- if (!fromParentFocusKey && !currentComponent) {
762
- this.setFocus(this.getForcedFocusKey());
763
- return;
764
- }
765
- this.log('smartNavigate', 'currentComponent', currentComponent ? currentComponent.focusKey : undefined, currentComponent ? currentComponent.node : undefined, currentComponent);
766
- if (currentComponent) {
767
- this.updateLayout(currentComponent.focusKey);
768
- var parentFocusKey_1 = currentComponent.parentFocusKey, focusKey = currentComponent.focusKey, layout = currentComponent.layout;
769
- var currentCutoffCoordinate_1 = SpatialNavigationService.getCutoffCoordinate(isVerticalDirection, isIncrementalDirection, false, layout, this.writingDirection);
770
- /**
771
- * Get only the siblings with the coords on the way of our moving direction
772
- */
773
- var siblings = filter(this.focusableComponents, function (component) {
774
- if (component.parentFocusKey === parentFocusKey_1 &&
775
- component.focusable) {
776
- _this.updateLayout(component.focusKey);
777
- var siblingCutoffCoordinate = SpatialNavigationService.getCutoffCoordinate(isVerticalDirection, isIncrementalDirection, true, component.layout, _this.writingDirection);
778
- return isVerticalDirection
779
- ? isIncrementalDirection
780
- ? siblingCutoffCoordinate >= currentCutoffCoordinate_1 // vertical next
781
- : siblingCutoffCoordinate <= currentCutoffCoordinate_1 // vertical previous
782
- : _this.writingDirection === WritingDirection$1.LTR
783
- ? isIncrementalDirection
784
- ? siblingCutoffCoordinate >= currentCutoffCoordinate_1 // horizontal LTR next
785
- : siblingCutoffCoordinate <= currentCutoffCoordinate_1 // horizontal LTR previous
786
- : isIncrementalDirection
787
- ? siblingCutoffCoordinate <= currentCutoffCoordinate_1 // horizontal RTL next
788
- : siblingCutoffCoordinate >= currentCutoffCoordinate_1; // horizontal RTL previous
986
+ return __awaiter(this, void 0, void 0, function () {
987
+ var isVerticalDirection, isIncrementalDirection, currentComponent, forcedKey, parentFocusKey_1, focusKey, layout, currentCutoffCoordinate_1, threshold_1, siblings, refCorners, sortedSiblings, nextComponent, parentComponent, focusBoundaryDirections;
988
+ var _this = this;
989
+ return __generator(this, function (_a) {
990
+ switch (_a.label) {
991
+ case 0:
992
+ isVerticalDirection = direction === DIRECTION_DOWN || direction === DIRECTION_UP;
993
+ isIncrementalDirection = direction === DIRECTION_DOWN ||
994
+ (this.writingDirection === WritingDirection$1.LTR
995
+ ? direction === DIRECTION_RIGHT
996
+ : direction === DIRECTION_LEFT);
997
+ this.log('smartNavigate', 'direction', direction);
998
+ this.log('smartNavigate', 'fromParentFocusKey', fromParentFocusKey);
999
+ this.log('smartNavigate', 'this.focusKey', this.focusKey);
1000
+ currentComponent = this.focusableComponents[fromParentFocusKey || this.focusKey];
1001
+ /**
1002
+ * When there's no currently focused component, an attempt is made, to force focus one of
1003
+ * the Focusable Containers, that have "forceFocus" flag enabled.
1004
+ */
1005
+ if (!fromParentFocusKey && !currentComponent) {
1006
+ forcedKey = this.getForcedFocusKey();
1007
+ if (forcedKey) {
1008
+ this.setFocus(forcedKey);
1009
+ }
1010
+ else {
1011
+ this.log('smartNavigate', 'Aborted due to missing current component and force-focusable key');
1012
+ }
1013
+ // Current component is null (e.g. nothing to navigate from)
1014
+ return [2 /*return*/];
1015
+ }
1016
+ this.log('smartNavigate', 'currentComponent', currentComponent ? currentComponent.focusKey : undefined, currentComponent ? currentComponent.node : undefined, currentComponent);
1017
+ if (!currentComponent) return [3 /*break*/, 5];
1018
+ return [4 /*yield*/, this.updateLayout(currentComponent.focusKey)];
1019
+ case 1:
1020
+ _a.sent();
1021
+ parentFocusKey_1 = currentComponent.parentFocusKey, focusKey = currentComponent.focusKey, layout = currentComponent.layout;
1022
+ currentCutoffCoordinate_1 = SpatialNavigationService.getCutoffCoordinate(isVerticalDirection, isIncrementalDirection, false, layout, this.writingDirection);
1023
+ threshold_1 = Date.now() - LAYOUT_STALE_TIME;
1024
+ return [4 /*yield*/, Promise.all(Object.values(this.focusableComponents)
1025
+ .filter(function (component) {
1026
+ return component.parentFocusKey === parentFocusKey_1 &&
1027
+ component.focusable &&
1028
+ component.layoutUpdatedAt <= threshold_1;
1029
+ })
1030
+ .map(function (component) { return _this.updateLayout(component.focusKey); }))];
1031
+ case 2:
1032
+ _a.sent();
1033
+ siblings = filter(this.focusableComponents, function (component) {
1034
+ if (component.parentFocusKey === parentFocusKey_1 &&
1035
+ component.focusKey !== currentComponent.focusKey &&
1036
+ component.focusable &&
1037
+ component.layout) {
1038
+ var siblingCutoffCoordinate = SpatialNavigationService.getCutoffCoordinate(isVerticalDirection, isIncrementalDirection, true, component.layout, _this.writingDirection);
1039
+ return isVerticalDirection
1040
+ ? isIncrementalDirection
1041
+ ? siblingCutoffCoordinate >= currentCutoffCoordinate_1 // vertical next
1042
+ : siblingCutoffCoordinate <= currentCutoffCoordinate_1 // vertical previous
1043
+ : _this.writingDirection === WritingDirection$1.LTR
1044
+ ? isIncrementalDirection
1045
+ ? siblingCutoffCoordinate >= currentCutoffCoordinate_1 // horizontal LTR next
1046
+ : siblingCutoffCoordinate <= currentCutoffCoordinate_1 // horizontal LTR previous
1047
+ : isIncrementalDirection
1048
+ ? siblingCutoffCoordinate <= currentCutoffCoordinate_1 // horizontal RTL next
1049
+ : siblingCutoffCoordinate >= currentCutoffCoordinate_1; // horizontal RTL previous
1050
+ }
1051
+ return false;
1052
+ });
1053
+ if (this.debug) {
1054
+ this.log('smartNavigate', 'currentCutoffCoordinate', currentCutoffCoordinate_1);
1055
+ this.log('smartNavigate', 'siblings', "".concat(siblings.length, " elements:"), siblings.map(function (sibling) { return sibling.focusKey; }).join(', '), siblings.map(function (sibling) { return sibling.node; }), siblings.map(function (sibling) { return sibling; }));
1056
+ }
1057
+ if (this.visualDebugger) {
1058
+ refCorners = SpatialNavigationService.getRefCorners(direction, false, layout);
1059
+ this.visualDebugger.drawPoint(refCorners.a.x, refCorners.a.y);
1060
+ this.visualDebugger.drawPoint(refCorners.b.x, refCorners.b.y);
1061
+ }
1062
+ sortedSiblings = this.sortSiblingsByPriority(siblings, layout, direction, focusKey);
1063
+ nextComponent = first(sortedSiblings);
1064
+ this.log('smartNavigate', 'nextComponent', nextComponent ? nextComponent.focusKey : undefined, nextComponent ? nextComponent.node : undefined, nextComponent);
1065
+ if (!nextComponent) return [3 /*break*/, 3];
1066
+ this.setFocus(nextComponent.focusKey, focusDetails);
1067
+ return [3 /*break*/, 5];
1068
+ case 3:
1069
+ parentComponent = this.focusableComponents[parentFocusKey_1];
1070
+ focusBoundaryDirections = (parentComponent === null || parentComponent === void 0 ? void 0 : parentComponent.isFocusBoundary)
1071
+ ? parentComponent.focusBoundaryDirections || [direction]
1072
+ : [];
1073
+ if (!(!parentComponent || !focusBoundaryDirections.includes(direction))) return [3 /*break*/, 5];
1074
+ return [4 /*yield*/, this.smartNavigate(direction, parentFocusKey_1, focusDetails)];
1075
+ case 4:
1076
+ _a.sent();
1077
+ _a.label = 5;
1078
+ case 5: return [2 /*return*/];
789
1079
  }
790
- return false;
791
1080
  });
792
- if (this.debug) {
793
- this.log('smartNavigate', 'currentCutoffCoordinate', currentCutoffCoordinate_1);
794
- this.log('smartNavigate', 'siblings', "".concat(siblings.length, " elements:"), siblings.map(function (sibling) { return sibling.focusKey; }).join(', '), siblings.map(function (sibling) { return sibling.node; }), siblings.map(function (sibling) { return sibling; }));
795
- }
796
- if (this.visualDebugger) {
797
- var refCorners = SpatialNavigationService.getRefCorners(direction, false, layout);
798
- this.visualDebugger.drawPoint(refCorners.a.x, refCorners.a.y);
799
- this.visualDebugger.drawPoint(refCorners.b.x, refCorners.b.y);
800
- }
801
- var sortedSiblings = this.sortSiblingsByPriority(siblings, layout, direction, focusKey);
802
- var nextComponent = first(sortedSiblings);
803
- this.log('smartNavigate', 'nextComponent', nextComponent ? nextComponent.focusKey : undefined, nextComponent ? nextComponent.node : undefined, nextComponent);
804
- if (nextComponent) {
805
- this.setFocus(nextComponent.focusKey, focusDetails);
806
- }
807
- else {
808
- var parentComponent = this.focusableComponents[parentFocusKey_1];
809
- var focusBoundaryDirections = (parentComponent === null || parentComponent === void 0 ? void 0 : parentComponent.isFocusBoundary)
810
- ? parentComponent.focusBoundaryDirections || [direction]
811
- : [];
812
- if (!parentComponent || !focusBoundaryDirections.includes(direction)) {
813
- this.smartNavigate(direction, parentFocusKey_1, focusDetails);
814
- }
815
- }
816
- }
1081
+ });
817
1082
  };
818
1083
  SpatialNavigationService.prototype.saveLastFocusedChildKey = function (component, focusKey) {
819
1084
  if (component) {
@@ -868,51 +1133,64 @@ var SpatialNavigationService = /** @class */ (function () {
868
1133
  * Based on "targetFocusKey" which means the "intended component to focus"
869
1134
  */
870
1135
  SpatialNavigationService.prototype.getNextFocusKey = function (targetFocusKey) {
871
- var _this = this;
872
- var targetComponent = this.focusableComponents[targetFocusKey];
873
- /**
874
- * Security check, if component doesn't exist, stay on the same focusKey
875
- */
876
- if (!targetComponent || this.nativeMode) {
877
- return targetFocusKey;
878
- }
879
- var children = filter(this.focusableComponents, function (component) {
880
- return component.parentFocusKey === targetFocusKey && component.focusable;
1136
+ return __awaiter(this, void 0, void 0, function () {
1137
+ var targetComponent, children, lastFocusedChildKey, preferredChildFocusKey, childKey;
1138
+ var _this = this;
1139
+ return __generator(this, function (_a) {
1140
+ switch (_a.label) {
1141
+ case 0:
1142
+ targetComponent = this.focusableComponents[targetFocusKey];
1143
+ /**
1144
+ * Security check, if component doesn't exist, stay on the same focusKey
1145
+ */
1146
+ if (!targetComponent) {
1147
+ return [2 /*return*/, targetFocusKey];
1148
+ }
1149
+ children = filter(this.focusableComponents, function (component) {
1150
+ return component.parentFocusKey === targetFocusKey && component.focusable;
1151
+ });
1152
+ if (!(children.length > 0)) return [3 /*break*/, 2];
1153
+ lastFocusedChildKey = targetComponent.lastFocusedChildKey, preferredChildFocusKey = targetComponent.preferredChildFocusKey;
1154
+ this.log('getNextFocusKey', 'lastFocusedChildKey is', lastFocusedChildKey);
1155
+ this.log('getNextFocusKey', 'preferredChildFocusKey is', preferredChildFocusKey);
1156
+ /**
1157
+ * First of all trying to focus last focused child
1158
+ */
1159
+ if (lastFocusedChildKey &&
1160
+ targetComponent.saveLastFocusedChild &&
1161
+ this.isParticipatingFocusableComponent(lastFocusedChildKey)) {
1162
+ this.log('getNextFocusKey', 'lastFocusedChildKey will be focused', lastFocusedChildKey);
1163
+ return [2 /*return*/, this.getNextFocusKey(lastFocusedChildKey)];
1164
+ }
1165
+ /**
1166
+ * If there is no lastFocusedChild, trying to focus the preferred focused key
1167
+ */
1168
+ if (preferredChildFocusKey &&
1169
+ this.isParticipatingFocusableComponent(preferredChildFocusKey)) {
1170
+ this.log('getNextFocusKey', 'preferredChildFocusKey will be focused', preferredChildFocusKey);
1171
+ return [2 /*return*/, this.getNextFocusKey(preferredChildFocusKey)];
1172
+ }
1173
+ /**
1174
+ * Otherwise, trying to focus something by coordinates
1175
+ */
1176
+ return [4 /*yield*/, Promise.all(children.map(function (component) { return _this.updateLayout(component.focusKey); }))];
1177
+ case 1:
1178
+ /**
1179
+ * Otherwise, trying to focus something by coordinates
1180
+ */
1181
+ _a.sent();
1182
+ childKey = getChildClosestToOrigin(children, this.writingDirection).focusKey;
1183
+ this.log('getNextFocusKey', 'childKey will be focused', childKey);
1184
+ return [2 /*return*/, this.getNextFocusKey(childKey)];
1185
+ case 2:
1186
+ /**
1187
+ * If no children, just return targetFocusKey back
1188
+ */
1189
+ this.log('getNextFocusKey', 'targetFocusKey', targetFocusKey);
1190
+ return [2 /*return*/, targetFocusKey];
1191
+ }
1192
+ });
881
1193
  });
882
- if (children.length > 0) {
883
- var lastFocusedChildKey = targetComponent.lastFocusedChildKey, preferredChildFocusKey = targetComponent.preferredChildFocusKey;
884
- this.log('getNextFocusKey', 'lastFocusedChildKey is', lastFocusedChildKey);
885
- this.log('getNextFocusKey', 'preferredChildFocusKey is', preferredChildFocusKey);
886
- /**
887
- * First of all trying to focus last focused child
888
- */
889
- if (lastFocusedChildKey &&
890
- targetComponent.saveLastFocusedChild &&
891
- this.isParticipatingFocusableComponent(lastFocusedChildKey)) {
892
- this.log('getNextFocusKey', 'lastFocusedChildKey will be focused', lastFocusedChildKey);
893
- return this.getNextFocusKey(lastFocusedChildKey);
894
- }
895
- /**
896
- * If there is no lastFocusedChild, trying to focus the preferred focused key
897
- */
898
- if (preferredChildFocusKey &&
899
- this.isParticipatingFocusableComponent(preferredChildFocusKey)) {
900
- this.log('getNextFocusKey', 'preferredChildFocusKey will be focused', preferredChildFocusKey);
901
- return this.getNextFocusKey(preferredChildFocusKey);
902
- }
903
- /**
904
- * Otherwise, trying to focus something by coordinates
905
- */
906
- children.forEach(function (component) { return _this.updateLayout(component.focusKey); });
907
- var childKey = getChildClosestToOrigin(children, this.writingDirection).focusKey;
908
- this.log('getNextFocusKey', 'childKey will be focused', childKey);
909
- return this.getNextFocusKey(childKey);
910
- }
911
- /**
912
- * If no children, just return targetFocusKey back
913
- */
914
- this.log('getNextFocusKey', 'targetFocusKey', targetFocusKey);
915
- return targetFocusKey;
916
1194
  };
917
1195
  SpatialNavigationService.prototype.addFocusable = function (_a) {
918
1196
  var focusKey = _a.focusKey, node = _a.node, parentFocusKey = _a.parentFocusKey, onEnterPress = _a.onEnterPress, onEnterRelease = _a.onEnterRelease, onArrowPress = _a.onArrowPress, onArrowRelease = _a.onArrowRelease, onFocus = _a.onFocus, onBlur = _a.onBlur, saveLastFocusedChild = _a.saveLastFocusedChild, trackChildren = _a.trackChildren, onUpdateFocus = _a.onUpdateFocus, onUpdateHasFocusedChild = _a.onUpdateHasFocusedChild, preferredChildFocusKey = _a.preferredChildFocusKey, autoRestoreFocus = _a.autoRestoreFocus, forceFocus = _a.forceFocus, focusable = _a.focusable, isFocusBoundary = _a.isFocusBoundary, focusBoundaryDirections = _a.focusBoundaryDirections;
@@ -937,6 +1215,7 @@ var SpatialNavigationService = /** @class */ (function () {
937
1215
  autoRestoreFocus: autoRestoreFocus,
938
1216
  forceFocus: forceFocus,
939
1217
  lastFocusedChildKey: null,
1218
+ layoutUpdatedAt: 0,
940
1219
  layout: {
941
1220
  x: 0,
942
1221
  y: 0,
@@ -950,16 +1229,12 @@ var SpatialNavigationService = /** @class */ (function () {
950
1229
  * Node ref is also duplicated in layout to be reported in onFocus callback
951
1230
  */
952
1231
  node: node
953
- },
954
- layoutUpdated: false
1232
+ }
955
1233
  };
956
1234
  if (!node) {
957
1235
  // eslint-disable-next-line no-console
958
1236
  console.warn('Component added without a node reference. This will result in its coordinates being empty and may cause lost focus. Check the "ref" passed to "useFocusable": ', this.focusableComponents[focusKey]);
959
1237
  }
960
- if (this.nativeMode) {
961
- return;
962
- }
963
1238
  this.updateLayout(focusKey);
964
1239
  this.log('addFocusable', 'Component added: ', this.focusableComponents[focusKey]);
965
1240
  /**
@@ -1001,9 +1276,6 @@ var SpatialNavigationService = /** @class */ (function () {
1001
1276
  if (parentComponent && parentComponent.lastFocusedChildKey === focusKey) {
1002
1277
  parentComponent.lastFocusedChildKey = null;
1003
1278
  }
1004
- if (this.nativeMode) {
1005
- return;
1006
- }
1007
1279
  /**
1008
1280
  * If the component was also focused at this time, OR had focused child, focus its parent -> it will focus another child
1009
1281
  * Normally the order of components unmount is children -> parents, but sometimes parent can be removed before the child
@@ -1022,33 +1294,43 @@ var SpatialNavigationService = /** @class */ (function () {
1022
1294
  }
1023
1295
  };
1024
1296
  SpatialNavigationService.prototype.getNodeLayoutByFocusKey = function (focusKey) {
1025
- var component = this.focusableComponents[focusKey];
1026
- if (component) {
1027
- this.updateLayout(component.focusKey);
1028
- return component.layout;
1029
- }
1030
- return null;
1297
+ return __awaiter(this, void 0, void 0, function () {
1298
+ var component;
1299
+ return __generator(this, function (_a) {
1300
+ switch (_a.label) {
1301
+ case 0:
1302
+ component = this.focusableComponents[focusKey];
1303
+ if (!component) return [3 /*break*/, 2];
1304
+ return [4 /*yield*/, this.updateLayout(component.focusKey)];
1305
+ case 1:
1306
+ _a.sent();
1307
+ return [2 /*return*/, component.layout];
1308
+ case 2: return [2 /*return*/, null];
1309
+ }
1310
+ });
1311
+ });
1031
1312
  };
1032
1313
  SpatialNavigationService.prototype.setCurrentFocusedKey = function (newFocusKey, focusDetails) {
1033
- var _a, _b, _c, _d;
1314
+ var _this = this;
1034
1315
  if (this.isFocusableComponent(this.focusKey) &&
1035
1316
  newFocusKey !== this.focusKey) {
1036
- var oldComponent = this.focusableComponents[this.focusKey];
1037
- oldComponent.onUpdateFocus(false);
1038
- oldComponent.onBlur(this.getNodeLayoutByFocusKey(this.focusKey), focusDetails);
1039
- (_b = (_a = oldComponent.node) === null || _a === void 0 ? void 0 : _a.removeAttribute) === null || _b === void 0 ? void 0 : _b.call(_a, 'data-focused');
1040
- this.log('setCurrentFocusedKey', 'onBlur', oldComponent);
1317
+ var oldComponent_1 = this.focusableComponents[this.focusKey];
1318
+ oldComponent_1.onUpdateFocus(false);
1319
+ this.layoutAdapter.blurNode(oldComponent_1);
1320
+ this.getNodeLayoutByFocusKey(this.focusKey).then(function (layout) {
1321
+ oldComponent_1.onBlur(layout, focusDetails);
1322
+ _this.log('setCurrentFocusedKey', 'onBlur', oldComponent_1);
1323
+ });
1041
1324
  }
1042
1325
  this.focusKey = newFocusKey;
1043
1326
  if (this.isFocusableComponent(this.focusKey)) {
1044
- var newComponent = this.focusableComponents[this.focusKey];
1045
- if (this.shouldFocusDOMNode && newComponent.node) {
1046
- newComponent.node.focus(this.domNodeFocusOptions);
1047
- }
1048
- (_d = (_c = newComponent.node) === null || _c === void 0 ? void 0 : _c.setAttribute) === null || _d === void 0 ? void 0 : _d.call(_c, 'data-focused', 'true');
1049
- newComponent.onUpdateFocus(true);
1050
- newComponent.onFocus(this.getNodeLayoutByFocusKey(this.focusKey), focusDetails);
1051
- this.log('setCurrentFocusedKey', 'onFocus', newComponent);
1327
+ var newComponent_1 = this.focusableComponents[this.focusKey];
1328
+ this.layoutAdapter.focusNode(newComponent_1);
1329
+ newComponent_1.onUpdateFocus(true);
1330
+ this.getNodeLayoutByFocusKey(this.focusKey).then(function (layout) {
1331
+ newComponent_1.onFocus(layout, focusDetails);
1332
+ _this.log('setCurrentFocusedKey', 'onFocus', newComponent_1);
1333
+ });
1052
1334
  }
1053
1335
  };
1054
1336
  SpatialNavigationService.prototype.updateParentsHasFocusedChild = function (focusKey, focusDetails) {
@@ -1117,13 +1399,19 @@ var SpatialNavigationService = /** @class */ (function () {
1117
1399
  this.focusableComponents[focusKey].focusable);
1118
1400
  };
1119
1401
  SpatialNavigationService.prototype.onIntermediateNodeBecameFocused = function (focusKey, focusDetails) {
1402
+ var _this = this;
1120
1403
  if (this.isParticipatingFocusableComponent(focusKey)) {
1121
- this.focusableComponents[focusKey].onFocus(this.getNodeLayoutByFocusKey(focusKey), focusDetails);
1404
+ this.getNodeLayoutByFocusKey(focusKey).then(function (layout) {
1405
+ _this.focusableComponents[focusKey].onFocus(layout, focusDetails);
1406
+ });
1122
1407
  }
1123
1408
  };
1124
1409
  SpatialNavigationService.prototype.onIntermediateNodeBecameBlurred = function (focusKey, focusDetails) {
1410
+ var _this = this;
1125
1411
  if (this.isParticipatingFocusableComponent(focusKey)) {
1126
- this.focusableComponents[focusKey].onBlur(this.getNodeLayoutByFocusKey(focusKey), focusDetails);
1412
+ this.getNodeLayoutByFocusKey(focusKey).then(function (layout) {
1413
+ _this.focusableComponents[focusKey].onBlur(layout, focusDetails);
1414
+ });
1127
1415
  }
1128
1416
  };
1129
1417
  SpatialNavigationService.prototype.pause = function () {
@@ -1132,54 +1420,90 @@ var SpatialNavigationService = /** @class */ (function () {
1132
1420
  SpatialNavigationService.prototype.resume = function () {
1133
1421
  this.paused = false;
1134
1422
  };
1135
- SpatialNavigationService.prototype.setFocus = function (focusKey, focusDetails) {
1136
- if (focusDetails === void 0) { focusDetails = {}; }
1137
- // Cancel any pending auto-restore focus calls if we are setting focus manually
1138
- this.setFocusDebounced.cancel();
1139
- if (!this.enabled) {
1140
- return;
1141
- }
1142
- this.log('setFocus', 'focusKey', focusKey);
1143
- /**
1144
- * When focusKey is not provided or is equal to `ROOT_FOCUS_KEY`, an attempt is made,
1145
- * to force focus one of the Focusable Containers, that have "forceFocus" flag enabled.
1146
- * A component closest to the top left viewport corner (0,0) is force-focused.
1147
- */
1148
- if (!focusKey || focusKey === ROOT_FOCUS_KEY) {
1149
- // eslint-disable-next-line no-param-reassign
1150
- focusKey = this.getForcedFocusKey();
1151
- }
1152
- var newFocusKey = this.getNextFocusKey(focusKey);
1153
- this.log('setFocus', 'newFocusKey', newFocusKey);
1154
- this.setCurrentFocusedKey(newFocusKey, focusDetails);
1155
- this.updateParentsHasFocusedChild(newFocusKey, focusDetails);
1156
- this.updateParentsLastFocusedChild(newFocusKey);
1423
+ SpatialNavigationService.prototype.setFocus = function (focusKey_1) {
1424
+ return __awaiter(this, arguments, void 0, function (focusKey, focusDetails) {
1425
+ var newFocusKey;
1426
+ if (focusDetails === void 0) { focusDetails = {}; }
1427
+ return __generator(this, function (_a) {
1428
+ switch (_a.label) {
1429
+ case 0:
1430
+ // Cancel any pending auto-restore focus calls if we are setting focus manually
1431
+ this.setFocusDebounced.cancel();
1432
+ if (!this.enabled) {
1433
+ return [2 /*return*/];
1434
+ }
1435
+ this.log('setFocus', 'focusKey', focusKey);
1436
+ /**
1437
+ * When focusKey is not provided or is equal to `ROOT_FOCUS_KEY`, an attempt is made,
1438
+ * to force focus one of the Focusable Containers, that have "forceFocus" flag enabled.
1439
+ * A component closest to the top left viewport corner (0,0) is force-focused.
1440
+ */
1441
+ if (!focusKey || focusKey === ROOT_FOCUS_KEY) {
1442
+ // eslint-disable-next-line no-param-reassign
1443
+ focusKey = this.getForcedFocusKey();
1444
+ // If there is no force-focusable key either then we abort
1445
+ if (!focusKey) {
1446
+ this.log('setFocus', 'Aborted due to missing force-focusable key');
1447
+ return [2 /*return*/];
1448
+ }
1449
+ }
1450
+ return [4 /*yield*/, this.getNextFocusKey(focusKey)];
1451
+ case 1:
1452
+ newFocusKey = _a.sent();
1453
+ if (!newFocusKey) {
1454
+ this.log('setFocus', 'Aborted due to missing next focus key');
1455
+ return [2 /*return*/];
1456
+ }
1457
+ this.log('setFocus', 'newFocusKey', newFocusKey);
1458
+ this.setCurrentFocusedKey(newFocusKey, focusDetails);
1459
+ this.updateParentsHasFocusedChild(newFocusKey, focusDetails);
1460
+ this.updateParentsLastFocusedChild(newFocusKey);
1461
+ return [2 /*return*/];
1462
+ }
1463
+ });
1464
+ });
1157
1465
  };
1158
1466
  SpatialNavigationService.prototype.updateAllLayouts = function () {
1159
- var _this = this;
1160
- if (!this.enabled || this.nativeMode) {
1161
- return;
1162
- }
1163
- forOwn(this.focusableComponents, function (component, focusKey) {
1164
- _this.updateLayout(focusKey);
1467
+ return __awaiter(this, void 0, void 0, function () {
1468
+ var _this = this;
1469
+ return __generator(this, function (_a) {
1470
+ switch (_a.label) {
1471
+ case 0:
1472
+ if (!this.enabled) {
1473
+ return [2 /*return*/];
1474
+ }
1475
+ return [4 /*yield*/, Promise.all(Object.keys(this.focusableComponents).map(function (focusKey) {
1476
+ return _this.updateLayout(focusKey);
1477
+ }))];
1478
+ case 1:
1479
+ _a.sent();
1480
+ return [2 /*return*/];
1481
+ }
1482
+ });
1165
1483
  });
1166
1484
  };
1167
1485
  SpatialNavigationService.prototype.updateLayout = function (focusKey) {
1168
- var component = this.focusableComponents[focusKey];
1169
- if (!component || this.nativeMode || component.layoutUpdated) {
1170
- return;
1171
- }
1172
- var node = component.node;
1173
- var layout = this.useGetBoundingClientRect
1174
- ? getBoundingClientRect(node)
1175
- : measureLayout(node);
1176
- component.layout = __assign(__assign({}, layout), { node: node });
1486
+ return __awaiter(this, void 0, void 0, function () {
1487
+ var component, _a;
1488
+ return __generator(this, function (_b) {
1489
+ switch (_b.label) {
1490
+ case 0:
1491
+ component = this.focusableComponents[focusKey];
1492
+ if (!component) {
1493
+ return [2 /*return*/];
1494
+ }
1495
+ _a = component;
1496
+ return [4 /*yield*/, this.layoutAdapter.measureLayout(component)];
1497
+ case 1:
1498
+ _a.layout = _b.sent();
1499
+ component.layoutUpdatedAt = Date.now();
1500
+ return [2 /*return*/];
1501
+ }
1502
+ });
1503
+ });
1177
1504
  };
1178
1505
  SpatialNavigationService.prototype.updateFocusable = function (focusKey, _a) {
1179
1506
  var node = _a.node, preferredChildFocusKey = _a.preferredChildFocusKey, focusable = _a.focusable, isFocusBoundary = _a.isFocusBoundary, focusBoundaryDirections = _a.focusBoundaryDirections, onEnterPress = _a.onEnterPress, onEnterRelease = _a.onEnterRelease, onArrowPress = _a.onArrowPress, onFocus = _a.onFocus, onBlur = _a.onBlur;
1180
- if (this.nativeMode) {
1181
- return;
1182
- }
1183
1507
  var component = this.focusableComponents[focusKey];
1184
1508
  if (component) {
1185
1509
  component.preferredChildFocusKey = preferredChildFocusKey;
@@ -1191,14 +1515,13 @@ var SpatialNavigationService = /** @class */ (function () {
1191
1515
  component.onArrowPress = onArrowPress;
1192
1516
  component.onFocus = onFocus;
1193
1517
  component.onBlur = onBlur;
1518
+ // Reset layout updated at to force a layout update
1519
+ component.layoutUpdatedAt = 0;
1194
1520
  if (node) {
1195
1521
  component.node = node;
1196
1522
  }
1197
1523
  }
1198
1524
  };
1199
- SpatialNavigationService.prototype.isNativeMode = function () {
1200
- return this.nativeMode;
1201
- };
1202
1525
  SpatialNavigationService.prototype.doesFocusableExist = function (focusKey) {
1203
1526
  return !!this.focusableComponents[focusKey];
1204
1527
  };
@@ -1217,4 +1540,4 @@ var SpatialNavigationService = /** @class */ (function () {
1217
1540
  var SpatialNavigation = new SpatialNavigationService();
1218
1541
  var init = SpatialNavigation.init, setThrottle = SpatialNavigation.setThrottle, destroy = SpatialNavigation.destroy, setKeyMap = SpatialNavigation.setKeyMap, setFocus = SpatialNavigation.setFocus, navigateByDirection = SpatialNavigation.navigateByDirection, pause = SpatialNavigation.pause, resume = SpatialNavigation.resume, updateAllLayouts = SpatialNavigation.updateAllLayouts, getCurrentFocusKey = SpatialNavigation.getCurrentFocusKey, doesFocusableExist = SpatialNavigation.doesFocusableExist, updateRtl = SpatialNavigation.updateRtl;
1219
1542
 
1220
- export { ROOT_FOCUS_KEY, SpatialNavigation, destroy, doesFocusableExist, getCurrentFocusKey, init, navigateByDirection, pause, resume, setFocus, setKeyMap, setThrottle, updateAllLayouts, updateRtl };
1543
+ export { BaseWebAdapter, GetBoundingClientRectAdapter, ROOT_FOCUS_KEY, SpatialNavigation, SpatialNavigationService, destroy, doesFocusableExist, getCurrentFocusKey, init, navigateByDirection, pause, resume, setFocus, setKeyMap, setThrottle, updateAllLayouts, updateRtl };