@elliemae/ds-menu-button 3.46.0-rc.2 → 3.46.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/config/useMenuButton.js +6 -2
- package/dist/cjs/config/useMenuButton.js.map +2 -2
- package/dist/cjs/config/useSplitInherithedProps.js +33 -15
- package/dist/cjs/config/useSplitInherithedProps.js.map +2 -2
- package/dist/cjs/parts/DSFlyoutMenu/DSFlyoutMenu.js +36 -12
- package/dist/cjs/parts/DSFlyoutMenu/DSFlyoutMenu.js.map +3 -3
- package/dist/cjs/parts/DSFlyoutMenu/react-desc-prop-types.js +1 -1
- package/dist/cjs/parts/DSFlyoutMenu/react-desc-prop-types.js.map +3 -3
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js +4 -4
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js.map +1 -1
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.js +40 -30
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.js.map +2 -2
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js +1 -1
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js.map +2 -2
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js +7 -7
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js.map +1 -1
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js +3 -0
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js.map +2 -2
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js +14 -14
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js.map +1 -1
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js +2 -2
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js.map +1 -1
- package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableMenuItem.js +4 -5
- package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js +4 -5
- package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js +6 -7
- package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js +7 -8
- package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js +6 -7
- package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js +6 -7
- package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js +4 -5
- package/dist/cjs/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.js +1 -1
- package/dist/cjs/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/focusNodeRacingConditionSolved.js +43 -0
- package/dist/cjs/parts/DSMenuItemRendererFactory/focusNodeRacingConditionSolved.js.map +7 -0
- package/dist/cjs/parts/DSMenuItemRendererFactory/react-desc-prop-types.js.map +2 -2
- package/dist/cjs/parts/DSOpinionatedButton/react-desc-prop-types.js.map +2 -2
- package/dist/cjs/react-desc-prop-types.js +10 -11
- package/dist/cjs/react-desc-prop-types.js.map +2 -2
- package/dist/cjs/utils/nodesTypeguardsAndGetters.js +18 -56
- package/dist/cjs/utils/nodesTypeguardsAndGetters.js.map +2 -2
- package/dist/cjs/utils/useOptionsArrayToDsTree.js +10 -3
- package/dist/cjs/utils/useOptionsArrayToDsTree.js.map +2 -2
- package/dist/esm/config/useMenuButton.js +7 -3
- package/dist/esm/config/useMenuButton.js.map +2 -2
- package/dist/esm/config/useSplitInherithedProps.js +33 -15
- package/dist/esm/config/useSplitInherithedProps.js.map +2 -2
- package/dist/esm/parts/DSFlyoutMenu/DSFlyoutMenu.js +34 -10
- package/dist/esm/parts/DSFlyoutMenu/DSFlyoutMenu.js.map +2 -2
- package/dist/esm/parts/DSFlyoutMenu/react-desc-prop-types.js +1 -4
- package/dist/esm/parts/DSFlyoutMenu/react-desc-prop-types.js.map +2 -2
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js +4 -4
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js.map +1 -1
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.js +40 -30
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.js.map +2 -2
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js +1 -1
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js.map +2 -2
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js +7 -7
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js.map +1 -1
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js +3 -0
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js.map +2 -2
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js +14 -14
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js.map +1 -1
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js +2 -2
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js.map +1 -1
- package/dist/esm/parts/DSMenuItemRendererFactory/ActivableMenuItem.js +4 -5
- package/dist/esm/parts/DSMenuItemRendererFactory/ActivableMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js +4 -5
- package/dist/esm/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js +6 -7
- package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js +7 -8
- package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js +6 -7
- package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js +6 -7
- package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js +4 -5
- package/dist/esm/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.js +1 -1
- package/dist/esm/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/focusNodeRacingConditionSolved.js +13 -0
- package/dist/esm/parts/DSMenuItemRendererFactory/focusNodeRacingConditionSolved.js.map +7 -0
- package/dist/esm/parts/DSMenuItemRendererFactory/react-desc-prop-types.js.map +2 -2
- package/dist/esm/parts/DSOpinionatedButton/react-desc-prop-types.js +1 -1
- package/dist/esm/parts/DSOpinionatedButton/react-desc-prop-types.js.map +2 -2
- package/dist/esm/react-desc-prop-types.js +10 -11
- package/dist/esm/react-desc-prop-types.js.map +2 -2
- package/dist/esm/utils/nodesTypeguardsAndGetters.js +18 -56
- package/dist/esm/utils/nodesTypeguardsAndGetters.js.map +2 -2
- package/dist/esm/utils/useOptionsArrayToDsTree.js +10 -3
- package/dist/esm/utils/useOptionsArrayToDsTree.js.map +2 -2
- package/dist/types/config/useSplitInherithedProps.d.ts +3 -4
- package/dist/types/parts/DSFlyoutMenu/react-desc-prop-types.d.ts +1 -1
- package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.d.ts +6 -6
- package/dist/types/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.d.ts +1 -0
- package/dist/types/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.d.ts +3 -3
- package/dist/types/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.d.ts +2 -2
- package/dist/types/parts/DSMenuItemRendererFactory/focusNodeRacingConditionSolved.d.ts +2 -0
- package/dist/types/parts/DSMenuItemRendererFactory/react-desc-prop-types.d.ts +2 -2
- package/dist/types/parts/DSOpinionatedButton/react-desc-prop-types.d.ts +1 -1
- package/dist/types/react-desc-prop-types.d.ts +10 -4
- package/dist/types/utils/nodesTypeguardsAndGetters.d.ts +113 -1
- package/dist/types/utils/useOptionsArrayToDsTree.d.ts +2 -1
- package/package.json +12 -13
@@ -41,7 +41,10 @@ var import_useOptionsArrayToDsTree = require("../utils/useOptionsArrayToDsTree.j
|
|
41
41
|
var import_useSplitInherithedProps = require("./useSplitInherithedProps.js");
|
42
42
|
var import_useValidateProps = require("./useValidateProps.js");
|
43
43
|
const useMenuButton = (propsFromUser) => {
|
44
|
-
const propsWithDefault = (0, import_ds_props_helpers.useMemoMergePropsWithDefault)(
|
44
|
+
const propsWithDefault = (0, import_ds_props_helpers.useMemoMergePropsWithDefault)(
|
45
|
+
propsFromUser,
|
46
|
+
import_react_desc_prop_types.menuSpecificDefaultProps
|
47
|
+
);
|
45
48
|
(0, import_useValidateProps.useValidateProps)(propsWithDefault, import_react_desc_prop_types.DSMenuButtonPropTypes);
|
46
49
|
const xstyledProps = (0, import_ds_props_helpers.useGetXstyledProps)(propsWithDefault);
|
47
50
|
const instanceUid = import_react.default.useMemo(() => `menu-button${(0, import_uid.uid)(5)}`, []);
|
@@ -49,7 +52,8 @@ const useMenuButton = (propsFromUser) => {
|
|
49
52
|
const optionsArray = Array.isArray(appOptions) ? appOptions : [];
|
50
53
|
const treeRootNodeFromOptionsArrayIfArray = (0, import_useOptionsArrayToDsTree.useOptionsArrayToDsTree)({
|
51
54
|
options: optionsArray,
|
52
|
-
instanceUid
|
55
|
+
instanceUid,
|
56
|
+
propsWithDefault
|
53
57
|
// this typecast is a safe type reconciliation, typescript checks they are compatible
|
54
58
|
// this typecast let us avoid to have to do the ` | OtherCompatibleType` dance
|
55
59
|
}).getRoot();
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../src/config/useMenuButton.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
4
|
-
"sourcesContent": ["/* eslint-disable max-statements */\nimport { useGetXstyledProps, useMemoMergePropsWithDefault } from '@elliemae/ds-props-helpers';\nimport React from 'react';\nimport { uid } from 'uid';\nimport { DSMenuButtonPropTypes,
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,8BAAiE;AACjE,mBAAkB;AAClB,iBAAoB;AACpB,
|
4
|
+
"sourcesContent": ["/* eslint-disable max-statements */\nimport { useGetXstyledProps, useMemoMergePropsWithDefault } from '@elliemae/ds-props-helpers';\nimport React from 'react';\nimport { uid } from 'uid';\nimport { DSMenuButtonPropTypes, menuSpecificDefaultProps, type DSMenuButtonT } from '../react-desc-prop-types.js';\nimport { getFocusableNodes } from '../utils/nodesTypeguardsAndGetters.js';\nimport { useOptionsArrayToDsTree } from '../utils/useOptionsArrayToDsTree.js';\nimport { useSplitInherithedProps } from './useSplitInherithedProps.js';\nimport { useValidateProps } from './useValidateProps.js';\nexport interface MenuButtonCTX extends ReturnType<typeof useSplitInherithedProps> {\n propsWithDefault: DSMenuButtonT.InternalProps;\n xstyledProps: ReturnType<typeof useGetXstyledProps>;\n instanceUid: string;\n}\n\nexport const useMenuButton = (propsFromUser: DSMenuButtonT.Props) => {\n // =============================================================================\n // MERGE WITH DEFAULT AND VALIDATE PROPS\n // =============================================================================\n const propsWithDefault = useMemoMergePropsWithDefault<DSMenuButtonT.InternalProps>(\n propsFromUser,\n menuSpecificDefaultProps,\n );\n useValidateProps(propsWithDefault, DSMenuButtonPropTypes);\n // =============================================================================\n // XSTYLED PROPS\n // =============================================================================\n const xstyledProps = useGetXstyledProps(propsWithDefault);\n // =============================================================================\n // AD HOC PER COMPONENT LOGIC\n // =============================================================================\n // custom code goes here, this is an example\n const instanceUid = React.useMemo(() => `menu-button${uid(5)}`, []);\n // =============================================================================\n // HELPERS HOOKS CONFIGS\n // =============================================================================\n\n // =============================================================================\n // React hooks can't be invoked conditionally...\n // =============================================================================\n\n // As per intended WIDGET API, user can provide options as an array of \"items\" or an array of \"nodes\"\n // we do the conversion from \"items\" to \"nodes\" here,\n // because the `parts` require the \"nodes\" extra properties to handle the logic and rendering\n const { options: appOptions } = propsWithDefault;\n const optionsArray: DSMenuButtonT.MenuItemInterface[] = Array.isArray(appOptions) ? appOptions : [];\n\n const treeRootNodeFromOptionsArrayIfArray = useOptionsArrayToDsTree({\n options: optionsArray,\n instanceUid,\n propsWithDefault,\n // this typecast is a safe type reconciliation, typescript checks they are compatible\n // this typecast let us avoid to have to do the ` | OtherCompatibleType` dance\n }).getRoot() as DSMenuButtonT.MenuNode;\n const treeRootNode = React.useMemo(\n () => (Array.isArray(appOptions) ? treeRootNodeFromOptionsArrayIfArray : appOptions),\n [appOptions, treeRootNodeFromOptionsArrayIfArray],\n );\n\n // =============================================================================\n // We calculate the focusableNodes from the treeRootNode.plainChildren via getFocusableNodes\n // =============================================================================\n const focusableNodes = React.useMemo(() => getFocusableNodes(treeRootNode), [treeRootNode]);\n const splitInherithedProps = useSplitInherithedProps({\n propsWithDefault,\n focusableNodes,\n treeRootNode,\n });\n\n return React.useMemo<MenuButtonCTX>(\n () => ({\n propsWithDefault,\n xstyledProps,\n instanceUid,\n ...splitInherithedProps,\n }),\n [propsWithDefault, xstyledProps, instanceUid, splitInherithedProps],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,8BAAiE;AACjE,mBAAkB;AAClB,iBAAoB;AACpB,mCAAoF;AACpF,uCAAkC;AAClC,qCAAwC;AACxC,qCAAwC;AACxC,8BAAiC;AAO1B,MAAM,gBAAgB,CAAC,kBAAuC;AAInE,QAAM,uBAAmB;AAAA,IACvB;AAAA,IACA;AAAA,EACF;AACA,gDAAiB,kBAAkB,kDAAqB;AAIxD,QAAM,mBAAe,4CAAmB,gBAAgB;AAKxD,QAAM,cAAc,aAAAA,QAAM,QAAQ,MAAM,kBAAc,gBAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAYlE,QAAM,EAAE,SAAS,WAAW,IAAI;AAChC,QAAM,eAAkD,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC;AAElG,QAAM,0CAAsC,wDAAwB;AAAA,IAClE,SAAS;AAAA,IACT;AAAA,IACA;AAAA;AAAA;AAAA,EAGF,CAAC,EAAE,QAAQ;AACX,QAAM,eAAe,aAAAA,QAAM;AAAA,IACzB,MAAO,MAAM,QAAQ,UAAU,IAAI,sCAAsC;AAAA,IACzE,CAAC,YAAY,mCAAmC;AAAA,EAClD;AAKA,QAAM,iBAAiB,aAAAA,QAAM,QAAQ,UAAM,oDAAkB,YAAY,GAAG,CAAC,YAAY,CAAC;AAC1F,QAAM,2BAAuB,wDAAwB;AAAA,IACnD;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,aAAAA,QAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAAA,IACA,CAAC,kBAAkB,cAAc,aAAa,oBAAoB;AAAA,EACpE;AACF;",
|
6
6
|
"names": ["React"]
|
7
7
|
}
|
@@ -33,7 +33,29 @@ __export(useSplitInherithedProps_exports, {
|
|
33
33
|
module.exports = __toCommonJS(useSplitInherithedProps_exports);
|
34
34
|
var React = __toESM(require("react"));
|
35
35
|
var import_react = __toESM(require("react"));
|
36
|
+
var import_nodesTypeguardsAndGetters = require("../utils/nodesTypeguardsAndGetters.js");
|
36
37
|
var import_resolveRef = require("../utils/resolveRef.js");
|
38
|
+
const convertSelectedOptionsToNodes = (selectedItems, treeRootNode) => {
|
39
|
+
const convertedSelection = [];
|
40
|
+
selectedItems.forEach((selectedItem) => {
|
41
|
+
const needsConversion = !(0, import_nodesTypeguardsAndGetters.isObjectAMenuNode)(selectedItem);
|
42
|
+
if (!needsConversion) {
|
43
|
+
convertedSelection.push(selectedItem);
|
44
|
+
return;
|
45
|
+
}
|
46
|
+
const { dsId } = selectedItem;
|
47
|
+
const selectedNode = treeRootNode.findNode((node) => node.dsId === dsId);
|
48
|
+
if (!selectedNode) {
|
49
|
+
throw new Error(`Selected option with dsId ${dsId} not found in the menu tree.`);
|
50
|
+
}
|
51
|
+
if (!(0, import_nodesTypeguardsAndGetters.isSelectionableNode)(selectedNode)) {
|
52
|
+
console.warn(`Selected option with dsId ${dsId} is not a selectionable node and will be ignored.`);
|
53
|
+
return;
|
54
|
+
}
|
55
|
+
convertedSelection.push(selectedNode);
|
56
|
+
});
|
57
|
+
return convertedSelection;
|
58
|
+
};
|
37
59
|
const useSplitInherithedProps = ({
|
38
60
|
propsWithDefault,
|
39
61
|
focusableNodes,
|
@@ -48,7 +70,6 @@ const useSplitInherithedProps = ({
|
|
48
70
|
onSubmenuToggle,
|
49
71
|
isLoading,
|
50
72
|
isSkeleton,
|
51
|
-
selectedOptions,
|
52
73
|
ItemRenderer,
|
53
74
|
innerRef,
|
54
75
|
selectedItems,
|
@@ -57,6 +78,8 @@ const useSplitInherithedProps = ({
|
|
57
78
|
onActivateItem,
|
58
79
|
onOpen,
|
59
80
|
onClose,
|
81
|
+
maxHeight,
|
82
|
+
// this is not shared with anything at all, it's instead a property of the "root" node, each node (with a submenu) can have its own maxHeight
|
60
83
|
...buttonInheritedProps
|
61
84
|
} = propsWithDefault;
|
62
85
|
const innerRefSnatchingNode = import_react.default.useCallback(
|
@@ -68,6 +91,12 @@ const useSplitInherithedProps = ({
|
|
68
91
|
},
|
69
92
|
[innerRef]
|
70
93
|
);
|
94
|
+
const selectedNodesMap = import_react.default.useMemo(() => {
|
95
|
+
if (selectedItems) {
|
96
|
+
return convertSelectedOptionsToNodes(selectedItems, treeRootNode);
|
97
|
+
}
|
98
|
+
return [];
|
99
|
+
}, [selectedItems, treeRootNode]);
|
71
100
|
const menuSpecificProps = import_react.default.useMemo(
|
72
101
|
() => ({
|
73
102
|
options,
|
@@ -77,26 +106,15 @@ const useSplitInherithedProps = ({
|
|
77
106
|
onSubmenuToggle,
|
78
107
|
isLoading,
|
79
108
|
isSkeleton,
|
80
|
-
selectedOptions,
|
81
109
|
ItemRenderer
|
82
110
|
}),
|
83
|
-
[
|
84
|
-
options,
|
85
|
-
onClickOutside,
|
86
|
-
onOptionClick,
|
87
|
-
openedSubmenus,
|
88
|
-
onSubmenuToggle,
|
89
|
-
isLoading,
|
90
|
-
isSkeleton,
|
91
|
-
selectedOptions,
|
92
|
-
ItemRenderer
|
93
|
-
]
|
111
|
+
[options, onClickOutside, onOptionClick, openedSubmenus, onSubmenuToggle, isLoading, isSkeleton, ItemRenderer]
|
94
112
|
);
|
95
113
|
return import_react.default.useMemo(
|
96
114
|
() => ({
|
97
115
|
menuBehaviouralLayerProps: {
|
98
116
|
buttonDOMNodeRef,
|
99
|
-
|
117
|
+
selectedNodes: selectedNodesMap,
|
100
118
|
focusableNodes,
|
101
119
|
optionsTree: treeRootNode,
|
102
120
|
onDisplayedSubmenuChange,
|
@@ -112,7 +130,7 @@ const useSplitInherithedProps = ({
|
|
112
130
|
}
|
113
131
|
}),
|
114
132
|
[
|
115
|
-
|
133
|
+
selectedNodesMap,
|
116
134
|
focusableNodes,
|
117
135
|
treeRootNode,
|
118
136
|
onDisplayedSubmenuChange,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../src/config/useSplitInherithedProps.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
4
|
-
"sourcesContent": ["/* *******************************************************\n * From official source definition\n *\n * Menu Button Pattern\n * About This Pattern:\n * A menu button is a button\n * that opens a menu\n * (as described in the Menu and Menubar Pattern).\n *\n * Since the menu button is a button, it inherits all the props from the Button component.\n * Since the menu button MUST have a menu, it also have a set of specific props used to handle the menu.\n * Because we build with atomic composition in mind, the \"logic layer\" is separated and has a yet another set of props.\n *\n * This is effectively an OOP \"extension\" of the Button component,\n * so it has the same props,\n * BUT also a few more to handle the specific behavior of the menu.\n *\n * this hooks is meant to take all the DSMenuButtonT.InternalProps with default already merged\n * and spit out menuSpecificProps & buttonInheritedProps\n ******************************************************* */\nimport {} from '@elliemae/ds-system';\nimport React from 'react';\nimport { type DSMenuButtonT } from '../react-desc-prop-types.js';\nimport { resolveRef } from '../utils/resolveRef.js';\n\ntype UseSplitInherithedPropsConfig = {\n propsWithDefault: DSMenuButtonT.InternalProps;\n focusableNodes: DSMenuButtonT.PseudoFocusableMenuNodes[];\n treeRootNode: DSMenuButtonT.MenuNode;\n};\nexport const useSplitInherithedProps = ({\n propsWithDefault,\n focusableNodes,\n treeRootNode,\n}: UseSplitInherithedPropsConfig) => {\n const buttonDOMNodeRef = React.useRef<HTMLElement | null>(null);\n // when this component has been wrote\n // =============================================================================\n // MENU BUTTON props are:\n // Required\n // optionsTree, menuSpecificProps\n // Default (we already have a value because props for this hook are already merged with default props)\n // onClickOutside, onOptionClick, openedSubmenus, onSubmenuToggle, isLoading, isSkeleton, selectedOptions\n // Optional (may or may not be present)\n // ItemRenderer\n // =============================================================================\n // Props for the DSMenuBehaviouralContextProvider\n // =============================================================================\n // Required\n // selectedItems, onItemSelected, onActivateItem,\n // Optional\n // onDisplayedSubmenuChange, onOpen, onClose\n\n const {\n options,\n onClickOutside,\n onOptionClick,\n openedSubmenus,\n onSubmenuToggle,\n isLoading,\n isSkeleton,\n
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADqBvB,mBAAkB;AAElB,wBAA2B;
|
4
|
+
"sourcesContent": ["/* *******************************************************\n * From official source definition\n *\n * Menu Button Pattern\n * About This Pattern:\n * A menu button is a button\n * that opens a menu\n * (as described in the Menu and Menubar Pattern).\n *\n * Since the menu button is a button, it inherits all the props from the Button component.\n * Since the menu button MUST have a menu, it also have a set of specific props used to handle the menu.\n * Because we build with atomic composition in mind, the \"logic layer\" is separated and has a yet another set of props.\n *\n * This is effectively an OOP \"extension\" of the Button component,\n * so it has the same props,\n * BUT also a few more to handle the specific behavior of the menu.\n *\n * this hooks is meant to take all the DSMenuButtonT.InternalProps with default already merged\n * and spit out menuSpecificProps & buttonInheritedProps\n ******************************************************* */\nimport {} from '@elliemae/ds-system';\nimport React from 'react';\nimport { type DSMenuButtonT } from '../react-desc-prop-types.js';\nimport { isSelectionableNode, isObjectAMenuNode } from '../utils/nodesTypeguardsAndGetters.js';\nimport { resolveRef } from '../utils/resolveRef.js';\n\n/**\n * Converts selected options to a map of selected nodes.\n * @param {DSMenuButtonT.SelectionableMenuNodes[]} selectedItems - The selected options, as provided by the user (either items or nodes).\n * @param {DSMenuButtonT.MenuNode} treeRootNode - The root node of the menu tree.\n * @returns {DSMenuButtonT.SelectionableMenuNodes[]} - The map of selected nodes.\n * @throws Will throw an error if a selected option is not found in the tree.\n */\nconst convertSelectedOptionsToNodes = (\n selectedItems: DSMenuButtonT.SelectionableMenuNodes[] | DSMenuButtonT.SelectionableMenuItemInterface[],\n treeRootNode: DSMenuButtonT.MenuNode,\n): DSMenuButtonT.SelectionableMenuNodes[] => {\n const convertedSelection: DSMenuButtonT.SelectionableMenuNodes[] = [];\n\n selectedItems.forEach((selectedItem) => {\n const needsConversion = !isObjectAMenuNode(selectedItem);\n if (!needsConversion) {\n convertedSelection.push(selectedItem);\n return;\n }\n\n const { dsId } = selectedItem;\n const selectedNode = treeRootNode.findNode((node: DSMenuButtonT.MenuNode) => node.dsId === dsId);\n if (!selectedNode) {\n throw new Error(`Selected option with dsId ${dsId} not found in the menu tree.`);\n }\n if (!isSelectionableNode(selectedNode)) {\n // eslint-disable-next-line no-console\n console.warn(`Selected option with dsId ${dsId} is not a selectionable node and will be ignored.`);\n return;\n }\n convertedSelection.push(selectedNode);\n });\n\n return convertedSelection;\n};\n\ntype UseSplitInherithedPropsConfig = {\n propsWithDefault: DSMenuButtonT.InternalProps;\n focusableNodes: DSMenuButtonT.PseudoFocusableMenuNodes[];\n treeRootNode: DSMenuButtonT.MenuNode;\n};\nexport const useSplitInherithedProps = ({\n propsWithDefault,\n focusableNodes,\n treeRootNode,\n}: UseSplitInherithedPropsConfig) => {\n const buttonDOMNodeRef = React.useRef<HTMLElement | null>(null);\n // when this component has been wrote\n // =============================================================================\n // MENU BUTTON props are:\n // Required\n // optionsTree, menuSpecificProps\n // Default (we already have a value because props for this hook are already merged with default props)\n // onClickOutside, onOptionClick, openedSubmenus, onSubmenuToggle, isLoading, isSkeleton, selectedOptions\n // Optional (may or may not be present)\n // ItemRenderer\n // =============================================================================\n // Props for the DSMenuBehaviouralContextProvider\n // =============================================================================\n // Required\n // selectedItems, onItemSelected, onActivateItem,\n // Optional\n // onDisplayedSubmenuChange, onOpen, onClose\n\n const {\n options,\n onClickOutside,\n onOptionClick,\n openedSubmenus,\n onSubmenuToggle,\n isLoading,\n isSkeleton,\n ItemRenderer,\n innerRef,\n selectedItems,\n onDisplayedSubmenuChange,\n onItemSelected,\n onActivateItem,\n onOpen,\n onClose,\n maxHeight, // this is not shared with anything at all, it's instead a property of the \"root\" node, each node (with a submenu) can have its own maxHeight\n ...buttonInheritedProps\n } = propsWithDefault;\n\n // the button is allowed to receive innerRef, but we also need to invoke the setButtonDOMNode to store the button node\n // so we create a functional ref to do both\n const innerRefSnatchingNode: Required<DSMenuButtonT.Props>['innerRef'] = React.useCallback(\n (node: HTMLButtonElement) => {\n buttonDOMNodeRef.current = node;\n if (innerRef) {\n resolveRef(innerRef, node);\n }\n },\n [innerRef],\n );\n // in the WIDGET API, the user can provide selectedItems as an array of \"items\" or an array of \"nodes\"\n // the component needs the \"nodes\" to handle the logic and rendering & accessibility\n // if the user provides \"items\", we convert them to \"nodes\" here\n const selectedNodesMap = React.useMemo(() => {\n if (selectedItems) {\n return convertSelectedOptionsToNodes(selectedItems, treeRootNode);\n }\n return [];\n }, [selectedItems, treeRootNode]);\n\n const menuSpecificProps = React.useMemo(\n () => ({\n options,\n onClickOutside,\n onOptionClick,\n openedSubmenus,\n onSubmenuToggle,\n isLoading,\n isSkeleton,\n ItemRenderer,\n }),\n [options, onClickOutside, onOptionClick, openedSubmenus, onSubmenuToggle, isLoading, isSkeleton, ItemRenderer],\n );\n\n return React.useMemo(\n () => ({\n menuBehaviouralLayerProps: {\n buttonDOMNodeRef,\n selectedNodes: selectedNodesMap,\n focusableNodes,\n optionsTree: treeRootNode,\n onDisplayedSubmenuChange,\n onItemSelected,\n onActivateItem,\n onOpen,\n onClose,\n },\n opinionatedButtonProps: {\n ...(buttonInheritedProps as DSMenuButtonT.ButtonInheritedProps),\n innerRef: innerRefSnatchingNode,\n menuSpecificProps,\n },\n }),\n [\n selectedNodesMap,\n focusableNodes,\n treeRootNode,\n onDisplayedSubmenuChange,\n onItemSelected,\n onActivateItem,\n onOpen,\n onClose,\n buttonInheritedProps,\n innerRefSnatchingNode,\n menuSpecificProps,\n ],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADqBvB,mBAAkB;AAElB,uCAAuD;AACvD,wBAA2B;AAS3B,MAAM,gCAAgC,CACpC,eACA,iBAC2C;AAC3C,QAAM,qBAA6D,CAAC;AAEpE,gBAAc,QAAQ,CAAC,iBAAiB;AACtC,UAAM,kBAAkB,KAAC,oDAAkB,YAAY;AACvD,QAAI,CAAC,iBAAiB;AACpB,yBAAmB,KAAK,YAAY;AACpC;AAAA,IACF;AAEA,UAAM,EAAE,KAAK,IAAI;AACjB,UAAM,eAAe,aAAa,SAAS,CAAC,SAAiC,KAAK,SAAS,IAAI;AAC/F,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,6BAA6B,IAAI,8BAA8B;AAAA,IACjF;AACA,QAAI,KAAC,sDAAoB,YAAY,GAAG;AAEtC,cAAQ,KAAK,6BAA6B,IAAI,mDAAmD;AACjG;AAAA,IACF;AACA,uBAAmB,KAAK,YAAY;AAAA,EACtC,CAAC;AAED,SAAO;AACT;AAOO,MAAM,0BAA0B,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AACF,MAAqC;AACnC,QAAM,mBAAmB,aAAAA,QAAM,OAA2B,IAAI;AAkB9D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAIJ,QAAM,wBAAmE,aAAAA,QAAM;AAAA,IAC7E,CAAC,SAA4B;AAC3B,uBAAiB,UAAU;AAC3B,UAAI,UAAU;AACZ,0CAAW,UAAU,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAIA,QAAM,mBAAmB,aAAAA,QAAM,QAAQ,MAAM;AAC3C,QAAI,eAAe;AACjB,aAAO,8BAA8B,eAAe,YAAY;AAAA,IAClE;AACA,WAAO,CAAC;AAAA,EACV,GAAG,CAAC,eAAe,YAAY,CAAC;AAEhC,QAAM,oBAAoB,aAAAA,QAAM;AAAA,IAC9B,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,SAAS,gBAAgB,eAAe,gBAAgB,iBAAiB,WAAW,YAAY,YAAY;AAAA,EAC/G;AAEA,SAAO,aAAAA,QAAM;AAAA,IACX,OAAO;AAAA,MACL,2BAA2B;AAAA,QACzB;AAAA,QACA,eAAe;AAAA,QACf;AAAA,QACA,aAAa;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,wBAAwB;AAAA,QACtB,GAAI;AAAA,QACJ,UAAU;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;",
|
6
6
|
"names": ["React"]
|
7
7
|
}
|
@@ -39,28 +39,36 @@ var import_ds_grid = require("@elliemae/ds-grid");
|
|
39
39
|
var import_ds_props_helpers = require("@elliemae/ds-props-helpers");
|
40
40
|
var import_ds_system = require("@elliemae/ds-system");
|
41
41
|
var import_react = __toESM(require("react"));
|
42
|
+
var import_react_desc_prop_types = require("../../react-desc-prop-types.js");
|
42
43
|
var import_MenuBehaviouralContextProviderCTX = require("../DSMenuBehaviouralContextProvider/MenuBehaviouralContextProviderCTX.js");
|
43
44
|
var import_DSMenuItemRendererFactory = require("../DSMenuItemRendererFactory/index.js");
|
44
45
|
var import_useFlyoutMenu = require("./config/useFlyoutMenu.js");
|
45
46
|
var import_constants = require("./constants/index.js");
|
46
|
-
var
|
47
|
+
var import_react_desc_prop_types2 = require("./react-desc-prop-types.js");
|
47
48
|
var import_nodesTypeguardsAndGetters = require("../../utils/nodesTypeguardsAndGetters.js");
|
48
|
-
const StyledWrapper = (0, import_ds_system.styled)(import_ds_grid.Grid, {
|
49
|
-
|
49
|
+
const StyledWrapper = (0, import_ds_system.styled)(import_ds_grid.Grid, {
|
50
|
+
name: import_constants.DSFlyoutMenuName,
|
51
|
+
slot: import_constants.FLYOUT_MENU_SLOTS.ROOT
|
52
|
+
})`
|
53
|
+
min-width: 1px;
|
50
54
|
background-color: white;
|
51
55
|
padding: ${({ theme }) => theme.space.xxxs} 0;
|
52
56
|
${import_ds_system.xStyledCommonProps}
|
53
57
|
`;
|
54
58
|
const StyledMenu = (0, import_ds_system.styled)("div", { name: import_constants.DSFlyoutMenuName, slot: import_constants.FLYOUT_MENU_SLOTS.LIST_WRAPPER })`
|
59
|
+
max-height: ${({ $maxHeight }) => typeof $maxHeight === "number" ? `${$maxHeight}px` : $maxHeight};
|
60
|
+
overflow-y: auto;
|
55
61
|
padding: 0;
|
56
62
|
margin: 0;
|
57
63
|
`;
|
64
|
+
const NoComponentPlaceholder = () => null;
|
58
65
|
const DSFlyoutMenu = (props) => {
|
59
66
|
const { propsWithDefault, xstyledProps } = (0, import_useFlyoutMenu.useFlyoutMenu)(props);
|
60
67
|
const {
|
61
68
|
instanceUid,
|
62
69
|
globalEventsHelpers: { mainMenuRef, handleSubmenusRefChange }
|
63
70
|
} = import_react.default.useContext(import_MenuBehaviouralContextProviderCTX.MenuBehaviouralContextProviderContext);
|
71
|
+
const [didAnimationEnd, setDidAnimationEnd] = import_react.default.useState(false);
|
64
72
|
const { setFloatingRef, floatingStyles, floatingContext, ItemRenderer, isMenuOpen, itemNode } = propsWithDefault;
|
65
73
|
const handleRefChange = import_react.default.useCallback(
|
66
74
|
(node) => {
|
@@ -72,6 +80,12 @@ const DSFlyoutMenu = (props) => {
|
|
72
80
|
},
|
73
81
|
[handleSubmenusRefChange, itemNode, mainMenuRef]
|
74
82
|
);
|
83
|
+
const handleAnimationStartTrigger = import_react.default.useCallback(() => {
|
84
|
+
setDidAnimationEnd(false);
|
85
|
+
}, []);
|
86
|
+
const handleAnimationEnd = import_react.default.useCallback(() => {
|
87
|
+
setDidAnimationEnd(true);
|
88
|
+
}, []);
|
75
89
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
76
90
|
import_ds_floating_context.FloatingWrapper,
|
77
91
|
{
|
@@ -79,19 +93,29 @@ const DSFlyoutMenu = (props) => {
|
|
79
93
|
floatingStyles,
|
80
94
|
isOpen: isMenuOpen,
|
81
95
|
context: floatingContext,
|
82
|
-
|
83
|
-
|
96
|
+
onAnimationStartTriggered: handleAnimationStartTrigger,
|
97
|
+
onAnimationEnd: handleAnimationEnd,
|
98
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledWrapper, { getOwnerProps: () => propsWithDefault, getOwnerPropsArguments: () => ({}), ...xstyledProps, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
99
|
+
StyledMenu,
|
84
100
|
{
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
101
|
+
role: "menu",
|
102
|
+
innerRef: handleRefChange,
|
103
|
+
$maxHeight: itemNode.plainItem.maxHeight ?? import_react_desc_prop_types.menuSpecificDefaultProps.maxHeight,
|
104
|
+
children: itemNode.children.map((optionNode) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
105
|
+
import_DSMenuItemRendererFactory.DSMenuItemRendererFactory,
|
106
|
+
{
|
107
|
+
itemNode: optionNode,
|
108
|
+
ItemRenderer,
|
109
|
+
FlyoutMenuCircularDepInject: didAnimationEnd ? DSFlyoutMenu : NoComponentPlaceholder
|
110
|
+
},
|
111
|
+
`flyout-menu-item-${optionNode.dsId}-${instanceUid}`
|
112
|
+
))
|
113
|
+
}
|
114
|
+
) })
|
91
115
|
}
|
92
116
|
);
|
93
117
|
};
|
94
118
|
DSFlyoutMenu.displayName = import_constants.DSFlyoutMenuName;
|
95
119
|
const DSFlyoutMenuWithSchema = (0, import_ds_props_helpers.describe)(DSFlyoutMenu);
|
96
|
-
DSFlyoutMenuWithSchema.propTypes =
|
120
|
+
DSFlyoutMenuWithSchema.propTypes = import_react_desc_prop_types2.DSFlyoutMenuPropTypesSchema;
|
97
121
|
//# sourceMappingURL=DSFlyoutMenu.js.map
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../../src/parts/DSFlyoutMenu/DSFlyoutMenu.tsx", "../../../../../../../scripts/build/transpile/react-shim.js"],
|
4
|
-
"sourcesContent": ["import { FloatingWrapper } from '@elliemae/ds-floating-context';\nimport { Grid } from '@elliemae/ds-grid';\nimport { describe } from '@elliemae/ds-props-helpers';\nimport { styled, xStyledCommonProps } from '@elliemae/ds-system';\nimport React from 'react';\nimport type
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;
|
6
|
-
"names": ["React"]
|
4
|
+
"sourcesContent": ["import { FloatingWrapper } from '@elliemae/ds-floating-context';\nimport { Grid } from '@elliemae/ds-grid';\nimport { describe } from '@elliemae/ds-props-helpers';\nimport { styled, xStyledCommonProps } from '@elliemae/ds-system';\nimport React from 'react';\nimport { type DSMenuButtonT, menuSpecificDefaultProps } from '../../react-desc-prop-types.js';\nimport { MenuBehaviouralContextProviderContext } from '../DSMenuBehaviouralContextProvider/MenuBehaviouralContextProviderCTX.js';\nimport { DSMenuItemRendererFactory } from '../DSMenuItemRendererFactory/index.js';\nimport { useFlyoutMenu } from './config/useFlyoutMenu.js';\nimport { DSFlyoutMenuName, FLYOUT_MENU_SLOTS } from './constants/index.js';\nimport { DSFlyoutMenuPropTypesSchema, type DSFlyoutMenuT } from './react-desc-prop-types.js';\nimport { isRootNode } from '../../utils/nodesTypeguardsAndGetters.js';\n\nconst StyledWrapper = styled(Grid, {\n name: DSFlyoutMenuName,\n slot: FLYOUT_MENU_SLOTS.ROOT,\n})`\n min-width: 1px;\n background-color: white;\n padding: ${({ theme }) => theme.space.xxxs} 0;\n ${xStyledCommonProps}\n`;\n\nconst StyledMenu = styled('div', { name: DSFlyoutMenuName, slot: FLYOUT_MENU_SLOTS.LIST_WRAPPER })<{\n $maxHeight: string | number;\n}>`\n max-height: ${({ $maxHeight }) => (typeof $maxHeight === 'number' ? `${$maxHeight}px` : $maxHeight)};\n overflow-y: auto;\n padding: 0;\n margin: 0;\n`;\n\nconst NoComponentPlaceholder = () => null;\n\nconst DSFlyoutMenu: React.ComponentType<DSFlyoutMenuT.Props> = (props) => {\n const { propsWithDefault, xstyledProps } = useFlyoutMenu(props);\n const {\n instanceUid,\n globalEventsHelpers: { mainMenuRef, handleSubmenusRefChange },\n } = React.useContext(MenuBehaviouralContextProviderContext);\n const [didAnimationEnd, setDidAnimationEnd] = React.useState(false);\n\n const { setFloatingRef, floatingStyles, floatingContext, ItemRenderer, isMenuOpen, itemNode } = propsWithDefault;\n\n const handleRefChange = React.useCallback(\n (node: HTMLDivElement) => {\n if (isRootNode(itemNode)) {\n mainMenuRef.current = node;\n return;\n }\n handleSubmenusRefChange(node, itemNode.dsId);\n },\n [handleSubmenusRefChange, itemNode, mainMenuRef],\n );\n\n const handleAnimationStartTrigger = React.useCallback(() => {\n setDidAnimationEnd(false);\n }, []);\n const handleAnimationEnd = React.useCallback(() => {\n setDidAnimationEnd(true);\n }, []);\n\n return (\n <FloatingWrapper\n innerRef={setFloatingRef}\n floatingStyles={floatingStyles}\n isOpen={isMenuOpen}\n context={floatingContext}\n onAnimationStartTriggered={handleAnimationStartTrigger}\n onAnimationEnd={handleAnimationEnd}\n >\n <StyledWrapper getOwnerProps={() => propsWithDefault} getOwnerPropsArguments={() => ({})} {...xstyledProps}>\n <StyledMenu\n role=\"menu\"\n innerRef={handleRefChange}\n $maxHeight={itemNode.plainItem.maxHeight ?? menuSpecificDefaultProps.maxHeight}\n >\n {itemNode.children.map((optionNode) => (\n <DSMenuItemRendererFactory\n key={`flyout-menu-item-${optionNode.dsId}-${instanceUid}`}\n // DSTree doesn't support children having a polymorphic type, so we need to cast it manually\n itemNode={optionNode as DSMenuButtonT.MenuNode}\n ItemRenderer={ItemRenderer}\n // we are passing the DSFlyoutMenu component as a prop to the DSMenuItemRendererFactory\n // this solves the circular-ish dependency\n // the conditional `didAnimationEnd` solves the visual artefact of nested FloatingWrapper wrongly positioned due to animation\n FlyoutMenuCircularDepInject={didAnimationEnd ? DSFlyoutMenu : NoComponentPlaceholder}\n />\n ))}\n </StyledMenu>\n </StyledWrapper>\n </FloatingWrapper>\n );\n};\n\nDSFlyoutMenu.displayName = DSFlyoutMenuName;\nconst DSFlyoutMenuWithSchema = describe(DSFlyoutMenu);\nDSFlyoutMenuWithSchema.propTypes = DSFlyoutMenuPropTypesSchema;\n\nexport { DSFlyoutMenu, DSFlyoutMenuWithSchema };\n", "import * as React from 'react';\nexport { React };\n"],
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;AD8EX;AA9EZ,iCAAgC;AAChC,qBAAqB;AACrB,8BAAyB;AACzB,uBAA2C;AAC3C,mBAAkB;AAClB,mCAA6D;AAC7D,+CAAsD;AACtD,uCAA0C;AAC1C,2BAA8B;AAC9B,uBAAoD;AACpD,IAAAA,gCAAgE;AAChE,uCAA2B;AAE3B,MAAM,oBAAgB,yBAAO,qBAAM;AAAA,EACjC,MAAM;AAAA,EACN,MAAM,mCAAkB;AAC1B,CAAC;AAAA;AAAA;AAAA,aAGY,CAAC,EAAE,MAAM,MAAM,MAAM,MAAM,IAAI;AAAA,IACxC,mCAAkB;AAAA;AAGtB,MAAM,iBAAa,yBAAO,OAAO,EAAE,MAAM,mCAAkB,MAAM,mCAAkB,aAAa,CAAC;AAAA,gBAGjF,CAAC,EAAE,WAAW,MAAO,OAAO,eAAe,WAAW,GAAG,UAAU,OAAO,UAAW;AAAA;AAAA;AAAA;AAAA;AAMrG,MAAM,yBAAyB,MAAM;AAErC,MAAM,eAAyD,CAAC,UAAU;AACxE,QAAM,EAAE,kBAAkB,aAAa,QAAI,oCAAc,KAAK;AAC9D,QAAM;AAAA,IACJ;AAAA,IACA,qBAAqB,EAAE,aAAa,wBAAwB;AAAA,EAC9D,IAAI,aAAAC,QAAM,WAAW,8EAAqC;AAC1D,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,aAAAA,QAAM,SAAS,KAAK;AAElE,QAAM,EAAE,gBAAgB,gBAAgB,iBAAiB,cAAc,YAAY,SAAS,IAAI;AAEhG,QAAM,kBAAkB,aAAAA,QAAM;AAAA,IAC5B,CAAC,SAAyB;AACxB,cAAI,6CAAW,QAAQ,GAAG;AACxB,oBAAY,UAAU;AACtB;AAAA,MACF;AACA,8BAAwB,MAAM,SAAS,IAAI;AAAA,IAC7C;AAAA,IACA,CAAC,yBAAyB,UAAU,WAAW;AAAA,EACjD;AAEA,QAAM,8BAA8B,aAAAA,QAAM,YAAY,MAAM;AAC1D,uBAAmB,KAAK;AAAA,EAC1B,GAAG,CAAC,CAAC;AACL,QAAM,qBAAqB,aAAAA,QAAM,YAAY,MAAM;AACjD,uBAAmB,IAAI;AAAA,EACzB,GAAG,CAAC,CAAC;AAEL,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,2BAA2B;AAAA,MAC3B,gBAAgB;AAAA,MAEhB,sDAAC,iBAAc,eAAe,MAAM,kBAAkB,wBAAwB,OAAO,CAAC,IAAK,GAAG,cAC5F;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU;AAAA,UACV,YAAY,SAAS,UAAU,aAAa,sDAAyB;AAAA,UAEpE,mBAAS,SAAS,IAAI,CAAC,eACtB;AAAA,YAAC;AAAA;AAAA,cAGC,UAAU;AAAA,cACV;AAAA,cAIA,6BAA6B,kBAAkB,eAAe;AAAA;AAAA,YAPzD,oBAAoB,WAAW,IAAI,IAAI,WAAW;AAAA,UAQzD,CACD;AAAA;AAAA,MACH,GACF;AAAA;AAAA,EACF;AAEJ;AAEA,aAAa,cAAc;AAC3B,MAAM,6BAAyB,kCAAS,YAAY;AACpD,uBAAuB,YAAY;",
|
6
|
+
"names": ["import_react_desc_prop_types", "React"]
|
7
7
|
}
|
@@ -37,7 +37,7 @@ var React = __toESM(require("react"));
|
|
37
37
|
var import_ds_props_helpers = require("@elliemae/ds-props-helpers");
|
38
38
|
var import_react_desc_prop_types = require("../../react-desc-prop-types.js");
|
39
39
|
var import_constants = require("./constants/index.js");
|
40
|
-
const defaultProps = { ...import_react_desc_prop_types.
|
40
|
+
const defaultProps = { ...import_react_desc_prop_types.menuSpecificDefaultProps };
|
41
41
|
const DSFlyoutMenuPropTypes = {
|
42
42
|
itemNode: import_ds_props_helpers.PropTypes.object.description("The parent menu node to render the menu from").isRequired,
|
43
43
|
setFloatingRef: import_ds_props_helpers.PropTypes.func.description(
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../../src/parts/DSFlyoutMenu/react-desc-prop-types.ts", "../../../../../../../scripts/build/transpile/react-shim.js"],
|
4
|
-
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-empty-interface */\nimport type { DSPropTypesSchema, ValidationMap } from '@elliemae/ds-props-helpers';\nimport {\n PropTypes,\n getPropsPerSlotPropTypes,\n globalAttributesPropTypes,\n xstyledPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { type TypescriptHelpersT } from '@elliemae/ds-typescript-helpers';\nimport {
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;
|
6
|
-
"names": [
|
4
|
+
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-empty-interface */\nimport { type useFloatingContext } from '@elliemae/ds-floating-context';\nimport type { DSPropTypesSchema, ValidationMap } from '@elliemae/ds-props-helpers';\nimport {\n PropTypes,\n getPropsPerSlotPropTypes,\n globalAttributesPropTypes,\n xstyledPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport { type TypescriptHelpersT } from '@elliemae/ds-typescript-helpers';\nimport { DSMenuSpecificPropTypes, menuSpecificDefaultProps, type DSMenuButtonT } from '../../react-desc-prop-types.js';\nimport { DSFlyoutMenuName, FLYOUT_MENU_SLOTS } from './constants/index.js';\n\nexport declare namespace DSFlyoutMenuT {\n /*\n * everything that is specifically added in this namespace declaration and is not part of the original component\n * is because the original component is an \"opinionated widget\" that offloads a chunk of responsibilities from dev to dimsum\n * as such, the widget generates those interfaces,\n * but the app developer is not supposed to know about them\n * untill they go atomic composition (this namespace)\n */\n export interface RequiredProps extends DSMenuButtonT.MenuSpecificRequiredProps {\n isMenuOpen: boolean;\n itemNode:\n | DSMenuButtonT.MenuNodeWithSubmenuItem\n | DSMenuButtonT.MenuNodeSingleSelectWithSubmenuItem\n | DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem\n | DSMenuButtonT.MenuNodeActivableWithSubmenuItem\n | DSMenuButtonT.MenuNodeRootItem;\n setFloatingRef: ReturnType<typeof useFloatingContext>['refs']['setFloating'];\n floatingStyles: ReturnType<typeof useFloatingContext>['floatingStyles'];\n floatingContext: ReturnType<typeof useFloatingContext>['context'];\n }\n\n export interface DefaultProps extends DSMenuButtonT.MenuSpecifiDefaultProps {}\n\n export interface OptionalProps\n extends TypescriptHelpersT.PropsForGlobalOnSlots<typeof DSFlyoutMenuName, typeof FLYOUT_MENU_SLOTS>,\n DSMenuButtonT.MenuSpecificOptionalProps {}\n\n export interface Props extends RequiredProps, Partial<DefaultProps>, OptionalProps {}\n\n export interface InternalProps extends RequiredProps, DefaultProps, OptionalProps {}\n}\n\nexport const defaultProps: DSFlyoutMenuT.DefaultProps = { ...menuSpecificDefaultProps };\n\nexport const DSFlyoutMenuPropTypes: DSPropTypesSchema<DSFlyoutMenuT.Props> = {\n itemNode: PropTypes.object.description('The parent menu node to render the menu from').isRequired,\n setFloatingRef: PropTypes.func.description(\n 'The function to set the ref of the floating element (from useFloatingContext.refs.setFloating)',\n ).isRequired,\n floatingStyles: PropTypes.object.description(\n 'The styles to apply to the floating element to correctly position it (from useFloatingContext.floatingStyles)',\n ).isRequired,\n floatingContext: PropTypes.object.description(\n 'The context object from useFloatingContext, used to allow FloatingWrapper correct functionality',\n ).isRequired,\n // anchorNode: PropTypes.instanceOf(HTMLElement).isRequired,\n isMenuOpen: PropTypes.bool.description('Wheter or not this particular instance of the flyout menu is open')\n .isRequired,\n ...getPropsPerSlotPropTypes(DSFlyoutMenuName, FLYOUT_MENU_SLOTS),\n ...globalAttributesPropTypes,\n // this component is meant to be used from a ds-menu-button compliant API,\n // for this reason we want to inherit the DSMenuButton props interface that relates to the menu and not the button...\n ...DSMenuSpecificPropTypes,\n ...xstyledPropTypes,\n};\n\nexport const DSFlyoutMenuPropTypesSchema = DSFlyoutMenuPropTypes as unknown as ValidationMap<DSFlyoutMenuT.Props>;\n", "import * as React from 'react';\nexport { React };\n"],
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,8BAKO;AAEP,mCAAsF;AACtF,uBAAoD;AAkC7C,MAAM,eAA2C,EAAE,GAAG,sDAAyB;AAE/E,MAAM,wBAAgE;AAAA,EAC3E,UAAU,kCAAU,OAAO,YAAY,8CAA8C,EAAE;AAAA,EACvF,gBAAgB,kCAAU,KAAK;AAAA,IAC7B;AAAA,EACF,EAAE;AAAA,EACF,gBAAgB,kCAAU,OAAO;AAAA,IAC/B;AAAA,EACF,EAAE;AAAA,EACF,iBAAiB,kCAAU,OAAO;AAAA,IAChC;AAAA,EACF,EAAE;AAAA;AAAA,EAEF,YAAY,kCAAU,KAAK,YAAY,mEAAmE,EACvG;AAAA,EACH,OAAG,kDAAyB,mCAAkB,kCAAiB;AAAA,EAC/D,GAAG;AAAA;AAAA;AAAA,EAGH,GAAG;AAAA,EACH,GAAG;AACL;AAEO,MAAM,8BAA8B;",
|
6
|
+
"names": []
|
7
7
|
}
|
@@ -35,7 +35,7 @@ var React = __toESM(require("react"));
|
|
35
35
|
var import_react = require("react");
|
36
36
|
var import_nodesTypeguardsAndGetters = require("../../../utils/nodesTypeguardsAndGetters.js");
|
37
37
|
const useAdvancedValidation = ({ propsWithDefault }) => {
|
38
|
-
const { onActivateItem, onItemSelected,
|
38
|
+
const { onActivateItem, onItemSelected, selectedNodes, optionsTree } = propsWithDefault;
|
39
39
|
(0, import_react.useEffect)(() => {
|
40
40
|
const allNodes = optionsTree.flatten();
|
41
41
|
const nodesByDsId = {};
|
@@ -76,11 +76,11 @@ The dsId must be unique.`
|
|
76
76
|
"DSMenuButton:\nSome items are activable, but onActivateItem is not provided.\n\nYou must provide onActivateItem to handle activation."
|
77
77
|
);
|
78
78
|
}
|
79
|
-
if (hasSelection && (!onItemSelected || !
|
79
|
+
if (hasSelection && (!onItemSelected || !selectedNodes)) {
|
80
80
|
throw new Error(
|
81
|
-
"DSMenuButton:\nSome items are selectionable, but onItemSelected or
|
81
|
+
"DSMenuButton:\nSome items are selectionable, but onItemSelected or selectedNodes are not provided.\n\nYou must provide onItemSelected and selectedNodes to handle selection."
|
82
82
|
);
|
83
83
|
}
|
84
|
-
}, [onActivateItem, onItemSelected,
|
84
|
+
}, [onActivateItem, onItemSelected, selectedNodes, optionsTree]);
|
85
85
|
};
|
86
86
|
//# sourceMappingURL=useAdvancedValidation.js.map
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../../../src/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.ts", "../../../../../../../../scripts/build/transpile/react-shim.js"],
|
4
|
-
"sourcesContent": ["import { useEffect } from 'react';\nimport { type DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport { type DSMenuBehaviouralContextProviderT } from '../react-desc-prop-types.js';\nimport { isActivableNode, isSelectionableNode } from '../../../utils/nodesTypeguardsAndGetters.js';\n\ntype UseAdvancedValidationConfigT = {\n propsWithDefault: DSMenuBehaviouralContextProviderT.InternalProps;\n};\nexport const useAdvancedValidation = ({ propsWithDefault }: UseAdvancedValidationConfigT): void => {\n const { onActivateItem, onItemSelected,
|
4
|
+
"sourcesContent": ["import { useEffect } from 'react';\nimport { type DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport { type DSMenuBehaviouralContextProviderT } from '../react-desc-prop-types.js';\nimport { isActivableNode, isSelectionableNode } from '../../../utils/nodesTypeguardsAndGetters.js';\n\ntype UseAdvancedValidationConfigT = {\n propsWithDefault: DSMenuBehaviouralContextProviderT.InternalProps;\n};\nexport const useAdvancedValidation = ({ propsWithDefault }: UseAdvancedValidationConfigT): void => {\n const { onActivateItem, onItemSelected, selectedNodes, optionsTree } = propsWithDefault;\n // =============================================================================\n // SPECIAL VALIDATIONS\n // =============================================================================\n // We iterate onces, validate everything in one go for performance reasons\n // =============================================================================\n // - No repeated dsId\n // (only validating focusableNodes may work, but to avoid complexity we validate the whole tree)\n // - if any item is \"selectionable\", selection IoC props must be provided\n // - if any item is \"activable\", activation IoC props must be provided\n // =============================================================================\n // we want to validate only when dependencies change, should improve performance if app is using memoization\n // and be virtually a free overhead if the app is not using memoization\n // =============================================================================\n useEffect(() => {\n const allNodes = optionsTree.flatten();\n const nodesByDsId: { [key: DSMenuButtonT.MenuNode['dsId']]: DSMenuButtonT.MenuNode[] } = {};\n const duplicatedIdsNodes: { [key: DSMenuButtonT.MenuNode['dsId']]: DSMenuButtonT.MenuNode[] } = {};\n let hasActivation = false;\n let hasSelection = false;\n let hasDuplicateDsId = false;\n allNodes.forEach((node) => {\n const { dsId } = node;\n if (!Array.isArray(nodesByDsId[dsId])) {\n nodesByDsId[dsId] = [node];\n } else {\n nodesByDsId[dsId].push(node);\n hasDuplicateDsId = true;\n duplicatedIdsNodes[dsId] = nodesByDsId[dsId];\n }\n\n if (isActivableNode(node)) {\n hasActivation = true;\n }\n if (isSelectionableNode(node)) {\n hasSelection = true;\n }\n });\n if (hasDuplicateDsId) {\n // eslint-disable-next-line no-console\n console.log('duplicatedIdsNodes', duplicatedIdsNodes);\n throw new Error(\n `DSMenuButton:\\nThe following dsId are repeated:\\n${Object.keys(duplicatedIdsNodes).join(\n '\\n',\n )}\\n\\nThe dsId must be unique.`,\n );\n }\n if (hasActivation && !onActivateItem) {\n throw new Error(\n 'DSMenuButton:\\nSome items are activable, but onActivateItem is not provided.\\n\\nYou must provide onActivateItem to handle activation.',\n );\n }\n if (hasSelection && (!onItemSelected || !selectedNodes)) {\n throw new Error(\n 'DSMenuButton:\\nSome items are selectionable, but onItemSelected or selectedNodes are not provided.\\n\\nYou must provide onItemSelected and selectedNodes to handle selection.',\n );\n }\n }, [onActivateItem, onItemSelected, selectedNodes, optionsTree]);\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,mBAA0B;AAG1B,uCAAqD;AAK9C,MAAM,wBAAwB,CAAC,EAAE,iBAAiB,MAA0C;AACjG,QAAM,EAAE,gBAAgB,gBAAgB,eAAe,YAAY,IAAI;AAcvE,8BAAU,MAAM;AACd,UAAM,WAAW,YAAY,QAAQ;AACrC,UAAM,cAAmF,CAAC;AAC1F,UAAM,qBAA0F,CAAC;AACjG,QAAI,gBAAgB;AACpB,QAAI,eAAe;AACnB,QAAI,mBAAmB;AACvB,aAAS,QAAQ,CAAC,SAAS;AACzB,YAAM,EAAE,KAAK,IAAI;AACjB,UAAI,CAAC,MAAM,QAAQ,YAAY,IAAI,CAAC,GAAG;AACrC,oBAAY,IAAI,IAAI,CAAC,IAAI;AAAA,MAC3B,OAAO;AACL,oBAAY,IAAI,EAAE,KAAK,IAAI;AAC3B,2BAAmB;AACnB,2BAAmB,IAAI,IAAI,YAAY,IAAI;AAAA,MAC7C;AAEA,cAAI,kDAAgB,IAAI,GAAG;AACzB,wBAAgB;AAAA,MAClB;AACA,cAAI,sDAAoB,IAAI,GAAG;AAC7B,uBAAe;AAAA,MACjB;AAAA,IACF,CAAC;AACD,QAAI,kBAAkB;AAEpB,cAAQ,IAAI,sBAAsB,kBAAkB;AACpD,YAAM,IAAI;AAAA,QACR;AAAA;AAAA,EAAoD,OAAO,KAAK,kBAAkB,EAAE;AAAA,UAClF;AAAA,QACF,CAAC;AAAA;AAAA;AAAA,MACH;AAAA,IACF;AACA,QAAI,iBAAiB,CAAC,gBAAgB;AACpC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,iBAAiB,CAAC,kBAAkB,CAAC,gBAAgB;AACvD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,gBAAgB,gBAAgB,eAAe,WAAW,CAAC;AACjE;",
|
6
6
|
"names": []
|
7
7
|
}
|
@@ -32,6 +32,7 @@ __export(useFocusTracker_exports, {
|
|
32
32
|
});
|
33
33
|
module.exports = __toCommonJS(useFocusTracker_exports);
|
34
34
|
var React = __toESM(require("react"));
|
35
|
+
var import_lodash = require("lodash");
|
35
36
|
var import_react = __toESM(require("react"));
|
36
37
|
var import_nodesTypeguardsAndGetters = require("../../../utils/nodesTypeguardsAndGetters.js");
|
37
38
|
var import_Errors = require("../constants/Errors.js");
|
@@ -44,24 +45,34 @@ const useFocusTracker = () => {
|
|
44
45
|
const focusedElementItemNode = import_react.default.useRef(
|
45
46
|
null
|
46
47
|
);
|
47
|
-
const
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
48
|
+
const racingConditionDebounceTrackFocus = import_react.default.useCallback(
|
49
|
+
(0, import_lodash.throttle)(
|
50
|
+
(newFocusRegion, focusNode) => {
|
51
|
+
setFocusRegion(newFocusRegion);
|
52
|
+
focusedRegionPerformanceHelper.current = newFocusRegion;
|
53
|
+
focusedElementItemNode.current = focusNode;
|
54
|
+
return focusNode;
|
55
|
+
},
|
56
|
+
50,
|
57
|
+
{ leading: true, trailing: true }
|
58
|
+
),
|
59
|
+
[]
|
60
|
+
);
|
61
|
+
const trackFocusTrigger = import_react.default.useCallback(
|
62
|
+
() => racingConditionDebounceTrackFocus(import_constants.MENU_FOCUS_REGIONS.TRIGGER, null),
|
63
|
+
[racingConditionDebounceTrackFocus]
|
64
|
+
);
|
65
|
+
const trackFocusNode = import_react.default.useCallback(
|
66
|
+
(nodeToFocus) => {
|
67
|
+
const newFocusRegion = import_constants.MENU_FOCUS_REGIONS.ITEM_BY_DSID(nodeToFocus.dsId);
|
68
|
+
racingConditionDebounceTrackFocus(newFocusRegion, nodeToFocus);
|
69
|
+
},
|
70
|
+
[racingConditionDebounceTrackFocus]
|
71
|
+
);
|
72
|
+
const trackFocusRegionReset = import_react.default.useCallback(
|
73
|
+
() => racingConditionDebounceTrackFocus(import_constants.MENU_FOCUS_REGIONS.RESET, null),
|
74
|
+
[racingConditionDebounceTrackFocus]
|
75
|
+
);
|
65
76
|
const trackFocusFirstChildItem = import_react.default.useCallback(
|
66
77
|
(itemNode) => {
|
67
78
|
if (!(0, import_nodesTypeguardsAndGetters.isMenuNodeAllowedToHaveChildren)(itemNode)) {
|
@@ -78,10 +89,9 @@ const useFocusTracker = () => {
|
|
78
89
|
throw new Error("No focusable nodes found in the children of the item node");
|
79
90
|
}
|
80
91
|
const newFocusedNode = focusableChildrenNodes[0];
|
81
|
-
|
82
|
-
return newFocusedNode;
|
92
|
+
return racingConditionDebounceTrackFocus(import_constants.MENU_FOCUS_REGIONS.ITEM_BY_DSID(newFocusedNode.dsId), newFocusedNode);
|
83
93
|
},
|
84
|
-
[
|
94
|
+
[racingConditionDebounceTrackFocus]
|
85
95
|
);
|
86
96
|
const trackFocusLastChildItem = import_react.default.useCallback(
|
87
97
|
(itemNode) => {
|
@@ -98,10 +108,12 @@ const useFocusTracker = () => {
|
|
98
108
|
console.log("focus last child item > itemNode", itemNode);
|
99
109
|
throw new Error("No focusable nodes found in the children of the item node");
|
100
110
|
}
|
101
|
-
|
102
|
-
|
111
|
+
return racingConditionDebounceTrackFocus(
|
112
|
+
import_constants.MENU_FOCUS_REGIONS.ITEM_BY_DSID(focusableChildrenNodes[focusableChildrenNodes.length - 1].dsId),
|
113
|
+
focusableChildrenNodes[focusableChildrenNodes.length - 1]
|
114
|
+
);
|
103
115
|
},
|
104
|
-
[
|
116
|
+
[racingConditionDebounceTrackFocus]
|
105
117
|
);
|
106
118
|
const trackFocusNextItem = import_react.default.useCallback(
|
107
119
|
(itemNode) => {
|
@@ -109,10 +121,9 @@ const useFocusTracker = () => {
|
|
109
121
|
const currIndex = focusableSiblingsNodes.findIndex((node) => node.dsId === itemNode.dsId);
|
110
122
|
const nextIndex = currIndex + 1 < focusableSiblingsNodes.length ? currIndex + 1 : 0;
|
111
123
|
const newFocusedNode = focusableSiblingsNodes[nextIndex];
|
112
|
-
|
113
|
-
return newFocusedNode;
|
124
|
+
return racingConditionDebounceTrackFocus(import_constants.MENU_FOCUS_REGIONS.ITEM_BY_DSID(newFocusedNode.dsId), newFocusedNode);
|
114
125
|
},
|
115
|
-
[
|
126
|
+
[racingConditionDebounceTrackFocus]
|
116
127
|
);
|
117
128
|
const trackFocusPreviousItem = import_react.default.useCallback(
|
118
129
|
(itemNode) => {
|
@@ -120,10 +131,9 @@ const useFocusTracker = () => {
|
|
120
131
|
const currIndex = focusableSiblingsNodes.findIndex((node) => node.dsId === itemNode.dsId);
|
121
132
|
const previousIndex = currIndex - 1 >= 0 ? currIndex - 1 : focusableSiblingsNodes.length - 1;
|
122
133
|
const newFocusNode = focusableSiblingsNodes[previousIndex];
|
123
|
-
|
124
|
-
return newFocusNode;
|
134
|
+
return racingConditionDebounceTrackFocus(import_constants.MENU_FOCUS_REGIONS.ITEM_BY_DSID(newFocusNode.dsId), newFocusNode);
|
125
135
|
},
|
126
|
-
[
|
136
|
+
[racingConditionDebounceTrackFocus]
|
127
137
|
);
|
128
138
|
const trackFocusParentItem = import_react.default.useCallback(
|
129
139
|
(itemNode) => {
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../../../src/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.ts", "../../../../../../../../scripts/build/transpile/react-shim.js"],
|
4
|
-
"sourcesContent": ["/* eslint-disable no-console */\n/* eslint-disable max-lines */\n/* eslint-disable max-statements */\n/* eslint-disable complexity */\nimport React from 'react';\nimport type { DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport {\n isFocusableNode,\n isGroup,\n isMenuNodeAllowedToHaveChildren,\n isRootNode,\n} from '../../../utils/nodesTypeguardsAndGetters.js';\nimport { TREE_STRUCTURE_ERRORS } from '../constants/Errors.js';\nimport { MENU_FOCUS_REGIONS } from '../constants/index.js';\nimport { getFocusableSiblingsList } from '../utils/nodeGettersByCriterias.js';\n\ntype MenuFocusRegionsValues = (typeof MENU_FOCUS_REGIONS)[keyof typeof MENU_FOCUS_REGIONS];\n// if MenuFocusRegionsValues may be a string or a function that returns a string, we want only the resolved strings\ntype ValidRegionsValues<T extends MenuFocusRegionsValues = MenuFocusRegionsValues> = T extends string\n ? T\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends (...args: any) => any\n ? ReturnType<T>\n : never;\n\nexport const useFocusTracker = () => {\n const [focusRegion, setFocusRegion] = React.useState<ValidRegionsValues>('');\n // we want to keep the focus region trackers as stable as possible to avoid unnecessary re-renders\n // there is no need to change the trackers reference when the focus region changes,\n // since changing the focus region is always triggered by a final user interaction (so after reacts reconciliation)\n const focusedRegionPerformanceHelper = React.useRef('') as React.MutableRefObject<ValidRegionsValues>;\n const preventBlurReset = React.useRef(false);\n\n const focusedElementItemNode = React.useRef(\n null,\n ) as React.MutableRefObject<DSMenuButtonT.PseudoFocusableMenuNodes | null>;\n const
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADIvB,mBAAkB;AAElB,uCAKO;AACP,oBAAsC;AACtC,uBAAmC;AACnC,oCAAyC;AAWlC,MAAM,kBAAkB,MAAM;AACnC,QAAM,CAAC,aAAa,cAAc,IAAI,aAAAA,QAAM,SAA6B,EAAE;AAI3E,QAAM,iCAAiC,aAAAA,QAAM,OAAO,EAAE;AACtD,QAAM,mBAAmB,aAAAA,QAAM,OAAO,KAAK;AAE3C,QAAM,yBAAyB,aAAAA,QAAM;AAAA,IACnC;AAAA,EACF;
|
4
|
+
"sourcesContent": ["/* eslint-disable no-console */\n/* eslint-disable max-lines */\n/* eslint-disable max-statements */\n/* eslint-disable complexity */\nimport { throttle } from 'lodash';\nimport React from 'react';\nimport type { DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport {\n isFocusableNode,\n isGroup,\n isMenuNodeAllowedToHaveChildren,\n isRootNode,\n} from '../../../utils/nodesTypeguardsAndGetters.js';\nimport { TREE_STRUCTURE_ERRORS } from '../constants/Errors.js';\nimport { MENU_FOCUS_REGIONS } from '../constants/index.js';\nimport { getFocusableSiblingsList } from '../utils/nodeGettersByCriterias.js';\n\ntype MenuFocusRegionsValues = (typeof MENU_FOCUS_REGIONS)[keyof typeof MENU_FOCUS_REGIONS];\n// if MenuFocusRegionsValues may be a string or a function that returns a string, we want only the resolved strings\ntype ValidRegionsValues<T extends MenuFocusRegionsValues = MenuFocusRegionsValues> = T extends string\n ? T\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends (...args: any) => any\n ? ReturnType<T>\n : never;\n\nexport const useFocusTracker = () => {\n const [focusRegion, setFocusRegion] = React.useState<ValidRegionsValues>('');\n // we want to keep the focus region trackers as stable as possible to avoid unnecessary re-renders\n // there is no need to change the trackers reference when the focus region changes,\n // since changing the focus region is always triggered by a final user interaction (so after reacts reconciliation)\n const focusedRegionPerformanceHelper = React.useRef('') as React.MutableRefObject<ValidRegionsValues>;\n const preventBlurReset = React.useRef(false);\n\n const focusedElementItemNode = React.useRef(\n null,\n ) as React.MutableRefObject<DSMenuButtonT.PseudoFocusableMenuNodes | null>;\n\n // typescript with debounce doesn't work well, so we need to disable the exhaustive deps rule here\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const racingConditionDebounceTrackFocus = React.useCallback(\n throttle(\n (newFocusRegion: ValidRegionsValues, focusNode: DSMenuButtonT.PseudoFocusableMenuNodes | null) => {\n setFocusRegion(newFocusRegion);\n focusedRegionPerformanceHelper.current = newFocusRegion;\n focusedElementItemNode.current = focusNode;\n\n return focusNode;\n },\n 50,\n { leading: true, trailing: true },\n ),\n [],\n );\n\n const trackFocusTrigger = React.useCallback(\n () => racingConditionDebounceTrackFocus(MENU_FOCUS_REGIONS.TRIGGER, null),\n [racingConditionDebounceTrackFocus],\n );\n\n const trackFocusNode = React.useCallback(\n (nodeToFocus: DSMenuButtonT.PseudoFocusableMenuNodes) => {\n const newFocusRegion = MENU_FOCUS_REGIONS.ITEM_BY_DSID(nodeToFocus.dsId);\n racingConditionDebounceTrackFocus(newFocusRegion, nodeToFocus);\n },\n [racingConditionDebounceTrackFocus],\n );\n\n const trackFocusRegionReset = React.useCallback(\n () => racingConditionDebounceTrackFocus(MENU_FOCUS_REGIONS.RESET, null),\n [racingConditionDebounceTrackFocus],\n );\n\n const trackFocusFirstChildItem = React.useCallback(\n (itemNode: DSMenuButtonT.PseudoFocusableMenuNodes) => {\n if (!isMenuNodeAllowedToHaveChildren(itemNode)) {\n console.log('focus first child item > itemNode', itemNode);\n throw TREE_STRUCTURE_ERRORS.NODE_CANNOT_HAVE_CHILDREN;\n }\n if (itemNode.children.length === 0) {\n console.log(itemNode);\n throw new Error('No children found in the item node');\n }\n const focusableChildrenNodes = getFocusableSiblingsList(itemNode.children[0]);\n if (focusableChildrenNodes.length === 0) {\n console.log('focus first child item > itemNode', itemNode);\n throw new Error('No focusable nodes found in the children of the item node');\n }\n\n const newFocusedNode = focusableChildrenNodes[0];\n return racingConditionDebounceTrackFocus(MENU_FOCUS_REGIONS.ITEM_BY_DSID(newFocusedNode.dsId), newFocusedNode);\n },\n [racingConditionDebounceTrackFocus],\n );\n\n const trackFocusLastChildItem = React.useCallback(\n (itemNode: DSMenuButtonT.PseudoFocusableMenuNodes) => {\n if (!isMenuNodeAllowedToHaveChildren(itemNode)) {\n console.log('focus last child item > itemNode', itemNode);\n throw new Error('Item node is not allowed to have children');\n }\n if (itemNode.children.length === 0) {\n console.log(itemNode);\n throw new Error('No children found in the item node');\n }\n const focusableChildrenNodes = getFocusableSiblingsList(itemNode.children[0]);\n if (focusableChildrenNodes.length === 0) {\n console.log('focus last child item > itemNode', itemNode);\n throw new Error('No focusable nodes found in the children of the item node');\n }\n return racingConditionDebounceTrackFocus(\n MENU_FOCUS_REGIONS.ITEM_BY_DSID(focusableChildrenNodes[focusableChildrenNodes.length - 1].dsId),\n focusableChildrenNodes[focusableChildrenNodes.length - 1],\n );\n },\n [racingConditionDebounceTrackFocus],\n );\n\n const trackFocusNextItem = React.useCallback(\n (itemNode: DSMenuButtonT.PseudoFocusableMenuNodes) => {\n const focusableSiblingsNodes = getFocusableSiblingsList(itemNode);\n // we find the current item node index in the focusableSiblingsNodes array\n const currIndex = focusableSiblingsNodes.findIndex((node) => node.dsId === itemNode.dsId);\n\n const nextIndex = currIndex + 1 < focusableSiblingsNodes.length ? currIndex + 1 : 0;\n const newFocusedNode = focusableSiblingsNodes[nextIndex];\n return racingConditionDebounceTrackFocus(MENU_FOCUS_REGIONS.ITEM_BY_DSID(newFocusedNode.dsId), newFocusedNode);\n },\n [racingConditionDebounceTrackFocus],\n );\n\n const trackFocusPreviousItem = React.useCallback(\n (itemNode: DSMenuButtonT.PseudoFocusableMenuNodes) => {\n const focusableSiblingsNodes = getFocusableSiblingsList(itemNode);\n // we find the current item node index in the focusableSiblingsNodes array\n const currIndex = focusableSiblingsNodes.findIndex((node) => node.dsId === itemNode.dsId);\n\n const previousIndex = currIndex - 1 >= 0 ? currIndex - 1 : focusableSiblingsNodes.length - 1;\n const newFocusNode = focusableSiblingsNodes[previousIndex];\n return racingConditionDebounceTrackFocus(MENU_FOCUS_REGIONS.ITEM_BY_DSID(newFocusNode.dsId), newFocusNode);\n },\n [racingConditionDebounceTrackFocus],\n );\n\n const trackFocusParentItem = React.useCallback(\n (itemNode: DSMenuButtonT.PseudoFocusableMenuNodes) => {\n const { parent } = itemNode;\n // this typecast is required because we are reading the parent property from the itemNode\n // while this function can receive any PseudoFocusableMenuNodes,\n // the parent property may be a non-pseudo focusable node (specifically when the parent property is group node)\n const parentNode = parent;\n if (!parentNode) {\n console.log('focus parent item', { itemNode, parentNode });\n throw new Error(`No parent node found for the item node`);\n }\n\n let nodeToFocus: DSMenuButtonT.PseudoFocusableMenuNodes | null = parentNode;\n // if parent is SingleSelectGroupNode then we can't focus it\n if (isGroup(parentNode)) {\n const groupParent = parentNode.parent;\n if (!isFocusableNode(groupParent) && !isRootNode(groupParent)) {\n console.log('focus parent item', { itemNode, parentNode, groupParent });\n throw new Error('No focusable parent node found for the item node');\n }\n nodeToFocus = groupParent;\n }\n\n const focusableNode = isRootNode(nodeToFocus) ? null : nodeToFocus;\n const newFocusNode = focusableNode;\n if (!newFocusNode) trackFocusTrigger();\n else trackFocusNode(newFocusNode);\n\n return focusableNode;\n },\n [trackFocusNode, trackFocusTrigger],\n );\n\n return React.useMemo(\n () => ({\n preventBlurReset,\n focusRegion,\n focusedElementItemNode,\n trackFocusTrigger,\n trackFocusNode,\n trackFocusRegionReset,\n trackFocusFirstChildItem,\n trackFocusLastChildItem,\n trackFocusNextItem,\n trackFocusPreviousItem,\n trackFocusParentItem,\n }),\n [\n focusRegion,\n trackFocusFirstChildItem,\n trackFocusLastChildItem,\n trackFocusNextItem,\n trackFocusNode,\n trackFocusParentItem,\n trackFocusPreviousItem,\n trackFocusRegionReset,\n trackFocusTrigger,\n ],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
5
|
+
"mappings": "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",
|
6
6
|
"names": ["React"]
|
7
7
|
}
|