@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.
- package/README.md +67 -1
- package/README.md.baseline +1 -0
- package/dist/absolute/absolute.js +5 -1
- package/dist/button/button.d.ts +2 -1
- package/dist/button/button.js +22 -5
- package/dist/checkboxListWithAction/checkboxListWithAction.d.ts +2 -0
- package/dist/checkboxListWithAction/checkboxListWithAction.js +1 -1
- package/dist/commonHelpers/ShowMoreCell.d.ts +5 -0
- package/dist/commonHelpers/ShowMoreCell.js +66 -0
- package/dist/commonHelpers/getAriaAttributes.js +6 -9
- package/dist/commonHelpers/getNonAriaProps.d.ts +11 -0
- package/dist/commonHelpers/getNonAriaProps.js +19 -0
- package/dist/commonHelpers/hooks/useScroll.d.ts +1 -1
- package/dist/commonHelpers/hooks/useScroll.js +6 -6
- package/dist/commonHelpers/isAriaProp.d.ts +9 -0
- package/dist/commonHelpers/isAriaProp.js +13 -0
- package/dist/commonHelpers/showMoreRow.d.ts +28 -0
- package/dist/commonHelpers/showMoreRow.js +29 -0
- package/dist/commonHelpers/tabsKeyboard.d.ts +1 -1
- package/dist/commonHelpers/tabsKeyboard.js +15 -1
- package/dist/commonStyles/colors/colors.less +18 -0
- package/dist/dataFeed/dataFeedColumnsItems.js +3 -1
- package/dist/dataGrid/columns/checkboxColumn/checkboxCell.d.ts +2 -1
- package/dist/dataGrid/columns/checkboxColumn/checkboxCell.js +1 -1
- package/dist/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.d.ts +4 -2
- package/dist/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.js +10 -1
- package/dist/dataGrid/dataGrid.d.ts +5 -1
- package/dist/dataGrid/dataGrid.js +39 -2
- package/dist/dataGrid/lazyLoadingEnd/lazyLoadingEnd.d.ts +3 -0
- package/dist/dataGrid/lazyLoadingEnd/lazyLoadingEnd.js +54 -0
- package/dist/dataGrid/row/row.js +20 -2
- package/dist/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +3 -1
- package/dist/dataGrid/withSelectableRows/components/bulkActions/bulkActions.js +39 -4
- package/dist/dataGrid/withSelectableRows/withSelectableRows.js +73 -12
- package/dist/dropdown/dropdownTrigger.d.ts +1 -1
- package/dist/dropdownRaw/dropdownHelper.d.ts +12 -0
- package/dist/dropdownRaw/dropdownHelper.js +32 -11
- package/dist/dropdownRaw/dropdownRaw.js +36 -8
- package/dist/dropdownRaw/dropdownSearchableTrigger.d.ts +2 -1
- package/dist/dropdownRaw/dropdownSearchableTrigger.js +13 -6
- package/dist/dropdownRaw/dropdownTrigger.d.ts +2 -1
- package/dist/dropdownRaw/dropdownTrigger.js +2 -2
- package/dist/dropdownRaw/stateReducer/stateReducer.d.ts +8 -0
- package/dist/dropdownRaw/stateReducer/stateReducer.js +5 -2
- package/dist/dropdownRaw/types.d.ts +36 -0
- package/dist/filterButton/filterButton.d.ts +1 -1
- package/dist/formGroup/hooks/rowHooks/useLabelClasses.js +8 -2
- package/dist/formLayout/utils/applyLayoutPosition/applyLayoutPosition.d.ts +2 -1
- package/dist/formLayout/utils/applyLayoutPosition/applyLayoutPosition.js +37 -90
- package/dist/header/components/collapsedItemsControl/collapsedItemsControl.d.ts +1 -1
- package/dist/header/components/collapsedItemsControl/collapsedItemsControl.js +6 -2
- package/dist/header/headerButton.d.ts +3 -1
- package/dist/header/headerButton.js +4 -2
- package/dist/header/headerMenu.d.ts +2 -0
- package/dist/header/headerMenu.js +1 -1
- package/dist/index.css +319 -68
- package/dist/index.d.ts +3 -1
- package/dist/index.js +9 -3
- package/dist/menu/components/menuButton.d.ts +3 -1
- package/dist/menu/components/menuButton.js +66 -47
- package/dist/menu/components/menuItem.js +4 -4
- package/dist/miniTabs/miniTabs.js +4 -2
- package/dist/pageHeader/pageHeaderButton.d.ts +1 -1
- package/dist/pageHeader/pageHeaderButton.js +4 -2
- package/dist/pagination/pagination.d.ts +19 -4
- package/dist/pagination/pagination.js +21 -1
- package/dist/pagination/paginationText/paginationText.d.ts +7 -1
- package/dist/pagination/paginationText/paginationText.js +6 -3
- package/dist/pillExpandable/pillContent.d.ts +3 -2
- package/dist/pillExpandable/pillContent.js +2 -2
- package/dist/pillExpandable/pillExpandable.js +20 -5
- package/dist/pillExpandable/pillExpandablePopoverContent.d.ts +3 -2
- package/dist/pillExpandable/pillExpandablePopoverContent.js +1 -1
- package/dist/pillExpandable/pillExpandableSimple.d.ts +3 -1
- package/dist/pillExpandable/pillExpandableSimple.js +19 -9
- package/dist/selectList/selectList.js +1 -0
- package/dist/selectList/selectListItem.d.ts +10 -1
- package/dist/selectList/selectListItem.js +12 -9
- package/dist/table/children/tablePagination.d.ts +1 -1
- package/dist/table/children/useTableChildren.d.ts +4 -2
- package/dist/table/children/useTableChildren.js +64 -16
- package/dist/table/nested/nestedData.d.ts +29 -1
- package/dist/table/nested/nestedData.js +45 -4
- package/dist/table/nested/useNestedRows.js +18 -22
- package/dist/table/nested/useShowMore.d.ts +41 -0
- package/dist/table/nested/useShowMore.js +56 -0
- package/dist/table/selectable/interfaces.d.ts +17 -0
- package/dist/table/selectable/useDragSelection.d.ts +10 -0
- package/dist/table/selectable/useDragSelection.js +145 -0
- package/dist/table/selectable/useSelectableRows.d.ts +5 -2
- package/dist/table/selectable/useSelectableRows.js +131 -36
- package/dist/table/selectable/utils/calculateSelectionState.d.ts +1 -1
- package/dist/table/selectable/utils/calculateSelectionState.js +43 -7
- package/dist/table/selectable/utils/checkRow.js +4 -2
- package/dist/table/selectable/utils/getCurrentPageSelection.js +9 -5
- package/dist/table/selectable/utils/getDragSelectionRows.d.ts +15 -0
- package/dist/table/selectable/utils/getDragSelectionRows.js +28 -0
- package/dist/table/selectable/utils/getRangeIds.d.ts +2 -0
- package/dist/table/selectable/utils/getRangeIds.js +21 -0
- package/dist/table/selectable/utils/isRowChecked.d.ts +1 -1
- package/dist/table/selectable/utils/isRowChecked.js +40 -7
- package/dist/table/table.d.ts +1 -2
- package/dist/table/table.js +58 -31
- package/dist/tabs/tabs.d.ts +1 -0
- package/dist/tabs/tabs.js +50 -17
- package/dist/textInputRaw/textInputRaw.js +3 -2
- package/dist/tooltip/tooltip.d.ts +2 -0
- package/dist/tooltip/tooltip.js +19 -7
- package/dist/utils/localization/translations/ar-001.json +1 -0
- package/dist/utils/localization/translations/bg-BG.json +1 -0
- package/dist/utils/localization/translations/cs.json +1 -0
- package/dist/utils/localization/translations/da-DK.json +1 -0
- package/dist/utils/localization/translations/de.json +1 -0
- package/dist/utils/localization/translations/el-GR.json +1 -0
- package/dist/utils/localization/translations/en.json +4 -0
- package/dist/utils/localization/translations/es.json +1 -0
- package/dist/utils/localization/translations/et-EE.json +1 -0
- package/dist/utils/localization/translations/fi-FI.json +1 -0
- package/dist/utils/localization/translations/fr-FR.json +1 -0
- package/dist/utils/localization/translations/fr.json +1 -0
- package/dist/utils/localization/translations/hu-HU.json +1 -0
- package/dist/utils/localization/translations/id.json +1 -0
- package/dist/utils/localization/translations/it.json +1 -0
- package/dist/utils/localization/translations/ja.json +1 -0
- package/dist/utils/localization/translations/ka-GE.json +1 -0
- package/dist/utils/localization/translations/ko-KR.json +1 -0
- package/dist/utils/localization/translations/lt-LT.json +1 -0
- package/dist/utils/localization/translations/lv-LV.json +1 -0
- package/dist/utils/localization/translations/ms.json +1 -0
- package/dist/utils/localization/translations/nb-NO.json +1 -0
- package/dist/utils/localization/translations/nl.json +1 -0
- package/dist/utils/localization/translations/pl.json +1 -0
- package/dist/utils/localization/translations/pt-BR.json +1 -0
- package/dist/utils/localization/translations/pt-PT.json +1 -0
- package/dist/utils/localization/translations/ro-RO.json +1 -0
- package/dist/utils/localization/translations/sk-SK.json +1 -0
- package/dist/utils/localization/translations/sv.json +1 -0
- package/dist/utils/localization/translations/th.json +1 -0
- package/dist/utils/localization/translations/tr.json +1 -0
- package/dist/utils/localization/translations/zh-Hans.json +1 -0
- package/dist/utils/localization/translations/zh-TW.json +1 -0
- package/dist/waiting/waiting.js +97 -1
- package/esm/absolute/absolute.js +5 -1
- package/esm/button/button.d.ts +2 -1
- package/esm/button/button.js +22 -5
- package/esm/checkboxListWithAction/checkboxListWithAction.d.ts +2 -0
- package/esm/checkboxListWithAction/checkboxListWithAction.js +1 -1
- package/esm/commonHelpers/ShowMoreCell.d.ts +5 -0
- package/esm/commonHelpers/ShowMoreCell.js +57 -0
- package/esm/commonHelpers/getAriaAttributes.js +6 -9
- package/esm/commonHelpers/getNonAriaProps.d.ts +11 -0
- package/esm/commonHelpers/getNonAriaProps.js +15 -0
- package/esm/commonHelpers/hooks/useScroll.d.ts +1 -1
- package/esm/commonHelpers/hooks/useScroll.js +6 -6
- package/esm/commonHelpers/isAriaProp.d.ts +9 -0
- package/esm/commonHelpers/isAriaProp.js +9 -0
- package/esm/commonHelpers/showMoreRow.d.ts +28 -0
- package/esm/commonHelpers/showMoreRow.js +22 -0
- package/esm/commonHelpers/tabsKeyboard.d.ts +1 -1
- package/esm/commonHelpers/tabsKeyboard.js +15 -1
- package/esm/commonStyles/colors/colorsConstant.js +11 -11
- package/esm/dataFeed/dataFeedColumnsItems.js +3 -1
- package/esm/dataGrid/columns/checkboxColumn/checkboxCell.d.ts +2 -1
- package/esm/dataGrid/columns/checkboxColumn/checkboxCell.js +1 -1
- package/esm/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.d.ts +4 -2
- package/esm/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.js +10 -1
- package/esm/dataGrid/dataGrid.d.ts +5 -1
- package/esm/dataGrid/dataGrid.js +38 -2
- package/esm/dataGrid/lazyLoadingEnd/lazyLoadingEnd.d.ts +3 -0
- package/esm/dataGrid/lazyLoadingEnd/lazyLoadingEnd.js +45 -0
- package/esm/dataGrid/row/row.js +20 -2
- package/esm/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +3 -1
- package/esm/dataGrid/withSelectableRows/components/bulkActions/bulkActions.js +39 -4
- package/esm/dataGrid/withSelectableRows/withSelectableRows.js +73 -12
- package/esm/dropdown/dropdownTrigger.d.ts +1 -1
- package/esm/dropdownRaw/dropdownHelper.d.ts +12 -0
- package/esm/dropdownRaw/dropdownHelper.js +30 -10
- package/esm/dropdownRaw/dropdownRaw.js +37 -9
- package/esm/dropdownRaw/dropdownSearchableTrigger.d.ts +2 -1
- package/esm/dropdownRaw/dropdownSearchableTrigger.js +13 -6
- package/esm/dropdownRaw/dropdownTrigger.d.ts +2 -1
- package/esm/dropdownRaw/dropdownTrigger.js +2 -2
- package/esm/dropdownRaw/stateReducer/stateReducer.d.ts +8 -0
- package/esm/dropdownRaw/stateReducer/stateReducer.js +5 -2
- package/esm/dropdownRaw/types.d.ts +36 -0
- package/esm/filterButton/filterButton.d.ts +1 -1
- package/esm/formGroup/hooks/rowHooks/useLabelClasses.js +8 -2
- package/esm/formLayout/utils/applyLayoutPosition/applyLayoutPosition.d.ts +2 -1
- package/esm/formLayout/utils/applyLayoutPosition/applyLayoutPosition.js +37 -90
- package/esm/header/components/collapsedItemsControl/collapsedItemsControl.d.ts +1 -1
- package/esm/header/components/collapsedItemsControl/collapsedItemsControl.js +6 -2
- package/esm/header/headerButton.d.ts +3 -1
- package/esm/header/headerButton.js +4 -2
- package/esm/header/headerMenu.d.ts +2 -0
- package/esm/header/headerMenu.js +1 -1
- package/esm/index.d.ts +3 -1
- package/esm/index.js +3 -1
- package/esm/menu/components/menuButton.d.ts +3 -1
- package/esm/menu/components/menuButton.js +66 -47
- package/esm/menu/components/menuItem.js +4 -4
- package/esm/miniTabs/miniTabs.js +4 -2
- package/esm/pageHeader/pageHeaderButton.d.ts +1 -1
- package/esm/pageHeader/pageHeaderButton.js +4 -2
- package/esm/pagination/pagination.d.ts +19 -4
- package/esm/pagination/pagination.js +21 -1
- package/esm/pagination/paginationText/paginationText.d.ts +7 -1
- package/esm/pagination/paginationText/paginationText.js +6 -3
- package/esm/pillExpandable/pillContent.d.ts +3 -2
- package/esm/pillExpandable/pillContent.js +2 -2
- package/esm/pillExpandable/pillExpandable.js +20 -5
- package/esm/pillExpandable/pillExpandablePopoverContent.d.ts +3 -2
- package/esm/pillExpandable/pillExpandablePopoverContent.js +1 -1
- package/esm/pillExpandable/pillExpandableSimple.d.ts +3 -1
- package/esm/pillExpandable/pillExpandableSimple.js +20 -10
- package/esm/selectList/selectList.js +1 -0
- package/esm/selectList/selectListItem.d.ts +10 -1
- package/esm/selectList/selectListItem.js +12 -9
- package/esm/table/children/tablePagination.d.ts +1 -1
- package/esm/table/children/useTableChildren.d.ts +4 -2
- package/esm/table/children/useTableChildren.js +64 -16
- package/esm/table/nested/nestedData.d.ts +29 -1
- package/esm/table/nested/nestedData.js +44 -3
- package/esm/table/nested/useNestedRows.js +18 -22
- package/esm/table/nested/useShowMore.d.ts +41 -0
- package/esm/table/nested/useShowMore.js +52 -0
- package/esm/table/selectable/interfaces.d.ts +17 -0
- package/esm/table/selectable/useDragSelection.d.ts +10 -0
- package/esm/table/selectable/useDragSelection.js +141 -0
- package/esm/table/selectable/useSelectableRows.d.ts +5 -2
- package/esm/table/selectable/useSelectableRows.js +129 -35
- package/esm/table/selectable/utils/calculateSelectionState.d.ts +1 -1
- package/esm/table/selectable/utils/calculateSelectionState.js +43 -7
- package/esm/table/selectable/utils/checkRow.js +4 -2
- package/esm/table/selectable/utils/getCurrentPageSelection.js +9 -5
- package/esm/table/selectable/utils/getDragSelectionRows.d.ts +15 -0
- package/esm/table/selectable/utils/getDragSelectionRows.js +24 -0
- package/esm/table/selectable/utils/getRangeIds.d.ts +2 -0
- package/esm/table/selectable/utils/getRangeIds.js +17 -0
- package/esm/table/selectable/utils/isRowChecked.d.ts +1 -1
- package/esm/table/selectable/utils/isRowChecked.js +40 -7
- package/esm/table/table.d.ts +1 -2
- package/esm/table/table.js +43 -16
- package/esm/tabs/tabs.d.ts +1 -0
- package/esm/tabs/tabs.js +50 -17
- package/esm/textInputRaw/textInputRaw.js +3 -2
- package/esm/tooltip/tooltip.d.ts +2 -0
- package/esm/tooltip/tooltip.js +19 -7
- package/esm/utils/localization/translations/ar-001.json +1 -0
- package/esm/utils/localization/translations/bg-BG.json +1 -0
- package/esm/utils/localization/translations/cs.json +1 -0
- package/esm/utils/localization/translations/da-DK.json +1 -0
- package/esm/utils/localization/translations/de.json +1 -0
- package/esm/utils/localization/translations/el-GR.json +1 -0
- package/esm/utils/localization/translations/en.json +4 -0
- package/esm/utils/localization/translations/es.json +1 -0
- package/esm/utils/localization/translations/et-EE.json +1 -0
- package/esm/utils/localization/translations/fi-FI.json +1 -0
- package/esm/utils/localization/translations/fr-FR.json +1 -0
- package/esm/utils/localization/translations/fr.json +1 -0
- package/esm/utils/localization/translations/hu-HU.json +1 -0
- package/esm/utils/localization/translations/id.json +1 -0
- package/esm/utils/localization/translations/it.json +1 -0
- package/esm/utils/localization/translations/ja.json +1 -0
- package/esm/utils/localization/translations/ka-GE.json +1 -0
- package/esm/utils/localization/translations/ko-KR.json +1 -0
- package/esm/utils/localization/translations/lt-LT.json +1 -0
- package/esm/utils/localization/translations/lv-LV.json +1 -0
- package/esm/utils/localization/translations/ms.json +1 -0
- package/esm/utils/localization/translations/nb-NO.json +1 -0
- package/esm/utils/localization/translations/nl.json +1 -0
- package/esm/utils/localization/translations/pl.json +1 -0
- package/esm/utils/localization/translations/pt-BR.json +1 -0
- package/esm/utils/localization/translations/pt-PT.json +1 -0
- package/esm/utils/localization/translations/ro-RO.json +1 -0
- package/esm/utils/localization/translations/sk-SK.json +1 -0
- package/esm/utils/localization/translations/sv.json +1 -0
- package/esm/utils/localization/translations/th.json +1 -0
- package/esm/utils/localization/translations/tr.json +1 -0
- package/esm/utils/localization/translations/zh-Hans.json +1 -0
- package/esm/utils/localization/translations/zh-TW.json +1 -0
- package/esm/waiting/waiting.js +98 -2
- 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
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1135
|
-
//
|
|
1136
|
-
|
|
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
|
-
},
|
|
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
|
-
|
|
1
|
+
import { ReactElement } from "react";
|
|
2
|
+
export declare const applyLayoutPosition: (components: ReactElement[], result: ReactElement[]) => void;
|