@geotab/zenith 3.16.0-beta.2 → 3.16.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -12
- package/dist/absolute/absolute.js +1 -1
- package/dist/chart/plugins/linePlugin/getInterpolatedValue.d.ts +2 -2
- package/dist/chart/plugins/linePlugin/getInterpolatedValue.js +3 -2
- package/dist/chart/plugins/linePlugin/linePlugin.js +2 -1
- package/dist/chart/utils/getFormattedLabel.js +5 -1
- package/dist/checkbox/checkbox.d.ts +2 -1
- package/dist/checkbox/checkbox.js +2 -2
- package/dist/checkboxListWithAction/checkboxListWithAction.js +1 -0
- package/dist/commonHelpers/hooks/useTrapFocus.d.ts +0 -9
- package/dist/commonHelpers/hooks/useTrapFocus.js +14 -66
- package/dist/index.css +1 -1
- package/dist/table/selectable/interfaces.d.ts +0 -13
- package/dist/table/selectable/useSelectableRows.js +12 -46
- package/dist/table/selectable/utils/calculateSelectionState.js +0 -35
- package/dist/table/selectable/utils/isRowChecked.js +1 -12
- package/esm/absolute/absolute.js +1 -1
- package/esm/chart/plugins/linePlugin/getInterpolatedValue.d.ts +2 -2
- package/esm/chart/plugins/linePlugin/getInterpolatedValue.js +3 -2
- package/esm/chart/plugins/linePlugin/linePlugin.js +2 -1
- package/esm/chart/utils/getFormattedLabel.js +5 -1
- package/esm/checkbox/checkbox.d.ts +2 -1
- package/esm/checkbox/checkbox.js +2 -2
- package/esm/checkboxListWithAction/checkboxListWithAction.js +1 -0
- package/esm/commonHelpers/hooks/useTrapFocus.d.ts +0 -9
- package/esm/commonHelpers/hooks/useTrapFocus.js +15 -67
- package/esm/table/selectable/interfaces.d.ts +0 -13
- package/esm/table/selectable/useSelectableRows.js +12 -46
- package/esm/table/selectable/utils/calculateSelectionState.js +0 -35
- package/esm/table/selectable/utils/isRowChecked.js +1 -12
- 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.
|
|
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
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
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
|
|
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
|
-
-
|
|
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
|
-
-
|
|
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
|
-
-
|
|
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)((
|
|
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
|
|
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
|
|
15
|
+
var _a, _b, _c, _d, _e, _f;
|
|
25
16
|
/* eslint-enable complexity */
|
|
26
17
|
const getChildCondition = () => {
|
|
27
|
-
var _a, _b
|
|
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)(
|
|
41
|
-
|
|
42
|
-
!(0, isChildOf_1.isChildOf)(
|
|
43
|
-
: !(0, isChildOf_1.isChildOf)(
|
|
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
|
|
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 (((
|
|
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 && ((
|
|
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 (((
|
|
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 && ((
|
|
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)((
|
|
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;
|
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:
|
|
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,6 @@ 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
|
}
|
|
@@ -142,30 +142,19 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
|
|
|
142
142
|
}
|
|
143
143
|
}, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, selectable === null || selectable === void 0 ? void 0 : selectable.strategy]);
|
|
144
144
|
const getNewSelection = (0, react_1.useCallback)((id, checked) => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// exclusion set - it must never be rebuilt from `entities` (the current page),
|
|
150
|
-
// otherwise every other page's rows would silently fall out of the selection.
|
|
151
|
-
const excluded = new Set(selections);
|
|
152
|
-
(0, checkRow_1.checkRow)(excluded, selectable, entities, id, !checked);
|
|
153
|
-
return excluded;
|
|
145
|
+
if (state === interfaces_1.SelectionState.All) {
|
|
146
|
+
const newSelection = (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, selectable);
|
|
147
|
+
(0, checkRow_1.checkRow)(newSelection, selectable, entities, id, false);
|
|
148
|
+
return newSelection;
|
|
154
149
|
}
|
|
155
150
|
(0, checkRow_1.checkRow)(selections, selectable, entities, id, checked);
|
|
156
151
|
return selections;
|
|
157
|
-
}, [entities, selectable, selections]);
|
|
152
|
+
}, [state, entities, selectable, selections]);
|
|
158
153
|
const onSelectListener = (0, react_1.useCallback)((id, checked) => {
|
|
159
154
|
var _a;
|
|
160
|
-
const wasAllSelected = ((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all) || false;
|
|
161
155
|
const newSelection = getNewSelection(id, checked);
|
|
162
|
-
const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, newSelection,
|
|
163
|
-
|
|
164
|
-
// and only record the exclusion - it must not collapse to the current page's ids.
|
|
165
|
-
const newValue = wasAllSelected ? {
|
|
166
|
-
selected: [...newSelection],
|
|
167
|
-
all: true
|
|
168
|
-
} : {
|
|
156
|
+
const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, newSelection, ((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all) || false, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy);
|
|
157
|
+
const newValue = {
|
|
169
158
|
selected: [...newSelection],
|
|
170
159
|
all: newState === interfaces_1.SelectionState.All
|
|
171
160
|
};
|
|
@@ -174,7 +163,7 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
|
|
|
174
163
|
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
175
164
|
}, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, setState, getNewSelection]);
|
|
176
165
|
const onChangeSelectionState = (0, react_1.useCallback)(newState => {
|
|
177
|
-
var _a, _b
|
|
166
|
+
var _a, _b;
|
|
178
167
|
if (newState === interfaces_1.SelectionState.All) {
|
|
179
168
|
(selectable === null || selectable === void 0 ? void 0 : selectable.onSelect) && selectable.onSelect({
|
|
180
169
|
selected: [],
|
|
@@ -193,11 +182,7 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
|
|
|
193
182
|
}
|
|
194
183
|
const newSelections = (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, selectable);
|
|
195
184
|
setState(newState);
|
|
196
|
-
|
|
197
|
-
// included ids when `all` is false, excluded ids when `all` is true. Switching to an
|
|
198
|
-
// explicit "select current page" here always leaves `all: false`, so a previous
|
|
199
|
-
// exclusion list must not be reinterpreted as an inclusion list.
|
|
200
|
-
const previousSelections = ((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all) ? [] : (_c = (_b = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _b === void 0 ? void 0 : _b.selected) !== null && _c !== void 0 ? _c : [];
|
|
185
|
+
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 : [];
|
|
201
186
|
const mergedSelections = new Set([...previousSelections, ...newSelections]);
|
|
202
187
|
const newValue = {
|
|
203
188
|
selected: [...mergedSelections],
|
|
@@ -216,12 +201,7 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
|
|
|
216
201
|
}
|
|
217
202
|
return translate("Deselect all");
|
|
218
203
|
}, [selectable, selectableState, state, translate]);
|
|
219
|
-
const isEntityChecked = (0, react_1.useCallback)(
|
|
220
|
-
// MYG-142234: while `selection.all` is true, `selections` holds excluded ids, and every
|
|
221
|
-
// row must be evaluated through the SelectionState.All (exclusion-aware) branch of
|
|
222
|
-
// isRowChecked - not the per-page `state`, which can be Partial/None for a page that
|
|
223
|
-
// contains some of those exclusions.
|
|
224
|
-
(entity, isNested) => (0, isRowChecked_1.isRowChecked)(selections, isAllSelected ? interfaces_1.SelectionState.All : state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, entity, isNested), [selections, isAllSelected, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy]);
|
|
204
|
+
const isEntityChecked = (0, react_1.useCallback)((entity, isNested) => (0, isRowChecked_1.isRowChecked)(selections, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, entity, isNested), [selections, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy]);
|
|
225
205
|
const hasSelectable = !!selectable;
|
|
226
206
|
const selectableCheckboxSelectsCurrentPage = selectable === null || selectable === void 0 ? void 0 : selectable.checkboxSelectsCurrentPage;
|
|
227
207
|
const selectableTurnOffSelectAll = selectable === null || selectable === void 0 ? void 0 : selectable.turnOffSelectAll;
|
|
@@ -273,30 +253,16 @@ const useSelectableRows = (columns, entities, isMobile, selectMode, setSelectMod
|
|
|
273
253
|
checked: state === interfaces_1.SelectionState.CurrentPage || state === interfaces_1.SelectionState.All,
|
|
274
254
|
indeterminate: state === interfaces_1.SelectionState.Partial,
|
|
275
255
|
onChange: newValue => {
|
|
276
|
-
var _a, _b
|
|
256
|
+
var _a, _b;
|
|
277
257
|
if (newValue) {
|
|
278
258
|
const newState = checkboxEmitsCurrentPage ? interfaces_1.SelectionState.CurrentPage : interfaces_1.SelectionState.All;
|
|
279
259
|
setState(newState);
|
|
280
260
|
onChangeSelectionState(newState);
|
|
281
|
-
} else if ((_a = selectable.selection) === null || _a === void 0 ? void 0 : _a.all) {
|
|
282
|
-
// MYG-142234: in exclusion mode, `selected` holds excluded ids. Unchecking
|
|
283
|
-
// the header must add the current page's ids to that exclusion set and
|
|
284
|
-
// keep `all: true` - it must never be treated as an inclusion list, or
|
|
285
|
-
// every other page's selection would be silently wiped out.
|
|
286
|
-
const currentPageIds = (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, selectable);
|
|
287
|
-
const newExcluded = new Set([...selectable.selection.selected, ...currentPageIds]);
|
|
288
|
-
const newState = (0, calculateSelectionState_1.calculateSelectionState)(entities, newExcluded, true, checkboxVisible, checkboxDisabled, selectable.strategy);
|
|
289
|
-
setState(newState);
|
|
290
|
-
selectable.onSelect({
|
|
291
|
-
selected: [...newExcluded],
|
|
292
|
-
all: true
|
|
293
|
-
});
|
|
294
|
-
setSelectMode(true);
|
|
295
261
|
} else {
|
|
296
262
|
// Intentionally different from onSelect(None) ("Deselect all" menu item, which clears everything).
|
|
297
263
|
// Unchecking the header checkbox only removes the current page from the selection, preserving other pages.
|
|
298
264
|
const currentPageIds = (0, getCurrentPageSelection_1.getCurrentPageSelection)(entities, selectable);
|
|
299
|
-
const remaining = ((
|
|
265
|
+
const remaining = ((_b = (_a = selectable.selection) === null || _a === void 0 ? void 0 : _a.selected) !== null && _b !== void 0 ? _b : []).filter(id => !currentPageIds.has(id));
|
|
300
266
|
const newState = remaining.length > 0 ? interfaces_1.SelectionState.Partial : interfaces_1.SelectionState.None;
|
|
301
267
|
setState(newState);
|
|
302
268
|
selectable.onSelect({
|
|
@@ -6,41 +6,6 @@ const calculateSelectionState = (entities, selections, all, checkboxVisible, che
|
|
|
6
6
|
if (selections.size === 0) {
|
|
7
7
|
return all ? interfaces_1.SelectionState.All : interfaces_1.SelectionState.None;
|
|
8
8
|
}
|
|
9
|
-
if (all) {
|
|
10
|
-
// When `all` is true, `selections` holds the ids explicitly excluded from the
|
|
11
|
-
// otherwise-fully-selected set (see ISelectionValue), rather than included ids.
|
|
12
|
-
const isExcluded = (entity) => {
|
|
13
|
-
if (strategy === "nested" && entity.children) {
|
|
14
|
-
if (entity.children.length === 0) {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
return entity.children.every(child => {
|
|
18
|
-
if (!checkboxVisible(child)) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
if (checkboxDisabled(child)) {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
return selections.has(child.id);
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
return selections.has(entity.id);
|
|
28
|
-
};
|
|
29
|
-
const isPartiallyExcluded = (entity) => {
|
|
30
|
-
if (strategy === "nested" && entity.children) {
|
|
31
|
-
return entity.children.some(child => selections.has(child.id));
|
|
32
|
-
}
|
|
33
|
-
return selections.has(entity.id);
|
|
34
|
-
};
|
|
35
|
-
const relevantEntities = entities.filter(entity => checkboxVisible(entity) && !checkboxDisabled(entity));
|
|
36
|
-
if (relevantEntities.length === 0) {
|
|
37
|
-
return interfaces_1.SelectionState.All;
|
|
38
|
-
}
|
|
39
|
-
if (relevantEntities.every(entity => !isPartiallyExcluded(entity))) {
|
|
40
|
-
return interfaces_1.SelectionState.All;
|
|
41
|
-
}
|
|
42
|
-
return relevantEntities.every(entity => isExcluded(entity)) ? interfaces_1.SelectionState.None : interfaces_1.SelectionState.Partial;
|
|
43
|
-
}
|
|
44
9
|
return entities.every(entity => {
|
|
45
10
|
if (!checkboxVisible(entity)) {
|
|
46
11
|
return true;
|
|
@@ -4,18 +4,7 @@ exports.isRowChecked = void 0;
|
|
|
4
4
|
const interfaces_1 = require("../interfaces");
|
|
5
5
|
const isRowChecked = (selections, state, strategy, entity, isNested) => {
|
|
6
6
|
if (state === interfaces_1.SelectionState.All) {
|
|
7
|
-
|
|
8
|
-
// explicitly excluded from that selection (see ISelectionValue), not included ids.
|
|
9
|
-
if (isNested) {
|
|
10
|
-
return { indeterminate: false, checked: !selections.has(entity.id) };
|
|
11
|
-
}
|
|
12
|
-
const mainEntity = entity;
|
|
13
|
-
if (strategy === "nested" && mainEntity.children && mainEntity.children.length > 0) {
|
|
14
|
-
const allChildrenChecked = mainEntity.children.every(child => !selections.has(child.id));
|
|
15
|
-
const someChildrenChecked = mainEntity.children.some(child => !selections.has(child.id));
|
|
16
|
-
return { indeterminate: someChildrenChecked && !allChildrenChecked, checked: allChildrenChecked };
|
|
17
|
-
}
|
|
18
|
-
return { indeterminate: false, checked: !selections.has(entity.id) };
|
|
7
|
+
return { indeterminate: false, checked: true };
|
|
19
8
|
}
|
|
20
9
|
if (isNested) {
|
|
21
10
|
return { indeterminate: false, checked: selections.has(entity.id) };
|
package/esm/absolute/absolute.js
CHANGED
|
@@ -108,7 +108,7 @@ export const Absolute = ({ isOpen, id, paddingX, paddingY, className, children,
|
|
|
108
108
|
returnFocusToTrigger();
|
|
109
109
|
}
|
|
110
110
|
}, [isOpen, returnFocusToTrigger]);
|
|
111
|
-
const condition = useCallback((
|
|
111
|
+
const condition = useCallback(() => (useTrapFocusWithTrigger === "off" ? false : true), [useTrapFocusWithTrigger]);
|
|
112
112
|
useTrapFocus(popupRef, useTrapFocusWithTrigger === "withTrigger" ? triggerRef : undefined, isOpen, condition);
|
|
113
113
|
useEscape(popupRef, handleEscape, isOpen);
|
|
114
114
|
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,4 +1,4 @@
|
|
|
1
|
-
export function getInterpolatedValue(xScale, data, datasetIndex, xPixel) {
|
|
1
|
+
export function getInterpolatedValue(xScale, data, datasetIndex, xPixel, parsing) {
|
|
2
2
|
const dataset = data.datasets[datasetIndex];
|
|
3
3
|
const dataPoints = dataset.data;
|
|
4
4
|
if (dataPoints.length < 2) {
|
|
@@ -15,7 +15,8 @@ export function getInterpolatedValue(xScale, data, datasetIndex, xPixel) {
|
|
|
15
15
|
if (y === null) {
|
|
16
16
|
continue;
|
|
17
17
|
}
|
|
18
|
-
const
|
|
18
|
+
const parsedX = parsing === false ? x : xScale.parse(x, i);
|
|
19
|
+
const pointXPixel = xScale.getPixelForValue(parsedX);
|
|
19
20
|
if (pointXPixel <= xPixel && pointXPixel > lowerXPixel) {
|
|
20
21
|
lowerPoint = y;
|
|
21
22
|
lowerXPixel = pointXPixel;
|
|
@@ -57,6 +57,7 @@ export const LinePlugin = (containerId, options, isDark) => ({
|
|
|
57
57
|
let lowestValueY = Infinity;
|
|
58
58
|
const items = datasets
|
|
59
59
|
.map((dataset, dsIndex) => {
|
|
60
|
+
var _a;
|
|
60
61
|
if (!chart.isDatasetVisible(dsIndex)) {
|
|
61
62
|
return undefined;
|
|
62
63
|
}
|
|
@@ -64,7 +65,7 @@ export const LinePlugin = (containerId, options, isDark) => ({
|
|
|
64
65
|
return undefined;
|
|
65
66
|
}
|
|
66
67
|
const xScale = chart.scales.x;
|
|
67
|
-
const value = getInterpolatedValue(xScale, chart.data, dsIndex, x);
|
|
68
|
+
const value = getInterpolatedValue(xScale, chart.data, dsIndex, x, (_a = dataset.parsing) !== null && _a !== void 0 ? _a : chart.options.parsing);
|
|
68
69
|
const yAxisID = dataset.yAxisID || "y";
|
|
69
70
|
const yScale = chart.scales[yAxisID];
|
|
70
71
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
@@ -3,14 +3,18 @@ export function getFormattedLabel(value, dateFormatter, options) {
|
|
|
3
3
|
var _a, _b, _c;
|
|
4
4
|
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;
|
|
5
5
|
let format;
|
|
6
|
+
let parser;
|
|
6
7
|
if (((_c = options === null || options === void 0 ? void 0 : options.scales) === null || _c === void 0 ? void 0 : _c.x) && scaleType) {
|
|
7
8
|
const scaleFormat = options.scales.x[scaleType];
|
|
8
9
|
if ((scaleFormat === null || scaleFormat === void 0 ? void 0 : scaleFormat.unit) && scaleFormat.displayFormats && scaleFormat.displayFormats[scaleFormat.unit]) {
|
|
9
10
|
format = scaleFormat.displayFormats[scaleFormat.unit];
|
|
10
11
|
}
|
|
12
|
+
if (options.parsing !== false && scaleFormat && "parser" in scaleFormat && typeof scaleFormat.parser === "function") {
|
|
13
|
+
parser = scaleFormat.parser;
|
|
14
|
+
}
|
|
11
15
|
}
|
|
12
16
|
if (value instanceof Date || (typeof value === "string" && isDateString(value))) {
|
|
13
|
-
return dateFormatter(value, format);
|
|
17
|
+
return dateFormatter(parser ? new Date(parser(value)) : value, format);
|
|
14
18
|
}
|
|
15
19
|
return String(value);
|
|
16
20
|
}
|
|
@@ -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;
|
package/esm/checkbox/checkbox.js
CHANGED
|
@@ -20,14 +20,14 @@ import { CheckboxIconCheckmark } from "./checkboxIconCheckmark";
|
|
|
20
20
|
import { CheckboxIconMinus } from "./checkboxIconMinus";
|
|
21
21
|
import { useMobile } from "../commonHelpers/hooks/useMobile";
|
|
22
22
|
export const Checkbox = (_a) => {
|
|
23
|
-
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"]);
|
|
23
|
+
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"]);
|
|
24
24
|
const state = getCheckboxState(checked, indeterminate);
|
|
25
25
|
const generatedId = React.useId();
|
|
26
26
|
const intId = id || generatedId;
|
|
27
27
|
const driveClasses = useDriveClassName("zen-checkbox");
|
|
28
28
|
const isMobile = useMobile();
|
|
29
29
|
const checkboxIconClasses = useMemo(() => classNames(["zen-checkbox__icon", disabled ? "zen-checkbox__icon--disabled" : ""]), [disabled]);
|
|
30
|
-
const checkbox = (_jsx(TriStateCheckbox, Object.assign({ className: "zen-checkbox__input", id: intId, checked: checked, indeterminate: indeterminate, disabled: disabled, "aria-label": title, "aria-describedby": describedBy }, rest)));
|
|
30
|
+
const checkbox = (_jsx(TriStateCheckbox, Object.assign({ className: "zen-checkbox__input", id: intId, checked: checked, indeterminate: indeterminate, disabled: disabled, "aria-label": ariaLabel || title, "aria-describedby": describedBy }, rest)));
|
|
31
31
|
const iconAndLabel = (_jsxs(_Fragment, { children: [_jsx("div", { className: "zen-checkbox__box", "aria-hidden": true, children: state === CheckboxState.Indeterminate ? (_jsx(CheckboxIconMinus, { className: checkboxIconClasses, size: driveClasses ? "bigger" : "medium" })) : state === CheckboxState.On ? (_jsx(CheckboxIconCheckmark, { className: checkboxIconClasses, size: driveClasses ? "bigger" : "medium" })) : null }), children ? (_jsx("div", { className: classNames(["zen-checkbox__label-text", fullWidth ? "zen-checkbox__label-text--full-width" : ""]), children: children })) : null] }));
|
|
32
32
|
if (wrapped) {
|
|
33
33
|
return (_jsxs("label", { className: classNames(["zen-checkbox", driveClasses || "", className]), title: title, children: [checkbox, _jsx("div", { className: classNames(["zen-checkbox__label", reverse ? "zen-checkbox__label--reverse" : ""]), children: iconAndLabel })] }));
|
|
@@ -445,6 +445,7 @@ export const CheckboxListWithAction = ({
|
|
|
445
445
|
checked: opt.checked,
|
|
446
446
|
disabled: opt.blocked,
|
|
447
447
|
title: translate("Toggle {groupName} filter").replace("{groupName}", titleForRender),
|
|
448
|
+
ariaLabel: titleForRender,
|
|
448
449
|
describedBy: opt.isWithAction ? navigationInstructionsId : undefined,
|
|
449
450
|
"data-indeterminate": opt.partialChecked,
|
|
450
451
|
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 {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback
|
|
1
|
+
import { useCallback } from "react";
|
|
2
2
|
import { isElementInsideContainer } from "../../dialog/dialogHelpers";
|
|
3
3
|
import { FOCUSABLE_SELECTOR } from "../../utils/focusableSelector";
|
|
4
4
|
import { useKeydown } from "./useKeydown";
|
|
@@ -6,38 +6,18 @@ import { isChildOf } from "../../utils/isChildOf";
|
|
|
6
6
|
import { isElementHidden } from "../../utils/isElementHidden";
|
|
7
7
|
import { zen } from "../../utils/zen";
|
|
8
8
|
const findFirstVisible = (elems, isElementVisible) => elems.find(elem => isElementVisible(elem));
|
|
9
|
-
/**
|
|
10
|
-
* Traps keyboard (Tab) focus within `containerRef` (and optionally its `triggerRef`).
|
|
11
|
-
*
|
|
12
|
-
* Nested-popup contract: for correct nested-popup behaviour, a focused element that triggers an
|
|
13
|
-
* open child popup must expose a `data-popup-id` attribute whose value is the `id` of the child
|
|
14
|
-
* popup element rendered in the DOM. When present, focus is deferred to that child popup's trap.
|
|
15
|
-
* This contract is fulfilled automatically by `ControlledPopup`; callers using `useTrapFocus`
|
|
16
|
-
* directly must set `data-popup-id` themselves or nested popups will silently lose focus handling.
|
|
17
|
-
*/
|
|
18
9
|
export const useTrapFocus = (containerRef, triggerRef, subscriptionTrigger, condition, isElementVisible) => {
|
|
19
10
|
/* eslint-disable complexity */
|
|
20
11
|
const handleKeyDown = useCallback(e => {
|
|
21
|
-
var _a, _b, _c, _d, _e, _f
|
|
12
|
+
var _a, _b, _c, _d, _e, _f;
|
|
22
13
|
/* eslint-enable complexity */
|
|
23
14
|
const getChildCondition = () => {
|
|
24
|
-
var _a, _b
|
|
25
|
-
const targetEl = e.target;
|
|
26
|
-
// If the target is a trigger for an open child popup, defer to that popup's
|
|
27
|
-
// focus trap. Key on data-popup-id + DOM presence so this works even when
|
|
28
|
-
// preventAttributesAutoSet suppresses aria-expanded.
|
|
29
|
-
const dataPopupId = targetEl.getAttribute("data-popup-id");
|
|
30
|
-
if (dataPopupId &&
|
|
31
|
-
((_a = zen.document) === null || _a === void 0 ? void 0 : _a.getElementById(dataPopupId)) &&
|
|
32
|
-
isChildOf(targetEl, containerRef.current) &&
|
|
33
|
-
targetEl !== (triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current)) {
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
15
|
+
var _a, _b;
|
|
36
16
|
return triggerRef
|
|
37
|
-
? !isChildOf(
|
|
38
|
-
|
|
39
|
-
!isChildOf(
|
|
40
|
-
: !isChildOf(
|
|
17
|
+
? !isChildOf(e.target, containerRef.current) &&
|
|
18
|
+
e.target !== ((_a = zen.document) === null || _a === void 0 ? void 0 : _a.body) &&
|
|
19
|
+
!isChildOf(e.target, triggerRef.current)
|
|
20
|
+
: !isChildOf(e.target, containerRef.current) && e.target !== ((_b = zen.document) === null || _b === void 0 ? void 0 : _b.body);
|
|
41
21
|
};
|
|
42
22
|
if (!containerRef.current || getChildCondition()) {
|
|
43
23
|
return;
|
|
@@ -47,14 +27,9 @@ export const useTrapFocus = (containerRef, triggerRef, subscriptionTrigger, cond
|
|
|
47
27
|
: !isElementInsideContainer(target, containerEl.current) &&
|
|
48
28
|
!isElementInsideContainer(target, triggerEl.current);
|
|
49
29
|
const isTargetOutside = e.target ? checkIsElementOutside(e.target, containerRef, triggerRef) : undefined;
|
|
50
|
-
const
|
|
51
|
-
const triggerSelf = (triggerElement === null || triggerElement === void 0 ? void 0 : triggerElement.matches(FOCUSABLE_SELECTOR)) ? [triggerElement] : [];
|
|
52
|
-
const triggerChildren = Array.from((_b = triggerElement === null || triggerElement === void 0 ? void 0 : triggerElement.querySelectorAll(FOCUSABLE_SELECTOR)) !== null && _b !== void 0 ? _b : []);
|
|
53
|
-
// querySelectorAll only returns descendants (never the element itself), so triggerSelf
|
|
54
|
-
// and triggerChildren are disjoint by definition and need no deduplication.
|
|
55
|
-
const triggerSelectors = [...triggerSelf, ...triggerChildren];
|
|
30
|
+
const triggerSelectors = ((_a = triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(FOCUSABLE_SELECTOR)) || [];
|
|
56
31
|
const containerSelectors = containerRef.current.querySelectorAll(FOCUSABLE_SELECTOR);
|
|
57
|
-
const focusable = triggerRef ? [...triggerSelectors, ...Array.from(containerSelectors)] : [...Array.from(containerSelectors)];
|
|
32
|
+
const focusable = triggerRef ? [...Array.from(triggerSelectors), ...Array.from(containerSelectors)] : [...Array.from(containerSelectors)];
|
|
58
33
|
if (!focusable.length) {
|
|
59
34
|
return;
|
|
60
35
|
}
|
|
@@ -71,58 +46,31 @@ export const useTrapFocus = (containerRef, triggerRef, subscriptionTrigger, cond
|
|
|
71
46
|
return;
|
|
72
47
|
}
|
|
73
48
|
if (e.shiftKey) {
|
|
74
|
-
if (((
|
|
49
|
+
if (((_b = zen.document) === null || _b === void 0 ? void 0 : _b.activeElement) === first) {
|
|
75
50
|
e.preventDefault();
|
|
76
51
|
last === null || last === void 0 ? void 0 : last.focus();
|
|
77
52
|
return;
|
|
78
53
|
}
|
|
79
|
-
if (firstContainerFocusable && ((
|
|
54
|
+
if (firstContainerFocusable && ((_c = zen.document) === null || _c === void 0 ? void 0 : _c.activeElement) === firstContainerFocusable) {
|
|
80
55
|
e.preventDefault();
|
|
81
56
|
lastTriggerFocusable === null || lastTriggerFocusable === void 0 ? void 0 : lastTriggerFocusable.focus();
|
|
82
57
|
}
|
|
83
58
|
return;
|
|
84
59
|
}
|
|
85
|
-
if (((
|
|
60
|
+
if (((_d = zen.document) === null || _d === void 0 ? void 0 : _d.activeElement) === last) {
|
|
86
61
|
e.preventDefault();
|
|
87
62
|
first === null || first === void 0 ? void 0 : first.focus();
|
|
88
63
|
return;
|
|
89
64
|
}
|
|
90
|
-
if (lastTriggerFocusable && ((
|
|
65
|
+
if (lastTriggerFocusable && ((_e = zen.document) === null || _e === void 0 ? void 0 : _e.activeElement) === lastTriggerFocusable) {
|
|
91
66
|
e.preventDefault();
|
|
92
67
|
firstContainerFocusable === null || firstContainerFocusable === void 0 ? void 0 : firstContainerFocusable.focus();
|
|
93
68
|
}
|
|
94
|
-
else if (isLastChildOfFirst && first && isChildOf((
|
|
69
|
+
else if (isLastChildOfFirst && first && isChildOf((_f = zen.document) === null || _f === void 0 ? void 0 : _f.activeElement, first)) {
|
|
95
70
|
e.preventDefault();
|
|
96
71
|
}
|
|
97
72
|
return;
|
|
98
73
|
}
|
|
99
|
-
},
|
|
100
|
-
// condition is consumed by useKeydown below, not read by handleKeyDown directly; its absence from deps is intentional.
|
|
101
|
-
[containerRef, triggerRef, isElementVisible]);
|
|
74
|
+
}, [containerRef, triggerRef, isElementVisible]);
|
|
102
75
|
useKeydown(handleKeyDown, subscriptionTrigger, condition);
|
|
103
|
-
// When withTrigger mode closes (condition goes false), restore focus to the trigger
|
|
104
|
-
// if focus landed on body (which happens when the popup's focused element is unmounted).
|
|
105
|
-
// This restoration is intentionally scoped to the "focused element unmounted → body" case;
|
|
106
|
-
// the general close case (e.g. click-outside, item selection) is handled separately by the
|
|
107
|
-
// returnFocusToTrigger effect in absolute.tsx. Both are idempotent, so overlap is harmless.
|
|
108
|
-
// Initialized to false because popups mount closed; the guard below reconciles the first
|
|
109
|
-
// active/inactive edge, so a popup that mounts already open still resolves correctly.
|
|
110
|
-
const isActiveRef = useRef(false);
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
var _a, _b;
|
|
113
|
-
const isActive = condition ? condition(subscriptionTrigger) : !!subscriptionTrigger;
|
|
114
|
-
// Guard: short-circuit when the raw open/close state is unchanged to avoid spurious
|
|
115
|
-
// focus restoration if an unstable condition reference re-fires this effect.
|
|
116
|
-
if (!!subscriptionTrigger === isActiveRef.current) {
|
|
117
|
-
isActiveRef.current = isActive;
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (!isActive && isActiveRef.current && (triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current)) {
|
|
121
|
-
const active = (_a = zen.document) === null || _a === void 0 ? void 0 : _a.activeElement;
|
|
122
|
-
if (!active || active === ((_b = zen.document) === null || _b === void 0 ? void 0 : _b.body)) {
|
|
123
|
-
triggerRef.current.focus();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
isActiveRef.current = isActive;
|
|
127
|
-
}, [condition, subscriptionTrigger, triggerRef]);
|
|
128
76
|
};
|
|
@@ -5,19 +5,6 @@ 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
|
}
|
|
@@ -133,30 +133,19 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
133
133
|
}
|
|
134
134
|
}, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, selectable === null || selectable === void 0 ? void 0 : selectable.strategy]);
|
|
135
135
|
const getNewSelection = useCallback((id, checked) => {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
// exclusion set - it must never be rebuilt from `entities` (the current page),
|
|
141
|
-
// otherwise every other page's rows would silently fall out of the selection.
|
|
142
|
-
const excluded = new Set(selections);
|
|
143
|
-
checkRow(excluded, selectable, entities, id, !checked);
|
|
144
|
-
return excluded;
|
|
136
|
+
if (state === SelectionState.All) {
|
|
137
|
+
const newSelection = getCurrentPageSelection(entities, selectable);
|
|
138
|
+
checkRow(newSelection, selectable, entities, id, false);
|
|
139
|
+
return newSelection;
|
|
145
140
|
}
|
|
146
141
|
checkRow(selections, selectable, entities, id, checked);
|
|
147
142
|
return selections;
|
|
148
|
-
}, [entities, selectable, selections]);
|
|
143
|
+
}, [state, entities, selectable, selections]);
|
|
149
144
|
const onSelectListener = useCallback((id, checked) => {
|
|
150
145
|
var _a;
|
|
151
|
-
const wasAllSelected = ((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all) || false;
|
|
152
146
|
const newSelection = getNewSelection(id, checked);
|
|
153
|
-
const newState = calculateSelectionState(entities, newSelection,
|
|
154
|
-
|
|
155
|
-
// and only record the exclusion - it must not collapse to the current page's ids.
|
|
156
|
-
const newValue = wasAllSelected ? {
|
|
157
|
-
selected: [...newSelection],
|
|
158
|
-
all: true
|
|
159
|
-
} : {
|
|
147
|
+
const newState = calculateSelectionState(entities, newSelection, ((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all) || false, checkboxVisible, checkboxDisabled, selectable === null || selectable === void 0 ? void 0 : selectable.strategy);
|
|
148
|
+
const newValue = {
|
|
160
149
|
selected: [...newSelection],
|
|
161
150
|
all: newState === SelectionState.All
|
|
162
151
|
};
|
|
@@ -165,7 +154,7 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
165
154
|
setSelectMode(newValue.all || newValue.selected.length > 0);
|
|
166
155
|
}, [checkboxDisabled, checkboxVisible, entities, selectable, setSelectMode, setState, getNewSelection]);
|
|
167
156
|
const onChangeSelectionState = useCallback(newState => {
|
|
168
|
-
var _a, _b
|
|
157
|
+
var _a, _b;
|
|
169
158
|
if (newState === SelectionState.All) {
|
|
170
159
|
(selectable === null || selectable === void 0 ? void 0 : selectable.onSelect) && selectable.onSelect({
|
|
171
160
|
selected: [],
|
|
@@ -184,11 +173,7 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
184
173
|
}
|
|
185
174
|
const newSelections = getCurrentPageSelection(entities, selectable);
|
|
186
175
|
setState(newState);
|
|
187
|
-
|
|
188
|
-
// included ids when `all` is false, excluded ids when `all` is true. Switching to an
|
|
189
|
-
// explicit "select current page" here always leaves `all: false`, so a previous
|
|
190
|
-
// exclusion list must not be reinterpreted as an inclusion list.
|
|
191
|
-
const previousSelections = ((_a = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _a === void 0 ? void 0 : _a.all) ? [] : (_c = (_b = selectable === null || selectable === void 0 ? void 0 : selectable.selection) === null || _b === void 0 ? void 0 : _b.selected) !== null && _c !== void 0 ? _c : [];
|
|
176
|
+
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 : [];
|
|
192
177
|
const mergedSelections = new Set([...previousSelections, ...newSelections]);
|
|
193
178
|
const newValue = {
|
|
194
179
|
selected: [...mergedSelections],
|
|
@@ -207,12 +192,7 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
207
192
|
}
|
|
208
193
|
return translate("Deselect all");
|
|
209
194
|
}, [selectable, selectableState, state, translate]);
|
|
210
|
-
const isEntityChecked = useCallback(
|
|
211
|
-
// MYG-142234: while `selection.all` is true, `selections` holds excluded ids, and every
|
|
212
|
-
// row must be evaluated through the SelectionState.All (exclusion-aware) branch of
|
|
213
|
-
// isRowChecked - not the per-page `state`, which can be Partial/None for a page that
|
|
214
|
-
// contains some of those exclusions.
|
|
215
|
-
(entity, isNested) => isRowChecked(selections, isAllSelected ? SelectionState.All : state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, entity, isNested), [selections, isAllSelected, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy]);
|
|
195
|
+
const isEntityChecked = useCallback((entity, isNested) => isRowChecked(selections, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy, entity, isNested), [selections, state, selectable === null || selectable === void 0 ? void 0 : selectable.strategy]);
|
|
216
196
|
const hasSelectable = !!selectable;
|
|
217
197
|
const selectableCheckboxSelectsCurrentPage = selectable === null || selectable === void 0 ? void 0 : selectable.checkboxSelectsCurrentPage;
|
|
218
198
|
const selectableTurnOffSelectAll = selectable === null || selectable === void 0 ? void 0 : selectable.turnOffSelectAll;
|
|
@@ -264,30 +244,16 @@ export const useSelectableRows = (columns, entities, isMobile, selectMode, setSe
|
|
|
264
244
|
checked: state === SelectionState.CurrentPage || state === SelectionState.All,
|
|
265
245
|
indeterminate: state === SelectionState.Partial,
|
|
266
246
|
onChange: newValue => {
|
|
267
|
-
var _a, _b
|
|
247
|
+
var _a, _b;
|
|
268
248
|
if (newValue) {
|
|
269
249
|
const newState = checkboxEmitsCurrentPage ? SelectionState.CurrentPage : SelectionState.All;
|
|
270
250
|
setState(newState);
|
|
271
251
|
onChangeSelectionState(newState);
|
|
272
|
-
} else if ((_a = selectable.selection) === null || _a === void 0 ? void 0 : _a.all) {
|
|
273
|
-
// MYG-142234: in exclusion mode, `selected` holds excluded ids. Unchecking
|
|
274
|
-
// the header must add the current page's ids to that exclusion set and
|
|
275
|
-
// keep `all: true` - it must never be treated as an inclusion list, or
|
|
276
|
-
// every other page's selection would be silently wiped out.
|
|
277
|
-
const currentPageIds = getCurrentPageSelection(entities, selectable);
|
|
278
|
-
const newExcluded = new Set([...selectable.selection.selected, ...currentPageIds]);
|
|
279
|
-
const newState = calculateSelectionState(entities, newExcluded, true, checkboxVisible, checkboxDisabled, selectable.strategy);
|
|
280
|
-
setState(newState);
|
|
281
|
-
selectable.onSelect({
|
|
282
|
-
selected: [...newExcluded],
|
|
283
|
-
all: true
|
|
284
|
-
});
|
|
285
|
-
setSelectMode(true);
|
|
286
252
|
} else {
|
|
287
253
|
// Intentionally different from onSelect(None) ("Deselect all" menu item, which clears everything).
|
|
288
254
|
// Unchecking the header checkbox only removes the current page from the selection, preserving other pages.
|
|
289
255
|
const currentPageIds = getCurrentPageSelection(entities, selectable);
|
|
290
|
-
const remaining = ((
|
|
256
|
+
const remaining = ((_b = (_a = selectable.selection) === null || _a === void 0 ? void 0 : _a.selected) !== null && _b !== void 0 ? _b : []).filter(id => !currentPageIds.has(id));
|
|
291
257
|
const newState = remaining.length > 0 ? SelectionState.Partial : SelectionState.None;
|
|
292
258
|
setState(newState);
|
|
293
259
|
selectable.onSelect({
|
|
@@ -3,41 +3,6 @@ export const calculateSelectionState = (entities, selections, all, checkboxVisib
|
|
|
3
3
|
if (selections.size === 0) {
|
|
4
4
|
return all ? SelectionState.All : SelectionState.None;
|
|
5
5
|
}
|
|
6
|
-
if (all) {
|
|
7
|
-
// When `all` is true, `selections` holds the ids explicitly excluded from the
|
|
8
|
-
// otherwise-fully-selected set (see ISelectionValue), rather than included ids.
|
|
9
|
-
const isExcluded = (entity) => {
|
|
10
|
-
if (strategy === "nested" && entity.children) {
|
|
11
|
-
if (entity.children.length === 0) {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
return entity.children.every(child => {
|
|
15
|
-
if (!checkboxVisible(child)) {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
if (checkboxDisabled(child)) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
return selections.has(child.id);
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
return selections.has(entity.id);
|
|
25
|
-
};
|
|
26
|
-
const isPartiallyExcluded = (entity) => {
|
|
27
|
-
if (strategy === "nested" && entity.children) {
|
|
28
|
-
return entity.children.some(child => selections.has(child.id));
|
|
29
|
-
}
|
|
30
|
-
return selections.has(entity.id);
|
|
31
|
-
};
|
|
32
|
-
const relevantEntities = entities.filter(entity => checkboxVisible(entity) && !checkboxDisabled(entity));
|
|
33
|
-
if (relevantEntities.length === 0) {
|
|
34
|
-
return SelectionState.All;
|
|
35
|
-
}
|
|
36
|
-
if (relevantEntities.every(entity => !isPartiallyExcluded(entity))) {
|
|
37
|
-
return SelectionState.All;
|
|
38
|
-
}
|
|
39
|
-
return relevantEntities.every(entity => isExcluded(entity)) ? SelectionState.None : SelectionState.Partial;
|
|
40
|
-
}
|
|
41
6
|
return entities.every(entity => {
|
|
42
7
|
if (!checkboxVisible(entity)) {
|
|
43
8
|
return true;
|
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
import { SelectionState } from "../interfaces";
|
|
2
2
|
export const isRowChecked = (selections, state, strategy, entity, isNested) => {
|
|
3
3
|
if (state === SelectionState.All) {
|
|
4
|
-
|
|
5
|
-
// explicitly excluded from that selection (see ISelectionValue), not included ids.
|
|
6
|
-
if (isNested) {
|
|
7
|
-
return { indeterminate: false, checked: !selections.has(entity.id) };
|
|
8
|
-
}
|
|
9
|
-
const mainEntity = entity;
|
|
10
|
-
if (strategy === "nested" && mainEntity.children && mainEntity.children.length > 0) {
|
|
11
|
-
const allChildrenChecked = mainEntity.children.every(child => !selections.has(child.id));
|
|
12
|
-
const someChildrenChecked = mainEntity.children.some(child => !selections.has(child.id));
|
|
13
|
-
return { indeterminate: someChildrenChecked && !allChildrenChecked, checked: allChildrenChecked };
|
|
14
|
-
}
|
|
15
|
-
return { indeterminate: false, checked: !selections.has(entity.id) };
|
|
4
|
+
return { indeterminate: false, checked: true };
|
|
16
5
|
}
|
|
17
6
|
if (isNested) {
|
|
18
7
|
return { indeterminate: false, checked: selections.has(entity.id) };
|