@geotab/zenith 3.16.0-beta.2 → 3.16.0-beta.3

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 (59) hide show
  1. package/README.md +15 -12
  2. package/dist/absolute/absolute.js +1 -1
  3. package/dist/chart/plugins/linePlugin/getInterpolatedValue.d.ts +2 -2
  4. package/dist/chart/plugins/linePlugin/getInterpolatedValue.js +3 -2
  5. package/dist/chart/plugins/linePlugin/linePlugin.js +2 -1
  6. package/dist/chart/utils/getFormattedLabel.js +5 -1
  7. package/dist/checkbox/checkbox.d.ts +2 -1
  8. package/dist/checkbox/checkbox.js +2 -2
  9. package/dist/checkboxListWithAction/checkboxListWithAction.js +1 -0
  10. package/dist/commonHelpers/hooks/useTrapFocus.d.ts +0 -9
  11. package/dist/commonHelpers/hooks/useTrapFocus.js +14 -66
  12. package/dist/dataGrid/columns/checkboxColumn/checkboxCell.d.ts +2 -1
  13. package/dist/dataGrid/columns/checkboxColumn/checkboxCell.js +1 -1
  14. package/dist/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.d.ts +4 -2
  15. package/dist/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.js +10 -1
  16. package/dist/dataGrid/row/row.js +3 -2
  17. package/dist/dataGrid/withSelectableRows/withSelectableRows.js +73 -12
  18. package/dist/index.css +1 -1
  19. package/dist/table/selectable/interfaces.d.ts +9 -13
  20. package/dist/table/selectable/useDragSelection.d.ts +10 -0
  21. package/dist/table/selectable/useDragSelection.js +139 -0
  22. package/dist/table/selectable/useSelectableRows.d.ts +2 -2
  23. package/dist/table/selectable/useSelectableRows.js +59 -49
  24. package/dist/table/selectable/utils/calculateSelectionState.js +0 -35
  25. package/dist/table/selectable/utils/getDragSelectionRows.d.ts +15 -0
  26. package/dist/table/selectable/utils/getDragSelectionRows.js +28 -0
  27. package/dist/table/selectable/utils/getRangeIds.d.ts +2 -0
  28. package/dist/table/selectable/utils/getRangeIds.js +21 -0
  29. package/dist/table/selectable/utils/isRowChecked.js +1 -12
  30. package/dist/table/table.js +1 -1
  31. package/esm/absolute/absolute.js +1 -1
  32. package/esm/chart/plugins/linePlugin/getInterpolatedValue.d.ts +2 -2
  33. package/esm/chart/plugins/linePlugin/getInterpolatedValue.js +3 -2
  34. package/esm/chart/plugins/linePlugin/linePlugin.js +2 -1
  35. package/esm/chart/utils/getFormattedLabel.js +5 -1
  36. package/esm/checkbox/checkbox.d.ts +2 -1
  37. package/esm/checkbox/checkbox.js +2 -2
  38. package/esm/checkboxListWithAction/checkboxListWithAction.js +1 -0
  39. package/esm/commonHelpers/hooks/useTrapFocus.d.ts +0 -9
  40. package/esm/commonHelpers/hooks/useTrapFocus.js +15 -67
  41. package/esm/dataGrid/columns/checkboxColumn/checkboxCell.d.ts +2 -1
  42. package/esm/dataGrid/columns/checkboxColumn/checkboxCell.js +1 -1
  43. package/esm/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.d.ts +4 -2
  44. package/esm/dataGrid/columns/checkboxColumn/checkboxColumnWrapper.js +10 -1
  45. package/esm/dataGrid/row/row.js +3 -2
  46. package/esm/dataGrid/withSelectableRows/withSelectableRows.js +73 -12
  47. package/esm/table/selectable/interfaces.d.ts +9 -13
  48. package/esm/table/selectable/useDragSelection.d.ts +10 -0
  49. package/esm/table/selectable/useDragSelection.js +135 -0
  50. package/esm/table/selectable/useSelectableRows.d.ts +2 -2
  51. package/esm/table/selectable/useSelectableRows.js +59 -49
  52. package/esm/table/selectable/utils/calculateSelectionState.js +0 -35
  53. package/esm/table/selectable/utils/getDragSelectionRows.d.ts +15 -0
  54. package/esm/table/selectable/utils/getDragSelectionRows.js +24 -0
  55. package/esm/table/selectable/utils/getRangeIds.d.ts +2 -0
  56. package/esm/table/selectable/utils/getRangeIds.js +17 -0
  57. package/esm/table/selectable/utils/isRowChecked.js +1 -12
  58. package/esm/table/table.js +1 -1
  59. package/package.json +1 -1
package/README.md CHANGED
@@ -49,28 +49,31 @@ Zenith library provides components defined in Zenith Design System. It includes
49
49
 
50
50
  ### 3.16.0
51
51
 
52
- - Add `Tooltip.Inline` subcomponent for inline tooltip triggers
52
+ - Add `Tooltip.InlineTrigger` subcomponent for inline tooltip triggers
53
+ - Add `TrendIndicator` component, the `getTrendIndicatorDirection` helper, and `Table.TrendIndicator`
53
54
  - Add popup button variant for `Nav` items
54
55
  - Add integer-only mode prop to `Range` / `FilterBar.Range`
55
- - Add Arabic language support
56
56
  - Add experimental feature-flag infrastructure (`ZenithExperimentalProvider`, `useExperimentalFeature`)
57
57
  - Expose `Tag` and `ProgressIndicator` as `Table` sub-components (`Table.Tag`, `Table.ProgressIndicator`)
58
- - Complete RTL logical-direction support: CSS logical modifiers, `TAlignment` deprecated in favour of logical direction values, controlled `Popup` migration
59
- - Export `getTrendIndicatorDirection` helper
60
- - Add support for six additional languages
61
- - Fix cross-page selection in selectable tables clearing when a row is unchecked after select-all
58
+ - Add `MODAL_SCROLL_LOCK_CLASS` export to control scroll-lock release timing when a `Modal` closes
59
+ - Rename the Arabic locale from `ar` to `ar-001`; `ar` and any `ar-*` value still resolve to it
60
+ - Migrate component alignment defaults to logical direction values — `ControlledPopup` now defaults to `bottom-start` and `Tooltip` to `end`
61
+ - Complete RTL logical-direction support: `ControlledPopup` migration and `PillExpandable` alignment flipping
62
+ - Remove `isBannerTarget` from the side panel overlay target checks
63
+ - Apply `dataAnalyticsId` to nested `PillExpandable` child pill triggers
64
+ - Resolve 20 npm audit vulnerabilities in Zenith dependencies
65
+ - Add an `ariaLabel` prop to `Checkbox` and accessible names to `Dropdown` multi-select options
62
66
  - Fix multiline `Banner` header spacing when there is no close button
63
67
  - Fix scrolling in `Tabs` and `FiltersBar`
64
- - Fix `Tabs` fading and side panel slide direction in RTL layouts
68
+ - Fix `Tabs` fading in RTL layouts
69
+ - Fix side panel slide direction in RTL layouts
65
70
  - Fix pills and chips scrolling the page to a blank area in RTL
66
- - Fix icons ignoring their component's colour
67
71
  - Fix mobile header overflow and `ReportsPopup` missing from the kebab menu in non-English languages
68
- - Move `Tabs` :focus-visible outline outside the tab to distinguish it from the active state
72
+ - Distinguish the `Tabs` focus ring from the active tab, and move focus to a tab only on user-initiated changes
69
73
  - Fix `BetaPill` synthesising a Send feedback button when `feedbackAction` is undefined
70
- - Migrate component alignment defaults to logical direction values
71
- - Fix Storybook brand URL to resolve based on the environment
74
+ - Fix `Nav` mobile search autofocusing when the search box is closed
72
75
  - Fix `AutoFill` not selecting the chosen option on `DropdownRaw`
73
- - Resolve 20 npm audit vulnerabilities in Zenith dependencies
76
+ - Fix `LineChart` tooltip interpolation and accessible chart dates when a custom x-axis parser is used
74
77
 
75
78
  ### 3.15.0
76
79
 
@@ -111,7 +111,7 @@ const Absolute = ({ isOpen, id, paddingX, paddingY, className, children, trigger
111
111
  returnFocusToTrigger();
112
112
  }
113
113
  }, [isOpen, returnFocusToTrigger]);
114
- const condition = (0, react_1.useCallback)((subscriptionTrigger) => useTrapFocusWithTrigger !== "off" && !!subscriptionTrigger, [useTrapFocusWithTrigger]);
114
+ const condition = (0, react_1.useCallback)(() => (useTrapFocusWithTrigger === "off" ? false : true), [useTrapFocusWithTrigger]);
115
115
  (0, useTrapFocus_1.useTrapFocus)(popupRef, useTrapFocusWithTrigger === "withTrigger" ? triggerRef : undefined, isOpen, condition);
116
116
  (0, useEscape_1.useEscape)(popupRef, handleEscape, isOpen);
117
117
  (0, useArrowKey_1.useArrowKey)(popupRef, handleEscape, isOpen);
@@ -1,3 +1,3 @@
1
- import { Scale } from "chart.js";
1
+ import { Scale, type ChartOptions } from "chart.js";
2
2
  import { ILineChartData } from "../../lineChart/interfaces";
3
- export declare function getInterpolatedValue(xScale: Scale, data: ILineChartData, datasetIndex: number, xPixel: number): number | null;
3
+ export declare function getInterpolatedValue(xScale: Scale, data: ILineChartData, datasetIndex: number, xPixel: number, parsing?: ChartOptions<"line">["parsing"]): number | null;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getInterpolatedValue = getInterpolatedValue;
4
- function getInterpolatedValue(xScale, data, datasetIndex, xPixel) {
4
+ function getInterpolatedValue(xScale, data, datasetIndex, xPixel, parsing) {
5
5
  const dataset = data.datasets[datasetIndex];
6
6
  const dataPoints = dataset.data;
7
7
  if (dataPoints.length < 2) {
@@ -18,7 +18,8 @@ function getInterpolatedValue(xScale, data, datasetIndex, xPixel) {
18
18
  if (y === null) {
19
19
  continue;
20
20
  }
21
- const pointXPixel = xScale.getPixelForValue(x);
21
+ const parsedX = parsing === false ? x : xScale.parse(x, i);
22
+ const pointXPixel = xScale.getPixelForValue(parsedX);
22
23
  if (pointXPixel <= xPixel && pointXPixel > lowerXPixel) {
23
24
  lowerPoint = y;
24
25
  lowerXPixel = pointXPixel;
@@ -60,6 +60,7 @@ const LinePlugin = (containerId, options, isDark) => ({
60
60
  let lowestValueY = Infinity;
61
61
  const items = datasets
62
62
  .map((dataset, dsIndex) => {
63
+ var _a;
63
64
  if (!chart.isDatasetVisible(dsIndex)) {
64
65
  return undefined;
65
66
  }
@@ -67,7 +68,7 @@ const LinePlugin = (containerId, options, isDark) => ({
67
68
  return undefined;
68
69
  }
69
70
  const xScale = chart.scales.x;
70
- const value = (0, getInterpolatedValue_1.getInterpolatedValue)(xScale, chart.data, dsIndex, x);
71
+ const value = (0, getInterpolatedValue_1.getInterpolatedValue)(xScale, chart.data, dsIndex, x, (_a = dataset.parsing) !== null && _a !== void 0 ? _a : chart.options.parsing);
71
72
  const yAxisID = dataset.yAxisID || "y";
72
73
  const yScale = chart.scales[yAxisID];
73
74
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -6,14 +6,18 @@ function getFormattedLabel(value, dateFormatter, options) {
6
6
  var _a, _b, _c;
7
7
  const scaleType = (_b = (_a = options === null || options === void 0 ? void 0 : options.scales) === null || _a === void 0 ? void 0 : _a.x) === null || _b === void 0 ? void 0 : _b.type;
8
8
  let format;
9
+ let parser;
9
10
  if (((_c = options === null || options === void 0 ? void 0 : options.scales) === null || _c === void 0 ? void 0 : _c.x) && scaleType) {
10
11
  const scaleFormat = options.scales.x[scaleType];
11
12
  if ((scaleFormat === null || scaleFormat === void 0 ? void 0 : scaleFormat.unit) && scaleFormat.displayFormats && scaleFormat.displayFormats[scaleFormat.unit]) {
12
13
  format = scaleFormat.displayFormats[scaleFormat.unit];
13
14
  }
15
+ if (options.parsing !== false && scaleFormat && "parser" in scaleFormat && typeof scaleFormat.parser === "function") {
16
+ parser = scaleFormat.parser;
17
+ }
14
18
  }
15
19
  if (value instanceof Date || (typeof value === "string" && (0, isDateString_1.isDateString)(value))) {
16
- return dateFormatter(value, format);
20
+ return dateFormatter(parser ? new Date(parser(value)) : value, format);
17
21
  }
18
22
  return String(value);
19
23
  }
@@ -8,6 +8,7 @@ export interface ICheckbox extends IZenComponentProps {
8
8
  checked?: boolean;
9
9
  indeterminate?: boolean;
10
10
  title?: string;
11
+ ariaLabel?: string;
11
12
  disabled?: boolean;
12
13
  fullWidth?: boolean;
13
14
  reverse?: boolean;
@@ -16,4 +17,4 @@ export interface ICheckbox extends IZenComponentProps {
16
17
  tabIndex?: number;
17
18
  describedBy?: string;
18
19
  }
19
- export declare const Checkbox: ({ reverse, fullWidth, id, checked, indeterminate, title, className, children, disabled, wrapped, describedBy, ...rest }: ICheckbox) => import("react/jsx-runtime").JSX.Element;
20
+ export declare const Checkbox: ({ reverse, fullWidth, id, checked, indeterminate, title, ariaLabel, className, children, disabled, wrapped, describedBy, ...rest }: ICheckbox) => import("react/jsx-runtime").JSX.Element;
@@ -56,14 +56,14 @@ const checkboxIconCheckmark_1 = require("./checkboxIconCheckmark");
56
56
  const checkboxIconMinus_1 = require("./checkboxIconMinus");
57
57
  const useMobile_1 = require("../commonHelpers/hooks/useMobile");
58
58
  const Checkbox = (_a) => {
59
- var { reverse, fullWidth, id, checked, indeterminate, title, className = "", children, disabled, wrapped, describedBy } = _a, rest = __rest(_a, ["reverse", "fullWidth", "id", "checked", "indeterminate", "title", "className", "children", "disabled", "wrapped", "describedBy"]);
59
+ var { reverse, fullWidth, id, checked, indeterminate, title, ariaLabel, className = "", children, disabled, wrapped, describedBy } = _a, rest = __rest(_a, ["reverse", "fullWidth", "id", "checked", "indeterminate", "title", "ariaLabel", "className", "children", "disabled", "wrapped", "describedBy"]);
60
60
  const state = (0, checkboxUtils_1.getCheckboxState)(checked, indeterminate);
61
61
  const generatedId = react_1.default.useId();
62
62
  const intId = id || generatedId;
63
63
  const driveClasses = (0, useDriveClassName_1.useDriveClassName)("zen-checkbox");
64
64
  const isMobile = (0, useMobile_1.useMobile)();
65
65
  const checkboxIconClasses = (0, react_1.useMemo)(() => (0, classNames_1.classNames)(["zen-checkbox__icon", disabled ? "zen-checkbox__icon--disabled" : ""]), [disabled]);
66
- const checkbox = ((0, jsx_runtime_1.jsx)(triStateCheckbox_1.TriStateCheckbox, Object.assign({ className: "zen-checkbox__input", id: intId, checked: checked, indeterminate: indeterminate, disabled: disabled, "aria-label": title, "aria-describedby": describedBy }, rest)));
66
+ const checkbox = ((0, jsx_runtime_1.jsx)(triStateCheckbox_1.TriStateCheckbox, Object.assign({ className: "zen-checkbox__input", id: intId, checked: checked, indeterminate: indeterminate, disabled: disabled, "aria-label": ariaLabel || title, "aria-describedby": describedBy }, rest)));
67
67
  const iconAndLabel = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "zen-checkbox__box", "aria-hidden": true, children: state === checkboxState_1.CheckboxState.Indeterminate ? ((0, jsx_runtime_1.jsx)(checkboxIconMinus_1.CheckboxIconMinus, { className: checkboxIconClasses, size: driveClasses ? "bigger" : "medium" })) : state === checkboxState_1.CheckboxState.On ? ((0, jsx_runtime_1.jsx)(checkboxIconCheckmark_1.CheckboxIconCheckmark, { className: checkboxIconClasses, size: driveClasses ? "bigger" : "medium" })) : null }), children ? ((0, jsx_runtime_1.jsx)("div", { className: (0, classNames_1.classNames)(["zen-checkbox__label-text", fullWidth ? "zen-checkbox__label-text--full-width" : ""]), children: children })) : null] }));
68
68
  if (wrapped) {
69
69
  return ((0, jsx_runtime_1.jsxs)("label", { className: (0, classNames_1.classNames)(["zen-checkbox", driveClasses || "", className]), title: title, children: [checkbox, (0, jsx_runtime_1.jsx)("div", { className: (0, classNames_1.classNames)(["zen-checkbox__label", reverse ? "zen-checkbox__label--reverse" : ""]), children: iconAndLabel })] }));
@@ -453,6 +453,7 @@ const CheckboxListWithAction = ({
453
453
  checked: opt.checked,
454
454
  disabled: opt.blocked,
455
455
  title: translate("Toggle {groupName} filter").replace("{groupName}", titleForRender),
456
+ ariaLabel: titleForRender,
456
457
  describedBy: opt.isWithAction ? navigationInstructionsId : undefined,
457
458
  "data-indeterminate": opt.partialChecked,
458
459
  tabIndex: getTabIndex(ind, "checkbox", opt.blocked),
@@ -1,13 +1,4 @@
1
1
  import { RefObject } from "react";
2
2
  type TElementToBool = (element: HTMLElement) => boolean;
3
- /**
4
- * Traps keyboard (Tab) focus within `containerRef` (and optionally its `triggerRef`).
5
- *
6
- * Nested-popup contract: for correct nested-popup behaviour, a focused element that triggers an
7
- * open child popup must expose a `data-popup-id` attribute whose value is the `id` of the child
8
- * popup element rendered in the DOM. When present, focus is deferred to that child popup's trap.
9
- * This contract is fulfilled automatically by `ControlledPopup`; callers using `useTrapFocus`
10
- * directly must set `data-popup-id` themselves or nested popups will silently lose focus handling.
11
- */
12
3
  export declare const useTrapFocus: (containerRef: RefObject<HTMLElement | null>, triggerRef: RefObject<HTMLElement | null> | undefined, subscriptionTrigger: unknown, condition?: (t: unknown) => boolean, isElementVisible?: TElementToBool) => void;
13
4
  export {};
@@ -9,38 +9,18 @@ const isChildOf_1 = require("../../utils/isChildOf");
9
9
  const isElementHidden_1 = require("../../utils/isElementHidden");
10
10
  const zen_1 = require("../../utils/zen");
11
11
  const findFirstVisible = (elems, isElementVisible) => elems.find(elem => isElementVisible(elem));
12
- /**
13
- * Traps keyboard (Tab) focus within `containerRef` (and optionally its `triggerRef`).
14
- *
15
- * Nested-popup contract: for correct nested-popup behaviour, a focused element that triggers an
16
- * open child popup must expose a `data-popup-id` attribute whose value is the `id` of the child
17
- * popup element rendered in the DOM. When present, focus is deferred to that child popup's trap.
18
- * This contract is fulfilled automatically by `ControlledPopup`; callers using `useTrapFocus`
19
- * directly must set `data-popup-id` themselves or nested popups will silently lose focus handling.
20
- */
21
12
  const useTrapFocus = (containerRef, triggerRef, subscriptionTrigger, condition, isElementVisible) => {
22
13
  /* eslint-disable complexity */
23
14
  const handleKeyDown = (0, react_1.useCallback)(e => {
24
- var _a, _b, _c, _d, _e, _f, _g;
15
+ var _a, _b, _c, _d, _e, _f;
25
16
  /* eslint-enable complexity */
26
17
  const getChildCondition = () => {
27
- var _a, _b, _c;
28
- const targetEl = e.target;
29
- // If the target is a trigger for an open child popup, defer to that popup's
30
- // focus trap. Key on data-popup-id + DOM presence so this works even when
31
- // preventAttributesAutoSet suppresses aria-expanded.
32
- const dataPopupId = targetEl.getAttribute("data-popup-id");
33
- if (dataPopupId &&
34
- ((_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.getElementById(dataPopupId)) &&
35
- (0, isChildOf_1.isChildOf)(targetEl, containerRef.current) &&
36
- targetEl !== (triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current)) {
37
- return true;
38
- }
18
+ var _a, _b;
39
19
  return triggerRef
40
- ? !(0, isChildOf_1.isChildOf)(targetEl, containerRef.current) &&
41
- targetEl !== ((_b = zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.body) &&
42
- !(0, isChildOf_1.isChildOf)(targetEl, triggerRef.current)
43
- : !(0, isChildOf_1.isChildOf)(targetEl, containerRef.current) && targetEl !== ((_c = zen_1.zen.document) === null || _c === void 0 ? void 0 : _c.body);
20
+ ? !(0, isChildOf_1.isChildOf)(e.target, containerRef.current) &&
21
+ e.target !== ((_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.body) &&
22
+ !(0, isChildOf_1.isChildOf)(e.target, triggerRef.current)
23
+ : !(0, isChildOf_1.isChildOf)(e.target, containerRef.current) && e.target !== ((_b = zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.body);
44
24
  };
45
25
  if (!containerRef.current || getChildCondition()) {
46
26
  return;
@@ -50,14 +30,9 @@ const useTrapFocus = (containerRef, triggerRef, subscriptionTrigger, condition,
50
30
  : !(0, dialogHelpers_1.isElementInsideContainer)(target, containerEl.current) &&
51
31
  !(0, dialogHelpers_1.isElementInsideContainer)(target, triggerEl.current);
52
32
  const isTargetOutside = e.target ? checkIsElementOutside(e.target, containerRef, triggerRef) : undefined;
53
- const triggerElement = (_a = triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current) !== null && _a !== void 0 ? _a : null;
54
- const triggerSelf = (triggerElement === null || triggerElement === void 0 ? void 0 : triggerElement.matches(focusableSelector_1.FOCUSABLE_SELECTOR)) ? [triggerElement] : [];
55
- const triggerChildren = Array.from((_b = triggerElement === null || triggerElement === void 0 ? void 0 : triggerElement.querySelectorAll(focusableSelector_1.FOCUSABLE_SELECTOR)) !== null && _b !== void 0 ? _b : []);
56
- // querySelectorAll only returns descendants (never the element itself), so triggerSelf
57
- // and triggerChildren are disjoint by definition and need no deduplication.
58
- const triggerSelectors = [...triggerSelf, ...triggerChildren];
33
+ const triggerSelectors = ((_a = triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(focusableSelector_1.FOCUSABLE_SELECTOR)) || [];
59
34
  const containerSelectors = containerRef.current.querySelectorAll(focusableSelector_1.FOCUSABLE_SELECTOR);
60
- const focusable = triggerRef ? [...triggerSelectors, ...Array.from(containerSelectors)] : [...Array.from(containerSelectors)];
35
+ const focusable = triggerRef ? [...Array.from(triggerSelectors), ...Array.from(containerSelectors)] : [...Array.from(containerSelectors)];
61
36
  if (!focusable.length) {
62
37
  return;
63
38
  }
@@ -74,59 +49,32 @@ const useTrapFocus = (containerRef, triggerRef, subscriptionTrigger, condition,
74
49
  return;
75
50
  }
76
51
  if (e.shiftKey) {
77
- if (((_c = zen_1.zen.document) === null || _c === void 0 ? void 0 : _c.activeElement) === first) {
52
+ if (((_b = zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.activeElement) === first) {
78
53
  e.preventDefault();
79
54
  last === null || last === void 0 ? void 0 : last.focus();
80
55
  return;
81
56
  }
82
- if (firstContainerFocusable && ((_d = zen_1.zen.document) === null || _d === void 0 ? void 0 : _d.activeElement) === firstContainerFocusable) {
57
+ if (firstContainerFocusable && ((_c = zen_1.zen.document) === null || _c === void 0 ? void 0 : _c.activeElement) === firstContainerFocusable) {
83
58
  e.preventDefault();
84
59
  lastTriggerFocusable === null || lastTriggerFocusable === void 0 ? void 0 : lastTriggerFocusable.focus();
85
60
  }
86
61
  return;
87
62
  }
88
- if (((_e = zen_1.zen.document) === null || _e === void 0 ? void 0 : _e.activeElement) === last) {
63
+ if (((_d = zen_1.zen.document) === null || _d === void 0 ? void 0 : _d.activeElement) === last) {
89
64
  e.preventDefault();
90
65
  first === null || first === void 0 ? void 0 : first.focus();
91
66
  return;
92
67
  }
93
- if (lastTriggerFocusable && ((_f = zen_1.zen.document) === null || _f === void 0 ? void 0 : _f.activeElement) === lastTriggerFocusable) {
68
+ if (lastTriggerFocusable && ((_e = zen_1.zen.document) === null || _e === void 0 ? void 0 : _e.activeElement) === lastTriggerFocusable) {
94
69
  e.preventDefault();
95
70
  firstContainerFocusable === null || firstContainerFocusable === void 0 ? void 0 : firstContainerFocusable.focus();
96
71
  }
97
- else if (isLastChildOfFirst && first && (0, isChildOf_1.isChildOf)((_g = zen_1.zen.document) === null || _g === void 0 ? void 0 : _g.activeElement, first)) {
72
+ else if (isLastChildOfFirst && first && (0, isChildOf_1.isChildOf)((_f = zen_1.zen.document) === null || _f === void 0 ? void 0 : _f.activeElement, first)) {
98
73
  e.preventDefault();
99
74
  }
100
75
  return;
101
76
  }
102
- },
103
- // condition is consumed by useKeydown below, not read by handleKeyDown directly; its absence from deps is intentional.
104
- [containerRef, triggerRef, isElementVisible]);
77
+ }, [containerRef, triggerRef, isElementVisible]);
105
78
  (0, useKeydown_1.useKeydown)(handleKeyDown, subscriptionTrigger, condition);
106
- // When withTrigger mode closes (condition goes false), restore focus to the trigger
107
- // if focus landed on body (which happens when the popup's focused element is unmounted).
108
- // This restoration is intentionally scoped to the "focused element unmounted → body" case;
109
- // the general close case (e.g. click-outside, item selection) is handled separately by the
110
- // returnFocusToTrigger effect in absolute.tsx. Both are idempotent, so overlap is harmless.
111
- // Initialized to false because popups mount closed; the guard below reconciles the first
112
- // active/inactive edge, so a popup that mounts already open still resolves correctly.
113
- const isActiveRef = (0, react_1.useRef)(false);
114
- (0, react_1.useEffect)(() => {
115
- var _a, _b;
116
- const isActive = condition ? condition(subscriptionTrigger) : !!subscriptionTrigger;
117
- // Guard: short-circuit when the raw open/close state is unchanged to avoid spurious
118
- // focus restoration if an unstable condition reference re-fires this effect.
119
- if (!!subscriptionTrigger === isActiveRef.current) {
120
- isActiveRef.current = isActive;
121
- return;
122
- }
123
- if (!isActive && isActiveRef.current && (triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current)) {
124
- const active = (_a = zen_1.zen.document) === null || _a === void 0 ? void 0 : _a.activeElement;
125
- if (!active || active === ((_b = zen_1.zen.document) === null || _b === void 0 ? void 0 : _b.body)) {
126
- triggerRef.current.focus();
127
- }
128
- }
129
- isActiveRef.current = isActive;
130
- }, [condition, subscriptionTrigger, triggerRef]);
131
79
  };
132
80
  exports.useTrapFocus = useTrapFocus;
@@ -1,4 +1,4 @@
1
- import { FC, PropsWithChildren, ReactElement } from "react";
1
+ import { FC, MouseEvent as ReactMouseEvent, PropsWithChildren, ReactElement } from "react";
2
2
  import { IZenIdComponentProps } from "../../../commonHelpers/zenComponent";
3
3
  import "./checkboxColumn.less";
4
4
  interface ICheckboxCellProps extends IZenIdComponentProps {
@@ -8,6 +8,7 @@ interface ICheckboxCellProps extends IZenIdComponentProps {
8
8
  disabled?: boolean;
9
9
  children?: ReactElement<typeof CheckboxCell.Content>;
10
10
  onChange?: (id: string, checked: boolean) => void;
11
+ onMouseDown?: (id: string, checked: boolean, e: ReactMouseEvent) => void;
11
12
  }
12
13
  interface ICheckboxCell extends FC<ICheckboxCellProps> {
13
14
  Content: FC<PropsWithChildren>;
@@ -4,7 +4,7 @@ exports.CheckboxCell = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const checkbox_1 = require("../../../checkbox/checkbox");
6
6
  const classNames_1 = require("../../../commonHelpers/classNames/classNames");
7
- const CheckboxCell = ({ id, checked, indeterminate, label, disabled, className, onChange, children }) => ((0, jsx_runtime_1.jsxs)("div", { className: (0, classNames_1.classNames)(["zen-checkbox-column", className || ""]), children: [(0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { className: "zen-checkbox-column__checkbox", checked: checked, indeterminate: indeterminate, disabled: disabled, title: label, onChange: e => onChange && onChange(id, e.target.checked), wrapped: true }), children] }));
7
+ const CheckboxCell = ({ id, checked, indeterminate, label, disabled, className, onChange, onMouseDown, children }) => ((0, jsx_runtime_1.jsxs)("div", { className: (0, classNames_1.classNames)(["zen-checkbox-column", className || ""]), onMouseDown: onMouseDown ? e => onMouseDown(id, checked, e) : undefined, children: [(0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { className: "zen-checkbox-column__checkbox", checked: checked, indeterminate: indeterminate, disabled: disabled, title: label, onChange: e => onChange && onChange(id, e.target.checked), wrapped: true }), children] }));
8
8
  exports.CheckboxCell = CheckboxCell;
9
9
  exports.CheckboxCell.Content = function content({ children }) {
10
10
  return (0, jsx_runtime_1.jsx)("div", { className: "zen-checkbox-column__content", children: children });
@@ -1,4 +1,4 @@
1
- import { ReactNode, RefObject } from "react";
1
+ import { MouseEvent as ReactMouseEvent, ReactNode, RefObject } from "react";
2
2
  import { IListColumnWrapper } from "../../listColumn";
3
3
  import "./checkboxColumn.less";
4
4
  import { SimpleEventHandler } from "../../../commonHelpers/simpleEventHandler";
@@ -17,7 +17,8 @@ export interface ICheckboxColumnWrapper<T extends object> extends IListColumnWra
17
17
  attach(event: "toggle", handler: (state: [Event, HTMLButtonElement]) => void): this;
18
18
  attach(event: "change", handler: (state: [string, boolean]) => void): this;
19
19
  attach(event: "change-all", handler: (state: [boolean]) => void): this;
20
- detach(event: "change" | "toggle" | "change-all", handler?: (state: unknown) => void): this;
20
+ attach(event: "mousedown", handler: (state: [string, boolean, ReactMouseEvent]) => void): this;
21
+ detach(event: "change" | "toggle" | "change-all" | "mousedown", handler?: (state: unknown) => void): this;
21
22
  }
22
23
  export declare enum SelectionState {
23
24
  All = 0,
@@ -34,6 +35,7 @@ export declare class CheckboxColumnWrapper<T extends IEntityWithId> extends Simp
34
35
  private state;
35
36
  private readonly actionsClickHandler;
36
37
  private readonly changeHandler;
38
+ private readonly mouseDownHandler;
37
39
  private readonly changeHandlerAll;
38
40
  constructor(selections: Set<string>, options: ICheckboxColumnOptions<T>, menuTriggerRef: RefObject<HTMLButtonElement | null>);
39
41
  get selectionState(): SelectionState;
@@ -67,6 +67,15 @@ class CheckboxColumnWrapper extends simpleEventHandler_1.SimpleEventHandler {
67
67
  this.fire("change", [id, checked]);
68
68
  }
69
69
  });
70
+ // Only fired for enabled checkboxes, so a disabled row can never become a drag anchor.
71
+ Object.defineProperty(this, "mouseDownHandler", {
72
+ enumerable: true,
73
+ configurable: true,
74
+ writable: true,
75
+ value: (id, checked, e) => {
76
+ this.fire("mousedown", [id, checked, e]);
77
+ }
78
+ });
70
79
  Object.defineProperty(this, "changeHandlerAll", {
71
80
  enumerable: true,
72
81
  configurable: true,
@@ -92,7 +101,7 @@ class CheckboxColumnWrapper extends simpleEventHandler_1.SimpleEventHandler {
92
101
  }
93
102
  const allowed = this.condition(entity);
94
103
  const isDisable = this.disabled ? this.disabled(entity) : this.state === SelectionState.All;
95
- const cell = ((0, jsx_runtime_1.jsx)(checkboxCell_1.CheckboxCell, { id: entity.id, className: allowed ? "" : "zen-checkbox-column--no-checkbox", checked: this.state === SelectionState.All || this.selections.has(entity.id), indeterminate: false, disabled: isDisable, label: this.options.createTitle(entity), onChange: this.changeHandler, children: (0, jsx_runtime_1.jsx)(checkboxCell_1.CheckboxCell.Content, { children: value }) }));
104
+ const cell = ((0, jsx_runtime_1.jsx)(checkboxCell_1.CheckboxCell, { id: entity.id, className: allowed ? "" : "zen-checkbox-column--no-checkbox", checked: this.state === SelectionState.All || this.selections.has(entity.id), indeterminate: false, disabled: isDisable, label: this.options.createTitle(entity), onChange: this.changeHandler, onMouseDown: isDisable ? undefined : this.mouseDownHandler, children: (0, jsx_runtime_1.jsx)(checkboxCell_1.CheckboxCell.Content, { children: value }) }));
96
105
  return cell;
97
106
  }
98
107
  renderHeader(title) {
@@ -60,7 +60,8 @@ const Row = ({ id, entity, columns, visibleRows, flexibleColumnWidth, isLastRow,
60
60
  return acc;
61
61
  }, { cells: [], colspan: 0 }).cells, [columns, expanded, getCellParams, isVisible, onExpandedChange, isActive, active, onClick]);
62
62
  const cells = (0, react_1.useMemo)(() => renderCells(entity, false), [entity, renderCells]);
63
- const nestedCells = (0, react_1.useMemo)(() => (expanded && entity.children ? entity.children : []).map(nestedEntity => renderCells(nestedEntity, true)), [entity.children, expanded, renderCells]);
64
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("tr", { "data-row-id": id, id: mainRowId, role: "row", "aria-level": isTreeGrid ? 1 : undefined, "aria-posinset": isTreeGrid ? ariaPosinset : undefined, "aria-setsize": isTreeGrid ? ariaSetsize : undefined, "aria-expanded": isTreeGrid ? expanded : undefined, className: (0, classNames_1.classNames)(["zen-data-grid__row", className || "", isLastRow ? "zen-data-grid__row--last" : ""]), children: cells }, mainRowId), nestedCells.map((nestedRow, index) => ((0, jsx_runtime_1.jsx)("tr", { id: `${mainRowId}_child_${index}`, role: "row", "aria-level": 2, "aria-posinset": index + 1, "aria-setsize": nestedCells.length, className: "zen-data-grid__row zen-data-grid__row--nested", children: nestedRow }, `${mainRowId}_child_${index}`)))] }));
63
+ const nestedEntities = (0, react_1.useMemo)(() => (expanded && entity.children ? entity.children : []), [entity.children, expanded]);
64
+ const nestedCells = (0, react_1.useMemo)(() => nestedEntities.map(nestedEntity => renderCells(nestedEntity, true)), [nestedEntities, renderCells]);
65
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("tr", { "data-row-id": id, id: mainRowId, role: "row", "aria-level": isTreeGrid ? 1 : undefined, "aria-posinset": isTreeGrid ? ariaPosinset : undefined, "aria-setsize": isTreeGrid ? ariaSetsize : undefined, "aria-expanded": isTreeGrid ? expanded : undefined, className: (0, classNames_1.classNames)(["zen-data-grid__row", className || "", isLastRow ? "zen-data-grid__row--last" : ""]), children: cells }, mainRowId), nestedCells.map((nestedRow, index) => ((0, jsx_runtime_1.jsx)("tr", { "data-row-id": nestedEntities[index].id, id: `${mainRowId}_child_${index}`, role: "row", "aria-level": 2, "aria-posinset": index + 1, "aria-setsize": nestedCells.length, className: "zen-data-grid__row zen-data-grid__row--nested", children: nestedRow }, `${mainRowId}_child_${index}`)))] }));
65
66
  };
66
67
  exports.DataGridRow = (0, react_1.memo)(Row);
@@ -15,6 +15,8 @@ const selectList_1 = require("../../selectList/selectList");
15
15
  const checkboxState_1 = require("../../checkbox/checkboxState");
16
16
  const selectableRowsColumnWrapper_1 = require("./columns/selectableRowsColumnWrapper");
17
17
  const useLanguage_1 = require("../../utils/localization/useLanguage");
18
+ const useDragSelection_1 = require("../../table/selectable/useDragSelection");
19
+ const getDragSelectionRows_1 = require("../../table/selectable/utils/getDragSelectionRows");
18
20
  injectString("cs", "Select all", "Vybrat v\u0161e");
19
21
  injectString("da-DK", "Select all", "V\xE6lg alle");
20
22
  injectString("de", "Select all", "Alle ausw\xE4hlen");
@@ -209,13 +211,29 @@ const withSelectableRows = DataGridComponent => {
209
211
  const selectMenuRef = (0, react_1.useRef)(null);
210
212
  const selections = (0, exports.getSelections)(selection);
211
213
  const allSelected = selection !== undefined && selection.allSelected;
212
- const wrapper = (0, react_1.useMemo)(() => selectMode ? new selectableRowsColumnWrapper_1.SelectableRowsColumnWrapper(selections, {
213
- createTitle: options.createTitle,
214
- headerTitle: options.headerTitle,
215
- condition: options.condition || options.checkboxVisible,
216
- disabled: options.checkboxDisabled ? options.checkboxDisabled : entity => options.selectionLimit !== undefined ? !selections.has(entity.id) && selections.size >= options.selectionLimit : false,
217
- header: options.selectionLimit === undefined && options.checkboxDisabled === undefined && options.checkboxVisible === undefined && options.condition === undefined || options.checkboxInHeader === true && !options.selectionLimit
218
- }, selectMenuRef) : null, [selectMode, selections, options.createTitle, options.headerTitle, options.condition, options.checkboxVisible, options.checkboxDisabled, options.selectionLimit, options.checkboxInHeader]);
214
+ const isCheckboxVisible = (0, react_1.useCallback)(entity => {
215
+ const condition = options.condition || options.checkboxVisible;
216
+ return condition ? condition(entity) : true;
217
+ }, [options.condition, options.checkboxVisible]);
218
+ const isCheckboxDisabled = (0, react_1.useCallback)(entity => {
219
+ if (options.checkboxDisabled) {
220
+ return options.checkboxDisabled(entity);
221
+ }
222
+ if (options.selectionLimit !== undefined) {
223
+ return !selections.has(entity.id) && selections.size >= options.selectionLimit;
224
+ }
225
+ return false;
226
+ }, [options, selections]);
227
+ const wrapper = (0, react_1.useMemo)(() => {
228
+ var _a;
229
+ return selectMode ? new selectableRowsColumnWrapper_1.SelectableRowsColumnWrapper(selections, {
230
+ createTitle: options.createTitle,
231
+ headerTitle: options.headerTitle,
232
+ condition: options.condition || options.checkboxVisible,
233
+ disabled: (_a = options.checkboxDisabled) !== null && _a !== void 0 ? _a : isCheckboxDisabled,
234
+ header: options.selectionLimit === undefined && options.checkboxDisabled === undefined && options.checkboxVisible === undefined && options.condition === undefined || options.checkboxInHeader === true && !options.selectionLimit
235
+ }, selectMenuRef) : null;
236
+ }, [selectMode, selections, options.createTitle, options.headerTitle, options.condition, options.checkboxVisible, options.checkboxDisabled, options.selectionLimit, options.checkboxInHeader, isCheckboxDisabled]);
219
237
  if (wrapper) {
220
238
  wrapper.selectionState = calculateSelectionState(entities, selections, allSelected, options);
221
239
  }
@@ -223,9 +241,10 @@ const withSelectableRows = DataGridComponent => {
223
241
  const newSelections = new Set(selections);
224
242
  entities.forEach(entity => {
225
243
  if (checked) {
226
- const isVisible = options.condition ? options.condition(entity) : options.checkboxVisible ? options.checkboxVisible(entity) : true;
244
+ // Intentionally not isCheckboxDisabled: "select all" ignores the selection
245
+ // limit, it only skips rows the consumer explicitly disabled.
227
246
  const isEnabled = !options.checkboxDisabled || !options.checkboxDisabled(entity);
228
- if (isVisible && isEnabled) {
247
+ if (isCheckboxVisible(entity) && isEnabled) {
229
248
  newSelections.add(entity.id);
230
249
  }
231
250
  return;
@@ -238,8 +257,49 @@ const withSelectableRows = DataGridComponent => {
238
257
  allSelected: newState === checkboxColumnWrapper_1.SelectionState.All,
239
258
  turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
240
259
  });
241
- }, [selections, entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
260
+ }, [selections, entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll, isCheckboxVisible]);
261
+ const {
262
+ rows: dragRows,
263
+ entityById
264
+ } = (0, react_1.useMemo)(() => (0, getDragSelectionRows_1.getDragSelectionRows)(entities), [entities]);
265
+ const isRowSelectable = (0, react_1.useCallback)(row => {
266
+ const entity = entityById.get(row.id);
267
+ return !!entity && isCheckboxVisible(entity) && !isCheckboxDisabled(entity);
268
+ }, [entityById, isCheckboxVisible, isCheckboxDisabled]);
269
+ // "Select all" is held as a flag rather than a list of ids, so materialise the page before
270
+ // a range starts editing it — otherwise the range would be applied to an empty selection.
271
+ const getBaseSelection = (0, react_1.useCallback)(() => allSelected ? new Set(entities.map(entity => entity.id)) : new Set(selections), [allSelected, entities, selections]);
272
+ const onBatchSelect = (0, react_1.useCallback)((rangeIds, select, base) => {
273
+ const result = new Set(base);
274
+ const limit = options.selectionLimit;
275
+ for (const id of rangeIds) {
276
+ if (select) {
277
+ if (limit !== undefined && result.size >= limit) {
278
+ break;
279
+ }
280
+ result.add(id);
281
+ } else {
282
+ result.delete(id);
283
+ }
284
+ }
285
+ const newState = calculateSelectionState(entities, result, false, options);
286
+ onSelect({
287
+ selected: [...result],
288
+ allSelected: newState === checkboxColumnWrapper_1.SelectionState.All,
289
+ turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
290
+ });
291
+ }, [entities, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
292
+ const {
293
+ onCheckboxMouseDown,
294
+ suppressNextChangeRef
295
+ } = (0, useDragSelection_1.useDragSelection)(dragRows, props.ref, onBatchSelect, getBaseSelection, isRowSelectable, selectMode);
242
296
  const onSelectListener = (0, react_1.useCallback)(([id, checked]) => {
297
+ // A drag or shift-click has already emitted the whole range; swallow the click that
298
+ // ends it so the row it landed on is not toggled back.
299
+ if (suppressNextChangeRef.current) {
300
+ suppressNextChangeRef.current = false;
301
+ return;
302
+ }
243
303
  if (allSelected) {
244
304
  const newSelection = new Set(entities.map(entity => entity.id));
245
305
  newSelection.delete(id);
@@ -261,7 +321,7 @@ const withSelectableRows = DataGridComponent => {
261
321
  allSelected: newState === checkboxColumnWrapper_1.SelectionState.All,
262
322
  turnOffSelectAll: selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll
263
323
  });
264
- }, [entities, selections, allSelected, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll]);
324
+ }, [entities, selections, allSelected, options, onSelect, selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll, suppressNextChangeRef]);
265
325
  const onSelectAll = (0, react_1.useCallback)(([checked]) => {
266
326
  if (checked && ((selection === null || selection === void 0 ? void 0 : selection.turnOffSelectAll) || options.turnOffSelectAll)) {
267
327
  selectAll(true);
@@ -310,10 +370,11 @@ const withSelectableRows = DataGridComponent => {
310
370
  wrapper.attach("change", onSelectListener);
311
371
  wrapper.attach("change-all", onSelectAll);
312
372
  wrapper.attach("toggle", onTriggerClick);
373
+ wrapper.attach("mousedown", ([id, checked, e]) => onCheckboxMouseDown(id, checked, e));
313
374
  return () => {
314
375
  wrapper.detach();
315
376
  };
316
- }, [wrapper, onSelectListener, onSelectAll, onTriggerClick]);
377
+ }, [wrapper, onSelectListener, onSelectAll, onTriggerClick, onCheckboxMouseDown]);
317
378
  const listColumns = (0, react_1.useMemo)(() => {
318
379
  const newColumns = columns.map(c => Object.assign({}, c));
319
380
  // Remove CheckboxColumnWrappers from wrappers list
package/dist/index.css CHANGED
@@ -13083,7 +13083,7 @@ html:lang(ar) .zen-radio__wrapper--mobile .zen-radio__label {
13083
13083
  .zen-waiting--inline {
13084
13084
  position: relative;
13085
13085
  width: 2.5rem;
13086
- height: 1.5rem;
13086
+ height: 2.5rem;
13087
13087
  }
13088
13088
  .zen-waiting__spinner-text {
13089
13089
  font-family: Roboto, "Segoe UI", Segoe, "Helvetica Neue", Helvetica, sans-serif;
@@ -5,19 +5,15 @@ export declare enum SelectionState {
5
5
  None = "none"
6
6
  }
7
7
  export interface ISelectionValue {
8
- /**
9
- * Whether every selectable row across every page is selected.
10
- */
11
8
  all: boolean;
12
- /**
13
- * The meaning of this list depends on `all`:
14
- * - when `all` is `false`, it is the ids explicitly *included* in the selection.
15
- * - when `all` is `true`, it is the ids explicitly *excluded* from the otherwise
16
- * fully-selected set (e.g. rows unchecked after a "select all" across paginated data).
17
- *
18
- * This lets `all: true` represent "all except these ids" without needing to know the
19
- * full id universe (MYG-142234) - unchecking a row while `all` is true only ever adds
20
- * to this exclusion list; it must never be rebuilt from the currently rendered page.
21
- */
22
9
  selected: string[];
23
10
  }
11
+ /**
12
+ * One checkbox row in the order it is rendered. Expanded nested rows are part of this list,
13
+ * directly after their parent, so a drag or shift-click range can span nesting levels the
14
+ * same way it spans sibling rows.
15
+ */
16
+ export interface IDragSelectionRow {
17
+ id: string;
18
+ isNested: boolean;
19
+ }
@@ -0,0 +1,10 @@
1
+ import { MouseEvent as ReactMouseEvent, RefObject } from "react";
2
+ import { IDragSelectionRow } from "./interfaces";
3
+ /**
4
+ * @param rows every checkbox row in render order, expanded nested rows included, so ranges can
5
+ * span nesting levels.
6
+ */
7
+ export declare const useDragSelection: (rows: IDragSelectionRow[], gridRef: RefObject<HTMLElement | null> | undefined, onBatchSelect: (rangeIds: string[], select: boolean, base: Set<string>) => void, getBaseSelection: () => Set<string>, isSelectable: (row: IDragSelectionRow) => boolean, isEnabled: boolean) => {
8
+ onCheckboxMouseDown: (id: string, checked: boolean, e: ReactMouseEvent) => void;
9
+ suppressNextChangeRef: RefObject<boolean>;
10
+ };