@elliemae/ds-menu-button 3.46.0-rc.1 → 3.46.0-rc.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. package/dist/cjs/config/useMenuButton.js +4 -17
  2. package/dist/cjs/config/useMenuButton.js.map +2 -2
  3. package/dist/cjs/config/useSplitInherithedProps.js +31 -15
  4. package/dist/cjs/config/useSplitInherithedProps.js.map +2 -2
  5. package/dist/cjs/index.js +2 -0
  6. package/dist/cjs/index.js.map +2 -2
  7. package/dist/cjs/parts/DSFlyoutMenu/DSFlyoutMenu.js +11 -1
  8. package/dist/cjs/parts/DSFlyoutMenu/DSFlyoutMenu.js.map +2 -2
  9. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js +86 -0
  10. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js.map +7 -0
  11. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js +2 -0
  12. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js.map +2 -2
  13. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js +56 -29
  14. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js.map +2 -2
  15. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js +3 -0
  16. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js.map +2 -2
  17. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js +14 -14
  18. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js.map +1 -1
  19. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js +2 -2
  20. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js.map +1 -1
  21. package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableMenuItem.js +9 -4
  22. package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableMenuItem.js.map +2 -2
  23. package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js +9 -4
  24. package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js.map +2 -2
  25. package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js +11 -6
  26. package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js.map +2 -2
  27. package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js +14 -7
  28. package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js.map +2 -2
  29. package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js +11 -6
  30. package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js.map +2 -2
  31. package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js +11 -6
  32. package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js.map +2 -2
  33. package/dist/cjs/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js +9 -4
  34. package/dist/cjs/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js.map +2 -2
  35. package/dist/cjs/react-desc-prop-types.js +9 -11
  36. package/dist/cjs/react-desc-prop-types.js.map +2 -2
  37. package/dist/cjs/utils/nodesTypeguardsAndGetters.js +18 -56
  38. package/dist/cjs/utils/nodesTypeguardsAndGetters.js.map +2 -2
  39. package/dist/esm/config/useMenuButton.js +4 -17
  40. package/dist/esm/config/useMenuButton.js.map +2 -2
  41. package/dist/esm/config/useSplitInherithedProps.js +31 -15
  42. package/dist/esm/config/useSplitInherithedProps.js.map +2 -2
  43. package/dist/esm/index.js +2 -0
  44. package/dist/esm/index.js.map +2 -2
  45. package/dist/esm/parts/DSFlyoutMenu/DSFlyoutMenu.js +11 -1
  46. package/dist/esm/parts/DSFlyoutMenu/DSFlyoutMenu.js.map +2 -2
  47. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js +56 -0
  48. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.js.map +7 -0
  49. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js +2 -0
  50. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js.map +2 -2
  51. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js +56 -29
  52. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js.map +2 -2
  53. package/dist/esm/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js +3 -0
  54. package/dist/esm/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js.map +2 -2
  55. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js +14 -14
  56. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js.map +1 -1
  57. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js +2 -2
  58. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js.map +1 -1
  59. package/dist/esm/parts/DSMenuItemRendererFactory/ActivableMenuItem.js +9 -4
  60. package/dist/esm/parts/DSMenuItemRendererFactory/ActivableMenuItem.js.map +2 -2
  61. package/dist/esm/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js +9 -4
  62. package/dist/esm/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js.map +2 -2
  63. package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js +11 -6
  64. package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js.map +2 -2
  65. package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js +14 -7
  66. package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js.map +2 -2
  67. package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js +11 -6
  68. package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js.map +2 -2
  69. package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js +11 -6
  70. package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js.map +2 -2
  71. package/dist/esm/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js +9 -4
  72. package/dist/esm/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js.map +2 -2
  73. package/dist/esm/react-desc-prop-types.js +9 -11
  74. package/dist/esm/react-desc-prop-types.js.map +2 -2
  75. package/dist/esm/utils/nodesTypeguardsAndGetters.js +18 -56
  76. package/dist/esm/utils/nodesTypeguardsAndGetters.js.map +2 -2
  77. package/dist/types/config/useSplitInherithedProps.d.ts +8 -8
  78. package/dist/types/index.d.ts +1 -1
  79. package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useAdvancedValidation.d.ts +6 -0
  80. package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.d.ts +2 -1
  81. package/dist/types/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.d.ts +1 -0
  82. package/dist/types/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.d.ts +3 -3
  83. package/dist/types/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.d.ts +2 -2
  84. package/dist/types/react-desc-prop-types.d.ts +15 -15
  85. package/dist/types/utils/nodesTypeguardsAndGetters.d.ts +113 -1
  86. package/package.json +13 -13
@@ -32,14 +32,14 @@ __export(useMenuButton_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(useMenuButton_exports);
34
34
  var React = __toESM(require("react"));
35
- var import_react = __toESM(require("react"));
36
35
  var import_ds_props_helpers = require("@elliemae/ds-props-helpers");
36
+ var import_react = __toESM(require("react"));
37
37
  var import_uid = require("uid");
38
38
  var import_react_desc_prop_types = require("../react-desc-prop-types.js");
39
- var import_useValidateProps = require("./useValidateProps.js");
40
- var import_useSplitInherithedProps = require("./useSplitInherithedProps.js");
41
- var import_useOptionsArrayToDsTree = require("../utils/useOptionsArrayToDsTree.js");
42
39
  var import_nodesTypeguardsAndGetters = require("../utils/nodesTypeguardsAndGetters.js");
40
+ var import_useOptionsArrayToDsTree = require("../utils/useOptionsArrayToDsTree.js");
41
+ var import_useSplitInherithedProps = require("./useSplitInherithedProps.js");
42
+ var import_useValidateProps = require("./useValidateProps.js");
43
43
  const useMenuButton = (propsFromUser) => {
44
44
  const propsWithDefault = (0, import_ds_props_helpers.useMemoMergePropsWithDefault)(propsFromUser, import_react_desc_prop_types.defaultProps);
45
45
  (0, import_useValidateProps.useValidateProps)(propsWithDefault, import_react_desc_prop_types.DSMenuButtonPropTypes);
@@ -63,19 +63,6 @@ const useMenuButton = (propsFromUser) => {
63
63
  focusableNodes,
64
64
  treeRootNode
65
65
  });
66
- const allNodes = treeRootNode.flatten();
67
- const nodesWithRepeatedDsId = allNodes.filter(
68
- (node, index, self) => self.findIndex((n) => n.dsId === node.dsId) !== index
69
- );
70
- if (nodesWithRepeatedDsId.length > 0) {
71
- throw new Error(
72
- `DSMenuButton:
73
- The following dsId are repeated:
74
- ${nodesWithRepeatedDsId.map((n) => n.dsId).join("\n ")}
75
-
76
- The dsId must be unique.`
77
- );
78
- }
79
66
  return import_react.default.useMemo(
80
67
  () => ({
81
68
  propsWithDefault,
@@ -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": ["import React from 'react';\nimport { useGetXstyledProps, useMemoMergePropsWithDefault } from '@elliemae/ds-props-helpers';\nimport { uid } from 'uid';\nimport { type DSMenuButtonT, DSMenuButtonPropTypes, defaultProps } from '../react-desc-prop-types.js';\nimport { useValidateProps } from './useValidateProps.js';\nimport { useSplitInherithedProps } from './useSplitInherithedProps.js';\nimport { useOptionsArrayToDsTree } from '../utils/useOptionsArrayToDsTree.js';\nimport { getFocusableNodes } from '../utils/nodesTypeguardsAndGetters.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>(propsFromUser, defaultProps);\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 const { options: appOptions } = propsWithDefault;\n const optionsArray: DSMenuButtonT.MenuItemInterface[] = Array.isArray(appOptions) ? appOptions : [];\n\n const treeRootNodeFromOptionsArrayIfArray = useOptionsArrayToDsTree({\n options: optionsArray,\n instanceUid,\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 // =============================================================================\n // if any item as a repeated dsId, we must throw an error,\n // the component will not work properly if the dsId is not guaranteed to be unique\n // (only validating focusableNodes may work, but as a good practice it's better to validate the whole tree)\n // =============================================================================\n const allNodes = treeRootNode.flatten();\n const nodesWithRepeatedDsId = allNodes.filter(\n (node, index, self) => self.findIndex((n) => n.dsId === node.dsId) !== index,\n );\n if (nodesWithRepeatedDsId.length > 0) {\n throw new Error(\n `DSMenuButton:\\nThe following dsId are repeated:\\n${nodesWithRepeatedDsId\n .map((n) => n.dsId)\n .join('\\n ')}\\n\\nThe dsId must be unique.`,\n );\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;ADAvB,mBAAkB;AAClB,8BAAiE;AACjE,iBAAoB;AACpB,mCAAwE;AACxE,8BAAiC;AACjC,qCAAwC;AACxC,qCAAwC;AACxC,uCAAkC;AAO3B,MAAM,gBAAgB,CAAC,kBAAuC;AAInE,QAAM,uBAAmB,sDAA0D,eAAe,yCAAY;AAC9G,gDAAiB,kBAAkB,kDAAqB;AAIxD,QAAM,mBAAe,4CAAmB,gBAAgB;AAKxD,QAAM,cAAc,aAAAA,QAAM,QAAQ,MAAM,kBAAc,gBAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAQlE,QAAM,EAAE,SAAS,WAAW,IAAI;AAChC,QAAM,eAAkD,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC;AAElG,QAAM,0CAAsC,wDAAwB;AAAA,IAClE,SAAS;AAAA,IACT;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;AAOD,QAAM,WAAW,aAAa,QAAQ;AACtC,QAAM,wBAAwB,SAAS;AAAA,IACrC,CAAC,MAAM,OAAO,SAAS,KAAK,UAAU,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,MAAM;AAAA,EACzE;AACA,MAAI,sBAAsB,SAAS,GAAG;AACpC,UAAM,IAAI;AAAA,MACR;AAAA;AAAA,EAAoD,sBACjD,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,KAAK,CAAC;AAAA;AAAA;AAAA,IAChB;AAAA,EACF;AAEA,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;",
4
+ "sourcesContent": ["/* eslint-disable max-statements */\nimport { useGetXstyledProps, useMemoMergePropsWithDefault } from '@elliemae/ds-props-helpers';\nimport React from 'react';\nimport { uid } from 'uid';\nimport { DSMenuButtonPropTypes, defaultProps, 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>(propsFromUser, defaultProps);\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 // 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,mCAAwE;AACxE,uCAAkC;AAClC,qCAAwC;AACxC,qCAAwC;AACxC,8BAAiC;AAO1B,MAAM,gBAAgB,CAAC,kBAAuC;AAInE,QAAM,uBAAmB,sDAA0D,eAAe,yCAAY;AAC9G,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;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,
@@ -68,6 +89,12 @@ const useSplitInherithedProps = ({
68
89
  },
69
90
  [innerRef]
70
91
  );
92
+ const selectedNodesMap = import_react.default.useMemo(() => {
93
+ if (selectedItems) {
94
+ return convertSelectedOptionsToNodes(selectedItems, treeRootNode);
95
+ }
96
+ return [];
97
+ }, [selectedItems, treeRootNode]);
71
98
  const menuSpecificProps = import_react.default.useMemo(
72
99
  () => ({
73
100
  options,
@@ -77,26 +104,15 @@ const useSplitInherithedProps = ({
77
104
  onSubmenuToggle,
78
105
  isLoading,
79
106
  isSkeleton,
80
- selectedOptions,
81
107
  ItemRenderer
82
108
  }),
83
- [
84
- options,
85
- onClickOutside,
86
- onOptionClick,
87
- openedSubmenus,
88
- onSubmenuToggle,
89
- isLoading,
90
- isSkeleton,
91
- selectedOptions,
92
- ItemRenderer
93
- ]
109
+ [options, onClickOutside, onOptionClick, openedSubmenus, onSubmenuToggle, isLoading, isSkeleton, ItemRenderer]
94
110
  );
95
111
  return import_react.default.useMemo(
96
112
  () => ({
97
113
  menuBehaviouralLayerProps: {
98
114
  buttonDOMNodeRef,
99
- selectedItems,
115
+ selectedNodes: selectedNodesMap,
100
116
  focusableNodes,
101
117
  optionsTree: treeRootNode,
102
118
  onDisplayedSubmenuChange,
@@ -112,7 +128,7 @@ const useSplitInherithedProps = ({
112
128
  }
113
129
  }),
114
130
  [
115
- selectedItems,
131
+ selectedNodesMap,
116
132
  focusableNodes,
117
133
  treeRootNode,
118
134
  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 selectedOptions,\n ItemRenderer,\n innerRef,\n selectedItems,\n onDisplayedSubmenuChange,\n onItemSelected,\n onActivateItem,\n onOpen,\n onClose,\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 const menuSpecificProps = React.useMemo(\n () => ({\n options,\n onClickOutside,\n onOptionClick,\n openedSubmenus,\n onSubmenuToggle,\n isLoading,\n isSkeleton,\n selectedOptions,\n ItemRenderer,\n }),\n [\n options,\n onClickOutside,\n onOptionClick,\n openedSubmenus,\n onSubmenuToggle,\n isLoading,\n isSkeleton,\n selectedOptions,\n ItemRenderer,\n ],\n );\n\n return React.useMemo(\n () => ({\n menuBehaviouralLayerProps: {\n buttonDOMNodeRef,\n selectedItems,\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 selectedItems,\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,wBAA2B;AAOpB,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,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;AACA,QAAM,oBAAoB,aAAAA,QAAM;AAAA,IAC9B,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,aAAAA,QAAM;AAAA,IACX,OAAO;AAAA,MACL,2BAA2B;AAAA,QACzB;AAAA,QACA;AAAA,QACA;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;",
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 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 ...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;AACtC,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,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
  }
package/dist/cjs/index.js CHANGED
@@ -29,6 +29,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  var src_exports = {};
30
30
  __export(src_exports, {
31
31
  DSMenuButton: () => import_DSMenuButton.DSMenuButton,
32
+ DSMenuButtonPropTypes: () => import_react_desc_prop_types.DSMenuButtonPropTypes,
32
33
  DSMenuButtonWithSchema: () => import_DSMenuButton.DSMenuButtonWithSchema,
33
34
  MENU_BUTTON_DATA_TESTID: () => import_constants.MENU_BUTTON_DATA_TESTID,
34
35
  MENU_BUTTON_SLOTS: () => import_constants.MENU_BUTTON_SLOTS,
@@ -39,6 +40,7 @@ __export(src_exports, {
39
40
  module.exports = __toCommonJS(src_exports);
40
41
  var React = __toESM(require("react"));
41
42
  var import_DSMenuButton = require("./DSMenuButton.js");
43
+ var import_react_desc_prop_types = require("./react-desc-prop-types.js");
42
44
  var import_constants = require("./constants/index.js");
43
45
  var import_nodesTypeguardsAndGetters = require("./utils/nodesTypeguardsAndGetters.js");
44
46
  var import_useOptionsArrayToDsTree = require("./utils/useOptionsArrayToDsTree.js");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts", "../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["// 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", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,0BAAqD;AAErD,uBAA6E;AAC7E,uCAAgC;AAChC,qCAAwC;",
4
+ "sourcesContent": ["// 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", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,0BAAqD;AACrD,mCAA0D;AAC1D,uBAA6E;AAC7E,uCAAgC;AAChC,qCAAwC;",
6
6
  "names": []
7
7
  }
@@ -55,12 +55,14 @@ const StyledMenu = (0, import_ds_system.styled)("div", { name: import_constants.
55
55
  padding: 0;
56
56
  margin: 0;
57
57
  `;
58
+ const NoComponentPlaceholder = () => null;
58
59
  const DSFlyoutMenu = (props) => {
59
60
  const { propsWithDefault, xstyledProps } = (0, import_useFlyoutMenu.useFlyoutMenu)(props);
60
61
  const {
61
62
  instanceUid,
62
63
  globalEventsHelpers: { mainMenuRef, handleSubmenusRefChange }
63
64
  } = import_react.default.useContext(import_MenuBehaviouralContextProviderCTX.MenuBehaviouralContextProviderContext);
65
+ const [didAnimationEnd, setDidAnimationEnd] = import_react.default.useState(false);
64
66
  const { setFloatingRef, floatingStyles, floatingContext, ItemRenderer, isMenuOpen, itemNode } = propsWithDefault;
65
67
  const handleRefChange = import_react.default.useCallback(
66
68
  (node) => {
@@ -72,6 +74,12 @@ const DSFlyoutMenu = (props) => {
72
74
  },
73
75
  [handleSubmenusRefChange, itemNode, mainMenuRef]
74
76
  );
77
+ const handleAnimationStartTrigger = import_react.default.useCallback(() => {
78
+ setDidAnimationEnd(false);
79
+ }, []);
80
+ const handleAnimationEnd = import_react.default.useCallback(() => {
81
+ setDidAnimationEnd(true);
82
+ }, []);
75
83
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
76
84
  import_ds_floating_context.FloatingWrapper,
77
85
  {
@@ -79,12 +87,14 @@ const DSFlyoutMenu = (props) => {
79
87
  floatingStyles,
80
88
  isOpen: isMenuOpen,
81
89
  context: floatingContext,
90
+ onAnimationStartTriggered: handleAnimationStartTrigger,
91
+ onAnimationEnd: handleAnimationEnd,
82
92
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledWrapper, { getOwnerProps: () => propsWithDefault, getOwnerPropsArguments: () => ({}), ...xstyledProps, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledMenu, { role: "menu", innerRef: handleRefChange, children: itemNode.children.map((optionNode) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
83
93
  import_DSMenuItemRendererFactory.DSMenuItemRendererFactory,
84
94
  {
85
95
  itemNode: optionNode,
86
96
  ItemRenderer,
87
- FlyoutMenuCircularDepInject: DSFlyoutMenu
97
+ FlyoutMenuCircularDepInject: didAnimationEnd ? DSFlyoutMenu : NoComponentPlaceholder
88
98
  },
89
99
  `flyout-menu-item-${optionNode.dsId}-${instanceUid}`
90
100
  )) }) })
@@ -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 { DSMenuButtonT } 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, { name: DSFlyoutMenuName, slot: FLYOUT_MENU_SLOTS.ROOT })`\n min-width: 150px;\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 padding: 0;\n margin: 0;\n`;\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\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 return (\n <FloatingWrapper\n innerRef={setFloatingRef}\n floatingStyles={floatingStyles}\n isOpen={isMenuOpen}\n context={floatingContext}\n >\n <StyledWrapper getOwnerProps={() => propsWithDefault} getOwnerPropsArguments={() => ({})} {...xstyledProps}>\n <StyledMenu role=\"menu\" innerRef={handleRefChange}>\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 FlyoutMenuCircularDepInject={DSFlyoutMenu}\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;ADuDX;AAvDZ,iCAAgC;AAChC,qBAAqB;AACrB,8BAAyB;AACzB,uBAA2C;AAC3C,mBAAkB;AAElB,+CAAsD;AACtD,uCAA0C;AAC1C,2BAA8B;AAC9B,uBAAoD;AACpD,mCAAgE;AAChE,uCAA2B;AAE3B,MAAM,oBAAgB,yBAAO,qBAAM,EAAE,MAAM,mCAAkB,MAAM,mCAAkB,KAAK,CAAC;AAAA;AAAA;AAAA,aAG9E,CAAC,EAAE,MAAM,MAAM,MAAM,MAAM,IAAI;AAAA,IACxC,mCAAkB;AAAA;AAGtB,MAAM,iBAAa,yBAAO,OAAO,EAAE,MAAM,mCAAkB,MAAM,mCAAkB,aAAa,CAAC;AAAA;AAAA;AAAA;AAKjG,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,aAAAA,QAAM,WAAW,8EAAqC;AAE1D,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,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,MACR,SAAS;AAAA,MAET,sDAAC,iBAAc,eAAe,MAAM,kBAAkB,wBAAwB,OAAO,CAAC,IAAK,GAAG,cAC5F,sDAAC,cAAW,MAAK,QAAO,UAAU,iBAC/B,mBAAS,SAAS,IAAI,CAAC,eACtB;AAAA,QAAC;AAAA;AAAA,UAGC,UAAU;AAAA,UACV;AAAA,UAGA,6BAA6B;AAAA;AAAA,QANxB,oBAAoB,WAAW,IAAI,IAAI,WAAW;AAAA,MAOzD,CACD,GACH,GACF;AAAA;AAAA,EACF;AAEJ;AAEA,aAAa,cAAc;AAC3B,MAAM,6BAAyB,kCAAS,YAAY;AACpD,uBAAuB,YAAY;",
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 } 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, { name: DSFlyoutMenuName, slot: FLYOUT_MENU_SLOTS.ROOT })`\n min-width: 150px;\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 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 role=\"menu\" innerRef={handleRefChange}>\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;ADmEX;AAnEZ,iCAAgC;AAChC,qBAAqB;AACrB,8BAAyB;AACzB,uBAA2C;AAC3C,mBAAkB;AAElB,+CAAsD;AACtD,uCAA0C;AAC1C,2BAA8B;AAC9B,uBAAoD;AACpD,mCAAgE;AAChE,uCAA2B;AAE3B,MAAM,oBAAgB,yBAAO,qBAAM,EAAE,MAAM,mCAAkB,MAAM,mCAAkB,KAAK,CAAC;AAAA;AAAA;AAAA,aAG9E,CAAC,EAAE,MAAM,MAAM,MAAM,MAAM,IAAI;AAAA,IACxC,mCAAkB;AAAA;AAGtB,MAAM,iBAAa,yBAAO,OAAO,EAAE,MAAM,mCAAkB,MAAM,mCAAkB,aAAa,CAAC;AAAA;AAAA;AAAA;AAKjG,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,aAAAA,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,sDAAC,cAAW,MAAK,QAAO,UAAU,iBAC/B,mBAAS,SAAS,IAAI,CAAC,eACtB;AAAA,QAAC;AAAA;AAAA,UAGC,UAAU;AAAA,UACV;AAAA,UAIA,6BAA6B,kBAAkB,eAAe;AAAA;AAAA,QAPzD,oBAAoB,WAAW,IAAI,IAAI,WAAW;AAAA,MAQzD,CACD,GACH,GACF;AAAA;AAAA,EACF;AAEJ;AAEA,aAAa,cAAc;AAC3B,MAAM,6BAAyB,kCAAS,YAAY;AACpD,uBAAuB,YAAY;",
6
6
  "names": ["React"]
7
7
  }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var useAdvancedValidation_exports = {};
30
+ __export(useAdvancedValidation_exports, {
31
+ useAdvancedValidation: () => useAdvancedValidation
32
+ });
33
+ module.exports = __toCommonJS(useAdvancedValidation_exports);
34
+ var React = __toESM(require("react"));
35
+ var import_react = require("react");
36
+ var import_nodesTypeguardsAndGetters = require("../../../utils/nodesTypeguardsAndGetters.js");
37
+ const useAdvancedValidation = ({ propsWithDefault }) => {
38
+ const { onActivateItem, onItemSelected, selectedNodes, optionsTree } = propsWithDefault;
39
+ (0, import_react.useEffect)(() => {
40
+ const allNodes = optionsTree.flatten();
41
+ const nodesByDsId = {};
42
+ const duplicatedIdsNodes = {};
43
+ let hasActivation = false;
44
+ let hasSelection = false;
45
+ let hasDuplicateDsId = false;
46
+ allNodes.forEach((node) => {
47
+ const { dsId } = node;
48
+ if (!Array.isArray(nodesByDsId[dsId])) {
49
+ nodesByDsId[dsId] = [node];
50
+ } else {
51
+ nodesByDsId[dsId].push(node);
52
+ hasDuplicateDsId = true;
53
+ duplicatedIdsNodes[dsId] = nodesByDsId[dsId];
54
+ }
55
+ if ((0, import_nodesTypeguardsAndGetters.isActivableNode)(node)) {
56
+ hasActivation = true;
57
+ }
58
+ if ((0, import_nodesTypeguardsAndGetters.isSelectionableNode)(node)) {
59
+ hasSelection = true;
60
+ }
61
+ });
62
+ if (hasDuplicateDsId) {
63
+ console.log("duplicatedIdsNodes", duplicatedIdsNodes);
64
+ throw new Error(
65
+ `DSMenuButton:
66
+ The following dsId are repeated:
67
+ ${Object.keys(duplicatedIdsNodes).join(
68
+ "\n"
69
+ )}
70
+
71
+ The dsId must be unique.`
72
+ );
73
+ }
74
+ if (hasActivation && !onActivateItem) {
75
+ throw new Error(
76
+ "DSMenuButton:\nSome items are activable, but onActivateItem is not provided.\n\nYou must provide onActivateItem to handle activation."
77
+ );
78
+ }
79
+ if (hasSelection && (!onItemSelected || !selectedNodes)) {
80
+ throw new Error(
81
+ "DSMenuButton:\nSome items are selectionable, but onItemSelected or selectedNodes are not provided.\n\nYou must provide onItemSelected and selectedNodes to handle selection."
82
+ );
83
+ }
84
+ }, [onActivateItem, onItemSelected, selectedNodes, optionsTree]);
85
+ };
86
+ //# sourceMappingURL=useAdvancedValidation.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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, 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
+ "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
+ "names": []
7
+ }
@@ -40,6 +40,7 @@ var import_useGlobalEvents = require("./useGlobalEvents.js");
40
40
  var import_useMenuItemEventsHandlers = require("./useMenuItemEventsHandlers.js");
41
41
  var import_useMenuOpenStatus = require("./useMenuOpenStatus.js");
42
42
  var import_useValidateProps = require("./useValidateProps.js");
43
+ var import_useAdvancedValidation = require("./useAdvancedValidation.js");
43
44
  const useMenuBehaviouralContextProvider = (propsFromUser) => {
44
45
  const propsWithDefault = import_react.default.useMemo(
45
46
  () => ({
@@ -49,6 +50,7 @@ const useMenuBehaviouralContextProvider = (propsFromUser) => {
49
50
  [propsFromUser]
50
51
  );
51
52
  (0, import_useValidateProps.useValidateProps)(propsWithDefault, import_react_desc_prop_types.DSMenuBehaviouralContextProviderPropTypesSchema);
53
+ (0, import_useAdvancedValidation.useAdvancedValidation)({ propsWithDefault });
52
54
  const { onDisplayedSubmenuChange } = propsWithDefault;
53
55
  const instanceUid = import_react.default.useMemo(() => `ds-menu-behavioural-context-provider-${(0, import_uid.uid)(5)}`, []);
54
56
  const [openedSubItems, setOpenedSubItems] = import_react.default.useState([]);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.ts", "../../../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["import React from 'react';\nimport { uid } from 'uid';\nimport type { DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport {\n DSMenuBehaviouralContextProviderPropTypesSchema,\n defaultProps,\n type DSMenuBehaviouralContextProviderT,\n} from '../react-desc-prop-types.js';\nimport { useFocusTracker } from './useFocusTracker.js';\nimport { useGlobalEvents } from './useGlobalEvents.js';\nimport { useMenuItemEventsHandlers } from './useMenuItemEventsHandlers.js';\nimport { useMenuOpenStatus } from './useMenuOpenStatus.js';\nimport { useValidateProps } from './useValidateProps.js';\n\nexport interface MenuBehaviouralContextProviderCTX\n extends ReturnType<typeof useFocusTracker>,\n ReturnType<typeof useMenuOpenStatus> {\n propsWithDefault: DSMenuBehaviouralContextProviderT.InternalProps;\n instanceUid: string;\n menuItemEventsHandlers: ReturnType<typeof useMenuItemEventsHandlers>;\n openedSubItems: DSMenuButtonT.WithSubmenuMenuNodes[];\n handleChangeOpenedSubItems: Required<DSMenuButtonT.MenuBehaviouralLayerOptionalProps>['onDisplayedSubmenuChange'];\n globalEventsHelpers: ReturnType<typeof useGlobalEvents>;\n}\n\nexport const useMenuBehaviouralContextProvider = (propsFromUser: DSMenuBehaviouralContextProviderT.Props) => {\n // =============================================================================\n // MERGE WITH DEFAULT AND VALIDATE PROPS\n // =============================================================================\n // the component deals with HTML DOM elements,\n // Deep compare of HTML DOM elements is pointless and extremely costly\n // for this specific case, we are better of not using `useMemoMergePropsWithDefault`\n const propsWithDefault = React.useMemo(\n () => ({\n ...defaultProps,\n ...propsFromUser,\n }),\n [propsFromUser],\n ) as DSMenuBehaviouralContextProviderT.InternalProps;\n useValidateProps(propsWithDefault, DSMenuBehaviouralContextProviderPropTypesSchema);\n // =============================================================================\n // XSTYLED PROPS\n // =============================================================================\n // NO XSTYLED PROPS\n // this is 100% a pure logic context provider, it's not a visual component\n\n // =============================================================================\n // AD HOC PER COMPONENT LOGIC\n // =============================================================================\n // custom code goes here, this is an example\n const { onDisplayedSubmenuChange } = propsWithDefault;\n const instanceUid = React.useMemo(() => `ds-menu-behavioural-context-provider-${uid(5)}`, []);\n const [openedSubItems, setOpenedSubItems] = React.useState<DSMenuButtonT.WithSubmenuMenuNodes[]>([]);\n\n const handleChangeOpenedSubItems = React.useCallback<\n Required<DSMenuButtonT.MenuBehaviouralLayerOptionalProps>['onDisplayedSubmenuChange']\n >(\n (newOpenedItems, metainfo) => {\n setOpenedSubItems(newOpenedItems);\n onDisplayedSubmenuChange?.(newOpenedItems, metainfo);\n },\n [onDisplayedSubmenuChange],\n );\n\n // =============================================================================\n // HELPERS HOOKS CONFIGS\n // =============================================================================\n const focusTrackers = useFocusTracker();\n const menuOpenStatus = useMenuOpenStatus({ propsWithDefault, focusTrackers });\n\n // why item events handlers declared in the menu behaviour context provider and not in the menu item itself?\n // 1 - each menu item depending on it's own type (single select, multiple select, with submenu) will have different behaviours\n // having each menu item to declare it's own events handlers would make the single event handler way easier to create per se\n // BUT we would lose the big picture of how the menu items are interacting with each other\n // 2 - having each item to declare it's own event handler repeatdly is a waste of resources (even if it's a useless micro-optimization, it hurts me)\n const menuItemEventsHandlers = useMenuItemEventsHandlers({\n propsWithDefault,\n focusTrackers,\n menuOpenStatus,\n handleChangeOpenedSubItems,\n });\n\n // handle \"onClickOutside\" + on window blur...\n // the helpers contain a way to register the submenu refs/mainmenu refs, used in checking \"if click is outside\"\n const globalEventsHelpers = useGlobalEvents({ menuOpenStatus, handleChangeOpenedSubItems, propsWithDefault });\n\n return React.useMemo<MenuBehaviouralContextProviderCTX>(\n () => ({\n propsWithDefault,\n instanceUid,\n ...focusTrackers,\n ...menuOpenStatus,\n menuItemEventsHandlers,\n openedSubItems,\n handleChangeOpenedSubItems,\n globalEventsHelpers,\n }),\n [\n propsWithDefault,\n instanceUid,\n focusTrackers,\n menuOpenStatus,\n menuItemEventsHandlers,\n openedSubItems,\n handleChangeOpenedSubItems,\n globalEventsHelpers,\n ],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,mBAAkB;AAClB,iBAAoB;AAEpB,mCAIO;AACP,6BAAgC;AAChC,6BAAgC;AAChC,uCAA0C;AAC1C,+BAAkC;AAClC,8BAAiC;AAa1B,MAAM,oCAAoC,CAAC,kBAA2D;AAO3G,QAAM,mBAAmB,aAAAA,QAAM;AAAA,IAC7B,OAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AACA,gDAAiB,kBAAkB,4EAA+C;AAWlF,QAAM,EAAE,yBAAyB,IAAI;AACrC,QAAM,cAAc,aAAAA,QAAM,QAAQ,MAAM,4CAAwC,gBAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAC5F,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,aAAAA,QAAM,SAA+C,CAAC,CAAC;AAEnG,QAAM,6BAA6B,aAAAA,QAAM;AAAA,IAGvC,CAAC,gBAAgB,aAAa;AAC5B,wBAAkB,cAAc;AAChC,iCAA2B,gBAAgB,QAAQ;AAAA,IACrD;AAAA,IACA,CAAC,wBAAwB;AAAA,EAC3B;AAKA,QAAM,oBAAgB,wCAAgB;AACtC,QAAM,qBAAiB,4CAAkB,EAAE,kBAAkB,cAAc,CAAC;AAO5E,QAAM,6BAAyB,4DAA0B;AAAA,IACvD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAID,QAAM,0BAAsB,wCAAgB,EAAE,gBAAgB,4BAA4B,iBAAiB,CAAC;AAE5G,SAAO,aAAAA,QAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import React from 'react';\nimport { uid } from 'uid';\nimport type { DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport {\n DSMenuBehaviouralContextProviderPropTypesSchema,\n defaultProps,\n type DSMenuBehaviouralContextProviderT,\n} from '../react-desc-prop-types.js';\nimport { useFocusTracker } from './useFocusTracker.js';\nimport { useGlobalEvents } from './useGlobalEvents.js';\nimport { useMenuItemEventsHandlers } from './useMenuItemEventsHandlers.js';\nimport { useMenuOpenStatus } from './useMenuOpenStatus.js';\nimport { useValidateProps } from './useValidateProps.js';\nimport { useAdvancedValidation } from './useAdvancedValidation.js';\n\nexport interface MenuBehaviouralContextProviderCTX\n extends ReturnType<typeof useFocusTracker>,\n ReturnType<typeof useMenuOpenStatus> {\n propsWithDefault: DSMenuBehaviouralContextProviderT.InternalProps;\n instanceUid: string;\n menuItemEventsHandlers: ReturnType<typeof useMenuItemEventsHandlers>;\n openedSubItems: DSMenuButtonT.WithSubmenuMenuNodes[];\n handleChangeOpenedSubItems: Required<DSMenuButtonT.MenuBehaviouralLayerOptionalProps>['onDisplayedSubmenuChange'];\n globalEventsHelpers: ReturnType<typeof useGlobalEvents>;\n}\n\nexport const useMenuBehaviouralContextProvider = (propsFromUser: DSMenuBehaviouralContextProviderT.Props) => {\n // =============================================================================\n // MERGE WITH DEFAULT AND VALIDATE PROPS\n // =============================================================================\n // the component deals with HTML DOM elements,\n // Deep compare of HTML DOM elements is pointless and extremely costly\n // for this specific case, we are better of not using `useMemoMergePropsWithDefault`\n const propsWithDefault = React.useMemo(\n () => ({\n ...defaultProps,\n ...propsFromUser,\n }),\n [propsFromUser],\n ) as DSMenuBehaviouralContextProviderT.InternalProps;\n useValidateProps(propsWithDefault, DSMenuBehaviouralContextProviderPropTypesSchema);\n\n // =============================================================================\n // SPECIAL VALIDATIONS\n // =============================================================================\n useAdvancedValidation({ propsWithDefault });\n\n // =============================================================================\n // XSTYLED PROPS\n // =============================================================================\n // NO XSTYLED PROPS\n // this is 100% a pure logic context provider, it's not a visual component\n\n // =============================================================================\n // AD HOC PER COMPONENT LOGIC\n // =============================================================================\n // custom code goes here, this is an example\n const { onDisplayedSubmenuChange } = propsWithDefault;\n const instanceUid = React.useMemo(() => `ds-menu-behavioural-context-provider-${uid(5)}`, []);\n const [openedSubItems, setOpenedSubItems] = React.useState<DSMenuButtonT.WithSubmenuMenuNodes[]>([]);\n\n const handleChangeOpenedSubItems = React.useCallback<\n Required<DSMenuButtonT.MenuBehaviouralLayerOptionalProps>['onDisplayedSubmenuChange']\n >(\n (newOpenedItems, metainfo) => {\n setOpenedSubItems(newOpenedItems);\n onDisplayedSubmenuChange?.(newOpenedItems, metainfo);\n },\n [onDisplayedSubmenuChange],\n );\n\n // =============================================================================\n // HELPERS HOOKS CONFIGS\n // =============================================================================\n const focusTrackers = useFocusTracker();\n const menuOpenStatus = useMenuOpenStatus({ propsWithDefault, focusTrackers });\n\n // why item events handlers declared in the menu behaviour context provider and not in the menu item itself?\n // 1 - each menu item depending on it's own type (single select, multiple select, with submenu) will have different behaviours\n // having each menu item to declare it's own events handlers would make the single event handler way easier to create per se\n // BUT we would lose the big picture of how the menu items are interacting with each other\n // 2 - having each item to declare it's own event handler repeatdly is a waste of resources (even if it's a useless micro-optimization, it hurts me)\n const menuItemEventsHandlers = useMenuItemEventsHandlers({\n propsWithDefault,\n focusTrackers,\n menuOpenStatus,\n handleChangeOpenedSubItems,\n });\n\n // handle \"onClickOutside\" + on window blur...\n // the helpers contain a way to register the submenu refs/mainmenu refs, used in checking \"if click is outside\"\n const globalEventsHelpers = useGlobalEvents({ menuOpenStatus, handleChangeOpenedSubItems, propsWithDefault });\n\n return React.useMemo<MenuBehaviouralContextProviderCTX>(\n () => ({\n propsWithDefault,\n instanceUid,\n ...focusTrackers,\n ...menuOpenStatus,\n menuItemEventsHandlers,\n openedSubItems,\n handleChangeOpenedSubItems,\n globalEventsHelpers,\n }),\n [\n propsWithDefault,\n instanceUid,\n focusTrackers,\n menuOpenStatus,\n menuItemEventsHandlers,\n openedSubItems,\n handleChangeOpenedSubItems,\n globalEventsHelpers,\n ],\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,mBAAkB;AAClB,iBAAoB;AAEpB,mCAIO;AACP,6BAAgC;AAChC,6BAAgC;AAChC,uCAA0C;AAC1C,+BAAkC;AAClC,8BAAiC;AACjC,mCAAsC;AAa/B,MAAM,oCAAoC,CAAC,kBAA2D;AAO3G,QAAM,mBAAmB,aAAAA,QAAM;AAAA,IAC7B,OAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AACA,gDAAiB,kBAAkB,4EAA+C;AAKlF,0DAAsB,EAAE,iBAAiB,CAAC;AAY1C,QAAM,EAAE,yBAAyB,IAAI;AACrC,QAAM,cAAc,aAAAA,QAAM,QAAQ,MAAM,4CAAwC,gBAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAC5F,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,aAAAA,QAAM,SAA+C,CAAC,CAAC;AAEnG,QAAM,6BAA6B,aAAAA,QAAM;AAAA,IAGvC,CAAC,gBAAgB,aAAa;AAC5B,wBAAkB,cAAc;AAChC,iCAA2B,gBAAgB,QAAQ;AAAA,IACrD;AAAA,IACA,CAAC,wBAAwB;AAAA,EAC3B;AAKA,QAAM,oBAAgB,wCAAgB;AACtC,QAAM,qBAAiB,4CAAkB,EAAE,kBAAkB,cAAc,CAAC;AAO5E,QAAM,6BAAyB,4DAA0B;AAAA,IACvD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAID,QAAM,0BAAsB,wCAAgB,EAAE,gBAAgB,4BAA4B,iBAAiB,CAAC;AAE5G,SAAO,aAAAA,QAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;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
  }
@@ -44,7 +44,7 @@ const useMenuItemEventsHandlers = ({
44
44
  menuOpenStatus,
45
45
  handleChangeOpenedSubItems
46
46
  }) => {
47
- const { onItemSelected, onActivateItem, selectedItems } = propsWithDefault;
47
+ const { onItemSelected, onActivateItem, selectedNodes } = propsWithDefault;
48
48
  const { onOpinionatedClose } = menuOpenStatus;
49
49
  const {
50
50
  trackFocusFirstChildItem,
@@ -95,10 +95,10 @@ const useMenuItemEventsHandlers = ({
95
95
  trackFocusFirstChildItem(pseudoFocusedItemNode);
96
96
  } else {
97
97
  if ((0, import_nodesTypeguardsAndGetters.isMultipleSelectNode)(pseudoFocusedItemNode)) {
98
- const newSelection = (0, import_multipleSelectionHelpers.getNewSelectionMultipleSelect)(selectedItems, pseudoFocusedItemNode);
98
+ const newSelection = (0, import_multipleSelectionHelpers.getNewSelectionMultipleSelect)(selectedNodes, pseudoFocusedItemNode);
99
99
  onItemSelected(newSelection, { itemNode: pseudoFocusedItemNode, event });
100
100
  } else if ((0, import_nodesTypeguardsAndGetters.isSingleSelectNode)(pseudoFocusedItemNode)) {
101
- const newSelection = (0, import_singleSelectionHelpers.getNewSelectionSingleSelect)(selectedItems, pseudoFocusedItemNode);
101
+ const newSelection = (0, import_singleSelectionHelpers.getNewSelectionSingleSelect)(selectedNodes, pseudoFocusedItemNode);
102
102
  onItemSelected(newSelection, { itemNode: pseudoFocusedItemNode, event });
103
103
  } else {
104
104
  onActivateItem(pseudoFocusedItemNode, { itemNode: pseudoFocusedItemNode, event });
@@ -114,7 +114,7 @@ const useMenuItemEventsHandlers = ({
114
114
  openSubmenu,
115
115
  handleChangeOpenedSubItems,
116
116
  onOpinionatedClose,
117
- selectedItems,
117
+ selectedNodes,
118
118
  onItemSelected,
119
119
  onActivateItem
120
120
  ]
@@ -127,16 +127,16 @@ const useMenuItemEventsHandlers = ({
127
127
  return;
128
128
  }
129
129
  if ((0, import_nodesTypeguardsAndGetters.isMultipleSelectNode)(pseudoFocusedItemNode)) {
130
- const newSelection = (0, import_multipleSelectionHelpers.getNewSelectionMultipleSelect)(selectedItems, pseudoFocusedItemNode);
130
+ const newSelection = (0, import_multipleSelectionHelpers.getNewSelectionMultipleSelect)(selectedNodes, pseudoFocusedItemNode);
131
131
  onItemSelected(newSelection, { itemNode: pseudoFocusedItemNode, event });
132
132
  return;
133
133
  }
134
134
  if ((0, import_nodesTypeguardsAndGetters.isSingleSelectNode)(pseudoFocusedItemNode)) {
135
- const newSelection = (0, import_singleSelectionHelpers.getNewSelectionSingleSelect)(selectedItems, pseudoFocusedItemNode);
135
+ const newSelection = (0, import_singleSelectionHelpers.getNewSelectionSingleSelect)(selectedNodes, pseudoFocusedItemNode);
136
136
  onItemSelected(newSelection, { itemNode: pseudoFocusedItemNode, event });
137
137
  return;
138
138
  }
139
- onActivateItem(pseudoFocusedItemNode, { itemNode: pseudoFocusedItemNode, event });
139
+ onActivateItem?.(pseudoFocusedItemNode, { itemNode: pseudoFocusedItemNode, event });
140
140
  const metainfo = { itemNode: pseudoFocusedItemNode, event };
141
141
  const newOpenedItems = [];
142
142
  handleChangeOpenedSubItems(newOpenedItems, metainfo);
@@ -148,7 +148,7 @@ const useMenuItemEventsHandlers = ({
148
148
  onOpinionatedClose,
149
149
  trackFocusFirstChildItem,
150
150
  openSubmenu,
151
- selectedItems,
151
+ selectedNodes,
152
152
  onItemSelected
153
153
  ]
154
154
  );
@@ -247,25 +247,6 @@ const useMenuItemEventsHandlers = ({
247
247
  onOpinionatedClose
248
248
  ]
249
249
  );
250
- const handleFocusableMenuItemOnMouseEnter = import_react.default.useCallback(
251
- (itemNode, event) => {
252
- if (!(0, import_nodesTypeguardsAndGetters.isFocusableNode)(itemNode)) {
253
- console.log("handleFocusableMenuItemOnMouseEnter > itemNode:", itemNode);
254
- throw import_Errors.FORBIDDEN_BEHAVIOURS.TRYING_TO_FOCUS_NON_FOCUSABLE_NODE;
255
- }
256
- trackFocusNode(itemNode);
257
- if (!(0, import_nodesTypeguardsAndGetters.isWithSubmenuNode)(itemNode)) {
258
- const subMenuNodesPath = (0, import_nodeGettersByCriterias.getSubMenusPath)(itemNode);
259
- const metainfo = { itemNode, event };
260
- const newOpenedItems = [...subMenuNodesPath];
261
- handleChangeOpenedSubItems(newOpenedItems, metainfo);
262
- return;
263
- }
264
- if (itemNode.plainItem.disabled) return;
265
- openSubmenu({ itemNode, event });
266
- },
267
- [handleChangeOpenedSubItems, openSubmenu, trackFocusNode]
268
- );
269
250
  const handleFocusableMenuItemClick = import_react.default.useCallback(
270
251
  (event) => {
271
252
  const pseudoFocusedItemNode = focusedElementItemNode.current;
@@ -289,13 +270,59 @@ const useMenuItemEventsHandlers = ({
289
270
  },
290
271
  [focusedElementItemNode, handleMenuItemSpaceKeyDown, handleChangeOpenedSubItems]
291
272
  );
273
+ const opinionatedFocusBehaviour = import_react.default.useCallback(
274
+ // we currently know only one "event" that can trigger this opinionated behaviour
275
+ // - focus => React.FocusEvent <-- triggered by ATs "focus mode" or "virtual cursor" navigation
276
+ // NOTE:
277
+ // mouseEnter => React.MouseEvent
278
+ // still ends up calling this function, but as a side effect of mouse-enter focusing the item, not as the main event
279
+ (itemNode, event) => {
280
+ if (!(0, import_nodesTypeguardsAndGetters.isFocusableNode)(itemNode)) {
281
+ console.log("handleFocusableMenuItemOnMouseEnter > itemNode:", itemNode);
282
+ throw import_Errors.FORBIDDEN_BEHAVIOURS.TRYING_TO_FOCUS_NON_FOCUSABLE_NODE;
283
+ }
284
+ trackFocusNode(itemNode);
285
+ if (!(0, import_nodesTypeguardsAndGetters.isWithSubmenuNode)(itemNode)) {
286
+ const subMenuNodesPath = (0, import_nodeGettersByCriterias.getSubMenusPath)(itemNode);
287
+ const metainfo = { itemNode, event };
288
+ const newOpenedItems = [...subMenuNodesPath];
289
+ handleChangeOpenedSubItems(newOpenedItems, metainfo);
290
+ return;
291
+ }
292
+ if (itemNode.plainItem.disabled) return;
293
+ openSubmenu({ itemNode, event });
294
+ },
295
+ [handleChangeOpenedSubItems, openSubmenu, trackFocusNode]
296
+ );
297
+ const handleFocusableMenuItemOnMouseEnter = import_react.default.useCallback(
298
+ (itemNode) => {
299
+ if (!(0, import_nodesTypeguardsAndGetters.isFocusableNode)(itemNode)) {
300
+ console.log("handleFocusableMenuItemOnMouseEnter > itemNode:", itemNode);
301
+ throw import_Errors.FORBIDDEN_BEHAVIOURS.TRYING_TO_FOCUS_NON_FOCUSABLE_NODE;
302
+ }
303
+ trackFocusNode(itemNode);
304
+ },
305
+ [trackFocusNode]
306
+ );
307
+ const handleFocusableMenuItemNativeFocusEvent = import_react.default.useCallback(
308
+ (itemNode, event) => {
309
+ opinionatedFocusBehaviour(itemNode, event);
310
+ },
311
+ [opinionatedFocusBehaviour]
312
+ );
292
313
  return import_react.default.useMemo(
293
314
  () => ({
294
315
  handleFocusableMenuItemKeyDown,
295
316
  handleFocusableMenuItemClick,
296
- handleFocusableMenuItemOnMouseEnter
317
+ handleFocusableMenuItemOnMouseEnter,
318
+ handleFocusableMenuItemNativeFocusEvent
297
319
  }),
298
- [handleFocusableMenuItemClick, handleFocusableMenuItemKeyDown, handleFocusableMenuItemOnMouseEnter]
320
+ [
321
+ handleFocusableMenuItemClick,
322
+ handleFocusableMenuItemKeyDown,
323
+ handleFocusableMenuItemNativeFocusEvent,
324
+ handleFocusableMenuItemOnMouseEnter
325
+ ]
299
326
  );
300
327
  };
301
328
  //# sourceMappingURL=useMenuItemEventsHandlers.js.map