@linzjs/step-ag-grid 23.0.1 → 25.0.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 (292) hide show
  1. package/dist/GridTheme.scss +1 -1
  2. package/dist/index.css +0 -13
  3. package/dist/src/components/ComponentLoadingWrapper.d.ts +1 -1
  4. package/dist/src/components/Grid.d.ts +17 -17
  5. package/dist/src/components/GridCell.d.ts +9 -9
  6. package/dist/src/components/GridCellFiller.d.ts +2 -2
  7. package/dist/src/components/GridCellMultiEditor.d.ts +6 -6
  8. package/dist/src/components/GridCellMultiSelectClassRules.d.ts +1 -1
  9. package/dist/src/components/GridIcon.d.ts +2 -2
  10. package/dist/src/components/GridNoRowsOverlay.d.ts +1 -1
  11. package/dist/src/components/GridPopoverHook.d.ts +2 -2
  12. package/dist/src/components/GridWrapper.d.ts +1 -1
  13. package/dist/src/components/PostSortRowsHook.d.ts +1 -1
  14. package/dist/src/components/clickInputWhenContainingCellClicked.d.ts +1 -1
  15. package/dist/src/components/gridFilter/GridFilterButtons.d.ts +5 -5
  16. package/dist/src/components/gridFilter/GridFilterColumnsToggle.d.ts +1 -1
  17. package/dist/src/components/gridFilter/GridFilterDownloadCsvButton.d.ts +1 -1
  18. package/dist/src/components/gridFilter/GridFilterHeaderIconButton.d.ts +2 -2
  19. package/dist/src/components/gridFilter/GridFilters.d.ts +1 -1
  20. package/dist/src/components/gridFilter/index.d.ts +7 -7
  21. package/dist/src/components/gridFilter/useGridFilter.d.ts +2 -2
  22. package/dist/src/components/gridForm/GridFormDropDown.d.ts +8 -8
  23. package/dist/src/components/gridForm/GridFormEditBearing.d.ts +2 -2
  24. package/dist/src/components/gridForm/GridFormMessage.d.ts +3 -3
  25. package/dist/src/components/gridForm/GridFormMultiSelect.d.ts +4 -4
  26. package/dist/src/components/gridForm/GridFormMultiSelectGrid.d.ts +4 -4
  27. package/dist/src/components/gridForm/GridFormPopoverMenu.d.ts +5 -5
  28. package/dist/src/components/gridForm/GridFormSubComponentTextArea.d.ts +4 -4
  29. package/dist/src/components/gridForm/GridFormSubComponentTextInput.d.ts +4 -4
  30. package/dist/src/components/gridForm/GridFormTextArea.d.ts +4 -4
  31. package/dist/src/components/gridForm/GridFormTextInput.d.ts +3 -3
  32. package/dist/src/components/gridForm/index.d.ts +10 -10
  33. package/dist/src/components/gridHeader/GridHeaderSelect.d.ts +1 -1
  34. package/dist/src/components/gridHeader/index.d.ts +1 -1
  35. package/dist/src/components/gridHook/index.d.ts +1 -1
  36. package/dist/src/components/gridHook/useGridContextMenu.d.ts +4 -4
  37. package/dist/src/components/gridPopoverEdit/GridButton.d.ts +5 -5
  38. package/dist/src/components/gridPopoverEdit/GridEditBoolean.d.ts +4 -4
  39. package/dist/src/components/gridPopoverEdit/GridPopoutEditMultiSelect.d.ts +4 -4
  40. package/dist/src/components/gridPopoverEdit/GridPopoutEditMultiSelectGrid.d.ts +4 -4
  41. package/dist/src/components/gridPopoverEdit/GridPopoverEditBearing.d.ts +4 -4
  42. package/dist/src/components/gridPopoverEdit/GridPopoverEditDropDown.d.ts +4 -4
  43. package/dist/src/components/gridPopoverEdit/GridPopoverMenu.d.ts +4 -4
  44. package/dist/src/components/gridPopoverEdit/GridPopoverMessage.d.ts +4 -4
  45. package/dist/src/components/gridPopoverEdit/GridPopoverTextArea.d.ts +4 -4
  46. package/dist/src/components/gridPopoverEdit/GridPopoverTextInput.d.ts +4 -4
  47. package/dist/src/components/gridPopoverEdit/index.d.ts +11 -11
  48. package/dist/src/components/gridRender/GridRenderGenericCell.d.ts +5 -5
  49. package/dist/src/components/gridRender/GridRenderPopoutMenuCell.d.ts +1 -1
  50. package/dist/src/components/gridRender/index.d.ts +2 -2
  51. package/dist/src/components/gridUtil.d.ts +1 -1
  52. package/dist/src/components/index.d.ts +19 -19
  53. package/dist/src/contexts/GridContext.d.ts +4 -4
  54. package/dist/src/contexts/GridContextProvider.d.ts +3 -3
  55. package/dist/src/contexts/GridPopoverContext.d.ts +3 -3
  56. package/dist/src/contexts/GridPopoverContextProvider.d.ts +4 -4
  57. package/dist/src/contexts/GridUpdatingContextProvider.d.ts +1 -1
  58. package/dist/src/index.d.ts +19 -17
  59. package/dist/src/lui/ActionButton.d.ts +9 -9
  60. package/dist/src/lui/FormError.d.ts +2 -2
  61. package/dist/src/lui/TextAreaInput.d.ts +1 -1
  62. package/dist/src/lui/TextInputFormatted.d.ts +2 -2
  63. package/dist/src/lui/reactUtils.d.ts +1 -1
  64. package/dist/src/lui/stateDeferredHook.d.ts +1 -1
  65. package/dist/src/react-menu3/components/ControlledMenu.d.ts +2 -2
  66. package/dist/src/react-menu3/components/FocusableItem.d.ts +3 -3
  67. package/dist/src/react-menu3/components/Menu.d.ts +3 -3
  68. package/dist/src/react-menu3/components/MenuButton.d.ts +2 -2
  69. package/dist/src/react-menu3/components/MenuDivider.d.ts +1 -1
  70. package/dist/src/react-menu3/components/MenuGroup.d.ts +2 -2
  71. package/dist/src/react-menu3/components/MenuHeader.d.ts +2 -2
  72. package/dist/src/react-menu3/components/MenuItem.d.ts +3 -3
  73. package/dist/src/react-menu3/components/MenuList.d.ts +1 -1
  74. package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +2 -2
  75. package/dist/src/react-menu3/components/SubMenu.d.ts +5 -5
  76. package/dist/src/react-menu3/contexts/EventHandlersContext.d.ts +1 -1
  77. package/dist/src/react-menu3/contexts/MenuListContext.d.ts +2 -2
  78. package/dist/src/react-menu3/contexts/MenuListItemContext.d.ts +1 -1
  79. package/dist/src/react-menu3/contexts/RadioGroupContext.d.ts +1 -1
  80. package/dist/src/react-menu3/contexts/SettingsContext.d.ts +2 -2
  81. package/dist/src/react-menu3/hooks/index.d.ts +9 -9
  82. package/dist/src/react-menu3/hooks/useBEM.d.ts +1 -1
  83. package/dist/src/react-menu3/hooks/useCombinedRef.d.ts +1 -1
  84. package/dist/src/react-menu3/hooks/useIsomorphicLayoutEffect.d.ts +1 -1
  85. package/dist/src/react-menu3/hooks/useItemEffect.d.ts +1 -1
  86. package/dist/src/react-menu3/hooks/useItemState.d.ts +1 -1
  87. package/dist/src/react-menu3/hooks/useItems.d.ts +2 -2
  88. package/dist/src/react-menu3/hooks/useMenuChange.d.ts +1 -1
  89. package/dist/src/react-menu3/hooks/useMenuState.d.ts +1 -1
  90. package/dist/src/react-menu3/hooks/useMenuStateAndFocus.d.ts +1 -1
  91. package/dist/src/react-menu3/index.d.ts +11 -11
  92. package/dist/src/react-menu3/positionUtils/getPositionHelpers.d.ts +1 -1
  93. package/dist/src/react-menu3/positionUtils/index.d.ts +3 -3
  94. package/dist/src/react-menu3/positionUtils/placeArrowHorizontal.d.ts +1 -1
  95. package/dist/src/react-menu3/positionUtils/placeArrowVertical.d.ts +1 -1
  96. package/dist/src/react-menu3/positionUtils/placeLeftorRight.d.ts +4 -4
  97. package/dist/src/react-menu3/positionUtils/placeToporBottom.d.ts +5 -5
  98. package/dist/src/react-menu3/positionUtils/positionContextMenu.d.ts +2 -2
  99. package/dist/src/react-menu3/positionUtils/positionMenu.d.ts +5 -5
  100. package/dist/src/react-menu3/style-utils/index.d.ts +1 -1
  101. package/dist/src/react-menu3/types.d.ts +15 -15
  102. package/dist/src/react-menu3/utils/constants.d.ts +1 -1
  103. package/dist/src/react-menu3/utils/index.d.ts +3 -3
  104. package/dist/src/react-menu3/utils/utils.d.ts +5 -5
  105. package/dist/src/react-menu3/utils/withHovering.d.ts +1 -1
  106. package/{src/utils → dist/src/utils/__tests__}/storybookTestUtil.ts +2 -2
  107. package/{src/utils → dist/src/utils/__tests__}/testQuick.ts +15 -14
  108. package/{src/utils → dist/src/utils/__tests__}/testUtil.ts +31 -36
  109. package/dist/src/utils/__tests__/vitestUtil.ts +295 -0
  110. package/dist/src/utils/textValidator.d.ts +2 -2
  111. package/dist/{step-ag-grid.cjs.js → step-ag-grid.cjs} +969 -955
  112. package/dist/step-ag-grid.cjs.map +1 -0
  113. package/dist/step-ag-grid.esm.js +970 -958
  114. package/dist/step-ag-grid.esm.js.map +1 -1
  115. package/dist/vite.config.d.ts +1 -1
  116. package/package.json +38 -57
  117. package/src/components/ComponentLoadingWrapper.tsx +5 -6
  118. package/src/components/Grid.tsx +85 -83
  119. package/src/components/GridCell.test.tsx +17 -15
  120. package/src/components/GridCell.tsx +46 -44
  121. package/src/components/GridCellFiller.tsx +5 -4
  122. package/src/components/GridCellMultiEditor.tsx +7 -7
  123. package/src/components/GridCellMultiSelectClassRules.tsx +3 -3
  124. package/src/components/GridIcon.tsx +6 -7
  125. package/src/components/GridLoadableCell.tsx +2 -2
  126. package/src/components/GridNoRowsOverlay.tsx +8 -8
  127. package/src/components/GridPopoverHook.tsx +16 -16
  128. package/src/components/GridWrapper.tsx +2 -2
  129. package/src/components/PostSortRowsHook.ts +11 -11
  130. package/src/components/clickInputWhenContainingCellClicked.tsx +5 -5
  131. package/src/components/gridFilter/GridFilterButtons.tsx +8 -9
  132. package/src/components/gridFilter/GridFilterColumnsToggle.tsx +25 -26
  133. package/src/components/gridFilter/GridFilterDownloadCsvButton.tsx +12 -13
  134. package/src/components/gridFilter/GridFilterHeaderIconButton.tsx +9 -10
  135. package/src/components/gridFilter/GridFilterQuick.tsx +6 -6
  136. package/src/components/gridFilter/GridFilters.tsx +1 -1
  137. package/src/components/gridFilter/index.ts +7 -7
  138. package/src/components/gridFilter/useGridFilter.ts +3 -3
  139. package/src/components/gridForm/GridFormDropDown.tsx +56 -52
  140. package/src/components/gridForm/GridFormEditBearing.tsx +12 -12
  141. package/src/components/gridForm/GridFormMessage.tsx +10 -10
  142. package/src/components/gridForm/GridFormMultiSelect.tsx +53 -51
  143. package/src/components/gridForm/GridFormMultiSelectGrid.tsx +25 -26
  144. package/src/components/gridForm/GridFormPopoverMenu.tsx +32 -29
  145. package/src/components/gridForm/GridFormSubComponentTextArea.tsx +10 -10
  146. package/src/components/gridForm/GridFormSubComponentTextInput.tsx +8 -8
  147. package/src/components/gridForm/GridFormTextArea.tsx +11 -11
  148. package/src/components/gridForm/GridFormTextInput.tsx +11 -11
  149. package/src/components/gridForm/index.ts +10 -10
  150. package/src/components/gridHeader/GridHeaderSelect.tsx +9 -9
  151. package/src/components/gridHeader/index.ts +1 -1
  152. package/src/components/gridHook/index.ts +1 -1
  153. package/src/components/gridHook/useGridContextMenu.tsx +7 -7
  154. package/src/components/gridPopoverEdit/GridButton.tsx +13 -12
  155. package/src/components/gridPopoverEdit/GridEditBoolean.tsx +19 -18
  156. package/src/components/gridPopoverEdit/GridPopoutEditMultiSelect.ts +7 -6
  157. package/src/components/gridPopoverEdit/GridPopoutEditMultiSelectGrid.ts +7 -6
  158. package/src/components/gridPopoverEdit/GridPopoverEditBearing.ts +9 -9
  159. package/src/components/gridPopoverEdit/GridPopoverEditDropDown.ts +8 -7
  160. package/src/components/gridPopoverEdit/GridPopoverMenu.tsx +6 -6
  161. package/src/components/gridPopoverEdit/GridPopoverMessage.ts +4 -4
  162. package/src/components/gridPopoverEdit/GridPopoverTextArea.ts +4 -4
  163. package/src/components/gridPopoverEdit/GridPopoverTextInput.ts +4 -4
  164. package/src/components/gridPopoverEdit/index.ts +11 -11
  165. package/src/components/gridRender/GridRenderGenericCell.tsx +5 -5
  166. package/src/components/gridRender/GridRenderPopoutMenuCell.tsx +8 -9
  167. package/src/components/gridRender/index.ts +2 -2
  168. package/src/components/gridUtil.ts +3 -3
  169. package/src/components/index.ts +19 -19
  170. package/src/contexts/GridContext.tsx +52 -46
  171. package/src/contexts/GridContextProvider.test.tsx +15 -14
  172. package/src/contexts/GridContextProvider.tsx +42 -42
  173. package/src/contexts/GridPopoverContext.tsx +10 -7
  174. package/src/contexts/GridPopoverContextProvider.tsx +12 -10
  175. package/src/contexts/GridSubComponentContext.ts +6 -5
  176. package/src/contexts/GridUpdatingContext.tsx +5 -4
  177. package/src/contexts/GridUpdatingContextProvider.tsx +3 -3
  178. package/src/index.ts +19 -21
  179. package/src/lui/ActionButton.scss +2 -2
  180. package/src/lui/ActionButton.tsx +42 -41
  181. package/src/lui/FormError.scss +3 -4
  182. package/src/lui/FormError.tsx +4 -4
  183. package/src/lui/TextAreaInput.tsx +9 -9
  184. package/src/lui/TextInputFormatted.scss +1 -1
  185. package/src/lui/TextInputFormatted.tsx +11 -11
  186. package/src/lui/reactUtils.test.tsx +9 -8
  187. package/src/lui/reactUtils.tsx +2 -2
  188. package/src/lui/stateDeferredHook.tsx +3 -5
  189. package/src/lui/timeoutHook.test.tsx +12 -11
  190. package/src/lui/timeoutHook.tsx +1 -1
  191. package/src/react-app-env.d.ts +1 -1
  192. package/src/react-menu3/components/ControlledMenu.tsx +48 -48
  193. package/src/react-menu3/components/FocusableItem.tsx +7 -7
  194. package/src/react-menu3/components/Menu.tsx +11 -11
  195. package/src/react-menu3/components/MenuButton.tsx +4 -4
  196. package/src/react-menu3/components/MenuDivider.tsx +4 -4
  197. package/src/react-menu3/components/MenuGroup.tsx +5 -5
  198. package/src/react-menu3/components/MenuHeader.tsx +4 -4
  199. package/src/react-menu3/components/MenuItem.tsx +14 -14
  200. package/src/react-menu3/components/MenuList.tsx +55 -55
  201. package/src/react-menu3/components/MenuRadioGroup.tsx +7 -7
  202. package/src/react-menu3/components/SubMenu.tsx +24 -24
  203. package/src/react-menu3/contexts/EventHandlersContext.ts +2 -2
  204. package/src/react-menu3/contexts/HoverItemContext.ts +1 -1
  205. package/src/react-menu3/contexts/ItemSettingsContext.ts +1 -1
  206. package/src/react-menu3/contexts/MenuListContext.ts +2 -2
  207. package/src/react-menu3/contexts/MenuListItemContext.ts +2 -2
  208. package/src/react-menu3/contexts/RadioGroupContext.ts +2 -2
  209. package/src/react-menu3/contexts/SettingsContext.ts +2 -2
  210. package/src/react-menu3/hooks/index.ts +9 -9
  211. package/src/react-menu3/hooks/useBEM.ts +4 -4
  212. package/src/react-menu3/hooks/useCombinedRef.ts +2 -2
  213. package/src/react-menu3/hooks/useIsomorphicLayoutEffect.ts +4 -4
  214. package/src/react-menu3/hooks/useItemEffect.ts +3 -3
  215. package/src/react-menu3/hooks/useItemState.ts +5 -5
  216. package/src/react-menu3/hooks/useItems.ts +8 -8
  217. package/src/react-menu3/hooks/useMenuChange.ts +3 -3
  218. package/src/react-menu3/hooks/useMenuState.ts +5 -5
  219. package/src/react-menu3/hooks/useMenuStateAndFocus.ts +4 -4
  220. package/src/react-menu3/index.ts +11 -11
  221. package/src/react-menu3/positionUtils/getPositionHelpers.ts +2 -2
  222. package/src/react-menu3/positionUtils/index.ts +3 -3
  223. package/src/react-menu3/positionUtils/placeArrowHorizontal.ts +1 -1
  224. package/src/react-menu3/positionUtils/placeArrowVertical.ts +1 -1
  225. package/src/react-menu3/positionUtils/placeLeftorRight.ts +13 -13
  226. package/src/react-menu3/positionUtils/placeToporBottom.ts +15 -15
  227. package/src/react-menu3/positionUtils/positionContextMenu.ts +4 -4
  228. package/src/react-menu3/positionUtils/positionMenu.ts +14 -14
  229. package/src/react-menu3/style-utils/index.ts +24 -24
  230. package/src/react-menu3/types.ts +15 -15
  231. package/src/react-menu3/utils/constants.ts +33 -33
  232. package/src/react-menu3/utils/index.ts +3 -4
  233. package/src/react-menu3/utils/propTypes2.ts +10 -10
  234. package/src/react-menu3/utils/utils.ts +14 -14
  235. package/src/react-menu3/utils/withHovering.tsx +3 -3
  236. package/src/stories/components/ActionButton.stories.tsx +23 -24
  237. package/src/stories/grid/FormTest.tsx +15 -16
  238. package/src/stories/grid/GridDragRow.stories.tsx +33 -34
  239. package/src/stories/grid/GridFilterButtons.stories.tsx +32 -33
  240. package/src/stories/grid/GridNoRowsOverlay.stories.tsx +9 -10
  241. package/src/stories/grid/GridNonEditableRow.stories.tsx +40 -41
  242. package/src/stories/grid/GridPinnedRow.stories.tsx +25 -26
  243. package/src/stories/grid/GridPopoutContextMenu.stories.tsx +33 -32
  244. package/src/stories/grid/GridPopoutEditBoolean.stories.tsx +21 -22
  245. package/src/stories/grid/GridPopoutEditGeneric.stories.tsx +18 -19
  246. package/src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx +50 -49
  247. package/src/stories/grid/GridPopoverEditBearing.stories.tsx +25 -26
  248. package/src/stories/grid/GridPopoverEditDropDown.stories.tsx +93 -94
  249. package/src/stories/grid/GridPopoverEditMultiSelect.stories.tsx +62 -63
  250. package/src/stories/grid/GridPopoverEditMultiSelectGrid.stories.tsx +28 -28
  251. package/src/stories/grid/GridReadOnly.stories.tsx +66 -67
  252. package/src/stories/grid/GridViewList.stories.tsx +37 -38
  253. package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +37 -38
  254. package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx +25 -26
  255. package/src/stories/grid/gridFormInteraction/GridFormEditBearingInteraction.stories.tsx +25 -26
  256. package/src/stories/grid/gridFormInteraction/GridFormMultiSelectGridInteraction.stories.tsx +31 -31
  257. package/src/stories/grid/gridFormInteraction/GridFormMultiSelectInteraction.stories.tsx +47 -48
  258. package/src/stories/grid/gridFormInteraction/GridFormPopoverMenuInteraction.stories.tsx +44 -45
  259. package/src/stories/grid/gridFormInteraction/GridFormTextAreaInteraction.stories.tsx +19 -20
  260. package/src/stories/grid/gridFormInteraction/GridFormTextInputInteraction.stories.tsx +21 -22
  261. package/src/stories/grid/gridFormStatic/GridFormDropDown.stories.tsx +40 -41
  262. package/src/stories/grid/gridFormStatic/GridFormEditBearing.stories.tsx +14 -15
  263. package/src/stories/grid/gridFormStatic/GridFormEditBearingCorrection.stories.tsx +14 -15
  264. package/src/stories/grid/gridFormStatic/GridFormMessage.stories.tsx +10 -11
  265. package/src/stories/grid/gridFormStatic/GridFormMultiSelect.stories.tsx +20 -21
  266. package/src/stories/grid/gridFormStatic/GridFormPopoverMenu.stories.tsx +16 -17
  267. package/src/stories/grid/gridFormStatic/GridFormTextArea.stories.tsx +13 -14
  268. package/src/stories/grid/gridFormStatic/GridFormTextInput.stories.tsx +13 -14
  269. package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +68 -71
  270. package/src/stories/react-menu/ReactMenu.stories.tsx +26 -26
  271. package/src/styles/Grid.scss +9 -9
  272. package/src/styles/GridIcon.scss +6 -6
  273. package/src/styles/GridPopoverMenu.scss +3 -3
  274. package/src/styles/GridTheme.scss +1 -1
  275. package/src/styles/react-menu-customisations.scss +26 -41
  276. package/src/utils/__tests__/storybookTestUtil.ts +4 -0
  277. package/src/utils/__tests__/testQuick.ts +157 -0
  278. package/src/utils/__tests__/testUtil.ts +294 -0
  279. package/src/utils/__tests__/vitestUtil.ts +295 -0
  280. package/src/utils/bearing.test.ts +47 -45
  281. package/src/utils/bearing.ts +20 -20
  282. package/src/utils/deferredPromise.ts +1 -1
  283. package/src/utils/textMatcher.test.ts +10 -9
  284. package/src/utils/textMatcher.ts +8 -8
  285. package/src/utils/textValidator.test.ts +61 -62
  286. package/src/utils/textValidator.ts +11 -11
  287. package/src/utils/util.test.ts +21 -20
  288. package/src/utils/util.ts +7 -7
  289. package/dist/src/utils/storybookTestUtil.d.ts +0 -3
  290. package/dist/src/utils/testQuick.d.ts +0 -62
  291. package/dist/src/utils/testUtil.d.ts +0 -46
  292. package/dist/step-ag-grid.cjs.js.map +0 -1
@@ -1,16 +1,48 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { LuiMiniSpinner, LuiStatusSpinner, LuiIcon, LuiButton, LuiCheckboxInput, LuiButtonGroup } from '@linzjs/lui';
2
+ import { LuiMiniSpinner, LuiStatusSpinner, LuiIcon, LuiButtonGroup, LuiButton, LuiCheckboxInput } from '@linzjs/lui';
3
3
  import { RowHighlightPosition } from 'ag-grid-community';
4
4
  import { AgGridReact } from 'ag-grid-react';
5
- import { negate, isEmpty, findIndex, defer as defer$1, debounce as debounce$1, xorBy, last, difference, omit, sortBy, delay, partition, pick, groupBy, fromPairs, toPairs, isEqual, compact, filter, sumBy, pull, remove, castArray, flatten } from 'lodash-es';
6
- import React, { useRef, useEffect, useLayoutEffect, createContext, useContext, forwardRef, useCallback, useState, useMemo, memo, useReducer, cloneElement, useImperativeHandle, Fragment as Fragment$1, useId } from 'react';
5
+ import { negate, isEmpty, findIndex, defer as defer$1, debounce as debounce$1, xorBy, last, difference, omit, sortBy, delay, partition, pick, groupBy, fromPairs, toPairs, isEqual, compact, filter, sumBy, remove, pull, castArray, flatten } from 'lodash-es';
6
+ import React, { useRef, useLayoutEffect, useEffect, createContext, useContext, useState, useMemo, memo, forwardRef, useCallback, useReducer, cloneElement, useImperativeHandle, Fragment as Fragment$1, useId } from 'react';
7
7
  import { unstable_batchedUpdates, flushSync, createPortal } from 'react-dom';
8
8
 
9
+ /**
10
+ * AgGrid checkbox select does not pass clicks within cell but not on the checkbox to checkbox.
11
+ * This passes the event to the checkbox when you click anywhere in the cell.
12
+ */
13
+ const clickInputWhenContainingCellClicked = (params) => {
14
+ const { data, event, colDef } = params;
15
+ if (!data || !event)
16
+ return;
17
+ const element = event.target;
18
+ // Already handled
19
+ if (element.closest('.GridCell-readonly') ||
20
+ (['BUTTON', 'INPUT'].includes(element?.tagName) && element.closest('.ag-cell-inline-editing'))) {
21
+ return;
22
+ }
23
+ const row = element.closest('[row-id]');
24
+ if (!row)
25
+ return;
26
+ const colId = colDef.colId;
27
+ if (!colId)
28
+ return;
29
+ const clickInput = () => {
30
+ const cell = row.querySelector(`[col-id='${colId}']`);
31
+ if (!cell)
32
+ return;
33
+ const input = cell.querySelector('input, button');
34
+ if (!input)
35
+ return;
36
+ input?.dispatchEvent(event);
37
+ };
38
+ setTimeout(clickInput, 20);
39
+ };
40
+
9
41
  /**
10
42
  * If loading is true this returns a loading spinner, otherwise it returns its children.
11
43
  */
12
44
  const ComponentLoadingWrapper = (props) => {
13
- return props.loading ? (jsx(LuiMiniSpinner, { size: 22, divProps: { role: "status", ["aria-label"]: "Loading", style: { padding: 16 } } })) : (jsxs("div", { style: { pointerEvents: props.saving ? "none" : "inherit" }, className: props.className, children: [props.saving && jsx("div", { className: "ComponentLoadingWrapper-saveOverlay" }), props.children] }));
45
+ return props.loading ? (jsx(LuiMiniSpinner, { size: 22, divProps: { role: 'status', ['aria-label']: 'Loading', style: { padding: 16 } } })) : (jsxs("div", { style: { pointerEvents: props.saving ? 'none' : 'inherit' }, className: props.className, children: [props.saving && jsx("div", { className: 'ComponentLoadingWrapper-saveOverlay' }), props.children] }));
14
46
  };
15
47
 
16
48
  function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
@@ -59,153 +91,160 @@ const GridContext = createContext({
59
91
  gridReady: false,
60
92
  gridRenderState: () => null,
61
93
  getColDef: () => {
62
- console.error("no context provider for getColDef");
94
+ console.error('no context provider for getColDef');
63
95
  return undefined;
64
96
  },
65
97
  getColumns: () => {
66
- console.error("no context provider for getColumns");
98
+ console.error('no context provider for getColumns');
67
99
  return [];
68
100
  },
69
101
  getColumnIds: () => {
70
- console.error("no context provider for getColumnIds");
102
+ console.error('no context provider for getColumnIds');
71
103
  return [];
72
104
  },
73
105
  invisibleColumnIds: undefined,
74
106
  setInvisibleColumnIds: () => {
75
- console.error("no context provider for setInvisibleColumnIds");
107
+ console.error('no context provider for setInvisibleColumnIds');
76
108
  },
77
109
  prePopupOps: () => {
78
- console.error("no context provider for prePopupOps");
110
+ console.error('no context provider for prePopupOps');
79
111
  },
80
112
  postPopupOps: () => {
81
- console.error("no context provider for prePopupOps");
113
+ console.error('no context provider for prePopupOps');
82
114
  },
83
115
  externallySelectedItemsAreInSync: false,
84
116
  setApis: () => {
85
- console.error("no context provider for setApis");
117
+ console.error('no context provider for setApis');
86
118
  },
87
119
  setQuickFilter: () => {
88
- console.error("no context provider for setQuickFilter");
120
+ console.error('no context provider for setQuickFilter');
89
121
  },
90
122
  selectRowsById: () => {
91
- console.error("no context provider for selectRows");
123
+ console.error('no context provider for selectRows');
92
124
  },
93
125
  getSelectedRows: () => {
94
- console.error("no context provider for getSelectedRows");
126
+ console.error('no context provider for getSelectedRows');
95
127
  return [];
96
128
  },
97
129
  getFilteredSelectedRows: () => {
98
- console.error("no context provider for getFilteredSelectedRows");
130
+ console.error('no context provider for getFilteredSelectedRows');
99
131
  return [];
100
132
  },
101
133
  getSelectedRowIds: () => {
102
- console.error("no context provider for getSelectedRowIds");
134
+ console.error('no context provider for getSelectedRowIds');
103
135
  return [];
104
136
  },
105
137
  getFilteredSelectedRowIds: () => {
106
- console.error("no context provider for getFilteredSelectedRowIds");
138
+ console.error('no context provider for getFilteredSelectedRowIds');
107
139
  return [];
108
140
  },
141
+ // eslint-disable-next-line @typescript-eslint/require-await
109
142
  selectRowsDiff: async () => {
110
- console.error("no context provider for selectRowsDiff");
143
+ console.error('no context provider for selectRowsDiff');
111
144
  },
112
145
  selectRowsByIdWithFlash: () => {
113
- console.error("no context provider for selectRowsWithFlash");
146
+ console.error('no context provider for selectRowsWithFlash');
114
147
  },
148
+ // eslint-disable-next-line @typescript-eslint/require-await
115
149
  selectRowsWithFlashDiff: async () => {
116
- console.error("no context provider for selectRowsWithFlashDiff");
150
+ console.error('no context provider for selectRowsWithFlashDiff');
117
151
  },
118
152
  flashRows: () => {
119
- console.error("no context provider for flashRows");
153
+ console.error('no context provider for flashRows');
120
154
  },
155
+ // eslint-disable-next-line @typescript-eslint/require-await
121
156
  flashRowsDiff: async () => {
122
- console.error("no context provider for flashRows");
157
+ console.error('no context provider for flashRows');
123
158
  },
159
+ // eslint-disable-next-line @typescript-eslint/require-await,@typescript-eslint/no-misused-promises
124
160
  focusByRowById: async () => {
125
- console.error("no context provider for focusByRowById");
161
+ console.error('no context provider for focusByRowById');
126
162
  },
127
163
  ensureRowVisible: () => {
128
- console.error("no context provider for ensureRowVisible");
164
+ console.error('no context provider for ensureRowVisible');
129
165
  return true;
130
166
  },
131
167
  ensureSelectedRowIsVisible: () => {
132
- console.error("no context provider for ensureSelectedRowIsVisible");
168
+ console.error('no context provider for ensureSelectedRowIsVisible');
133
169
  },
134
170
  getFirstRowId: () => {
135
- console.error("no context provider for getFirstRowId");
171
+ console.error('no context provider for getFirstRowId');
136
172
  return -1;
137
173
  },
138
174
  autoSizeColumns: () => {
139
- console.error("no context provider for autoSizeColumns");
175
+ console.error('no context provider for autoSizeColumns');
140
176
  return null;
141
177
  },
142
178
  sizeColumnsToFit: () => {
143
- console.error("no context provider for autoSizeAllColumns");
179
+ console.error('no context provider for autoSizeAllColumns');
144
180
  return null;
145
181
  },
146
182
  editingCells: () => {
147
- console.error("no context provider for editingCells");
183
+ console.error('no context provider for editingCells');
148
184
  return false;
149
185
  },
150
186
  cancelEdit: () => {
151
- console.error("no context provider for cancelEdit");
187
+ console.error('no context provider for cancelEdit');
152
188
  },
153
189
  startCellEditing: () => {
154
- console.error("no context provider for startCellEditing");
190
+ console.error('no context provider for startCellEditing');
155
191
  },
156
192
  stopEditing: () => {
157
- console.error("no context provider for stopEditing");
193
+ console.error('no context provider for stopEditing');
158
194
  },
195
+ // eslint-disable-next-line @typescript-eslint/require-await
159
196
  updatingCells: async () => {
160
- console.error("no context provider for modifyUpdating");
197
+ console.error('no context provider for modifyUpdating');
161
198
  return false;
162
199
  },
163
200
  redrawRows: () => {
164
- console.error("no context provider for redrawRows");
201
+ console.error('no context provider for redrawRows');
165
202
  },
166
203
  setExternallySelectedItemsAreInSync: () => {
167
- console.error("no context provider for setExternallySelectedItemsAreInSync");
204
+ console.error('no context provider for setExternallySelectedItemsAreInSync');
168
205
  },
206
+ // eslint-disable-next-line @typescript-eslint/require-await
169
207
  waitForExternallySelectedItemsToBeInSync: async () => {
170
- console.error("no context provider for waitForExternallySelectedItemsToBeInSync");
208
+ console.error('no context provider for waitForExternallySelectedItemsToBeInSync');
171
209
  },
172
210
  addExternalFilter: () => {
173
- console.error("no context provider for addExternalFilter");
211
+ console.error('no context provider for addExternalFilter');
174
212
  },
175
213
  removeExternalFilter: () => {
176
- console.error("no context provider for removeExternalFilter");
214
+ console.error('no context provider for removeExternalFilter');
177
215
  },
178
216
  isExternalFilterPresent: () => {
179
- console.error("no context provider for isExternalFilterPresent");
217
+ console.error('no context provider for isExternalFilterPresent');
180
218
  return false;
181
219
  },
182
220
  doesExternalFilterPass: () => {
183
- console.error("no context provider for doesExternalFilterPass");
221
+ console.error('no context provider for doesExternalFilterPass');
184
222
  return true;
185
223
  },
186
224
  downloadCsv: () => {
187
- console.error("no context provider for downloadCsv");
225
+ console.error('no context provider for downloadCsv');
188
226
  },
189
227
  setOnCellEditingComplete: () => {
190
- console.error("no context provider for setOnCellEditingComplete");
228
+ console.error('no context provider for setOnCellEditingComplete');
191
229
  },
192
230
  showNoRowsOverlay: () => {
193
- console.error("no context provider for showLoadingOverlay");
231
+ console.error('no context provider for showLoadingOverlay');
194
232
  },
195
233
  });
196
234
  const useGridContext = () => useContext(GridContext);
197
235
 
198
236
  const GridUpdatingContext = createContext({
199
237
  checkUpdating: () => {
200
- console.error("Missing GridUpdatingContext");
238
+ console.error('Missing GridUpdatingContext');
201
239
  return false;
202
240
  },
203
241
  updatingCols: () => {
204
- console.error("Missing GridUpdatingContext");
242
+ console.error('Missing GridUpdatingContext');
205
243
  return [];
206
244
  },
245
+ // eslint-disable-next-line @typescript-eslint/require-await
207
246
  modifyUpdating: async () => {
208
- console.error("Missing GridUpdatingContext");
247
+ console.error('Missing GridUpdatingContext');
209
248
  },
210
249
  updatedDep: 0,
211
250
  });
@@ -247,196 +286,19 @@ const hasParentClass = function (className, child) {
247
286
  return false;
248
287
  };
249
288
  const stringByteLengthIsInvalid = (str, maxBytes) => new TextEncoder().encode(str).length > maxBytes;
250
- const fnOrVar = (fn, param) => (typeof fn === "function" ? fn(param) : fn);
289
+ const fnOrVar = (fn, param) => (typeof fn === 'function' ? fn(param) : fn);
251
290
  const sanitiseFileName = (filename) => {
252
291
  const valid = filename
253
292
  .trim()
254
- .replaceAll(/(\/|\\)+/g, "-")
255
- .replaceAll(/\s+/g, "_")
256
- .replaceAll(/[^\w\-āēīōūĀĒĪŌŪ.]/g, "");
257
- const parts = valid.split(".");
293
+ .replaceAll(/(\/|\\)+/g, '-')
294
+ .replaceAll(/\s+/g, '_')
295
+ .replaceAll(/[^\w\-āēīōūĀĒĪŌŪ.]/g, '');
296
+ const parts = valid.split('.');
258
297
  const fileExt = parts.length > 1 ? parts.pop() : undefined;
259
298
  // Arbitrary max filename length of 64 chars + extension
260
299
  if (!fileExt)
261
300
  return valid.slice().slice(0, 64);
262
- return valid.slice(0, -fileExt.length - 1).slice(0, 64) + "." + fileExt;
263
- };
264
-
265
- const GridLoadingOverlayComponentFr = (props, externalRef) => (jsx("div", { ref: externalRef, style: {
266
- left: 0,
267
- top: 0,
268
- bottom: 0,
269
- right: 0,
270
- position: "absolute",
271
- backgroundColor: "rgba(255,255,255,0.5)",
272
- }, children: jsx("div", { style: { height: "100%", position: "relative" }, children: jsx("div", { style: { position: "absolute", left: 0, top: props.headerRowHeight, right: 0, bottom: 0 }, children: jsx(LuiStatusSpinner, {}) }) }) }));
273
- const GridLoadingOverlayComponent = forwardRef(GridLoadingOverlayComponentFr);
274
- const GridNoRowsOverlayFr = (props, externalRef) => {
275
- if (props.loading) {
276
- return jsx(GridLoadingOverlayComponent, { ref: externalRef, headerRowHeight: props.headerRowHeight });
277
- }
278
- if (props.rowCount === 0) {
279
- return jsx("div", { ref: externalRef, children: props.noRowsOverlayText ?? "There are currently no rows" });
280
- }
281
- if (props.filteredRowCount === 0) {
282
- return jsx("div", { ref: externalRef, children: props.noRowsMatchingOverlayText ?? "All rows have been filtered" });
283
- }
284
- return jsx("div", { ref: externalRef });
285
- };
286
- const GridNoRowsOverlay = forwardRef(GridNoRowsOverlayFr);
287
-
288
- /**
289
- * Retains last sort order from via <AgGrid postRowSort>.
290
- * Then applies this sort until next sort column change.
291
- * Handles stale sort, when you edit a row but don't want to re-sort.
292
- */
293
- const usePostSortRowsHook = ({ setStaleGrid }) => {
294
- const { redrawRows } = useContext(GridContext);
295
- // On first run we need to init the first backed up sort order
296
- const initialised = useRef(false);
297
- // Used to detect sort order has changed since last run
298
- const lastSortOrderHash = useRef("");
299
- // Used to detect if sort order was the same, has the direction changed
300
- const previousRowSortIndexRef = useRef({});
301
- // stale sort is when there's a sort and user edits a row
302
- // this applies a class to the div wrapping the grid which in turn adds a * beside the sort arrow
303
- const sortWasStale = useRef(false);
304
- // Previous col sort is stored and reapplied if the sort direction changes on the same column and the sort was stale
305
- // As a sort on a stale row should just resort, not change sort direction
306
- const previousColSort = useRef([]);
307
- const previousQuickFilter = useRef("");
308
- return useCallback(({ api, nodes }) => {
309
- // Grid is destroyed
310
- if (!api)
311
- return;
312
- const previousRowSortIndex = previousRowSortIndexRef.current;
313
- const hashNode = (node) => {
314
- return node ? JSON.stringify(node.data) : "";
315
- };
316
- const copyCurrentSortSettings = () => api.getColumnState().map((row) => ({ colId: row.colId, sort: row.sort, sortIndex: row.sortIndex }));
317
- const backupSortOrder = () => {
318
- for (const x in previousRowSortIndex)
319
- delete previousRowSortIndex[x];
320
- nodes.forEach((node, index) => (previousRowSortIndex[`${node.data.id}`] = { index, hash: hashNode(node) }));
321
- };
322
- // Check if column is the first sorted column. Note: column is preconfigured to sort its sortIndex is null not 1
323
- const isFirstSortColumn = (row) => row.sort && [0, null].includes(row.sortIndex ?? null);
324
- const isSameColumnAndDifferentSort = (col1, col2) => col1 && col2 && col1.colId === col2.colId && col1.sort != col2.sort;
325
- const restorePreviousSortColumnState = () => api.applyColumnState({ state: previousColSort.current });
326
- const sortNodesByPreviousSort = () => {
327
- nodes.sort((a, b) => (previousRowSortIndex[`${a.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER) -
328
- (previousRowSortIndex[`${b.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER));
329
- };
330
- // On first load copy the current sort
331
- if (!initialised.current) {
332
- initialised.current = true;
333
- previousColSort.current = copyCurrentSortSettings();
334
- }
335
- const newSortOrder = JSON.stringify(copyCurrentSortSettings());
336
- let sortOrderChanged = newSortOrder != lastSortOrderHash.current;
337
- const quickFilter = api.getQuickFilter();
338
- if (previousQuickFilter.current != quickFilter) {
339
- previousQuickFilter.current = quickFilter ?? "";
340
- sortOrderChanged = true;
341
- }
342
- if (isEmpty(previousRowSortIndex)) {
343
- backupSortOrder();
344
- }
345
- if (sortOrderChanged) {
346
- const thisFirstCol = copyCurrentSortSettings().find(isFirstSortColumn);
347
- const previousFirstCol = previousColSort.current.find(isFirstSortColumn);
348
- // Change to sort can be: (in the context of stale sort do...)
349
- // - no sort to sorted (do nothing)
350
- // - asc to desc (resort as asc, and remove stale sort)
351
- // - desc to no sort (resort as desc, and remove stale sort)
352
- const wasSortChangedOnSameColumn = previousFirstCol && (!thisFirstCol || isSameColumnAndDifferentSort(previousFirstCol, thisFirstCol));
353
- // if sort was stale, and we're here, someone has clicked a stale sort order (^*) in the column header
354
- if (sortWasStale.current && wasSortChangedOnSameColumn) {
355
- // Sort was an existing priority 1 column
356
- // We want to re-sort with the old sort direction and clear stale sort
357
- sortWasStale.current = false;
358
- setStaleGrid(false);
359
- // trigger a recapture of sort order
360
- lastSortOrderHash.current = "";
361
- restorePreviousSortColumnState();
362
- }
363
- else {
364
- // Sort was on a different column so clear sort and sort like normal
365
- if (sortWasStale.current) {
366
- sortWasStale.current = false;
367
- setStaleGrid(false);
368
- }
369
- // Columns were sorted so retain the sort
370
- backupSortOrder();
371
- lastSortOrderHash.current = newSortOrder;
372
- }
373
- }
374
- else {
375
- let firstChangedNodeIndex = -1;
376
- let lastNewNode = undefined;
377
- let changedRowCount = 0;
378
- let newRowCount = 0;
379
- let index = 0;
380
- for (const node of nodes) {
381
- const psr = previousRowSortIndex[`${node.data.id}`];
382
- if (psr) {
383
- if (psr.hash != hashNode(node)) {
384
- if (firstChangedNodeIndex === -1)
385
- firstChangedNodeIndex = index;
386
- changedRowCount++;
387
- }
388
- }
389
- else {
390
- lastNewNode = node;
391
- newRowCount++;
392
- }
393
- index++;
394
- }
395
- let wasStale = false;
396
- if (changedRowCount === 0 && newRowCount === 1) {
397
- // insert new row at end
398
- const newIndex = index - 1;
399
- previousRowSortIndex[`${lastNewNode?.data.id}`] = { index: newIndex, hash: hashNode(lastNewNode) };
400
- wasStale = true;
401
- }
402
- else if (changedRowCount === 2 && newRowCount === 0) {
403
- // This must be a swap rows (sometimes it's not, needs further attention)
404
- backupSortOrder();
405
- wasStale = false;
406
- }
407
- else if (changedRowCount > 1 && newRowCount === 1) {
408
- // This must be a insert so, insert new row near the row that changed
409
- previousRowSortIndex[`${lastNewNode?.data.id}`] = {
410
- index: firstChangedNodeIndex + 0.5,
411
- hash: hashNode(lastNewNode),
412
- };
413
- wasStale = true;
414
- // For some reason AgGrid mis-positions the inserted row.
415
- lastNewNode && redrawRows();
416
- }
417
- else if (changedRowCount == 1 && newRowCount === 0) {
418
- // User edited one row so, do nothing, retain sort
419
- wasStale = true;
420
- }
421
- else if (changedRowCount !== 0 || newRowCount != 0) {
422
- // too many rows changed, resort
423
- backupSortOrder();
424
- }
425
- if (wasStale) {
426
- // Check if the sort order the aggrid passed matches our stale sort order
427
- const stillStale = Object.keys(previousRowSortIndex).length != nodes.length ||
428
- nodes.some((node, index) => previousRowSortIndex[`${node.data.id}`]?.index !== index);
429
- // If we haven't already processed a stale sort then...
430
- if (stillStale && !sortWasStale.current) {
431
- // backup sort state, so we can restore it when sort is clicked on a stale column
432
- previousColSort.current = copyCurrentSortSettings();
433
- sortWasStale.current = true;
434
- setStaleGrid(true);
435
- }
436
- }
437
- sortNodesByPreviousSort();
438
- }
439
- }, [redrawRows, setStaleGrid]);
301
+ return valid.slice(0, -fileExt.length - 1).slice(0, 64) + '.' + fileExt;
440
302
  };
441
303
 
442
304
  /**
@@ -452,9 +314,9 @@ const GridHeaderSelect = ({ api }) => {
452
314
  const clickHandler = () => {
453
315
  setUpdateCounter(updateCounter + 1);
454
316
  };
455
- api.addEventListener("selectionChanged", clickHandler);
317
+ api.addEventListener('selectionChanged', clickHandler);
456
318
  return () => {
457
- !api.isDestroyed() && api.removeEventListener("selectionChanged", clickHandler);
319
+ !api.isDestroyed() && api.removeEventListener('selectionChanged', clickHandler);
458
320
  };
459
321
  }, [api, updateCounter]);
460
322
  const handleMultiSelect = () => {
@@ -468,11 +330,23 @@ const GridHeaderSelect = ({ api }) => {
468
330
  const totalNodeCount = api.getDisplayedRowCount();
469
331
  const partialSelect = selectedNodeCount != 0 && selectedNodeCount != totalNodeCount;
470
332
  const allSelected = selectedNodeCount != 0 && selectedNodeCount == totalNodeCount;
471
- return (jsx("div", { className: clsx("ag-wrapper ag-input-wrapper ag-checkbox-input-wrapper", partialSelect && "ag-indeterminate", allSelected && "ag-checked"), onClick: handleMultiSelect, children: jsx("input", { type: "checkbox", className: "ag-checkbox-input-wrapper", onChange: () => {
333
+ return (jsx("div", { className: clsx('ag-wrapper ag-input-wrapper ag-checkbox-input-wrapper', partialSelect && 'ag-indeterminate', allSelected && 'ag-checked'), onClick: handleMultiSelect, children: jsx("input", { type: "checkbox", className: 'ag-checkbox-input-wrapper', onChange: () => {
472
334
  /* do nothing */
473
335
  } }) }));
474
336
  };
475
337
 
338
+ const EventHandlersContext = createContext({
339
+ handleClick: () => { },
340
+ });
341
+
342
+ const ItemSettingsContext = createContext({
343
+ submenuOpenDelay: 0,
344
+ submenuCloseDelay: 0,
345
+ });
346
+
347
+ // FIXME hacking a default context in here is probably bad, but the context is mess
348
+ const SettingsContext = createContext({});
349
+
476
350
  // Generate className following BEM methodology: http://getbem.com/naming/
477
351
  // Modifier value can be one of the following types: boolean, string, undefined
478
352
  const useBEM = ({ block, element, modifiers, className }) => useMemo(() => {
@@ -484,8 +358,8 @@ const useBEM = ({ block, element, modifiers, className }) => useMemo(() => {
484
358
  if (value)
485
359
  classString += ` ${blockElement}--${value === true ? name : `${name}-${value}`}`;
486
360
  });
487
- let expandedClassName = typeof className === "function" ? className(modifiers) : className;
488
- if (typeof expandedClassName === "string") {
361
+ let expandedClassName = typeof className === 'function' ? className(modifiers) : className;
362
+ if (typeof expandedClassName === 'string') {
489
363
  expandedClassName = expandedClassName.trim();
490
364
  if (expandedClassName)
491
365
  classString += ` ${expandedClassName}`;
@@ -496,7 +370,7 @@ const useBEM = ({ block, element, modifiers, className }) => useMemo(() => {
496
370
  // Adapted from material-ui
497
371
  // https://github.com/mui-org/material-ui/blob/f996027d00e7e4bff3fc040786c1706f9c6c3f82/packages/material-ui-utils/src/useForkRef.ts
498
372
  const setRef = (ref, instance) => {
499
- if (typeof ref === "function") {
373
+ if (typeof ref === 'function') {
500
374
  ref(instance);
501
375
  }
502
376
  else if (ref) {
@@ -516,33 +390,50 @@ const useCombinedRef = (refA, refB) => {
516
390
  // https://github.com/reduxjs/react-redux/blob/b48d087d76f666e1c6c5a9713bbec112a1631841/src/utils/useIsomorphicLayoutEffect.js#L12
517
391
  // https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
518
392
  // https://github.com/facebook/react/issues/14927#issuecomment-549457471
519
- const useIsomorphicLayoutEffect = typeof window !== "undefined" &&
520
- typeof window.document !== "undefined" &&
521
- typeof window.document.createElement !== "undefined"
393
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' &&
394
+ typeof window.document !== 'undefined' &&
395
+ typeof window.document.createElement !== 'undefined'
522
396
  ? useLayoutEffect
523
397
  : useEffect;
524
398
 
525
- const menuContainerClass = "szh-menu-container";
526
- const menuClass = "szh-menu";
527
- const menuButtonClass = "szh-menu-button";
528
- const menuArrowClass = "arrow";
529
- const menuItemClass = "item";
530
- const menuDividerClass = "divider";
531
- const menuHeaderClass = "header";
532
- const menuGroupClass = "group";
533
- const subMenuClass = "submenu";
534
- const radioGroupClass = "radio-group";
399
+ const useItemEffect = (isDisabled, menuItemRef, updateItems) => {
400
+ useIsomorphicLayoutEffect(() => {
401
+ if (!menuItemRef)
402
+ return;
403
+ if (process.env.NODE_ENV !== 'production' && !updateItems) {
404
+ throw new Error(`[React-Menu] This menu item or submenu should be rendered under a menu: ${menuItemRef.current.outerHTML}`);
405
+ }
406
+ if (isDisabled)
407
+ return;
408
+ const item = menuItemRef.current;
409
+ updateItems(item, true);
410
+ return () => {
411
+ updateItems(item);
412
+ };
413
+ }, [isDisabled, menuItemRef, updateItems]);
414
+ };
415
+
416
+ const menuContainerClass = 'szh-menu-container';
417
+ const menuClass = 'szh-menu';
418
+ const menuButtonClass = 'szh-menu-button';
419
+ const menuArrowClass = 'arrow';
420
+ const menuItemClass = 'item';
421
+ const menuDividerClass = 'divider';
422
+ const menuHeaderClass = 'header';
423
+ const menuGroupClass = 'group';
424
+ const subMenuClass = 'submenu';
425
+ const radioGroupClass = 'radio-group';
535
426
  const Keys = Object.freeze({
536
- ENTER: "Enter",
537
- TAB: "Tab",
538
- ESC: "Escape",
539
- SPACE: " ",
540
- HOME: "Home",
541
- END: "End",
542
- LEFT: "ArrowLeft",
543
- RIGHT: "ArrowRight",
544
- UP: "ArrowUp",
545
- DOWN: "ArrowDown",
427
+ ENTER: 'Enter',
428
+ TAB: 'Tab',
429
+ ESC: 'Escape',
430
+ SPACE: ' ',
431
+ HOME: 'Home',
432
+ END: 'End',
433
+ LEFT: 'ArrowLeft',
434
+ RIGHT: 'ArrowRight',
435
+ UP: 'ArrowUp',
436
+ DOWN: 'ArrowDown',
546
437
  });
547
438
  const HoverActionTypes = Object.freeze({
548
439
  RESET: 0,
@@ -555,39 +446,39 @@ const HoverActionTypes = Object.freeze({
555
446
  SET_INDEX: 7,
556
447
  });
557
448
  const CloseReason = Object.freeze({
558
- CLICK: "click",
559
- CANCEL: "cancel",
560
- BLUR: "blur",
561
- SCROLL: "scroll",
562
- TAB_FORWARD: "tab_forward",
563
- TAB_BACKWARD: "tab_backward",
449
+ CLICK: 'click',
450
+ CANCEL: 'cancel',
451
+ BLUR: 'blur',
452
+ SCROLL: 'scroll',
453
+ TAB_FORWARD: 'tab_forward',
454
+ TAB_BACKWARD: 'tab_backward',
564
455
  });
565
456
  const FocusPositions = Object.freeze({
566
- FIRST: "first",
567
- LAST: "last",
457
+ FIRST: 'first',
458
+ LAST: 'last',
568
459
  });
569
460
  const MenuStateMap = Object.freeze({
570
- entering: "opening",
571
- entered: "open",
572
- exiting: "closing",
573
- exited: "closed",
461
+ entering: 'opening',
462
+ entered: 'open',
463
+ exiting: 'closing',
464
+ exited: 'closed',
574
465
  });
575
466
 
576
- const isMenuOpen = (state) => !!state && state[0] === "o";
467
+ const isMenuOpen = (state) => !!state && state[0] === 'o';
577
468
  const batchedUpdates = unstable_batchedUpdates || ((callback) => callback());
578
469
  const floatEqual = (a, b, diff = 0.0001) => Math.abs(a - b) < diff;
579
470
  const getTransition = (transition, name) => transition === true || !!(transition && transition[name]);
580
471
  function safeCall(fn, arg) {
581
- return typeof fn === "function" ? fn(arg) : fn;
472
+ return typeof fn === 'function' ? fn(arg) : fn;
582
473
  }
583
- const internalKey = "_szhsinMenu";
474
+ const internalKey = '_szhsinMenu';
584
475
  const getName = (component) => component[internalKey];
585
476
  const mergeProps = (target, source) => {
586
477
  source &&
587
478
  Object.keys(source).forEach((key) => {
588
479
  const targetProp = target[key];
589
480
  const sourceProp = source[key];
590
- if (typeof sourceProp === "function" && targetProp) {
481
+ if (typeof sourceProp === 'function' && targetProp) {
591
482
  target[key] = (...arg) => {
592
483
  sourceProp(...arg);
593
484
  targetProp(...arg);
@@ -629,24 +520,24 @@ const getScrollAncestor = (node) => {
629
520
  };
630
521
  function commonProps(isDisabled, isHovering) {
631
522
  return {
632
- "aria-disabled": isDisabled || undefined,
523
+ 'aria-disabled': isDisabled || undefined,
633
524
  tabIndex: isHovering ? 0 : -1,
634
525
  };
635
526
  }
636
527
  const indexOfNode = (nodeList, node) => findIndex(nodeList, node);
637
528
  const focusFirstInput = (container) => {
638
529
  // We can't use instanceof Element in portals, so I use querySelectorAll as a proxy here
639
- if (!container || !("querySelectorAll" in container))
530
+ if (!container || !('querySelectorAll' in container))
640
531
  return false;
641
532
  const inputs = container.querySelectorAll("input[type='text'],input:not([type]),textarea");
642
533
  const input = inputs[0];
643
534
  // Using focus as proxy for HTMLElement
644
- if (!input || !("focus" in input))
535
+ if (!input || !('focus' in input))
645
536
  return false;
646
537
  input.focus();
647
538
  // Text areas should start at end
648
539
  // this is a proxy for instanceof HTMLTextAreaElement
649
- if (["textarea", "text"].includes(input.type)) {
540
+ if (['textarea', 'text'].includes(input.type)) {
650
541
  input.setSelectionRange(0, input.value.length);
651
542
  }
652
543
  return true;
@@ -698,7 +589,7 @@ const useItems = (menuRef, focusRef) => {
698
589
  const sortItems = () => {
699
590
  if (mutableState.sorted)
700
591
  return;
701
- const orderedNodes = menuRef.current.querySelectorAll(".szh-menu__item");
592
+ const orderedNodes = menuRef.current.querySelectorAll('.szh-menu__item');
702
593
  items.sort((a, b) => indexOfNode(orderedNodes, a) - indexOfNode(orderedNodes, b));
703
594
  mutableState.sorted = true;
704
595
  };
@@ -725,12 +616,12 @@ const useItems = (menuRef, focusRef) => {
725
616
  newItem = items[index];
726
617
  break;
727
618
  case HoverActionTypes.SET_INDEX:
728
- if (typeof nextIndex !== "number")
619
+ if (typeof nextIndex !== 'number')
729
620
  break;
730
621
  sortItems();
731
622
  index = nextIndex;
732
623
  newItem = items[index];
733
- defer$1(() => newItem.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" }));
624
+ defer$1(() => newItem.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }));
734
625
  break;
735
626
  case HoverActionTypes.INCREASE:
736
627
  sortItems();
@@ -756,7 +647,7 @@ const useItems = (menuRef, focusRef) => {
756
647
  break;
757
648
  }
758
649
  default:
759
- if (process.env.NODE_ENV !== "production")
650
+ if (process.env.NODE_ENV !== 'production')
760
651
  throw new Error(`[React-Menu] Unknown hover action type: ${actionType}`);
761
652
  }
762
653
  if (!newItem && !newItemFn)
@@ -767,28 +658,6 @@ const useItems = (menuRef, focusRef) => {
767
658
  return { hoverItem, dispatch, updateItems };
768
659
  };
769
660
 
770
- const useItemEffect = (isDisabled, menuItemRef, updateItems) => {
771
- useIsomorphicLayoutEffect(() => {
772
- if (!menuItemRef)
773
- return;
774
- if (process.env.NODE_ENV !== "production" && !updateItems) {
775
- throw new Error(`[React-Menu] This menu item or submenu should be rendered under a menu: ${menuItemRef.current.outerHTML}`);
776
- }
777
- if (isDisabled)
778
- return;
779
- const item = menuItemRef.current;
780
- updateItems(item, true);
781
- return () => {
782
- updateItems(item);
783
- };
784
- }, [isDisabled, menuItemRef, updateItems]);
785
- };
786
-
787
- const ItemSettingsContext = createContext({
788
- submenuOpenDelay: 0,
789
- submenuCloseDelay: 0,
790
- });
791
-
792
661
  const MenuListItemContext = createContext({
793
662
  dispatch: () => { },
794
663
  updateItems: () => { },
@@ -956,8 +825,8 @@ const useMenuState = (props) => {
956
825
  mountOnEnter: !initialMounted,
957
826
  unmountOnExit: unmountOnClose,
958
827
  timeout: transitionTimeout ?? 500,
959
- enter: getTransition(transition, "open"),
960
- exit: getTransition(transition, "close"),
828
+ enter: getTransition(transition, 'open'),
829
+ exit: getTransition(transition, 'close'),
961
830
  });
962
831
  return [{ state: MenuStateMap[state.status], endTransition }, toggleMenu];
963
832
  };
@@ -972,18 +841,6 @@ const useMenuStateAndFocus = (options) => {
972
841
  return [{ menuItemFocus, ...menuProps }, toggleMenu, openMenu];
973
842
  };
974
843
 
975
- const MenuButton = forwardRef(function MenuButton({ className, isOpen, disabled, children, ...restProps }, ref) {
976
- const modifiers = useMemo(() => ({ open: isOpen }), [isOpen]);
977
- return (jsx("button", { "aria-haspopup": true, "aria-expanded": isOpen, "aria-disabled": disabled || undefined, type: "button", disabled: disabled, ...restProps, ref: ref, className: useBEM({ block: menuButtonClass, modifiers, className }), children: children }));
978
- });
979
-
980
- const EventHandlersContext = createContext({
981
- handleClick: () => { },
982
- });
983
-
984
- // FIXME hacking a default context in here is probably bad, but the context is mess
985
- const SettingsContext = createContext({});
986
-
987
844
  const MenuListContext = createContext({});
988
845
 
989
846
  const getPositionHelpers = (containerRef, menuRef, menuScroll, boundingBoxPadding) => {
@@ -1078,14 +935,14 @@ const positionContextMenu = ({ positionHelpers, anchorPoint, }) => {
1078
935
  x = confineHorizontally(x);
1079
936
  }
1080
937
  // Similar logic to the left and right side above.
1081
- let computedDirection = "bottom";
938
+ let computedDirection = 'bottom';
1082
939
  const bottomOverflow = getBottomOverflow(y);
1083
940
  if (bottomOverflow > 0) {
1084
941
  const adjustedY = y - menuRect.height;
1085
942
  const topOverflow = getTopOverflow(adjustedY);
1086
943
  if (topOverflow >= 0 || -topOverflow < bottomOverflow) {
1087
944
  y = adjustedY;
1088
- computedDirection = "top";
945
+ computedDirection = 'top';
1089
946
  }
1090
947
  y = confineVertically(y);
1091
948
  }
@@ -1104,18 +961,18 @@ const placeLeftorRight = (props) => {
1104
961
  const { anchorRect, containerRect, menuRect, placeLeftorRightY, placeLeftX, placeRightX, getLeftOverflow, getRightOverflow, confineHorizontally, confineVertically, arrowRef, arrow, direction, position, } = props;
1105
962
  let computedDirection = direction;
1106
963
  let y = placeLeftorRightY;
1107
- if (position !== "initial") {
964
+ if (position !== 'initial') {
1108
965
  y = confineVertically(y);
1109
- if (position === "anchor") {
966
+ if (position === 'anchor') {
1110
967
  // restrict menu to the edge of anchor element
1111
968
  y = Math.min(y, anchorRect.bottom - containerRect.top);
1112
969
  y = Math.max(y, anchorRect.top - containerRect.top - menuRect.height);
1113
970
  }
1114
971
  }
1115
972
  let x, leftOverflow, rightOverflow;
1116
- if (computedDirection === "left") {
973
+ if (computedDirection === 'left') {
1117
974
  x = placeLeftX;
1118
- if (position !== "initial") {
975
+ if (position !== 'initial') {
1119
976
  // if menu overflows to the left,
1120
977
  // try to reposition it to the right of the anchor.
1121
978
  leftOverflow = getLeftOverflow(x);
@@ -1125,7 +982,7 @@ const placeLeftorRight = (props) => {
1125
982
  rightOverflow = getRightOverflow(placeRightX);
1126
983
  if (rightOverflow <= 0 || -leftOverflow > rightOverflow) {
1127
984
  x = placeRightX;
1128
- computedDirection = "right";
985
+ computedDirection = 'right';
1129
986
  }
1130
987
  }
1131
988
  }
@@ -1133,18 +990,18 @@ const placeLeftorRight = (props) => {
1133
990
  else {
1134
991
  // Opposite logic to the 'left' direction above
1135
992
  x = placeRightX;
1136
- if (position !== "initial") {
993
+ if (position !== 'initial') {
1137
994
  rightOverflow = getRightOverflow(x);
1138
995
  if (rightOverflow > 0) {
1139
996
  leftOverflow = getLeftOverflow(placeLeftX);
1140
997
  if (leftOverflow >= 0 || -leftOverflow < rightOverflow) {
1141
998
  x = placeLeftX;
1142
- computedDirection = "left";
999
+ computedDirection = 'left';
1143
1000
  }
1144
1001
  }
1145
1002
  }
1146
1003
  }
1147
- if (position === "auto")
1004
+ if (position === 'auto')
1148
1005
  x = confineHorizontally(x);
1149
1006
  const arrowY = arrow
1150
1007
  ? placeArrowVertical({
@@ -1169,20 +1026,20 @@ const placeArrowHorizontal = (p) => {
1169
1026
  const placeToporBottom = (props) => {
1170
1027
  const { anchorRect, containerRect, menuRect, placeToporBottomX, placeTopY, placeBottomY, getTopOverflow, getBottomOverflow, confineHorizontally, confineVertically, arrowRef, arrow, direction, position, } = props;
1171
1028
  // make sure invalid direction is treated as 'bottom'
1172
- let computedDirection = direction === "top" ? "top" : "bottom";
1029
+ let computedDirection = direction === 'top' ? 'top' : 'bottom';
1173
1030
  let x = placeToporBottomX;
1174
- if (position !== "initial") {
1031
+ if (position !== 'initial') {
1175
1032
  x = confineHorizontally(x);
1176
- if (position === "anchor") {
1033
+ if (position === 'anchor') {
1177
1034
  // restrict menu to the edge of anchor element
1178
1035
  x = Math.min(x, anchorRect.right - containerRect.left);
1179
1036
  x = Math.max(x, anchorRect.left - containerRect.left - menuRect.width);
1180
1037
  }
1181
1038
  }
1182
1039
  let y, topOverflow, bottomOverflow;
1183
- if (computedDirection === "top") {
1040
+ if (computedDirection === 'top') {
1184
1041
  y = placeTopY;
1185
- if (position !== "initial") {
1042
+ if (position !== 'initial') {
1186
1043
  // if menu overflows to the top,
1187
1044
  // try to reposition it to the bottom of the anchor.
1188
1045
  topOverflow = getTopOverflow(y);
@@ -1192,7 +1049,7 @@ const placeToporBottom = (props) => {
1192
1049
  bottomOverflow = getBottomOverflow(placeBottomY);
1193
1050
  if (bottomOverflow <= 0 || -topOverflow > bottomOverflow) {
1194
1051
  y = placeBottomY;
1195
- computedDirection = "bottom";
1052
+ computedDirection = 'bottom';
1196
1053
  }
1197
1054
  }
1198
1055
  }
@@ -1200,18 +1057,18 @@ const placeToporBottom = (props) => {
1200
1057
  else {
1201
1058
  // Opposite logic to the 'top' direction above
1202
1059
  y = placeBottomY;
1203
- if (position !== "initial") {
1060
+ if (position !== 'initial') {
1204
1061
  bottomOverflow = getBottomOverflow(y);
1205
1062
  if (bottomOverflow > 0) {
1206
1063
  topOverflow = getTopOverflow(placeTopY);
1207
1064
  if (topOverflow >= 0 || -topOverflow < bottomOverflow) {
1208
1065
  y = placeTopY;
1209
- computedDirection = "top";
1066
+ computedDirection = 'top';
1210
1067
  }
1211
1068
  }
1212
1069
  }
1213
1070
  }
1214
- if (position === "auto")
1071
+ if (position === 'auto')
1215
1072
  y = confineVertically(y);
1216
1073
  const arrowX = arrow
1217
1074
  ? placeArrowHorizontal({
@@ -1231,7 +1088,7 @@ const positionMenu = (props) => {
1231
1088
  let horizontalOffset = offsetX;
1232
1089
  let verticalOffset = offsetY;
1233
1090
  if (arrow && arrowRef.current) {
1234
- if (direction === "left" || direction === "right") {
1091
+ if (direction === 'left' || direction === 'right') {
1235
1092
  horizontalOffset += arrowRef.current.offsetWidth;
1236
1093
  }
1237
1094
  else {
@@ -1246,11 +1103,11 @@ const positionMenu = (props) => {
1246
1103
  const placeTopY = anchorRect.top - containerRect.top - menuRect.height - verticalOffset;
1247
1104
  const placeBottomY = anchorRect.bottom - containerRect.top + verticalOffset;
1248
1105
  let placeToporBottomX, placeLeftorRightY;
1249
- if (align === "end") {
1106
+ if (align === 'end') {
1250
1107
  placeToporBottomX = anchorRect.right - containerRect.left - menuRect.width;
1251
1108
  placeLeftorRightY = anchorRect.bottom - containerRect.top - menuRect.height;
1252
1109
  }
1253
- else if (align === "center") {
1110
+ else if (align === 'center') {
1254
1111
  placeToporBottomX = anchorRect.left - containerRect.left - (menuRect.width - anchorRect.width) / 2;
1255
1112
  placeLeftorRightY = anchorRect.top - containerRect.top - (menuRect.height - anchorRect.height) / 2;
1256
1113
  }
@@ -1275,17 +1132,17 @@ const positionMenu = (props) => {
1275
1132
  position,
1276
1133
  };
1277
1134
  switch (direction) {
1278
- case "left":
1279
- case "right":
1135
+ case 'left':
1136
+ case 'right':
1280
1137
  return placeLeftorRight(options);
1281
- case "top":
1282
- case "bottom":
1138
+ case 'top':
1139
+ case 'bottom':
1283
1140
  default:
1284
1141
  return placeToporBottom(options);
1285
1142
  }
1286
1143
  };
1287
1144
 
1288
- const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowStyle, anchorPoint, anchorRef, containerRef, externalRef, parentScrollingRef, arrow, align = "start", direction = "bottom", position = "auto", overflow = "visible", setDownOverflow, repositionFlag, captureFocus = true, state, endTransition, isDisabled, menuItemFocus, dontShrinkIfDirectionIsTop, offsetX = 0, offsetY = 0, children, onClose, ...restProps }) => {
1145
+ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowStyle, anchorPoint, anchorRef, containerRef, externalRef, parentScrollingRef, arrow, align = 'start', direction = 'bottom', position = 'auto', overflow = 'visible', setDownOverflow, repositionFlag, captureFocus = true, state, endTransition, isDisabled, menuItemFocus, dontShrinkIfDirectionIsTop, offsetX = 0, offsetY = 0, children, onClose, ...restProps }) => {
1289
1146
  const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
1290
1147
  const [arrowPosition, setArrowPosition] = useState({ x: 0, y: 0 });
1291
1148
  const [overflowData, setOverflowData] = useState();
@@ -1303,8 +1160,8 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1303
1160
  const latestHandlePosition = useRef(() => { });
1304
1161
  const { hoverItem, dispatch, updateItems } = useItems(menuRef, focusRef);
1305
1162
  const isOpen = isMenuOpen(state);
1306
- const openTransition = getTransition(transition, "open");
1307
- const closeTransition = getTransition(transition, "close");
1163
+ const openTransition = getTransition(transition, 'open');
1164
+ const closeTransition = getTransition(transition, 'close');
1308
1165
  const scrollNodes = scrollNodesRef.current;
1309
1166
  /**
1310
1167
  * Given the menu-item we are on, find the closest or furthest next menu-item horizontally and focus it.
@@ -1314,8 +1171,8 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1314
1171
  if (!menuItemEl)
1315
1172
  return false;
1316
1173
  let [best, worst] = [];
1317
- findParentWithClass("szh-menu", menuItemEl)
1318
- ?.querySelectorAll(".szh-menu__item")
1174
+ findParentWithClass('szh-menu', menuItemEl)
1175
+ ?.querySelectorAll('.szh-menu__item')
1319
1176
  ?.forEach((item, i) => {
1320
1177
  // Must be at same height as currently focused menu-item
1321
1178
  if (item.offsetTop === menuItemEl.offsetTop) {
@@ -1330,14 +1187,14 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1330
1187
  const r = best ?? worst;
1331
1188
  if (!r)
1332
1189
  return false;
1333
- dispatch(HoverActionTypes.SET_INDEX, undefined, r["i"]);
1190
+ dispatch(HoverActionTypes.SET_INDEX, undefined, r['i']);
1334
1191
  return true;
1335
1192
  };
1336
1193
  const onKeyDown = (e) => {
1337
1194
  const elementTarget = e.target instanceof HTMLElement ? e.target : null;
1338
1195
  const isTextInputTarget = elementTarget &&
1339
- (elementTarget.nodeName === "TEXTAREA" ||
1340
- (elementTarget.nodeName === "INPUT" && elementTarget.getAttribute("type") === "text"));
1196
+ (elementTarget.nodeName === 'TEXTAREA' ||
1197
+ (elementTarget.nodeName === 'INPUT' && elementTarget.getAttribute('type') === 'text'));
1341
1198
  switch (e.key) {
1342
1199
  case Keys.HOME:
1343
1200
  // Don't eat home/end events on inputs
@@ -1381,14 +1238,14 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1381
1238
  e.stopPropagation();
1382
1239
  };
1383
1240
  const onAnimationEnd = () => {
1384
- if (state === "closing") {
1241
+ if (state === 'closing') {
1385
1242
  setOverflowData(undefined); // reset overflowData after closing
1386
1243
  }
1387
1244
  endTransition && safeCall(endTransition);
1388
1245
  };
1389
1246
  const handlePosition = useCallback((noOverflowCheck) => {
1390
1247
  if (!containerRef?.current) {
1391
- if (process.env.NODE_ENV !== "production") {
1248
+ if (process.env.NODE_ENV !== 'production') {
1392
1249
  console.error('[React-Menu] Menu cannot be positioned properly as container ref is null. If you need to initialise `state` prop to "open" for ControlledMenu, please see this solution: https://codesandbox.io/s/initial-open-sp10wn');
1393
1250
  }
1394
1251
  return;
@@ -1402,7 +1259,7 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1402
1259
  const positionHelpers = getPositionHelpers(containerRef, menuRef, scrollNodes.menu, boundingBoxPadding);
1403
1260
  const { menuRect } = positionHelpers;
1404
1261
  let results = {
1405
- computedDirection: "bottom",
1262
+ computedDirection: 'bottom',
1406
1263
  x: 0,
1407
1264
  y: 0,
1408
1265
  };
@@ -1425,7 +1282,7 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1425
1282
  let { y } = results;
1426
1283
  const { x, arrowX, arrowY, computedDirection } = results;
1427
1284
  let menuHeight = menuRect.height;
1428
- if (!noOverflowCheck && overflow !== "visible") {
1285
+ if (!noOverflowCheck && overflow !== 'visible') {
1429
1286
  const { getTopOverflow, getBottomOverflow } = positionHelpers;
1430
1287
  let height, overflowAmt;
1431
1288
  const prevHeight = latestMenuSize.current.height;
@@ -1506,21 +1363,21 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1506
1363
  }
1507
1364
  }
1508
1365
  let scroll = viewScroll;
1509
- if (scrollNodes.anchors.length && scroll === "initial")
1510
- scroll = "auto";
1511
- if (scroll === "initial")
1366
+ if (scrollNodes.anchors.length && scroll === 'initial')
1367
+ scroll = 'auto';
1368
+ if (scroll === 'initial')
1512
1369
  return;
1513
1370
  const handleScroll = () => {
1514
- if (scroll === "auto") {
1371
+ if (scroll === 'auto') {
1515
1372
  batchedUpdates(() => handlePosition(true));
1516
1373
  }
1517
1374
  else {
1518
1375
  safeCall(onClose, { reason: CloseReason.SCROLL });
1519
1376
  }
1520
1377
  };
1521
- const scrollObservers = scrollNodes.anchors.concat(viewScroll !== "initial" ? menuScroll : []);
1522
- scrollObservers.forEach((o) => o.addEventListener("scroll", handleScroll));
1523
- return () => scrollObservers.forEach((o) => o.removeEventListener("scroll", handleScroll));
1378
+ const scrollObservers = scrollNodes.anchors.concat(viewScroll !== 'initial' ? menuScroll : []);
1379
+ scrollObservers.forEach((o) => o.addEventListener('scroll', handleScroll));
1380
+ return () => scrollObservers.forEach((o) => o.removeEventListener('scroll', handleScroll));
1524
1381
  }, [rootAnchorRef, scrollNodes, isOpen, onClose, viewScroll, handlePosition]);
1525
1382
  const hasOverflow = !!overflowData && overflowData.overflowAmt != null && overflowData.overflowAmt > 0;
1526
1383
  useEffect(() => {
@@ -1528,11 +1385,11 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1528
1385
  return;
1529
1386
  const handleScroll = () => batchedUpdates(handlePosition);
1530
1387
  const parentScroll = parentScrollingRef.current;
1531
- parentScroll.addEventListener("scroll", handleScroll);
1532
- return () => parentScroll.removeEventListener("scroll", handleScroll);
1388
+ parentScroll.addEventListener('scroll', handleScroll);
1389
+ return () => parentScroll.removeEventListener('scroll', handleScroll);
1533
1390
  }, [isOpen, hasOverflow, parentScrollingRef, handlePosition]);
1534
1391
  useEffect(() => {
1535
- if (typeof ResizeObserver !== "function" || reposition === "initial")
1392
+ if (typeof ResizeObserver !== 'function' || reposition === 'initial')
1536
1393
  return;
1537
1394
  const resizeObserver = new ResizeObserver(([entry]) => {
1538
1395
  const { borderBoxSize, target } = entry;
@@ -1557,12 +1414,12 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1557
1414
  });
1558
1415
  });
1559
1416
  const observeTarget = menuRef.current;
1560
- resizeObserver.observe(observeTarget, { box: "border-box" });
1417
+ resizeObserver.observe(observeTarget, { box: 'border-box' });
1561
1418
  return () => resizeObserver.unobserve(observeTarget);
1562
1419
  }, [reposition]);
1563
1420
  // Matt added window resize observer
1564
1421
  useEffect(() => {
1565
- if (typeof ResizeObserver !== "function" || reposition === "initial")
1422
+ if (typeof ResizeObserver !== 'function' || reposition === 'initial')
1566
1423
  return;
1567
1424
  const callback = debounce$1(() => {
1568
1425
  const { width, height } = menuRef.current.ownerDocument.body.getBoundingClientRect();
@@ -1580,7 +1437,7 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1580
1437
  }, 250);
1581
1438
  const resizeObserver = new ResizeObserver(callback);
1582
1439
  const observeTarget = menuRef.current.ownerDocument.body;
1583
- resizeObserver.observe(observeTarget, { box: "border-box" });
1440
+ resizeObserver.observe(observeTarget, { box: 'border-box' });
1584
1441
  return () => {
1585
1442
  callback.cancel();
1586
1443
  resizeObserver.unobserve(observeTarget);
@@ -1601,7 +1458,7 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1601
1458
  else if (position === FocusPositions.LAST) {
1602
1459
  dispatch(HoverActionTypes.LAST, undefined, 0);
1603
1460
  }
1604
- else if (typeof position === "number" && position >= -1) {
1461
+ else if (typeof position === 'number' && position >= -1) {
1605
1462
  dispatch(HoverActionTypes.SET_INDEX, undefined, position);
1606
1463
  }
1607
1464
  };
@@ -1663,10 +1520,10 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1663
1520
  if (minHeight.current < h)
1664
1521
  minHeight.current = h;
1665
1522
  }
1666
- const dontShrinkOps = useMemo(() => expandedDirection === "top" && dontShrinkIfDirectionIsTop
1523
+ const dontShrinkOps = useMemo(() => expandedDirection === 'top' && dontShrinkIfDirectionIsTop
1667
1524
  ? {
1668
- overflowY: isSubmenuOpen ? "" : "auto",
1669
- minHeight: (isSubmenuOpen ? 0 : minHeight.current) + "px",
1525
+ overflowY: isSubmenuOpen ? '' : 'auto',
1526
+ minHeight: (isSubmenuOpen ? 0 : minHeight.current) + 'px',
1670
1527
  }
1671
1528
  : undefined, [dontShrinkIfDirectionIsTop, expandedDirection, isSubmenuOpen]);
1672
1529
  return (jsxs("ul", { role: "menu", "aria-label": ariaLabel, ...mergeProps({ onKeyDown, onAnimationEnd }, restProps), ...commonProps(isDisabled), ref: useCombinedRef(externalRef, menuRef), className: useBEM({ block: menuClass, modifiers, className: menuClassName }), style: {
@@ -1674,18 +1531,18 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1674
1531
  ...overflowStyle,
1675
1532
  ...dontShrinkOps,
1676
1533
  margin: 0,
1677
- display: state === "closed" ? "none" : undefined,
1678
- position: "absolute",
1534
+ display: state === 'closed' ? 'none' : undefined,
1535
+ position: 'absolute',
1679
1536
  left: menuPosition.x,
1680
1537
  top: menuPosition.y,
1681
- }, children: [jsx("div", { ref: focusRef, tabIndex: -1, style: { position: "absolute", left: 0, top: 0 }, onKeyDown: (event) => {
1682
- if (event.key == "Tab") {
1538
+ }, children: [jsx("div", { ref: focusRef, tabIndex: -1, style: { position: 'absolute', left: 0, top: 0 }, onKeyDown: (event) => {
1539
+ if (event.key == 'Tab') {
1683
1540
  event.preventDefault();
1684
1541
  event.stopPropagation();
1685
1542
  safeCall(onClose, {
1686
1543
  key: event.key,
1687
1544
  shiftKey: event.shiftKey,
1688
- reason: event.key === "Tab"
1545
+ reason: event.key === 'Tab'
1689
1546
  ? event.shiftKey
1690
1547
  ? CloseReason.TAB_BACKWARD
1691
1548
  : CloseReason.TAB_FORWARD
@@ -1694,13 +1551,13 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
1694
1551
  }
1695
1552
  } }), arrow && (jsx("div", { className: _arrowClass, style: {
1696
1553
  ...arrowStyle,
1697
- position: "absolute",
1554
+ position: 'absolute',
1698
1555
  left: arrowPosition.x,
1699
1556
  top: arrowPosition.y,
1700
1557
  }, ref: arrowRef })), jsx(MenuListContext.Provider, { value: listContext, children: jsx(MenuListItemContext.Provider, { value: itemContext, children: jsx(HoverItemContext.Provider, { value: hoverItem, children: children }) }) })] }));
1701
1558
  };
1702
1559
 
1703
- const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps, initialMounted, unmountOnClose, transition, transitionTimeout, boundingBoxRef, boundingBoxPadding, reposition = "auto", submenuOpenDelay = 300, submenuCloseDelay = 150, skipOpen, viewScroll = "initial", portal, theming, onItemClick, onClose, saveButtonRef, ...restProps }, externalRef) => {
1560
+ const ControlledMenuFr = ({ 'aria-label': ariaLabel, className, containerProps, initialMounted, unmountOnClose, transition, transitionTimeout, boundingBoxRef, boundingBoxPadding, reposition = 'auto', submenuOpenDelay = 300, submenuCloseDelay = 150, skipOpen, viewScroll = 'initial', portal, theming, onItemClick, onClose, saveButtonRef, ...restProps }, externalRef) => {
1704
1561
  const containerRef = useRef();
1705
1562
  const scrollNodesRef = useRef({});
1706
1563
  const { anchorRef, state } = restProps;
@@ -1727,10 +1584,10 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1727
1584
  reposition,
1728
1585
  viewScroll,
1729
1586
  ]);
1730
- const isWithinMenu = useCallback((target) => hasParentClass("szh-menu--state-open", target) ||
1587
+ const isWithinMenu = useCallback((target) => hasParentClass('szh-menu--state-open', target) ||
1731
1588
  // This is temporary, it will be removed when the overlay click is fixed
1732
- hasParentClass("LuiModalPrefab", target) ||
1733
- hasParentClass("prefab-modal", target), []);
1589
+ hasParentClass('LuiModalPrefab', target) ||
1590
+ hasParentClass('prefab-modal', target), []);
1734
1591
  const handleScreenEventForSave = useCallback((ev) => {
1735
1592
  if (!isWithinMenu(ev.target)) {
1736
1593
  ev.preventDefault();
@@ -1740,7 +1597,7 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1740
1597
  // This doesn't happen in React18
1741
1598
  // To work around it, I invoke the save by clicking on a passed in invisible button ref
1742
1599
  if (saveButtonRef?.current) {
1743
- saveButtonRef.current.setAttribute("data-reason", CloseReason.BLUR);
1600
+ saveButtonRef.current.setAttribute('data-reason', CloseReason.BLUR);
1744
1601
  saveButtonRef.current.click();
1745
1602
  }
1746
1603
  else
@@ -1770,7 +1627,7 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1770
1627
  const activeElement = thisDocument.activeElement;
1771
1628
  if (!anchorRef?.current || !activeElement)
1772
1629
  return;
1773
- if (ev.key !== "Tab" && ev.key !== "Enter")
1630
+ if (ev.key !== 'Tab' && ev.key !== 'Enter')
1774
1631
  return;
1775
1632
  if (ev.repeat) {
1776
1633
  ev.preventDefault();
@@ -1780,12 +1637,12 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1780
1637
  const invokeSave = (reason) => {
1781
1638
  if (!saveButtonRef?.current)
1782
1639
  return;
1783
- saveButtonRef.current?.setAttribute("data-reason", reason);
1640
+ saveButtonRef.current?.setAttribute('data-reason', reason);
1784
1641
  saveButtonRef?.current?.click();
1785
1642
  };
1786
1643
  // data-allowtabtosave is used such that list filter inputs can use tab to save
1787
- const allowTabToSave = activeElement.getAttribute("data-allowtabtosave") == "true";
1788
- const inputElsIterator = thisDocument.querySelectorAll(".szh-menu--state-open input,textarea");
1644
+ const allowTabToSave = activeElement.getAttribute('data-allowtabtosave') == 'true';
1645
+ const inputElsIterator = thisDocument.querySelectorAll('.szh-menu--state-open input,textarea');
1789
1646
  let inputEls = [];
1790
1647
  inputElsIterator.forEach((el) => inputEls.push(el));
1791
1648
  inputEls = inputEls.filter((el) => !el.disabled);
@@ -1793,9 +1650,9 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1793
1650
  return;
1794
1651
  const firstInputEl = inputEls[0];
1795
1652
  const lastInputEl = inputEls[inputEls.length - 1];
1796
- const isTextArea = activeElement.nodeName === "TEXTAREA";
1797
- const suppressEnterAutoSave = activeElement.getAttribute("data-disableenterautosave") == "true" || isTextArea;
1798
- if (ev.key === "Tab") {
1653
+ const isTextArea = activeElement.nodeName === 'TEXTAREA';
1654
+ const suppressEnterAutoSave = activeElement.getAttribute('data-disableenterautosave') == 'true' || isTextArea;
1655
+ if (ev.key === 'Tab') {
1799
1656
  const tabDirection = ev.shiftKey ? CloseReason.TAB_BACKWARD : CloseReason.TAB_FORWARD;
1800
1657
  if ((activeElement === lastInputEl && !ev.shiftKey) ||
1801
1658
  (activeElement === firstInputEl && ev.shiftKey) ||
@@ -1810,13 +1667,13 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1810
1667
  }
1811
1668
  }
1812
1669
  }
1813
- const type = activeElement.getAttribute("type");
1814
- const isTextInput = type === "text" || type == null || type === "textarea";
1670
+ const type = activeElement.getAttribute('type');
1671
+ const isTextInput = type === 'text' || type == null || type === 'textarea';
1815
1672
  switch (activeElement.nodeName) {
1816
- case "INPUT":
1673
+ case 'INPUT':
1817
1674
  {
1818
1675
  // If there's only one input element, we support tab and enter
1819
- if (isTextInput && ev.key === "Enter" && !suppressEnterAutoSave) {
1676
+ if (isTextInput && ev.key === 'Enter' && !suppressEnterAutoSave) {
1820
1677
  ev.preventDefault();
1821
1678
  ev.stopPropagation();
1822
1679
  if (isDown) {
@@ -1835,19 +1692,19 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1835
1692
  useEffect(() => {
1836
1693
  if (isMenuOpen(state)) {
1837
1694
  const thisDocument = anchorRef?.current ? anchorRef?.current.ownerDocument : document;
1838
- thisDocument.addEventListener("keydown", handleKeydownTabAndEnter, true);
1839
- thisDocument.addEventListener("keyup", handleKeyupTabAndEnter, true);
1840
- thisDocument.addEventListener("mousedown", handleScreenEventForSave, true);
1841
- thisDocument.addEventListener("mouseup", handleScreenEventForCancel, true);
1842
- thisDocument.addEventListener("click", handleScreenEventForCancel, true);
1843
- thisDocument.addEventListener("dblclick", handleScreenEventForCancel, true);
1695
+ thisDocument.addEventListener('keydown', handleKeydownTabAndEnter, true);
1696
+ thisDocument.addEventListener('keyup', handleKeyupTabAndEnter, true);
1697
+ thisDocument.addEventListener('mousedown', handleScreenEventForSave, true);
1698
+ thisDocument.addEventListener('mouseup', handleScreenEventForCancel, true);
1699
+ thisDocument.addEventListener('click', handleScreenEventForCancel, true);
1700
+ thisDocument.addEventListener('dblclick', handleScreenEventForCancel, true);
1844
1701
  return () => {
1845
- thisDocument.removeEventListener("keydown", handleKeydownTabAndEnter, true);
1846
- thisDocument.removeEventListener("keyup", handleKeyupTabAndEnter, true);
1847
- thisDocument.removeEventListener("mousedown", handleScreenEventForSave, true);
1848
- thisDocument.removeEventListener("mouseup", handleScreenEventForCancel, true);
1849
- thisDocument.removeEventListener("click", handleScreenEventForCancel, true);
1850
- thisDocument.removeEventListener("dblclick", handleScreenEventForCancel, true);
1702
+ thisDocument.removeEventListener('keydown', handleKeydownTabAndEnter, true);
1703
+ thisDocument.removeEventListener('keyup', handleKeyupTabAndEnter, true);
1704
+ thisDocument.removeEventListener('mousedown', handleScreenEventForSave, true);
1705
+ thisDocument.removeEventListener('mouseup', handleScreenEventForCancel, true);
1706
+ thisDocument.removeEventListener('click', handleScreenEventForCancel, true);
1707
+ thisDocument.removeEventListener('dblclick', handleScreenEventForCancel, true);
1851
1708
  };
1852
1709
  }
1853
1710
  return () => { };
@@ -1879,7 +1736,7 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1879
1736
  value: event.value,
1880
1737
  key: event.key,
1881
1738
  shiftKey: event.shiftKey,
1882
- reason: event.key === "Tab"
1739
+ reason: event.key === 'Tab'
1883
1740
  ? event.shiftKey
1884
1741
  ? CloseReason.TAB_BACKWARD
1885
1742
  : CloseReason.TAB_FORWARD
@@ -1917,15 +1774,15 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1917
1774
  }
1918
1775
  }
1919
1776
  };
1920
- const itemTransition = getTransition(transition, "item");
1777
+ const itemTransition = getTransition(transition, 'item');
1921
1778
  const modifiers = useMemo(() => ({ theme: theming, itemTransition }), [theming, itemTransition]);
1922
1779
  const menuList = (jsx("div", { ...mergeProps({ onKeyUp, onBlur }, containerProps), className: useBEM({
1923
1780
  block: menuContainerClass,
1924
1781
  modifiers,
1925
1782
  className,
1926
- }), style: { ...containerProps?.style, position: "relative" }, ref: containerRef, children: state && (jsx(SettingsContext.Provider, { value: settings, children: jsx(ItemSettingsContext.Provider, { value: itemSettings, children: jsx(EventHandlersContext.Provider, { value: eventHandlers, children: jsx(MenuList, { ...restProps, ariaLabel: ariaLabel || "Menu", externalRef: externalRef, containerRef: containerRef, onClose: onClose }) }) }) })) }));
1783
+ }), style: { ...containerProps?.style, position: 'relative' }, ref: containerRef, children: state && (jsx(SettingsContext.Provider, { value: settings, children: jsx(ItemSettingsContext.Provider, { value: itemSettings, children: jsx(EventHandlersContext.Provider, { value: eventHandlers, children: jsx(MenuList, { ...restProps, ariaLabel: ariaLabel || 'Menu', externalRef: externalRef, containerRef: containerRef, onClose: onClose }) }) }) })) }));
1927
1784
  if (portal === true && anchorRef?.current != null) {
1928
- if (hasParentClass("react-menu-inline-test", anchorRef.current)) {
1785
+ if (hasParentClass('react-menu-inline-test', anchorRef.current)) {
1929
1786
  portal = false;
1930
1787
  }
1931
1788
  else {
@@ -1933,8 +1790,8 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1933
1790
  }
1934
1791
  }
1935
1792
  if (portal) {
1936
- if (typeof portal === "boolean") {
1937
- if (portal && typeof document !== "undefined") {
1793
+ if (typeof portal === 'boolean') {
1794
+ if (portal && typeof document !== 'undefined') {
1938
1795
  return createPortal(menuList, document.body);
1939
1796
  }
1940
1797
  }
@@ -1946,7 +1803,31 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
1946
1803
  };
1947
1804
  const ControlledMenu = forwardRef(ControlledMenuFr);
1948
1805
 
1949
- function MenuFr({ "aria-label": ariaLabel, menuButton, instanceRef, onMenuChange, ...restProps }, externalRef) {
1806
+ const FocusableItemFr = ({ className, disabled, children, isHovering, menuItemRef, externalRef, ...restProps }) => {
1807
+ const isDisabled = !!disabled;
1808
+ const ref = useRef(null);
1809
+ const { setHover, onPointerLeave, ...restStateProps } = useItemState(menuItemRef, ref, isHovering, isDisabled);
1810
+ const { handleClose } = useContext(EventHandlersContext);
1811
+ const modifiers = useMemo(() => ({
1812
+ disabled: isDisabled,
1813
+ hover: isHovering,
1814
+ focusable: true,
1815
+ }), [isDisabled, isHovering]);
1816
+ const renderChildren = useMemo(() => safeCall(children, {
1817
+ ...modifiers,
1818
+ ref,
1819
+ closeMenu: handleClose,
1820
+ }), [children, modifiers, handleClose]);
1821
+ const mergedProps = mergeProps({
1822
+ ...restStateProps,
1823
+ onPointerLeave: (e) => onPointerLeave(e, true),
1824
+ onFocus: setHover,
1825
+ }, restProps);
1826
+ return (jsx("li", { role: "menuitem", ...mergedProps, ...commonProps(isDisabled), ref: useCombinedRef(externalRef, menuItemRef), className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }), children: renderChildren }));
1827
+ };
1828
+ const FocusableItem = withHovering('FocusableItem', FocusableItemFr);
1829
+
1830
+ function MenuFr({ 'aria-label': ariaLabel, menuButton, instanceRef, onMenuChange, ...restProps }, externalRef) {
1950
1831
  const [stateProps, toggleMenu, openMenu] = useMenuStateAndFocus(restProps);
1951
1832
  const isOpen = isMenuOpen(stateProps.state);
1952
1833
  const skipOpen = useRef(false);
@@ -1978,13 +1859,13 @@ function MenuFr({ "aria-label": ariaLabel, menuButton, instanceRef, onMenuChange
1978
1859
  // Too many mixed types here to figure out what to pick for button. Bad code.
1979
1860
  const button = safeCall(menuButton, { open: isOpen });
1980
1861
  if (!button || !button.type)
1981
- throw new Error("Menu requires a menuButton prop.");
1862
+ throw new Error('Menu requires a menuButton prop.');
1982
1863
  const buttonProps = {
1983
1864
  ref: useCombinedRef(button.ref, buttonRef),
1984
1865
  ...mergeProps({ onClick, onKeyDown }, button.props),
1985
1866
  isOpen: false,
1986
1867
  };
1987
- if (getName(button.type) === "MenuButton") {
1868
+ if (getName(button.type) === 'MenuButton') {
1988
1869
  buttonProps.isOpen = isOpen;
1989
1870
  }
1990
1871
  const renderButton = cloneElement(button, buttonProps);
@@ -1993,17 +1874,165 @@ function MenuFr({ "aria-label": ariaLabel, menuButton, instanceRef, onMenuChange
1993
1874
  openMenu,
1994
1875
  closeMenu: () => toggleMenu(false),
1995
1876
  }));
1996
- return (jsxs(Fragment$1, { children: [renderButton, jsx(ControlledMenu, { ...restProps, ...stateProps, "aria-label": ariaLabel || (typeof button.props.children === "string" ? button.props.children : "Menu"), anchorRef: buttonRef, ref: externalRef, onClose: handleClose, skipOpen: skipOpen })] }));
1877
+ return (jsxs(Fragment$1, { children: [renderButton, jsx(ControlledMenu, { ...restProps, ...stateProps, "aria-label": ariaLabel || (typeof button.props.children === 'string' ? button.props.children : 'Menu'), anchorRef: buttonRef, ref: externalRef, onClose: handleClose, skipOpen: skipOpen })] }));
1997
1878
  }
1998
1879
  const Menu = forwardRef(MenuFr);
1999
1880
 
2000
- const SubMenuFr = ({ "aria-label": ariaLabel, className, disabled, direction, label, openTrigger, onMenuChange, isHovering, instanceRef, menuItemRef, itemProps = {}, ...restProps }) => {
1881
+ const MenuButton = forwardRef(function MenuButton({ className, isOpen, disabled, children, ...restProps }, ref) {
1882
+ const modifiers = useMemo(() => ({ open: isOpen }), [isOpen]);
1883
+ return (jsx("button", { "aria-haspopup": true, "aria-expanded": isOpen, "aria-disabled": disabled || undefined, type: "button", disabled: disabled, ...restProps, ref: ref, className: useBEM({ block: menuButtonClass, modifiers, className }), children: children }));
1884
+ });
1885
+
1886
+ const MenuDividerFr = ({ className, ...restProps }, externalRef) => {
1887
+ return (jsx("li", { role: "separator", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: menuDividerClass, className }) }));
1888
+ };
1889
+ const MenuDivider = memo(forwardRef(MenuDividerFr));
1890
+
1891
+ const MenuGroupFr = ({ className, style, takeOverflow, ...restProps }, externalRef) => {
1892
+ const ref = useRef(null);
1893
+ const [overflowStyle, setOverflowStyle] = useState();
1894
+ const { overflow, overflowAmt } = useContext(MenuListContext);
1895
+ useIsomorphicLayoutEffect(() => {
1896
+ let maxHeight;
1897
+ if (takeOverflow && overflowAmt != null && overflowAmt >= 0 && ref.current) {
1898
+ maxHeight = ref.current.getBoundingClientRect().height - overflowAmt;
1899
+ if (maxHeight < 0)
1900
+ maxHeight = 0;
1901
+ }
1902
+ setOverflowStyle(maxHeight != null && maxHeight >= 0 ? { maxHeight, overflow } : undefined);
1903
+ }, [takeOverflow, overflow, overflowAmt]);
1904
+ useIsomorphicLayoutEffect(() => {
1905
+ if (overflowStyle && ref.current)
1906
+ ref.current.scrollTop = 0;
1907
+ }, [overflowStyle]);
1908
+ return (jsx("div", { ...restProps, ref: useCombinedRef(externalRef, ref), className: useBEM({ block: menuClass, element: menuGroupClass, className }), style: { ...style, ...overflowStyle } }));
1909
+ };
1910
+ const MenuGroup = forwardRef(MenuGroupFr);
1911
+
1912
+ const MenuHeaderFr = ({ className, ...restProps }, externalRef) => {
1913
+ return (jsx("li", { role: "presentation", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: menuHeaderClass, className }) }));
1914
+ };
1915
+ const MenuHeader = memo(forwardRef(MenuHeaderFr));
1916
+
1917
+ const RadioGroupContext = createContext({});
1918
+
1919
+ const MenuItemFr = ({ className, value, href, type, checked, disabled, children, onClick, isHovering, menuItemRef, externalRef, ...restProps }) => {
1920
+ const isDisabled = !!disabled;
1921
+ const { setHover, ...restStateProps } = useItemState(menuItemRef, menuItemRef, isHovering, isDisabled);
1922
+ const eventHandlers = useContext(EventHandlersContext);
1923
+ const radioGroup = useContext(RadioGroupContext);
1924
+ const isRadio = type === 'radio';
1925
+ const isCheckBox = type === 'checkbox';
1926
+ const isAnchor = !!href && !isDisabled && !isRadio && !isCheckBox;
1927
+ const isChecked = isRadio ? radioGroup.value === value : isCheckBox ? !!checked : false;
1928
+ // handle click seems to be a combination of multiple event types, bad code.
1929
+ const handleClick = (e) => {
1930
+ if (isDisabled) {
1931
+ if (e.syntheticEvent) {
1932
+ e.syntheticEvent.stopPropagation();
1933
+ e.syntheticEvent.preventDefault();
1934
+ }
1935
+ else {
1936
+ e.stopPropagation();
1937
+ e.preventDefault();
1938
+ }
1939
+ return;
1940
+ }
1941
+ const event = {
1942
+ value,
1943
+ syntheticEvent: e,
1944
+ };
1945
+ if (e.key !== undefined) {
1946
+ const ke = e;
1947
+ event.key = ke.key;
1948
+ event.shiftKey = ke.shiftKey;
1949
+ }
1950
+ if (isCheckBox)
1951
+ event.checked = !isChecked;
1952
+ if (isRadio)
1953
+ event.name = radioGroup.name;
1954
+ safeCall(onClick, event);
1955
+ if (isRadio)
1956
+ safeCall(radioGroup.onRadioChange, event);
1957
+ eventHandlers.handleClick(event, isCheckBox || isRadio);
1958
+ };
1959
+ const handleKeyDown = (e) => {
1960
+ // if tab is allowed the handleKeyUp event can't process the tab
1961
+ if (e.key === 'Tab') {
1962
+ e.preventDefault();
1963
+ e.stopPropagation();
1964
+ }
1965
+ };
1966
+ /**
1967
+ * Keyboard events are triggered on up, otherwise subcomponents get spaces and enters typed in them
1968
+ */
1969
+ const handleKeyUp = (e) => {
1970
+ if (!isHovering)
1971
+ return;
1972
+ switch (e.key) {
1973
+ case Keys.ENTER:
1974
+ case Keys.TAB:
1975
+ case Keys.SPACE:
1976
+ e.preventDefault();
1977
+ e.stopPropagation();
1978
+ if (isAnchor) {
1979
+ menuItemRef?.current && menuItemRef.current.click();
1980
+ }
1981
+ else {
1982
+ handleClick(e);
1983
+ }
1984
+ break;
1985
+ }
1986
+ };
1987
+ const modifiers = useMemo(() => ({
1988
+ type,
1989
+ disabled: isDisabled,
1990
+ hover: isHovering,
1991
+ checked: isChecked,
1992
+ anchor: isAnchor,
1993
+ }), [type, isDisabled, isHovering, isChecked, isAnchor]);
1994
+ const mergedProps = mergeProps({
1995
+ ...restStateProps,
1996
+ onPointerDown: setHover,
1997
+ onKeyDown: handleKeyDown,
1998
+ onKeyUp: handleKeyUp,
1999
+ onClick: handleClick,
2000
+ }, restProps);
2001
+ // Order of props overriding (same in all components):
2002
+ // 1. Preset props adhering to WAI-ARIA Authoring Practices.
2003
+ // 2. Merged outer and local props
2004
+ // 3. ref, className
2005
+ const menuItemProps = {
2006
+ role: isRadio ? 'menuitemradio' : isCheckBox ? 'menuitemcheckbox' : 'menuitem',
2007
+ 'aria-checked': isRadio || isCheckBox ? isChecked : undefined,
2008
+ ...mergedProps,
2009
+ ...commonProps(isDisabled, isHovering),
2010
+ ref: useCombinedRef(externalRef, menuItemRef),
2011
+ className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }),
2012
+ children: useMemo(() => safeCall(children, modifiers), [children, modifiers]),
2013
+ };
2014
+ if (isAnchor) {
2015
+ return (jsx("li", { role: "presentation", children: jsx("a", { href: href, ...menuItemProps }) }));
2016
+ }
2017
+ else {
2018
+ return jsx("li", { ...menuItemProps });
2019
+ }
2020
+ };
2021
+ const MenuItem = withHovering('MenuItem', MenuItemFr);
2022
+
2023
+ const MenuRadioGroupFr = ({ 'aria-label': ariaLabel, className, name, value, onRadioChange, ...restProps }, externalRef) => {
2024
+ const contextValue = useMemo(() => ({ name, value, onRadioChange }), [name, value, onRadioChange]);
2025
+ return (jsx(RadioGroupContext.Provider, { value: contextValue, children: jsx("li", { role: "presentation", children: jsx("ul", { role: "group", "aria-label": ariaLabel || name || 'Radio group', ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: radioGroupClass, className }) }) }) }));
2026
+ };
2027
+ const MenuRadioGroup = forwardRef(MenuRadioGroupFr);
2028
+
2029
+ const SubMenuFr = ({ 'aria-label': ariaLabel, className, disabled, direction, label, openTrigger, onMenuChange, isHovering, instanceRef, menuItemRef, itemProps = {}, ...restProps }) => {
2001
2030
  const settings = useContext(SettingsContext);
2002
2031
  const { rootMenuRef } = settings;
2003
2032
  const { submenuOpenDelay, submenuCloseDelay } = useContext(ItemSettingsContext);
2004
2033
  const { parentMenuRef, parentDir, overflow: parentOverflow } = useContext(MenuListContext);
2005
2034
  const { isParentOpen, isSubmenuOpen, setOpenSubmenuCount, dispatch, updateItems } = useContext(MenuListItemContext);
2006
- const isPortal = parentOverflow !== "visible";
2035
+ const isPortal = parentOverflow !== 'visible';
2007
2036
  const [stateProps, toggleMenu, _openMenu] = useMenuStateAndFocus(settings);
2008
2037
  const { state } = stateProps;
2009
2038
  const isDisabled = !!disabled;
@@ -2071,7 +2100,7 @@ const SubMenuFr = ({ "aria-label": ariaLabel, className, disabled, direction, la
2071
2100
  case Keys.ENTER:
2072
2101
  case Keys.SPACE:
2073
2102
  case Keys.RIGHT:
2074
- openTrigger !== "none" && openMenu(FocusPositions.FIRST);
2103
+ openTrigger !== 'none' && openMenu(FocusPositions.FIRST);
2075
2104
  break;
2076
2105
  }
2077
2106
  };
@@ -2113,188 +2142,21 @@ const SubMenuFr = ({ "aria-label": ariaLabel, className, disabled, direction, la
2113
2142
  onPointerMove: handlePointerMove,
2114
2143
  onPointerLeave: handlePointerLeave,
2115
2144
  onKeyDown: handleItemKeyDown,
2116
- onClick: () => openTrigger !== "none" && openMenu(),
2145
+ onClick: () => openTrigger !== 'none' && openMenu(),
2117
2146
  }, restItemProps);
2118
2147
  const getMenuList = () => {
2119
- const menuList = (jsx(MenuList, { ...restProps, ...stateProps, ariaLabel: ariaLabel || (typeof label === "string" ? label : "Submenu"), anchorRef: menuItemRef, containerRef: isPortal ? rootMenuRef : containerRef, direction: direction || (parentDir === "right" || parentDir === "left" ? parentDir : "right"), parentScrollingRef: isPortal && parentMenuRef, isDisabled: isDisabled }));
2148
+ const menuList = (jsx(MenuList, { ...restProps, ...stateProps, ariaLabel: ariaLabel || (typeof label === 'string' ? label : 'Submenu'), anchorRef: menuItemRef, containerRef: isPortal ? rootMenuRef : containerRef, direction: direction || (parentDir === 'right' || parentDir === 'left' ? parentDir : 'right'), parentScrollingRef: isPortal && parentMenuRef, isDisabled: isDisabled }));
2120
2149
  const container = rootMenuRef?.current;
2121
2150
  return isPortal && container ? createPortal(menuList, container) : menuList;
2122
2151
  };
2123
- return (jsxs("li", { className: useBEM({ block: menuClass, element: subMenuClass, className }), style: { position: "relative" }, role: "presentation", ref: containerRef, onKeyDown: handleKeyDown, children: [jsx("div", { role: "menuitem", "aria-haspopup": true, "aria-expanded": isOpen, ...mergedItemProps, ...commonProps(isDisabled, isHovering), ref: useCombinedRef(externalItemRef, menuItemRef), className: useBEM({
2152
+ return (jsxs("li", { className: useBEM({ block: menuClass, element: subMenuClass, className }), style: { position: 'relative' }, role: "presentation", ref: containerRef, onKeyDown: handleKeyDown, children: [jsx("div", { role: "menuitem", "aria-haspopup": true, "aria-expanded": isOpen, ...mergedItemProps, ...commonProps(isDisabled, isHovering), ref: useCombinedRef(externalItemRef, menuItemRef), className: useBEM({
2124
2153
  block: menuClass,
2125
2154
  element: menuItemClass,
2126
2155
  modifiers,
2127
2156
  className: itemClassName,
2128
2157
  }), children: useMemo(() => safeCall(label, modifiers), [label, modifiers]) }), state && getMenuList()] }));
2129
2158
  };
2130
- const SubMenu = withHovering("SubMenu", SubMenuFr);
2131
-
2132
- const RadioGroupContext = createContext({});
2133
-
2134
- const MenuItemFr = ({ className, value, href, type, checked, disabled, children, onClick, isHovering, menuItemRef, externalRef, ...restProps }) => {
2135
- const isDisabled = !!disabled;
2136
- const { setHover, ...restStateProps } = useItemState(menuItemRef, menuItemRef, isHovering, isDisabled);
2137
- const eventHandlers = useContext(EventHandlersContext);
2138
- const radioGroup = useContext(RadioGroupContext);
2139
- const isRadio = type === "radio";
2140
- const isCheckBox = type === "checkbox";
2141
- const isAnchor = !!href && !isDisabled && !isRadio && !isCheckBox;
2142
- const isChecked = isRadio ? radioGroup.value === value : isCheckBox ? !!checked : false;
2143
- // handle click seems to be a combination of multiple event types, bad code.
2144
- const handleClick = (e) => {
2145
- if (isDisabled) {
2146
- if (e.syntheticEvent) {
2147
- e.syntheticEvent.stopPropagation();
2148
- e.syntheticEvent.preventDefault();
2149
- }
2150
- else {
2151
- e.stopPropagation();
2152
- e.preventDefault();
2153
- }
2154
- return;
2155
- }
2156
- const event = {
2157
- value,
2158
- syntheticEvent: e,
2159
- };
2160
- if (e.key !== undefined) {
2161
- const ke = e;
2162
- event.key = ke.key;
2163
- event.shiftKey = ke.shiftKey;
2164
- }
2165
- if (isCheckBox)
2166
- event.checked = !isChecked;
2167
- if (isRadio)
2168
- event.name = radioGroup.name;
2169
- safeCall(onClick, event);
2170
- if (isRadio)
2171
- safeCall(radioGroup.onRadioChange, event);
2172
- eventHandlers.handleClick(event, isCheckBox || isRadio);
2173
- };
2174
- const handleKeyDown = (e) => {
2175
- // if tab is allowed the handleKeyUp event can't process the tab
2176
- if (e.key === "Tab") {
2177
- e.preventDefault();
2178
- e.stopPropagation();
2179
- }
2180
- };
2181
- /**
2182
- * Keyboard events are triggered on up, otherwise subcomponents get spaces and enters typed in them
2183
- */
2184
- const handleKeyUp = (e) => {
2185
- if (!isHovering)
2186
- return;
2187
- switch (e.key) {
2188
- case Keys.ENTER:
2189
- case Keys.TAB:
2190
- case Keys.SPACE:
2191
- e.preventDefault();
2192
- e.stopPropagation();
2193
- if (isAnchor) {
2194
- menuItemRef?.current && menuItemRef.current.click();
2195
- }
2196
- else {
2197
- handleClick(e);
2198
- }
2199
- break;
2200
- }
2201
- };
2202
- const modifiers = useMemo(() => ({
2203
- type,
2204
- disabled: isDisabled,
2205
- hover: isHovering,
2206
- checked: isChecked,
2207
- anchor: isAnchor,
2208
- }), [type, isDisabled, isHovering, isChecked, isAnchor]);
2209
- const mergedProps = mergeProps({
2210
- ...restStateProps,
2211
- onPointerDown: setHover,
2212
- onKeyDown: handleKeyDown,
2213
- onKeyUp: handleKeyUp,
2214
- onClick: handleClick,
2215
- }, restProps);
2216
- // Order of props overriding (same in all components):
2217
- // 1. Preset props adhering to WAI-ARIA Authoring Practices.
2218
- // 2. Merged outer and local props
2219
- // 3. ref, className
2220
- const menuItemProps = {
2221
- role: isRadio ? "menuitemradio" : isCheckBox ? "menuitemcheckbox" : "menuitem",
2222
- "aria-checked": isRadio || isCheckBox ? isChecked : undefined,
2223
- ...mergedProps,
2224
- ...commonProps(isDisabled, isHovering),
2225
- ref: useCombinedRef(externalRef, menuItemRef),
2226
- className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }),
2227
- children: useMemo(() => safeCall(children, modifiers), [children, modifiers]),
2228
- };
2229
- if (isAnchor) {
2230
- return (jsx("li", { role: "presentation", children: jsx("a", { href: href, ...menuItemProps }) }));
2231
- }
2232
- else {
2233
- return jsx("li", { ...menuItemProps });
2234
- }
2235
- };
2236
- const MenuItem = withHovering("MenuItem", MenuItemFr);
2237
-
2238
- const FocusableItemFr = ({ className, disabled, children, isHovering, menuItemRef, externalRef, ...restProps }) => {
2239
- const isDisabled = !!disabled;
2240
- const ref = useRef(null);
2241
- const { setHover, onPointerLeave, ...restStateProps } = useItemState(menuItemRef, ref, isHovering, isDisabled);
2242
- const { handleClose } = useContext(EventHandlersContext);
2243
- const modifiers = useMemo(() => ({
2244
- disabled: isDisabled,
2245
- hover: isHovering,
2246
- focusable: true,
2247
- }), [isDisabled, isHovering]);
2248
- const renderChildren = useMemo(() => safeCall(children, {
2249
- ...modifiers,
2250
- ref,
2251
- closeMenu: handleClose,
2252
- }), [children, modifiers, handleClose]);
2253
- const mergedProps = mergeProps({
2254
- ...restStateProps,
2255
- onPointerLeave: (e) => onPointerLeave(e, true),
2256
- onFocus: setHover,
2257
- }, restProps);
2258
- return (jsx("li", { role: "menuitem", ...mergedProps, ...commonProps(isDisabled), ref: useCombinedRef(externalRef, menuItemRef), className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }), children: renderChildren }));
2259
- };
2260
- const FocusableItem = withHovering("FocusableItem", FocusableItemFr);
2261
-
2262
- const MenuDividerFr = ({ className, ...restProps }, externalRef) => {
2263
- return (jsx("li", { role: "separator", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: menuDividerClass, className }) }));
2264
- };
2265
- const MenuDivider = memo(forwardRef(MenuDividerFr));
2266
-
2267
- const MenuHeaderFr = ({ className, ...restProps }, externalRef) => {
2268
- return (jsx("li", { role: "presentation", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: menuHeaderClass, className }) }));
2269
- };
2270
- const MenuHeader = memo(forwardRef(MenuHeaderFr));
2271
-
2272
- const MenuGroupFr = ({ className, style, takeOverflow, ...restProps }, externalRef) => {
2273
- const ref = useRef(null);
2274
- const [overflowStyle, setOverflowStyle] = useState();
2275
- const { overflow, overflowAmt } = useContext(MenuListContext);
2276
- useIsomorphicLayoutEffect(() => {
2277
- let maxHeight;
2278
- if (takeOverflow && overflowAmt != null && overflowAmt >= 0 && ref.current) {
2279
- maxHeight = ref.current.getBoundingClientRect().height - overflowAmt;
2280
- if (maxHeight < 0)
2281
- maxHeight = 0;
2282
- }
2283
- setOverflowStyle(maxHeight != null && maxHeight >= 0 ? { maxHeight, overflow } : undefined);
2284
- }, [takeOverflow, overflow, overflowAmt]);
2285
- useIsomorphicLayoutEffect(() => {
2286
- if (overflowStyle && ref.current)
2287
- ref.current.scrollTop = 0;
2288
- }, [overflowStyle]);
2289
- return (jsx("div", { ...restProps, ref: useCombinedRef(externalRef, ref), className: useBEM({ block: menuClass, element: menuGroupClass, className }), style: { ...style, ...overflowStyle } }));
2290
- };
2291
- const MenuGroup = forwardRef(MenuGroupFr);
2292
-
2293
- const MenuRadioGroupFr = ({ "aria-label": ariaLabel, className, name, value, onRadioChange, ...restProps }, externalRef) => {
2294
- const contextValue = useMemo(() => ({ name, value, onRadioChange }), [name, value, onRadioChange]);
2295
- return (jsx(RadioGroupContext.Provider, { value: contextValue, children: jsx("li", { role: "presentation", children: jsx("ul", { role: "group", "aria-label": ariaLabel || name || "Radio group", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: radioGroupClass, className }) }) }) }));
2296
- };
2297
- const MenuRadioGroup = forwardRef(MenuRadioGroupFr);
2159
+ const SubMenu = withHovering('SubMenu', SubMenuFr);
2298
2160
 
2299
2161
  const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, }) => {
2300
2162
  const { redrawRows, prePopupOps, postPopupOps, getSelectedRows } = useContext(GridContext);
@@ -2329,46 +2191,191 @@ const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, })
2329
2191
  return {
2330
2192
  openMenu,
2331
2193
  cellContextMenu,
2332
- component: ContextMenu ? (jsx(Fragment, { children: jsx(ControlledMenu, { anchorPoint: anchorPoint, state: isOpen ? "open" : "closed", direction: "right", onClose: closeMenu, children: isOpen && (jsx(ContextMenu, { selectedRows: selectedRowsRef.current, clickedRow: clickedRowRef.current, colDef: clickedColDefRef.current, close: closeMenu })) }) })) : null,
2194
+ component: ContextMenu ? (jsx(Fragment, { children: jsx(ControlledMenu, { anchorPoint: anchorPoint, state: isOpen ? 'open' : 'closed', direction: "right", onClose: closeMenu, children: isOpen && (jsx(ContextMenu, { selectedRows: selectedRowsRef.current, clickedRow: clickedRowRef.current, colDef: clickedColDefRef.current, close: closeMenu })) }) })) : null,
2333
2195
  };
2334
2196
  };
2335
2197
 
2198
+ const GridLoadingOverlayComponentFr = (props, externalRef) => (jsx("div", { ref: externalRef, style: {
2199
+ left: 0,
2200
+ top: 0,
2201
+ bottom: 0,
2202
+ right: 0,
2203
+ position: 'absolute',
2204
+ backgroundColor: 'rgba(255,255,255,0.5)',
2205
+ }, children: jsx("div", { style: { height: '100%', position: 'relative' }, children: jsx("div", { style: { position: 'absolute', left: 0, top: props.headerRowHeight, right: 0, bottom: 0 }, children: jsx(LuiStatusSpinner, {}) }) }) }));
2206
+ const GridLoadingOverlayComponent = forwardRef(GridLoadingOverlayComponentFr);
2207
+ const GridNoRowsOverlayFr = (props, externalRef) => {
2208
+ if (props.loading) {
2209
+ return jsx(GridLoadingOverlayComponent, { ref: externalRef, headerRowHeight: props.headerRowHeight });
2210
+ }
2211
+ if (props.rowCount === 0) {
2212
+ return jsx("div", { ref: externalRef, children: props.noRowsOverlayText ?? 'There are currently no rows' });
2213
+ }
2214
+ if (props.filteredRowCount === 0) {
2215
+ return jsx("div", { ref: externalRef, children: props.noRowsMatchingOverlayText ?? 'All rows have been filtered' });
2216
+ }
2217
+ return jsx("div", { ref: externalRef });
2218
+ };
2219
+ const GridNoRowsOverlay = forwardRef(GridNoRowsOverlayFr);
2220
+
2336
2221
  /**
2337
- * AgGrid checkbox select does not pass clicks within cell but not on the checkbox to checkbox.
2338
- * This passes the event to the checkbox when you click anywhere in the cell.
2222
+ * Retains last sort order from via <AgGrid postRowSort>.
2223
+ * Then applies this sort until next sort column change.
2224
+ * Handles stale sort, when you edit a row but don't want to re-sort.
2339
2225
  */
2340
- const clickInputWhenContainingCellClicked = (params) => {
2341
- const { data, event, colDef } = params;
2342
- if (!data || !event)
2343
- return;
2344
- const element = event.target;
2345
- // Already handled
2346
- if (element.closest(".GridCell-readonly") ||
2347
- (["BUTTON", "INPUT"].includes(element?.tagName) && element.closest(".ag-cell-inline-editing"))) {
2348
- return;
2349
- }
2350
- const row = element.closest("[row-id]");
2351
- if (!row)
2352
- return;
2353
- const colId = colDef.colId;
2354
- if (!colId)
2355
- return;
2356
- const clickInput = () => {
2357
- const cell = row.querySelector(`[col-id='${colId}']`);
2358
- if (!cell)
2359
- return;
2360
- const input = cell.querySelector("input, button");
2361
- if (!input)
2226
+ const usePostSortRowsHook = ({ setStaleGrid }) => {
2227
+ const { redrawRows } = useContext(GridContext);
2228
+ // On first run we need to init the first backed up sort order
2229
+ const initialised = useRef(false);
2230
+ // Used to detect sort order has changed since last run
2231
+ const lastSortOrderHash = useRef('');
2232
+ // Used to detect if sort order was the same, has the direction changed
2233
+ const previousRowSortIndexRef = useRef({});
2234
+ // stale sort is when there's a sort and user edits a row
2235
+ // this applies a class to the div wrapping the grid which in turn adds a * beside the sort arrow
2236
+ const sortWasStale = useRef(false);
2237
+ // Previous col sort is stored and reapplied if the sort direction changes on the same column and the sort was stale
2238
+ // As a sort on a stale row should just resort, not change sort direction
2239
+ const previousColSort = useRef([]);
2240
+ const previousQuickFilter = useRef('');
2241
+ return useCallback(({ api, nodes }) => {
2242
+ // Grid is destroyed
2243
+ if (!api)
2362
2244
  return;
2363
- input?.dispatchEvent(event);
2364
- };
2365
- setTimeout(clickInput, 20);
2245
+ const previousRowSortIndex = previousRowSortIndexRef.current;
2246
+ const hashNode = (node) => {
2247
+ return node ? JSON.stringify(node.data) : '';
2248
+ };
2249
+ const copyCurrentSortSettings = () => api.getColumnState().map((row) => ({ colId: row.colId, sort: row.sort, sortIndex: row.sortIndex }));
2250
+ const backupSortOrder = () => {
2251
+ for (const x in previousRowSortIndex)
2252
+ delete previousRowSortIndex[x];
2253
+ nodes.forEach((node, index) => (previousRowSortIndex[`${node.data.id}`] = { index, hash: hashNode(node) }));
2254
+ };
2255
+ // Check if column is the first sorted column. Note: column is preconfigured to sort its sortIndex is null not 1
2256
+ const isFirstSortColumn = (row) => row.sort && [0, null].includes(row.sortIndex ?? null);
2257
+ const isSameColumnAndDifferentSort = (col1, col2) => col1 && col2 && col1.colId === col2.colId && col1.sort != col2.sort;
2258
+ const restorePreviousSortColumnState = () => api.applyColumnState({ state: previousColSort.current });
2259
+ const sortNodesByPreviousSort = () => {
2260
+ nodes.sort((a, b) => (previousRowSortIndex[`${a.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER) -
2261
+ (previousRowSortIndex[`${b.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER));
2262
+ };
2263
+ // On first load copy the current sort
2264
+ if (!initialised.current) {
2265
+ initialised.current = true;
2266
+ previousColSort.current = copyCurrentSortSettings();
2267
+ }
2268
+ const newSortOrder = JSON.stringify(copyCurrentSortSettings());
2269
+ let sortOrderChanged = newSortOrder != lastSortOrderHash.current;
2270
+ const quickFilter = api.getQuickFilter();
2271
+ if (previousQuickFilter.current != quickFilter) {
2272
+ previousQuickFilter.current = quickFilter ?? '';
2273
+ sortOrderChanged = true;
2274
+ }
2275
+ if (isEmpty(previousRowSortIndex)) {
2276
+ backupSortOrder();
2277
+ }
2278
+ if (sortOrderChanged) {
2279
+ const thisFirstCol = copyCurrentSortSettings().find(isFirstSortColumn);
2280
+ const previousFirstCol = previousColSort.current.find(isFirstSortColumn);
2281
+ // Change to sort can be: (in the context of stale sort do...)
2282
+ // - no sort to sorted (do nothing)
2283
+ // - asc to desc (resort as asc, and remove stale sort)
2284
+ // - desc to no sort (resort as desc, and remove stale sort)
2285
+ const wasSortChangedOnSameColumn = previousFirstCol && (!thisFirstCol || isSameColumnAndDifferentSort(previousFirstCol, thisFirstCol));
2286
+ // if sort was stale, and we're here, someone has clicked a stale sort order (^*) in the column header
2287
+ if (sortWasStale.current && wasSortChangedOnSameColumn) {
2288
+ // Sort was an existing priority 1 column
2289
+ // We want to re-sort with the old sort direction and clear stale sort
2290
+ sortWasStale.current = false;
2291
+ setStaleGrid(false);
2292
+ // trigger a recapture of sort order
2293
+ lastSortOrderHash.current = '';
2294
+ restorePreviousSortColumnState();
2295
+ }
2296
+ else {
2297
+ // Sort was on a different column so clear sort and sort like normal
2298
+ if (sortWasStale.current) {
2299
+ sortWasStale.current = false;
2300
+ setStaleGrid(false);
2301
+ }
2302
+ // Columns were sorted so retain the sort
2303
+ backupSortOrder();
2304
+ lastSortOrderHash.current = newSortOrder;
2305
+ }
2306
+ }
2307
+ else {
2308
+ let firstChangedNodeIndex = -1;
2309
+ let lastNewNode = undefined;
2310
+ let changedRowCount = 0;
2311
+ let newRowCount = 0;
2312
+ let index = 0;
2313
+ for (const node of nodes) {
2314
+ const psr = previousRowSortIndex[`${node.data.id}`];
2315
+ if (psr) {
2316
+ if (psr.hash != hashNode(node)) {
2317
+ if (firstChangedNodeIndex === -1)
2318
+ firstChangedNodeIndex = index;
2319
+ changedRowCount++;
2320
+ }
2321
+ }
2322
+ else {
2323
+ lastNewNode = node;
2324
+ newRowCount++;
2325
+ }
2326
+ index++;
2327
+ }
2328
+ let wasStale = false;
2329
+ if (changedRowCount === 0 && newRowCount === 1) {
2330
+ // insert new row at end
2331
+ const newIndex = index - 1;
2332
+ previousRowSortIndex[`${lastNewNode?.data.id}`] = { index: newIndex, hash: hashNode(lastNewNode) };
2333
+ wasStale = true;
2334
+ }
2335
+ else if (changedRowCount === 2 && newRowCount === 0) {
2336
+ // This must be a swap rows (sometimes it's not, needs further attention)
2337
+ backupSortOrder();
2338
+ wasStale = false;
2339
+ }
2340
+ else if (changedRowCount > 1 && newRowCount === 1) {
2341
+ // This must be a insert so, insert new row near the row that changed
2342
+ previousRowSortIndex[`${lastNewNode?.data.id}`] = {
2343
+ index: firstChangedNodeIndex + 0.5,
2344
+ hash: hashNode(lastNewNode),
2345
+ };
2346
+ wasStale = true;
2347
+ // For some reason AgGrid mis-positions the inserted row.
2348
+ lastNewNode && redrawRows();
2349
+ }
2350
+ else if (changedRowCount == 1 && newRowCount === 0) {
2351
+ // User edited one row so, do nothing, retain sort
2352
+ wasStale = true;
2353
+ }
2354
+ else if (changedRowCount !== 0 || newRowCount != 0) {
2355
+ // too many rows changed, resort
2356
+ backupSortOrder();
2357
+ }
2358
+ if (wasStale) {
2359
+ // Check if the sort order the aggrid passed matches our stale sort order
2360
+ const stillStale = Object.keys(previousRowSortIndex).length != nodes.length ||
2361
+ nodes.some((node, index) => previousRowSortIndex[`${node.data.id}`]?.index !== index);
2362
+ // If we haven't already processed a stale sort then...
2363
+ if (stillStale && !sortWasStale.current) {
2364
+ // backup sort state, so we can restore it when sort is clicked on a stale column
2365
+ previousColSort.current = copyCurrentSortSettings();
2366
+ sortWasStale.current = true;
2367
+ setStaleGrid(true);
2368
+ }
2369
+ }
2370
+ sortNodesByPreviousSort();
2371
+ }
2372
+ }, [redrawRows, setStaleGrid]);
2366
2373
  };
2367
2374
 
2368
2375
  /**
2369
2376
  * Wrapper for AgGrid to add commonly used functionality.
2370
2377
  */
2371
- const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection = "multiple", suppressColumnVirtualization = true, theme = "ag-theme-step-default", sizeColumns = "auto", selectColumnPinned = null, contextMenuSelectRow = false, singleClickEdit = false, rowData, rowHeight = theme === "ag-theme-step-default" ? 40 : theme === "ag-theme-step-compact" ? 36 : 40, ...params }) => {
2378
+ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection = 'multiple', suppressColumnVirtualization = true, theme = 'ag-theme-step-default', sizeColumns = 'auto', selectColumnPinned = null, contextMenuSelectRow = false, singleClickEdit = false, rowData, rowHeight = theme === 'ag-theme-step-default' ? 40 : theme === 'ag-theme-step-compact' ? 36 : 40, ...params }) => {
2372
2379
  const { gridReady, gridRenderState, setApis, ensureRowVisible, getFirstRowId, selectRowsById, focusByRowById, ensureSelectedRowIsVisible, autoSizeColumns, sizeColumnsToFit, externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync, isExternalFilterPresent, doesExternalFilterPass, setOnCellEditingComplete, getColDef, showNoRowsOverlay, prePopupOps, stopEditing, } = useContext(GridContext);
2373
2380
  const { checkUpdating, updatedDep, updatingCols } = useContext(GridUpdatingContext);
2374
2381
  const gridDivRef = useRef(null);
@@ -2397,20 +2404,20 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2397
2404
  needsAutoSize.current = true;
2398
2405
  return;
2399
2406
  }
2400
- const skipHeader = sizeColumns === "auto-skip-headers" && gridRendered === "rows-visible";
2401
- if (sizeColumns === "auto" || skipHeader) {
2407
+ const skipHeader = sizeColumns === 'auto-skip-headers' && gridRendered === 'rows-visible';
2408
+ if (sizeColumns === 'auto' || skipHeader) {
2402
2409
  const result = autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, includeFlex: true });
2403
2410
  if (!result) {
2404
2411
  needsAutoSize.current = true;
2405
2412
  return;
2406
2413
  }
2407
- if (gridRendered === "empty") {
2414
+ if (gridRendered === 'empty') {
2408
2415
  if (!hasSetContentSizeEmpty.current && !hasSetContentSize.current) {
2409
2416
  hasSetContentSizeEmpty.current = true;
2410
2417
  params.onContentSize?.(result);
2411
2418
  }
2412
2419
  }
2413
- else if (gridRendered === "rows-visible") {
2420
+ else if (gridRendered === 'rows-visible') {
2414
2421
  if (!hasSetContentSize.current) {
2415
2422
  if (lastFullResize.current === result.width) {
2416
2423
  hasSetContentSize.current = true;
@@ -2424,10 +2431,10 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2424
2431
  }
2425
2432
  else {
2426
2433
  // It should be impossible to get here
2427
- console.error("Unknown value returned from hasGridRendered");
2434
+ console.error('Unknown value returned from hasGridRendered');
2428
2435
  }
2429
2436
  }
2430
- if (sizeColumns !== "none") {
2437
+ if (sizeColumns !== 'none') {
2431
2438
  sizeColumnsToFit();
2432
2439
  }
2433
2440
  setAutoSized(true);
@@ -2446,7 +2453,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2446
2453
  needsAutoSize.current = true;
2447
2454
  }
2448
2455
  }
2449
- if (needsAutoSize.current || (!hasSetContentSize.current && sizeColumns === "auto")) {
2456
+ if (needsAutoSize.current || (!hasSetContentSize.current && sizeColumns === 'auto')) {
2450
2457
  needsAutoSize.current = false;
2451
2458
  setInitialContentSize();
2452
2459
  }
@@ -2488,7 +2495,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2488
2495
  }
2489
2496
  const selectedRows = api.getSelectedRows();
2490
2497
  // We don't want to update selected Items if it hasn't changed to prevent excess renders
2491
- if (params.externalSelectedItems.length != selectedRows.length ||
2498
+ if (params.externalSelectedItems.length !== selectedRows.length ||
2492
2499
  isNotEmpty(xorBy(selectedRows, params.externalSelectedItems, (row) => row.id))) {
2493
2500
  setExternallySelectedItemsAreInSync(false);
2494
2501
  params.setExternalSelectedItems([...selectedRows]);
@@ -2544,14 +2551,14 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2544
2551
  editable,
2545
2552
  cellClassRules: {
2546
2553
  ...colDef.cellClassRules,
2547
- "GridCell-readonly": (ccp) => !editable(ccp),
2554
+ 'GridCell-readonly': (ccp) => !editable(ccp),
2548
2555
  },
2549
2556
  };
2550
2557
  });
2551
2558
  return params.selectable || params.onRowDragEnd
2552
2559
  ? [
2553
2560
  {
2554
- colId: "selection",
2561
+ colId: 'selection',
2555
2562
  editable: false,
2556
2563
  rowDrag: !!params.onRowDragEnd,
2557
2564
  minWidth: params.selectable && params.onRowDragEnd ? 76 : 48,
@@ -2561,12 +2568,12 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2561
2568
  exportable: false,
2562
2569
  },
2563
2570
  checkboxSelection: params.selectable,
2564
- headerClass: params.onRowDragEnd ? "ag-header-select-draggable" : undefined,
2565
- headerComponent: rowSelection === "multiple" ? GridHeaderSelect : null,
2571
+ headerClass: params.onRowDragEnd ? 'ag-header-select-draggable' : undefined,
2572
+ headerComponent: rowSelection === 'multiple' ? GridHeaderSelect : null,
2566
2573
  suppressHeaderKeyboardEvent: (e) => {
2567
2574
  if (!params.selectable)
2568
2575
  return false;
2569
- if ((e.event.key === "Enter" || e.event.key === " ") && !e.event.repeat) {
2576
+ if ((e.event.key === 'Enter' || e.event.key === ' ') && !e.event.repeat) {
2570
2577
  if (isEmpty(e.api.getSelectedRows())) {
2571
2578
  e.api.selectAllFiltered();
2572
2579
  }
@@ -2617,7 +2624,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2617
2624
  // Don't update while there are spinners
2618
2625
  if (!isEmpty(updatingCols()))
2619
2626
  return;
2620
- const skipHeader = sizeColumns === "auto-skip-headers";
2627
+ const skipHeader = sizeColumns === 'auto-skip-headers';
2621
2628
  if (hasSetContentSize.current) {
2622
2629
  autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, colIds: colIdsEdited.current });
2623
2630
  }
@@ -2647,7 +2654,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2647
2654
  event.node.setSelected(true, true);
2648
2655
  }
2649
2656
  // Cell already being edited, so don't re-edit until finished
2650
- if (checkUpdating([event.colDef.field ?? ""], event.data.id)) {
2657
+ if (checkUpdating([event.colDef.field ?? ''], event.data.id)) {
2651
2658
  return;
2652
2659
  }
2653
2660
  if (event.rowIndex !== null) {
@@ -2693,11 +2700,11 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2693
2700
  */
2694
2701
  const onCellKeyPress = useCallback((e) => {
2695
2702
  const kbe = e.event;
2696
- if (kbe.key === "Enter") {
2703
+ if (kbe.key === 'Enter') {
2697
2704
  if (!invokeEditAction(e))
2698
2705
  startCellEditing(e);
2699
2706
  }
2700
- if (kbe.key === "Tab") {
2707
+ if (kbe.key === 'Tab') {
2701
2708
  // eslint-disable-next-line
2702
2709
  prePopupOps();
2703
2710
  }
@@ -2707,14 +2714,14 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2707
2714
  * but we don't want the non-flex auto-sized columns to "fit" size, so suppressSizeToFit is set to true.
2708
2715
  */
2709
2716
  const columnDefsAdjusted = useMemo(() => {
2710
- const adjustColDefOrGroup = (colDef) => "children" in colDef ? adjustGroupColDef(colDef) : adjustColDef(colDef);
2717
+ const adjustColDefOrGroup = (colDef) => 'children' in colDef ? adjustGroupColDef(colDef) : adjustColDef(colDef);
2711
2718
  const adjustGroupColDef = (colDef) => ({
2712
2719
  ...colDef,
2713
2720
  children: colDef.children.map((colDef) => adjustColDefOrGroup(colDef)),
2714
2721
  });
2715
2722
  const adjustColDef = (colDef) => ({
2716
2723
  ...colDef,
2717
- suppressSizeToFit: (sizeColumns === "auto" || sizeColumns === "auto-skip-headers") && !colDef.flex,
2724
+ suppressSizeToFit: (sizeColumns === 'auto' || sizeColumns === 'auto-skip-headers') && !colDef.flex,
2718
2725
  sortable: colDef.sortable && params.defaultColDef?.sortable !== false,
2719
2726
  });
2720
2727
  return columnDefs.map((colDef) => adjustColDefOrGroup(colDef));
@@ -2736,8 +2743,8 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2736
2743
  if (isEmpty(colIds)) {
2737
2744
  // Columns to resize?
2738
2745
  if (!isEmpty(colIdsEdited.current)) {
2739
- const skipHeader = sizeColumns === "auto-skip-headers";
2740
- if (sizeColumns === "auto" || skipHeader) {
2746
+ const skipHeader = sizeColumns === 'auto-skip-headers';
2747
+ if (sizeColumns === 'auto' || skipHeader) {
2741
2748
  defer$1(() => {
2742
2749
  if (hasSetContentSize.current) {
2743
2750
  autoSizeColumns({
@@ -2773,7 +2780,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2773
2780
  * Resize columns to fit if required on window/container resize
2774
2781
  */
2775
2782
  const onGridSizeChanged = useCallback(() => {
2776
- if (sizeColumns !== "none") {
2783
+ if (sizeColumns !== 'none') {
2777
2784
  sizeColumnsToFit();
2778
2785
  }
2779
2786
  }, [sizeColumns, sizeColumnsToFit]);
@@ -2789,10 +2796,10 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2789
2796
  if (colId == null)
2790
2797
  return;
2791
2798
  switch (e.source) {
2792
- case "uiColumnDragged":
2799
+ case 'uiColumnDragged':
2793
2800
  userSizedColIds.current.add(colId);
2794
2801
  break;
2795
- case "autosizeColumns":
2802
+ case 'autosizeColumns':
2796
2803
  userSizedColIds.current.delete(colId);
2797
2804
  break;
2798
2805
  }
@@ -2814,33 +2821,35 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
2814
2821
  }
2815
2822
  }
2816
2823
  }, []);
2817
- const onRowDragEnd = useCallback(async (event) => {
2818
- const clientSideRowModel = event.api.getModel();
2819
- if (event.node.rowIndex != null) {
2820
- const lastHighlightedRowNode = clientSideRowModel.getLastHighlightedRowNode();
2821
- const isBelow = lastHighlightedRowNode && lastHighlightedRowNode.highlighted === RowHighlightPosition.Below;
2822
- let targetIndex = event.overIndex;
2823
- if (event.node.rowIndex > event.overIndex) {
2824
- targetIndex += isBelow ? 1 : 0;
2825
- }
2826
- else {
2827
- targetIndex += isBelow ? 0 : -1;
2824
+ const onRowDragEnd = useCallback((event) => {
2825
+ void (async () => {
2826
+ const clientSideRowModel = event.api.getModel();
2827
+ if (event.node.rowIndex != null) {
2828
+ const lastHighlightedRowNode = clientSideRowModel.getLastHighlightedRowNode();
2829
+ const isBelow = lastHighlightedRowNode && lastHighlightedRowNode.highlighted === RowHighlightPosition.Below;
2830
+ let targetIndex = event.overIndex;
2831
+ if (event.node.rowIndex > event.overIndex) {
2832
+ targetIndex += isBelow ? 1 : 0;
2833
+ }
2834
+ else {
2835
+ targetIndex += isBelow ? 0 : -1;
2836
+ }
2837
+ const moved = event.node.data;
2838
+ const target = event.overNode?.data;
2839
+ moved.id !== target?.id && //moved over a different row
2840
+ event.node.rowIndex != targetIndex && //moved to a different index
2841
+ params.onRowDragEnd &&
2842
+ (await params.onRowDragEnd(moved, target, targetIndex));
2828
2843
  }
2829
- const moved = event.node.data;
2830
- const target = event.overNode?.data;
2831
- moved.id !== target?.id && //moved over a different row
2832
- event.node.rowIndex != targetIndex && //moved to a different index
2833
- params.onRowDragEnd &&
2834
- (await params.onRowDragEnd(moved, target, targetIndex));
2835
- }
2836
- clientSideRowModel.highlightRowAtPixel(null);
2844
+ clientSideRowModel.highlightRowAtPixel(null);
2845
+ })();
2837
2846
  }, [params]);
2838
2847
  // This is setting a ref in the GridContext so won't be triggering an update loop
2839
2848
  setOnCellEditingComplete(params.onCellEditingComplete);
2840
2849
  const headerRowCount = columnDefs.some((c) => c.children) ? 2 : 1;
2841
- return (jsxs("div", { "data-testid": dataTestId, className: clsx("Grid-container", theme, "theme-specific", staleGrid && "Grid-sortIsStale", gridReady && rowData && autoSized && "Grid-ready"), children: [gridContextMenu.component, jsx("div", { style: { flex: 1 }, ref: gridDivRef, children: jsx(AgGridReact, { rowHeight: rowHeight, animateRows: params.animateRows ?? false, rowClassRules: params.rowClassRules, getRowId: (params) => `${params.data.id}`, suppressRowClickSelection: true, rowSelection: rowSelection, suppressBrowserResizeObserver: true, onGridSizeChanged: onGridSizeChanged, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onColumnVisible: () => {
2850
+ return (jsxs("div", { "data-testid": dataTestId, className: clsx('Grid-container', theme, 'theme-specific', staleGrid && 'Grid-sortIsStale', gridReady && rowData && autoSized && 'Grid-ready'), children: [gridContextMenu.component, jsx("div", { style: { flex: 1 }, ref: gridDivRef, children: jsx(AgGridReact, { rowHeight: rowHeight, animateRows: params.animateRows ?? false, rowClassRules: params.rowClassRules, getRowId: (params) => `${params.data.id}`, suppressRowClickSelection: true, rowSelection: rowSelection, suppressBrowserResizeObserver: true, onGridSizeChanged: onGridSizeChanged, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onColumnVisible: () => {
2842
2851
  setInitialContentSize();
2843
- }, onRowDataUpdated: onRowDataChanged, onCellKeyDown: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStarted: refreshSelectedRows, domLayout: params.domLayout, onColumnResized: onColumnResized, defaultColDef: { minWidth: 48, ...omit(params.defaultColDef, ["editable"]) }, columnDefs: columnDefsAdjusted, rowData: rowData, noRowsOverlayComponent: (event) => {
2852
+ }, onRowDataUpdated: onRowDataChanged, onCellKeyDown: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStarted: refreshSelectedRows, domLayout: params.domLayout, onColumnResized: onColumnResized, defaultColDef: { minWidth: 48, ...omit(params.defaultColDef, ['editable']) }, columnDefs: columnDefsAdjusted, rowData: rowData, noRowsOverlayComponent: (event) => {
2844
2853
  let rowCount = 0;
2845
2854
  event.api.forEachNode(() => rowCount++);
2846
2855
  return (jsx(GridNoRowsOverlay, { loading: !rowData || params.loading === true, rowCount: rowCount, headerRowHeight: headerRowCount * rowHeight, filteredRowCount: event.api.getDisplayedRowCount(), noRowsOverlayText: params.noRowsOverlayText, noRowsMatchingOverlayText: params.noRowsMatchingOverlayText }));
@@ -2851,18 +2860,20 @@ const GridPopoverContext = createContext({
2851
2860
  anchorRef: { current: null },
2852
2861
  saving: false,
2853
2862
  setSaving: () => { },
2854
- colId: "",
2855
- field: "",
2863
+ colId: '',
2864
+ field: '',
2856
2865
  value: null,
2857
2866
  data: {},
2858
2867
  selectedRows: [],
2859
- updateValue: async () => false,
2860
- formatValue: () => "! No gridPopoverContextProvider !",
2868
+ updateValue: () => false,
2869
+ formatValue: () => '! No gridPopoverContextProvider !',
2861
2870
  });
2862
2871
  const useGridPopoverContext = () => useContext(GridPopoverContext);
2863
2872
 
2864
- const GridPopoverContextProvider = ({ props, children }) => {
2873
+ const GridPopoverContextProvider = (props2) => {
2865
2874
  const { getFilteredSelectedRows, updatingCells } = useContext(GridContext);
2875
+ const children = props2.children;
2876
+ const props = props2.props;
2866
2877
  const anchorRef = useRef(props.eGridCell);
2867
2878
  const hasSaved = useRef(false);
2868
2879
  const [saving, setSaving] = useState(false);
@@ -2871,8 +2882,8 @@ const GridPopoverContextProvider = ({ props, children }) => {
2871
2882
  const multiEdit = cellEditorParams?.multiEdit ?? false;
2872
2883
  // Then item that is clicked on will always be first in the list
2873
2884
  const selectedRows = useMemo(() => multiEdit ? sortBy(getFilteredSelectedRows(), (row) => row.id !== props.data.id) : [props.data], [getFilteredSelectedRows, multiEdit, props.data]);
2874
- const field = props.colDef?.field ?? "";
2875
- const colId = props.colDef?.colId ?? field ?? "";
2885
+ const field = props.colDef?.field ?? '';
2886
+ const colId = props.colDef?.colId ?? field ?? '';
2876
2887
  const updateValue = useCallback(async (saveFn, tabDirection) => {
2877
2888
  if (hasSaved.current)
2878
2889
  return true;
@@ -2894,7 +2905,7 @@ const GridPopoverContextProvider = ({ props, children }) => {
2894
2905
  };
2895
2906
 
2896
2907
  const GridCellMultiSelectClassRules = {
2897
- "ag-selected-for-edit": (params) => {
2908
+ 'ag-selected-for-edit': (params) => {
2898
2909
  const { api, node, colDef } = params;
2899
2910
  const cep = colDef.cellEditorSelector
2900
2911
  ? colDef.cellEditorSelector(params)?.params
@@ -2908,9 +2919,9 @@ const GridCellMultiSelectClassRules = {
2908
2919
  },
2909
2920
  };
2910
2921
 
2911
- const GridIcon = (props) => (jsx(LuiIcon, { name: props.icon, title: props.title, alt: props.title, size: props.size ?? "md", className: clsx(`AgGridGenericCellRenderer-${props.icon}Icon`, props.className, props.disabled && "GridIcon-disabled") }));
2922
+ const GridIcon = (props) => (jsx(LuiIcon, { name: props.icon, title: props.title, alt: props.title, size: props.size ?? 'md', className: clsx(`AgGridGenericCellRenderer-${props.icon}Icon`, props.className, props.disabled && 'GridIcon-disabled') }));
2912
2923
 
2913
- const GridLoadableCell = () => (jsx(LuiMiniSpinner, { size: 22, divProps: { className: "GridLoadableCell-container", role: "status", "aria-label": "Loading" } }));
2924
+ const GridLoadableCell = () => (jsx(LuiMiniSpinner, { size: 22, divProps: { className: 'GridLoadableCell-container', role: 'status', 'aria-label': 'Loading' } }));
2914
2925
 
2915
2926
  const GridCellRenderer = (props) => {
2916
2927
  const { checkUpdating } = useContext(GridUpdatingContext);
@@ -2921,38 +2932,38 @@ const GridCellRenderer = (props) => {
2921
2932
  const infoFn = rendererParams?.info;
2922
2933
  let infoText = props.data !== undefined && infoFn ? infoFn(props) : undefined;
2923
2934
  if (Array.isArray(warningText))
2924
- warningText = warningText.join("\n");
2935
+ warningText = warningText.join('\n');
2925
2936
  if (Array.isArray(infoText))
2926
- infoText = infoText.join("\n");
2927
- return checkUpdating(colDef.field ?? colDef.colId ?? "", props.data.id) ? (jsx(GridLoadableCell, {})) : (jsxs(Fragment, { children: [!!warningText && (jsx(GridIcon, { icon: "ic_warning_outline", title: typeof warningText === "string" ? warningText : "Warning" })), !!infoText && jsx(GridIcon, { icon: "ic_info_outline", title: typeof infoText === "string" ? infoText : "Info" }), jsx("div", { className: "GridCell-container", children: colDef.cellRendererParams?.originalCellRenderer ? (jsx(colDef.cellRendererParams.originalCellRenderer, { ...props })) : (jsx("span", { title: props.valueFormatted ?? undefined, children: props.valueFormatted })) }), fnOrVar(colDef.editable, props) && rendererParams?.rightHoverElement && (jsx("div", { className: "GridCell-hoverRight", children: rendererParams?.rightHoverElement }))] }));
2937
+ infoText = infoText.join('\n');
2938
+ return checkUpdating(colDef.field ?? colDef.colId ?? '', props.data.id) ? (jsx(GridLoadableCell, {})) : (jsxs(Fragment, { children: [!!warningText && (jsx(GridIcon, { icon: 'ic_warning_outline', title: typeof warningText === 'string' ? warningText : 'Warning' })), !!infoText && jsx(GridIcon, { icon: 'ic_info_outline', title: typeof infoText === 'string' ? infoText : 'Info' }), jsx("div", { className: 'GridCell-container', children: colDef.cellRendererParams?.originalCellRenderer ? (jsx(colDef.cellRendererParams.originalCellRenderer, { ...props })) : (jsx("span", { title: props.valueFormatted ?? undefined, children: props.valueFormatted })) }), fnOrVar(colDef.editable, props) && rendererParams?.rightHoverElement && (jsx("div", { className: 'GridCell-hoverRight', children: rendererParams?.rightHoverElement }))] }));
2928
2939
  };
2929
2940
  const suppressCellKeyboardEvents = (e) => {
2930
2941
  const shortcutKeys = e.colDef.cellRendererParams?.shortcutKeys ?? {};
2931
2942
  const exec = shortcutKeys[e.event.key];
2932
- if (exec && !e.editing && !e.event.repeat && e.event.type === "keydown") {
2943
+ if (exec && !e.editing && !e.event.repeat && e.event.type === 'keydown') {
2933
2944
  const editable = fnOrVar(e.colDef?.editable, e);
2934
2945
  return editable ? (exec(e) ?? true) : true;
2935
2946
  }
2936
2947
  // It's important that aggrid doesn't trigger edit on enter
2937
2948
  // as the incorrect selected rows will be returned
2938
- return !["ArrowLeft", "ArrowRight", "ArrowDown", "ArrowUp", "Tab", " ", "Home", "End", "PageUp", "PageDown"].includes(e.event.key);
2949
+ return !['ArrowLeft', 'ArrowRight', 'ArrowDown', 'ArrowUp', 'Tab', ' ', 'Home', 'End', 'PageUp', 'PageDown'].includes(e.event.key);
2939
2950
  };
2940
2951
  const generateFilterGetter = (field, filterValueGetter, valueFormatter) => {
2941
2952
  if (filterValueGetter)
2942
2953
  return filterValueGetter;
2943
2954
  // aggrid will default to valueGetter
2944
- if (typeof valueFormatter !== "function" || !field)
2955
+ if (typeof valueFormatter !== 'function' || !field)
2945
2956
  return undefined;
2946
2957
  return (params) => {
2947
2958
  const value = params.getValue(field);
2948
2959
  let formattedValue = valueFormatter({ ...params, value });
2949
2960
  // Search for null values using standard dash
2950
- if (formattedValue === "")
2951
- formattedValue += " -";
2961
+ if (formattedValue === '')
2962
+ formattedValue += ' -';
2952
2963
  // Search by raw value as well as formatted
2953
- const gotValue = ["string", "number"].includes(typeof value) ? value : undefined;
2954
- return (formattedValue + (gotValue != null && formattedValue != gotValue ? " " + gotValue : "")) //
2955
- .replace(/\s+/g, " ")
2964
+ const gotValue = ['string', 'number'].includes(typeof value) ? value : undefined;
2965
+ return (formattedValue + (gotValue != null && formattedValue != gotValue ? ' ' + gotValue : '')) //
2966
+ .replace(/\s+/g, ' ')
2956
2967
  .trim();
2957
2968
  };
2958
2969
  };
@@ -2995,15 +3006,15 @@ const GridCell = (props, custom) => {
2995
3006
  // Default value formatter, otherwise react freaks out on objects
2996
3007
  valueFormatter: (params) => {
2997
3008
  if (params.value == null)
2998
- return "";
2999
- const types = ["number", "boolean", "string"];
3009
+ return '';
3010
+ const types = ['number', 'boolean', 'string'];
3000
3011
  if (types.includes(typeof params.value))
3001
3012
  return `${params.value}`;
3002
3013
  else
3003
3014
  return JSON.stringify(params.value);
3004
3015
  },
3005
3016
  ...props,
3006
- cellRenderer: typeof props.cellRenderer === "string" ? props.cellRenderer : GridCellRenderer,
3017
+ cellRenderer: typeof props.cellRenderer === 'string' ? props.cellRenderer : GridCellRenderer,
3007
3018
  cellRendererParams: {
3008
3019
  originalCellRenderer: props.cellRenderer,
3009
3020
  ...props.cellRendererParams,
@@ -3019,16 +3030,16 @@ const GenericCellEditorComponentWrapper = (editor) => {
3019
3030
  return forwardRef(function GenericCellEditorComponentFr(cellEditorParams, _) {
3020
3031
  const valueFormatted = cellEditorParams.formatValue
3021
3032
  ? cellEditorParams.formatValue(cellEditorParams.value)
3022
- : "Missing formatter";
3023
- return (jsxs(GridPopoverContextProvider, { props: cellEditorParams, children: [jsx(cellEditorParams.colDef.cellRenderer, { ...cellEditorParams, valueFormatted: valueFormatted, ...cellEditorParams.colDef.cellRendererParams }), obj.editor && jsx(obj.editor, { ...cellEditorParams })] }));
3033
+ : 'Missing formatter';
3034
+ return (jsx(GridPopoverContextProvider, { props: cellEditorParams, children: jsxs(Fragment, { children: [jsx(cellEditorParams.colDef.cellRenderer, { ...cellEditorParams, valueFormatted: valueFormatted, ...cellEditorParams.colDef.cellRendererParams }), obj.editor && jsx(obj.editor, { ...cellEditorParams })] }) }));
3024
3035
  });
3025
3036
  };
3026
3037
 
3027
- const GridCellFillerColId = "gridCellFiller";
3038
+ const GridCellFillerColId = 'gridCellFiller';
3028
3039
  const isGridCellFiller = (col) => col.colId === GridCellFillerColId;
3029
3040
  const GridCellFiller = () => ({
3030
3041
  colId: GridCellFillerColId,
3031
- headerName: "",
3042
+ headerName: '',
3032
3043
  flex: 1,
3033
3044
  });
3034
3045
 
@@ -3046,8 +3057,27 @@ const GridCellMultiEditor = (props, cellEditorSelector) => GridCell({
3046
3057
  ...props,
3047
3058
  });
3048
3059
 
3049
- const GridFilterHeaderIconButton = forwardRef(function columnsButton({ icon, title, onClick, buttonProps, disabled = false, size = "md" }, ref) {
3050
- return (jsx(LuiButton, { ...buttonProps, type: "button", level: "tertiary", className: "lui-button-icon-only", ref: ref, buttonProps: { "aria-label": title }, title: title, onClick: onClick, disabled: disabled, children: jsx(LuiIcon, { name: icon, alt: "Menu", size: size }) }));
3060
+ const useGridFilter = (filter) => {
3061
+ const { addExternalFilter, removeExternalFilter } = useContext(GridContext);
3062
+ useEffect(() => {
3063
+ const thisFilter = filter;
3064
+ thisFilter && addExternalFilter(thisFilter);
3065
+ return () => {
3066
+ thisFilter && removeExternalFilter(thisFilter);
3067
+ };
3068
+ }, [addExternalFilter, filter, removeExternalFilter]);
3069
+ };
3070
+
3071
+ const GridFilterButtons = ({ className, luiButtonProps, options, }) => {
3072
+ // Select defaultSelected option, otherwise first option. If no options select none.
3073
+ const [selectedOption, setSelectedOption] = useState(options.find((option) => option.defaultSelected) ?? options[0]);
3074
+ const filter = useMemo(() => selectedOption?.filter, [selectedOption]);
3075
+ useGridFilter(filter);
3076
+ return (jsx("div", { className: clsx(className, 'flex-col-center'), children: jsx(LuiButtonGroup, { children: options.map((option, index) => (jsx(LuiButton, { ...luiButtonProps, className: clsx(`lui-button lui-button-secondary`, selectedOption?.label === option.label && `lui-button-active`, luiButtonProps?.className), onClick: () => setSelectedOption(option), children: option.label }, `${index}`))) }) }));
3077
+ };
3078
+
3079
+ const GridFilterHeaderIconButton = forwardRef(function columnsButton({ icon, title, onClick, buttonProps, disabled = false, size = 'md' }, ref) {
3080
+ return (jsx(LuiButton, { ...buttonProps, type: 'button', level: 'tertiary', className: 'lui-button-icon-only', ref: ref, buttonProps: { 'aria-label': title }, title: title, onClick: onClick, disabled: disabled, children: jsx(LuiIcon, { name: icon, alt: 'Menu', size: size }) }));
3051
3081
  });
3052
3082
 
3053
3083
  const GridFilterColumnsToggle = ({ saveState = true }) => {
@@ -3055,9 +3085,9 @@ const GridFilterColumnsToggle = ({ saveState = true }) => {
3055
3085
  const { getColumns, getColumnIds, invisibleColumnIds, setInvisibleColumnIds } = useContext(GridContext);
3056
3086
  const columnStorageKey = useMemo(() => isEmpty(getColumnIds())
3057
3087
  ? null // Grid hasn't been initialised yet
3058
- : "stepAgGrid_invisibleColumnIds_" + getColumnIds().join("_"), [getColumnIds]);
3088
+ : 'stepAgGrid_invisibleColumnIds_' + getColumnIds().join('_'), [getColumnIds]);
3059
3089
  // infer the invisible ids from colDefs
3060
- const resetColumns = useCallback(() => setInvisibleColumnIds(getColumnIds("initialHide")), [getColumnIds, setInvisibleColumnIds]);
3090
+ const resetColumns = useCallback(() => setInvisibleColumnIds(getColumnIds('initialHide')), [getColumnIds, setInvisibleColumnIds]);
3061
3091
  // Load state on start
3062
3092
  useEffect(() => {
3063
3093
  if (!columnStorageKey || loaded)
@@ -3069,11 +3099,11 @@ const GridFilterColumnsToggle = ({ saveState = true }) => {
3069
3099
  resetColumns();
3070
3100
  }
3071
3101
  else {
3072
- const invisibleIds = JSON.parse(stored ?? "[]");
3102
+ const invisibleIds = JSON.parse(stored ?? '[]');
3073
3103
  if (!Array.isArray(invisibleIds)) {
3074
3104
  console.error(`stored invisible ids not an array: ${stored}`);
3075
3105
  }
3076
- else if (!invisibleIds.every((id) => typeof id === "string")) {
3106
+ else if (!invisibleIds.every((id) => typeof id === 'string')) {
3077
3107
  console.error(`stored invisible ids not strings: ${stored}`);
3078
3108
  }
3079
3109
  else {
@@ -3103,15 +3133,15 @@ const GridFilterColumnsToggle = ({ saveState = true }) => {
3103
3133
  }, [invisibleColumnIds, setInvisibleColumnIds]);
3104
3134
  const numericRegExp = /^\d+$/;
3105
3135
  const isNonManageableColumn = (col) => col.lockVisible || col.colId == null || numericRegExp.test(col.colId);
3106
- return (jsxs(Menu, { menuButton: jsx(GridFilterHeaderIconButton, { icon: "ic_columns", title: "Column visibility" }), menuClassName: "step-ag-grid-react-menu", portal: true, unmountOnClose: true, children: [jsx("div", { className: "GridFilterColumnsToggle-container", children: getColumns("headerName").map((col) => (jsx(MenuItem, { disabled: isNonManageableColumn(col), onClick: (e) => {
3136
+ return (jsxs(Menu, { menuButton: jsx(GridFilterHeaderIconButton, { icon: 'ic_columns', title: 'Column visibility' }), menuClassName: 'step-ag-grid-react-menu', portal: true, unmountOnClose: true, children: [jsx("div", { className: 'GridFilterColumnsToggle-container', children: getColumns('headerName').map((col) => (jsx(MenuItem, { disabled: isNonManageableColumn(col), onClick: (e) => {
3107
3137
  // Global react-menu MenuItem handler handles tabs
3108
- if (e.key !== "Tab") {
3138
+ if (e.key !== 'Tab') {
3109
3139
  e.keepOpen = true;
3110
- if (e.key !== "Enter") {
3140
+ if (e.key !== 'Enter') {
3111
3141
  toggleColumn(col.colId);
3112
3142
  }
3113
3143
  }
3114
- }, children: jsx(LuiCheckboxInput, { isChecked: !!invisibleColumnIds && !invisibleColumnIds.includes(col.colId ?? ""), value: `${col.colId}`, label: col.headerName ?? "", isDisabled: isNonManageableColumn(col), inputProps: {
3144
+ }, children: jsx(LuiCheckboxInput, { isChecked: !!invisibleColumnIds && !invisibleColumnIds.includes(col.colId ?? ''), value: `${col.colId}`, label: col.headerName ?? '', isDisabled: isNonManageableColumn(col), inputProps: {
3115
3145
  onClick: (e) => {
3116
3146
  // Click is handled by MenuItem onClick so keyboard events work
3117
3147
  e.preventDefault();
@@ -3119,47 +3149,15 @@ const GridFilterColumnsToggle = ({ saveState = true }) => {
3119
3149
  },
3120
3150
  }, onChange: () => {
3121
3151
  /*Do nothing, change handled by menuItem*/
3122
- } }) }, col.colId ?? "no_col_id"))) }), jsx(MenuDivider, {}, `$$divider_reset_columns`), jsxs(MenuItem, { onClick: (e) => {
3152
+ } }) }, col.colId ?? 'no_col_id'))) }), jsx(MenuDivider, {}, `$$divider_reset_columns`), jsxs(MenuItem, { onClick: (e) => {
3123
3153
  // Global react-menu MenuItem handler handles tabs
3124
- if (e.key !== "Tab") {
3125
- e.keepOpen = e.key !== "Enter";
3154
+ if (e.key !== 'Tab') {
3155
+ e.keepOpen = e.key !== 'Enter';
3126
3156
  resetColumns();
3127
3157
  }
3128
- }, children: [jsx(LuiIcon, { name: "ic_regenerate", alt: "Reset columns", size: "md", className: "MenuItem-icon" }), "Reset columns"] }, "$$reset_columns")] }));
3129
- };
3130
-
3131
- const useGridFilter = (filter) => {
3132
- const { addExternalFilter, removeExternalFilter } = useContext(GridContext);
3133
- useEffect(() => {
3134
- const thisFilter = filter;
3135
- thisFilter && addExternalFilter(thisFilter);
3136
- return () => {
3137
- thisFilter && removeExternalFilter(thisFilter);
3138
- };
3139
- }, [addExternalFilter, filter, removeExternalFilter]);
3140
- };
3141
-
3142
- const GridFilterButtons = ({ className, luiButtonProps, options, }) => {
3143
- // Select defaultSelected option, otherwise first option. If no options select none.
3144
- const [selectedOption, setSelectedOption] = useState(options.find((option) => option.defaultSelected) ?? options[0]);
3145
- const filter = useMemo(() => selectedOption?.filter, [selectedOption]);
3146
- useGridFilter(filter);
3147
- return (jsx("div", { className: clsx(className, "flex-col-center"), children: jsx(LuiButtonGroup, { children: options.map((option, index) => (jsx(LuiButton, { ...luiButtonProps, className: clsx(`lui-button lui-button-secondary`, selectedOption?.label === option.label && `lui-button-active`, luiButtonProps?.className), onClick: () => setSelectedOption(option), children: option.label }, `${index}`))) }) }));
3148
- };
3149
-
3150
- const GridFilterQuick = ({ quickFilterPlaceholder, defaultValue }) => {
3151
- const { setQuickFilter } = useContext(GridContext);
3152
- const [quickFilterValue, setQuickFilterValue] = useState(defaultValue ?? "");
3153
- useEffect(() => {
3154
- setQuickFilter(quickFilterValue);
3155
- }, [quickFilterValue, setQuickFilter]);
3156
- return (jsxs("div", { className: "GridFilterQuick-container", children: [jsx("div", { className: "GridFilterQuick-icon", children: jsx(LuiIcon, { name: "ic_search", alt: "Search", size: "md" }) }), jsx("input", { "aria-label": "Search", className: "GridFilterQuick-input", type: "text", placeholder: quickFilterPlaceholder ?? "Search", value: quickFilterValue, onChange: (event) => {
3157
- setQuickFilterValue(event.target.value);
3158
- } })] }));
3158
+ }, children: [jsx(LuiIcon, { name: 'ic_regenerate', alt: 'Reset columns', size: 'md', className: 'MenuItem-icon' }), "Reset columns"] }, '$$reset_columns')] }));
3159
3159
  };
3160
3160
 
3161
- const GridFilters = ({ children }) => (jsx("div", { className: "Grid-container-filters", children: children }));
3162
-
3163
3161
  /**
3164
3162
  * Cancels timeouts on scope being destroyed.
3165
3163
  *
@@ -3226,12 +3224,25 @@ const GridFilterDownloadCsvButton = (csvExportParams) => {
3226
3224
  }, 100);
3227
3225
  };
3228
3226
  return downloading ? (jsx(LuiMiniSpinner, { size: 22, divProps: {
3229
- role: "status",
3230
- ["aria-label"]: "Downloading...",
3231
- style: { width: 42, display: "flex", justifyContent: "center" },
3232
- } })) : (jsx(GridFilterHeaderIconButton, { icon: "ic_csv_file", title: "Download CSV", onClick: handleDownloadClick, disabled: downloading }));
3227
+ role: 'status',
3228
+ ['aria-label']: 'Downloading...',
3229
+ style: { width: 42, display: 'flex', justifyContent: 'center' },
3230
+ } })) : (jsx(GridFilterHeaderIconButton, { icon: 'ic_csv_file', title: 'Download CSV', onClick: handleDownloadClick, disabled: downloading }));
3231
+ };
3232
+
3233
+ const GridFilterQuick = ({ quickFilterPlaceholder, defaultValue }) => {
3234
+ const { setQuickFilter } = useContext(GridContext);
3235
+ const [quickFilterValue, setQuickFilterValue] = useState(defaultValue ?? '');
3236
+ useEffect(() => {
3237
+ setQuickFilter(quickFilterValue);
3238
+ }, [quickFilterValue, setQuickFilter]);
3239
+ return (jsxs("div", { className: "GridFilterQuick-container", children: [jsx("div", { className: "GridFilterQuick-icon", children: jsx(LuiIcon, { name: 'ic_search', alt: 'Search', size: 'md' }) }), jsx("input", { "aria-label": "Search", className: "GridFilterQuick-input", type: "text", placeholder: quickFilterPlaceholder ?? 'Search', value: quickFilterValue, onChange: (event) => {
3240
+ setQuickFilterValue(event.target.value);
3241
+ } })] }));
3233
3242
  };
3234
3243
 
3244
+ const GridFilters = ({ children }) => (jsx("div", { className: "Grid-container-filters", children: children }));
3245
+
3235
3246
  /* global setTimeout, clearTimeout */
3236
3247
 
3237
3248
  var dist = function debounce(fn) {
@@ -3307,16 +3318,17 @@ function defer() {
3307
3318
  var debounce = /*@__PURE__*/getDefaultExportFromCjs(dist);
3308
3319
 
3309
3320
  const GridSubComponentContext = createContext({
3310
- value: "GridSubComponentContext value no context",
3321
+ value: 'GridSubComponentContext value no context',
3311
3322
  data: {},
3312
3323
  setValue: () => {
3313
- console.error("GridSubComponentContext setValue no context");
3324
+ console.error('GridSubComponentContext setValue no context');
3314
3325
  },
3315
3326
  setValid: () => {
3316
- console.error("GridSubComponentContext setValid no context");
3327
+ console.error('GridSubComponentContext setValid no context');
3317
3328
  },
3329
+ // eslint-disable-next-line @typescript-eslint/require-await
3318
3330
  triggerSave: async () => {
3319
- console.error("GridSubComponentContext triggerSave no context");
3331
+ console.error('GridSubComponentContext triggerSave no context');
3320
3332
  },
3321
3333
  context: null,
3322
3334
  });
@@ -3352,7 +3364,7 @@ var css_248z$2 = ".FormError{display:flex}.FormError-helpText{color:#6b6966;font
3352
3364
  styleInject(css_248z$2);
3353
3365
 
3354
3366
  const FormError = (props) => {
3355
- return (jsxs(Fragment, { children: [props.error && (jsxs("div", { className: "FormError", children: [jsx(LuiIcon, { alt: "error", name: "ic_error", className: "FormError-text-icon", size: "sm", status: "error" }), jsx("span", { className: "FormError-error", children: props.error })] })), props.helpText && !props.error && jsx("span", { className: "FormError-helpText", children: props.helpText })] }));
3367
+ return (jsxs(Fragment, { children: [props.error && (jsxs("div", { className: "FormError", children: [jsx(LuiIcon, { alt: "error", name: "ic_error", className: "FormError-text-icon", size: "sm", status: "error" }), jsx("span", { className: "FormError-error", children: props.error })] })), props.helpText && !props.error && jsx("span", { className: 'FormError-helpText', children: props.helpText })] }));
3356
3368
  };
3357
3369
 
3358
3370
  function escapeStringRegexp(string) {
@@ -3492,18 +3504,18 @@ const textMatch = (text, filter) => {
3492
3504
  if (text == null)
3493
3505
  return true;
3494
3506
  const superFilters = filter
3495
- .split(",")
3507
+ .split(',')
3496
3508
  .map((sf) => sf.trim())
3497
3509
  .filter((sf) => sf)
3498
3510
  .map((r) => r
3499
3511
  .split(/\s+/)
3500
- .map((f) => (f.startsWith("=") ? f.slice(1) : f + "*"))
3501
- .join(" "));
3502
- const [negativeFilters, positiveFilters] = partition(superFilters, (superFilters) => superFilters.startsWith("!"));
3503
- const values = text.replaceAll(",", " ").trim().split(/\s+/);
3512
+ .map((f) => (f.startsWith('=') ? f.slice(1) : f + '*'))
3513
+ .join(' '));
3514
+ const [negativeFilters, positiveFilters] = partition(superFilters, (superFilters) => superFilters.startsWith('!'));
3515
+ const values = text.replaceAll(',', ' ').trim().split(/\s+/);
3504
3516
  return ((isEmpty(positiveFilters) || // Not filtered
3505
3517
  positiveFilters.some((superFilter) => {
3506
- const subFilters = superFilter.split(/\s+/).map((s) => s.replaceAll(/([!?])/g, "\\$1"));
3518
+ const subFilters = superFilter.split(/\s+/).map((s) => s.replaceAll(/([!?])/g, '\\$1'));
3507
3519
  return subFilters.every((subFilter) => values.some((value) => isMatch(value, subFilter)));
3508
3520
  })) &&
3509
3521
  (isEmpty(negativeFilters) ||
@@ -3540,19 +3552,19 @@ const useGridPopoverHook = (props) => {
3540
3552
  }
3541
3553
  }, [cancelEdit, props, stopEditing, updateValue]);
3542
3554
  const popoverWrapper = useCallback((children) => {
3543
- return (jsx(Fragment, { children: anchorRef.current && (jsxs(ControlledMenu, { state: isOpen ? "open" : "closed", portal: true, unmountOnClose: true, anchorRef: anchorRef, saveButtonRef: saveButtonRef, menuClassName: "step-ag-grid-react-menu", onClose: (event) => {
3555
+ return (jsx(Fragment, { children: anchorRef.current && (jsxs(ControlledMenu, { state: isOpen ? 'open' : 'closed', portal: true, unmountOnClose: true, anchorRef: anchorRef, saveButtonRef: saveButtonRef, menuClassName: 'step-ag-grid-react-menu', onClose: (event) => {
3544
3556
  // Prevent menu from closing when modals are invoked
3545
3557
  if (event.reason === CloseReason.BLUR)
3546
3558
  return;
3547
- triggerSave(event.reason).then();
3548
- }, viewScroll: "auto", dontShrinkIfDirectionIsTop: true, className: props.className, children: [saving && ( // This is the overlay that prevents editing when the editor is saving
3549
- jsx("div", { className: "ComponentLoadingWrapper-saveOverlay" })), children, jsx("button", { ref: saveButtonRef, "data-reason": "", onClick: (e) => {
3550
- let reason = e.currentTarget.getAttribute("data-reason") ?? undefined;
3559
+ void triggerSave(event.reason);
3560
+ }, viewScroll: 'auto', dontShrinkIfDirectionIsTop: true, className: props.className, children: [saving && ( // This is the overlay that prevents editing when the editor is saving
3561
+ jsx("div", { className: 'ComponentLoadingWrapper-saveOverlay' })), children, jsx("button", { ref: saveButtonRef, "data-reason": '', onClick: (e) => {
3562
+ let reason = e.currentTarget.getAttribute('data-reason') ?? undefined;
3551
3563
  if (props.dontSaveOnExternalClick && reason === CloseReason.BLUR) {
3552
3564
  reason = CloseReason.CANCEL;
3553
3565
  }
3554
- triggerSave(reason).then();
3555
- }, style: { display: "none" } })] })) }));
3566
+ void triggerSave(reason);
3567
+ }, style: { display: 'none' } })] })) }));
3556
3568
  }, [anchorRef, isOpen, props.className, props.dontSaveOnExternalClick, saving, triggerSave]);
3557
3569
  return {
3558
3570
  popoverWrapper,
@@ -3560,19 +3572,19 @@ const useGridPopoverHook = (props) => {
3560
3572
  };
3561
3573
  };
3562
3574
 
3563
- const MenuSeparatorString = "_____MENU_SEPARATOR_____";
3575
+ const MenuSeparatorString = '_____MENU_SEPARATOR_____';
3564
3576
  const MenuSeparator = Object.freeze({ value: MenuSeparatorString });
3565
- const MenuHeaderString = "_____MENU_HEADER_____";
3577
+ const MenuHeaderString = '_____MENU_HEADER_____';
3566
3578
  const MenuHeaderItem = (title) => {
3567
3579
  return { label: title, value: MenuHeaderString };
3568
3580
  };
3569
3581
  const fieldToString = (field) => {
3570
- return typeof field == "symbol" ? field.toString() : `${field}`;
3582
+ return typeof field === 'symbol' ? field.toString() : `${field}`;
3571
3583
  };
3572
3584
  const GridFormDropDown = (props) => {
3573
3585
  const { selectedRows, field, data } = useGridPopoverContext();
3574
3586
  // Save triggers during async action processing which triggers another selectItem(), this ref blocks that
3575
- const [filter, setFilter] = useState(props.filterDefaultValue ?? "");
3587
+ const [filter, setFilter] = useState(props.filterDefaultValue ?? '');
3576
3588
  const [filteredValues, setFilteredValues] = useState();
3577
3589
  const [options, setOptions] = useState(null);
3578
3590
  const subComponentIsValid = useRef(false);
@@ -3603,12 +3615,12 @@ const GridFormDropDown = (props) => {
3603
3615
  if (options)
3604
3616
  return;
3605
3617
  let optionsConf = props.options;
3606
- (async () => {
3607
- if (typeof optionsConf == "function") {
3618
+ void (async () => {
3619
+ if (typeof optionsConf === 'function') {
3608
3620
  optionsConf = await optionsConf(selectedRows, filter);
3609
3621
  }
3610
3622
  if (optionsConf !== undefined) {
3611
- const optionsList = optionsConf?.map((item) => item == null || typeof item == "string"
3623
+ const optionsList = optionsConf?.map((item) => item == null || typeof item === 'string'
3612
3624
  ? {
3613
3625
  value: item,
3614
3626
  label: item,
@@ -3621,16 +3633,16 @@ const GridFormDropDown = (props) => {
3621
3633
  }, [filter, options, props, selectedRows]);
3622
3634
  // Local filtering.
3623
3635
  useEffect(() => {
3624
- if (props.filtered == "local") {
3636
+ if (props.filtered == 'local') {
3625
3637
  if (options == null)
3626
3638
  return;
3627
3639
  setFilteredValues(options
3628
3640
  .map((option) => {
3629
- if (option.label != null && typeof option.label !== "string") {
3630
- console.error("Cannot filter non-string labels", option);
3641
+ if (option.label != null && typeof option.label !== 'string') {
3642
+ console.error('Cannot filter non-string labels', option);
3631
3643
  return undefined;
3632
3644
  }
3633
- return textMatch(option.label || "", filter) ? option : undefined;
3645
+ return textMatch(option.label || '', filter) ? option : undefined;
3634
3646
  })
3635
3647
  .filter((r) => r !== undefined));
3636
3648
  }
@@ -3641,9 +3653,9 @@ const GridFormDropDown = (props) => {
3641
3653
  const previousFilter = useRef(filter);
3642
3654
  // Reload filtering.
3643
3655
  useEffect(() => {
3644
- if (previousFilter.current != filter && props.filtered == "reload") {
3656
+ if (previousFilter.current != filter && props.filtered == 'reload') {
3645
3657
  previousFilter.current = filter;
3646
- reSearchOnFilterChange().then();
3658
+ void reSearchOnFilterChange();
3647
3659
  }
3648
3660
  }, [filter, props, reSearchOnFilterChange]);
3649
3661
  /**
@@ -3681,12 +3693,12 @@ const GridFormDropDown = (props) => {
3681
3693
  });
3682
3694
  let lastHeader = null;
3683
3695
  let showHeader = null;
3684
- return popoverWrapper(jsxs(Fragment, { children: [props.filtered && (jsxs("div", { className: "GridFormDropDown-filter", children: [jsx(FocusableItem, { className: "filter-item", onFocus: () => {
3696
+ return popoverWrapper(jsxs(Fragment, { children: [props.filtered && (jsxs("div", { className: 'GridFormDropDown-filter', children: [jsx(FocusableItem, { className: 'filter-item', onFocus: () => {
3685
3697
  setSelectedItem(null);
3686
3698
  setSubSelectedValue(null);
3687
3699
  subComponentIsValid.current = true;
3688
- }, children: ({ ref }) => (jsxs("div", { style: { display: "flex", flexDirection: "column", width: "100%" }, children: [jsx("input", { className: "LuiTextInput-input", ref: ref, type: "text", placeholder: props.filterPlaceholder ?? "Filter...", "data-testid": "filteredMenu-free-text-input", defaultValue: filter, "data-allowtabtosave": true, "data-disableenterautosave": !props.onSelectFilter &&
3689
- !(filteredValues && filteredValues.length === 1 && !filteredValues[0].subComponent), onChange: (e) => setFilter(e.target.value) }), props.filterHelpText && isNotEmpty(filter) && (jsx(FormError, { error: null, helpText: props.filterHelpText }))] })) }), jsx(MenuDivider, {}, `$$divider_filter`)] })), jsx(ComponentLoadingWrapper, { loading: !options, className: "GridFormDropDown-options", children: jsxs(Fragment, { children: [options && (isEmpty(options) || (filteredValues && isEmpty(filteredValues))) && (jsx(MenuItem, { className: "GridPopoverEditDropDown-noOptions", disabled: true, children: props.noOptionsMessage ?? "No Options" }, `${fieldToString(field)}-empty`)), options?.map((item, index) => {
3700
+ }, children: ({ ref }) => (jsxs("div", { style: { display: 'flex', flexDirection: 'column', width: '100%' }, children: [jsx("input", { className: 'LuiTextInput-input', ref: ref, type: "text", placeholder: props.filterPlaceholder ?? 'Filter...', "data-testid": 'filteredMenu-free-text-input', defaultValue: filter, "data-allowtabtosave": true, "data-disableenterautosave": !props.onSelectFilter &&
3701
+ !(filteredValues && filteredValues.length === 1 && !filteredValues[0].subComponent), onChange: (e) => setFilter(e.target.value) }), props.filterHelpText && isNotEmpty(filter) && (jsx(FormError, { error: null, helpText: props.filterHelpText }))] })) }), jsx(MenuDivider, {}, `$$divider_filter`)] })), jsx(ComponentLoadingWrapper, { loading: !options, className: 'GridFormDropDown-options', children: jsxs(Fragment, { children: [options && (isEmpty(options) || (filteredValues && isEmpty(filteredValues))) && (jsx(MenuItem, { className: 'GridPopoverEditDropDown-noOptions', disabled: true, children: props.noOptionsMessage ?? 'No Options' }, `${fieldToString(field)}-empty`)), options?.map((item, index) => {
3690
3702
  showHeader = null;
3691
3703
  if (item.value === MenuSeparatorString) {
3692
3704
  return jsx(MenuDivider, {}, `$$divider_${index}`);
@@ -3701,7 +3713,7 @@ const GridFormDropDown = (props) => {
3701
3713
  lastHeader = null;
3702
3714
  }
3703
3715
  }
3704
- return ((!filteredValues || filteredValues.includes(item)) && (jsxs(Fragment$1, { children: [showHeader, jsxs("div", { children: [jsxs(MenuItem, { disabled: !!item.disabled, title: item.disabled && typeof item.disabled !== "boolean" ? item.disabled : "", value: item.value, onFocus: () => {
3716
+ return ((!filteredValues || filteredValues.includes(item)) && (jsxs(Fragment$1, { children: [showHeader, jsxs("div", { children: [jsxs(MenuItem, { disabled: !!item.disabled, title: item.disabled && typeof item.disabled !== 'boolean' ? item.disabled : '', value: item.value, onFocus: () => {
3705
3717
  if (selectedItem !== item) {
3706
3718
  setSelectedItem(item);
3707
3719
  setSubSelectedValue(null);
@@ -3712,7 +3724,7 @@ const GridFormDropDown = (props) => {
3712
3724
  }
3713
3725
  }, onClick: (e) => {
3714
3726
  e.keepOpen = !!item.subComponent;
3715
- }, children: [item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`), item.subComponent ? "..." : ""] }, `${fieldToString(field)}-${index}`), item.subComponent && selectedItem === item && (jsx(FocusableItem, { className: "LuiDeprecatedForms", children: () => (jsx(GridSubComponentContext.Provider, { value: {
3727
+ }, children: [item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`), item.subComponent ? '...' : ''] }, `${fieldToString(field)}-${index}`), item.subComponent && selectedItem === item && (jsx(FocusableItem, { className: 'LuiDeprecatedForms', children: () => (jsx(GridSubComponentContext.Provider, { value: {
3716
3728
  context: { options },
3717
3729
  data,
3718
3730
  value: subSelectedValue,
@@ -3729,7 +3741,7 @@ const GridFormDropDown = (props) => {
3729
3741
  triggerSave: async () => {
3730
3742
  // empty
3731
3743
  },
3732
- }, children: item.subComponent && (jsx("div", { className: "subComponent", children: jsx(item.subComponent, {}) })) })) }, `${item.label}_subcomponent`))] }, `menu-wrapper-${index}`)] }, `${index}`)));
3744
+ }, children: item.subComponent && (jsx("div", { className: 'subComponent', children: jsx(item.subComponent, {}) })) })) }, `${String(item.label)}_subcomponent`))] }, `menu-wrapper-${index}`)] }, `${index}`)));
3733
3745
  })] }) })] }));
3734
3746
  };
3735
3747
 
@@ -3737,45 +3749,45 @@ var css_248z$1 = ".LuiTextInput.GridLuiTextInput{margin-bottom:0}.LuiTextInput-f
3737
3749
  styleInject(css_248z$1);
3738
3750
 
3739
3751
  const TextInputFormatted = (props) => {
3740
- return (jsxs("div", { className: clsx("LuiTextInput GridLuiTextInput Grid-popoverContainer", props.error && "hasError", props.className), children: [jsxs("span", { className: "LuiTextInput-inputWrapper", children: [jsx("input", { type: "text", spellCheck: true, defaultValue: props.value, ...omit(props, ["error", "value", "helpText", "formatted", "className", "allowTabToSave"]), className: "LuiTextInput-input", onMouseEnter: (e) => {
3752
+ return (jsxs("div", { className: clsx('LuiTextInput GridLuiTextInput Grid-popoverContainer', props.error && 'hasError', props.className), children: [jsxs("span", { className: "LuiTextInput-inputWrapper", children: [jsx("input", { type: 'text', spellCheck: true, defaultValue: props.value, ...omit(props, ['error', 'value', 'helpText', 'formatted', 'className', 'allowTabToSave']), className: 'LuiTextInput-input', onMouseEnter: (e) => {
3741
3753
  e.currentTarget.focus();
3742
3754
  props.onMouseEnter && props.onMouseEnter(e);
3743
- }, "data-allowtabtosave": props.allowTabToSave }), jsx("span", { className: "LuiTextInput-formatted", children: props.formatted })] }), jsx(FormError, { error: props.error, helpText: props.helpText })] }));
3755
+ }, "data-allowtabtosave": props.allowTabToSave }), jsx("span", { className: 'LuiTextInput-formatted', children: props.formatted })] }), jsx(FormError, { error: props.error, helpText: props.helpText })] }));
3744
3756
  };
3745
3757
 
3746
3758
  const bearingValueFormatter = (value) => {
3747
- const safeValue = typeof value == "string" ? parseFloat(value) : value;
3759
+ const safeValue = typeof value === 'string' ? parseFloat(value) : value;
3748
3760
  if (safeValue == null) {
3749
- return "";
3761
+ return '';
3750
3762
  }
3751
3763
  return convertDDToDMS(safeValue, false);
3752
3764
  };
3753
3765
  const bearingCorrectionValueFormatter = (value) => {
3754
3766
  const safeValue = value;
3755
3767
  if (safeValue == null) {
3756
- return "";
3768
+ return '';
3757
3769
  }
3758
- if (typeof safeValue === "string") {
3770
+ if (typeof safeValue === 'string') {
3759
3771
  return convertDDToDMS(bearingNumberParser(safeValue), true, 4);
3760
3772
  }
3761
3773
  return convertDDToDMS(safeValue, true, 4);
3762
3774
  };
3763
3775
  const bearingNumberParser = (value) => {
3764
- if (value === "")
3776
+ if (value === '')
3765
3777
  return null;
3766
3778
  return parseFloat(value);
3767
3779
  };
3768
3780
  const validMaskForDmsBearing = /^((-)?\d+)?(\.([0-5](\d([0-5](\d(\d+)?)?)?)?)?)?$/;
3769
3781
  const bearingStringValidator = (value, customInvalid) => {
3770
3782
  value = value.trim();
3771
- if (value === "")
3783
+ if (value === '')
3772
3784
  return null;
3773
3785
  const match = value.match(validMaskForDmsBearing);
3774
3786
  if (!match)
3775
- return "Bearing must be a number in D.MMSSS format";
3787
+ return 'Bearing must be a number in D.MMSSS format';
3776
3788
  const decimalPart = match[4];
3777
3789
  if (decimalPart != null && decimalPart.length > 5) {
3778
- return "Bearing has a maximum of 5 decimal places";
3790
+ return 'Bearing has a maximum of 5 decimal places';
3779
3791
  }
3780
3792
  const bearing = parseFloat(value);
3781
3793
  return customInvalid ? customInvalid(bearing) : null;
@@ -3794,9 +3806,9 @@ const bearingStringValidator = (value, customInvalid) => {
3794
3806
  */
3795
3807
  const convertDDToDMS = (dd, showPositiveSymbol = true, trailingZeroDp = 2) => {
3796
3808
  if (dd == null)
3797
- return "";
3809
+ return '';
3798
3810
  // toFixed rounds parts up greater than 60, which has to be corrected below
3799
- const [bearingWholeString, bearingDecimalString] = dd.toFixed(5).split(".");
3811
+ const [bearingWholeString, bearingDecimalString] = dd.toFixed(5).split('.');
3800
3812
  let bearingWhole = Math.abs(parseInt(bearingWholeString));
3801
3813
  let minNumeric = parseInt(bearingDecimalString?.substring(0, 2));
3802
3814
  let secNumeric = parseInt(bearingDecimalString?.substring(2, 4));
@@ -3812,11 +3824,11 @@ const convertDDToDMS = (dd, showPositiveSymbol = true, trailingZeroDp = 2) => {
3812
3824
  if (bearingWhole >= 360) {
3813
3825
  bearingWhole -= 360;
3814
3826
  }
3815
- const minString = minNumeric.toString().padStart(2, "0");
3816
- const secString = secNumeric.toString().padStart(2, "0");
3827
+ const minString = minNumeric.toString().padStart(2, '0');
3828
+ const secString = secNumeric.toString().padStart(2, '0');
3817
3829
  const deciSecString = bearingDecimalString?.substring(4, 5);
3818
- let dmsString = `${showPositiveSymbol && dd > 0 ? "+" : ""}${dd < 0 ? "-" : ""}${bearingWhole}°`;
3819
- if (trailingZeroDp === 5 || deciSecString != "0") {
3830
+ let dmsString = `${showPositiveSymbol && dd > 0 ? '+' : ''}${dd < 0 ? '-' : ''}${bearingWhole}°`;
3831
+ if (trailingZeroDp === 5 || deciSecString != '0') {
3820
3832
  dmsString += `\xa0${minString}'\xa0${secString}.${deciSecString}"`; // "\xa0" is here for non-breaking space
3821
3833
  }
3822
3834
  else if (trailingZeroDp === 4 || secNumeric != 0) {
@@ -3829,27 +3841,27 @@ const convertDDToDMS = (dd, showPositiveSymbol = true, trailingZeroDp = 2) => {
3829
3841
  };
3830
3842
  const bearingRangeValidator = (value) => {
3831
3843
  if (value === null)
3832
- return "Bearing is required";
3844
+ return 'Bearing is required';
3833
3845
  if (value >= 360)
3834
- return "Bearing must be less than 360 degrees";
3846
+ return 'Bearing must be less than 360 degrees';
3835
3847
  if (value < 0)
3836
- return "Bearing must not be negative";
3848
+ return 'Bearing must not be negative';
3837
3849
  return null;
3838
3850
  };
3839
3851
  const bearingCorrectionRangeValidator = (value) => {
3840
3852
  if (value === null)
3841
- return "Bearing correction is required";
3853
+ return 'Bearing correction is required';
3842
3854
  if (value >= 360)
3843
- return "Bearing correction must be less than 360 degrees";
3855
+ return 'Bearing correction must be less than 360 degrees';
3844
3856
  if (value <= -180)
3845
- return "Bearing correction must be greater then -180 degrees";
3857
+ return 'Bearing correction must be greater then -180 degrees';
3846
3858
  return null;
3847
3859
  };
3848
3860
 
3849
3861
  const GridFormEditBearing = (props) => {
3850
3862
  const { field, value: initialValue } = useGridPopoverContext();
3851
3863
  // This clears out any scientific precision
3852
- const defaultValue = useMemo(() => (initialValue == null ? "" : parseFloat(parseFloat(initialValue).toFixed(10)).toString()), [initialValue]);
3864
+ const defaultValue = useMemo(() => (initialValue == null ? '' : parseFloat(parseFloat(initialValue).toFixed(10)).toString()), [initialValue]);
3853
3865
  const [value, setValue] = useState(defaultValue);
3854
3866
  const invalid = useCallback(() => bearingStringValidator(value, props.range), [props.range, value]);
3855
3867
  const save = useCallback(async (selectedRows) => {
@@ -3863,7 +3875,7 @@ const GridFormEditBearing = (props) => {
3863
3875
  }
3864
3876
  else {
3865
3877
  if (field == null) {
3866
- console.error("field is not defined in ColDef");
3878
+ console.error('field is not defined in ColDef');
3867
3879
  }
3868
3880
  else {
3869
3881
  selectedRows.forEach((row) => {
@@ -3878,11 +3890,11 @@ const GridFormEditBearing = (props) => {
3878
3890
  invalid,
3879
3891
  save,
3880
3892
  });
3881
- return popoverWrapper(jsx("div", { className: "GridFormEditBearing-input", children: jsx(TextInputFormatted, { value: defaultValue, onChange: (e) => {
3893
+ return popoverWrapper(jsx("div", { className: 'GridFormEditBearing-input', children: jsx(TextInputFormatted, { value: defaultValue, onChange: (e) => {
3882
3894
  setValue(e.target.value.trim());
3883
3895
  }, autoFocus: true, placeholder: props.placeHolder, formatted: bearingStringValidator(value, props.range) || !props.formatValue
3884
- ? "?"
3885
- : props.formatValue(bearingNumberParser(value)), error: bearingStringValidator(value, props.range), helpText: "Press enter or tab to save" }) }));
3896
+ ? '?'
3897
+ : props.formatValue(bearingNumberParser(value)), error: bearingStringValidator(value, props.range), helpText: 'Press enter or tab to save' }) }));
3886
3898
  };
3887
3899
 
3888
3900
  const GridFormMessage = (props) => {
@@ -3890,11 +3902,11 @@ const GridFormMessage = (props) => {
3890
3902
  const [message, setMessage] = useState(null);
3891
3903
  const { popoverWrapper } = useGridPopoverHook({ className: props.className });
3892
3904
  useEffect(() => {
3893
- (async () => {
3905
+ void (async () => {
3894
3906
  setMessage(await props.message(selectedRows));
3895
- })().then();
3907
+ })();
3896
3908
  }, [props, selectedRows]);
3897
- return popoverWrapper(jsx(ComponentLoadingWrapper, { loading: message === null, className: clsx("GridFormMessage-container", props.className), children: jsx(Fragment, { children: message }) }));
3909
+ return popoverWrapper(jsx(ComponentLoadingWrapper, { loading: message === null, className: clsx('GridFormMessage-container', props.className), children: jsx(Fragment, { children: message }) }));
3898
3910
  };
3899
3911
 
3900
3912
  const GridFormMultiSelect = (props) => {
@@ -3902,8 +3914,8 @@ const GridFormMultiSelect = (props) => {
3902
3914
  const subComponentIsValidRef = useRef({});
3903
3915
  const optionsInitialising = useRef(false);
3904
3916
  const firstInputSubComponent = useRef(null);
3905
- const [filter, setFilter] = useState("");
3906
- const [initialValues, setInitialValues] = useState("");
3917
+ const [filter, setFilter] = useState('');
3918
+ const [initialValues, setInitialValues] = useState('');
3907
3919
  const [options, setOptions] = useState();
3908
3920
  const invalid = useCallback(() => {
3909
3921
  if (!options)
@@ -3931,8 +3943,8 @@ const GridFormMultiSelect = (props) => {
3931
3943
  if (options || optionsInitialising.current)
3932
3944
  return;
3933
3945
  optionsInitialising.current = true;
3934
- (async () => {
3935
- const optionsList = typeof props.options === "function" ? await props.options(selectedRows) : props.options;
3946
+ void (async () => {
3947
+ const optionsList = typeof props.options === 'function' ? await props.options(selectedRows) : props.options;
3936
3948
  setInitialValues(JSON.stringify(optionsList));
3937
3949
  setOptions(optionsList);
3938
3950
  optionsInitialising.current = false;
@@ -3944,7 +3956,7 @@ const GridFormMultiSelect = (props) => {
3944
3956
  const headerGroups = useMemo(() => {
3945
3957
  if (!options)
3946
3958
  return undefined;
3947
- const result = groupBy(options.filter((o) => textMatch(o.label, filter) && o.value != null), "filter");
3959
+ const result = groupBy(options.filter((o) => textMatch(o.label, filter) && o.value != null), 'filter');
3948
3960
  // remove leading/trailing/duplicate dividers
3949
3961
  return fromPairs(toPairs(result).map(([key, arr]) => {
3950
3962
  let lastWasDivider = true;
@@ -3968,14 +3980,14 @@ const GridFormMultiSelect = (props) => {
3968
3980
  ];
3969
3981
  }));
3970
3982
  }, [filter, options]);
3971
- const headers = useMemo(() => props.headers ?? [{ header: "" }], [props.headers]);
3983
+ const headers = useMemo(() => props.headers ?? [{ header: '' }], [props.headers]);
3972
3984
  const { popoverWrapper, triggerSave } = useGridPopoverHook({
3973
3985
  className: props.className,
3974
3986
  invalid,
3975
3987
  save,
3976
3988
  });
3977
- return popoverWrapper(jsx(ComponentLoadingWrapper, { loading: !options, className: "GridFormMultiSelect-container", children: options && (jsxs(Fragment, { children: [props.filtered && (jsx(FilterInput, { headerGroups, options, setOptions, filter, setFilter, triggerSave, filterHelpText: props.filterHelpText, onSelectFilter: props.onSelectFilter, filterPlaceholder: props.filterPlaceholder })), headerGroups &&
3978
- (isEmpty(headerGroups) || !toPairs(headerGroups).some(([_, options]) => !isEmpty(options))) && (jsx(MenuItem, { className: "GridMultiSelect-noOptions", disabled: true, children: props.noOptionsMessage ?? "No Options" }, "noOptions")), headerGroups && !isEmpty(headerGroups) && (jsx("div", { className: "GridFormMultiSelect-options", children: headers.map((header, index) => {
3989
+ return popoverWrapper(jsx(ComponentLoadingWrapper, { loading: !options, className: 'GridFormMultiSelect-container', children: options && (jsxs(Fragment, { children: [props.filtered && (jsx(FilterInput, { headerGroups, options, setOptions, filter, setFilter, triggerSave, filterHelpText: props.filterHelpText, onSelectFilter: props.onSelectFilter, filterPlaceholder: props.filterPlaceholder })), headerGroups &&
3990
+ (isEmpty(headerGroups) || !toPairs(headerGroups).some(([_, options]) => !isEmpty(options))) && (jsx(MenuItem, { className: 'GridMultiSelect-noOptions', disabled: true, children: props.noOptionsMessage ?? 'No Options' }, 'noOptions')), headerGroups && !isEmpty(headerGroups) && (jsx("div", { className: 'GridFormMultiSelect-options', children: headers.map((header, index) => {
3979
3991
  const subOptions = headerGroups[`${header.filter}`];
3980
3992
  return (!isEmpty(subOptions) && (jsxs(Fragment$1, { children: [header.header && jsx(MenuHeader, { children: header.header }), subOptions.map((item, index) => item.value === MenuSeparatorString ? (jsx(MenuDivider, {}, `div_${index}`)) : (jsxs(Fragment$1, { children: [jsx(MenuRadioItem, { item: item, options: options, setOptions: setOptions, onChecked: () => {
3981
3993
  // Default to focus on first input in subComponent
@@ -4017,7 +4029,7 @@ const FilterInput = (props) => {
4017
4029
  return;
4018
4030
  const filterTrimmed = filter.trim();
4019
4031
  if (isEmpty(filterTrimmed)) {
4020
- triggerSave().then();
4032
+ void triggerSave();
4021
4033
  return;
4022
4034
  }
4023
4035
  const preFilterOptions = JSON.stringify(options);
@@ -4026,15 +4038,15 @@ const FilterInput = (props) => {
4026
4038
  if (preFilterOptions === JSON.stringify(options))
4027
4039
  return;
4028
4040
  setOptions([...options]);
4029
- setFilter("");
4041
+ setFilter('');
4030
4042
  }, [filter, onSelectFilter, options, setFilter, setOptions, triggerSave]);
4031
4043
  const handleKeyDown = useCallback((e) => {
4032
- if (e.key === "Enter") {
4044
+ if (e.key === 'Enter') {
4033
4045
  enterHasBeenPressed.current = true;
4034
4046
  }
4035
4047
  }, []);
4036
4048
  const handleKeyUp = useCallback((e) => {
4037
- if (e.key === "Enter") {
4049
+ if (e.key === 'Enter') {
4038
4050
  e.stopPropagation();
4039
4051
  e.preventDefault();
4040
4052
  if (e.ctrlKey)
@@ -4042,22 +4054,22 @@ const FilterInput = (props) => {
4042
4054
  else if (enterHasBeenPressed.current) {
4043
4055
  const filterTrimmed = filter.trim();
4044
4056
  if (isEmpty(filterTrimmed)) {
4045
- triggerSave().then();
4057
+ void triggerSave();
4046
4058
  return;
4047
4059
  }
4048
4060
  onSelectFilter && addCustomFilterValue();
4049
4061
  }
4050
4062
  lastKeyWasEnter.current = true;
4051
4063
  }
4052
- else if (e.key === "Control") {
4053
- lastKeyWasEnter.current && setFilter("");
4064
+ else if (e.key === 'Control') {
4065
+ lastKeyWasEnter.current && setFilter('');
4054
4066
  lastKeyWasEnter.current = false;
4055
4067
  }
4056
4068
  else {
4057
4069
  lastKeyWasEnter.current = false;
4058
4070
  }
4059
4071
  }, [addCustomFilterValue, filter, onSelectFilter, setFilter, toggleSelectAllVisible, triggerSave]);
4060
- return (jsxs(Fragment, { children: [jsx(FocusableItem, { className: "filter-item", children: (_) => (jsxs("div", { style: { width: "100%" }, className: "GridFormMultiSelect-filter", children: [jsx("input", { className: "LuiTextInput-input", type: "text", placeholder: filterPlaceholder ?? "Filter...", "data-testid": "filteredMenu-free-text-input", value: filter, "data-disableenterautosave": true, "data-allowtabtosave": true, onChange: (e) => setFilter(e.target.value), onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }), filterHelpText && (jsx(FormError, { error: null, helpText: typeof filterHelpText === "function" ? filterHelpText(filter.trim(), options) : filterHelpText }))] })) }, "filter"), jsx(MenuDivider, {}, `$$divider_filter`)] }));
4072
+ return (jsxs(Fragment, { children: [jsx(FocusableItem, { className: 'filter-item', children: (_) => (jsxs("div", { style: { width: '100%' }, className: 'GridFormMultiSelect-filter', children: [jsx("input", { className: 'LuiTextInput-input', type: "text", placeholder: filterPlaceholder ?? 'Filter...', "data-testid": 'filteredMenu-free-text-input', value: filter, "data-disableenterautosave": true, "data-allowtabtosave": true, onChange: (e) => setFilter(e.target.value), onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }), filterHelpText && (jsx(FormError, { error: null, helpText: typeof filterHelpText === 'function' ? filterHelpText(filter.trim(), options) : filterHelpText }))] })) }, 'filter'), jsx(MenuDivider, {}, `$$divider_filter`)] }));
4061
4073
  };
4062
4074
  const MenuRadioItem = (props) => {
4063
4075
  const { item, options, setOptions } = props;
@@ -4067,12 +4079,12 @@ const MenuRadioItem = (props) => {
4067
4079
  }, [options, setOptions]);
4068
4080
  return (jsx(MenuItem, { onClick: (e) => {
4069
4081
  // Global react-menu MenuItem handler handles tabs
4070
- if (e.key !== "Tab" && e.key !== "Enter") {
4082
+ if (e.key !== 'Tab' && e.key !== 'Enter') {
4071
4083
  e.keepOpen = true;
4072
4084
  toggleValue(item);
4073
4085
  }
4074
4086
  item.checked && props.onChecked && props.onChecked();
4075
- }, children: jsx(LuiCheckboxInput, { isChecked: item.checked ?? false, value: `${item.value}`, label: jsxs(Fragment, { children: [item.warning && jsx(GridIcon, { icon: "ic_warning_outline", title: item.warning }), item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)] }), inputProps: {
4087
+ }, children: jsx(LuiCheckboxInput, { isChecked: item.checked ?? false, value: `${item.value}`, label: jsxs(Fragment, { children: [item.warning && jsx(GridIcon, { icon: 'ic_warning_outline', title: item.warning }), item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)] }), inputProps: {
4076
4088
  onClick: (e) => {
4077
4089
  // Click is handled by MenuItem onClick
4078
4090
  e.preventDefault();
@@ -4088,8 +4100,8 @@ function MenuSubComponentFr(props, ref) {
4088
4100
  const focusableRef = React.useRef(null);
4089
4101
  useEffect(() => {
4090
4102
  if (focusableRef.current) {
4091
- const firstInputElement = focusableRef.current.querySelectorAll("input")[0] ?? null;
4092
- if (typeof ref === "function") {
4103
+ const firstInputElement = focusableRef.current.querySelectorAll('input')[0] ?? null;
4104
+ if (typeof ref === 'function') {
4093
4105
  ref(firstInputElement);
4094
4106
  }
4095
4107
  else if (ref) {
@@ -4097,7 +4109,7 @@ function MenuSubComponentFr(props, ref) {
4097
4109
  }
4098
4110
  }
4099
4111
  }, [ref]);
4100
- return (jsx(FocusableItem, { className: "LuiDeprecatedForms", ref: focusableRef, children: () => (jsx(GridSubComponentContext.Provider, { value: {
4112
+ return (jsx(FocusableItem, { className: 'LuiDeprecatedForms', ref: focusableRef, children: () => (jsx(GridSubComponentContext.Provider, { value: {
4101
4113
  context: { options },
4102
4114
  data,
4103
4115
  value: item.subValue,
@@ -4109,7 +4121,7 @@ function MenuSubComponentFr(props, ref) {
4109
4121
  subComponentIsValid[`${item.value}`] = valid;
4110
4122
  },
4111
4123
  triggerSave,
4112
- }, children: jsx("div", { className: "subComponent", children: item.subComponent && jsx(item.subComponent, {}) }) })) }, `${item.value}_subcomponent`));
4124
+ }, children: jsx("div", { className: 'subComponent', children: item.subComponent && jsx(item.subComponent, {}) }) })) }, `${item.value}_subcomponent`));
4113
4125
  }
4114
4126
 
4115
4127
  const GridFormMultiSelectGrid = (props) => {
@@ -4154,33 +4166,33 @@ const GridFormMultiSelectGrid = (props) => {
4154
4166
  if (options || optionsInitialising.current)
4155
4167
  return;
4156
4168
  optionsInitialising.current = true;
4157
- (async () => {
4158
- const optionsList = typeof props.options === "function" ? await props.options(selectedRows) : props.options;
4159
- setInitialValues(optionsList.map((o) => ({ ...o, label: "" })));
4169
+ void (async () => {
4170
+ const optionsList = typeof props.options === 'function' ? await props.options(selectedRows) : props.options;
4171
+ setInitialValues(optionsList.map((o) => ({ ...o, label: '' })));
4160
4172
  setOptions(optionsList);
4161
4173
  optionsInitialising.current = false;
4162
4174
  })();
4163
4175
  }, [options, props, selectedRows]);
4164
4176
  const toggleValue = useCallback((item) => {
4165
4177
  if (options) {
4166
- item.checked = item.checked === true && item.canSelectPartial ? "partial" : !item.checked;
4178
+ item.checked = item.checked === true && item.canSelectPartial ? 'partial' : !item.checked;
4167
4179
  setOptions([...options]);
4168
4180
  }
4169
4181
  }, [options, setOptions]);
4170
- return popoverWrapper(jsx(Fragment, { children: jsx("div", { className: "Grid-popoverContainer", children: jsx("div", { style: {
4171
- display: "grid",
4172
- gridAutoFlow: "column",
4182
+ return popoverWrapper(jsx(Fragment, { children: jsx("div", { className: 'Grid-popoverContainer', children: jsx("div", { style: {
4183
+ display: 'grid',
4184
+ gridAutoFlow: 'column',
4173
4185
  gridTemplateRows: `repeat(${props.maxRowCount ?? 10}, auto)`,
4174
- maxWidth: "calc(min(100vw,500px))",
4175
- overflowX: "auto",
4186
+ maxWidth: 'calc(min(100vw,500px))',
4187
+ overflowX: 'auto',
4176
4188
  }, children: options &&
4177
4189
  options.map((o) => (jsx(Fragment, { children: jsx(MenuItem, { onClick: (e) => {
4178
4190
  // Global react-menu MenuItem handler handles tabs
4179
- if (e.key !== "Tab" && e.key !== "Enter") {
4191
+ if (e.key !== 'Tab' && e.key !== 'Enter') {
4180
4192
  e.keepOpen = true;
4181
4193
  toggleValue(o);
4182
4194
  }
4183
- }, children: jsx(LuiCheckboxInput, { isChecked: !!o.checked, isIndeterminate: o.checked === "partial", value: `${o.value}`, label: jsxs(Fragment, { children: [o.warning && jsx(GridIcon, { icon: "ic_warning_outline", title: o.warning }, "$$icon$$"), jsx("span", { className: "GridMultiSelectGrid-Label", children: o.label ?? (o.value == null ? `<${o.value}>` : `${o.value}`) }, "$$label$$")] }), inputProps: {
4195
+ }, children: jsx(LuiCheckboxInput, { isChecked: !!o.checked, isIndeterminate: o.checked === 'partial', value: `${o.value}`, label: jsxs(Fragment, { children: [o.warning && jsx(GridIcon, { icon: 'ic_warning_outline', title: o.warning }, '$$icon$$'), jsx("span", { className: 'GridMultiSelectGrid-Label', children: o.label ?? (o.value == null ? `<${o.value}>` : `${o.value}`) }, '$$label$$')] }), inputProps: {
4184
4196
  onClick: (e) => {
4185
4197
  // Click is handled by MenuItem onClick
4186
4198
  e.preventDefault();
@@ -4192,7 +4204,7 @@ const GridFormMultiSelectGrid = (props) => {
4192
4204
  };
4193
4205
 
4194
4206
  /** Menu configuration types **/
4195
- const __isMenuSeparator__ = "__isMenuSeparator__";
4207
+ const __isMenuSeparator__ = '__isMenuSeparator__';
4196
4208
  const PopoutMenuSeparator = Object.freeze({ label: __isMenuSeparator__ });
4197
4209
  /**
4198
4210
  * NOTE: If the popout menu doesn't appear on single click when also selecting row it's because
@@ -4209,7 +4221,7 @@ const GridFormPopoverMenu = (props) => {
4209
4221
  if (props.defaultAction)
4210
4222
  await props.defaultAction(params);
4211
4223
  else
4212
- console.error(`No action specified for ${params.menuOption.label} menu options`);
4224
+ console.error(`No action specified for ${String(params.menuOption.label)} menu options`);
4213
4225
  }, [props]);
4214
4226
  // Load up options list if it's async function
4215
4227
  useEffect(() => {
@@ -4217,8 +4229,8 @@ const GridFormPopoverMenu = (props) => {
4217
4229
  return;
4218
4230
  optionsInitialising.current = true;
4219
4231
  const optionsConf = props.options ?? [];
4220
- (async () => {
4221
- const newOptions = typeof optionsConf == "function" ? await optionsConf(selectedRows) : optionsConf;
4232
+ void (async () => {
4233
+ const newOptions = typeof optionsConf === 'function' ? await optionsConf(selectedRows) : optionsConf;
4222
4234
  setOptions(newOptions);
4223
4235
  if (!props.defaultAction) {
4224
4236
  const anyOptionsAreMissingAction = newOptions.some((option) => !option.action);
@@ -4248,7 +4260,7 @@ const GridFormPopoverMenu = (props) => {
4248
4260
  else {
4249
4261
  subComponentIsValid.current = true;
4250
4262
  setSubSelectedValue(null);
4251
- await updateValue(async () => actionClick(item), e.key === "Tab" ? (e.shiftKey ? -1 : 1) : 0);
4263
+ await updateValue(async () => actionClick(item), e.key === 'Tab' ? (e.shiftKey ? -1 : 1) : 0);
4252
4264
  }
4253
4265
  }, [actionClick, subComponentSelected, updateValue]);
4254
4266
  const save = useCallback(async () => {
@@ -4266,7 +4278,7 @@ const GridFormPopoverMenu = (props) => {
4266
4278
  invalid: () => subComponentSelected && !subComponentIsValid.current,
4267
4279
  save,
4268
4280
  });
4269
- return popoverWrapper(jsx(ComponentLoadingWrapper, { loading: !options, className: "GridFormPopupMenu", children: jsx(Fragment, { children: isEmpty(options) ? (jsx(MenuItem, { className: "GridPopoverMenu-noOptions", disabled: true, children: "No actions" }, `GridPopoverMenu-empty`)) : (options?.map((item, index) => item.label === "__isMenuSeparator__" ? (jsx(MenuDivider, {}, `$$divider_${index}`)) : (!item.hidden && (jsxs(Fragment$1, { children: [item.subMenu ? (jsx(SubMenu, { disabled: !!item.disabled, label: item.label, title: item.disabled && typeof item.disabled !== "boolean" ? item.disabled : "", children: jsx(item.subMenu, {}) }, `${item.label}`)) : (jsx(MenuItem, { onClick: (e) => onMenuItemClick(e, item), disabled: !!item.disabled, title: item.disabled && typeof item.disabled !== "boolean" ? item.disabled : "", children: item.label }, `${item.label}`)), item.subComponent && subComponentSelected === item && (jsx(FocusableItem, { className: "LuiDeprecatedForms", children: () => (jsx(GridSubComponentContext.Provider, { value: {
4281
+ return popoverWrapper(jsx(ComponentLoadingWrapper, { loading: !options, className: 'GridFormPopupMenu', children: jsx(Fragment, { children: isEmpty(options) ? (jsx(MenuItem, { className: 'GridPopoverMenu-noOptions', disabled: true, children: "No actions" }, `GridPopoverMenu-empty`)) : (options?.map((item, index) => item.label === '__isMenuSeparator__' ? (jsx(MenuDivider, {}, `$$divider_${index}`)) : (!item.hidden && (jsxs(Fragment$1, { children: [item.subMenu ? (jsx(SubMenu, { disabled: !!item.disabled, label: item.label, title: item.disabled && typeof item.disabled !== 'boolean' ? item.disabled : '', children: jsx(item.subMenu, {}) }, `${String(item.label)}`)) : (jsx(MenuItem, { onClick: (e) => void onMenuItemClick(e, item), disabled: !!item.disabled, title: item.disabled && typeof item.disabled !== 'boolean' ? item.disabled : '', children: item.label }, `${String(item.label)}`)), item.subComponent && subComponentSelected === item && (jsx(FocusableItem, { className: 'LuiDeprecatedForms', children: () => (jsx(GridSubComponentContext.Provider, { value: {
4270
4282
  context: {},
4271
4283
  data,
4272
4284
  value: subSelectedValue,
@@ -4277,13 +4289,13 @@ const GridFormPopoverMenu = (props) => {
4277
4289
  subComponentIsValid.current = valid;
4278
4290
  },
4279
4291
  triggerSave,
4280
- }, children: jsx("div", { className: "subComponent", children: item.subComponent && jsx(item.subComponent, {}) }) })) }, `${item.label}_subcomponent`))] }, `${item.label}`))))) }) }));
4292
+ }, children: jsx("div", { className: 'subComponent', children: item.subComponent && jsx(item.subComponent, {}) }) })) }, `${String(item.label)}_subcomponent`))] }, `${String(item.label)}`))))) }) }));
4281
4293
  };
4282
4294
 
4283
4295
  const TextAreaInput = (props) => {
4284
4296
  const reactId = useId();
4285
4297
  const id = props?.id ?? reactId;
4286
- return (jsxs("div", { className: clsx("LuiTextAreaInput Grid-popoverContainer", props.disabled ? "isDisabled" : "", props.error ? "hasError" : "", props.className), children: [jsxs("label", { htmlFor: id, children: [props.mandatory != null && jsx("span", { className: "LuiTextAreaInput-mandatory", children: "*" }), props.label != null && jsx("span", { className: "LuiTextAreaInput-label", children: props.label }), jsx("div", { className: "LuiTextAreaInput-wrapper", children: jsx("textarea", { rows: 5, ...omit(props, ["error", "value", "helpText", "formatted", "className", "allowTabToSave"]), id: id, value: props.value ?? "", spellCheck: true, onMouseEnter: (e) => {
4298
+ return (jsxs("div", { className: clsx('LuiTextAreaInput Grid-popoverContainer', props.disabled ? 'isDisabled' : '', props.error ? 'hasError' : '', props.className), children: [jsxs("label", { htmlFor: id, children: [props.mandatory != null && jsx("span", { className: "LuiTextAreaInput-mandatory", children: "*" }), props.label != null && jsx("span", { className: "LuiTextAreaInput-label", children: props.label }), jsx("div", { className: "LuiTextAreaInput-wrapper", children: jsx("textarea", { rows: 5, ...omit(props, ['error', 'value', 'helpText', 'formatted', 'className', 'allowTabToSave']), id: id, value: props.value ?? '', spellCheck: true, onMouseEnter: (e) => {
4287
4299
  if (document.activeElement != e.currentTarget) {
4288
4300
  e.currentTarget.focus();
4289
4301
  e.currentTarget.selectionStart = e.currentTarget.value.length;
@@ -4296,11 +4308,11 @@ const TextInputValidator = (props, value, data, context) => {
4296
4308
  if (value == null)
4297
4309
  return null;
4298
4310
  // This can happen because subcomponent is invoked without type safety
4299
- if (typeof value !== "string") {
4300
- return "Value is not a string";
4311
+ if (typeof value !== 'string') {
4312
+ return 'Value is not a string';
4301
4313
  }
4302
- if (props.required && value.trim() == "") {
4303
- return "Must not be empty";
4314
+ if (props.required && value.trim() == '') {
4315
+ return 'Must not be empty';
4304
4316
  }
4305
4317
  if (props.maxLength && value.length > props.maxLength) {
4306
4318
  return `Must be no longer than ${props.maxLength} characters`;
@@ -4310,10 +4322,10 @@ const TextInputValidator = (props, value, data, context) => {
4310
4322
  }
4311
4323
  const nf = props.numberFormat;
4312
4324
  if (nf) {
4313
- if (value != "" && !isFloat(value)) {
4325
+ if (value != '' && !isFloat(value)) {
4314
4326
  return `Must be a valid number`;
4315
4327
  }
4316
- if (value != "") {
4328
+ if (value != '') {
4317
4329
  const number = parseFloat(value);
4318
4330
  if (nf.notZero && number === 0) {
4319
4331
  return `Must not be 0`;
@@ -4330,12 +4342,12 @@ const TextInputValidator = (props, value, data, context) => {
4330
4342
  if (nf.leMax != null && number > nf.leMax) {
4331
4343
  return `Must not be greater than ${nf.leMax.toLocaleString()}`;
4332
4344
  }
4333
- if (nf.precision != null && value != "") {
4345
+ if (nf.precision != null && value != '') {
4334
4346
  if (parseFloat(number.toPrecision(nf.precision)) != number) {
4335
4347
  return `Must have no more than ${nf.precision} digits precision`;
4336
4348
  }
4337
4349
  }
4338
- if (nf.scale != null && value != "") {
4350
+ if (nf.scale != null && value != '') {
4339
4351
  if (parseFloat(number.toFixed(nf.scale)) != number) {
4340
4352
  return nf.scale == 0 ? `Must be a whole number` : `Must have no more than ${nf.scale} decimal places`;
4341
4353
  }
@@ -4350,7 +4362,7 @@ const TextInputValidator = (props, value, data, context) => {
4350
4362
 
4351
4363
  const GridFormSubComponentTextArea = (props) => {
4352
4364
  const { value, data, setValue, setValid, context } = useContext(GridSubComponentContext);
4353
- const helpText = props.helpText ?? "Press tab to save";
4365
+ const helpText = props.helpText ?? 'Press tab to save';
4354
4366
  // If is not initialised yet as it's just been created then set the default value
4355
4367
  useEffect(() => {
4356
4368
  if (value == null)
@@ -4360,12 +4372,12 @@ const GridFormSubComponentTextArea = (props) => {
4360
4372
  useEffect(() => {
4361
4373
  setValid(value != null && invalid() == null);
4362
4374
  }, [setValid, invalid, value]);
4363
- return (jsx("div", { className: clsx("FreeTextInput", props.className), children: jsx(TextAreaInput, { className: "free-text-input", value: value, onChange: (e) => setValue(e.target.value), error: invalid(), helpText: helpText, placeholder: props.placeholder, allowTabToSave: true }) }));
4375
+ return (jsx("div", { className: clsx('FreeTextInput', props.className), children: jsx(TextAreaInput, { className: 'free-text-input', value: value, onChange: (e) => setValue(e.target.value), error: invalid(), helpText: helpText, placeholder: props.placeholder, allowTabToSave: true }) }));
4364
4376
  };
4365
4377
 
4366
4378
  const GridFormSubComponentTextInput = (props) => {
4367
4379
  const { value, setValue, setValid, data, context } = useContext(GridSubComponentContext);
4368
- const helpText = props.helpText ?? "Press enter or tab to save";
4380
+ const helpText = props.helpText ?? 'Press enter or tab to save';
4369
4381
  // If is not initialised yet as it's just been created then set the default value
4370
4382
  useEffect(() => {
4371
4383
  if (value == null)
@@ -4375,14 +4387,14 @@ const GridFormSubComponentTextInput = (props) => {
4375
4387
  useEffect(() => {
4376
4388
  setValid(value != null && invalid() == null);
4377
4389
  }, [setValid, invalid, value]);
4378
- return (jsx(TextInputFormatted, { value: value, error: invalid(), onChange: (e) => setValue(e.target.value), helpText: helpText, placeholder: props.placeholder, style: { width: "100%" }, allowTabToSave: true }));
4390
+ return (jsx(TextInputFormatted, { value: value, error: invalid(), onChange: (e) => setValue(e.target.value), helpText: helpText, placeholder: props.placeholder, style: { width: '100%' }, allowTabToSave: true }));
4379
4391
  };
4380
4392
 
4381
4393
  const GridFormTextArea = (props) => {
4382
4394
  const { field, value: initialVale, data } = useGridPopoverContext();
4383
- const initValue = useMemo(() => (initialVale == null ? "" : `${initialVale}`), [initialVale]);
4395
+ const initValue = useMemo(() => (initialVale == null ? '' : `${initialVale}`), [initialVale]);
4384
4396
  const [value, setValue] = useState(initValue);
4385
- const helpText = props.helpText ?? "Press tab to save";
4397
+ const helpText = props.helpText ?? 'Press tab to save';
4386
4398
  const invalid = useCallback(() => TextInputValidator(props, value, data, {}), [props, value, data]);
4387
4399
  const save = useCallback(async (selectedRows) => {
4388
4400
  if (invalid())
@@ -4402,13 +4414,13 @@ const GridFormTextArea = (props) => {
4402
4414
  invalid,
4403
4415
  save,
4404
4416
  });
4405
- return popoverWrapper(jsx("div", { className: "subComponent", style: { display: "flex", flexDirection: "row", width: props.width ?? 240 }, children: jsx(TextAreaInput, { value: value, onChange: (e) => setValue(e.target.value), error: invalid(), placeholder: props.placeholder ?? "Type here", helpText: helpText }) }));
4417
+ return popoverWrapper(jsx("div", { className: 'subComponent', style: { display: 'flex', flexDirection: 'row', width: props.width ?? 240 }, children: jsx(TextAreaInput, { value: value, onChange: (e) => setValue(e.target.value), error: invalid(), placeholder: props.placeholder ?? 'Type here', helpText: helpText }) }));
4406
4418
  };
4407
4419
 
4408
4420
  const GridFormTextInput = (props) => {
4409
4421
  const { field, value: initialVale, data } = useGridPopoverContext();
4410
- const helpText = props.helpText ?? "Press enter or tab to save";
4411
- const initValue = useMemo(() => (initialVale == null ? "" : `${initialVale}`), [initialVale]);
4422
+ const helpText = props.helpText ?? 'Press enter or tab to save';
4423
+ const initValue = useMemo(() => (initialVale == null ? '' : `${initialVale}`), [initialVale]);
4412
4424
  const [value, setValue] = useState(initValue);
4413
4425
  const invalid = useCallback(() => TextInputValidator(props, value, data, {}), [data, props, value]);
4414
4426
  const save = useCallback(async (selectedRows) => {
@@ -4429,7 +4441,7 @@ const GridFormTextInput = (props) => {
4429
4441
  invalid,
4430
4442
  save,
4431
4443
  });
4432
- return popoverWrapper(jsx("div", { style: { display: "flex", flexDirection: "row" }, className: "FormTest subComponent", children: jsx(TextInputFormatted, { value: value, onChange: (e) => setValue(e.target.value), error: invalid(), formatted: props.units, style: { width: props.width ?? 240 }, placeholder: props.placeholder ?? "Type here", helpText: helpText }) }));
4444
+ return popoverWrapper(jsx("div", { style: { display: 'flex', flexDirection: 'row' }, className: 'FormTest subComponent', children: jsx(TextInputFormatted, { value: value, onChange: (e) => setValue(e.target.value), error: invalid(), formatted: props.units, style: { width: props.width ?? 240 }, placeholder: props.placeholder ?? 'Type here', helpText: helpText }) }));
4433
4445
  };
4434
4446
 
4435
4447
  const ButtonCellRenderer = (props) => {
@@ -4441,24 +4453,24 @@ const ButtonCellRenderer = (props) => {
4441
4453
  inputRef.current?.focus();
4442
4454
  }
4443
4455
  };
4444
- api.addEventListener("cellFocused", checkFocus);
4456
+ api.addEventListener('cellFocused', checkFocus);
4445
4457
  return () => {
4446
- api.removeEventListener("cellFocused", checkFocus);
4458
+ api.removeEventListener('cellFocused', checkFocus);
4447
4459
  };
4448
4460
  }, [api, column, node.rowIndex]);
4449
4461
  return (jsx(LuiButton, { ref: inputRef, className: "lui-button-icon-only", size: "sm", level: "text", onClick: () => {
4450
4462
  const selectedRows = [data];
4451
4463
  const selectedRowIds = selectedRows.map((r) => r.id);
4452
4464
  colDef?.cellEditorParams.onClick?.({ selectedRows, selectedRowIds });
4453
- }, style: { display: colDef?.cellEditorParams?.visible?.(props) !== false ? "" : "none" }, children: jsx(LuiIcon, { name: "ic_redo", alt: "revert", size: "md" }) }));
4465
+ }, style: { display: colDef?.cellEditorParams?.visible?.(props) !== false ? '' : 'none' }, children: jsx(LuiIcon, { name: "ic_redo", alt: "revert", size: "md" }) }));
4454
4466
  };
4455
4467
  const GridButton = (colDef, editor) => {
4456
4468
  return GridCell({
4457
4469
  minWidth: 72,
4458
4470
  maxWidth: 72,
4459
4471
  resizable: false,
4460
- headerClass: "GridHeaderAlignCenter",
4461
- cellClass: "GridCellAlignCenter",
4472
+ headerClass: 'GridHeaderAlignCenter',
4473
+ cellClass: 'GridCellAlignCenter',
4462
4474
  cellRenderer: ButtonCellRenderer,
4463
4475
  cellEditorParams: {
4464
4476
  ...editor,
@@ -4476,15 +4488,15 @@ const BooleanCellRenderer = (props) => {
4476
4488
  inputRef.current?.focus();
4477
4489
  }
4478
4490
  };
4479
- api.addEventListener("cellFocused", checkFocus);
4491
+ api.addEventListener('cellFocused', checkFocus);
4480
4492
  return () => {
4481
- api.removeEventListener("cellFocused", checkFocus);
4493
+ api.removeEventListener('cellFocused', checkFocus);
4482
4494
  };
4483
4495
  }, [api, column, node.rowIndex]);
4484
4496
  const isDisabled = !fnOrVar(colDef?.editable, props);
4485
- return (jsx("div", { className: clsx("ag-wrapper ag-input-wrapper ag-checkbox-input-wrapper", {
4486
- "ag-checked": props.value,
4487
- "ag-disabled": isDisabled,
4497
+ return (jsx("div", { className: clsx('ag-wrapper ag-input-wrapper ag-checkbox-input-wrapper', {
4498
+ 'ag-checked': props.value,
4499
+ 'ag-disabled': isDisabled,
4488
4500
  }), children: jsx("input", { type: "checkbox", className: "ag-input-field-input ag-checkbox-input", disabled: isDisabled, ref: inputRef, checked: value, onChange: () => { }, onClick: (e) => {
4489
4501
  e.stopPropagation();
4490
4502
  // cell has to be in edit mode
@@ -4504,7 +4516,7 @@ const BooleanCellRenderer = (props) => {
4504
4516
  });
4505
4517
  const checked = !value;
4506
4518
  onValueChange(checked);
4507
- params.onClick({ selectedRows, selectedRowIds: selectedRows.map((r) => r.id), checked }).then();
4519
+ void params.onClick({ selectedRows, selectedRowIds: selectedRows.map((r) => r.id), checked });
4508
4520
  } }) }));
4509
4521
  };
4510
4522
  const GridEditBoolean = (colDef, editorProps) => {
@@ -4518,8 +4530,8 @@ const GridEditBoolean = (colDef, editorProps) => {
4518
4530
  singleClickEdit: true,
4519
4531
  resizable: false,
4520
4532
  editable: true,
4521
- cellClass: "GridCellAlignCenter",
4522
- headerClass: "GridHeaderAlignCenter",
4533
+ cellClass: 'GridCellAlignCenter',
4534
+ headerClass: 'GridHeaderAlignCenter',
4523
4535
  ...colDef,
4524
4536
  });
4525
4537
  };
@@ -4529,7 +4541,7 @@ const GridPopoutEditMultiSelect = (colDef, props) => GridCell(colDef, {
4529
4541
  ...props,
4530
4542
  editorParams: {
4531
4543
  ...props.editorParams,
4532
- className: clsx("GridMultiSelect-containerMedium", props.editorParams?.className),
4544
+ className: clsx('GridMultiSelect-containerMedium', props.editorParams?.className),
4533
4545
  },
4534
4546
  });
4535
4547
 
@@ -4538,47 +4550,19 @@ const GridPopoutEditMultiSelectGrid = (colDef, props) => GridCell(colDef, {
4538
4550
  ...props,
4539
4551
  editorParams: {
4540
4552
  ...props.editorParams,
4541
- className: clsx("GridMultiSelect-containerMedium", props.editorParams?.className),
4542
- },
4543
- });
4544
-
4545
- const GridRenderPopoutMenuCell = (props) => {
4546
- const disabled = !fnOrVar(props.colDef?.editable, props);
4547
- return (jsx(LuiIcon, { name: "ic_more_vert", alt: "More actions", size: "md", className: clsx("GridPopoutMenu-burger", disabled && "GridPopoutMenu-burgerDisabled") }));
4548
- };
4549
-
4550
- /**
4551
- * Popout burger menu
4552
- */
4553
- const GridPopoverMenu = (colDef, custom) => GridCell({
4554
- minWidth: 48,
4555
- maxWidth: 48,
4556
- width: 40,
4557
- sortable: false,
4558
- editable: colDef.editable != null ? colDef.editable : true,
4559
- exportable: false,
4560
- cellStyle: { flex: 1, justifyContent: "center" },
4561
- cellRenderer: GridRenderPopoutMenuCell,
4562
- ...colDef,
4563
- cellRendererParams: {
4564
- // Menus open on single click, this parameter is picked up in Grid.tsx
4565
- singleClickEdit: true,
4553
+ className: clsx('GridMultiSelect-containerMedium', props.editorParams?.className),
4566
4554
  },
4567
- }, {
4568
- editor: GridFormPopoverMenu,
4569
- preventAutoEdit: true,
4570
- ...custom,
4571
4555
  });
4572
4556
 
4573
4557
  const GridPopoverEditBearingLike = (colDef, props) => GridCell({
4574
- valueFormatter: (params) => props.editorParams?.formatValue(params.value) ?? "",
4558
+ valueFormatter: (params) => props.editorParams?.formatValue(params.value) ?? '',
4575
4559
  ...colDef,
4576
4560
  }, {
4577
4561
  editor: GridFormEditBearing,
4578
4562
  ...props,
4579
4563
  });
4580
4564
  const GridPopoverEditBearingEditorParams = {
4581
- placeHolder: "Enter bearing",
4565
+ placeHolder: 'Enter bearing',
4582
4566
  formatValue: bearingValueFormatter,
4583
4567
  range: bearingRangeValidator,
4584
4568
  };
@@ -4590,7 +4574,7 @@ const GridPopoverEditBearing = (colDef, props) => GridPopoverEditBearingLike(col
4590
4574
  },
4591
4575
  });
4592
4576
  const GridPopoverEditBearingCorrectionEditorParams = {
4593
- placeHolder: "Enter bearing correction",
4577
+ placeHolder: 'Enter bearing correction',
4594
4578
  formatValue: bearingCorrectionValueFormatter,
4595
4579
  range: bearingCorrectionRangeValidator,
4596
4580
  };
@@ -4608,11 +4592,39 @@ const GridPopoverEditDropDown = (colDef, props) => GridCell(colDef, {
4608
4592
  editorParams: {
4609
4593
  ...props.editorParams,
4610
4594
  className: clsx({
4611
- "GridPopoverEditDropDown-containerLarge": !props.editorParams?.className?.includes("GridPopoverEditDropDown-container"),
4595
+ 'GridPopoverEditDropDown-containerLarge': !props.editorParams?.className?.includes('GridPopoverEditDropDown-container'),
4612
4596
  }, props.editorParams?.className),
4613
4597
  },
4614
4598
  });
4615
4599
 
4600
+ const GridRenderPopoutMenuCell = (props) => {
4601
+ const disabled = !fnOrVar(props.colDef?.editable, props);
4602
+ return (jsx(LuiIcon, { name: 'ic_more_vert', alt: 'More actions', size: 'md', className: clsx('GridPopoutMenu-burger', disabled && 'GridPopoutMenu-burgerDisabled') }));
4603
+ };
4604
+
4605
+ /**
4606
+ * Popout burger menu
4607
+ */
4608
+ const GridPopoverMenu = (colDef, custom) => GridCell({
4609
+ minWidth: 48,
4610
+ maxWidth: 48,
4611
+ width: 40,
4612
+ sortable: false,
4613
+ editable: colDef.editable != null ? colDef.editable : true,
4614
+ exportable: false,
4615
+ cellStyle: { flex: 1, justifyContent: 'center' },
4616
+ cellRenderer: GridRenderPopoutMenuCell,
4617
+ ...colDef,
4618
+ cellRendererParams: {
4619
+ // Menus open on single click, this parameter is picked up in Grid.tsx
4620
+ singleClickEdit: true,
4621
+ },
4622
+ }, {
4623
+ editor: GridFormPopoverMenu,
4624
+ preventAutoEdit: true,
4625
+ ...custom,
4626
+ });
4627
+
4616
4628
  const GridPopoverMessage = (colDef, props) => GridCell({
4617
4629
  resizable: true,
4618
4630
  ...colDef,
@@ -4632,9 +4644,9 @@ const GridPopoverTextInput = (colDef, params) => GridCell(colDef, {
4632
4644
  ...params,
4633
4645
  });
4634
4646
 
4635
- const GridWrapper = ({ children, maxHeight }) => (jsx("div", { className: "Grid-wrapper", style: { maxHeight }, children: children }));
4647
+ const GridWrapper = ({ children, maxHeight }) => (jsx("div", { className: 'Grid-wrapper', style: { maxHeight }, children: children }));
4636
4648
 
4637
- const getColId = (colDef) => colDef.colId ?? "";
4649
+ const getColId = (colDef) => colDef.colId ?? '';
4638
4650
  const isFlexColumn = (colDef) => !!colDef.flex && !isGridCellFiller(colDef);
4639
4651
 
4640
4652
  /**
@@ -4646,7 +4658,7 @@ const GridContextProvider = (props) => {
4646
4658
  const { modifyUpdating, checkUpdating } = useContext(GridUpdatingContext);
4647
4659
  const [gridApi, setGridApi] = useState();
4648
4660
  const [gridReady, setGridReady] = useState(false);
4649
- const [quickFilter, _setQuickFilter] = useState("");
4661
+ const [quickFilter, _setQuickFilter] = useState('');
4650
4662
  const [invisibleColumnIds, _setInvisibleColumnIds] = useState();
4651
4663
  const testId = useRef();
4652
4664
  const idsBeforeUpdate = useRef([]);
@@ -4666,7 +4678,7 @@ const GridContextProvider = (props) => {
4666
4678
  * Set quick filter directly on grid, based on previously save quickFilter state.
4667
4679
  */
4668
4680
  useEffect(() => {
4669
- gridApi?.setGridOption("quickFilterText", quickFilter);
4681
+ gridApi?.setGridOption('quickFilterText', quickFilter);
4670
4682
  }, [gridApi, quickFilter]);
4671
4683
  /**
4672
4684
  * Wraps things that require gridApi in common handling, for when gridApi not present.
@@ -4699,9 +4711,9 @@ const GridContextProvider = (props) => {
4699
4711
  let id = 0;
4700
4712
  try {
4701
4713
  gridApi?.forEachNodeAfterFilterAndSort((rowNode) => {
4702
- id = parseInt(rowNode.id ?? "0");
4714
+ id = parseInt(rowNode.id ?? '0');
4703
4715
  // this is the only way to get out of the loop
4704
- throw "expected exception - exit_loop";
4716
+ throw 'expected exception - exit_loop';
4705
4717
  });
4706
4718
  }
4707
4719
  catch (ex) {
@@ -4715,7 +4727,7 @@ const GridContextProvider = (props) => {
4715
4727
  const setApis = useCallback((gridApi, dataTestId) => {
4716
4728
  testId.current = dataTestId;
4717
4729
  setGridApi(gridApi);
4718
- gridApi?.setGridOption("quickFilterText", quickFilter);
4730
+ gridApi?.setGridOption('quickFilterText', quickFilter);
4719
4731
  setGridReady(!!gridApi);
4720
4732
  }, [quickFilter]);
4721
4733
  /**
@@ -4725,9 +4737,9 @@ const GridContextProvider = (props) => {
4725
4737
  if (!gridApi)
4726
4738
  return null;
4727
4739
  if (!gridApi.getDisplayedRowCount())
4728
- return "empty";
4740
+ return 'empty';
4729
4741
  if (!isEmpty(gridApi.getRenderedNodes()))
4730
- return "rows-visible";
4742
+ return 'rows-visible';
4731
4743
  // If there are rows to render, but there are no rendered nodes then we should wait
4732
4744
  return null;
4733
4745
  }, [gridApi]);
@@ -4783,7 +4795,7 @@ const GridContextProvider = (props) => {
4783
4795
  * Uses beforeUpdate ids to find new nodes.
4784
4796
  */
4785
4797
  const _getNewNodes = useCallback(() => {
4786
- return gridApiOp((gridApi) => compact(difference(_getAllRowIds(), idsBeforeUpdate.current).map((rowId) => gridApi.getRowNode("" + rowId))), () => []);
4798
+ return gridApiOp((gridApi) => compact(difference(_getAllRowIds(), idsBeforeUpdate.current).map((rowId) => gridApi.getRowNode('' + rowId))), () => []);
4787
4799
  }, [_getAllRowIds, gridApiOp]);
4788
4800
  /**
4789
4801
  * Get grid nodes via rowIds. If rowIds has no matching node the result may be smaller than expected.
@@ -4792,7 +4804,7 @@ const GridContextProvider = (props) => {
4792
4804
  * @param rowIds Row ids to get from grid.
4793
4805
  */
4794
4806
  const _rowIdsToNodes = useCallback((rowIds) => {
4795
- return gridApiOp((gridApi) => compact(rowIds.map((rowId) => gridApi.getRowNode("" + rowId))), () => []);
4807
+ return gridApiOp((gridApi) => compact(rowIds.map((rowId) => gridApi.getRowNode('' + rowId))), () => []);
4796
4808
  }, [gridApiOp]);
4797
4809
  /**
4798
4810
  * Get ColDefs, with flattened ColGroupDefs
@@ -4933,7 +4945,7 @@ const GridContextProvider = (props) => {
4933
4945
  gridApi.autoSizeColumns(colsToResize.map((colState) => colState.colId), skipHeader);
4934
4946
  }
4935
4947
  return {
4936
- width: sumBy(gridApi.getColumnState().filter((col) => !col.hide), "width"),
4948
+ width: sumBy(gridApi.getColumnState().filter((col) => !col.hide), 'width'),
4937
4949
  };
4938
4950
  }, [gridApi]);
4939
4951
  /**
@@ -4950,7 +4962,9 @@ const GridContextProvider = (props) => {
4950
4962
  }
4951
4963
  gridApi.stopEditing();
4952
4964
  }, [gridApi]);
4953
- const startCellEditing = useCallback(async ({ rowId, colId }) => {
4965
+ const startCellEditing = useCallback(
4966
+ // eslint-disable-next-line @typescript-eslint/require-await
4967
+ ({ rowId, colId }) => {
4954
4968
  if (!gridApi)
4955
4969
  return;
4956
4970
  const colDef = gridApi.getColumnDef(colId);
@@ -4965,7 +4979,7 @@ const GridContextProvider = (props) => {
4965
4979
  rowNode.setSelected(true, true);
4966
4980
  }
4967
4981
  // Cell already being edited, so don't re-edit until finished
4968
- if (checkUpdating([colDef.field ?? ""], rowId)) {
4982
+ if (checkUpdating([colDef.field ?? ''], rowId)) {
4969
4983
  return;
4970
4984
  }
4971
4985
  const rowIndex = rowNode.rowIndex;
@@ -5036,11 +5050,11 @@ const GridContextProvider = (props) => {
5036
5050
  return await gridApiOp(async (gridApi) => {
5037
5051
  const selectedRows = props.selectedRows;
5038
5052
  let ok = false;
5039
- await modifyUpdating(props.field ?? "", selectedRows.map((data) => data.id), async () => {
5053
+ await modifyUpdating(props.field ?? '', selectedRows.map((data) => data.id), async () => {
5040
5054
  // Need to refresh to get spinners to work on all rows
5041
5055
  gridApi.refreshCells({ rowNodes: props.selectedRows, force: true });
5042
5056
  ok = await fnUpdate(selectedRows).catch((ex) => {
5043
- console.error("Exception during modifyUpdating", ex);
5057
+ console.error('Exception during modifyUpdating', ex);
5044
5058
  return false;
5045
5059
  });
5046
5060
  });
@@ -5076,9 +5090,7 @@ const GridContextProvider = (props) => {
5076
5090
  gridApi && gridApi.redrawRows(rowNodes ? { rowNodes } : undefined);
5077
5091
  }
5078
5092
  catch (ex) {
5079
- // Hide errors in jest, but log them in browser
5080
- if (typeof jest === "undefined")
5081
- console.error(ex);
5093
+ console.error(ex);
5082
5094
  }
5083
5095
  }, 50), [gridApi]);
5084
5096
  // waitForExternallySelectedItemsToBeInSync can't use the state as it won't be updated during function execution
@@ -5099,7 +5111,7 @@ const GridContextProvider = (props) => {
5099
5111
  gridApi?.forEachNodeAfterFilter((rowNode) => {
5100
5112
  arr.push(rowNode.id);
5101
5113
  });
5102
- return arr.join("|");
5114
+ return arr.join('|');
5103
5115
  };
5104
5116
  if (gridApi) {
5105
5117
  const hasFocusedCell = gridApi.getFocusedCell();
@@ -5113,11 +5125,11 @@ const GridContextProvider = (props) => {
5113
5125
  }, 200), [gridApi]);
5114
5126
  const addExternalFilter = (filter) => {
5115
5127
  externalFilters.current.push(filter);
5116
- onFilterChanged().then();
5128
+ void onFilterChanged();
5117
5129
  };
5118
5130
  const removeExternalFilter = (filter) => {
5119
5131
  remove(externalFilters.current, (v) => v === filter);
5120
- onFilterChanged().then();
5132
+ void onFilterChanged();
5121
5133
  };
5122
5134
  const isExternalFilterPresent = () => !isEmpty(externalFilters.current);
5123
5135
  const doesExternalFilterPass = (node) => externalFilters.current.every((filter) => filter(node.data, node));
@@ -5221,10 +5233,10 @@ const GridContextProvider = (props) => {
5221
5233
  const downloadCsvUseValueFormattersProcessCellCallback = (params) => {
5222
5234
  const encodeToString = (value) => {
5223
5235
  // Convert nullish values to blank
5224
- if (value === "-" || value === "" || value == null) {
5225
- return "";
5236
+ if (value === '-' || value === '' || value == null) {
5237
+ return '';
5226
5238
  }
5227
- if (typeof value === "string") {
5239
+ if (typeof value === 'string') {
5228
5240
  return value;
5229
5241
  }
5230
5242
  return JSON.stringify(value);
@@ -5238,19 +5250,19 @@ const downloadCsvUseValueFormattersProcessCellCallback = (params) => {
5238
5250
  const valueFormatter = colDef.valueFormatter;
5239
5251
  // If no valueFormatter then value _must_ be a string
5240
5252
  if (valueFormatter == null) {
5241
- if (params.value != null && typeof params.value !== "string") {
5253
+ if (params.value != null && typeof params.value !== 'string') {
5242
5254
  console.error(`downloadCsv: valueFormatter missing and getValue is not a string, colId: ${colDef.colId}`);
5243
5255
  }
5244
5256
  return encodeToString(params.value);
5245
5257
  }
5246
5258
  // We don't have access to registered functions, so we can't call them
5247
- if (typeof valueFormatter !== "function") {
5259
+ if (typeof valueFormatter !== 'function') {
5248
5260
  console.error(`downloadCsv: String type (registered) value formatters are unsupported in downloadCsv, colId: ${colDef.colId}`);
5249
5261
  return encodeToString(params.value);
5250
5262
  }
5251
5263
  const result = valueFormatter({ ...params, data: params.node?.data, colDef, node: null });
5252
5264
  // type may not be string due to casting, leave the type check in
5253
- if (params.value != null && typeof result !== "string") {
5265
+ if (params.value != null && typeof result !== 'string') {
5254
5266
  console.error(`downloadCsv: valueFormatter is returning non string values, colDef:", colId: ${colDef.colId}`);
5255
5267
  }
5256
5268
  // We add an extra encodeToString here just in case valueFormatter is returning non string values
@@ -5309,7 +5321,7 @@ const usePrevious = (value) => {
5309
5321
 
5310
5322
  // Kept this less than one second, so I don't have issues with waitFor as it defaults to 1s
5311
5323
  const minimumInProgressTimeMs = 950;
5312
- const ActionButton = ({ icon, name, inProgressName, disabled, dataTestId, style, className, title, onClick, size = "sm", iconPosition = "left", level = "tertiary", "aria-label": ariaLabel, }) => {
5324
+ const ActionButton = ({ icon, name, inProgressName, disabled, dataTestId, style, className, title, onClick, size = 'sm', iconPosition = 'left', level = 'tertiary', 'aria-label': ariaLabel, }) => {
5313
5325
  const [inProgress, setInProgress] = useState(false);
5314
5326
  const lastInProgress = usePrevious(inProgress ?? false);
5315
5327
  const [localInProgress, setLocalInProgress, setLocalInProgressDeferred] = useStateDeferred(inProgress);
@@ -5318,28 +5330,28 @@ const ActionButton = ({ icon, name, inProgressName, disabled, dataTestId, style,
5318
5330
  return;
5319
5331
  inProgress ? setLocalInProgress(true) : setLocalInProgressDeferred(false, minimumInProgressTimeMs);
5320
5332
  }, [inProgress, lastInProgress, setLocalInProgress, setLocalInProgressDeferred]);
5321
- const buttonText = (jsxs("span", { className: "ActionButton-minimalArea", children: [jsx("span", { className: "ActionButton-minimalAreaDisplay", children: (localInProgress ? inProgressName : name) ?? name }), jsx("span", { className: "ActionButton-minimalAreaExpand", children: name })] }));
5322
- return (jsxs(LuiButton, { "data-testid": dataTestId, type: "button", level: level, title: title ?? ariaLabel ?? name, buttonProps: { "aria-label": ariaLabel ?? name }, className: clsx("lui-button-icon-right", "ActionButton", className, localInProgress && "ActionButton-inProgress", name != null && !className?.includes("ActionButton-fill") && "ActionButton-minimal", name == null && "ActionButton-iconOnly"), size: "lg", style: style, onClick: async () => {
5333
+ const buttonText = (jsxs("span", { className: 'ActionButton-minimalArea', children: [jsx("span", { className: 'ActionButton-minimalAreaDisplay', children: (localInProgress ? inProgressName : name) ?? name }), jsx("span", { className: 'ActionButton-minimalAreaExpand', children: name })] }));
5334
+ return (jsxs(LuiButton, { "data-testid": dataTestId, type: 'button', level: level, title: title ?? ariaLabel ?? name, buttonProps: { 'aria-label': ariaLabel ?? name }, className: clsx('lui-button-icon-right', 'ActionButton', className, localInProgress && 'ActionButton-inProgress', name != null && !className?.includes('ActionButton-fill') && 'ActionButton-minimal', name == null && 'ActionButton-iconOnly'), size: 'lg', style: style, onClick: () => {
5323
5335
  const promise = onClick();
5324
- const isPromise = typeof promise !== "undefined";
5336
+ const isPromise = typeof promise !== 'undefined';
5325
5337
  if (isPromise) {
5326
5338
  setInProgress(true);
5327
- if (isPromise)
5328
- await promise;
5329
- setInProgress(false);
5339
+ void promise.finally(() => {
5340
+ setInProgress(false);
5341
+ });
5330
5342
  }
5331
- }, disabled: localInProgress || disabled, children: [iconPosition === "right" && buttonText, localInProgress && (jsx("div", { style: { position: "relative" }, children: jsx(LuiMiniSpinner, { size: 14, divProps: {
5332
- "data-testid": "loading-spinner",
5343
+ }, disabled: localInProgress || disabled, children: [iconPosition === 'right' && buttonText, localInProgress && (jsx("div", { style: { position: 'relative' }, children: jsx(LuiMiniSpinner, { size: 14, divProps: {
5344
+ 'data-testid': 'loading-spinner',
5333
5345
  style: {
5334
- position: "absolute",
5346
+ position: 'absolute',
5335
5347
  left: 4,
5336
5348
  top: -10,
5337
5349
  bottom: 10,
5338
5350
  right: -4,
5339
5351
  },
5340
- role: "status",
5341
- "aria-label": "Loading",
5342
- } }) })), jsx(LuiIcon, { name: icon, alt: ariaLabel ?? name ?? "", size: size }), iconPosition === "left" && buttonText] }));
5352
+ role: 'status',
5353
+ 'aria-label': 'Loading',
5354
+ } }) })), jsx(LuiIcon, { name: icon, alt: ariaLabel ?? name ?? '', size: size }), iconPosition === 'left' && buttonText] }));
5343
5355
  };
5344
5356
 
5345
5357
  const useDeferredPromise = () => {
@@ -5380,5 +5392,5 @@ const useDeferredPromise = () => {
5380
5392
  };
5381
5393
  };
5382
5394
 
5383
- export { ActionButton, ComponentLoadingWrapper, ControlledMenu, Editor, FocusableItem, FormError, GenericCellEditorComponentWrapper, Grid, GridButton, GridCell, GridCellFiller, GridCellFillerColId, GridCellMultiEditor, GridCellMultiSelectClassRules, GridCellRenderer, GridContext, GridContextProvider, GridEditBoolean, GridFilterButtons, GridFilterColumnsToggle, GridFilterDownloadCsvButton, GridFilterHeaderIconButton, GridFilterQuick, GridFilters, GridFormDropDown, GridFormEditBearing, GridFormMessage, GridFormMultiSelect, GridFormMultiSelectGrid, GridFormPopoverMenu, GridFormSubComponentTextArea, GridFormSubComponentTextInput, GridFormTextArea, GridFormTextInput, GridHeaderSelect, GridIcon, GridLoadableCell, GridNoRowsOverlay, GridNoRowsOverlayFr, GridPopoutEditMultiSelect, GridPopoutEditMultiSelectGrid, GridPopoverContext, GridPopoverContextProvider, GridPopoverEditBearing, GridPopoverEditBearingCorrection, GridPopoverEditBearingCorrectionEditorParams, GridPopoverEditBearingEditorParams, GridPopoverEditDropDown, GridPopoverMenu, GridPopoverMessage, GridPopoverTextArea, GridPopoverTextInput, GridRenderPopoutMenuCell, GridSubComponentContext, GridUpdatingContext, GridUpdatingContextProvider, GridWrapper, Menu, MenuButton, MenuDivider, MenuGroup, MenuHeader, MenuHeaderItem, MenuHeaderString, MenuItem, MenuRadioGroup, MenuSeparator, MenuSeparatorString, PopoutMenuSeparator, SubMenu, TextAreaInput, TextInputFormatted, bearingCorrectionRangeValidator, bearingCorrectionValueFormatter, bearingNumberParser, bearingRangeValidator, bearingStringValidator, bearingValueFormatter, clickInputWhenContainingCellClicked, convertDDToDMS, downloadCsvUseValueFormattersProcessCellCallback, findParentWithClass, fnOrVar, generateFilterGetter, hasParentClass, isFloat, isGridCellFiller, isNotEmpty, sanitiseFileName, stringByteLengthIsInvalid, suppressCellKeyboardEvents, useDeferredPromise, useGridContext, useGridContextMenu, useGridFilter, useGridPopoverContext, useGridPopoverHook, useMenuState, usePostSortRowsHook, wait };
5395
+ export { ActionButton, ComponentLoadingWrapper, ControlledMenu, Editor, FocusableItem, FormError, GenericCellEditorComponentWrapper, Grid, GridButton, GridCell, GridCellFiller, GridCellFillerColId, GridCellMultiEditor, GridCellMultiSelectClassRules, GridCellRenderer, GridContext, GridContextProvider, GridEditBoolean, GridFilterButtons, GridFilterColumnsToggle, GridFilterDownloadCsvButton, GridFilterHeaderIconButton, GridFilterQuick, GridFilters, GridFormDropDown, GridFormEditBearing, GridFormMessage, GridFormMultiSelect, GridFormMultiSelectGrid, GridFormPopoverMenu, GridFormSubComponentTextArea, GridFormSubComponentTextInput, GridFormTextArea, GridFormTextInput, GridHeaderSelect, GridIcon, GridLoadableCell, GridNoRowsOverlay, GridNoRowsOverlayFr, GridPopoutEditMultiSelect, GridPopoutEditMultiSelectGrid, GridPopoverContext, GridPopoverContextProvider, GridPopoverEditBearing, GridPopoverEditBearingCorrection, GridPopoverEditBearingCorrectionEditorParams, GridPopoverEditBearingEditorParams, GridPopoverEditDropDown, GridPopoverMenu, GridPopoverMessage, GridPopoverTextArea, GridPopoverTextInput, GridRenderPopoutMenuCell, GridSubComponentContext, GridUpdatingContext, GridUpdatingContextProvider, GridWrapper, Menu, MenuButton, MenuDivider, MenuGroup, MenuHeader, MenuHeaderItem, MenuHeaderString, MenuItem, MenuRadioGroup, MenuSeparator, MenuSeparatorString, PopoutMenuSeparator, SubMenu, TextAreaInput, TextInputFormatted, TextInputValidator, bearingCorrectionRangeValidator, bearingCorrectionValueFormatter, bearingNumberParser, bearingRangeValidator, bearingStringValidator, bearingValueFormatter, clickInputWhenContainingCellClicked, convertDDToDMS, downloadCsvUseValueFormattersProcessCellCallback, findParentWithClass, fnOrVar, generateFilterGetter, hasParentClass, isFloat, isGridCellFiller, isNotEmpty, sanitiseFileName, stringByteLengthIsInvalid, suppressCellKeyboardEvents, textMatch, useDeferredPromise, useGridContext, useGridContextMenu, useGridFilter, useGridPopoverContext, useGridPopoverHook, useMenuState, usePostSortRowsHook, wait };
5384
5396
  //# sourceMappingURL=step-ag-grid.esm.js.map