@elliemae/ds-menu-button 3.46.0-rc.1 → 3.46.0-rc.11
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 +10 -19
- 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/index.js +2 -0
- package/dist/cjs/index.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 +86 -0
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js.map +7 -0
- 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 +2 -0
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js.map +2 -2
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js +77 -33
- package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js.map +2 -2
- 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 +13 -9
- package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js +13 -9
- package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.js +10 -9
- package/dist/cjs/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js +15 -11
- package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js +18 -12
- package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js +15 -11
- package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js +15 -11
- package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js.map +2 -2
- package/dist/cjs/parts/DSMenuItemRendererFactory/SkeletonMenuItem.js +112 -0
- package/dist/cjs/parts/DSMenuItemRendererFactory/SkeletonMenuItem.js.map +7 -0
- package/dist/cjs/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js +13 -9
- 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 +16 -15
- 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 +11 -20
- 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/index.js +2 -0
- package/dist/esm/index.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 +56 -0
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js.map +7 -0
- 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 +2 -0
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js.map +2 -2
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js +77 -33
- package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js.map +2 -2
- 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 +13 -9
- package/dist/esm/parts/DSMenuItemRendererFactory/ActivableMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js +13 -9
- package/dist/esm/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.js +19 -18
- package/dist/esm/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js +15 -11
- package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js +18 -12
- package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js +15 -11
- package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js +15 -11
- package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js.map +2 -2
- package/dist/esm/parts/DSMenuItemRendererFactory/SkeletonMenuItem.js +82 -0
- package/dist/esm/parts/DSMenuItemRendererFactory/SkeletonMenuItem.js.map +7 -0
- package/dist/esm/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js +13 -9
- 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 +16 -15
- 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 +8 -9
- package/dist/types/index.d.ts +1 -1
- package/dist/types/parts/DSFlyoutMenu/react-desc-prop-types.d.ts +1 -1
- package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.d.ts +6 -0
- package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.d.ts +6 -6
- package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.d.ts +2 -1
- 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/SkeletonMenuItem.d.ts +5 -0
- 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/config/useOpinionatedButton.d.ts +1 -1
- package/dist/types/parts/DSOpinionatedButton/react-desc-prop-types.d.ts +1 -1
- package/dist/types/react-desc-prop-types.d.ts +23 -17
- package/dist/types/utils/nodesTypeguardsAndGetters.d.ts +113 -1
- package/dist/types/utils/useOptionsArrayToDsTree.d.ts +2 -1
- package/package.json +12 -13
|
@@ -34,21 +34,28 @@ module.exports = __toCommonJS(useOptionsArrayToDsTree_exports);
|
|
|
34
34
|
var React = __toESM(require("react"));
|
|
35
35
|
var import_react = __toESM(require("react"));
|
|
36
36
|
var import_ds_tree_model = require("@elliemae/ds-tree-model");
|
|
37
|
+
var import_react_desc_prop_types = require("../react-desc-prop-types.js");
|
|
37
38
|
const useDsTreeOpts = {
|
|
38
39
|
getUniqueId: (item) => item.dsId
|
|
39
40
|
};
|
|
40
|
-
const useOptionsArrayToDsTree = ({
|
|
41
|
+
const useOptionsArrayToDsTree = ({
|
|
42
|
+
options,
|
|
43
|
+
instanceUid,
|
|
44
|
+
propsWithDefault
|
|
45
|
+
}) => {
|
|
46
|
+
const { maxHeight } = propsWithDefault || import_react_desc_prop_types.menuSpecificDefaultProps;
|
|
41
47
|
const rootNode = import_react.default.useMemo(
|
|
42
48
|
() => ({
|
|
43
49
|
dsId: `root-${instanceUid}`,
|
|
44
50
|
type: "ROOT_ITEM",
|
|
45
|
-
subitems: options
|
|
51
|
+
subitems: options,
|
|
52
|
+
maxHeight
|
|
46
53
|
// as unknown as RootNodeType is because currently
|
|
47
54
|
// the DS tree model doesn't support the type of the root node being different from the subitems
|
|
48
55
|
// in practice, this is fine because the root node is never rendered & the subitems are the only thing that matters
|
|
49
56
|
// will be addresssed via PUI-XXXX
|
|
50
57
|
}),
|
|
51
|
-
[instanceUid, options]
|
|
58
|
+
[instanceUid, maxHeight, options]
|
|
52
59
|
);
|
|
53
60
|
return (0, import_ds_tree_model.useDSTree)(rootNode, useDsTreeOpts);
|
|
54
61
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/utils/useOptionsArrayToDsTree.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["import React from 'react';\nimport { useDSTree } from '@elliemae/ds-tree-model';\nimport type { UseDSTreeT } from '@elliemae/ds-tree-model';\nimport { type DSMenuButtonT } from '../react-desc-prop-types.js';\n\nconst useDsTreeOpts: UseDSTreeT.SecondParameter<DSMenuButtonT.MenuItemInterface> = {\n getUniqueId: (item) => item.dsId,\n};\n\ntype UseOptionsArrayToDsTreeRootNodeConfig = {\n options: DSMenuButtonT.MenuItemInterface[];\n instanceUid: string;\n};\n\ntype RootNodeType = UseDSTreeT.Item<DSMenuButtonT.MenuItemInterface>;\n\nexport const useOptionsArrayToDsTree = ({
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,mBAAkB;AAClB,2BAA0B;
|
|
4
|
+
"sourcesContent": ["import React from 'react';\nimport { useDSTree } from '@elliemae/ds-tree-model';\nimport type { UseDSTreeT } from '@elliemae/ds-tree-model';\nimport { type DSMenuButtonT, menuSpecificDefaultProps } from '../react-desc-prop-types.js';\n\nconst useDsTreeOpts: UseDSTreeT.SecondParameter<DSMenuButtonT.MenuItemInterface> = {\n getUniqueId: (item) => item.dsId,\n};\n\ntype UseOptionsArrayToDsTreeRootNodeConfig = {\n options: DSMenuButtonT.MenuItemInterface[];\n instanceUid: string;\n propsWithDefault?: DSMenuButtonT.MenuSpecifiDefaultProps;\n};\n\ntype RootNodeType = UseDSTreeT.Item<DSMenuButtonT.MenuItemInterface>;\n\nexport const useOptionsArrayToDsTree = ({\n options,\n instanceUid,\n propsWithDefault,\n}: UseOptionsArrayToDsTreeRootNodeConfig) => {\n const { maxHeight } = propsWithDefault || menuSpecificDefaultProps;\n // we need to create the root node that the app dev doesn't need to worry about\n const rootNode = React.useMemo<RootNodeType>(\n () =>\n ({\n dsId: `root-${instanceUid}`,\n type: 'ROOT_ITEM',\n subitems: options,\n maxHeight,\n // as unknown as RootNodeType is because currently\n // the DS tree model doesn't support the type of the root node being different from the subitems\n // in practice, this is fine because the root node is never rendered & the subitems are the only thing that matters\n // will be addresssed via PUI-XXXX\n }) as unknown as RootNodeType,\n [instanceUid, maxHeight, options],\n );\n return useDSTree<DSMenuButtonT.MenuItemInterface>(rootNode, useDsTreeOpts);\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,mBAAkB;AAClB,2BAA0B;AAE1B,mCAA6D;AAE7D,MAAM,gBAA6E;AAAA,EACjF,aAAa,CAAC,SAAS,KAAK;AAC9B;AAUO,MAAM,0BAA0B,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AACF,MAA6C;AAC3C,QAAM,EAAE,UAAU,IAAI,oBAAoB;AAE1C,QAAM,WAAW,aAAAA,QAAM;AAAA,IACrB,OACG;AAAA,MACC,MAAM,QAAQ,WAAW;AAAA,MACzB,MAAM;AAAA,MACN,UAAU;AAAA,MACV;AAAA;AAAA;AAAA;AAAA;AAAA,IAKF;AAAA,IACF,CAAC,aAAa,WAAW,OAAO;AAAA,EAClC;AACA,aAAO,gCAA2C,UAAU,aAAa;AAC3E;",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import React2 from "react";
|
|
3
2
|
import { useGetXstyledProps, useMemoMergePropsWithDefault } from "@elliemae/ds-props-helpers";
|
|
3
|
+
import React2 from "react";
|
|
4
4
|
import { uid } from "uid";
|
|
5
|
-
import { DSMenuButtonPropTypes,
|
|
6
|
-
import { useValidateProps } from "./useValidateProps.js";
|
|
7
|
-
import { useSplitInherithedProps } from "./useSplitInherithedProps.js";
|
|
8
|
-
import { useOptionsArrayToDsTree } from "../utils/useOptionsArrayToDsTree.js";
|
|
5
|
+
import { DSMenuButtonPropTypes, menuSpecificDefaultProps } from "../react-desc-prop-types.js";
|
|
9
6
|
import { getFocusableNodes } from "../utils/nodesTypeguardsAndGetters.js";
|
|
7
|
+
import { useOptionsArrayToDsTree } from "../utils/useOptionsArrayToDsTree.js";
|
|
8
|
+
import { useSplitInherithedProps } from "./useSplitInherithedProps.js";
|
|
9
|
+
import { useValidateProps } from "./useValidateProps.js";
|
|
10
10
|
const useMenuButton = (propsFromUser) => {
|
|
11
|
-
const propsWithDefault = useMemoMergePropsWithDefault(
|
|
11
|
+
const propsWithDefault = useMemoMergePropsWithDefault(
|
|
12
|
+
propsFromUser,
|
|
13
|
+
menuSpecificDefaultProps
|
|
14
|
+
);
|
|
12
15
|
useValidateProps(propsWithDefault, DSMenuButtonPropTypes);
|
|
13
16
|
const xstyledProps = useGetXstyledProps(propsWithDefault);
|
|
14
17
|
const instanceUid = React2.useMemo(() => `menu-button${uid(5)}`, []);
|
|
@@ -16,7 +19,8 @@ const useMenuButton = (propsFromUser) => {
|
|
|
16
19
|
const optionsArray = Array.isArray(appOptions) ? appOptions : [];
|
|
17
20
|
const treeRootNodeFromOptionsArrayIfArray = useOptionsArrayToDsTree({
|
|
18
21
|
options: optionsArray,
|
|
19
|
-
instanceUid
|
|
22
|
+
instanceUid,
|
|
23
|
+
propsWithDefault
|
|
20
24
|
// this typecast is a safe type reconciliation, typescript checks they are compatible
|
|
21
25
|
// this typecast let us avoid to have to do the ` | OtherCompatibleType` dance
|
|
22
26
|
}).getRoot();
|
|
@@ -30,19 +34,6 @@ const useMenuButton = (propsFromUser) => {
|
|
|
30
34
|
focusableNodes,
|
|
31
35
|
treeRootNode
|
|
32
36
|
});
|
|
33
|
-
const allNodes = treeRootNode.flatten();
|
|
34
|
-
const nodesWithRepeatedDsId = allNodes.filter(
|
|
35
|
-
(node, index, self) => self.findIndex((n) => n.dsId === node.dsId) !== index
|
|
36
|
-
);
|
|
37
|
-
if (nodesWithRepeatedDsId.length > 0) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`DSMenuButton:
|
|
40
|
-
The following dsId are repeated:
|
|
41
|
-
${nodesWithRepeatedDsId.map((n) => n.dsId).join("\n ")}
|
|
42
|
-
|
|
43
|
-
The dsId must be unique.`
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
37
|
return React2.useMemo(
|
|
47
38
|
() => ({
|
|
48
39
|
propsWithDefault,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/config/useMenuButton.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* 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"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,oBAAoB,oCAAoC;AACjE,OAAOA,YAAW;AAClB,SAAS,WAAW;AACpB,SAAS,uBAAuB,gCAAoD;AACpF,SAAS,yBAAyB;AAClC,SAAS,+BAA+B;AACxC,SAAS,+BAA+B;AACxC,SAAS,wBAAwB;AAO1B,MAAM,gBAAgB,CAAC,kBAAuC;AAInE,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA;AAAA,EACF;AACA,mBAAiB,kBAAkB,qBAAqB;AAIxD,QAAM,eAAe,mBAAmB,gBAAgB;AAKxD,QAAM,cAAcA,OAAM,QAAQ,MAAM,cAAc,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAYlE,QAAM,EAAE,SAAS,WAAW,IAAI;AAChC,QAAM,eAAkD,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC;AAElG,QAAM,sCAAsC,wBAAwB;AAAA,IAClE,SAAS;AAAA,IACT;AAAA,IACA;AAAA;AAAA;AAAA,EAGF,CAAC,EAAE,QAAQ;AACX,QAAM,eAAeA,OAAM;AAAA,IACzB,MAAO,MAAM,QAAQ,UAAU,IAAI,sCAAsC;AAAA,IACzE,CAAC,YAAY,mCAAmC;AAAA,EAClD;AAKA,QAAM,iBAAiBA,OAAM,QAAQ,MAAM,kBAAkB,YAAY,GAAG,CAAC,YAAY,CAAC;AAC1F,QAAM,uBAAuB,wBAAwB;AAAA,IACnD;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAOA,OAAM;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
|
}
|
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import React2 from "react";
|
|
3
|
+
import { isSelectionableNode, isObjectAMenuNode } from "../utils/nodesTypeguardsAndGetters.js";
|
|
3
4
|
import { resolveRef } from "../utils/resolveRef.js";
|
|
5
|
+
const convertSelectedOptionsToNodes = (selectedItems, treeRootNode) => {
|
|
6
|
+
const convertedSelection = [];
|
|
7
|
+
selectedItems.forEach((selectedItem) => {
|
|
8
|
+
const needsConversion = !isObjectAMenuNode(selectedItem);
|
|
9
|
+
if (!needsConversion) {
|
|
10
|
+
convertedSelection.push(selectedItem);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const { dsId } = selectedItem;
|
|
14
|
+
const selectedNode = treeRootNode.findNode((node) => node.dsId === dsId);
|
|
15
|
+
if (!selectedNode) {
|
|
16
|
+
throw new Error(`Selected option with dsId ${dsId} not found in the menu tree.`);
|
|
17
|
+
}
|
|
18
|
+
if (!isSelectionableNode(selectedNode)) {
|
|
19
|
+
console.warn(`Selected option with dsId ${dsId} is not a selectionable node and will be ignored.`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
convertedSelection.push(selectedNode);
|
|
23
|
+
});
|
|
24
|
+
return convertedSelection;
|
|
25
|
+
};
|
|
4
26
|
const useSplitInherithedProps = ({
|
|
5
27
|
propsWithDefault,
|
|
6
28
|
focusableNodes,
|
|
@@ -15,7 +37,6 @@ const useSplitInherithedProps = ({
|
|
|
15
37
|
onSubmenuToggle,
|
|
16
38
|
isLoading,
|
|
17
39
|
isSkeleton,
|
|
18
|
-
selectedOptions,
|
|
19
40
|
ItemRenderer,
|
|
20
41
|
innerRef,
|
|
21
42
|
selectedItems,
|
|
@@ -24,6 +45,8 @@ const useSplitInherithedProps = ({
|
|
|
24
45
|
onActivateItem,
|
|
25
46
|
onOpen,
|
|
26
47
|
onClose,
|
|
48
|
+
maxHeight,
|
|
49
|
+
// 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
|
|
27
50
|
...buttonInheritedProps
|
|
28
51
|
} = propsWithDefault;
|
|
29
52
|
const innerRefSnatchingNode = React2.useCallback(
|
|
@@ -35,6 +58,12 @@ const useSplitInherithedProps = ({
|
|
|
35
58
|
},
|
|
36
59
|
[innerRef]
|
|
37
60
|
);
|
|
61
|
+
const selectedNodesMap = React2.useMemo(() => {
|
|
62
|
+
if (selectedItems) {
|
|
63
|
+
return convertSelectedOptionsToNodes(selectedItems, treeRootNode);
|
|
64
|
+
}
|
|
65
|
+
return [];
|
|
66
|
+
}, [selectedItems, treeRootNode]);
|
|
38
67
|
const menuSpecificProps = React2.useMemo(
|
|
39
68
|
() => ({
|
|
40
69
|
options,
|
|
@@ -44,26 +73,15 @@ const useSplitInherithedProps = ({
|
|
|
44
73
|
onSubmenuToggle,
|
|
45
74
|
isLoading,
|
|
46
75
|
isSkeleton,
|
|
47
|
-
selectedOptions,
|
|
48
76
|
ItemRenderer
|
|
49
77
|
}),
|
|
50
|
-
[
|
|
51
|
-
options,
|
|
52
|
-
onClickOutside,
|
|
53
|
-
onOptionClick,
|
|
54
|
-
openedSubmenus,
|
|
55
|
-
onSubmenuToggle,
|
|
56
|
-
isLoading,
|
|
57
|
-
isSkeleton,
|
|
58
|
-
selectedOptions,
|
|
59
|
-
ItemRenderer
|
|
60
|
-
]
|
|
78
|
+
[options, onClickOutside, onOptionClick, openedSubmenus, onSubmenuToggle, isLoading, isSkeleton, ItemRenderer]
|
|
61
79
|
);
|
|
62
80
|
return React2.useMemo(
|
|
63
81
|
() => ({
|
|
64
82
|
menuBehaviouralLayerProps: {
|
|
65
83
|
buttonDOMNodeRef,
|
|
66
|
-
|
|
84
|
+
selectedNodes: selectedNodesMap,
|
|
67
85
|
focusableNodes,
|
|
68
86
|
optionsTree: treeRootNode,
|
|
69
87
|
onDisplayedSubmenuChange,
|
|
@@ -79,7 +97,7 @@ const useSplitInherithedProps = ({
|
|
|
79
97
|
}
|
|
80
98
|
}),
|
|
81
99
|
[
|
|
82
|
-
|
|
100
|
+
selectedNodesMap,
|
|
83
101
|
focusableNodes,
|
|
84
102
|
treeRootNode,
|
|
85
103
|
onDisplayedSubmenuChange,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/config/useSplitInherithedProps.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* *******************************************************\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,YAAY,WAAW;ACqBvB,OAAOA,YAAW;AAElB,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* *******************************************************\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"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACqBvB,OAAOA,YAAW;AAElB,SAAS,qBAAqB,yBAAyB;AACvD,SAAS,kBAAkB;AAS3B,MAAM,gCAAgC,CACpC,eACA,iBAC2C;AAC3C,QAAM,qBAA6D,CAAC;AAEpE,gBAAc,QAAQ,CAAC,iBAAiB;AACtC,UAAM,kBAAkB,CAAC,kBAAkB,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,CAAC,oBAAoB,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,mBAAmBA,OAAM,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,wBAAmEA,OAAM;AAAA,IAC7E,CAAC,SAA4B;AAC3B,uBAAiB,UAAU;AAC3B,UAAI,UAAU;AACZ,mBAAW,UAAU,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAIA,QAAM,mBAAmBA,OAAM,QAAQ,MAAM;AAC3C,QAAI,eAAe;AACjB,aAAO,8BAA8B,eAAe,YAAY;AAAA,IAClE;AACA,WAAO,CAAC;AAAA,EACV,GAAG,CAAC,eAAe,YAAY,CAAC;AAEhC,QAAM,oBAAoBA,OAAM;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,SAAOA,OAAM;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
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { DSMenuButton, DSMenuButtonWithSchema } from "./DSMenuButton.js";
|
|
3
|
+
import { DSMenuButtonPropTypes } from "./react-desc-prop-types.js";
|
|
3
4
|
import { MENU_BUTTON_SLOTS, MENU_BUTTON_DATA_TESTID, MENU_ITEMS_TYPES } from "./constants/index.js";
|
|
4
5
|
import { isFocusableNode } from "./utils/nodesTypeguardsAndGetters.js";
|
|
5
6
|
import { useOptionsArrayToDsTree } from "./utils/useOptionsArrayToDsTree.js";
|
|
6
7
|
export {
|
|
7
8
|
DSMenuButton,
|
|
9
|
+
DSMenuButtonPropTypes,
|
|
8
10
|
DSMenuButtonWithSchema,
|
|
9
11
|
MENU_BUTTON_DATA_TESTID,
|
|
10
12
|
MENU_BUTTON_SLOTS,
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "// this is a workaround to typescript error TS2742\n// https://github.com/microsoft/TypeScript/issues/47663\nimport type {} from '@xstyled/system';\nexport { DSMenuButton, DSMenuButtonWithSchema } from './DSMenuButton.js';\nexport { type DSMenuButtonT } from './react-desc-prop-types.js';\nexport { MENU_BUTTON_SLOTS, MENU_BUTTON_DATA_TESTID, MENU_ITEMS_TYPES } from './constants/index.js';\nexport { isFocusableNode } from './utils/nodesTypeguardsAndGetters.js';\nexport { useOptionsArrayToDsTree } from './utils/useOptionsArrayToDsTree.js';\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACGvB,SAAS,cAAc,8BAA8B;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "// this is a workaround to typescript error TS2742\n// https://github.com/microsoft/TypeScript/issues/47663\nimport type {} from '@xstyled/system';\nexport { DSMenuButton, DSMenuButtonWithSchema } from './DSMenuButton.js';\nexport { type DSMenuButtonT, DSMenuButtonPropTypes } from './react-desc-prop-types.js';\nexport { MENU_BUTTON_SLOTS, MENU_BUTTON_DATA_TESTID, MENU_ITEMS_TYPES } from './constants/index.js';\nexport { isFocusableNode } from './utils/nodesTypeguardsAndGetters.js';\nexport { useOptionsArrayToDsTree } from './utils/useOptionsArrayToDsTree.js';\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACGvB,SAAS,cAAc,8BAA8B;AACrD,SAA6B,6BAA6B;AAC1D,SAAS,mBAAmB,yBAAyB,wBAAwB;AAC7E,SAAS,uBAAuB;AAChC,SAAS,+BAA+B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,28 +5,36 @@ import { Grid } from "@elliemae/ds-grid";
|
|
|
5
5
|
import { describe } from "@elliemae/ds-props-helpers";
|
|
6
6
|
import { styled, xStyledCommonProps } from "@elliemae/ds-system";
|
|
7
7
|
import React2 from "react";
|
|
8
|
+
import { menuSpecificDefaultProps } from "../../react-desc-prop-types.js";
|
|
8
9
|
import { MenuBehaviouralContextProviderContext } from "../DSMenuBehaviouralContextProvider/MenuBehaviouralContextProviderCTX.js";
|
|
9
10
|
import { DSMenuItemRendererFactory } from "../DSMenuItemRendererFactory/index.js";
|
|
10
11
|
import { useFlyoutMenu } from "./config/useFlyoutMenu.js";
|
|
11
12
|
import { DSFlyoutMenuName, FLYOUT_MENU_SLOTS } from "./constants/index.js";
|
|
12
13
|
import { DSFlyoutMenuPropTypesSchema } from "./react-desc-prop-types.js";
|
|
13
14
|
import { isRootNode } from "../../utils/nodesTypeguardsAndGetters.js";
|
|
14
|
-
const StyledWrapper = styled(Grid, {
|
|
15
|
-
|
|
15
|
+
const StyledWrapper = styled(Grid, {
|
|
16
|
+
name: DSFlyoutMenuName,
|
|
17
|
+
slot: FLYOUT_MENU_SLOTS.ROOT
|
|
18
|
+
})`
|
|
19
|
+
min-width: 1px;
|
|
16
20
|
background-color: white;
|
|
17
21
|
padding: ${({ theme }) => theme.space.xxxs} 0;
|
|
18
22
|
${xStyledCommonProps}
|
|
19
23
|
`;
|
|
20
24
|
const StyledMenu = styled("div", { name: DSFlyoutMenuName, slot: FLYOUT_MENU_SLOTS.LIST_WRAPPER })`
|
|
25
|
+
max-height: ${({ $maxHeight }) => typeof $maxHeight === "number" ? `${$maxHeight}px` : $maxHeight};
|
|
26
|
+
overflow-y: auto;
|
|
21
27
|
padding: 0;
|
|
22
28
|
margin: 0;
|
|
23
29
|
`;
|
|
30
|
+
const NoComponentPlaceholder = () => null;
|
|
24
31
|
const DSFlyoutMenu = (props) => {
|
|
25
32
|
const { propsWithDefault, xstyledProps } = useFlyoutMenu(props);
|
|
26
33
|
const {
|
|
27
34
|
instanceUid,
|
|
28
35
|
globalEventsHelpers: { mainMenuRef, handleSubmenusRefChange }
|
|
29
36
|
} = React2.useContext(MenuBehaviouralContextProviderContext);
|
|
37
|
+
const [didAnimationEnd, setDidAnimationEnd] = React2.useState(false);
|
|
30
38
|
const { setFloatingRef, floatingStyles, floatingContext, ItemRenderer, isMenuOpen, itemNode } = propsWithDefault;
|
|
31
39
|
const handleRefChange = React2.useCallback(
|
|
32
40
|
(node) => {
|
|
@@ -38,6 +46,12 @@ const DSFlyoutMenu = (props) => {
|
|
|
38
46
|
},
|
|
39
47
|
[handleSubmenusRefChange, itemNode, mainMenuRef]
|
|
40
48
|
);
|
|
49
|
+
const handleAnimationStartTrigger = React2.useCallback(() => {
|
|
50
|
+
setDidAnimationEnd(false);
|
|
51
|
+
}, []);
|
|
52
|
+
const handleAnimationEnd = React2.useCallback(() => {
|
|
53
|
+
setDidAnimationEnd(true);
|
|
54
|
+
}, []);
|
|
41
55
|
return /* @__PURE__ */ jsx(
|
|
42
56
|
FloatingWrapper,
|
|
43
57
|
{
|
|
@@ -45,15 +59,25 @@ const DSFlyoutMenu = (props) => {
|
|
|
45
59
|
floatingStyles,
|
|
46
60
|
isOpen: isMenuOpen,
|
|
47
61
|
context: floatingContext,
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
onAnimationStartTriggered: handleAnimationStartTrigger,
|
|
63
|
+
onAnimationEnd: handleAnimationEnd,
|
|
64
|
+
children: /* @__PURE__ */ jsx(StyledWrapper, { getOwnerProps: () => propsWithDefault, getOwnerPropsArguments: () => ({}), ...xstyledProps, children: /* @__PURE__ */ jsx(
|
|
65
|
+
StyledMenu,
|
|
50
66
|
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
67
|
+
role: "menu",
|
|
68
|
+
innerRef: handleRefChange,
|
|
69
|
+
$maxHeight: itemNode.plainItem.maxHeight ?? menuSpecificDefaultProps.maxHeight,
|
|
70
|
+
children: itemNode.children.map((optionNode) => /* @__PURE__ */ jsx(
|
|
71
|
+
DSMenuItemRendererFactory,
|
|
72
|
+
{
|
|
73
|
+
itemNode: optionNode,
|
|
74
|
+
ItemRenderer,
|
|
75
|
+
FlyoutMenuCircularDepInject: didAnimationEnd ? DSFlyoutMenu : NoComponentPlaceholder
|
|
76
|
+
},
|
|
77
|
+
`flyout-menu-item-${optionNode.dsId}-${instanceUid}`
|
|
78
|
+
))
|
|
79
|
+
}
|
|
80
|
+
) })
|
|
57
81
|
}
|
|
58
82
|
);
|
|
59
83
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../scripts/build/transpile/react-shim.js", "../../../../src/parts/DSFlyoutMenu/DSFlyoutMenu.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "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,YAAY,WAAW;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "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"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;AC8EX;AA9EZ,SAAS,uBAAuB;AAChC,SAAS,YAAY;AACrB,SAAS,gBAAgB;AACzB,SAAS,QAAQ,0BAA0B;AAC3C,OAAOA,YAAW;AAClB,SAA6B,gCAAgC;AAC7D,SAAS,6CAA6C;AACtD,SAAS,iCAAiC;AAC1C,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,yBAAyB;AACpD,SAAS,mCAAuD;AAChE,SAAS,kBAAkB;AAE3B,MAAM,gBAAgB,OAAO,MAAM;AAAA,EACjC,MAAM;AAAA,EACN,MAAM,kBAAkB;AAC1B,CAAC;AAAA;AAAA;AAAA,aAGY,CAAC,EAAE,MAAM,MAAM,MAAM,MAAM,IAAI;AAAA,IACxC,kBAAkB;AAAA;AAGtB,MAAM,aAAa,OAAO,OAAO,EAAE,MAAM,kBAAkB,MAAM,kBAAkB,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,IAAI,cAAc,KAAK;AAC9D,QAAM;AAAA,IACJ;AAAA,IACA,qBAAqB,EAAE,aAAa,wBAAwB;AAAA,EAC9D,IAAIA,OAAM,WAAW,qCAAqC;AAC1D,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,OAAM,SAAS,KAAK;AAElE,QAAM,EAAE,gBAAgB,gBAAgB,iBAAiB,cAAc,YAAY,SAAS,IAAI;AAEhG,QAAM,kBAAkBA,OAAM;AAAA,IAC5B,CAAC,SAAyB;AACxB,UAAI,WAAW,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,8BAA8BA,OAAM,YAAY,MAAM;AAC1D,uBAAmB,KAAK;AAAA,EAC1B,GAAG,CAAC,CAAC;AACL,QAAM,qBAAqBA,OAAM,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,8BAAC,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,yBAAyB;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,yBAAyB,SAAS,YAAY;AACpD,uBAAuB,YAAY;",
|
|
6
6
|
"names": ["React"]
|
|
7
7
|
}
|
|
@@ -5,10 +5,7 @@ import {
|
|
|
5
5
|
globalAttributesPropTypes,
|
|
6
6
|
xstyledPropTypes
|
|
7
7
|
} from "@elliemae/ds-props-helpers";
|
|
8
|
-
import {
|
|
9
|
-
DSMenuSpecificPropTypes,
|
|
10
|
-
defaultProps as menuSpecificDefaultProps
|
|
11
|
-
} from "../../react-desc-prop-types.js";
|
|
8
|
+
import { DSMenuSpecificPropTypes, menuSpecificDefaultProps } from "../../react-desc-prop-types.js";
|
|
12
9
|
import { DSFlyoutMenuName, FLYOUT_MENU_SLOTS } from "./constants/index.js";
|
|
13
10
|
const defaultProps = { ...menuSpecificDefaultProps };
|
|
14
11
|
const DSFlyoutMenuPropTypes = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../scripts/build/transpile/react-shim.js", "../../../../src/parts/DSFlyoutMenu/react-desc-prop-types.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* 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,YAAY,WAAW;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* 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"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACGvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,yBAAyB,gCAAoD;AACtF,SAAS,kBAAkB,yBAAyB;AAkC7C,MAAM,eAA2C,EAAE,GAAG,yBAAyB;AAE/E,MAAM,wBAAgE;AAAA,EAC3E,UAAU,UAAU,OAAO,YAAY,8CAA8C,EAAE;AAAA,EACvF,gBAAgB,UAAU,KAAK;AAAA,IAC7B;AAAA,EACF,EAAE;AAAA,EACF,gBAAgB,UAAU,OAAO;AAAA,IAC/B;AAAA,EACF,EAAE;AAAA,EACF,iBAAiB,UAAU,OAAO;AAAA,IAChC;AAAA,EACF,EAAE;AAAA;AAAA,EAEF,YAAY,UAAU,KAAK,YAAY,mEAAmE,EACvG;AAAA,EACH,GAAG,yBAAyB,kBAAkB,iBAAiB;AAAA,EAC/D,GAAG;AAAA;AAAA;AAAA,EAGH,GAAG;AAAA,EACH,GAAG;AACL;AAEO,MAAM,8BAA8B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import { isActivableNode, isSelectionableNode } from "../../../utils/nodesTypeguardsAndGetters.js";
|
|
4
|
+
const useAdvancedValidation = ({ propsWithDefault }) => {
|
|
5
|
+
const { onActivateItem, onItemSelected, selectedNodes, optionsTree } = propsWithDefault;
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const allNodes = optionsTree.flatten();
|
|
8
|
+
const nodesByDsId = {};
|
|
9
|
+
const duplicatedIdsNodes = {};
|
|
10
|
+
let hasActivation = false;
|
|
11
|
+
let hasSelection = false;
|
|
12
|
+
let hasDuplicateDsId = false;
|
|
13
|
+
allNodes.forEach((node) => {
|
|
14
|
+
const { dsId } = node;
|
|
15
|
+
if (!Array.isArray(nodesByDsId[dsId])) {
|
|
16
|
+
nodesByDsId[dsId] = [node];
|
|
17
|
+
} else {
|
|
18
|
+
nodesByDsId[dsId].push(node);
|
|
19
|
+
hasDuplicateDsId = true;
|
|
20
|
+
duplicatedIdsNodes[dsId] = nodesByDsId[dsId];
|
|
21
|
+
}
|
|
22
|
+
if (isActivableNode(node)) {
|
|
23
|
+
hasActivation = true;
|
|
24
|
+
}
|
|
25
|
+
if (isSelectionableNode(node)) {
|
|
26
|
+
hasSelection = true;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
if (hasDuplicateDsId) {
|
|
30
|
+
console.log("duplicatedIdsNodes", duplicatedIdsNodes);
|
|
31
|
+
throw new Error(
|
|
32
|
+
`DSMenuButton:
|
|
33
|
+
The following dsId are repeated:
|
|
34
|
+
${Object.keys(duplicatedIdsNodes).join(
|
|
35
|
+
"\n"
|
|
36
|
+
)}
|
|
37
|
+
|
|
38
|
+
The dsId must be unique.`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (hasActivation && !onActivateItem) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
"DSMenuButton:\nSome items are activable, but onActivateItem is not provided.\n\nYou must provide onActivateItem to handle activation."
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (hasSelection && (!onItemSelected || !selectedNodes)) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
"DSMenuButton:\nSome items are selectionable, but onItemSelected or selectedNodes are not provided.\n\nYou must provide onItemSelected and selectedNodes to handle selection."
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}, [onActivateItem, onItemSelected, selectedNodes, optionsTree]);
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
useAdvancedValidation
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=useAdvancedValidation.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.ts"],
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "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"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,iBAAiB;AAG1B,SAAS,iBAAiB,2BAA2B;AAK9C,MAAM,wBAAwB,CAAC,EAAE,iBAAiB,MAA0C;AACjG,QAAM,EAAE,gBAAgB,gBAAgB,eAAe,YAAY,IAAI;AAcvE,YAAU,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,UAAI,gBAAgB,IAAI,GAAG;AACzB,wBAAgB;AAAA,MAClB;AACA,UAAI,oBAAoB,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
|
+
"names": []
|
|
7
|
+
}
|