@geotab/zenith 3.17.0-beta.1 → 3.17.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/README.md +26 -29
- package/dist/button/button.d.ts +1 -2
- package/dist/button/button.js +5 -22
- package/dist/button/buttonDisabledProps.d.ts +35 -0
- package/dist/button/buttonDisabledProps.js +33 -0
- package/dist/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +1 -1
- package/dist/dropdownRaw/dropdownHelper.d.ts +20 -3
- package/dist/dropdownRaw/dropdownHelper.js +29 -6
- package/dist/dropdownRaw/dropdownRaw.js +22 -6
- package/dist/header/components/collapsedItemsControl/collapsedItemsControl.js +1 -1
- package/dist/header/headerButton.d.ts +15 -2
- package/dist/header/headerButton.js +11 -6
- package/dist/index.css +4 -8
- package/dist/menu/components/menuButton.js +40 -58
- package/dist/pageHeader/pageHeaderButton.d.ts +15 -1
- package/dist/pageHeader/pageHeaderButton.js +8 -6
- package/dist/pillExpandable/pillExpandable.js +3 -1
- package/dist/pillExpandable/pillExpandableSimple.d.ts +2 -1
- package/dist/pillExpandable/pillExpandableSimple.js +2 -2
- package/dist/table/selectable/interfaces.d.ts +6 -0
- package/dist/table/selectable/useDragSelection.d.ts +1 -1
- package/dist/table/selectable/useDragSelection.js +4 -4
- package/dist/table/selectable/useSelectableRows.d.ts +2 -0
- package/dist/table/selectable/useSelectableRows.js +88 -41
- package/dist/table/selectable/utils/calculateSelectionState.js +3 -2
- package/dist/table/selectable/utils/getCurrentPageSelection.js +9 -4
- package/dist/table/selectable/utils/groupExclusions.d.ts +7 -0
- package/dist/table/selectable/utils/groupExclusions.js +61 -0
- package/dist/table/selectable/utils/isRowChecked.js +1 -1
- package/dist/table/table.js +6 -5
- package/dist/tooltip/tooltip.d.ts +5 -3
- package/dist/tooltip/tooltip.js +11 -9
- package/esm/button/button.d.ts +1 -2
- package/esm/button/button.js +5 -22
- package/esm/button/buttonDisabledProps.d.ts +35 -0
- package/esm/button/buttonDisabledProps.js +29 -0
- package/esm/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +1 -1
- package/esm/dropdownRaw/dropdownHelper.d.ts +20 -3
- package/esm/dropdownRaw/dropdownHelper.js +27 -5
- package/esm/dropdownRaw/dropdownRaw.js +23 -7
- package/esm/header/components/collapsedItemsControl/collapsedItemsControl.js +1 -1
- package/esm/header/headerButton.d.ts +15 -2
- package/esm/header/headerButton.js +11 -6
- package/esm/menu/components/menuButton.js +40 -58
- package/esm/pageHeader/pageHeaderButton.d.ts +15 -1
- package/esm/pageHeader/pageHeaderButton.js +8 -6
- package/esm/pillExpandable/pillExpandable.js +3 -1
- package/esm/pillExpandable/pillExpandableSimple.d.ts +2 -1
- package/esm/pillExpandable/pillExpandableSimple.js +2 -2
- package/esm/table/selectable/interfaces.d.ts +6 -0
- package/esm/table/selectable/useDragSelection.d.ts +1 -1
- package/esm/table/selectable/useDragSelection.js +4 -4
- package/esm/table/selectable/useSelectableRows.d.ts +2 -0
- package/esm/table/selectable/useSelectableRows.js +90 -43
- package/esm/table/selectable/utils/calculateSelectionState.js +3 -2
- package/esm/table/selectable/utils/getCurrentPageSelection.js +9 -4
- package/esm/table/selectable/utils/groupExclusions.d.ts +7 -0
- package/esm/table/selectable/utils/groupExclusions.js +55 -0
- package/esm/table/selectable/utils/isRowChecked.js +1 -1
- package/esm/table/table.js +6 -5
- package/esm/tooltip/tooltip.d.ts +5 -3
- package/esm/tooltip/tooltip.js +11 -9
- package/package.json +1 -1
- package/README.md.baseline +0 -1
|
@@ -2,6 +2,7 @@ import { IButton } from "../button/button";
|
|
|
2
2
|
import { TButtonIconPosition } from "../textIconButton/textIconButton";
|
|
3
3
|
import { TSvgIconSize } from "../svgIcon/svgIconSize";
|
|
4
4
|
import { IIcon } from "../icons/icon";
|
|
5
|
+
import { TAlignment } from "../absolute/absolute";
|
|
5
6
|
export interface IPageHeaderButton extends Omit<IButton, "onClick" | "icon" | "title"> {
|
|
6
7
|
id: string;
|
|
7
8
|
icon: React.FC<IIcon>;
|
|
@@ -9,10 +10,23 @@ export interface IPageHeaderButton extends Omit<IButton, "onClick" | "icon" | "t
|
|
|
9
10
|
iconPosition?: TButtonIconPosition;
|
|
10
11
|
iconClasses?: string;
|
|
11
12
|
iconSize?: TSvgIconSize;
|
|
13
|
+
/**
|
|
14
|
+
* Tooltip content shown only while the button is `disabled`.
|
|
15
|
+
*
|
|
16
|
+
* When `disabled` and `disabledTooltip` are both set, the button uses `aria-disabled` instead of the native
|
|
17
|
+
* `disabled` attribute, so it stays focusable and hoverable and the tooltip can explain why it is unavailable.
|
|
18
|
+
* In every other case the standard `disabled` attribute is used, and `disabledTooltip` is ignored while the
|
|
19
|
+
* button is enabled.
|
|
20
|
+
*/
|
|
21
|
+
disabledTooltip?: React.ReactNode;
|
|
12
22
|
onClick?: (id: string, event: React.MouseEvent) => void;
|
|
13
23
|
}
|
|
24
|
+
interface IPageHeaderButtonInternal {
|
|
25
|
+
tooltipAlignment?: TAlignment;
|
|
26
|
+
}
|
|
14
27
|
export declare const PageHeaderButtonDisplayName = "PageHeaderButton";
|
|
15
28
|
export declare const PageHeaderButton: {
|
|
16
|
-
({ id, children, icon, iconPosition, className, onClick, title, disabled,
|
|
29
|
+
({ id, children, icon, iconPosition, className, onClick, title, disabledTooltip, tooltipAlignment, disabled, link, ...restProps }: IPageHeaderButton & IPageHeaderButtonInternal): import("react/jsx-runtime").JSX.Element;
|
|
17
30
|
displayName: string;
|
|
18
31
|
};
|
|
32
|
+
export {};
|
|
@@ -12,13 +12,15 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
13
|
import { ButtonIconPosition, TextIconButton } from "../textIconButton/textIconButton";
|
|
14
14
|
import { classNames } from "../commonHelpers/classNames/classNames";
|
|
15
|
+
import { Tooltip } from "../tooltip/tooltip";
|
|
16
|
+
import { getButtonDisabledProps } from "../button/buttonDisabledProps";
|
|
15
17
|
export const PageHeaderButtonDisplayName = "PageHeaderButton";
|
|
16
18
|
export const PageHeaderButton = (_a) => {
|
|
17
|
-
var { id, children, icon, iconPosition = ButtonIconPosition.Start, className = "", onClick, title, disabled,
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return (_jsx(
|
|
19
|
+
var { id, children, icon, iconPosition = ButtonIconPosition.Start, className = "", onClick, title, disabledTooltip, tooltipAlignment = "bottom", disabled, link } = _a, restProps = __rest(_a, ["id", "children", "icon", "iconPosition", "className", "onClick", "title", "disabledTooltip", "tooltipAlignment", "disabled", "link"]);
|
|
20
|
+
const tooltip = disabled ? disabledTooltip : undefined;
|
|
21
|
+
const _b = getButtonDisabledProps({ disabled, focusable: Boolean(tooltip), link }), { className: disabledClassName } = _b, disabledProps = __rest(_b, ["className"]);
|
|
22
|
+
const fullClassName = classNames(["zen-page-header-button", className || "", disabledClassName !== null && disabledClassName !== void 0 ? disabledClassName : ""]);
|
|
23
|
+
const button = (_jsx(TextIconButton, Object.assign({ id: id, icon: icon, title: title, iconPosition: iconPosition, className: fullClassName, onClick: onClick ? e => onClick(id, e) : undefined, link: link }, restProps, disabledProps, { children: children })));
|
|
24
|
+
return tooltip ? (_jsx(Tooltip, { trigger: button, alignment: tooltipAlignment, children: tooltip })) : (button);
|
|
23
25
|
};
|
|
24
26
|
PageHeaderButton.displayName = PageHeaderButtonDisplayName;
|
|
@@ -420,6 +420,7 @@ const PillExpandableBase = ({
|
|
|
420
420
|
}) => {
|
|
421
421
|
const popupId = useId();
|
|
422
422
|
const descriptionId = useId();
|
|
423
|
+
const counterId = useId();
|
|
423
424
|
const [descriptionElement, setDescriptionElement] = useState(null);
|
|
424
425
|
const isDrive = useDrive();
|
|
425
426
|
const [isMobile, setIsMobile] = useState(false);
|
|
@@ -588,10 +589,11 @@ const PillExpandableBase = ({
|
|
|
588
589
|
errorHandler: errorHandler,
|
|
589
590
|
isBeta: isBeta,
|
|
590
591
|
isMobile: isMobile,
|
|
591
|
-
descriptionId: isPopupOpen && descriptionElement ? descriptionId : undefined,
|
|
592
|
+
descriptionId: [uniqueChildren && !hideCounterNumber ? counterId : undefined, isPopupOpen && descriptionElement ? descriptionId : undefined].filter(Boolean).join(" ") || undefined,
|
|
592
593
|
ariaHasPopup: "dialog",
|
|
593
594
|
dataAnalyticsId: dataAnalyticsId
|
|
594
595
|
}), uniqueChildren && _jsx(PillExpandableSimple, {
|
|
596
|
+
id: counterId,
|
|
595
597
|
icon: secondaryIcon || effectiveIcon,
|
|
596
598
|
text: hideCounterNumber ? "" : counterText,
|
|
597
599
|
includeExpandIcon: false,
|
|
@@ -2,6 +2,7 @@ import { FC, RefObject } from "react";
|
|
|
2
2
|
import { IPillExpandableBase, TPillType } from "./pillExpandable";
|
|
3
3
|
import { IIcon } from "../icons/icon";
|
|
4
4
|
interface IPillExpandableSimple extends IPillExpandableBase {
|
|
5
|
+
id?: string;
|
|
5
6
|
includeExpandIcon?: boolean;
|
|
6
7
|
expanded?: boolean;
|
|
7
8
|
onExpand?: () => void;
|
|
@@ -15,7 +16,7 @@ interface IPillExpandableSimple extends IPillExpandableBase {
|
|
|
15
16
|
type?: TPillType;
|
|
16
17
|
}
|
|
17
18
|
export declare const PillExpandableSimple: {
|
|
18
|
-
({ onExpand, text, expanded, includeExpandIcon, type, icon, isBeta, isMobile, ref, className, descriptionId, ariaHasPopup, isDecorative, dataAnalyticsId }: IPillExpandableSimple): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
({ id, onExpand, text, expanded, includeExpandIcon, type, icon, isBeta, isMobile, ref, className, descriptionId, ariaHasPopup, isDecorative, dataAnalyticsId }: IPillExpandableSimple): import("react/jsx-runtime").JSX.Element;
|
|
19
20
|
displayName: string;
|
|
20
21
|
};
|
|
21
22
|
export {};
|
|
@@ -5,7 +5,7 @@ import { IconChevronTop } from "../icons/iconChevronTop";
|
|
|
5
5
|
import { IconChevronBottom } from "../icons/iconChevronBottom";
|
|
6
6
|
import { IconException } from "../icons/iconException";
|
|
7
7
|
import { classNames } from "../commonHelpers/classNames/classNames";
|
|
8
|
-
export const PillExpandableSimple = ({ onExpand, text, expanded, includeExpandIcon = true, type = "warning", icon = IconException, isBeta, isMobile, ref, className, descriptionId, ariaHasPopup, isDecorative, dataAnalyticsId
|
|
8
|
+
export const PillExpandableSimple = ({ id, onExpand, text, expanded, includeExpandIcon = true, type = "warning", icon = IconException, isBeta, isMobile, ref, className, descriptionId, ariaHasPopup, isDecorative, dataAnalyticsId
|
|
9
9
|
// eslint-disable-next-line complexity
|
|
10
10
|
}) => {
|
|
11
11
|
const iconDriveClassName = useDriveClassName("icon");
|
|
@@ -34,7 +34,7 @@ export const PillExpandableSimple = ({ onExpand, text, expanded, includeExpandIc
|
|
|
34
34
|
size: iconSize
|
|
35
35
|
}) }) }))] }));
|
|
36
36
|
if (isDecorative) {
|
|
37
|
-
return (_jsx("span", { className: classNames([
|
|
37
|
+
return (_jsx("span", { id: id, className: classNames([
|
|
38
38
|
"zen-status-pill__container",
|
|
39
39
|
`zen-status-pill__container--${type}`,
|
|
40
40
|
containerDriveClassName || "",
|
|
@@ -15,6 +15,12 @@ export interface ISelectionValue {
|
|
|
15
15
|
* Consumers opting in must resolve the effective selection before running bulk actions.
|
|
16
16
|
*/
|
|
17
17
|
selected: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Excluded nested groups, including children that have not loaded yet. Only used with
|
|
20
|
+
* allowExclusions and all: true. Preserve this field when saving controlled selection;
|
|
21
|
+
* resolve these groups as well as selected before running a bulk action.
|
|
22
|
+
*/
|
|
23
|
+
excludedGroupIds?: string[];
|
|
18
24
|
}
|
|
19
25
|
/**
|
|
20
26
|
* One checkbox row in the order it is rendered. Expanded nested rows are part of this list,
|
|
@@ -4,7 +4,7 @@ import { IDragSelectionRow } from "./interfaces";
|
|
|
4
4
|
* @param rows every checkbox row in render order, expanded nested rows included, so ranges can
|
|
5
5
|
* span nesting levels.
|
|
6
6
|
*/
|
|
7
|
-
export declare const useDragSelection: (rows: IDragSelectionRow[], gridRef: RefObject<HTMLElement | null> | undefined, onBatchSelect: (rangeIds: string[], select: boolean, base:
|
|
7
|
+
export declare const useDragSelection: <TSelection = Set<string>>(rows: IDragSelectionRow[], gridRef: RefObject<HTMLElement | null> | undefined, onBatchSelect: (rangeIds: string[], select: boolean, base: TSelection) => void, getBaseSelection: () => TSelection, isSelectable: (row: IDragSelectionRow) => boolean, isEnabled: boolean) => {
|
|
8
8
|
onCheckboxMouseDown: (id: string, checked: boolean, e: ReactMouseEvent) => void;
|
|
9
9
|
suppressNextChangeRef: RefObject<boolean>;
|
|
10
10
|
};
|
|
@@ -19,7 +19,7 @@ export const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection,
|
|
|
19
19
|
isEnabledRef.current = isEnabled;
|
|
20
20
|
const anchorIdRef = useRef(null);
|
|
21
21
|
const anchorSelectRef = useRef(true);
|
|
22
|
-
const baseSelectedRef = useRef(
|
|
22
|
+
const baseSelectedRef = useRef(null);
|
|
23
23
|
const isDraggingRef = useRef(false);
|
|
24
24
|
const movedRef = useRef(false);
|
|
25
25
|
const lastResultKeyRef = useRef("");
|
|
@@ -28,7 +28,7 @@ export const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection,
|
|
|
28
28
|
const attachedGridElementRef = useRef(null);
|
|
29
29
|
const emitRange = useCallback((currentId) => {
|
|
30
30
|
const anchorId = anchorIdRef.current;
|
|
31
|
-
if (anchorId === null) {
|
|
31
|
+
if (anchorId === null || baseSelectedRef.current === null) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
const range = getRangeIds(rowsRef.current, anchorId, currentId, isSelectableRef.current);
|
|
@@ -82,7 +82,7 @@ export const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection,
|
|
|
82
82
|
(_c = attachedGridElementRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener("scroll", onScroll);
|
|
83
83
|
(_d = attachedGridElementRef.current) === null || _d === void 0 ? void 0 : _d.classList.remove(DRAG_CLASS);
|
|
84
84
|
attachedGridElementRef.current = null;
|
|
85
|
-
}, [onMouseMove, onScroll]);
|
|
85
|
+
}, [onMouseMove, onScroll]);
|
|
86
86
|
const onCheckboxMouseDown = useCallback((id, checked, e) => {
|
|
87
87
|
var _a, _b, _c, _d, _e;
|
|
88
88
|
// Right-click between drag-end and the trailing click must not clear suppression.
|
|
@@ -92,7 +92,7 @@ export const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection,
|
|
|
92
92
|
if (!isEnabledRef.current || e.button !== 0) {
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
95
|
-
if (e.shiftKey && anchorIdRef.current !== null) {
|
|
95
|
+
if (e.shiftKey && anchorIdRef.current !== null && baseSelectedRef.current !== null) {
|
|
96
96
|
e.preventDefault();
|
|
97
97
|
const anchorId = anchorIdRef.current;
|
|
98
98
|
const anchorInList = rowsRef.current.some(row => row.id === anchorId);
|
|
@@ -10,6 +10,8 @@ export interface ISelectableRowsOptions<T extends IRowEntity<N>, N extends IEnti
|
|
|
10
10
|
onSelect: (selection: ISelectionValue) => void;
|
|
11
11
|
/** Preserve cross-page Select All using excluded IDs. Consumers must resolve exclusions before running bulk actions. Defaults to false. */
|
|
12
12
|
allowExclusions?: boolean;
|
|
13
|
+
/** Changes when the dataset represented by the selection is replaced, rather than paged. */
|
|
14
|
+
selectionDatasetId?: string | number;
|
|
13
15
|
checkboxDisabled?: (entity: T | N, isNested?: boolean) => boolean;
|
|
14
16
|
checkboxVisible?: (entity: T | N, isNested?: boolean) => boolean;
|
|
15
17
|
checkboxInHeader?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { injectString } from "../../utils/localization/translationsDictionary";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
/* eslint-disable complexity */
|
|
4
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { SelectionState } from "./interfaces";
|
|
6
6
|
import { CheckboxCell } from "../../dataGrid/columns/checkboxColumn/checkboxCell";
|
|
7
7
|
import { SelectableHeader } from "./selectableHeader";
|
|
@@ -13,7 +13,8 @@ import { isRowChecked } from "./utils/isRowChecked";
|
|
|
13
13
|
import { getCurrentPageSelection } from "./utils/getCurrentPageSelection";
|
|
14
14
|
import { useDragSelection } from "./useDragSelection";
|
|
15
15
|
import { getDragSelectionRows } from "./utils/getDragSelectionRows";
|
|
16
|
-
import { isShowMoreRow } from "../../commonHelpers/showMoreRow";
|
|
16
|
+
import { getChildrenForSelection, isShowMoreRow } from "../../commonHelpers/showMoreRow";
|
|
17
|
+
import { checkExcludedRow, createExcludedSelection, resolveGroupExclusions } from "./utils/groupExclusions";
|
|
17
18
|
injectString("cs", "Select all", "Vybrat v\u0161e");
|
|
18
19
|
injectString("da-DK", "Select all", "V\xE6lg alle");
|
|
19
20
|
injectString("de", "Select all", "Alle ausw\xE4hlen");
|
|
@@ -88,13 +89,14 @@ export const isAllSelection = (all, selectedCount, allowExclusions) => !!all &&
|
|
|
88
89
|
export const SelectableWrapperName = "Selectable";
|
|
89
90
|
// Infinite scroll has no pages, so the header checkbox always means "select all" (never current page).
|
|
90
91
|
const resolveCheckboxEmitsCurrentPage = (isInfinite, checkboxSelectsCurrentPage, turnOffSelectAll) => isInfinite ? false : checkboxSelectsCurrentPage !== null && checkboxSelectsCurrentPage !== void 0 ? checkboxSelectsCurrentPage : turnOffSelectAll;
|
|
91
|
-
const getSelectionMenuState = (allSelected, selections, pageState) => allSelected ? selections.size === 0 ? SelectionState.All : SelectionState.Partial : pageState;
|
|
92
92
|
export const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMode, selectable, isInfinite = false, gridRef, expandedRows) => {
|
|
93
93
|
var _a;
|
|
94
94
|
const {
|
|
95
95
|
translate
|
|
96
96
|
} = useLanguage();
|
|
97
|
-
const
|
|
97
|
+
const previousDatasetId = useRef(selectable === null || selectable === void 0 ? void 0 : selectable.selectionDatasetId);
|
|
98
|
+
const datasetWasReplaced = (selectable === null || selectable === void 0 ? void 0 : selectable.selectionDatasetId) !== undefined && previousDatasetId.current !== undefined && selectable.selectionDatasetId !== previousDatasetId.current;
|
|
99
|
+
const appliedSelections = useMemo(() => getSelections(selectable === null || selectable === void 0 ? void 0 : selectable.selection), [selectable === null || selectable === void 0 ? void 0 : selectable.selection]);
|
|
98
100
|
const [state, setState] = useState(SelectionState.None);
|
|
99
101
|
const checkboxVisible = useMemo(() => {
|
|
100
102
|
const base = (selectable === null || selectable === void 0 ? void 0 : selectable.checkboxVisible) ? selectable.checkboxVisible : (selectable === null || selectable === void 0 ? void 0 : selectable.strategy) !== "nested" ? (_, isNested) => !isNested : () => true;
|
|
@@ -110,16 +112,19 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
110
112
|
}
|
|
111
113
|
if (selectable === null || selectable === void 0 ? void 0 : selectable.selectionLimit) {
|
|
112
114
|
const limit = selectable.selectionLimit;
|
|
113
|
-
return entity =>
|
|
115
|
+
return entity => appliedSelections.size >= limit && !appliedSelections.has(entity.id);
|
|
114
116
|
}
|
|
115
117
|
return () => false;
|
|
116
|
-
}, [selectable,
|
|
118
|
+
}, [selectable, appliedSelections]);
|
|
117
119
|
// `checkRow` and `getCurrentPageSelection` read callbacks off `selectable`, so hand them the
|
|
118
120
|
// wrapped ones to apply the same exclusions.
|
|
119
121
|
const wrappedSelectable = useMemo(() => selectable ? Object.assign(Object.assign({}, selectable), {
|
|
120
122
|
checkboxVisible,
|
|
121
123
|
checkboxDisabled
|
|
122
124
|
}) : undefined, [selectable, checkboxVisible, checkboxDisabled]);
|
|
125
|
+
const resolvedSelection = useMemo(() => resolveGroupExclusions(entities, wrappedSelectable, datasetWasReplaced), [datasetWasReplaced, entities, wrappedSelectable]);
|
|
126
|
+
const selections = useMemo(() => getSelections(resolvedSelection), [resolvedSelection]);
|
|
127
|
+
const excludedGroupIds = useMemo(() => new Set((selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) && selectable.strategy === "nested" && (resolvedSelection === null || resolvedSelection === void 0 ? void 0 : resolvedSelection.all) ? resolvedSelection.excludedGroupIds : []), [selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, resolvedSelection === null || resolvedSelection === void 0 ? void 0 : resolvedSelection.all, resolvedSelection === null || resolvedSelection === void 0 ? void 0 : resolvedSelection.excludedGroupIds]);
|
|
123
128
|
const checkboxPlaceholder = useMemo(() => {
|
|
124
129
|
if ((selectable === null || selectable === void 0 ? void 0 : selectable.checkboxPlaceholder) !== undefined) {
|
|
125
130
|
return selectable.checkboxPlaceholder;
|
|
@@ -134,21 +139,21 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
134
139
|
var _a;
|
|
135
140
|
return isAllSelection((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all, selections.size, selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions);
|
|
136
141
|
}, [(_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all, selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions, selections.size]);
|
|
137
|
-
const selectableState = useMemo(() => calculateSelectionState(entities, selections, isAllSelected, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy), [checkboxDisabled, checkboxVisible, entities, isAllSelected, selections, selectable === null || selectable === void 0 ? void 0 : selectable.strategy]);
|
|
138
|
-
const selectionMenuState = getSelectionMenuState(isAllSelected, selections, selectableState);
|
|
142
|
+
const selectableState = useMemo(() => calculateSelectionState(entities, new Set([...selections, ...excludedGroupIds]), isAllSelected, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy), [checkboxDisabled, checkboxVisible, entities, isAllSelected, selections, excludedGroupIds, selectable === null || selectable === void 0 ? void 0 : selectable.strategy]);
|
|
139
143
|
const firstColumnId = useMemo(() => columns.length > 0 ? columns[0].id : null, [columns]);
|
|
140
144
|
useEffect(() => {
|
|
141
145
|
if (selectable && selectable.selection) {
|
|
142
|
-
|
|
143
|
-
const newState = calculateSelectionState(entities, newSelections, isAllSelected, checkboxVisible, checkboxDisabled, selectable.strategy);
|
|
144
|
-
setState(newState);
|
|
146
|
+
setState(selectableState);
|
|
145
147
|
}
|
|
146
|
-
}, [
|
|
148
|
+
}, [selectable, selectableState]);
|
|
147
149
|
const getNewSelection = useCallback((id, checked) => {
|
|
148
150
|
if (isAllSelected && !(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions)) {
|
|
149
151
|
const included = getCurrentPageSelection(entities, wrappedSelectable);
|
|
150
152
|
checkRow(included, wrappedSelectable, entities, id, checked);
|
|
151
|
-
return
|
|
153
|
+
return {
|
|
154
|
+
selected: included,
|
|
155
|
+
groups: new Set()
|
|
156
|
+
};
|
|
152
157
|
}
|
|
153
158
|
if (isAllSelected) {
|
|
154
159
|
// MYG-142234: `selections` holds the ids excluded from the "all" selection.
|
|
@@ -156,22 +161,29 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
156
161
|
// exclusion set - it must never be rebuilt from `entities` (the current page),
|
|
157
162
|
// otherwise every other page's rows would silently fall out of the selection.
|
|
158
163
|
const excluded = new Set(selections);
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
const groups = new Set(excludedGroupIds);
|
|
165
|
+
checkExcludedRow(excluded, groups, wrappedSelectable, entities, id, checked);
|
|
166
|
+
return {
|
|
167
|
+
selected: excluded,
|
|
168
|
+
groups
|
|
169
|
+
};
|
|
161
170
|
}
|
|
162
171
|
checkRow(selections, wrappedSelectable, entities, id, checked);
|
|
163
|
-
return
|
|
164
|
-
|
|
172
|
+
return {
|
|
173
|
+
selected: selections,
|
|
174
|
+
groups: new Set()
|
|
175
|
+
};
|
|
176
|
+
}, [entities, selectable, wrappedSelectable, selections, excludedGroupIds, isAllSelected]);
|
|
165
177
|
const onSelectListener = useCallback((id, checked) => {
|
|
166
178
|
const wasAllSelected = !!(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) && isAllSelected;
|
|
167
|
-
const
|
|
179
|
+
const {
|
|
180
|
+
selected: newSelection,
|
|
181
|
+
groups
|
|
182
|
+
} = getNewSelection(id, checked);
|
|
168
183
|
const newState = calculateSelectionState(entities, newSelection, wasAllSelected, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy);
|
|
169
184
|
// MYG-142234: once selection spans "all" pages, unchecking a row must keep `all: true`
|
|
170
185
|
// and only record the exclusion - it must not collapse to the current page's ids.
|
|
171
|
-
const newValue = wasAllSelected ? {
|
|
172
|
-
selected: [...newSelection],
|
|
173
|
-
all: true
|
|
174
|
-
} : {
|
|
186
|
+
const newValue = wasAllSelected ? createExcludedSelection(newSelection, groups) : {
|
|
175
187
|
selected: [...newSelection],
|
|
176
188
|
all: newState === SelectionState.All
|
|
177
189
|
};
|
|
@@ -180,24 +192,43 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
180
192
|
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
181
193
|
}, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, setState, getNewSelection, isAllSelected]);
|
|
182
194
|
const onBatchSelect = useCallback((rangeIds, select, base) => {
|
|
183
|
-
const result = new Set(base);
|
|
195
|
+
const result = new Set(base.selected);
|
|
196
|
+
const groups = new Set(base.excludedGroupIds);
|
|
184
197
|
const limit = selectable === null || selectable === void 0 ? void 0 : selectable.selectionLimit;
|
|
185
198
|
const wasAllSelected = !!(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) && isAllSelected;
|
|
186
199
|
for (const id of rangeIds) {
|
|
187
200
|
if (!wasAllSelected && select && limit !== undefined && result.size >= limit) {
|
|
188
201
|
break;
|
|
189
202
|
}
|
|
190
|
-
|
|
203
|
+
if (wasAllSelected) {
|
|
204
|
+
checkExcludedRow(result, groups, wrappedSelectable, entities, id, select);
|
|
205
|
+
} else {
|
|
206
|
+
checkRow(result, wrappedSelectable, entities, id, select);
|
|
207
|
+
}
|
|
191
208
|
}
|
|
192
209
|
const newState = calculateSelectionState(entities, result, wasAllSelected, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy);
|
|
193
|
-
const newValue = {
|
|
210
|
+
const newValue = wasAllSelected ? createExcludedSelection(result, groups) : {
|
|
194
211
|
selected: [...result],
|
|
195
|
-
all:
|
|
212
|
+
all: newState === SelectionState.All
|
|
196
213
|
};
|
|
197
214
|
setState(newState);
|
|
198
215
|
selectable === null || selectable === void 0 ? void 0 : selectable.onSelect(newValue);
|
|
199
216
|
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
200
217
|
}, [entities, selectable, wrappedSelectable, checkboxVisible, checkboxDisabled, setSelectMode, isAllSelected]);
|
|
218
|
+
// Persist group intent separately from concrete IDs so remounts and incremental batches agree.
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
previousDatasetId.current = selectable === null || selectable === void 0 ? void 0 : selectable.selectionDatasetId;
|
|
221
|
+
}, [selectable === null || selectable === void 0 ? void 0 : selectable.selectionDatasetId]);
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
const applied = selectable === null || selectable === void 0 ? void 0 : selectable.selection;
|
|
224
|
+
if (!applied || !resolvedSelection || !selectable.allowExclusions || !applied.all || selectable.strategy !== "nested") {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const sameIds = (left = [], right = []) => left.length === right.length && left.every((id, index) => id === right[index]);
|
|
228
|
+
if (!sameIds(applied.selected, resolvedSelection.selected) || !sameIds(applied.excludedGroupIds, resolvedSelection.excludedGroupIds)) {
|
|
229
|
+
selectable.onSelect(resolvedSelection);
|
|
230
|
+
}
|
|
231
|
+
}, [selectable, resolvedSelection]);
|
|
201
232
|
// Deliberately independent of the current selection, so the drag anchor survives the
|
|
202
233
|
// selection changes a drag itself produces.
|
|
203
234
|
const {
|
|
@@ -208,7 +239,12 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
208
239
|
const entity = entityById.get(row.id);
|
|
209
240
|
return !!entity && checkboxVisible(entity, row.isNested) && !checkboxDisabled(entity, row.isNested);
|
|
210
241
|
}, [entityById, checkboxVisible, checkboxDisabled]);
|
|
211
|
-
const getBaseSelection = useCallback(() =>
|
|
242
|
+
const getBaseSelection = useCallback(() => Object.assign({
|
|
243
|
+
all: isAllSelected,
|
|
244
|
+
selected: [...(isAllSelected && !(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) ? getCurrentPageSelection(entities, wrappedSelectable) : selections)]
|
|
245
|
+
}, excludedGroupIds.size > 0 ? {
|
|
246
|
+
excludedGroupIds: [...excludedGroupIds]
|
|
247
|
+
} : {}), [isAllSelected, selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions, entities, wrappedSelectable, selections, excludedGroupIds]);
|
|
212
248
|
const {
|
|
213
249
|
onCheckboxMouseDown,
|
|
214
250
|
suppressNextChangeRef
|
|
@@ -221,7 +257,7 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
221
257
|
onSelectListener(id, checked);
|
|
222
258
|
}, [onSelectListener, suppressNextChangeRef]);
|
|
223
259
|
const onChangeSelectionState = useCallback(newState => {
|
|
224
|
-
var _a
|
|
260
|
+
var _a;
|
|
225
261
|
if (newState === SelectionState.All) {
|
|
226
262
|
(selectable === null || selectable === void 0 ? void 0 : selectable.onSelect) && selectable.onSelect({
|
|
227
263
|
selected: [],
|
|
@@ -240,17 +276,16 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
240
276
|
}
|
|
241
277
|
const newSelections = getCurrentPageSelection(entities, wrappedSelectable);
|
|
242
278
|
setState(newState);
|
|
243
|
-
const previousSelections =
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
} : {
|
|
279
|
+
const previousSelections = [...selections];
|
|
280
|
+
const groups = new Set(excludedGroupIds);
|
|
281
|
+
entities.forEach(entity => groups.delete(entity.id));
|
|
282
|
+
const newValue = (selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) && ((_a = selectable.selection) === null || _a === void 0 ? void 0 : _a.all) ? createExcludedSelection(new Set(previousSelections.filter(id => !newSelections.has(id))), groups) : {
|
|
248
283
|
selected: [...new Set([...previousSelections, ...newSelections])],
|
|
249
284
|
all: false
|
|
250
285
|
};
|
|
251
286
|
selectable === null || selectable === void 0 ? void 0 : selectable.onSelect(newValue);
|
|
252
287
|
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
253
|
-
}, [selectable, wrappedSelectable, entities, setSelectMode]);
|
|
288
|
+
}, [selectable, wrappedSelectable, entities, setSelectMode, selections, excludedGroupIds]);
|
|
254
289
|
const checkboxTitle = useCallback(entity => (selectable === null || selectable === void 0 ? void 0 : selectable.checkboxTitle) ? selectable.checkboxTitle(entity) : firstColumnId ? entity[firstColumnId] || entity.id : entity.id, [firstColumnId, selectable]);
|
|
255
290
|
const headerTitle = useCallback(() => {
|
|
256
291
|
if (selectable === null || selectable === void 0 ? void 0 : selectable.headerTitle) {
|
|
@@ -266,7 +301,15 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
266
301
|
// row must be evaluated through the SelectionState.All (exclusion-aware) branch of
|
|
267
302
|
// isRowChecked - not the per-page `state`, which can be Partial/None for a page that
|
|
268
303
|
// contains some of those exclusions.
|
|
269
|
-
(entity, isNested) =>
|
|
304
|
+
(entity, isNested) => {
|
|
305
|
+
if (!isNested && isAllSelected && excludedGroupIds.has(entity.id)) {
|
|
306
|
+
return {
|
|
307
|
+
indeterminate: false,
|
|
308
|
+
checked: false
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
return isRowChecked(selections, isAllSelected ? SelectionState.All : state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, entity, isNested, checkboxVisible, checkboxDisabled);
|
|
312
|
+
}, [selections, excludedGroupIds, isAllSelected, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, checkboxVisible, checkboxDisabled]);
|
|
270
313
|
const hasSelectable = !!selectable;
|
|
271
314
|
const selectableCheckboxSelectsCurrentPage = selectable === null || selectable === void 0 ? void 0 : selectable.checkboxSelectsCurrentPage;
|
|
272
315
|
const selectableTurnOffSelectAll = selectable === null || selectable === void 0 ? void 0 : selectable.turnOffSelectAll;
|
|
@@ -332,13 +375,17 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
332
375
|
// keep `all: true` - it must never be treated as an inclusion list, or
|
|
333
376
|
// every other page's selection would be silently wiped out.
|
|
334
377
|
const currentPageIds = getCurrentPageSelection(entities, wrappedSelectable);
|
|
335
|
-
const newExcluded = new Set([...
|
|
336
|
-
const
|
|
378
|
+
const newExcluded = new Set([...selections, ...currentPageIds]);
|
|
379
|
+
const groups = new Set(excludedGroupIds);
|
|
380
|
+
if (selectable.strategy === "nested") {
|
|
381
|
+
entities.forEach(entity => {
|
|
382
|
+
var _a;
|
|
383
|
+
if ((_a = getChildrenForSelection(entity)) === null || _a === void 0 ? void 0 : _a.length) groups.add(entity.id);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
const newState = calculateSelectionState(entities, new Set([...newExcluded, ...groups]), true, checkboxVisible, checkboxDisabled, selectable.strategy);
|
|
337
387
|
setState(newState);
|
|
338
|
-
selectable.onSelect(
|
|
339
|
-
selected: [...newExcluded],
|
|
340
|
-
all: true
|
|
341
|
-
});
|
|
388
|
+
selectable.onSelect(createExcludedSelection(newExcluded, groups));
|
|
342
389
|
setSelectMode(true);
|
|
343
390
|
} else {
|
|
344
391
|
// Intentionally different from onSelect(None) ("Deselect all" menu item, which clears everything).
|
|
@@ -354,7 +401,7 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
354
401
|
setSelectMode(remaining.length > 0);
|
|
355
402
|
}
|
|
356
403
|
},
|
|
357
|
-
calculateSelectionState: () =>
|
|
404
|
+
calculateSelectionState: () => isAllSelected ? selections.size === 0 && excludedGroupIds.size === 0 ? SelectionState.All : SelectionState.Partial : selections.size === 0 ? SelectionState.None : selectableState === SelectionState.CurrentPage ? SelectionState.CurrentPage : SelectionState.Partial,
|
|
358
405
|
checkboxInHeader: checkboxInHeaderValue,
|
|
359
406
|
header: selectableHeader,
|
|
360
407
|
onSelect: newState => {
|
|
@@ -367,7 +414,7 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
367
414
|
return cell;
|
|
368
415
|
}
|
|
369
416
|
};
|
|
370
|
-
}, [checkboxDisabled, checkboxTitle, checkboxVisible, headerTitle, onChangeSelectionState, onCheckboxChange, onCheckboxMouseDown, hasSelectable, checkboxEmitsCurrentPage, checkboxInHeaderValue, selectableHeader, selectableTurnOffSelectAll, isInfinite, selectable, wrappedSelectable,
|
|
417
|
+
}, [checkboxDisabled, checkboxTitle, checkboxVisible, headerTitle, onChangeSelectionState, onCheckboxChange, onCheckboxMouseDown, hasSelectable, checkboxEmitsCurrentPage, checkboxInHeaderValue, selectableHeader, selectableTurnOffSelectAll, isInfinite, selectable, wrappedSelectable, selectableState, isAllSelected, selections, excludedGroupIds, state, isMobile, checkboxPlaceholder, isEntityChecked, entities, setSelectMode]);
|
|
371
418
|
const selectableFeedWrapper = useCallback((primaryData, secondaryData, entity, isNested) => {
|
|
372
419
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
373
420
|
if (!entity) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getChildrenForSelection } from "../../../commonHelpers/showMoreRow";
|
|
2
2
|
import { SelectionState } from "../interfaces";
|
|
3
|
+
const areAllLoading = (children) => children.every(child => child.isLoading);
|
|
3
4
|
export const calculateSelectionState = (entities, selections, all, checkboxVisible, checkboxDisabled, strategy) => {
|
|
4
5
|
if (selections.size === 0) {
|
|
5
6
|
return all ? SelectionState.All : SelectionState.None;
|
|
@@ -9,7 +10,7 @@ export const calculateSelectionState = (entities, selections, all, checkboxVisib
|
|
|
9
10
|
// otherwise-fully-selected set (see ISelectionValue), rather than included ids.
|
|
10
11
|
const isExcluded = (entity) => {
|
|
11
12
|
const children = strategy === "nested" ? getChildrenForSelection(entity) : undefined;
|
|
12
|
-
if (children && children.length > 0) {
|
|
13
|
+
if (children && children.length > 0 && !areAllLoading(children)) {
|
|
13
14
|
return children.every(child => {
|
|
14
15
|
if (!checkboxVisible(child, true)) {
|
|
15
16
|
return true;
|
|
@@ -24,7 +25,7 @@ export const calculateSelectionState = (entities, selections, all, checkboxVisib
|
|
|
24
25
|
};
|
|
25
26
|
const isPartiallyExcluded = (entity) => {
|
|
26
27
|
const children = strategy === "nested" ? getChildrenForSelection(entity) : undefined;
|
|
27
|
-
if (children && children.length > 0) {
|
|
28
|
+
if (children && children.length > 0 && !areAllLoading(children)) {
|
|
28
29
|
return children.some(child => selections.has(child.id));
|
|
29
30
|
}
|
|
30
31
|
return selections.has(entity.id);
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { getChildrenForSelection, isShowMoreRow } from "../../../commonHelpers/showMoreRow";
|
|
2
|
+
const isLoadingRow = (entity) => !!entity.isLoading;
|
|
2
3
|
export const getCurrentPageSelection = (entities, selectable) => {
|
|
3
4
|
const newSelections = new Set();
|
|
4
5
|
entities.forEach(entity => {
|
|
5
|
-
|
|
6
|
+
if (isLoadingRow(entity) || isShowMoreRow(entity)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const isVisible = (selectable === null || selectable === void 0 ? void 0 : selectable.checkboxVisible) ? selectable.checkboxVisible(entity) : true;
|
|
6
10
|
const isEnabled = !(selectable === null || selectable === void 0 ? void 0 : selectable.checkboxDisabled) || !selectable.checkboxDisabled(entity);
|
|
7
11
|
const children = (selectable === null || selectable === void 0 ? void 0 : selectable.strategy) === "nested" ? getChildrenForSelection(entity) : undefined;
|
|
8
12
|
if (children && children.length > 0) {
|
|
9
13
|
children.forEach(child => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
if (isLoadingRow(child) || isShowMoreRow(child)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const isChildVisible = (selectable === null || selectable === void 0 ? void 0 : selectable.checkboxVisible) ? selectable.checkboxVisible(child, true) : true;
|
|
13
18
|
const isChildEnabled = !(selectable === null || selectable === void 0 ? void 0 : selectable.checkboxDisabled) || !selectable.checkboxDisabled(child, true);
|
|
14
19
|
if (isChildVisible && isChildEnabled) {
|
|
15
20
|
newSelections.add(child.id);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IEntityWithId } from "../../../commonHelpers/entity";
|
|
2
|
+
import { IRowEntity } from "../../../dataGrid/row/row";
|
|
3
|
+
import { ISelectionValue } from "../interfaces";
|
|
4
|
+
import { ISelectableRowsOptions } from "../useSelectableRows";
|
|
5
|
+
export declare const createExcludedSelection: (selected: Set<string>, groups: Set<string>) => ISelectionValue;
|
|
6
|
+
export declare const resolveGroupExclusions: <T extends IRowEntity<N>, N extends IEntityWithId>(entities: T[], selectable: ISelectableRowsOptions<T, N> | undefined, pruneMissingGroups?: boolean) => ISelectionValue | undefined;
|
|
7
|
+
export declare const checkExcludedRow: <T extends IRowEntity<N>, N extends IEntityWithId>(selected: Set<string>, groups: Set<string>, selectable: ISelectableRowsOptions<T, N> | undefined, entities: T[], id: string, checked: boolean) => void;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getChildrenForSelection } from "../../../commonHelpers/showMoreRow";
|
|
2
|
+
import { checkRow } from "./checkRow";
|
|
3
|
+
import { getCurrentPageSelection } from "./getCurrentPageSelection";
|
|
4
|
+
export const createExcludedSelection = (selected, groups) => (Object.assign({ all: true, selected: [...selected] }, (groups.size > 0 ? { excludedGroupIds: [...groups] } : {})));
|
|
5
|
+
export const resolveGroupExclusions = (entities, selectable, pruneMissingGroups = false) => {
|
|
6
|
+
var _a, _b;
|
|
7
|
+
const selection = selectable === null || selectable === void 0 ? void 0 : selectable.selection;
|
|
8
|
+
if (!(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) || !(selection === null || selection === void 0 ? void 0 : selection.all) || selectable.strategy !== "nested") {
|
|
9
|
+
return selection;
|
|
10
|
+
}
|
|
11
|
+
const selected = new Set(selection.selected);
|
|
12
|
+
const groups = new Set(selection.excludedGroupIds);
|
|
13
|
+
for (const entity of entities) {
|
|
14
|
+
if (selected.has(entity.id) && ((_a = getChildrenForSelection(entity)) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
15
|
+
groups.add(entity.id);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
for (const id of groups) {
|
|
19
|
+
const entity = entities.find(item => item.id === id);
|
|
20
|
+
if (!entity && pruneMissingGroups) {
|
|
21
|
+
selected.delete(id);
|
|
22
|
+
groups.delete(id);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (!entity)
|
|
26
|
+
continue;
|
|
27
|
+
if ((_b = getChildrenForSelection(entity)) === null || _b === void 0 ? void 0 : _b.length) {
|
|
28
|
+
selected.delete(id);
|
|
29
|
+
}
|
|
30
|
+
for (const childId of getCurrentPageSelection([entity], selectable)) {
|
|
31
|
+
selected.add(childId);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return createExcludedSelection(selected, groups);
|
|
35
|
+
};
|
|
36
|
+
export const checkExcludedRow = (selected, groups, selectable, entities, id, checked) => {
|
|
37
|
+
var _a, _b;
|
|
38
|
+
if ((selectable === null || selectable === void 0 ? void 0 : selectable.strategy) === "nested") {
|
|
39
|
+
const entity = entities.find(item => item.id === id);
|
|
40
|
+
if (checked) {
|
|
41
|
+
groups.delete(id);
|
|
42
|
+
selected.delete(id);
|
|
43
|
+
// Selecting a child overrides the whole-group intent, retaining the other concrete exclusions.
|
|
44
|
+
for (const parent of entities) {
|
|
45
|
+
if ((_a = getChildrenForSelection(parent)) === null || _a === void 0 ? void 0 : _a.some(child => child.id === id)) {
|
|
46
|
+
groups.delete(parent.id);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (entity && ((_b = getChildrenForSelection(entity)) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
51
|
+
groups.add(id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
checkRow(selected, selectable, entities, id, !checked);
|
|
55
|
+
};
|
|
@@ -24,7 +24,7 @@ export const isRowChecked = (selections, state, strategy, entity, isNested, chec
|
|
|
24
24
|
if (children && children.length > 0) {
|
|
25
25
|
const selectableChildren = filterSelectable(children, checkboxVisible, checkboxDisabled);
|
|
26
26
|
if (selectableChildren.length === 0) {
|
|
27
|
-
return { indeterminate: false, checked:
|
|
27
|
+
return { indeterminate: false, checked: !selections.has(entity.id) };
|
|
28
28
|
}
|
|
29
29
|
const allChildrenChecked = selectableChildren.every(child => !selections.has(child.id));
|
|
30
30
|
const someChildrenChecked = selectableChildren.some(child => !selections.has(child.id));
|