@mezzanine-ui/react 1.0.0-alpha.0 → 1.0.0-beta.1
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/Breadcrumb/Breadcrumb.js +40 -12
- package/Breadcrumb/typings.d.ts +8 -3
- package/Drawer/Drawer.d.ts +47 -6
- package/Drawer/Drawer.js +36 -11
- package/Dropdown/Dropdown.d.ts +116 -15
- package/Dropdown/Dropdown.js +235 -32
- package/Dropdown/DropdownAction.d.ts +50 -0
- package/Dropdown/DropdownAction.js +26 -0
- package/Dropdown/DropdownItem.d.ts +60 -0
- package/Dropdown/DropdownItem.js +318 -0
- package/Dropdown/DropdownItemCard.d.ts +96 -0
- package/Dropdown/DropdownItemCard.js +115 -0
- package/Dropdown/DropdownStatus.d.ts +22 -0
- package/Dropdown/dropdownKeydownHandler.d.ts +15 -0
- package/Dropdown/highlightText.d.ts +9 -0
- package/Dropdown/highlightText.js +32 -0
- package/Dropdown/index.d.ts +1 -1
- package/Empty/Empty.js +26 -3
- package/Empty/typings.d.ts +16 -7
- package/Navigation/Navigation.d.ts +11 -17
- package/Navigation/Navigation.js +58 -41
- package/Navigation/NavigationFooter.d.ts +10 -0
- package/Navigation/NavigationFooter.js +26 -0
- package/Navigation/NavigationHeader.d.ts +8 -0
- package/Navigation/NavigationHeader.js +13 -0
- package/Navigation/NavigationIconButton.d.ts +15 -0
- package/Navigation/NavigationIconButton.js +12 -0
- package/Navigation/NavigationOption.d.ts +35 -0
- package/Navigation/NavigationOption.js +60 -0
- package/Navigation/NavigationOptionCategory.d.ts +6 -0
- package/Navigation/NavigationOptionCategory.js +12 -0
- package/Navigation/NavigationUserMenu.d.ts +8 -0
- package/Navigation/NavigationUserMenu.js +18 -0
- package/Navigation/context.d.ts +13 -0
- package/Navigation/context.js +7 -0
- package/Navigation/index.d.ts +12 -6
- package/Navigation/index.js +6 -3
- package/Navigation/useCurrentPathname.d.ts +1 -0
- package/Navigation/useCurrentPathname.js +14 -0
- package/PageHeader/PageHeader.d.ts +5 -1
- package/PageHeader/PageHeader.js +8 -3
- package/PageToolbar/PageToolbar.d.ts +73 -26
- package/PageToolbar/PageToolbar.js +10 -101
- package/PageToolbar/utils.d.ts +23 -0
- package/PageToolbar/utils.js +165 -0
- package/Pagination/PaginationItem.js +1 -3
- package/Pagination/usePagination.js +0 -18
- package/Radio/Radio.d.ts +36 -3
- package/Radio/Radio.js +21 -11
- package/Radio/RadioGroup.d.ts +36 -7
- package/Radio/RadioGroup.js +5 -4
- package/Radio/RadioGroupContext.d.ts +2 -1
- package/Radio/index.d.ts +3 -3
- package/Slider/useSlider.js +1 -1
- package/Tab/Tab.d.ts +32 -0
- package/Tab/Tab.js +57 -0
- package/Tab/TabItem.d.ts +27 -0
- package/Tab/TabItem.js +18 -0
- package/Tab/index.d.ts +4 -0
- package/Tab/index.js +2 -0
- package/Table/Table.d.ts +75 -94
- package/Table/Table.js +216 -161
- package/Table/TableContext.d.ts +114 -51
- package/Table/TableContext.js +21 -3
- package/Table/components/TableBody.d.ts +5 -0
- package/Table/components/TableBody.js +102 -0
- package/Table/components/TableCell.d.ts +17 -0
- package/Table/components/TableCell.js +74 -0
- package/Table/components/TableColGroup.d.ts +4 -0
- package/Table/components/TableColGroup.js +206 -0
- package/Table/components/TableDragHandleCell.d.ts +9 -0
- package/Table/components/TableDragHandleCell.js +37 -0
- package/Table/components/TableExpandCell.d.ts +11 -0
- package/Table/components/TableExpandCell.js +44 -0
- package/Table/components/TableExpandedRow.d.ts +9 -0
- package/Table/components/TableExpandedRow.js +46 -0
- package/Table/components/TableHeader.d.ts +4 -0
- package/Table/components/TableHeader.js +125 -0
- package/Table/components/TablePagination.d.ts +3 -0
- package/Table/components/TablePagination.js +11 -0
- package/Table/components/TableResizeHandle.d.ts +13 -0
- package/Table/components/TableResizeHandle.js +115 -0
- package/Table/components/TableRow.d.ts +12 -0
- package/Table/components/TableRow.js +126 -0
- package/Table/components/TableSelectionCell.d.ts +13 -0
- package/Table/components/TableSelectionCell.js +35 -0
- package/Table/components/index.d.ts +10 -0
- package/Table/components/index.js +10 -0
- package/Table/hooks/index.d.ts +9 -0
- package/Table/hooks/index.js +8 -0
- package/Table/hooks/typings.d.ts +14 -0
- package/Table/hooks/useTableColumns.d.ts +8 -0
- package/Table/hooks/useTableColumns.js +91 -0
- package/Table/hooks/useTableDataSource.d.ts +57 -0
- package/Table/hooks/useTableDataSource.js +183 -0
- package/Table/hooks/useTableExpansion.d.ts +7 -0
- package/Table/hooks/useTableExpansion.js +52 -0
- package/Table/hooks/useTableFixedOffsets.d.ts +29 -0
- package/Table/hooks/useTableFixedOffsets.js +241 -0
- package/Table/hooks/useTableScroll.d.ts +12 -0
- package/Table/hooks/useTableScroll.js +58 -0
- package/Table/hooks/useTableSelection.d.ts +7 -0
- package/Table/hooks/useTableSelection.js +94 -0
- package/Table/hooks/useTableSorting.d.ts +6 -0
- package/Table/hooks/useTableSorting.js +32 -0
- package/Table/hooks/useTableVirtualization.d.ts +22 -0
- package/Table/hooks/useTableVirtualization.js +115 -0
- package/Table/index.d.ts +7 -10
- package/Table/index.js +22 -6
- package/Table/utils/index.d.ts +2 -0
- package/Table/utils/index.js +1 -0
- package/Table/utils/useTableRowSelection.d.ts +18 -0
- package/Table/utils/useTableRowSelection.js +63 -0
- package/_internal/InputCheck/InputCheck.d.ts +15 -1
- package/_internal/InputCheck/InputCheck.js +6 -2
- package/_internal/InputCheck/InputCheckGroup.d.ts +11 -1
- package/_internal/InputCheck/InputCheckGroup.js +4 -2
- package/_internal/SlideFadeOverlay/SlideFadeOverlay.d.ts +1 -1
- package/_internal/SlideFadeOverlay/SlideFadeOverlay.js +1 -1
- package/hooks/useElementHeight.d.ts +8 -0
- package/hooks/useElementHeight.js +41 -0
- package/index.d.ts +9 -7
- package/index.js +6 -11
- package/package.json +6 -4
- package/utils/flatten-children.d.ts +12 -0
- package/utils/flatten-children.js +37 -0
- package/utils/get-css-variable-value.d.ts +1 -0
- package/utils/get-css-variable-value.js +4 -1
- package/Navigation/NavigationContext.d.ts +0 -5
- package/Navigation/NavigationContext.js +0 -8
- package/Navigation/NavigationItem.d.ts +0 -31
- package/Navigation/NavigationItem.js +0 -23
- package/Navigation/NavigationSubMenu.d.ts +0 -22
- package/Navigation/NavigationSubMenu.js +0 -50
- package/Table/TableBody.d.ts +0 -10
- package/Table/TableBody.js +0 -31
- package/Table/TableBodyRow.d.ts +0 -11
- package/Table/TableBodyRow.js +0 -65
- package/Table/TableCell.d.ts +0 -19
- package/Table/TableCell.js +0 -24
- package/Table/TableExpandedTable.d.ts +0 -11
- package/Table/TableExpandedTable.js +0 -29
- package/Table/TableHeader.d.ts +0 -3
- package/Table/TableHeader.js +0 -36
- package/Table/draggable/useTableDraggable.d.ts +0 -14
- package/Table/draggable/useTableDraggable.js +0 -64
- package/Table/editable/TableEditRenderWrapper.d.ts +0 -7
- package/Table/editable/TableEditRenderWrapper.js +0 -16
- package/Table/expandable/TableExpandable.d.ts +0 -27
- package/Table/expandable/TableExpandable.js +0 -24
- package/Table/pagination/TablePagination.d.ts +0 -10
- package/Table/pagination/TablePagination.js +0 -26
- package/Table/pagination/useTablePagination.d.ts +0 -8
- package/Table/pagination/useTablePagination.js +0 -30
- package/Table/refresh/TableRefresh.d.ts +0 -10
- package/Table/refresh/TableRefresh.js +0 -22
- package/Table/rowSelection/TableRowSelection.d.ts +0 -18
- package/Table/rowSelection/TableRowSelection.js +0 -93
- package/Table/rowSelection/useTableRowSelection.d.ts +0 -6
- package/Table/rowSelection/useTableRowSelection.js +0 -53
- package/Table/sorting/TableSortingIcon.d.ts +0 -10
- package/Table/sorting/TableSortingIcon.js +0 -33
- package/Table/sorting/useTableSorting.d.ts +0 -11
- package/Table/sorting/useTableSorting.js +0 -121
- package/Table/useTableFetchMore.d.ts +0 -10
- package/Table/useTableFetchMore.js +0 -50
- package/Table/useTableLoading.d.ts +0 -5
- package/Table/useTableLoading.js +0 -19
- package/Table/useTableScroll.d.ts +0 -592
- package/Table/useTableScroll.js +0 -296
- package/Tabs/Tab.d.ts +0 -18
- package/Tabs/Tab.js +0 -16
- package/Tabs/TabPane.d.ts +0 -14
- package/Tabs/TabPane.js +0 -19
- package/Tabs/Tabs.d.ts +0 -39
- package/Tabs/Tabs.js +0 -52
- package/Tabs/index.d.ts +0 -6
- package/Tabs/index.js +0 -3
- package/Tabs/useTabsOverflow.d.ts +0 -8
- package/Tabs/useTabsOverflow.js +0 -62
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ButtonProps } from "../Button";
|
|
2
|
+
export interface DropdownActionProps {
|
|
3
|
+
/**
|
|
4
|
+
* The text of the custom action button.
|
|
5
|
+
*/
|
|
6
|
+
actionText?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The text of the cancel button.
|
|
9
|
+
*/
|
|
10
|
+
cancelText?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The text of the clear button.
|
|
13
|
+
*/
|
|
14
|
+
clearText?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The text of the confirm button.
|
|
17
|
+
*/
|
|
18
|
+
confirmText?: string;
|
|
19
|
+
/**
|
|
20
|
+
* The custom action button props of the dropdown.
|
|
21
|
+
*/
|
|
22
|
+
customActionButtonProps?: ButtonProps;
|
|
23
|
+
/**
|
|
24
|
+
* Click handler for cancel button.
|
|
25
|
+
*/
|
|
26
|
+
onCancel?: () => void;
|
|
27
|
+
/**
|
|
28
|
+
* Click handler for clear button.
|
|
29
|
+
*/
|
|
30
|
+
onClear?: () => void;
|
|
31
|
+
/**
|
|
32
|
+
* Click handler for confirm button.
|
|
33
|
+
*/
|
|
34
|
+
onConfirm?: () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Click handler for custom action button.
|
|
37
|
+
*/
|
|
38
|
+
onClick?: () => void;
|
|
39
|
+
/**
|
|
40
|
+
* Whether to show the actions.
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
showActions?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* If true, display a bar at the top of the dropdown action area.
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
showTopBar?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export default function DropdownAction(props: DropdownActionProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { dropdownClasses } from '@mezzanine-ui/core/dropdown/dropdown';
|
|
4
|
+
import { CloseIcon } from '@mezzanine-ui/icons';
|
|
5
|
+
import Button from '../Button/Button.js';
|
|
6
|
+
|
|
7
|
+
const actionButtonSize = 'minor';
|
|
8
|
+
function DropdownAction(props) {
|
|
9
|
+
const { showActions = false, showTopBar, customActionButtonProps, cancelText, confirmText, actionText, clearText, onCancel, onConfirm, onClick, onClear, } = props;
|
|
10
|
+
const cancelLabel = cancelText || 'Cancel';
|
|
11
|
+
const confirmLabel = confirmText || 'Confirm';
|
|
12
|
+
const actionLabel = actionText || 'Custom Action';
|
|
13
|
+
const clearLabel = clearText || 'Clear Options';
|
|
14
|
+
const hasAnyEvent = Boolean(onCancel || onConfirm || onClick || onClear);
|
|
15
|
+
const isClearMode = Boolean(onClear && !onClick);
|
|
16
|
+
const isCustomMode = Boolean(onClick && !onClear);
|
|
17
|
+
const isDefaultMode = !isClearMode && !isCustomMode;
|
|
18
|
+
const hasCancel = Boolean(onCancel && isDefaultMode);
|
|
19
|
+
const hasConfirm = Boolean(onConfirm && isDefaultMode);
|
|
20
|
+
return (jsx(Fragment, { children: showActions && hasAnyEvent && (jsxs("div", { className: dropdownClasses.action, children: [showTopBar && jsx("i", { className: dropdownClasses.actionTopBar }), jsxs("div", { className: dropdownClasses.actionTools, children: [hasCancel && (jsx(Button, { variant: "base-ghost", size: actionButtonSize, onClick: onCancel, children: cancelLabel })), hasConfirm && (jsx(Button, { size: actionButtonSize, style: hasCancel ? undefined : { marginLeft: 'auto' }, onClick: onConfirm, children: confirmLabel })), isCustomMode && (jsx(Button, { size: actionButtonSize, variant: "base-ghost", ...customActionButtonProps, onClick: onClick, children: actionLabel })), isClearMode && (jsx(Button, { size: actionButtonSize, variant: "base-ghost", icon: {
|
|
21
|
+
position: 'leading',
|
|
22
|
+
src: CloseIcon,
|
|
23
|
+
}, onClick: onClear, children: clearLabel }))] })] })) }));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { DropdownAction as default };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DropdownItemSharedProps, DropdownOptionsByType, dropdownType } from '@mezzanine-ui/core/dropdown/dropdown';
|
|
3
|
+
import { type DropdownActionProps } from './DropdownAction';
|
|
4
|
+
export interface DropdownItemProps<T extends dropdownType | undefined = dropdownType> extends Omit<DropdownItemSharedProps, 'type'> {
|
|
5
|
+
/**
|
|
6
|
+
* The action configuration for the dropdown.
|
|
7
|
+
*/
|
|
8
|
+
actionConfig?: DropdownActionProps;
|
|
9
|
+
/**
|
|
10
|
+
* The active option index for hover/focus state.
|
|
11
|
+
*/
|
|
12
|
+
activeIndex: number | null;
|
|
13
|
+
/**
|
|
14
|
+
* The text to follow.
|
|
15
|
+
*/
|
|
16
|
+
followText?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Custom content rendered before options (e.g. inline trigger).
|
|
19
|
+
*/
|
|
20
|
+
headerContent?: ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* The listbox id for aria usage.
|
|
23
|
+
*/
|
|
24
|
+
listboxId: string;
|
|
25
|
+
/**
|
|
26
|
+
* The aria-label for the listbox.
|
|
27
|
+
* If not provided, a default label will be used when there are no options.
|
|
28
|
+
*/
|
|
29
|
+
listboxLabel?: string;
|
|
30
|
+
/**
|
|
31
|
+
* The max height of the dropdown list.
|
|
32
|
+
*/
|
|
33
|
+
maxHeight?: number | string;
|
|
34
|
+
/**
|
|
35
|
+
* Whether to set the same width as its anchor element.
|
|
36
|
+
* @default false
|
|
37
|
+
*/
|
|
38
|
+
sameWidth?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Callback when hovering option index changes.
|
|
41
|
+
*/
|
|
42
|
+
onHover?: (index: number) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Options to render.
|
|
45
|
+
* The structure is constrained based on the `type` prop:
|
|
46
|
+
* - 'default': flat array (no children allowed)
|
|
47
|
+
* - 'grouped': array with one level of children (children cannot have children)
|
|
48
|
+
* - 'tree': array with nested children up to 3 levels (strictly enforced at compile time)
|
|
49
|
+
*/
|
|
50
|
+
options: DropdownOptionsByType<T>;
|
|
51
|
+
/**
|
|
52
|
+
* The type of the dropdown.
|
|
53
|
+
* This prop determines the structure of the `options` array:
|
|
54
|
+
* - 'default': flat array (no children allowed)
|
|
55
|
+
* - 'grouped': array with one level of children (children cannot have children)
|
|
56
|
+
* - 'tree': array with nested children up to 3 levels
|
|
57
|
+
*/
|
|
58
|
+
type?: dropdownType;
|
|
59
|
+
}
|
|
60
|
+
export default function DropdownItem<T extends dropdownType | undefined = dropdownType>(props: DropdownItemProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import keycode from 'keycode';
|
|
4
|
+
import { useRef, useState, useCallback, useMemo, useEffect } from 'react';
|
|
5
|
+
import { dropdownClasses } from '@mezzanine-ui/core/dropdown/dropdown';
|
|
6
|
+
import { CaretDownIcon, CaretRightIcon } from '@mezzanine-ui/icons';
|
|
7
|
+
import { useElementHeight } from '../hooks/useElementHeight.js';
|
|
8
|
+
import Typography from '../Typography/Typography.js';
|
|
9
|
+
import DropdownAction from './DropdownAction.js';
|
|
10
|
+
import DropdownItemCard from './DropdownItemCard.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Limits DropdownOption array to a maximum depth, truncating extra children levels and showing error message if exceeded.
|
|
14
|
+
* @param input - The original DropdownOption array
|
|
15
|
+
* @param maxDepth - Maximum depth (default: 3)
|
|
16
|
+
* @param warn - Whether to show warning (default: true)
|
|
17
|
+
* @returns DropdownOption array with at most the specified depth
|
|
18
|
+
*/
|
|
19
|
+
function truncateArrayDepth(input, maxDepth = 3, warn = true) {
|
|
20
|
+
// Internal recursive function: truncates children to specified depth
|
|
21
|
+
const truncate = (options, currentDepth = 1) => {
|
|
22
|
+
if (currentDepth >= maxDepth) {
|
|
23
|
+
// Stop going deeper once maximum depth is reached, remove children
|
|
24
|
+
return options.map(({ children: _children, ...option }) => option);
|
|
25
|
+
}
|
|
26
|
+
return options.map(option => {
|
|
27
|
+
if (!option.children)
|
|
28
|
+
return option;
|
|
29
|
+
return {
|
|
30
|
+
...option,
|
|
31
|
+
children: truncate(option.children, currentDepth + 1),
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
// Calculate maximum depth by checking all elements (not just the first one)
|
|
36
|
+
const getDepth = (options, depth = 1) => {
|
|
37
|
+
if (!options || options.length === 0)
|
|
38
|
+
return depth - 1;
|
|
39
|
+
// Find the maximum depth among all options
|
|
40
|
+
return Math.max(...options.map((option) => {
|
|
41
|
+
if (!option.children || option.children.length === 0) {
|
|
42
|
+
return depth - 1;
|
|
43
|
+
}
|
|
44
|
+
return getDepth(option.children, depth + 1);
|
|
45
|
+
}));
|
|
46
|
+
};
|
|
47
|
+
const depth = getDepth(input);
|
|
48
|
+
if (depth <= maxDepth)
|
|
49
|
+
return input;
|
|
50
|
+
// Exceeds maximum depth → warn
|
|
51
|
+
if (warn) {
|
|
52
|
+
console.error(`[truncateArrayDepth] Input DropdownOption array exceeds ${maxDepth} levels. Extra levels were truncated.`);
|
|
53
|
+
}
|
|
54
|
+
// Truncate to specified depth
|
|
55
|
+
return truncate(input);
|
|
56
|
+
}
|
|
57
|
+
function DropdownItem(props) {
|
|
58
|
+
const { activeIndex, disabled = false, listboxId, listboxLabel, mode = 'single', options, value, type, maxHeight, actionConfig, onHover, onSelect, followText, headerContent, } = props;
|
|
59
|
+
const optionsContent = truncateArrayDepth(options, 3);
|
|
60
|
+
const listRef = useRef(null);
|
|
61
|
+
const [expandedNodes, setExpandedNodes] = useState(new Set());
|
|
62
|
+
const hasActions = Boolean(actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.showActions);
|
|
63
|
+
const hasHeader = Boolean(headerContent);
|
|
64
|
+
// Use custom hook to measure element heights
|
|
65
|
+
const [actionRef, actionHeight] = useElementHeight(hasActions && !!maxHeight);
|
|
66
|
+
const [headerRef, headerHeight] = useElementHeight(hasHeader && !!maxHeight);
|
|
67
|
+
const toggleExpand = useCallback((optionId) => {
|
|
68
|
+
setExpandedNodes((prev) => {
|
|
69
|
+
const next = new Set(prev);
|
|
70
|
+
if (next.has(optionId)) {
|
|
71
|
+
next.delete(optionId);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
next.add(optionId);
|
|
75
|
+
}
|
|
76
|
+
return next;
|
|
77
|
+
});
|
|
78
|
+
}, []);
|
|
79
|
+
const visibleShortcutOptions = useMemo(() => {
|
|
80
|
+
const result = [];
|
|
81
|
+
const collectDefault = (optionList) => {
|
|
82
|
+
optionList === null || optionList === void 0 ? void 0 : optionList.forEach((option) => {
|
|
83
|
+
result.push(option);
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
const collectGrouped = (optionList) => {
|
|
87
|
+
optionList === null || optionList === void 0 ? void 0 : optionList.forEach((groupOption) => {
|
|
88
|
+
var _a;
|
|
89
|
+
(_a = groupOption.children) === null || _a === void 0 ? void 0 : _a.forEach((option) => {
|
|
90
|
+
result.push(option);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
const collectTree = (optionList) => {
|
|
95
|
+
optionList === null || optionList === void 0 ? void 0 : optionList.forEach((option) => {
|
|
96
|
+
result.push(option);
|
|
97
|
+
if (option.children && expandedNodes.has(option.id)) {
|
|
98
|
+
collectTree(option.children);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
if (type === 'grouped') {
|
|
103
|
+
collectGrouped(optionsContent);
|
|
104
|
+
}
|
|
105
|
+
else if (type === 'tree') {
|
|
106
|
+
collectTree(optionsContent);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
collectDefault(optionsContent);
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}, [expandedNodes, optionsContent, type]);
|
|
113
|
+
const matchShortcut = useCallback((event, shortcut) => {
|
|
114
|
+
var _a, _b;
|
|
115
|
+
const eventCode = (_a = event.which) !== null && _a !== void 0 ? _a : event.keyCode;
|
|
116
|
+
if (typeof shortcut === 'number') {
|
|
117
|
+
return eventCode === shortcut;
|
|
118
|
+
}
|
|
119
|
+
const tokens = shortcut
|
|
120
|
+
.split('+')
|
|
121
|
+
.map((token) => token.trim().toLowerCase())
|
|
122
|
+
.filter(Boolean);
|
|
123
|
+
let requireMeta = false;
|
|
124
|
+
let requireCtrl = false;
|
|
125
|
+
let requireAlt = false;
|
|
126
|
+
let requireShift = false;
|
|
127
|
+
let mainToken = null;
|
|
128
|
+
tokens.forEach((token) => {
|
|
129
|
+
switch (token) {
|
|
130
|
+
case 'cmd':
|
|
131
|
+
case 'meta':
|
|
132
|
+
case 'command':
|
|
133
|
+
requireMeta = true;
|
|
134
|
+
break;
|
|
135
|
+
case 'ctrl':
|
|
136
|
+
case 'control':
|
|
137
|
+
requireCtrl = true;
|
|
138
|
+
break;
|
|
139
|
+
case 'alt':
|
|
140
|
+
case 'option':
|
|
141
|
+
requireAlt = true;
|
|
142
|
+
break;
|
|
143
|
+
case 'shift':
|
|
144
|
+
requireShift = true;
|
|
145
|
+
break;
|
|
146
|
+
default:
|
|
147
|
+
mainToken = token;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
if (!mainToken)
|
|
152
|
+
return false;
|
|
153
|
+
if (requireMeta !== event.metaKey
|
|
154
|
+
|| requireCtrl !== event.ctrlKey
|
|
155
|
+
|| requireAlt !== event.altKey
|
|
156
|
+
|| requireShift !== event.shiftKey) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
const mainCode = keycode(mainToken);
|
|
160
|
+
if (typeof mainCode === 'number' && eventCode === mainCode) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
const eventKey = (_b = event.key) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
164
|
+
if (eventKey && eventKey === mainToken) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
const eventKeyName = keycode(eventCode);
|
|
168
|
+
return typeof eventKeyName === 'string' && eventKeyName.toLowerCase() === mainToken;
|
|
169
|
+
}, []);
|
|
170
|
+
const renderGroupedOptions = (optionList, startIndex) => {
|
|
171
|
+
let currentIndex = startIndex;
|
|
172
|
+
const elements = (optionList !== null && optionList !== void 0 ? optionList : []).flatMap((groupOption) => {
|
|
173
|
+
var _a;
|
|
174
|
+
const hasChildren = Boolean(groupOption.children && groupOption.children.length > 0);
|
|
175
|
+
const groupElements = [];
|
|
176
|
+
if (hasChildren) {
|
|
177
|
+
groupElements.push(jsx(Typography, { variant: "body", className: dropdownClasses.groupLabel, children: groupOption.name }, groupOption.id));
|
|
178
|
+
(_a = groupOption.children) === null || _a === void 0 ? void 0 : _a.forEach((option) => {
|
|
179
|
+
var _a, _b;
|
|
180
|
+
currentIndex += 1;
|
|
181
|
+
const optionIndex = currentIndex;
|
|
182
|
+
const isActive = optionIndex === activeIndex;
|
|
183
|
+
const isSelected = Array.isArray(value)
|
|
184
|
+
? value.includes(option.id)
|
|
185
|
+
: value === option.id;
|
|
186
|
+
groupElements.push(jsx(DropdownItemCard, { followText: followText, active: isActive, checked: isSelected, disabled: disabled, id: `${listboxId}-option-${optionIndex}`, label: option.name, mode: mode, name: option.name, onClick: () => {
|
|
187
|
+
if (disabled)
|
|
188
|
+
return;
|
|
189
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
|
|
190
|
+
}, checkSite: "none", validate: (_a = option.validate) !== null && _a !== void 0 ? _a : 'default', onMouseEnter: () => onHover === null || onHover === void 0 ? void 0 : onHover(optionIndex), showUnderline: (_b = option.showUnderline) !== null && _b !== void 0 ? _b : false, appendContent: option.shortcutText }, option.id));
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return groupElements;
|
|
194
|
+
});
|
|
195
|
+
return { elements, nextIndex: currentIndex };
|
|
196
|
+
};
|
|
197
|
+
const renderTreeOptions = (optionList, depth, startIndex) => {
|
|
198
|
+
let currentIndex = startIndex;
|
|
199
|
+
const elements = (optionList !== null && optionList !== void 0 ? optionList : []).flatMap((option) => {
|
|
200
|
+
var _a, _b;
|
|
201
|
+
currentIndex += 1;
|
|
202
|
+
const optionIndex = currentIndex;
|
|
203
|
+
const level = Math.min(depth, 2);
|
|
204
|
+
const isActive = optionIndex === activeIndex;
|
|
205
|
+
const isSelected = Array.isArray(value)
|
|
206
|
+
? value.includes(option.id)
|
|
207
|
+
: value === option.id;
|
|
208
|
+
const hasChildren = Boolean(option.children && option.children.length > 0);
|
|
209
|
+
const isExpanded = hasChildren && expandedNodes.has(option.id);
|
|
210
|
+
let prependIcon = undefined;
|
|
211
|
+
if (hasChildren && level !== 2) {
|
|
212
|
+
prependIcon = isExpanded ? CaretDownIcon : CaretRightIcon;
|
|
213
|
+
}
|
|
214
|
+
const checkSite = option.showCheckbox ? 'prepend' : 'none';
|
|
215
|
+
const card = (jsx(DropdownItemCard, { active: isActive, checked: isSelected, disabled: disabled, id: `${listboxId}-option-${optionIndex}`, label: option.name, level: level, mode: mode, name: option.name, onClick: () => {
|
|
216
|
+
if (disabled)
|
|
217
|
+
return;
|
|
218
|
+
if (hasChildren && type === 'tree') {
|
|
219
|
+
toggleExpand(option.id);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
|
|
223
|
+
}
|
|
224
|
+
}, followText: followText, checkSite: checkSite, onMouseEnter: () => onHover === null || onHover === void 0 ? void 0 : onHover(optionIndex), prependIcon: prependIcon, showUnderline: (_a = option.showUnderline) !== null && _a !== void 0 ? _a : false, validate: (_b = option.validate) !== null && _b !== void 0 ? _b : 'default', appendContent: option.shortcutText }, option.id));
|
|
225
|
+
if (hasChildren && isExpanded && type === 'tree') {
|
|
226
|
+
const childResult = renderTreeOptions(option.children, depth + 1, currentIndex);
|
|
227
|
+
currentIndex = childResult.nextIndex;
|
|
228
|
+
return [card, ...childResult.elements];
|
|
229
|
+
}
|
|
230
|
+
return [card];
|
|
231
|
+
});
|
|
232
|
+
return { elements, nextIndex: currentIndex };
|
|
233
|
+
};
|
|
234
|
+
const renderDefaultOptions = (optionList, startIndex) => {
|
|
235
|
+
let currentIndex = startIndex;
|
|
236
|
+
const elements = (optionList !== null && optionList !== void 0 ? optionList : []).flatMap((option) => {
|
|
237
|
+
var _a, _b;
|
|
238
|
+
currentIndex += 1;
|
|
239
|
+
const optionIndex = currentIndex;
|
|
240
|
+
const isSelected = Array.isArray(value)
|
|
241
|
+
? value.includes(option.id)
|
|
242
|
+
: value === option.id;
|
|
243
|
+
const isActive = optionIndex === activeIndex;
|
|
244
|
+
let checkSite = 'none';
|
|
245
|
+
if (option === null || option === void 0 ? void 0 : option.checkSite) {
|
|
246
|
+
checkSite = option.checkSite;
|
|
247
|
+
}
|
|
248
|
+
return (jsx(DropdownItemCard, { followText: followText, active: isActive, checked: isSelected, disabled: disabled, id: `${listboxId}-option-${optionIndex}`, label: option.name, mode: mode, name: option.name, onClick: () => {
|
|
249
|
+
if (disabled)
|
|
250
|
+
return;
|
|
251
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
|
|
252
|
+
}, onMouseEnter: () => onHover === null || onHover === void 0 ? void 0 : onHover(optionIndex), prependIcon: option.icon, validate: (_a = option.validate) !== null && _a !== void 0 ? _a : 'default', showUnderline: (_b = option.showUnderline) !== null && _b !== void 0 ? _b : false, checkSite: checkSite, appendContent: option.shortcutText }, option.id));
|
|
253
|
+
});
|
|
254
|
+
return { elements, nextIndex: currentIndex };
|
|
255
|
+
};
|
|
256
|
+
const renderOptions = (optionList, depth, startIndex) => {
|
|
257
|
+
if (type === 'grouped') {
|
|
258
|
+
return renderGroupedOptions(optionList, startIndex);
|
|
259
|
+
}
|
|
260
|
+
if (type === 'tree') {
|
|
261
|
+
return renderTreeOptions(optionList, depth, startIndex);
|
|
262
|
+
}
|
|
263
|
+
return renderDefaultOptions(optionList, startIndex);
|
|
264
|
+
};
|
|
265
|
+
const { elements: renderedOptions } = renderOptions(optionsContent, 0, -1);
|
|
266
|
+
const listStyle = useMemo(() => {
|
|
267
|
+
if (!maxHeight) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight,
|
|
272
|
+
};
|
|
273
|
+
}, [maxHeight]);
|
|
274
|
+
const listWrapperStyle = useMemo(() => {
|
|
275
|
+
if (!maxHeight) {
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
const maxHeightValue = typeof maxHeight === 'number' ? maxHeight : parseFloat(maxHeight);
|
|
279
|
+
const availableHeight = Math.max(0, maxHeightValue - actionHeight - headerHeight);
|
|
280
|
+
return {
|
|
281
|
+
maxHeight: `${availableHeight}px`,
|
|
282
|
+
};
|
|
283
|
+
}, [maxHeight, actionHeight, headerHeight]);
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
const listElement = listRef.current;
|
|
286
|
+
if (!listElement || disabled) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const handleKeyDown = (event) => {
|
|
290
|
+
if (event.repeat)
|
|
291
|
+
return;
|
|
292
|
+
const targetOption = visibleShortcutOptions.find((option) => {
|
|
293
|
+
if (!Array.isArray(option.shortcutKeys) || option.shortcutKeys.length === 0) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
return option.shortcutKeys.some((shortcut) => matchShortcut(event, shortcut));
|
|
297
|
+
});
|
|
298
|
+
if (!targetOption)
|
|
299
|
+
return;
|
|
300
|
+
event.preventDefault();
|
|
301
|
+
event.stopPropagation();
|
|
302
|
+
if (type === 'tree' && targetOption.children && targetOption.children.length > 0) {
|
|
303
|
+
toggleExpand(targetOption.id);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(targetOption);
|
|
307
|
+
};
|
|
308
|
+
listElement.addEventListener('keydown', handleKeyDown);
|
|
309
|
+
return () => {
|
|
310
|
+
listElement.removeEventListener('keydown', handleKeyDown);
|
|
311
|
+
};
|
|
312
|
+
}, [disabled, matchShortcut, onSelect, type, toggleExpand, visibleShortcutOptions]);
|
|
313
|
+
return (jsxs("ul", { "aria-label": listboxLabel || (optionsContent.length === 0 ? 'Dropdown options' : undefined), className: dropdownClasses.list, id: listboxId, ref: listRef, role: "listbox", style: listStyle, tabIndex: -1, children: [hasHeader && (jsx("li", { className: dropdownClasses.listHeader, role: "presentation", ref: headerRef, children: jsx("div", { className: dropdownClasses.listHeaderInner, children: headerContent }) })), maxHeight
|
|
314
|
+
? (jsx("div", { className: dropdownClasses.listWrapper, style: listWrapperStyle, children: renderedOptions }))
|
|
315
|
+
: renderedOptions, hasActions && (jsx("div", { ref: actionRef, children: jsx(DropdownAction, { ...actionConfig }) }))] }));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export { DropdownItem as default };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { dropdownCheckPosition, dropdownItemLevel, dropdownItemValidate, dropdownMode } from "@mezzanine-ui/core/dropdown/dropdown";
|
|
2
|
+
import { type IconDefinition } from "@mezzanine-ui/icons";
|
|
3
|
+
export interface DropdownItemCardProps {
|
|
4
|
+
/**
|
|
5
|
+
* Whether the option is currently active (highlighted by keyboard navigation).
|
|
6
|
+
* This controls the aria-selected attribute according to W3C ARIA spec.
|
|
7
|
+
* When an option is referenced by aria-activedescendant, it should have aria-selected="true".
|
|
8
|
+
*/
|
|
9
|
+
active?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* The icon to append.
|
|
12
|
+
*/
|
|
13
|
+
appendIcon?: IconDefinition;
|
|
14
|
+
/**
|
|
15
|
+
* The content to append.
|
|
16
|
+
*/
|
|
17
|
+
appendContent?: string;
|
|
18
|
+
/**
|
|
19
|
+
* The position of the checkbox.
|
|
20
|
+
*/
|
|
21
|
+
checkSite?: dropdownCheckPosition;
|
|
22
|
+
/**
|
|
23
|
+
* Controlled: Whether the option is selected/checked.
|
|
24
|
+
* Controls checkbox state in multiple mode.
|
|
25
|
+
* When provided, the state is controlled externally.
|
|
26
|
+
*/
|
|
27
|
+
checked?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Additional className for the list item.
|
|
30
|
+
*/
|
|
31
|
+
className?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Uncontrolled: Default checked/selected state.
|
|
34
|
+
* Only used when `checked` is not provided.
|
|
35
|
+
*/
|
|
36
|
+
defaultChecked?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Whether the dropdown item card is disabled.
|
|
39
|
+
*/
|
|
40
|
+
disabled?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The text to follow.
|
|
43
|
+
*/
|
|
44
|
+
followText?: string;
|
|
45
|
+
/**
|
|
46
|
+
* DOM id for the option, useful for aria-activedescendant.
|
|
47
|
+
*/
|
|
48
|
+
id?: string;
|
|
49
|
+
/**
|
|
50
|
+
* The label of the dropdown item card.
|
|
51
|
+
*/
|
|
52
|
+
label?: string;
|
|
53
|
+
/**
|
|
54
|
+
* The level of the dropdown item card.
|
|
55
|
+
*/
|
|
56
|
+
level?: dropdownItemLevel;
|
|
57
|
+
/**
|
|
58
|
+
* The mode of the dropdown item card.
|
|
59
|
+
*/
|
|
60
|
+
mode: dropdownMode;
|
|
61
|
+
/**
|
|
62
|
+
* The accessible name / label for the option.
|
|
63
|
+
* Falls back to label if not provided.
|
|
64
|
+
*/
|
|
65
|
+
name?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Callback fired when the checked/selected state changes.
|
|
68
|
+
*/
|
|
69
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Click handler when the list item is activated.
|
|
72
|
+
*/
|
|
73
|
+
onClick?: () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Mouse enter handler.
|
|
76
|
+
*/
|
|
77
|
+
onMouseEnter?: () => void;
|
|
78
|
+
/**
|
|
79
|
+
* The icon to prepend.
|
|
80
|
+
*/
|
|
81
|
+
prependIcon?: IconDefinition;
|
|
82
|
+
/**
|
|
83
|
+
* Whether to show the underline.
|
|
84
|
+
* @default false
|
|
85
|
+
*/
|
|
86
|
+
showUnderline?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* The subtitle of the dropdown item card.
|
|
89
|
+
*/
|
|
90
|
+
subTitle?: string;
|
|
91
|
+
/**
|
|
92
|
+
* The validation of the dropdown item card.
|
|
93
|
+
*/
|
|
94
|
+
validate?: dropdownItemValidate;
|
|
95
|
+
}
|
|
96
|
+
export default function DropdownItemCard(props: DropdownItemCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import cx from 'clsx';
|
|
4
|
+
import { useMemo, useState } from 'react';
|
|
5
|
+
import { dropdownClasses } from '@mezzanine-ui/core/dropdown/dropdown';
|
|
6
|
+
import { CheckedIcon } from '@mezzanine-ui/icons';
|
|
7
|
+
import Checkbox from '../Checkbox/Checkbox.js';
|
|
8
|
+
import Typography from '../Typography/Typography.js';
|
|
9
|
+
import { highlightText } from './highlightText.js';
|
|
10
|
+
import Icon from '../Icon/Icon.js';
|
|
11
|
+
|
|
12
|
+
function DropdownItemCard(props) {
|
|
13
|
+
const { active = false, appendIcon, appendContent, followText, id, label, level: levelProp, mode, name: _name, prependIcon, subTitle, validate, disabled, checked, defaultChecked, checkSite, onCheckedChange, onClick, className, onMouseEnter, showUnderline, } = props;
|
|
14
|
+
const cardLabel = label || '';
|
|
15
|
+
const cardName = _name || cardLabel;
|
|
16
|
+
const level = levelProp || 0;
|
|
17
|
+
// Generate ID for the label element to use with aria-labelledby
|
|
18
|
+
// If no id is provided, we'll rely on the visible text content for accessibility
|
|
19
|
+
const labelId = useMemo(() => {
|
|
20
|
+
if (!id)
|
|
21
|
+
return undefined;
|
|
22
|
+
return `${id}-label`;
|
|
23
|
+
}, [id]);
|
|
24
|
+
// If name is different from label, we need to use aria-label as fallback
|
|
25
|
+
// Note: aria-label on role="option" has limited support, but it's better than nothing
|
|
26
|
+
const ariaLabel = useMemo(() => {
|
|
27
|
+
if (cardName !== cardLabel) {
|
|
28
|
+
return cardName;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}, [cardName, cardLabel]);
|
|
32
|
+
// Controlled/uncontrolled mode for checked/selected state
|
|
33
|
+
const isControlled = checked !== undefined;
|
|
34
|
+
const [internalChecked, setInternalChecked] = useState(defaultChecked !== null && defaultChecked !== void 0 ? defaultChecked : false);
|
|
35
|
+
const isChecked = isControlled ? checked : internalChecked;
|
|
36
|
+
const labelColor = useMemo(() => {
|
|
37
|
+
return validate === 'danger' ? 'text-error' : 'text-neutral-solid';
|
|
38
|
+
}, [validate]);
|
|
39
|
+
const appendIconColor = useMemo(() => {
|
|
40
|
+
return disabled || validate === 'danger' ? 'neutral-light' : 'neutral';
|
|
41
|
+
}, [disabled, validate]);
|
|
42
|
+
const iconColor = useMemo(() => {
|
|
43
|
+
if (disabled)
|
|
44
|
+
return 'neutral-light';
|
|
45
|
+
return validate === 'danger' ? 'error' : 'neutral';
|
|
46
|
+
}, [disabled, validate]);
|
|
47
|
+
const labelParts = useMemo(() => {
|
|
48
|
+
return followText
|
|
49
|
+
? highlightText(cardLabel, followText)
|
|
50
|
+
: [
|
|
51
|
+
{
|
|
52
|
+
text: cardLabel,
|
|
53
|
+
highlight: false
|
|
54
|
+
}
|
|
55
|
+
];
|
|
56
|
+
}, [cardLabel, followText]);
|
|
57
|
+
const showPrependContent = useMemo(() => {
|
|
58
|
+
return prependIcon || (checkSite === 'prepend' && mode === 'multiple');
|
|
59
|
+
}, [prependIcon, checkSite, mode]);
|
|
60
|
+
const showAppendContent = useMemo(() => {
|
|
61
|
+
return appendContent || appendIcon || (checkSite === 'append' && isChecked);
|
|
62
|
+
}, [appendContent, appendIcon, checkSite, isChecked]);
|
|
63
|
+
const subTitleParts = useMemo(() => {
|
|
64
|
+
return followText && subTitle
|
|
65
|
+
? highlightText(subTitle, followText)
|
|
66
|
+
: subTitle
|
|
67
|
+
? [
|
|
68
|
+
{
|
|
69
|
+
text: subTitle,
|
|
70
|
+
highlight: false
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
: [];
|
|
74
|
+
}, [subTitle, followText]);
|
|
75
|
+
const renderHighlightedText = (parts, defaultColor, className, id) => {
|
|
76
|
+
return (jsx(Typography, { color: defaultColor, className: className, id: id, children: parts.map((part, index) => (jsx("span", { className: part.highlight && validate !== 'danger' ? dropdownClasses.cardHighlightedText : '', children: part.text }, index))) }));
|
|
77
|
+
};
|
|
78
|
+
const toggleChecked = () => {
|
|
79
|
+
if (disabled)
|
|
80
|
+
return;
|
|
81
|
+
const newChecked = !isChecked;
|
|
82
|
+
if (!isControlled) {
|
|
83
|
+
setInternalChecked(newChecked);
|
|
84
|
+
}
|
|
85
|
+
onCheckedChange === null || onCheckedChange === void 0 ? void 0 : onCheckedChange(newChecked);
|
|
86
|
+
};
|
|
87
|
+
const handleClick = () => {
|
|
88
|
+
if (disabled)
|
|
89
|
+
return;
|
|
90
|
+
if (mode === 'multiple') {
|
|
91
|
+
toggleChecked();
|
|
92
|
+
}
|
|
93
|
+
onClick === null || onClick === void 0 ? void 0 : onClick();
|
|
94
|
+
};
|
|
95
|
+
const handleCheckboxChange = (event) => {
|
|
96
|
+
event.stopPropagation();
|
|
97
|
+
toggleChecked();
|
|
98
|
+
};
|
|
99
|
+
const handleKeyDown = (event) => {
|
|
100
|
+
if (disabled)
|
|
101
|
+
return;
|
|
102
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
onClick === null || onClick === void 0 ? void 0 : onClick();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
return (jsxs(Fragment, { children: [jsx("li", { ...(labelId ? { 'aria-labelledby': labelId } : {}), ...(ariaLabel ? { 'aria-label': ariaLabel } : {}), "aria-selected": active, className: cx(dropdownClasses.card, dropdownClasses.cardLevel(level), {
|
|
108
|
+
// Highlight: keyboard/mouse focused (active) or selected (isChecked)
|
|
109
|
+
[dropdownClasses.cardActive]: active || isChecked,
|
|
110
|
+
[dropdownClasses.cardDisabled]: disabled,
|
|
111
|
+
}, className), id: id, role: "option", tabIndex: -1, onMouseEnter: onMouseEnter, onClick: handleClick, onKeyDown: handleKeyDown, children: jsxs("div", { className: dropdownClasses.cardContainer, children: [showPrependContent && (jsxs("div", { className: dropdownClasses.cardPrependContent, children: [prependIcon
|
|
112
|
+
&& jsx(Icon, { icon: prependIcon, color: iconColor }), checkSite === 'prepend' && mode === 'multiple' && (jsx(Checkbox, { checked: isChecked, disabled: disabled, onChange: handleCheckboxChange }))] })), jsxs("div", { className: dropdownClasses.cardBody, children: [cardLabel && renderHighlightedText(labelParts, labelColor, dropdownClasses.cardTitle, labelId), subTitleParts.length > 0 && renderHighlightedText(subTitleParts, 'text-neutral', dropdownClasses.cardDescription)] }), showAppendContent && (jsxs("div", { className: dropdownClasses.cardAppendContent, children: [appendContent && jsx(Typography, { color: "text-neutral-light", children: appendContent }), appendIcon && jsx(Icon, { icon: appendIcon, color: iconColor }), checkSite === 'append' && isChecked && jsx(Icon, { icon: CheckedIcon, color: appendIconColor, size: 16 })] }))] }) }), showUnderline && jsx("div", { className: dropdownClasses.cardUnderline })] }));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { DropdownItemCard as default };
|