@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.
Files changed (64) hide show
  1. package/README.md +26 -29
  2. package/dist/button/button.d.ts +1 -2
  3. package/dist/button/button.js +5 -22
  4. package/dist/button/buttonDisabledProps.d.ts +35 -0
  5. package/dist/button/buttonDisabledProps.js +33 -0
  6. package/dist/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +1 -1
  7. package/dist/dropdownRaw/dropdownHelper.d.ts +20 -3
  8. package/dist/dropdownRaw/dropdownHelper.js +29 -6
  9. package/dist/dropdownRaw/dropdownRaw.js +22 -6
  10. package/dist/header/components/collapsedItemsControl/collapsedItemsControl.js +1 -1
  11. package/dist/header/headerButton.d.ts +15 -2
  12. package/dist/header/headerButton.js +11 -6
  13. package/dist/index.css +4 -8
  14. package/dist/menu/components/menuButton.js +40 -58
  15. package/dist/pageHeader/pageHeaderButton.d.ts +15 -1
  16. package/dist/pageHeader/pageHeaderButton.js +8 -6
  17. package/dist/pillExpandable/pillExpandable.js +3 -1
  18. package/dist/pillExpandable/pillExpandableSimple.d.ts +2 -1
  19. package/dist/pillExpandable/pillExpandableSimple.js +2 -2
  20. package/dist/table/selectable/interfaces.d.ts +6 -0
  21. package/dist/table/selectable/useDragSelection.d.ts +1 -1
  22. package/dist/table/selectable/useDragSelection.js +4 -4
  23. package/dist/table/selectable/useSelectableRows.d.ts +2 -0
  24. package/dist/table/selectable/useSelectableRows.js +88 -41
  25. package/dist/table/selectable/utils/calculateSelectionState.js +3 -2
  26. package/dist/table/selectable/utils/getCurrentPageSelection.js +9 -4
  27. package/dist/table/selectable/utils/groupExclusions.d.ts +7 -0
  28. package/dist/table/selectable/utils/groupExclusions.js +61 -0
  29. package/dist/table/selectable/utils/isRowChecked.js +1 -1
  30. package/dist/table/table.js +6 -5
  31. package/dist/tooltip/tooltip.d.ts +5 -3
  32. package/dist/tooltip/tooltip.js +11 -9
  33. package/esm/button/button.d.ts +1 -2
  34. package/esm/button/button.js +5 -22
  35. package/esm/button/buttonDisabledProps.d.ts +35 -0
  36. package/esm/button/buttonDisabledProps.js +29 -0
  37. package/esm/dataGrid/withSelectableRows/components/bulkActions/bulkActions.d.ts +1 -1
  38. package/esm/dropdownRaw/dropdownHelper.d.ts +20 -3
  39. package/esm/dropdownRaw/dropdownHelper.js +27 -5
  40. package/esm/dropdownRaw/dropdownRaw.js +23 -7
  41. package/esm/header/components/collapsedItemsControl/collapsedItemsControl.js +1 -1
  42. package/esm/header/headerButton.d.ts +15 -2
  43. package/esm/header/headerButton.js +11 -6
  44. package/esm/menu/components/menuButton.js +40 -58
  45. package/esm/pageHeader/pageHeaderButton.d.ts +15 -1
  46. package/esm/pageHeader/pageHeaderButton.js +8 -6
  47. package/esm/pillExpandable/pillExpandable.js +3 -1
  48. package/esm/pillExpandable/pillExpandableSimple.d.ts +2 -1
  49. package/esm/pillExpandable/pillExpandableSimple.js +2 -2
  50. package/esm/table/selectable/interfaces.d.ts +6 -0
  51. package/esm/table/selectable/useDragSelection.d.ts +1 -1
  52. package/esm/table/selectable/useDragSelection.js +4 -4
  53. package/esm/table/selectable/useSelectableRows.d.ts +2 -0
  54. package/esm/table/selectable/useSelectableRows.js +90 -43
  55. package/esm/table/selectable/utils/calculateSelectionState.js +3 -2
  56. package/esm/table/selectable/utils/getCurrentPageSelection.js +9 -4
  57. package/esm/table/selectable/utils/groupExclusions.d.ts +7 -0
  58. package/esm/table/selectable/utils/groupExclusions.js +55 -0
  59. package/esm/table/selectable/utils/isRowChecked.js +1 -1
  60. package/esm/table/table.js +6 -5
  61. package/esm/tooltip/tooltip.d.ts +5 -3
  62. package/esm/tooltip/tooltip.js +11 -9
  63. package/package.json +1 -1
  64. 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, focusableWhenDisabled, ...restProps }: IPageHeaderButton): import("react/jsx-runtime").JSX.Element;
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 {};
@@ -15,14 +15,16 @@ exports.PageHeaderButton = exports.PageHeaderButtonDisplayName = void 0;
15
15
  const jsx_runtime_1 = require("react/jsx-runtime");
16
16
  const textIconButton_1 = require("../textIconButton/textIconButton");
17
17
  const classNames_1 = require("../commonHelpers/classNames/classNames");
18
+ const tooltip_1 = require("../tooltip/tooltip");
19
+ const buttonDisabledProps_1 = require("../button/buttonDisabledProps");
18
20
  exports.PageHeaderButtonDisplayName = "PageHeaderButton";
19
21
  const PageHeaderButton = (_a) => {
20
- var { id, children, icon, iconPosition = textIconButton_1.ButtonIconPosition.Start, className = "", onClick, title, disabled, focusableWhenDisabled } = _a, restProps = __rest(_a, ["id", "children", "icon", "iconPosition", "className", "onClick", "title", "disabled", "focusableWhenDisabled"]);
21
- const fullClassName = (0, classNames_1.classNames)(["zen-page-header-button", className || ""]);
22
- const props = Object.assign(Object.assign({}, restProps), { disabled,
23
- // Defaults on when disabled; pass `focusableWhenDisabled={false}` to opt back into native `disabled`.
24
- focusableWhenDisabled: focusableWhenDisabled !== null && focusableWhenDisabled !== void 0 ? focusableWhenDisabled : Boolean(disabled) });
25
- return ((0, jsx_runtime_1.jsx)(textIconButton_1.TextIconButton, Object.assign({ id: id, icon: icon, title: title, iconPosition: iconPosition, className: fullClassName, onClick: onClick ? e => onClick(id, e) : undefined }, props, { children: children })));
22
+ var { id, children, icon, iconPosition = textIconButton_1.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"]);
23
+ const tooltip = disabled ? disabledTooltip : undefined;
24
+ const _b = (0, buttonDisabledProps_1.getButtonDisabledProps)({ disabled, focusable: Boolean(tooltip), link }), { className: disabledClassName } = _b, disabledProps = __rest(_b, ["className"]);
25
+ const fullClassName = (0, classNames_1.classNames)(["zen-page-header-button", className || "", disabledClassName !== null && disabledClassName !== void 0 ? disabledClassName : ""]);
26
+ const button = ((0, jsx_runtime_1.jsx)(textIconButton_1.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 })));
27
+ return tooltip ? ((0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { trigger: button, alignment: tooltipAlignment, children: tooltip })) : (button);
26
28
  };
27
29
  exports.PageHeaderButton = PageHeaderButton;
28
30
  exports.PageHeaderButton.displayName = exports.PageHeaderButtonDisplayName;
@@ -428,6 +428,7 @@ const PillExpandableBase = ({
428
428
  }) => {
429
429
  const popupId = (0, react_1.useId)();
430
430
  const descriptionId = (0, react_1.useId)();
431
+ const counterId = (0, react_1.useId)();
431
432
  const [descriptionElement, setDescriptionElement] = (0, react_1.useState)(null);
432
433
  const isDrive = (0, useDrive_1.useDrive)();
433
434
  const [isMobile, setIsMobile] = (0, react_1.useState)(false);
@@ -596,10 +597,11 @@ const PillExpandableBase = ({
596
597
  errorHandler: errorHandler,
597
598
  isBeta: isBeta,
598
599
  isMobile: isMobile,
599
- descriptionId: isPopupOpen && descriptionElement ? descriptionId : undefined,
600
+ descriptionId: [uniqueChildren && !hideCounterNumber ? counterId : undefined, isPopupOpen && descriptionElement ? descriptionId : undefined].filter(Boolean).join(" ") || undefined,
600
601
  ariaHasPopup: "dialog",
601
602
  dataAnalyticsId: dataAnalyticsId
602
603
  }), uniqueChildren && (0, jsx_runtime_1.jsx)(pillExpandableSimple_1.PillExpandableSimple, {
604
+ id: counterId,
603
605
  icon: secondaryIcon || effectiveIcon,
604
606
  text: hideCounterNumber ? "" : counterText,
605
607
  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 {};
@@ -8,7 +8,7 @@ const iconChevronTop_1 = require("../icons/iconChevronTop");
8
8
  const iconChevronBottom_1 = require("../icons/iconChevronBottom");
9
9
  const iconException_1 = require("../icons/iconException");
10
10
  const classNames_1 = require("../commonHelpers/classNames/classNames");
11
- const PillExpandableSimple = ({ onExpand, text, expanded, includeExpandIcon = true, type = "warning", icon = iconException_1.IconException, isBeta, isMobile, ref, className, descriptionId, ariaHasPopup, isDecorative, dataAnalyticsId
11
+ const PillExpandableSimple = ({ id, onExpand, text, expanded, includeExpandIcon = true, type = "warning", icon = iconException_1.IconException, isBeta, isMobile, ref, className, descriptionId, ariaHasPopup, isDecorative, dataAnalyticsId
12
12
  // eslint-disable-next-line complexity
13
13
  }) => {
14
14
  const iconDriveClassName = (0, useDriveClassName_1.useDriveClassName)("icon");
@@ -37,7 +37,7 @@ const PillExpandableSimple = ({ onExpand, text, expanded, includeExpandIcon = tr
37
37
  size: iconSize
38
38
  }) }) }))] }));
39
39
  if (isDecorative) {
40
- return ((0, jsx_runtime_1.jsx)("span", { className: (0, classNames_1.classNames)([
40
+ return ((0, jsx_runtime_1.jsx)("span", { id: id, className: (0, classNames_1.classNames)([
41
41
  "zen-status-pill__container",
42
42
  `zen-status-pill__container--${type}`,
43
43
  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: Set<string>) => void, getBaseSelection: () => Set<string>, isSelectable: (row: IDragSelectionRow) => boolean, isEnabled: boolean) => {
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
  };
@@ -22,7 +22,7 @@ const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection, isSele
22
22
  isEnabledRef.current = isEnabled;
23
23
  const anchorIdRef = (0, react_1.useRef)(null);
24
24
  const anchorSelectRef = (0, react_1.useRef)(true);
25
- const baseSelectedRef = (0, react_1.useRef)(new Set());
25
+ const baseSelectedRef = (0, react_1.useRef)(null);
26
26
  const isDraggingRef = (0, react_1.useRef)(false);
27
27
  const movedRef = (0, react_1.useRef)(false);
28
28
  const lastResultKeyRef = (0, react_1.useRef)("");
@@ -31,7 +31,7 @@ const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection, isSele
31
31
  const attachedGridElementRef = (0, react_1.useRef)(null);
32
32
  const emitRange = (0, react_1.useCallback)((currentId) => {
33
33
  const anchorId = anchorIdRef.current;
34
- if (anchorId === null) {
34
+ if (anchorId === null || baseSelectedRef.current === null) {
35
35
  return;
36
36
  }
37
37
  const range = (0, getRangeIds_1.getRangeIds)(rowsRef.current, anchorId, currentId, isSelectableRef.current);
@@ -85,7 +85,7 @@ const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection, isSele
85
85
  (_c = attachedGridElementRef.current) === null || _c === void 0 ? void 0 : _c.removeEventListener("scroll", onScroll);
86
86
  (_d = attachedGridElementRef.current) === null || _d === void 0 ? void 0 : _d.classList.remove(DRAG_CLASS);
87
87
  attachedGridElementRef.current = null;
88
- }, [onMouseMove, onScroll]); // eslint-disable-line react-hooks/exhaustive-deps
88
+ }, [onMouseMove, onScroll]);
89
89
  const onCheckboxMouseDown = (0, react_1.useCallback)((id, checked, e) => {
90
90
  var _a, _b, _c, _d, _e;
91
91
  // Right-click between drag-end and the trailing click must not clear suppression.
@@ -95,7 +95,7 @@ const useDragSelection = (rows, gridRef, onBatchSelect, getBaseSelection, isSele
95
95
  if (!isEnabledRef.current || e.button !== 0) {
96
96
  return;
97
97
  }
98
- if (e.shiftKey && anchorIdRef.current !== null) {
98
+ if (e.shiftKey && anchorIdRef.current !== null && baseSelectedRef.current !== null) {
99
99
  e.preventDefault();
100
100
  const anchorId = anchorIdRef.current;
101
101
  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;
@@ -88,6 +88,7 @@ const getCurrentPageSelection_1 = require("./utils/getCurrentPageSelection");
88
88
  const useDragSelection_1 = require("./useDragSelection");
89
89
  const getDragSelectionRows_1 = require("./utils/getDragSelectionRows");
90
90
  const showMoreRow_1 = require("../../commonHelpers/showMoreRow");
91
+ const groupExclusions_1 = require("./utils/groupExclusions");
91
92
  const getEmptySelection = () => ({
92
93
  all: false,
93
94
  selected: []
@@ -98,13 +99,14 @@ exports.isAllSelection = isAllSelection;
98
99
  exports.SelectableWrapperName = "Selectable";
99
100
  // Infinite scroll has no pages, so the header checkbox always means "select all" (never current page).
100
101
  const resolveCheckboxEmitsCurrentPage = (isInfinite, checkboxSelectsCurrentPage, turnOffSelectAll) => isInfinite ? false : checkboxSelectsCurrentPage !== null && checkboxSelectsCurrentPage !== void 0 ? checkboxSelectsCurrentPage : turnOffSelectAll;
101
- const getSelectionMenuState = (allSelected, selections, pageState) => allSelected ? selections.size === 0 ? interfaces_1.SelectionState.All : interfaces_1.SelectionState.Partial : pageState;
102
102
  const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMode, selectable, isInfinite = false, gridRef, expandedRows) => {
103
103
  var _a;
104
104
  const {
105
105
  translate
106
106
  } = (0, useLanguage_1.useLanguage)();
107
- const selections = (0, react_1.useMemo)(() => (0, getSelection_1.getSelections)(selectable === null || selectable === void 0 ? void 0 : selectable.selection), [selectable === null || selectable === void 0 ? void 0 : selectable.selection]);
107
+ const previousDatasetId = (0, react_1.useRef)(selectable === null || selectable === void 0 ? void 0 : selectable.selectionDatasetId);
108
+ const datasetWasReplaced = (selectable === null || selectable === void 0 ? void 0 : selectable.selectionDatasetId) !== undefined && previousDatasetId.current !== undefined && selectable.selectionDatasetId !== previousDatasetId.current;
109
+ const appliedSelections = (0, react_1.useMemo)(() => (0, getSelection_1.getSelections)(selectable === null || selectable === void 0 ? void 0 : selectable.selection), [selectable === null || selectable === void 0 ? void 0 : selectable.selection]);
108
110
  const [state, setState] = (0, react_1.useState)(interfaces_1.SelectionState.None);
109
111
  const checkboxVisible = (0, react_1.useMemo)(() => {
110
112
  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;
@@ -120,16 +122,19 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
120
122
  }
121
123
  if (selectable === null || selectable === void 0 ? void 0 : selectable.selectionLimit) {
122
124
  const limit = selectable.selectionLimit;
123
- return entity => selections.size >= limit && !selections.has(entity.id);
125
+ return entity => appliedSelections.size >= limit && !appliedSelections.has(entity.id);
124
126
  }
125
127
  return () => false;
126
- }, [selectable, selections]);
128
+ }, [selectable, appliedSelections]);
127
129
  // `checkRow` and `getCurrentPageSelection` read callbacks off `selectable`, so hand them the
128
130
  // wrapped ones to apply the same exclusions.
129
131
  const wrappedSelectable = (0, react_1.useMemo)(() => selectable ? Object.assign(Object.assign({}, selectable), {
130
132
  checkboxVisible,
131
133
  checkboxDisabled
132
134
  }) : undefined, [selectable, checkboxVisible, checkboxDisabled]);
135
+ const resolvedSelection = (0, react_1.useMemo)(() => (0, groupExclusions_1.resolveGroupExclusions)(entities, wrappedSelectable, datasetWasReplaced), [datasetWasReplaced, entities, wrappedSelectable]);
136
+ const selections = (0, react_1.useMemo)(() => (0, getSelection_1.getSelections)(resolvedSelection), [resolvedSelection]);
137
+ const excludedGroupIds = (0, react_1.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]);
133
138
  const checkboxPlaceholder = (0, react_1.useMemo)(() => {
134
139
  if ((selectable === null || selectable === void 0 ? void 0 : selectable.checkboxPlaceholder) !== undefined) {
135
140
  return selectable.checkboxPlaceholder;
@@ -144,21 +149,21 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
144
149
  var _a;
145
150
  return (0, exports.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);
146
151
  }, [(_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]);
147
- const selectableState = (0, react_1.useMemo)(() => (0, calculateSelectionState_1.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]);
148
- const selectionMenuState = getSelectionMenuState(isAllSelected, selections, selectableState);
152
+ const selectableState = (0, react_1.useMemo)(() => (0, calculateSelectionState_1.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]);
149
153
  const firstColumnId = (0, react_1.useMemo)(() => columns.length > 0 ? columns[0].id : null, [columns]);
150
154
  (0, react_1.useEffect)(() => {
151
155
  if (selectable && selectable.selection) {
152
- const newSelections = new Set(selectable.selection.selected);
153
- const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, newSelections, isAllSelected, checkboxVisible, checkboxDisabled, selectable.strategy);
154
- setState(newState);
156
+ setState(selectableState);
155
157
  }
156
- }, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, isAllSelected]);
158
+ }, [selectable, selectableState]);
157
159
  const getNewSelection = (0, react_1.useCallback)((id, checked) => {
158
160
  if (isAllSelected && !(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions)) {
159
161
  const included = (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, wrappedSelectable);
160
162
  (0, checkRow_1.checkRow)(included, wrappedSelectable, entities, id, checked);
161
- return included;
163
+ return {
164
+ selected: included,
165
+ groups: new Set()
166
+ };
162
167
  }
163
168
  if (isAllSelected) {
164
169
  // MYG-142234: `selections` holds the ids excluded from the "all" selection.
@@ -166,22 +171,29 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
166
171
  // exclusion set - it must never be rebuilt from `entities` (the current page),
167
172
  // otherwise every other page's rows would silently fall out of the selection.
168
173
  const excluded = new Set(selections);
169
- (0, checkRow_1.checkRow)(excluded, wrappedSelectable, entities, id, !checked);
170
- return excluded;
174
+ const groups = new Set(excludedGroupIds);
175
+ (0, groupExclusions_1.checkExcludedRow)(excluded, groups, wrappedSelectable, entities, id, checked);
176
+ return {
177
+ selected: excluded,
178
+ groups
179
+ };
171
180
  }
172
181
  (0, checkRow_1.checkRow)(selections, wrappedSelectable, entities, id, checked);
173
- return selections;
174
- }, [entities, selectable, wrappedSelectable, selections, isAllSelected]);
182
+ return {
183
+ selected: selections,
184
+ groups: new Set()
185
+ };
186
+ }, [entities, selectable, wrappedSelectable, selections, excludedGroupIds, isAllSelected]);
175
187
  const onSelectListener = (0, react_1.useCallback)((id, checked) => {
176
188
  const wasAllSelected = !!(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) && isAllSelected;
177
- const newSelection = getNewSelection(id, checked);
189
+ const {
190
+ selected: newSelection,
191
+ groups
192
+ } = getNewSelection(id, checked);
178
193
  const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, newSelection, wasAllSelected, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy);
179
194
  // MYG-142234: once selection spans "all" pages, unchecking a row must keep `all: true`
180
195
  // and only record the exclusion - it must not collapse to the current page's ids.
181
- const newValue = wasAllSelected ? {
182
- selected: [...newSelection],
183
- all: true
184
- } : {
196
+ const newValue = wasAllSelected ? (0, groupExclusions_1.createExcludedSelection)(newSelection, groups) : {
185
197
  selected: [...newSelection],
186
198
  all: newState === interfaces_1.SelectionState.All
187
199
  };
@@ -190,24 +202,43 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
190
202
  setSelectMode(newValue.all || newValue.selected.length > 0);
191
203
  }, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, setState, getNewSelection, isAllSelected]);
192
204
  const onBatchSelect = (0, react_1.useCallback)((rangeIds, select, base) => {
193
- const result = new Set(base);
205
+ const result = new Set(base.selected);
206
+ const groups = new Set(base.excludedGroupIds);
194
207
  const limit = selectable === null || selectable === void 0 ? void 0 : selectable.selectionLimit;
195
208
  const wasAllSelected = !!(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) && isAllSelected;
196
209
  for (const id of rangeIds) {
197
210
  if (!wasAllSelected && select && limit !== undefined && result.size >= limit) {
198
211
  break;
199
212
  }
200
- (0, checkRow_1.checkRow)(result, wrappedSelectable, entities, id, wasAllSelected ? !select : select);
213
+ if (wasAllSelected) {
214
+ (0, groupExclusions_1.checkExcludedRow)(result, groups, wrappedSelectable, entities, id, select);
215
+ } else {
216
+ (0, checkRow_1.checkRow)(result, wrappedSelectable, entities, id, select);
217
+ }
201
218
  }
202
219
  const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, result, wasAllSelected, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy);
203
- const newValue = {
220
+ const newValue = wasAllSelected ? (0, groupExclusions_1.createExcludedSelection)(result, groups) : {
204
221
  selected: [...result],
205
- all: wasAllSelected || newState === interfaces_1.SelectionState.All
222
+ all: newState === interfaces_1.SelectionState.All
206
223
  };
207
224
  setState(newState);
208
225
  selectable === null || selectable === void 0 ? void 0 : selectable.onSelect(newValue);
209
226
  setSelectMode(newValue.all || newValue.selected.length > 0);
210
227
  }, [entities, selectable, wrappedSelectable, checkboxVisible, checkboxDisabled, setSelectMode, isAllSelected]);
228
+ // Persist group intent separately from concrete IDs so remounts and incremental batches agree.
229
+ (0, react_1.useEffect)(() => {
230
+ previousDatasetId.current = selectable === null || selectable === void 0 ? void 0 : selectable.selectionDatasetId;
231
+ }, [selectable === null || selectable === void 0 ? void 0 : selectable.selectionDatasetId]);
232
+ (0, react_1.useEffect)(() => {
233
+ const applied = selectable === null || selectable === void 0 ? void 0 : selectable.selection;
234
+ if (!applied || !resolvedSelection || !selectable.allowExclusions || !applied.all || selectable.strategy !== "nested") {
235
+ return;
236
+ }
237
+ const sameIds = (left = [], right = []) => left.length === right.length && left.every((id, index) => id === right[index]);
238
+ if (!sameIds(applied.selected, resolvedSelection.selected) || !sameIds(applied.excludedGroupIds, resolvedSelection.excludedGroupIds)) {
239
+ selectable.onSelect(resolvedSelection);
240
+ }
241
+ }, [selectable, resolvedSelection]);
211
242
  // Deliberately independent of the current selection, so the drag anchor survives the
212
243
  // selection changes a drag itself produces.
213
244
  const {
@@ -218,7 +249,12 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
218
249
  const entity = entityById.get(row.id);
219
250
  return !!entity && checkboxVisible(entity, row.isNested) && !checkboxDisabled(entity, row.isNested);
220
251
  }, [entityById, checkboxVisible, checkboxDisabled]);
221
- const getBaseSelection = (0, react_1.useCallback)(() => isAllSelected && !(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) ? (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, wrappedSelectable) : new Set(selections), [isAllSelected, selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions, entities, wrappedSelectable, selections]);
252
+ const getBaseSelection = (0, react_1.useCallback)(() => Object.assign({
253
+ all: isAllSelected,
254
+ selected: [...(isAllSelected && !(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) ? (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, wrappedSelectable) : selections)]
255
+ }, excludedGroupIds.size > 0 ? {
256
+ excludedGroupIds: [...excludedGroupIds]
257
+ } : {}), [isAllSelected, selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions, entities, wrappedSelectable, selections, excludedGroupIds]);
222
258
  const {
223
259
  onCheckboxMouseDown,
224
260
  suppressNextChangeRef
@@ -231,7 +267,7 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
231
267
  onSelectListener(id, checked);
232
268
  }, [onSelectListener, suppressNextChangeRef]);
233
269
  const onChangeSelectionState = (0, react_1.useCallback)(newState => {
234
- var _a, _b, _c;
270
+ var _a;
235
271
  if (newState === interfaces_1.SelectionState.All) {
236
272
  (selectable === null || selectable === void 0 ? void 0 : selectable.onSelect) && selectable.onSelect({
237
273
  selected: [],
@@ -250,17 +286,16 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
250
286
  }
251
287
  const newSelections = (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, wrappedSelectable);
252
288
  setState(newState);
253
- const previousSelections = (_b = (_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.selected) !== null && _b !== void 0 ? _b : [];
254
- const newValue = (selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) && ((_c = selectable.selection) === null || _c === void 0 ? void 0 : _c.all) ? {
255
- selected: previousSelections.filter(id => !newSelections.has(id)),
256
- all: true
257
- } : {
289
+ const previousSelections = [...selections];
290
+ const groups = new Set(excludedGroupIds);
291
+ entities.forEach(entity => groups.delete(entity.id));
292
+ const newValue = (selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) && ((_a = selectable.selection) === null || _a === void 0 ? void 0 : _a.all) ? (0, groupExclusions_1.createExcludedSelection)(new Set(previousSelections.filter(id => !newSelections.has(id))), groups) : {
258
293
  selected: [...new Set([...previousSelections, ...newSelections])],
259
294
  all: false
260
295
  };
261
296
  selectable === null || selectable === void 0 ? void 0 : selectable.onSelect(newValue);
262
297
  setSelectMode(newValue.all || newValue.selected.length > 0);
263
- }, [selectable, wrappedSelectable, entities, setSelectMode]);
298
+ }, [selectable, wrappedSelectable, entities, setSelectMode, selections, excludedGroupIds]);
264
299
  const checkboxTitle = (0, react_1.useCallback)(entity => (selectable === null || selectable === void 0 ? void 0 : selectable.checkboxTitle) ? selectable.checkboxTitle(entity) : firstColumnId ? entity[firstColumnId] || entity.id : entity.id, [firstColumnId, selectable]);
265
300
  const headerTitle = (0, react_1.useCallback)(() => {
266
301
  if (selectable === null || selectable === void 0 ? void 0 : selectable.headerTitle) {
@@ -276,7 +311,15 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
276
311
  // row must be evaluated through the SelectionState.All (exclusion-aware) branch of
277
312
  // isRowChecked - not the per-page `state`, which can be Partial/None for a page that
278
313
  // contains some of those exclusions.
279
- (entity, isNested) => (0, isRowChecked_1.isRowChecked)(selections, isAllSelected ? interfaces_1.SelectionState.All : state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, entity, isNested, checkboxVisible, checkboxDisabled), [selections, isAllSelected, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, checkboxVisible, checkboxDisabled]);
314
+ (entity, isNested) => {
315
+ if (!isNested && isAllSelected && excludedGroupIds.has(entity.id)) {
316
+ return {
317
+ indeterminate: false,
318
+ checked: false
319
+ };
320
+ }
321
+ return (0, isRowChecked_1.isRowChecked)(selections, isAllSelected ? interfaces_1.SelectionState.All : state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, entity, isNested, checkboxVisible, checkboxDisabled);
322
+ }, [selections, excludedGroupIds, isAllSelected, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, checkboxVisible, checkboxDisabled]);
280
323
  const hasSelectable = !!selectable;
281
324
  const selectableCheckboxSelectsCurrentPage = selectable === null || selectable === void 0 ? void 0 : selectable.checkboxSelectsCurrentPage;
282
325
  const selectableTurnOffSelectAll = selectable === null || selectable === void 0 ? void 0 : selectable.turnOffSelectAll;
@@ -342,13 +385,17 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
342
385
  // keep `all: true` - it must never be treated as an inclusion list, or
343
386
  // every other page's selection would be silently wiped out.
344
387
  const currentPageIds = (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, wrappedSelectable);
345
- const newExcluded = new Set([...selectable.selection.selected, ...currentPageIds]);
346
- const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, newExcluded, true, checkboxVisible, checkboxDisabled, selectable.strategy);
388
+ const newExcluded = new Set([...selections, ...currentPageIds]);
389
+ const groups = new Set(excludedGroupIds);
390
+ if (selectable.strategy === "nested") {
391
+ entities.forEach(entity => {
392
+ var _a;
393
+ if ((_a = (0, showMoreRow_1.getChildrenForSelection)(entity)) === null || _a === void 0 ? void 0 : _a.length) groups.add(entity.id);
394
+ });
395
+ }
396
+ const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, new Set([...newExcluded, ...groups]), true, checkboxVisible, checkboxDisabled, selectable.strategy);
347
397
  setState(newState);
348
- selectable.onSelect({
349
- selected: [...newExcluded],
350
- all: true
351
- });
398
+ selectable.onSelect((0, groupExclusions_1.createExcludedSelection)(newExcluded, groups));
352
399
  setSelectMode(true);
353
400
  } else {
354
401
  // Intentionally different from onSelect(None) ("Deselect all" menu item, which clears everything).
@@ -364,7 +411,7 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
364
411
  setSelectMode(remaining.length > 0);
365
412
  }
366
413
  },
367
- calculateSelectionState: () => selectionMenuState,
414
+ calculateSelectionState: () => isAllSelected ? selections.size === 0 && excludedGroupIds.size === 0 ? interfaces_1.SelectionState.All : interfaces_1.SelectionState.Partial : selections.size === 0 ? interfaces_1.SelectionState.None : selectableState === interfaces_1.SelectionState.CurrentPage ? interfaces_1.SelectionState.CurrentPage : interfaces_1.SelectionState.Partial,
368
415
  checkboxInHeader: checkboxInHeaderValue,
369
416
  header: selectableHeader,
370
417
  onSelect: newState => {
@@ -377,7 +424,7 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
377
424
  return cell;
378
425
  }
379
426
  };
380
- }, [checkboxDisabled, checkboxTitle, checkboxVisible, headerTitle, onChangeSelectionState, onCheckboxChange, onCheckboxMouseDown, hasSelectable, checkboxEmitsCurrentPage, checkboxInHeaderValue, selectableHeader, selectableTurnOffSelectAll, isInfinite, selectable, wrappedSelectable, selectionMenuState, state, isMobile, checkboxPlaceholder, isEntityChecked, entities, setSelectMode]);
427
+ }, [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]);
381
428
  const selectableFeedWrapper = (0, react_1.useCallback)((primaryData, secondaryData, entity, isNested) => {
382
429
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
383
430
  if (!entity) {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.calculateSelectionState = void 0;
4
4
  const showMoreRow_1 = require("../../../commonHelpers/showMoreRow");
5
5
  const interfaces_1 = require("../interfaces");
6
+ const areAllLoading = (children) => children.every(child => child.isLoading);
6
7
  const calculateSelectionState = (entities, selections, all, checkboxVisible, checkboxDisabled, strategy) => {
7
8
  if (selections.size === 0) {
8
9
  return all ? interfaces_1.SelectionState.All : interfaces_1.SelectionState.None;
@@ -12,7 +13,7 @@ const calculateSelectionState = (entities, selections, all, checkboxVisible, che
12
13
  // otherwise-fully-selected set (see ISelectionValue), rather than included ids.
13
14
  const isExcluded = (entity) => {
14
15
  const children = strategy === "nested" ? (0, showMoreRow_1.getChildrenForSelection)(entity) : undefined;
15
- if (children && children.length > 0) {
16
+ if (children && children.length > 0 && !areAllLoading(children)) {
16
17
  return children.every(child => {
17
18
  if (!checkboxVisible(child, true)) {
18
19
  return true;
@@ -27,7 +28,7 @@ const calculateSelectionState = (entities, selections, all, checkboxVisible, che
27
28
  };
28
29
  const isPartiallyExcluded = (entity) => {
29
30
  const children = strategy === "nested" ? (0, showMoreRow_1.getChildrenForSelection)(entity) : undefined;
30
- if (children && children.length > 0) {
31
+ if (children && children.length > 0 && !areAllLoading(children)) {
31
32
  return children.some(child => selections.has(child.id));
32
33
  }
33
34
  return selections.has(entity.id);
@@ -2,17 +2,22 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getCurrentPageSelection = void 0;
4
4
  const showMoreRow_1 = require("../../../commonHelpers/showMoreRow");
5
+ const isLoadingRow = (entity) => !!entity.isLoading;
5
6
  const getCurrentPageSelection = (entities, selectable) => {
6
7
  const newSelections = new Set();
7
8
  entities.forEach(entity => {
8
- const isVisible = !entity.isLoading && !(0, showMoreRow_1.isShowMoreRow)(entity) && ((selectable === null || selectable === void 0 ? void 0 : selectable.checkboxVisible) ? selectable.checkboxVisible(entity) : true);
9
+ if (isLoadingRow(entity) || (0, showMoreRow_1.isShowMoreRow)(entity)) {
10
+ return;
11
+ }
12
+ const isVisible = (selectable === null || selectable === void 0 ? void 0 : selectable.checkboxVisible) ? selectable.checkboxVisible(entity) : true;
9
13
  const isEnabled = !(selectable === null || selectable === void 0 ? void 0 : selectable.checkboxDisabled) || !selectable.checkboxDisabled(entity);
10
14
  const children = (selectable === null || selectable === void 0 ? void 0 : selectable.strategy) === "nested" ? (0, showMoreRow_1.getChildrenForSelection)(entity) : undefined;
11
15
  if (children && children.length > 0) {
12
16
  children.forEach(child => {
13
- const isChildVisible = !child.isLoading &&
14
- !(0, showMoreRow_1.isShowMoreRow)(child) &&
15
- ((selectable === null || selectable === void 0 ? void 0 : selectable.checkboxVisible) ? selectable.checkboxVisible(child, true) : true);
17
+ if (isLoadingRow(child) || (0, showMoreRow_1.isShowMoreRow)(child)) {
18
+ return;
19
+ }
20
+ const isChildVisible = (selectable === null || selectable === void 0 ? void 0 : selectable.checkboxVisible) ? selectable.checkboxVisible(child, true) : true;
16
21
  const isChildEnabled = !(selectable === null || selectable === void 0 ? void 0 : selectable.checkboxDisabled) || !selectable.checkboxDisabled(child, true);
17
22
  if (isChildVisible && isChildEnabled) {
18
23
  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,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkExcludedRow = exports.resolveGroupExclusions = exports.createExcludedSelection = void 0;
4
+ const showMoreRow_1 = require("../../../commonHelpers/showMoreRow");
5
+ const checkRow_1 = require("./checkRow");
6
+ const getCurrentPageSelection_1 = require("./getCurrentPageSelection");
7
+ const createExcludedSelection = (selected, groups) => (Object.assign({ all: true, selected: [...selected] }, (groups.size > 0 ? { excludedGroupIds: [...groups] } : {})));
8
+ exports.createExcludedSelection = createExcludedSelection;
9
+ const resolveGroupExclusions = (entities, selectable, pruneMissingGroups = false) => {
10
+ var _a, _b;
11
+ const selection = selectable === null || selectable === void 0 ? void 0 : selectable.selection;
12
+ if (!(selectable === null || selectable === void 0 ? void 0 : selectable.allowExclusions) || !(selection === null || selection === void 0 ? void 0 : selection.all) || selectable.strategy !== "nested") {
13
+ return selection;
14
+ }
15
+ const selected = new Set(selection.selected);
16
+ const groups = new Set(selection.excludedGroupIds);
17
+ for (const entity of entities) {
18
+ if (selected.has(entity.id) && ((_a = (0, showMoreRow_1.getChildrenForSelection)(entity)) === null || _a === void 0 ? void 0 : _a.length)) {
19
+ groups.add(entity.id);
20
+ }
21
+ }
22
+ for (const id of groups) {
23
+ const entity = entities.find(item => item.id === id);
24
+ if (!entity && pruneMissingGroups) {
25
+ selected.delete(id);
26
+ groups.delete(id);
27
+ continue;
28
+ }
29
+ if (!entity)
30
+ continue;
31
+ if ((_b = (0, showMoreRow_1.getChildrenForSelection)(entity)) === null || _b === void 0 ? void 0 : _b.length) {
32
+ selected.delete(id);
33
+ }
34
+ for (const childId of (0, getCurrentPageSelection_1.getCurrentPageSelection)([entity], selectable)) {
35
+ selected.add(childId);
36
+ }
37
+ }
38
+ return (0, exports.createExcludedSelection)(selected, groups);
39
+ };
40
+ exports.resolveGroupExclusions = resolveGroupExclusions;
41
+ const checkExcludedRow = (selected, groups, selectable, entities, id, checked) => {
42
+ var _a, _b;
43
+ if ((selectable === null || selectable === void 0 ? void 0 : selectable.strategy) === "nested") {
44
+ const entity = entities.find(item => item.id === id);
45
+ if (checked) {
46
+ groups.delete(id);
47
+ selected.delete(id);
48
+ // Selecting a child overrides the whole-group intent, retaining the other concrete exclusions.
49
+ for (const parent of entities) {
50
+ if ((_a = (0, showMoreRow_1.getChildrenForSelection)(parent)) === null || _a === void 0 ? void 0 : _a.some(child => child.id === id)) {
51
+ groups.delete(parent.id);
52
+ }
53
+ }
54
+ }
55
+ else if (entity && ((_b = (0, showMoreRow_1.getChildrenForSelection)(entity)) === null || _b === void 0 ? void 0 : _b.length)) {
56
+ groups.add(id);
57
+ }
58
+ }
59
+ (0, checkRow_1.checkRow)(selected, selectable, entities, id, !checked);
60
+ };
61
+ exports.checkExcludedRow = checkExcludedRow;
@@ -27,7 +27,7 @@ const isRowChecked = (selections, state, strategy, entity, isNested, checkboxVis
27
27
  if (children && children.length > 0) {
28
28
  const selectableChildren = filterSelectable(children, checkboxVisible, checkboxDisabled);
29
29
  if (selectableChildren.length === 0) {
30
- return { indeterminate: false, checked: true };
30
+ return { indeterminate: false, checked: !selections.has(entity.id) };
31
31
  }
32
32
  const allChildrenChecked = selectableChildren.every(child => !selections.has(child.id));
33
33
  const someChildrenChecked = selectableChildren.some(child => !selections.has(child.id));