@geotab/zenith 3.16.0-beta.3 → 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dataGrid/columns/checkboxColumn/checkboxCell.d.ts +1 -2
- package/dist/dataGrid/columns/checkboxColumn/checkboxCell.js +1 -1
- package/dist/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.d.ts +2 -4
- package/dist/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.js +1 -10
- package/dist/dataGrid/row/row.js +2 -3
- package/dist/dataGrid/withSelectableRows/withSelectableRows.js +12 -73
- package/dist/table/selectable/interfaces.d.ts +0 -9
- package/dist/table/selectable/useSelectableRows.d.ts +2 -2
- package/dist/table/selectable/useSelectableRows.js +3 -47
- package/dist/table/table.js +1 -1
- package/esm/dataGrid/columns/checkboxColumn/checkboxCell.d.ts +1 -2
- package/esm/dataGrid/columns/checkboxColumn/checkboxCell.js +1 -1
- package/esm/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.d.ts +2 -4
- package/esm/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.js +1 -10
- package/esm/dataGrid/row/row.js +2 -3
- package/esm/dataGrid/withSelectableRows/withSelectableRows.js +12 -73
- package/esm/table/selectable/interfaces.d.ts +0 -9
- package/esm/table/selectable/useSelectableRows.d.ts +2 -2
- package/esm/table/selectable/useSelectableRows.js +3 -47
- package/esm/table/table.js +1 -1
- package/package.json +1 -1
- package/dist/table/selectable/useDragSelection.d.ts +0 -10
- package/dist/table/selectable/useDragSelection.js +0 -139
- package/dist/table/selectable/utils/getDragSelectionRows.d.ts +0 -15
- package/dist/table/selectable/utils/getDragSelectionRows.js +0 -28
- package/dist/table/selectable/utils/getRangeIds.d.ts +0 -2
- package/dist/table/selectable/utils/getRangeIds.js +0 -21
- package/esm/table/selectable/useDragSelection.d.ts +0 -10
- package/esm/table/selectable/useDragSelection.js +0 -135
- package/esm/table/selectable/utils/getDragSelectionRows.d.ts +0 -15
- package/esm/table/selectable/utils/getDragSelectionRows.js +0 -24
- package/esm/table/selectable/utils/getRangeIds.d.ts +0 -2
- package/esm/table/selectable/utils/getRangeIds.js +0 -17
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FC,
|
|
1
|
+
import { FC, PropsWithChildren, ReactElement } from "react";
|
|
2
2
|
import { IZenIdComponentProps } from "../../../commonHelpers/zenComponent";
|
|
3
3
|
import "./checkboxColumn.less";
|
|
4
4
|
interface ICheckboxCellProps extends IZenIdComponentProps {
|
|
@@ -8,7 +8,6 @@ interface ICheckboxCellProps extends IZenIdComponentProps {
|
|
|
8
8
|
disabled?: boolean;
|
|
9
9
|
children?: ReactElement<typeof CheckboxCell.Content>;
|
|
10
10
|
onChange?: (id: string, checked: boolean) => void;
|
|
11
|
-
onMouseDown?: (id: string, checked: boolean, e: ReactMouseEvent) => void;
|
|
12
11
|
}
|
|
13
12
|
interface ICheckboxCell extends FC<ICheckboxCellProps> {
|
|
14
13
|
Content: FC<PropsWithChildren>;
|
|
@@ -4,7 +4,7 @@ exports.CheckboxCell = void 0;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const checkbox_1 = require("../../../checkbox/checkbox");
|
|
6
6
|
const classNames_1 = require("../../../commonHelpers/classNames/classNames");
|
|
7
|
-
const CheckboxCell = ({ id, checked, indeterminate, label, disabled, className, onChange,
|
|
7
|
+
const CheckboxCell = ({ id, checked, indeterminate, label, disabled, className, onChange, children }) => ((0, jsx_runtime_1.jsxs)("div", { className: (0, classNames_1.classNames)(["zen-checkbox-column", className || ""]), children: [(0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { className: "zen-checkbox-column__checkbox", checked: checked, indeterminate: indeterminate, disabled: disabled, title: label, onChange: e => onChange && onChange(id, e.target.checked), wrapped: true }), children] }));
|
|
8
8
|
exports.CheckboxCell = CheckboxCell;
|
|
9
9
|
exports.CheckboxCell.Content = function content({ children }) {
|
|
10
10
|
return (0, jsx_runtime_1.jsx)("div", { className: "zen-checkbox-column__content", children: children });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactNode, RefObject } from "react";
|
|
2
2
|
import { IListColumnWrapper } from "../../listColumn";
|
|
3
3
|
import "./checkboxColumn.less";
|
|
4
4
|
import { SimpleEventHandler } from "../../../commonHelpers/simpleEventHandler";
|
|
@@ -17,8 +17,7 @@ export interface ICheckboxColumnWrapper<T extends object> extends IListColumnWra
|
|
|
17
17
|
attach(event: "toggle", handler: (state: [Event, HTMLButtonElement]) => void): this;
|
|
18
18
|
attach(event: "change", handler: (state: [string, boolean]) => void): this;
|
|
19
19
|
attach(event: "change-all", handler: (state: [boolean]) => void): this;
|
|
20
|
-
|
|
21
|
-
detach(event: "change" | "toggle" | "change-all" | "mousedown", handler?: (state: unknown) => void): this;
|
|
20
|
+
detach(event: "change" | "toggle" | "change-all", handler?: (state: unknown) => void): this;
|
|
22
21
|
}
|
|
23
22
|
export declare enum SelectionState {
|
|
24
23
|
All = 0,
|
|
@@ -35,7 +34,6 @@ export declare class CheckboxColumnWrapper<T extends IEntityWithId> extends Simp
|
|
|
35
34
|
private state;
|
|
36
35
|
private readonly actionsClickHandler;
|
|
37
36
|
private readonly changeHandler;
|
|
38
|
-
private readonly mouseDownHandler;
|
|
39
37
|
private readonly changeHandlerAll;
|
|
40
38
|
constructor(selections: Set<string>, options: ICheckboxColumnOptions<T>, menuTriggerRef: RefObject<HTMLButtonElement | null>);
|
|
41
39
|
get selectionState(): SelectionState;
|
|
@@ -67,15 +67,6 @@ class CheckboxColumnWrapper extends simpleEventHandler_1.SimpleEventHandler {
|
|
|
67
67
|
this.fire("change", [id, checked]);
|
|
68
68
|
}
|
|
69
69
|
});
|
|
70
|
-
// Only fired for enabled checkboxes, so a disabled row can never become a drag anchor.
|
|
71
|
-
Object.defineProperty(this, "mouseDownHandler", {
|
|
72
|
-
enumerable: true,
|
|
73
|
-
configurable: true,
|
|
74
|
-
writable: true,
|
|
75
|
-
value: (id, checked, e) => {
|
|
76
|
-
this.fire("mousedown", [id, checked, e]);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
70
|
Object.defineProperty(this, "changeHandlerAll", {
|
|
80
71
|
enumerable: true,
|
|
81
72
|
configurable: true,
|
|
@@ -101,7 +92,7 @@ class CheckboxColumnWrapper extends simpleEventHandler_1.SimpleEventHandler {
|
|
|
101
92
|
}
|
|
102
93
|
const allowed = this.condition(entity);
|
|
103
94
|
const isDisable = this.disabled ? this.disabled(entity) : this.state === SelectionState.All;
|
|
104
|
-
const cell = ((0, jsx_runtime_1.jsx)(checkboxCell_1.CheckboxCell, { id: entity.id, className: allowed ? "" : "zen-checkbox-column--no-checkbox", checked: this.state === SelectionState.All || this.selections.has(entity.id), indeterminate: false, disabled: isDisable, label: this.options.createTitle(entity), onChange: this.changeHandler,
|
|
95
|
+
const cell = ((0, jsx_runtime_1.jsx)(checkboxCell_1.CheckboxCell, { id: entity.id, className: allowed ? "" : "zen-checkbox-column--no-checkbox", checked: this.state === SelectionState.All || this.selections.has(entity.id), indeterminate: false, disabled: isDisable, label: this.options.createTitle(entity), onChange: this.changeHandler, children: (0, jsx_runtime_1.jsx)(checkboxCell_1.CheckboxCell.Content, { children: value }) }));
|
|
105
96
|
return cell;
|
|
106
97
|
}
|
|
107
98
|
renderHeader(title) {
|
package/dist/dataGrid/row/row.js
CHANGED
|
@@ -60,8 +60,7 @@ const Row = ({ id, entity, columns, visibleRows, flexibleColumnWidth, isLastRow,
|
|
|
60
60
|
return acc;
|
|
61
61
|
}, { cells: [], colspan: 0 }).cells, [columns, expanded, getCellParams, isVisible, onExpandedChange, isActive, active, onClick]);
|
|
62
62
|
const cells = (0, react_1.useMemo)(() => renderCells(entity, false), [entity, renderCells]);
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("tr", { "data-row-id": id, id: mainRowId, role: "row", "aria-level": isTreeGrid ? 1 : undefined, "aria-posinset": isTreeGrid ? ariaPosinset : undefined, "aria-setsize": isTreeGrid ? ariaSetsize : undefined, "aria-expanded": isTreeGrid ? expanded : undefined, className: (0, classNames_1.classNames)(["zen-data-grid__row", className || "", isLastRow ? "zen-data-grid__row--last" : ""]), children: cells }, mainRowId), nestedCells.map((nestedRow, index) => ((0, jsx_runtime_1.jsx)("tr", { "data-row-id": nestedEntities[index].id, id: `${mainRowId}_child_${index}`, role: "row", "aria-level": 2, "aria-posinset": index + 1, "aria-setsize": nestedCells.length, className: "zen-data-grid__row zen-data-grid__row--nested", children: nestedRow }, `${mainRowId}_child_${index}`)))] }));
|
|
63
|
+
const nestedCells = (0, react_1.useMemo)(() => (expanded && entity.children ? entity.children : []).map(nestedEntity => renderCells(nestedEntity, true)), [entity.children, expanded, renderCells]);
|
|
64
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("tr", { "data-row-id": id, id: mainRowId, role: "row", "aria-level": isTreeGrid ? 1 : undefined, "aria-posinset": isTreeGrid ? ariaPosinset : undefined, "aria-setsize": isTreeGrid ? ariaSetsize : undefined, "aria-expanded": isTreeGrid ? expanded : undefined, className: (0, classNames_1.classNames)(["zen-data-grid__row", className || "", isLastRow ? "zen-data-grid__row--last" : ""]), children: cells }, mainRowId), nestedCells.map((nestedRow, index) => ((0, jsx_runtime_1.jsx)("tr", { id: `${mainRowId}_child_${index}`, role: "row", "aria-level": 2, "aria-posinset": index + 1, "aria-setsize": nestedCells.length, className: "zen-data-grid__row zen-data-grid__row--nested", children: nestedRow }, `${mainRowId}_child_${index}`)))] }));
|
|
66
65
|
};
|
|
67
66
|
exports.DataGridRow = (0, react_1.memo)(Row);
|
|
@@ -15,8 +15,6 @@ const selectList_1 = require("../../selectList/selectList");
|
|
|
15
15
|
const checkboxState_1 = require("../../checkbox/checkboxState");
|
|
16
16
|
const selectableRowsColumnWrapper_1 = require("./columns/selectableRowsColumnWrapper");
|
|
17
17
|
const useLanguage_1 = require("../../utils/localization/useLanguage");
|
|
18
|
-
const useDragSelection_1 = require("../../table/selectable/useDragSelection");
|
|
19
|
-
const getDragSelectionRows_1 = require("../../table/selectable/utils/getDragSelectionRows");
|
|
20
18
|
injectString("cs", "Select all", "Vybrat v\u0161e");
|
|
21
19
|
injectString("da-DK", "Select all", "V\xE6lg alle");
|
|
22
20
|
injectString("de", "Select all", "Alle ausw\xE4hlen");
|
|
@@ -211,29 +209,13 @@ const withSelectableRows = DataGridComponent => {
|
|
|
211
209
|
const selectMenuRef = (0, react_1.useRef)(null);
|
|
212
210
|
const selections = (0, exports.getSelections)(selection);
|
|
213
211
|
const allSelected = selection !== undefined && selection.allSelected;
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
if (options.selectionLimit !== undefined) {
|
|
223
|
-
return !selections.has(entity.id) && selections.size >= options.selectionLimit;
|
|
224
|
-
}
|
|
225
|
-
return false;
|
|
226
|
-
}, [options, selections]);
|
|
227
|
-
const wrapper = (0, react_1.useMemo)(() => {
|
|
228
|
-
var _a;
|
|
229
|
-
return selectMode ? new selectableRowsColumnWrapper_1.SelectableRowsColumnWrapper(selections, {
|
|
230
|
-
createTitle: options.createTitle,
|
|
231
|
-
headerTitle: options.headerTitle,
|
|
232
|
-
condition: options.condition || options.checkboxVisible,
|
|
233
|
-
disabled: (_a = options.checkboxDisabled) !== null && _a !== void 0 ? _a : isCheckboxDisabled,
|
|
234
|
-
header: options.selectionLimit === undefined && options.checkboxDisabled === undefined && options.checkboxVisible === undefined && options.condition === undefined || options.checkboxInHeader === true && !options.selectionLimit
|
|
235
|
-
}, selectMenuRef) : null;
|
|
236
|
-
}, [selectMode, selections, options.createTitle, options.headerTitle, options.condition, options.checkboxVisible, options.checkboxDisabled, options.selectionLimit, options.checkboxInHeader, isCheckboxDisabled]);
|
|
212
|
+
const wrapper = (0, react_1.useMemo)(() => selectMode ? new selectableRowsColumnWrapper_1.SelectableRowsColumnWrapper(selections, {
|
|
213
|
+
createTitle: options.createTitle,
|
|
214
|
+
headerTitle: options.headerTitle,
|
|
215
|
+
condition: options.condition || options.checkboxVisible,
|
|
216
|
+
disabled: options.checkboxDisabled ? options.checkboxDisabled : entity => options.selectionLimit !== undefined ? !selections.has(entity.id) && selections.size >= options.selectionLimit : false,
|
|
217
|
+
header: options.selectionLimit === undefined && options.checkboxDisabled === undefined && options.checkboxVisible === undefined && options.condition === undefined || options.checkboxInHeader === true && !options.selectionLimit
|
|
218
|
+
}, selectMenuRef) : null, [selectMode, selections, options.createTitle, options.headerTitle, options.condition, options.checkboxVisible, options.checkboxDisabled, options.selectionLimit, options.checkboxInHeader]);
|
|
237
219
|
if (wrapper) {
|
|
238
220
|
wrapper.selectionState = calculateSelectionState(entities, selections, allSelected, options);
|
|
239
221
|
}
|
|
@@ -241,10 +223,9 @@ const withSelectableRows = DataGridComponent => {
|
|
|
241
223
|
const newSelections = new Set(selections);
|
|
242
224
|
entities.forEach(entity => {
|
|
243
225
|
if (checked) {
|
|
244
|
-
|
|
245
|
-
// limit, it only skips rows the consumer explicitly disabled.
|
|
226
|
+
const isVisible = options.condition ? options.condition(entity) : options.checkboxVisible ? options.checkboxVisible(entity) : true;
|
|
246
227
|
const isEnabled = !options.checkboxDisabled || !options.checkboxDisabled(entity);
|
|
247
|
-
if (
|
|
228
|
+
if (isVisible && isEnabled) {
|
|
248
229
|
newSelections.add(entity.id);
|
|
249
230
|
}
|
|
250
231
|
return;
|
|
@@ -257,49 +238,8 @@ const withSelectableRows = DataGridComponent => {
|
|
|
257
238
|
allSelected: newState === checkboxColumnWrapper_1.SelectionState.All,
|
|
258
239
|
turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
259
240
|
});
|
|
260
|
-
}, [selections, entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
261
|
-
const {
|
|
262
|
-
rows: dragRows,
|
|
263
|
-
entityById
|
|
264
|
-
} = (0, react_1.useMemo)(() => (0, getDragSelectionRows_1.getDragSelectionRows)(entities), [entities]);
|
|
265
|
-
const isRowSelectable = (0, react_1.useCallback)(row => {
|
|
266
|
-
const entity = entityById.get(row.id);
|
|
267
|
-
return !!entity && isCheckboxVisible(entity) && !isCheckboxDisabled(entity);
|
|
268
|
-
}, [entityById, isCheckboxVisible, isCheckboxDisabled]);
|
|
269
|
-
// "Select all" is held as a flag rather than a list of ids, so materialise the page before
|
|
270
|
-
// a range starts editing it — otherwise the range would be applied to an empty selection.
|
|
271
|
-
const getBaseSelection = (0, react_1.useCallback)(() => allSelected ? new Set(entities.map(entity => entity.id)) : new Set(selections), [allSelected, entities, selections]);
|
|
272
|
-
const onBatchSelect = (0, react_1.useCallback)((rangeIds, select, base) => {
|
|
273
|
-
const result = new Set(base);
|
|
274
|
-
const limit = options.selectionLimit;
|
|
275
|
-
for (const id of rangeIds) {
|
|
276
|
-
if (select) {
|
|
277
|
-
if (limit !== undefined && result.size >= limit) {
|
|
278
|
-
break;
|
|
279
|
-
}
|
|
280
|
-
result.add(id);
|
|
281
|
-
} else {
|
|
282
|
-
result.delete(id);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
const newState = calculateSelectionState(entities, result, false, options);
|
|
286
|
-
onSelect({
|
|
287
|
-
selected: [...result],
|
|
288
|
-
allSelected: newState === checkboxColumnWrapper_1.SelectionState.All,
|
|
289
|
-
turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
290
|
-
});
|
|
291
|
-
}, [entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
|
|
292
|
-
const {
|
|
293
|
-
onCheckboxMouseDown,
|
|
294
|
-
suppressNextChangeRef
|
|
295
|
-
} = (0, useDragSelection_1.useDragSelection)(dragRows, props.ref, onBatchSelect, getBaseSelection, isRowSelectable, selectMode);
|
|
241
|
+
}, [selections, entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
|
|
296
242
|
const onSelectListener = (0, react_1.useCallback)(([id, checked]) => {
|
|
297
|
-
// A drag or shift-click has already emitted the whole range; swallow the click that
|
|
298
|
-
// ends it so the row it landed on is not toggled back.
|
|
299
|
-
if (suppressNextChangeRef.current) {
|
|
300
|
-
suppressNextChangeRef.current = false;
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
243
|
if (allSelected) {
|
|
304
244
|
const newSelection = new Set(entities.map(entity => entity.id));
|
|
305
245
|
newSelection.delete(id);
|
|
@@ -321,7 +261,7 @@ const withSelectableRows = DataGridComponent => {
|
|
|
321
261
|
allSelected: newState === checkboxColumnWrapper_1.SelectionState.All,
|
|
322
262
|
turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
323
263
|
});
|
|
324
|
-
}, [entities, selections, allSelected, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
264
|
+
}, [entities, selections, allSelected, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
|
|
325
265
|
const onSelectAll = (0, react_1.useCallback)(([checked]) => {
|
|
326
266
|
if (checked && ((selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll) || options.turnOffSelectAll)) {
|
|
327
267
|
selectAll(true);
|
|
@@ -370,11 +310,10 @@ const withSelectableRows = DataGridComponent => {
|
|
|
370
310
|
wrapper.attach("change", onSelectListener);
|
|
371
311
|
wrapper.attach("change-all", onSelectAll);
|
|
372
312
|
wrapper.attach("toggle", onTriggerClick);
|
|
373
|
-
wrapper.attach("mousedown", ([id, checked, e]) => onCheckboxMouseDown(id, checked, e));
|
|
374
313
|
return () => {
|
|
375
314
|
wrapper.detach();
|
|
376
315
|
};
|
|
377
|
-
}, [wrapper, onSelectListener, onSelectAll, onTriggerClick
|
|
316
|
+
}, [wrapper, onSelectListener, onSelectAll, onTriggerClick]);
|
|
378
317
|
const listColumns = (0, react_1.useMemo)(() => {
|
|
379
318
|
const newColumns = columns.map(c => Object.assign({}, c));
|
|
380
319
|
// Remove CheckboxColumnWrappers from wrappers list
|
|
@@ -8,12 +8,3 @@ export interface ISelectionValue {
|
|
|
8
8
|
all: boolean;
|
|
9
9
|
selected: string[];
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
12
|
-
* One checkbox row in the order it is rendered. Expanded nested rows are part of this list,
|
|
13
|
-
* directly after their parent, so a drag or shift-click range can span nesting levels the
|
|
14
|
-
* same way it spans sibling rows.
|
|
15
|
-
*/
|
|
16
|
-
export interface IDragSelectionRow {
|
|
17
|
-
id: string;
|
|
18
|
-
isNested: boolean;
|
|
19
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
2
|
import { IListColumn } from "../table";
|
|
3
3
|
import { ISelectionValue, SelectionState } from "./interfaces";
|
|
4
4
|
import "./selectableColumn.less";
|
|
@@ -33,7 +33,7 @@ export declare const getEmptySelection: () => {
|
|
|
33
33
|
selected: string[];
|
|
34
34
|
};
|
|
35
35
|
export declare const SelectableWrapperName = "Selectable";
|
|
36
|
-
export declare const useSelectableRows: <T extends IRowEntity<N>, N extends IEntityWithId>(columns: IListColumn<T, N>[], entities: T[], isMobile: boolean, selectMode: boolean, setSelectMode: (value: boolean) => void, selectable?: ISelectableRowsOptions<T, N>, isInfinite?: boolean
|
|
36
|
+
export declare const useSelectableRows: <T extends IRowEntity<N>, N extends IEntityWithId>(columns: IListColumn<T, N>[], entities: T[], isMobile: boolean, selectMode: boolean, setSelectMode: (value: boolean) => void, selectable?: ISelectableRowsOptions<T, N>, isInfinite?: boolean) => {
|
|
37
37
|
selectableColumns: IListColumn<T, N>[];
|
|
38
38
|
selectableFeedWrapper: (primaryData: ReactNode, secondaryData: ReactNode, entity: T | N, isNested: boolean) => [ReactNode, ReactNode];
|
|
39
39
|
};
|
|
@@ -84,8 +84,6 @@ const useLanguage_1 = require("../../utils/localization/useLanguage");
|
|
|
84
84
|
const checkRow_1 = require("./utils/checkRow");
|
|
85
85
|
const isRowChecked_1 = require("./utils/isRowChecked");
|
|
86
86
|
const getCurrentPageSelection_1 = require("./utils/getCurrentPageSelection");
|
|
87
|
-
const useDragSelection_1 = require("./useDragSelection");
|
|
88
|
-
const getDragSelectionRows_1 = require("./utils/getDragSelectionRows");
|
|
89
87
|
const getEmptySelection = () => ({
|
|
90
88
|
all: false,
|
|
91
89
|
selected: []
|
|
@@ -94,7 +92,7 @@ exports.getEmptySelection = getEmptySelection;
|
|
|
94
92
|
exports.SelectableWrapperName = "Selectable";
|
|
95
93
|
// Infinite scroll has no pages, so the header checkbox always means "select all" (never current page).
|
|
96
94
|
const resolveCheckboxEmitsCurrentPage = (isInfinite, checkboxSelectsCurrentPage, turnOffSelectAll) => isInfinite ? false : checkboxSelectsCurrentPage !== null && checkboxSelectsCurrentPage !== void 0 ? checkboxSelectsCurrentPage : turnOffSelectAll;
|
|
97
|
-
const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMode, selectable, isInfinite = false
|
|
95
|
+
const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMode, selectable, isInfinite = false) => {
|
|
98
96
|
var _a;
|
|
99
97
|
const {
|
|
100
98
|
translate
|
|
@@ -164,47 +162,6 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
|
|
|
164
162
|
selectable === null || selectable === void 0 ? void 0 : selectable.onSelect(newValue);
|
|
165
163
|
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
166
164
|
}, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, setState, getNewSelection]);
|
|
167
|
-
const onBatchSelect = (0, react_1.useCallback)((rangeIds, select, base) => {
|
|
168
|
-
var _a;
|
|
169
|
-
const result = new Set(base);
|
|
170
|
-
const limit = selectable === null || selectable === void 0 ? void 0 : selectable.selectionLimit;
|
|
171
|
-
for (const id of rangeIds) {
|
|
172
|
-
if (select && limit !== undefined && result.size >= limit) {
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
(0, checkRow_1.checkRow)(result, selectable, entities, id, select);
|
|
176
|
-
}
|
|
177
|
-
const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, result, ((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all) || false, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy);
|
|
178
|
-
const newValue = {
|
|
179
|
-
selected: [...result],
|
|
180
|
-
all: newState === interfaces_1.SelectionState.All
|
|
181
|
-
};
|
|
182
|
-
setState(newState);
|
|
183
|
-
selectable === null || selectable === void 0 ? void 0 : selectable.onSelect(newValue);
|
|
184
|
-
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
185
|
-
}, [entities, selectable, checkboxVisible, checkboxDisabled, setSelectMode]);
|
|
186
|
-
// Deliberately independent of the current selection, so the drag anchor survives the
|
|
187
|
-
// selection changes a drag itself produces.
|
|
188
|
-
const {
|
|
189
|
-
rows: dragRows,
|
|
190
|
-
entityById
|
|
191
|
-
} = (0, react_1.useMemo)(() => (0, getDragSelectionRows_1.getDragSelectionRows)(entities, expandedRows), [entities, expandedRows]);
|
|
192
|
-
const isSelectable = (0, react_1.useCallback)(row => {
|
|
193
|
-
const entity = entityById.get(row.id);
|
|
194
|
-
return !!entity && checkboxVisible(entity, row.isNested) && !checkboxDisabled(entity, row.isNested);
|
|
195
|
-
}, [entityById, checkboxVisible, checkboxDisabled]);
|
|
196
|
-
const getBaseSelection = (0, react_1.useCallback)(() => state === interfaces_1.SelectionState.All ? (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, selectable) : new Set(selections), [state, entities, selectable, selections]);
|
|
197
|
-
const {
|
|
198
|
-
onCheckboxMouseDown,
|
|
199
|
-
suppressNextChangeRef
|
|
200
|
-
} = (0, useDragSelection_1.useDragSelection)(dragRows, gridRef, onBatchSelect, getBaseSelection, isSelectable, !!selectable);
|
|
201
|
-
const onCheckboxChange = (0, react_1.useCallback)((id, checked) => {
|
|
202
|
-
if (suppressNextChangeRef.current) {
|
|
203
|
-
suppressNextChangeRef.current = false;
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
onSelectListener(id, checked);
|
|
207
|
-
}, [onSelectListener, suppressNextChangeRef]);
|
|
208
165
|
const onChangeSelectionState = (0, react_1.useCallback)(newState => {
|
|
209
166
|
var _a, _b;
|
|
210
167
|
if (newState === interfaces_1.SelectionState.All) {
|
|
@@ -282,8 +239,7 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
|
|
|
282
239
|
indeterminate: checked.indeterminate,
|
|
283
240
|
disabled: isDisable,
|
|
284
241
|
label: checkboxTitle(entity),
|
|
285
|
-
onChange:
|
|
286
|
-
onMouseDown: isDisable ? undefined : onCheckboxMouseDown,
|
|
242
|
+
onChange: onSelectListener,
|
|
287
243
|
children: (0, jsx_runtime_1.jsx)(checkboxCell_1.CheckboxCell.Content, {
|
|
288
244
|
children: value
|
|
289
245
|
})
|
|
@@ -329,7 +285,7 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
|
|
|
329
285
|
return cell;
|
|
330
286
|
}
|
|
331
287
|
};
|
|
332
|
-
}, [checkboxDisabled, checkboxTitle, checkboxVisible, headerTitle, onChangeSelectionState,
|
|
288
|
+
}, [checkboxDisabled, checkboxTitle, checkboxVisible, headerTitle, onChangeSelectionState, onSelectListener, hasSelectable, checkboxEmitsCurrentPage, checkboxInHeaderValue, selectableHeader, selectableTurnOffSelectAll, isInfinite, selectable, selectableState, state, isMobile, checkboxPlaceholder, isEntityChecked, entities, setSelectMode]);
|
|
333
289
|
const selectableFeedWrapper = (0, react_1.useCallback)((primaryData, secondaryData, entity, isNested) => {
|
|
334
290
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
335
291
|
if (!entity) {
|
package/dist/table/table.js
CHANGED
|
@@ -288,7 +288,7 @@ const TableInner = ({
|
|
|
288
288
|
const {
|
|
289
289
|
selectableColumns,
|
|
290
290
|
selectableFeedWrapper
|
|
291
|
-
} = (0, useSelectableRows_1.useSelectableRows)(nestedColumns, entities, isMobile, selectMode, setMobileSelectMode, isLoading ? undefined : selectable, isInfinite
|
|
291
|
+
} = (0, useSelectableRows_1.useSelectableRows)(nestedColumns, entities, isMobile, selectMode, setMobileSelectMode, isLoading ? undefined : selectable, isInfinite);
|
|
292
292
|
const {
|
|
293
293
|
sortableColumns,
|
|
294
294
|
feedSortControl
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FC,
|
|
1
|
+
import { FC, PropsWithChildren, ReactElement } from "react";
|
|
2
2
|
import { IZenIdComponentProps } from "../../../commonHelpers/zenComponent";
|
|
3
3
|
import "./checkboxColumn.less";
|
|
4
4
|
interface ICheckboxCellProps extends IZenIdComponentProps {
|
|
@@ -8,7 +8,6 @@ interface ICheckboxCellProps extends IZenIdComponentProps {
|
|
|
8
8
|
disabled?: boolean;
|
|
9
9
|
children?: ReactElement<typeof CheckboxCell.Content>;
|
|
10
10
|
onChange?: (id: string, checked: boolean) => void;
|
|
11
|
-
onMouseDown?: (id: string, checked: boolean, e: ReactMouseEvent) => void;
|
|
12
11
|
}
|
|
13
12
|
interface ICheckboxCell extends FC<ICheckboxCellProps> {
|
|
14
13
|
Content: FC<PropsWithChildren>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Checkbox } from "../../../checkbox/checkbox";
|
|
3
3
|
import { classNames } from "../../../commonHelpers/classNames/classNames";
|
|
4
|
-
export const CheckboxCell = ({ id, checked, indeterminate, label, disabled, className, onChange,
|
|
4
|
+
export const CheckboxCell = ({ id, checked, indeterminate, label, disabled, className, onChange, children }) => (_jsxs("div", { className: classNames(["zen-checkbox-column", className || ""]), children: [_jsx(Checkbox, { className: "zen-checkbox-column__checkbox", checked: checked, indeterminate: indeterminate, disabled: disabled, title: label, onChange: e => onChange && onChange(id, e.target.checked), wrapped: true }), children] }));
|
|
5
5
|
CheckboxCell.Content = function content({ children }) {
|
|
6
6
|
return _jsx("div", { className: "zen-checkbox-column__content", children: children });
|
|
7
7
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactNode, RefObject } from "react";
|
|
2
2
|
import { IListColumnWrapper } from "../../listColumn";
|
|
3
3
|
import "./checkboxColumn.less";
|
|
4
4
|
import { SimpleEventHandler } from "../../../commonHelpers/simpleEventHandler";
|
|
@@ -17,8 +17,7 @@ export interface ICheckboxColumnWrapper<T extends object> extends IListColumnWra
|
|
|
17
17
|
attach(event: "toggle", handler: (state: [Event, HTMLButtonElement]) => void): this;
|
|
18
18
|
attach(event: "change", handler: (state: [string, boolean]) => void): this;
|
|
19
19
|
attach(event: "change-all", handler: (state: [boolean]) => void): this;
|
|
20
|
-
|
|
21
|
-
detach(event: "change" | "toggle" | "change-all" | "mousedown", handler?: (state: unknown) => void): this;
|
|
20
|
+
detach(event: "change" | "toggle" | "change-all", handler?: (state: unknown) => void): this;
|
|
22
21
|
}
|
|
23
22
|
export declare enum SelectionState {
|
|
24
23
|
All = 0,
|
|
@@ -35,7 +34,6 @@ export declare class CheckboxColumnWrapper<T extends IEntityWithId> extends Simp
|
|
|
35
34
|
private state;
|
|
36
35
|
private readonly actionsClickHandler;
|
|
37
36
|
private readonly changeHandler;
|
|
38
|
-
private readonly mouseDownHandler;
|
|
39
37
|
private readonly changeHandlerAll;
|
|
40
38
|
constructor(selections: Set<string>, options: ICheckboxColumnOptions<T>, menuTriggerRef: RefObject<HTMLButtonElement | null>);
|
|
41
39
|
get selectionState(): SelectionState;
|
|
@@ -64,15 +64,6 @@ export class CheckboxColumnWrapper extends SimpleEventHandler {
|
|
|
64
64
|
this.fire("change", [id, checked]);
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
|
-
// Only fired for enabled checkboxes, so a disabled row can never become a drag anchor.
|
|
68
|
-
Object.defineProperty(this, "mouseDownHandler", {
|
|
69
|
-
enumerable: true,
|
|
70
|
-
configurable: true,
|
|
71
|
-
writable: true,
|
|
72
|
-
value: (id, checked, e) => {
|
|
73
|
-
this.fire("mousedown", [id, checked, e]);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
67
|
Object.defineProperty(this, "changeHandlerAll", {
|
|
77
68
|
enumerable: true,
|
|
78
69
|
configurable: true,
|
|
@@ -98,7 +89,7 @@ export class CheckboxColumnWrapper extends SimpleEventHandler {
|
|
|
98
89
|
}
|
|
99
90
|
const allowed = this.condition(entity);
|
|
100
91
|
const isDisable = this.disabled ? this.disabled(entity) : this.state === SelectionState.All;
|
|
101
|
-
const cell = (_jsx(CheckboxCell, { id: entity.id, className: allowed ? "" : "zen-checkbox-column--no-checkbox", checked: this.state === SelectionState.All || this.selections.has(entity.id), indeterminate: false, disabled: isDisable, label: this.options.createTitle(entity), onChange: this.changeHandler,
|
|
92
|
+
const cell = (_jsx(CheckboxCell, { id: entity.id, className: allowed ? "" : "zen-checkbox-column--no-checkbox", checked: this.state === SelectionState.All || this.selections.has(entity.id), indeterminate: false, disabled: isDisable, label: this.options.createTitle(entity), onChange: this.changeHandler, children: _jsx(CheckboxCell.Content, { children: value }) }));
|
|
102
93
|
return cell;
|
|
103
94
|
}
|
|
104
95
|
renderHeader(title) {
|
package/esm/dataGrid/row/row.js
CHANGED
|
@@ -57,8 +57,7 @@ const Row = ({ id, entity, columns, visibleRows, flexibleColumnWidth, isLastRow,
|
|
|
57
57
|
return acc;
|
|
58
58
|
}, { cells: [], colspan: 0 }).cells, [columns, expanded, getCellParams, isVisible, onExpandedChange, isActive, active, onClick]);
|
|
59
59
|
const cells = useMemo(() => renderCells(entity, false), [entity, renderCells]);
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
return (_jsxs(_Fragment, { children: [_jsx("tr", { "data-row-id": id, id: mainRowId, role: "row", "aria-level": isTreeGrid ? 1 : undefined, "aria-posinset": isTreeGrid ? ariaPosinset : undefined, "aria-setsize": isTreeGrid ? ariaSetsize : undefined, "aria-expanded": isTreeGrid ? expanded : undefined, className: classNames(["zen-data-grid__row", className || "", isLastRow ? "zen-data-grid__row--last" : ""]), children: cells }, mainRowId), nestedCells.map((nestedRow, index) => (_jsx("tr", { "data-row-id": nestedEntities[index].id, id: `${mainRowId}_child_${index}`, role: "row", "aria-level": 2, "aria-posinset": index + 1, "aria-setsize": nestedCells.length, className: "zen-data-grid__row zen-data-grid__row--nested", children: nestedRow }, `${mainRowId}_child_${index}`)))] }));
|
|
60
|
+
const nestedCells = useMemo(() => (expanded && entity.children ? entity.children : []).map(nestedEntity => renderCells(nestedEntity, true)), [entity.children, expanded, renderCells]);
|
|
61
|
+
return (_jsxs(_Fragment, { children: [_jsx("tr", { "data-row-id": id, id: mainRowId, role: "row", "aria-level": isTreeGrid ? 1 : undefined, "aria-posinset": isTreeGrid ? ariaPosinset : undefined, "aria-setsize": isTreeGrid ? ariaSetsize : undefined, "aria-expanded": isTreeGrid ? expanded : undefined, className: classNames(["zen-data-grid__row", className || "", isLastRow ? "zen-data-grid__row--last" : ""]), children: cells }, mainRowId), nestedCells.map((nestedRow, index) => (_jsx("tr", { id: `${mainRowId}_child_${index}`, role: "row", "aria-level": 2, "aria-posinset": index + 1, "aria-setsize": nestedCells.length, className: "zen-data-grid__row zen-data-grid__row--nested", children: nestedRow }, `${mainRowId}_child_${index}`)))] }));
|
|
63
62
|
};
|
|
64
63
|
export const DataGridRow = memo(Row);
|
|
@@ -7,8 +7,6 @@ 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";
|
|
12
10
|
injectString("cs", "Select all", "Vybrat v\u0161e");
|
|
13
11
|
injectString("da-DK", "Select all", "V\xE6lg alle");
|
|
14
12
|
injectString("de", "Select all", "Alle ausw\xE4hlen");
|
|
@@ -202,29 +200,13 @@ export const withSelectableRows = DataGridComponent => {
|
|
|
202
200
|
const selectMenuRef = useRef(null);
|
|
203
201
|
const selections = getSelections(selection);
|
|
204
202
|
const allSelected = selection !== undefined && selection.allSelected;
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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]);
|
|
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]);
|
|
228
210
|
if (wrapper) {
|
|
229
211
|
wrapper.selectionState = calculateSelectionState(entities, selections, allSelected, options);
|
|
230
212
|
}
|
|
@@ -232,10 +214,9 @@ export const withSelectableRows = DataGridComponent => {
|
|
|
232
214
|
const newSelections = new Set(selections);
|
|
233
215
|
entities.forEach(entity => {
|
|
234
216
|
if (checked) {
|
|
235
|
-
|
|
236
|
-
// limit, it only skips rows the consumer explicitly disabled.
|
|
217
|
+
const isVisible = options.condition ? options.condition(entity) : options.checkboxVisible ? options.checkboxVisible(entity) : true;
|
|
237
218
|
const isEnabled = !options.checkboxDisabled || !options.checkboxDisabled(entity);
|
|
238
|
-
if (
|
|
219
|
+
if (isVisible && isEnabled) {
|
|
239
220
|
newSelections.add(entity.id);
|
|
240
221
|
}
|
|
241
222
|
return;
|
|
@@ -248,49 +229,8 @@ export const withSelectableRows = DataGridComponent => {
|
|
|
248
229
|
allSelected: newState === SelectionState.All,
|
|
249
230
|
turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
250
231
|
});
|
|
251
|
-
}, [selections, entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
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);
|
|
232
|
+
}, [selections, entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
|
|
287
233
|
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
|
-
}
|
|
294
234
|
if (allSelected) {
|
|
295
235
|
const newSelection = new Set(entities.map(entity => entity.id));
|
|
296
236
|
newSelection.delete(id);
|
|
@@ -312,7 +252,7 @@ export const withSelectableRows = DataGridComponent => {
|
|
|
312
252
|
allSelected: newState === SelectionState.All,
|
|
313
253
|
turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
314
254
|
});
|
|
315
|
-
}, [entities, selections, allSelected, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
|
|
255
|
+
}, [entities, selections, allSelected, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
|
|
316
256
|
const onSelectAll = useCallback(([checked]) => {
|
|
317
257
|
if (checked && ((selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll) || options.turnOffSelectAll)) {
|
|
318
258
|
selectAll(true);
|
|
@@ -361,11 +301,10 @@ export const withSelectableRows = DataGridComponent => {
|
|
|
361
301
|
wrapper.attach("change", onSelectListener);
|
|
362
302
|
wrapper.attach("change-all", onSelectAll);
|
|
363
303
|
wrapper.attach("toggle", onTriggerClick);
|
|
364
|
-
wrapper.attach("mousedown", ([id, checked, e]) => onCheckboxMouseDown(id, checked, e));
|
|
365
304
|
return () => {
|
|
366
305
|
wrapper.detach();
|
|
367
306
|
};
|
|
368
|
-
}, [wrapper, onSelectListener, onSelectAll, onTriggerClick
|
|
307
|
+
}, [wrapper, onSelectListener, onSelectAll, onTriggerClick]);
|
|
369
308
|
const listColumns = useMemo(() => {
|
|
370
309
|
const newColumns = columns.map(c => Object.assign({}, c));
|
|
371
310
|
// Remove CheckboxColumnWrappers from wrappers list
|
|
@@ -8,12 +8,3 @@ export interface ISelectionValue {
|
|
|
8
8
|
all: boolean;
|
|
9
9
|
selected: string[];
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
12
|
-
* One checkbox row in the order it is rendered. Expanded nested rows are part of this list,
|
|
13
|
-
* directly after their parent, so a drag or shift-click range can span nesting levels the
|
|
14
|
-
* same way it spans sibling rows.
|
|
15
|
-
*/
|
|
16
|
-
export interface IDragSelectionRow {
|
|
17
|
-
id: string;
|
|
18
|
-
isNested: boolean;
|
|
19
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
2
|
import { IListColumn } from "../table";
|
|
3
3
|
import { ISelectionValue, SelectionState } from "./interfaces";
|
|
4
4
|
import "./selectableColumn.less";
|
|
@@ -33,7 +33,7 @@ export declare const getEmptySelection: () => {
|
|
|
33
33
|
selected: string[];
|
|
34
34
|
};
|
|
35
35
|
export declare const SelectableWrapperName = "Selectable";
|
|
36
|
-
export declare const useSelectableRows: <T extends IRowEntity<N>, N extends IEntityWithId>(columns: IListColumn<T, N>[], entities: T[], isMobile: boolean, selectMode: boolean, setSelectMode: (value: boolean) => void, selectable?: ISelectableRowsOptions<T, N>, isInfinite?: boolean
|
|
36
|
+
export declare const useSelectableRows: <T extends IRowEntity<N>, N extends IEntityWithId>(columns: IListColumn<T, N>[], entities: T[], isMobile: boolean, selectMode: boolean, setSelectMode: (value: boolean) => void, selectable?: ISelectableRowsOptions<T, N>, isInfinite?: boolean) => {
|
|
37
37
|
selectableColumns: IListColumn<T, N>[];
|
|
38
38
|
selectableFeedWrapper: (primaryData: ReactNode, secondaryData: ReactNode, entity: T | N, isNested: boolean) => [ReactNode, ReactNode];
|
|
39
39
|
};
|
|
@@ -10,8 +10,6 @@ import { useLanguage } from "../../utils/localization/useLanguage";
|
|
|
10
10
|
import { checkRow } from "./utils/checkRow";
|
|
11
11
|
import { isRowChecked } from "./utils/isRowChecked";
|
|
12
12
|
import { getCurrentPageSelection } from "./utils/getCurrentPageSelection";
|
|
13
|
-
import { useDragSelection } from "./useDragSelection";
|
|
14
|
-
import { getDragSelectionRows } from "./utils/getDragSelectionRows";
|
|
15
13
|
injectString("cs", "Select all", "Vybrat v\u0161e");
|
|
16
14
|
injectString("da-DK", "Select all", "V\xE6lg alle");
|
|
17
15
|
injectString("de", "Select all", "Alle ausw\xE4hlen");
|
|
@@ -85,7 +83,7 @@ export const getEmptySelection = () => ({
|
|
|
85
83
|
export const SelectableWrapperName = "Selectable";
|
|
86
84
|
// Infinite scroll has no pages, so the header checkbox always means "select all" (never current page).
|
|
87
85
|
const resolveCheckboxEmitsCurrentPage = (isInfinite, checkboxSelectsCurrentPage, turnOffSelectAll) => isInfinite ? false : checkboxSelectsCurrentPage !== null && checkboxSelectsCurrentPage !== void 0 ? checkboxSelectsCurrentPage : turnOffSelectAll;
|
|
88
|
-
export const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMode, selectable, isInfinite = false
|
|
86
|
+
export const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMode, selectable, isInfinite = false) => {
|
|
89
87
|
var _a;
|
|
90
88
|
const {
|
|
91
89
|
translate
|
|
@@ -155,47 +153,6 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
155
153
|
selectable === null || selectable === void 0 ? void 0 : selectable.onSelect(newValue);
|
|
156
154
|
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
157
155
|
}, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, setState, getNewSelection]);
|
|
158
|
-
const onBatchSelect = useCallback((rangeIds, select, base) => {
|
|
159
|
-
var _a;
|
|
160
|
-
const result = new Set(base);
|
|
161
|
-
const limit = selectable === null || selectable === void 0 ? void 0 : selectable.selectionLimit;
|
|
162
|
-
for (const id of rangeIds) {
|
|
163
|
-
if (select && limit !== undefined && result.size >= limit) {
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
checkRow(result, selectable, entities, id, select);
|
|
167
|
-
}
|
|
168
|
-
const newState = calculateSelectionState(entities, result, ((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all) || false, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy);
|
|
169
|
-
const newValue = {
|
|
170
|
-
selected: [...result],
|
|
171
|
-
all: newState === SelectionState.All
|
|
172
|
-
};
|
|
173
|
-
setState(newState);
|
|
174
|
-
selectable === null || selectable === void 0 ? void 0 : selectable.onSelect(newValue);
|
|
175
|
-
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
176
|
-
}, [entities, selectable, checkboxVisible, checkboxDisabled, setSelectMode]);
|
|
177
|
-
// Deliberately independent of the current selection, so the drag anchor survives the
|
|
178
|
-
// selection changes a drag itself produces.
|
|
179
|
-
const {
|
|
180
|
-
rows: dragRows,
|
|
181
|
-
entityById
|
|
182
|
-
} = useMemo(() => getDragSelectionRows(entities, expandedRows), [entities, expandedRows]);
|
|
183
|
-
const isSelectable = useCallback(row => {
|
|
184
|
-
const entity = entityById.get(row.id);
|
|
185
|
-
return !!entity && checkboxVisible(entity, row.isNested) && !checkboxDisabled(entity, row.isNested);
|
|
186
|
-
}, [entityById, checkboxVisible, checkboxDisabled]);
|
|
187
|
-
const getBaseSelection = useCallback(() => state === SelectionState.All ? getCurrentPageSelection(entities, selectable) : new Set(selections), [state, entities, selectable, selections]);
|
|
188
|
-
const {
|
|
189
|
-
onCheckboxMouseDown,
|
|
190
|
-
suppressNextChangeRef
|
|
191
|
-
} = useDragSelection(dragRows, gridRef, onBatchSelect, getBaseSelection, isSelectable, !!selectable);
|
|
192
|
-
const onCheckboxChange = useCallback((id, checked) => {
|
|
193
|
-
if (suppressNextChangeRef.current) {
|
|
194
|
-
suppressNextChangeRef.current = false;
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
onSelectListener(id, checked);
|
|
198
|
-
}, [onSelectListener, suppressNextChangeRef]);
|
|
199
156
|
const onChangeSelectionState = useCallback(newState => {
|
|
200
157
|
var _a, _b;
|
|
201
158
|
if (newState === SelectionState.All) {
|
|
@@ -273,8 +230,7 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
273
230
|
indeterminate: checked.indeterminate,
|
|
274
231
|
disabled: isDisable,
|
|
275
232
|
label: checkboxTitle(entity),
|
|
276
|
-
onChange:
|
|
277
|
-
onMouseDown: isDisable ? undefined : onCheckboxMouseDown,
|
|
233
|
+
onChange: onSelectListener,
|
|
278
234
|
children: _jsx(CheckboxCell.Content, {
|
|
279
235
|
children: value
|
|
280
236
|
})
|
|
@@ -320,7 +276,7 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
320
276
|
return cell;
|
|
321
277
|
}
|
|
322
278
|
};
|
|
323
|
-
}, [checkboxDisabled, checkboxTitle, checkboxVisible, headerTitle, onChangeSelectionState,
|
|
279
|
+
}, [checkboxDisabled, checkboxTitle, checkboxVisible, headerTitle, onChangeSelectionState, onSelectListener, hasSelectable, checkboxEmitsCurrentPage, checkboxInHeaderValue, selectableHeader, selectableTurnOffSelectAll, isInfinite, selectable, selectableState, state, isMobile, checkboxPlaceholder, isEntityChecked, entities, setSelectMode]);
|
|
324
280
|
const selectableFeedWrapper = useCallback((primaryData, secondaryData, entity, isNested) => {
|
|
325
281
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
326
282
|
if (!entity) {
|
package/esm/table/table.js
CHANGED
|
@@ -238,7 +238,7 @@ const TableInner = ({
|
|
|
238
238
|
const {
|
|
239
239
|
selectableColumns,
|
|
240
240
|
selectableFeedWrapper
|
|
241
|
-
} = useSelectableRows(nestedColumns, entities, isMobile, selectMode, setMobileSelectMode, isLoading ? undefined : selectable, isInfinite
|
|
241
|
+
} = useSelectableRows(nestedColumns, entities, isMobile, selectMode, setMobileSelectMode, isLoading ? undefined : selectable, isInfinite);
|
|
242
242
|
const {
|
|
243
243
|
sortableColumns,
|
|
244
244
|
feedSortControl
|
package/package.json
CHANGED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { MouseEvent as ReactMouseEvent, RefObject } from "react";
|
|
2
|
-
import { IDragSelectionRow } from "./interfaces";
|
|
3
|
-
/**
|
|
4
|
-
* @param rows every checkbox row in render order, expanded nested rows included, so ranges can
|
|
5
|
-
* span nesting levels.
|
|
6
|
-
*/
|
|
7
|
-
export declare const useDragSelection: (rows: IDragSelectionRow[], gridRef: RefObject<HTMLElement | null> | undefined, onBatchSelect: (rangeIds: string[], select: boolean, base: Set<string>) => void, getBaseSelection: () => Set<string>, isSelectable: (row: IDragSelectionRow) => boolean, isEnabled: boolean) => {
|
|
8
|
-
onCheckboxMouseDown: (id: string, checked: boolean, e: ReactMouseEvent) => void;
|
|
9
|
-
suppressNextChangeRef: RefObject<boolean>;
|
|
10
|
-
};
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useDragSelection = void 0;
|
|
4
|
-
const react_1 = require("react");
|
|
5
|
-
const zen_1 = require("../../utils/zen");
|
|
6
|
-
const getRangeIds_1 = require("./utils/getRangeIds");
|
|
7
|
-
const DRAG_CLASS = "zen-not-selectable";
|
|
8
|
-
/**
|
|
9
|
-
* @param rows every checkbox row in render order, expanded nested rows included, so ranges can
|
|
10
|
-
* span nesting levels.
|
|
11
|
-
*/
|
|
12
|
-
const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection, isSelectable, isEnabled) => {
|
|
13
|
-
const rowsRef = (0, react_1.useRef)(rows);
|
|
14
|
-
rowsRef.current = rows;
|
|
15
|
-
const getBaseSelectionRef = (0, react_1.useRef)(getBaseSelection);
|
|
16
|
-
getBaseSelectionRef.current = getBaseSelection;
|
|
17
|
-
const onBatchSelectRef = (0, react_1.useRef)(onBatchSelect);
|
|
18
|
-
onBatchSelectRef.current = onBatchSelect;
|
|
19
|
-
const isSelectableRef = (0, react_1.useRef)(isSelectable);
|
|
20
|
-
isSelectableRef.current = isSelectable;
|
|
21
|
-
const isEnabledRef = (0, react_1.useRef)(isEnabled);
|
|
22
|
-
isEnabledRef.current = isEnabled;
|
|
23
|
-
const anchorIdRef = (0, react_1.useRef)(null);
|
|
24
|
-
const anchorSelectRef = (0, react_1.useRef)(true);
|
|
25
|
-
const baseSelectedRef = (0, react_1.useRef)(new Set());
|
|
26
|
-
const isDraggingRef = (0, react_1.useRef)(false);
|
|
27
|
-
const movedRef = (0, react_1.useRef)(false);
|
|
28
|
-
const lastResultKeyRef = (0, react_1.useRef)("");
|
|
29
|
-
const lastPointRef = (0, react_1.useRef)(null);
|
|
30
|
-
const suppressNextChangeRef = (0, react_1.useRef)(false);
|
|
31
|
-
const attachedGridElementRef = (0, react_1.useRef)(null);
|
|
32
|
-
const emitRange = (0, react_1.useCallback)((currentId) => {
|
|
33
|
-
const anchorId = anchorIdRef.current;
|
|
34
|
-
if (anchorId === null) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const range = (0, getRangeIds_1.getRangeIds)(rowsRef.current, anchorId, currentId, isSelectableRef.current);
|
|
38
|
-
if (range.length === 0) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const select = anchorSelectRef.current;
|
|
42
|
-
const key = `${select}|${range.join(",")}`;
|
|
43
|
-
if (key === lastResultKeyRef.current) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
lastResultKeyRef.current = key;
|
|
47
|
-
onBatchSelectRef.current(range, select, baseSelectedRef.current);
|
|
48
|
-
}, []);
|
|
49
|
-
const extend = (0, react_1.useCallback)((x, y) => {
|
|
50
|
-
var _a, _b;
|
|
51
|
-
lastPointRef.current = { x, y };
|
|
52
|
-
const row = (_b = (_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.elementFromPoint(x, y)) === null || _b === void 0 ? void 0 : _b.closest("[data-row-id]");
|
|
53
|
-
const currentId = row === null || row === void 0 ? void 0 : row.getAttribute("data-row-id");
|
|
54
|
-
if (!currentId) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (currentId !== anchorIdRef.current) {
|
|
58
|
-
movedRef.current = true;
|
|
59
|
-
}
|
|
60
|
-
if (!movedRef.current) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
emitRange(currentId);
|
|
64
|
-
}, [emitRange]);
|
|
65
|
-
const onMouseMove = (0, react_1.useCallback)((e) => {
|
|
66
|
-
extend(e.clientX, e.clientY);
|
|
67
|
-
}, [extend]);
|
|
68
|
-
const onScroll = (0, react_1.useCallback)(() => {
|
|
69
|
-
const point = lastPointRef.current;
|
|
70
|
-
if (point) {
|
|
71
|
-
extend(point.x, point.y);
|
|
72
|
-
}
|
|
73
|
-
}, [extend]);
|
|
74
|
-
const endDrag = (0, react_1.useCallback)(() => {
|
|
75
|
-
var _a, _b, _c, _d;
|
|
76
|
-
if (!isDraggingRef.current) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
isDraggingRef.current = false;
|
|
80
|
-
if (movedRef.current) {
|
|
81
|
-
suppressNextChangeRef.current = true;
|
|
82
|
-
}
|
|
83
|
-
(_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.removeEventListener("mousemove", onMouseMove);
|
|
84
|
-
(_b = zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.removeEventListener("mouseup", endDrag);
|
|
85
|
-
(_c = attachedGridElementRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener("scroll", onScroll);
|
|
86
|
-
(_d = attachedGridElementRef.current) === null || _d === void 0 ? void 0 : _d.classList.remove(DRAG_CLASS);
|
|
87
|
-
attachedGridElementRef.current = null;
|
|
88
|
-
}, [onMouseMove, onScroll]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
89
|
-
const onCheckboxMouseDown = (0, react_1.useCallback)((id, checked, e) => {
|
|
90
|
-
var _a, _b, _c, _d, _e;
|
|
91
|
-
// Right-click between drag-end and the trailing click must not clear suppression.
|
|
92
|
-
if (e.button === 0) {
|
|
93
|
-
suppressNextChangeRef.current = false;
|
|
94
|
-
}
|
|
95
|
-
if (!isEnabledRef.current || e.button !== 0) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
if (e.shiftKey && anchorIdRef.current !== null) {
|
|
99
|
-
e.preventDefault();
|
|
100
|
-
const anchorId = anchorIdRef.current;
|
|
101
|
-
const anchorInList = rowsRef.current.some(row => row.id === anchorId);
|
|
102
|
-
if (!anchorInList) {
|
|
103
|
-
// The anchor is no longer rendered (e.g. its parent was collapsed, or the list was
|
|
104
|
-
// re-filtered/paginated since). Drop the stale anchor and let the target row's own
|
|
105
|
-
// onChange fire normally, rather than swallowing it as a silent no-op.
|
|
106
|
-
anchorIdRef.current = null;
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
// Gmail-style: every shift-click re-applies the range to the selection captured when
|
|
110
|
-
// the anchor was clicked, so moving the target closer to the anchor deselects the rows
|
|
111
|
-
// that dropped out of the range. Shift-clicking the anchor itself collapses the range
|
|
112
|
-
// to nothing, restoring that captured selection — the anchor included.
|
|
113
|
-
const range = id === anchorId ? [] : (0, getRangeIds_1.getRangeIds)(rowsRef.current, anchorId, id, isSelectableRef.current);
|
|
114
|
-
// Suppress even when the range is empty to prevent the anchor from double-toggling
|
|
115
|
-
// on a same-row shift-click.
|
|
116
|
-
suppressNextChangeRef.current = true;
|
|
117
|
-
onBatchSelectRef.current(range, anchorSelectRef.current, baseSelectedRef.current);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
anchorIdRef.current = id;
|
|
121
|
-
anchorSelectRef.current = !checked;
|
|
122
|
-
baseSelectedRef.current = getBaseSelectionRef.current();
|
|
123
|
-
isDraggingRef.current = true;
|
|
124
|
-
movedRef.current = false;
|
|
125
|
-
lastResultKeyRef.current = "";
|
|
126
|
-
lastPointRef.current = { x: e.clientX, y: e.clientY };
|
|
127
|
-
attachedGridElementRef.current = (_a = gridRef === null || gridRef === void 0 ? void 0 : gridRef.current) !== null && _a !== void 0 ? _a : null;
|
|
128
|
-
(_b = attachedGridElementRef.current) === null || _b === void 0 ? void 0 : _b.classList.add(DRAG_CLASS);
|
|
129
|
-
(_c = zen_1.zen.document) === null || _c === void 0 ? void 0 : _c.addEventListener("mousemove", onMouseMove);
|
|
130
|
-
(_d = zen_1.zen.document) === null || _d === void 0 ? void 0 : _d.addEventListener("mouseup", endDrag);
|
|
131
|
-
(_e = attachedGridElementRef.current) === null || _e === void 0 ? void 0 : _e.addEventListener("scroll", onScroll);
|
|
132
|
-
}, [gridRef, onMouseMove, onScroll, endDrag]);
|
|
133
|
-
(0, react_1.useEffect)(() => {
|
|
134
|
-
anchorIdRef.current = null;
|
|
135
|
-
}, [rows]);
|
|
136
|
-
(0, react_1.useEffect)(() => endDrag, [endDrag]);
|
|
137
|
-
return { onCheckboxMouseDown, suppressNextChangeRef };
|
|
138
|
-
};
|
|
139
|
-
exports.useDragSelection = useDragSelection;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { IEntityWithId } from "../../../commonHelpers/entity";
|
|
2
|
-
import { IRowEntity } from "../../../dataGrid/row/row";
|
|
3
|
-
import { IDragSelectionRow } from "../interfaces";
|
|
4
|
-
export interface IDragSelection<T> {
|
|
5
|
-
/** The rows in render order. */
|
|
6
|
-
rows: IDragSelectionRow[];
|
|
7
|
-
/** Every entity a row can point at, parents and children alike. */
|
|
8
|
-
entityById: Map<string, T>;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Flattens the entities into the rows the grid actually renders: each entity followed by its
|
|
12
|
-
* children while it is expanded. Drag and shift-click ranges walk this list, so they cross
|
|
13
|
-
* nesting levels the way the user sees them on screen.
|
|
14
|
-
*/
|
|
15
|
-
export declare const getDragSelectionRows: <T extends IRowEntity<N>, N extends IEntityWithId>(entities: T[], expandedRows?: string[]) => IDragSelection<T | N>;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDragSelectionRows = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Flattens the entities into the rows the grid actually renders: each entity followed by its
|
|
6
|
-
* children while it is expanded. Drag and shift-click ranges walk this list, so they cross
|
|
7
|
-
* nesting levels the way the user sees them on screen.
|
|
8
|
-
*/
|
|
9
|
-
const getDragSelectionRows = (entities, expandedRows) => {
|
|
10
|
-
const expanded = new Set(expandedRows);
|
|
11
|
-
const rows = [];
|
|
12
|
-
const entityById = new Map();
|
|
13
|
-
entities.forEach(entity => {
|
|
14
|
-
rows.push({ id: entity.id, isNested: false });
|
|
15
|
-
entityById.set(entity.id, entity);
|
|
16
|
-
// Children are always indexed — a collapsed row's children still need to resolve for
|
|
17
|
-
// the selection predicates — but only an expanded row contributes them to the range.
|
|
18
|
-
const isExpanded = expanded.has(entity.id);
|
|
19
|
-
(entity.children || []).forEach(child => {
|
|
20
|
-
entityById.set(child.id, child);
|
|
21
|
-
if (isExpanded) {
|
|
22
|
-
rows.push({ id: child.id, isNested: true });
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
return { rows, entityById };
|
|
27
|
-
};
|
|
28
|
-
exports.getDragSelectionRows = getDragSelectionRows;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getRangeIds = void 0;
|
|
4
|
-
const getRangeIds = (rows, fromId, toId, isSelectable) => {
|
|
5
|
-
const fromIdx = rows.findIndex(row => row.id === fromId);
|
|
6
|
-
const toIdx = rows.findIndex(row => row.id === toId);
|
|
7
|
-
if (fromIdx === -1 || toIdx === -1) {
|
|
8
|
-
return [];
|
|
9
|
-
}
|
|
10
|
-
const start = Math.min(fromIdx, toIdx);
|
|
11
|
-
const end = Math.max(fromIdx, toIdx);
|
|
12
|
-
const ids = [];
|
|
13
|
-
for (let i = start; i <= end; i++) {
|
|
14
|
-
const row = rows[i];
|
|
15
|
-
if (isSelectable(row)) {
|
|
16
|
-
ids.push(row.id);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return ids;
|
|
20
|
-
};
|
|
21
|
-
exports.getRangeIds = getRangeIds;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { MouseEvent as ReactMouseEvent, RefObject } from "react";
|
|
2
|
-
import { IDragSelectionRow } from "./interfaces";
|
|
3
|
-
/**
|
|
4
|
-
* @param rows every checkbox row in render order, expanded nested rows included, so ranges can
|
|
5
|
-
* span nesting levels.
|
|
6
|
-
*/
|
|
7
|
-
export declare const useDragSelection: (rows: IDragSelectionRow[], gridRef: RefObject<HTMLElement | null> | undefined, onBatchSelect: (rangeIds: string[], select: boolean, base: Set<string>) => void, getBaseSelection: () => Set<string>, isSelectable: (row: IDragSelectionRow) => boolean, isEnabled: boolean) => {
|
|
8
|
-
onCheckboxMouseDown: (id: string, checked: boolean, e: ReactMouseEvent) => void;
|
|
9
|
-
suppressNextChangeRef: RefObject<boolean>;
|
|
10
|
-
};
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef } from "react";
|
|
2
|
-
import { zen } from "../../utils/zen";
|
|
3
|
-
import { getRangeIds } from "./utils/getRangeIds";
|
|
4
|
-
const DRAG_CLASS = "zen-not-selectable";
|
|
5
|
-
/**
|
|
6
|
-
* @param rows every checkbox row in render order, expanded nested rows included, so ranges can
|
|
7
|
-
* span nesting levels.
|
|
8
|
-
*/
|
|
9
|
-
export const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection, isSelectable, isEnabled) => {
|
|
10
|
-
const rowsRef = useRef(rows);
|
|
11
|
-
rowsRef.current = rows;
|
|
12
|
-
const getBaseSelectionRef = useRef(getBaseSelection);
|
|
13
|
-
getBaseSelectionRef.current = getBaseSelection;
|
|
14
|
-
const onBatchSelectRef = useRef(onBatchSelect);
|
|
15
|
-
onBatchSelectRef.current = onBatchSelect;
|
|
16
|
-
const isSelectableRef = useRef(isSelectable);
|
|
17
|
-
isSelectableRef.current = isSelectable;
|
|
18
|
-
const isEnabledRef = useRef(isEnabled);
|
|
19
|
-
isEnabledRef.current = isEnabled;
|
|
20
|
-
const anchorIdRef = useRef(null);
|
|
21
|
-
const anchorSelectRef = useRef(true);
|
|
22
|
-
const baseSelectedRef = useRef(new Set());
|
|
23
|
-
const isDraggingRef = useRef(false);
|
|
24
|
-
const movedRef = useRef(false);
|
|
25
|
-
const lastResultKeyRef = useRef("");
|
|
26
|
-
const lastPointRef = useRef(null);
|
|
27
|
-
const suppressNextChangeRef = useRef(false);
|
|
28
|
-
const attachedGridElementRef = useRef(null);
|
|
29
|
-
const emitRange = useCallback((currentId) => {
|
|
30
|
-
const anchorId = anchorIdRef.current;
|
|
31
|
-
if (anchorId === null) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const range = getRangeIds(rowsRef.current, anchorId, currentId, isSelectableRef.current);
|
|
35
|
-
if (range.length === 0) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
const select = anchorSelectRef.current;
|
|
39
|
-
const key = `${select}|${range.join(",")}`;
|
|
40
|
-
if (key === lastResultKeyRef.current) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
lastResultKeyRef.current = key;
|
|
44
|
-
onBatchSelectRef.current(range, select, baseSelectedRef.current);
|
|
45
|
-
}, []);
|
|
46
|
-
const extend = useCallback((x, y) => {
|
|
47
|
-
var _a, _b;
|
|
48
|
-
lastPointRef.current = { x, y };
|
|
49
|
-
const row = (_b = (_a = zen.document) === null || _a === void 0 ? void 0 : _a.elementFromPoint(x, y)) === null || _b === void 0 ? void 0 : _b.closest("[data-row-id]");
|
|
50
|
-
const currentId = row === null || row === void 0 ? void 0 : row.getAttribute("data-row-id");
|
|
51
|
-
if (!currentId) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
if (currentId !== anchorIdRef.current) {
|
|
55
|
-
movedRef.current = true;
|
|
56
|
-
}
|
|
57
|
-
if (!movedRef.current) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
emitRange(currentId);
|
|
61
|
-
}, [emitRange]);
|
|
62
|
-
const onMouseMove = useCallback((e) => {
|
|
63
|
-
extend(e.clientX, e.clientY);
|
|
64
|
-
}, [extend]);
|
|
65
|
-
const onScroll = useCallback(() => {
|
|
66
|
-
const point = lastPointRef.current;
|
|
67
|
-
if (point) {
|
|
68
|
-
extend(point.x, point.y);
|
|
69
|
-
}
|
|
70
|
-
}, [extend]);
|
|
71
|
-
const endDrag = useCallback(() => {
|
|
72
|
-
var _a, _b, _c, _d;
|
|
73
|
-
if (!isDraggingRef.current) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
isDraggingRef.current = false;
|
|
77
|
-
if (movedRef.current) {
|
|
78
|
-
suppressNextChangeRef.current = true;
|
|
79
|
-
}
|
|
80
|
-
(_a = zen.document) === null || _a === void 0 ? void 0 : _a.removeEventListener("mousemove", onMouseMove);
|
|
81
|
-
(_b = zen.document) === null || _b === void 0 ? void 0 : _b.removeEventListener("mouseup", endDrag);
|
|
82
|
-
(_c = attachedGridElementRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener("scroll", onScroll);
|
|
83
|
-
(_d = attachedGridElementRef.current) === null || _d === void 0 ? void 0 : _d.classList.remove(DRAG_CLASS);
|
|
84
|
-
attachedGridElementRef.current = null;
|
|
85
|
-
}, [onMouseMove, onScroll]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
86
|
-
const onCheckboxMouseDown = useCallback((id, checked, e) => {
|
|
87
|
-
var _a, _b, _c, _d, _e;
|
|
88
|
-
// Right-click between drag-end and the trailing click must not clear suppression.
|
|
89
|
-
if (e.button === 0) {
|
|
90
|
-
suppressNextChangeRef.current = false;
|
|
91
|
-
}
|
|
92
|
-
if (!isEnabledRef.current || e.button !== 0) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
if (e.shiftKey && anchorIdRef.current !== null) {
|
|
96
|
-
e.preventDefault();
|
|
97
|
-
const anchorId = anchorIdRef.current;
|
|
98
|
-
const anchorInList = rowsRef.current.some(row => row.id === anchorId);
|
|
99
|
-
if (!anchorInList) {
|
|
100
|
-
// The anchor is no longer rendered (e.g. its parent was collapsed, or the list was
|
|
101
|
-
// re-filtered/paginated since). Drop the stale anchor and let the target row's own
|
|
102
|
-
// onChange fire normally, rather than swallowing it as a silent no-op.
|
|
103
|
-
anchorIdRef.current = null;
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
// Gmail-style: every shift-click re-applies the range to the selection captured when
|
|
107
|
-
// the anchor was clicked, so moving the target closer to the anchor deselects the rows
|
|
108
|
-
// that dropped out of the range. Shift-clicking the anchor itself collapses the range
|
|
109
|
-
// to nothing, restoring that captured selection — the anchor included.
|
|
110
|
-
const range = id === anchorId ? [] : getRangeIds(rowsRef.current, anchorId, id, isSelectableRef.current);
|
|
111
|
-
// Suppress even when the range is empty to prevent the anchor from double-toggling
|
|
112
|
-
// on a same-row shift-click.
|
|
113
|
-
suppressNextChangeRef.current = true;
|
|
114
|
-
onBatchSelectRef.current(range, anchorSelectRef.current, baseSelectedRef.current);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
anchorIdRef.current = id;
|
|
118
|
-
anchorSelectRef.current = !checked;
|
|
119
|
-
baseSelectedRef.current = getBaseSelectionRef.current();
|
|
120
|
-
isDraggingRef.current = true;
|
|
121
|
-
movedRef.current = false;
|
|
122
|
-
lastResultKeyRef.current = "";
|
|
123
|
-
lastPointRef.current = { x: e.clientX, y: e.clientY };
|
|
124
|
-
attachedGridElementRef.current = (_a = gridRef === null || gridRef === void 0 ? void 0 : gridRef.current) !== null && _a !== void 0 ? _a : null;
|
|
125
|
-
(_b = attachedGridElementRef.current) === null || _b === void 0 ? void 0 : _b.classList.add(DRAG_CLASS);
|
|
126
|
-
(_c = zen.document) === null || _c === void 0 ? void 0 : _c.addEventListener("mousemove", onMouseMove);
|
|
127
|
-
(_d = zen.document) === null || _d === void 0 ? void 0 : _d.addEventListener("mouseup", endDrag);
|
|
128
|
-
(_e = attachedGridElementRef.current) === null || _e === void 0 ? void 0 : _e.addEventListener("scroll", onScroll);
|
|
129
|
-
}, [gridRef, onMouseMove, onScroll, endDrag]);
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
anchorIdRef.current = null;
|
|
132
|
-
}, [rows]);
|
|
133
|
-
useEffect(() => endDrag, [endDrag]);
|
|
134
|
-
return { onCheckboxMouseDown, suppressNextChangeRef };
|
|
135
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { IEntityWithId } from "../../../commonHelpers/entity";
|
|
2
|
-
import { IRowEntity } from "../../../dataGrid/row/row";
|
|
3
|
-
import { IDragSelectionRow } from "../interfaces";
|
|
4
|
-
export interface IDragSelection<T> {
|
|
5
|
-
/** The rows in render order. */
|
|
6
|
-
rows: IDragSelectionRow[];
|
|
7
|
-
/** Every entity a row can point at, parents and children alike. */
|
|
8
|
-
entityById: Map<string, T>;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Flattens the entities into the rows the grid actually renders: each entity followed by its
|
|
12
|
-
* children while it is expanded. Drag and shift-click ranges walk this list, so they cross
|
|
13
|
-
* nesting levels the way the user sees them on screen.
|
|
14
|
-
*/
|
|
15
|
-
export declare const getDragSelectionRows: <T extends IRowEntity<N>, N extends IEntityWithId>(entities: T[], expandedRows?: string[]) => IDragSelection<T | N>;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Flattens the entities into the rows the grid actually renders: each entity followed by its
|
|
3
|
-
* children while it is expanded. Drag and shift-click ranges walk this list, so they cross
|
|
4
|
-
* nesting levels the way the user sees them on screen.
|
|
5
|
-
*/
|
|
6
|
-
export const getDragSelectionRows = (entities, expandedRows) => {
|
|
7
|
-
const expanded = new Set(expandedRows);
|
|
8
|
-
const rows = [];
|
|
9
|
-
const entityById = new Map();
|
|
10
|
-
entities.forEach(entity => {
|
|
11
|
-
rows.push({ id: entity.id, isNested: false });
|
|
12
|
-
entityById.set(entity.id, entity);
|
|
13
|
-
// Children are always indexed — a collapsed row's children still need to resolve for
|
|
14
|
-
// the selection predicates — but only an expanded row contributes them to the range.
|
|
15
|
-
const isExpanded = expanded.has(entity.id);
|
|
16
|
-
(entity.children || []).forEach(child => {
|
|
17
|
-
entityById.set(child.id, child);
|
|
18
|
-
if (isExpanded) {
|
|
19
|
-
rows.push({ id: child.id, isNested: true });
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
return { rows, entityById };
|
|
24
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export const getRangeIds = (rows, fromId, toId, isSelectable) => {
|
|
2
|
-
const fromIdx = rows.findIndex(row => row.id === fromId);
|
|
3
|
-
const toIdx = rows.findIndex(row => row.id === toId);
|
|
4
|
-
if (fromIdx === -1 || toIdx === -1) {
|
|
5
|
-
return [];
|
|
6
|
-
}
|
|
7
|
-
const start = Math.min(fromIdx, toIdx);
|
|
8
|
-
const end = Math.max(fromIdx, toIdx);
|
|
9
|
-
const ids = [];
|
|
10
|
-
for (let i = start; i <= end; i++) {
|
|
11
|
-
const row = rows[i];
|
|
12
|
-
if (isSelectable(row)) {
|
|
13
|
-
ids.push(row.id);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return ids;
|
|
17
|
-
};
|