@geotab/zenith 3.6.3 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/absolute/absolute.d.ts +3 -1
- package/dist/absolute/absolute.js +4 -4
- package/dist/checkbox/checkbox.d.ts +3 -1
- package/dist/checkbox/checkbox.js +5 -8
- package/dist/checkboxListWithAction/checkboxListWithAction.d.ts +3 -1
- package/dist/checkboxListWithAction/checkboxListWithAction.js +185 -3
- package/dist/controlledPopup/controlledPopup.d.ts +3 -1
- package/dist/controlledPopup/controlledPopup.js +2 -2
- package/dist/dropdown/dropdownPopup.d.ts +1 -1
- package/dist/dropdown/dropdownTrigger.d.ts +1 -1
- package/dist/dropdownRaw/dropdownList.d.ts +2 -1
- package/dist/dropdownRaw/dropdownList.js +15 -4
- package/dist/dropdownRaw/dropdownPopup.d.ts +3 -1
- package/dist/dropdownRaw/dropdownPopup.js +35 -5
- package/dist/dropdownRaw/dropdownRaw.js +82 -7
- package/dist/dropdownRaw/dropdownSearchableTrigger.d.ts +2 -1
- package/dist/dropdownRaw/dropdownSearchableTrigger.js +7 -2
- package/dist/dropdownRaw/dropdownTrigger.d.ts +2 -1
- package/dist/dropdownRaw/dropdownTrigger.js +3 -5
- package/dist/footerButtons/footerButtons.d.ts +6 -4
- package/dist/footerButtons/footerButtons.js +3 -8
- package/dist/groupsFilterRaw/groupsFilterCurrentlySelectedState.js +8 -2
- package/dist/groupsFilterRaw/groupsFilterInitialState.js +16 -0
- package/dist/groupsFilterRaw/groupsFilterRaw.js +43 -9
- package/dist/groupsFilterRaw/groupsFilterTrigger.d.ts +2 -1
- package/dist/groupsFilterRaw/groupsFilterTrigger.js +13 -2
- package/dist/index.css +222 -18
- package/dist/index.d.ts +1 -1
- package/dist/list/hooks/useDragAndDrop.d.ts +3 -1
- package/dist/list/hooks/useDragAndDrop.js +11 -4
- package/dist/menu/components/menuItem.js +12 -2
- package/dist/menu/contexts/pathContext.d.ts +3 -1
- package/dist/menu/contexts/pathProvider.d.ts +1 -1
- package/dist/menu/contexts/pathProvider.js +1 -1
- package/dist/menu/controlledMenu.js +97 -29
- package/dist/nav/nav.d.ts +2 -1
- package/dist/nav/nav.js +3 -2
- package/dist/nav/navEditList/navEditList.js +2 -1
- package/dist/nav/navItem/navItem.d.ts +1 -0
- package/dist/nav/navItem/navItem.js +4 -1
- package/dist/pillExpandable/pillContent.d.ts +2 -1
- package/dist/pillExpandable/pillContent.js +8 -3
- package/dist/pillExpandable/pillExpandable.d.ts +27 -4
- package/dist/pillExpandable/pillExpandable.js +426 -196
- package/dist/pillExpandable/pillExpandablePopoverContent.d.ts +19 -0
- package/dist/pillExpandable/pillExpandablePopoverContent.js +7 -0
- package/dist/pillExpandable/pillExpandableSimple.d.ts +5 -3
- package/dist/pillExpandable/pillExpandableSimple.js +12 -5
- package/dist/summary/summary.js +29 -1
- package/dist/summaryTile/summaryTile.d.ts +2 -1
- package/dist/summaryTile/summaryTile.js +175 -65
- package/dist/summaryTile/summaryTileTrigger.d.ts +1 -1
- package/dist/summaryTile/summaryTileTrigger.js +1 -1
- package/dist/toggleButtonRaw/toggleButtonRaw.js +2 -1
- package/dist/utils/localization/getSupportedLanguage.d.ts +2 -2
- package/dist/utils/localization/getSupportedLanguage.js +28 -8
- package/dist/utils/localization/languageContext.d.ts +1 -1
- package/dist/utils/localization/translations/cs.json +2 -1
- package/dist/utils/localization/translations/de.json +2 -1
- package/dist/utils/localization/translations/en.json +2 -1
- package/dist/utils/localization/translations/es.json +2 -1
- package/dist/utils/localization/translations/fr-FR.json +2 -1
- package/dist/utils/localization/translations/fr.json +2 -1
- package/dist/utils/localization/translations/id.json +2 -1
- package/dist/utils/localization/translations/it.json +2 -1
- package/dist/utils/localization/translations/ja.json +2 -1
- package/dist/utils/localization/translations/ms.json +2 -1
- package/dist/utils/localization/translations/nl.json +2 -1
- package/dist/utils/localization/translations/pl.json +2 -1
- package/dist/utils/localization/translations/pt-BR.json +2 -1
- package/dist/utils/localization/translations/sv.json +2 -1
- package/dist/utils/localization/translations/th.json +2 -1
- package/dist/utils/localization/translations/tr.json +2 -1
- package/dist/utils/localization/translations/zh-Hans.json +2 -1
- package/esm/absolute/absolute.d.ts +3 -1
- package/esm/absolute/absolute.js +4 -4
- package/esm/checkbox/checkbox.d.ts +3 -1
- package/esm/checkbox/checkbox.js +5 -8
- package/esm/checkboxListWithAction/checkboxListWithAction.d.ts +3 -1
- package/esm/checkboxListWithAction/checkboxListWithAction.js +186 -4
- package/esm/controlledPopup/controlledPopup.d.ts +3 -1
- package/esm/controlledPopup/controlledPopup.js +2 -2
- package/esm/dropdown/dropdownPopup.d.ts +1 -1
- package/esm/dropdown/dropdownTrigger.d.ts +1 -1
- package/esm/dropdownRaw/dropdownList.d.ts +2 -1
- package/esm/dropdownRaw/dropdownList.js +16 -5
- package/esm/dropdownRaw/dropdownPopup.d.ts +3 -1
- package/esm/dropdownRaw/dropdownPopup.js +37 -7
- package/esm/dropdownRaw/dropdownRaw.js +82 -7
- package/esm/dropdownRaw/dropdownSearchableTrigger.d.ts +2 -1
- package/esm/dropdownRaw/dropdownSearchableTrigger.js +7 -2
- package/esm/dropdownRaw/dropdownTrigger.d.ts +2 -1
- package/esm/dropdownRaw/dropdownTrigger.js +3 -5
- package/esm/footerButtons/footerButtons.d.ts +6 -4
- package/esm/footerButtons/footerButtons.js +3 -8
- package/esm/groupsFilterRaw/groupsFilterCurrentlySelectedState.js +9 -3
- package/esm/groupsFilterRaw/groupsFilterInitialState.js +16 -0
- package/esm/groupsFilterRaw/groupsFilterRaw.js +43 -9
- package/esm/groupsFilterRaw/groupsFilterTrigger.d.ts +2 -1
- package/esm/groupsFilterRaw/groupsFilterTrigger.js +13 -2
- package/esm/index.d.ts +1 -1
- package/esm/list/hooks/useDragAndDrop.d.ts +3 -1
- package/esm/list/hooks/useDragAndDrop.js +11 -4
- package/esm/menu/components/menuItem.js +12 -2
- package/esm/menu/contexts/pathContext.d.ts +3 -1
- package/esm/menu/contexts/pathProvider.d.ts +1 -1
- package/esm/menu/contexts/pathProvider.js +1 -1
- package/esm/menu/controlledMenu.js +98 -30
- package/esm/nav/nav.d.ts +2 -1
- package/esm/nav/nav.js +3 -2
- package/esm/nav/navEditList/navEditList.js +2 -1
- package/esm/nav/navItem/navItem.d.ts +1 -0
- package/esm/nav/navItem/navItem.js +5 -2
- package/esm/pillExpandable/pillContent.d.ts +2 -1
- package/esm/pillExpandable/pillContent.js +8 -3
- package/esm/pillExpandable/pillExpandable.d.ts +27 -4
- package/esm/pillExpandable/pillExpandable.js +427 -197
- package/esm/pillExpandable/pillExpandablePopoverContent.d.ts +19 -0
- package/esm/pillExpandable/pillExpandablePopoverContent.js +3 -0
- package/esm/pillExpandable/pillExpandableSimple.d.ts +5 -3
- package/esm/pillExpandable/pillExpandableSimple.js +12 -5
- package/esm/summary/summary.js +29 -1
- package/esm/summaryTile/summaryTile.d.ts +2 -1
- package/esm/summaryTile/summaryTile.js +140 -43
- package/esm/summaryTile/summaryTileTrigger.d.ts +1 -1
- package/esm/summaryTile/summaryTileTrigger.js +1 -1
- package/esm/toggleButtonRaw/toggleButtonRaw.js +2 -1
- package/esm/utils/localization/getSupportedLanguage.d.ts +2 -2
- package/esm/utils/localization/getSupportedLanguage.js +28 -8
- package/esm/utils/localization/languageContext.d.ts +1 -1
- package/esm/utils/localization/translations/cs.json +2 -1
- package/esm/utils/localization/translations/de.json +2 -1
- package/esm/utils/localization/translations/en.json +2 -1
- package/esm/utils/localization/translations/es.json +2 -1
- package/esm/utils/localization/translations/fr-FR.json +2 -1
- package/esm/utils/localization/translations/fr.json +2 -1
- package/esm/utils/localization/translations/id.json +2 -1
- package/esm/utils/localization/translations/it.json +2 -1
- package/esm/utils/localization/translations/ja.json +2 -1
- package/esm/utils/localization/translations/ms.json +2 -1
- package/esm/utils/localization/translations/nl.json +2 -1
- package/esm/utils/localization/translations/pl.json +2 -1
- package/esm/utils/localization/translations/pt-BR.json +2 -1
- package/esm/utils/localization/translations/sv.json +2 -1
- package/esm/utils/localization/translations/th.json +2 -1
- package/esm/utils/localization/translations/tr.json +2 -1
- package/esm/utils/localization/translations/zh-Hans.json +2 -1
- package/package.json +4 -7
|
@@ -23,5 +23,7 @@ export interface IAbsolute extends IZenComponentProps {
|
|
|
23
23
|
alignmentsFn?: IAlignment;
|
|
24
24
|
recalculateOnScroll?: boolean;
|
|
25
25
|
recalculateTrigger?: boolean;
|
|
26
|
+
/** Whether to focus the first focusable element when popup opens. Default: true */
|
|
27
|
+
focusOnOpen?: boolean;
|
|
26
28
|
}
|
|
27
|
-
export declare const Absolute: ({ isOpen, id, paddingX, paddingY, className, children, triggerRef, alignment, inline, onOpenChange, useTrapFocusWithTrigger, shouldHoldScroll, stateFullChilds, role, ariaLabel, ariaLabelledby, alignmentsFn, recalculateOnScroll, recalculateTrigger }: IAbsolute) => import("react/jsx-runtime").JSX.Element | "" | null;
|
|
29
|
+
export declare const Absolute: ({ isOpen, id, paddingX, paddingY, className, children, triggerRef, alignment, inline, onOpenChange, useTrapFocusWithTrigger, shouldHoldScroll, stateFullChilds, role, ariaLabel, ariaLabelledby, alignmentsFn, recalculateOnScroll, recalculateTrigger, focusOnOpen }: IAbsolute) => import("react/jsx-runtime").JSX.Element | "" | null;
|
package/esm/absolute/absolute.js
CHANGED
|
@@ -16,7 +16,7 @@ import { useScroll } from "../commonHelpers/hooks/useScroll";
|
|
|
16
16
|
import { getScrollableParent } from "../utils/getScrollableParent";
|
|
17
17
|
import { useClientReady } from "../commonHelpers/hooks/useClientReady";
|
|
18
18
|
import { zen } from "../utils/zen";
|
|
19
|
-
export const Absolute = ({ isOpen, id, paddingX, paddingY, className, children, triggerRef, alignment, inline, onOpenChange, useTrapFocusWithTrigger = "off", shouldHoldScroll, stateFullChilds, role, ariaLabel, ariaLabelledby, alignmentsFn, recalculateOnScroll, recalculateTrigger = true }) => {
|
|
19
|
+
export const Absolute = ({ isOpen, id, paddingX, paddingY, className, children, triggerRef, alignment, inline, onOpenChange, useTrapFocusWithTrigger = "off", shouldHoldScroll, stateFullChilds, role, ariaLabel, ariaLabelledby, alignmentsFn, recalculateOnScroll, recalculateTrigger = true, focusOnOpen = true }) => {
|
|
20
20
|
const popupRef = useRef(null);
|
|
21
21
|
const prevScroll = useRef(0);
|
|
22
22
|
const { dark } = useContext(themeContext);
|
|
@@ -35,7 +35,7 @@ export const Absolute = ({ isOpen, id, paddingX, paddingY, className, children,
|
|
|
35
35
|
const renderPopup = () => {
|
|
36
36
|
var _a, _b;
|
|
37
37
|
if (isOpen) {
|
|
38
|
-
const result = (_jsx("div", Object.assign({}, accessibleAttr, { ref: popupRef, id: id, onScroll: shouldHoldScroll ? onScrollHandler : undefined, className: classNames(["zen-absolute", darkClassName, className || ""]), children: children })));
|
|
38
|
+
const result = (_jsx("div", Object.assign({}, accessibleAttr, { ref: popupRef, id: id, tabIndex: -1, onScroll: shouldHoldScroll ? onScrollHandler : undefined, className: classNames(["zen-absolute", darkClassName, className || ""]), children: children })));
|
|
39
39
|
if (inline) {
|
|
40
40
|
return result;
|
|
41
41
|
}
|
|
@@ -91,7 +91,7 @@ export const Absolute = ({ isOpen, id, paddingX, paddingY, className, children,
|
|
|
91
91
|
if (useTrapFocusWithTrigger === "none") {
|
|
92
92
|
return undefined;
|
|
93
93
|
}
|
|
94
|
-
if (useTrapFocusWithTrigger !== "withTrigger") {
|
|
94
|
+
if (useTrapFocusWithTrigger !== "withTrigger" && focusOnOpen) {
|
|
95
95
|
if (firstFocusable) {
|
|
96
96
|
firstFocusable.focus();
|
|
97
97
|
}
|
|
@@ -105,7 +105,7 @@ export const Absolute = ({ isOpen, id, paddingX, paddingY, className, children,
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
return () => { };
|
|
108
|
-
}, [isOpen, onOpenChange, triggerRef, useTrapFocusWithTrigger, stateFullChilds]);
|
|
108
|
+
}, [isOpen, onOpenChange, triggerRef, useTrapFocusWithTrigger, stateFullChilds, focusOnOpen]);
|
|
109
109
|
useEffect(() => {
|
|
110
110
|
var _a;
|
|
111
111
|
if (isOpen) {
|
|
@@ -13,5 +13,7 @@ export interface ICheckbox extends IZenComponentProps {
|
|
|
13
13
|
reverse?: boolean;
|
|
14
14
|
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
15
15
|
wrapped?: boolean;
|
|
16
|
+
tabIndex?: number;
|
|
17
|
+
describedBy?: string;
|
|
16
18
|
}
|
|
17
|
-
export declare const Checkbox: ({ reverse, fullWidth, id, checked, indeterminate, title, className, children, disabled, wrapped, ...rest }: ICheckbox) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare const Checkbox: ({ reverse, fullWidth, id, checked, indeterminate, title, className, children, disabled, wrapped, describedBy, ...rest }: ICheckbox) => import("react/jsx-runtime").JSX.Element;
|
package/esm/checkbox/checkbox.js
CHANGED
|
@@ -20,20 +20,17 @@ 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 } = _a, rest = __rest(_a, ["reverse", "fullWidth", "id", "checked", "indeterminate", "title", "className", "children", "disabled", "wrapped"]);
|
|
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"]);
|
|
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 }, rest));
|
|
31
|
-
const iconAndLabel = _jsxs(_Fragment, { children: [_jsx("div", { className: "zen-checkbox__box", children: state === CheckboxState.Indeterminate ? _jsx(CheckboxIconMinus, { className: checkboxIconClasses, size: driveClasses ? "bigger" : "medium" }) :
|
|
32
|
-
state === CheckboxState.On ? _jsx(CheckboxIconCheckmark, { className: checkboxIconClasses, size: driveClasses ? "bigger" : "medium" }) : null }), children
|
|
33
|
-
? _jsx("div", { className: classNames(["zen-checkbox__label-text", fullWidth ? "zen-checkbox__label-text--full-width" : ""]), children: children })
|
|
34
|
-
: null] });
|
|
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)));
|
|
31
|
+
const iconAndLabel = (_jsxs(_Fragment, { children: [_jsx("div", { className: "zen-checkbox__box", 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] }));
|
|
35
32
|
if (wrapped) {
|
|
36
|
-
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 })] });
|
|
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 })] }));
|
|
37
34
|
}
|
|
38
|
-
return _jsxs("div", { className: classNames(["zen-checkbox", isMobile && !driveClasses ? "zen-checkbox--mobile" : "", driveClasses || "", className]), children: [checkbox, _jsx("label", { className: classNames(["zen-checkbox__label", reverse ? "zen-checkbox__label--reverse" : ""]), htmlFor: intId, title: title, children: iconAndLabel })] });
|
|
35
|
+
return (_jsxs("div", { className: classNames(["zen-checkbox", isMobile && !driveClasses ? "zen-checkbox--mobile" : "", driveClasses || "", className]), children: [checkbox, _jsx("label", { className: classNames(["zen-checkbox__label", reverse ? "zen-checkbox__label--reverse" : ""]), htmlFor: intId, title: title, children: iconAndLabel })] }));
|
|
39
36
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import "./checkboxListWithAction.less";
|
|
2
3
|
import { IZenComponentProps } from "../commonHelpers/zenComponent";
|
|
3
4
|
import { IColor } from "../groupsFilterRaw/groupsFilterInterfaces";
|
|
@@ -23,6 +24,7 @@ export interface ICheckboxListWithAction extends IZenComponentProps {
|
|
|
23
24
|
search?: string[];
|
|
24
25
|
onChange: (value: IChangeCheckbox) => void;
|
|
25
26
|
onClick: (id: string) => void;
|
|
27
|
+
handleTab?: (e: React.KeyboardEvent, shift?: boolean) => void;
|
|
26
28
|
}
|
|
27
|
-
export declare const CheckboxListWithAction: ({ label, options, onChange, onClick, search, className }: ICheckboxListWithAction) => import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export declare const CheckboxListWithAction: ({ label, options, onChange, onClick, search, className, handleTab }: ICheckboxListWithAction) => import("react/jsx-runtime").JSX.Element;
|
|
28
30
|
export declare const TRANSLATIONS: string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { injectString } from "../utils/localization/translationsDictionary";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { Fragment, useId } from "react";
|
|
3
|
+
import { Fragment, useCallback, useEffect, useId, useRef, useState } from "react";
|
|
4
4
|
import { Checkbox } from "../checkbox/checkbox";
|
|
5
5
|
import { classNames } from "../commonHelpers/classNames/classNames";
|
|
6
6
|
import { IconChevronRight } from "../icons/iconChevronRight";
|
|
@@ -84,13 +84,15 @@ injectString("tr", "Toggle {groupName} filter", "{groupName} filtresini de\u011F
|
|
|
84
84
|
injectString("zh-Hans", "Toggle {groupName} filter", "\u5207\u6362 {groupName} \u7B5B\u9009\u5668");
|
|
85
85
|
injectString("zh-TW", "Toggle {groupName} filter", "\u5207\u63DB\u300C{groupName}\u300D\u7BE9\u9078\u689D\u4EF6");
|
|
86
86
|
injectString("ro-RO", "Toggle {groupName} filter", "Activa\u021Bi filtrul {groupName}");
|
|
87
|
+
injectString("en", "Has additional actions. Use right arrow to access button, left arrow to return.", "Has additional actions. Use right arrow to access button, left arrow to return.");
|
|
87
88
|
export const CheckboxListWithAction = ({
|
|
88
89
|
label,
|
|
89
90
|
options,
|
|
90
91
|
onChange,
|
|
91
92
|
onClick,
|
|
92
93
|
search = [],
|
|
93
|
-
className
|
|
94
|
+
className,
|
|
95
|
+
handleTab
|
|
94
96
|
}) => {
|
|
95
97
|
const {
|
|
96
98
|
translate
|
|
@@ -98,6 +100,11 @@ export const CheckboxListWithAction = ({
|
|
|
98
100
|
const driveComponentClass = useDriveClassName("zen-checkbox-list-with-action");
|
|
99
101
|
const listId = useId();
|
|
100
102
|
const checkboxId = `${listId}_check_list-item_`;
|
|
103
|
+
const navigationInstructionsId = `${listId}_navigation_instructions`;
|
|
104
|
+
const listRef = useRef(null);
|
|
105
|
+
const [focusedRowIndex, setFocusedRowIndex] = useState(0);
|
|
106
|
+
const [focusedElementType, setFocusedElementType] = useState("checkbox");
|
|
107
|
+
const isInitialized = useRef(false);
|
|
101
108
|
const handleChange = e => {
|
|
102
109
|
const evtTarget = e.target;
|
|
103
110
|
const elId = evtTarget.getAttribute("id").replace(checkboxId, "");
|
|
@@ -112,7 +119,171 @@ export const CheckboxListWithAction = ({
|
|
|
112
119
|
const evtTarget = e.target;
|
|
113
120
|
const elId = evtTarget.getAttribute("data-btn") || ((_a = evtTarget.parentElement) === null || _a === void 0 ? void 0 : _a.getAttribute("data-btn")) || "";
|
|
114
121
|
onClick(elId);
|
|
122
|
+
setFocusedElementType("checkbox");
|
|
115
123
|
};
|
|
124
|
+
const getFocusableElements = useCallback(() => {
|
|
125
|
+
if (!listRef.current || !options) return [];
|
|
126
|
+
const elements = [];
|
|
127
|
+
options.forEach((opt, rowIndex) => {
|
|
128
|
+
var _a;
|
|
129
|
+
const listItem = (_a = listRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(`li[data-item="${opt.property}"]`);
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
131
|
+
if (listItem) {
|
|
132
|
+
const checkbox = listItem.querySelector('input[type="checkbox"]');
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
134
|
+
if (checkbox) {
|
|
135
|
+
elements.push({
|
|
136
|
+
element: checkbox,
|
|
137
|
+
rowIndex,
|
|
138
|
+
type: "checkbox",
|
|
139
|
+
blocked: opt.blocked
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (opt.isWithAction) {
|
|
143
|
+
const button = listItem.querySelector("button[data-btn]");
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
145
|
+
if (button) {
|
|
146
|
+
elements.push({
|
|
147
|
+
element: button,
|
|
148
|
+
rowIndex,
|
|
149
|
+
type: "button",
|
|
150
|
+
blocked: opt.blocked
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
return elements;
|
|
157
|
+
}, [options]);
|
|
158
|
+
const updateTabIndex = useCallback((newRowIndex, newElementType) => {
|
|
159
|
+
const elements = getFocusableElements();
|
|
160
|
+
elements.forEach(({
|
|
161
|
+
element,
|
|
162
|
+
rowIndex,
|
|
163
|
+
type,
|
|
164
|
+
blocked
|
|
165
|
+
}) => {
|
|
166
|
+
const isActive = rowIndex === newRowIndex && type === newElementType && !blocked;
|
|
167
|
+
element.setAttribute("tabindex", isActive ? "0" : "-1");
|
|
168
|
+
});
|
|
169
|
+
}, [getFocusableElements]);
|
|
170
|
+
const handleKeyDown = useCallback(
|
|
171
|
+
// eslint-disable-next-line complexity
|
|
172
|
+
e => {
|
|
173
|
+
var _a;
|
|
174
|
+
const elements = getFocusableElements();
|
|
175
|
+
if (elements.length === 0 || !options) return;
|
|
176
|
+
let newRowIndex = focusedRowIndex;
|
|
177
|
+
let newElementType = focusedElementType;
|
|
178
|
+
let preventDefault = false;
|
|
179
|
+
if (e.key === "Enter") {
|
|
180
|
+
const evtTarget = e.target;
|
|
181
|
+
const elId = ((_a = evtTarget.getAttribute("id")) === null || _a === void 0 ? void 0 : _a.replace(checkboxId, "")) || "";
|
|
182
|
+
elId && onChange({
|
|
183
|
+
id: elId,
|
|
184
|
+
state: evtTarget.checked,
|
|
185
|
+
partial: evtTarget.dataset.indeterminate === "true"
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (e.key === "ArrowDown") {
|
|
190
|
+
// Go to next row
|
|
191
|
+
do {
|
|
192
|
+
newRowIndex = (newRowIndex + 1) % options.length;
|
|
193
|
+
} while (options[newRowIndex].blocked && newRowIndex !== focusedRowIndex);
|
|
194
|
+
preventDefault = true;
|
|
195
|
+
} else if (e.key === "ArrowUp") {
|
|
196
|
+
// Go to previous row
|
|
197
|
+
do {
|
|
198
|
+
newRowIndex = (newRowIndex - 1 + options.length) % options.length;
|
|
199
|
+
} while (options[newRowIndex].blocked && newRowIndex !== focusedRowIndex);
|
|
200
|
+
preventDefault = true;
|
|
201
|
+
} else if (e.key === "ArrowRight") {
|
|
202
|
+
// Go to button if exists in current row and not blocked
|
|
203
|
+
if (options[focusedRowIndex].isWithAction && focusedElementType === "checkbox" && !options[focusedRowIndex].blocked) {
|
|
204
|
+
newElementType = "button";
|
|
205
|
+
preventDefault = true;
|
|
206
|
+
}
|
|
207
|
+
} else if (e.key === "ArrowLeft") {
|
|
208
|
+
// Go to checkbox if currently on button and checkbox not blocked
|
|
209
|
+
if (focusedElementType === "button" && !options[focusedRowIndex].blocked) {
|
|
210
|
+
newElementType = "checkbox";
|
|
211
|
+
preventDefault = true;
|
|
212
|
+
}
|
|
213
|
+
} else if (e.key === "Home") {
|
|
214
|
+
// Go to first non-blocked row
|
|
215
|
+
newRowIndex = 0;
|
|
216
|
+
while (newRowIndex < options.length && options[newRowIndex].blocked) {
|
|
217
|
+
newRowIndex++;
|
|
218
|
+
}
|
|
219
|
+
if (newRowIndex < options.length) {
|
|
220
|
+
newElementType = "checkbox";
|
|
221
|
+
preventDefault = true;
|
|
222
|
+
}
|
|
223
|
+
} else if (e.key === "End") {
|
|
224
|
+
// Go to last non-blocked row
|
|
225
|
+
newRowIndex = options.length - 1;
|
|
226
|
+
while (newRowIndex >= 0 && options[newRowIndex].blocked) {
|
|
227
|
+
newRowIndex--;
|
|
228
|
+
}
|
|
229
|
+
if (newRowIndex >= 0) {
|
|
230
|
+
newElementType = "checkbox";
|
|
231
|
+
preventDefault = true;
|
|
232
|
+
}
|
|
233
|
+
} else if (e.key === "Tab") {
|
|
234
|
+
if (handleTab) {
|
|
235
|
+
handleTab(e, e.shiftKey);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (preventDefault) {
|
|
240
|
+
e.preventDefault();
|
|
241
|
+
setFocusedRowIndex(newRowIndex);
|
|
242
|
+
setFocusedElementType(newElementType);
|
|
243
|
+
updateTabIndex(newRowIndex, newElementType);
|
|
244
|
+
// Find and focus the target element
|
|
245
|
+
const targetElement = elements.find(({
|
|
246
|
+
rowIndex,
|
|
247
|
+
type,
|
|
248
|
+
blocked
|
|
249
|
+
}) => rowIndex === newRowIndex && type === newElementType && !blocked);
|
|
250
|
+
targetElement === null || targetElement === void 0 ? void 0 : targetElement.element.focus();
|
|
251
|
+
}
|
|
252
|
+
}, [getFocusableElements, options, focusedRowIndex, focusedElementType, checkboxId, onChange, handleTab, updateTabIndex]);
|
|
253
|
+
const handleFocus = useCallback(e => {
|
|
254
|
+
const elements = getFocusableElements();
|
|
255
|
+
const focusedElement = e.target;
|
|
256
|
+
const targetElementInfo = elements.find(({
|
|
257
|
+
element
|
|
258
|
+
}) => element === focusedElement);
|
|
259
|
+
if (targetElementInfo && !targetElementInfo.blocked && (targetElementInfo.rowIndex !== focusedRowIndex || targetElementInfo.type !== focusedElementType)) {
|
|
260
|
+
setFocusedRowIndex(targetElementInfo.rowIndex);
|
|
261
|
+
setFocusedElementType(targetElementInfo.type);
|
|
262
|
+
updateTabIndex(targetElementInfo.rowIndex, targetElementInfo.type);
|
|
263
|
+
}
|
|
264
|
+
}, [focusedRowIndex, focusedElementType, getFocusableElements, updateTabIndex]);
|
|
265
|
+
// Initialize tabindex when options first become available
|
|
266
|
+
useEffect(() => {
|
|
267
|
+
if (options && options.length > 0 && !isInitialized.current) {
|
|
268
|
+
// Find first non-blocked row
|
|
269
|
+
let firstValidRow = 0;
|
|
270
|
+
while (firstValidRow < options.length && options[firstValidRow].blocked) {
|
|
271
|
+
firstValidRow++;
|
|
272
|
+
}
|
|
273
|
+
if (firstValidRow < options.length) {
|
|
274
|
+
setFocusedRowIndex(firstValidRow);
|
|
275
|
+
setFocusedElementType("checkbox");
|
|
276
|
+
updateTabIndex(firstValidRow, "checkbox");
|
|
277
|
+
isInitialized.current = true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}, [options, updateTabIndex]);
|
|
281
|
+
// Update tabindex when focused position changes (only after initialization)
|
|
282
|
+
useEffect(() => {
|
|
283
|
+
if (isInitialized.current) {
|
|
284
|
+
updateTabIndex(focusedRowIndex, focusedElementType);
|
|
285
|
+
}
|
|
286
|
+
}, [focusedRowIndex, focusedElementType, updateTabIndex]);
|
|
116
287
|
const getLabelColorInfo = (color, withRightPadding, isHidden, extraArgs) => {
|
|
117
288
|
if (!color) {
|
|
118
289
|
return null;
|
|
@@ -170,7 +341,8 @@ export const CheckboxListWithAction = ({
|
|
|
170
341
|
type: "button",
|
|
171
342
|
onClick: handleClick,
|
|
172
343
|
title: title,
|
|
173
|
-
className: classN
|
|
344
|
+
className: classN,
|
|
345
|
+
tabIndex: -1
|
|
174
346
|
}, otherArgs, {
|
|
175
347
|
children: childEl
|
|
176
348
|
})) : _jsx("div", {
|
|
@@ -200,6 +372,9 @@ export const CheckboxListWithAction = ({
|
|
|
200
372
|
};
|
|
201
373
|
return optionsArr ? _jsx("ul", {
|
|
202
374
|
className: "zen-checkbox-list-with-action__list",
|
|
375
|
+
ref: listRef,
|
|
376
|
+
onKeyDown: handleKeyDown,
|
|
377
|
+
onFocus: handleFocus,
|
|
203
378
|
children: optionsArr.map((opt, ind) => {
|
|
204
379
|
const titleForRender = opt.title || opt.label;
|
|
205
380
|
const labelForRender = selectSearchTerm(opt.label);
|
|
@@ -215,7 +390,9 @@ export const CheckboxListWithAction = ({
|
|
|
215
390
|
checked: opt.checked,
|
|
216
391
|
disabled: opt.blocked,
|
|
217
392
|
title: translate("Toggle {groupName} filter").replace("{groupName}", titleForRender),
|
|
393
|
+
describedBy: opt.isWithAction ? navigationInstructionsId : undefined,
|
|
218
394
|
"data-indeterminate": opt.partialChecked,
|
|
395
|
+
tabIndex: -1,
|
|
219
396
|
children: opt.isWithAction ? null : labelElement
|
|
220
397
|
}), opt.isWithAction && labelElement]
|
|
221
398
|
}, `li_${ind}_${opt.property}`);
|
|
@@ -227,7 +404,12 @@ export const CheckboxListWithAction = ({
|
|
|
227
404
|
children: [label ? _jsx("div", {
|
|
228
405
|
className: "zen-checkbox-list-with-action__title",
|
|
229
406
|
children: label
|
|
230
|
-
}) : null, build(options)
|
|
407
|
+
}) : null, build(options), _jsx("div", {
|
|
408
|
+
id: navigationInstructionsId,
|
|
409
|
+
className: "zen-checkbox-list-with-action__sr-only",
|
|
410
|
+
"aria-hidden": "true",
|
|
411
|
+
children: translate("Has additional actions. Use right arrow to access button, left arrow to return.")
|
|
412
|
+
})]
|
|
231
413
|
});
|
|
232
414
|
};
|
|
233
415
|
export const TRANSLATIONS = ["View {groupName} children", "Toggle {groupName} filter", "Number of selected child groups - {count}"];
|
|
@@ -27,5 +27,7 @@ export interface IControlledPopup extends IZenComponentProps {
|
|
|
27
27
|
ariaLabelledby?: string;
|
|
28
28
|
recalculateOnScroll?: boolean;
|
|
29
29
|
preventAttributesAutoSet?: boolean;
|
|
30
|
+
/** Whether to focus the first focusable element when popup opens. Default: true */
|
|
31
|
+
focusOnOpen?: boolean;
|
|
30
32
|
}
|
|
31
|
-
export declare const ControlledPopup: ({ isOpen, id, paddingX, paddingY, triggerRef, className, children, alignment, inline, onOpenChange, useTrapFocusWithTrigger, shouldHoldScroll, ariaLabel, ariaLabelledby, recalculateOnScroll, preventAttributesAutoSet }: IControlledPopup) => import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export declare const ControlledPopup: ({ isOpen, id, paddingX, paddingY, triggerRef, className, children, alignment, inline, onOpenChange, useTrapFocusWithTrigger, shouldHoldScroll, ariaLabel, ariaLabelledby, recalculateOnScroll, preventAttributesAutoSet, focusOnOpen }: IControlledPopup) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,7 +3,7 @@ import { useEffect, useId } from "react";
|
|
|
3
3
|
import { Absolute } from "../absolute/absolute";
|
|
4
4
|
import { classNames } from "../commonHelpers/classNames/classNames";
|
|
5
5
|
import { useClientReady } from "../commonHelpers/hooks/useClientReady";
|
|
6
|
-
export const ControlledPopup = ({ isOpen, id, paddingX, paddingY, triggerRef, className, children, alignment, inline, onOpenChange, useTrapFocusWithTrigger, shouldHoldScroll, ariaLabel, ariaLabelledby, recalculateOnScroll, preventAttributesAutoSet }) => {
|
|
6
|
+
export const ControlledPopup = ({ isOpen, id, paddingX, paddingY, triggerRef, className, children, alignment, inline, onOpenChange, useTrapFocusWithTrigger, shouldHoldScroll, ariaLabel, ariaLabelledby, recalculateOnScroll, preventAttributesAutoSet, focusOnOpen }) => {
|
|
7
7
|
const autoId = useId();
|
|
8
8
|
const popupId = id || autoId;
|
|
9
9
|
const isClientReady = useClientReady();
|
|
@@ -21,5 +21,5 @@ export const ControlledPopup = ({ isOpen, id, paddingX, paddingY, triggerRef, cl
|
|
|
21
21
|
triggerRef.current.setAttribute("aria-expanded", isOpen ? "true" : "false");
|
|
22
22
|
triggerRef.current.setAttribute("aria-controls", popupId);
|
|
23
23
|
}, [triggerRef, isOpen, popupId, preventAttributesAutoSet, isClientReady]);
|
|
24
|
-
return (_jsx(Absolute, { triggerRef: triggerRef, alignment: alignment, id: popupId, isOpen: isOpen, className: classNames(["zen-popup", className ? className : ""]), paddingX: paddingX, paddingY: paddingY, inline: inline, onOpenChange: onOpenChange, useTrapFocusWithTrigger: useTrapFocusWithTrigger, shouldHoldScroll: shouldHoldScroll, role: "dialog", ariaLabel: ariaLabel, ariaLabelledby: ariaLabelledby, recalculateOnScroll: recalculateOnScroll, children: children }));
|
|
24
|
+
return (_jsx(Absolute, { triggerRef: triggerRef, alignment: alignment, id: popupId, isOpen: isOpen, className: classNames(["zen-popup", className ? className : ""]), paddingX: paddingX, paddingY: paddingY, inline: inline, onOpenChange: onOpenChange, useTrapFocusWithTrigger: useTrapFocusWithTrigger, shouldHoldScroll: shouldHoldScroll, role: "dialog", ariaLabel: ariaLabel, ariaLabelledby: ariaLabelledby, recalculateOnScroll: recalculateOnScroll, focusOnOpen: focusOnOpen, children: children }));
|
|
25
25
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { IDropdownPopup as IDropdownPopupRaw } from "../dropdownRaw/dropdownPopup";
|
|
2
|
-
export declare const DropdownPopup: ({ alignment, triggerRef, classNamePopup, isMobile, inputValue, dialogAriaLabel, disabled, filterName, handleApplyClick, handleClearClick, handleTriggerClick, mobileSheetStackingClassName, onInputChange, hasApplyButton, inputId, isClearButtonDisabled, isWithFooter, placeholder, searchField, isSearchInPopup, isApplyButtonDisabled, isOpenCombo, inputRef, contentRef, children, onReadyForFocus, handleCheckboxChange, checkboxLabel, isChecked, popupId }: IDropdownPopupRaw) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare const DropdownPopup: ({ alignment, triggerRef, classNamePopup, isMobile, inputValue, dialogAriaLabel, disabled, filterName, handleApplyClick, handleClearClick, handleTriggerClick, mobileSheetStackingClassName, onInputChange, hasApplyButton, inputId, isClearButtonDisabled, isWithFooter, placeholder, searchField, isSearchInPopup, isApplyButtonDisabled, isOpenCombo, inputRef, contentRef, children, onReadyForFocus, handleCheckboxChange, checkboxLabel, isChecked, popupId, handleKeydown, handleFocusOnSentinelItem }: IDropdownPopupRaw) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
export type IDropdownPopup = IDropdownPopupRaw;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const DropdownTrigger: ({ name, onBlur, isActive, id, triggerRef, searchField, placeholder, disabled, fullWidth, currentSelection, handleClick, inputValue, className, onSearchChange, width, title, triggerAriaLabel, count, inputRef, buttonType, isError, popupId, ...otherProps }: import("../dropdownRaw/dropdownTrigger").IDropdownTrigger) => import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
export declare const DropdownTrigger: ({ name, onBlur, isActive, id, triggerRef, searchField, placeholder, disabled, fullWidth, currentSelection, handleClick, inputValue, className, onSearchChange, width, title, triggerAriaLabel, count, inputRef, buttonType, isError, popupId, handleFocusOnPopup, ...otherProps }: import("../dropdownRaw/dropdownTrigger").IDropdownTrigger) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -32,11 +32,12 @@ export interface IDropdownList extends IZenComponentProps {
|
|
|
32
32
|
handleCheckboxChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
33
33
|
checkboxLabel?: string;
|
|
34
34
|
isChecked?: boolean;
|
|
35
|
+
listElementRef?: React.RefObject<HTMLDivElement>;
|
|
35
36
|
}
|
|
36
37
|
interface IDropdownEmptyList extends Pick<IDropdownList, "className" | "width" | "onClearClick" | "onApplyClick" | "onCancelClick" | "hasApplyButton" | "isApplyDisabled" | "isClearButtonDisabled" | "isWithFooter"> {
|
|
37
38
|
hasError: boolean;
|
|
38
39
|
}
|
|
39
40
|
export declare const EmptyList: ({ className, width, onClearClick, onApplyClick, onCancelClick, hasApplyButton, isApplyDisabled, isClearButtonDisabled, isWithFooter, hasError }: IDropdownEmptyList) => import("react/jsx-runtime").JSX.Element;
|
|
40
|
-
export declare const DropdownList: ({ onBackButtonClick, onSelectAllClick, onClearClick, onApplyClick, onCancelClick, onChange, onSelect, onSingleSelect, listData, isAllSelected, backButtonName, width, minWidth, isSelectAllButtonDisable, hasSelectAllButton, filterName, isMultiselect, hasApplyButton, isApplyDisabled, isClearButtonDisabled, activeValue, forceSelection, isWithFooter, isMobile, handleCheckboxChange, checkboxLabel, isChecked }: IDropdownList) => import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
export declare const DropdownList: ({ onBackButtonClick, onSelectAllClick, onClearClick, onApplyClick, onCancelClick, onChange, onSelect, onSingleSelect, listData, isAllSelected, backButtonName, width, minWidth, isSelectAllButtonDisable, hasSelectAllButton, filterName, isMultiselect, hasApplyButton, isApplyDisabled, isClearButtonDisabled, activeValue, forceSelection, isWithFooter, isMobile, handleCheckboxChange, checkboxLabel, isChecked, listElementRef }: IDropdownList) => import("react/jsx-runtime").JSX.Element;
|
|
41
42
|
export declare const TRANSLATIONS: string[];
|
|
42
43
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { injectString } from "../utils/localization/translationsDictionary";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import React, { useCallback, useId, useMemo } from "react";
|
|
3
|
+
import React, { useCallback, useId, useMemo, useRef } from "react";
|
|
4
4
|
import { CheckboxListWithAction } from "../checkboxListWithAction/checkboxListWithAction";
|
|
5
5
|
import { classNames } from "../commonHelpers/classNames/classNames";
|
|
6
6
|
import { IconBackArrow } from "../icons/deprecated/iconBackArrow";
|
|
@@ -309,7 +309,8 @@ export const DropdownList = ({
|
|
|
309
309
|
isMobile,
|
|
310
310
|
handleCheckboxChange,
|
|
311
311
|
checkboxLabel,
|
|
312
|
-
isChecked
|
|
312
|
+
isChecked,
|
|
313
|
+
listElementRef
|
|
313
314
|
}) => {
|
|
314
315
|
const {
|
|
315
316
|
translate
|
|
@@ -320,6 +321,13 @@ export const DropdownList = ({
|
|
|
320
321
|
const handleSelectAllClick = () => {
|
|
321
322
|
onSelectAllClick(isAllSelected);
|
|
322
323
|
};
|
|
324
|
+
const handleBackButtonKeyDown = useCallback(event => {
|
|
325
|
+
if (event.key === "ArrowLeft") {
|
|
326
|
+
event.preventDefault();
|
|
327
|
+
onBackButtonClick();
|
|
328
|
+
}
|
|
329
|
+
}, [onBackButtonClick]);
|
|
330
|
+
const componentRef = useRef(null);
|
|
323
331
|
const handleChange = useCallback(value => {
|
|
324
332
|
onChange(value);
|
|
325
333
|
}, [onChange]);
|
|
@@ -340,10 +348,11 @@ export const DropdownList = ({
|
|
|
340
348
|
forceSelection ? onSingleSelect(false, newActiveEl || activeValue) : onSingleSelect(false, newActiveEl);
|
|
341
349
|
}, [activeValue, forceSelection, onSingleSelect]);
|
|
342
350
|
const selectButtonLabel = isAllSelected ? translate("Deselect all") : translate("Select all");
|
|
343
|
-
const getActionButton = (label, title, icon, isDisabled, clickHandler, size) => _jsx("button", {
|
|
351
|
+
const getActionButton = (label, title, icon, isDisabled, clickHandler, size, onKeyDown) => _jsx("button", {
|
|
344
352
|
type: "button",
|
|
345
353
|
disabled: isDisabled,
|
|
346
354
|
onClick: clickHandler,
|
|
355
|
+
onKeyDown: onKeyDown,
|
|
347
356
|
className: "zen-dropdown-list__item zen-dropdown-list__item--interactive zen-dropdown-list__action-button zen-dropdown-list__action-button-back",
|
|
348
357
|
title: title,
|
|
349
358
|
children: _jsxs(_Fragment, {
|
|
@@ -382,6 +391,7 @@ export const DropdownList = ({
|
|
|
382
391
|
};
|
|
383
392
|
return _jsx("div", {
|
|
384
393
|
className: "zen-dropdown-list__elements",
|
|
394
|
+
ref: listElementRef,
|
|
385
395
|
children: isMultiselect ? _jsx(CheckboxListWithAction, {
|
|
386
396
|
options: listData,
|
|
387
397
|
label: "",
|
|
@@ -399,10 +409,11 @@ export const DropdownList = ({
|
|
|
399
409
|
value: createValue(listData, activeValue)
|
|
400
410
|
})
|
|
401
411
|
});
|
|
402
|
-
}, [isMultiselect, listData, handleChange, handleClick, handleSingleChange, translate, listId, forceSelection, activeValue]);
|
|
412
|
+
}, [listElementRef, isMultiselect, listData, handleChange, handleClick, handleSingleChange, translate, listId, forceSelection, activeValue]);
|
|
403
413
|
return _jsxs("div", Object.assign({
|
|
404
414
|
className: classNames(["zen-dropdown-list", driveComponentClass || ""])
|
|
405
415
|
}, styleWidth, {
|
|
416
|
+
ref: componentRef,
|
|
406
417
|
children: [filterName ? _jsx("div", {
|
|
407
418
|
className: "zen-dropdown-list__label",
|
|
408
419
|
children: filterName
|
|
@@ -415,7 +426,7 @@ export const DropdownList = ({
|
|
|
415
426
|
})
|
|
416
427
|
}) : null, backButtonName ? _jsx("div", {
|
|
417
428
|
className: "zen-dropdown-list__item-wrapper",
|
|
418
|
-
children: getActionButton(backButtonName, translate("Back"), IconBackArrow, false, onBackButtonClick, "large")
|
|
429
|
+
children: getActionButton(backButtonName, translate("Back"), IconBackArrow, false, onBackButtonClick, "large", handleBackButtonKeyDown)
|
|
419
430
|
}) : null, hasSelectAllButton ? getActionButton(selectButtonLabel, selectButtonLabel, IconCheckRadio, !!isSelectAllButtonDisable, handleSelectAllClick, isDrive ? "huger" : "huge") : null, listDataComponent, isWithFooter ? _jsxs("div", {
|
|
420
431
|
className: "zen-dropdown-list__footer",
|
|
421
432
|
children: [_jsx(Button, {
|
|
@@ -31,5 +31,7 @@ export interface IDropdownPopup extends IZenComponentProps {
|
|
|
31
31
|
checkboxLabel?: string;
|
|
32
32
|
isChecked?: boolean;
|
|
33
33
|
isSearchInPopup?: boolean;
|
|
34
|
+
handleKeydown: (event: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
35
|
+
handleFocusOnSentinelItem?: () => void;
|
|
34
36
|
}
|
|
35
|
-
export declare const DropdownPopup: ({ alignment, triggerRef, classNamePopup, isMobile, inputValue, dialogAriaLabel, disabled, filterName, handleApplyClick, handleClearClick, handleTriggerClick, mobileSheetStackingClassName, onInputChange, hasApplyButton, inputId, isClearButtonDisabled, isWithFooter, placeholder, searchField, isSearchInPopup, isApplyButtonDisabled, isOpenCombo, inputRef, contentRef, children, onReadyForFocus, handleCheckboxChange, checkboxLabel, isChecked, popupId }: IDropdownPopup) => import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export declare const DropdownPopup: ({ alignment, triggerRef, classNamePopup, isMobile, inputValue, dialogAriaLabel, disabled, filterName, handleApplyClick, handleClearClick, handleTriggerClick, mobileSheetStackingClassName, onInputChange, hasApplyButton, inputId, isClearButtonDisabled, isWithFooter, placeholder, searchField, isSearchInPopup, isApplyButtonDisabled, isOpenCombo, inputRef, contentRef, children, onReadyForFocus, handleCheckboxChange, checkboxLabel, isChecked, popupId, handleKeydown, handleFocusOnSentinelItem }: IDropdownPopup) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { injectString } from "../utils/localization/translationsDictionary";
|
|
2
|
-
import { jsx as _jsx,
|
|
3
|
-
import { useCallback, useId, useMemo } from "react";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useId, useMemo, useRef } from "react";
|
|
4
4
|
import { MobileSheet } from "../mobileSheet/mobileSheet";
|
|
5
5
|
import { Button } from "../button/button";
|
|
6
6
|
import { ButtonType } from "../button/buttonType";
|
|
@@ -11,6 +11,7 @@ import { useLanguage } from "../utils/localization/useLanguage";
|
|
|
11
11
|
import { FooterButtons } from "../footerButtons/footerButtons";
|
|
12
12
|
import { Checkbox } from "../checkbox/checkbox";
|
|
13
13
|
import { useScrollWithAndroidKeyboard } from "../utils/useScrollWithAndroidKeyboard";
|
|
14
|
+
import { getFirstFocusableItem } from "../utils/keyboardHelpers";
|
|
14
15
|
injectString("cs", "Filter by group", "Filtrovat podle skupiny");
|
|
15
16
|
injectString("da-DK", "Filter by group", "Filtrer efter gruppe");
|
|
16
17
|
injectString("de", "Filter by group", "Nach Gruppe filtern");
|
|
@@ -119,12 +120,16 @@ export const DropdownPopup = ({
|
|
|
119
120
|
handleCheckboxChange,
|
|
120
121
|
checkboxLabel,
|
|
121
122
|
isChecked,
|
|
122
|
-
popupId
|
|
123
|
+
popupId,
|
|
124
|
+
handleKeydown,
|
|
125
|
+
handleFocusOnSentinelItem
|
|
123
126
|
}) => {
|
|
124
127
|
const {
|
|
125
128
|
translate
|
|
126
129
|
} = useLanguage();
|
|
127
130
|
const triggerId = useId();
|
|
131
|
+
const footerButtonsRef = useRef(null);
|
|
132
|
+
const mobileContentRef = useRef(null);
|
|
128
133
|
const {
|
|
129
134
|
handleFocus,
|
|
130
135
|
handleBlur,
|
|
@@ -133,7 +138,22 @@ export const DropdownPopup = ({
|
|
|
133
138
|
const memoizedHandleHide = useCallback(() => {
|
|
134
139
|
handleTriggerClick(false);
|
|
135
140
|
}, [handleTriggerClick]);
|
|
136
|
-
const
|
|
141
|
+
const handleMobileFocusOnSentinelItem = useCallback(() => {
|
|
142
|
+
if (!isMobile) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
let nextFocusableElement = footerButtonsRef.current ? getFirstFocusableItem(footerButtonsRef.current) : null;
|
|
146
|
+
if (nextFocusableElement) {
|
|
147
|
+
nextFocusableElement.focus();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
nextFocusableElement = getFirstFocusableItem(mobileContentRef.current);
|
|
151
|
+
nextFocusableElement === null || nextFocusableElement === void 0 ? void 0 : nextFocusableElement.focus();
|
|
152
|
+
return;
|
|
153
|
+
}, [isMobile, footerButtonsRef, mobileContentRef]);
|
|
154
|
+
const memoizedMobileContent = useMemo(() => _jsxs("div", {
|
|
155
|
+
onKeyDown: handleKeydown,
|
|
156
|
+
ref: mobileContentRef,
|
|
137
157
|
children: [searchField ? _jsx("div", {
|
|
138
158
|
className: "zen-dropdown-mobile-sheet__search-container",
|
|
139
159
|
children: _jsx(SearchInput, {
|
|
@@ -157,13 +177,18 @@ export const DropdownPopup = ({
|
|
|
157
177
|
}) : null, _jsx("div", {
|
|
158
178
|
ref: contentRef,
|
|
159
179
|
children: children
|
|
180
|
+
}), _jsx("div", {
|
|
181
|
+
tabIndex: 0,
|
|
182
|
+
onFocus: handleMobileFocusOnSentinelItem,
|
|
183
|
+
className: "zen-dropdown-list__sentinel-item"
|
|
160
184
|
})]
|
|
161
|
-
}), [searchField, onInputChange, handleBlur, handleFocus, inputValue, inputRef, inputId, triggerId, disabled, placeholder, translate, handleCheckboxChange, isChecked, checkboxLabel, contentRef, children]);
|
|
185
|
+
}), [handleKeydown, searchField, onInputChange, handleBlur, handleFocus, inputValue, inputRef, inputId, triggerId, disabled, placeholder, translate, handleCheckboxChange, isChecked, checkboxLabel, contentRef, children, handleMobileFocusOnSentinelItem]);
|
|
162
186
|
const memoizedMobileFooter = useMemo(() => {
|
|
163
187
|
if (!isWithFooter) {
|
|
164
188
|
return null;
|
|
165
189
|
}
|
|
166
190
|
return _jsxs(FooterButtons, {
|
|
191
|
+
ref: footerButtonsRef,
|
|
167
192
|
children: [hasApplyButton ? _jsx(Button, {
|
|
168
193
|
onClick: handleApplyClick,
|
|
169
194
|
type: ButtonType.Primary,
|
|
@@ -216,6 +241,7 @@ export const DropdownPopup = ({
|
|
|
216
241
|
recalculateOnScroll: true,
|
|
217
242
|
children: _jsxs("div", {
|
|
218
243
|
ref: contentRef,
|
|
244
|
+
onKeyDown: handleKeydown,
|
|
219
245
|
children: [searchField && isSearchInPopup ? _jsx("div", {
|
|
220
246
|
className: "zen-dropdown-popup__search-container",
|
|
221
247
|
children: _jsx(SearchInput, {
|
|
@@ -227,8 +253,12 @@ export const DropdownPopup = ({
|
|
|
227
253
|
disabled: disabled,
|
|
228
254
|
placeholder: placeholder || translate("Filter by group")
|
|
229
255
|
})
|
|
230
|
-
}) : null, children
|
|
256
|
+
}) : null, children, _jsx("div", {
|
|
257
|
+
tabIndex: 0,
|
|
258
|
+
onFocus: handleFocusOnSentinelItem,
|
|
259
|
+
className: "zen-dropdown-list__sentinel-item"
|
|
260
|
+
})]
|
|
231
261
|
})
|
|
232
|
-
}), [alignment, children, classNamePopup, contentRef, dialogAriaLabel, disabled, handleTriggerClick, inputId, inputRef, inputValue, isOpenCombo, isSearchInPopup, onInputChange, placeholder, popupId, searchField, translate, triggerId, triggerRef]);
|
|
262
|
+
}), [alignment, children, classNamePopup, contentRef, dialogAriaLabel, disabled, handleFocusOnSentinelItem, handleKeydown, handleTriggerClick, inputId, inputRef, inputValue, isOpenCombo, isSearchInPopup, onInputChange, placeholder, popupId, searchField, translate, triggerId, triggerRef]);
|
|
233
263
|
return isMobile ? memoizedMobileView : memoizedDesktopView;
|
|
234
264
|
};
|