@elliemae/ds-menu-button 3.45.0-rc.0 → 3.45.0-rc.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. package/dist/cjs/DSMenuButton.js +16 -5
  2. package/dist/cjs/DSMenuButton.js.map +2 -2
  3. package/dist/cjs/config/useMenuButton.js +49 -18
  4. package/dist/cjs/config/useMenuButton.js.map +3 -3
  5. package/dist/cjs/config/useSplitInherithedProps.js +141 -0
  6. package/dist/cjs/config/useSplitInherithedProps.js.map +7 -0
  7. package/dist/cjs/config/useValidateProps.js.map +2 -2
  8. package/dist/cjs/constants/index.js +17 -4
  9. package/dist/cjs/constants/index.js.map +2 -2
  10. package/dist/cjs/index.js +7 -3
  11. package/dist/cjs/index.js.map +3 -3
  12. package/dist/cjs/parts/DSFlyoutMenu/DSFlyoutMenu.js +96 -0
  13. package/dist/cjs/parts/DSFlyoutMenu/DSFlyoutMenu.js.map +7 -0
  14. package/dist/cjs/parts/DSFlyoutMenu/config/useFlyoutMenu.js +54 -0
  15. package/dist/cjs/parts/DSFlyoutMenu/config/useFlyoutMenu.js.map +7 -0
  16. package/dist/cjs/parts/{ItemFactory.js → DSFlyoutMenu/config/useValidateProps.js} +9 -35
  17. package/dist/cjs/parts/DSFlyoutMenu/config/useValidateProps.js.map +7 -0
  18. package/dist/cjs/parts/DSFlyoutMenu/constants/index.js +46 -0
  19. package/dist/cjs/parts/DSFlyoutMenu/constants/index.js.map +7 -0
  20. package/dist/cjs/{DSMenuButtonCTX.js → parts/DSFlyoutMenu/index.js} +7 -8
  21. package/dist/cjs/parts/DSFlyoutMenu/index.js.map +7 -0
  22. package/dist/cjs/parts/DSFlyoutMenu/react-desc-prop-types.js +62 -0
  23. package/dist/cjs/parts/DSFlyoutMenu/react-desc-prop-types.js.map +7 -0
  24. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/DSMenuBehaviouralContextProvider.js +70 -0
  25. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/DSMenuBehaviouralContextProvider.js.map +7 -0
  26. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/MenuBehaviouralContextProviderCTX.js +40 -0
  27. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/MenuBehaviouralContextProviderCTX.js.map +7 -0
  28. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.js +186 -0
  29. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.js.map +7 -0
  30. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useGlobalEvents.js +89 -0
  31. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useGlobalEvents.js.map +7 -0
  32. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js +92 -0
  33. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js.map +7 -0
  34. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js +315 -0
  35. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js.map +7 -0
  36. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuOpenStatus.js +66 -0
  37. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useMenuOpenStatus.js.map +7 -0
  38. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useValidateProps.js +40 -0
  39. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/config/useValidateProps.js.map +7 -0
  40. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/constants/Errors.js +58 -0
  41. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/constants/Errors.js.map +7 -0
  42. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/constants/index.js +44 -0
  43. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/constants/index.js.map +7 -0
  44. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/index.js +37 -0
  45. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/index.js.map +7 -0
  46. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js +53 -0
  47. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js.map +7 -0
  48. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js +139 -0
  49. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js.map +7 -0
  50. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/nodeGettersByCriterias.js +144 -0
  51. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/nodeGettersByCriterias.js.map +7 -0
  52. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js +44 -0
  53. package/dist/cjs/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js.map +7 -0
  54. package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableMenuItem.js +116 -0
  55. package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableMenuItem.js.map +7 -0
  56. package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js +159 -0
  57. package/dist/cjs/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js.map +7 -0
  58. package/dist/cjs/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.js +97 -0
  59. package/dist/cjs/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.js.map +7 -0
  60. package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js +122 -0
  61. package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js.map +7 -0
  62. package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js +173 -0
  63. package/dist/cjs/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js.map +7 -0
  64. package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js +130 -0
  65. package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js.map +7 -0
  66. package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js +176 -0
  67. package/dist/cjs/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js.map +7 -0
  68. package/dist/cjs/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js +162 -0
  69. package/dist/cjs/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js.map +7 -0
  70. package/dist/cjs/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.js +57 -0
  71. package/dist/cjs/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.js.map +7 -0
  72. package/dist/cjs/parts/DSMenuItemRendererFactory/config/useValidateProps.js +40 -0
  73. package/dist/cjs/parts/DSMenuItemRendererFactory/config/useValidateProps.js.map +7 -0
  74. package/dist/cjs/parts/DSMenuItemRendererFactory/constants/index.js +48 -0
  75. package/dist/cjs/parts/DSMenuItemRendererFactory/constants/index.js.map +7 -0
  76. package/dist/cjs/parts/DSMenuItemRendererFactory/index.js +37 -0
  77. package/dist/cjs/parts/DSMenuItemRendererFactory/index.js.map +7 -0
  78. package/dist/cjs/parts/DSMenuItemRendererFactory/react-desc-prop-types.js +51 -0
  79. package/dist/cjs/parts/DSMenuItemRendererFactory/react-desc-prop-types.js.map +7 -0
  80. package/dist/cjs/parts/DSMenuItemRendererFactory/useMenuItemHighlightState.js +62 -0
  81. package/dist/cjs/parts/DSMenuItemRendererFactory/useMenuItemHighlightState.js.map +7 -0
  82. package/dist/cjs/parts/DSOpinionatedButton/DSOpinionatedButton.js +100 -0
  83. package/dist/cjs/parts/DSOpinionatedButton/DSOpinionatedButton.js.map +7 -0
  84. package/dist/cjs/parts/DSOpinionatedButton/config/useOpinionatedButton.js +80 -0
  85. package/dist/cjs/parts/DSOpinionatedButton/config/useOpinionatedButton.js.map +7 -0
  86. package/dist/cjs/parts/DSOpinionatedButton/config/useTriggerEventsHandlers.js +98 -0
  87. package/dist/cjs/parts/DSOpinionatedButton/config/useTriggerEventsHandlers.js.map +7 -0
  88. package/dist/cjs/parts/DSOpinionatedButton/config/useValidateProps.js +40 -0
  89. package/dist/cjs/parts/DSOpinionatedButton/config/useValidateProps.js.map +7 -0
  90. package/dist/cjs/parts/DSOpinionatedButton/constants/index.js +48 -0
  91. package/dist/cjs/parts/DSOpinionatedButton/constants/index.js.map +7 -0
  92. package/dist/cjs/parts/DSOpinionatedButton/index.js +37 -0
  93. package/dist/cjs/parts/DSOpinionatedButton/index.js.map +7 -0
  94. package/dist/cjs/parts/DSOpinionatedButton/react-desc-prop-types.js +53 -0
  95. package/dist/cjs/parts/DSOpinionatedButton/react-desc-prop-types.js.map +7 -0
  96. package/dist/cjs/react-desc-prop-types.js +61 -25
  97. package/dist/cjs/react-desc-prop-types.js.map +2 -2
  98. package/dist/cjs/utils/nodesTypeguardsAndGetters.js +123 -0
  99. package/dist/cjs/utils/nodesTypeguardsAndGetters.js.map +7 -0
  100. package/dist/cjs/utils/useOptionsArrayToDsTree.js +55 -0
  101. package/dist/cjs/utils/useOptionsArrayToDsTree.js.map +7 -0
  102. package/dist/esm/DSMenuButton.js +19 -8
  103. package/dist/esm/DSMenuButton.js.map +2 -2
  104. package/dist/esm/config/useMenuButton.js +51 -20
  105. package/dist/esm/config/useMenuButton.js.map +3 -3
  106. package/dist/esm/config/useSplitInherithedProps.js +111 -0
  107. package/dist/esm/config/useSplitInherithedProps.js.map +7 -0
  108. package/dist/esm/config/useValidateProps.js.map +2 -2
  109. package/dist/esm/constants/index.js +17 -4
  110. package/dist/esm/constants/index.js.map +2 -2
  111. package/dist/esm/index.js +8 -4
  112. package/dist/esm/index.js.map +3 -3
  113. package/dist/esm/parts/DSFlyoutMenu/DSFlyoutMenu.js +66 -0
  114. package/dist/esm/parts/DSFlyoutMenu/DSFlyoutMenu.js.map +7 -0
  115. package/dist/esm/parts/DSFlyoutMenu/config/useFlyoutMenu.js +24 -0
  116. package/dist/esm/parts/DSFlyoutMenu/config/useFlyoutMenu.js.map +7 -0
  117. package/dist/esm/parts/DSFlyoutMenu/config/useValidateProps.js +10 -0
  118. package/dist/esm/parts/DSFlyoutMenu/config/useValidateProps.js.map +7 -0
  119. package/dist/esm/parts/DSFlyoutMenu/constants/index.js +16 -0
  120. package/dist/esm/parts/DSFlyoutMenu/constants/index.js.map +7 -0
  121. package/dist/esm/parts/DSFlyoutMenu/index.js +7 -0
  122. package/dist/esm/parts/DSFlyoutMenu/index.js.map +7 -0
  123. package/dist/esm/parts/DSFlyoutMenu/react-desc-prop-types.js +40 -0
  124. package/dist/esm/parts/DSFlyoutMenu/react-desc-prop-types.js.map +7 -0
  125. package/dist/esm/parts/DSMenuBehaviouralContextProvider/DSMenuBehaviouralContextProvider.js +42 -0
  126. package/dist/esm/parts/DSMenuBehaviouralContextProvider/DSMenuBehaviouralContextProvider.js.map +7 -0
  127. package/dist/esm/parts/DSMenuBehaviouralContextProvider/MenuBehaviouralContextProviderCTX.js +10 -0
  128. package/dist/esm/parts/DSMenuBehaviouralContextProvider/MenuBehaviouralContextProviderCTX.js.map +7 -0
  129. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.js +161 -0
  130. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.js.map +7 -0
  131. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useGlobalEvents.js +59 -0
  132. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useGlobalEvents.js.map +7 -0
  133. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js +65 -0
  134. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.js.map +7 -0
  135. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js +292 -0
  136. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.js.map +7 -0
  137. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuOpenStatus.js +36 -0
  138. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useMenuOpenStatus.js.map +7 -0
  139. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useValidateProps.js +10 -0
  140. package/dist/esm/parts/DSMenuBehaviouralContextProvider/config/useValidateProps.js.map +7 -0
  141. package/dist/esm/parts/DSMenuBehaviouralContextProvider/constants/Errors.js +28 -0
  142. package/dist/esm/parts/DSMenuBehaviouralContextProvider/constants/Errors.js.map +7 -0
  143. package/dist/esm/parts/DSMenuBehaviouralContextProvider/constants/index.js +14 -0
  144. package/dist/esm/parts/DSMenuBehaviouralContextProvider/constants/index.js.map +7 -0
  145. package/dist/esm/parts/DSMenuBehaviouralContextProvider/index.js +10 -0
  146. package/dist/esm/parts/DSMenuBehaviouralContextProvider/index.js.map +7 -0
  147. package/dist/esm/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js +23 -0
  148. package/dist/esm/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.js.map +7 -0
  149. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js +113 -0
  150. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.js.map +7 -0
  151. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/nodeGettersByCriterias.js +123 -0
  152. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/nodeGettersByCriterias.js.map +7 -0
  153. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js +14 -0
  154. package/dist/esm/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.js.map +7 -0
  155. package/dist/esm/parts/DSMenuItemRendererFactory/ActivableMenuItem.js +91 -0
  156. package/dist/esm/parts/DSMenuItemRendererFactory/ActivableMenuItem.js.map +7 -0
  157. package/dist/esm/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js +134 -0
  158. package/dist/esm/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.js.map +7 -0
  159. package/dist/esm/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.js +78 -0
  160. package/dist/esm/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.js.map +7 -0
  161. package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js +97 -0
  162. package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.js.map +7 -0
  163. package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js +148 -0
  164. package/dist/esm/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.js.map +7 -0
  165. package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js +105 -0
  166. package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.js.map +7 -0
  167. package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js +151 -0
  168. package/dist/esm/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.js.map +7 -0
  169. package/dist/esm/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js +137 -0
  170. package/dist/esm/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.js.map +7 -0
  171. package/dist/esm/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.js +30 -0
  172. package/dist/esm/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.js.map +7 -0
  173. package/dist/esm/parts/DSMenuItemRendererFactory/config/useValidateProps.js +10 -0
  174. package/dist/esm/parts/DSMenuItemRendererFactory/config/useValidateProps.js.map +7 -0
  175. package/dist/esm/parts/DSMenuItemRendererFactory/constants/index.js +18 -0
  176. package/dist/esm/parts/DSMenuItemRendererFactory/constants/index.js.map +7 -0
  177. package/dist/esm/parts/DSMenuItemRendererFactory/index.js +7 -0
  178. package/dist/esm/parts/DSMenuItemRendererFactory/index.js.map +7 -0
  179. package/dist/esm/parts/DSMenuItemRendererFactory/react-desc-prop-types.js +26 -0
  180. package/dist/esm/parts/DSMenuItemRendererFactory/react-desc-prop-types.js.map +7 -0
  181. package/dist/esm/parts/DSMenuItemRendererFactory/useMenuItemHighlightState.js +32 -0
  182. package/dist/esm/parts/DSMenuItemRendererFactory/useMenuItemHighlightState.js.map +7 -0
  183. package/dist/esm/parts/DSOpinionatedButton/DSOpinionatedButton.js +70 -0
  184. package/dist/esm/parts/DSOpinionatedButton/DSOpinionatedButton.js.map +7 -0
  185. package/dist/esm/parts/DSOpinionatedButton/config/useOpinionatedButton.js +53 -0
  186. package/dist/esm/parts/DSOpinionatedButton/config/useOpinionatedButton.js.map +7 -0
  187. package/dist/esm/parts/DSOpinionatedButton/config/useTriggerEventsHandlers.js +68 -0
  188. package/dist/esm/parts/DSOpinionatedButton/config/useTriggerEventsHandlers.js.map +7 -0
  189. package/dist/esm/parts/DSOpinionatedButton/config/useValidateProps.js +10 -0
  190. package/dist/esm/parts/DSOpinionatedButton/config/useValidateProps.js.map +7 -0
  191. package/dist/esm/parts/DSOpinionatedButton/constants/index.js +18 -0
  192. package/dist/esm/parts/DSOpinionatedButton/constants/index.js.map +7 -0
  193. package/dist/esm/parts/DSOpinionatedButton/index.js +10 -0
  194. package/dist/esm/parts/DSOpinionatedButton/index.js.map +7 -0
  195. package/dist/esm/parts/DSOpinionatedButton/react-desc-prop-types.js +23 -0
  196. package/dist/esm/parts/DSOpinionatedButton/react-desc-prop-types.js.map +7 -0
  197. package/dist/esm/react-desc-prop-types.js +62 -26
  198. package/dist/esm/react-desc-prop-types.js.map +2 -2
  199. package/dist/esm/utils/nodesTypeguardsAndGetters.js +93 -0
  200. package/dist/esm/utils/nodesTypeguardsAndGetters.js.map +7 -0
  201. package/dist/esm/utils/useOptionsArrayToDsTree.js +25 -0
  202. package/dist/esm/utils/useOptionsArrayToDsTree.js.map +7 -0
  203. package/dist/types/DSMenuButton.d.ts +4 -6
  204. package/dist/types/config/useMenuButton.d.ts +9 -13
  205. package/dist/types/config/useSplitInherithedProps.d.ts +495 -0
  206. package/dist/types/config/useValidateProps.d.ts +3 -3
  207. package/dist/types/constants/index.d.ts +14 -2
  208. package/dist/types/index.d.ts +4 -2
  209. package/dist/types/parts/DSFlyoutMenu/DSFlyoutMenu.d.ts +5 -0
  210. package/dist/types/parts/DSFlyoutMenu/config/useFlyoutMenu.d.ts +8 -0
  211. package/dist/types/parts/DSFlyoutMenu/config/useValidateProps.d.ts +3 -0
  212. package/dist/types/parts/DSFlyoutMenu/constants/index.d.ts +7 -0
  213. package/dist/types/parts/DSFlyoutMenu/index.d.ts +1 -0
  214. package/dist/types/parts/DSFlyoutMenu/react-desc-prop-types.d.ts +25 -0
  215. package/dist/types/parts/DSMenuBehaviouralContextProvider/DSMenuBehaviouralContextProvider.d.ts +5 -0
  216. package/dist/types/parts/DSMenuBehaviouralContextProvider/MenuBehaviouralContextProviderCTX.d.ts +5 -0
  217. package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useFocusTracker.d.ts +15 -0
  218. package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useGlobalEvents.d.ts +15 -0
  219. package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useMenuBehaviouralContextProvider.d.ts +15 -0
  220. package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.d.ts +18 -0
  221. package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useMenuOpenStatus.d.ts +17 -0
  222. package/dist/types/parts/DSMenuBehaviouralContextProvider/config/useValidateProps.d.ts +3 -0
  223. package/dist/types/parts/DSMenuBehaviouralContextProvider/constants/Errors.d.ts +15 -0
  224. package/dist/types/parts/DSMenuBehaviouralContextProvider/constants/index.d.ts +7 -0
  225. package/dist/types/parts/DSMenuBehaviouralContextProvider/index.d.ts +1 -0
  226. package/dist/types/parts/DSMenuBehaviouralContextProvider/react-desc-prop-types.d.ts +24 -0
  227. package/dist/types/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.d.ts +6 -0
  228. package/dist/types/parts/DSMenuBehaviouralContextProvider/utils/nodeGettersByCriterias.d.ts +35 -0
  229. package/dist/types/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.d.ts +13 -0
  230. package/dist/types/parts/DSMenuItemRendererFactory/ActivableMenuItem.d.ts +5 -0
  231. package/dist/types/parts/DSMenuItemRendererFactory/ActivableWithSubmenuMenuItem.d.ts +7 -0
  232. package/dist/types/parts/DSMenuItemRendererFactory/DSMenuItemRendererFactory.d.ts +5 -0
  233. package/dist/types/parts/DSMenuItemRendererFactory/MultipleSelectMenuItem.d.ts +5 -0
  234. package/dist/types/parts/DSMenuItemRendererFactory/MultipleSelectWithSubmenuMenuItem.d.ts +7 -0
  235. package/dist/types/parts/DSMenuItemRendererFactory/SingleSelectMenuItem.d.ts +5 -0
  236. package/dist/types/parts/DSMenuItemRendererFactory/SingleSelectWithSubmenuMenuItem.d.ts +7 -0
  237. package/dist/types/parts/DSMenuItemRendererFactory/WithSubmenuMenuItem.d.ts +7 -0
  238. package/dist/types/parts/DSMenuItemRendererFactory/config/useMenuItemRendererFactory.d.ts +6 -0
  239. package/dist/types/parts/DSMenuItemRendererFactory/config/useValidateProps.d.ts +3 -0
  240. package/dist/types/parts/DSMenuItemRendererFactory/constants/index.d.ts +6 -0
  241. package/dist/types/parts/DSMenuItemRendererFactory/index.d.ts +1 -0
  242. package/dist/types/parts/DSMenuItemRendererFactory/react-desc-prop-types.d.ts +24 -0
  243. package/dist/types/parts/DSMenuItemRendererFactory/useMenuItemHighlightState.d.ts +12 -0
  244. package/dist/types/parts/DSOpinionatedButton/DSOpinionatedButton.d.ts +5 -0
  245. package/dist/types/parts/DSOpinionatedButton/config/useOpinionatedButton.d.ts +38 -0
  246. package/dist/types/parts/DSOpinionatedButton/config/useTriggerEventsHandlers.d.ts +14 -0
  247. package/dist/types/parts/DSOpinionatedButton/config/useValidateProps.d.ts +3 -0
  248. package/dist/types/parts/DSOpinionatedButton/constants/index.d.ts +6 -0
  249. package/dist/types/parts/DSOpinionatedButton/index.d.ts +1 -0
  250. package/dist/types/parts/DSOpinionatedButton/react-desc-prop-types.d.ts +23 -0
  251. package/dist/types/react-desc-prop-types.d.ts +206 -41
  252. package/dist/types/utils/nodesTypeguardsAndGetters.d.ts +22 -0
  253. package/dist/types/utils/useOptionsArrayToDsTree.d.ts +8 -0
  254. package/package.json +18 -16
  255. package/dist/cjs/DSMenuButtonCTX.js.map +0 -7
  256. package/dist/cjs/parts/ItemFactory.js.map +0 -7
  257. package/dist/cjs/parts/Menu.js +0 -125
  258. package/dist/cjs/parts/Menu.js.map +0 -7
  259. package/dist/cjs/parts/MenuButtonContent.js +0 -156
  260. package/dist/cjs/parts/MenuButtonContent.js.map +0 -7
  261. package/dist/cjs/parts/MenuItem.js +0 -252
  262. package/dist/cjs/parts/MenuItem.js.map +0 -7
  263. package/dist/cjs/styled.js +0 -132
  264. package/dist/cjs/styled.js.map +0 -7
  265. package/dist/esm/DSMenuButtonCTX.js +0 -8
  266. package/dist/esm/DSMenuButtonCTX.js.map +0 -7
  267. package/dist/esm/parts/ItemFactory.js +0 -36
  268. package/dist/esm/parts/ItemFactory.js.map +0 -7
  269. package/dist/esm/parts/Menu.js +0 -95
  270. package/dist/esm/parts/Menu.js.map +0 -7
  271. package/dist/esm/parts/MenuButtonContent.js +0 -126
  272. package/dist/esm/parts/MenuButtonContent.js.map +0 -7
  273. package/dist/esm/parts/MenuItem.js +0 -229
  274. package/dist/esm/parts/MenuItem.js.map +0 -7
  275. package/dist/esm/styled.js +0 -102
  276. package/dist/esm/styled.js.map +0 -7
  277. package/dist/types/DSMenuButtonCTX.d.ts +0 -15
  278. package/dist/types/parts/ItemFactory.d.ts +0 -14
  279. package/dist/types/parts/Menu.d.ts +0 -14
  280. package/dist/types/parts/MenuButtonContent.d.ts +0 -1
  281. package/dist/types/parts/MenuItem.d.ts +0 -21
  282. package/dist/types/styled.d.ts +0 -16
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/config/useMenuItemEventsHandlers.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable no-console */\n/* eslint-disable max-lines */\n// in this files the returns are not useless, they are used to clearly demark the intended behavior shortcircuit for the next developer that reads the code\n/* eslint-disable no-useless-return */\n/* eslint-disable complexity */\n/* eslint-disable max-statements */\nimport debounce from 'lodash/debounce';\nimport React from 'react';\nimport { type DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport {\n isFocusableNode,\n isMultipleSelectNode,\n isRootNode,\n isSingleSelectNode,\n isWithSubmenuNode,\n isWithSubmenuOnlyNode,\n} from '../../../utils/nodesTypeguardsAndGetters.js';\nimport { FORBIDDEN_BEHAVIOURS, UNEXPECTED_INTERNAL_ERRORS } from '../constants/Errors.js';\nimport { type DSMenuBehaviouralContextProviderT } from '../react-desc-prop-types.js';\nimport { getNewSelectionMultipleSelect } from '../utils/multipleSelectionHelpers.js';\nimport { getSubMenusPath } from '../utils/nodeGettersByCriterias.js';\nimport { getNewSelectionSingleSelect } from '../utils/singleSelectionHelpers.js';\nimport type { useFocusTracker } from './useFocusTracker.js';\nimport type { useMenuOpenStatus } from './useMenuOpenStatus.js';\n\ntype ItemKeydownHelpersArgs = {\n pseudoFocusedItemNode: DSMenuButtonT.PseudoFocusableMenuNodes;\n event?: React.KeyboardEvent | React.MouseEvent;\n};\ntype SubmenuChangeMetainfo = {\n itemNode: DSMenuButtonT.PseudoFocusableMenuNodes;\n event?: React.SyntheticEvent;\n};\n\ntype UseMenuItemEventsHandlersConfig = {\n propsWithDefault: DSMenuBehaviouralContextProviderT.InternalProps;\n focusTrackers: ReturnType<typeof useFocusTracker>;\n menuOpenStatus: ReturnType<typeof useMenuOpenStatus>;\n handleChangeOpenedSubItems: Required<DSMenuButtonT.MenuBehaviouralLayerOptionalProps>['onDisplayedSubmenuChange'];\n};\n\nexport const useMenuItemEventsHandlers = ({\n propsWithDefault,\n focusTrackers,\n menuOpenStatus,\n handleChangeOpenedSubItems,\n}: UseMenuItemEventsHandlersConfig) => {\n const { onItemSelected, onActivateItem, selectedItems } = propsWithDefault;\n const { onOpinionatedClose } = menuOpenStatus;\n const {\n trackFocusFirstChildItem,\n trackFocusLastChildItem,\n trackFocusNextItem,\n trackFocusPreviousItem,\n trackFocusParentItem,\n trackFocusNode,\n focusedElementItemNode,\n } = focusTrackers;\n\n const openSubmenu = React.useCallback(\n ({\n itemNode,\n event,\n }: {\n itemNode: DSMenuButtonT.WithSubmenuMenuNodes;\n event?: React.KeyboardEvent | React.MouseEvent;\n }) => {\n if (!isWithSubmenuNode(itemNode)) {\n console.log('openSubmenu -> itemNode:', itemNode);\n throw FORBIDDEN_BEHAVIOURS.TRYING_TO_OPEN_SUBMENU_OF_NODE_WITHOUT_SUBMENU;\n }\n const subMenuNodesPath = getSubMenusPath(itemNode);\n const metainfo: SubmenuChangeMetainfo = { itemNode, event };\n const newOpenedItems: DSMenuButtonT.WithSubmenuMenuNodes[] = [...subMenuNodesPath, itemNode];\n handleChangeOpenedSubItems(newOpenedItems, metainfo);\n },\n [handleChangeOpenedSubItems],\n );\n const closeCurrentSubmenu = React.useCallback(\n ({\n itemNode,\n event,\n }: {\n itemNode: DSMenuButtonT.PseudoFocusableMenuNodes;\n event?: React.KeyboardEvent | React.MouseEvent;\n }) => {\n const metainfo: SubmenuChangeMetainfo = { itemNode, event };\n const subMenuNodesPath = getSubMenusPath(itemNode);\n // if length is 0, it means the parent is the root node, so we close all the submenus\n if (subMenuNodesPath.length === 0) {\n handleChangeOpenedSubItems([], metainfo);\n return { currentSubmenuWasMainMenu: true };\n }\n\n // we want to close current submenu, so we pop the last element\n // getSubMenusPath guarantees the order by walkParents + reverse at the end\n subMenuNodesPath.pop();\n handleChangeOpenedSubItems(subMenuNodesPath, metainfo);\n return { currentSubmenuWasMainMenu: false };\n },\n [handleChangeOpenedSubItems],\n );\n /*\n * 13th August 2024:\n * https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/\n * Additional roles, states, and properties needed for the menu element are described in the Menu and Menubar Pattern.\n * https://www.w3.org/WAI/ARIA/apg/patterns/menubar/\n * Because menubar and menu elements are composite widgets as described in the practice for Keyboard Navigation Inside Components,\n * Tab and Shift + Tab do not move focus among the items in the menu.\n * Instead, the keyboard commands described in this section enable users to move focus among the elements in a menubar or menu.\n * Tab and Shift + Tab:\n * - Move focus into a menubar <- Not relevant for this component, this is ONLY FOR MENU, not for MENUBARS\n * - When focus is on a menuitem in a menu or menubar, move focus out of the menu or menubar, and close all menus and submenus.\n * ************************************************************************************************************************************\n * this will be implemented by not setting document.activeElement to the menuitem but keeping it on the trigger button\n * why? because there is no javascript API to trigger a \"tab\"/\"shift+tab\" navigation and any algorithm trying to do so is fragile\n * also, this is enforced by w3.org too as per:\n * ************************************************************************************************************************************\n * Note that Tab and Shift + Tab do not move focus into a menu.\n * Unlike a menubar, a menu is not visually persistent,\n * and authors are responsible for ensuring focus moves to an item inside of a menu when the menu opens.\n *\n */\n const handleMenuItemEnterKeyDown = React.useCallback(\n ({ pseudoFocusedItemNode, event }: ItemKeydownHelpersArgs) => {\n // Enter:\n // - When focus is on a menuitem that has a submenu, opens the submenu and places focus on its first item.\n // ...\n if (isWithSubmenuOnlyNode(pseudoFocusedItemNode)) {\n openSubmenu({ itemNode: pseudoFocusedItemNode, event });\n trackFocusFirstChildItem(pseudoFocusedItemNode);\n } else {\n // - Otherwise, activates the item...\n\n // ----------------------------------\n // 4. Although it is recommended that authors avoid doing so,\n // some implementations of navigation menubars may have menuitem elements that both perform a function and open a submenu.\n // In such implementations, Enter and Space perform a navigation function,\n // e.g., load new content, while Down Arrow, in a horizontal menubar, opens the submenu associated with that same menuitem.\n // ---------------------------------\n // Based on an investigation, the above statement is not specific to \"navigation\" nor to ONLY \"menubars\", it really is about \"menuitems\" in general\n // as long as the role=\"menuitem\" & aria-haspopup=\"${id-of-the-submenu}\" & aria-expanded=\"${true/false}\" (& aria-orientation=\"vertical/horizontal\" if non-default)\n // are set, the Screen Readers will provide the same announcement for the menuitem regardless of the parent role\n\n // \"activation\" is a concept,\n // WCAG here implies that for menuitemscheckbox and menuitemsradio this triggers the selection\n // for menuitems (that doesn't fit selection nor submenus) it triggers the action\n // this also triggers enter -> single-select-item-with-submenu as expected\n if (isMultipleSelectNode(pseudoFocusedItemNode)) {\n const newSelection = getNewSelectionMultipleSelect(selectedItems, pseudoFocusedItemNode);\n onItemSelected(newSelection, { itemNode: pseudoFocusedItemNode, event });\n } else if (isSingleSelectNode(pseudoFocusedItemNode)) {\n const newSelection = getNewSelectionSingleSelect(selectedItems, pseudoFocusedItemNode);\n onItemSelected(newSelection, { itemNode: pseudoFocusedItemNode, event });\n } else {\n onActivateItem(pseudoFocusedItemNode, { itemNode: pseudoFocusedItemNode, event });\n }\n // ... and closes the menu.\n const metainfo: SubmenuChangeMetainfo = { itemNode: pseudoFocusedItemNode, event };\n const newOpenedItems: DSMenuButtonT.WithSubmenuMenuNodes[] = [];\n handleChangeOpenedSubItems(newOpenedItems, metainfo);\n onOpinionatedClose();\n }\n },\n [\n trackFocusFirstChildItem,\n openSubmenu,\n handleChangeOpenedSubItems,\n onOpinionatedClose,\n selectedItems,\n onItemSelected,\n onActivateItem,\n ],\n );\n const handleMenuItemSpaceKeyDown = React.useCallback(\n ({ pseudoFocusedItemNode, event }: ItemKeydownHelpersArgs) => {\n // Space:\n // [X] (Optional): When focus is on a menuitem that has a submenu, opens the submenu and places focus on its first item.\n // ----------------------------------\n // 4. Although it is recommended that authors avoid doing so,\n // some implementations of navigation menubars may have menuitem elements that both perform a function and open a submenu.\n // In such implementations, Enter and Space perform a navigation function,\n // e.g., load new content, while Down Arrow, in a horizontal menubar, opens the submenu associated with that same menuitem.\n // ---------------------------------\n // Based on an investigation, the above statement is not specific to \"navigation\" nor to ONLY \"menubars\", it really is about \"menuitems\" in general\n // as long as the role=\"menuitem\" & aria-haspopup=\"${id-of-the-submenu}\" & aria-expanded=\"${true/false}\" (& aria-orientation=\"vertical/horizontal\" if non-default)\n // are set, the Screen Readers will provide the same announcement for the menuitem regardless of the parent role\n if (isWithSubmenuOnlyNode(pseudoFocusedItemNode)) {\n openSubmenu({ itemNode: pseudoFocusedItemNode, event });\n trackFocusFirstChildItem(pseudoFocusedItemNode);\n return;\n }\n // [X] (Optional): When focus is on a menuitemcheckbox, changes the state without closing the menu.\n if (isMultipleSelectNode(pseudoFocusedItemNode)) {\n const newSelection = getNewSelectionMultipleSelect(selectedItems, pseudoFocusedItemNode);\n onItemSelected(newSelection, { itemNode: pseudoFocusedItemNode, event });\n return;\n }\n // [X] (Optional): When focus is on a menuitemradio that is not checked, without closing the menu,\n // checks the focused menuitemradio and unchecks any other checked menuitemradio element in the same group.\n if (isSingleSelectNode(pseudoFocusedItemNode)) {\n const newSelection = getNewSelectionSingleSelect(selectedItems, pseudoFocusedItemNode);\n onItemSelected(newSelection, { itemNode: pseudoFocusedItemNode, event });\n return;\n }\n // [X] (Optional): When focus is on a menuitem that does not have a submenu, activates the menuitem and closes the menu.\n onActivateItem(pseudoFocusedItemNode, { itemNode: pseudoFocusedItemNode, event });\n\n const metainfo: SubmenuChangeMetainfo = { itemNode: pseudoFocusedItemNode, event };\n const newOpenedItems: DSMenuButtonT.WithSubmenuMenuNodes[] = [];\n handleChangeOpenedSubItems(newOpenedItems, metainfo);\n onOpinionatedClose();\n },\n [\n onActivateItem,\n handleChangeOpenedSubItems,\n onOpinionatedClose,\n trackFocusFirstChildItem,\n openSubmenu,\n selectedItems,\n onItemSelected,\n ],\n );\n const handleMenuItemRightArrowKeyDown = React.useCallback(\n ({ pseudoFocusedItemNode, event }: ItemKeydownHelpersArgs) => {\n // Right Arrow:\n // [N/A] When focus is in a menubar, moves focus to the next item, optionally wrapping from the last to the first.\n // /\\ Not relevant for this component, this is ONLY FOR MENU, not for MENUBARS\n\n // [X] When focus is in a menu and on a menuitem that has a submenu, opens the submenu and places focus on its first item.\n // [N/A] When focus is in a menu and on an item that does not have a submenu, performs the following 3 actions:\n // [N/A] Closes the submenu and any parent menus.\n // [N/A] Moves focus to the next item in the menubar.\n // /\\ Not relevant for this component, this is ONLY FOR MENU, not for MENUBARS\n\n // [X] If focus is now on a menuitem with a submenu, either:\n // [X] (Recommended) opens the submenu of that menuitem without moving focus into the submenu,\n // /\\ we choose the recommended option\n // OR\n // [N/A] opens the submenu of that menuitem and places focus on the first item in the submenu.\n // ***********************************************************\n // Dimsum implements IoC, if APP side for whatever reason wants to open the new sub sub menu,\n // it's up to them to listen to the pseudo focus event and open the sub sub menu\n // ***********************************************************\n if (isWithSubmenuNode(pseudoFocusedItemNode)) {\n openSubmenu({ itemNode: pseudoFocusedItemNode, event });\n trackFocusFirstChildItem(pseudoFocusedItemNode);\n return;\n }\n // Note that if the menubar were not present, e.g., the menus were opened from a menubutton,\n // Right Arrow would not do anything when focus is on an item that does not have a submenu.\n return;\n },\n [openSubmenu, trackFocusFirstChildItem],\n );\n\n const handleMenuItemLeftArrowKeyDown = React.useCallback(\n ({ pseudoFocusedItemNode, event }: ItemKeydownHelpersArgs) => {\n // Left Arrow:\n // [N/A] When focus is in a menubar, moves focus to the previous item, optionally wrapping from the first to the last.\n // /\\ Not relevant for this component, this is ONLY FOR MENU, not for MENUBARS\n\n // [X] When focus is in a submenu of an item in a menu, closes the submenu and returns focus to the parent menuitem.\n const { currentSubmenuWasMainMenu } = closeCurrentSubmenu({ itemNode: pseudoFocusedItemNode, event });\n if (!currentSubmenuWasMainMenu) {\n trackFocusParentItem(pseudoFocusedItemNode);\n }\n\n // [N/A] When focus is in a submenu of an item in a menubar, performs the following 3 actions:\n // [N/A] Closes the submenu.\n // [N/A] Moves focus to the previous item in the menubar.\n // [N/A] If focus is now on a menuitem with a submenu, either:\n // (Recommended) opens the submenu of that menuitem without moving focus into the submenu,\n // or\n // opens the submenu of that menuitem and places focus on the first item in the submenu.\n // /\\ Not relevant for this component, this is ONLY FOR MENU, not for MENUBARS\n },\n [closeCurrentSubmenu, trackFocusParentItem],\n );\n\n const handleFocusableMenuItemKeyDown = React.useCallback<React.KeyboardEventHandler<HTMLDivElement>>(\n (event) => {\n const pseudoFocusedItemNode = focusedElementItemNode.current;\n // if there is no focused item, we can't handle the logics\n if (pseudoFocusedItemNode === null) throw UNEXPECTED_INTERNAL_ERRORS.FOCUSED_ITEM_NODE_NOT_SET;\n // if the item contains an `onKeyDown` prop, we trigger it\n if (pseudoFocusedItemNode.plainItem.onKeyDown) pseudoFocusedItemNode.plainItem.onKeyDown(event);\n\n // Down Arrow:\n // [N/A] When focus is on a menuitem in a menubar, and that menuitem has a submenu, opens the submenu and places focus on the first item in the submenu.\n // /\\ Not relevant for this component, this is ONLY FOR MENU, not for MENUBARS\n // [X] When focus is in a menu, moves focus to the next item,\n // [X] optionally wrapping from the last to the first.\n if (event.key === 'ArrowDown') {\n trackFocusNextItem(pseudoFocusedItemNode);\n return;\n }\n // Up Arrow:\n // [X] When focus is in a menu, moves focus to the previous item,\n // [X] optionally wrapping from the first to the last.\n // [N/A] (Optional): When focus is on a menuitem in a menubar, and that menuitem has a submenu, opens the submenu and places focus on the last item in the submenu.\n // /\\ Not relevant for this component, this is ONLY FOR MENU, not for MENUBARS\n if (event.key === 'ArrowUp') {\n trackFocusPreviousItem(pseudoFocusedItemNode);\n return;\n }\n // Left Arrow:\n if (event.key === 'ArrowLeft') {\n handleMenuItemLeftArrowKeyDown({ pseudoFocusedItemNode, event });\n return;\n }\n // Home: If arrow key wrapping is not supported, moves focus to the first item in the current menu or menubar.\n if (event.key === 'Home') {\n if (!pseudoFocusedItemNode.parent) {\n console.log('handleFocusableMenuItemKeyDown -> Home > focused item node', pseudoFocusedItemNode);\n // should be impossible, at most the .parent is the root node, which is not able to trigger this event\n throw UNEXPECTED_INTERNAL_ERRORS.FOCUSED_ITEM_HAS_NO_PARENT;\n }\n trackFocusFirstChildItem(pseudoFocusedItemNode.parent);\n return;\n }\n // End: If arrow key wrapping is not supported, moves focus to the last item in the current menu or menubar.\n if (event.key === 'End') {\n if (!pseudoFocusedItemNode.parent) {\n console.log('handleFocusableMenuItemKeyDown -> Home > focused item node', pseudoFocusedItemNode);\n // should be impossible, at most the .parent is the root node, which is not able to trigger this event\n throw UNEXPECTED_INTERNAL_ERRORS.FOCUSED_ITEM_HAS_NO_PARENT;\n }\n trackFocusLastChildItem(pseudoFocusedItemNode.parent);\n return;\n }\n // Escape: Close the menu that contains focus and return focus to the element or context, e.g., menu button or parent menuitem, from which the menu was opened\n if (event.key === 'Escape') {\n const { currentSubmenuWasMainMenu } = closeCurrentSubmenu({ itemNode: pseudoFocusedItemNode, event });\n trackFocusParentItem(pseudoFocusedItemNode);\n // if the menu we are trying to close is the main menu, we adittionally close the main menu itself\n if (currentSubmenuWasMainMenu) {\n // if parent is the root node, we close also the main menu\n onOpinionatedClose();\n }\n return;\n }\n /* ************************************************************************************\n * ******* ACTIVATION & SUBMENU keys doesn't apply if the item is \"disabled\" **********\n * ************************************************************************************ */\n if (pseudoFocusedItemNode.plainItem.disabled) return;\n // Enter:\n if (event.key === 'Enter') {\n handleMenuItemEnterKeyDown({ pseudoFocusedItemNode, event });\n return;\n }\n // Space:\n if (event.key === ' ') {\n handleMenuItemSpaceKeyDown({ pseudoFocusedItemNode, event });\n return;\n }\n // Right Arrow:\n if (event.key === 'ArrowRight') {\n handleMenuItemRightArrowKeyDown({ pseudoFocusedItemNode, event });\n return;\n }\n },\n [\n focusedElementItemNode,\n handleMenuItemEnterKeyDown,\n handleMenuItemSpaceKeyDown,\n trackFocusNextItem,\n trackFocusPreviousItem,\n handleMenuItemRightArrowKeyDown,\n handleMenuItemLeftArrowKeyDown,\n trackFocusFirstChildItem,\n trackFocusLastChildItem,\n closeCurrentSubmenu,\n trackFocusParentItem,\n onOpinionatedClose,\n ],\n );\n\n const handleFocusableMenuItemOnMouseEnter = React.useCallback(\n (itemNode: DSMenuButtonT.PseudoFocusableMenuNodes, event: React.MouseEvent) => {\n if (!isFocusableNode(itemNode)) {\n console.log('handleFocusableMenuItemOnMouseEnter > itemNode:', itemNode);\n throw FORBIDDEN_BEHAVIOURS.TRYING_TO_FOCUS_NON_FOCUSABLE_NODE;\n }\n // on hover -> we track the hovered item as the focused one on top of which events should work on\n trackFocusNode(itemNode);\n if (!isWithSubmenuNode(itemNode)) {\n // if the item has nosubmenu we close all the siblings submenus\n const subMenuNodesPath = getSubMenusPath(itemNode);\n const metainfo: SubmenuChangeMetainfo = { itemNode, event };\n const newOpenedItems: DSMenuButtonT.WithSubmenuMenuNodes[] = [...subMenuNodesPath];\n handleChangeOpenedSubItems(newOpenedItems, metainfo);\n return;\n }\n // if the item is disabled, we don't open the submenu\n if (itemNode.plainItem.disabled) return;\n // if not disabled and it has a submenu, we open it\n openSubmenu({ itemNode, event });\n },\n [handleChangeOpenedSubItems, openSubmenu, trackFocusNode],\n );\n\n const handleFocusableMenuItemClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n const pseudoFocusedItemNode = focusedElementItemNode.current;\n if (pseudoFocusedItemNode === null) throw UNEXPECTED_INTERNAL_ERRORS.FOCUSED_ITEM_NODE_NOT_SET;\n // if the item is disabled, we don't do anything\n if (pseudoFocusedItemNode.plainItem.disabled) return;\n // we need to handle which submenu needs to close automagically based on the click\n // starting from the itemNode, we check:\n // - the parent of the itemNode is root?\n // - yes -> we close all the submenus\n const parentMenuNode = pseudoFocusedItemNode.parent;\n if (isRootNode(parentMenuNode)) {\n const metainfo: SubmenuChangeMetainfo = { itemNode: pseudoFocusedItemNode, event };\n const newOpenedItems: DSMenuButtonT.WithSubmenuMenuNodes[] = [];\n handleChangeOpenedSubItems(newOpenedItems, metainfo);\n } else {\n // - no -> we close all the submenus that are not in the path to the root of the itemNode\n // this is necessary on click because the user can still interact with other (visual) depths of the menu\n // during keyboard navigation, the user is limited to the current (visual) depth\n const newOpenedItems: DSMenuButtonT.WithSubmenuMenuNodes[] = [...getSubMenusPath(pseudoFocusedItemNode)];\n // - if the clicked node has a submenu, keep it open\n if (isWithSubmenuNode(pseudoFocusedItemNode)) {\n newOpenedItems.push(pseudoFocusedItemNode);\n }\n const metainfo: SubmenuChangeMetainfo = { itemNode: pseudoFocusedItemNode, event };\n handleChangeOpenedSubItems(newOpenedItems, metainfo);\n }\n\n // to all effects and purposes, the click event is the same as the space key\n // the main difference between enter and space is that\n // - enter ALWAYS closes the menu excepts for submenus\n // - space closes the menu if \"activable\", selections doesn't, submenus doesn't\n handleMenuItemSpaceKeyDown({ pseudoFocusedItemNode, event });\n // if the item contains an `onClick` prop, we trigger it\n if (pseudoFocusedItemNode.plainItem.onClick) pseudoFocusedItemNode.plainItem.onClick(event);\n },\n [focusedElementItemNode, handleMenuItemSpaceKeyDown, handleChangeOpenedSubItems],\n );\n\n // SR softwares have a setting (that is on by default in mac VoiceOver)\n // that express the will from the user to have the \"voice over pseudo navigation\"\n // also \"act as a navigation\", it usually isn't so easy to catch/see this\n // because usually special key navigation is a secondary way to navigate\n // BUT, some role (surprise suprise, menu falls into this category)\n // inverts the \"navigation\" and \"special key navigation\" when SR is on by default\n // Long story short, if when the item triggers a focus event, we don't track it\n // and the user uses the \"special key navigation\" to navigate\n // weird navigation and visual feedbacks will happen\n // This handler ensures that\n // the focus is tracked when the item is focused via special key navigation in the SR software preference asking for it is on\n // IMPORTANT:\n // we need to make sure this is only invoked for the last focused item if many focus events are triggered in quick succession\n // so we MUST debounce this\n const handleMenuItemFocusReconciliation: (itemNode: DSMenuButtonT.PseudoFocusableMenuNodes) => void =\n React.useCallback(\n (itemNode) => {\n debounce(\n () => {\n if (focusedElementItemNode.current?.dsId !== itemNode.dsId) trackFocusNode(itemNode);\n },\n 10,\n { leading: false, trailing: true },\n );\n },\n\n [focusedElementItemNode, trackFocusNode],\n );\n return React.useMemo(\n () => ({\n handleFocusableMenuItemKeyDown,\n handleFocusableMenuItemClick,\n handleFocusableMenuItemOnMouseEnter,\n handleMenuItemFocusReconciliation,\n }),\n [\n handleFocusableMenuItemClick,\n handleFocusableMenuItemKeyDown,\n handleFocusableMenuItemOnMouseEnter,\n handleMenuItemFocusReconciliation,\n ],\n );\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["React"]
7
+ }
@@ -0,0 +1,36 @@
1
+ import * as React from "react";
2
+ import React2 from "react";
3
+ const useMenuOpenStatus = ({ propsWithDefault, focusTrackers }) => {
4
+ const { trackFocusTrigger, trackFocusFirstChildItem, trackFocusLastChildItem, preventBlurReset } = focusTrackers;
5
+ const { onClose, onOpen, optionsTree } = propsWithDefault;
6
+ const [isMenuOpen, setIsMenuOpen] = React2.useState(false);
7
+ const onOpinionatedClose = React2.useCallback(
8
+ ({ skipFocus } = { skipFocus: false }) => {
9
+ setIsMenuOpen(false);
10
+ if (onClose) onClose();
11
+ if (!skipFocus) trackFocusTrigger();
12
+ preventBlurReset.current = false;
13
+ },
14
+ [onClose, preventBlurReset, trackFocusTrigger]
15
+ );
16
+ const onOpinionatedOpen = React2.useCallback(
17
+ (config) => {
18
+ const { focusLastChild = false } = config || {};
19
+ setIsMenuOpen(true);
20
+ if (onOpen) onOpen();
21
+ const typeCastedOptionsTree = optionsTree;
22
+ if (focusLastChild) trackFocusLastChildItem(typeCastedOptionsTree);
23
+ else trackFocusFirstChildItem(typeCastedOptionsTree);
24
+ preventBlurReset.current = true;
25
+ },
26
+ [onOpen, optionsTree, preventBlurReset, trackFocusFirstChildItem, trackFocusLastChildItem]
27
+ );
28
+ return React2.useMemo(
29
+ () => ({ isMenuOpen, onOpinionatedClose, onOpinionatedOpen }),
30
+ [isMenuOpen, onOpinionatedClose, onOpinionatedOpen]
31
+ );
32
+ };
33
+ export {
34
+ useMenuOpenStatus
35
+ };
36
+ //# sourceMappingURL=useMenuOpenStatus.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/config/useMenuOpenStatus.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import React from 'react';\nimport { type DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport { type DSMenuBehaviouralContextProviderT } from '../react-desc-prop-types.js';\nimport type { useFocusTracker } from './useFocusTracker.js';\n\ntype UseMenuOpenStatusConfig = {\n propsWithDefault: DSMenuBehaviouralContextProviderT.InternalProps;\n focusTrackers: ReturnType<typeof useFocusTracker>;\n};\n\ntype OnOpinionatedOpenConfig = {\n focusLastChild?: boolean;\n};\n\nexport const useMenuOpenStatus = ({ propsWithDefault, focusTrackers }: UseMenuOpenStatusConfig) => {\n // when the menu closes the focus must be returned to the trigger\n const { trackFocusTrigger, trackFocusFirstChildItem, trackFocusLastChildItem, preventBlurReset } = focusTrackers;\n const { onClose, onOpen, optionsTree } = propsWithDefault;\n const [isMenuOpen, setIsMenuOpen] = React.useState(false);\n\n const onOpinionatedClose = React.useCallback(\n ({ skipFocus } = { skipFocus: false }) => {\n setIsMenuOpen(false);\n if (onClose) onClose();\n if (!skipFocus) trackFocusTrigger();\n preventBlurReset.current = false;\n },\n [onClose, preventBlurReset, trackFocusTrigger],\n );\n\n const onOpinionatedOpen = React.useCallback(\n (config?: OnOpinionatedOpenConfig) => {\n const { focusLastChild = false } = config || {};\n setIsMenuOpen(true);\n if (onOpen) onOpen();\n // Focus on the first item\n // this conversion is a unsafe but that's because we are handling the treeroot node\n // and DSTree doesn't have direct support for typescript tree-root interfaces being different from the rest of the tree\n // the function trackFocusLastChildItem takes any MenuNode and generates the list from subitems autonomously\n // except for the \"trigger\" scenario, we always expect to invoke this function with a PseudoFocusableMenuNodes\n // so we typecast here instead of losing the type safety in the rest of the code\n const typeCastedOptionsTree = optionsTree as DSMenuButtonT.PseudoFocusableMenuNodes;\n if (focusLastChild) trackFocusLastChildItem(typeCastedOptionsTree);\n else trackFocusFirstChildItem(typeCastedOptionsTree);\n preventBlurReset.current = true;\n },\n [onOpen, optionsTree, preventBlurReset, trackFocusFirstChildItem, trackFocusLastChildItem],\n );\n\n return React.useMemo(\n () => ({ isMenuOpen, onOpinionatedClose, onOpinionatedOpen }),\n [isMenuOpen, onOpinionatedClose, onOpinionatedOpen],\n );\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,OAAOA,YAAW;AAcX,MAAM,oBAAoB,CAAC,EAAE,kBAAkB,cAAc,MAA+B;AAEjG,QAAM,EAAE,mBAAmB,0BAA0B,yBAAyB,iBAAiB,IAAI;AACnG,QAAM,EAAE,SAAS,QAAQ,YAAY,IAAI;AACzC,QAAM,CAAC,YAAY,aAAa,IAAIA,OAAM,SAAS,KAAK;AAExD,QAAM,qBAAqBA,OAAM;AAAA,IAC/B,CAAC,EAAE,UAAU,IAAI,EAAE,WAAW,MAAM,MAAM;AACxC,oBAAc,KAAK;AACnB,UAAI,QAAS,SAAQ;AACrB,UAAI,CAAC,UAAW,mBAAkB;AAClC,uBAAiB,UAAU;AAAA,IAC7B;AAAA,IACA,CAAC,SAAS,kBAAkB,iBAAiB;AAAA,EAC/C;AAEA,QAAM,oBAAoBA,OAAM;AAAA,IAC9B,CAAC,WAAqC;AACpC,YAAM,EAAE,iBAAiB,MAAM,IAAI,UAAU,CAAC;AAC9C,oBAAc,IAAI;AAClB,UAAI,OAAQ,QAAO;AAOnB,YAAM,wBAAwB;AAC9B,UAAI,eAAgB,yBAAwB,qBAAqB;AAAA,UAC5D,0BAAyB,qBAAqB;AACnD,uBAAiB,UAAU;AAAA,IAC7B;AAAA,IACA,CAAC,QAAQ,aAAa,kBAAkB,0BAA0B,uBAAuB;AAAA,EAC3F;AAEA,SAAOA,OAAM;AAAA,IACX,OAAO,EAAE,YAAY,oBAAoB,kBAAkB;AAAA,IAC3D,CAAC,YAAY,oBAAoB,iBAAiB;AAAA,EACpD;AACF;",
6
+ "names": ["React"]
7
+ }
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ import { useValidateTypescriptPropTypes } from "@elliemae/ds-props-helpers";
3
+ import { DSMenuBehaviouralContextProviderName } from "../constants/index.js";
4
+ const useValidateProps = (props, propTypes) => {
5
+ useValidateTypescriptPropTypes(props, propTypes, DSMenuBehaviouralContextProviderName);
6
+ };
7
+ export {
8
+ useValidateProps
9
+ };
10
+ //# sourceMappingURL=useValidateProps.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/config/useValidateProps.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useValidateTypescriptPropTypes } from '@elliemae/ds-props-helpers';\nimport type { ValidationMap } from '@elliemae/ds-props-helpers';\nimport { type DSMenuBehaviouralContextProviderT } from '../react-desc-prop-types.js';\nimport { DSMenuBehaviouralContextProviderName } from '../constants/index.js';\n\nexport const useValidateProps = (\n props: DSMenuBehaviouralContextProviderT.InternalProps,\n propTypes: ValidationMap<DSMenuBehaviouralContextProviderT.Props>,\n): void => {\n // we validate the \"required if\" via 'isRequiredIf from our custom PropTypes\n useValidateTypescriptPropTypes(props, propTypes, DSMenuBehaviouralContextProviderName);\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,sCAAsC;AAG/C,SAAS,4CAA4C;AAE9C,MAAM,mBAAmB,CAC9B,OACA,cACS;AAET,iCAA+B,OAAO,WAAW,oCAAoC;AACvF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ const TREE_STRUCTURE_ERRORS = {
3
+ PARENT_NOT_GROUP: new Error(
4
+ "Tree structure violation: parent node of single-selectionable node MUST ALWAYS be a single select group node"
5
+ ),
6
+ GROUP_WITHOUT_PARENT: new Error("Tree structure violation: single select group node has no parent"),
7
+ NODE_CANNOT_HAVE_CHILDREN: new Error("Tree structure violation: node cannot have children")
8
+ };
9
+ const FORBIDDEN_BEHAVIOURS = {
10
+ TRYING_TO_FOCUS_NON_FOCUSABLE_NODE: new Error("Behavioural violation: trying to focus a non-focusable node"),
11
+ TRYING_TO_OPEN_SUBMENU_OF_NODE_WITHOUT_SUBMENU: new Error(
12
+ "Behavioural violation: trying to open submenu of node without submenu"
13
+ )
14
+ };
15
+ const UNEXPECTED_INTERNAL_ERRORS = {
16
+ FOCUSED_ITEM_NODE_NOT_SET: new Error("Internal error: focused item node not set"),
17
+ FOCUSED_ITEM_HAS_NO_PARENT: new Error("Internal error: focused item has no parent node (is root?)"),
18
+ NODE_WITHOUT_PARENT: new Error("Internal error: the node has no parent"),
19
+ CALCULATING_MULTI_SELECTION_OF_NON_MULTI_SELECTION_NODE: new Error(
20
+ "Internal error: the node is not multi-selectable or wrongly recognized as non-multi-selectable"
21
+ )
22
+ };
23
+ export {
24
+ FORBIDDEN_BEHAVIOURS,
25
+ TREE_STRUCTURE_ERRORS,
26
+ UNEXPECTED_INTERNAL_ERRORS
27
+ };
28
+ //# sourceMappingURL=Errors.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/constants/Errors.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "export const TREE_STRUCTURE_ERRORS = {\n PARENT_NOT_GROUP: new Error(\n 'Tree structure violation: parent node of single-selectionable node MUST ALWAYS be a single select group node',\n ),\n GROUP_WITHOUT_PARENT: new Error('Tree structure violation: single select group node has no parent'),\n NODE_CANNOT_HAVE_CHILDREN: new Error('Tree structure violation: node cannot have children'),\n};\n\nexport const FORBIDDEN_BEHAVIOURS = {\n TRYING_TO_FOCUS_NON_FOCUSABLE_NODE: new Error('Behavioural violation: trying to focus a non-focusable node'),\n TRYING_TO_OPEN_SUBMENU_OF_NODE_WITHOUT_SUBMENU: new Error(\n 'Behavioural violation: trying to open submenu of node without submenu',\n ),\n};\n\nexport const UNEXPECTED_INTERNAL_ERRORS = {\n FOCUSED_ITEM_NODE_NOT_SET: new Error('Internal error: focused item node not set'),\n FOCUSED_ITEM_HAS_NO_PARENT: new Error('Internal error: focused item has no parent node (is root?)'),\n NODE_WITHOUT_PARENT: new Error('Internal error: the node has no parent'),\n CALCULATING_MULTI_SELECTION_OF_NON_MULTI_SELECTION_NODE: new Error(\n 'Internal error: the node is not multi-selectable or wrongly recognized as non-multi-selectable',\n ),\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAhB,MAAM,wBAAwB;AAAA,EACnC,kBAAkB,IAAI;AAAA,IACpB;AAAA,EACF;AAAA,EACA,sBAAsB,IAAI,MAAM,kEAAkE;AAAA,EAClG,2BAA2B,IAAI,MAAM,qDAAqD;AAC5F;AAEO,MAAM,uBAAuB;AAAA,EAClC,oCAAoC,IAAI,MAAM,6DAA6D;AAAA,EAC3G,gDAAgD,IAAI;AAAA,IAClD;AAAA,EACF;AACF;AAEO,MAAM,6BAA6B;AAAA,EACxC,2BAA2B,IAAI,MAAM,2CAA2C;AAAA,EAChF,4BAA4B,IAAI,MAAM,4DAA4D;AAAA,EAClG,qBAAqB,IAAI,MAAM,wCAAwC;AAAA,EACvE,yDAAyD,IAAI;AAAA,IAC3D;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ const DSMenuBehaviouralContextProviderName = "DSMenuBehaviouralContextProvider";
3
+ const MENU_FOCUS_REGIONS = {
4
+ TRIGGER: "trigger",
5
+ // eslint thinks this is unnecceary, but this forces the string format, without it, it would be a generic string
6
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
7
+ ITEM_BY_DSID: (dsId) => `item-${dsId}`,
8
+ RESET: ""
9
+ };
10
+ export {
11
+ DSMenuBehaviouralContextProviderName,
12
+ MENU_FOCUS_REGIONS
13
+ };
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/constants/index.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type { DSMenuButtonT } from '../../../react-desc-prop-types.js';\nexport const DSMenuBehaviouralContextProviderName = 'DSMenuBehaviouralContextProvider';\n\nexport const MENU_FOCUS_REGIONS = {\n TRIGGER: 'trigger',\n // eslint thinks this is unnecceary, but this forces the string format, without it, it would be a generic string\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n ITEM_BY_DSID: (dsId: DSMenuButtonT.MenuNode['dsId']) =>\n `item-${dsId}` as `item-dsid-${DSMenuButtonT.MenuNode['dsId']}`,\n RESET: '',\n} as const;\n\n/* **************************************************************** */\n// THIS HAS NO STYLES/SLOTS/DOM, IT'S A PURE LOGIC CONTEXT PROVIDER\n/* **************************************************************** */\n\n// we are naming this with the ${component_name}_slots convention to namespace & avoid errors on duplicate exports variables in aggregators\n// export const MENU_BEHAVIOURAL_CONTEXT_PROVIDER_SLOTS = {\n// ROOT: 'root',\n// } as const;\n\n// // we are naming this with the ${component_name}_data_testid convention to namespace & avoid errors on duplicate exports variables in aggregators\n// export const MENU_BEHAVIOURAL_CONTEXT_PROVIDER_DATA_TESTID = slotObjectToDataTestIds(DSMenuBehaviouralContextProviderName, MENU_BEHAVIOURAL_CONTEXT_PROVIDER_SLOTS)\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACChB,MAAM,uCAAuC;AAE7C,MAAM,qBAAqB;AAAA,EAChC,SAAS;AAAA;AAAA;AAAA,EAGT,cAAc,CAAC,SACb,QAAQ,IAAI;AAAA,EACd,OAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ import {
3
+ DSMenuBehaviouralContextProvider,
4
+ DSMenuBehaviouralContextProviderWithSchema
5
+ } from "./DSMenuBehaviouralContextProvider.js";
6
+ export {
7
+ DSMenuBehaviouralContextProvider,
8
+ DSMenuBehaviouralContextProviderWithSchema
9
+ };
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../scripts/build/transpile/react-shim.js", "../../../../src/parts/DSMenuBehaviouralContextProvider/index.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "export {\n DSMenuBehaviouralContextProvider,\n DSMenuBehaviouralContextProviderWithSchema,\n} from './DSMenuBehaviouralContextProvider.js';\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB;AAAA,EACE;AAAA,EACA;AAAA,OACK;",
6
+ "names": []
7
+ }
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ import { PropTypes } from "@elliemae/ds-props-helpers";
3
+ import { MenuBehaviouralLayerPropTypes } from "../../react-desc-prop-types.js";
4
+ const defaultProps = {};
5
+ const DSMenuBehaviouralContextProviderPropTypes = {
6
+ buttonDOMNode: PropTypes.object.description("The DOM node of the button (on close -> return focus to)").isRequired,
7
+ buttonDOMNodeRef: PropTypes.object.description(
8
+ "The DOM node of the button as a mutable Refs (required for performance reasons)"
9
+ ).isRequired,
10
+ children: PropTypes.node.description("the menu trigger and the menu components").isRequired,
11
+ optionsTree: PropTypes.object.description("DSTree node to build branches from").isRequired,
12
+ focusableNodes: PropTypes.arrayOf(PropTypes.object).description(
13
+ "an array of nodes that can receive pseudoFocus, obtainable via ds-tree flatten + filter(isFocusable)"
14
+ ).isRequired,
15
+ ...MenuBehaviouralLayerPropTypes
16
+ };
17
+ const DSMenuBehaviouralContextProviderPropTypesSchema = DSMenuBehaviouralContextProviderPropTypes;
18
+ export {
19
+ DSMenuBehaviouralContextProviderPropTypes,
20
+ DSMenuBehaviouralContextProviderPropTypesSchema,
21
+ defaultProps
22
+ };
23
+ //# sourceMappingURL=react-desc-prop-types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../scripts/build/transpile/react-shim.js", "../../../../src/parts/DSMenuBehaviouralContextProvider/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 { PropTypes } from '@elliemae/ds-props-helpers';\nimport { type TypescriptHelpersT } from '@elliemae/ds-typescript-helpers';\nimport { type DSMenuButtonT, MenuBehaviouralLayerPropTypes } from '../../react-desc-prop-types.js';\n\nexport declare namespace DSMenuBehaviouralContextProviderT {\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.MenuBehaviouralLayerRequiredProps {\n buttonDOMNode: HTMLElement | null;\n buttonDOMNodeRef: React.MutableRefObject<HTMLElement | null>;\n optionsTree: DSMenuButtonT.MenuNode;\n children: TypescriptHelpersT.ReactChildrenComplete;\n focusableNodes: DSMenuButtonT.PseudoFocusableMenuNodes[];\n }\n\n export interface DefaultProps extends DSMenuButtonT.MenuBehaviouralLayerDefaultProps {}\n\n export interface OptionalProps extends DSMenuButtonT.MenuBehaviouralLayerOptionalProps {}\n export interface Props extends Partial<DefaultProps>, OptionalProps, RequiredProps {}\n\n export interface InternalProps extends DefaultProps, OptionalProps, RequiredProps {}\n}\n\nexport const defaultProps: DSMenuBehaviouralContextProviderT.DefaultProps = {};\n\nexport const DSMenuBehaviouralContextProviderPropTypes: DSPropTypesSchema<DSMenuBehaviouralContextProviderT.Props> = {\n buttonDOMNode: PropTypes.object.description('The DOM node of the button (on close -> return focus to)').isRequired,\n buttonDOMNodeRef: PropTypes.object.description(\n 'The DOM node of the button as a mutable Refs (required for performance reasons)',\n ).isRequired,\n children: PropTypes.node.description('the menu trigger and the menu components').isRequired,\n optionsTree: PropTypes.object.description('DSTree node to build branches from').isRequired,\n focusableNodes: PropTypes.arrayOf(PropTypes.object).description(\n 'an array of nodes that can receive pseudoFocus, obtainable via ds-tree flatten + filter(isFocusable)',\n ).isRequired,\n ...MenuBehaviouralLayerPropTypes,\n};\n\nexport const DSMenuBehaviouralContextProviderPropTypesSchema =\n DSMenuBehaviouralContextProviderPropTypes as unknown as ValidationMap<DSMenuBehaviouralContextProviderT.Props>;\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACEvB,SAAS,iBAAiB;AAE1B,SAA6B,qCAAqC;AA0B3D,MAAM,eAA+D,CAAC;AAEtE,MAAM,4CAAwG;AAAA,EACnH,eAAe,UAAU,OAAO,YAAY,0DAA0D,EAAE;AAAA,EACxG,kBAAkB,UAAU,OAAO;AAAA,IACjC;AAAA,EACF,EAAE;AAAA,EACF,UAAU,UAAU,KAAK,YAAY,0CAA0C,EAAE;AAAA,EACjF,aAAa,UAAU,OAAO,YAAY,oCAAoC,EAAE;AAAA,EAChF,gBAAgB,UAAU,QAAQ,UAAU,MAAM,EAAE;AAAA,IAClD;AAAA,EACF,EAAE;AAAA,EACF,GAAG;AACL;AAEO,MAAM,kDACX;",
6
+ "names": []
7
+ }
@@ -0,0 +1,113 @@
1
+ import * as React from "react";
2
+ import {
3
+ isMultipleSelectNode,
4
+ isMultipleSelectOnlyNode,
5
+ isMultipleSelectWithSubmenuNode
6
+ } from "../../../utils/nodesTypeguardsAndGetters.js";
7
+ import { UNEXPECTED_INTERNAL_ERRORS } from "../constants/Errors.js";
8
+ import { getChildrenByCriterias } from "./nodeGettersByCriterias.js";
9
+ const getIsMultipleSelectNodeWithSubmenuSelected = ({
10
+ itemNode,
11
+ selectedItems
12
+ }) => {
13
+ if (selectedItems.length === 0) return false;
14
+ const { multiSelectionableChilrens } = getChildrenByCriterias(itemNode);
15
+ const selectedMultiChildren = [];
16
+ let isSelectedItself = false;
17
+ selectedItems.forEach((itemMarkesAsSelected) => {
18
+ if (itemMarkesAsSelected.dsId === itemNode.dsId) isSelectedItself = true;
19
+ if (isMultipleSelectNode(itemMarkesAsSelected)) {
20
+ if (multiSelectionableChilrens.some((child) => child.dsId === itemMarkesAsSelected.dsId))
21
+ selectedMultiChildren.push(itemMarkesAsSelected);
22
+ }
23
+ });
24
+ if (!isSelectedItself) return false;
25
+ if (multiSelectionableChilrens.length === 0) return true;
26
+ if (selectedMultiChildren.length === 0) return false;
27
+ if (selectedMultiChildren.length !== multiSelectionableChilrens.length) return "mixed";
28
+ return true;
29
+ };
30
+ const getNewSelectionForMultipleSelectOnlyNode = (selectedItems, selectedItem) => {
31
+ const isDeselectingItem = selectedItems.find((item) => item.dsId === selectedItem.dsId) ?? false;
32
+ let newSelection = isDeselectingItem ? selectedItems.filter(({ dsId }) => dsId !== selectedItem.dsId) : [...selectedItems, selectedItem];
33
+ const notSelectedMultiParents = [];
34
+ const selectedMultiParents = [];
35
+ const multiParentsToDeselect = [];
36
+ selectedItem.walkParents((parent) => {
37
+ if (parent.dsId === selectedItem.dsId) return true;
38
+ const typedParent = parent;
39
+ if (isMultipleSelectWithSubmenuNode(typedParent)) {
40
+ const isAlreadySelected = newSelection.find((item) => item.dsId === typedParent.dsId);
41
+ if (isAlreadySelected) {
42
+ selectedMultiParents.push(typedParent);
43
+ const isParentSelected = getIsMultipleSelectNodeWithSubmenuSelected({
44
+ itemNode: typedParent,
45
+ selectedItems: newSelection
46
+ });
47
+ if (isParentSelected === false) multiParentsToDeselect.push(typedParent);
48
+ } else notSelectedMultiParents.push(typedParent);
49
+ }
50
+ return true;
51
+ });
52
+ if (isDeselectingItem) {
53
+ newSelection = newSelection.filter(({ dsId }) => !multiParentsToDeselect.some((parent) => parent.dsId === dsId));
54
+ } else {
55
+ newSelection.push(...notSelectedMultiParents);
56
+ }
57
+ return newSelection;
58
+ };
59
+ const getNewSelectionForMultipleSelectionWithSubmenuNode = (selectedItems, selectedItem) => {
60
+ const currentStatus = getIsMultipleSelectNodeWithSubmenuSelected({
61
+ itemNode: selectedItem,
62
+ selectedItems
63
+ });
64
+ const isDeselectingItem = currentStatus === true;
65
+ let newSelection = isDeselectingItem ? selectedItems.filter(({ dsId }) => dsId !== selectedItem.dsId) : [...selectedItems, selectedItem];
66
+ selectedItem.walk((child) => {
67
+ const typedChild = child;
68
+ if (isDeselectingItem) {
69
+ newSelection = newSelection.filter(({ dsId }) => dsId !== typedChild.dsId);
70
+ } else if (isMultipleSelectNode(typedChild) && !newSelection.find((item) => item.dsId === typedChild.dsId)) {
71
+ newSelection.push(typedChild);
72
+ }
73
+ return true;
74
+ });
75
+ const notSelectedMultiParents = [];
76
+ const selectedMultiParents = [];
77
+ const multiParentsToDeselect = [];
78
+ selectedItem.walkParents((parent) => {
79
+ if (parent.dsId === selectedItem.dsId) return true;
80
+ const typedParent = parent;
81
+ if (isMultipleSelectWithSubmenuNode(typedParent)) {
82
+ const isAlreadySelected = newSelection.find((item) => item.dsId === typedParent.dsId);
83
+ if (isAlreadySelected) {
84
+ selectedMultiParents.push(typedParent);
85
+ const isParentSelected = getIsMultipleSelectNodeWithSubmenuSelected({
86
+ itemNode: typedParent,
87
+ selectedItems: newSelection
88
+ });
89
+ if (isParentSelected === false) multiParentsToDeselect.push(typedParent);
90
+ } else notSelectedMultiParents.push(typedParent);
91
+ }
92
+ return true;
93
+ });
94
+ if (isDeselectingItem) {
95
+ newSelection = newSelection.filter(({ dsId }) => !multiParentsToDeselect.some((parent) => parent.dsId === dsId));
96
+ } else {
97
+ newSelection.push(...notSelectedMultiParents);
98
+ }
99
+ return newSelection;
100
+ };
101
+ const getNewSelectionMultipleSelect = (selectedItems, selectedItem) => {
102
+ if (isMultipleSelectOnlyNode(selectedItem))
103
+ return getNewSelectionForMultipleSelectOnlyNode(selectedItems, selectedItem);
104
+ if (isMultipleSelectWithSubmenuNode(selectedItem))
105
+ return getNewSelectionForMultipleSelectionWithSubmenuNode(selectedItems, selectedItem);
106
+ console.log(selectedItem);
107
+ throw UNEXPECTED_INTERNAL_ERRORS.CALCULATING_MULTI_SELECTION_OF_NON_MULTI_SELECTION_NODE;
108
+ };
109
+ export {
110
+ getIsMultipleSelectNodeWithSubmenuSelected,
111
+ getNewSelectionMultipleSelect
112
+ };
113
+ //# sourceMappingURL=multipleSelectionHelpers.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/utils/multipleSelectionHelpers.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable no-console */\n/* eslint-disable max-statements */\nimport { type DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport {\n isMultipleSelectNode,\n isMultipleSelectOnlyNode,\n isMultipleSelectWithSubmenuNode,\n} from '../../../utils/nodesTypeguardsAndGetters.js';\nimport { UNEXPECTED_INTERNAL_ERRORS } from '../constants/Errors.js';\nimport { getChildrenByCriterias } from './nodeGettersByCriterias.js';\n\nexport const getIsMultipleSelectNodeWithSubmenuSelected = ({\n itemNode,\n selectedItems,\n}: {\n itemNode: DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem;\n selectedItems: DSMenuButtonT.SelectionableMenuNodes[];\n}) => {\n // no selected items, nothing is selected <- this is not selected neither, nothing else to check\n if (selectedItems.length === 0) return false;\n\n const { multiSelectionableChilrens } = getChildrenByCriterias(itemNode);\n const selectedMultiChildren: DSMenuButtonT.MultipleSelectionableMenuNodes[] = [];\n let isSelectedItself = false;\n selectedItems.forEach((itemMarkesAsSelected) => {\n if (itemMarkesAsSelected.dsId === itemNode.dsId) isSelectedItself = true;\n if (isMultipleSelectNode(itemMarkesAsSelected)) {\n // we reduce scenarios of O(n*m), if the node is not a multi-selectable node, we don't iterate the multiSelectionable childrens\n if (multiSelectionableChilrens.some((child) => child.dsId === itemMarkesAsSelected.dsId))\n selectedMultiChildren.push(itemMarkesAsSelected);\n }\n });\n // console.group(`${itemNode.dsId} > getting \"selected\" (true/false/mixed) status`);\n // console.log({\n // itemNode: itemNode.dsId,\n // selectedItems: selectedItems.map((itm) => itm.dsId),\n // multiSelectionableChilrens: multiSelectionableChilrens.map((itm) => itm.dsId),\n // selectedMultiChildren: selectedMultiChildren.map((itm) => itm.dsId),\n // isSelectedItself,\n // });\n // console.groupEnd();\n // if it's not marked as selected, it's not selected.\n if (!isSelectedItself) return false;\n // if the node doesn't even have multi children, to calculate 'mixed' status upon (it may still have radios)\n // (and is selected itself), it's selected\n if (multiSelectionableChilrens.length === 0) return true;\n\n // multi children exist and the node is selected\n // it can be\n // true if all the multi children are selected\n // mixed if not all the multi children are selected\n // false if all the multi children are not selected\n\n // multi children exist but none are selected at all?\n if (selectedMultiChildren.length === 0) return false;\n // any multi children is not selected?\n if (selectedMultiChildren.length !== multiSelectionableChilrens.length) return 'mixed';\n // there is a multi selection, and everything is selected\n return true;\n};\n\nconst getNewSelectionForMultipleSelectOnlyNode = (\n selectedItems: DSMenuButtonT.SelectionableMenuNodes[],\n selectedItem: DSMenuButtonT.MenuNodeMultipleSelectItem,\n) => {\n const isDeselectingItem = selectedItems.find((item) => item.dsId === selectedItem.dsId) ?? false;\n\n let newSelection = isDeselectingItem\n ? selectedItems.filter(({ dsId }) => dsId !== selectedItem.dsId)\n : [...selectedItems, selectedItem];\n const notSelectedMultiParents: DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem[] = [];\n const selectedMultiParents: DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem[] = [];\n const multiParentsToDeselect: DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem[] = [];\n\n // we walk the parents and track info about them\n selectedItem.walkParents((parent) => {\n // discard ourself, only interested in the parents\n if (parent.dsId === selectedItem.dsId) return true;\n // DSTree typescripst doesn't understand ethereogenic nodes, so we need to typecast\n const typedParent = parent as unknown as DSMenuButtonT.MenuNode;\n if (isMultipleSelectWithSubmenuNode(typedParent)) {\n // before we add the parent, we need to check if it's already in the selection\n const isAlreadySelected = newSelection.find((item) => item.dsId === typedParent.dsId);\n if (isAlreadySelected) {\n selectedMultiParents.push(typedParent);\n // we check if the parent is mixed or should be false (so we can deselect it)\n const isParentSelected = getIsMultipleSelectNodeWithSubmenuSelected({\n itemNode: typedParent,\n selectedItems: newSelection,\n });\n if (isParentSelected === false) multiParentsToDeselect.push(typedParent);\n } else notSelectedMultiParents.push(typedParent);\n }\n return true;\n });\n\n if (isDeselectingItem) {\n // if we are deselecting:\n // we need to remove the parent nodes that are not selected anymore\n // (they transition from mixed to not selected because of this item deselection)\n newSelection = newSelection.filter(({ dsId }) => !multiParentsToDeselect.some((parent) => parent.dsId === dsId));\n } else {\n // if we are selecting:\n // we need to add the parent nodes that are not selected yet\n // (they transition from not selected to mixed because of this item selection)\n newSelection.push(...notSelectedMultiParents);\n }\n\n return newSelection;\n};\n\nconst getNewSelectionForMultipleSelectionWithSubmenuNode = (\n selectedItems: DSMenuButtonT.SelectionableMenuNodes[],\n selectedItem: DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem,\n) => {\n // when selecting/deselecting a node with a submenu, we need to consider the hierarchy of the selection starting from here\n // both upwards and downwards\n // - upwards\n // we have to check if any multi-selectable-with-submenu parent transition from not selected to mixed || mixed to selected\n // - downwards\n // - Deselect\n // we have to deselect all the selectable children (regarless of the depth of the children and kind of selection)\n // - Select\n // we have to select all the multi-selectable children that are not selected yet (both with and without submenu)\n\n // console.group(`${selectedItem.dsId} > getting new selection`);\n const currentStatus = getIsMultipleSelectNodeWithSubmenuSelected({\n itemNode: selectedItem,\n selectedItems,\n });\n const isDeselectingItem = currentStatus === true;\n\n let newSelection = isDeselectingItem\n ? selectedItems.filter(({ dsId }) => dsId !== selectedItem.dsId)\n : [...selectedItems, selectedItem];\n\n // console.log(\n // 'starting newSelection',\n // newSelection.map(({ dsId }) => dsId),\n // );\n\n // we walk the children first and update the new selection accordingly\n // (it's important we first traverse the children, so we can update the selection of the parents accordingly to the new selection)\n selectedItem.walk((child) => {\n // DSTree typescripst doesn't understand ethereogenic nodes, so we need to typecast\n const typedChild = child as unknown as DSMenuButtonT.SelectionableMenuNodes;\n if (isDeselectingItem) {\n // if we are deselecting, we need to remove the children from the selection\n newSelection = newSelection.filter(({ dsId }) => dsId !== typedChild.dsId);\n } else if (isMultipleSelectNode(typedChild) && !newSelection.find((item) => item.dsId === typedChild.dsId)) {\n // if we are selecting, we need to add all the multi children to the selection (if they are not already there)\n // (we don't do anything with single-selectable nodes, they are not affected by this operation by definition)\n newSelection.push(typedChild);\n }\n return true;\n });\n\n // console.log(\n // 'newSelection after applying logic to children, pre parents traversal',\n // newSelection.map(({ dsId }) => dsId),\n // );\n\n // now newSelection has the correct information about the node itself and its children\n // we need to update the parents accordingly\n\n const notSelectedMultiParents: DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem[] = [];\n const selectedMultiParents: DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem[] = [];\n const multiParentsToDeselect: DSMenuButtonT.MenuNodeMultipleSelectWithSubmenuItem[] = [];\n // we walk the parents and track info about them\n selectedItem.walkParents((parent) => {\n // discard ourself, only interested in the parents\n if (parent.dsId === selectedItem.dsId) return true;\n // DSTree typescripst doesn't understand ethereogenic nodes, so we need to typecast\n const typedParent = parent as unknown as DSMenuButtonT.MenuNode;\n if (isMultipleSelectWithSubmenuNode(typedParent)) {\n // before we add the parent, we need to check if it's already in the selection\n const isAlreadySelected = newSelection.find((item) => item.dsId === typedParent.dsId);\n if (isAlreadySelected) {\n selectedMultiParents.push(typedParent);\n // we check if the parent is mixed or should be false (so we can deselect it)\n const isParentSelected = getIsMultipleSelectNodeWithSubmenuSelected({\n itemNode: typedParent,\n selectedItems: newSelection,\n });\n if (isParentSelected === false) multiParentsToDeselect.push(typedParent);\n } else notSelectedMultiParents.push(typedParent);\n }\n return true;\n });\n\n // console.log(\n // 'parents info > notSelectedMultiParents',\n // notSelectedMultiParents.map(({ dsId }) => dsId),\n // );\n // console.log(\n // 'parents info > selectedMultiParents',\n // selectedMultiParents.map(({ dsId }) => dsId),\n // );\n // console.log(\n // 'parents info > multiParentsToDeselect',\n // multiParentsToDeselect.map(({ dsId }) => dsId),\n // );\n\n // finally we use the info we gathered to update the selection\n if (isDeselectingItem) {\n // if we are deselecting:\n // we need to remove the parent nodes that are not selected anymore\n // (they transition from mixed to not selected because of this item deselection)\n newSelection = newSelection.filter(({ dsId }) => !multiParentsToDeselect.some((parent) => parent.dsId === dsId));\n } else {\n // if we are selecting:\n // we need to add the parent nodes that are not selected yet\n // (they transition from not selected to mixed because of this item selection)\n newSelection.push(...notSelectedMultiParents);\n }\n\n // console.log(\n // 'final newSelection',\n // newSelection.map(({ dsId }) => dsId),\n // );\n\n // console.groupEnd();\n return newSelection;\n};\n\nexport const getNewSelectionMultipleSelect = (\n selectedItems: DSMenuButtonT.SelectionableMenuNodes[],\n selectedItem: DSMenuButtonT.MultipleSelectionableMenuNodes,\n) => {\n // depending on if we are selecting/deselecting an item with/without submenu, we need to handle the selection differently\n if (isMultipleSelectOnlyNode(selectedItem))\n return getNewSelectionForMultipleSelectOnlyNode(selectedItems, selectedItem);\n\n if (isMultipleSelectWithSubmenuNode(selectedItem))\n return getNewSelectionForMultipleSelectionWithSubmenuNode(selectedItems, selectedItem);\n\n // if we reach this point, we are in an invalid state, we should never reach here\n console.log(selectedItem);\n throw UNEXPECTED_INTERNAL_ERRORS.CALCULATING_MULTI_SELECTION_OF_NON_MULTI_SELECTION_NODE;\n};\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,123 @@
1
+ import * as React from "react";
2
+ import {
3
+ isFocusableNode,
4
+ isGroup,
5
+ isMenuNodeAllowedToHaveChildren,
6
+ isMultipleSelectNode,
7
+ isSelectionableNode,
8
+ isSelectionableWithSubmenuNode,
9
+ isSingleSelectNode,
10
+ isWithSubmenuNode
11
+ } from "../../../utils/nodesTypeguardsAndGetters.js";
12
+ import { TREE_STRUCTURE_ERRORS, UNEXPECTED_INTERNAL_ERRORS } from "../constants/Errors.js";
13
+ const getSubMenusPath = (itemNode) => {
14
+ const subMenuNodesPath = [];
15
+ itemNode.walkParents((node) => {
16
+ if (node.dsId === itemNode.dsId) return true;
17
+ if (isWithSubmenuNode(node)) {
18
+ subMenuNodesPath.push(node);
19
+ }
20
+ return true;
21
+ });
22
+ return subMenuNodesPath.reverse();
23
+ };
24
+ const getFocusableSiblingsList = (itemNode) => {
25
+ const { parent: parentNode } = itemNode;
26
+ if (!parentNode) {
27
+ console.log("getFocusableSiblingsList > itemNode", itemNode);
28
+ throw UNEXPECTED_INTERNAL_ERRORS.NODE_WITHOUT_PARENT;
29
+ }
30
+ if (!isMenuNodeAllowedToHaveChildren(parentNode)) {
31
+ console.log("parentNode", parentNode);
32
+ console.log("itemNode", itemNode);
33
+ throw TREE_STRUCTURE_ERRORS.NODE_CANNOT_HAVE_CHILDREN;
34
+ }
35
+ const focusableSiblingsNodes = [];
36
+ let parseableParentNode = parentNode;
37
+ if (isGroup(parentNode)) {
38
+ if (!parentNode.parent) {
39
+ throw TREE_STRUCTURE_ERRORS.GROUP_WITHOUT_PARENT;
40
+ }
41
+ parseableParentNode = parentNode.parent;
42
+ }
43
+ parseableParentNode.children.forEach((node) => {
44
+ if (isFocusableNode(node)) {
45
+ focusableSiblingsNodes.push(node);
46
+ }
47
+ if (isGroup(node)) {
48
+ node.children.forEach((groupChild) => {
49
+ if (isFocusableNode(groupChild)) {
50
+ focusableSiblingsNodes.push(groupChild);
51
+ }
52
+ });
53
+ }
54
+ });
55
+ return focusableSiblingsNodes;
56
+ };
57
+ const getAllSingleSelectIdsFromParent = (oldestParent) => {
58
+ const singleSelectionableItemsIds = [];
59
+ oldestParent.walk((node) => {
60
+ const typeCastedNode = node;
61
+ if (isSingleSelectNode(typeCastedNode)) {
62
+ singleSelectionableItemsIds.push(node.dsId);
63
+ }
64
+ return true;
65
+ });
66
+ return singleSelectionableItemsIds;
67
+ };
68
+ const getParentsByCriterias = (menuNode) => {
69
+ let oldestGroupFoundSoFar;
70
+ const selectionableParentsWithSubmenu = [];
71
+ const groupParents = [];
72
+ menuNode.walkParents((node) => {
73
+ if (node.dsId === menuNode.dsId) return true;
74
+ const typeCastedNode = node;
75
+ if (isGroup(typeCastedNode)) {
76
+ oldestGroupFoundSoFar = typeCastedNode;
77
+ groupParents.push(oldestGroupFoundSoFar);
78
+ return true;
79
+ }
80
+ if (isSelectionableWithSubmenuNode(typeCastedNode)) {
81
+ selectionableParentsWithSubmenu.push(typeCastedNode);
82
+ return true;
83
+ }
84
+ return true;
85
+ });
86
+ if (!oldestGroupFoundSoFar) {
87
+ console.log("node:", menuNode);
88
+ console.log("parent:", menuNode.parent);
89
+ throw TREE_STRUCTURE_ERRORS.PARENT_NOT_GROUP;
90
+ }
91
+ return {
92
+ oldestGroup: oldestGroupFoundSoFar,
93
+ selectionableParentsWithSubmenu,
94
+ groupParents
95
+ };
96
+ };
97
+ const getChildrenByCriterias = (menuNode) => {
98
+ const selectionableChilrens = [];
99
+ const multiSelectionableChilrens = [];
100
+ menuNode.walk((node) => {
101
+ if (node.dsId === menuNode.dsId) return true;
102
+ const typeCastedNode = node;
103
+ if (isSelectionableNode(typeCastedNode)) {
104
+ selectionableChilrens.push(typeCastedNode);
105
+ if (isMultipleSelectNode(typeCastedNode)) {
106
+ multiSelectionableChilrens.push(typeCastedNode);
107
+ }
108
+ }
109
+ return true;
110
+ });
111
+ return {
112
+ selectionableChilrens,
113
+ multiSelectionableChilrens
114
+ };
115
+ };
116
+ export {
117
+ getAllSingleSelectIdsFromParent,
118
+ getChildrenByCriterias,
119
+ getFocusableSiblingsList,
120
+ getParentsByCriterias,
121
+ getSubMenusPath
122
+ };
123
+ //# sourceMappingURL=nodeGettersByCriterias.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/utils/nodeGettersByCriterias.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable no-console */\n/* eslint-disable max-lines */\n/* eslint-disable max-statements */\n/* eslint-disable complexity */\nimport type { DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport {\n isFocusableNode,\n isGroup,\n isMenuNodeAllowedToHaveChildren,\n isMultipleSelectNode,\n isSelectionableNode,\n isSelectionableWithSubmenuNode,\n isSingleSelectNode,\n isWithSubmenuNode,\n} from '../../../utils/nodesTypeguardsAndGetters.js';\nimport { TREE_STRUCTURE_ERRORS, UNEXPECTED_INTERNAL_ERRORS } from '../constants/Errors.js';\n\nexport const getSubMenusPath = (itemNode: DSMenuButtonT.MenuNode) => {\n const subMenuNodesPath: DSMenuButtonT.WithSubmenuMenuNodes[] = [];\n itemNode.walkParents((node) => {\n // discards itself, we want the parents only\n if (node.dsId === itemNode.dsId) return true;\n if (isWithSubmenuNode(node)) {\n subMenuNodesPath.push(node);\n }\n return true;\n });\n return subMenuNodesPath.reverse();\n};\n\nexport const getFocusableSiblingsList = (itemNode: DSMenuButtonT.MenuNode) => {\n const { parent: parentNode } = itemNode;\n if (!parentNode) {\n console.log('getFocusableSiblingsList > itemNode', itemNode);\n throw UNEXPECTED_INTERNAL_ERRORS.NODE_WITHOUT_PARENT;\n }\n if (!isMenuNodeAllowedToHaveChildren(parentNode)) {\n // this should be impossible to reach, if this is reached, there is a bug in the code/validation checks\n console.log('parentNode', parentNode);\n console.log('itemNode', itemNode);\n throw TREE_STRUCTURE_ERRORS.NODE_CANNOT_HAVE_CHILDREN;\n }\n // each tree depth may be composed of a mix of focusable and non-focusable nodes\n // in particular, the parent node may be a group node which is not focusable but it's children are (and are visually siblings)\n // we need to do our calculations only on top of focusable nodes, and we also need to consider the scenario of a group node\n const focusableSiblingsNodes: DSMenuButtonT.PseudoFocusableMenuNodes[] = [];\n\n let parseableParentNode = parentNode;\n // nesting a group node inside another group node is not allowed\n // I could not find a supporting explicit statement in the WCAG standard,\n // but given how everything else is defined and graphically represented,\n // it's the only logical conclusion.\n // Nesting would result in nodes being visually siblings\n // but logically non-exclusively selectable,\n // which would be a contradiction of the visuals\n // so violating the WCAG standard for other reasons\n if (isGroup(parentNode)) {\n if (!parentNode.parent) {\n throw TREE_STRUCTURE_ERRORS.GROUP_WITHOUT_PARENT;\n }\n parseableParentNode = parentNode.parent;\n }\n\n parseableParentNode.children.forEach((node) => {\n if (isFocusableNode(node)) {\n focusableSiblingsNodes.push(node);\n }\n // if we encounter a group node we need to add it's children too\n // (which here is guaranteed because we checked it in the if statement above)\n if (isGroup(node)) {\n node.children.forEach((groupChild) => {\n if (isFocusableNode(groupChild)) {\n focusableSiblingsNodes.push(groupChild);\n }\n });\n }\n });\n\n return focusableSiblingsNodes;\n};\n\n/**\n * This functions walks the tree downwards starting from the oldest shared parent and returns all the single-selectable items ids\n * @param oldestParent - the oldest parent to start the walk from\n * @returns string | number[] - the list of all the single-selectable items ids starting from the oldest shared group\n */\nexport const getAllSingleSelectIdsFromParent = (oldestParent: DSMenuButtonT.MenuNodesAllowedToHaveChildren) => {\n const singleSelectionableItemsIds: (string | number)[] = [];\n oldestParent.walk((node) => {\n // DSTree typescript doesn't understand ethereogeneous subitems, so we need to typecast manually\n const typeCastedNode = node as unknown as\n | DSMenuButtonT.SingleSelectionableMenuNodes\n | DSMenuButtonT.MenuNodeSeparatorItem;\n // is the node is a single-selectable item, we add it to the list\n if (isSingleSelectNode(typeCastedNode)) {\n singleSelectionableItemsIds.push(node.dsId);\n }\n // we walk all the tree (from the shared group), we never shortcircuit\n return true;\n });\n return singleSelectionableItemsIds;\n};\n\n/**\n * walk all parents from a given node and gives back multiple supporting datastructures by different criterias\n *\n * @param menuNode\n * @returns {object} - an object holding different datastructures and information about the parents\n * @property {Object} oldestGroup - the oldest shared group\n * @property {Object[]} selectionableParentsWithSubmenu - the single/multiple selection parents with submenu\n * @property {Object[]} groupParents - all the 'groups' encountered while traversing the tree upwards\n */\nexport const getParentsByCriterias = (menuNode: DSMenuButtonT.MenuNode) => {\n // group\n let oldestGroupFoundSoFar: DSMenuButtonT.MenuNodeGroupItem;\n const selectionableParentsWithSubmenu: DSMenuButtonT.SelectionablesWithSubmenuMenuNodes[] = [];\n const groupParents: DSMenuButtonT.MenuNodeGroupItem[] = [];\n\n menuNode.walkParents((node) => {\n // discards itself, we want the parents only\n if (node.dsId === menuNode.dsId) return true;\n // DSTree is not able to understand ethereogeneous subitems, so we need to typecast manually\n const typeCastedNode = node as unknown as DSMenuButtonT.MenuNode;\n\n if (isGroup(typeCastedNode)) {\n oldestGroupFoundSoFar = typeCastedNode;\n groupParents.push(oldestGroupFoundSoFar);\n // nothing else to do in this walking step, returing true to continue the walk\n return true;\n }\n // we continue checking shared parents untill we see the pattern\n // group -> single-select-with-submenu -> group -> ...\n // the moment the parent of a group is not a single-select-with-submenu we can stop,\n // we have found the oldest shared group\n if (isSelectionableWithSubmenuNode(typeCastedNode)) {\n selectionableParentsWithSubmenu.push(typeCastedNode);\n return true;\n }\n // the node is not a single-select-with-submenu, we can stop the walk\n return true;\n });\n // if we found no group parent starting from menuNode, the tree is malformed\n // @ts-expect-error - typescript doesn't understand that \"walkParents\" actually executes the function synchronously\n // so it thinks that oldestGroupFoundSoFar was never assigned, it's a false positive\n if (!oldestGroupFoundSoFar) {\n console.log('node:', menuNode);\n console.log('parent:', menuNode.parent);\n throw TREE_STRUCTURE_ERRORS.PARENT_NOT_GROUP;\n }\n return {\n oldestGroup: oldestGroupFoundSoFar,\n selectionableParentsWithSubmenu,\n groupParents,\n };\n};\n\n/**\n * walk all childrens from a given node and gives back multiple supporting datastructures by different criterias\n *\n * @param menuNode\n * @returns {object} - an object holding different datastructures and information about the children\n * @property {Object[]} selectionableChilrens - the single/multiple selection children (regardless of the presence of a submenu)\n * @property {Object[]} multiSelectionableChilrens - the multiple selection children (regardless of the presence of a submenu)\n */\nexport const getChildrenByCriterias = (menuNode: DSMenuButtonT.MenuNode) => {\n const selectionableChilrens: DSMenuButtonT.SelectionableMenuNodes[] = [];\n const multiSelectionableChilrens: DSMenuButtonT.MultipleSelectionableMenuNodes[] = [];\n menuNode.walk((node) => {\n // discards itself, we want the children only\n if (node.dsId === menuNode.dsId) return true;\n // DSTree is not able to understand ethereogeneous subitems, so we need to typecast manually\n const typeCastedNode = node as unknown as DSMenuButtonT.MenuNode;\n if (isSelectionableNode(typeCastedNode)) {\n selectionableChilrens.push(typeCastedNode);\n if (isMultipleSelectNode(typeCastedNode)) {\n multiSelectionableChilrens.push(typeCastedNode);\n }\n }\n // we walk all the tree (from the shared group), we never shortcircuit\n return true;\n });\n return {\n selectionableChilrens,\n multiSelectionableChilrens,\n };\n};\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import { getAllSingleSelectIdsFromParent, getParentsByCriterias } from "./nodeGettersByCriterias.js";
3
+ const getNewSelectionSingleSelect = (selectedItems, selectedItem) => {
4
+ const { oldestGroup, selectionableParentsWithSubmenu } = getParentsByCriterias(selectedItem);
5
+ const itemsIdsToDeselect = getAllSingleSelectIdsFromParent(oldestGroup);
6
+ const newSelection = selectedItems.filter((item) => !itemsIdsToDeselect.includes(item.plainItem.dsId));
7
+ newSelection.push(...selectionableParentsWithSubmenu);
8
+ newSelection.push(selectedItem);
9
+ return newSelection;
10
+ };
11
+ export {
12
+ getNewSelectionSingleSelect
13
+ };
14
+ //# sourceMappingURL=singleSelectionHelpers.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../../scripts/build/transpile/react-shim.js", "../../../../../src/parts/DSMenuBehaviouralContextProvider/utils/singleSelectionHelpers.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { type DSMenuButtonT } from '../../../react-desc-prop-types.js';\nimport { getAllSingleSelectIdsFromParent, getParentsByCriterias } from './nodeGettersByCriterias.js';\n\n/**\n * When a single-selectable item is selected, all other single-selectable items in the same group are deselected;\n *\n * If the (visual) parent is a single-select-with-submenu,\n * the selection must be propagated because\n * a single-select within a single-select-with-submenu can't be selected without implying the selection of the parent single-select-with-submenu\n *\n * @param selectedItems - the current selected items\n * @param selectedItem - the newly selected item\n * @returns DSMenuButtonT.SelectionableMenuNodes[] - the new selection\n */\nexport const getNewSelectionSingleSelect = (\n selectedItems: DSMenuButtonT.SelectionableMenuNodes[],\n selectedItem: DSMenuButtonT.MenuNodeSingleSelectItem | DSMenuButtonT.MenuNodeSingleSelectWithSubmenuItem,\n) => {\n const { oldestGroup, selectionableParentsWithSubmenu } = getParentsByCriterias(selectedItem);\n const itemsIdsToDeselect = getAllSingleSelectIdsFromParent(oldestGroup);\n // we remove all the ids of single selection parents from the previous selection\n const newSelection = selectedItems.filter((item) => !itemsIdsToDeselect.includes(item.plainItem.dsId));\n // we add all the parents submenus to the selection\n newSelection.push(...selectionableParentsWithSubmenu);\n // finally we add the newly selected item\n newSelection.push(selectedItem);\n\n return newSelection;\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,iCAAiC,6BAA6B;AAahE,MAAM,8BAA8B,CACzC,eACA,iBACG;AACH,QAAM,EAAE,aAAa,gCAAgC,IAAI,sBAAsB,YAAY;AAC3F,QAAM,qBAAqB,gCAAgC,WAAW;AAEtE,QAAM,eAAe,cAAc,OAAO,CAAC,SAAS,CAAC,mBAAmB,SAAS,KAAK,UAAU,IAAI,CAAC;AAErG,eAAa,KAAK,GAAG,+BAA+B;AAEpD,eAAa,KAAK,YAAY;AAE9B,SAAO;AACT;",
6
+ "names": []
7
+ }