@fluentui/react-aria 9.6.2 → 9.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,31 @@
1
1
  # Change Log - @fluentui/react-aria
2
2
 
3
- This log was last generated on Mon, 08 Jan 2024 16:20:07 GMT and should not be manually modified.
3
+ This log was last generated on Tue, 16 Jan 2024 13:07:07 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.7.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-aria_v9.7.1)
8
+
9
+ Tue, 16 Jan 2024 13:07:07 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-aria_v9.7.0..@fluentui/react-aria_v9.7.1)
11
+
12
+ ### Patches
13
+
14
+ - fix: correct version of @types/react-dom peer dep that matches for 16.x ([PR #30259](https://github.com/microsoft/fluentui/pull/30259) by mgodbolt@microsoft.com)
15
+ - Bump @fluentui/react-tabster to v9.17.1 ([PR #30299](https://github.com/microsoft/fluentui/pull/30299) by beachball)
16
+
17
+ ## [9.7.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-aria_v9.7.0)
18
+
19
+ Thu, 11 Jan 2024 09:04:28 GMT
20
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-aria_v9.6.2..@fluentui/react-aria_v9.7.0)
21
+
22
+ ### Minor changes
23
+
24
+ - feat: active descedant improvements ([PR #30253](https://github.com/microsoft/fluentui/pull/30253) by lingfan.gao@microsoft.com)
25
+
7
26
  ## [9.6.2](https://github.com/microsoft/fluentui/tree/@fluentui/react-aria_v9.6.2)
8
27
 
9
- Mon, 08 Jan 2024 16:20:07 GMT
28
+ Mon, 08 Jan 2024 16:24:28 GMT
10
29
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-aria_v9.6.1..@fluentui/react-aria_v9.6.2)
11
30
 
12
31
  ### Patches
package/dist/index.d.ts CHANGED
@@ -3,17 +3,31 @@ import * as React_2 from 'react';
3
3
  import type { ResolveShorthandFunction } from '@fluentui/react-utilities';
4
4
  import type { Slot } from '@fluentui/react-utilities';
5
5
 
6
+ /**
7
+ * Applied to the active descendant when the user is navigating with keyboard
8
+ */
9
+ export declare const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = "data-activedescendant-focusvisible";
10
+
6
11
  export declare interface ActiveDescendantImperativeRef {
7
- first: () => void;
8
- next: () => void;
9
- prev: () => void;
12
+ first: (options?: IteratorOptions) => string | undefined;
13
+ last: (options?: IteratorOptions) => string | undefined;
14
+ next: (options?: IteratorOptions) => string | undefined;
15
+ prev: (options?: IteratorOptions) => string | undefined;
16
+ find: (predicate: (id: string) => boolean, options?: IteratorOptions) => string | undefined;
10
17
  blur: () => void;
11
18
  active: () => string | undefined;
12
19
  focus: (id: string) => void;
13
20
  }
14
21
 
15
22
  export declare interface ActiveDescendantOptions {
23
+ /**
24
+ * @param el - HTML element to test
25
+ * @returns whether the element can be an active descendant
26
+ */
16
27
  matchOption: (el: HTMLElement) => boolean;
28
+ /**
29
+ * Forward imperative refs when exposing functionality from a React component
30
+ */
17
31
  imperativeRef?: React_2.RefObject<ActiveDescendantImperativeRef>;
18
32
  }
19
33
 
@@ -55,12 +69,32 @@ export declare type ARIAButtonSlotProps<AlternateAs extends 'a' | 'div' = 'a' |
55
69
 
56
70
  export declare type ARIAButtonType = 'button' | 'a' | 'div';
57
71
 
72
+ declare interface IteratorOptions {
73
+ /**
74
+ * When passive, the active descendant is changed
75
+ * @default false
76
+ */
77
+ passive?: boolean;
78
+ }
79
+
58
80
  declare type UnionToIntersection<U> = (U extends unknown ? (x: U) => U : never) extends (x: infer I) => U ? I : never;
59
81
 
60
- export declare function useActiveDescendant<TActiveParentElement extends HTMLElement, TListboxElement extends HTMLElement>(options: ActiveDescendantOptions): {
61
- listboxRef: React_2.MutableRefObject<TListboxElement | null>;
62
- activeParentRef: React_2.RefObject<TActiveParentElement>;
63
- };
82
+ export declare function useActiveDescendant<TActiveParentElement extends HTMLElement, TListboxElement extends HTMLElement>(options: ActiveDescendantOptions): UseActiveDescendantReturn<TActiveParentElement, TListboxElement>;
83
+
84
+ declare interface UseActiveDescendantReturn<TActiveParentElement extends HTMLElement = HTMLElement, TListboxElement extends HTMLElement = HTMLElement> {
85
+ /**
86
+ * Attach this to the element that contains all active descendants
87
+ */
88
+ listboxRef: React_2.Ref<TListboxElement>;
89
+ /**
90
+ * Attach this to the element that has an active descendant
91
+ */
92
+ activeParentRef: React_2.Ref<TActiveParentElement>;
93
+ /**
94
+ * Imperative functions to manage active descendants within the listboxRef
95
+ */
96
+ controller: ActiveDescendantImperativeRef;
97
+ }
64
98
 
65
99
  /**
66
100
  * @internal
@@ -1 +1,6 @@
1
- export const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';
1
+ /**
2
+ * Applied to the element that is active descendant
3
+ */ export const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';
4
+ /**
5
+ * Applied to the active descendant when the user is navigating with keyboard
6
+ */ export const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = 'data-activedescendant-focusvisible';
@@ -1 +1 @@
1
- {"version":3,"sources":["constants.ts"],"sourcesContent":["export const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';\n"],"names":["ACTIVEDESCENDANT_ATTRIBUTE"],"mappings":"AAAA,OAAO,MAAMA,6BAA6B,wBAAwB"}
1
+ {"version":3,"sources":["constants.ts"],"sourcesContent":["/**\n * Applied to the element that is active descendant\n */\nexport const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';\n\n/**\n * Applied to the active descendant when the user is navigating with keyboard\n */\nexport const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = 'data-activedescendant-focusvisible';\n"],"names":["ACTIVEDESCENDANT_ATTRIBUTE","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE"],"mappings":"AAAA;;CAEC,GACD,OAAO,MAAMA,6BAA6B,wBAAwB;AAElE;;CAEC,GACD,OAAO,MAAMC,0CAA0C,qCAAqC"}
@@ -1,2 +1,3 @@
1
1
  export * from './useActiveDescendant';
2
+ export * from './constants';
2
3
  export * from './types';
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"sourcesContent":["export * from './useActiveDescendant';\nexport * from './types';\n"],"names":[],"mappings":"AAAA,cAAc,wBAAwB;AACtC,cAAc,UAAU"}
1
+ {"version":3,"sources":["index.ts"],"sourcesContent":["export * from './useActiveDescendant';\nexport * from './constants';\nexport * from './types';\n"],"names":[],"mappings":"AAAA,cAAc,wBAAwB;AACtC,cAAc,cAAc;AAC5B,cAAc,UAAU"}
@@ -0,0 +1,19 @@
1
+ export const scrollIntoView = (target, scrollParent)=>{
2
+ if (!target || !scrollParent) {
3
+ return;
4
+ }
5
+ if (scrollParent.offsetHeight >= scrollParent.scrollHeight) {
6
+ return;
7
+ }
8
+ const { offsetHeight, offsetTop } = target;
9
+ const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;
10
+ const isAbove = offsetTop < scrollTop;
11
+ const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;
12
+ const buffer = 2;
13
+ if (isAbove) {
14
+ scrollParent.scrollTo(0, offsetTop - buffer);
15
+ }
16
+ if (isBelow) {
17
+ scrollParent.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);
18
+ }
19
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["scrollIntoView.ts"],"sourcesContent":["export const scrollIntoView = (\n target: HTMLElement | null | undefined,\n scrollParent: HTMLElement | null | undefined,\n) => {\n if (!target || !scrollParent) {\n return;\n }\n\n if (scrollParent.offsetHeight >= scrollParent.scrollHeight) {\n return;\n }\n\n const { offsetHeight, offsetTop } = target;\n const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;\n\n const isAbove = offsetTop < scrollTop;\n const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;\n\n const buffer = 2;\n\n if (isAbove) {\n scrollParent.scrollTo(0, offsetTop - buffer);\n }\n\n if (isBelow) {\n scrollParent.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);\n }\n};\n"],"names":["scrollIntoView","target","scrollParent","offsetHeight","scrollHeight","offsetTop","parentOffsetHeight","scrollTop","isAbove","isBelow","buffer","scrollTo"],"mappings":"AAAA,OAAO,MAAMA,iBAAiB,CAC5BC,QACAC;IAEA,IAAI,CAACD,UAAU,CAACC,cAAc;QAC5B;IACF;IAEA,IAAIA,aAAaC,YAAY,IAAID,aAAaE,YAAY,EAAE;QAC1D;IACF;IAEA,MAAM,EAAED,YAAY,EAAEE,SAAS,EAAE,GAAGJ;IACpC,MAAM,EAAEE,cAAcG,kBAAkB,EAAEC,SAAS,EAAE,GAAGL;IAExD,MAAMM,UAAUH,YAAYE;IAC5B,MAAME,UAAUJ,YAAYF,eAAeI,YAAYD;IAEvD,MAAMI,SAAS;IAEf,IAAIF,SAAS;QACXN,aAAaS,QAAQ,CAAC,GAAGN,YAAYK;IACvC;IAEA,IAAID,SAAS;QACXP,aAAaS,QAAQ,CAAC,GAAGN,YAAYC,qBAAqBH,eAAeO;IAC3E;AACF,EAAE"}
@@ -1 +1 @@
1
- {"version":3,"sources":["types.ts"],"sourcesContent":["import * as React from 'react';\n\nexport interface ActiveDescendantImperativeRef {\n first: () => void;\n next: () => void;\n prev: () => void;\n blur: () => void;\n active: () => string | undefined;\n focus: (id: string) => void;\n}\n\nexport interface ActiveDescendantOptions {\n matchOption: (el: HTMLElement) => boolean;\n imperativeRef?: React.RefObject<ActiveDescendantImperativeRef>;\n}\n"],"names":["React"],"mappings":"AAAA,YAAYA,WAAW,QAAQ"}
1
+ {"version":3,"sources":["types.ts"],"sourcesContent":["import * as React from 'react';\n\nexport interface ActiveDescendantImperativeRef {\n first: (options?: IteratorOptions) => string | undefined;\n last: (options?: IteratorOptions) => string | undefined;\n next: (options?: IteratorOptions) => string | undefined;\n prev: (options?: IteratorOptions) => string | undefined;\n find: (predicate: (id: string) => boolean, options?: IteratorOptions) => string | undefined;\n blur: () => void;\n active: () => string | undefined;\n focus: (id: string) => void;\n}\n\nexport interface ActiveDescendantOptions {\n /**\n * @param el - HTML element to test\n * @returns whether the element can be an active descendant\n */\n matchOption: (el: HTMLElement) => boolean;\n /**\n * Forward imperative refs when exposing functionality from a React component\n */\n imperativeRef?: React.RefObject<ActiveDescendantImperativeRef>;\n}\n\nexport interface UseActiveDescendantReturn<\n TActiveParentElement extends HTMLElement = HTMLElement,\n TListboxElement extends HTMLElement = HTMLElement,\n> {\n /**\n * Attach this to the element that contains all active descendants\n */\n listboxRef: React.Ref<TListboxElement>;\n /**\n * Attach this to the element that has an active descendant\n */\n activeParentRef: React.Ref<TActiveParentElement>;\n /**\n * Imperative functions to manage active descendants within the listboxRef\n */\n controller: ActiveDescendantImperativeRef;\n}\n\nexport interface IteratorOptions {\n /**\n * When passive, the active descendant is changed\n * @default false\n */\n passive?: boolean;\n}\n"],"names":["React"],"mappings":"AAAA,YAAYA,WAAW,QAAQ"}
@@ -1,120 +1,140 @@
1
1
  import * as React from 'react';
2
+ import { useEventCallback } from '@fluentui/react-utilities';
3
+ import { useOnKeyboardNavigationChange } from '@fluentui/react-tabster';
2
4
  import { useOptionWalker } from './useOptionWalker';
3
- import { ACTIVEDESCENDANT_ATTRIBUTE } from './constants';
5
+ import { ACTIVEDESCENDANT_ATTRIBUTE, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './constants';
6
+ import { scrollIntoView } from './scrollIntoView';
4
7
  export function useActiveDescendant(options) {
5
- const { imperativeRef, matchOption } = options;
8
+ const { imperativeRef, matchOption: matchOptionUnstable } = options;
9
+ const focusVisibleRef = React.useRef(false);
10
+ const activeIdRef = React.useRef(null);
6
11
  const activeParentRef = React.useRef(null);
12
+ useOnKeyboardNavigationChange((isNavigatingWithKeyboard)=>{
13
+ focusVisibleRef.current = isNavigatingWithKeyboard;
14
+ const active = getActiveDescendant();
15
+ if (!active) {
16
+ return;
17
+ }
18
+ if (isNavigatingWithKeyboard) {
19
+ active.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
20
+ } else {
21
+ active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
22
+ }
23
+ });
24
+ const matchOption = useEventCallback(matchOptionUnstable);
7
25
  const { listboxRef, optionWalker } = useOptionWalker({
8
26
  matchOption
9
27
  });
10
- const getActiveDescendant = ()=>{
28
+ const getActiveDescendant = React.useCallback(()=>{
11
29
  var _listboxRef_current;
12
- return (_listboxRef_current = listboxRef.current) === null || _listboxRef_current === void 0 ? void 0 : _listboxRef_current.querySelector(`[${ACTIVEDESCENDANT_ATTRIBUTE}]`);
13
- };
14
- const scrollActiveIntoView = (active)=>{
15
- if (!listboxRef.current) {
16
- return;
17
- }
18
- if (listboxRef.current.offsetHeight >= listboxRef.current.scrollHeight) {
19
- return;
20
- }
21
- const { offsetHeight, offsetTop } = active;
22
- const { offsetHeight: parentOffsetHeight, scrollTop } = listboxRef.current;
23
- const isAbove = offsetTop < scrollTop;
24
- const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;
25
- const buffer = 2;
26
- if (isAbove) {
27
- listboxRef.current.scrollTo(0, offsetTop - buffer);
28
- }
29
- if (isBelow) {
30
- listboxRef.current.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);
31
- }
32
- };
33
- const setActiveDescendant = (nextActive)=>{
30
+ return (_listboxRef_current = listboxRef.current) === null || _listboxRef_current === void 0 ? void 0 : _listboxRef_current.querySelector(`#${activeIdRef.current}`);
31
+ }, [
32
+ listboxRef
33
+ ]);
34
+ const blurActiveDescendant = React.useCallback(()=>{
35
+ var _activeParentRef_current;
34
36
  const active = getActiveDescendant();
35
37
  if (active) {
36
38
  active.removeAttribute(ACTIVEDESCENDANT_ATTRIBUTE);
39
+ active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
37
40
  }
38
- if (nextActive) {
39
- var _activeParentRef_current;
40
- nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');
41
- scrollActiveIntoView(nextActive);
42
- (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.setAttribute('aria-activedescendant', nextActive.id);
43
- } else {
44
- var _activeParentRef_current1;
45
- (_activeParentRef_current1 = activeParentRef.current) === null || _activeParentRef_current1 === void 0 ? void 0 : _activeParentRef_current1.removeAttribute('aria-activedescendant');
41
+ (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.removeAttribute('aria-activedescendant');
42
+ activeIdRef.current = null;
43
+ }, [
44
+ activeParentRef,
45
+ getActiveDescendant
46
+ ]);
47
+ const focusActiveDescendant = React.useCallback((nextActive)=>{
48
+ var _activeParentRef_current;
49
+ if (!nextActive) {
50
+ return;
46
51
  }
47
- };
48
- React.useImperativeHandle(imperativeRef, ()=>({
49
- first: ()=>{
50
- if (!listboxRef.current || !activeParentRef.current) {
51
- return;
52
- }
53
- optionWalker.setCurrent(listboxRef.current);
52
+ blurActiveDescendant();
53
+ scrollIntoView(nextActive, listboxRef.current);
54
+ (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.setAttribute('aria-activedescendant', nextActive.id);
55
+ activeIdRef.current = nextActive.id;
56
+ nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');
57
+ if (focusVisibleRef.current) {
58
+ nextActive.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
59
+ }
60
+ }, [
61
+ activeParentRef,
62
+ listboxRef,
63
+ blurActiveDescendant
64
+ ]);
65
+ const controller = React.useMemo(()=>({
66
+ first: ({ passive } = {})=>{
54
67
  const first = optionWalker.first();
55
- if (first) {
56
- setActiveDescendant(first);
68
+ if (!passive) {
69
+ focusActiveDescendant(first);
57
70
  }
71
+ return first === null || first === void 0 ? void 0 : first.id;
58
72
  },
59
- next: ()=>{
60
- if (!listboxRef.current || !activeParentRef.current) {
61
- return;
73
+ last: ({ passive } = {})=>{
74
+ const last = optionWalker.last();
75
+ if (!passive) {
76
+ focusActiveDescendant(last);
62
77
  }
78
+ return last === null || last === void 0 ? void 0 : last.id;
79
+ },
80
+ next: ({ passive } = {})=>{
63
81
  const active = getActiveDescendant();
64
82
  if (!active) {
65
83
  return;
66
84
  }
67
85
  optionWalker.setCurrent(active);
68
86
  const next = optionWalker.next();
69
- if (next) {
70
- setActiveDescendant(next);
87
+ if (!passive) {
88
+ focusActiveDescendant(next);
71
89
  }
90
+ return next === null || next === void 0 ? void 0 : next.id;
72
91
  },
73
- prev: ()=>{
74
- if (!listboxRef.current || !activeParentRef.current) {
75
- return;
76
- }
92
+ prev: ({ passive } = {})=>{
77
93
  const active = getActiveDescendant();
78
94
  if (!active) {
79
95
  return;
80
96
  }
81
97
  optionWalker.setCurrent(active);
82
- if (!matchOption(active)) {
83
- optionWalker.prev();
84
- }
85
98
  const next = optionWalker.prev();
86
- if (next && next !== listboxRef.current) {
87
- setActiveDescendant(next);
99
+ if (!passive) {
100
+ focusActiveDescendant(next);
88
101
  }
102
+ return next === null || next === void 0 ? void 0 : next.id;
89
103
  },
90
104
  blur: ()=>{
91
- if (!activeParentRef.current) {
92
- return;
93
- }
94
- setActiveDescendant(undefined);
105
+ blurActiveDescendant();
95
106
  },
96
107
  active: ()=>{
97
- if (listboxRef.current) {
98
- var _getActiveDescendant;
99
- return (_getActiveDescendant = getActiveDescendant()) === null || _getActiveDescendant === void 0 ? void 0 : _getActiveDescendant.id;
100
- }
108
+ var _getActiveDescendant;
109
+ return (_getActiveDescendant = getActiveDescendant()) === null || _getActiveDescendant === void 0 ? void 0 : _getActiveDescendant.id;
101
110
  },
102
111
  focus: (id)=>{
103
112
  if (!listboxRef.current) {
104
113
  return;
105
114
  }
106
- optionWalker.setCurrent(listboxRef.current);
107
- let cur = optionWalker.next();
108
- while(cur && cur.id !== id){
109
- cur = optionWalker.next();
115
+ const target = listboxRef.current.querySelector(`#${id}`);
116
+ if (target) {
117
+ focusActiveDescendant(target);
110
118
  }
111
- if (cur) {
112
- setActiveDescendant(cur);
119
+ },
120
+ find (predicate, { passive } = {}) {
121
+ const target = optionWalker.find(predicate);
122
+ if (!passive) {
123
+ focusActiveDescendant(target);
113
124
  }
125
+ return target === null || target === void 0 ? void 0 : target.id;
114
126
  }
115
- }));
127
+ }), [
128
+ optionWalker,
129
+ listboxRef,
130
+ focusActiveDescendant,
131
+ blurActiveDescendant,
132
+ getActiveDescendant
133
+ ]);
134
+ React.useImperativeHandle(imperativeRef, ()=>controller);
116
135
  return {
117
136
  listboxRef,
118
- activeParentRef
137
+ activeParentRef,
138
+ controller
119
139
  };
120
140
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["useActiveDescendant.ts"],"sourcesContent":["import * as React from 'react';\nimport { useOptionWalker } from './useOptionWalker';\nimport type { ActiveDescendantOptions } from './types';\nimport { ACTIVEDESCENDANT_ATTRIBUTE } from './constants';\n\nexport function useActiveDescendant<TActiveParentElement extends HTMLElement, TListboxElement extends HTMLElement>(\n options: ActiveDescendantOptions,\n) {\n const { imperativeRef, matchOption } = options;\n const activeParentRef = React.useRef<TActiveParentElement>(null);\n const { listboxRef, optionWalker } = useOptionWalker<TListboxElement>({ matchOption });\n const getActiveDescendant = () => {\n return listboxRef.current?.querySelector<HTMLElement>(`[${ACTIVEDESCENDANT_ATTRIBUTE}]`);\n };\n\n const scrollActiveIntoView = (active: HTMLElement) => {\n if (!listboxRef.current) {\n return;\n }\n\n if (listboxRef.current.offsetHeight >= listboxRef.current.scrollHeight) {\n return;\n }\n\n const { offsetHeight, offsetTop } = active;\n const { offsetHeight: parentOffsetHeight, scrollTop } = listboxRef.current;\n\n const isAbove = offsetTop < scrollTop;\n const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;\n\n const buffer = 2;\n\n if (isAbove) {\n listboxRef.current.scrollTo(0, offsetTop - buffer);\n }\n\n if (isBelow) {\n listboxRef.current.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);\n }\n };\n\n const setActiveDescendant = (nextActive: HTMLElement | undefined) => {\n const active = getActiveDescendant();\n if (active) {\n active.removeAttribute(ACTIVEDESCENDANT_ATTRIBUTE);\n }\n\n if (nextActive) {\n nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');\n scrollActiveIntoView(nextActive);\n activeParentRef.current?.setAttribute('aria-activedescendant', nextActive.id);\n } else {\n activeParentRef.current?.removeAttribute('aria-activedescendant');\n }\n };\n\n React.useImperativeHandle(imperativeRef, () => ({\n first: () => {\n if (!listboxRef.current || !activeParentRef.current) {\n return;\n }\n\n optionWalker.setCurrent(listboxRef.current);\n const first = optionWalker.first();\n if (first) {\n setActiveDescendant(first);\n }\n },\n next: () => {\n if (!listboxRef.current || !activeParentRef.current) {\n return;\n }\n\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n\n optionWalker.setCurrent(active);\n const next = optionWalker.next();\n if (next) {\n setActiveDescendant(next);\n }\n },\n prev: () => {\n if (!listboxRef.current || !activeParentRef.current) {\n return;\n }\n\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n\n optionWalker.setCurrent(active);\n if (!matchOption(active)) {\n optionWalker.prev();\n }\n\n const next = optionWalker.prev();\n\n if (next && next !== listboxRef.current) {\n setActiveDescendant(next);\n }\n },\n blur: () => {\n if (!activeParentRef.current) {\n return;\n }\n\n setActiveDescendant(undefined);\n },\n active: () => {\n if (listboxRef.current) {\n return getActiveDescendant()?.id;\n }\n },\n\n focus: (id: string) => {\n if (!listboxRef.current) {\n return;\n }\n\n optionWalker.setCurrent(listboxRef.current);\n let cur = optionWalker.next();\n\n while (cur && cur.id !== id) {\n cur = optionWalker.next();\n }\n\n if (cur) {\n setActiveDescendant(cur);\n }\n },\n }));\n\n return { listboxRef, activeParentRef };\n}\n"],"names":["React","useOptionWalker","ACTIVEDESCENDANT_ATTRIBUTE","useActiveDescendant","options","imperativeRef","matchOption","activeParentRef","useRef","listboxRef","optionWalker","getActiveDescendant","current","querySelector","scrollActiveIntoView","active","offsetHeight","scrollHeight","offsetTop","parentOffsetHeight","scrollTop","isAbove","isBelow","buffer","scrollTo","setActiveDescendant","nextActive","removeAttribute","setAttribute","id","useImperativeHandle","first","setCurrent","next","prev","blur","undefined","focus","cur"],"mappings":"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"}
1
+ {"version":3,"sources":["useActiveDescendant.ts"],"sourcesContent":["import * as React from 'react';\nimport { useEventCallback } from '@fluentui/react-utilities';\nimport { useOnKeyboardNavigationChange } from '@fluentui/react-tabster';\nimport { useOptionWalker } from './useOptionWalker';\nimport type { ActiveDescendantImperativeRef, ActiveDescendantOptions, UseActiveDescendantReturn } from './types';\nimport { ACTIVEDESCENDANT_ATTRIBUTE, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './constants';\nimport { scrollIntoView } from './scrollIntoView';\n\nexport function useActiveDescendant<TActiveParentElement extends HTMLElement, TListboxElement extends HTMLElement>(\n options: ActiveDescendantOptions,\n): UseActiveDescendantReturn<TActiveParentElement, TListboxElement> {\n const { imperativeRef, matchOption: matchOptionUnstable } = options;\n const focusVisibleRef = React.useRef(false);\n const activeIdRef = React.useRef<string | null>(null);\n const activeParentRef = React.useRef<TActiveParentElement>(null);\n\n useOnKeyboardNavigationChange(isNavigatingWithKeyboard => {\n focusVisibleRef.current = isNavigatingWithKeyboard;\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n\n if (isNavigatingWithKeyboard) {\n active.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');\n } else {\n active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);\n }\n });\n\n const matchOption = useEventCallback(matchOptionUnstable);\n const { listboxRef, optionWalker } = useOptionWalker<TListboxElement>({ matchOption });\n const getActiveDescendant = React.useCallback(() => {\n return listboxRef.current?.querySelector<HTMLElement>(`#${activeIdRef.current}`);\n }, [listboxRef]);\n\n const blurActiveDescendant = React.useCallback(() => {\n const active = getActiveDescendant();\n if (active) {\n active.removeAttribute(ACTIVEDESCENDANT_ATTRIBUTE);\n active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);\n }\n\n activeParentRef.current?.removeAttribute('aria-activedescendant');\n activeIdRef.current = null;\n }, [activeParentRef, getActiveDescendant]);\n\n const focusActiveDescendant = React.useCallback(\n (nextActive: HTMLElement | null) => {\n if (!nextActive) {\n return;\n }\n\n blurActiveDescendant();\n\n scrollIntoView(nextActive, listboxRef.current);\n activeParentRef.current?.setAttribute('aria-activedescendant', nextActive.id);\n activeIdRef.current = nextActive.id;\n nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');\n\n if (focusVisibleRef.current) {\n nextActive.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');\n }\n },\n [activeParentRef, listboxRef, blurActiveDescendant],\n );\n\n const controller: ActiveDescendantImperativeRef = React.useMemo(\n () => ({\n first: ({ passive } = {}) => {\n const first = optionWalker.first();\n if (!passive) {\n focusActiveDescendant(first);\n }\n\n return first?.id;\n },\n last: ({ passive } = {}) => {\n const last = optionWalker.last();\n if (!passive) {\n focusActiveDescendant(last);\n }\n\n return last?.id;\n },\n next: ({ passive } = {}) => {\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n\n optionWalker.setCurrent(active);\n const next = optionWalker.next();\n if (!passive) {\n focusActiveDescendant(next);\n }\n\n return next?.id;\n },\n prev: ({ passive } = {}) => {\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n\n optionWalker.setCurrent(active);\n const next = optionWalker.prev();\n\n if (!passive) {\n focusActiveDescendant(next);\n }\n\n return next?.id;\n },\n blur: () => {\n blurActiveDescendant();\n },\n active: () => {\n return getActiveDescendant()?.id;\n },\n\n focus: (id: string) => {\n if (!listboxRef.current) {\n return;\n }\n\n const target = listboxRef.current.querySelector<HTMLElement>(`#${id}`);\n if (target) {\n focusActiveDescendant(target);\n }\n },\n\n find(predicate, { passive } = {}) {\n const target = optionWalker.find(predicate);\n if (!passive) {\n focusActiveDescendant(target);\n }\n\n return target?.id;\n },\n }),\n [optionWalker, listboxRef, focusActiveDescendant, blurActiveDescendant, getActiveDescendant],\n );\n\n React.useImperativeHandle(imperativeRef, () => controller);\n\n return { listboxRef, activeParentRef, controller };\n}\n"],"names":["React","useEventCallback","useOnKeyboardNavigationChange","useOptionWalker","ACTIVEDESCENDANT_ATTRIBUTE","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE","scrollIntoView","useActiveDescendant","options","imperativeRef","matchOption","matchOptionUnstable","focusVisibleRef","useRef","activeIdRef","activeParentRef","isNavigatingWithKeyboard","current","active","getActiveDescendant","setAttribute","removeAttribute","listboxRef","optionWalker","useCallback","querySelector","blurActiveDescendant","focusActiveDescendant","nextActive","id","controller","useMemo","first","passive","last","next","setCurrent","prev","blur","focus","target","find","predicate","useImperativeHandle"],"mappings":"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"}
@@ -25,11 +25,18 @@ export function useOptionWalker(options) {
25
25
  ]);
26
26
  const optionWalker = React.useMemo(()=>({
27
27
  first: ()=>{
28
- if (!treeWalkerRef.current) {
28
+ if (!treeWalkerRef.current || !listboxRef.current) {
29
29
  return null;
30
30
  }
31
+ treeWalkerRef.current.currentNode = listboxRef.current;
31
32
  return treeWalkerRef.current.firstChild();
32
33
  },
34
+ last: ()=>{
35
+ if (!treeWalkerRef.current || !listboxRef.current) {
36
+ return null;
37
+ }
38
+ return treeWalkerRef.current.lastChild();
39
+ },
33
40
  next: ()=>{
34
41
  if (!treeWalkerRef.current) {
35
42
  return null;
@@ -42,6 +49,17 @@ export function useOptionWalker(options) {
42
49
  }
43
50
  return treeWalkerRef.current.previousNode();
44
51
  },
52
+ find: (predicate)=>{
53
+ if (!treeWalkerRef.current || !listboxRef.current) {
54
+ return null;
55
+ }
56
+ treeWalkerRef.current.currentNode = listboxRef.current;
57
+ let cur = treeWalkerRef.current.currentNode;
58
+ while(cur && !predicate(cur.id)){
59
+ cur = treeWalkerRef.current.nextNode();
60
+ }
61
+ return cur;
62
+ },
45
63
  setCurrent: (el)=>{
46
64
  if (!treeWalkerRef.current) {
47
65
  return;
@@ -1 +1 @@
1
- {"version":3,"sources":["useOptionWalker.ts"],"sourcesContent":["import * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { isHTMLElement, useIsomorphicLayoutEffect } from '@fluentui/react-utilities';\n\ninterface UseOptionWalkerOptions {\n matchOption: (el: HTMLElement) => boolean;\n}\n\nexport function useOptionWalker<TListboxElement extends HTMLElement>(options: UseOptionWalkerOptions) {\n const { matchOption } = options;\n const { targetDocument } = useFluent();\n const treeWalkerRef = React.useRef<TreeWalker | null>(null);\n const listboxRef = React.useRef<TListboxElement | null>(null);\n\n const optionFilter = React.useCallback(\n (node: Node) => {\n if (isHTMLElement(node) && matchOption(node)) {\n return NodeFilter.FILTER_ACCEPT;\n }\n\n return NodeFilter.FILTER_SKIP;\n },\n [matchOption],\n );\n\n useIsomorphicLayoutEffect(() => {\n if (!targetDocument || !listboxRef.current) {\n return;\n }\n\n treeWalkerRef.current = targetDocument.createTreeWalker(listboxRef.current, NodeFilter.SHOW_ELEMENT, optionFilter);\n }, [targetDocument, optionFilter]);\n\n const optionWalker = React.useMemo(\n () => ({\n first: () => {\n if (!treeWalkerRef.current) {\n return null;\n }\n\n return treeWalkerRef.current.firstChild() as HTMLElement | null;\n },\n next: () => {\n if (!treeWalkerRef.current) {\n return null;\n }\n\n return treeWalkerRef.current.nextNode() as HTMLElement | null;\n },\n prev: () => {\n if (!treeWalkerRef.current) {\n return null;\n }\n\n return treeWalkerRef.current.previousNode() as HTMLElement | null;\n },\n setCurrent: (el: HTMLElement) => {\n if (!treeWalkerRef.current) {\n return;\n }\n\n treeWalkerRef.current.currentNode = el;\n },\n }),\n [],\n );\n\n return {\n optionWalker,\n listboxRef,\n };\n}\n"],"names":["React","useFluent_unstable","useFluent","isHTMLElement","useIsomorphicLayoutEffect","useOptionWalker","options","matchOption","targetDocument","treeWalkerRef","useRef","listboxRef","optionFilter","useCallback","node","NodeFilter","FILTER_ACCEPT","FILTER_SKIP","current","createTreeWalker","SHOW_ELEMENT","optionWalker","useMemo","first","firstChild","next","nextNode","prev","previousNode","setCurrent","el","currentNode"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,aAAa,EAAEC,yBAAyB,QAAQ,4BAA4B;AAMrF,OAAO,SAASC,gBAAqDC,OAA+B;IAClG,MAAM,EAAEC,WAAW,EAAE,GAAGD;IACxB,MAAM,EAAEE,cAAc,EAAE,GAAGN;IAC3B,MAAMO,gBAAgBT,MAAMU,MAAM,CAAoB;IACtD,MAAMC,aAAaX,MAAMU,MAAM,CAAyB;IAExD,MAAME,eAAeZ,MAAMa,WAAW,CACpC,CAACC;QACC,IAAIX,cAAcW,SAASP,YAAYO,OAAO;YAC5C,OAAOC,WAAWC,aAAa;QACjC;QAEA,OAAOD,WAAWE,WAAW;IAC/B,GACA;QAACV;KAAY;IAGfH,0BAA0B;QACxB,IAAI,CAACI,kBAAkB,CAACG,WAAWO,OAAO,EAAE;YAC1C;QACF;QAEAT,cAAcS,OAAO,GAAGV,eAAeW,gBAAgB,CAACR,WAAWO,OAAO,EAAEH,WAAWK,YAAY,EAAER;IACvG,GAAG;QAACJ;QAAgBI;KAAa;IAEjC,MAAMS,eAAerB,MAAMsB,OAAO,CAChC,IAAO,CAAA;YACLC,OAAO;gBACL,IAAI,CAACd,cAAcS,OAAO,EAAE;oBAC1B,OAAO;gBACT;gBAEA,OAAOT,cAAcS,OAAO,CAACM,UAAU;YACzC;YACAC,MAAM;gBACJ,IAAI,CAAChB,cAAcS,OAAO,EAAE;oBAC1B,OAAO;gBACT;gBAEA,OAAOT,cAAcS,OAAO,CAACQ,QAAQ;YACvC;YACAC,MAAM;gBACJ,IAAI,CAAClB,cAAcS,OAAO,EAAE;oBAC1B,OAAO;gBACT;gBAEA,OAAOT,cAAcS,OAAO,CAACU,YAAY;YAC3C;YACAC,YAAY,CAACC;gBACX,IAAI,CAACrB,cAAcS,OAAO,EAAE;oBAC1B;gBACF;gBAEAT,cAAcS,OAAO,CAACa,WAAW,GAAGD;YACtC;QACF,CAAA,GACA,EAAE;IAGJ,OAAO;QACLT;QACAV;IACF;AACF"}
1
+ {"version":3,"sources":["useOptionWalker.ts"],"sourcesContent":["import * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { isHTMLElement, useIsomorphicLayoutEffect } from '@fluentui/react-utilities';\n\ninterface UseOptionWalkerOptions {\n matchOption: (el: HTMLElement) => boolean;\n}\n\nexport function useOptionWalker<TListboxElement extends HTMLElement>(options: UseOptionWalkerOptions) {\n const { matchOption } = options;\n const { targetDocument } = useFluent();\n const treeWalkerRef = React.useRef<TreeWalker | null>(null);\n const listboxRef = React.useRef<TListboxElement | null>(null);\n\n const optionFilter = React.useCallback(\n (node: Node) => {\n if (isHTMLElement(node) && matchOption(node)) {\n return NodeFilter.FILTER_ACCEPT;\n }\n\n return NodeFilter.FILTER_SKIP;\n },\n [matchOption],\n );\n\n useIsomorphicLayoutEffect(() => {\n if (!targetDocument || !listboxRef.current) {\n return;\n }\n\n treeWalkerRef.current = targetDocument.createTreeWalker(listboxRef.current, NodeFilter.SHOW_ELEMENT, optionFilter);\n }, [targetDocument, optionFilter]);\n\n const optionWalker = React.useMemo(\n () => ({\n first: () => {\n if (!treeWalkerRef.current || !listboxRef.current) {\n return null;\n }\n\n treeWalkerRef.current.currentNode = listboxRef.current;\n return treeWalkerRef.current.firstChild() as HTMLElement | null;\n },\n last: () => {\n if (!treeWalkerRef.current || !listboxRef.current) {\n return null;\n }\n\n return treeWalkerRef.current.lastChild() as HTMLElement | null;\n },\n next: () => {\n if (!treeWalkerRef.current) {\n return null;\n }\n\n return treeWalkerRef.current.nextNode() as HTMLElement | null;\n },\n prev: () => {\n if (!treeWalkerRef.current) {\n return null;\n }\n\n return treeWalkerRef.current.previousNode() as HTMLElement | null;\n },\n find: (predicate: (id: string) => boolean) => {\n if (!treeWalkerRef.current || !listboxRef.current) {\n return null;\n }\n\n treeWalkerRef.current.currentNode = listboxRef.current;\n let cur: HTMLElement | null = treeWalkerRef.current.currentNode as HTMLElement;\n while (cur && !predicate(cur.id)) {\n cur = treeWalkerRef.current.nextNode() as HTMLElement | null;\n }\n\n return cur;\n },\n setCurrent: (el: HTMLElement) => {\n if (!treeWalkerRef.current) {\n return;\n }\n\n treeWalkerRef.current.currentNode = el;\n },\n }),\n [],\n );\n\n return {\n optionWalker,\n listboxRef,\n };\n}\n"],"names":["React","useFluent_unstable","useFluent","isHTMLElement","useIsomorphicLayoutEffect","useOptionWalker","options","matchOption","targetDocument","treeWalkerRef","useRef","listboxRef","optionFilter","useCallback","node","NodeFilter","FILTER_ACCEPT","FILTER_SKIP","current","createTreeWalker","SHOW_ELEMENT","optionWalker","useMemo","first","currentNode","firstChild","last","lastChild","next","nextNode","prev","previousNode","find","predicate","cur","id","setCurrent","el"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,aAAa,EAAEC,yBAAyB,QAAQ,4BAA4B;AAMrF,OAAO,SAASC,gBAAqDC,OAA+B;IAClG,MAAM,EAAEC,WAAW,EAAE,GAAGD;IACxB,MAAM,EAAEE,cAAc,EAAE,GAAGN;IAC3B,MAAMO,gBAAgBT,MAAMU,MAAM,CAAoB;IACtD,MAAMC,aAAaX,MAAMU,MAAM,CAAyB;IAExD,MAAME,eAAeZ,MAAMa,WAAW,CACpC,CAACC;QACC,IAAIX,cAAcW,SAASP,YAAYO,OAAO;YAC5C,OAAOC,WAAWC,aAAa;QACjC;QAEA,OAAOD,WAAWE,WAAW;IAC/B,GACA;QAACV;KAAY;IAGfH,0BAA0B;QACxB,IAAI,CAACI,kBAAkB,CAACG,WAAWO,OAAO,EAAE;YAC1C;QACF;QAEAT,cAAcS,OAAO,GAAGV,eAAeW,gBAAgB,CAACR,WAAWO,OAAO,EAAEH,WAAWK,YAAY,EAAER;IACvG,GAAG;QAACJ;QAAgBI;KAAa;IAEjC,MAAMS,eAAerB,MAAMsB,OAAO,CAChC,IAAO,CAAA;YACLC,OAAO;gBACL,IAAI,CAACd,cAAcS,OAAO,IAAI,CAACP,WAAWO,OAAO,EAAE;oBACjD,OAAO;gBACT;gBAEAT,cAAcS,OAAO,CAACM,WAAW,GAAGb,WAAWO,OAAO;gBACtD,OAAOT,cAAcS,OAAO,CAACO,UAAU;YACzC;YACAC,MAAM;gBACJ,IAAI,CAACjB,cAAcS,OAAO,IAAI,CAACP,WAAWO,OAAO,EAAE;oBACjD,OAAO;gBACT;gBAEA,OAAOT,cAAcS,OAAO,CAACS,SAAS;YACxC;YACAC,MAAM;gBACJ,IAAI,CAACnB,cAAcS,OAAO,EAAE;oBAC1B,OAAO;gBACT;gBAEA,OAAOT,cAAcS,OAAO,CAACW,QAAQ;YACvC;YACAC,MAAM;gBACJ,IAAI,CAACrB,cAAcS,OAAO,EAAE;oBAC1B,OAAO;gBACT;gBAEA,OAAOT,cAAcS,OAAO,CAACa,YAAY;YAC3C;YACAC,MAAM,CAACC;gBACL,IAAI,CAACxB,cAAcS,OAAO,IAAI,CAACP,WAAWO,OAAO,EAAE;oBACjD,OAAO;gBACT;gBAEAT,cAAcS,OAAO,CAACM,WAAW,GAAGb,WAAWO,OAAO;gBACtD,IAAIgB,MAA0BzB,cAAcS,OAAO,CAACM,WAAW;gBAC/D,MAAOU,OAAO,CAACD,UAAUC,IAAIC,EAAE,EAAG;oBAChCD,MAAMzB,cAAcS,OAAO,CAACW,QAAQ;gBACtC;gBAEA,OAAOK;YACT;YACAE,YAAY,CAACC;gBACX,IAAI,CAAC5B,cAAcS,OAAO,EAAE;oBAC1B;gBACF;gBAEAT,cAAcS,OAAO,CAACM,WAAW,GAAGa;YACtC;QACF,CAAA,GACA,EAAE;IAGJ,OAAO;QACLhB;QACAV;IACF;AACF"}
package/lib/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { // eslint-disable-next-line deprecation/deprecation
2
2
  useARIAButtonShorthand, useARIAButtonProps } from './button/index';
3
- export { useActiveDescendant } from './activedescendant';
3
+ export { useActiveDescendant, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './activedescendant';
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"sourcesContent":["export {\n // eslint-disable-next-line deprecation/deprecation\n useARIAButtonShorthand,\n useARIAButtonProps,\n} from './button/index';\nexport { useActiveDescendant } from './activedescendant';\nexport type { ActiveDescendantImperativeRef, ActiveDescendantOptions } from './activedescendant';\nexport type {\n ARIAButtonSlotProps,\n ARIAButtonProps,\n ARIAButtonResultProps,\n ARIAButtonType,\n ARIAButtonElement,\n ARIAButtonElementIntersection,\n ARIAButtonAlteredProps,\n} from './button/index';\n"],"names":["useARIAButtonShorthand","useARIAButtonProps","useActiveDescendant"],"mappings":"AAAA,SACE,mDAAmD;AACnDA,sBAAsB,EACtBC,kBAAkB,QACb,iBAAiB;AACxB,SAASC,mBAAmB,QAAQ,qBAAqB"}
1
+ {"version":3,"sources":["index.ts"],"sourcesContent":["export {\n // eslint-disable-next-line deprecation/deprecation\n useARIAButtonShorthand,\n useARIAButtonProps,\n} from './button/index';\nexport { useActiveDescendant, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './activedescendant';\nexport type { ActiveDescendantImperativeRef, ActiveDescendantOptions } from './activedescendant';\nexport type {\n ARIAButtonSlotProps,\n ARIAButtonProps,\n ARIAButtonResultProps,\n ARIAButtonType,\n ARIAButtonElement,\n ARIAButtonElementIntersection,\n ARIAButtonAlteredProps,\n} from './button/index';\n"],"names":["useARIAButtonShorthand","useARIAButtonProps","useActiveDescendant","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE"],"mappings":"AAAA,SACE,mDAAmD;AACnDA,sBAAsB,EACtBC,kBAAkB,QACb,iBAAiB;AACxB,SAASC,mBAAmB,EAAEC,uCAAuC,QAAQ,qBAAqB"}
@@ -1,11 +1,22 @@
1
- "use strict";
1
+ /**
2
+ * Applied to the element that is active descendant
3
+ */ "use strict";
2
4
  Object.defineProperty(exports, "__esModule", {
3
5
  value: true
4
6
  });
5
- Object.defineProperty(exports, "ACTIVEDESCENDANT_ATTRIBUTE", {
6
- enumerable: true,
7
- get: function() {
7
+ function _export(target, all) {
8
+ for(var name in all)Object.defineProperty(target, name, {
9
+ enumerable: true,
10
+ get: all[name]
11
+ });
12
+ }
13
+ _export(exports, {
14
+ ACTIVEDESCENDANT_ATTRIBUTE: function() {
8
15
  return ACTIVEDESCENDANT_ATTRIBUTE;
16
+ },
17
+ ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE: function() {
18
+ return ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE;
9
19
  }
10
20
  });
11
21
  const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';
22
+ const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = 'data-activedescendant-focusvisible';
@@ -1 +1 @@
1
- {"version":3,"sources":["constants.js"],"sourcesContent":["export const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';\n"],"names":["ACTIVEDESCENDANT_ATTRIBUTE"],"mappings":";;;;+BAAaA;;;eAAAA;;;AAAN,MAAMA,6BAA6B"}
1
+ {"version":3,"sources":["constants.js"],"sourcesContent":["/**\n * Applied to the element that is active descendant\n */ export const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';\n/**\n * Applied to the active descendant when the user is navigating with keyboard\n */ export const ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE = 'data-activedescendant-focusvisible';\n"],"names":["ACTIVEDESCENDANT_ATTRIBUTE","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE"],"mappings":"AAAA;;CAEC;;;;;;;;;;;IAAgBA,0BAA0B;eAA1BA;;IAGAC,uCAAuC;eAAvCA;;;AAHN,MAAMD,6BAA6B;AAGnC,MAAMC,0CAA0C"}
@@ -4,4 +4,5 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  const _export_star = require("@swc/helpers/_/_export_star");
6
6
  _export_star._(require("./useActiveDescendant"), exports);
7
+ _export_star._(require("./constants"), exports);
7
8
  _export_star._(require("./types"), exports);
@@ -1 +1 @@
1
- {"version":3,"sources":["index.js"],"sourcesContent":["export * from './useActiveDescendant';\nexport * from './types';\n"],"names":[],"mappings":";;;;;uBAAc;uBACA"}
1
+ {"version":3,"sources":["index.js"],"sourcesContent":["export * from './useActiveDescendant';\nexport * from './constants';\nexport * from './types';\n"],"names":[],"mappings":";;;;;uBAAc;uBACA;uBACA"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "scrollIntoView", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return scrollIntoView;
9
+ }
10
+ });
11
+ const scrollIntoView = (target, scrollParent)=>{
12
+ if (!target || !scrollParent) {
13
+ return;
14
+ }
15
+ if (scrollParent.offsetHeight >= scrollParent.scrollHeight) {
16
+ return;
17
+ }
18
+ const { offsetHeight, offsetTop } = target;
19
+ const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;
20
+ const isAbove = offsetTop < scrollTop;
21
+ const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;
22
+ const buffer = 2;
23
+ if (isAbove) {
24
+ scrollParent.scrollTo(0, offsetTop - buffer);
25
+ }
26
+ if (isBelow) {
27
+ scrollParent.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);
28
+ }
29
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["scrollIntoView.js"],"sourcesContent":["export const scrollIntoView = (target, scrollParent)=>{\n if (!target || !scrollParent) {\n return;\n }\n if (scrollParent.offsetHeight >= scrollParent.scrollHeight) {\n return;\n }\n const { offsetHeight, offsetTop } = target;\n const { offsetHeight: parentOffsetHeight, scrollTop } = scrollParent;\n const isAbove = offsetTop < scrollTop;\n const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;\n const buffer = 2;\n if (isAbove) {\n scrollParent.scrollTo(0, offsetTop - buffer);\n }\n if (isBelow) {\n scrollParent.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);\n }\n};\n"],"names":["scrollIntoView","target","scrollParent","offsetHeight","scrollHeight","offsetTop","parentOffsetHeight","scrollTop","isAbove","isBelow","buffer","scrollTo"],"mappings":";;;;+BAAaA;;;eAAAA;;;AAAN,MAAMA,iBAAiB,CAACC,QAAQC;IACnC,IAAI,CAACD,UAAU,CAACC,cAAc;QAC1B;IACJ;IACA,IAAIA,aAAaC,YAAY,IAAID,aAAaE,YAAY,EAAE;QACxD;IACJ;IACA,MAAM,EAAED,YAAY,EAAEE,SAAS,EAAE,GAAGJ;IACpC,MAAM,EAAEE,cAAcG,kBAAkB,EAAEC,SAAS,EAAE,GAAGL;IACxD,MAAMM,UAAUH,YAAYE;IAC5B,MAAME,UAAUJ,YAAYF,eAAeI,YAAYD;IACvD,MAAMI,SAAS;IACf,IAAIF,SAAS;QACTN,aAAaS,QAAQ,CAAC,GAAGN,YAAYK;IACzC;IACA,IAAID,SAAS;QACTP,aAAaS,QAAQ,CAAC,GAAGN,YAAYC,qBAAqBH,eAAeO;IAC7E;AACJ"}
@@ -10,122 +10,142 @@ Object.defineProperty(exports, "useActiveDescendant", {
10
10
  });
11
11
  const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
12
12
  const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
13
+ const _reactutilities = require("@fluentui/react-utilities");
14
+ const _reacttabster = require("@fluentui/react-tabster");
13
15
  const _useOptionWalker = require("./useOptionWalker");
14
16
  const _constants = require("./constants");
17
+ const _scrollIntoView = require("./scrollIntoView");
15
18
  function useActiveDescendant(options) {
16
- const { imperativeRef, matchOption } = options;
19
+ const { imperativeRef, matchOption: matchOptionUnstable } = options;
20
+ const focusVisibleRef = _react.useRef(false);
21
+ const activeIdRef = _react.useRef(null);
17
22
  const activeParentRef = _react.useRef(null);
23
+ (0, _reacttabster.useOnKeyboardNavigationChange)((isNavigatingWithKeyboard)=>{
24
+ focusVisibleRef.current = isNavigatingWithKeyboard;
25
+ const active = getActiveDescendant();
26
+ if (!active) {
27
+ return;
28
+ }
29
+ if (isNavigatingWithKeyboard) {
30
+ active.setAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
31
+ } else {
32
+ active.removeAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
33
+ }
34
+ });
35
+ const matchOption = (0, _reactutilities.useEventCallback)(matchOptionUnstable);
18
36
  const { listboxRef, optionWalker } = (0, _useOptionWalker.useOptionWalker)({
19
37
  matchOption
20
38
  });
21
- const getActiveDescendant = ()=>{
39
+ const getActiveDescendant = _react.useCallback(()=>{
22
40
  var _listboxRef_current;
23
- return (_listboxRef_current = listboxRef.current) === null || _listboxRef_current === void 0 ? void 0 : _listboxRef_current.querySelector(`[${_constants.ACTIVEDESCENDANT_ATTRIBUTE}]`);
24
- };
25
- const scrollActiveIntoView = (active)=>{
26
- if (!listboxRef.current) {
27
- return;
28
- }
29
- if (listboxRef.current.offsetHeight >= listboxRef.current.scrollHeight) {
30
- return;
31
- }
32
- const { offsetHeight, offsetTop } = active;
33
- const { offsetHeight: parentOffsetHeight, scrollTop } = listboxRef.current;
34
- const isAbove = offsetTop < scrollTop;
35
- const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;
36
- const buffer = 2;
37
- if (isAbove) {
38
- listboxRef.current.scrollTo(0, offsetTop - buffer);
39
- }
40
- if (isBelow) {
41
- listboxRef.current.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);
42
- }
43
- };
44
- const setActiveDescendant = (nextActive)=>{
41
+ return (_listboxRef_current = listboxRef.current) === null || _listboxRef_current === void 0 ? void 0 : _listboxRef_current.querySelector(`#${activeIdRef.current}`);
42
+ }, [
43
+ listboxRef
44
+ ]);
45
+ const blurActiveDescendant = _react.useCallback(()=>{
46
+ var _activeParentRef_current;
45
47
  const active = getActiveDescendant();
46
48
  if (active) {
47
49
  active.removeAttribute(_constants.ACTIVEDESCENDANT_ATTRIBUTE);
50
+ active.removeAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
48
51
  }
49
- if (nextActive) {
50
- var _activeParentRef_current;
51
- nextActive.setAttribute(_constants.ACTIVEDESCENDANT_ATTRIBUTE, '');
52
- scrollActiveIntoView(nextActive);
53
- (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.setAttribute('aria-activedescendant', nextActive.id);
54
- } else {
55
- var _activeParentRef_current1;
56
- (_activeParentRef_current1 = activeParentRef.current) === null || _activeParentRef_current1 === void 0 ? void 0 : _activeParentRef_current1.removeAttribute('aria-activedescendant');
52
+ (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.removeAttribute('aria-activedescendant');
53
+ activeIdRef.current = null;
54
+ }, [
55
+ activeParentRef,
56
+ getActiveDescendant
57
+ ]);
58
+ const focusActiveDescendant = _react.useCallback((nextActive)=>{
59
+ var _activeParentRef_current;
60
+ if (!nextActive) {
61
+ return;
57
62
  }
58
- };
59
- _react.useImperativeHandle(imperativeRef, ()=>({
60
- first: ()=>{
61
- if (!listboxRef.current || !activeParentRef.current) {
62
- return;
63
- }
64
- optionWalker.setCurrent(listboxRef.current);
63
+ blurActiveDescendant();
64
+ (0, _scrollIntoView.scrollIntoView)(nextActive, listboxRef.current);
65
+ (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.setAttribute('aria-activedescendant', nextActive.id);
66
+ activeIdRef.current = nextActive.id;
67
+ nextActive.setAttribute(_constants.ACTIVEDESCENDANT_ATTRIBUTE, '');
68
+ if (focusVisibleRef.current) {
69
+ nextActive.setAttribute(_constants.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
70
+ }
71
+ }, [
72
+ activeParentRef,
73
+ listboxRef,
74
+ blurActiveDescendant
75
+ ]);
76
+ const controller = _react.useMemo(()=>({
77
+ first: ({ passive } = {})=>{
65
78
  const first = optionWalker.first();
66
- if (first) {
67
- setActiveDescendant(first);
79
+ if (!passive) {
80
+ focusActiveDescendant(first);
68
81
  }
82
+ return first === null || first === void 0 ? void 0 : first.id;
69
83
  },
70
- next: ()=>{
71
- if (!listboxRef.current || !activeParentRef.current) {
72
- return;
84
+ last: ({ passive } = {})=>{
85
+ const last = optionWalker.last();
86
+ if (!passive) {
87
+ focusActiveDescendant(last);
73
88
  }
89
+ return last === null || last === void 0 ? void 0 : last.id;
90
+ },
91
+ next: ({ passive } = {})=>{
74
92
  const active = getActiveDescendant();
75
93
  if (!active) {
76
94
  return;
77
95
  }
78
96
  optionWalker.setCurrent(active);
79
97
  const next = optionWalker.next();
80
- if (next) {
81
- setActiveDescendant(next);
98
+ if (!passive) {
99
+ focusActiveDescendant(next);
82
100
  }
101
+ return next === null || next === void 0 ? void 0 : next.id;
83
102
  },
84
- prev: ()=>{
85
- if (!listboxRef.current || !activeParentRef.current) {
86
- return;
87
- }
103
+ prev: ({ passive } = {})=>{
88
104
  const active = getActiveDescendant();
89
105
  if (!active) {
90
106
  return;
91
107
  }
92
108
  optionWalker.setCurrent(active);
93
- if (!matchOption(active)) {
94
- optionWalker.prev();
95
- }
96
109
  const next = optionWalker.prev();
97
- if (next && next !== listboxRef.current) {
98
- setActiveDescendant(next);
110
+ if (!passive) {
111
+ focusActiveDescendant(next);
99
112
  }
113
+ return next === null || next === void 0 ? void 0 : next.id;
100
114
  },
101
115
  blur: ()=>{
102
- if (!activeParentRef.current) {
103
- return;
104
- }
105
- setActiveDescendant(undefined);
116
+ blurActiveDescendant();
106
117
  },
107
118
  active: ()=>{
108
- if (listboxRef.current) {
109
- var _getActiveDescendant;
110
- return (_getActiveDescendant = getActiveDescendant()) === null || _getActiveDescendant === void 0 ? void 0 : _getActiveDescendant.id;
111
- }
119
+ var _getActiveDescendant;
120
+ return (_getActiveDescendant = getActiveDescendant()) === null || _getActiveDescendant === void 0 ? void 0 : _getActiveDescendant.id;
112
121
  },
113
122
  focus: (id)=>{
114
123
  if (!listboxRef.current) {
115
124
  return;
116
125
  }
117
- optionWalker.setCurrent(listboxRef.current);
118
- let cur = optionWalker.next();
119
- while(cur && cur.id !== id){
120
- cur = optionWalker.next();
126
+ const target = listboxRef.current.querySelector(`#${id}`);
127
+ if (target) {
128
+ focusActiveDescendant(target);
121
129
  }
122
- if (cur) {
123
- setActiveDescendant(cur);
130
+ },
131
+ find (predicate, { passive } = {}) {
132
+ const target = optionWalker.find(predicate);
133
+ if (!passive) {
134
+ focusActiveDescendant(target);
124
135
  }
136
+ return target === null || target === void 0 ? void 0 : target.id;
125
137
  }
126
- }));
138
+ }), [
139
+ optionWalker,
140
+ listboxRef,
141
+ focusActiveDescendant,
142
+ blurActiveDescendant,
143
+ getActiveDescendant
144
+ ]);
145
+ _react.useImperativeHandle(imperativeRef, ()=>controller);
127
146
  return {
128
147
  listboxRef,
129
- activeParentRef
148
+ activeParentRef,
149
+ controller
130
150
  };
131
151
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["useActiveDescendant.js"],"sourcesContent":["import * as React from 'react';\nimport { useOptionWalker } from './useOptionWalker';\nimport { ACTIVEDESCENDANT_ATTRIBUTE } from './constants';\nexport function useActiveDescendant(options) {\n const { imperativeRef, matchOption } = options;\n const activeParentRef = React.useRef(null);\n const { listboxRef, optionWalker } = useOptionWalker({\n matchOption\n });\n const getActiveDescendant = ()=>{\n var _listboxRef_current;\n return (_listboxRef_current = listboxRef.current) === null || _listboxRef_current === void 0 ? void 0 : _listboxRef_current.querySelector(`[${ACTIVEDESCENDANT_ATTRIBUTE}]`);\n };\n const scrollActiveIntoView = (active)=>{\n if (!listboxRef.current) {\n return;\n }\n if (listboxRef.current.offsetHeight >= listboxRef.current.scrollHeight) {\n return;\n }\n const { offsetHeight, offsetTop } = active;\n const { offsetHeight: parentOffsetHeight, scrollTop } = listboxRef.current;\n const isAbove = offsetTop < scrollTop;\n const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;\n const buffer = 2;\n if (isAbove) {\n listboxRef.current.scrollTo(0, offsetTop - buffer);\n }\n if (isBelow) {\n listboxRef.current.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);\n }\n };\n const setActiveDescendant = (nextActive)=>{\n const active = getActiveDescendant();\n if (active) {\n active.removeAttribute(ACTIVEDESCENDANT_ATTRIBUTE);\n }\n if (nextActive) {\n var _activeParentRef_current;\n nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');\n scrollActiveIntoView(nextActive);\n (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.setAttribute('aria-activedescendant', nextActive.id);\n } else {\n var _activeParentRef_current1;\n (_activeParentRef_current1 = activeParentRef.current) === null || _activeParentRef_current1 === void 0 ? void 0 : _activeParentRef_current1.removeAttribute('aria-activedescendant');\n }\n };\n React.useImperativeHandle(imperativeRef, ()=>({\n first: ()=>{\n if (!listboxRef.current || !activeParentRef.current) {\n return;\n }\n optionWalker.setCurrent(listboxRef.current);\n const first = optionWalker.first();\n if (first) {\n setActiveDescendant(first);\n }\n },\n next: ()=>{\n if (!listboxRef.current || !activeParentRef.current) {\n return;\n }\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n optionWalker.setCurrent(active);\n const next = optionWalker.next();\n if (next) {\n setActiveDescendant(next);\n }\n },\n prev: ()=>{\n if (!listboxRef.current || !activeParentRef.current) {\n return;\n }\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n optionWalker.setCurrent(active);\n if (!matchOption(active)) {\n optionWalker.prev();\n }\n const next = optionWalker.prev();\n if (next && next !== listboxRef.current) {\n setActiveDescendant(next);\n }\n },\n blur: ()=>{\n if (!activeParentRef.current) {\n return;\n }\n setActiveDescendant(undefined);\n },\n active: ()=>{\n if (listboxRef.current) {\n var _getActiveDescendant;\n return (_getActiveDescendant = getActiveDescendant()) === null || _getActiveDescendant === void 0 ? void 0 : _getActiveDescendant.id;\n }\n },\n focus: (id)=>{\n if (!listboxRef.current) {\n return;\n }\n optionWalker.setCurrent(listboxRef.current);\n let cur = optionWalker.next();\n while(cur && cur.id !== id){\n cur = optionWalker.next();\n }\n if (cur) {\n setActiveDescendant(cur);\n }\n }\n }));\n return {\n listboxRef,\n activeParentRef\n };\n}\n"],"names":["useActiveDescendant","options","imperativeRef","matchOption","activeParentRef","React","useRef","listboxRef","optionWalker","useOptionWalker","getActiveDescendant","_listboxRef_current","current","querySelector","ACTIVEDESCENDANT_ATTRIBUTE","scrollActiveIntoView","active","offsetHeight","scrollHeight","offsetTop","parentOffsetHeight","scrollTop","isAbove","isBelow","buffer","scrollTo","setActiveDescendant","nextActive","removeAttribute","_activeParentRef_current","setAttribute","id","_activeParentRef_current1","useImperativeHandle","first","setCurrent","next","prev","blur","undefined","_getActiveDescendant","focus","cur"],"mappings":";;;;+BAGgBA;;;eAAAA;;;;iEAHO;iCACS;2BACW;AACpC,SAASA,oBAAoBC,OAAO;IACvC,MAAM,EAAEC,aAAa,EAAEC,WAAW,EAAE,GAAGF;IACvC,MAAMG,kBAAkBC,OAAMC,MAAM,CAAC;IACrC,MAAM,EAAEC,UAAU,EAAEC,YAAY,EAAE,GAAGC,IAAAA,gCAAe,EAAC;QACjDN;IACJ;IACA,MAAMO,sBAAsB;QACxB,IAAIC;QACJ,OAAO,AAACA,CAAAA,sBAAsBJ,WAAWK,OAAO,AAAD,MAAO,QAAQD,wBAAwB,KAAK,IAAI,KAAK,IAAIA,oBAAoBE,aAAa,CAAC,CAAC,CAAC,EAAEC,qCAA0B,CAAC,CAAC,CAAC;IAC/K;IACA,MAAMC,uBAAuB,CAACC;QAC1B,IAAI,CAACT,WAAWK,OAAO,EAAE;YACrB;QACJ;QACA,IAAIL,WAAWK,OAAO,CAACK,YAAY,IAAIV,WAAWK,OAAO,CAACM,YAAY,EAAE;YACpE;QACJ;QACA,MAAM,EAAED,YAAY,EAAEE,SAAS,EAAE,GAAGH;QACpC,MAAM,EAAEC,cAAcG,kBAAkB,EAAEC,SAAS,EAAE,GAAGd,WAAWK,OAAO;QAC1E,MAAMU,UAAUH,YAAYE;QAC5B,MAAME,UAAUJ,YAAYF,eAAeI,YAAYD;QACvD,MAAMI,SAAS;QACf,IAAIF,SAAS;YACTf,WAAWK,OAAO,CAACa,QAAQ,CAAC,GAAGN,YAAYK;QAC/C;QACA,IAAID,SAAS;YACThB,WAAWK,OAAO,CAACa,QAAQ,CAAC,GAAGN,YAAYC,qBAAqBH,eAAeO;QACnF;IACJ;IACA,MAAME,sBAAsB,CAACC;QACzB,MAAMX,SAASN;QACf,IAAIM,QAAQ;YACRA,OAAOY,eAAe,CAACd,qCAA0B;QACrD;QACA,IAAIa,YAAY;YACZ,IAAIE;YACJF,WAAWG,YAAY,CAAChB,qCAA0B,EAAE;YACpDC,qBAAqBY;YACpBE,CAAAA,2BAA2BzB,gBAAgBQ,OAAO,AAAD,MAAO,QAAQiB,6BAA6B,KAAK,IAAI,KAAK,IAAIA,yBAAyBC,YAAY,CAAC,yBAAyBH,WAAWI,EAAE;QAChM,OAAO;YACH,IAAIC;YACHA,CAAAA,4BAA4B5B,gBAAgBQ,OAAO,AAAD,MAAO,QAAQoB,8BAA8B,KAAK,IAAI,KAAK,IAAIA,0BAA0BJ,eAAe,CAAC;QAChK;IACJ;IACAvB,OAAM4B,mBAAmB,CAAC/B,eAAe,IAAK,CAAA;YACtCgC,OAAO;gBACH,IAAI,CAAC3B,WAAWK,OAAO,IAAI,CAACR,gBAAgBQ,OAAO,EAAE;oBACjD;gBACJ;gBACAJ,aAAa2B,UAAU,CAAC5B,WAAWK,OAAO;gBAC1C,MAAMsB,QAAQ1B,aAAa0B,KAAK;gBAChC,IAAIA,OAAO;oBACPR,oBAAoBQ;gBACxB;YACJ;YACAE,MAAM;gBACF,IAAI,CAAC7B,WAAWK,OAAO,IAAI,CAACR,gBAAgBQ,OAAO,EAAE;oBACjD;gBACJ;gBACA,MAAMI,SAASN;gBACf,IAAI,CAACM,QAAQ;oBACT;gBACJ;gBACAR,aAAa2B,UAAU,CAACnB;gBACxB,MAAMoB,OAAO5B,aAAa4B,IAAI;gBAC9B,IAAIA,MAAM;oBACNV,oBAAoBU;gBACxB;YACJ;YACAC,MAAM;gBACF,IAAI,CAAC9B,WAAWK,OAAO,IAAI,CAACR,gBAAgBQ,OAAO,EAAE;oBACjD;gBACJ;gBACA,MAAMI,SAASN;gBACf,IAAI,CAACM,QAAQ;oBACT;gBACJ;gBACAR,aAAa2B,UAAU,CAACnB;gBACxB,IAAI,CAACb,YAAYa,SAAS;oBACtBR,aAAa6B,IAAI;gBACrB;gBACA,MAAMD,OAAO5B,aAAa6B,IAAI;gBAC9B,IAAID,QAAQA,SAAS7B,WAAWK,OAAO,EAAE;oBACrCc,oBAAoBU;gBACxB;YACJ;YACAE,MAAM;gBACF,IAAI,CAAClC,gBAAgBQ,OAAO,EAAE;oBAC1B;gBACJ;gBACAc,oBAAoBa;YACxB;YACAvB,QAAQ;gBACJ,IAAIT,WAAWK,OAAO,EAAE;oBACpB,IAAI4B;oBACJ,OAAO,AAACA,CAAAA,uBAAuB9B,qBAAoB,MAAO,QAAQ8B,yBAAyB,KAAK,IAAI,KAAK,IAAIA,qBAAqBT,EAAE;gBACxI;YACJ;YACAU,OAAO,CAACV;gBACJ,IAAI,CAACxB,WAAWK,OAAO,EAAE;oBACrB;gBACJ;gBACAJ,aAAa2B,UAAU,CAAC5B,WAAWK,OAAO;gBAC1C,IAAI8B,MAAMlC,aAAa4B,IAAI;gBAC3B,MAAMM,OAAOA,IAAIX,EAAE,KAAKA,GAAG;oBACvBW,MAAMlC,aAAa4B,IAAI;gBAC3B;gBACA,IAAIM,KAAK;oBACLhB,oBAAoBgB;gBACxB;YACJ;QACJ,CAAA;IACJ,OAAO;QACHnC;QACAH;IACJ;AACJ"}
1
+ {"version":3,"sources":["useActiveDescendant.js"],"sourcesContent":["import * as React from 'react';\nimport { useEventCallback } from '@fluentui/react-utilities';\nimport { useOnKeyboardNavigationChange } from '@fluentui/react-tabster';\nimport { useOptionWalker } from './useOptionWalker';\nimport { ACTIVEDESCENDANT_ATTRIBUTE, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './constants';\nimport { scrollIntoView } from './scrollIntoView';\nexport function useActiveDescendant(options) {\n const { imperativeRef, matchOption: matchOptionUnstable } = options;\n const focusVisibleRef = React.useRef(false);\n const activeIdRef = React.useRef(null);\n const activeParentRef = React.useRef(null);\n useOnKeyboardNavigationChange((isNavigatingWithKeyboard)=>{\n focusVisibleRef.current = isNavigatingWithKeyboard;\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n if (isNavigatingWithKeyboard) {\n active.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');\n } else {\n active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);\n }\n });\n const matchOption = useEventCallback(matchOptionUnstable);\n const { listboxRef, optionWalker } = useOptionWalker({\n matchOption\n });\n const getActiveDescendant = React.useCallback(()=>{\n var _listboxRef_current;\n return (_listboxRef_current = listboxRef.current) === null || _listboxRef_current === void 0 ? void 0 : _listboxRef_current.querySelector(`#${activeIdRef.current}`);\n }, [\n listboxRef\n ]);\n const blurActiveDescendant = React.useCallback(()=>{\n var _activeParentRef_current;\n const active = getActiveDescendant();\n if (active) {\n active.removeAttribute(ACTIVEDESCENDANT_ATTRIBUTE);\n active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);\n }\n (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.removeAttribute('aria-activedescendant');\n activeIdRef.current = null;\n }, [\n activeParentRef,\n getActiveDescendant\n ]);\n const focusActiveDescendant = React.useCallback((nextActive)=>{\n var _activeParentRef_current;\n if (!nextActive) {\n return;\n }\n blurActiveDescendant();\n scrollIntoView(nextActive, listboxRef.current);\n (_activeParentRef_current = activeParentRef.current) === null || _activeParentRef_current === void 0 ? void 0 : _activeParentRef_current.setAttribute('aria-activedescendant', nextActive.id);\n activeIdRef.current = nextActive.id;\n nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');\n if (focusVisibleRef.current) {\n nextActive.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');\n }\n }, [\n activeParentRef,\n listboxRef,\n blurActiveDescendant\n ]);\n const controller = React.useMemo(()=>({\n first: ({ passive } = {})=>{\n const first = optionWalker.first();\n if (!passive) {\n focusActiveDescendant(first);\n }\n return first === null || first === void 0 ? void 0 : first.id;\n },\n last: ({ passive } = {})=>{\n const last = optionWalker.last();\n if (!passive) {\n focusActiveDescendant(last);\n }\n return last === null || last === void 0 ? void 0 : last.id;\n },\n next: ({ passive } = {})=>{\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n optionWalker.setCurrent(active);\n const next = optionWalker.next();\n if (!passive) {\n focusActiveDescendant(next);\n }\n return next === null || next === void 0 ? void 0 : next.id;\n },\n prev: ({ passive } = {})=>{\n const active = getActiveDescendant();\n if (!active) {\n return;\n }\n optionWalker.setCurrent(active);\n const next = optionWalker.prev();\n if (!passive) {\n focusActiveDescendant(next);\n }\n return next === null || next === void 0 ? void 0 : next.id;\n },\n blur: ()=>{\n blurActiveDescendant();\n },\n active: ()=>{\n var _getActiveDescendant;\n return (_getActiveDescendant = getActiveDescendant()) === null || _getActiveDescendant === void 0 ? void 0 : _getActiveDescendant.id;\n },\n focus: (id)=>{\n if (!listboxRef.current) {\n return;\n }\n const target = listboxRef.current.querySelector(`#${id}`);\n if (target) {\n focusActiveDescendant(target);\n }\n },\n find (predicate, { passive } = {}) {\n const target = optionWalker.find(predicate);\n if (!passive) {\n focusActiveDescendant(target);\n }\n return target === null || target === void 0 ? void 0 : target.id;\n }\n }), [\n optionWalker,\n listboxRef,\n focusActiveDescendant,\n blurActiveDescendant,\n getActiveDescendant\n ]);\n React.useImperativeHandle(imperativeRef, ()=>controller);\n return {\n listboxRef,\n activeParentRef,\n controller\n };\n}\n"],"names":["useActiveDescendant","options","imperativeRef","matchOption","matchOptionUnstable","focusVisibleRef","React","useRef","activeIdRef","activeParentRef","useOnKeyboardNavigationChange","isNavigatingWithKeyboard","current","active","getActiveDescendant","setAttribute","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE","removeAttribute","useEventCallback","listboxRef","optionWalker","useOptionWalker","useCallback","_listboxRef_current","querySelector","blurActiveDescendant","_activeParentRef_current","ACTIVEDESCENDANT_ATTRIBUTE","focusActiveDescendant","nextActive","scrollIntoView","id","controller","useMemo","first","passive","last","next","setCurrent","prev","blur","_getActiveDescendant","focus","target","find","predicate","useImperativeHandle"],"mappings":"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"}
@@ -36,11 +36,18 @@ function useOptionWalker(options) {
36
36
  ]);
37
37
  const optionWalker = _react.useMemo(()=>({
38
38
  first: ()=>{
39
- if (!treeWalkerRef.current) {
39
+ if (!treeWalkerRef.current || !listboxRef.current) {
40
40
  return null;
41
41
  }
42
+ treeWalkerRef.current.currentNode = listboxRef.current;
42
43
  return treeWalkerRef.current.firstChild();
43
44
  },
45
+ last: ()=>{
46
+ if (!treeWalkerRef.current || !listboxRef.current) {
47
+ return null;
48
+ }
49
+ return treeWalkerRef.current.lastChild();
50
+ },
44
51
  next: ()=>{
45
52
  if (!treeWalkerRef.current) {
46
53
  return null;
@@ -53,6 +60,17 @@ function useOptionWalker(options) {
53
60
  }
54
61
  return treeWalkerRef.current.previousNode();
55
62
  },
63
+ find: (predicate)=>{
64
+ if (!treeWalkerRef.current || !listboxRef.current) {
65
+ return null;
66
+ }
67
+ treeWalkerRef.current.currentNode = listboxRef.current;
68
+ let cur = treeWalkerRef.current.currentNode;
69
+ while(cur && !predicate(cur.id)){
70
+ cur = treeWalkerRef.current.nextNode();
71
+ }
72
+ return cur;
73
+ },
56
74
  setCurrent: (el)=>{
57
75
  if (!treeWalkerRef.current) {
58
76
  return;
@@ -1 +1 @@
1
- {"version":3,"sources":["useOptionWalker.js"],"sourcesContent":["import * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { isHTMLElement, useIsomorphicLayoutEffect } from '@fluentui/react-utilities';\nexport function useOptionWalker(options) {\n const { matchOption } = options;\n const { targetDocument } = useFluent();\n const treeWalkerRef = React.useRef(null);\n const listboxRef = React.useRef(null);\n const optionFilter = React.useCallback((node)=>{\n if (isHTMLElement(node) && matchOption(node)) {\n return NodeFilter.FILTER_ACCEPT;\n }\n return NodeFilter.FILTER_SKIP;\n }, [\n matchOption\n ]);\n useIsomorphicLayoutEffect(()=>{\n if (!targetDocument || !listboxRef.current) {\n return;\n }\n treeWalkerRef.current = targetDocument.createTreeWalker(listboxRef.current, NodeFilter.SHOW_ELEMENT, optionFilter);\n }, [\n targetDocument,\n optionFilter\n ]);\n const optionWalker = React.useMemo(()=>({\n first: ()=>{\n if (!treeWalkerRef.current) {\n return null;\n }\n return treeWalkerRef.current.firstChild();\n },\n next: ()=>{\n if (!treeWalkerRef.current) {\n return null;\n }\n return treeWalkerRef.current.nextNode();\n },\n prev: ()=>{\n if (!treeWalkerRef.current) {\n return null;\n }\n return treeWalkerRef.current.previousNode();\n },\n setCurrent: (el)=>{\n if (!treeWalkerRef.current) {\n return;\n }\n treeWalkerRef.current.currentNode = el;\n }\n }), []);\n return {\n optionWalker,\n listboxRef\n };\n}\n"],"names":["useOptionWalker","options","matchOption","targetDocument","useFluent","treeWalkerRef","React","useRef","listboxRef","optionFilter","useCallback","node","isHTMLElement","NodeFilter","FILTER_ACCEPT","FILTER_SKIP","useIsomorphicLayoutEffect","current","createTreeWalker","SHOW_ELEMENT","optionWalker","useMemo","first","firstChild","next","nextNode","prev","previousNode","setCurrent","el","currentNode"],"mappings":";;;;+BAGgBA;;;eAAAA;;;;iEAHO;qCACyB;gCACS;AAClD,SAASA,gBAAgBC,OAAO;IACnC,MAAM,EAAEC,WAAW,EAAE,GAAGD;IACxB,MAAM,EAAEE,cAAc,EAAE,GAAGC,IAAAA,uCAAS;IACpC,MAAMC,gBAAgBC,OAAMC,MAAM,CAAC;IACnC,MAAMC,aAAaF,OAAMC,MAAM,CAAC;IAChC,MAAME,eAAeH,OAAMI,WAAW,CAAC,CAACC;QACpC,IAAIC,IAAAA,6BAAa,EAACD,SAAST,YAAYS,OAAO;YAC1C,OAAOE,WAAWC,aAAa;QACnC;QACA,OAAOD,WAAWE,WAAW;IACjC,GAAG;QACCb;KACH;IACDc,IAAAA,yCAAyB,EAAC;QACtB,IAAI,CAACb,kBAAkB,CAACK,WAAWS,OAAO,EAAE;YACxC;QACJ;QACAZ,cAAcY,OAAO,GAAGd,eAAee,gBAAgB,CAACV,WAAWS,OAAO,EAAEJ,WAAWM,YAAY,EAAEV;IACzG,GAAG;QACCN;QACAM;KACH;IACD,MAAMW,eAAed,OAAMe,OAAO,CAAC,IAAK,CAAA;YAChCC,OAAO;gBACH,IAAI,CAACjB,cAAcY,OAAO,EAAE;oBACxB,OAAO;gBACX;gBACA,OAAOZ,cAAcY,OAAO,CAACM,UAAU;YAC3C;YACAC,MAAM;gBACF,IAAI,CAACnB,cAAcY,OAAO,EAAE;oBACxB,OAAO;gBACX;gBACA,OAAOZ,cAAcY,OAAO,CAACQ,QAAQ;YACzC;YACAC,MAAM;gBACF,IAAI,CAACrB,cAAcY,OAAO,EAAE;oBACxB,OAAO;gBACX;gBACA,OAAOZ,cAAcY,OAAO,CAACU,YAAY;YAC7C;YACAC,YAAY,CAACC;gBACT,IAAI,CAACxB,cAAcY,OAAO,EAAE;oBACxB;gBACJ;gBACAZ,cAAcY,OAAO,CAACa,WAAW,GAAGD;YACxC;QACJ,CAAA,GAAI,EAAE;IACV,OAAO;QACHT;QACAZ;IACJ;AACJ"}
1
+ {"version":3,"sources":["useOptionWalker.js"],"sourcesContent":["import * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { isHTMLElement, useIsomorphicLayoutEffect } from '@fluentui/react-utilities';\nexport function useOptionWalker(options) {\n const { matchOption } = options;\n const { targetDocument } = useFluent();\n const treeWalkerRef = React.useRef(null);\n const listboxRef = React.useRef(null);\n const optionFilter = React.useCallback((node)=>{\n if (isHTMLElement(node) && matchOption(node)) {\n return NodeFilter.FILTER_ACCEPT;\n }\n return NodeFilter.FILTER_SKIP;\n }, [\n matchOption\n ]);\n useIsomorphicLayoutEffect(()=>{\n if (!targetDocument || !listboxRef.current) {\n return;\n }\n treeWalkerRef.current = targetDocument.createTreeWalker(listboxRef.current, NodeFilter.SHOW_ELEMENT, optionFilter);\n }, [\n targetDocument,\n optionFilter\n ]);\n const optionWalker = React.useMemo(()=>({\n first: ()=>{\n if (!treeWalkerRef.current || !listboxRef.current) {\n return null;\n }\n treeWalkerRef.current.currentNode = listboxRef.current;\n return treeWalkerRef.current.firstChild();\n },\n last: ()=>{\n if (!treeWalkerRef.current || !listboxRef.current) {\n return null;\n }\n return treeWalkerRef.current.lastChild();\n },\n next: ()=>{\n if (!treeWalkerRef.current) {\n return null;\n }\n return treeWalkerRef.current.nextNode();\n },\n prev: ()=>{\n if (!treeWalkerRef.current) {\n return null;\n }\n return treeWalkerRef.current.previousNode();\n },\n find: (predicate)=>{\n if (!treeWalkerRef.current || !listboxRef.current) {\n return null;\n }\n treeWalkerRef.current.currentNode = listboxRef.current;\n let cur = treeWalkerRef.current.currentNode;\n while(cur && !predicate(cur.id)){\n cur = treeWalkerRef.current.nextNode();\n }\n return cur;\n },\n setCurrent: (el)=>{\n if (!treeWalkerRef.current) {\n return;\n }\n treeWalkerRef.current.currentNode = el;\n }\n }), []);\n return {\n optionWalker,\n listboxRef\n };\n}\n"],"names":["useOptionWalker","options","matchOption","targetDocument","useFluent","treeWalkerRef","React","useRef","listboxRef","optionFilter","useCallback","node","isHTMLElement","NodeFilter","FILTER_ACCEPT","FILTER_SKIP","useIsomorphicLayoutEffect","current","createTreeWalker","SHOW_ELEMENT","optionWalker","useMemo","first","currentNode","firstChild","last","lastChild","next","nextNode","prev","previousNode","find","predicate","cur","id","setCurrent","el"],"mappings":";;;;+BAGgBA;;;eAAAA;;;;iEAHO;qCACyB;gCACS;AAClD,SAASA,gBAAgBC,OAAO;IACnC,MAAM,EAAEC,WAAW,EAAE,GAAGD;IACxB,MAAM,EAAEE,cAAc,EAAE,GAAGC,IAAAA,uCAAS;IACpC,MAAMC,gBAAgBC,OAAMC,MAAM,CAAC;IACnC,MAAMC,aAAaF,OAAMC,MAAM,CAAC;IAChC,MAAME,eAAeH,OAAMI,WAAW,CAAC,CAACC;QACpC,IAAIC,IAAAA,6BAAa,EAACD,SAAST,YAAYS,OAAO;YAC1C,OAAOE,WAAWC,aAAa;QACnC;QACA,OAAOD,WAAWE,WAAW;IACjC,GAAG;QACCb;KACH;IACDc,IAAAA,yCAAyB,EAAC;QACtB,IAAI,CAACb,kBAAkB,CAACK,WAAWS,OAAO,EAAE;YACxC;QACJ;QACAZ,cAAcY,OAAO,GAAGd,eAAee,gBAAgB,CAACV,WAAWS,OAAO,EAAEJ,WAAWM,YAAY,EAAEV;IACzG,GAAG;QACCN;QACAM;KACH;IACD,MAAMW,eAAed,OAAMe,OAAO,CAAC,IAAK,CAAA;YAChCC,OAAO;gBACH,IAAI,CAACjB,cAAcY,OAAO,IAAI,CAACT,WAAWS,OAAO,EAAE;oBAC/C,OAAO;gBACX;gBACAZ,cAAcY,OAAO,CAACM,WAAW,GAAGf,WAAWS,OAAO;gBACtD,OAAOZ,cAAcY,OAAO,CAACO,UAAU;YAC3C;YACAC,MAAM;gBACF,IAAI,CAACpB,cAAcY,OAAO,IAAI,CAACT,WAAWS,OAAO,EAAE;oBAC/C,OAAO;gBACX;gBACA,OAAOZ,cAAcY,OAAO,CAACS,SAAS;YAC1C;YACAC,MAAM;gBACF,IAAI,CAACtB,cAAcY,OAAO,EAAE;oBACxB,OAAO;gBACX;gBACA,OAAOZ,cAAcY,OAAO,CAACW,QAAQ;YACzC;YACAC,MAAM;gBACF,IAAI,CAACxB,cAAcY,OAAO,EAAE;oBACxB,OAAO;gBACX;gBACA,OAAOZ,cAAcY,OAAO,CAACa,YAAY;YAC7C;YACAC,MAAM,CAACC;gBACH,IAAI,CAAC3B,cAAcY,OAAO,IAAI,CAACT,WAAWS,OAAO,EAAE;oBAC/C,OAAO;gBACX;gBACAZ,cAAcY,OAAO,CAACM,WAAW,GAAGf,WAAWS,OAAO;gBACtD,IAAIgB,MAAM5B,cAAcY,OAAO,CAACM,WAAW;gBAC3C,MAAMU,OAAO,CAACD,UAAUC,IAAIC,EAAE,EAAE;oBAC5BD,MAAM5B,cAAcY,OAAO,CAACW,QAAQ;gBACxC;gBACA,OAAOK;YACX;YACAE,YAAY,CAACC;gBACT,IAAI,CAAC/B,cAAcY,OAAO,EAAE;oBACxB;gBACJ;gBACAZ,cAAcY,OAAO,CAACM,WAAW,GAAGa;YACxC;QACJ,CAAA,GAAI,EAAE;IACV,OAAO;QACHhB;QACAZ;IACJ;AACJ"}
@@ -17,6 +17,9 @@ _export(exports, {
17
17
  },
18
18
  useActiveDescendant: function() {
19
19
  return _activedescendant.useActiveDescendant;
20
+ },
21
+ ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE: function() {
22
+ return _activedescendant.ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE;
20
23
  }
21
24
  });
22
25
  const _index = require("./button/index");
@@ -1 +1 @@
1
- {"version":3,"sources":["index.js"],"sourcesContent":["export { // eslint-disable-next-line deprecation/deprecation\nuseARIAButtonShorthand, useARIAButtonProps } from './button/index';\nexport { useActiveDescendant } from './activedescendant';\n"],"names":["useARIAButtonShorthand","useARIAButtonProps","useActiveDescendant"],"mappings":";;;;;;;;;;;IACAA,sBAAsB;eAAtBA,6BAAsB;;IAAEC,kBAAkB;eAAlBA,yBAAkB;;IACjCC,mBAAmB;eAAnBA,qCAAmB;;;uBADsB;kCACd"}
1
+ {"version":3,"sources":["index.js"],"sourcesContent":["export { // eslint-disable-next-line deprecation/deprecation\nuseARIAButtonShorthand, useARIAButtonProps } from './button/index';\nexport { useActiveDescendant, ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from './activedescendant';\n"],"names":["useARIAButtonShorthand","useARIAButtonProps","useActiveDescendant","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE"],"mappings":";;;;;;;;;;;IACAA,sBAAsB;eAAtBA,6BAAsB;;IAAEC,kBAAkB;eAAlBA,yBAAkB;;IACjCC,mBAAmB;eAAnBA,qCAAmB;;IAAEC,uCAAuC;eAAvCA,yDAAuC;;;uBADnB;kCAC2B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-aria",
3
- "version": "9.6.2",
3
+ "version": "9.7.1",
4
4
  "description": "React helper to ensure ARIA",
5
5
  "main": "lib-commonjs/index.js",
6
6
  "module": "lib/index.js",
@@ -15,6 +15,8 @@
15
15
  "build": "just-scripts build",
16
16
  "clean": "just-scripts clean",
17
17
  "code-style": "just-scripts code-style",
18
+ "e2e": "cypress run --component",
19
+ "e2e:local": "cypress open --component",
18
20
  "just": "just-scripts",
19
21
  "lint": "just-scripts lint",
20
22
  "start": "yarn storybook",
@@ -33,12 +35,13 @@
33
35
  "dependencies": {
34
36
  "@fluentui/keyboard-keys": "^9.0.7",
35
37
  "@fluentui/react-shared-contexts": "^9.13.2",
38
+ "@fluentui/react-tabster": "^9.17.1",
36
39
  "@fluentui/react-utilities": "^9.15.6",
37
40
  "@swc/helpers": "^0.5.1"
38
41
  },
39
42
  "peerDependencies": {
40
43
  "@types/react": ">=16.14.0 <19.0.0",
41
- "@types/react-dom": ">=16.14.0 <19.0.0",
44
+ "@types/react-dom": ">=16.9.0 <19.0.0",
42
45
  "react": ">=16.14.0 <19.0.0",
43
46
  "react-dom": ">=16.14.0 <19.0.0"
44
47
  },