@fluentui/react-tabster 0.0.0-nightly-20220302-0405.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.json +1981 -0
  2. package/CHANGELOG.md +821 -0
  3. package/LICENSE +15 -0
  4. package/README.md +42 -0
  5. package/dist/react-tabster.d.ts +122 -0
  6. package/lib/hooks/index.d.ts +7 -0
  7. package/lib/hooks/index.js +8 -0
  8. package/lib/hooks/index.js.map +1 -0
  9. package/lib/hooks/useArrowNavigationGroup.d.ts +22 -0
  10. package/lib/hooks/useArrowNavigationGroup.js +37 -0
  11. package/lib/hooks/useArrowNavigationGroup.js.map +1 -0
  12. package/lib/hooks/useFocusFinders.d.ts +11 -0
  13. package/lib/hooks/useFocusFinders.js +36 -0
  14. package/lib/hooks/useFocusFinders.js.map +1 -0
  15. package/lib/hooks/useFocusIndicatorStyle.d.ts +33 -0
  16. package/lib/hooks/useFocusIndicatorStyle.js +84 -0
  17. package/lib/hooks/useFocusIndicatorStyle.js.map +1 -0
  18. package/lib/hooks/useFocusableGroup.d.ts +12 -0
  19. package/lib/hooks/useFocusableGroup.js +38 -0
  20. package/lib/hooks/useFocusableGroup.js.map +1 -0
  21. package/lib/hooks/useKeyboardNavAttribute.d.ts +5 -0
  22. package/lib/hooks/useKeyboardNavAttribute.js +41 -0
  23. package/lib/hooks/useKeyboardNavAttribute.js.map +1 -0
  24. package/lib/hooks/useModalAttributes.d.ts +22 -0
  25. package/lib/hooks/useModalAttributes.js +42 -0
  26. package/lib/hooks/useModalAttributes.js.map +1 -0
  27. package/lib/hooks/useTabster.d.ts +9 -0
  28. package/lib/hooks/useTabster.js +30 -0
  29. package/lib/hooks/useTabster.js.map +1 -0
  30. package/lib/hooks/useTabsterAttributes.d.ts +5 -0
  31. package/lib/hooks/useTabsterAttributes.js +13 -0
  32. package/lib/hooks/useTabsterAttributes.js.map +1 -0
  33. package/lib/index.d.ts +1 -0
  34. package/lib/index.js +2 -0
  35. package/lib/index.js.map +1 -0
  36. package/lib/symbols.d.ts +2 -0
  37. package/lib/symbols.js +3 -0
  38. package/lib/symbols.js.map +1 -0
  39. package/lib/tsdoc-metadata.json +11 -0
  40. package/lib-commonjs/hooks/index.d.ts +7 -0
  41. package/lib-commonjs/hooks/index.js +22 -0
  42. package/lib-commonjs/hooks/index.js.map +1 -0
  43. package/lib-commonjs/hooks/useArrowNavigationGroup.d.ts +22 -0
  44. package/lib-commonjs/hooks/useArrowNavigationGroup.js +49 -0
  45. package/lib-commonjs/hooks/useArrowNavigationGroup.js.map +1 -0
  46. package/lib-commonjs/hooks/useFocusFinders.d.ts +11 -0
  47. package/lib-commonjs/hooks/useFocusFinders.js +47 -0
  48. package/lib-commonjs/hooks/useFocusFinders.js.map +1 -0
  49. package/lib-commonjs/hooks/useFocusIndicatorStyle.d.ts +33 -0
  50. package/lib-commonjs/hooks/useFocusIndicatorStyle.js +97 -0
  51. package/lib-commonjs/hooks/useFocusIndicatorStyle.js.map +1 -0
  52. package/lib-commonjs/hooks/useFocusableGroup.d.ts +12 -0
  53. package/lib-commonjs/hooks/useFocusableGroup.js +50 -0
  54. package/lib-commonjs/hooks/useFocusableGroup.js.map +1 -0
  55. package/lib-commonjs/hooks/useKeyboardNavAttribute.d.ts +5 -0
  56. package/lib-commonjs/hooks/useKeyboardNavAttribute.js +54 -0
  57. package/lib-commonjs/hooks/useKeyboardNavAttribute.js.map +1 -0
  58. package/lib-commonjs/hooks/useModalAttributes.d.ts +22 -0
  59. package/lib-commonjs/hooks/useModalAttributes.js +55 -0
  60. package/lib-commonjs/hooks/useModalAttributes.js.map +1 -0
  61. package/lib-commonjs/hooks/useTabster.d.ts +9 -0
  62. package/lib-commonjs/hooks/useTabster.js +41 -0
  63. package/lib-commonjs/hooks/useTabster.js.map +1 -0
  64. package/lib-commonjs/hooks/useTabsterAttributes.d.ts +5 -0
  65. package/lib-commonjs/hooks/useTabsterAttributes.js +24 -0
  66. package/lib-commonjs/hooks/useTabsterAttributes.js.map +1 -0
  67. package/lib-commonjs/index.d.ts +1 -0
  68. package/lib-commonjs/index.js +10 -0
  69. package/lib-commonjs/index.js.map +1 -0
  70. package/lib-commonjs/symbols.d.ts +2 -0
  71. package/lib-commonjs/symbols.js +9 -0
  72. package/lib-commonjs/symbols.js.map +1 -0
  73. package/package.json +59 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ @fluentui/react-focus-management
2
+
3
+ Copyright (c) Microsoft Corporation
4
+
5
+ All rights reserved.
6
+
7
+ MIT License
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+
15
+ Note: Usage of the fonts and icons referenced in Fluent UI React is subject to the terms listed at https://aka.ms/fluentui-assets-license
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # @fluentui/react-tabster
2
+
3
+ **Tabster components for [Fluent UI React](https://developer.microsoft.com/en-us/fluentui)**
4
+
5
+ Experimental library for focus management that leverages [tabster](https://github.com/microsoft/tabster).
6
+
7
+ These library is not production-ready and **should never be used in product**. This space is useful for testing new features whose APIs might change before final release.
8
+
9
+ The provider needs to be wrapped around your application:
10
+
11
+ ```tsx
12
+ <TabsterProvider>{children}</TabsterProvider>
13
+ ```
14
+
15
+ The API currently only supports declarative data-\* attributes that are returned using the exported react hooks:
16
+
17
+ ```tsx
18
+ const Item: React.FC = ({ children }) => <div tabIndex={0}>Item</div>;
19
+
20
+ const ArrowNavigationExample: React.FC = ({ children }) => {
21
+ const attrs = useArrowNavigationGroup({ circular: true });
22
+
23
+ return (
24
+ <div {...attrs}>
25
+ <Item />
26
+ <Item />
27
+ <Item />
28
+ <Item />
29
+ <Item />
30
+ <Item />
31
+ </div>
32
+ );
33
+ };
34
+
35
+ const App: React.FC = () => {
36
+ return (
37
+ <TabsterProvider>
38
+ <ArrowNavigationExample />
39
+ </TabsterProvider>
40
+ );
41
+ };
42
+ ```
@@ -0,0 +1,122 @@
1
+ import type { GriffelStyle } from '@griffel/react';
2
+ import type { RefObject } from 'react';
3
+ import { Types } from 'tabster';
4
+
5
+ /**
6
+ * Creates a style for @see makeStyles that includes the necessary selectors for focus.
7
+ * Should be used only when @see createFocusOutlineStyle does not fit requirements
8
+ *
9
+ * @param style - styling applied on focus, defaults to @see getDefaultFocusOutlineStyes
10
+ */
11
+ export declare const createCustomFocusIndicatorStyle: (style: GriffelStyle, options?: CreateFocusIndicatorStyleRuleOptions) => GriffelStyle;
12
+
13
+ export declare interface CreateFocusIndicatorStyleRuleOptions {
14
+ selector?: 'focus' | 'focus-within';
15
+ }
16
+
17
+ /**
18
+ * NOTE: The element with the focus outline needs to have `position: relative` so that the
19
+ * pseudo element can be properly positioned.
20
+ *
21
+ * @param theme - Theme used in @see makeStyles
22
+ * @param options - Configure the style of the focus outline
23
+ * @returns focus outline styles object for @see makeStyles
24
+ */
25
+ export declare const createFocusOutlineStyle: (options?: {
26
+ style: Partial<FocusOutlineStyleOptions>;
27
+ } & CreateFocusIndicatorStyleRuleOptions) => GriffelStyle;
28
+
29
+ export declare type FocusOutlineOffset = Record<'top' | 'bottom' | 'left' | 'right', string>;
30
+
31
+ export declare type FocusOutlineStyleOptions = {
32
+ /**
33
+ * Only property not supported by the native CSS `outline`, if this is no longer needed
34
+ * we can just go native instead
35
+ */
36
+ outlineRadius: string;
37
+ outlineColor: string;
38
+ outlineWidth: string;
39
+ outlineOffset?: string | FocusOutlineOffset;
40
+ };
41
+
42
+ /**
43
+ * A hook that returns the necessary tabster attributes to support arrow key navigation
44
+ * @param options - Options to configure keyboard navigation
45
+ */
46
+ export declare const useArrowNavigationGroup: (options?: UseArrowNavigationGroupOptions | undefined) => Types.TabsterDOMAttribute;
47
+
48
+ export declare interface UseArrowNavigationGroupOptions {
49
+ /**
50
+ * Focus will navigate vertically or horizontally, defaults to horizontally
51
+ * @defaultValue vertical
52
+ */
53
+ axis?: 'vertical' | 'horizontal';
54
+ /**
55
+ * Focus will cycle to the first/last elements of the group without stopping
56
+ */
57
+ circular?: boolean;
58
+ /**
59
+ * Last focused element in the group will be remembered and focused (if still
60
+ * available) when tabbing from outside of the group
61
+ */
62
+ memorizeCurrent?: boolean;
63
+ }
64
+
65
+ /**
66
+ * A hook that returns the necessary tabster attributes to support groupping.
67
+ * @param options - Options to configure keyboard navigation
68
+ */
69
+ export declare const useFocusableGroup: (options?: UseFocusableGroupOptions | undefined) => Types.TabsterDOMAttribute;
70
+
71
+ export declare interface UseFocusableGroupOptions {
72
+ /**
73
+ * Behavior for the Tab key.
74
+ */
75
+ tabBehavior?: 'unlimited' | 'limited' | 'limitedTrapFocus';
76
+ }
77
+
78
+ /**
79
+ * Returns a set of helper functions that will traverse focusable elements in the context of a root DOM element
80
+ */
81
+ export declare const useFocusFinders: () => {
82
+ findAllFocusable: (container: HTMLElement, acceptCondition: (el: HTMLElement) => boolean) => HTMLElement[];
83
+ findFirstFocusable: (container: HTMLElement) => HTMLElement | null | undefined;
84
+ findLastFocusable: (container: HTMLElement) => HTMLElement | null | undefined;
85
+ findNextFocusable: (currentElement: HTMLElement, options?: Pick<Types.FindNextProps, 'container'>) => HTMLElement | null | undefined;
86
+ findPrevFocusable: (currentElement: HTMLElement, options?: Pick<Types.FindNextProps, 'container'>) => HTMLElement | null | undefined;
87
+ };
88
+
89
+ /**
90
+ * instantiates keyborg and add attribute to ensure focus indicator synced to keyborg logic
91
+ */
92
+ export declare function useKeyboardNavAttribute<E extends HTMLElement>(): RefObject<E>;
93
+
94
+ /**
95
+ * Applies modal dialog behaviour through DOM attributes
96
+ * Modal element will focus trap and hide other content on the page
97
+ * The trigger element will be focused if focus is lost after the modal element is removed
98
+ *
99
+ * @returns DOM attributes to apply to the modal element and its trigger
100
+ */
101
+ export declare const useModalAttributes: (options?: UseModalAttributesOptions) => {
102
+ modalAttributes: Types.TabsterDOMAttribute;
103
+ triggerAttributes: Types.TabsterDOMAttribute;
104
+ };
105
+
106
+ export declare interface UseModalAttributesOptions {
107
+ /**
108
+ * Traps focus inside the elements the attributes are applied
109
+ */
110
+ trapFocus?: boolean;
111
+ /**
112
+ * Always reachabled in Tab order
113
+ */
114
+ alwaysFocusable?: boolean;
115
+ }
116
+
117
+ /**
118
+ * Hook that returns tabster attributes while ensuring tabster exists
119
+ */
120
+ export declare const useTabsterAttributes: (props: Types.TabsterAttributeProps) => Types.TabsterDOMAttribute;
121
+
122
+ export { }
@@ -0,0 +1,7 @@
1
+ export * from './useArrowNavigationGroup';
2
+ export * from './useFocusFinders';
3
+ export * from './useModalAttributes';
4
+ export * from './useTabsterAttributes';
5
+ export * from './useFocusIndicatorStyle';
6
+ export * from './useKeyboardNavAttribute';
7
+ export * from './useFocusableGroup';
@@ -0,0 +1,8 @@
1
+ export * from './useArrowNavigationGroup';
2
+ export * from './useFocusFinders';
3
+ export * from './useModalAttributes';
4
+ export * from './useTabsterAttributes';
5
+ export * from './useFocusIndicatorStyle';
6
+ export * from './useKeyboardNavAttribute';
7
+ export * from './useFocusableGroup';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"../src/","sources":["hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC","sourcesContent":["export * from './useArrowNavigationGroup';\nexport * from './useFocusFinders';\nexport * from './useModalAttributes';\nexport * from './useTabsterAttributes';\nexport * from './useFocusIndicatorStyle';\nexport * from './useKeyboardNavAttribute';\nexport * from './useFocusableGroup';\n"]}
@@ -0,0 +1,22 @@
1
+ import { Types } from 'tabster';
2
+ export interface UseArrowNavigationGroupOptions {
3
+ /**
4
+ * Focus will navigate vertically or horizontally, defaults to horizontally
5
+ * @defaultValue vertical
6
+ */
7
+ axis?: 'vertical' | 'horizontal';
8
+ /**
9
+ * Focus will cycle to the first/last elements of the group without stopping
10
+ */
11
+ circular?: boolean;
12
+ /**
13
+ * Last focused element in the group will be remembered and focused (if still
14
+ * available) when tabbing from outside of the group
15
+ */
16
+ memorizeCurrent?: boolean;
17
+ }
18
+ /**
19
+ * A hook that returns the necessary tabster attributes to support arrow key navigation
20
+ * @param options - Options to configure keyboard navigation
21
+ */
22
+ export declare const useArrowNavigationGroup: (options?: UseArrowNavigationGroupOptions | undefined) => Types.TabsterDOMAttribute;
@@ -0,0 +1,37 @@
1
+ import { Types, getMover } from 'tabster';
2
+ import { useTabsterAttributes } from './useTabsterAttributes';
3
+ import { useTabster } from './useTabster';
4
+ /**
5
+ * A hook that returns the necessary tabster attributes to support arrow key navigation
6
+ * @param options - Options to configure keyboard navigation
7
+ */
8
+
9
+ export const useArrowNavigationGroup = options => {
10
+ var _a;
11
+
12
+ const tabster = useTabster();
13
+
14
+ if (tabster) {
15
+ getMover(tabster);
16
+ }
17
+
18
+ return useTabsterAttributes({
19
+ mover: {
20
+ cyclic: !!(options === null || options === void 0 ? void 0 : options.circular),
21
+ direction: axisToMoverDirection((_a = options === null || options === void 0 ? void 0 : options.axis) !== null && _a !== void 0 ? _a : 'vertical'),
22
+ memorizeCurrent: options === null || options === void 0 ? void 0 : options.memorizeCurrent
23
+ }
24
+ });
25
+ };
26
+
27
+ function axisToMoverDirection(axis) {
28
+ switch (axis) {
29
+ case 'horizontal':
30
+ return Types.MoverDirections.Horizontal;
31
+
32
+ case 'vertical':
33
+ default:
34
+ return Types.MoverDirections.Vertical;
35
+ }
36
+ }
37
+ //# sourceMappingURL=useArrowNavigationGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["hooks/useArrowNavigationGroup.ts"],"names":[],"mappings":"AAAA,SAAS,KAAT,EAAgB,QAAhB,QAAgC,SAAhC;AACA,SAAS,oBAAT,QAAqC,wBAArC;AACA,SAAS,UAAT,QAA2B,cAA3B;AAmBA;;;AAGG;;AACH,OAAO,MAAM,uBAAuB,GAAI,OAAD,IAA6C;;;AAClF,QAAM,OAAO,GAAG,UAAU,EAA1B;;AAEA,MAAI,OAAJ,EAAa;AACX,IAAA,QAAQ,CAAC,OAAD,CAAR;AACD;;AAED,SAAO,oBAAoB,CAAC;AAC1B,IAAA,KAAK,EAAE;AACL,MAAA,MAAM,EAAE,CAAC,EAAC,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE,QAAV,CADJ;AAEL,MAAA,SAAS,EAAE,oBAAoB,CAAC,CAAA,EAAA,GAAA,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE,IAAT,MAAa,IAAb,IAAa,EAAA,KAAA,KAAA,CAAb,GAAa,EAAb,GAAiB,UAAlB,CAF1B;AAGL,MAAA,eAAe,EAAE,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE;AAHrB;AADmB,GAAD,CAA3B;AAOD,CAdM;;AAgBP,SAAS,oBAAT,CAA8B,IAA9B,EAA0E;AACxE,UAAQ,IAAR;AACE,SAAK,YAAL;AACE,aAAO,KAAK,CAAC,eAAN,CAAsB,UAA7B;;AAEF,SAAK,UAAL;AACA;AACE,aAAO,KAAK,CAAC,eAAN,CAAsB,QAA7B;AANJ;AAQD","sourcesContent":["import { Types, getMover } from 'tabster';\nimport { useTabsterAttributes } from './useTabsterAttributes';\nimport { useTabster } from './useTabster';\n\nexport interface UseArrowNavigationGroupOptions {\n /**\n * Focus will navigate vertically or horizontally, defaults to horizontally\n * @defaultValue vertical\n */\n axis?: 'vertical' | 'horizontal';\n /**\n * Focus will cycle to the first/last elements of the group without stopping\n */\n circular?: boolean;\n /**\n * Last focused element in the group will be remembered and focused (if still\n * available) when tabbing from outside of the group\n */\n memorizeCurrent?: boolean;\n}\n\n/**\n * A hook that returns the necessary tabster attributes to support arrow key navigation\n * @param options - Options to configure keyboard navigation\n */\nexport const useArrowNavigationGroup = (options?: UseArrowNavigationGroupOptions) => {\n const tabster = useTabster();\n\n if (tabster) {\n getMover(tabster);\n }\n\n return useTabsterAttributes({\n mover: {\n cyclic: !!options?.circular,\n direction: axisToMoverDirection(options?.axis ?? 'vertical'),\n memorizeCurrent: options?.memorizeCurrent,\n },\n });\n};\n\nfunction axisToMoverDirection(axis: UseArrowNavigationGroupOptions['axis']): Types.MoverDirection {\n switch (axis) {\n case 'horizontal':\n return Types.MoverDirections.Horizontal;\n\n case 'vertical':\n default:\n return Types.MoverDirections.Vertical;\n }\n}\n"],"sourceRoot":"../src/"}
@@ -0,0 +1,11 @@
1
+ import { Types as TabsterTypes } from 'tabster';
2
+ /**
3
+ * Returns a set of helper functions that will traverse focusable elements in the context of a root DOM element
4
+ */
5
+ export declare const useFocusFinders: () => {
6
+ findAllFocusable: (container: HTMLElement, acceptCondition: (el: HTMLElement) => boolean) => HTMLElement[];
7
+ findFirstFocusable: (container: HTMLElement) => HTMLElement | null | undefined;
8
+ findLastFocusable: (container: HTMLElement) => HTMLElement | null | undefined;
9
+ findNextFocusable: (currentElement: HTMLElement, options?: Pick<TabsterTypes.FindNextProps, 'container'>) => HTMLElement | null | undefined;
10
+ findPrevFocusable: (currentElement: HTMLElement, options?: Pick<TabsterTypes.FindNextProps, 'container'>) => HTMLElement | null | undefined;
11
+ };
@@ -0,0 +1,36 @@
1
+ import * as React from 'react';
2
+ import { useTabster } from './useTabster';
3
+ /**
4
+ * Returns a set of helper functions that will traverse focusable elements in the context of a root DOM element
5
+ */
6
+
7
+ export const useFocusFinders = () => {
8
+ const tabster = useTabster(); // Narrow props for now and let need dictate additional props in the future
9
+
10
+ const findAllFocusable = React.useCallback((container, acceptCondition) => (tabster === null || tabster === void 0 ? void 0 : tabster.focusable.findAll({
11
+ container,
12
+ acceptCondition
13
+ })) || [], [tabster]);
14
+ const findFirstFocusable = React.useCallback(container => tabster === null || tabster === void 0 ? void 0 : tabster.focusable.findFirst({
15
+ container
16
+ }), [tabster]);
17
+ const findLastFocusable = React.useCallback(container => tabster === null || tabster === void 0 ? void 0 : tabster.focusable.findLast({
18
+ container
19
+ }), [tabster]);
20
+ const findNextFocusable = React.useCallback((currentElement, options = {}) => tabster === null || tabster === void 0 ? void 0 : tabster.focusable.findNext({
21
+ currentElement,
22
+ ...options
23
+ }), [tabster]);
24
+ const findPrevFocusable = React.useCallback((currentElement, options = {}) => tabster === null || tabster === void 0 ? void 0 : tabster.focusable.findPrev({
25
+ currentElement,
26
+ ...options
27
+ }), [tabster]);
28
+ return {
29
+ findAllFocusable,
30
+ findFirstFocusable,
31
+ findLastFocusable,
32
+ findNextFocusable,
33
+ findPrevFocusable
34
+ };
35
+ };
36
+ //# sourceMappingURL=useFocusFinders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["hooks/useFocusFinders.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAZ,MAAuB,OAAvB;AAEA,SAAS,UAAT,QAA2B,cAA3B;AAEA;;AAEG;;AACH,OAAO,MAAM,eAAe,GAAG,MAAK;AAClC,QAAM,OAAO,GAAG,UAAU,EAA1B,CADkC,CAGlC;;AACA,QAAM,gBAAgB,GAAG,KAAK,CAAC,WAAN,CACvB,CAAC,SAAD,EAAyB,eAAzB,KACE,CAAA,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE,SAAT,CAAmB,OAAnB,CAA2B;AAAE,IAAA,SAAF;AAAa,IAAA;AAAb,GAA3B,CAAA,KAA8D,EAFzC,EAGvB,CAAC,OAAD,CAHuB,CAAzB;AAMA,QAAM,kBAAkB,GAAG,KAAK,CAAC,WAAN,CACxB,SAAD,IAA4B,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE,SAAT,CAAmB,SAAnB,CAA6B;AAAE,IAAA;AAAF,GAA7B,CADH,EAEzB,CAAC,OAAD,CAFyB,CAA3B;AAKA,QAAM,iBAAiB,GAAG,KAAK,CAAC,WAAN,CAAmB,SAAD,IAA4B,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE,SAAT,CAAmB,QAAnB,CAA4B;AAAE,IAAA;AAAF,GAA5B,CAA9C,EAA0F,CAClH,OADkH,CAA1F,CAA1B;AAIA,QAAM,iBAAiB,GAAG,KAAK,CAAC,WAAN,CACxB,CAAC,cAAD,EAA8B,OAAA,GAAyD,EAAvF,KACE,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE,SAAT,CAAmB,QAAnB,CAA4B;AAAE,IAAA,cAAF;AAAkB,OAAG;AAArB,GAA5B,CAFsB,EAGxB,CAAC,OAAD,CAHwB,CAA1B;AAMA,QAAM,iBAAiB,GAAG,KAAK,CAAC,WAAN,CACxB,CAAC,cAAD,EAA8B,OAAA,GAAyD,EAAvF,KACE,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE,SAAT,CAAmB,QAAnB,CAA4B;AAAE,IAAA,cAAF;AAAkB,OAAG;AAArB,GAA5B,CAFsB,EAGxB,CAAC,OAAD,CAHwB,CAA1B;AAMA,SAAO;AACL,IAAA,gBADK;AAEL,IAAA,kBAFK;AAGL,IAAA,iBAHK;AAIL,IAAA,iBAJK;AAKL,IAAA;AALK,GAAP;AAOD,CAtCM","sourcesContent":["import * as React from 'react';\nimport { Types as TabsterTypes } from 'tabster';\nimport { useTabster } from './useTabster';\n\n/**\n * Returns a set of helper functions that will traverse focusable elements in the context of a root DOM element\n */\nexport const useFocusFinders = () => {\n const tabster = useTabster();\n\n // Narrow props for now and let need dictate additional props in the future\n const findAllFocusable = React.useCallback(\n (container: HTMLElement, acceptCondition: (el: HTMLElement) => boolean) =>\n tabster?.focusable.findAll({ container, acceptCondition }) || [],\n [tabster],\n );\n\n const findFirstFocusable = React.useCallback(\n (container: HTMLElement) => tabster?.focusable.findFirst({ container }),\n [tabster],\n );\n\n const findLastFocusable = React.useCallback((container: HTMLElement) => tabster?.focusable.findLast({ container }), [\n tabster,\n ]);\n\n const findNextFocusable = React.useCallback(\n (currentElement: HTMLElement, options: Pick<TabsterTypes.FindNextProps, 'container'> = {}) =>\n tabster?.focusable.findNext({ currentElement, ...options }),\n [tabster],\n );\n\n const findPrevFocusable = React.useCallback(\n (currentElement: HTMLElement, options: Pick<TabsterTypes.FindNextProps, 'container'> = {}) =>\n tabster?.focusable.findPrev({ currentElement, ...options }),\n [tabster],\n );\n\n return {\n findAllFocusable,\n findFirstFocusable,\n findLastFocusable,\n findNextFocusable,\n findPrevFocusable,\n };\n};\n"],"sourceRoot":"../src/"}
@@ -0,0 +1,33 @@
1
+ import type { GriffelStyle } from '@griffel/react';
2
+ export declare type FocusOutlineOffset = Record<'top' | 'bottom' | 'left' | 'right', string>;
3
+ export declare type FocusOutlineStyleOptions = {
4
+ /**
5
+ * Only property not supported by the native CSS `outline`, if this is no longer needed
6
+ * we can just go native instead
7
+ */
8
+ outlineRadius: string;
9
+ outlineColor: string;
10
+ outlineWidth: string;
11
+ outlineOffset?: string | FocusOutlineOffset;
12
+ };
13
+ export interface CreateFocusIndicatorStyleRuleOptions {
14
+ selector?: 'focus' | 'focus-within';
15
+ }
16
+ /**
17
+ * NOTE: The element with the focus outline needs to have `position: relative` so that the
18
+ * pseudo element can be properly positioned.
19
+ *
20
+ * @param theme - Theme used in @see makeStyles
21
+ * @param options - Configure the style of the focus outline
22
+ * @returns focus outline styles object for @see makeStyles
23
+ */
24
+ export declare const createFocusOutlineStyle: (options?: {
25
+ style: Partial<FocusOutlineStyleOptions>;
26
+ } & CreateFocusIndicatorStyleRuleOptions) => GriffelStyle;
27
+ /**
28
+ * Creates a style for @see makeStyles that includes the necessary selectors for focus.
29
+ * Should be used only when @see createFocusOutlineStyle does not fit requirements
30
+ *
31
+ * @param style - styling applied on focus, defaults to @see getDefaultFocusOutlineStyes
32
+ */
33
+ export declare const createCustomFocusIndicatorStyle: (style: GriffelStyle, options?: CreateFocusIndicatorStyleRuleOptions) => GriffelStyle;
@@ -0,0 +1,84 @@
1
+ import { tokens } from '@fluentui/react-theme';
2
+ import { KEYBOARD_NAV_SELECTOR } from '../symbols';
3
+ /**
4
+ * NOTE: the element with the focus outline needs to have `position: relative` so that the
5
+ * pseudo element can be properly positioned.
6
+ *
7
+ * @param options - Configures the style of the focus outline
8
+ * @returns focus outline styles object
9
+ */
10
+
11
+ const getFocusOutlineStyles = options => {
12
+ var _a, _b, _c, _d;
13
+
14
+ const {
15
+ outlineRadius,
16
+ outlineColor,
17
+ outlineOffset,
18
+ outlineWidth
19
+ } = options;
20
+ const outlineOffsetTop = ((_a = outlineOffset) === null || _a === void 0 ? void 0 : _a.top) || outlineOffset;
21
+ const outlineOffsetBottom = ((_b = outlineOffset) === null || _b === void 0 ? void 0 : _b.bottom) || outlineOffset;
22
+ const outlineOffsetLeft = ((_c = outlineOffset) === null || _c === void 0 ? void 0 : _c.left) || outlineOffset;
23
+ const outlineOffsetRight = ((_d = outlineOffset) === null || _d === void 0 ? void 0 : _d.right) || outlineOffset;
24
+ return {
25
+ borderColor: 'transparent',
26
+ ':after': {
27
+ content: '""',
28
+ position: 'absolute',
29
+ pointerEvents: 'none',
30
+ boxSizing: 'outline-box',
31
+ zIndex: 1,
32
+ borderStyle: 'solid',
33
+ borderWidth: outlineWidth,
34
+ borderRadius: outlineRadius,
35
+ borderColor: outlineColor,
36
+ top: !outlineOffset ? `-${outlineWidth}` : `calc(0px - ${outlineWidth} - ${outlineOffsetTop})`,
37
+ bottom: !outlineOffset ? `-${outlineWidth}` : `calc(0px - ${outlineWidth} - ${outlineOffsetBottom})`,
38
+ left: !outlineOffset ? `-${outlineWidth}` : `calc(0px - ${outlineWidth} - ${outlineOffsetLeft})`,
39
+ right: !outlineOffset ? `-${outlineWidth}` : `calc(0px - ${outlineWidth} - ${outlineOffsetRight})`
40
+ }
41
+ };
42
+ };
43
+
44
+ const defaultOptions = {
45
+ selector: 'focus'
46
+ };
47
+ /**
48
+ * NOTE: The element with the focus outline needs to have `position: relative` so that the
49
+ * pseudo element can be properly positioned.
50
+ *
51
+ * @param theme - Theme used in @see makeStyles
52
+ * @param options - Configure the style of the focus outline
53
+ * @returns focus outline styles object for @see makeStyles
54
+ */
55
+
56
+ export const createFocusOutlineStyle = (options = {
57
+ style: {},
58
+ ...defaultOptions
59
+ }) => ({
60
+ ':focus-visible': {
61
+ outlineStyle: 'none'
62
+ },
63
+ [`${KEYBOARD_NAV_SELECTOR} :${options.selector || defaultOptions.selector}`]: getFocusOutlineStyles({
64
+ outlineColor: tokens.colorStrokeFocus2,
65
+ outlineRadius: tokens.borderRadiusMedium,
66
+ // FIXME: tokens.strokeWidthThick causes some weird bugs
67
+ outlineWidth: '2px',
68
+ ...options.style
69
+ })
70
+ });
71
+ /**
72
+ * Creates a style for @see makeStyles that includes the necessary selectors for focus.
73
+ * Should be used only when @see createFocusOutlineStyle does not fit requirements
74
+ *
75
+ * @param style - styling applied on focus, defaults to @see getDefaultFocusOutlineStyes
76
+ */
77
+
78
+ export const createCustomFocusIndicatorStyle = (style, options = defaultOptions) => ({
79
+ ':focus-visible': {
80
+ outlineStyle: 'none'
81
+ },
82
+ [`${KEYBOARD_NAV_SELECTOR} :${options.selector || defaultOptions.selector}`]: style
83
+ });
84
+ //# sourceMappingURL=useFocusIndicatorStyle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["hooks/useFocusIndicatorStyle.ts"],"names":[],"mappings":"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","sourcesContent":["import { tokens } from '@fluentui/react-theme';\nimport { KEYBOARD_NAV_SELECTOR } from '../symbols';\nimport type { GriffelStyle } from '@griffel/react';\n\nexport type FocusOutlineOffset = Record<'top' | 'bottom' | 'left' | 'right', string>;\nexport type FocusOutlineStyleOptions = {\n /**\n * Only property not supported by the native CSS `outline`, if this is no longer needed\n * we can just go native instead\n */\n outlineRadius: string;\n outlineColor: string;\n outlineWidth: string;\n outlineOffset?: string | FocusOutlineOffset;\n};\n\n/**\n * NOTE: the element with the focus outline needs to have `position: relative` so that the\n * pseudo element can be properly positioned.\n *\n * @param options - Configures the style of the focus outline\n * @returns focus outline styles object\n */\nconst getFocusOutlineStyles = (options: FocusOutlineStyleOptions) => {\n const { outlineRadius, outlineColor, outlineOffset, outlineWidth } = options;\n\n const outlineOffsetTop = (outlineOffset as FocusOutlineOffset)?.top || outlineOffset;\n const outlineOffsetBottom = (outlineOffset as FocusOutlineOffset)?.bottom || outlineOffset;\n const outlineOffsetLeft = (outlineOffset as FocusOutlineOffset)?.left || outlineOffset;\n const outlineOffsetRight = (outlineOffset as FocusOutlineOffset)?.right || outlineOffset;\n\n return {\n borderColor: 'transparent',\n ':after': {\n content: '\"\"',\n position: 'absolute',\n pointerEvents: 'none',\n boxSizing: 'outline-box',\n zIndex: 1,\n\n borderStyle: 'solid',\n borderWidth: outlineWidth,\n borderRadius: outlineRadius,\n borderColor: outlineColor,\n\n top: !outlineOffset ? `-${outlineWidth}` : `calc(0px - ${outlineWidth} - ${outlineOffsetTop})`,\n bottom: !outlineOffset ? `-${outlineWidth}` : `calc(0px - ${outlineWidth} - ${outlineOffsetBottom})`,\n left: !outlineOffset ? `-${outlineWidth}` : `calc(0px - ${outlineWidth} - ${outlineOffsetLeft})`,\n right: !outlineOffset ? `-${outlineWidth}` : `calc(0px - ${outlineWidth} - ${outlineOffsetRight})`,\n },\n };\n};\n\nexport interface CreateFocusIndicatorStyleRuleOptions {\n selector?: 'focus' | 'focus-within';\n}\n\nconst defaultOptions: CreateFocusIndicatorStyleRuleOptions = {\n selector: 'focus',\n};\n\n/**\n * NOTE: The element with the focus outline needs to have `position: relative` so that the\n * pseudo element can be properly positioned.\n *\n * @param theme - Theme used in @see makeStyles\n * @param options - Configure the style of the focus outline\n * @returns focus outline styles object for @see makeStyles\n */\nexport const createFocusOutlineStyle = (\n options: {\n style: Partial<FocusOutlineStyleOptions>;\n } & CreateFocusIndicatorStyleRuleOptions = { style: {}, ...defaultOptions },\n): GriffelStyle => ({\n ':focus-visible': {\n outlineStyle: 'none',\n },\n [`${KEYBOARD_NAV_SELECTOR} :${options.selector || defaultOptions.selector}`]: getFocusOutlineStyles({\n outlineColor: tokens.colorStrokeFocus2,\n outlineRadius: tokens.borderRadiusMedium,\n // FIXME: tokens.strokeWidthThick causes some weird bugs\n outlineWidth: '2px',\n ...options.style,\n }),\n});\n\n/**\n * Creates a style for @see makeStyles that includes the necessary selectors for focus.\n * Should be used only when @see createFocusOutlineStyle does not fit requirements\n *\n * @param style - styling applied on focus, defaults to @see getDefaultFocusOutlineStyes\n */\nexport const createCustomFocusIndicatorStyle = (\n style: GriffelStyle,\n options: CreateFocusIndicatorStyleRuleOptions = defaultOptions,\n): GriffelStyle => ({\n ':focus-visible': {\n outlineStyle: 'none',\n },\n [`${KEYBOARD_NAV_SELECTOR} :${options.selector || defaultOptions.selector}`]: style,\n});\n"],"sourceRoot":"../src/"}
@@ -0,0 +1,12 @@
1
+ import { Types } from 'tabster';
2
+ export interface UseFocusableGroupOptions {
3
+ /**
4
+ * Behavior for the Tab key.
5
+ */
6
+ tabBehavior?: 'unlimited' | 'limited' | 'limitedTrapFocus';
7
+ }
8
+ /**
9
+ * A hook that returns the necessary tabster attributes to support groupping.
10
+ * @param options - Options to configure keyboard navigation
11
+ */
12
+ export declare const useFocusableGroup: (options?: UseFocusableGroupOptions | undefined) => Types.TabsterDOMAttribute;
@@ -0,0 +1,38 @@
1
+ import { Types, getGroupper } from 'tabster';
2
+ import { useTabsterAttributes } from './useTabsterAttributes';
3
+ import { useTabster } from './useTabster';
4
+ /**
5
+ * A hook that returns the necessary tabster attributes to support groupping.
6
+ * @param options - Options to configure keyboard navigation
7
+ */
8
+
9
+ export const useFocusableGroup = options => {
10
+ const tabster = useTabster();
11
+
12
+ if (tabster) {
13
+ getGroupper(tabster);
14
+ }
15
+
16
+ return useTabsterAttributes({
17
+ groupper: {
18
+ tabbability: getTabbability(options === null || options === void 0 ? void 0 : options.tabBehavior)
19
+ }
20
+ });
21
+ };
22
+
23
+ const getTabbability = tabBehavior => {
24
+ switch (tabBehavior) {
25
+ case 'unlimited':
26
+ return Types.GroupperTabbabilities.Unlimited;
27
+
28
+ case 'limited':
29
+ return Types.GroupperTabbabilities.Limited;
30
+
31
+ case 'limitedTrapFocus':
32
+ return Types.GroupperTabbabilities.LimitedTrapFocus;
33
+
34
+ default:
35
+ return undefined;
36
+ }
37
+ };
38
+ //# sourceMappingURL=useFocusableGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["hooks/useFocusableGroup.ts"],"names":[],"mappings":"AAAA,SAAS,KAAT,EAAgB,WAAhB,QAAmC,SAAnC;AACA,SAAS,oBAAT,QAAqC,wBAArC;AACA,SAAS,UAAT,QAA2B,cAA3B;AASA;;;AAGG;;AACH,OAAO,MAAM,iBAAiB,GAAI,OAAD,IAAuC;AACtE,QAAM,OAAO,GAAG,UAAU,EAA1B;;AAEA,MAAI,OAAJ,EAAa;AACX,IAAA,WAAW,CAAC,OAAD,CAAX;AACD;;AAED,SAAO,oBAAoB,CAAC;AAC1B,IAAA,QAAQ,EAAE;AACR,MAAA,WAAW,EAAE,cAAc,CAAC,OAAO,KAAA,IAAP,IAAA,OAAO,KAAA,KAAA,CAAP,GAAO,KAAA,CAAP,GAAA,OAAO,CAAE,WAAV;AADnB;AADgB,GAAD,CAA3B;AAKD,CAZM;;AAcP,MAAM,cAAc,GAClB,WADqB,IAEoB;AACzC,UAAQ,WAAR;AACE,SAAK,WAAL;AACE,aAAO,KAAK,CAAC,qBAAN,CAA4B,SAAnC;;AACF,SAAK,SAAL;AACE,aAAO,KAAK,CAAC,qBAAN,CAA4B,OAAnC;;AACF,SAAK,kBAAL;AACE,aAAO,KAAK,CAAC,qBAAN,CAA4B,gBAAnC;;AACF;AACE,aAAO,SAAP;AARJ;AAUD,CAbD","sourcesContent":["import { Types, getGroupper } from 'tabster';\nimport { useTabsterAttributes } from './useTabsterAttributes';\nimport { useTabster } from './useTabster';\n\nexport interface UseFocusableGroupOptions {\n /**\n * Behavior for the Tab key.\n */\n tabBehavior?: 'unlimited' | 'limited' | 'limitedTrapFocus';\n}\n\n/**\n * A hook that returns the necessary tabster attributes to support groupping.\n * @param options - Options to configure keyboard navigation\n */\nexport const useFocusableGroup = (options?: UseFocusableGroupOptions) => {\n const tabster = useTabster();\n\n if (tabster) {\n getGroupper(tabster);\n }\n\n return useTabsterAttributes({\n groupper: {\n tabbability: getTabbability(options?.tabBehavior),\n },\n });\n};\n\nconst getTabbability = (\n tabBehavior?: UseFocusableGroupOptions['tabBehavior'],\n): Types.GroupperTabbability | undefined => {\n switch (tabBehavior) {\n case 'unlimited':\n return Types.GroupperTabbabilities.Unlimited;\n case 'limited':\n return Types.GroupperTabbabilities.Limited;\n case 'limitedTrapFocus':\n return Types.GroupperTabbabilities.LimitedTrapFocus;\n default:\n return undefined;\n }\n};\n"],"sourceRoot":"../src/"}
@@ -0,0 +1,5 @@
1
+ import type { RefObject } from 'react';
2
+ /**
3
+ * instantiates keyborg and add attribute to ensure focus indicator synced to keyborg logic
4
+ */
5
+ export declare function useKeyboardNavAttribute<E extends HTMLElement>(): RefObject<E>;
@@ -0,0 +1,41 @@
1
+ import { createKeyborg } from 'keyborg';
2
+ import { useEffect, useMemo, useRef } from 'react';
3
+ import { KEYBOARD_NAV_ATTRIBUTE } from '../symbols';
4
+ import { useFluent } from '@fluentui/react-shared-contexts';
5
+ /**
6
+ * instantiates keyborg and add attribute to ensure focus indicator synced to keyborg logic
7
+ */
8
+
9
+ export function useKeyboardNavAttribute() {
10
+ const {
11
+ targetDocument
12
+ } = useFluent();
13
+ const keyborg = useMemo(() => targetDocument && createKeyborg(targetDocument.defaultView), [targetDocument]);
14
+ const ref = useRef(null);
15
+ useEffect(() => {
16
+ if (keyborg) {
17
+ setBooleanAttribute(ref, KEYBOARD_NAV_ATTRIBUTE, keyborg.isNavigatingWithKeyboard());
18
+
19
+ const cb = next => {
20
+ setBooleanAttribute(ref, KEYBOARD_NAV_ATTRIBUTE, next);
21
+ };
22
+
23
+ keyborg.subscribe(cb);
24
+ return () => keyborg.unsubscribe(cb);
25
+ }
26
+ }, [keyborg]);
27
+ return ref;
28
+ }
29
+
30
+ function setBooleanAttribute(elementRef, attribute, value) {
31
+ if (!elementRef.current) {
32
+ return;
33
+ }
34
+
35
+ if (value) {
36
+ elementRef.current.setAttribute(attribute, '');
37
+ } else {
38
+ elementRef.current.removeAttribute(attribute);
39
+ }
40
+ }
41
+ //# sourceMappingURL=useKeyboardNavAttribute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["hooks/useKeyboardNavAttribute.ts"],"names":[],"mappings":"AAAA,SAAS,aAAT,QAA8B,SAA9B;AACA,SAAS,SAAT,EAAoB,OAApB,EAA6B,MAA7B,QAA2C,OAA3C;AACA,SAAS,sBAAT,QAAuC,YAAvC;AACA,SAAS,SAAT,QAA0B,iCAA1B;AAIA;;AAEG;;AACH,OAAM,SAAU,uBAAV,GAAiC;AACrC,QAAM;AAAE,IAAA;AAAF,MAAqB,SAAS,EAApC;AACA,QAAM,OAAO,GAAG,OAAO,CAAC,MAAM,cAAc,IAAI,aAAa,CAAC,cAAc,CAAC,WAAhB,CAAtC,EAAqE,CAAC,cAAD,CAArE,CAAvB;AACA,QAAM,GAAG,GAAG,MAAM,CAAI,IAAJ,CAAlB;AACA,EAAA,SAAS,CAAC,MAAK;AACb,QAAI,OAAJ,EAAa;AACX,MAAA,mBAAmB,CAAC,GAAD,EAAM,sBAAN,EAA8B,OAAO,CAAC,wBAAR,EAA9B,CAAnB;;AACA,YAAM,EAAE,GAAoB,IAAI,IAAG;AACjC,QAAA,mBAAmB,CAAC,GAAD,EAAM,sBAAN,EAA8B,IAA9B,CAAnB;AACD,OAFD;;AAGA,MAAA,OAAO,CAAC,SAAR,CAAkB,EAAlB;AACA,aAAO,MAAM,OAAO,CAAC,WAAR,CAAoB,EAApB,CAAb;AACD;AACF,GATQ,EASN,CAAC,OAAD,CATM,CAAT;AAUA,SAAO,GAAP;AACD;;AAED,SAAS,mBAAT,CAA6B,UAA7B,EAAiE,SAAjE,EAAoF,KAApF,EAAkG;AAChG,MAAI,CAAC,UAAU,CAAC,OAAhB,EAAyB;AACvB;AACD;;AACD,MAAI,KAAJ,EAAW;AACT,IAAA,UAAU,CAAC,OAAX,CAAmB,YAAnB,CAAgC,SAAhC,EAA2C,EAA3C;AACD,GAFD,MAEO;AACL,IAAA,UAAU,CAAC,OAAX,CAAmB,eAAnB,CAAmC,SAAnC;AACD;AACF","sourcesContent":["import { createKeyborg } from 'keyborg';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { KEYBOARD_NAV_ATTRIBUTE } from '../symbols';\nimport { useFluent } from '@fluentui/react-shared-contexts';\nimport type { KeyborgCallback } from 'keyborg/dist/Keyborg';\nimport type { RefObject } from 'react';\n\n/**\n * instantiates keyborg and add attribute to ensure focus indicator synced to keyborg logic\n */\nexport function useKeyboardNavAttribute<E extends HTMLElement>() {\n const { targetDocument } = useFluent();\n const keyborg = useMemo(() => targetDocument && createKeyborg(targetDocument.defaultView!), [targetDocument]);\n const ref = useRef<E>(null);\n useEffect(() => {\n if (keyborg) {\n setBooleanAttribute(ref, KEYBOARD_NAV_ATTRIBUTE, keyborg.isNavigatingWithKeyboard());\n const cb: KeyborgCallback = next => {\n setBooleanAttribute(ref, KEYBOARD_NAV_ATTRIBUTE, next);\n };\n keyborg.subscribe(cb);\n return () => keyborg.unsubscribe(cb);\n }\n }, [keyborg]);\n return ref;\n}\n\nfunction setBooleanAttribute(elementRef: RefObject<HTMLElement>, attribute: string, value: boolean) {\n if (!elementRef.current) {\n return;\n }\n if (value) {\n elementRef.current.setAttribute(attribute, '');\n } else {\n elementRef.current.removeAttribute(attribute);\n }\n}\n"],"sourceRoot":"../src/"}
@@ -0,0 +1,22 @@
1
+ import { Types as TabsterTypes } from 'tabster';
2
+ export interface UseModalAttributesOptions {
3
+ /**
4
+ * Traps focus inside the elements the attributes are applied
5
+ */
6
+ trapFocus?: boolean;
7
+ /**
8
+ * Always reachabled in Tab order
9
+ */
10
+ alwaysFocusable?: boolean;
11
+ }
12
+ /**
13
+ * Applies modal dialog behaviour through DOM attributes
14
+ * Modal element will focus trap and hide other content on the page
15
+ * The trigger element will be focused if focus is lost after the modal element is removed
16
+ *
17
+ * @returns DOM attributes to apply to the modal element and its trigger
18
+ */
19
+ export declare const useModalAttributes: (options?: UseModalAttributesOptions) => {
20
+ modalAttributes: TabsterTypes.TabsterDOMAttribute;
21
+ triggerAttributes: TabsterTypes.TabsterDOMAttribute;
22
+ };
@@ -0,0 +1,42 @@
1
+ import { useId } from '@fluentui/react-utilities';
2
+ import { useTabsterAttributes } from './useTabsterAttributes';
3
+ import { getDeloser, getModalizer } from 'tabster';
4
+ import { useTabster } from './useTabster';
5
+ /**
6
+ * Applies modal dialog behaviour through DOM attributes
7
+ * Modal element will focus trap and hide other content on the page
8
+ * The trigger element will be focused if focus is lost after the modal element is removed
9
+ *
10
+ * @returns DOM attributes to apply to the modal element and its trigger
11
+ */
12
+
13
+ export const useModalAttributes = (options = {}) => {
14
+ const {
15
+ trapFocus,
16
+ alwaysFocusable
17
+ } = options;
18
+ const tabster = useTabster(); // Initializes the modalizer and deloser APIs
19
+
20
+ if (tabster) {
21
+ getModalizer(tabster);
22
+ getDeloser(tabster);
23
+ }
24
+
25
+ const id = useId('modal-');
26
+ const modalAttributes = useTabsterAttributes({
27
+ deloser: {},
28
+ modalizer: {
29
+ id,
30
+ isOthersAccessible: !trapFocus,
31
+ isAlwaysAccessible: alwaysFocusable
32
+ }
33
+ });
34
+ const triggerAttributes = useTabsterAttributes({
35
+ deloser: {}
36
+ });
37
+ return {
38
+ modalAttributes,
39
+ triggerAttributes
40
+ };
41
+ };
42
+ //# sourceMappingURL=useModalAttributes.js.map