@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.
- package/CHANGELOG.json +1981 -0
- package/CHANGELOG.md +821 -0
- package/LICENSE +15 -0
- package/README.md +42 -0
- package/dist/react-tabster.d.ts +122 -0
- package/lib/hooks/index.d.ts +7 -0
- package/lib/hooks/index.js +8 -0
- package/lib/hooks/index.js.map +1 -0
- package/lib/hooks/useArrowNavigationGroup.d.ts +22 -0
- package/lib/hooks/useArrowNavigationGroup.js +37 -0
- package/lib/hooks/useArrowNavigationGroup.js.map +1 -0
- package/lib/hooks/useFocusFinders.d.ts +11 -0
- package/lib/hooks/useFocusFinders.js +36 -0
- package/lib/hooks/useFocusFinders.js.map +1 -0
- package/lib/hooks/useFocusIndicatorStyle.d.ts +33 -0
- package/lib/hooks/useFocusIndicatorStyle.js +84 -0
- package/lib/hooks/useFocusIndicatorStyle.js.map +1 -0
- package/lib/hooks/useFocusableGroup.d.ts +12 -0
- package/lib/hooks/useFocusableGroup.js +38 -0
- package/lib/hooks/useFocusableGroup.js.map +1 -0
- package/lib/hooks/useKeyboardNavAttribute.d.ts +5 -0
- package/lib/hooks/useKeyboardNavAttribute.js +41 -0
- package/lib/hooks/useKeyboardNavAttribute.js.map +1 -0
- package/lib/hooks/useModalAttributes.d.ts +22 -0
- package/lib/hooks/useModalAttributes.js +42 -0
- package/lib/hooks/useModalAttributes.js.map +1 -0
- package/lib/hooks/useTabster.d.ts +9 -0
- package/lib/hooks/useTabster.js +30 -0
- package/lib/hooks/useTabster.js.map +1 -0
- package/lib/hooks/useTabsterAttributes.d.ts +5 -0
- package/lib/hooks/useTabsterAttributes.js +13 -0
- package/lib/hooks/useTabsterAttributes.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/symbols.d.ts +2 -0
- package/lib/symbols.js +3 -0
- package/lib/symbols.js.map +1 -0
- package/lib/tsdoc-metadata.json +11 -0
- package/lib-commonjs/hooks/index.d.ts +7 -0
- package/lib-commonjs/hooks/index.js +22 -0
- package/lib-commonjs/hooks/index.js.map +1 -0
- package/lib-commonjs/hooks/useArrowNavigationGroup.d.ts +22 -0
- package/lib-commonjs/hooks/useArrowNavigationGroup.js +49 -0
- package/lib-commonjs/hooks/useArrowNavigationGroup.js.map +1 -0
- package/lib-commonjs/hooks/useFocusFinders.d.ts +11 -0
- package/lib-commonjs/hooks/useFocusFinders.js +47 -0
- package/lib-commonjs/hooks/useFocusFinders.js.map +1 -0
- package/lib-commonjs/hooks/useFocusIndicatorStyle.d.ts +33 -0
- package/lib-commonjs/hooks/useFocusIndicatorStyle.js +97 -0
- package/lib-commonjs/hooks/useFocusIndicatorStyle.js.map +1 -0
- package/lib-commonjs/hooks/useFocusableGroup.d.ts +12 -0
- package/lib-commonjs/hooks/useFocusableGroup.js +50 -0
- package/lib-commonjs/hooks/useFocusableGroup.js.map +1 -0
- package/lib-commonjs/hooks/useKeyboardNavAttribute.d.ts +5 -0
- package/lib-commonjs/hooks/useKeyboardNavAttribute.js +54 -0
- package/lib-commonjs/hooks/useKeyboardNavAttribute.js.map +1 -0
- package/lib-commonjs/hooks/useModalAttributes.d.ts +22 -0
- package/lib-commonjs/hooks/useModalAttributes.js +55 -0
- package/lib-commonjs/hooks/useModalAttributes.js.map +1 -0
- package/lib-commonjs/hooks/useTabster.d.ts +9 -0
- package/lib-commonjs/hooks/useTabster.js +41 -0
- package/lib-commonjs/hooks/useTabster.js.map +1 -0
- package/lib-commonjs/hooks/useTabsterAttributes.d.ts +5 -0
- package/lib-commonjs/hooks/useTabsterAttributes.js +24 -0
- package/lib-commonjs/hooks/useTabsterAttributes.js.map +1 -0
- package/lib-commonjs/index.d.ts +1 -0
- package/lib-commonjs/index.js +10 -0
- package/lib-commonjs/index.js.map +1 -0
- package/lib-commonjs/symbols.d.ts +2 -0
- package/lib-commonjs/symbols.js +9 -0
- package/lib-commonjs/symbols.js.map +1 -0
- 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":"AAAA,SAAS,MAAT,QAAuB,uBAAvB;AACA,SAAS,qBAAT,QAAsC,YAAtC;AAeA;;;;;;AAMG;;AACH,MAAM,qBAAqB,GAAI,OAAD,IAAsC;;;AAClE,QAAM;AAAE,IAAA,aAAF;AAAiB,IAAA,YAAjB;AAA+B,IAAA,aAA/B;AAA8C,IAAA;AAA9C,MAA+D,OAArE;AAEA,QAAM,gBAAgB,GAAG,CAAA,CAAA,EAAA,GAAC,aAAD,MAAqC,IAArC,IAAqC,EAAA,KAAA,KAAA,CAArC,GAAqC,KAAA,CAArC,GAAqC,EAAA,CAAE,GAAvC,KAA8C,aAAvE;AACA,QAAM,mBAAmB,GAAG,CAAA,CAAA,EAAA,GAAC,aAAD,MAAqC,IAArC,IAAqC,EAAA,KAAA,KAAA,CAArC,GAAqC,KAAA,CAArC,GAAqC,EAAA,CAAE,MAAvC,KAAiD,aAA7E;AACA,QAAM,iBAAiB,GAAG,CAAA,CAAA,EAAA,GAAC,aAAD,MAAqC,IAArC,IAAqC,EAAA,KAAA,KAAA,CAArC,GAAqC,KAAA,CAArC,GAAqC,EAAA,CAAE,IAAvC,KAA+C,aAAzE;AACA,QAAM,kBAAkB,GAAG,CAAA,CAAA,EAAA,GAAC,aAAD,MAAqC,IAArC,IAAqC,EAAA,KAAA,KAAA,CAArC,GAAqC,KAAA,CAArC,GAAqC,EAAA,CAAE,KAAvC,KAAgD,aAA3E;AAEA,SAAO;AACL,IAAA,WAAW,EAAE,aADR;AAEL,cAAU;AACR,MAAA,OAAO,EAAE,IADD;AAER,MAAA,QAAQ,EAAE,UAFF;AAGR,MAAA,aAAa,EAAE,MAHP;AAIR,MAAA,SAAS,EAAE,aAJH;AAKR,MAAA,MAAM,EAAE,CALA;AAOR,MAAA,WAAW,EAAE,OAPL;AAQR,MAAA,WAAW,EAAE,YARL;AASR,MAAA,YAAY,EAAE,aATN;AAUR,MAAA,WAAW,EAAE,YAVL;AAYR,MAAA,GAAG,EAAE,CAAC,aAAD,GAAiB,IAAI,YAAY,EAAjC,GAAsC,cAAc,YAAY,MAAM,gBAAgB,GAZnF;AAaR,MAAA,MAAM,EAAE,CAAC,aAAD,GAAiB,IAAI,YAAY,EAAjC,GAAsC,cAAc,YAAY,MAAM,mBAAmB,GAbzF;AAcR,MAAA,IAAI,EAAE,CAAC,aAAD,GAAiB,IAAI,YAAY,EAAjC,GAAsC,cAAc,YAAY,MAAM,iBAAiB,GAdrF;AAeR,MAAA,KAAK,EAAE,CAAC,aAAD,GAAiB,IAAI,YAAY,EAAjC,GAAsC,cAAc,YAAY,MAAM,kBAAkB;AAfvF;AAFL,GAAP;AAoBD,CA5BD;;AAkCA,MAAM,cAAc,GAAyC;AAC3D,EAAA,QAAQ,EAAE;AADiD,CAA7D;AAIA;;;;;;;AAOG;;AACH,OAAO,MAAM,uBAAuB,GAAG,CACrC,OAAA,GAE2C;AAAE,EAAA,KAAK,EAAE,EAAT;AAAa,KAAG;AAAhB,CAHN,MAInB;AAClB,oBAAkB;AAChB,IAAA,YAAY,EAAE;AADE,GADA;AAIlB,GAAC,GAAG,qBAAqB,KAAK,OAAO,CAAC,QAAR,IAAoB,cAAc,CAAC,QAAQ,EAAzE,GAA8E,qBAAqB,CAAC;AAClG,IAAA,YAAY,EAAE,MAAM,CAAC,iBAD6E;AAElG,IAAA,aAAa,EAAE,MAAM,CAAC,kBAF4E;AAGlG;AACA,IAAA,YAAY,EAAE,KAJoF;AAKlG,OAAG,OAAO,CAAC;AALuF,GAAD;AAJjF,CAJmB,CAAhC;AAiBP;;;;;AAKG;;AACH,OAAO,MAAM,+BAA+B,GAAG,CAC7C,KAD6C,EAE7C,OAAA,GAAgD,cAFH,MAG3B;AAClB,oBAAkB;AAChB,IAAA,YAAY,EAAE;AADE,GADA;AAIlB,GAAC,GAAG,qBAAqB,KAAK,OAAO,CAAC,QAAR,IAAoB,cAAc,CAAC,QAAQ,EAAzE,GAA8E;AAJ5D,CAH2B,CAAxC","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,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
|