@geotab/zenith 3.10.0-beta.7 → 3.11.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/README.md +33 -0
  2. package/dist/calendar/calendar.js +7 -4
  3. package/dist/card/components/title.js +4 -1
  4. package/dist/card/components/titleLink.js +5 -2
  5. package/dist/chart/barChart/getDefaultOptions.d.ts +2 -1
  6. package/dist/chart/barChart/getDefaultOptions.js +5 -2
  7. package/dist/chart/barChart.js +6 -4
  8. package/dist/chart/lineChart/getDefaultOptions.d.ts +2 -1
  9. package/dist/chart/lineChart/getDefaultOptions.js +5 -2
  10. package/dist/chart/lineChart.js +4 -2
  11. package/dist/checkboxListWithAction/checkboxListWithAction.js +4 -1
  12. package/dist/commonHelpers/arrowNavigation/components/arrowButton/arrowButton.js +4 -1
  13. package/dist/commonStyles/pillStyles/pillContent.less +13 -14
  14. package/dist/commonStyles/pillStyles/pillStyles.less +4 -5
  15. package/dist/commonStyles/pillStyles/pillTextContent.less +2 -2
  16. package/dist/commonStyles/typography/typography.less +579 -19
  17. package/dist/controlledPopup/controlledPopup.d.ts +1 -0
  18. package/dist/controlledPopup/controlledPopup.js +3 -1
  19. package/dist/dataGrid/cell/cell.d.ts +2 -1
  20. package/dist/dataGrid/cell/cell.js +2 -2
  21. package/dist/dataGrid/dataGrid.js +7 -4
  22. package/dist/dataGrid/listColumn.d.ts +2 -0
  23. package/dist/dataGrid/row/row.d.ts +2 -1
  24. package/dist/dataGrid/row/row.js +13 -9
  25. package/dist/dataGrid/withFlexibleColumns/components/columnSettingsList.js +2 -1
  26. package/dist/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +4 -0
  27. package/dist/dateRangeInner/dateRangeInner.js +5 -2
  28. package/dist/dateRangeRaw/dateRangeRaw.js +5 -2
  29. package/dist/dateRangeRaw/utils/parseLabel.js +1 -1
  30. package/dist/dropdownRaw/dropdownRaw.js +12 -6
  31. package/dist/fileUpload/components/dropZoneContent.js +100 -100
  32. package/dist/fileUpload/fileUpload.js +100 -100
  33. package/dist/filters/components/filtersSearchList.js +4 -1
  34. package/dist/filtersBar/filtersContainer/filtersContainer.js +62 -61
  35. package/dist/formStepperButtons/formStepperButtons.js +4 -1
  36. package/dist/groupsFilterRaw/groupsFilterAdjustmentState.js +4 -1
  37. package/dist/groupsFilterRaw/groupsFilterInitialState.js +4 -1
  38. package/dist/header/headerBack.js +4 -1
  39. package/dist/icons/iconAlignLeft.js +1 -3
  40. package/dist/icons/iconAlignmentLeft.js +1 -3
  41. package/dist/icons/iconAlignmentRight.js +1 -3
  42. package/dist/icons/iconArrowBottomLeft.js +1 -3
  43. package/dist/icons/iconArrowBottomRight.js +1 -3
  44. package/dist/icons/iconArrowLeftPath.js +1 -3
  45. package/dist/icons/iconArrowRight.js +1 -3
  46. package/dist/icons/iconArrowRightCircle.js +1 -3
  47. package/dist/icons/iconArrowRightPath.js +1 -3
  48. package/dist/icons/iconArrowTopLeft.js +1 -3
  49. package/dist/icons/iconArrowTopRight.js +1 -3
  50. package/dist/icons/iconChevronDoubleRight.js +1 -3
  51. package/dist/icons/iconChevronRight.js +1 -3
  52. package/dist/icons/iconChevronRightSmall.js +1 -3
  53. package/dist/icons/iconCornerDownLeft.js +1 -3
  54. package/dist/icons/iconCornerDownRight.js +1 -3
  55. package/dist/icons/iconCornerLeftDown.js +1 -3
  56. package/dist/icons/iconCornerLeftUp.js +1 -3
  57. package/dist/icons/iconCornerRightDown.js +1 -3
  58. package/dist/icons/iconCornerRightUp.js +1 -3
  59. package/dist/icons/iconCornerUpLeft.js +1 -3
  60. package/dist/icons/iconCornerUpRight.js +1 -3
  61. package/dist/index.css +3257 -2925
  62. package/dist/index.d.ts +1 -0
  63. package/dist/index.js +3 -1
  64. package/dist/lineChartMini/lineChartMini.js +15 -3
  65. package/dist/list/itemData/itemDataInternal.js +4 -1
  66. package/dist/list/list.d.ts +1 -0
  67. package/dist/list/list.js +2 -2
  68. package/dist/list/listItem/listItem.d.ts +1 -3
  69. package/dist/list/listItem/listItem.js +6 -5
  70. package/dist/menu/components/controlledMenuList/controlledMenuList.d.ts +27 -0
  71. package/dist/menu/components/controlledMenuList/controlledMenuList.js +126 -0
  72. package/dist/menu/components/createControlledMenuList.d.ts +37 -0
  73. package/dist/menu/components/createControlledMenuList.js +55 -0
  74. package/dist/menu/components/createMenuItem.d.ts +67 -0
  75. package/dist/menu/components/createMenuItem.js +97 -0
  76. package/dist/menu/components/menuButton.js +12 -3
  77. package/dist/menu/components/menuItem.d.ts +1 -2
  78. package/dist/menu/components/menuItem.js +20 -74
  79. package/dist/menu/contexts/usePathContext.d.ts +2 -0
  80. package/dist/menu/contexts/usePathContext.js +9 -0
  81. package/dist/menu/controlledMenu.js +8 -175
  82. package/dist/menu/utils/buildMenuContent.d.ts +2 -0
  83. package/dist/menu/utils/buildMenuContent.js +38 -0
  84. package/dist/menu/utils/findContent.d.ts +2 -2
  85. package/dist/menu/utils/findContent.js +4 -3
  86. package/dist/menu/utils/getItemLabel.d.ts +2 -0
  87. package/dist/menu/utils/getItemLabel.js +8 -0
  88. package/dist/menu/utils/getSafeRel.d.ts +1 -0
  89. package/dist/menu/utils/getSafeRel.js +14 -0
  90. package/dist/menu/utils/isMenuItem.d.ts +2 -0
  91. package/dist/menu/utils/isMenuItem.js +13 -0
  92. package/dist/menu/utils/isSafeHref.d.ts +1 -0
  93. package/dist/menu/utils/isSafeHref.js +10 -0
  94. package/dist/menu/utils/normalizeSeparators.d.ts +2 -0
  95. package/dist/menu/utils/normalizeSeparators.js +23 -0
  96. package/dist/menu/utils/resolveKeys.d.ts +12 -0
  97. package/dist/menu/utils/resolveKeys.js +22 -0
  98. package/dist/menu/utils/useLastValidSheet.d.ts +7 -0
  99. package/dist/menu/utils/useLastValidSheet.js +30 -0
  100. package/dist/menu/utils/useMenuItemCore.d.ts +31 -0
  101. package/dist/menu/utils/useMenuItemCore.js +54 -0
  102. package/dist/menu/utils/useMenuItemKeyboardNav.d.ts +2 -0
  103. package/dist/menu/utils/useMenuItemKeyboardNav.js +15 -0
  104. package/dist/menu/utils/useMenuListKeyboardNav.d.ts +12 -0
  105. package/dist/menu/utils/useMenuListKeyboardNav.js +77 -0
  106. package/dist/menu/utils/useMenuPath.d.ts +6 -0
  107. package/dist/menu/utils/useMenuPath.js +35 -0
  108. package/dist/nav/navItem/navItem.js +10 -5
  109. package/dist/nav/navSection/navSection.js +7 -5
  110. package/dist/pagination/paginationArrow.js +10 -3
  111. package/dist/radioGroupRaw/radioGroupRaw.js +2 -1
  112. package/dist/rangeRaw/rangeRaw.js +0 -1
  113. package/dist/selectList/selectList.helpers.d.ts +1 -1
  114. package/dist/selectList/selectList.helpers.js +29 -4
  115. package/dist/selectList/selectList.js +3 -1
  116. package/dist/selectList/selectList.reducer.js +1 -2
  117. package/dist/selectList/selectListItem.js +4 -1
  118. package/dist/sortControl/sortControl.js +59 -4
  119. package/dist/table/children/useTableChildren.d.ts +1 -1
  120. package/dist/table/children/useTableChildren.js +3 -3
  121. package/dist/table/flexible/columnsList.js +4 -2
  122. package/dist/table/selectable/useSelectableRows.d.ts +8 -0
  123. package/dist/table/selectable/useSelectableRows.js +14 -6
  124. package/dist/table/table.js +1 -7
  125. package/dist/tabs/tabs.js +60 -58
  126. package/dist/tabs/tabsTestHelper.js +2 -2
  127. package/dist/timePickerRaw/timePickerRaw.js +1 -1
  128. package/dist/toggleButtonRaw/toggleButtonRaw.js +5 -2
  129. package/dist/utils/localization/translations/ar.json +3 -1
  130. package/dist/utils/localization/translations/cs.json +9 -5
  131. package/dist/utils/localization/translations/da-DK.json +9 -5
  132. package/dist/utils/localization/translations/de.json +9 -5
  133. package/dist/utils/localization/translations/en.json +5 -1
  134. package/dist/utils/localization/translations/es.json +9 -5
  135. package/dist/utils/localization/translations/fi-FI.json +9 -5
  136. package/dist/utils/localization/translations/fr-FR.json +9 -5
  137. package/dist/utils/localization/translations/fr.json +9 -5
  138. package/dist/utils/localization/translations/hu-HU.json +9 -5
  139. package/dist/utils/localization/translations/id.json +9 -5
  140. package/dist/utils/localization/translations/it.json +9 -5
  141. package/dist/utils/localization/translations/ja.json +9 -5
  142. package/dist/utils/localization/translations/ko-KR.json +9 -5
  143. package/dist/utils/localization/translations/ms.json +9 -5
  144. package/dist/utils/localization/translations/nb-NO.json +9 -5
  145. package/dist/utils/localization/translations/nl.json +9 -5
  146. package/dist/utils/localization/translations/pl.json +9 -5
  147. package/dist/utils/localization/translations/pt-BR.json +9 -5
  148. package/dist/utils/localization/translations/pt-PT.json +9 -5
  149. package/dist/utils/localization/translations/ro-RO.json +9 -5
  150. package/dist/utils/localization/translations/sk-SK.json +9 -5
  151. package/dist/utils/localization/translations/sv.json +9 -5
  152. package/dist/utils/localization/translations/th.json +9 -5
  153. package/dist/utils/localization/translations/tr.json +9 -5
  154. package/dist/utils/localization/translations/zh-Hans.json +9 -5
  155. package/dist/utils/localization/translations/zh-TW.json +9 -5
  156. package/dist/utils/localization/useDirectionalIcon.d.ts +3 -0
  157. package/dist/utils/localization/useDirectionalIcon.js +9 -0
  158. package/dist/utils/positioningUtils/alignments.d.ts +2 -2
  159. package/dist/utils/positioningUtils/alignments.js +2 -2
  160. package/dist/utils/positioningUtils/calculatePosition.js +4 -6
  161. package/esm/calendar/calendar.js +7 -4
  162. package/esm/card/components/title.js +4 -1
  163. package/esm/card/components/titleLink.js +5 -2
  164. package/esm/chart/barChart/getDefaultOptions.d.ts +2 -1
  165. package/esm/chart/barChart/getDefaultOptions.js +5 -2
  166. package/esm/chart/barChart.js +6 -4
  167. package/esm/chart/lineChart/getDefaultOptions.d.ts +2 -1
  168. package/esm/chart/lineChart/getDefaultOptions.js +5 -2
  169. package/esm/chart/lineChart.js +4 -2
  170. package/esm/checkboxListWithAction/checkboxListWithAction.js +4 -1
  171. package/esm/commonHelpers/arrowNavigation/components/arrowButton/arrowButton.js +4 -1
  172. package/esm/controlledPopup/controlledPopup.d.ts +1 -0
  173. package/esm/controlledPopup/controlledPopup.js +3 -1
  174. package/esm/dataGrid/cell/cell.d.ts +2 -1
  175. package/esm/dataGrid/cell/cell.js +2 -2
  176. package/esm/dataGrid/dataGrid.js +7 -4
  177. package/esm/dataGrid/listColumn.d.ts +2 -0
  178. package/esm/dataGrid/row/row.d.ts +2 -1
  179. package/esm/dataGrid/row/row.js +13 -9
  180. package/esm/dataGrid/withFlexibleColumns/components/columnSettingsList.js +2 -1
  181. package/esm/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +4 -0
  182. package/esm/dateRangeInner/dateRangeInner.js +5 -2
  183. package/esm/dateRangeRaw/dateRangeRaw.js +5 -2
  184. package/esm/dateRangeRaw/utils/parseLabel.js +1 -1
  185. package/esm/dropdownRaw/dropdownRaw.js +12 -6
  186. package/esm/fileUpload/components/dropZoneContent.js +100 -100
  187. package/esm/fileUpload/fileUpload.js +100 -100
  188. package/esm/filters/components/filtersSearchList.js +4 -1
  189. package/esm/filtersBar/filtersContainer/filtersContainer.js +62 -61
  190. package/esm/formStepperButtons/formStepperButtons.js +4 -1
  191. package/esm/groupsFilterRaw/groupsFilterAdjustmentState.js +4 -1
  192. package/esm/groupsFilterRaw/groupsFilterInitialState.js +4 -1
  193. package/esm/header/headerBack.js +4 -1
  194. package/esm/icons/iconAlignLeft.js +1 -3
  195. package/esm/icons/iconAlignmentLeft.js +1 -3
  196. package/esm/icons/iconAlignmentRight.js +1 -3
  197. package/esm/icons/iconArrowBottomLeft.js +1 -3
  198. package/esm/icons/iconArrowBottomRight.js +1 -3
  199. package/esm/icons/iconArrowLeftPath.js +1 -3
  200. package/esm/icons/iconArrowRight.js +1 -3
  201. package/esm/icons/iconArrowRightCircle.js +1 -3
  202. package/esm/icons/iconArrowRightPath.js +1 -3
  203. package/esm/icons/iconArrowTopLeft.js +1 -3
  204. package/esm/icons/iconArrowTopRight.js +1 -3
  205. package/esm/icons/iconChevronDoubleRight.js +1 -3
  206. package/esm/icons/iconChevronRight.js +1 -3
  207. package/esm/icons/iconChevronRightSmall.js +1 -3
  208. package/esm/icons/iconCornerDownLeft.js +1 -3
  209. package/esm/icons/iconCornerDownRight.js +1 -3
  210. package/esm/icons/iconCornerLeftDown.js +1 -3
  211. package/esm/icons/iconCornerLeftUp.js +1 -3
  212. package/esm/icons/iconCornerRightDown.js +1 -3
  213. package/esm/icons/iconCornerRightUp.js +1 -3
  214. package/esm/icons/iconCornerUpLeft.js +1 -3
  215. package/esm/icons/iconCornerUpRight.js +1 -3
  216. package/esm/index.d.ts +1 -0
  217. package/esm/index.js +1 -0
  218. package/esm/lineChartMini/lineChartMini.js +15 -3
  219. package/esm/list/itemData/itemDataInternal.js +4 -1
  220. package/esm/list/list.d.ts +1 -0
  221. package/esm/list/list.js +2 -2
  222. package/esm/list/listItem/listItem.d.ts +1 -3
  223. package/esm/list/listItem/listItem.js +6 -5
  224. package/esm/menu/components/controlledMenuList/controlledMenuList.d.ts +27 -0
  225. package/esm/menu/components/controlledMenuList/controlledMenuList.js +123 -0
  226. package/esm/menu/components/createControlledMenuList.d.ts +37 -0
  227. package/esm/menu/components/createControlledMenuList.js +51 -0
  228. package/esm/menu/components/createMenuItem.d.ts +67 -0
  229. package/esm/menu/components/createMenuItem.js +93 -0
  230. package/esm/menu/components/menuButton.js +12 -3
  231. package/esm/menu/components/menuItem.d.ts +1 -2
  232. package/esm/menu/components/menuItem.js +20 -74
  233. package/esm/menu/contexts/usePathContext.d.ts +2 -0
  234. package/esm/menu/contexts/usePathContext.js +5 -0
  235. package/esm/menu/controlledMenu.js +10 -177
  236. package/esm/menu/utils/buildMenuContent.d.ts +2 -0
  237. package/esm/menu/utils/buildMenuContent.js +34 -0
  238. package/esm/menu/utils/findContent.d.ts +2 -2
  239. package/esm/menu/utils/findContent.js +4 -3
  240. package/esm/menu/utils/getItemLabel.d.ts +2 -0
  241. package/esm/menu/utils/getItemLabel.js +4 -0
  242. package/esm/menu/utils/getSafeRel.d.ts +1 -0
  243. package/esm/menu/utils/getSafeRel.js +10 -0
  244. package/esm/menu/utils/isMenuItem.d.ts +2 -0
  245. package/esm/menu/utils/isMenuItem.js +9 -0
  246. package/esm/menu/utils/isSafeHref.d.ts +1 -0
  247. package/esm/menu/utils/isSafeHref.js +6 -0
  248. package/esm/menu/utils/normalizeSeparators.d.ts +2 -0
  249. package/esm/menu/utils/normalizeSeparators.js +19 -0
  250. package/esm/menu/utils/resolveKeys.d.ts +12 -0
  251. package/esm/menu/utils/resolveKeys.js +18 -0
  252. package/esm/menu/utils/useLastValidSheet.d.ts +7 -0
  253. package/esm/menu/utils/useLastValidSheet.js +26 -0
  254. package/esm/menu/utils/useMenuItemCore.d.ts +31 -0
  255. package/esm/menu/utils/useMenuItemCore.js +50 -0
  256. package/esm/menu/utils/useMenuItemKeyboardNav.d.ts +2 -0
  257. package/esm/menu/utils/useMenuItemKeyboardNav.js +11 -0
  258. package/esm/menu/utils/useMenuListKeyboardNav.d.ts +12 -0
  259. package/esm/menu/utils/useMenuListKeyboardNav.js +73 -0
  260. package/esm/menu/utils/useMenuPath.d.ts +6 -0
  261. package/esm/menu/utils/useMenuPath.js +31 -0
  262. package/esm/nav/navItem/navItem.js +10 -5
  263. package/esm/nav/navSection/navSection.js +7 -5
  264. package/esm/pagination/paginationArrow.js +10 -3
  265. package/esm/radioGroupRaw/radioGroupRaw.js +2 -1
  266. package/esm/rangeRaw/rangeRaw.js +0 -1
  267. package/esm/selectList/selectList.helpers.d.ts +1 -1
  268. package/esm/selectList/selectList.helpers.js +29 -4
  269. package/esm/selectList/selectList.js +3 -1
  270. package/esm/selectList/selectList.reducer.js +1 -2
  271. package/esm/selectList/selectListItem.js +4 -1
  272. package/esm/sortControl/sortControl.js +59 -4
  273. package/esm/table/children/useTableChildren.d.ts +1 -1
  274. package/esm/table/children/useTableChildren.js +3 -3
  275. package/esm/table/flexible/columnsList.js +4 -2
  276. package/esm/table/selectable/useSelectableRows.d.ts +8 -0
  277. package/esm/table/selectable/useSelectableRows.js +14 -6
  278. package/esm/table/table.js +1 -7
  279. package/esm/tabs/tabs.js +60 -58
  280. package/esm/tabs/tabsTestHelper.js +2 -2
  281. package/esm/testHelpers/mockAbsoluteAlignment.d.ts +1 -0
  282. package/esm/testHelpers/mockAbsoluteAlignment.js +10 -0
  283. package/esm/timePickerRaw/timePickerRaw.js +1 -1
  284. package/esm/toggleButtonRaw/toggleButtonRaw.js +5 -2
  285. package/esm/utils/localization/translations/ar.json +3 -1
  286. package/esm/utils/localization/translations/cs.json +9 -5
  287. package/esm/utils/localization/translations/da-DK.json +9 -5
  288. package/esm/utils/localization/translations/de.json +9 -5
  289. package/esm/utils/localization/translations/en.json +5 -1
  290. package/esm/utils/localization/translations/es.json +9 -5
  291. package/esm/utils/localization/translations/fi-FI.json +9 -5
  292. package/esm/utils/localization/translations/fr-FR.json +9 -5
  293. package/esm/utils/localization/translations/fr.json +9 -5
  294. package/esm/utils/localization/translations/hu-HU.json +9 -5
  295. package/esm/utils/localization/translations/id.json +9 -5
  296. package/esm/utils/localization/translations/it.json +9 -5
  297. package/esm/utils/localization/translations/ja.json +9 -5
  298. package/esm/utils/localization/translations/ko-KR.json +9 -5
  299. package/esm/utils/localization/translations/ms.json +9 -5
  300. package/esm/utils/localization/translations/nb-NO.json +9 -5
  301. package/esm/utils/localization/translations/nl.json +9 -5
  302. package/esm/utils/localization/translations/pl.json +9 -5
  303. package/esm/utils/localization/translations/pt-BR.json +9 -5
  304. package/esm/utils/localization/translations/pt-PT.json +9 -5
  305. package/esm/utils/localization/translations/ro-RO.json +9 -5
  306. package/esm/utils/localization/translations/sk-SK.json +9 -5
  307. package/esm/utils/localization/translations/sv.json +9 -5
  308. package/esm/utils/localization/translations/th.json +9 -5
  309. package/esm/utils/localization/translations/tr.json +9 -5
  310. package/esm/utils/localization/translations/zh-Hans.json +9 -5
  311. package/esm/utils/localization/translations/zh-TW.json +9 -5
  312. package/esm/utils/localization/useDirectionalIcon.d.ts +3 -0
  313. package/esm/utils/localization/useDirectionalIcon.js +5 -0
  314. package/esm/utils/positioningUtils/alignments.d.ts +2 -2
  315. package/esm/utils/positioningUtils/alignments.js +2 -2
  316. package/esm/utils/positioningUtils/calculatePosition.js +4 -6
  317. package/package.json +123 -122
@@ -2,18 +2,24 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createElement, useCallback, useMemo } from "react";
3
3
  import { classNames } from "../../commonHelpers/classNames/classNames";
4
4
  import { IconChevronRight } from "../../icons/iconChevronRight";
5
+ import { IconChevronLeft } from "../../icons/iconChevronLeft";
6
+ import { useDirectionalIcon } from "../../utils/localization/useDirectionalIcon";
5
7
  import { useDriveClassName } from "../../utils/theme/useDriveClassName";
6
8
  import { useDrive } from "../../utils/theme/useDrive";
7
9
  import { getMenuButtonState } from "../utils/getMenuButtonState";
10
+ import { isSafeHref } from "../utils/isSafeHref";
11
+ import { getSafeRel } from "../utils/getSafeRel";
8
12
  export const MenuButton = ({ id, onClick, hasChildren, disabled, icon, name, link, target, rel, className = "", active = null, ref }) => {
9
13
  const { hasState, isActive } = getMenuButtonState(active, disabled);
10
14
  const driveMenuButtonActionClasses = useDriveClassName("zen-menu-button__action");
11
15
  const isDrive = useDrive();
16
+ const ChevronIcon = useDirectionalIcon(IconChevronRight, IconChevronLeft);
12
17
  const linkEvents = useMemo(() => ({
13
18
  onKeyDown: e => {
14
19
  if (e.key === " ") {
15
20
  e.preventDefault();
16
21
  const linkEl = e.target;
22
+ linkEl.dataset.spaceDown = "1";
17
23
  linkEl.classList.add("zen-menu-button__action--active");
18
24
  }
19
25
  },
@@ -22,7 +28,10 @@ export const MenuButton = ({ id, onClick, hasChildren, disabled, icon, name, lin
22
28
  e.preventDefault();
23
29
  const linkEl = e.target;
24
30
  linkEl.classList.remove("zen-menu-button__action--active");
25
- linkEl.click();
31
+ if (linkEl.dataset.spaceDown) {
32
+ delete linkEl.dataset.spaceDown;
33
+ linkEl.click();
34
+ }
26
35
  }
27
36
  }
28
37
  }), []);
@@ -40,13 +49,13 @@ export const MenuButton = ({ id, onClick, hasChildren, disabled, icon, name, lin
40
49
  createElement(icon, {
41
50
  size: isDrive ? "huge" : "large",
42
51
  className: classNames(["zen-caption__pre-content", "zen-menu-button__icon"])
43
- }), _jsx("span", { className: "zen-menu-button__action-text", children: name }), !!hasChildren && (_jsx(IconChevronRight, { size: isDrive ? "huge" : "large", className: classNames(["zen-caption__pre-content", "zen-menu-button__more-icon"]) }))] }));
52
+ }), _jsx("span", { className: "zen-menu-button__action-text", children: name }), !!hasChildren && (_jsx(ChevronIcon, { size: isDrive ? "huge" : "large", className: classNames(["zen-caption__pre-content", "zen-menu-button__more-icon"]) }))] }));
44
53
  const linkTemplate = (_jsxs("a", Object.assign({ "data-id": id, role: "menuitem", className: classNames([
45
54
  "zen-menu-button__action",
46
55
  "zen-caption",
47
56
  disabled ? "zen-menu-button__action--disabled" : "",
48
57
  driveMenuButtonActionClasses || ""
49
- ]), href: disabled ? undefined : link, "aria-disabled": disabled, onClick: onClickHandler, target: target, rel: rel }, linkEvents, { children: [!!icon &&
58
+ ]), href: disabled || !isSafeHref(link) ? undefined : link, "aria-disabled": disabled, onClick: onClickHandler, target: target, rel: getSafeRel(rel, target) }, linkEvents, { children: [!!icon &&
50
59
  createElement(icon, {
51
60
  size: isDrive ? "huge" : "large",
52
61
  className: "zen-caption__pre-content"
@@ -2,6 +2,7 @@ import { FC, ReactElement } from "react";
2
2
  import { IMenuButton } from "./menuButton";
3
3
  import "./menuItem.less";
4
4
  import { TAlignment } from "../../absolute/absolute";
5
+ export { isMenuItem } from "../utils/isMenuItem";
5
6
  interface IMenuItemInternal {
6
7
  isMobile?: boolean;
7
8
  setIsOpen?: (v: boolean) => void;
@@ -12,6 +13,4 @@ export interface IMenuControlledItem extends IMenuItem {
12
13
  export interface IMenuItem extends IMenuButton {
13
14
  alignment?: TAlignment;
14
15
  }
15
- export declare const isMenuItem: (element: ReactElement | undefined) => boolean;
16
16
  export declare const MenuItem: FC<Omit<IMenuItem & IMenuControlledItem & IMenuItemInternal, "hasChildren">>;
17
- export {};
@@ -1,34 +1,27 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument, @typescript-eslint/naming-convention */
3
- import { Children, Fragment, cloneElement, useMemo, useRef, useContext, useCallback, isValidElement } from "react";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument */
3
+ import { Fragment, cloneElement, useCallback } from "react";
4
4
  import { MenuButton } from "./menuButton";
5
- import { ControlledMenu } from "../controlledMenu";
6
5
  import { ControlledPopup } from "../../controlledPopup/controlledPopup";
7
- import { PathContext } from "../contexts/pathContext";
8
6
  import { classNames } from "../../commonHelpers/classNames/classNames";
9
- import { generateId } from "../../commonHelpers/generateId";
10
- import { MenuAlignmentContext } from "../../header/headerContext";
11
- import { isSeparator } from "./menuSeparator";
12
- export const isMenuItem = (element) => {
13
- if (!element || !element.type) {
14
- return false;
15
- }
16
- if (element.type === ControlledMenu.Item) {
17
- return true;
18
- }
19
- if ((typeof element.type === "object" || typeof element.type === "function") && "displayName" in element.type) {
20
- return element.type.displayName === "MenuItem";
21
- }
22
- return false;
23
- };
7
+ import { useMenuItemCore } from "../utils/useMenuItemCore";
8
+ export { isMenuItem } from "../utils/isMenuItem";
24
9
  export const MenuItem = ({ id, children, name, icon, disabled, onClick, link, target, rel, isMobile = false, setIsOpen, trigger, className, active, alignment }) => {
25
- const aligmentContext = useContext(MenuAlignmentContext);
26
- const contentAlignment = alignment || aligmentContext.alignment || "right-top";
27
- const { path, onOpenBranch, closeBranch, navigatedViaKeyboardRef } = useContext(PathContext);
28
- const memoizedDesktopActionOnClick = useCallback((itemId, e) => {
10
+ const { ref, isOpen, hasChildren, content, openedViaKeyboard, contentAlignment, path, onOpenBranch, handleOpenChange } = useMenuItemCore({
11
+ id,
12
+ children,
13
+ className,
14
+ alignment,
15
+ isMobile,
16
+ setIsOpen,
17
+ onClick
18
+ });
19
+ // MenuButton.onClick signature is (id, e) — adapt the hook's (e)-only handler
20
+ const memoizedDesktopActionOnClick = useCallback((_, e) => {
29
21
  setIsOpen === null || setIsOpen === void 0 ? void 0 : setIsOpen(false);
30
- onClick === null || onClick === void 0 ? void 0 : onClick(itemId, e);
31
- }, [setIsOpen, onClick]);
22
+ onClick === null || onClick === void 0 ? void 0 : onClick(id, e);
23
+ }, [setIsOpen, onClick, id]);
24
+ // MenuItem-specific callbacks (not provided by hook)
32
25
  const memoizedMobileActionOnClick = useCallback((itemId, e) => {
33
26
  onOpenBranch(id);
34
27
  !link && (onClick === null || onClick === void 0 ? void 0 : onClick(itemId, e));
@@ -46,54 +39,7 @@ export const MenuItem = ({ id, children, name, icon, disabled, onClick, link, ta
46
39
  }
47
40
  onClick === null || onClick === void 0 ? void 0 : onClick(id, e);
48
41
  }, [onClick, onOpenBranch, id, trigger]);
49
- const memoizedOnOpenChange = useCallback(() => {
50
- closeBranch();
51
- }, [closeBranch]);
52
- const ref = useRef(null);
53
- const content = useMemo(() => {
54
- const cont = [];
55
- Children.map(children, (child) => {
56
- if (!child) {
57
- return;
58
- }
59
- if (typeof child === "string") {
60
- cont.push(_jsx("li", { className: classNames(["zen-menu-item__content", className !== null && className !== void 0 ? className : ""]), role: "presentation", children: child }, generateId()));
61
- return;
62
- }
63
- if (isValidElement(child) && isSeparator(child)) {
64
- const clone = cloneElement(child, {
65
- key: child.props.key || generateId()
66
- });
67
- cont.push(clone);
68
- return;
69
- }
70
- if (isMenuItem(child)) {
71
- const childProps = child.props;
72
- const clone = cloneElement(child, {
73
- isMobile,
74
- key: childProps.id,
75
- setIsOpen
76
- });
77
- cont.push(clone);
78
- return;
79
- }
80
- const childProps = child.props;
81
- cont.push(_jsx("li", { className: classNames(["zen-menu-item__content", className !== null && className !== void 0 ? className : ""]), role: "presentation", children: child }, childProps.id || childProps["data-id"] || generateId()));
82
- });
83
- return cont;
84
- }, [children, isMobile, setIsOpen, className]);
85
- const isOpen = useMemo(() => path.includes(id), [path, id]);
86
- // Track previous isOpen state to detect when submenu opens
87
- const wasOpenRef = useRef(false);
88
- const localOpenedViaKeyboardRef = useRef(false);
89
- // Capture keyboard navigation state synchronously when isOpen transitions to true
90
- if (isOpen && !wasOpenRef.current && navigatedViaKeyboardRef) {
91
- localOpenedViaKeyboardRef.current = navigatedViaKeyboardRef.current;
92
- navigatedViaKeyboardRef.current = false; // Reset for next navigation
93
- }
94
- wasOpenRef.current = isOpen;
95
- const openedViaKeyboard = localOpenedViaKeyboardRef.current;
96
- if (content.length === 0) {
42
+ if (!hasChildren) {
97
43
  return (_jsx(MenuButton, { id: id, name: name, icon: icon, disabled: disabled, link: link, target: target, rel: rel, onClick: memoizedDesktopActionOnClick, className: className, active: active, hasChildren: false }, id));
98
44
  }
99
45
  if (isMobile) {
@@ -109,6 +55,6 @@ export const MenuItem = ({ id, children, name, icon, disabled, onClick, link, ta
109
55
  else {
110
56
  popupTrigger = (_jsx(MenuButton, { id: id, ref: ref, name: name, icon: icon, disabled: disabled, hasChildren: true, onClick: memoizedTriggerOnClick, active: active }, id));
111
57
  }
112
- return (_jsxs(Fragment, { children: [popupTrigger, _jsx(ControlledPopup, { className: classNames([`zen-controlled-menu-submenu--${path.length}`]), useTrapFocusWithTrigger: openedViaKeyboard ? "on" : "withTrigger", alignment: contentAlignment, triggerRef: ref, isOpen: isOpen, onOpenChange: memoizedOnOpenChange, ariaLabel: popupTrigger.props.name, recalculateOnScroll: true, children: _jsx("ul", { role: "menu", className: "zen-menu-item", children: content }) })] }, id));
58
+ return (_jsxs(Fragment, { children: [popupTrigger, _jsx(ControlledPopup, { className: classNames([`zen-controlled-menu-submenu--${path.length}`]), useTrapFocusWithTrigger: openedViaKeyboard ? "on" : "withTrigger", alignment: contentAlignment, triggerRef: ref, isOpen: isOpen, onOpenChange: handleOpenChange, ariaLabel: popupTrigger.props.name, recalculateOnScroll: true, children: _jsx("ul", { role: "menu", className: "zen-menu-item", children: content }) })] }, id));
113
59
  };
114
60
  MenuItem.displayName = "MenuItem";
@@ -0,0 +1,2 @@
1
+ import { IPathContext } from "./pathContext";
2
+ export declare function usePathContext(): IPathContext;
@@ -0,0 +1,5 @@
1
+ import { useContext } from "react";
2
+ import { PathContext } from "./pathContext";
3
+ export function usePathContext() {
4
+ return useContext(PathContext);
5
+ }
@@ -1,45 +1,26 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- /* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument */
3
- import { Children, cloneElement, isValidElement, useState, useMemo, useCallback, useEffect, useRef } from "react";
4
- import { MenuItem, isMenuItem } from "./components/menuItem";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback, useEffect, useRef } from "react";
5
3
  import { classNames } from "../commonHelpers/classNames/classNames";
6
- import { findContent } from "./utils/findContent";
7
- import { findFirstFocusable } from "./utils/findFirstFocusable";
8
- import { findLastFocusable } from "./utils/findLastFocusable";
9
- import { findNextFocusable } from "./utils/findNextFocusable";
10
- import { isButton } from "./utils/isButton";
11
- import { isLink } from "./utils/isLink";
12
- import { findPrevFocusable } from "./utils/findPrevFocusable";
13
- import { MenuButton } from "./components/menuButton";
14
- import { IconArrowLeft } from "../icons/iconArrowLeft";
15
4
  import { ControlledPopup } from "../controlledPopup/controlledPopup";
16
5
  import { MobileSheet } from "../mobileSheet/mobileSheet";
17
6
  import { DeviceType } from "../commonHelpers/hooks/deviceType";
18
7
  import { useDeviceType } from "../commonHelpers/hooks/useDeviceType";
19
- import { generateId } from "../commonHelpers/generateId";
20
- import { PathProvider } from "./contexts/pathProvider";
21
- import { isSeparator, MenuSeparator } from "./components/menuSeparator";
22
8
  import { FOCUSABLE_SELECTOR } from "../utils/focusableSelector";
9
+ import { ControlledMenuList } from "./components/controlledMenuList/controlledMenuList";
10
+ const EmbeddedMenuList = ControlledMenuList;
23
11
  export const ControlledMenu = ({ children, isOpen, setIsOpen, triggerRef, ariaLabel, ariaLabelledby, id, title, className = "", listClassName = "", paddingX = 0, paddingY = 0, alignment, closeOnScroll = true }) => {
24
12
  const [deviceType, setDeviceType] = useState(DeviceType.Desktop);
25
13
  const isMobile = deviceType === DeviceType.Mobile;
26
14
  const memoizedOnChange = useCallback(setIsOpen, [setIsOpen]);
27
15
  useDeviceType(setDeviceType);
28
16
  const menuListRef = useRef(null);
29
- const [path, setPath] = useState([]);
30
- // Track if the trigger was activated via keyboard
31
17
  const openedViaKeyboardRef = useRef(false);
32
- // Track if submenu was navigated via keyboard (ArrowRight)
33
- const navigatedViaKeyboardRef = useRef(false);
34
- // Track if keyboard is actively being used for navigation (vs mouse/touch)
35
- const keyboardActiveRef = useRef(false);
36
- // Listen for keyboard activation on trigger
37
18
  useEffect(() => {
38
19
  const trigger = triggerRef.current;
39
20
  if (!trigger)
40
21
  return undefined;
41
22
  const handleKeyDown = (e) => {
42
- if (e.key === "Enter" || e.key === " ") {
23
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowRight") {
43
24
  openedViaKeyboardRef.current = true;
44
25
  }
45
26
  };
@@ -53,12 +34,6 @@ export const ControlledMenu = ({ children, isOpen, setIsOpen, triggerRef, ariaLa
53
34
  trigger.removeEventListener("mousedown", handleMouseDown);
54
35
  };
55
36
  }, [triggerRef]);
56
- useEffect(() => {
57
- if (path.length && !isOpen) {
58
- setPath([]);
59
- }
60
- }, [isOpen, path, setPath]);
61
- // Focus the menu list container or first item when menu opens (for keyboard navigation)
62
37
  useEffect(() => {
63
38
  var _a;
64
39
  if (isOpen && !isMobile && menuListRef.current) {
@@ -70,156 +45,14 @@ export const ControlledMenu = ({ children, isOpen, setIsOpen, triggerRef, ariaLa
70
45
  }
71
46
  }
72
47
  }, [isOpen, isMobile]);
73
- const onOpenBranch = useCallback((branchId) => {
74
- if (!branchId) {
75
- return;
76
- }
77
- if (!path.includes(branchId)) {
78
- setPath([...path, branchId]);
79
- return;
80
- }
81
- if (path.includes(branchId)) {
82
- setPath(v => {
83
- const newPath = [...v];
84
- newPath.pop();
85
- return newPath;
86
- });
87
- }
88
- }, [setPath, path]);
89
- const closeBranch = useCallback(() => {
90
- setPath(v => {
91
- const newPath = [...v];
92
- newPath.pop();
93
- return newPath;
94
- });
95
- }, [setPath]);
96
- const [content, parent] = useMemo(() => {
97
- let par = null;
98
- let currentChildren = children;
99
- if (isMobile && path.length > 0) {
100
- const el = findContent(children, ControlledMenu.Item, path[path.length - 1]);
101
- if (el || isValidElement(el)) {
102
- const elProps = el.props;
103
- currentChildren = elProps.children;
104
- par = el;
105
- }
106
- }
107
- let cont = [];
108
- Children.map(currentChildren, (child) => {
109
- if (!child) {
110
- return;
111
- }
112
- if (typeof child === "string") {
113
- cont.push(_jsx("li", { role: "presentation", className: classNames(["zen-menu-item__content"]), children: child }, generateId()));
114
- return;
115
- }
116
- if (isValidElement(child) && isSeparator(child)) {
117
- const clone = cloneElement(child, {
118
- key: child.props.key || generateId()
119
- });
120
- cont.push(clone);
121
- return;
122
- }
123
- if (isValidElement(child) && isMenuItem(child)) {
124
- const clone = cloneElement(child, {
125
- isMobile,
126
- key: child.props.id,
127
- setIsOpen,
128
- onClick: child.props.onClick
129
- });
130
- cont.push(clone);
131
- return;
132
- }
133
- const childProps = child.props;
134
- cont.push(_jsx("li", { className: classNames(["zen-menu-item__content"]), role: "presentation", children: child }, childProps.id || childProps["data-id"] || generateId()));
135
- });
136
- while (cont[0] && isSeparator(cont[0])) {
137
- cont.shift();
138
- }
139
- while (cont[cont.length - 1] && isSeparator(cont[cont.length - 1])) {
140
- cont.pop();
141
- }
142
- cont = cont.filter((el, indx, arr) => {
143
- if (isSeparator(el) && arr[indx - 1] && isSeparator(arr[indx - 1])) {
144
- return false;
145
- }
146
- return true;
147
- });
148
- return [cont, par];
149
- }, [children, isMobile, path, setIsOpen]);
150
- // Handle keyboard navigation when no menu item is focused (e.g., when menu just opened)
151
- const handleUnfocusedKeyDown = (e, menuList) => {
152
- var _a, _b;
153
- if (e.key === "ArrowDown" || e.key === "Home") {
154
- e.preventDefault();
155
- (_a = findFirstFocusable(menuList)) === null || _a === void 0 ? void 0 : _a.focus();
156
- return true;
157
- }
158
- if (e.key === "ArrowUp" || e.key === "End") {
159
- e.preventDefault();
160
- (_b = findLastFocusable(menuList)) === null || _b === void 0 ? void 0 : _b.focus();
161
- return true;
162
- }
163
- return false;
164
- };
165
- const onMouseDown = () => {
166
- keyboardActiveRef.current = false;
167
- };
168
- const onKeyDown = e => {
169
- var _a, _b, _c, _d;
170
- keyboardActiveRef.current = true;
171
- const target = e.target;
172
- const currentTarget = e.currentTarget;
173
- if (!isButton(target) && !isLink(target)) {
174
- if (target === currentTarget) {
175
- const menuList = currentTarget.querySelector("ul");
176
- if (menuList) {
177
- handleUnfocusedKeyDown(e, menuList);
178
- }
179
- }
180
- return;
181
- }
182
- if (e.key === "ArrowDown") {
183
- e.preventDefault();
184
- (_a = findNextFocusable(target)) === null || _a === void 0 ? void 0 : _a.focus();
185
- return;
186
- }
187
- if (e.key === "ArrowUp") {
188
- e.preventDefault();
189
- (_b = findPrevFocusable(target)) === null || _b === void 0 ? void 0 : _b.focus();
190
- return;
191
- }
192
- if (e.key === "Home") {
193
- e.preventDefault();
194
- (_c = findFirstFocusable(target)) === null || _c === void 0 ? void 0 : _c.focus();
195
- return;
196
- }
197
- if (e.key === "End") {
198
- e.preventDefault();
199
- (_d = findLastFocusable(target)) === null || _d === void 0 ? void 0 : _d.focus();
200
- return;
201
- }
202
- if (isButton(target) &&
203
- (e.key === "ArrowRight" || e.key === "Enter" || e.key === " ") &&
204
- target.classList.contains("zen-menu-button__action--has-children")) {
205
- e.preventDefault();
206
- navigatedViaKeyboardRef.current = true;
207
- target.click();
208
- }
209
- };
210
- const renderMenuList = () => (_jsx("div", { ref: menuListRef, tabIndex: -1, onKeyDown: onKeyDown, onMouseDown: onMouseDown, className: classNames(["zen-action-list", className]), children: _jsxs("ul", { role: "menu", className: classNames(["zen-menu-item", className, listClassName]), children: [parent ? (_jsx(MenuButton, { id: "root", name: parent.props.name || "", icon: IconArrowLeft, onClick: closeBranch, hasChildren: false, disabled: false }, "root")) : null, content] }) }));
211
48
  const hideMenu = useCallback(() => {
212
- closeBranch();
213
49
  setIsOpen(false);
214
- }, [closeBranch, setIsOpen]);
50
+ }, [setIsOpen]);
215
51
  if (isMobile) {
216
- return (_jsx(_Fragment, { children: _jsx(PathProvider, { path: path, onOpenBranch: onOpenBranch, closeBranch: closeBranch, navigatedViaKeyboardRef: navigatedViaKeyboardRef, keyboardActiveRef: keyboardActiveRef, children: _jsxs(MobileSheet, { label: title, isOpen: isOpen, triggerRef: triggerRef, onHidePanel: hideMenu, onCloseClick: hideMenu, children: [_jsx(MobileSheet.Title, { children: title }), _jsx(MobileSheet.Content, { children: renderMenuList() })] }) }) }));
52
+ return (_jsxs(MobileSheet, { label: title, isOpen: isOpen, triggerRef: triggerRef, onHidePanel: hideMenu, onCloseClick: hideMenu, children: [_jsx(MobileSheet.Title, { children: title }), _jsx(MobileSheet.Content, { children: _jsx(EmbeddedMenuList, { ref: menuListRef, setIsOpen: setIsOpen, isOpen: isOpen, className: className, listClassName: listClassName, children: children }) })] }));
217
53
  }
218
- return (_jsx(_Fragment, { children: _jsx(PathProvider, { path: path, onOpenBranch: onOpenBranch, closeBranch: closeBranch, navigatedViaKeyboardRef: navigatedViaKeyboardRef, keyboardActiveRef: keyboardActiveRef, children: _jsx(ControlledPopup, { id: id, useTrapFocusWithTrigger: "on", className: classNames(["zen-controlled-menu", className]), onOpenChange: memoizedOnChange, isOpen: isOpen, triggerRef: triggerRef, paddingX: paddingX, paddingY: paddingY, alignment: alignment, ariaLabelledby: ariaLabelledby, ariaLabel: ariaLabel || title, closeOnScroll: closeOnScroll,
219
- // focusOnOpen is false - ControlledMenu handles focus based on input method
220
- // (keyboard vs mouse) in its own useEffect
221
- focusOnOpen: false, children: renderMenuList() }) }) }));
54
+ return (_jsx(ControlledPopup, { id: id, useTrapFocusWithTrigger: "on", className: classNames(["zen-controlled-menu", className]), onOpenChange: memoizedOnChange, isOpen: isOpen, triggerRef: triggerRef, paddingX: paddingX, paddingY: paddingY, alignment: alignment, ariaLabelledby: ariaLabelledby, ariaLabel: ariaLabel || title, recalculateOnScroll: true, focusOnOpen: false, closeOnScroll: closeOnScroll, children: _jsx(EmbeddedMenuList, { ref: menuListRef, setIsOpen: setIsOpen, isOpen: isOpen, className: className, listClassName: listClassName, children: children }) }));
222
55
  };
223
- ControlledMenu.Item = MenuItem;
224
- ControlledMenu.Separator = MenuSeparator;
56
+ ControlledMenu.Item = ControlledMenuList.Item;
57
+ ControlledMenu.Separator = ControlledMenuList.Separator;
225
58
  export const TRANSLATIONS = ["Back"];
@@ -0,0 +1,2 @@
1
+ import { ReactNode } from "react";
2
+ export declare function buildMenuContent(children: ReactNode, isMobile: boolean, setIsOpen: ((v: boolean) => void) | undefined, className: string | undefined): ReactNode[];
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument */
3
+ import { Children, cloneElement, isValidElement } from "react";
4
+ import { classNames } from "../../commonHelpers/classNames/classNames";
5
+ import { isSeparator } from "../components/menuSeparator";
6
+ import { isMenuItem } from "./isMenuItem";
7
+ import { generateId } from "../../commonHelpers/generateId";
8
+ export function buildMenuContent(children, isMobile, setIsOpen, className) {
9
+ const cont = [];
10
+ Children.map(children, (child) => {
11
+ if (!child) {
12
+ return;
13
+ }
14
+ if (typeof child === "string") {
15
+ cont.push(_jsx("li", { className: classNames(["zen-menu-item__content", className !== null && className !== void 0 ? className : ""]), role: "presentation", children: child }, generateId()));
16
+ return;
17
+ }
18
+ if (isValidElement(child) && isSeparator(child)) {
19
+ const clone = cloneElement(child, { key: child.props.key || generateId() });
20
+ cont.push(clone);
21
+ return;
22
+ }
23
+ if (isMenuItem(child)) {
24
+ const childProps = child.props;
25
+ const clone = cloneElement(child, { isMobile, key: childProps.id, setIsOpen });
26
+ cont.push(clone);
27
+ return;
28
+ }
29
+ // eslint-disable-next-line @typescript-eslint/naming-convention
30
+ const childProps = child.props;
31
+ cont.push(_jsx("li", { className: classNames(["zen-menu-item__content", className !== null && className !== void 0 ? className : ""]), role: "presentation", children: child }, childProps.id || childProps["data-id"] || generateId()));
32
+ });
33
+ return cont;
34
+ }
@@ -1,2 +1,2 @@
1
- import React, { ReactNode, ReactElement } from "react";
2
- export declare const findContent: (children: ReactNode, targetComponent: React.FC | React.ComponentClass, id?: string) => ReactElement | null;
1
+ import { ReactNode, ReactElement } from "react";
2
+ export declare const findContent: (children: ReactNode, matcher: (child: ReactElement) => boolean, id?: string) => ReactElement | null;
@@ -1,17 +1,18 @@
1
1
  import React from "react";
2
- export const findContent = (children, targetComponent, id) => {
2
+ export const findContent = (children, matcher, id) => {
3
3
  let found = null;
4
4
  React.Children.forEach(children, (child) => {
5
5
  if (found || !React.isValidElement(child)) {
6
6
  return;
7
7
  }
8
8
  const childProps = child.props;
9
- if (id ? child.type === targetComponent && childProps.id === id : child.type === targetComponent) {
9
+ const matches = matcher(child);
10
+ if (id ? matches && childProps.id === id : matches) {
10
11
  found = child;
11
12
  return;
12
13
  }
13
14
  if (childProps.children) {
14
- found = findContent(childProps.children, targetComponent, id);
15
+ found = findContent(childProps.children, matcher, id);
15
16
  }
16
17
  });
17
18
  return found;
@@ -0,0 +1,2 @@
1
+ import { ReactElement } from "react";
2
+ export declare const getItemLabel: (el: ReactElement | null) => string;
@@ -0,0 +1,4 @@
1
+ export const getItemLabel = (el) => {
2
+ const props = el === null || el === void 0 ? void 0 : el.props;
3
+ return (props === null || props === void 0 ? void 0 : props.name) || (props === null || props === void 0 ? void 0 : props.title) || "";
4
+ };
@@ -0,0 +1 @@
1
+ export declare const getSafeRel: (rel?: string, target?: string) => string | undefined;
@@ -0,0 +1,10 @@
1
+ export const getSafeRel = (rel, target) => {
2
+ if (target !== "_blank")
3
+ return rel;
4
+ const parts = rel ? rel.split(/\s+/) : [];
5
+ if (!parts.includes("noopener"))
6
+ parts.push("noopener");
7
+ if (!parts.includes("noreferrer"))
8
+ parts.push("noreferrer");
9
+ return parts.join(" ");
10
+ };
@@ -0,0 +1,2 @@
1
+ import { ReactElement } from "react";
2
+ export declare const isMenuItem: (element: ReactElement | undefined) => boolean;
@@ -0,0 +1,9 @@
1
+ export const isMenuItem = (element) => {
2
+ if (!element || !element.type) {
3
+ return false;
4
+ }
5
+ if ((typeof element.type === "object" || typeof element.type === "function") && "displayName" in element.type) {
6
+ return element.type.displayName === "MenuItem";
7
+ }
8
+ return false;
9
+ };
@@ -0,0 +1 @@
1
+ export declare const isSafeHref: (href?: string) => boolean;
@@ -0,0 +1,6 @@
1
+ export const isSafeHref = (href) => {
2
+ if (!href)
3
+ return false;
4
+ const lower = href.toLowerCase().trimStart();
5
+ return !lower.startsWith("javascript:") && !lower.startsWith("data:") && !lower.startsWith("vbscript:");
6
+ };
@@ -0,0 +1,2 @@
1
+ import { ReactElement } from "react";
2
+ export declare const normalizeSeparators: (items: ReactElement[]) => ReactElement[];
@@ -0,0 +1,19 @@
1
+ import { isSeparator } from "../components/menuSeparator";
2
+ export const normalizeSeparators = (items) => {
3
+ // Find the first non-separator index
4
+ let start = 0;
5
+ while (start < items.length && isSeparator(items[start])) {
6
+ start++;
7
+ }
8
+ // Find the last non-separator index
9
+ let end = items.length - 1;
10
+ while (end >= start && isSeparator(items[end])) {
11
+ end--;
12
+ }
13
+ // If all items are separators or array is empty
14
+ if (start > end) {
15
+ return [];
16
+ }
17
+ // Slice to remove leading/trailing separators and filter consecutive duplicates
18
+ return items.slice(start, end + 1).filter((el, i, arr) => !(isSeparator(el) && arr[i - 1] && isSeparator(arr[i - 1])));
19
+ };
@@ -0,0 +1,12 @@
1
+ export declare const verticalKeys: {
2
+ keyNext: string;
3
+ keyPrev: string;
4
+ keyOpenNested: string;
5
+ keyBack: string;
6
+ };
7
+ export declare const resolveKeys: (target: HTMLElement, isHorizontal: boolean) => {
8
+ keyNext: string;
9
+ keyPrev: string;
10
+ keyOpenNested: string;
11
+ keyBack: string;
12
+ };
@@ -0,0 +1,18 @@
1
+ export const verticalKeys = {
2
+ keyNext: "ArrowDown",
3
+ keyPrev: "ArrowUp",
4
+ keyOpenNested: "ArrowRight",
5
+ keyBack: "ArrowLeft"
6
+ };
7
+ export const resolveKeys = (target, isHorizontal) => {
8
+ const inSubMenu = isHorizontal && !!target.closest('[class*="zen-controlled-menu-submenu"]');
9
+ if (inSubMenu) {
10
+ return verticalKeys;
11
+ }
12
+ return {
13
+ keyNext: isHorizontal ? "ArrowRight" : "ArrowDown",
14
+ keyPrev: isHorizontal ? "ArrowLeft" : "ArrowUp",
15
+ keyOpenNested: isHorizontal ? "ArrowUp" : "ArrowRight",
16
+ keyBack: isHorizontal ? "ArrowDown" : "ArrowLeft"
17
+ };
18
+ };
@@ -0,0 +1,7 @@
1
+ import { ReactElement, ReactNode } from "react";
2
+ export declare const useLastValidSheet: (nestedContent: ReactElement[] | null, nestedParent: ReactElement | null, path: string[], children: ReactNode) => {
3
+ sheetContent: ReactElement<unknown, string | import("react").JSXElementConstructor<any>>[];
4
+ sheetParent: ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | null;
5
+ sheetPathLength: number;
6
+ sheetParentName: string;
7
+ };
@@ -0,0 +1,26 @@
1
+ import { useRef } from "react";
2
+ import { findContent } from "./findContent";
3
+ import { getItemLabel } from "./getItemLabel";
4
+ import { isMenuItem } from "../components/menuItem";
5
+ // Preserves the last non-null nested sheet state so the MobileSheet has content
6
+ // to render during its closing animation after `nestedContent` goes null.
7
+ export const useLastValidSheet = (nestedContent, nestedParent, path, children) => {
8
+ const lastNestedContentRef = useRef([]);
9
+ const lastNestedParentRef = useRef(null);
10
+ const lastPathLengthRef = useRef(0);
11
+ const lastSheetTitleRef = useRef("");
12
+ const rootEl = path.length > 0 ? findContent(children, isMenuItem, path[0]) : null;
13
+ const currentSheetTitle = rootEl ? getItemLabel(rootEl) : "";
14
+ if (nestedContent !== null) {
15
+ lastNestedContentRef.current = nestedContent;
16
+ lastNestedParentRef.current = nestedParent;
17
+ lastPathLengthRef.current = path.length;
18
+ lastSheetTitleRef.current = currentSheetTitle;
19
+ }
20
+ return {
21
+ sheetContent: nestedContent !== null ? nestedContent : lastNestedContentRef.current,
22
+ sheetParent: nestedContent !== null ? nestedParent : lastNestedParentRef.current,
23
+ sheetPathLength: nestedContent !== null ? path.length : lastPathLengthRef.current,
24
+ sheetParentName: nestedContent !== null ? currentSheetTitle : lastSheetTitleRef.current
25
+ };
26
+ };