@fluentui/react-menu-grid-preview 0.3.2 → 0.4.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 +22 -2
- package/dist/index.d.ts +16 -1
- package/lib/components/MenuGrid/MenuGrid.types.js +1 -1
- package/lib/components/MenuGrid/MenuGrid.types.js.map +1 -1
- package/lib/components/MenuGrid/useMenuGrid.js +54 -6
- package/lib/components/MenuGrid/useMenuGrid.js.map +1 -1
- package/lib/components/MenuGrid/useMenuGridContextValues.js +5 -3
- package/lib/components/MenuGrid/useMenuGridContextValues.js.map +1 -1
- package/lib/components/MenuGridRow/useCharacterSearch.js +25 -0
- package/lib/components/MenuGridRow/useCharacterSearch.js.map +1 -0
- package/lib/components/MenuGridRow/useMenuGridRow.js +7 -3
- package/lib/components/MenuGridRow/useMenuGridRow.js.map +1 -1
- package/lib/contexts/menuGridContext.js +2 -1
- package/lib/contexts/menuGridContext.js.map +1 -1
- package/lib-commonjs/components/MenuGrid/MenuGrid.types.js +2 -0
- package/lib-commonjs/components/MenuGrid/MenuGrid.types.js.map +1 -1
- package/lib-commonjs/components/MenuGrid/useMenuGrid.js +53 -5
- package/lib-commonjs/components/MenuGrid/useMenuGrid.js.map +1 -1
- package/lib-commonjs/components/MenuGrid/useMenuGridContextValues.js +5 -3
- package/lib-commonjs/components/MenuGrid/useMenuGridContextValues.js.map +1 -1
- package/lib-commonjs/components/MenuGridRow/useCharacterSearch.js +32 -0
- package/lib-commonjs/components/MenuGridRow/useCharacterSearch.js.map +1 -0
- package/lib-commonjs/components/MenuGridRow/useMenuGridRow.js +7 -3
- package/lib-commonjs/components/MenuGridRow/useMenuGridRow.js.map +1 -1
- package/lib-commonjs/contexts/menuGridContext.js +2 -1
- package/lib-commonjs/contexts/menuGridContext.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
# Change Log - @fluentui/react-menu-grid-preview
|
|
2
2
|
|
|
3
|
-
This log was last generated on
|
|
3
|
+
This log was last generated on Mon, 30 Mar 2026 14:35:50 GMT and should not be manually modified.
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
+
## [0.4.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-menu-grid-preview_v0.4.1)
|
|
8
|
+
|
|
9
|
+
Mon, 30 Mar 2026 14:35:50 GMT
|
|
10
|
+
[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-menu-grid-preview_v0.4.0..@fluentui/react-menu-grid-preview_v0.4.1)
|
|
11
|
+
|
|
12
|
+
### Patches
|
|
13
|
+
|
|
14
|
+
- Bump @fluentui/react-menu to v9.23.1 ([PR #35907](https://github.com/microsoft/fluentui/pull/35907) by beachball)
|
|
15
|
+
- Bump @fluentui/react-table to v9.19.13 ([PR #35907](https://github.com/microsoft/fluentui/pull/35907) by beachball)
|
|
16
|
+
|
|
17
|
+
## [0.4.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-menu-grid-preview_v0.4.0)
|
|
18
|
+
|
|
19
|
+
Thu, 26 Mar 2026 08:12:50 GMT
|
|
20
|
+
[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-menu-grid-preview_v0.3.2..@fluentui/react-menu-grid-preview_v0.4.0)
|
|
21
|
+
|
|
22
|
+
### Minor changes
|
|
23
|
+
|
|
24
|
+
- Add circular and first-letter navigation ([PR #35880](https://github.com/microsoft/fluentui/pull/35880) by email not defined)
|
|
25
|
+
- Bump @fluentui/react-table to v9.19.12 ([PR #35824](https://github.com/microsoft/fluentui/pull/35824) by beachball)
|
|
26
|
+
|
|
7
27
|
## [0.3.2](https://github.com/microsoft/fluentui/tree/@fluentui/react-menu-grid-preview_v0.3.2)
|
|
8
28
|
|
|
9
|
-
Tue, 17 Mar 2026 07:
|
|
29
|
+
Tue, 17 Mar 2026 07:57:16 GMT
|
|
10
30
|
[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-menu-grid-preview_v0.3.1..@fluentui/react-menu-grid-preview_v0.3.2)
|
|
11
31
|
|
|
12
32
|
### Patches
|
package/dist/index.d.ts
CHANGED
|
@@ -46,6 +46,10 @@ export declare type MenuGridContextValue = {
|
|
|
46
46
|
* Tabster row attributes applied to the `MenuGridRow` components
|
|
47
47
|
*/
|
|
48
48
|
tableRowTabsterAttribute: TabsterDOMAttribute | null;
|
|
49
|
+
/**
|
|
50
|
+
* Callback to focus the first row in the grid whose text content starts with the given character.
|
|
51
|
+
*/
|
|
52
|
+
setFocusByFirstCharacter?: (e: React_2.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => void;
|
|
49
53
|
};
|
|
50
54
|
|
|
51
55
|
export declare type MenuGridContextValues = {
|
|
@@ -140,7 +144,14 @@ export declare type MenuGridItemSlots = {
|
|
|
140
144
|
|
|
141
145
|
export declare type MenuGridItemState = ComponentState<MenuGridItemSlots>;
|
|
142
146
|
|
|
143
|
-
export declare type MenuGridProps = ComponentProps<MenuGridSlots> & {
|
|
147
|
+
export declare type MenuGridProps = ComponentProps<MenuGridSlots> & {
|
|
148
|
+
/**
|
|
149
|
+
* Whether keyboard navigation wraps from the last row to the first and vice versa.
|
|
150
|
+
*
|
|
151
|
+
* @default true
|
|
152
|
+
*/
|
|
153
|
+
circular?: boolean;
|
|
154
|
+
};
|
|
144
155
|
|
|
145
156
|
/**
|
|
146
157
|
* Define a MenuGridRow, using the `useMenuGridRow_unstable` hook.
|
|
@@ -166,6 +177,10 @@ export declare type MenuGridState = ComponentState<MenuGridSlots> & {
|
|
|
166
177
|
* Tabster row attributes applied to the `MenuGridRow` components
|
|
167
178
|
*/
|
|
168
179
|
tableRowTabsterAttribute: TabsterDOMAttribute | null;
|
|
180
|
+
/**
|
|
181
|
+
* Callback to focus the first row in the grid whose text content starts with the given character.
|
|
182
|
+
*/
|
|
183
|
+
setFocusByFirstCharacter?: (e: React_2.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => void;
|
|
169
184
|
};
|
|
170
185
|
|
|
171
186
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import * as React from 'react';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MenuGrid/MenuGrid.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport { TabsterDOMAttribute } from '@fluentui/react-tabster';\nimport type { MenuListContextValue } from '@fluentui/react-menu';\n\nimport type { MenuGridContextValue } from '../../contexts/menuGridContext';\n\nexport type MenuGridSlots = {\n root: Slot<'div'>;\n};\n\nexport type MenuGridProps = ComponentProps<MenuGridSlots> & {};\n\nexport type MenuGridState = ComponentState<MenuGridSlots> & {\n /**\n * Tabster row attributes applied to the `MenuGridRow` components\n */\n tableRowTabsterAttribute: TabsterDOMAttribute | null;\n};\n\nexport type MenuGridContextValues = {\n menuGrid: MenuGridContextValue;\n menuList: MenuListContextValue;\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGrid/MenuGrid.types.ts"],"sourcesContent":["import * as React from 'react';\nimport type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport { TabsterDOMAttribute } from '@fluentui/react-tabster';\nimport type { MenuListContextValue } from '@fluentui/react-menu';\n\nimport type { MenuGridContextValue } from '../../contexts/menuGridContext';\n\nexport type MenuGridSlots = {\n root: Slot<'div'>;\n};\n\nexport type MenuGridProps = ComponentProps<MenuGridSlots> & {\n /**\n * Whether keyboard navigation wraps from the last row to the first and vice versa.\n *\n * @default true\n */\n circular?: boolean;\n};\n\nexport type MenuGridState = ComponentState<MenuGridSlots> & {\n /**\n * Tabster row attributes applied to the `MenuGridRow` components\n */\n tableRowTabsterAttribute: TabsterDOMAttribute | null;\n\n /**\n * Callback to focus the first row in the grid whose text content starts with the given character.\n */\n setFocusByFirstCharacter?: (e: React.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => void;\n};\n\nexport type MenuGridContextValues = {\n menuGrid: MenuGridContextValue;\n menuList: MenuListContextValue;\n};\n"],"names":["React"],"mappings":"AAAA,YAAYA,WAAW,QAAQ"}
|
|
@@ -2,16 +2,22 @@
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { useMergedRefs, useEventCallback, mergeCallbacks, getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
|
|
4
4
|
import { useTableCompositeNavigation } from '@fluentui/react-table';
|
|
5
|
-
import { useMergedTabsterAttributes_unstable, useTabsterAttributes } from '@fluentui/react-tabster';
|
|
5
|
+
import { useArrowNavigationGroup, useFocusFinders, useMergedTabsterAttributes_unstable, useTabsterAttributes } from '@fluentui/react-tabster';
|
|
6
6
|
import { useMenuContext_unstable } from '@fluentui/react-menu';
|
|
7
7
|
import { useValidateNesting } from '../../utils/useValidateNesting';
|
|
8
8
|
/**
|
|
9
9
|
* Returns the props and state required to render the component
|
|
10
10
|
*/ export const useMenuGrid_unstable = (props, ref)=>{
|
|
11
|
+
const { circular = true, ...restProps } = props;
|
|
11
12
|
const validateNestingRef = useValidateNesting('MenuGrid');
|
|
13
|
+
const innerRef = React.useRef(null);
|
|
14
|
+
const { findAllFocusable } = useFocusFinders();
|
|
12
15
|
const triggerId = useMenuContext_unstable((context)=>context.triggerId);
|
|
13
16
|
const { tableRowTabsterAttribute, tableTabsterAttribute, onTableKeyDown } = useTableCompositeNavigation();
|
|
14
|
-
const
|
|
17
|
+
const circularGridAttribute = useArrowNavigationGroup({
|
|
18
|
+
circular
|
|
19
|
+
});
|
|
20
|
+
const mergedTabsterAttribute = useMergedTabsterAttributes_unstable(tableTabsterAttribute, circularGridAttribute);
|
|
15
21
|
const ignoreEnterKeyAttribute = useTabsterAttributes({
|
|
16
22
|
focusable: {
|
|
17
23
|
ignoreKeydown: {
|
|
@@ -20,20 +26,62 @@ import { useValidateNesting } from '../../utils/useValidateNesting';
|
|
|
20
26
|
}
|
|
21
27
|
});
|
|
22
28
|
const mergedRowTabsterAttribute = useMergedTabsterAttributes_unstable(tableRowTabsterAttribute, ignoreEnterKeyAttribute);
|
|
29
|
+
const onKeyDown = useEventCallback(mergeCallbacks(props.onKeyDown, onTableKeyDown));
|
|
30
|
+
const setFocusByFirstCharacter = React.useCallback((e, itemEl)=>{
|
|
31
|
+
if (!innerRef.current) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const target = e.target;
|
|
35
|
+
// Only apply first-letter navigation when event target is a grid row, otherwise it may conflict with other components inside the grid row
|
|
36
|
+
if (!target.hasAttribute('role') || target.getAttribute('role') !== 'row') {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const rows = findAllFocusable(innerRef.current, (el)=>el.hasAttribute('role') && el.getAttribute('role') === 'row');
|
|
40
|
+
let startIndex = rows.indexOf(itemEl) + 1;
|
|
41
|
+
if (startIndex === rows.length) {
|
|
42
|
+
startIndex = 0;
|
|
43
|
+
}
|
|
44
|
+
const firstChars = rows.map((row)=>{
|
|
45
|
+
var _row_textContent;
|
|
46
|
+
return (_row_textContent = row.textContent) === null || _row_textContent === void 0 ? void 0 : _row_textContent.charAt(0).toLowerCase();
|
|
47
|
+
});
|
|
48
|
+
const char = e.key.toLowerCase();
|
|
49
|
+
const getIndexFirstChars = (start)=>{
|
|
50
|
+
for(let i = start; i < firstChars.length; i++){
|
|
51
|
+
if (char === firstChars[i]) {
|
|
52
|
+
return i;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return -1;
|
|
56
|
+
};
|
|
57
|
+
// Check remaining rows in the grid
|
|
58
|
+
let index = getIndexFirstChars(startIndex);
|
|
59
|
+
// If not found in remaining rows, check from beginning
|
|
60
|
+
if (index === -1) {
|
|
61
|
+
index = getIndexFirstChars(0);
|
|
62
|
+
}
|
|
63
|
+
// If match was found, focus it
|
|
64
|
+
if (index > -1) {
|
|
65
|
+
rows[index].focus();
|
|
66
|
+
}
|
|
67
|
+
}, [
|
|
68
|
+
findAllFocusable
|
|
69
|
+
]);
|
|
23
70
|
return {
|
|
24
71
|
components: {
|
|
25
72
|
root: 'div'
|
|
26
73
|
},
|
|
27
74
|
root: slot.always(getIntrinsicElementProps('div', {
|
|
28
|
-
ref: useMergedRefs(ref, validateNestingRef),
|
|
75
|
+
ref: useMergedRefs(ref, validateNestingRef, innerRef),
|
|
29
76
|
role: 'grid',
|
|
30
77
|
'aria-labelledby': triggerId,
|
|
31
|
-
...
|
|
32
|
-
...
|
|
78
|
+
...mergedTabsterAttribute,
|
|
79
|
+
...restProps,
|
|
33
80
|
onKeyDown
|
|
34
81
|
}), {
|
|
35
82
|
elementType: 'div'
|
|
36
83
|
}),
|
|
37
|
-
tableRowTabsterAttribute: mergedRowTabsterAttribute
|
|
84
|
+
tableRowTabsterAttribute: mergedRowTabsterAttribute,
|
|
85
|
+
setFocusByFirstCharacter
|
|
38
86
|
};
|
|
39
87
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MenuGrid/useMenuGrid.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n useMergedRefs,\n useEventCallback,\n mergeCallbacks,\n getIntrinsicElementProps,\n slot,\n} from '@fluentui/react-utilities';\n\nimport { useTableCompositeNavigation } from '@fluentui/react-table';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGrid/useMenuGrid.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n useMergedRefs,\n useEventCallback,\n mergeCallbacks,\n getIntrinsicElementProps,\n slot,\n} from '@fluentui/react-utilities';\n\nimport { useTableCompositeNavigation } from '@fluentui/react-table';\nimport {\n useArrowNavigationGroup,\n useFocusFinders,\n useMergedTabsterAttributes_unstable,\n useTabsterAttributes,\n} from '@fluentui/react-tabster';\nimport type { MenuGridProps, MenuGridState } from './MenuGrid.types';\nimport { useMenuContext_unstable } from '@fluentui/react-menu';\nimport { useValidateNesting } from '../../utils/useValidateNesting';\n\n/**\n * Returns the props and state required to render the component\n */\nexport const useMenuGrid_unstable = (props: MenuGridProps, ref: React.Ref<HTMLDivElement>): MenuGridState => {\n const { circular = true, ...restProps } = props;\n const validateNestingRef = useValidateNesting('MenuGrid');\n const innerRef = React.useRef<HTMLDivElement>(null);\n const { findAllFocusable } = useFocusFinders();\n const triggerId = useMenuContext_unstable(context => context.triggerId);\n\n const { tableRowTabsterAttribute, tableTabsterAttribute, onTableKeyDown } = useTableCompositeNavigation();\n\n const circularGridAttribute = useArrowNavigationGroup({ circular });\n const mergedTabsterAttribute = useMergedTabsterAttributes_unstable(tableTabsterAttribute, circularGridAttribute);\n\n const ignoreEnterKeyAttribute = useTabsterAttributes({\n focusable: {\n ignoreKeydown: { Enter: true },\n },\n });\n const mergedRowTabsterAttribute = useMergedTabsterAttributes_unstable(\n tableRowTabsterAttribute,\n ignoreEnterKeyAttribute,\n );\n\n const onKeyDown = useEventCallback(mergeCallbacks(props.onKeyDown, onTableKeyDown));\n\n const setFocusByFirstCharacter = React.useCallback(\n (e: React.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => {\n if (!innerRef.current) {\n return;\n }\n\n const target = e.target as HTMLElement;\n\n // Only apply first-letter navigation when event target is a grid row, otherwise it may conflict with other components inside the grid row\n if (!target.hasAttribute('role') || target.getAttribute('role') !== 'row') {\n return;\n }\n\n const rows = findAllFocusable(\n innerRef.current,\n (el: HTMLElement) => el.hasAttribute('role') && el.getAttribute('role') === 'row',\n );\n\n let startIndex = rows.indexOf(itemEl) + 1;\n if (startIndex === rows.length) {\n startIndex = 0;\n }\n\n const firstChars = rows.map(row => row.textContent?.charAt(0).toLowerCase());\n const char = e.key.toLowerCase();\n\n const getIndexFirstChars = (start: number) => {\n for (let i = start; i < firstChars.length; i++) {\n if (char === firstChars[i]) {\n return i;\n }\n }\n return -1;\n };\n\n // Check remaining rows in the grid\n let index = getIndexFirstChars(startIndex);\n\n // If not found in remaining rows, check from beginning\n if (index === -1) {\n index = getIndexFirstChars(0);\n }\n\n // If match was found, focus it\n if (index > -1) {\n rows[index].focus();\n }\n },\n [findAllFocusable],\n );\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: useMergedRefs(ref, validateNestingRef, innerRef),\n role: 'grid',\n 'aria-labelledby': triggerId,\n ...mergedTabsterAttribute,\n ...restProps,\n onKeyDown,\n }),\n { elementType: 'div' },\n ),\n tableRowTabsterAttribute: mergedRowTabsterAttribute,\n setFocusByFirstCharacter,\n };\n};\n"],"names":["React","useMergedRefs","useEventCallback","mergeCallbacks","getIntrinsicElementProps","slot","useTableCompositeNavigation","useArrowNavigationGroup","useFocusFinders","useMergedTabsterAttributes_unstable","useTabsterAttributes","useMenuContext_unstable","useValidateNesting","useMenuGrid_unstable","props","ref","circular","restProps","validateNestingRef","innerRef","useRef","findAllFocusable","triggerId","context","tableRowTabsterAttribute","tableTabsterAttribute","onTableKeyDown","circularGridAttribute","mergedTabsterAttribute","ignoreEnterKeyAttribute","focusable","ignoreKeydown","Enter","mergedRowTabsterAttribute","onKeyDown","setFocusByFirstCharacter","useCallback","e","itemEl","current","target","hasAttribute","getAttribute","rows","el","startIndex","indexOf","length","firstChars","map","row","textContent","charAt","toLowerCase","char","key","getIndexFirstChars","start","i","index","focus","components","root","always","role","elementType"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SACEC,aAAa,EACbC,gBAAgB,EAChBC,cAAc,EACdC,wBAAwB,EACxBC,IAAI,QACC,4BAA4B;AAEnC,SAASC,2BAA2B,QAAQ,wBAAwB;AACpE,SACEC,uBAAuB,EACvBC,eAAe,EACfC,mCAAmC,EACnCC,oBAAoB,QACf,0BAA0B;AAEjC,SAASC,uBAAuB,QAAQ,uBAAuB;AAC/D,SAASC,kBAAkB,QAAQ,iCAAiC;AAEpE;;CAEC,GACD,OAAO,MAAMC,uBAAuB,CAACC,OAAsBC;IACzD,MAAM,EAAEC,WAAW,IAAI,EAAE,GAAGC,WAAW,GAAGH;IAC1C,MAAMI,qBAAqBN,mBAAmB;IAC9C,MAAMO,WAAWnB,MAAMoB,MAAM,CAAiB;IAC9C,MAAM,EAAEC,gBAAgB,EAAE,GAAGb;IAC7B,MAAMc,YAAYX,wBAAwBY,CAAAA,UAAWA,QAAQD,SAAS;IAEtE,MAAM,EAAEE,wBAAwB,EAAEC,qBAAqB,EAAEC,cAAc,EAAE,GAAGpB;IAE5E,MAAMqB,wBAAwBpB,wBAAwB;QAAES;IAAS;IACjE,MAAMY,yBAAyBnB,oCAAoCgB,uBAAuBE;IAE1F,MAAME,0BAA0BnB,qBAAqB;QACnDoB,WAAW;YACTC,eAAe;gBAAEC,OAAO;YAAK;QAC/B;IACF;IACA,MAAMC,4BAA4BxB,oCAChCe,0BACAK;IAGF,MAAMK,YAAYhC,iBAAiBC,eAAeW,MAAMoB,SAAS,EAAER;IAEnE,MAAMS,2BAA2BnC,MAAMoC,WAAW,CAChD,CAACC,GAAqCC;QACpC,IAAI,CAACnB,SAASoB,OAAO,EAAE;YACrB;QACF;QAEA,MAAMC,SAASH,EAAEG,MAAM;QAEvB,0IAA0I;QAC1I,IAAI,CAACA,OAAOC,YAAY,CAAC,WAAWD,OAAOE,YAAY,CAAC,YAAY,OAAO;YACzE;QACF;QAEA,MAAMC,OAAOtB,iBACXF,SAASoB,OAAO,EAChB,CAACK,KAAoBA,GAAGH,YAAY,CAAC,WAAWG,GAAGF,YAAY,CAAC,YAAY;QAG9E,IAAIG,aAAaF,KAAKG,OAAO,CAACR,UAAU;QACxC,IAAIO,eAAeF,KAAKI,MAAM,EAAE;YAC9BF,aAAa;QACf;QAEA,MAAMG,aAAaL,KAAKM,GAAG,CAACC,CAAAA;gBAAOA;oBAAAA,mBAAAA,IAAIC,WAAW,cAAfD,uCAAAA,iBAAiBE,MAAM,CAAC,GAAGC,WAAW;;QACzE,MAAMC,OAAOjB,EAAEkB,GAAG,CAACF,WAAW;QAE9B,MAAMG,qBAAqB,CAACC;YAC1B,IAAK,IAAIC,IAAID,OAAOC,IAAIV,WAAWD,MAAM,EAAEW,IAAK;gBAC9C,IAAIJ,SAASN,UAAU,CAACU,EAAE,EAAE;oBAC1B,OAAOA;gBACT;YACF;YACA,OAAO,CAAC;QACV;QAEA,mCAAmC;QACnC,IAAIC,QAAQH,mBAAmBX;QAE/B,uDAAuD;QACvD,IAAIc,UAAU,CAAC,GAAG;YAChBA,QAAQH,mBAAmB;QAC7B;QAEA,+BAA+B;QAC/B,IAAIG,QAAQ,CAAC,GAAG;YACdhB,IAAI,CAACgB,MAAM,CAACC,KAAK;QACnB;IACF,GACA;QAACvC;KAAiB;IAGpB,OAAO;QACLwC,YAAY;YACVC,MAAM;QACR;QACAA,MAAMzD,KAAK0D,MAAM,CACf3D,yBAAyB,OAAO;YAC9BW,KAAKd,cAAcc,KAAKG,oBAAoBC;YAC5C6C,MAAM;YACN,mBAAmB1C;YACnB,GAAGM,sBAAsB;YACzB,GAAGX,SAAS;YACZiB;QACF,IACA;YAAE+B,aAAa;QAAM;QAEvBzC,0BAA0BS;QAC1BE;IACF;AACF,EAAE"}
|
|
@@ -7,11 +7,13 @@ const menuList = {
|
|
|
7
7
|
shouldOpenOnArrowRight: false
|
|
8
8
|
};
|
|
9
9
|
export function useMenuGridContextValues_unstable(state) {
|
|
10
|
-
const { tableRowTabsterAttribute } = state;
|
|
10
|
+
const { tableRowTabsterAttribute, setFocusByFirstCharacter } = state;
|
|
11
11
|
const menuGrid = React.useMemo(()=>({
|
|
12
|
-
tableRowTabsterAttribute
|
|
12
|
+
tableRowTabsterAttribute,
|
|
13
|
+
setFocusByFirstCharacter
|
|
13
14
|
}), [
|
|
14
|
-
tableRowTabsterAttribute
|
|
15
|
+
tableRowTabsterAttribute,
|
|
16
|
+
setFocusByFirstCharacter
|
|
15
17
|
]);
|
|
16
18
|
return {
|
|
17
19
|
menuGrid,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MenuGrid/useMenuGridContextValues.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { MenuGridContextValues, MenuGridState } from './MenuGrid.types';\n\nconst menuList = {\n checkedValues: {},\n hasIcons: false,\n hasCheckmarks: false,\n shouldOpenOnArrowRight: false,\n};\n\nexport function useMenuGridContextValues_unstable(state: MenuGridState): MenuGridContextValues {\n const { tableRowTabsterAttribute } = state;\n const menuGrid = React.useMemo(() => ({ tableRowTabsterAttribute }),
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGrid/useMenuGridContextValues.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { MenuGridContextValues, MenuGridState } from './MenuGrid.types';\n\nconst menuList = {\n checkedValues: {},\n hasIcons: false,\n hasCheckmarks: false,\n shouldOpenOnArrowRight: false,\n};\n\nexport function useMenuGridContextValues_unstable(state: MenuGridState): MenuGridContextValues {\n const { tableRowTabsterAttribute, setFocusByFirstCharacter } = state;\n const menuGrid = React.useMemo(\n () => ({ tableRowTabsterAttribute, setFocusByFirstCharacter }),\n [tableRowTabsterAttribute, setFocusByFirstCharacter],\n );\n\n return { menuGrid, menuList };\n}\n"],"names":["React","menuList","checkedValues","hasIcons","hasCheckmarks","shouldOpenOnArrowRight","useMenuGridContextValues_unstable","state","tableRowTabsterAttribute","setFocusByFirstCharacter","menuGrid","useMemo"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAG/B,MAAMC,WAAW;IACfC,eAAe,CAAC;IAChBC,UAAU;IACVC,eAAe;IACfC,wBAAwB;AAC1B;AAEA,OAAO,SAASC,kCAAkCC,KAAoB;IACpE,MAAM,EAAEC,wBAAwB,EAAEC,wBAAwB,EAAE,GAAGF;IAC/D,MAAMG,WAAWV,MAAMW,OAAO,CAC5B,IAAO,CAAA;YAAEH;YAA0BC;QAAyB,CAAA,GAC5D;QAACD;QAA0BC;KAAyB;IAGtD,OAAO;QAAEC;QAAUT;IAAS;AAC9B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { useMenuGridContext_unstable } from '../../contexts/menuGridContext';
|
|
4
|
+
/**
|
|
5
|
+
* Returns the MenuGridRow's `onKeyDown` handler to support first-letter navigation.
|
|
6
|
+
* When a single character key is pressed, it delegates to the grid-level `setFocusByFirstCharacter`
|
|
7
|
+
* callback which finds and focuses the next row starting with that character.
|
|
8
|
+
*/ export const useCharacterSearch = ()=>{
|
|
9
|
+
'use no memo';
|
|
10
|
+
const characterSearchRef = React.useRef(null);
|
|
11
|
+
const { setFocusByFirstCharacter } = useMenuGridContext_unstable();
|
|
12
|
+
const characterSearchOnKeyDown = (e)=>{
|
|
13
|
+
var _e_key;
|
|
14
|
+
if (((_e_key = e.key) === null || _e_key === void 0 ? void 0 : _e_key.length) > 1) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (characterSearchRef.current) {
|
|
18
|
+
setFocusByFirstCharacter === null || setFocusByFirstCharacter === void 0 ? void 0 : setFocusByFirstCharacter(e, characterSearchRef.current);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
characterSearchOnKeyDown,
|
|
23
|
+
characterSearchRef
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGridRow/useCharacterSearch.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useMenuGridContext_unstable } from '../../contexts/menuGridContext';\n\n/**\n * Returns the MenuGridRow's `onKeyDown` handler to support first-letter navigation.\n * When a single character key is pressed, it delegates to the grid-level `setFocusByFirstCharacter`\n * callback which finds and focuses the next row starting with that character.\n */\nexport const useCharacterSearch = (): {\n characterSearchOnKeyDown: React.KeyboardEventHandler<HTMLElement>;\n characterSearchRef: React.RefObject<HTMLElement | null>;\n} => {\n 'use no memo';\n\n const characterSearchRef = React.useRef<HTMLDivElement>(null);\n\n const { setFocusByFirstCharacter } = useMenuGridContext_unstable();\n\n const characterSearchOnKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key?.length > 1) {\n return;\n }\n\n if (characterSearchRef.current) {\n setFocusByFirstCharacter?.(e, characterSearchRef.current);\n }\n };\n\n return { characterSearchOnKeyDown, characterSearchRef };\n};\n"],"names":["React","useMenuGridContext_unstable","useCharacterSearch","characterSearchRef","useRef","setFocusByFirstCharacter","characterSearchOnKeyDown","e","key","length","current"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,2BAA2B,QAAQ,iCAAiC;AAE7E;;;;CAIC,GACD,OAAO,MAAMC,qBAAqB;IAIhC;IAEA,MAAMC,qBAAqBH,MAAMI,MAAM,CAAiB;IAExD,MAAM,EAAEC,wBAAwB,EAAE,GAAGJ;IAErC,MAAMK,2BAA2B,CAACC;YAC5BA;QAAJ,IAAIA,EAAAA,SAAAA,EAAEC,GAAG,cAALD,6BAAAA,OAAOE,MAAM,IAAG,GAAG;YACrB;QACF;QAEA,IAAIN,mBAAmBO,OAAO,EAAE;YAC9BL,qCAAAA,+CAAAA,yBAA2BE,GAAGJ,mBAAmBO,OAAO;QAC1D;IACF;IAEA,OAAO;QAAEJ;QAA0BH;IAAmB;AACxD,EAAE"}
|
|
@@ -4,17 +4,20 @@ import { Enter, Space } from '@fluentui/keyboard-keys';
|
|
|
4
4
|
import { useMergedRefs, useEventCallback, mergeCallbacks, getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
|
|
5
5
|
import { useMenuGridContext_unstable } from '../../contexts/menuGridContext';
|
|
6
6
|
import { useValidateNesting } from '../../utils/useValidateNesting';
|
|
7
|
+
import { useCharacterSearch } from './useCharacterSearch';
|
|
7
8
|
/**
|
|
8
9
|
* Given user props, returns state and render function for a MenuGridRow.
|
|
9
10
|
*/ export function useMenuGridRow_unstable(props, ref) {
|
|
10
11
|
const validateNestingRef = useValidateNesting('MenuGridRow');
|
|
12
|
+
const innerRef = React.useRef(null);
|
|
11
13
|
const { tableRowTabsterAttribute } = useMenuGridContext_unstable();
|
|
14
|
+
const { characterSearchOnKeyDown, characterSearchRef } = useCharacterSearch();
|
|
12
15
|
const onKeyDownToClick = useEventCallback((event)=>{
|
|
13
16
|
if (!event.isDefaultPrevented() && (event.key === Enter || event.key === Space) && event.target === event.currentTarget) {
|
|
14
17
|
event.currentTarget.click();
|
|
15
18
|
}
|
|
16
19
|
});
|
|
17
|
-
const onKeyDown = useEventCallback(mergeCallbacks(props.onKeyDown, onKeyDownToClick));
|
|
20
|
+
const onKeyDown = useEventCallback(mergeCallbacks(props.onKeyDown, mergeCallbacks(onKeyDownToClick, characterSearchOnKeyDown)));
|
|
18
21
|
const onClick = useEventCallback((event)=>{
|
|
19
22
|
var _props_onClick;
|
|
20
23
|
let element = event.target;
|
|
@@ -26,12 +29,12 @@ import { useValidateNesting } from '../../utils/useValidateNesting';
|
|
|
26
29
|
}
|
|
27
30
|
(_props_onClick = props.onClick) === null || _props_onClick === void 0 ? void 0 : _props_onClick.call(props, event);
|
|
28
31
|
});
|
|
29
|
-
|
|
32
|
+
const state = {
|
|
30
33
|
components: {
|
|
31
34
|
root: 'div'
|
|
32
35
|
},
|
|
33
36
|
root: slot.always(getIntrinsicElementProps('div', {
|
|
34
|
-
ref: useMergedRefs(ref, validateNestingRef),
|
|
37
|
+
ref: useMergedRefs(ref, validateNestingRef, innerRef, characterSearchRef),
|
|
35
38
|
role: 'row',
|
|
36
39
|
tabIndex: 0,
|
|
37
40
|
...tableRowTabsterAttribute,
|
|
@@ -42,4 +45,5 @@ import { useValidateNesting } from '../../utils/useValidateNesting';
|
|
|
42
45
|
elementType: 'div'
|
|
43
46
|
})
|
|
44
47
|
};
|
|
48
|
+
return state;
|
|
45
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MenuGridRow/useMenuGridRow.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Enter, Space } from '@fluentui/keyboard-keys';\nimport {\n useMergedRefs,\n useEventCallback,\n mergeCallbacks,\n getIntrinsicElementProps,\n slot,\n} from '@fluentui/react-utilities';\n\nimport { useMenuGridContext_unstable } from '../../contexts/menuGridContext';\nimport { MenuGridRowProps, MenuGridRowState } from './MenuGridRow.types';\nimport { useValidateNesting } from '../../utils/useValidateNesting';\n\n/**\n * Given user props, returns state and render function for a MenuGridRow.\n */\nexport function useMenuGridRow_unstable(props: MenuGridRowProps, ref: React.Ref<HTMLDivElement>): MenuGridRowState {\n const validateNestingRef = useValidateNesting('MenuGridRow');\n const { tableRowTabsterAttribute } = useMenuGridContext_unstable();\n\n const onKeyDownToClick = useEventCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if (\n !event.isDefaultPrevented() &&\n (event.key === Enter || event.key === Space) &&\n event.target === event.currentTarget\n ) {\n event.currentTarget.click();\n }\n });\n\n const onKeyDown = useEventCallback(mergeCallbacks(props.onKeyDown, onKeyDownToClick));\n\n const onClick = useEventCallback((event: React.MouseEvent<HTMLDivElement>) => {\n let element = event.target as HTMLElement | null;\n while (element && element !== event.currentTarget) {\n if (element.tabIndex >= 0) {\n return;\n }\n element = element.parentElement;\n }\n props.onClick?.(event);\n });\n\n
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGridRow/useMenuGridRow.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Enter, Space } from '@fluentui/keyboard-keys';\nimport {\n useMergedRefs,\n useEventCallback,\n mergeCallbacks,\n getIntrinsicElementProps,\n slot,\n} from '@fluentui/react-utilities';\n\nimport { useMenuGridContext_unstable } from '../../contexts/menuGridContext';\nimport { MenuGridRowProps, MenuGridRowState } from './MenuGridRow.types';\nimport { useValidateNesting } from '../../utils/useValidateNesting';\nimport { useCharacterSearch } from './useCharacterSearch';\n\n/**\n * Given user props, returns state and render function for a MenuGridRow.\n */\nexport function useMenuGridRow_unstable(props: MenuGridRowProps, ref: React.Ref<HTMLDivElement>): MenuGridRowState {\n const validateNestingRef = useValidateNesting('MenuGridRow');\n const innerRef = React.useRef<HTMLDivElement>(null);\n const { tableRowTabsterAttribute } = useMenuGridContext_unstable();\n\n const { characterSearchOnKeyDown, characterSearchRef } = useCharacterSearch();\n\n const onKeyDownToClick = useEventCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if (\n !event.isDefaultPrevented() &&\n (event.key === Enter || event.key === Space) &&\n event.target === event.currentTarget\n ) {\n event.currentTarget.click();\n }\n });\n\n const onKeyDown = useEventCallback(\n mergeCallbacks(props.onKeyDown, mergeCallbacks(onKeyDownToClick, characterSearchOnKeyDown)),\n );\n\n const onClick = useEventCallback((event: React.MouseEvent<HTMLDivElement>) => {\n let element = event.target as HTMLElement | null;\n while (element && element !== event.currentTarget) {\n if (element.tabIndex >= 0) {\n return;\n }\n element = element.parentElement;\n }\n props.onClick?.(event);\n });\n\n const state: MenuGridRowState = {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: useMergedRefs(ref, validateNestingRef, innerRef, characterSearchRef),\n role: 'row',\n tabIndex: 0,\n ...tableRowTabsterAttribute,\n ...props,\n onKeyDown,\n onClick,\n }),\n { elementType: 'div' },\n ),\n };\n\n return state;\n}\n"],"names":["React","Enter","Space","useMergedRefs","useEventCallback","mergeCallbacks","getIntrinsicElementProps","slot","useMenuGridContext_unstable","useValidateNesting","useCharacterSearch","useMenuGridRow_unstable","props","ref","validateNestingRef","innerRef","useRef","tableRowTabsterAttribute","characterSearchOnKeyDown","characterSearchRef","onKeyDownToClick","event","isDefaultPrevented","key","target","currentTarget","click","onKeyDown","onClick","element","tabIndex","parentElement","state","components","root","always","role","elementType"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,KAAK,EAAEC,KAAK,QAAQ,0BAA0B;AACvD,SACEC,aAAa,EACbC,gBAAgB,EAChBC,cAAc,EACdC,wBAAwB,EACxBC,IAAI,QACC,4BAA4B;AAEnC,SAASC,2BAA2B,QAAQ,iCAAiC;AAE7E,SAASC,kBAAkB,QAAQ,iCAAiC;AACpE,SAASC,kBAAkB,QAAQ,uBAAuB;AAE1D;;CAEC,GACD,OAAO,SAASC,wBAAwBC,KAAuB,EAAEC,GAA8B;IAC7F,MAAMC,qBAAqBL,mBAAmB;IAC9C,MAAMM,WAAWf,MAAMgB,MAAM,CAAiB;IAC9C,MAAM,EAAEC,wBAAwB,EAAE,GAAGT;IAErC,MAAM,EAAEU,wBAAwB,EAAEC,kBAAkB,EAAE,GAAGT;IAEzD,MAAMU,mBAAmBhB,iBAAiB,CAACiB;QACzC,IACE,CAACA,MAAMC,kBAAkB,MACxBD,CAAAA,MAAME,GAAG,KAAKtB,SAASoB,MAAME,GAAG,KAAKrB,KAAI,KAC1CmB,MAAMG,MAAM,KAAKH,MAAMI,aAAa,EACpC;YACAJ,MAAMI,aAAa,CAACC,KAAK;QAC3B;IACF;IAEA,MAAMC,YAAYvB,iBAChBC,eAAeO,MAAMe,SAAS,EAAEtB,eAAee,kBAAkBF;IAGnE,MAAMU,UAAUxB,iBAAiB,CAACiB;YAQhCT;QAPA,IAAIiB,UAAUR,MAAMG,MAAM;QAC1B,MAAOK,WAAWA,YAAYR,MAAMI,aAAa,CAAE;YACjD,IAAII,QAAQC,QAAQ,IAAI,GAAG;gBACzB;YACF;YACAD,UAAUA,QAAQE,aAAa;QACjC;SACAnB,iBAAAA,MAAMgB,OAAO,cAAbhB,qCAAAA,oBAAAA,OAAgBS;IAClB;IAEA,MAAMW,QAA0B;QAC9BC,YAAY;YACVC,MAAM;QACR;QACAA,MAAM3B,KAAK4B,MAAM,CACf7B,yBAAyB,OAAO;YAC9BO,KAAKV,cAAcU,KAAKC,oBAAoBC,UAAUI;YACtDiB,MAAM;YACNN,UAAU;YACV,GAAGb,wBAAwB;YAC3B,GAAGL,KAAK;YACRe;YACAC;QACF,IACA;YAAES,aAAa;QAAM;IAEzB;IAEA,OAAOL;AACT"}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
export const MenuGridContext = React.createContext(undefined);
|
|
4
4
|
const menuGridContextDefaultValue = {
|
|
5
|
-
tableRowTabsterAttribute: null
|
|
5
|
+
tableRowTabsterAttribute: null,
|
|
6
|
+
setFocusByFirstCharacter: undefined
|
|
6
7
|
};
|
|
7
8
|
export const MenuGridContextProvider = MenuGridContext.Provider;
|
|
8
9
|
export const useMenuGridContext_unstable = ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/contexts/menuGridContext.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { TabsterDOMAttribute } from '@fluentui/react-tabster';\n\nexport const MenuGridContext = React.createContext<MenuGridContextValue | undefined>(\n undefined,\n) as React.Context<MenuGridContextValue>;\n\nconst menuGridContextDefaultValue: MenuGridContextValue = {\n tableRowTabsterAttribute: null,\n};\n\n/**\n * Context shared between MenuGrid and its children components\n */\nexport type MenuGridContextValue = {\n /**\n * Tabster row attributes applied to the `MenuGridRow` components\n */\n tableRowTabsterAttribute: TabsterDOMAttribute | null;\n};\n\nexport const MenuGridContextProvider = MenuGridContext.Provider;\n\nexport const useMenuGridContext_unstable = (): MenuGridContextValue =>\n React.useContext(MenuGridContext) ?? menuGridContextDefaultValue;\n"],"names":["React","MenuGridContext","createContext","undefined","menuGridContextDefaultValue","tableRowTabsterAttribute","MenuGridContextProvider","Provider","useMenuGridContext_unstable","useContext"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAG/B,OAAO,MAAMC,kBAAkBD,MAAME,aAAa,CAChDC,WACuC;AAEzC,MAAMC,8BAAoD;IACxDC,0BAA0B;AAC5B;
|
|
1
|
+
{"version":3,"sources":["../src/contexts/menuGridContext.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { TabsterDOMAttribute } from '@fluentui/react-tabster';\n\nexport const MenuGridContext = React.createContext<MenuGridContextValue | undefined>(\n undefined,\n) as React.Context<MenuGridContextValue>;\n\nconst menuGridContextDefaultValue: MenuGridContextValue = {\n tableRowTabsterAttribute: null,\n setFocusByFirstCharacter: undefined,\n};\n\n/**\n * Context shared between MenuGrid and its children components\n */\nexport type MenuGridContextValue = {\n /**\n * Tabster row attributes applied to the `MenuGridRow` components\n */\n tableRowTabsterAttribute: TabsterDOMAttribute | null;\n\n /**\n * Callback to focus the first row in the grid whose text content starts with the given character.\n */\n setFocusByFirstCharacter?: (e: React.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => void;\n};\n\nexport const MenuGridContextProvider = MenuGridContext.Provider;\n\nexport const useMenuGridContext_unstable = (): MenuGridContextValue =>\n React.useContext(MenuGridContext) ?? menuGridContextDefaultValue;\n"],"names":["React","MenuGridContext","createContext","undefined","menuGridContextDefaultValue","tableRowTabsterAttribute","setFocusByFirstCharacter","MenuGridContextProvider","Provider","useMenuGridContext_unstable","useContext"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAG/B,OAAO,MAAMC,kBAAkBD,MAAME,aAAa,CAChDC,WACuC;AAEzC,MAAMC,8BAAoD;IACxDC,0BAA0B;IAC1BC,0BAA0BH;AAC5B;AAiBA,OAAO,MAAMI,0BAA0BN,gBAAgBO,QAAQ,CAAC;AAEhE,OAAO,MAAMC,8BAA8B;QACzCT;WAAAA,CAAAA,oBAAAA,MAAMU,UAAU,CAACT,8BAAjBD,+BAAAA,oBAAqCI;EAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MenuGrid/MenuGrid.types.ts"],"sourcesContent":["import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport { TabsterDOMAttribute } from '@fluentui/react-tabster';\nimport type { MenuListContextValue } from '@fluentui/react-menu';\n\nimport type { MenuGridContextValue } from '../../contexts/menuGridContext';\n\nexport type MenuGridSlots = {\n root: Slot<'div'>;\n};\n\nexport type MenuGridProps = ComponentProps<MenuGridSlots> & {};\n\nexport type MenuGridState = ComponentState<MenuGridSlots> & {\n /**\n * Tabster row attributes applied to the `MenuGridRow` components\n */\n tableRowTabsterAttribute: TabsterDOMAttribute | null;\n};\n\nexport type MenuGridContextValues = {\n menuGrid: MenuGridContextValue;\n menuList: MenuListContextValue;\n};\n"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGrid/MenuGrid.types.ts"],"sourcesContent":["import * as React from 'react';\nimport type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';\nimport { TabsterDOMAttribute } from '@fluentui/react-tabster';\nimport type { MenuListContextValue } from '@fluentui/react-menu';\n\nimport type { MenuGridContextValue } from '../../contexts/menuGridContext';\n\nexport type MenuGridSlots = {\n root: Slot<'div'>;\n};\n\nexport type MenuGridProps = ComponentProps<MenuGridSlots> & {\n /**\n * Whether keyboard navigation wraps from the last row to the first and vice versa.\n *\n * @default true\n */\n circular?: boolean;\n};\n\nexport type MenuGridState = ComponentState<MenuGridSlots> & {\n /**\n * Tabster row attributes applied to the `MenuGridRow` components\n */\n tableRowTabsterAttribute: TabsterDOMAttribute | null;\n\n /**\n * Callback to focus the first row in the grid whose text content starts with the given character.\n */\n setFocusByFirstCharacter?: (e: React.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => void;\n};\n\nexport type MenuGridContextValues = {\n menuGrid: MenuGridContextValue;\n menuList: MenuListContextValue;\n};\n"],"names":["React"],"mappings":";;;;;iEAAuB,QAAQ"}
|
|
@@ -17,10 +17,16 @@ const _reacttabster = require("@fluentui/react-tabster");
|
|
|
17
17
|
const _reactmenu = require("@fluentui/react-menu");
|
|
18
18
|
const _useValidateNesting = require("../../utils/useValidateNesting");
|
|
19
19
|
const useMenuGrid_unstable = (props, ref)=>{
|
|
20
|
+
const { circular = true, ...restProps } = props;
|
|
20
21
|
const validateNestingRef = (0, _useValidateNesting.useValidateNesting)('MenuGrid');
|
|
22
|
+
const innerRef = _react.useRef(null);
|
|
23
|
+
const { findAllFocusable } = (0, _reacttabster.useFocusFinders)();
|
|
21
24
|
const triggerId = (0, _reactmenu.useMenuContext_unstable)((context)=>context.triggerId);
|
|
22
25
|
const { tableRowTabsterAttribute, tableTabsterAttribute, onTableKeyDown } = (0, _reacttable.useTableCompositeNavigation)();
|
|
23
|
-
const
|
|
26
|
+
const circularGridAttribute = (0, _reacttabster.useArrowNavigationGroup)({
|
|
27
|
+
circular
|
|
28
|
+
});
|
|
29
|
+
const mergedTabsterAttribute = (0, _reacttabster.useMergedTabsterAttributes_unstable)(tableTabsterAttribute, circularGridAttribute);
|
|
24
30
|
const ignoreEnterKeyAttribute = (0, _reacttabster.useTabsterAttributes)({
|
|
25
31
|
focusable: {
|
|
26
32
|
ignoreKeydown: {
|
|
@@ -29,20 +35,62 @@ const useMenuGrid_unstable = (props, ref)=>{
|
|
|
29
35
|
}
|
|
30
36
|
});
|
|
31
37
|
const mergedRowTabsterAttribute = (0, _reacttabster.useMergedTabsterAttributes_unstable)(tableRowTabsterAttribute, ignoreEnterKeyAttribute);
|
|
38
|
+
const onKeyDown = (0, _reactutilities.useEventCallback)((0, _reactutilities.mergeCallbacks)(props.onKeyDown, onTableKeyDown));
|
|
39
|
+
const setFocusByFirstCharacter = _react.useCallback((e, itemEl)=>{
|
|
40
|
+
if (!innerRef.current) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const target = e.target;
|
|
44
|
+
// Only apply first-letter navigation when event target is a grid row, otherwise it may conflict with other components inside the grid row
|
|
45
|
+
if (!target.hasAttribute('role') || target.getAttribute('role') !== 'row') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const rows = findAllFocusable(innerRef.current, (el)=>el.hasAttribute('role') && el.getAttribute('role') === 'row');
|
|
49
|
+
let startIndex = rows.indexOf(itemEl) + 1;
|
|
50
|
+
if (startIndex === rows.length) {
|
|
51
|
+
startIndex = 0;
|
|
52
|
+
}
|
|
53
|
+
const firstChars = rows.map((row)=>{
|
|
54
|
+
var _row_textContent;
|
|
55
|
+
return (_row_textContent = row.textContent) === null || _row_textContent === void 0 ? void 0 : _row_textContent.charAt(0).toLowerCase();
|
|
56
|
+
});
|
|
57
|
+
const char = e.key.toLowerCase();
|
|
58
|
+
const getIndexFirstChars = (start)=>{
|
|
59
|
+
for(let i = start; i < firstChars.length; i++){
|
|
60
|
+
if (char === firstChars[i]) {
|
|
61
|
+
return i;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return -1;
|
|
65
|
+
};
|
|
66
|
+
// Check remaining rows in the grid
|
|
67
|
+
let index = getIndexFirstChars(startIndex);
|
|
68
|
+
// If not found in remaining rows, check from beginning
|
|
69
|
+
if (index === -1) {
|
|
70
|
+
index = getIndexFirstChars(0);
|
|
71
|
+
}
|
|
72
|
+
// If match was found, focus it
|
|
73
|
+
if (index > -1) {
|
|
74
|
+
rows[index].focus();
|
|
75
|
+
}
|
|
76
|
+
}, [
|
|
77
|
+
findAllFocusable
|
|
78
|
+
]);
|
|
32
79
|
return {
|
|
33
80
|
components: {
|
|
34
81
|
root: 'div'
|
|
35
82
|
},
|
|
36
83
|
root: _reactutilities.slot.always((0, _reactutilities.getIntrinsicElementProps)('div', {
|
|
37
|
-
ref: (0, _reactutilities.useMergedRefs)(ref, validateNestingRef),
|
|
84
|
+
ref: (0, _reactutilities.useMergedRefs)(ref, validateNestingRef, innerRef),
|
|
38
85
|
role: 'grid',
|
|
39
86
|
'aria-labelledby': triggerId,
|
|
40
|
-
...
|
|
41
|
-
...
|
|
87
|
+
...mergedTabsterAttribute,
|
|
88
|
+
...restProps,
|
|
42
89
|
onKeyDown
|
|
43
90
|
}), {
|
|
44
91
|
elementType: 'div'
|
|
45
92
|
}),
|
|
46
|
-
tableRowTabsterAttribute: mergedRowTabsterAttribute
|
|
93
|
+
tableRowTabsterAttribute: mergedRowTabsterAttribute,
|
|
94
|
+
setFocusByFirstCharacter
|
|
47
95
|
};
|
|
48
96
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MenuGrid/useMenuGrid.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n useMergedRefs,\n useEventCallback,\n mergeCallbacks,\n getIntrinsicElementProps,\n slot,\n} from '@fluentui/react-utilities';\n\nimport { useTableCompositeNavigation } from '@fluentui/react-table';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGrid/useMenuGrid.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n useMergedRefs,\n useEventCallback,\n mergeCallbacks,\n getIntrinsicElementProps,\n slot,\n} from '@fluentui/react-utilities';\n\nimport { useTableCompositeNavigation } from '@fluentui/react-table';\nimport {\n useArrowNavigationGroup,\n useFocusFinders,\n useMergedTabsterAttributes_unstable,\n useTabsterAttributes,\n} from '@fluentui/react-tabster';\nimport type { MenuGridProps, MenuGridState } from './MenuGrid.types';\nimport { useMenuContext_unstable } from '@fluentui/react-menu';\nimport { useValidateNesting } from '../../utils/useValidateNesting';\n\n/**\n * Returns the props and state required to render the component\n */\nexport const useMenuGrid_unstable = (props: MenuGridProps, ref: React.Ref<HTMLDivElement>): MenuGridState => {\n const { circular = true, ...restProps } = props;\n const validateNestingRef = useValidateNesting('MenuGrid');\n const innerRef = React.useRef<HTMLDivElement>(null);\n const { findAllFocusable } = useFocusFinders();\n const triggerId = useMenuContext_unstable(context => context.triggerId);\n\n const { tableRowTabsterAttribute, tableTabsterAttribute, onTableKeyDown } = useTableCompositeNavigation();\n\n const circularGridAttribute = useArrowNavigationGroup({ circular });\n const mergedTabsterAttribute = useMergedTabsterAttributes_unstable(tableTabsterAttribute, circularGridAttribute);\n\n const ignoreEnterKeyAttribute = useTabsterAttributes({\n focusable: {\n ignoreKeydown: { Enter: true },\n },\n });\n const mergedRowTabsterAttribute = useMergedTabsterAttributes_unstable(\n tableRowTabsterAttribute,\n ignoreEnterKeyAttribute,\n );\n\n const onKeyDown = useEventCallback(mergeCallbacks(props.onKeyDown, onTableKeyDown));\n\n const setFocusByFirstCharacter = React.useCallback(\n (e: React.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => {\n if (!innerRef.current) {\n return;\n }\n\n const target = e.target as HTMLElement;\n\n // Only apply first-letter navigation when event target is a grid row, otherwise it may conflict with other components inside the grid row\n if (!target.hasAttribute('role') || target.getAttribute('role') !== 'row') {\n return;\n }\n\n const rows = findAllFocusable(\n innerRef.current,\n (el: HTMLElement) => el.hasAttribute('role') && el.getAttribute('role') === 'row',\n );\n\n let startIndex = rows.indexOf(itemEl) + 1;\n if (startIndex === rows.length) {\n startIndex = 0;\n }\n\n const firstChars = rows.map(row => row.textContent?.charAt(0).toLowerCase());\n const char = e.key.toLowerCase();\n\n const getIndexFirstChars = (start: number) => {\n for (let i = start; i < firstChars.length; i++) {\n if (char === firstChars[i]) {\n return i;\n }\n }\n return -1;\n };\n\n // Check remaining rows in the grid\n let index = getIndexFirstChars(startIndex);\n\n // If not found in remaining rows, check from beginning\n if (index === -1) {\n index = getIndexFirstChars(0);\n }\n\n // If match was found, focus it\n if (index > -1) {\n rows[index].focus();\n }\n },\n [findAllFocusable],\n );\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: useMergedRefs(ref, validateNestingRef, innerRef),\n role: 'grid',\n 'aria-labelledby': triggerId,\n ...mergedTabsterAttribute,\n ...restProps,\n onKeyDown,\n }),\n { elementType: 'div' },\n ),\n tableRowTabsterAttribute: mergedRowTabsterAttribute,\n setFocusByFirstCharacter,\n };\n};\n"],"names":["React","useMergedRefs","useEventCallback","mergeCallbacks","getIntrinsicElementProps","slot","useTableCompositeNavigation","useArrowNavigationGroup","useFocusFinders","useMergedTabsterAttributes_unstable","useTabsterAttributes","useMenuContext_unstable","useValidateNesting","useMenuGrid_unstable","props","ref","circular","restProps","validateNestingRef","innerRef","useRef","findAllFocusable","triggerId","context","tableRowTabsterAttribute","tableTabsterAttribute","onTableKeyDown","circularGridAttribute","mergedTabsterAttribute","ignoreEnterKeyAttribute","focusable","ignoreKeydown","Enter","mergedRowTabsterAttribute","onKeyDown","setFocusByFirstCharacter","useCallback","e","itemEl","current","target","hasAttribute","getAttribute","rows","el","startIndex","indexOf","length","firstChars","map","row","textContent","charAt","toLowerCase","char","key","getIndexFirstChars","start","i","index","focus","components","root","always","role","elementType"],"mappings":"AAAA;;;;;+BAyBaa;;;;;;;iEAvBU,QAAQ;gCAOxB,4BAA4B;4BAES,wBAAwB;8BAM7D,0BAA0B;2BAEO,uBAAuB;oCAC5B,iCAAiC;AAK7D,6BAA6B,CAACC,OAAsBC;IACzD,MAAM,EAAEC,WAAW,IAAI,EAAE,GAAGC,WAAW,GAAGH;IAC1C,MAAMI,yBAAqBN,sCAAAA,EAAmB;IAC9C,MAAMO,WAAWnB,OAAMoB,MAAM,CAAiB;IAC9C,MAAM,EAAEC,gBAAgB,EAAE,OAAGb,6BAAAA;IAC7B,MAAMc,gBAAYX,kCAAAA,EAAwBY,CAAAA,UAAWA,QAAQD,SAAS;IAEtE,MAAM,EAAEE,wBAAwB,EAAEC,qBAAqB,EAAEC,cAAc,EAAE,OAAGpB,uCAAAA;IAE5E,MAAMqB,4BAAwBpB,qCAAAA,EAAwB;QAAES;IAAS;IACjE,MAAMY,6BAAyBnB,iDAAAA,EAAoCgB,uBAAuBE;IAE1F,MAAME,8BAA0BnB,kCAAAA,EAAqB;QACnDoB,WAAW;YACTC,eAAe;gBAAEC,OAAO;YAAK;QAC/B;IACF;IACA,MAAMC,gCAA4BxB,iDAAAA,EAChCe,0BACAK;IAGF,MAAMK,YAAYhC,oCAAAA,MAAiBC,8BAAAA,EAAeW,MAAMoB,SAAS,EAAER;IAEnE,MAAMS,2BAA2BnC,OAAMoC,WAAW,CAChD,CAACC,GAAqCC;QACpC,IAAI,CAACnB,SAASoB,OAAO,EAAE;YACrB;QACF;QAEA,MAAMC,SAASH,EAAEG,MAAM;QAEvB,0IAA0I;QAC1I,IAAI,CAACA,OAAOC,YAAY,CAAC,WAAWD,OAAOE,YAAY,CAAC,YAAY,OAAO;YACzE;QACF;QAEA,MAAMC,OAAOtB,iBACXF,SAASoB,OAAO,EAChB,CAACK,KAAoBA,GAAGH,YAAY,CAAC,WAAWG,GAAGF,YAAY,CAAC,YAAY;QAG9E,IAAIG,aAAaF,KAAKG,OAAO,CAACR,UAAU;QACxC,IAAIO,eAAeF,KAAKI,MAAM,EAAE;YAC9BF,aAAa;QACf;QAEA,MAAMG,aAAaL,KAAKM,GAAG,CAACC,CAAAA;gBAAOA;oBAAAA,mBAAAA,IAAIC,WAAAA,AAAW,MAAA,QAAfD,qBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,iBAAiBE,MAAM,CAAC,GAAGC,WAAW;;QACzE,MAAMC,OAAOjB,EAAEkB,GAAG,CAACF,WAAW;QAE9B,MAAMG,qBAAqB,CAACC;YAC1B,IAAK,IAAIC,IAAID,OAAOC,IAAIV,WAAWD,MAAM,EAAEW,IAAK;gBAC9C,IAAIJ,SAASN,UAAU,CAACU,EAAE,EAAE;oBAC1B,OAAOA;gBACT;YACF;YACA,OAAO,CAAC;QACV;QAEA,mCAAmC;QACnC,IAAIC,QAAQH,mBAAmBX;QAE/B,uDAAuD;QACvD,IAAIc,UAAU,CAAC,GAAG;YAChBA,QAAQH,mBAAmB;QAC7B;QAEA,+BAA+B;QAC/B,IAAIG,QAAQ,CAAC,GAAG;YACdhB,IAAI,CAACgB,MAAM,CAACC,KAAK;QACnB;IACF,GACA;QAACvC;KAAiB;IAGpB,OAAO;QACLwC,YAAY;YACVC,MAAM;QACR;QACAA,MAAMzD,oBAAAA,CAAK0D,MAAM,KACf3D,wCAAAA,EAAyB,OAAO;YAC9BW,SAAKd,6BAAAA,EAAcc,KAAKG,oBAAoBC;YAC5C6C,MAAM;YACN,mBAAmB1C;YACnB,GAAGM,sBAAsB;YACzB,GAAGX,SAAS;YACZiB;QACF,IACA;YAAE+B,aAAa;QAAM;QAEvBzC,0BAA0BS;QAC1BE;IACF;AACF,EAAE"}
|
|
@@ -18,11 +18,13 @@ const menuList = {
|
|
|
18
18
|
shouldOpenOnArrowRight: false
|
|
19
19
|
};
|
|
20
20
|
function useMenuGridContextValues_unstable(state) {
|
|
21
|
-
const { tableRowTabsterAttribute } = state;
|
|
21
|
+
const { tableRowTabsterAttribute, setFocusByFirstCharacter } = state;
|
|
22
22
|
const menuGrid = _react.useMemo(()=>({
|
|
23
|
-
tableRowTabsterAttribute
|
|
23
|
+
tableRowTabsterAttribute,
|
|
24
|
+
setFocusByFirstCharacter
|
|
24
25
|
}), [
|
|
25
|
-
tableRowTabsterAttribute
|
|
26
|
+
tableRowTabsterAttribute,
|
|
27
|
+
setFocusByFirstCharacter
|
|
26
28
|
]);
|
|
27
29
|
return {
|
|
28
30
|
menuGrid,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MenuGrid/useMenuGridContextValues.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { MenuGridContextValues, MenuGridState } from './MenuGrid.types';\n\nconst menuList = {\n checkedValues: {},\n hasIcons: false,\n hasCheckmarks: false,\n shouldOpenOnArrowRight: false,\n};\n\nexport function useMenuGridContextValues_unstable(state: MenuGridState): MenuGridContextValues {\n const { tableRowTabsterAttribute } = state;\n const menuGrid = React.useMemo(() => ({ tableRowTabsterAttribute }),
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGrid/useMenuGridContextValues.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { MenuGridContextValues, MenuGridState } from './MenuGrid.types';\n\nconst menuList = {\n checkedValues: {},\n hasIcons: false,\n hasCheckmarks: false,\n shouldOpenOnArrowRight: false,\n};\n\nexport function useMenuGridContextValues_unstable(state: MenuGridState): MenuGridContextValues {\n const { tableRowTabsterAttribute, setFocusByFirstCharacter } = state;\n const menuGrid = React.useMemo(\n () => ({ tableRowTabsterAttribute, setFocusByFirstCharacter }),\n [tableRowTabsterAttribute, setFocusByFirstCharacter],\n );\n\n return { menuGrid, menuList };\n}\n"],"names":["React","menuList","checkedValues","hasIcons","hasCheckmarks","shouldOpenOnArrowRight","useMenuGridContextValues_unstable","state","tableRowTabsterAttribute","setFocusByFirstCharacter","menuGrid","useMemo"],"mappings":"AAAA;;;;;;;;;;;;iEAEuB,QAAQ;AAG/B,MAAMC,WAAW;IACfC,eAAe,CAAC;IAChBC,UAAU;IACVC,eAAe;IACfC,wBAAwB;AAC1B;AAEO,SAASC,kCAAkCC,KAAoB;IACpE,MAAM,EAAEC,wBAAwB,EAAEC,wBAAwB,EAAE,GAAGF;IAC/D,MAAMG,WAAWV,OAAMW,OAAO,CAC5B,IAAO,CAAA;YAAEH;YAA0BC;SAAyB,CAAA,EAC5D;QAACD;QAA0BC;KAAyB;IAGtD,OAAO;QAAEC;QAAUT;IAAS;AAC9B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "useCharacterSearch", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function() {
|
|
9
|
+
return useCharacterSearch;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
|
|
13
|
+
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
|
|
14
|
+
const _menuGridContext = require("../../contexts/menuGridContext");
|
|
15
|
+
const useCharacterSearch = ()=>{
|
|
16
|
+
'use no memo';
|
|
17
|
+
const characterSearchRef = _react.useRef(null);
|
|
18
|
+
const { setFocusByFirstCharacter } = (0, _menuGridContext.useMenuGridContext_unstable)();
|
|
19
|
+
const characterSearchOnKeyDown = (e)=>{
|
|
20
|
+
var _e_key;
|
|
21
|
+
if (((_e_key = e.key) === null || _e_key === void 0 ? void 0 : _e_key.length) > 1) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (characterSearchRef.current) {
|
|
25
|
+
setFocusByFirstCharacter === null || setFocusByFirstCharacter === void 0 ? void 0 : setFocusByFirstCharacter(e, characterSearchRef.current);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
characterSearchOnKeyDown,
|
|
30
|
+
characterSearchRef
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGridRow/useCharacterSearch.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useMenuGridContext_unstable } from '../../contexts/menuGridContext';\n\n/**\n * Returns the MenuGridRow's `onKeyDown` handler to support first-letter navigation.\n * When a single character key is pressed, it delegates to the grid-level `setFocusByFirstCharacter`\n * callback which finds and focuses the next row starting with that character.\n */\nexport const useCharacterSearch = (): {\n characterSearchOnKeyDown: React.KeyboardEventHandler<HTMLElement>;\n characterSearchRef: React.RefObject<HTMLElement | null>;\n} => {\n 'use no memo';\n\n const characterSearchRef = React.useRef<HTMLDivElement>(null);\n\n const { setFocusByFirstCharacter } = useMenuGridContext_unstable();\n\n const characterSearchOnKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key?.length > 1) {\n return;\n }\n\n if (characterSearchRef.current) {\n setFocusByFirstCharacter?.(e, characterSearchRef.current);\n }\n };\n\n return { characterSearchOnKeyDown, characterSearchRef };\n};\n"],"names":["React","useMenuGridContext_unstable","useCharacterSearch","characterSearchRef","useRef","setFocusByFirstCharacter","characterSearchOnKeyDown","e","key","length","current"],"mappings":"AAAA;;;;;+BAUaE;;;;;;;iEARU,QAAQ;iCACa,iCAAiC;AAOtE,2BAA2B;IAIhC;IAEA,MAAMC,qBAAqBH,OAAMI,MAAM,CAAiB;IAExD,MAAM,EAAEC,wBAAwB,EAAE,GAAGJ,gDAAAA;IAErC,MAAMK,2BAA2B,CAACC;YAC5BA;QAAJ,IAAIA,CAAAA,CAAAA,SAAAA,EAAEC,GAAAA,AAAG,MAAA,QAALD,WAAAA,KAAAA,IAAAA,KAAAA,IAAAA,OAAOE,MAAAA,AAAM,IAAG,GAAG;YACrB;QACF;QAEA,IAAIN,mBAAmBO,OAAO,EAAE;YAC9BL,6BAAAA,QAAAA,6BAAAA,KAAAA,IAAAA,KAAAA,IAAAA,yBAA2BE,GAAGJ,mBAAmBO,OAAO;QAC1D;IACF;IAEA,OAAO;QAAEJ;QAA0BH;IAAmB;AACxD,EAAE"}
|
|
@@ -15,15 +15,18 @@ const _keyboardkeys = require("@fluentui/keyboard-keys");
|
|
|
15
15
|
const _reactutilities = require("@fluentui/react-utilities");
|
|
16
16
|
const _menuGridContext = require("../../contexts/menuGridContext");
|
|
17
17
|
const _useValidateNesting = require("../../utils/useValidateNesting");
|
|
18
|
+
const _useCharacterSearch = require("./useCharacterSearch");
|
|
18
19
|
function useMenuGridRow_unstable(props, ref) {
|
|
19
20
|
const validateNestingRef = (0, _useValidateNesting.useValidateNesting)('MenuGridRow');
|
|
21
|
+
const innerRef = _react.useRef(null);
|
|
20
22
|
const { tableRowTabsterAttribute } = (0, _menuGridContext.useMenuGridContext_unstable)();
|
|
23
|
+
const { characterSearchOnKeyDown, characterSearchRef } = (0, _useCharacterSearch.useCharacterSearch)();
|
|
21
24
|
const onKeyDownToClick = (0, _reactutilities.useEventCallback)((event)=>{
|
|
22
25
|
if (!event.isDefaultPrevented() && (event.key === _keyboardkeys.Enter || event.key === _keyboardkeys.Space) && event.target === event.currentTarget) {
|
|
23
26
|
event.currentTarget.click();
|
|
24
27
|
}
|
|
25
28
|
});
|
|
26
|
-
const onKeyDown = (0, _reactutilities.useEventCallback)((0, _reactutilities.mergeCallbacks)(props.onKeyDown, onKeyDownToClick));
|
|
29
|
+
const onKeyDown = (0, _reactutilities.useEventCallback)((0, _reactutilities.mergeCallbacks)(props.onKeyDown, (0, _reactutilities.mergeCallbacks)(onKeyDownToClick, characterSearchOnKeyDown)));
|
|
27
30
|
const onClick = (0, _reactutilities.useEventCallback)((event)=>{
|
|
28
31
|
var _props_onClick;
|
|
29
32
|
let element = event.target;
|
|
@@ -35,12 +38,12 @@ function useMenuGridRow_unstable(props, ref) {
|
|
|
35
38
|
}
|
|
36
39
|
(_props_onClick = props.onClick) === null || _props_onClick === void 0 ? void 0 : _props_onClick.call(props, event);
|
|
37
40
|
});
|
|
38
|
-
|
|
41
|
+
const state = {
|
|
39
42
|
components: {
|
|
40
43
|
root: 'div'
|
|
41
44
|
},
|
|
42
45
|
root: _reactutilities.slot.always((0, _reactutilities.getIntrinsicElementProps)('div', {
|
|
43
|
-
ref: (0, _reactutilities.useMergedRefs)(ref, validateNestingRef),
|
|
46
|
+
ref: (0, _reactutilities.useMergedRefs)(ref, validateNestingRef, innerRef, characterSearchRef),
|
|
44
47
|
role: 'row',
|
|
45
48
|
tabIndex: 0,
|
|
46
49
|
...tableRowTabsterAttribute,
|
|
@@ -51,4 +54,5 @@ function useMenuGridRow_unstable(props, ref) {
|
|
|
51
54
|
elementType: 'div'
|
|
52
55
|
})
|
|
53
56
|
};
|
|
57
|
+
return state;
|
|
54
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MenuGridRow/useMenuGridRow.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Enter, Space } from '@fluentui/keyboard-keys';\nimport {\n useMergedRefs,\n useEventCallback,\n mergeCallbacks,\n getIntrinsicElementProps,\n slot,\n} from '@fluentui/react-utilities';\n\nimport { useMenuGridContext_unstable } from '../../contexts/menuGridContext';\nimport { MenuGridRowProps, MenuGridRowState } from './MenuGridRow.types';\nimport { useValidateNesting } from '../../utils/useValidateNesting';\n\n/**\n * Given user props, returns state and render function for a MenuGridRow.\n */\nexport function useMenuGridRow_unstable(props: MenuGridRowProps, ref: React.Ref<HTMLDivElement>): MenuGridRowState {\n const validateNestingRef = useValidateNesting('MenuGridRow');\n const { tableRowTabsterAttribute } = useMenuGridContext_unstable();\n\n const onKeyDownToClick = useEventCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if (\n !event.isDefaultPrevented() &&\n (event.key === Enter || event.key === Space) &&\n event.target === event.currentTarget\n ) {\n event.currentTarget.click();\n }\n });\n\n const onKeyDown = useEventCallback(mergeCallbacks(props.onKeyDown, onKeyDownToClick));\n\n const onClick = useEventCallback((event: React.MouseEvent<HTMLDivElement>) => {\n let element = event.target as HTMLElement | null;\n while (element && element !== event.currentTarget) {\n if (element.tabIndex >= 0) {\n return;\n }\n element = element.parentElement;\n }\n props.onClick?.(event);\n });\n\n
|
|
1
|
+
{"version":3,"sources":["../src/components/MenuGridRow/useMenuGridRow.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { Enter, Space } from '@fluentui/keyboard-keys';\nimport {\n useMergedRefs,\n useEventCallback,\n mergeCallbacks,\n getIntrinsicElementProps,\n slot,\n} from '@fluentui/react-utilities';\n\nimport { useMenuGridContext_unstable } from '../../contexts/menuGridContext';\nimport { MenuGridRowProps, MenuGridRowState } from './MenuGridRow.types';\nimport { useValidateNesting } from '../../utils/useValidateNesting';\nimport { useCharacterSearch } from './useCharacterSearch';\n\n/**\n * Given user props, returns state and render function for a MenuGridRow.\n */\nexport function useMenuGridRow_unstable(props: MenuGridRowProps, ref: React.Ref<HTMLDivElement>): MenuGridRowState {\n const validateNestingRef = useValidateNesting('MenuGridRow');\n const innerRef = React.useRef<HTMLDivElement>(null);\n const { tableRowTabsterAttribute } = useMenuGridContext_unstable();\n\n const { characterSearchOnKeyDown, characterSearchRef } = useCharacterSearch();\n\n const onKeyDownToClick = useEventCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if (\n !event.isDefaultPrevented() &&\n (event.key === Enter || event.key === Space) &&\n event.target === event.currentTarget\n ) {\n event.currentTarget.click();\n }\n });\n\n const onKeyDown = useEventCallback(\n mergeCallbacks(props.onKeyDown, mergeCallbacks(onKeyDownToClick, characterSearchOnKeyDown)),\n );\n\n const onClick = useEventCallback((event: React.MouseEvent<HTMLDivElement>) => {\n let element = event.target as HTMLElement | null;\n while (element && element !== event.currentTarget) {\n if (element.tabIndex >= 0) {\n return;\n }\n element = element.parentElement;\n }\n props.onClick?.(event);\n });\n\n const state: MenuGridRowState = {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: useMergedRefs(ref, validateNestingRef, innerRef, characterSearchRef),\n role: 'row',\n tabIndex: 0,\n ...tableRowTabsterAttribute,\n ...props,\n onKeyDown,\n onClick,\n }),\n { elementType: 'div' },\n ),\n };\n\n return state;\n}\n"],"names":["React","Enter","Space","useMergedRefs","useEventCallback","mergeCallbacks","getIntrinsicElementProps","slot","useMenuGridContext_unstable","useValidateNesting","useCharacterSearch","useMenuGridRow_unstable","props","ref","validateNestingRef","innerRef","useRef","tableRowTabsterAttribute","characterSearchOnKeyDown","characterSearchRef","onKeyDownToClick","event","isDefaultPrevented","key","target","currentTarget","click","onKeyDown","onClick","element","tabIndex","parentElement","state","components","root","always","role","elementType"],"mappings":"AAAA;;;;;+BAoBgBW;;;;;;;iEAlBO,QAAQ;8BACF,0BAA0B;gCAOhD,4BAA4B;iCAES,iCAAiC;oCAE1C,iCAAiC;oCACjC,uBAAuB;AAKnD,iCAAiCC,KAAuB,EAAEC,GAA8B;IAC7F,MAAMC,yBAAqBL,sCAAAA,EAAmB;IAC9C,MAAMM,WAAWf,OAAMgB,MAAM,CAAiB;IAC9C,MAAM,EAAEC,wBAAwB,EAAE,GAAGT,gDAAAA;IAErC,MAAM,EAAEU,wBAAwB,EAAEC,kBAAkB,EAAE,OAAGT,sCAAAA;IAEzD,MAAMU,uBAAmBhB,gCAAAA,EAAiB,CAACiB;QACzC,IACE,CAACA,MAAMC,kBAAkB,MACxBD,CAAAA,MAAME,GAAG,KAAKtB,mBAAAA,IAASoB,MAAME,GAAG,KAAKrB,mBAAAA,AAAI,KAC1CmB,MAAMG,MAAM,KAAKH,MAAMI,aAAa,EACpC;YACAJ,MAAMI,aAAa,CAACC,KAAK;QAC3B;IACF;IAEA,MAAMC,gBAAYvB,gCAAAA,MAChBC,8BAAAA,EAAeO,MAAMe,SAAS,MAAEtB,8BAAAA,EAAee,kBAAkBF;IAGnE,MAAMU,cAAUxB,gCAAAA,EAAiB,CAACiB;YAQhCT;QAPA,IAAIiB,UAAUR,MAAMG,MAAM;QAC1B,MAAOK,WAAWA,YAAYR,MAAMI,aAAa,CAAE;YACjD,IAAII,QAAQC,QAAQ,IAAI,GAAG;gBACzB;YACF;YACAD,UAAUA,QAAQE,aAAa;QACjC;QACAnB,kBAAAA,MAAMgB,OAAAA,AAAO,MAAA,QAAbhB,mBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,eAAAA,IAAAA,CAAAA,OAAgBS;IAClB;IAEA,MAAMW,QAA0B;QAC9BC,YAAY;YACVC,MAAM;QACR;QACAA,MAAM3B,oBAAAA,CAAK4B,MAAM,KACf7B,wCAAAA,EAAyB,OAAO;YAC9BO,SAAKV,6BAAAA,EAAcU,KAAKC,oBAAoBC,UAAUI;YACtDiB,MAAM;YACNN,UAAU;YACV,GAAGb,wBAAwB;YAC3B,GAAGL,KAAK;YACRe;YACAC;QACF,IACA;YAAES,aAAa;QAAM;IAEzB;IAEA,OAAOL;AACT"}
|
|
@@ -24,7 +24,8 @@ const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildc
|
|
|
24
24
|
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
|
|
25
25
|
const MenuGridContext = /*#__PURE__*/ _react.createContext(undefined);
|
|
26
26
|
const menuGridContextDefaultValue = {
|
|
27
|
-
tableRowTabsterAttribute: null
|
|
27
|
+
tableRowTabsterAttribute: null,
|
|
28
|
+
setFocusByFirstCharacter: undefined
|
|
28
29
|
};
|
|
29
30
|
const MenuGridContextProvider = MenuGridContext.Provider;
|
|
30
31
|
const useMenuGridContext_unstable = ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/contexts/menuGridContext.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { TabsterDOMAttribute } from '@fluentui/react-tabster';\n\nexport const MenuGridContext = React.createContext<MenuGridContextValue | undefined>(\n undefined,\n) as React.Context<MenuGridContextValue>;\n\nconst menuGridContextDefaultValue: MenuGridContextValue = {\n tableRowTabsterAttribute: null,\n};\n\n/**\n * Context shared between MenuGrid and its children components\n */\nexport type MenuGridContextValue = {\n /**\n * Tabster row attributes applied to the `MenuGridRow` components\n */\n tableRowTabsterAttribute: TabsterDOMAttribute | null;\n};\n\nexport const MenuGridContextProvider = MenuGridContext.Provider;\n\nexport const useMenuGridContext_unstable = (): MenuGridContextValue =>\n React.useContext(MenuGridContext) ?? menuGridContextDefaultValue;\n"],"names":["React","MenuGridContext","createContext","undefined","menuGridContextDefaultValue","tableRowTabsterAttribute","MenuGridContextProvider","Provider","useMenuGridContext_unstable","useContext"],"mappings":"AAAA;;;;;;;;;;;;mBAKaC;;;
|
|
1
|
+
{"version":3,"sources":["../src/contexts/menuGridContext.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { TabsterDOMAttribute } from '@fluentui/react-tabster';\n\nexport const MenuGridContext = React.createContext<MenuGridContextValue | undefined>(\n undefined,\n) as React.Context<MenuGridContextValue>;\n\nconst menuGridContextDefaultValue: MenuGridContextValue = {\n tableRowTabsterAttribute: null,\n setFocusByFirstCharacter: undefined,\n};\n\n/**\n * Context shared between MenuGrid and its children components\n */\nexport type MenuGridContextValue = {\n /**\n * Tabster row attributes applied to the `MenuGridRow` components\n */\n tableRowTabsterAttribute: TabsterDOMAttribute | null;\n\n /**\n * Callback to focus the first row in the grid whose text content starts with the given character.\n */\n setFocusByFirstCharacter?: (e: React.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => void;\n};\n\nexport const MenuGridContextProvider = MenuGridContext.Provider;\n\nexport const useMenuGridContext_unstable = (): MenuGridContextValue =>\n React.useContext(MenuGridContext) ?? menuGridContextDefaultValue;\n"],"names":["React","MenuGridContext","createContext","undefined","menuGridContextDefaultValue","tableRowTabsterAttribute","setFocusByFirstCharacter","MenuGridContextProvider","Provider","useMenuGridContext_unstable","useContext"],"mappings":"AAAA;;;;;;;;;;;;mBAKaC;;;2BAwBAM;;;+BAEAE;;;;;iEA7BU,QAAQ;AAGxB,MAAMR,gCAAkBD,OAAME,aAAa,CAChDC,WACuC;AAEzC,MAAMC,8BAAoD;IACxDC,0BAA0B;IAC1BC,0BAA0BH;AAC5B;AAiBO,MAAMI,0BAA0BN,gBAAgBO,QAAQ,CAAC;AAEzD,MAAMC,8BAA8B;QACzCT;WAAAA,CAAAA,oBAAAA,OAAMU,UAAU,CAACT,gBAAAA,MAAAA,QAAjBD,sBAAAA,KAAAA,IAAAA,oBAAqCI;EAA4B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluentui/react-menu-grid-preview",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "New fluentui react package",
|
|
5
5
|
"main": "lib-commonjs/index.js",
|
|
6
6
|
"module": "lib/index.js",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@fluentui/keyboard-keys": "^9.0.8",
|
|
22
|
-
"@fluentui/react-menu": "^9.23.
|
|
22
|
+
"@fluentui/react-menu": "^9.23.1",
|
|
23
23
|
"@fluentui/react-icons": "^2.0.245",
|
|
24
|
-
"@fluentui/react-table": "^9.19.
|
|
24
|
+
"@fluentui/react-table": "^9.19.13",
|
|
25
25
|
"@fluentui/react-tabster": "^9.26.13",
|
|
26
26
|
"@fluentui/react-jsx-runtime": "^9.4.1",
|
|
27
27
|
"@fluentui/react-shared-contexts": "^9.26.2",
|