@geotab/zenith 3.16.0 → 3.17.0-beta.1

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 (282) hide show
  1. package/README.md +67 -1
  2. package/README.md.baseline +1 -0
  3. package/dist/absolute/absolute.js +5 -1
  4. package/dist/button/button.d.ts +2 -1
  5. package/dist/button/button.js +22 -5
  6. package/dist/checkboxListWithAction/checkboxListWithAction.d.ts +2 -0
  7. package/dist/checkboxListWithAction/checkboxListWithAction.js +1 -1
  8. package/dist/commonHelpers/ShowMoreCell.d.ts +5 -0
  9. package/dist/commonHelpers/ShowMoreCell.js +66 -0
  10. package/dist/commonHelpers/getAriaAttributes.js +6 -9
  11. package/dist/commonHelpers/getNonAriaProps.d.ts +11 -0
  12. package/dist/commonHelpers/getNonAriaProps.js +19 -0
  13. package/dist/commonHelpers/hooks/useScroll.d.ts +1 -1
  14. package/dist/commonHelpers/hooks/useScroll.js +6 -6
  15. package/dist/commonHelpers/isAriaProp.d.ts +9 -0
  16. package/dist/commonHelpers/isAriaProp.js +13 -0
  17. package/dist/commonHelpers/showMoreRow.d.ts +28 -0
  18. package/dist/commonHelpers/showMoreRow.js +29 -0
  19. package/dist/commonHelpers/tabsKeyboard.d.ts +1 -1
  20. package/dist/commonHelpers/tabsKeyboard.js +15 -1
  21. package/dist/commonStyles/colors/colors.less +18 -0
  22. package/dist/dataFeed/dataFeedColumnsItems.js +3 -1
  23. package/dist/dataGrid/columns/checkboxColumn/checkboxCell.d.ts +2 -1
  24. package/dist/dataGrid/columns/checkboxColumn/checkboxCell.js +1 -1
  25. package/dist/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.d.ts +4 -2
  26. package/dist/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.js +10 -1
  27. package/dist/dataGrid/dataGrid.d.ts +5 -1
  28. package/dist/dataGrid/dataGrid.js +39 -2
  29. package/dist/dataGrid/lazyLoadingEnd/lazyLoadingEnd.d.ts +3 -0
  30. package/dist/dataGrid/lazyLoadingEnd/lazyLoadingEnd.js +54 -0
  31. package/dist/dataGrid/row/row.js +20 -2
  32. package/dist/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +3 -1
  33. package/dist/dataGrid/withSelectableRows/components/bulkActions/bulkActions.js +39 -4
  34. package/dist/dataGrid/withSelectableRows/withSelectableRows.js +73 -12
  35. package/dist/dropdown/dropdownTrigger.d.ts +1 -1
  36. package/dist/dropdownRaw/dropdownHelper.d.ts +12 -0
  37. package/dist/dropdownRaw/dropdownHelper.js +32 -11
  38. package/dist/dropdownRaw/dropdownRaw.js +36 -8
  39. package/dist/dropdownRaw/dropdownSearchableTrigger.d.ts +2 -1
  40. package/dist/dropdownRaw/dropdownSearchableTrigger.js +13 -6
  41. package/dist/dropdownRaw/dropdownTrigger.d.ts +2 -1
  42. package/dist/dropdownRaw/dropdownTrigger.js +2 -2
  43. package/dist/dropdownRaw/stateReducer/stateReducer.d.ts +8 -0
  44. package/dist/dropdownRaw/stateReducer/stateReducer.js +5 -2
  45. package/dist/dropdownRaw/types.d.ts +36 -0
  46. package/dist/filterButton/filterButton.d.ts +1 -1
  47. package/dist/formGroup/hooks/rowHooks/useLabelClasses.js +8 -2
  48. package/dist/formLayout/utils/applyLayoutPosition/applyLayoutPosition.d.ts +2 -1
  49. package/dist/formLayout/utils/applyLayoutPosition/applyLayoutPosition.js +37 -90
  50. package/dist/header/components/collapsedItemsControl/collapsedItemsControl.d.ts +1 -1
  51. package/dist/header/components/collapsedItemsControl/collapsedItemsControl.js +6 -2
  52. package/dist/header/headerButton.d.ts +3 -1
  53. package/dist/header/headerButton.js +4 -2
  54. package/dist/header/headerMenu.d.ts +2 -0
  55. package/dist/header/headerMenu.js +1 -1
  56. package/dist/index.css +319 -68
  57. package/dist/index.d.ts +3 -1
  58. package/dist/index.js +9 -3
  59. package/dist/menu/components/menuButton.d.ts +3 -1
  60. package/dist/menu/components/menuButton.js +66 -47
  61. package/dist/menu/components/menuItem.js +4 -4
  62. package/dist/miniTabs/miniTabs.js +4 -2
  63. package/dist/pageHeader/pageHeaderButton.d.ts +1 -1
  64. package/dist/pageHeader/pageHeaderButton.js +4 -2
  65. package/dist/pagination/pagination.d.ts +19 -4
  66. package/dist/pagination/pagination.js +21 -1
  67. package/dist/pagination/paginationText/paginationText.d.ts +7 -1
  68. package/dist/pagination/paginationText/paginationText.js +6 -3
  69. package/dist/pillExpandable/pillContent.d.ts +3 -2
  70. package/dist/pillExpandable/pillContent.js +2 -2
  71. package/dist/pillExpandable/pillExpandable.js +20 -5
  72. package/dist/pillExpandable/pillExpandablePopoverContent.d.ts +3 -2
  73. package/dist/pillExpandable/pillExpandablePopoverContent.js +1 -1
  74. package/dist/pillExpandable/pillExpandableSimple.d.ts +3 -1
  75. package/dist/pillExpandable/pillExpandableSimple.js +19 -9
  76. package/dist/selectList/selectList.js +1 -0
  77. package/dist/selectList/selectListItem.d.ts +10 -1
  78. package/dist/selectList/selectListItem.js +12 -9
  79. package/dist/table/children/tablePagination.d.ts +1 -1
  80. package/dist/table/children/useTableChildren.d.ts +4 -2
  81. package/dist/table/children/useTableChildren.js +64 -16
  82. package/dist/table/nested/nestedData.d.ts +29 -1
  83. package/dist/table/nested/nestedData.js +45 -4
  84. package/dist/table/nested/useNestedRows.js +18 -22
  85. package/dist/table/nested/useShowMore.d.ts +41 -0
  86. package/dist/table/nested/useShowMore.js +56 -0
  87. package/dist/table/selectable/interfaces.d.ts +17 -0
  88. package/dist/table/selectable/useDragSelection.d.ts +10 -0
  89. package/dist/table/selectable/useDragSelection.js +145 -0
  90. package/dist/table/selectable/useSelectableRows.d.ts +5 -2
  91. package/dist/table/selectable/useSelectableRows.js +131 -36
  92. package/dist/table/selectable/utils/calculateSelectionState.d.ts +1 -1
  93. package/dist/table/selectable/utils/calculateSelectionState.js +43 -7
  94. package/dist/table/selectable/utils/checkRow.js +4 -2
  95. package/dist/table/selectable/utils/getCurrentPageSelection.js +9 -5
  96. package/dist/table/selectable/utils/getDragSelectionRows.d.ts +15 -0
  97. package/dist/table/selectable/utils/getDragSelectionRows.js +28 -0
  98. package/dist/table/selectable/utils/getRangeIds.d.ts +2 -0
  99. package/dist/table/selectable/utils/getRangeIds.js +21 -0
  100. package/dist/table/selectable/utils/isRowChecked.d.ts +1 -1
  101. package/dist/table/selectable/utils/isRowChecked.js +40 -7
  102. package/dist/table/table.d.ts +1 -2
  103. package/dist/table/table.js +58 -31
  104. package/dist/tabs/tabs.d.ts +1 -0
  105. package/dist/tabs/tabs.js +50 -17
  106. package/dist/textInputRaw/textInputRaw.js +3 -2
  107. package/dist/tooltip/tooltip.d.ts +2 -0
  108. package/dist/tooltip/tooltip.js +19 -7
  109. package/dist/utils/localization/translations/ar-001.json +1 -0
  110. package/dist/utils/localization/translations/bg-BG.json +1 -0
  111. package/dist/utils/localization/translations/cs.json +1 -0
  112. package/dist/utils/localization/translations/da-DK.json +1 -0
  113. package/dist/utils/localization/translations/de.json +1 -0
  114. package/dist/utils/localization/translations/el-GR.json +1 -0
  115. package/dist/utils/localization/translations/en.json +4 -0
  116. package/dist/utils/localization/translations/es.json +1 -0
  117. package/dist/utils/localization/translations/et-EE.json +1 -0
  118. package/dist/utils/localization/translations/fi-FI.json +1 -0
  119. package/dist/utils/localization/translations/fr-FR.json +1 -0
  120. package/dist/utils/localization/translations/fr.json +1 -0
  121. package/dist/utils/localization/translations/hu-HU.json +1 -0
  122. package/dist/utils/localization/translations/id.json +1 -0
  123. package/dist/utils/localization/translations/it.json +1 -0
  124. package/dist/utils/localization/translations/ja.json +1 -0
  125. package/dist/utils/localization/translations/ka-GE.json +1 -0
  126. package/dist/utils/localization/translations/ko-KR.json +1 -0
  127. package/dist/utils/localization/translations/lt-LT.json +1 -0
  128. package/dist/utils/localization/translations/lv-LV.json +1 -0
  129. package/dist/utils/localization/translations/ms.json +1 -0
  130. package/dist/utils/localization/translations/nb-NO.json +1 -0
  131. package/dist/utils/localization/translations/nl.json +1 -0
  132. package/dist/utils/localization/translations/pl.json +1 -0
  133. package/dist/utils/localization/translations/pt-BR.json +1 -0
  134. package/dist/utils/localization/translations/pt-PT.json +1 -0
  135. package/dist/utils/localization/translations/ro-RO.json +1 -0
  136. package/dist/utils/localization/translations/sk-SK.json +1 -0
  137. package/dist/utils/localization/translations/sv.json +1 -0
  138. package/dist/utils/localization/translations/th.json +1 -0
  139. package/dist/utils/localization/translations/tr.json +1 -0
  140. package/dist/utils/localization/translations/zh-Hans.json +1 -0
  141. package/dist/utils/localization/translations/zh-TW.json +1 -0
  142. package/dist/waiting/waiting.js +97 -1
  143. package/esm/absolute/absolute.js +5 -1
  144. package/esm/button/button.d.ts +2 -1
  145. package/esm/button/button.js +22 -5
  146. package/esm/checkboxListWithAction/checkboxListWithAction.d.ts +2 -0
  147. package/esm/checkboxListWithAction/checkboxListWithAction.js +1 -1
  148. package/esm/commonHelpers/ShowMoreCell.d.ts +5 -0
  149. package/esm/commonHelpers/ShowMoreCell.js +57 -0
  150. package/esm/commonHelpers/getAriaAttributes.js +6 -9
  151. package/esm/commonHelpers/getNonAriaProps.d.ts +11 -0
  152. package/esm/commonHelpers/getNonAriaProps.js +15 -0
  153. package/esm/commonHelpers/hooks/useScroll.d.ts +1 -1
  154. package/esm/commonHelpers/hooks/useScroll.js +6 -6
  155. package/esm/commonHelpers/isAriaProp.d.ts +9 -0
  156. package/esm/commonHelpers/isAriaProp.js +9 -0
  157. package/esm/commonHelpers/showMoreRow.d.ts +28 -0
  158. package/esm/commonHelpers/showMoreRow.js +22 -0
  159. package/esm/commonHelpers/tabsKeyboard.d.ts +1 -1
  160. package/esm/commonHelpers/tabsKeyboard.js +15 -1
  161. package/esm/commonStyles/colors/colorsConstant.js +11 -11
  162. package/esm/dataFeed/dataFeedColumnsItems.js +3 -1
  163. package/esm/dataGrid/columns/checkboxColumn/checkboxCell.d.ts +2 -1
  164. package/esm/dataGrid/columns/checkboxColumn/checkboxCell.js +1 -1
  165. package/esm/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.d.ts +4 -2
  166. package/esm/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.js +10 -1
  167. package/esm/dataGrid/dataGrid.d.ts +5 -1
  168. package/esm/dataGrid/dataGrid.js +38 -2
  169. package/esm/dataGrid/lazyLoadingEnd/lazyLoadingEnd.d.ts +3 -0
  170. package/esm/dataGrid/lazyLoadingEnd/lazyLoadingEnd.js +45 -0
  171. package/esm/dataGrid/row/row.js +20 -2
  172. package/esm/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +3 -1
  173. package/esm/dataGrid/withSelectableRows/components/bulkActions/bulkActions.js +39 -4
  174. package/esm/dataGrid/withSelectableRows/withSelectableRows.js +73 -12
  175. package/esm/dropdown/dropdownTrigger.d.ts +1 -1
  176. package/esm/dropdownRaw/dropdownHelper.d.ts +12 -0
  177. package/esm/dropdownRaw/dropdownHelper.js +30 -10
  178. package/esm/dropdownRaw/dropdownRaw.js +37 -9
  179. package/esm/dropdownRaw/dropdownSearchableTrigger.d.ts +2 -1
  180. package/esm/dropdownRaw/dropdownSearchableTrigger.js +13 -6
  181. package/esm/dropdownRaw/dropdownTrigger.d.ts +2 -1
  182. package/esm/dropdownRaw/dropdownTrigger.js +2 -2
  183. package/esm/dropdownRaw/stateReducer/stateReducer.d.ts +8 -0
  184. package/esm/dropdownRaw/stateReducer/stateReducer.js +5 -2
  185. package/esm/dropdownRaw/types.d.ts +36 -0
  186. package/esm/filterButton/filterButton.d.ts +1 -1
  187. package/esm/formGroup/hooks/rowHooks/useLabelClasses.js +8 -2
  188. package/esm/formLayout/utils/applyLayoutPosition/applyLayoutPosition.d.ts +2 -1
  189. package/esm/formLayout/utils/applyLayoutPosition/applyLayoutPosition.js +37 -90
  190. package/esm/header/components/collapsedItemsControl/collapsedItemsControl.d.ts +1 -1
  191. package/esm/header/components/collapsedItemsControl/collapsedItemsControl.js +6 -2
  192. package/esm/header/headerButton.d.ts +3 -1
  193. package/esm/header/headerButton.js +4 -2
  194. package/esm/header/headerMenu.d.ts +2 -0
  195. package/esm/header/headerMenu.js +1 -1
  196. package/esm/index.d.ts +3 -1
  197. package/esm/index.js +3 -1
  198. package/esm/menu/components/menuButton.d.ts +3 -1
  199. package/esm/menu/components/menuButton.js +66 -47
  200. package/esm/menu/components/menuItem.js +4 -4
  201. package/esm/miniTabs/miniTabs.js +4 -2
  202. package/esm/pageHeader/pageHeaderButton.d.ts +1 -1
  203. package/esm/pageHeader/pageHeaderButton.js +4 -2
  204. package/esm/pagination/pagination.d.ts +19 -4
  205. package/esm/pagination/pagination.js +21 -1
  206. package/esm/pagination/paginationText/paginationText.d.ts +7 -1
  207. package/esm/pagination/paginationText/paginationText.js +6 -3
  208. package/esm/pillExpandable/pillContent.d.ts +3 -2
  209. package/esm/pillExpandable/pillContent.js +2 -2
  210. package/esm/pillExpandable/pillExpandable.js +20 -5
  211. package/esm/pillExpandable/pillExpandablePopoverContent.d.ts +3 -2
  212. package/esm/pillExpandable/pillExpandablePopoverContent.js +1 -1
  213. package/esm/pillExpandable/pillExpandableSimple.d.ts +3 -1
  214. package/esm/pillExpandable/pillExpandableSimple.js +20 -10
  215. package/esm/selectList/selectList.js +1 -0
  216. package/esm/selectList/selectListItem.d.ts +10 -1
  217. package/esm/selectList/selectListItem.js +12 -9
  218. package/esm/table/children/tablePagination.d.ts +1 -1
  219. package/esm/table/children/useTableChildren.d.ts +4 -2
  220. package/esm/table/children/useTableChildren.js +64 -16
  221. package/esm/table/nested/nestedData.d.ts +29 -1
  222. package/esm/table/nested/nestedData.js +44 -3
  223. package/esm/table/nested/useNestedRows.js +18 -22
  224. package/esm/table/nested/useShowMore.d.ts +41 -0
  225. package/esm/table/nested/useShowMore.js +52 -0
  226. package/esm/table/selectable/interfaces.d.ts +17 -0
  227. package/esm/table/selectable/useDragSelection.d.ts +10 -0
  228. package/esm/table/selectable/useDragSelection.js +141 -0
  229. package/esm/table/selectable/useSelectableRows.d.ts +5 -2
  230. package/esm/table/selectable/useSelectableRows.js +129 -35
  231. package/esm/table/selectable/utils/calculateSelectionState.d.ts +1 -1
  232. package/esm/table/selectable/utils/calculateSelectionState.js +43 -7
  233. package/esm/table/selectable/utils/checkRow.js +4 -2
  234. package/esm/table/selectable/utils/getCurrentPageSelection.js +9 -5
  235. package/esm/table/selectable/utils/getDragSelectionRows.d.ts +15 -0
  236. package/esm/table/selectable/utils/getDragSelectionRows.js +24 -0
  237. package/esm/table/selectable/utils/getRangeIds.d.ts +2 -0
  238. package/esm/table/selectable/utils/getRangeIds.js +17 -0
  239. package/esm/table/selectable/utils/isRowChecked.d.ts +1 -1
  240. package/esm/table/selectable/utils/isRowChecked.js +40 -7
  241. package/esm/table/table.d.ts +1 -2
  242. package/esm/table/table.js +43 -16
  243. package/esm/tabs/tabs.d.ts +1 -0
  244. package/esm/tabs/tabs.js +50 -17
  245. package/esm/textInputRaw/textInputRaw.js +3 -2
  246. package/esm/tooltip/tooltip.d.ts +2 -0
  247. package/esm/tooltip/tooltip.js +19 -7
  248. package/esm/utils/localization/translations/ar-001.json +1 -0
  249. package/esm/utils/localization/translations/bg-BG.json +1 -0
  250. package/esm/utils/localization/translations/cs.json +1 -0
  251. package/esm/utils/localization/translations/da-DK.json +1 -0
  252. package/esm/utils/localization/translations/de.json +1 -0
  253. package/esm/utils/localization/translations/el-GR.json +1 -0
  254. package/esm/utils/localization/translations/en.json +4 -0
  255. package/esm/utils/localization/translations/es.json +1 -0
  256. package/esm/utils/localization/translations/et-EE.json +1 -0
  257. package/esm/utils/localization/translations/fi-FI.json +1 -0
  258. package/esm/utils/localization/translations/fr-FR.json +1 -0
  259. package/esm/utils/localization/translations/fr.json +1 -0
  260. package/esm/utils/localization/translations/hu-HU.json +1 -0
  261. package/esm/utils/localization/translations/id.json +1 -0
  262. package/esm/utils/localization/translations/it.json +1 -0
  263. package/esm/utils/localization/translations/ja.json +1 -0
  264. package/esm/utils/localization/translations/ka-GE.json +1 -0
  265. package/esm/utils/localization/translations/ko-KR.json +1 -0
  266. package/esm/utils/localization/translations/lt-LT.json +1 -0
  267. package/esm/utils/localization/translations/lv-LV.json +1 -0
  268. package/esm/utils/localization/translations/ms.json +1 -0
  269. package/esm/utils/localization/translations/nb-NO.json +1 -0
  270. package/esm/utils/localization/translations/nl.json +1 -0
  271. package/esm/utils/localization/translations/pl.json +1 -0
  272. package/esm/utils/localization/translations/pt-BR.json +1 -0
  273. package/esm/utils/localization/translations/pt-PT.json +1 -0
  274. package/esm/utils/localization/translations/ro-RO.json +1 -0
  275. package/esm/utils/localization/translations/sk-SK.json +1 -0
  276. package/esm/utils/localization/translations/sv.json +1 -0
  277. package/esm/utils/localization/translations/th.json +1 -0
  278. package/esm/utils/localization/translations/tr.json +1 -0
  279. package/esm/utils/localization/translations/zh-Hans.json +1 -0
  280. package/esm/utils/localization/translations/zh-TW.json +1 -0
  281. package/esm/waiting/waiting.js +98 -2
  282. package/package.json +15 -3
@@ -7,6 +7,8 @@ import { SelectList } from "../../selectList/selectList";
7
7
  import { CheckboxState } from "../../checkbox/checkboxState";
8
8
  import { SelectableRowsColumnWrapper } from "./columns/selectableRowsColumnWrapper";
9
9
  import { useLanguage } from "../../utils/localization/useLanguage";
10
+ import { useDragSelection } from "../../table/selectable/useDragSelection";
11
+ import { getDragSelectionRows } from "../../table/selectable/utils/getDragSelectionRows";
10
12
  injectString("cs", "Select all", "Vybrat v\u0161e");
11
13
  injectString("da-DK", "Select all", "V\xE6lg alle");
12
14
  injectString("de", "Select all", "Alle ausw\xE4hlen");
@@ -200,13 +202,29 @@ export const withSelectableRows = DataGridComponent => {
200
202
  const selectMenuRef = useRef(null);
201
203
  const selections = getSelections(selection);
202
204
  const allSelected = selection !== undefined && selection.allSelected;
203
- const wrapper = useMemo(() => selectMode ? new SelectableRowsColumnWrapper(selections, {
204
- createTitle: options.createTitle,
205
- headerTitle: options.headerTitle,
206
- condition: options.condition || options.checkboxVisible,
207
- disabled: options.checkboxDisabled ? options.checkboxDisabled : entity => options.selectionLimit !== undefined ? !selections.has(entity.id) && selections.size >= options.selectionLimit : false,
208
- header: options.selectionLimit === undefined && options.checkboxDisabled === undefined && options.checkboxVisible === undefined && options.condition === undefined || options.checkboxInHeader === true && !options.selectionLimit
209
- }, selectMenuRef) : null, [selectMode, selections, options.createTitle, options.headerTitle, options.condition, options.checkboxVisible, options.checkboxDisabled, options.selectionLimit, options.checkboxInHeader]);
205
+ const isCheckboxVisible = useCallback(entity => {
206
+ const condition = options.condition || options.checkboxVisible;
207
+ return condition ? condition(entity) : true;
208
+ }, [options.condition, options.checkboxVisible]);
209
+ const isCheckboxDisabled = useCallback(entity => {
210
+ if (options.checkboxDisabled) {
211
+ return options.checkboxDisabled(entity);
212
+ }
213
+ if (options.selectionLimit !== undefined) {
214
+ return !selections.has(entity.id) && selections.size >= options.selectionLimit;
215
+ }
216
+ return false;
217
+ }, [options, selections]);
218
+ const wrapper = useMemo(() => {
219
+ var _a;
220
+ return selectMode ? new SelectableRowsColumnWrapper(selections, {
221
+ createTitle: options.createTitle,
222
+ headerTitle: options.headerTitle,
223
+ condition: options.condition || options.checkboxVisible,
224
+ disabled: (_a = options.checkboxDisabled) !== null && _a !== void 0 ? _a : isCheckboxDisabled,
225
+ header: options.selectionLimit === undefined && options.checkboxDisabled === undefined && options.checkboxVisible === undefined && options.condition === undefined || options.checkboxInHeader === true && !options.selectionLimit
226
+ }, selectMenuRef) : null;
227
+ }, [selectMode, selections, options.createTitle, options.headerTitle, options.condition, options.checkboxVisible, options.checkboxDisabled, options.selectionLimit, options.checkboxInHeader, isCheckboxDisabled]);
210
228
  if (wrapper) {
211
229
  wrapper.selectionState = calculateSelectionState(entities, selections, allSelected, options);
212
230
  }
@@ -214,9 +232,10 @@ export const withSelectableRows = DataGridComponent => {
214
232
  const newSelections = new Set(selections);
215
233
  entities.forEach(entity => {
216
234
  if (checked) {
217
- const isVisible = options.condition ? options.condition(entity) : options.checkboxVisible ? options.checkboxVisible(entity) : true;
235
+ // Intentionally not isCheckboxDisabled: "select all" ignores the selection
236
+ // limit, it only skips rows the consumer explicitly disabled.
218
237
  const isEnabled = !options.checkboxDisabled || !options.checkboxDisabled(entity);
219
- if (isVisible && isEnabled) {
238
+ if (isCheckboxVisible(entity) && isEnabled) {
220
239
  newSelections.add(entity.id);
221
240
  }
222
241
  return;
@@ -229,8 +248,49 @@ export const withSelectableRows = DataGridComponent => {
229
248
  allSelected: newState === SelectionState.All,
230
249
  turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
231
250
  });
232
- }, [selections, entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
251
+ }, [selections, entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll, isCheckboxVisible]);
252
+ const {
253
+ rows: dragRows,
254
+ entityById
255
+ } = useMemo(() => getDragSelectionRows(entities), [entities]);
256
+ const isRowSelectable = useCallback(row => {
257
+ const entity = entityById.get(row.id);
258
+ return !!entity && isCheckboxVisible(entity) && !isCheckboxDisabled(entity);
259
+ }, [entityById, isCheckboxVisible, isCheckboxDisabled]);
260
+ // "Select all" is held as a flag rather than a list of ids, so materialise the page before
261
+ // a range starts editing it — otherwise the range would be applied to an empty selection.
262
+ const getBaseSelection = useCallback(() => allSelected ? new Set(entities.map(entity => entity.id)) : new Set(selections), [allSelected, entities, selections]);
263
+ const onBatchSelect = useCallback((rangeIds, select, base) => {
264
+ const result = new Set(base);
265
+ const limit = options.selectionLimit;
266
+ for (const id of rangeIds) {
267
+ if (select) {
268
+ if (limit !== undefined && result.size >= limit) {
269
+ break;
270
+ }
271
+ result.add(id);
272
+ } else {
273
+ result.delete(id);
274
+ }
275
+ }
276
+ const newState = calculateSelectionState(entities, result, false, options);
277
+ onSelect({
278
+ selected: [...result],
279
+ allSelected: newState === SelectionState.All,
280
+ turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
281
+ });
282
+ }, [entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
283
+ const {
284
+ onCheckboxMouseDown,
285
+ suppressNextChangeRef
286
+ } = useDragSelection(dragRows, props.ref, onBatchSelect, getBaseSelection, isRowSelectable, selectMode);
233
287
  const onSelectListener = useCallback(([id, checked]) => {
288
+ // A drag or shift-click has already emitted the whole range; swallow the click that
289
+ // ends it so the row it landed on is not toggled back.
290
+ if (suppressNextChangeRef.current) {
291
+ suppressNextChangeRef.current = false;
292
+ return;
293
+ }
234
294
  if (allSelected) {
235
295
  const newSelection = new Set(entities.map(entity => entity.id));
236
296
  newSelection.delete(id);
@@ -252,7 +312,7 @@ export const withSelectableRows = DataGridComponent => {
252
312
  allSelected: newState === SelectionState.All,
253
313
  turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
254
314
  });
255
- }, [entities, selections, allSelected, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
315
+ }, [entities, selections, allSelected, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll, suppressNextChangeRef]);
256
316
  const onSelectAll = useCallback(([checked]) => {
257
317
  if (checked && ((selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll) || options.turnOffSelectAll)) {
258
318
  selectAll(true);
@@ -301,10 +361,11 @@ export const withSelectableRows = DataGridComponent => {
301
361
  wrapper.attach("change", onSelectListener);
302
362
  wrapper.attach("change-all", onSelectAll);
303
363
  wrapper.attach("toggle", onTriggerClick);
364
+ wrapper.attach("mousedown", ([id, checked, e]) => onCheckboxMouseDown(id, checked, e));
304
365
  return () => {
305
366
  wrapper.detach();
306
367
  };
307
- }, [wrapper, onSelectListener, onSelectAll, onTriggerClick]);
368
+ }, [wrapper, onSelectListener, onSelectAll, onTriggerClick, onCheckboxMouseDown]);
308
369
  const listColumns = useMemo(() => {
309
370
  const newColumns = columns.map(c => Object.assign({}, c));
310
371
  // Remove CheckboxColumnWrappers from wrappers list
@@ -1 +1 @@
1
- export declare const DropdownTrigger: ({ name, onBlur, isActive, id, triggerRef, searchField, placeholder, disabled, fullWidth, currentSelection, handleClick, inputValue, className, onSearchChange, width, title, triggerAriaLabel, count, inputRef, autocomplete, buttonType, isError, popupId, handleFocusOnPopup, allyPattern, dataAnalyticsId, ...otherProps }: import("../dropdownRaw/dropdownTrigger").IDropdownTrigger) => import("react/jsx-runtime").JSX.Element;
1
+ export declare const DropdownTrigger: ({ name, onBlur, isActive, id, triggerRef, searchField, placeholder, disabled, fullWidth, currentSelection, handleClick, inputValue, className, onSearchChange, width, title, triggerAriaLabel, count, inputRef, autocomplete, buttonType, isError, popupId, handleFocusOnPopup, allyPattern, dataAnalyticsId, isFormItem, ...otherProps }: import("../dropdownRaw/dropdownTrigger").IDropdownTrigger) => import("react/jsx-runtime").JSX.Element;
@@ -12,15 +12,27 @@ export declare const isAllItemsHasOneParent: (listData: IDropdownRawItem[], chil
12
12
  export declare function prepareComboOptionsForList(actionListData: Set<string>, translate: (s: string) => string, options: IDropdownRawItem[], getSelectedFn: () => string[], getSelectedChildFn: (optionId: any) => string[], isFlatList: boolean, getTitle?: (itemId: string) => string, isAllSelected?: boolean): ICheckboxListWithActionOption[];
13
13
  export declare const createOptions: (stateObj: IDropdownState, translate: (s: string) => string, listItem: IDropdownRawItem[], isAllSelected?: boolean) => ICheckboxListWithActionOption[];
14
14
  export declare const sortDropdownItemArray: (arr: IDropdownRawItem[], sortFn?: (a: IDropdownRawItem, b: IDropdownRawItem) => number) => IDropdownRawItem[];
15
+ /**
16
+ * Floats selected items to the top of the list while preserving the relative order within each
17
+ * group (selected and unselected). When `selectedIds` is empty the original array is returned
18
+ * unchanged (no allocation). Uses a single-pass partition to avoid traversing `items` twice.
19
+ */
20
+ export declare const applySortSelectedToTop: (items: IDropdownRawItem[], selectedIds: string[]) => IDropdownRawItem[];
15
21
  export declare const createSingleListOptions: (stateObj: IDropdownState, translate: (s: string) => string, listItem: IDropdownRawItem[]) => {
22
+ destructive: boolean | undefined;
23
+ divider?: boolean | undefined;
16
24
  id: string;
17
25
  children: string;
26
+ title: string;
18
27
  disabled: boolean | undefined;
19
28
  multiLevel: boolean | undefined;
20
29
  }[];
21
30
  export declare const createListDataOptions: (stateObj: IDropdownState, translate: (s: string) => string, listItem: IDropdownRawItem[], isMultiselect: boolean, isAllSelected?: boolean) => ICheckboxListWithActionOption[] | {
31
+ destructive: boolean | undefined;
32
+ divider?: boolean | undefined;
22
33
  id: string;
23
34
  children: string;
35
+ title: string;
24
36
  disabled: boolean | undefined;
25
37
  multiLevel: boolean | undefined;
26
38
  }[];
@@ -45,7 +45,7 @@ export function prepareComboOptionsForList(actionListData, translate, options, g
45
45
  const preparedOptions = options && options.length
46
46
  ? options.map(option => {
47
47
  const selectedChild = getSelectedChildFn(option.id);
48
- return Object.assign({ label: getGroupDescription(option, translate), property: option.id, checked: isAllSelected ? true : selectedIds.has(option.id), isWithAction: actionListData.has(option.id), partialChecked: isAllSelected ? false : selectedChild.length > 0, countSelectedChild: 0, blocked: isFlatList ? option.disabled || false : false }, (getTitle ? { title: getTitle(option.id) } : {}));
48
+ return Object.assign(Object.assign({ label: getGroupDescription(option, translate), property: option.id, checked: isAllSelected ? true : selectedIds.has(option.id), isWithAction: actionListData.has(option.id), partialChecked: isAllSelected ? false : selectedChild.length > 0, countSelectedChild: 0, blocked: isFlatList ? option.disabled || false : false }, (getTitle ? { title: getTitle(option.id) } : {})), (option.divider ? { divider: true } : {}));
49
49
  })
50
50
  : [];
51
51
  return preparedOptions;
@@ -81,16 +81,32 @@ export const sortDropdownItemArray = (arr, sortFn) => {
81
81
  }
82
82
  return arr;
83
83
  };
84
+ /**
85
+ * Floats selected items to the top of the list while preserving the relative order within each
86
+ * group (selected and unselected). When `selectedIds` is empty the original array is returned
87
+ * unchanged (no allocation). Uses a single-pass partition to avoid traversing `items` twice.
88
+ */
89
+ export const applySortSelectedToTop = (items, selectedIds) => {
90
+ if (!selectedIds.length)
91
+ return items;
92
+ const selectedSet = new Set(selectedIds);
93
+ const selected = [];
94
+ const unselected = [];
95
+ for (const item of items) {
96
+ (selectedSet.has(item.id) ? selected : unselected).push(item);
97
+ }
98
+ return [...selected, ...unselected];
99
+ };
84
100
  export const createSingleListOptions = (stateObj, translate, listItem) => {
85
101
  const preparedOptions = listItem && listItem.length
86
- ? listItem.map(option => ({
87
- id: option.id,
88
- children: getGroupDescription(stateObj.groupsMap[option.id] || option, translate),
89
- disabled: option.disabled,
90
- multiLevel: Object.keys(stateObj.groupsMap).length === 0
91
- ? false
92
- : option.children && option.children.length > 0 && stateObj.groupsMap[option.id] !== undefined
93
- }))
102
+ ? listItem.map(option => {
103
+ const description = getGroupDescription(stateObj.groupsMap[option.id] || option, translate);
104
+ return Object.assign(Object.assign({ id: option.id, children: description,
105
+ // Long names are truncated by `zen-ellipsis`, so expose the full text on hover
106
+ title: description, disabled: option.disabled, multiLevel: Object.keys(stateObj.groupsMap).length === 0
107
+ ? false
108
+ : option.children && option.children.length > 0 && stateObj.groupsMap[option.id] !== undefined }, (option.divider ? { divider: true } : {})), { destructive: option.destructive });
109
+ })
94
110
  : [];
95
111
  return preparedOptions;
96
112
  };
@@ -109,7 +125,11 @@ export const compareObjectsArrays = (arr1, arr2) => arr1.length === arr2.length
109
125
  const sameDisabled = el.disabled === el2.disabled ||
110
126
  (el.disabled === undefined && el2.disabled === false) ||
111
127
  (el2.disabled === undefined && el.disabled === false);
112
- return sameId && sameDisabled;
128
+ const sameDivider = el.divider === el2.divider || (el.divider === undefined && el2.divider === false) || (el2.divider === undefined && el.divider === false);
129
+ const sameDestructive = el.destructive === el2.destructive ||
130
+ (el.destructive === undefined && el2.destructive === false) ||
131
+ (el2.destructive === undefined && el.destructive === false);
132
+ return sameId && sameDisabled && sameDivider && sameDestructive;
113
133
  });
114
134
  export const prepareSelectedIdsToItems = (selectedIds, groupsMap, groupsMapSelected) => {
115
135
  const selectedItems = selectedIds.map(id => {
@@ -8,7 +8,7 @@ import { getInitialState, stateReducer, ROOT_GROUP_ID } from "./stateReducer/sta
8
8
  import { StateActionType } from "./stateReducer/stateActionType";
9
9
  import { FOCUSABLE_SELECTOR } from "../utils/focusableSelector";
10
10
  import { useEscape } from "../commonHelpers/hooks/useEscape";
11
- import { checkIsDataProblem, compareObjectsArrays, compareStringsArrays, createListDataOptions, getDataForChange, getListDataWithDisabled, getSelectedCount, getStringFromAllSelected, getStringFromSelected, isAllChildrenSelected, isAllItemsHasOneParent, isEveryItemSelected, prepareSelectedIdsToItems, sortDropdownItemArray } from "./dropdownHelper";
11
+ import { applySortSelectedToTop, checkIsDataProblem, compareObjectsArrays, compareStringsArrays, createListDataOptions, getDataForChange, getListDataWithDisabled, getSelectedCount, getStringFromAllSelected, getStringFromSelected, isAllChildrenSelected, isAllItemsHasOneParent, isEveryItemSelected, prepareSelectedIdsToItems, sortDropdownItemArray } from "./dropdownHelper";
12
12
  import { DropdownTrigger } from "./dropdownTrigger";
13
13
  import { isFocusable } from "../dialog/dialogHelpers";
14
14
  import { useLanguage } from "../utils/localization/useLanguage";
@@ -127,7 +127,8 @@ export const DropdownRaw = props => {
127
127
  mobileSheetStackingClassName,
128
128
  isError,
129
129
  firstParentNodeIsVisible,
130
- dataAnalyticsId
130
+ dataAnalyticsId,
131
+ sortSelectedToTop = false
131
132
  } = props;
132
133
  const {
133
134
  isFormSection
@@ -937,7 +938,7 @@ export const DropdownRaw = props => {
937
938
  const currentAbort = abortToken.current;
938
939
  controlData(currentAbort.signal, newValue, state.isChecked);
939
940
  }, [controlData, state.isChecked]);
940
- const containerClassName = classNames(["zen-dropdown", isFormSection ? "zen-dropdown--form-item" : "", "zen-dropdown__container", className || ""]);
941
+ const containerClassName = classNames(["zen-dropdown", isFormSection || isFormItemVal ? "zen-dropdown--form-item" : "", "zen-dropdown__container", className || ""]);
941
942
  const handleCheckboxChange = useCallback(e => {
942
943
  const isChecked = e.target.checked;
943
944
  dispatchState({
@@ -1131,9 +1132,35 @@ export const DropdownRaw = props => {
1131
1132
  }
1132
1133
  if (state.showList) {
1133
1134
  const isSearchMode = state.inputValue && !state.currentId;
1134
- const currentListData = createListDataOptions(state, translate, isSearchMode ? sortDropdownItemArray(state.listData, sortFn).slice(0, listLimit).filter(el => el.id !== state.rootId) :
1135
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1136
- sortDropdownItemArray(((_b = state.groupsMap[state.currentId || state.rootId]) === null || _b === void 0 ? void 0 : _b.children) || [], sortFn).slice(0, listLimit) || [], multiselect, currentAllSelected);
1135
+ // For the non-search path, applySortSelectedToTop must run BEFORE .slice(0, listLimit)
1136
+ // so that selected items located beyond listLimit in sort order are floated into the
1137
+ // visible window rather than being discarded by the clip.
1138
+ // In search mode sort-to-top is suspended (results appear in natural/sortFn order).
1139
+ let rawItems;
1140
+ let pinnedCount = 0;
1141
+ if (isSearchMode) {
1142
+ rawItems = sortDropdownItemArray(state.listData, sortFn).slice(0, listLimit).filter(el => el.id !== state.rootId);
1143
+ } else {
1144
+ const children = sortDropdownItemArray(((_b = state.groupsMap[state.currentId || state.rootId]) === null || _b === void 0 ? void 0 : _b.children) || [], sortFn);
1145
+ // hasApplyButton=false (default): uses the open-time snapshot — items don't jump
1146
+ // while the dropdown is open; sort applies on the next open (confirmed design intent).
1147
+ // hasApplyButton=true: uses globalSelectedIds (committed selection) — reordering
1148
+ // only takes effect after the user clicks "Apply".
1149
+ const idsForSort = hasApplyButton ? state.globalSelectedIds : state.sortedTopSnapshot;
1150
+ const floated = sortSelectedToTop ? applySortSelectedToTop(children, idsForSort) : children;
1151
+ rawItems = floated.slice(0, listLimit);
1152
+ if (sortSelectedToTop) {
1153
+ const selectedSet = new Set(idsForSort);
1154
+ pinnedCount = rawItems.filter(item => selectedSet.has(item.id)).length;
1155
+ }
1156
+ }
1157
+ const listData = createListDataOptions(state, translate, rawItems, multiselect, currentAllSelected);
1158
+ // Explicit bounds check (rather than relying on CheckboxListWithAction's own
1159
+ // `ind < optionsArr.length - 1` guard) keeps the "don't draw a trailing divider"
1160
+ // intent local to where the boundary is computed.
1161
+ const currentListData = multiselect && sortSelectedToTop && pinnedCount > 0 && pinnedCount < listData.length ? listData.map((opt, ind) => ind === pinnedCount - 1 ? Object.assign(Object.assign({}, opt), {
1162
+ divider: true
1163
+ }) : opt) : listData;
1137
1164
  return _jsx(DropdownList, {
1138
1165
  onBackButtonClick: handleBackButtonClick,
1139
1166
  onSelectAllClick: isSearchMode ? handleSelectAllInSearch : handleSelectAllClick,
@@ -1167,7 +1194,7 @@ export const DropdownRaw = props => {
1167
1194
  });
1168
1195
  }
1169
1196
  return null;
1170
- }, [state, isLoading, isQueryMode, fetchState === null || fetchState === void 0 ? void 0 : fetchState.isLoading, fetchState === null || fetchState === void 0 ? void 0 : fetchState.error, handleClearClick, handleCancelClick, handleApplyClick, hasApplyButton, memoizedWithFooter, translate, sortFn, listLimit, multiselect, currentAllSelected, handleBackButtonClick, handleSelectAllInSearch, handleSelectAllClick, handleSelect, handleChangeCurrentId, handleSingleSelection, isMobile, filterName, forceSelection, width, selectAllButton, memoizedIsApplyButtonDisabled, memoizedIsClearButtonDisabled, isCheckboxMode, handleCheckboxChange, checkboxLabel, selectListId]);
1197
+ }, [state, isLoading, isQueryMode, fetchState === null || fetchState === void 0 ? void 0 : fetchState.isLoading, fetchState === null || fetchState === void 0 ? void 0 : fetchState.error, handleClearClick, handleCancelClick, handleApplyClick, hasApplyButton, memoizedWithFooter, translate, sortFn, listLimit, multiselect, currentAllSelected, handleBackButtonClick, handleSelectAllInSearch, handleSelectAllClick, handleSelect, handleChangeCurrentId, handleSingleSelection, isMobile, filterName, forceSelection, width, selectAllButton, memoizedIsApplyButtonDisabled, memoizedIsClearButtonDisabled, isCheckboxMode, handleCheckboxChange, checkboxLabel, selectListId, sortSelectedToTop]);
1171
1198
  const currentStringFromSelected = isFullSelectionMode && hasApplyButton && state.globalIsAllSelected || isFullSelectionMode && !hasApplyButton && state.isAllSelected ? getStringFromAllSelected(state.groupsMap, translate, state.rootId) : getStringFromSelected(hasApplyButton ? state.globalSelectedIds : state.selectedIds, state.groupsMapSelected, translate, state.rootId);
1172
1199
  const memoizedCurrentSelection = useMemo(() => showSelection && !state.inputValue ? currentStringFromSelected : "", [showSelection, state.inputValue, currentStringFromSelected]);
1173
1200
  const parentTriggerWidth = ((_b = comboboxRef.current) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect().width) || 420;
@@ -1211,7 +1238,7 @@ export const DropdownRaw = props => {
1211
1238
  isError: isError,
1212
1239
  disabled: disabled,
1213
1240
  count: showCounterPill ? countSelected : 0,
1214
- fullWidth: fullWidthTriggerButton,
1241
+ fullWidth: isFormItemVal && !searchField ? true : fullWidthTriggerButton,
1215
1242
  inputValue: state.inputValue,
1216
1243
  placeholder: placeholder || translate("Filter by group"),
1217
1244
  searchField: searchField && !isMobile ? searchField : false,
@@ -1227,7 +1254,8 @@ export const DropdownRaw = props => {
1227
1254
  handleFocusOnPopup: handleFocusOnPopup,
1228
1255
  popupId: memoizedAllyPattern === "selectOnlyCombobox" ? selectListId : popupId,
1229
1256
  allyPattern: memoizedAllyPattern,
1230
- dataAnalyticsId: dataAnalyticsId
1257
+ dataAnalyticsId: dataAnalyticsId,
1258
+ isFormItem: isFormItemVal
1231
1259
  }, accessibilityProps)), _jsx(DropdownPopup, {
1232
1260
  alignment: alignment,
1233
1261
  triggerRef: triggerRef,
@@ -23,9 +23,10 @@ interface IDropdownSearchableTrigger {
23
23
  autocomplete?: string;
24
24
  handleFocusOnPopup?: () => void;
25
25
  dataAnalyticsId?: string;
26
+ isFormItem?: boolean;
26
27
  }
27
28
  export declare const DropdownSearchableTrigger: {
28
- ({ value, className, onChange, placeholder, isOpenPopup, inputRef, handleClick, width, title, id, disabled, count, currentSelection, isError, fullWidth, ref, name, onBlur, popupId, autocomplete, handleFocusOnPopup, dataAnalyticsId, ...otherProps }: IDropdownSearchableTrigger): import("react/jsx-runtime").JSX.Element;
29
+ ({ value, className, onChange, placeholder, isOpenPopup, inputRef, handleClick, width, title, id, disabled, count, currentSelection, isError, fullWidth, ref, name, onBlur, popupId, autocomplete, handleFocusOnPopup, dataAnalyticsId, isFormItem, ...otherProps }: IDropdownSearchableTrigger): import("react/jsx-runtime").JSX.Element;
29
30
  displayName: string;
30
31
  };
31
32
  export declare const TRANSLATIONS: string[];
@@ -17,6 +17,8 @@ import { useLanguage } from "../utils/localization/useLanguage";
17
17
  import { useDriveClassName } from "../utils/theme/useDriveClassName";
18
18
  import { useDrive } from "../utils/theme/useDrive";
19
19
  import { FormSectionContext } from "../formSection/utils/formSectionProvider";
20
+ import { getAriaAttributes } from "../commonHelpers/getAriaAttributes";
21
+ import { getNonAriaProps } from "../commonHelpers/getNonAriaProps";
20
22
  injectString("cs", "Filter by group", "Filtrovat podle skupiny");
21
23
  injectString("da-DK", "Filter by group", "Filtrer efter gruppe");
22
24
  injectString("de", "Filter by group", "Nach Gruppe filtern");
@@ -172,9 +174,10 @@ export const DropdownSearchableTrigger = _a => {
172
174
  popupId,
173
175
  autocomplete,
174
176
  handleFocusOnPopup,
175
- dataAnalyticsId
177
+ dataAnalyticsId,
178
+ isFormItem
176
179
  } = _a,
177
- otherProps = __rest(_a, ["value", "className", "onChange", "placeholder", "isOpenPopup", "inputRef", "handleClick", "width", "title", "id", "disabled", "count", "currentSelection", "isError", "fullWidth", "ref", "name", "onBlur", "popupId", "autocomplete", "handleFocusOnPopup", "dataAnalyticsId"])
180
+ otherProps = __rest(_a, ["value", "className", "onChange", "placeholder", "isOpenPopup", "inputRef", "handleClick", "width", "title", "id", "disabled", "count", "currentSelection", "isError", "fullWidth", "ref", "name", "onBlur", "popupId", "autocomplete", "handleFocusOnPopup", "dataAnalyticsId", "isFormItem"])
178
181
  // eslint-disable-next-line complexity
179
182
  ;
180
183
  const {
@@ -193,6 +196,10 @@ export const DropdownSearchableTrigger = _a => {
193
196
  } : {};
194
197
  const isLargeNumber = count && count > 99;
195
198
  const clearRef = useRef(null);
199
+ // The element with role="combobox" is the inner TextInputRaw, not the wrapper, so aria-* props
200
+ // have to reach the input. Everything else stays on the wrapper.
201
+ const accessibilityProps = getAriaAttributes(otherProps);
202
+ const restProps = getNonAriaProps(otherProps);
196
203
  const handleKeydown = e => {
197
204
  if (e.key === "Enter" && !isOpenPopup) {
198
205
  handleClick(true);
@@ -222,10 +229,10 @@ export const DropdownSearchableTrigger = _a => {
222
229
  onChange(undefined);
223
230
  };
224
231
  return _jsxs("div", Object.assign({
225
- className: classNames(["zen-dropdown-searchable-trigger", isError ? "zen-dropdown-searchable-trigger--error" : "", driveComponentClass || "", isFormSection ? "zen-dropdown-searchable-trigger--form-item" : "", disabled ? "zen-dropdown-searchable-trigger--disabled" : ""])
232
+ className: classNames(["zen-dropdown-searchable-trigger", isError ? "zen-dropdown-searchable-trigger--error" : "", driveComponentClass || "", isFormSection || isFormItem ? "zen-dropdown-searchable-trigger--form-item" : "", disabled ? "zen-dropdown-searchable-trigger--disabled" : ""])
226
233
  }, inputStyle, {
227
234
  ref: ref
228
- }, otherProps, {
235
+ }, restProps, {
229
236
  onClick: disabled ? () => {} : clickHandler,
230
237
  "data-analytics-id": dataAnalyticsId,
231
238
  children: [_jsxs("div", {
@@ -234,7 +241,7 @@ export const DropdownSearchableTrigger = _a => {
234
241
  children: [_jsx("div", {
235
242
  className: "zen-dropdown-searchable-trigger__input-container",
236
243
  onKeyDown: handleKeydown,
237
- children: _jsx(TextInputRaw, {
244
+ children: _jsx(TextInputRaw, Object.assign({
238
245
  value: value,
239
246
  placeholder: currentSelection ? currentSelection : placeholder || translate("Filter by group"),
240
247
  className: classNames(["zen-dropdown-searchable-trigger__input", "zen-ellipsis", currentSelection ? "zen-dropdown-searchable-trigger__input--selected" : ""]),
@@ -250,7 +257,7 @@ export const DropdownSearchableTrigger = _a => {
250
257
  ariaHaspopup: "dialog",
251
258
  role: "combobox",
252
259
  autocomplete: autocomplete
253
- })
260
+ }, accessibilityProps))
254
261
  }), count ? _jsx("div", {
255
262
  className: "zen-dropdown-searchable-trigger__label-element",
256
263
  children: _jsx("div", {
@@ -27,6 +27,7 @@ export interface IDropdownTrigger extends IZenComponentProps {
27
27
  handleFocusOnPopup?: () => void;
28
28
  allyPattern?: "selectOnlyCombobox" | "comboboxWithDialog" | "buttonWithDialog" | "buttonWithMenu";
29
29
  dataAnalyticsId?: string;
30
+ isFormItem?: boolean;
30
31
  }
31
- export declare const DropdownTrigger: ({ name, onBlur, isActive, id, triggerRef, searchField, placeholder, disabled, fullWidth, currentSelection, handleClick, inputValue, className, onSearchChange, width, title, triggerAriaLabel, count, inputRef, autocomplete, buttonType, isError, popupId, handleFocusOnPopup, allyPattern, dataAnalyticsId, ...otherProps }: IDropdownTrigger) => import("react/jsx-runtime").JSX.Element;
32
+ export declare const DropdownTrigger: ({ name, onBlur, isActive, id, triggerRef, searchField, placeholder, disabled, fullWidth, currentSelection, handleClick, inputValue, className, onSearchChange, width, title, triggerAriaLabel, count, inputRef, autocomplete, buttonType, isError, popupId, handleFocusOnPopup, allyPattern, dataAnalyticsId, isFormItem, ...otherProps }: IDropdownTrigger) => import("react/jsx-runtime").JSX.Element;
32
33
  export declare const TRANSLATIONS: string[];
@@ -16,13 +16,13 @@ import { useMemo, useRef } from "react";
16
16
  import { classNames } from "../commonHelpers/classNames/classNames";
17
17
  import { getAllyTriggerProps } from "./dropdownHelper";
18
18
  export const DropdownTrigger = (_a) => {
19
- var { name, onBlur, isActive, id, triggerRef, searchField, placeholder, disabled, fullWidth, currentSelection, handleClick, inputValue, className, onSearchChange = () => { }, width, title, triggerAriaLabel, count, inputRef, autocomplete, buttonType, isError, popupId, handleFocusOnPopup, allyPattern = "buttonWithDialog", dataAnalyticsId } = _a, otherProps = __rest(_a, ["name", "onBlur", "isActive", "id", "triggerRef", "searchField", "placeholder", "disabled", "fullWidth", "currentSelection", "handleClick", "inputValue", "className", "onSearchChange", "width", "title", "triggerAriaLabel", "count", "inputRef", "autocomplete", "buttonType", "isError", "popupId", "handleFocusOnPopup", "allyPattern", "dataAnalyticsId"]);
19
+ var { name, onBlur, isActive, id, triggerRef, searchField, placeholder, disabled, fullWidth, currentSelection, handleClick, inputValue, className, onSearchChange = () => { }, width, title, triggerAriaLabel, count, inputRef, autocomplete, buttonType, isError, popupId, handleFocusOnPopup, allyPattern = "buttonWithDialog", dataAnalyticsId, isFormItem } = _a, otherProps = __rest(_a, ["name", "onBlur", "isActive", "id", "triggerRef", "searchField", "placeholder", "disabled", "fullWidth", "currentSelection", "handleClick", "inputValue", "className", "onSearchChange", "width", "title", "triggerAriaLabel", "count", "inputRef", "autocomplete", "buttonType", "isError", "popupId", "handleFocusOnPopup", "allyPattern", "dataAnalyticsId", "isFormItem"]);
20
20
  const elInpRef = useRef(null);
21
21
  const handleButtonClick = () => {
22
22
  handleClick(!isActive);
23
23
  };
24
24
  const allyTriggerProps = useMemo(() => getAllyTriggerProps(allyPattern), [allyPattern]);
25
- return (_jsx(_Fragment, { children: searchField ? (_jsx(DropdownSearchableTrigger, Object.assign({ value: inputValue || "", name: name, onChange: onSearchChange, isOpenPopup: isActive, inputRef: inputRef || elInpRef, handleClick: handleClick, handleFocusOnPopup: handleFocusOnPopup, ref: triggerRef, width: width, placeholder: placeholder, disabled: disabled, id: id, title: title, count: count, currentSelection: currentSelection, className: className, isError: isError, fullWidth: fullWidth, popupId: popupId, autocomplete: autocomplete, dataAnalyticsId: dataAnalyticsId }, otherProps))) : (_jsx(FilterButton, Object.assign({ ref: triggerRef, id: id, name: name, onBlur: onBlur, className: classNames(["zen-dropdown__trigger-button", isError ? "zen-dropdown__trigger-button--error" : "", className || ""]), onClick: handleButtonClick, disabled: disabled, isActive: isActive, fullWidth: width ? true : fullWidth, maxWidth: width, minWidth: width, quantity: count || undefined, type: buttonType, title: title, ariaLabel: triggerAriaLabel || currentSelection || placeholder, "aria-expanded": isActive, "aria-controls": popupId }, allyTriggerProps, { dataAnalyticsId: dataAnalyticsId }, otherProps, { children: currentSelection ? (_jsx("span", { className: classNames([
25
+ return (_jsx(_Fragment, { children: searchField ? (_jsx(DropdownSearchableTrigger, Object.assign({ value: inputValue || "", name: name, onChange: onSearchChange, isOpenPopup: isActive, inputRef: inputRef || elInpRef, handleClick: handleClick, handleFocusOnPopup: handleFocusOnPopup, ref: triggerRef, width: width, placeholder: placeholder, disabled: disabled, id: id, title: title, count: count, currentSelection: currentSelection, className: className, isError: isError, fullWidth: fullWidth, popupId: popupId, autocomplete: autocomplete, dataAnalyticsId: dataAnalyticsId, isFormItem: isFormItem }, otherProps))) : (_jsx(FilterButton, Object.assign({ ref: triggerRef, id: id, name: name, onBlur: onBlur, className: classNames(["zen-dropdown__trigger-button", isError ? "zen-dropdown__trigger-button--error" : "", className || ""]), onClick: handleButtonClick, disabled: disabled, isActive: isActive, fullWidth: width ? true : fullWidth, maxWidth: width, minWidth: width, quantity: count || undefined, type: buttonType, title: title, ariaLabel: triggerAriaLabel || currentSelection || placeholder, "aria-expanded": isActive, "aria-controls": popupId }, allyTriggerProps, { dataAnalyticsId: dataAnalyticsId }, otherProps, { children: currentSelection ? (_jsx("span", { className: classNames([
26
26
  "zen-dropdown__trigger-button-text",
27
27
  buttonType ? `zen-dropdown__trigger-button-text--${buttonType.toString()}` : ""
28
28
  ]), children: currentSelection })) : (placeholder) }))) }));
@@ -31,6 +31,13 @@ export interface IDropdownState {
31
31
  defaultValueIsChecked?: boolean;
32
32
  globalIsChecked?: boolean;
33
33
  firstParentNodeIsVisible?: boolean;
34
+ /**
35
+ * Snapshot of `selectedIds` captured when the dropdown transitions from closed to open
36
+ * (sortSelectedToTop, hasApplyButton=false path). Captured in the reducer — rather than via a
37
+ * ref mutated during render — so it is safe under concurrent rendering (an interrupted/discarded
38
+ * render can't cause a stale snapshot to be reused) and is directly testable via dispatch.
39
+ */
40
+ sortedTopSnapshot: string[];
34
41
  }
35
42
  export interface IStateReducer extends Reducer<IDropdownState, TStateAction> {
36
43
  }
@@ -62,5 +69,6 @@ export declare const getInitialState: (isFullSelectionMode: boolean, comboItems:
62
69
  listLimit: number;
63
70
  resultsExceedListLimit: boolean;
64
71
  firstParentNodeIsVisible: boolean | undefined;
72
+ sortedTopSnapshot: string[];
65
73
  };
66
74
  export declare function stateReducer(state: IDropdownState, action: TStateAction): IDropdownState;
@@ -47,7 +47,8 @@ export const getInitialState = (isFullSelectionMode, comboItems, selection, list
47
47
  globalIsChecked: isChecked,
48
48
  listLimit,
49
49
  resultsExceedListLimit: false,
50
- firstParentNodeIsVisible: firstParentNodeIsVisible
50
+ firstParentNodeIsVisible: firstParentNodeIsVisible,
51
+ sortedTopSnapshot: selection
51
52
  };
52
53
  };
53
54
  // eslint-disable-next-line complexity
@@ -99,7 +100,9 @@ export function stateReducer(state, action) {
99
100
  case StateActionType.SetCurrentId:
100
101
  return Object.assign(Object.assign({}, state), { currentId: payload || undefined });
101
102
  case StateActionType.SetIsOpenCombo:
102
- return Object.assign(Object.assign({}, state), { isOpenCombo: payload });
103
+ return Object.assign(Object.assign({}, state), { isOpenCombo: payload,
104
+ // Capture the sortSelectedToTop snapshot exactly on the closed→open transition.
105
+ sortedTopSnapshot: payload && !state.isOpenCombo ? [...state.selectedIds] : state.sortedTopSnapshot });
103
106
  case StateActionType.ResetSelection:
104
107
  return Object.assign(Object.assign({}, state), { selectedIds: [...state.defaultValue], isAllSelected: state.defaultValueIsAllSelected, isChecked: typeof state.isChecked === "boolean" ? state.defaultValueIsChecked || false : undefined });
105
108
  case StateActionType.ResetStateToGlobal:
@@ -15,6 +15,14 @@ export interface IDropdownRawItem extends IEntityWithId {
15
15
  children?: IEntityWithId[];
16
16
  color?: IColor;
17
17
  disabled?: boolean;
18
+ /** When true, renders a 1px separator line below this item. Purely visual — does not affect selection or keyboard navigation. */
19
+ divider?: boolean;
20
+ /**
21
+ * When true, renders the item label in `--text-error-message` red. Visual signal only — does not prevent selection.
22
+ * Only applies in single-select (SelectList) mode; ignored in multiselect (CheckboxListWithAction).
23
+ * Disabled+destructive renders with `--accents-error--main` (#ffeceb) on a transparent background, no hover feedback.
24
+ */
25
+ destructive?: boolean;
18
26
  }
19
27
  interface IFetchState<T> {
20
28
  data: T | undefined;
@@ -69,6 +77,34 @@ interface IDropdownBase extends IChipsParent {
69
77
  mobileSheetStackingClassName?: string;
70
78
  firstParentNodeIsVisible?: boolean;
71
79
  dataAnalyticsId?: string;
80
+ /**
81
+ * When `true`, floats currently-selected items to the top of the list when the dropdown opens.
82
+ * Selected items maintain their relative order among themselves; unselected items maintain
83
+ * their relative order below.
84
+ *
85
+ * **Reactivity — sort applies on open, not live:**
86
+ * - `hasApplyButton=false` (default): the sort is snapshotted at open-time. Checking or
87
+ * unchecking items while the dropdown is open does **not** reorder the list immediately;
88
+ * the user closes and reopens the dropdown to see the updated order.
89
+ * - `hasApplyButton=true`: order reflects the last committed selection (`globalSelectedIds`),
90
+ * so reordering only takes effect after the user clicks "Apply" and then reopens.
91
+ *
92
+ * In search mode the sort is suspended so results appear in natural/sortFn order.
93
+ * Compatible with `sortFn`: `sortFn` is applied within each group before concatenation.
94
+ * The float is applied before `listLimit` clipping, so selected items beyond the limit are
95
+ * still surfaced into the visible window.
96
+ * In nested lists the sort applies per-level: when the user drills into a sub-group, selected
97
+ * children of that group float to the top of that group's view, independent of other levels.
98
+ *
99
+ * **Known limitation — full-selection mode (`isAllSelected: true`):** when the value uses the
100
+ * `{ selected, isAllSelected: true }` form and `hasApplyButton=false`, `state.selectedIds`
101
+ * may be empty (all items are implicitly selected rather than enumerated). In this combination
102
+ * `sortSelectedToTop` silently does nothing — all items are already selected so the visual
103
+ * result is equivalent. If you need explicit float ordering, use the enumerated `selected`
104
+ * array form instead.
105
+ * @default false
106
+ */
107
+ sortSelectedToTop?: boolean;
72
108
  }
73
109
  interface IDropdownBaseDefault {
74
110
  disabled?: boolean;
@@ -2,7 +2,7 @@ import React, { RefObject } from "react";
2
2
  import "./filterButton.less";
3
3
  import { IZenComponentProps } from "../commonHelpers/zenComponent";
4
4
  import { ButtonType } from "../button/buttonType";
5
- export type TFilterButton = typeof ButtonType.Secondary | typeof ButtonType.Tertiary | typeof ButtonType.TertiaryBlack;
5
+ export type TFilterButton = typeof ButtonType.Primary | typeof ButtonType.Destructive | typeof ButtonType.Secondary | typeof ButtonType.Tertiary | typeof ButtonType.TertiaryBlack | typeof ButtonType.TertiaryDestructive;
6
6
  export interface IFilterButton extends IZenComponentProps {
7
7
  id?: string;
8
8
  name?: string;
@@ -5,7 +5,9 @@ import { getOneLabelOneControlClasses } from "../../utils/getLabelClasses/getOne
5
5
  import { useLabelAlign } from "../useLabelAlign";
6
6
  import { useMode } from "../useMode";
7
7
  import { useSectionType } from "../useSectionType";
8
+ const TOP_ALIGN_CLASS = "zen-form-field-label--top";
8
9
  export const useLabelClasses = (state) => {
10
+ var _a, _b;
9
11
  const type = useSectionType();
10
12
  const mode = useMode();
11
13
  const columns = useColumns();
@@ -15,10 +17,14 @@ export const useLabelClasses = (state) => {
15
17
  return;
16
18
  }
17
19
  const { labelClasses1, labelClasses2 } = getLabelClasses(state, columns, labelAlign, mode, type);
20
+ const effectiveLabelAlign1 = ((_a = state.elements.label1) === null || _a === void 0 ? void 0 : _a.labelAlign) || labelAlign;
21
+ const effectiveLabelAlign2 = ((_b = state.elements.label2) === null || _b === void 0 ? void 0 : _b.labelAlign) || labelAlign;
22
+ const topAlignClass1 = effectiveLabelAlign1 === "top" ? ` ${TOP_ALIGN_CLASS}` : "";
23
+ const topAlignClass2 = effectiveLabelAlign2 === "top" ? ` ${TOP_ALIGN_CLASS}` : "";
18
24
  if (state.elements.label1 && labelClasses1) {
19
- state.elements.label1.className = `${labelClasses1} ${state.elements.label1.className || ""}`;
25
+ state.elements.label1.className = `${labelClasses1}${topAlignClass1} ${state.elements.label1.className || ""}`;
20
26
  }
21
27
  if (state.elements.label2 && labelClasses2) {
22
- state.elements.label2.className = `${labelClasses2} ${state.elements.label2.className || ""}`;
28
+ state.elements.label2.className = `${labelClasses2}${topAlignClass2} ${state.elements.label2.className || ""}`;
23
29
  }
24
30
  };
@@ -1 +1,2 @@
1
- export declare const applyLayoutPosition: (components: any, result: any) => void;
1
+ import { ReactElement } from "react";
2
+ export declare const applyLayoutPosition: (components: ReactElement[], result: ReactElement[]) => void;