@react-aria/landmark 3.0.0-alpha.6 → 3.0.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/import.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import $TvsbU$swchelperssrc_define_propertymjs from "@swc/helpers/src/_define_property.mjs";
2
2
  import {useState as $TvsbU$useState, useCallback as $TvsbU$useCallback, useEffect as $TvsbU$useEffect} from "react";
3
3
  import {useLayoutEffect as $TvsbU$useLayoutEffect} from "@react-aria/utils";
4
- import {useSyncExternalStore as $TvsbU$useSyncExternalStore} from "use-sync-external-store/shim";
4
+ import {useSyncExternalStore as $TvsbU$useSyncExternalStore} from "use-sync-external-store/shim/index.js";
5
5
 
6
6
  /*
7
7
  * Copyright 2022 Adobe. All rights reserved.
@@ -37,6 +37,7 @@ function $a86207c5d7f7e1fb$var$subscribe(fn) {
37
37
  return ()=>document.removeEventListener("react-aria-landmark-manager-change", fn);
38
38
  }
39
39
  function $a86207c5d7f7e1fb$var$getLandmarkManager() {
40
+ if (typeof document === "undefined") return null;
40
41
  // Reuse an existing instance if it has the same or greater version.
41
42
  let instance = document[$a86207c5d7f7e1fb$var$landmarkSymbol];
42
43
  if (instance && instance.version >= $a86207c5d7f7e1fb$var$LANDMARK_API_VERSION) return instance;
@@ -48,7 +49,7 @@ function $a86207c5d7f7e1fb$var$getLandmarkManager() {
48
49
  }
49
50
  // Subscribes a React component to the current landmark manager instance.
50
51
  function $a86207c5d7f7e1fb$var$useLandmarkManager() {
51
- return (0, $TvsbU$useSyncExternalStore)($a86207c5d7f7e1fb$var$subscribe, $a86207c5d7f7e1fb$var$getLandmarkManager);
52
+ return (0, $TvsbU$useSyncExternalStore)($a86207c5d7f7e1fb$var$subscribe, $a86207c5d7f7e1fb$var$getLandmarkManager, $a86207c5d7f7e1fb$var$getLandmarkManager);
52
53
  }
53
54
  class $a86207c5d7f7e1fb$var$LandmarkManager {
54
55
  setupIfNeeded() {
@@ -78,8 +79,8 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
78
79
  this.isListening = false;
79
80
  }
80
81
  focusLandmark(landmark, direction) {
81
- var _this_landmarks_find;
82
- (_this_landmarks_find = this.landmarks.find((l)=>l.ref.current === landmark)) === null || _this_landmarks_find === void 0 ? void 0 : _this_landmarks_find.focus(direction);
82
+ var _this_landmarks_find, _this_landmarks_find_focus;
83
+ (_this_landmarks_find = this.landmarks.find((l)=>l.ref.current === landmark)) === null || _this_landmarks_find === void 0 ? void 0 : (_this_landmarks_find_focus = _this_landmarks_find.focus) === null || _this_landmarks_find_focus === void 0 ? void 0 : _this_landmarks_find_focus.call(_this_landmarks_find, direction);
83
84
  }
84
85
  /**
85
86
  * Return set of landmarks with a specific role.
@@ -93,7 +94,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
93
94
  }
94
95
  addLandmark(newLandmark) {
95
96
  this.setupIfNeeded();
96
- if (this.landmarks.find((landmark)=>landmark.ref === newLandmark.ref)) return;
97
+ if (this.landmarks.find((landmark)=>landmark.ref === newLandmark.ref) || !newLandmark.ref.current) return;
97
98
  if (this.landmarks.filter((landmark)=>landmark.role === "main").length > 1) console.error('Page can contain no more than one landmark with the role "main".');
98
99
  if (this.landmarks.length === 0) {
99
100
  this.landmarks = [
@@ -164,7 +165,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
164
165
  l
165
166
  ]));
166
167
  let currentElement = element;
167
- while(currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body)currentElement = currentElement.parentElement;
168
+ while(currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body && currentElement.parentElement)currentElement = currentElement.parentElement;
168
169
  return landmarkMap.get(currentElement);
169
170
  }
170
171
  /**
@@ -173,6 +174,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
173
174
  * If not inside a landmark, will return first landmark.
174
175
  * Returns undefined if there are no landmarks.
175
176
  */ getNextLandmark(element, { backward: backward }) {
177
+ var _this_landmarks_nextLandmarkIndex_ref_current;
176
178
  let currentLandmark = this.closestLandmark(element);
177
179
  let nextLandmarkIndex = backward ? this.landmarks.length - 1 : 0;
178
180
  if (currentLandmark) nextLandmarkIndex = this.landmarks.indexOf(currentLandmark) + (backward ? -1 : 1);
@@ -204,7 +206,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
204
206
  if (wrapIfNeeded()) return undefined;
205
207
  // Skip over hidden landmarks.
206
208
  let i = nextLandmarkIndex;
207
- while(this.landmarks[nextLandmarkIndex].ref.current.closest("[aria-hidden=true]")){
209
+ while((_this_landmarks_nextLandmarkIndex_ref_current = this.landmarks[nextLandmarkIndex].ref.current) === null || _this_landmarks_nextLandmarkIndex_ref_current === void 0 ? void 0 : _this_landmarks_nextLandmarkIndex_ref_current.closest("[aria-hidden=true]")){
208
210
  nextLandmarkIndex += backward ? -1 : 1;
209
211
  if (wrapIfNeeded()) return undefined;
210
212
  if (nextLandmarkIndex === i) break;
@@ -227,7 +229,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
227
229
  }
228
230
  focusMain() {
229
231
  let main = this.getLandmarkByRole("main");
230
- if (main && document.contains(main.ref.current)) {
232
+ if (main && main.ref.current && document.contains(main.ref.current)) {
231
233
  this.focusLandmark(main.ref.current, "forward");
232
234
  return true;
233
235
  }
@@ -247,7 +249,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
247
249
  }
248
250
  }
249
251
  // Otherwise, focus the landmark itself
250
- if (document.contains(nextLandmark.ref.current)) {
252
+ if (nextLandmark.ref.current && document.contains(nextLandmark.ref.current)) {
251
253
  this.focusLandmark(nextLandmark.ref.current, backward ? "backward" : "forward");
252
254
  return true;
253
255
  }
@@ -286,21 +288,26 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
286
288
  instance.setupIfNeeded();
287
289
  return {
288
290
  navigate (direction, opts) {
289
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, direction === "backward");
291
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
292
+ return instance.navigate(element, direction === "backward");
290
293
  },
291
294
  focusNext (opts) {
292
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, false);
295
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
296
+ return instance.navigate(element, false);
293
297
  },
294
298
  focusPrevious (opts) {
295
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, true);
299
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
300
+ return instance.navigate(element, true);
296
301
  },
297
302
  focusMain () {
298
303
  return instance.focusMain();
299
304
  },
300
305
  dispose () {
301
- instance.refCount--;
302
- instance.teardownIfNeeded();
303
- instance = null;
306
+ if (instance) {
307
+ instance.refCount--;
308
+ instance.teardownIfNeeded();
309
+ instance = null;
310
+ }
304
311
  }
305
312
  };
306
313
  }
@@ -322,13 +329,13 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
322
329
  function $a86207c5d7f7e1fb$export$f50151dbd51cd1d9() {
323
330
  // Get the current landmark manager and create a controller using it.
324
331
  let instance = $a86207c5d7f7e1fb$var$getLandmarkManager();
325
- let controller = instance.createLandmarkController();
332
+ let controller = instance === null || instance === void 0 ? void 0 : instance.createLandmarkController();
326
333
  let unsubscribe = $a86207c5d7f7e1fb$var$subscribe(()=>{
327
334
  // If the landmark manager changes, dispose the old
328
335
  // controller and create a new one.
329
- controller.dispose();
336
+ controller === null || controller === void 0 ? void 0 : controller.dispose();
330
337
  instance = $a86207c5d7f7e1fb$var$getLandmarkManager();
331
- controller = instance.createLandmarkController();
338
+ controller = instance === null || instance === void 0 ? void 0 : instance.createLandmarkController();
332
339
  });
333
340
  // Return a wrapper that proxies requests to the current controller instance.
334
341
  return {
@@ -345,9 +352,9 @@ function $a86207c5d7f7e1fb$export$f50151dbd51cd1d9() {
345
352
  return controller.focusMain();
346
353
  },
347
354
  dispose () {
348
- controller.dispose();
355
+ controller === null || controller === void 0 ? void 0 : controller.dispose();
349
356
  unsubscribe();
350
- controller = null;
357
+ controller = undefined;
351
358
  instance = null;
352
359
  }
353
360
  };
@@ -368,7 +375,7 @@ function $a86207c5d7f7e1fb$export$4cc632584fd87fae(props, ref) {
368
375
  setIsLandmarkFocused
369
376
  ]);
370
377
  (0, $TvsbU$useLayoutEffect)(()=>{
371
- return manager.registerLandmark({
378
+ if (manager) return manager.registerLandmark({
372
379
  ref: ref,
373
380
  label: label,
374
381
  role: role,
@@ -385,7 +392,8 @@ function $a86207c5d7f7e1fb$export$4cc632584fd87fae(props, ref) {
385
392
  blur
386
393
  ]);
387
394
  (0, $TvsbU$useEffect)(()=>{
388
- if (isLandmarkFocused) ref.current.focus();
395
+ var _ref_current;
396
+ if (isLandmarkFocused) (_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.focus();
389
397
  }, [
390
398
  isLandmarkFocused,
391
399
  ref
package/dist/main.js CHANGED
@@ -1,7 +1,7 @@
1
1
  var $8Ore6$swchelperslib_define_propertyjs = require("@swc/helpers/lib/_define_property.js");
2
2
  var $8Ore6$react = require("react");
3
3
  var $8Ore6$reactariautils = require("@react-aria/utils");
4
- var $8Ore6$usesyncexternalstoreshim = require("use-sync-external-store/shim");
4
+ var $8Ore6$usesyncexternalstoreshimindexjs = require("use-sync-external-store/shim/index.js");
5
5
 
6
6
  function $parcel$export(e, n, v, s) {
7
7
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
@@ -46,6 +46,7 @@ function $202c109aedff6705$var$subscribe(fn) {
46
46
  return ()=>document.removeEventListener("react-aria-landmark-manager-change", fn);
47
47
  }
48
48
  function $202c109aedff6705$var$getLandmarkManager() {
49
+ if (typeof document === "undefined") return null;
49
50
  // Reuse an existing instance if it has the same or greater version.
50
51
  let instance = document[$202c109aedff6705$var$landmarkSymbol];
51
52
  if (instance && instance.version >= $202c109aedff6705$var$LANDMARK_API_VERSION) return instance;
@@ -57,7 +58,7 @@ function $202c109aedff6705$var$getLandmarkManager() {
57
58
  }
58
59
  // Subscribes a React component to the current landmark manager instance.
59
60
  function $202c109aedff6705$var$useLandmarkManager() {
60
- return (0, $8Ore6$usesyncexternalstoreshim.useSyncExternalStore)($202c109aedff6705$var$subscribe, $202c109aedff6705$var$getLandmarkManager);
61
+ return (0, $8Ore6$usesyncexternalstoreshimindexjs.useSyncExternalStore)($202c109aedff6705$var$subscribe, $202c109aedff6705$var$getLandmarkManager, $202c109aedff6705$var$getLandmarkManager);
61
62
  }
62
63
  class $202c109aedff6705$var$LandmarkManager {
63
64
  setupIfNeeded() {
@@ -87,8 +88,8 @@ class $202c109aedff6705$var$LandmarkManager {
87
88
  this.isListening = false;
88
89
  }
89
90
  focusLandmark(landmark, direction) {
90
- var _this_landmarks_find;
91
- (_this_landmarks_find = this.landmarks.find((l)=>l.ref.current === landmark)) === null || _this_landmarks_find === void 0 ? void 0 : _this_landmarks_find.focus(direction);
91
+ var _this_landmarks_find, _this_landmarks_find_focus;
92
+ (_this_landmarks_find = this.landmarks.find((l)=>l.ref.current === landmark)) === null || _this_landmarks_find === void 0 ? void 0 : (_this_landmarks_find_focus = _this_landmarks_find.focus) === null || _this_landmarks_find_focus === void 0 ? void 0 : _this_landmarks_find_focus.call(_this_landmarks_find, direction);
92
93
  }
93
94
  /**
94
95
  * Return set of landmarks with a specific role.
@@ -102,7 +103,7 @@ class $202c109aedff6705$var$LandmarkManager {
102
103
  }
103
104
  addLandmark(newLandmark) {
104
105
  this.setupIfNeeded();
105
- if (this.landmarks.find((landmark)=>landmark.ref === newLandmark.ref)) return;
106
+ if (this.landmarks.find((landmark)=>landmark.ref === newLandmark.ref) || !newLandmark.ref.current) return;
106
107
  if (this.landmarks.filter((landmark)=>landmark.role === "main").length > 1) console.error('Page can contain no more than one landmark with the role "main".');
107
108
  if (this.landmarks.length === 0) {
108
109
  this.landmarks = [
@@ -173,7 +174,7 @@ class $202c109aedff6705$var$LandmarkManager {
173
174
  l
174
175
  ]));
175
176
  let currentElement = element;
176
- while(currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body)currentElement = currentElement.parentElement;
177
+ while(currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body && currentElement.parentElement)currentElement = currentElement.parentElement;
177
178
  return landmarkMap.get(currentElement);
178
179
  }
179
180
  /**
@@ -182,6 +183,7 @@ class $202c109aedff6705$var$LandmarkManager {
182
183
  * If not inside a landmark, will return first landmark.
183
184
  * Returns undefined if there are no landmarks.
184
185
  */ getNextLandmark(element, { backward: backward }) {
186
+ var _this_landmarks_nextLandmarkIndex_ref_current;
185
187
  let currentLandmark = this.closestLandmark(element);
186
188
  let nextLandmarkIndex = backward ? this.landmarks.length - 1 : 0;
187
189
  if (currentLandmark) nextLandmarkIndex = this.landmarks.indexOf(currentLandmark) + (backward ? -1 : 1);
@@ -213,7 +215,7 @@ class $202c109aedff6705$var$LandmarkManager {
213
215
  if (wrapIfNeeded()) return undefined;
214
216
  // Skip over hidden landmarks.
215
217
  let i = nextLandmarkIndex;
216
- while(this.landmarks[nextLandmarkIndex].ref.current.closest("[aria-hidden=true]")){
218
+ while((_this_landmarks_nextLandmarkIndex_ref_current = this.landmarks[nextLandmarkIndex].ref.current) === null || _this_landmarks_nextLandmarkIndex_ref_current === void 0 ? void 0 : _this_landmarks_nextLandmarkIndex_ref_current.closest("[aria-hidden=true]")){
217
219
  nextLandmarkIndex += backward ? -1 : 1;
218
220
  if (wrapIfNeeded()) return undefined;
219
221
  if (nextLandmarkIndex === i) break;
@@ -236,7 +238,7 @@ class $202c109aedff6705$var$LandmarkManager {
236
238
  }
237
239
  focusMain() {
238
240
  let main = this.getLandmarkByRole("main");
239
- if (main && document.contains(main.ref.current)) {
241
+ if (main && main.ref.current && document.contains(main.ref.current)) {
240
242
  this.focusLandmark(main.ref.current, "forward");
241
243
  return true;
242
244
  }
@@ -256,7 +258,7 @@ class $202c109aedff6705$var$LandmarkManager {
256
258
  }
257
259
  }
258
260
  // Otherwise, focus the landmark itself
259
- if (document.contains(nextLandmark.ref.current)) {
261
+ if (nextLandmark.ref.current && document.contains(nextLandmark.ref.current)) {
260
262
  this.focusLandmark(nextLandmark.ref.current, backward ? "backward" : "forward");
261
263
  return true;
262
264
  }
@@ -295,21 +297,26 @@ class $202c109aedff6705$var$LandmarkManager {
295
297
  instance.setupIfNeeded();
296
298
  return {
297
299
  navigate (direction, opts) {
298
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, direction === "backward");
300
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
301
+ return instance.navigate(element, direction === "backward");
299
302
  },
300
303
  focusNext (opts) {
301
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, false);
304
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
305
+ return instance.navigate(element, false);
302
306
  },
303
307
  focusPrevious (opts) {
304
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, true);
308
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
309
+ return instance.navigate(element, true);
305
310
  },
306
311
  focusMain () {
307
312
  return instance.focusMain();
308
313
  },
309
314
  dispose () {
310
- instance.refCount--;
311
- instance.teardownIfNeeded();
312
- instance = null;
315
+ if (instance) {
316
+ instance.refCount--;
317
+ instance.teardownIfNeeded();
318
+ instance = null;
319
+ }
313
320
  }
314
321
  };
315
322
  }
@@ -331,13 +338,13 @@ class $202c109aedff6705$var$LandmarkManager {
331
338
  function $202c109aedff6705$export$f50151dbd51cd1d9() {
332
339
  // Get the current landmark manager and create a controller using it.
333
340
  let instance = $202c109aedff6705$var$getLandmarkManager();
334
- let controller = instance.createLandmarkController();
341
+ let controller = instance === null || instance === void 0 ? void 0 : instance.createLandmarkController();
335
342
  let unsubscribe = $202c109aedff6705$var$subscribe(()=>{
336
343
  // If the landmark manager changes, dispose the old
337
344
  // controller and create a new one.
338
- controller.dispose();
345
+ controller === null || controller === void 0 ? void 0 : controller.dispose();
339
346
  instance = $202c109aedff6705$var$getLandmarkManager();
340
- controller = instance.createLandmarkController();
347
+ controller = instance === null || instance === void 0 ? void 0 : instance.createLandmarkController();
341
348
  });
342
349
  // Return a wrapper that proxies requests to the current controller instance.
343
350
  return {
@@ -354,9 +361,9 @@ function $202c109aedff6705$export$f50151dbd51cd1d9() {
354
361
  return controller.focusMain();
355
362
  },
356
363
  dispose () {
357
- controller.dispose();
364
+ controller === null || controller === void 0 ? void 0 : controller.dispose();
358
365
  unsubscribe();
359
- controller = null;
366
+ controller = undefined;
360
367
  instance = null;
361
368
  }
362
369
  };
@@ -377,7 +384,7 @@ function $202c109aedff6705$export$4cc632584fd87fae(props, ref) {
377
384
  setIsLandmarkFocused
378
385
  ]);
379
386
  (0, $8Ore6$reactariautils.useLayoutEffect)(()=>{
380
- return manager.registerLandmark({
387
+ if (manager) return manager.registerLandmark({
381
388
  ref: ref,
382
389
  label: label,
383
390
  role: role,
@@ -394,7 +401,8 @@ function $202c109aedff6705$export$4cc632584fd87fae(props, ref) {
394
401
  blur
395
402
  ]);
396
403
  (0, $8Ore6$react.useEffect)(()=>{
397
- if (isLandmarkFocused) ref.current.focus();
404
+ var _ref_current;
405
+ if (isLandmarkFocused) (_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.focus();
398
406
  }, [
399
407
  isLandmarkFocused,
400
408
  ref
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/@react-aria/landmark/src/index.ts","packages/@react-aria/landmark/src/useLandmark.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport type {AriaLandmarkRole, AriaLandmarkProps, LandmarkAria, LandmarkController} from './useLandmark';\nexport {useLandmark, createLandmarkController} from './useLandmark';\n","/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaLabelingProps, DOMAttributes, FocusableElement} from '@react-types/shared';\nimport {MutableRefObject, useCallback, useEffect, useState} from 'react';\nimport {useLayoutEffect} from '@react-aria/utils';\nimport {useSyncExternalStore} from 'use-sync-external-store/shim';\n\nexport type AriaLandmarkRole = 'main' | 'region' | 'search' | 'navigation' | 'form' | 'banner' | 'contentinfo' | 'complementary';\n\nexport interface AriaLandmarkProps extends AriaLabelingProps {\n role: AriaLandmarkRole,\n focus?: (direction: 'forward' | 'backward') => void\n}\n\nexport interface LandmarkAria {\n landmarkProps: DOMAttributes\n}\n\n// Increment this version number whenever the\n// LandmarkManagerApi or Landmark interfaces change.\nconst LANDMARK_API_VERSION = 1;\n\n// Minimal API for LandmarkManager that must continue to work between versions.\n// Changes to this interface are considered breaking. New methods/properties are\n// safe to add, but changes or removals are not allowed (same as public APIs).\ninterface LandmarkManagerApi {\n version: number,\n createLandmarkController(): LandmarkController,\n registerLandmark(landmark: Landmark): () => void\n}\n\n// Changes to this interface are considered breaking.\n// New properties MUST be optional so that registering a landmark\n// from an older version of useLandmark against a newer version of\n// LandmarkManager does not crash.\ninterface Landmark {\n ref: MutableRefObject<Element>,\n role: AriaLandmarkRole,\n label?: string,\n lastFocused?: FocusableElement,\n focus: (direction: 'forward' | 'backward') => void,\n blur: () => void\n}\n\nexport interface LandmarkControllerOptions {\n /**\n * The element from which to start navigating.\n * @default document.activeElement\n */\n from?: Element\n}\n\n/** A LandmarkController allows programmatic navigation of landmarks. */\nexport interface LandmarkController {\n /** Moves focus to the next landmark. */\n focusNext(opts?: LandmarkControllerOptions): boolean,\n /** Moves focus to the previous landmark. */\n focusPrevious(opts?: LandmarkControllerOptions): boolean,\n /** Moves focus to the main landmark. */\n focusMain(): boolean,\n /** Moves focus either forward or backward in the landmark sequence. */\n navigate(direction: 'forward' | 'backward', opts?: LandmarkControllerOptions): boolean,\n /**\n * Disposes the landmark controller. When no landmarks are registered, and no\n * controllers are active, the landmark keyboard listeners are removed from the page.\n */\n dispose(): void\n}\n\n// Symbol under which the singleton landmark manager instance is attached to the document.\nconst landmarkSymbol = Symbol.for('react-aria-landmark-manager');\n\nfunction subscribe(fn: () => void) {\n document.addEventListener('react-aria-landmark-manager-change', fn);\n return () => document.removeEventListener('react-aria-landmark-manager-change', fn);\n}\n\nfunction getLandmarkManager(): LandmarkManagerApi {\n // Reuse an existing instance if it has the same or greater version.\n let instance = document[landmarkSymbol];\n if (instance && instance.version >= LANDMARK_API_VERSION) {\n return instance;\n }\n\n // Otherwise, create a new instance and dispatch an event so anything using the existing\n // instance updates and re-registers their landmarks with the new one.\n document[landmarkSymbol] = new LandmarkManager();\n document.dispatchEvent(new CustomEvent('react-aria-landmark-manager-change'));\n return document[landmarkSymbol];\n}\n\n// Subscribes a React component to the current landmark manager instance.\nfunction useLandmarkManager(): LandmarkManagerApi {\n return useSyncExternalStore(subscribe, getLandmarkManager);\n}\n\nclass LandmarkManager implements LandmarkManagerApi {\n private landmarks: Array<Landmark> = [];\n private isListening = false;\n private refCount = 0;\n public version = LANDMARK_API_VERSION;\n\n constructor() {\n this.f6Handler = this.f6Handler.bind(this);\n this.focusinHandler = this.focusinHandler.bind(this);\n this.focusoutHandler = this.focusoutHandler.bind(this);\n }\n\n private setupIfNeeded() {\n if (this.isListening) {\n return;\n }\n document.addEventListener('keydown', this.f6Handler, {capture: true});\n document.addEventListener('focusin', this.focusinHandler, {capture: true});\n document.addEventListener('focusout', this.focusoutHandler, {capture: true});\n this.isListening = true;\n }\n\n private teardownIfNeeded() {\n if (!this.isListening || this.landmarks.length > 0 || this.refCount > 0) {\n return;\n }\n document.removeEventListener('keydown', this.f6Handler, {capture: true});\n document.removeEventListener('focusin', this.focusinHandler, {capture: true});\n document.removeEventListener('focusout', this.focusoutHandler, {capture: true});\n this.isListening = false;\n }\n\n private focusLandmark(landmark: Element, direction: 'forward' | 'backward') {\n this.landmarks.find(l => l.ref.current === landmark)?.focus(direction);\n }\n\n /**\n * Return set of landmarks with a specific role.\n */\n private getLandmarksByRole(role: AriaLandmarkRole) {\n return new Set(this.landmarks.filter(l => l.role === role));\n }\n\n /**\n * Return first landmark with a specific role.\n */\n private getLandmarkByRole(role: AriaLandmarkRole) {\n return this.landmarks.find(l => l.role === role);\n }\n\n private addLandmark(newLandmark: Landmark) {\n this.setupIfNeeded();\n if (this.landmarks.find(landmark => landmark.ref === newLandmark.ref)) {\n return;\n }\n\n if (this.landmarks.filter(landmark => landmark.role === 'main').length > 1) {\n console.error('Page can contain no more than one landmark with the role \"main\".');\n }\n\n if (this.landmarks.length === 0) {\n this.landmarks = [newLandmark];\n this.checkLabels(newLandmark.role);\n return;\n }\n\n\n // Binary search to insert new landmark based on position in document relative to existing landmarks.\n // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition\n let start = 0;\n let end = this.landmarks.length - 1;\n while (start <= end) {\n let mid = Math.floor((start + end) / 2);\n let comparedPosition = newLandmark.ref.current.compareDocumentPosition(this.landmarks[mid].ref.current as Node);\n let isNewAfterExisting = Boolean((comparedPosition & Node.DOCUMENT_POSITION_PRECEDING) || (comparedPosition & Node.DOCUMENT_POSITION_CONTAINS));\n\n if (isNewAfterExisting) {\n start = mid + 1;\n } else {\n end = mid - 1;\n }\n }\n\n this.landmarks.splice(start, 0, newLandmark);\n this.checkLabels(newLandmark.role);\n }\n\n private updateLandmark(landmark: Pick<Landmark, 'ref'> & Partial<Landmark>) {\n let index = this.landmarks.findIndex(l => l.ref === landmark.ref);\n if (index >= 0) {\n this.landmarks[index] = {...this.landmarks[index], ...landmark};\n this.checkLabels(this.landmarks[index].role);\n }\n }\n\n private removeLandmark(ref: MutableRefObject<Element>) {\n this.landmarks = this.landmarks.filter(landmark => landmark.ref !== ref);\n this.teardownIfNeeded();\n }\n\n /**\n * Warn if there are 2+ landmarks with the same role but no label.\n * Labels for landmarks with the same role must also be unique.\n *\n * See https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/.\n */\n private checkLabels(role: AriaLandmarkRole) {\n let landmarksWithRole = this.getLandmarksByRole(role);\n if (landmarksWithRole.size > 1) {\n let duplicatesWithoutLabel = [...landmarksWithRole].filter(landmark => !landmark.label);\n if (duplicatesWithoutLabel.length > 0) {\n console.warn(\n `Page contains more than one landmark with the '${role}' role. If two or more landmarks on a page share the same role, all must be labeled with an aria-label or aria-labelledby attribute: `,\n duplicatesWithoutLabel.map(landmark => landmark.ref.current)\n );\n } else {\n let labels = [...landmarksWithRole].map(landmark => landmark.label);\n let duplicateLabels = labels.filter((item, index) => labels.indexOf(item) !== index);\n\n duplicateLabels.forEach((label) => {\n console.warn(\n `Page contains more than one landmark with the '${role}' role and '${label}' label. If two or more landmarks on a page share the same role, they must have unique labels: `,\n [...landmarksWithRole].filter(landmark => landmark.label === label).map(landmark => landmark.ref.current)\n );\n });\n }\n }\n }\n\n /**\n * Get the landmark that is the closest parent in the DOM.\n * Returns undefined if no parent is a landmark.\n */\n private closestLandmark(element: Element) {\n let landmarkMap = new Map(this.landmarks.map(l => [l.ref.current, l]));\n let currentElement = element;\n while (currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body) {\n currentElement = currentElement.parentElement;\n }\n return landmarkMap.get(currentElement);\n }\n\n /**\n * Gets the next landmark, in DOM focus order, or previous if backwards is specified.\n * If last landmark, next should be the first landmark.\n * If not inside a landmark, will return first landmark.\n * Returns undefined if there are no landmarks.\n */\n private getNextLandmark(element: Element, {backward}: {backward?: boolean }) {\n let currentLandmark = this.closestLandmark(element);\n let nextLandmarkIndex = backward ? this.landmarks.length - 1 : 0;\n if (currentLandmark) {\n nextLandmarkIndex = this.landmarks.indexOf(currentLandmark) + (backward ? -1 : 1);\n }\n\n let wrapIfNeeded = () => {\n // When we reach the end of the landmark sequence, fire a custom event that can be listened for by applications.\n // If this event is canceled, we return immediately. This can be used to implement landmark navigation across iframes.\n if (nextLandmarkIndex < 0) {\n if (!element.dispatchEvent(new CustomEvent('react-aria-landmark-navigation', {detail: {direction: 'backward'}, bubbles: true, cancelable: true}))) {\n return true;\n }\n\n nextLandmarkIndex = this.landmarks.length - 1;\n } else if (nextLandmarkIndex >= this.landmarks.length) {\n if (!element.dispatchEvent(new CustomEvent('react-aria-landmark-navigation', {detail: {direction: 'forward'}, bubbles: true, cancelable: true}))) {\n return true;\n }\n\n nextLandmarkIndex = 0;\n }\n\n if (nextLandmarkIndex < 0 || nextLandmarkIndex >= this.landmarks.length) {\n return true;\n }\n\n return false;\n };\n\n if (wrapIfNeeded()) {\n return undefined;\n }\n\n // Skip over hidden landmarks.\n let i = nextLandmarkIndex;\n while (this.landmarks[nextLandmarkIndex].ref.current.closest('[aria-hidden=true]')) {\n nextLandmarkIndex += backward ? -1 : 1;\n if (wrapIfNeeded()) {\n return undefined;\n }\n\n if (nextLandmarkIndex === i) {\n break;\n }\n }\n\n return this.landmarks[nextLandmarkIndex];\n }\n\n /**\n * Look at next landmark. If an element was previously focused inside, restore focus there.\n * If not, focus the landmark itself.\n * If no landmarks at all, or none with focusable elements, don't move focus.\n */\n private f6Handler(e: KeyboardEvent) {\n if (e.key === 'F6') {\n // If alt key pressed, focus main landmark, otherwise navigate forward or backward based on shift key.\n let handled = e.altKey ? this.focusMain() : this.navigate(e.target as Element, e.shiftKey);\n if (handled) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n }\n\n private focusMain() {\n let main = this.getLandmarkByRole('main');\n if (main && document.contains(main.ref.current)) {\n this.focusLandmark(main.ref.current, 'forward');\n return true;\n }\n\n return false;\n }\n\n private navigate(from: Element, backward: boolean) {\n let nextLandmark = this.getNextLandmark(from, {\n backward\n });\n\n if (!nextLandmark) {\n return false;\n }\n\n // If something was previously focused in the next landmark, then return focus to it\n if (nextLandmark.lastFocused) {\n let lastFocused = nextLandmark.lastFocused;\n if (document.body.contains(lastFocused)) {\n lastFocused.focus();\n return true;\n }\n }\n\n // Otherwise, focus the landmark itself\n if (document.contains(nextLandmark.ref.current)) {\n this.focusLandmark(nextLandmark.ref.current, backward ? 'backward' : 'forward');\n return true;\n }\n\n return false;\n }\n\n /**\n * Sets lastFocused for a landmark, if focus is moved within that landmark.\n * Lets the last focused landmark know it was blurred if something else is focused.\n */\n private focusinHandler(e: FocusEvent) {\n let currentLandmark = this.closestLandmark(e.target as Element);\n if (currentLandmark && currentLandmark.ref.current !== e.target) {\n this.updateLandmark({ref: currentLandmark.ref, lastFocused: e.target as FocusableElement});\n }\n let previousFocusedElement = e.relatedTarget as Element;\n if (previousFocusedElement) {\n let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);\n if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {\n closestPreviousLandmark.blur();\n }\n }\n }\n\n /**\n * Track if the focus is lost to the body. If it is, do cleanup on the landmark that last had focus.\n */\n private focusoutHandler(e: FocusEvent) {\n let previousFocusedElement = e.target as Element;\n let nextFocusedElement = e.relatedTarget;\n // the === document seems to be a jest thing for focus to go there on generic blur event such as landmark.blur();\n // browsers appear to send focus instead to document.body and the relatedTarget is null when that happens\n if (!nextFocusedElement || nextFocusedElement === document) {\n let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);\n if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {\n closestPreviousLandmark.blur();\n }\n }\n }\n\n public createLandmarkController(): LandmarkController {\n let instance = this;\n instance.refCount++;\n instance.setupIfNeeded();\n return {\n navigate(direction, opts) {\n return instance.navigate(opts?.from || document.activeElement, direction === 'backward');\n },\n focusNext(opts) {\n return instance.navigate(opts?.from || document.activeElement, false);\n },\n focusPrevious(opts) {\n return instance.navigate(opts?.from || document.activeElement, true);\n },\n focusMain() {\n return instance.focusMain();\n },\n dispose() {\n instance.refCount--;\n instance.teardownIfNeeded();\n instance = null;\n }\n };\n }\n\n public registerLandmark(landmark: Landmark): () => void {\n if (this.landmarks.find(l => l.ref === landmark.ref)) {\n this.updateLandmark(landmark);\n } else {\n this.addLandmark(landmark);\n }\n\n return () => this.removeLandmark(landmark.ref);\n }\n}\n\n/** Creates a LandmarkController, which allows programmatic navigation of landmarks. */\nexport function createLandmarkController(): LandmarkController {\n // Get the current landmark manager and create a controller using it.\n let instance = getLandmarkManager();\n let controller = instance.createLandmarkController();\n\n let unsubscribe = subscribe(() => {\n // If the landmark manager changes, dispose the old\n // controller and create a new one.\n controller.dispose();\n instance = getLandmarkManager();\n controller = instance.createLandmarkController();\n });\n\n // Return a wrapper that proxies requests to the current controller instance.\n return {\n navigate(direction, opts) {\n return controller.navigate(direction, opts);\n },\n focusNext(opts) {\n return controller.focusNext(opts);\n },\n focusPrevious(opts) {\n return controller.focusPrevious(opts);\n },\n focusMain() {\n return controller.focusMain();\n },\n dispose() {\n controller.dispose();\n unsubscribe();\n controller = null;\n instance = null;\n }\n };\n}\n\n/**\n * Provides landmark navigation in an application. Call this with a role and label to register a landmark navigable with F6.\n * @param props - Props for the landmark.\n * @param ref - Ref to the landmark.\n */\nexport function useLandmark(props: AriaLandmarkProps, ref: MutableRefObject<FocusableElement>): LandmarkAria {\n const {\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n focus\n } = props;\n let manager = useLandmarkManager();\n let label = ariaLabel || ariaLabelledby;\n let [isLandmarkFocused, setIsLandmarkFocused] = useState(false);\n\n let defaultFocus = useCallback(() => {\n setIsLandmarkFocused(true);\n }, [setIsLandmarkFocused]);\n\n let blur = useCallback(() => {\n setIsLandmarkFocused(false);\n }, [setIsLandmarkFocused]);\n\n useLayoutEffect(() => {\n return manager.registerLandmark({ref, label, role, focus: focus || defaultFocus, blur});\n }, [manager, label, ref, role, focus, defaultFocus, blur]);\n\n useEffect(() => {\n if (isLandmarkFocused) {\n ref.current.focus();\n }\n }, [isLandmarkFocused, ref]);\n\n return {\n landmarkProps: {\n role,\n tabIndex: isLandmarkFocused ? -1 : undefined,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby\n }\n };\n}\n"],"names":[],"version":3,"file":"main.js.map"}
1
+ {"mappings":"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","sources":["packages/@react-aria/landmark/src/index.ts","packages/@react-aria/landmark/src/useLandmark.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport type {AriaLandmarkRole, AriaLandmarkProps, LandmarkAria, LandmarkController} from './useLandmark';\nexport {useLandmark, createLandmarkController} from './useLandmark';\n","/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaLabelingProps, DOMAttributes, FocusableElement} from '@react-types/shared';\nimport {RefObject, useCallback, useEffect, useState} from 'react';\nimport {useLayoutEffect} from '@react-aria/utils';\nimport {useSyncExternalStore} from 'use-sync-external-store/shim/index.js';\n\nexport type AriaLandmarkRole = 'main' | 'region' | 'search' | 'navigation' | 'form' | 'banner' | 'contentinfo' | 'complementary';\n\nexport interface AriaLandmarkProps extends AriaLabelingProps {\n role: AriaLandmarkRole,\n focus?: (direction: 'forward' | 'backward') => void\n}\n\nexport interface LandmarkAria {\n landmarkProps: DOMAttributes\n}\n\n// Increment this version number whenever the\n// LandmarkManagerApi or Landmark interfaces change.\nconst LANDMARK_API_VERSION = 1;\n\n// Minimal API for LandmarkManager that must continue to work between versions.\n// Changes to this interface are considered breaking. New methods/properties are\n// safe to add, but changes or removals are not allowed (same as public APIs).\ninterface LandmarkManagerApi {\n version: number,\n createLandmarkController(): LandmarkController,\n registerLandmark(landmark: Landmark): () => void\n}\n\n// Changes to this interface are considered breaking.\n// New properties MUST be optional so that registering a landmark\n// from an older version of useLandmark against a newer version of\n// LandmarkManager does not crash.\ninterface Landmark {\n ref: RefObject<FocusableElement>,\n role: AriaLandmarkRole,\n label?: string,\n lastFocused?: FocusableElement,\n focus: (direction: 'forward' | 'backward') => void,\n blur: () => void\n}\n\nexport interface LandmarkControllerOptions {\n /**\n * The element from which to start navigating.\n * @default document.activeElement\n */\n from?: FocusableElement\n}\n\n/** A LandmarkController allows programmatic navigation of landmarks. */\nexport interface LandmarkController {\n /** Moves focus to the next landmark. */\n focusNext(opts?: LandmarkControllerOptions): boolean,\n /** Moves focus to the previous landmark. */\n focusPrevious(opts?: LandmarkControllerOptions): boolean,\n /** Moves focus to the main landmark. */\n focusMain(): boolean,\n /** Moves focus either forward or backward in the landmark sequence. */\n navigate(direction: 'forward' | 'backward', opts?: LandmarkControllerOptions): boolean,\n /**\n * Disposes the landmark controller. When no landmarks are registered, and no\n * controllers are active, the landmark keyboard listeners are removed from the page.\n */\n dispose(): void\n}\n\n// Symbol under which the singleton landmark manager instance is attached to the document.\nconst landmarkSymbol = Symbol.for('react-aria-landmark-manager');\n\nfunction subscribe(fn: () => void) {\n document.addEventListener('react-aria-landmark-manager-change', fn);\n return () => document.removeEventListener('react-aria-landmark-manager-change', fn);\n}\n\nfunction getLandmarkManager(): LandmarkManagerApi | null {\n if (typeof document === 'undefined') {\n return null;\n }\n\n // Reuse an existing instance if it has the same or greater version.\n let instance = document[landmarkSymbol];\n if (instance && instance.version >= LANDMARK_API_VERSION) {\n return instance;\n }\n\n // Otherwise, create a new instance and dispatch an event so anything using the existing\n // instance updates and re-registers their landmarks with the new one.\n document[landmarkSymbol] = new LandmarkManager();\n document.dispatchEvent(new CustomEvent('react-aria-landmark-manager-change'));\n return document[landmarkSymbol];\n}\n\n// Subscribes a React component to the current landmark manager instance.\nfunction useLandmarkManager(): LandmarkManagerApi | null {\n return useSyncExternalStore(subscribe, getLandmarkManager, getLandmarkManager);\n}\n\nclass LandmarkManager implements LandmarkManagerApi {\n private landmarks: Array<Landmark> = [];\n private isListening = false;\n private refCount = 0;\n public version = LANDMARK_API_VERSION;\n\n constructor() {\n this.f6Handler = this.f6Handler.bind(this);\n this.focusinHandler = this.focusinHandler.bind(this);\n this.focusoutHandler = this.focusoutHandler.bind(this);\n }\n\n private setupIfNeeded() {\n if (this.isListening) {\n return;\n }\n document.addEventListener('keydown', this.f6Handler, {capture: true});\n document.addEventListener('focusin', this.focusinHandler, {capture: true});\n document.addEventListener('focusout', this.focusoutHandler, {capture: true});\n this.isListening = true;\n }\n\n private teardownIfNeeded() {\n if (!this.isListening || this.landmarks.length > 0 || this.refCount > 0) {\n return;\n }\n document.removeEventListener('keydown', this.f6Handler, {capture: true});\n document.removeEventListener('focusin', this.focusinHandler, {capture: true});\n document.removeEventListener('focusout', this.focusoutHandler, {capture: true});\n this.isListening = false;\n }\n\n private focusLandmark(landmark: FocusableElement, direction: 'forward' | 'backward') {\n this.landmarks.find(l => l.ref.current === landmark)?.focus?.(direction);\n }\n\n /**\n * Return set of landmarks with a specific role.\n */\n private getLandmarksByRole(role: AriaLandmarkRole) {\n return new Set(this.landmarks.filter(l => l.role === role));\n }\n\n /**\n * Return first landmark with a specific role.\n */\n private getLandmarkByRole(role: AriaLandmarkRole) {\n return this.landmarks.find(l => l.role === role);\n }\n\n private addLandmark(newLandmark: Landmark) {\n this.setupIfNeeded();\n if (this.landmarks.find(landmark => landmark.ref === newLandmark.ref) || !newLandmark.ref.current) {\n return;\n }\n\n if (this.landmarks.filter(landmark => landmark.role === 'main').length > 1) {\n console.error('Page can contain no more than one landmark with the role \"main\".');\n }\n\n if (this.landmarks.length === 0) {\n this.landmarks = [newLandmark];\n this.checkLabels(newLandmark.role);\n return;\n }\n\n\n // Binary search to insert new landmark based on position in document relative to existing landmarks.\n // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition\n let start = 0;\n let end = this.landmarks.length - 1;\n while (start <= end) {\n let mid = Math.floor((start + end) / 2);\n let comparedPosition = newLandmark.ref.current.compareDocumentPosition(this.landmarks[mid].ref.current as Node);\n let isNewAfterExisting = Boolean((comparedPosition & Node.DOCUMENT_POSITION_PRECEDING) || (comparedPosition & Node.DOCUMENT_POSITION_CONTAINS));\n\n if (isNewAfterExisting) {\n start = mid + 1;\n } else {\n end = mid - 1;\n }\n }\n\n this.landmarks.splice(start, 0, newLandmark);\n this.checkLabels(newLandmark.role);\n }\n\n private updateLandmark(landmark: Pick<Landmark, 'ref'> & Partial<Landmark>) {\n let index = this.landmarks.findIndex(l => l.ref === landmark.ref);\n if (index >= 0) {\n this.landmarks[index] = {...this.landmarks[index], ...landmark};\n this.checkLabels(this.landmarks[index].role);\n }\n }\n\n private removeLandmark(ref: RefObject<Element>) {\n this.landmarks = this.landmarks.filter(landmark => landmark.ref !== ref);\n this.teardownIfNeeded();\n }\n\n /**\n * Warn if there are 2+ landmarks with the same role but no label.\n * Labels for landmarks with the same role must also be unique.\n *\n * See https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/.\n */\n private checkLabels(role: AriaLandmarkRole) {\n let landmarksWithRole = this.getLandmarksByRole(role);\n if (landmarksWithRole.size > 1) {\n let duplicatesWithoutLabel = [...landmarksWithRole].filter(landmark => !landmark.label);\n if (duplicatesWithoutLabel.length > 0) {\n console.warn(\n `Page contains more than one landmark with the '${role}' role. If two or more landmarks on a page share the same role, all must be labeled with an aria-label or aria-labelledby attribute: `,\n duplicatesWithoutLabel.map(landmark => landmark.ref.current)\n );\n } else {\n let labels = [...landmarksWithRole].map(landmark => landmark.label);\n let duplicateLabels = labels.filter((item, index) => labels.indexOf(item) !== index);\n\n duplicateLabels.forEach((label) => {\n console.warn(\n `Page contains more than one landmark with the '${role}' role and '${label}' label. If two or more landmarks on a page share the same role, they must have unique labels: `,\n [...landmarksWithRole].filter(landmark => landmark.label === label).map(landmark => landmark.ref.current)\n );\n });\n }\n }\n }\n\n /**\n * Get the landmark that is the closest parent in the DOM.\n * Returns undefined if no parent is a landmark.\n */\n private closestLandmark(element: FocusableElement) {\n let landmarkMap = new Map(this.landmarks.map(l => [l.ref.current, l]));\n let currentElement = element;\n while (currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body && currentElement.parentElement) {\n currentElement = currentElement.parentElement;\n }\n return landmarkMap.get(currentElement);\n }\n\n /**\n * Gets the next landmark, in DOM focus order, or previous if backwards is specified.\n * If last landmark, next should be the first landmark.\n * If not inside a landmark, will return first landmark.\n * Returns undefined if there are no landmarks.\n */\n private getNextLandmark(element: FocusableElement, {backward}: {backward?: boolean }) {\n let currentLandmark = this.closestLandmark(element);\n let nextLandmarkIndex = backward ? this.landmarks.length - 1 : 0;\n if (currentLandmark) {\n nextLandmarkIndex = this.landmarks.indexOf(currentLandmark) + (backward ? -1 : 1);\n }\n\n let wrapIfNeeded = () => {\n // When we reach the end of the landmark sequence, fire a custom event that can be listened for by applications.\n // If this event is canceled, we return immediately. This can be used to implement landmark navigation across iframes.\n if (nextLandmarkIndex < 0) {\n if (!element.dispatchEvent(new CustomEvent('react-aria-landmark-navigation', {detail: {direction: 'backward'}, bubbles: true, cancelable: true}))) {\n return true;\n }\n\n nextLandmarkIndex = this.landmarks.length - 1;\n } else if (nextLandmarkIndex >= this.landmarks.length) {\n if (!element.dispatchEvent(new CustomEvent('react-aria-landmark-navigation', {detail: {direction: 'forward'}, bubbles: true, cancelable: true}))) {\n return true;\n }\n\n nextLandmarkIndex = 0;\n }\n\n if (nextLandmarkIndex < 0 || nextLandmarkIndex >= this.landmarks.length) {\n return true;\n }\n\n return false;\n };\n\n if (wrapIfNeeded()) {\n return undefined;\n }\n\n // Skip over hidden landmarks.\n let i = nextLandmarkIndex;\n while (this.landmarks[nextLandmarkIndex].ref.current?.closest('[aria-hidden=true]')) {\n nextLandmarkIndex += backward ? -1 : 1;\n if (wrapIfNeeded()) {\n return undefined;\n }\n\n if (nextLandmarkIndex === i) {\n break;\n }\n }\n\n return this.landmarks[nextLandmarkIndex];\n }\n\n /**\n * Look at next landmark. If an element was previously focused inside, restore focus there.\n * If not, focus the landmark itself.\n * If no landmarks at all, or none with focusable elements, don't move focus.\n */\n private f6Handler(e: KeyboardEvent) {\n if (e.key === 'F6') {\n // If alt key pressed, focus main landmark, otherwise navigate forward or backward based on shift key.\n let handled = e.altKey ? this.focusMain() : this.navigate(e.target as FocusableElement, e.shiftKey);\n if (handled) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n }\n\n private focusMain() {\n let main = this.getLandmarkByRole('main');\n if (main && main.ref.current && document.contains(main.ref.current)) {\n this.focusLandmark(main.ref.current, 'forward');\n return true;\n }\n\n return false;\n }\n\n private navigate(from: FocusableElement, backward: boolean) {\n let nextLandmark = this.getNextLandmark(from, {\n backward\n });\n\n if (!nextLandmark) {\n return false;\n }\n\n // If something was previously focused in the next landmark, then return focus to it\n if (nextLandmark.lastFocused) {\n let lastFocused = nextLandmark.lastFocused;\n if (document.body.contains(lastFocused)) {\n lastFocused.focus();\n return true;\n }\n }\n\n // Otherwise, focus the landmark itself\n if (nextLandmark.ref.current && document.contains(nextLandmark.ref.current)) {\n this.focusLandmark(nextLandmark.ref.current, backward ? 'backward' : 'forward');\n return true;\n }\n\n return false;\n }\n\n /**\n * Sets lastFocused for a landmark, if focus is moved within that landmark.\n * Lets the last focused landmark know it was blurred if something else is focused.\n */\n private focusinHandler(e: FocusEvent) {\n let currentLandmark = this.closestLandmark(e.target as FocusableElement);\n if (currentLandmark && currentLandmark.ref.current !== e.target) {\n this.updateLandmark({ref: currentLandmark.ref, lastFocused: e.target as FocusableElement});\n }\n let previousFocusedElement = e.relatedTarget as FocusableElement;\n if (previousFocusedElement) {\n let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);\n if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {\n closestPreviousLandmark.blur();\n }\n }\n }\n\n /**\n * Track if the focus is lost to the body. If it is, do cleanup on the landmark that last had focus.\n */\n private focusoutHandler(e: FocusEvent) {\n let previousFocusedElement = e.target as FocusableElement;\n let nextFocusedElement = e.relatedTarget;\n // the === document seems to be a jest thing for focus to go there on generic blur event such as landmark.blur();\n // browsers appear to send focus instead to document.body and the relatedTarget is null when that happens\n if (!nextFocusedElement || nextFocusedElement === document) {\n let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);\n if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {\n closestPreviousLandmark.blur();\n }\n }\n }\n\n public createLandmarkController(): LandmarkController {\n let instance: LandmarkManager | null = this;\n instance.refCount++;\n instance.setupIfNeeded();\n return {\n navigate(direction, opts) {\n let element = opts?.from || (document!.activeElement as FocusableElement);\n return instance!.navigate(element, direction === 'backward');\n },\n focusNext(opts) {\n let element = opts?.from || (document!.activeElement as FocusableElement);\n return instance!.navigate(element, false);\n },\n focusPrevious(opts) {\n let element = opts?.from || (document!.activeElement as FocusableElement);\n return instance!.navigate(element, true);\n },\n focusMain() {\n return instance!.focusMain();\n },\n dispose() {\n if (instance) {\n instance.refCount--;\n instance.teardownIfNeeded();\n instance = null;\n }\n }\n };\n }\n\n public registerLandmark(landmark: Landmark): () => void {\n if (this.landmarks.find(l => l.ref === landmark.ref)) {\n this.updateLandmark(landmark);\n } else {\n this.addLandmark(landmark);\n }\n\n return () => this.removeLandmark(landmark.ref);\n }\n}\n\n/** Creates a LandmarkController, which allows programmatic navigation of landmarks. */\nexport function createLandmarkController(): LandmarkController {\n // Get the current landmark manager and create a controller using it.\n let instance: LandmarkManagerApi | null = getLandmarkManager();\n let controller = instance?.createLandmarkController();\n\n let unsubscribe = subscribe(() => {\n // If the landmark manager changes, dispose the old\n // controller and create a new one.\n controller?.dispose();\n instance = getLandmarkManager();\n controller = instance?.createLandmarkController();\n });\n\n // Return a wrapper that proxies requests to the current controller instance.\n return {\n navigate(direction, opts) {\n return controller!.navigate(direction, opts);\n },\n focusNext(opts) {\n return controller!.focusNext(opts);\n },\n focusPrevious(opts) {\n return controller!.focusPrevious(opts);\n },\n focusMain() {\n return controller!.focusMain();\n },\n dispose() {\n controller?.dispose();\n unsubscribe();\n controller = undefined;\n instance = null;\n }\n };\n}\n\n/**\n * Provides landmark navigation in an application. Call this with a role and label to register a landmark navigable with F6.\n * @param props - Props for the landmark.\n * @param ref - Ref to the landmark.\n */\nexport function useLandmark(props: AriaLandmarkProps, ref: RefObject<FocusableElement>): LandmarkAria {\n const {\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n focus\n } = props;\n let manager = useLandmarkManager();\n let label = ariaLabel || ariaLabelledby;\n let [isLandmarkFocused, setIsLandmarkFocused] = useState(false);\n\n let defaultFocus = useCallback(() => {\n setIsLandmarkFocused(true);\n }, [setIsLandmarkFocused]);\n\n let blur = useCallback(() => {\n setIsLandmarkFocused(false);\n }, [setIsLandmarkFocused]);\n\n useLayoutEffect(() => {\n if (manager) {\n return manager.registerLandmark({ref, label, role, focus: focus || defaultFocus, blur});\n }\n }, [manager, label, ref, role, focus, defaultFocus, blur]);\n\n useEffect(() => {\n if (isLandmarkFocused) {\n ref.current?.focus();\n }\n }, [isLandmarkFocused, ref]);\n\n return {\n landmarkProps: {\n role,\n tabIndex: isLandmarkFocused ? -1 : undefined,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby\n }\n };\n}\n"],"names":[],"version":3,"file":"main.js.map"}
package/dist/module.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import $TvsbU$swchelperssrc_define_propertymjs from "@swc/helpers/src/_define_property.mjs";
2
2
  import {useState as $TvsbU$useState, useCallback as $TvsbU$useCallback, useEffect as $TvsbU$useEffect} from "react";
3
3
  import {useLayoutEffect as $TvsbU$useLayoutEffect} from "@react-aria/utils";
4
- import {useSyncExternalStore as $TvsbU$useSyncExternalStore} from "use-sync-external-store/shim";
4
+ import {useSyncExternalStore as $TvsbU$useSyncExternalStore} from "use-sync-external-store/shim/index.js";
5
5
 
6
6
  /*
7
7
  * Copyright 2022 Adobe. All rights reserved.
@@ -37,6 +37,7 @@ function $a86207c5d7f7e1fb$var$subscribe(fn) {
37
37
  return ()=>document.removeEventListener("react-aria-landmark-manager-change", fn);
38
38
  }
39
39
  function $a86207c5d7f7e1fb$var$getLandmarkManager() {
40
+ if (typeof document === "undefined") return null;
40
41
  // Reuse an existing instance if it has the same or greater version.
41
42
  let instance = document[$a86207c5d7f7e1fb$var$landmarkSymbol];
42
43
  if (instance && instance.version >= $a86207c5d7f7e1fb$var$LANDMARK_API_VERSION) return instance;
@@ -48,7 +49,7 @@ function $a86207c5d7f7e1fb$var$getLandmarkManager() {
48
49
  }
49
50
  // Subscribes a React component to the current landmark manager instance.
50
51
  function $a86207c5d7f7e1fb$var$useLandmarkManager() {
51
- return (0, $TvsbU$useSyncExternalStore)($a86207c5d7f7e1fb$var$subscribe, $a86207c5d7f7e1fb$var$getLandmarkManager);
52
+ return (0, $TvsbU$useSyncExternalStore)($a86207c5d7f7e1fb$var$subscribe, $a86207c5d7f7e1fb$var$getLandmarkManager, $a86207c5d7f7e1fb$var$getLandmarkManager);
52
53
  }
53
54
  class $a86207c5d7f7e1fb$var$LandmarkManager {
54
55
  setupIfNeeded() {
@@ -78,8 +79,8 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
78
79
  this.isListening = false;
79
80
  }
80
81
  focusLandmark(landmark, direction) {
81
- var _this_landmarks_find;
82
- (_this_landmarks_find = this.landmarks.find((l)=>l.ref.current === landmark)) === null || _this_landmarks_find === void 0 ? void 0 : _this_landmarks_find.focus(direction);
82
+ var _this_landmarks_find, _this_landmarks_find_focus;
83
+ (_this_landmarks_find = this.landmarks.find((l)=>l.ref.current === landmark)) === null || _this_landmarks_find === void 0 ? void 0 : (_this_landmarks_find_focus = _this_landmarks_find.focus) === null || _this_landmarks_find_focus === void 0 ? void 0 : _this_landmarks_find_focus.call(_this_landmarks_find, direction);
83
84
  }
84
85
  /**
85
86
  * Return set of landmarks with a specific role.
@@ -93,7 +94,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
93
94
  }
94
95
  addLandmark(newLandmark) {
95
96
  this.setupIfNeeded();
96
- if (this.landmarks.find((landmark)=>landmark.ref === newLandmark.ref)) return;
97
+ if (this.landmarks.find((landmark)=>landmark.ref === newLandmark.ref) || !newLandmark.ref.current) return;
97
98
  if (this.landmarks.filter((landmark)=>landmark.role === "main").length > 1) console.error('Page can contain no more than one landmark with the role "main".');
98
99
  if (this.landmarks.length === 0) {
99
100
  this.landmarks = [
@@ -164,7 +165,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
164
165
  l
165
166
  ]));
166
167
  let currentElement = element;
167
- while(currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body)currentElement = currentElement.parentElement;
168
+ while(currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body && currentElement.parentElement)currentElement = currentElement.parentElement;
168
169
  return landmarkMap.get(currentElement);
169
170
  }
170
171
  /**
@@ -173,6 +174,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
173
174
  * If not inside a landmark, will return first landmark.
174
175
  * Returns undefined if there are no landmarks.
175
176
  */ getNextLandmark(element, { backward: backward }) {
177
+ var _this_landmarks_nextLandmarkIndex_ref_current;
176
178
  let currentLandmark = this.closestLandmark(element);
177
179
  let nextLandmarkIndex = backward ? this.landmarks.length - 1 : 0;
178
180
  if (currentLandmark) nextLandmarkIndex = this.landmarks.indexOf(currentLandmark) + (backward ? -1 : 1);
@@ -204,7 +206,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
204
206
  if (wrapIfNeeded()) return undefined;
205
207
  // Skip over hidden landmarks.
206
208
  let i = nextLandmarkIndex;
207
- while(this.landmarks[nextLandmarkIndex].ref.current.closest("[aria-hidden=true]")){
209
+ while((_this_landmarks_nextLandmarkIndex_ref_current = this.landmarks[nextLandmarkIndex].ref.current) === null || _this_landmarks_nextLandmarkIndex_ref_current === void 0 ? void 0 : _this_landmarks_nextLandmarkIndex_ref_current.closest("[aria-hidden=true]")){
208
210
  nextLandmarkIndex += backward ? -1 : 1;
209
211
  if (wrapIfNeeded()) return undefined;
210
212
  if (nextLandmarkIndex === i) break;
@@ -227,7 +229,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
227
229
  }
228
230
  focusMain() {
229
231
  let main = this.getLandmarkByRole("main");
230
- if (main && document.contains(main.ref.current)) {
232
+ if (main && main.ref.current && document.contains(main.ref.current)) {
231
233
  this.focusLandmark(main.ref.current, "forward");
232
234
  return true;
233
235
  }
@@ -247,7 +249,7 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
247
249
  }
248
250
  }
249
251
  // Otherwise, focus the landmark itself
250
- if (document.contains(nextLandmark.ref.current)) {
252
+ if (nextLandmark.ref.current && document.contains(nextLandmark.ref.current)) {
251
253
  this.focusLandmark(nextLandmark.ref.current, backward ? "backward" : "forward");
252
254
  return true;
253
255
  }
@@ -286,21 +288,26 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
286
288
  instance.setupIfNeeded();
287
289
  return {
288
290
  navigate (direction, opts) {
289
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, direction === "backward");
291
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
292
+ return instance.navigate(element, direction === "backward");
290
293
  },
291
294
  focusNext (opts) {
292
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, false);
295
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
296
+ return instance.navigate(element, false);
293
297
  },
294
298
  focusPrevious (opts) {
295
- return instance.navigate((opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement, true);
299
+ let element = (opts === null || opts === void 0 ? void 0 : opts.from) || document.activeElement;
300
+ return instance.navigate(element, true);
296
301
  },
297
302
  focusMain () {
298
303
  return instance.focusMain();
299
304
  },
300
305
  dispose () {
301
- instance.refCount--;
302
- instance.teardownIfNeeded();
303
- instance = null;
306
+ if (instance) {
307
+ instance.refCount--;
308
+ instance.teardownIfNeeded();
309
+ instance = null;
310
+ }
304
311
  }
305
312
  };
306
313
  }
@@ -322,13 +329,13 @@ class $a86207c5d7f7e1fb$var$LandmarkManager {
322
329
  function $a86207c5d7f7e1fb$export$f50151dbd51cd1d9() {
323
330
  // Get the current landmark manager and create a controller using it.
324
331
  let instance = $a86207c5d7f7e1fb$var$getLandmarkManager();
325
- let controller = instance.createLandmarkController();
332
+ let controller = instance === null || instance === void 0 ? void 0 : instance.createLandmarkController();
326
333
  let unsubscribe = $a86207c5d7f7e1fb$var$subscribe(()=>{
327
334
  // If the landmark manager changes, dispose the old
328
335
  // controller and create a new one.
329
- controller.dispose();
336
+ controller === null || controller === void 0 ? void 0 : controller.dispose();
330
337
  instance = $a86207c5d7f7e1fb$var$getLandmarkManager();
331
- controller = instance.createLandmarkController();
338
+ controller = instance === null || instance === void 0 ? void 0 : instance.createLandmarkController();
332
339
  });
333
340
  // Return a wrapper that proxies requests to the current controller instance.
334
341
  return {
@@ -345,9 +352,9 @@ function $a86207c5d7f7e1fb$export$f50151dbd51cd1d9() {
345
352
  return controller.focusMain();
346
353
  },
347
354
  dispose () {
348
- controller.dispose();
355
+ controller === null || controller === void 0 ? void 0 : controller.dispose();
349
356
  unsubscribe();
350
- controller = null;
357
+ controller = undefined;
351
358
  instance = null;
352
359
  }
353
360
  };
@@ -368,7 +375,7 @@ function $a86207c5d7f7e1fb$export$4cc632584fd87fae(props, ref) {
368
375
  setIsLandmarkFocused
369
376
  ]);
370
377
  (0, $TvsbU$useLayoutEffect)(()=>{
371
- return manager.registerLandmark({
378
+ if (manager) return manager.registerLandmark({
372
379
  ref: ref,
373
380
  label: label,
374
381
  role: role,
@@ -385,7 +392,8 @@ function $a86207c5d7f7e1fb$export$4cc632584fd87fae(props, ref) {
385
392
  blur
386
393
  ]);
387
394
  (0, $TvsbU$useEffect)(()=>{
388
- if (isLandmarkFocused) ref.current.focus();
395
+ var _ref_current;
396
+ if (isLandmarkFocused) (_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.focus();
389
397
  }, [
390
398
  isLandmarkFocused,
391
399
  ref
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/@react-aria/landmark/src/index.ts","packages/@react-aria/landmark/src/useLandmark.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport type {AriaLandmarkRole, AriaLandmarkProps, LandmarkAria, LandmarkController} from './useLandmark';\nexport {useLandmark, createLandmarkController} from './useLandmark';\n","/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaLabelingProps, DOMAttributes, FocusableElement} from '@react-types/shared';\nimport {MutableRefObject, useCallback, useEffect, useState} from 'react';\nimport {useLayoutEffect} from '@react-aria/utils';\nimport {useSyncExternalStore} from 'use-sync-external-store/shim';\n\nexport type AriaLandmarkRole = 'main' | 'region' | 'search' | 'navigation' | 'form' | 'banner' | 'contentinfo' | 'complementary';\n\nexport interface AriaLandmarkProps extends AriaLabelingProps {\n role: AriaLandmarkRole,\n focus?: (direction: 'forward' | 'backward') => void\n}\n\nexport interface LandmarkAria {\n landmarkProps: DOMAttributes\n}\n\n// Increment this version number whenever the\n// LandmarkManagerApi or Landmark interfaces change.\nconst LANDMARK_API_VERSION = 1;\n\n// Minimal API for LandmarkManager that must continue to work between versions.\n// Changes to this interface are considered breaking. New methods/properties are\n// safe to add, but changes or removals are not allowed (same as public APIs).\ninterface LandmarkManagerApi {\n version: number,\n createLandmarkController(): LandmarkController,\n registerLandmark(landmark: Landmark): () => void\n}\n\n// Changes to this interface are considered breaking.\n// New properties MUST be optional so that registering a landmark\n// from an older version of useLandmark against a newer version of\n// LandmarkManager does not crash.\ninterface Landmark {\n ref: MutableRefObject<Element>,\n role: AriaLandmarkRole,\n label?: string,\n lastFocused?: FocusableElement,\n focus: (direction: 'forward' | 'backward') => void,\n blur: () => void\n}\n\nexport interface LandmarkControllerOptions {\n /**\n * The element from which to start navigating.\n * @default document.activeElement\n */\n from?: Element\n}\n\n/** A LandmarkController allows programmatic navigation of landmarks. */\nexport interface LandmarkController {\n /** Moves focus to the next landmark. */\n focusNext(opts?: LandmarkControllerOptions): boolean,\n /** Moves focus to the previous landmark. */\n focusPrevious(opts?: LandmarkControllerOptions): boolean,\n /** Moves focus to the main landmark. */\n focusMain(): boolean,\n /** Moves focus either forward or backward in the landmark sequence. */\n navigate(direction: 'forward' | 'backward', opts?: LandmarkControllerOptions): boolean,\n /**\n * Disposes the landmark controller. When no landmarks are registered, and no\n * controllers are active, the landmark keyboard listeners are removed from the page.\n */\n dispose(): void\n}\n\n// Symbol under which the singleton landmark manager instance is attached to the document.\nconst landmarkSymbol = Symbol.for('react-aria-landmark-manager');\n\nfunction subscribe(fn: () => void) {\n document.addEventListener('react-aria-landmark-manager-change', fn);\n return () => document.removeEventListener('react-aria-landmark-manager-change', fn);\n}\n\nfunction getLandmarkManager(): LandmarkManagerApi {\n // Reuse an existing instance if it has the same or greater version.\n let instance = document[landmarkSymbol];\n if (instance && instance.version >= LANDMARK_API_VERSION) {\n return instance;\n }\n\n // Otherwise, create a new instance and dispatch an event so anything using the existing\n // instance updates and re-registers their landmarks with the new one.\n document[landmarkSymbol] = new LandmarkManager();\n document.dispatchEvent(new CustomEvent('react-aria-landmark-manager-change'));\n return document[landmarkSymbol];\n}\n\n// Subscribes a React component to the current landmark manager instance.\nfunction useLandmarkManager(): LandmarkManagerApi {\n return useSyncExternalStore(subscribe, getLandmarkManager);\n}\n\nclass LandmarkManager implements LandmarkManagerApi {\n private landmarks: Array<Landmark> = [];\n private isListening = false;\n private refCount = 0;\n public version = LANDMARK_API_VERSION;\n\n constructor() {\n this.f6Handler = this.f6Handler.bind(this);\n this.focusinHandler = this.focusinHandler.bind(this);\n this.focusoutHandler = this.focusoutHandler.bind(this);\n }\n\n private setupIfNeeded() {\n if (this.isListening) {\n return;\n }\n document.addEventListener('keydown', this.f6Handler, {capture: true});\n document.addEventListener('focusin', this.focusinHandler, {capture: true});\n document.addEventListener('focusout', this.focusoutHandler, {capture: true});\n this.isListening = true;\n }\n\n private teardownIfNeeded() {\n if (!this.isListening || this.landmarks.length > 0 || this.refCount > 0) {\n return;\n }\n document.removeEventListener('keydown', this.f6Handler, {capture: true});\n document.removeEventListener('focusin', this.focusinHandler, {capture: true});\n document.removeEventListener('focusout', this.focusoutHandler, {capture: true});\n this.isListening = false;\n }\n\n private focusLandmark(landmark: Element, direction: 'forward' | 'backward') {\n this.landmarks.find(l => l.ref.current === landmark)?.focus(direction);\n }\n\n /**\n * Return set of landmarks with a specific role.\n */\n private getLandmarksByRole(role: AriaLandmarkRole) {\n return new Set(this.landmarks.filter(l => l.role === role));\n }\n\n /**\n * Return first landmark with a specific role.\n */\n private getLandmarkByRole(role: AriaLandmarkRole) {\n return this.landmarks.find(l => l.role === role);\n }\n\n private addLandmark(newLandmark: Landmark) {\n this.setupIfNeeded();\n if (this.landmarks.find(landmark => landmark.ref === newLandmark.ref)) {\n return;\n }\n\n if (this.landmarks.filter(landmark => landmark.role === 'main').length > 1) {\n console.error('Page can contain no more than one landmark with the role \"main\".');\n }\n\n if (this.landmarks.length === 0) {\n this.landmarks = [newLandmark];\n this.checkLabels(newLandmark.role);\n return;\n }\n\n\n // Binary search to insert new landmark based on position in document relative to existing landmarks.\n // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition\n let start = 0;\n let end = this.landmarks.length - 1;\n while (start <= end) {\n let mid = Math.floor((start + end) / 2);\n let comparedPosition = newLandmark.ref.current.compareDocumentPosition(this.landmarks[mid].ref.current as Node);\n let isNewAfterExisting = Boolean((comparedPosition & Node.DOCUMENT_POSITION_PRECEDING) || (comparedPosition & Node.DOCUMENT_POSITION_CONTAINS));\n\n if (isNewAfterExisting) {\n start = mid + 1;\n } else {\n end = mid - 1;\n }\n }\n\n this.landmarks.splice(start, 0, newLandmark);\n this.checkLabels(newLandmark.role);\n }\n\n private updateLandmark(landmark: Pick<Landmark, 'ref'> & Partial<Landmark>) {\n let index = this.landmarks.findIndex(l => l.ref === landmark.ref);\n if (index >= 0) {\n this.landmarks[index] = {...this.landmarks[index], ...landmark};\n this.checkLabels(this.landmarks[index].role);\n }\n }\n\n private removeLandmark(ref: MutableRefObject<Element>) {\n this.landmarks = this.landmarks.filter(landmark => landmark.ref !== ref);\n this.teardownIfNeeded();\n }\n\n /**\n * Warn if there are 2+ landmarks with the same role but no label.\n * Labels for landmarks with the same role must also be unique.\n *\n * See https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/.\n */\n private checkLabels(role: AriaLandmarkRole) {\n let landmarksWithRole = this.getLandmarksByRole(role);\n if (landmarksWithRole.size > 1) {\n let duplicatesWithoutLabel = [...landmarksWithRole].filter(landmark => !landmark.label);\n if (duplicatesWithoutLabel.length > 0) {\n console.warn(\n `Page contains more than one landmark with the '${role}' role. If two or more landmarks on a page share the same role, all must be labeled with an aria-label or aria-labelledby attribute: `,\n duplicatesWithoutLabel.map(landmark => landmark.ref.current)\n );\n } else {\n let labels = [...landmarksWithRole].map(landmark => landmark.label);\n let duplicateLabels = labels.filter((item, index) => labels.indexOf(item) !== index);\n\n duplicateLabels.forEach((label) => {\n console.warn(\n `Page contains more than one landmark with the '${role}' role and '${label}' label. If two or more landmarks on a page share the same role, they must have unique labels: `,\n [...landmarksWithRole].filter(landmark => landmark.label === label).map(landmark => landmark.ref.current)\n );\n });\n }\n }\n }\n\n /**\n * Get the landmark that is the closest parent in the DOM.\n * Returns undefined if no parent is a landmark.\n */\n private closestLandmark(element: Element) {\n let landmarkMap = new Map(this.landmarks.map(l => [l.ref.current, l]));\n let currentElement = element;\n while (currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body) {\n currentElement = currentElement.parentElement;\n }\n return landmarkMap.get(currentElement);\n }\n\n /**\n * Gets the next landmark, in DOM focus order, or previous if backwards is specified.\n * If last landmark, next should be the first landmark.\n * If not inside a landmark, will return first landmark.\n * Returns undefined if there are no landmarks.\n */\n private getNextLandmark(element: Element, {backward}: {backward?: boolean }) {\n let currentLandmark = this.closestLandmark(element);\n let nextLandmarkIndex = backward ? this.landmarks.length - 1 : 0;\n if (currentLandmark) {\n nextLandmarkIndex = this.landmarks.indexOf(currentLandmark) + (backward ? -1 : 1);\n }\n\n let wrapIfNeeded = () => {\n // When we reach the end of the landmark sequence, fire a custom event that can be listened for by applications.\n // If this event is canceled, we return immediately. This can be used to implement landmark navigation across iframes.\n if (nextLandmarkIndex < 0) {\n if (!element.dispatchEvent(new CustomEvent('react-aria-landmark-navigation', {detail: {direction: 'backward'}, bubbles: true, cancelable: true}))) {\n return true;\n }\n\n nextLandmarkIndex = this.landmarks.length - 1;\n } else if (nextLandmarkIndex >= this.landmarks.length) {\n if (!element.dispatchEvent(new CustomEvent('react-aria-landmark-navigation', {detail: {direction: 'forward'}, bubbles: true, cancelable: true}))) {\n return true;\n }\n\n nextLandmarkIndex = 0;\n }\n\n if (nextLandmarkIndex < 0 || nextLandmarkIndex >= this.landmarks.length) {\n return true;\n }\n\n return false;\n };\n\n if (wrapIfNeeded()) {\n return undefined;\n }\n\n // Skip over hidden landmarks.\n let i = nextLandmarkIndex;\n while (this.landmarks[nextLandmarkIndex].ref.current.closest('[aria-hidden=true]')) {\n nextLandmarkIndex += backward ? -1 : 1;\n if (wrapIfNeeded()) {\n return undefined;\n }\n\n if (nextLandmarkIndex === i) {\n break;\n }\n }\n\n return this.landmarks[nextLandmarkIndex];\n }\n\n /**\n * Look at next landmark. If an element was previously focused inside, restore focus there.\n * If not, focus the landmark itself.\n * If no landmarks at all, or none with focusable elements, don't move focus.\n */\n private f6Handler(e: KeyboardEvent) {\n if (e.key === 'F6') {\n // If alt key pressed, focus main landmark, otherwise navigate forward or backward based on shift key.\n let handled = e.altKey ? this.focusMain() : this.navigate(e.target as Element, e.shiftKey);\n if (handled) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n }\n\n private focusMain() {\n let main = this.getLandmarkByRole('main');\n if (main && document.contains(main.ref.current)) {\n this.focusLandmark(main.ref.current, 'forward');\n return true;\n }\n\n return false;\n }\n\n private navigate(from: Element, backward: boolean) {\n let nextLandmark = this.getNextLandmark(from, {\n backward\n });\n\n if (!nextLandmark) {\n return false;\n }\n\n // If something was previously focused in the next landmark, then return focus to it\n if (nextLandmark.lastFocused) {\n let lastFocused = nextLandmark.lastFocused;\n if (document.body.contains(lastFocused)) {\n lastFocused.focus();\n return true;\n }\n }\n\n // Otherwise, focus the landmark itself\n if (document.contains(nextLandmark.ref.current)) {\n this.focusLandmark(nextLandmark.ref.current, backward ? 'backward' : 'forward');\n return true;\n }\n\n return false;\n }\n\n /**\n * Sets lastFocused for a landmark, if focus is moved within that landmark.\n * Lets the last focused landmark know it was blurred if something else is focused.\n */\n private focusinHandler(e: FocusEvent) {\n let currentLandmark = this.closestLandmark(e.target as Element);\n if (currentLandmark && currentLandmark.ref.current !== e.target) {\n this.updateLandmark({ref: currentLandmark.ref, lastFocused: e.target as FocusableElement});\n }\n let previousFocusedElement = e.relatedTarget as Element;\n if (previousFocusedElement) {\n let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);\n if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {\n closestPreviousLandmark.blur();\n }\n }\n }\n\n /**\n * Track if the focus is lost to the body. If it is, do cleanup on the landmark that last had focus.\n */\n private focusoutHandler(e: FocusEvent) {\n let previousFocusedElement = e.target as Element;\n let nextFocusedElement = e.relatedTarget;\n // the === document seems to be a jest thing for focus to go there on generic blur event such as landmark.blur();\n // browsers appear to send focus instead to document.body and the relatedTarget is null when that happens\n if (!nextFocusedElement || nextFocusedElement === document) {\n let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);\n if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {\n closestPreviousLandmark.blur();\n }\n }\n }\n\n public createLandmarkController(): LandmarkController {\n let instance = this;\n instance.refCount++;\n instance.setupIfNeeded();\n return {\n navigate(direction, opts) {\n return instance.navigate(opts?.from || document.activeElement, direction === 'backward');\n },\n focusNext(opts) {\n return instance.navigate(opts?.from || document.activeElement, false);\n },\n focusPrevious(opts) {\n return instance.navigate(opts?.from || document.activeElement, true);\n },\n focusMain() {\n return instance.focusMain();\n },\n dispose() {\n instance.refCount--;\n instance.teardownIfNeeded();\n instance = null;\n }\n };\n }\n\n public registerLandmark(landmark: Landmark): () => void {\n if (this.landmarks.find(l => l.ref === landmark.ref)) {\n this.updateLandmark(landmark);\n } else {\n this.addLandmark(landmark);\n }\n\n return () => this.removeLandmark(landmark.ref);\n }\n}\n\n/** Creates a LandmarkController, which allows programmatic navigation of landmarks. */\nexport function createLandmarkController(): LandmarkController {\n // Get the current landmark manager and create a controller using it.\n let instance = getLandmarkManager();\n let controller = instance.createLandmarkController();\n\n let unsubscribe = subscribe(() => {\n // If the landmark manager changes, dispose the old\n // controller and create a new one.\n controller.dispose();\n instance = getLandmarkManager();\n controller = instance.createLandmarkController();\n });\n\n // Return a wrapper that proxies requests to the current controller instance.\n return {\n navigate(direction, opts) {\n return controller.navigate(direction, opts);\n },\n focusNext(opts) {\n return controller.focusNext(opts);\n },\n focusPrevious(opts) {\n return controller.focusPrevious(opts);\n },\n focusMain() {\n return controller.focusMain();\n },\n dispose() {\n controller.dispose();\n unsubscribe();\n controller = null;\n instance = null;\n }\n };\n}\n\n/**\n * Provides landmark navigation in an application. Call this with a role and label to register a landmark navigable with F6.\n * @param props - Props for the landmark.\n * @param ref - Ref to the landmark.\n */\nexport function useLandmark(props: AriaLandmarkProps, ref: MutableRefObject<FocusableElement>): LandmarkAria {\n const {\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n focus\n } = props;\n let manager = useLandmarkManager();\n let label = ariaLabel || ariaLabelledby;\n let [isLandmarkFocused, setIsLandmarkFocused] = useState(false);\n\n let defaultFocus = useCallback(() => {\n setIsLandmarkFocused(true);\n }, [setIsLandmarkFocused]);\n\n let blur = useCallback(() => {\n setIsLandmarkFocused(false);\n }, [setIsLandmarkFocused]);\n\n useLayoutEffect(() => {\n return manager.registerLandmark({ref, label, role, focus: focus || defaultFocus, blur});\n }, [manager, label, ref, role, focus, defaultFocus, blur]);\n\n useEffect(() => {\n if (isLandmarkFocused) {\n ref.current.focus();\n }\n }, [isLandmarkFocused, ref]);\n\n return {\n landmarkProps: {\n role,\n tabIndex: isLandmarkFocused ? -1 : undefined,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby\n }\n };\n}\n"],"names":[],"version":3,"file":"module.js.map"}
1
+ {"mappings":";;;;;AAAA;;;;;;;;;;ACAA;;;;;;;;;;CAUC,GAED;;;;AAgBA,6CAA6C;AAC7C,oDAAoD;AACpD,MAAM,6CAAuB;AAiD7B,0FAA0F;AAC1F,MAAM,uCAAiB,OAAO,GAAG,CAAC;AAElC,SAAS,gCAAU,EAAc,EAAE;IACjC,SAAS,gBAAgB,CAAC,sCAAsC;IAChE,OAAO,IAAM,SAAS,mBAAmB,CAAC,sCAAsC;AAClF;AAEA,SAAS,2CAAgD;IACvD,IAAI,OAAO,aAAa,aACtB,OAAO,IAAI;IAGb,oEAAoE;IACpE,IAAI,WAAW,QAAQ,CAAC,qCAAe;IACvC,IAAI,YAAY,SAAS,OAAO,IAAI,4CAClC,OAAO;IAGT,wFAAwF;IACxF,sEAAsE;IACtE,QAAQ,CAAC,qCAAe,GAAG,IAAI;IAC/B,SAAS,aAAa,CAAC,IAAI,YAAY;IACvC,OAAO,QAAQ,CAAC,qCAAe;AACjC;AAEA,yEAAyE;AACzE,SAAS,2CAAgD;IACvD,OAAO,CAAA,GAAA,2BAAoB,AAAD,EAAE,iCAAW,0CAAoB;AAC7D;AAEA,MAAM;IAYI,gBAAgB;QACtB,IAAI,IAAI,CAAC,WAAW,EAClB;QAEF,SAAS,gBAAgB,CAAC,WAAW,IAAI,CAAC,SAAS,EAAE;YAAC,SAAS,IAAI;QAAA;QACnE,SAAS,gBAAgB,CAAC,WAAW,IAAI,CAAC,cAAc,EAAE;YAAC,SAAS,IAAI;QAAA;QACxE,SAAS,gBAAgB,CAAC,YAAY,IAAI,CAAC,eAAe,EAAE;YAAC,SAAS,IAAI;QAAA;QAC1E,IAAI,CAAC,WAAW,GAAG,IAAI;IACzB;IAEQ,mBAAmB;QACzB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,KAAK,IAAI,CAAC,QAAQ,GAAG,GACpE;QAEF,SAAS,mBAAmB,CAAC,WAAW,IAAI,CAAC,SAAS,EAAE;YAAC,SAAS,IAAI;QAAA;QACtE,SAAS,mBAAmB,CAAC,WAAW,IAAI,CAAC,cAAc,EAAE;YAAC,SAAS,IAAI;QAAA;QAC3E,SAAS,mBAAmB,CAAC,YAAY,IAAI,CAAC,eAAe,EAAE;YAAC,SAAS,IAAI;QAAA;QAC7E,IAAI,CAAC,WAAW,GAAG,KAAK;IAC1B;IAEQ,cAAc,QAA0B,EAAE,SAAiC,EAAE;YACnF;QAAA,CAAA,uBAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,IAAK,EAAE,GAAG,CAAC,OAAO,KAAK,uBAA3C,kCAAA,KAAA,IAAA,8BAAA,qBAAsD,2DAAtD,KAAA,IAAA,2BAAA,KAAA,sBAA8D;IAChE;IAEA;;GAEC,GACD,AAAQ,mBAAmB,IAAsB,EAAE;QACjD,OAAO,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA,IAAK,EAAE,IAAI,KAAK;IACvD;IAEA;;GAEC,GACD,AAAQ,kBAAkB,IAAsB,EAAE;QAChD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,IAAK,EAAE,IAAI,KAAK;IAC7C;IAEQ,YAAY,WAAqB,EAAE;QACzC,IAAI,CAAC,aAAa;QAClB,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,WAAY,SAAS,GAAG,KAAK,YAAY,GAAG,KAAK,CAAC,YAAY,GAAG,CAAC,OAAO,EAC/F;QAGF,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA,WAAY,SAAS,IAAI,KAAK,QAAQ,MAAM,GAAG,GACvE,QAAQ,KAAK,CAAC;QAGhB,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,GAAG;YAC/B,IAAI,CAAC,SAAS,GAAG;gBAAC;aAAY;YAC9B,IAAI,CAAC,WAAW,CAAC,YAAY,IAAI;YACjC;QACF,CAAC;QAGD,qGAAqG;QACrG,gFAAgF;QAChF,IAAI,QAAQ;QACZ,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG;QAClC,MAAO,SAAS,IAAK;YACnB,IAAI,MAAM,KAAK,KAAK,CAAC,AAAC,CAAA,QAAQ,GAAE,IAAK;YACrC,IAAI,mBAAmB,YAAY,GAAG,CAAC,OAAO,CAAC,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO;YACtG,IAAI,qBAAqB,QAAQ,AAAC,mBAAmB,KAAK,2BAA2B,IAAM,mBAAmB,KAAK,0BAA0B;YAE7I,IAAI,oBACF,QAAQ,MAAM;iBAEd,MAAM,MAAM;QAEhB;QAEA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,GAAG;QAChC,IAAI,CAAC,WAAW,CAAC,YAAY,IAAI;IACnC;IAEQ,eAAe,QAAmD,EAAE;QAC1E,IAAI,QAAQ,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA,IAAK,EAAE,GAAG,KAAK,SAAS,GAAG;QAChE,IAAI,SAAS,GAAG;YACd,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG;gBAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM;gBAAE,GAAG,QAAQ;YAAA;YAC9D,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI;QAC7C,CAAC;IACH;IAEQ,eAAe,GAAuB,EAAE;QAC9C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA,WAAY,SAAS,GAAG,KAAK;QACpE,IAAI,CAAC,gBAAgB;IACvB;IAEA;;;;;GAKC,GACD,AAAQ,YAAY,IAAsB,EAAE;QAC1C,IAAI,oBAAoB,IAAI,CAAC,kBAAkB,CAAC;QAChD,IAAI,kBAAkB,IAAI,GAAG,GAAG;YAC9B,IAAI,yBAAyB;mBAAI;aAAkB,CAAC,MAAM,CAAC,CAAA,WAAY,CAAC,SAAS,KAAK;YACtF,IAAI,uBAAuB,MAAM,GAAG,GAClC,QAAQ,IAAI,CACV,CAAC,+CAA+C,EAAE,KAAK,qIAAqI,CAAC,EAC7L,uBAAuB,GAAG,CAAC,CAAA,WAAY,SAAS,GAAG,CAAC,OAAO;iBAExD;gBACL,IAAI,SAAS;uBAAI;iBAAkB,CAAC,GAAG,CAAC,CAAA,WAAY,SAAS,KAAK;gBAClE,IAAI,kBAAkB,OAAO,MAAM,CAAC,CAAC,MAAM,QAAU,OAAO,OAAO,CAAC,UAAU;gBAE9E,gBAAgB,OAAO,CAAC,CAAC,QAAU;oBACjC,QAAQ,IAAI,CACV,CAAC,+CAA+C,EAAE,KAAK,YAAY,EAAE,MAAM,+FAA+F,CAAC,EAC3K;2BAAI;qBAAkB,CAAC,MAAM,CAAC,CAAA,WAAY,SAAS,KAAK,KAAK,OAAO,GAAG,CAAC,CAAA,WAAY,SAAS,GAAG,CAAC,OAAO;gBAE5G;YACF,CAAC;QACH,CAAC;IACH;IAEA;;;GAGC,GACD,AAAQ,gBAAgB,OAAyB,EAAE;QACjD,IAAI,cAAc,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA,IAAK;gBAAC,EAAE,GAAG,CAAC,OAAO;gBAAE;aAAE;QACpE,IAAI,iBAAiB;QACrB,MAAO,kBAAkB,CAAC,YAAY,GAAG,CAAC,mBAAmB,mBAAmB,SAAS,IAAI,IAAI,eAAe,aAAa,CAC3H,iBAAiB,eAAe,aAAa;QAE/C,OAAO,YAAY,GAAG,CAAC;IACzB;IAEA;;;;;GAKC,GACD,AAAQ,gBAAgB,OAAyB,EAAE,YAAC,SAAQ,EAAwB,EAAE;YAqC7E;QApCP,IAAI,kBAAkB,IAAI,CAAC,eAAe,CAAC;QAC3C,IAAI,oBAAoB,WAAW,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC;QAChE,IAAI,iBACF,oBAAoB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,mBAAoB,CAAA,WAAW,KAAK,CAAC,AAAD;QAGjF,IAAI,eAAe,IAAM;YACvB,gHAAgH;YAChH,sHAAsH;YACtH,IAAI,oBAAoB,GAAG;gBACzB,IAAI,CAAC,QAAQ,aAAa,CAAC,IAAI,YAAY,kCAAkC;oBAAC,QAAQ;wBAAC,WAAW;oBAAU;oBAAG,SAAS,IAAI;oBAAE,YAAY,IAAI;gBAAA,KAC5I,OAAO,IAAI;gBAGb,oBAAoB,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG;YAC9C,OAAO,IAAI,qBAAqB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE;gBACrD,IAAI,CAAC,QAAQ,aAAa,CAAC,IAAI,YAAY,kCAAkC;oBAAC,QAAQ;wBAAC,WAAW;oBAAS;oBAAG,SAAS,IAAI;oBAAE,YAAY,IAAI;gBAAA,KAC3I,OAAO,IAAI;gBAGb,oBAAoB;YACtB,CAAC;YAED,IAAI,oBAAoB,KAAK,qBAAqB,IAAI,CAAC,SAAS,CAAC,MAAM,EACrE,OAAO,IAAI;YAGb,OAAO,KAAK;QACd;QAEA,IAAI,gBACF,OAAO;QAGT,8BAA8B;QAC9B,IAAI,IAAI;QACR,MAAO,CAAA,gDAAA,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,cAA7C,2DAAA,KAAA,IAAA,8CAA+C,QAAQ,sBAAuB;YACnF,qBAAqB,WAAW,KAAK,CAAC;YACtC,IAAI,gBACF,OAAO;YAGT,IAAI,sBAAsB,GACxB,KAAM;QAEV;QAEA,OAAO,IAAI,CAAC,SAAS,CAAC,kBAAkB;IAC1C;IAEA;;;;GAIC,GACD,AAAQ,UAAU,CAAgB,EAAE;QAClC,IAAI,EAAE,GAAG,KAAK,MAAM;YAClB,sGAAsG;YACtG,IAAI,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAsB,EAAE,QAAQ,CAAC;YACnG,IAAI,SAAS;gBACX,EAAE,cAAc;gBAChB,EAAE,eAAe;YACnB,CAAC;QACH,CAAC;IACH;IAEQ,YAAY;QAClB,IAAI,OAAO,IAAI,CAAC,iBAAiB,CAAC;QAClC,IAAI,QAAQ,KAAK,GAAG,CAAC,OAAO,IAAI,SAAS,QAAQ,CAAC,KAAK,GAAG,CAAC,OAAO,GAAG;YACnE,IAAI,CAAC,aAAa,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE;YACrC,OAAO,IAAI;QACb,CAAC;QAED,OAAO,KAAK;IACd;IAEQ,SAAS,IAAsB,EAAE,QAAiB,EAAE;QAC1D,IAAI,eAAe,IAAI,CAAC,eAAe,CAAC,MAAM;sBAC5C;QACF;QAEA,IAAI,CAAC,cACH,OAAO,KAAK;QAGd,oFAAoF;QACpF,IAAI,aAAa,WAAW,EAAE;YAC5B,IAAI,cAAc,aAAa,WAAW;YAC1C,IAAI,SAAS,IAAI,CAAC,QAAQ,CAAC,cAAc;gBACvC,YAAY,KAAK;gBACjB,OAAO,IAAI;YACb,CAAC;QACH,CAAC;QAED,uCAAuC;QACvC,IAAI,aAAa,GAAG,CAAC,OAAO,IAAI,SAAS,QAAQ,CAAC,aAAa,GAAG,CAAC,OAAO,GAAG;YAC3E,IAAI,CAAC,aAAa,CAAC,aAAa,GAAG,CAAC,OAAO,EAAE,WAAW,aAAa,SAAS;YAC9E,OAAO,IAAI;QACb,CAAC;QAED,OAAO,KAAK;IACd;IAEA;;;GAGC,GACD,AAAQ,eAAe,CAAa,EAAE;QACpC,IAAI,kBAAkB,IAAI,CAAC,eAAe,CAAC,EAAE,MAAM;QACnD,IAAI,mBAAmB,gBAAgB,GAAG,CAAC,OAAO,KAAK,EAAE,MAAM,EAC7D,IAAI,CAAC,cAAc,CAAC;YAAC,KAAK,gBAAgB,GAAG;YAAE,aAAa,EAAE,MAAM;QAAoB;QAE1F,IAAI,yBAAyB,EAAE,aAAa;QAC5C,IAAI,wBAAwB;YAC1B,IAAI,0BAA0B,IAAI,CAAC,eAAe,CAAC;YACnD,IAAI,2BAA2B,wBAAwB,GAAG,CAAC,OAAO,KAAK,wBACrE,wBAAwB,IAAI;QAEhC,CAAC;IACH;IAEA;;GAEC,GACD,AAAQ,gBAAgB,CAAa,EAAE;QACrC,IAAI,yBAAyB,EAAE,MAAM;QACrC,IAAI,qBAAqB,EAAE,aAAa;QACxC,iHAAiH;QACjH,yGAAyG;QACzG,IAAI,CAAC,sBAAsB,uBAAuB,UAAU;YAC1D,IAAI,0BAA0B,IAAI,CAAC,eAAe,CAAC;YACnD,IAAI,2BAA2B,wBAAwB,GAAG,CAAC,OAAO,KAAK,wBACrE,wBAAwB,IAAI;QAEhC,CAAC;IACH;IAEO,2BAA+C;QACpD,IAAI,WAAmC,IAAI;QAC3C,SAAS,QAAQ;QACjB,SAAS,aAAa;QACtB,OAAO;YACL,UAAS,SAAS,EAAE,IAAI,EAAE;gBACxB,IAAI,UAAU,CAAA,iBAAA,kBAAA,KAAA,IAAA,KAAM,IAAI,AAAD,KAAM,SAAU,aAAa;gBACpD,OAAO,SAAU,QAAQ,CAAC,SAAS,cAAc;YACnD;YACA,WAAU,IAAI,EAAE;gBACd,IAAI,UAAU,CAAA,iBAAA,kBAAA,KAAA,IAAA,KAAM,IAAI,AAAD,KAAM,SAAU,aAAa;gBACpD,OAAO,SAAU,QAAQ,CAAC,SAAS,KAAK;YAC1C;YACA,eAAc,IAAI,EAAE;gBAClB,IAAI,UAAU,CAAA,iBAAA,kBAAA,KAAA,IAAA,KAAM,IAAI,AAAD,KAAM,SAAU,aAAa;gBACpD,OAAO,SAAU,QAAQ,CAAC,SAAS,IAAI;YACzC;YACA,aAAY;gBACV,OAAO,SAAU,SAAS;YAC5B;YACA,WAAU;gBACR,IAAI,UAAU;oBACZ,SAAS,QAAQ;oBACjB,SAAS,gBAAgB;oBACzB,WAAW,IAAI;gBACjB,CAAC;YACH;QACF;IACF;IAEO,iBAAiB,QAAkB,EAAc;QACtD,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,IAAK,EAAE,GAAG,KAAK,SAAS,GAAG,GACjD,IAAI,CAAC,cAAc,CAAC;aAEpB,IAAI,CAAC,WAAW,CAAC;QAGnB,OAAO,IAAM,IAAI,CAAC,cAAc,CAAC,SAAS,GAAG;IAC/C;IA9TA,aAAc;QALd,mDAAQ,aAA6B,EAAE;QACvC,mDAAQ,eAAc,KAAK;QAC3B,mDAAQ,YAAW;QACnB,mDAAO,WAAU;QAGf,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI;QACzC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI;QACnD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI;IACvD;AA2TF;AAGO,SAAS,4CAA+C;IAC7D,qEAAqE;IACrE,IAAI,WAAsC;IAC1C,IAAI,aAAa,qBAAA,sBAAA,KAAA,IAAA,SAAU,wBAAwB;IAEnD,IAAI,cAAc,gCAAU,IAAM;QAChC,mDAAmD;QACnD,mCAAmC;QACnC,uBAAA,wBAAA,KAAA,IAAA,WAAY,OAAO;QACnB,WAAW;QACX,aAAa,qBAAA,sBAAA,KAAA,IAAA,SAAU,wBAAwB;IACjD;IAEA,6EAA6E;IAC7E,OAAO;QACL,UAAS,SAAS,EAAE,IAAI,EAAE;YACxB,OAAO,WAAY,QAAQ,CAAC,WAAW;QACzC;QACA,WAAU,IAAI,EAAE;YACd,OAAO,WAAY,SAAS,CAAC;QAC/B;QACA,eAAc,IAAI,EAAE;YAClB,OAAO,WAAY,aAAa,CAAC;QACnC;QACA,aAAY;YACV,OAAO,WAAY,SAAS;QAC9B;QACA,WAAU;YACR,uBAAA,wBAAA,KAAA,IAAA,WAAY,OAAO;YACnB;YACA,aAAa;YACb,WAAW,IAAI;QACjB;IACF;AACF;AAOO,SAAS,0CAAY,KAAwB,EAAE,GAAgC,EAAgB;IACpG,MAAM,QACJ,KAAI,EACJ,cAAc,UAAS,EACvB,mBAAmB,eAAc,SACjC,MAAK,EACN,GAAG;IACJ,IAAI,UAAU;IACd,IAAI,QAAQ,aAAa;IACzB,IAAI,CAAC,mBAAmB,qBAAqB,GAAG,CAAA,GAAA,eAAO,EAAE,KAAK;IAE9D,IAAI,eAAe,CAAA,GAAA,kBAAU,EAAE,IAAM;QACnC,qBAAqB,IAAI;IAC3B,GAAG;QAAC;KAAqB;IAEzB,IAAI,OAAO,CAAA,GAAA,kBAAU,EAAE,IAAM;QAC3B,qBAAqB,KAAK;IAC5B,GAAG;QAAC;KAAqB;IAEzB,CAAA,GAAA,sBAAe,AAAD,EAAE,IAAM;QACpB,IAAI,SACF,OAAO,QAAQ,gBAAgB,CAAC;iBAAC;mBAAK;kBAAO;YAAM,OAAO,SAAS;kBAAc;QAAI;IAEzF,GAAG;QAAC;QAAS;QAAO;QAAK;QAAM;QAAO;QAAc;KAAK;IAEzD,CAAA,GAAA,gBAAS,AAAD,EAAE,IAAM;YAEZ;QADF,IAAI,mBACF,CAAA,eAAA,IAAI,OAAO,cAAX,0BAAA,KAAA,IAAA,aAAa;IAEjB,GAAG;QAAC;QAAmB;KAAI;IAE3B,OAAO;QACL,eAAe;kBACb;YACA,UAAU,oBAAoB,KAAK,SAAS;YAC5C,cAAc;YACd,mBAAmB;QACrB;IACF;AACF;;CD5fC,GAED","sources":["packages/@react-aria/landmark/src/index.ts","packages/@react-aria/landmark/src/useLandmark.ts"],"sourcesContent":["/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport type {AriaLandmarkRole, AriaLandmarkProps, LandmarkAria, LandmarkController} from './useLandmark';\nexport {useLandmark, createLandmarkController} from './useLandmark';\n","/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaLabelingProps, DOMAttributes, FocusableElement} from '@react-types/shared';\nimport {RefObject, useCallback, useEffect, useState} from 'react';\nimport {useLayoutEffect} from '@react-aria/utils';\nimport {useSyncExternalStore} from 'use-sync-external-store/shim/index.js';\n\nexport type AriaLandmarkRole = 'main' | 'region' | 'search' | 'navigation' | 'form' | 'banner' | 'contentinfo' | 'complementary';\n\nexport interface AriaLandmarkProps extends AriaLabelingProps {\n role: AriaLandmarkRole,\n focus?: (direction: 'forward' | 'backward') => void\n}\n\nexport interface LandmarkAria {\n landmarkProps: DOMAttributes\n}\n\n// Increment this version number whenever the\n// LandmarkManagerApi or Landmark interfaces change.\nconst LANDMARK_API_VERSION = 1;\n\n// Minimal API for LandmarkManager that must continue to work between versions.\n// Changes to this interface are considered breaking. New methods/properties are\n// safe to add, but changes or removals are not allowed (same as public APIs).\ninterface LandmarkManagerApi {\n version: number,\n createLandmarkController(): LandmarkController,\n registerLandmark(landmark: Landmark): () => void\n}\n\n// Changes to this interface are considered breaking.\n// New properties MUST be optional so that registering a landmark\n// from an older version of useLandmark against a newer version of\n// LandmarkManager does not crash.\ninterface Landmark {\n ref: RefObject<FocusableElement>,\n role: AriaLandmarkRole,\n label?: string,\n lastFocused?: FocusableElement,\n focus: (direction: 'forward' | 'backward') => void,\n blur: () => void\n}\n\nexport interface LandmarkControllerOptions {\n /**\n * The element from which to start navigating.\n * @default document.activeElement\n */\n from?: FocusableElement\n}\n\n/** A LandmarkController allows programmatic navigation of landmarks. */\nexport interface LandmarkController {\n /** Moves focus to the next landmark. */\n focusNext(opts?: LandmarkControllerOptions): boolean,\n /** Moves focus to the previous landmark. */\n focusPrevious(opts?: LandmarkControllerOptions): boolean,\n /** Moves focus to the main landmark. */\n focusMain(): boolean,\n /** Moves focus either forward or backward in the landmark sequence. */\n navigate(direction: 'forward' | 'backward', opts?: LandmarkControllerOptions): boolean,\n /**\n * Disposes the landmark controller. When no landmarks are registered, and no\n * controllers are active, the landmark keyboard listeners are removed from the page.\n */\n dispose(): void\n}\n\n// Symbol under which the singleton landmark manager instance is attached to the document.\nconst landmarkSymbol = Symbol.for('react-aria-landmark-manager');\n\nfunction subscribe(fn: () => void) {\n document.addEventListener('react-aria-landmark-manager-change', fn);\n return () => document.removeEventListener('react-aria-landmark-manager-change', fn);\n}\n\nfunction getLandmarkManager(): LandmarkManagerApi | null {\n if (typeof document === 'undefined') {\n return null;\n }\n\n // Reuse an existing instance if it has the same or greater version.\n let instance = document[landmarkSymbol];\n if (instance && instance.version >= LANDMARK_API_VERSION) {\n return instance;\n }\n\n // Otherwise, create a new instance and dispatch an event so anything using the existing\n // instance updates and re-registers their landmarks with the new one.\n document[landmarkSymbol] = new LandmarkManager();\n document.dispatchEvent(new CustomEvent('react-aria-landmark-manager-change'));\n return document[landmarkSymbol];\n}\n\n// Subscribes a React component to the current landmark manager instance.\nfunction useLandmarkManager(): LandmarkManagerApi | null {\n return useSyncExternalStore(subscribe, getLandmarkManager, getLandmarkManager);\n}\n\nclass LandmarkManager implements LandmarkManagerApi {\n private landmarks: Array<Landmark> = [];\n private isListening = false;\n private refCount = 0;\n public version = LANDMARK_API_VERSION;\n\n constructor() {\n this.f6Handler = this.f6Handler.bind(this);\n this.focusinHandler = this.focusinHandler.bind(this);\n this.focusoutHandler = this.focusoutHandler.bind(this);\n }\n\n private setupIfNeeded() {\n if (this.isListening) {\n return;\n }\n document.addEventListener('keydown', this.f6Handler, {capture: true});\n document.addEventListener('focusin', this.focusinHandler, {capture: true});\n document.addEventListener('focusout', this.focusoutHandler, {capture: true});\n this.isListening = true;\n }\n\n private teardownIfNeeded() {\n if (!this.isListening || this.landmarks.length > 0 || this.refCount > 0) {\n return;\n }\n document.removeEventListener('keydown', this.f6Handler, {capture: true});\n document.removeEventListener('focusin', this.focusinHandler, {capture: true});\n document.removeEventListener('focusout', this.focusoutHandler, {capture: true});\n this.isListening = false;\n }\n\n private focusLandmark(landmark: FocusableElement, direction: 'forward' | 'backward') {\n this.landmarks.find(l => l.ref.current === landmark)?.focus?.(direction);\n }\n\n /**\n * Return set of landmarks with a specific role.\n */\n private getLandmarksByRole(role: AriaLandmarkRole) {\n return new Set(this.landmarks.filter(l => l.role === role));\n }\n\n /**\n * Return first landmark with a specific role.\n */\n private getLandmarkByRole(role: AriaLandmarkRole) {\n return this.landmarks.find(l => l.role === role);\n }\n\n private addLandmark(newLandmark: Landmark) {\n this.setupIfNeeded();\n if (this.landmarks.find(landmark => landmark.ref === newLandmark.ref) || !newLandmark.ref.current) {\n return;\n }\n\n if (this.landmarks.filter(landmark => landmark.role === 'main').length > 1) {\n console.error('Page can contain no more than one landmark with the role \"main\".');\n }\n\n if (this.landmarks.length === 0) {\n this.landmarks = [newLandmark];\n this.checkLabels(newLandmark.role);\n return;\n }\n\n\n // Binary search to insert new landmark based on position in document relative to existing landmarks.\n // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition\n let start = 0;\n let end = this.landmarks.length - 1;\n while (start <= end) {\n let mid = Math.floor((start + end) / 2);\n let comparedPosition = newLandmark.ref.current.compareDocumentPosition(this.landmarks[mid].ref.current as Node);\n let isNewAfterExisting = Boolean((comparedPosition & Node.DOCUMENT_POSITION_PRECEDING) || (comparedPosition & Node.DOCUMENT_POSITION_CONTAINS));\n\n if (isNewAfterExisting) {\n start = mid + 1;\n } else {\n end = mid - 1;\n }\n }\n\n this.landmarks.splice(start, 0, newLandmark);\n this.checkLabels(newLandmark.role);\n }\n\n private updateLandmark(landmark: Pick<Landmark, 'ref'> & Partial<Landmark>) {\n let index = this.landmarks.findIndex(l => l.ref === landmark.ref);\n if (index >= 0) {\n this.landmarks[index] = {...this.landmarks[index], ...landmark};\n this.checkLabels(this.landmarks[index].role);\n }\n }\n\n private removeLandmark(ref: RefObject<Element>) {\n this.landmarks = this.landmarks.filter(landmark => landmark.ref !== ref);\n this.teardownIfNeeded();\n }\n\n /**\n * Warn if there are 2+ landmarks with the same role but no label.\n * Labels for landmarks with the same role must also be unique.\n *\n * See https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/.\n */\n private checkLabels(role: AriaLandmarkRole) {\n let landmarksWithRole = this.getLandmarksByRole(role);\n if (landmarksWithRole.size > 1) {\n let duplicatesWithoutLabel = [...landmarksWithRole].filter(landmark => !landmark.label);\n if (duplicatesWithoutLabel.length > 0) {\n console.warn(\n `Page contains more than one landmark with the '${role}' role. If two or more landmarks on a page share the same role, all must be labeled with an aria-label or aria-labelledby attribute: `,\n duplicatesWithoutLabel.map(landmark => landmark.ref.current)\n );\n } else {\n let labels = [...landmarksWithRole].map(landmark => landmark.label);\n let duplicateLabels = labels.filter((item, index) => labels.indexOf(item) !== index);\n\n duplicateLabels.forEach((label) => {\n console.warn(\n `Page contains more than one landmark with the '${role}' role and '${label}' label. If two or more landmarks on a page share the same role, they must have unique labels: `,\n [...landmarksWithRole].filter(landmark => landmark.label === label).map(landmark => landmark.ref.current)\n );\n });\n }\n }\n }\n\n /**\n * Get the landmark that is the closest parent in the DOM.\n * Returns undefined if no parent is a landmark.\n */\n private closestLandmark(element: FocusableElement) {\n let landmarkMap = new Map(this.landmarks.map(l => [l.ref.current, l]));\n let currentElement = element;\n while (currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body && currentElement.parentElement) {\n currentElement = currentElement.parentElement;\n }\n return landmarkMap.get(currentElement);\n }\n\n /**\n * Gets the next landmark, in DOM focus order, or previous if backwards is specified.\n * If last landmark, next should be the first landmark.\n * If not inside a landmark, will return first landmark.\n * Returns undefined if there are no landmarks.\n */\n private getNextLandmark(element: FocusableElement, {backward}: {backward?: boolean }) {\n let currentLandmark = this.closestLandmark(element);\n let nextLandmarkIndex = backward ? this.landmarks.length - 1 : 0;\n if (currentLandmark) {\n nextLandmarkIndex = this.landmarks.indexOf(currentLandmark) + (backward ? -1 : 1);\n }\n\n let wrapIfNeeded = () => {\n // When we reach the end of the landmark sequence, fire a custom event that can be listened for by applications.\n // If this event is canceled, we return immediately. This can be used to implement landmark navigation across iframes.\n if (nextLandmarkIndex < 0) {\n if (!element.dispatchEvent(new CustomEvent('react-aria-landmark-navigation', {detail: {direction: 'backward'}, bubbles: true, cancelable: true}))) {\n return true;\n }\n\n nextLandmarkIndex = this.landmarks.length - 1;\n } else if (nextLandmarkIndex >= this.landmarks.length) {\n if (!element.dispatchEvent(new CustomEvent('react-aria-landmark-navigation', {detail: {direction: 'forward'}, bubbles: true, cancelable: true}))) {\n return true;\n }\n\n nextLandmarkIndex = 0;\n }\n\n if (nextLandmarkIndex < 0 || nextLandmarkIndex >= this.landmarks.length) {\n return true;\n }\n\n return false;\n };\n\n if (wrapIfNeeded()) {\n return undefined;\n }\n\n // Skip over hidden landmarks.\n let i = nextLandmarkIndex;\n while (this.landmarks[nextLandmarkIndex].ref.current?.closest('[aria-hidden=true]')) {\n nextLandmarkIndex += backward ? -1 : 1;\n if (wrapIfNeeded()) {\n return undefined;\n }\n\n if (nextLandmarkIndex === i) {\n break;\n }\n }\n\n return this.landmarks[nextLandmarkIndex];\n }\n\n /**\n * Look at next landmark. If an element was previously focused inside, restore focus there.\n * If not, focus the landmark itself.\n * If no landmarks at all, or none with focusable elements, don't move focus.\n */\n private f6Handler(e: KeyboardEvent) {\n if (e.key === 'F6') {\n // If alt key pressed, focus main landmark, otherwise navigate forward or backward based on shift key.\n let handled = e.altKey ? this.focusMain() : this.navigate(e.target as FocusableElement, e.shiftKey);\n if (handled) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n }\n\n private focusMain() {\n let main = this.getLandmarkByRole('main');\n if (main && main.ref.current && document.contains(main.ref.current)) {\n this.focusLandmark(main.ref.current, 'forward');\n return true;\n }\n\n return false;\n }\n\n private navigate(from: FocusableElement, backward: boolean) {\n let nextLandmark = this.getNextLandmark(from, {\n backward\n });\n\n if (!nextLandmark) {\n return false;\n }\n\n // If something was previously focused in the next landmark, then return focus to it\n if (nextLandmark.lastFocused) {\n let lastFocused = nextLandmark.lastFocused;\n if (document.body.contains(lastFocused)) {\n lastFocused.focus();\n return true;\n }\n }\n\n // Otherwise, focus the landmark itself\n if (nextLandmark.ref.current && document.contains(nextLandmark.ref.current)) {\n this.focusLandmark(nextLandmark.ref.current, backward ? 'backward' : 'forward');\n return true;\n }\n\n return false;\n }\n\n /**\n * Sets lastFocused for a landmark, if focus is moved within that landmark.\n * Lets the last focused landmark know it was blurred if something else is focused.\n */\n private focusinHandler(e: FocusEvent) {\n let currentLandmark = this.closestLandmark(e.target as FocusableElement);\n if (currentLandmark && currentLandmark.ref.current !== e.target) {\n this.updateLandmark({ref: currentLandmark.ref, lastFocused: e.target as FocusableElement});\n }\n let previousFocusedElement = e.relatedTarget as FocusableElement;\n if (previousFocusedElement) {\n let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);\n if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {\n closestPreviousLandmark.blur();\n }\n }\n }\n\n /**\n * Track if the focus is lost to the body. If it is, do cleanup on the landmark that last had focus.\n */\n private focusoutHandler(e: FocusEvent) {\n let previousFocusedElement = e.target as FocusableElement;\n let nextFocusedElement = e.relatedTarget;\n // the === document seems to be a jest thing for focus to go there on generic blur event such as landmark.blur();\n // browsers appear to send focus instead to document.body and the relatedTarget is null when that happens\n if (!nextFocusedElement || nextFocusedElement === document) {\n let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);\n if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {\n closestPreviousLandmark.blur();\n }\n }\n }\n\n public createLandmarkController(): LandmarkController {\n let instance: LandmarkManager | null = this;\n instance.refCount++;\n instance.setupIfNeeded();\n return {\n navigate(direction, opts) {\n let element = opts?.from || (document!.activeElement as FocusableElement);\n return instance!.navigate(element, direction === 'backward');\n },\n focusNext(opts) {\n let element = opts?.from || (document!.activeElement as FocusableElement);\n return instance!.navigate(element, false);\n },\n focusPrevious(opts) {\n let element = opts?.from || (document!.activeElement as FocusableElement);\n return instance!.navigate(element, true);\n },\n focusMain() {\n return instance!.focusMain();\n },\n dispose() {\n if (instance) {\n instance.refCount--;\n instance.teardownIfNeeded();\n instance = null;\n }\n }\n };\n }\n\n public registerLandmark(landmark: Landmark): () => void {\n if (this.landmarks.find(l => l.ref === landmark.ref)) {\n this.updateLandmark(landmark);\n } else {\n this.addLandmark(landmark);\n }\n\n return () => this.removeLandmark(landmark.ref);\n }\n}\n\n/** Creates a LandmarkController, which allows programmatic navigation of landmarks. */\nexport function createLandmarkController(): LandmarkController {\n // Get the current landmark manager and create a controller using it.\n let instance: LandmarkManagerApi | null = getLandmarkManager();\n let controller = instance?.createLandmarkController();\n\n let unsubscribe = subscribe(() => {\n // If the landmark manager changes, dispose the old\n // controller and create a new one.\n controller?.dispose();\n instance = getLandmarkManager();\n controller = instance?.createLandmarkController();\n });\n\n // Return a wrapper that proxies requests to the current controller instance.\n return {\n navigate(direction, opts) {\n return controller!.navigate(direction, opts);\n },\n focusNext(opts) {\n return controller!.focusNext(opts);\n },\n focusPrevious(opts) {\n return controller!.focusPrevious(opts);\n },\n focusMain() {\n return controller!.focusMain();\n },\n dispose() {\n controller?.dispose();\n unsubscribe();\n controller = undefined;\n instance = null;\n }\n };\n}\n\n/**\n * Provides landmark navigation in an application. Call this with a role and label to register a landmark navigable with F6.\n * @param props - Props for the landmark.\n * @param ref - Ref to the landmark.\n */\nexport function useLandmark(props: AriaLandmarkProps, ref: RefObject<FocusableElement>): LandmarkAria {\n const {\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n focus\n } = props;\n let manager = useLandmarkManager();\n let label = ariaLabel || ariaLabelledby;\n let [isLandmarkFocused, setIsLandmarkFocused] = useState(false);\n\n let defaultFocus = useCallback(() => {\n setIsLandmarkFocused(true);\n }, [setIsLandmarkFocused]);\n\n let blur = useCallback(() => {\n setIsLandmarkFocused(false);\n }, [setIsLandmarkFocused]);\n\n useLayoutEffect(() => {\n if (manager) {\n return manager.registerLandmark({ref, label, role, focus: focus || defaultFocus, blur});\n }\n }, [manager, label, ref, role, focus, defaultFocus, blur]);\n\n useEffect(() => {\n if (isLandmarkFocused) {\n ref.current?.focus();\n }\n }, [isLandmarkFocused, ref]);\n\n return {\n landmarkProps: {\n role,\n tabIndex: isLandmarkFocused ? -1 : undefined,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby\n }\n };\n}\n"],"names":[],"version":3,"file":"module.js.map"}
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AriaLabelingProps, DOMAttributes, FocusableElement } from "@react-types/shared";
2
- import { MutableRefObject } from "react";
2
+ import { RefObject } from "react";
3
3
  export type AriaLandmarkRole = 'main' | 'region' | 'search' | 'navigation' | 'form' | 'banner' | 'contentinfo' | 'complementary';
4
4
  export interface AriaLandmarkProps extends AriaLabelingProps {
5
5
  role: AriaLandmarkRole;
@@ -13,7 +13,7 @@ interface LandmarkControllerOptions {
13
13
  * The element from which to start navigating.
14
14
  * @default document.activeElement
15
15
  */
16
- from?: Element;
16
+ from?: FocusableElement;
17
17
  }
18
18
  /** A LandmarkController allows programmatic navigation of landmarks. */
19
19
  export interface LandmarkController {
@@ -38,6 +38,6 @@ export function createLandmarkController(): LandmarkController;
38
38
  * @param props - Props for the landmark.
39
39
  * @param ref - Ref to the landmark.
40
40
  */
41
- export function useLandmark(props: AriaLandmarkProps, ref: MutableRefObject<FocusableElement>): LandmarkAria;
41
+ export function useLandmark(props: AriaLandmarkProps, ref: RefObject<FocusableElement>): LandmarkAria;
42
42
 
43
43
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"mappings":";;AAiBA,+BAA+B,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,GAAG,eAAe,CAAC;AAEjI,kCAAmC,SAAQ,iBAAiB;IAC1D,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,KAAK,IAAI,CAAA;CACpD;AAED;IACE,aAAa,EAAE,aAAa,CAAA;CAC7B;AA4BD;IACE;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,wEAAwE;AACxE;IACE,wCAAwC;IACxC,SAAS,CAAC,IAAI,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC;IACrD,4CAA4C;IAC5C,aAAa,CAAC,IAAI,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC;IACzD,wCAAwC;IACxC,SAAS,IAAI,OAAO,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,EAAE,IAAI,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC;IACvF;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AA+VD,uFAAuF;AACvF,4CAA4C,kBAAkB,CAkC7D;AAED;;;;GAIG;AACH,4BAA4B,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,iBAAiB,gBAAgB,CAAC,GAAG,YAAY,CAqC3G","sources":["packages/@react-aria/landmark/src/packages/@react-aria/landmark/src/useLandmark.ts","packages/@react-aria/landmark/src/packages/@react-aria/landmark/src/index.ts","packages/@react-aria/landmark/src/index.ts"],"sourcesContent":[null,null,"/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport type {AriaLandmarkRole, AriaLandmarkProps, LandmarkAria, LandmarkController} from './useLandmark';\nexport {useLandmark, createLandmarkController} from './useLandmark';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
1
+ {"mappings":";;AAiBA,+BAA+B,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,GAAG,eAAe,CAAC;AAEjI,kCAAmC,SAAQ,iBAAiB;IAC1D,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,KAAK,IAAI,CAAA;CACpD;AAED;IACE,aAAa,EAAE,aAAa,CAAA;CAC7B;AA4BD;IACE;;;OAGG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAA;CACxB;AAED,wEAAwE;AACxE;IACE,wCAAwC;IACxC,SAAS,CAAC,IAAI,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC;IACrD,4CAA4C;IAC5C,aAAa,CAAC,IAAI,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC;IACzD,wCAAwC;IACxC,SAAS,IAAI,OAAO,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,EAAE,IAAI,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC;IACvF;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAwWD,uFAAuF;AACvF,4CAA4C,kBAAkB,CAkC7D;AAED;;;;GAIG;AACH,4BAA4B,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,UAAU,gBAAgB,CAAC,GAAG,YAAY,CAuCpG","sources":["packages/@react-aria/landmark/src/packages/@react-aria/landmark/src/useLandmark.ts","packages/@react-aria/landmark/src/packages/@react-aria/landmark/src/index.ts","packages/@react-aria/landmark/src/index.ts"],"sourcesContent":[null,null,"/*\n * Copyright 2022 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nexport type {AriaLandmarkRole, AriaLandmarkProps, LandmarkAria, LandmarkController} from './useLandmark';\nexport {useLandmark, createLandmarkController} from './useLandmark';\n"],"names":[],"version":3,"file":"types.d.ts.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-aria/landmark",
3
- "version": "3.0.0-alpha.6",
3
+ "version": "3.0.0-beta.0",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -22,9 +22,9 @@
22
22
  "url": "https://github.com/adobe/react-spectrum"
23
23
  },
24
24
  "dependencies": {
25
- "@react-aria/focus": "^3.11.0",
26
- "@react-aria/utils": "^3.15.0",
27
- "@react-types/shared": "^3.17.0",
25
+ "@react-aria/focus": "^3.12.0",
26
+ "@react-aria/utils": "^3.16.0",
27
+ "@react-types/shared": "^3.18.0",
28
28
  "@swc/helpers": "^0.4.14",
29
29
  "use-sync-external-store": "^1.2.0"
30
30
  },
@@ -34,5 +34,5 @@
34
34
  "publishConfig": {
35
35
  "access": "public"
36
36
  },
37
- "gitHead": "a0efee84aa178cb1a202951dfd6d8de02b292307"
37
+ "gitHead": "9d1ba9bd8ebcd63bf3495ade16d349bcb71795ce"
38
38
  }
@@ -11,9 +11,9 @@
11
11
  */
12
12
 
13
13
  import {AriaLabelingProps, DOMAttributes, FocusableElement} from '@react-types/shared';
14
- import {MutableRefObject, useCallback, useEffect, useState} from 'react';
14
+ import {RefObject, useCallback, useEffect, useState} from 'react';
15
15
  import {useLayoutEffect} from '@react-aria/utils';
16
- import {useSyncExternalStore} from 'use-sync-external-store/shim';
16
+ import {useSyncExternalStore} from 'use-sync-external-store/shim/index.js';
17
17
 
18
18
  export type AriaLandmarkRole = 'main' | 'region' | 'search' | 'navigation' | 'form' | 'banner' | 'contentinfo' | 'complementary';
19
19
 
@@ -44,7 +44,7 @@ interface LandmarkManagerApi {
44
44
  // from an older version of useLandmark against a newer version of
45
45
  // LandmarkManager does not crash.
46
46
  interface Landmark {
47
- ref: MutableRefObject<Element>,
47
+ ref: RefObject<FocusableElement>,
48
48
  role: AriaLandmarkRole,
49
49
  label?: string,
50
50
  lastFocused?: FocusableElement,
@@ -57,7 +57,7 @@ export interface LandmarkControllerOptions {
57
57
  * The element from which to start navigating.
58
58
  * @default document.activeElement
59
59
  */
60
- from?: Element
60
+ from?: FocusableElement
61
61
  }
62
62
 
63
63
  /** A LandmarkController allows programmatic navigation of landmarks. */
@@ -85,7 +85,11 @@ function subscribe(fn: () => void) {
85
85
  return () => document.removeEventListener('react-aria-landmark-manager-change', fn);
86
86
  }
87
87
 
88
- function getLandmarkManager(): LandmarkManagerApi {
88
+ function getLandmarkManager(): LandmarkManagerApi | null {
89
+ if (typeof document === 'undefined') {
90
+ return null;
91
+ }
92
+
89
93
  // Reuse an existing instance if it has the same or greater version.
90
94
  let instance = document[landmarkSymbol];
91
95
  if (instance && instance.version >= LANDMARK_API_VERSION) {
@@ -100,8 +104,8 @@ function getLandmarkManager(): LandmarkManagerApi {
100
104
  }
101
105
 
102
106
  // Subscribes a React component to the current landmark manager instance.
103
- function useLandmarkManager(): LandmarkManagerApi {
104
- return useSyncExternalStore(subscribe, getLandmarkManager);
107
+ function useLandmarkManager(): LandmarkManagerApi | null {
108
+ return useSyncExternalStore(subscribe, getLandmarkManager, getLandmarkManager);
105
109
  }
106
110
 
107
111
  class LandmarkManager implements LandmarkManagerApi {
@@ -136,8 +140,8 @@ class LandmarkManager implements LandmarkManagerApi {
136
140
  this.isListening = false;
137
141
  }
138
142
 
139
- private focusLandmark(landmark: Element, direction: 'forward' | 'backward') {
140
- this.landmarks.find(l => l.ref.current === landmark)?.focus(direction);
143
+ private focusLandmark(landmark: FocusableElement, direction: 'forward' | 'backward') {
144
+ this.landmarks.find(l => l.ref.current === landmark)?.focus?.(direction);
141
145
  }
142
146
 
143
147
  /**
@@ -156,7 +160,7 @@ class LandmarkManager implements LandmarkManagerApi {
156
160
 
157
161
  private addLandmark(newLandmark: Landmark) {
158
162
  this.setupIfNeeded();
159
- if (this.landmarks.find(landmark => landmark.ref === newLandmark.ref)) {
163
+ if (this.landmarks.find(landmark => landmark.ref === newLandmark.ref) || !newLandmark.ref.current) {
160
164
  return;
161
165
  }
162
166
 
@@ -199,7 +203,7 @@ class LandmarkManager implements LandmarkManagerApi {
199
203
  }
200
204
  }
201
205
 
202
- private removeLandmark(ref: MutableRefObject<Element>) {
206
+ private removeLandmark(ref: RefObject<Element>) {
203
207
  this.landmarks = this.landmarks.filter(landmark => landmark.ref !== ref);
204
208
  this.teardownIfNeeded();
205
209
  }
@@ -237,10 +241,10 @@ class LandmarkManager implements LandmarkManagerApi {
237
241
  * Get the landmark that is the closest parent in the DOM.
238
242
  * Returns undefined if no parent is a landmark.
239
243
  */
240
- private closestLandmark(element: Element) {
244
+ private closestLandmark(element: FocusableElement) {
241
245
  let landmarkMap = new Map(this.landmarks.map(l => [l.ref.current, l]));
242
246
  let currentElement = element;
243
- while (currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body) {
247
+ while (currentElement && !landmarkMap.has(currentElement) && currentElement !== document.body && currentElement.parentElement) {
244
248
  currentElement = currentElement.parentElement;
245
249
  }
246
250
  return landmarkMap.get(currentElement);
@@ -252,7 +256,7 @@ class LandmarkManager implements LandmarkManagerApi {
252
256
  * If not inside a landmark, will return first landmark.
253
257
  * Returns undefined if there are no landmarks.
254
258
  */
255
- private getNextLandmark(element: Element, {backward}: {backward?: boolean }) {
259
+ private getNextLandmark(element: FocusableElement, {backward}: {backward?: boolean }) {
256
260
  let currentLandmark = this.closestLandmark(element);
257
261
  let nextLandmarkIndex = backward ? this.landmarks.length - 1 : 0;
258
262
  if (currentLandmark) {
@@ -289,7 +293,7 @@ class LandmarkManager implements LandmarkManagerApi {
289
293
 
290
294
  // Skip over hidden landmarks.
291
295
  let i = nextLandmarkIndex;
292
- while (this.landmarks[nextLandmarkIndex].ref.current.closest('[aria-hidden=true]')) {
296
+ while (this.landmarks[nextLandmarkIndex].ref.current?.closest('[aria-hidden=true]')) {
293
297
  nextLandmarkIndex += backward ? -1 : 1;
294
298
  if (wrapIfNeeded()) {
295
299
  return undefined;
@@ -311,7 +315,7 @@ class LandmarkManager implements LandmarkManagerApi {
311
315
  private f6Handler(e: KeyboardEvent) {
312
316
  if (e.key === 'F6') {
313
317
  // If alt key pressed, focus main landmark, otherwise navigate forward or backward based on shift key.
314
- let handled = e.altKey ? this.focusMain() : this.navigate(e.target as Element, e.shiftKey);
318
+ let handled = e.altKey ? this.focusMain() : this.navigate(e.target as FocusableElement, e.shiftKey);
315
319
  if (handled) {
316
320
  e.preventDefault();
317
321
  e.stopPropagation();
@@ -321,7 +325,7 @@ class LandmarkManager implements LandmarkManagerApi {
321
325
 
322
326
  private focusMain() {
323
327
  let main = this.getLandmarkByRole('main');
324
- if (main && document.contains(main.ref.current)) {
328
+ if (main && main.ref.current && document.contains(main.ref.current)) {
325
329
  this.focusLandmark(main.ref.current, 'forward');
326
330
  return true;
327
331
  }
@@ -329,7 +333,7 @@ class LandmarkManager implements LandmarkManagerApi {
329
333
  return false;
330
334
  }
331
335
 
332
- private navigate(from: Element, backward: boolean) {
336
+ private navigate(from: FocusableElement, backward: boolean) {
333
337
  let nextLandmark = this.getNextLandmark(from, {
334
338
  backward
335
339
  });
@@ -348,7 +352,7 @@ class LandmarkManager implements LandmarkManagerApi {
348
352
  }
349
353
 
350
354
  // Otherwise, focus the landmark itself
351
- if (document.contains(nextLandmark.ref.current)) {
355
+ if (nextLandmark.ref.current && document.contains(nextLandmark.ref.current)) {
352
356
  this.focusLandmark(nextLandmark.ref.current, backward ? 'backward' : 'forward');
353
357
  return true;
354
358
  }
@@ -361,11 +365,11 @@ class LandmarkManager implements LandmarkManagerApi {
361
365
  * Lets the last focused landmark know it was blurred if something else is focused.
362
366
  */
363
367
  private focusinHandler(e: FocusEvent) {
364
- let currentLandmark = this.closestLandmark(e.target as Element);
368
+ let currentLandmark = this.closestLandmark(e.target as FocusableElement);
365
369
  if (currentLandmark && currentLandmark.ref.current !== e.target) {
366
370
  this.updateLandmark({ref: currentLandmark.ref, lastFocused: e.target as FocusableElement});
367
371
  }
368
- let previousFocusedElement = e.relatedTarget as Element;
372
+ let previousFocusedElement = e.relatedTarget as FocusableElement;
369
373
  if (previousFocusedElement) {
370
374
  let closestPreviousLandmark = this.closestLandmark(previousFocusedElement);
371
375
  if (closestPreviousLandmark && closestPreviousLandmark.ref.current === previousFocusedElement) {
@@ -378,7 +382,7 @@ class LandmarkManager implements LandmarkManagerApi {
378
382
  * Track if the focus is lost to the body. If it is, do cleanup on the landmark that last had focus.
379
383
  */
380
384
  private focusoutHandler(e: FocusEvent) {
381
- let previousFocusedElement = e.target as Element;
385
+ let previousFocusedElement = e.target as FocusableElement;
382
386
  let nextFocusedElement = e.relatedTarget;
383
387
  // the === document seems to be a jest thing for focus to go there on generic blur event such as landmark.blur();
384
388
  // browsers appear to send focus instead to document.body and the relatedTarget is null when that happens
@@ -391,26 +395,31 @@ class LandmarkManager implements LandmarkManagerApi {
391
395
  }
392
396
 
393
397
  public createLandmarkController(): LandmarkController {
394
- let instance = this;
398
+ let instance: LandmarkManager | null = this;
395
399
  instance.refCount++;
396
400
  instance.setupIfNeeded();
397
401
  return {
398
402
  navigate(direction, opts) {
399
- return instance.navigate(opts?.from || document.activeElement, direction === 'backward');
403
+ let element = opts?.from || (document!.activeElement as FocusableElement);
404
+ return instance!.navigate(element, direction === 'backward');
400
405
  },
401
406
  focusNext(opts) {
402
- return instance.navigate(opts?.from || document.activeElement, false);
407
+ let element = opts?.from || (document!.activeElement as FocusableElement);
408
+ return instance!.navigate(element, false);
403
409
  },
404
410
  focusPrevious(opts) {
405
- return instance.navigate(opts?.from || document.activeElement, true);
411
+ let element = opts?.from || (document!.activeElement as FocusableElement);
412
+ return instance!.navigate(element, true);
406
413
  },
407
414
  focusMain() {
408
- return instance.focusMain();
415
+ return instance!.focusMain();
409
416
  },
410
417
  dispose() {
411
- instance.refCount--;
412
- instance.teardownIfNeeded();
413
- instance = null;
418
+ if (instance) {
419
+ instance.refCount--;
420
+ instance.teardownIfNeeded();
421
+ instance = null;
422
+ }
414
423
  }
415
424
  };
416
425
  }
@@ -429,35 +438,35 @@ class LandmarkManager implements LandmarkManagerApi {
429
438
  /** Creates a LandmarkController, which allows programmatic navigation of landmarks. */
430
439
  export function createLandmarkController(): LandmarkController {
431
440
  // Get the current landmark manager and create a controller using it.
432
- let instance = getLandmarkManager();
433
- let controller = instance.createLandmarkController();
441
+ let instance: LandmarkManagerApi | null = getLandmarkManager();
442
+ let controller = instance?.createLandmarkController();
434
443
 
435
444
  let unsubscribe = subscribe(() => {
436
445
  // If the landmark manager changes, dispose the old
437
446
  // controller and create a new one.
438
- controller.dispose();
447
+ controller?.dispose();
439
448
  instance = getLandmarkManager();
440
- controller = instance.createLandmarkController();
449
+ controller = instance?.createLandmarkController();
441
450
  });
442
451
 
443
452
  // Return a wrapper that proxies requests to the current controller instance.
444
453
  return {
445
454
  navigate(direction, opts) {
446
- return controller.navigate(direction, opts);
455
+ return controller!.navigate(direction, opts);
447
456
  },
448
457
  focusNext(opts) {
449
- return controller.focusNext(opts);
458
+ return controller!.focusNext(opts);
450
459
  },
451
460
  focusPrevious(opts) {
452
- return controller.focusPrevious(opts);
461
+ return controller!.focusPrevious(opts);
453
462
  },
454
463
  focusMain() {
455
- return controller.focusMain();
464
+ return controller!.focusMain();
456
465
  },
457
466
  dispose() {
458
- controller.dispose();
467
+ controller?.dispose();
459
468
  unsubscribe();
460
- controller = null;
469
+ controller = undefined;
461
470
  instance = null;
462
471
  }
463
472
  };
@@ -468,7 +477,7 @@ export function createLandmarkController(): LandmarkController {
468
477
  * @param props - Props for the landmark.
469
478
  * @param ref - Ref to the landmark.
470
479
  */
471
- export function useLandmark(props: AriaLandmarkProps, ref: MutableRefObject<FocusableElement>): LandmarkAria {
480
+ export function useLandmark(props: AriaLandmarkProps, ref: RefObject<FocusableElement>): LandmarkAria {
472
481
  const {
473
482
  role,
474
483
  'aria-label': ariaLabel,
@@ -488,12 +497,14 @@ export function useLandmark(props: AriaLandmarkProps, ref: MutableRefObject<Focu
488
497
  }, [setIsLandmarkFocused]);
489
498
 
490
499
  useLayoutEffect(() => {
491
- return manager.registerLandmark({ref, label, role, focus: focus || defaultFocus, blur});
500
+ if (manager) {
501
+ return manager.registerLandmark({ref, label, role, focus: focus || defaultFocus, blur});
502
+ }
492
503
  }, [manager, label, ref, role, focus, defaultFocus, blur]);
493
504
 
494
505
  useEffect(() => {
495
506
  if (isLandmarkFocused) {
496
- ref.current.focus();
507
+ ref.current?.focus();
497
508
  }
498
509
  }, [isLandmarkFocused, ref]);
499
510