@mezzanine-ui/react 1.0.0-beta.5 → 1.0.0-beta.7
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/Accordion/Accordion.d.ts +23 -1
- package/Accordion/Accordion.js +59 -11
- package/Accordion/AccordionActions.d.ts +13 -0
- package/Accordion/AccordionActions.js +24 -0
- package/Accordion/AccordionContent.d.ts +9 -0
- package/Accordion/{AccordionDetails.js → AccordionContent.js} +4 -6
- package/Accordion/AccordionControlContext.d.ts +2 -2
- package/Accordion/AccordionGroup.d.ts +10 -0
- package/Accordion/AccordionGroup.js +26 -0
- package/Accordion/AccordionTitle.d.ts +14 -0
- package/Accordion/AccordionTitle.js +56 -0
- package/Accordion/index.d.ts +8 -4
- package/Accordion/index.js +4 -2
- package/AutoComplete/AutoComplete.d.ts +25 -6
- package/AutoComplete/AutoComplete.js +119 -30
- package/Backdrop/Backdrop.js +15 -19
- package/Breadcrumb/BreadcrumbDropdown.js +1 -1
- package/Breadcrumb/BreadcrumbItem.js +1 -1
- package/Breadcrumb/BreadcrumbOverflowMenuItem.js +1 -1
- package/Calendar/CalendarDays.js +1 -1
- package/Card/BaseCard.d.ts +11 -0
- package/Card/BaseCard.js +48 -0
- package/Card/BaseCardSkeleton.d.ts +14 -0
- package/Card/BaseCardSkeleton.js +18 -0
- package/Card/CardGroup.d.ts +47 -0
- package/Card/CardGroup.js +147 -0
- package/Card/FourThumbnailCard.d.ts +14 -0
- package/Card/FourThumbnailCard.js +73 -0
- package/Card/FourThumbnailCardSkeleton.d.ts +14 -0
- package/Card/FourThumbnailCardSkeleton.js +20 -0
- package/Card/QuickActionCard.d.ts +12 -0
- package/Card/QuickActionCard.js +23 -0
- package/Card/QuickActionCardSkeleton.d.ts +14 -0
- package/Card/QuickActionCardSkeleton.js +18 -0
- package/Card/SingleThumbnailCard.d.ts +13 -0
- package/Card/SingleThumbnailCard.js +44 -0
- package/Card/SingleThumbnailCardSkeleton.d.ts +19 -0
- package/Card/SingleThumbnailCardSkeleton.js +18 -0
- package/Card/Thumbnail.d.ts +12 -0
- package/Card/Thumbnail.js +18 -0
- package/Card/ThumbnailCardInfo.d.ts +34 -0
- package/Card/ThumbnailCardInfo.js +43 -0
- package/Card/index.d.ts +43 -4
- package/Card/index.js +19 -2
- package/Card/typings.d.ts +442 -0
- package/Checkbox/Checkbox.d.ts +8 -0
- package/Checkbox/Checkbox.js +3 -2
- package/Checkbox/CheckboxGroup.js +1 -1
- package/ContentHeader/ContentHeader.d.ts +22 -70
- package/ContentHeader/ContentHeader.js +1 -1
- package/ContentHeader/ContentHeaderResponsive.d.ts +9 -0
- package/ContentHeader/ContentHeaderResponsive.js +7 -0
- package/ContentHeader/utils.d.ts +3 -3
- package/ContentHeader/utils.js +66 -20
- package/Cropper/Cropper.d.ts +66 -0
- package/Cropper/Cropper.js +115 -0
- package/Cropper/CropperElement.d.ts +10 -0
- package/Cropper/CropperElement.js +892 -0
- package/Cropper/index.d.ts +18 -0
- package/Cropper/index.js +8 -0
- package/Cropper/tools.d.ts +90 -0
- package/Cropper/tools.js +143 -0
- package/Cropper/typings.d.ts +69 -0
- package/Cropper/utils/cropper-calculations.d.ts +39 -0
- package/Cropper/utils/cropper-calculations.js +95 -0
- package/DateTimePicker/DateTimePicker.d.ts +1 -1
- package/DateTimePicker/DateTimePicker.js +22 -5
- package/DateTimeRangePicker/DateTimeRangePicker.d.ts +34 -0
- package/DateTimeRangePicker/DateTimeRangePicker.js +118 -0
- package/DateTimeRangePicker/index.d.ts +2 -0
- package/DateTimeRangePicker/index.js +1 -0
- package/Drawer/Drawer.d.ts +132 -1
- package/Drawer/Drawer.js +47 -3
- package/Dropdown/Dropdown.d.ts +10 -4
- package/Dropdown/Dropdown.js +37 -42
- package/Dropdown/DropdownItem.d.ts +7 -1
- package/Dropdown/DropdownItem.js +36 -6
- package/Dropdown/DropdownItemCard.js +2 -1
- package/FloatingButton/FloatingButton.d.ts +21 -0
- package/FloatingButton/FloatingButton.js +18 -0
- package/FloatingButton/index.d.ts +2 -0
- package/FloatingButton/index.js +1 -0
- package/Form/FormField.d.ts +30 -7
- package/Form/FormField.js +12 -4
- package/Input/Input.js +12 -21
- package/Input/SelectButton/SelectButton.d.ts +25 -4
- package/Input/SelectButton/SelectButton.js +21 -9
- package/Message/Message.js +1 -1
- package/Modal/MediaPreviewModal.d.ts +11 -0
- package/Modal/MediaPreviewModal.js +24 -7
- package/Modal/Modal.d.ts +1 -1
- package/Modal/Modal.js +1 -1
- package/Modal/useModalContainer.js +6 -2
- package/MultipleDatePicker/MultipleDatePicker.d.ts +62 -0
- package/MultipleDatePicker/MultipleDatePicker.js +176 -0
- package/MultipleDatePicker/MultipleDatePickerTrigger.d.ts +56 -0
- package/MultipleDatePicker/MultipleDatePickerTrigger.js +92 -0
- package/MultipleDatePicker/index.d.ts +6 -0
- package/MultipleDatePicker/index.js +3 -0
- package/MultipleDatePicker/useMultipleDatePickerValue.d.ts +55 -0
- package/MultipleDatePicker/useMultipleDatePickerValue.js +68 -0
- package/Navigation/NavigationHeader.js +1 -1
- package/NotificationCenter/NotificationCenterDrawer.d.ts +10 -52
- package/NotificationCenter/NotificationCenterDrawer.js +128 -0
- package/NotificationCenter/index.d.ts +2 -0
- package/NotificationCenter/index.js +1 -0
- package/OverflowTooltip/index.d.ts +2 -2
- package/Picker/FormattedInput.d.ts +1 -1
- package/Picker/FormattedInput.js +2 -1
- package/Picker/PickerTriggerWithSeparator.d.ts +10 -0
- package/Picker/PickerTriggerWithSeparator.js +2 -2
- package/Picker/RangePickerTrigger.js +1 -1
- package/Picker/useDateInputFormatter.d.ts +6 -0
- package/Picker/useDateInputFormatter.js +4 -1
- package/Section/Section.d.ts +32 -0
- package/Section/Section.js +62 -0
- package/Section/index.d.ts +2 -0
- package/Select/Select.d.ts +11 -12
- package/Select/Select.js +13 -34
- package/Select/SelectTrigger.js +21 -7
- package/Select/index.d.ts +0 -4
- package/Select/index.js +0 -2
- package/Select/typings.d.ts +0 -4
- package/Select/useSelectTriggerTags.d.ts +1 -1
- package/Select/useSelectTriggerTags.js +9 -6
- package/Separator/Separator.d.ts +14 -0
- package/Separator/Separator.js +17 -0
- package/Separator/index.d.ts +2 -0
- package/Separator/index.js +1 -0
- package/Table/utils/useTableRowSelection.js +6 -0
- package/Tag/TagGroup.d.ts +4 -2
- package/Tag/TagGroup.js +7 -4
- package/TextField/TextField.d.ts +1 -1
- package/TextField/TextField.js +63 -9
- package/TimePanel/TimePanelColumn.js +30 -21
- package/TimeRangePicker/TimeRangePicker.d.ts +29 -0
- package/TimeRangePicker/TimeRangePicker.js +96 -0
- package/TimeRangePicker/index.d.ts +3 -0
- package/TimeRangePicker/index.js +2 -0
- package/TimeRangePicker/useTimeRangePickerValue.d.ts +30 -0
- package/TimeRangePicker/useTimeRangePickerValue.js +92 -0
- package/Transition/Rotate.js +2 -5
- package/index.d.ts +30 -28
- package/index.js +26 -27
- package/package.json +4 -4
- package/Accordion/AccordionDetails.d.ts +0 -9
- package/Accordion/AccordionSummary.d.ts +0 -18
- package/Accordion/AccordionSummary.js +0 -51
- package/Alert/Alert.d.ts +0 -20
- package/Alert/Alert.js +0 -18
- package/Alert/index.d.ts +0 -3
- package/Alert/index.js +0 -1
- package/AppBar/AppBar.d.ts +0 -14
- package/AppBar/AppBar.js +0 -33
- package/AppBar/AppBarBrand.d.ts +0 -4
- package/AppBar/AppBarBrand.js +0 -11
- package/AppBar/AppBarMain.d.ts +0 -4
- package/AppBar/AppBarMain.js +0 -11
- package/AppBar/AppBarSupport.d.ts +0 -4
- package/AppBar/AppBarSupport.js +0 -11
- package/AppBar/index.d.ts +0 -8
- package/AppBar/index.js +0 -4
- package/Card/Card.d.ts +0 -51
- package/Card/Card.js +0 -20
- package/Card/CardActions.d.ts +0 -34
- package/Card/CardActions.js +0 -15
- package/ConfirmActions/ConfirmActions.d.ts +0 -46
- package/ConfirmActions/ConfirmActions.js +0 -15
- package/ConfirmActions/index.d.ts +0 -2
- package/ConfirmActions/index.js +0 -1
- package/Popconfirm/Popconfirm.d.ts +0 -16
- package/Popconfirm/Popconfirm.js +0 -15
- package/Popconfirm/index.d.ts +0 -2
- package/Popconfirm/index.js +0 -1
- package/Popover/Popover.d.ts +0 -23
- package/Popover/Popover.js +0 -35
- package/Popover/index.d.ts +0 -2
- package/Popover/index.js +0 -1
- package/Select/Option.d.ts +0 -18
- package/Select/Option.js +0 -45
- package/Select/TreeSelect.d.ts +0 -67
- package/Select/TreeSelect.js +0 -198
- package/Tree/Tree.d.ts +0 -70
- package/Tree/Tree.js +0 -139
- package/Tree/TreeNode.d.ts +0 -40
- package/Tree/TreeNode.js +0 -50
- package/Tree/TreeNodeList.d.ts +0 -24
- package/Tree/TreeNodeList.js +0 -28
- package/Tree/getTreeNodeEntities.d.ts +0 -11
- package/Tree/getTreeNodeEntities.js +0 -92
- package/Tree/index.d.ts +0 -13
- package/Tree/index.js +0 -7
- package/Tree/toggleValue.d.ts +0 -4
- package/Tree/toggleValue.js +0 -19
- package/Tree/traverseTree.d.ts +0 -2
- package/Tree/traverseTree.js +0 -11
- package/Tree/typings.d.ts +0 -16
- package/Tree/useTreeExpandedValue.d.ts +0 -14
- package/Tree/useTreeExpandedValue.js +0 -33
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { notificationClasses } from '@mezzanine-ui/core/notification-center';
|
|
5
|
+
import { NotificationIcon } from '@mezzanine-ui/icons';
|
|
6
|
+
import Typography from '../Typography/Typography.js';
|
|
7
|
+
import NotificationCenter from './NotificationCenter.js';
|
|
8
|
+
import Drawer from '../Drawer/Drawer.js';
|
|
9
|
+
import Icon from '../Icon/Icon.js';
|
|
10
|
+
|
|
11
|
+
const isValidTime = (timestamp) => {
|
|
12
|
+
if (!timestamp)
|
|
13
|
+
return false;
|
|
14
|
+
const date = new Date(timestamp);
|
|
15
|
+
return !Number.isNaN(date.getTime());
|
|
16
|
+
};
|
|
17
|
+
const getValidTime = (timestamp) => {
|
|
18
|
+
if (!isValidTime(timestamp))
|
|
19
|
+
return 0;
|
|
20
|
+
const date = new Date(timestamp);
|
|
21
|
+
return date.getTime();
|
|
22
|
+
};
|
|
23
|
+
const DEFAULT_TIME_GROUP_LABELS = {
|
|
24
|
+
today: '今天',
|
|
25
|
+
yesterday: '昨天',
|
|
26
|
+
past7Days: '過去七天',
|
|
27
|
+
earlier: '更早',
|
|
28
|
+
};
|
|
29
|
+
const TIME_GROUP_ORDER = [
|
|
30
|
+
'today',
|
|
31
|
+
'yesterday',
|
|
32
|
+
'past7Days',
|
|
33
|
+
'earlier',
|
|
34
|
+
];
|
|
35
|
+
const getTimeGroup = (timestamp, now) => {
|
|
36
|
+
if (!isValidTime(timestamp))
|
|
37
|
+
return 'earlier';
|
|
38
|
+
const notificationDate = new Date(timestamp);
|
|
39
|
+
const nowStartOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
40
|
+
const notificationStartOfDay = new Date(notificationDate.getFullYear(), notificationDate.getMonth(), notificationDate.getDate());
|
|
41
|
+
// Today: same calendar day
|
|
42
|
+
if (notificationStartOfDay.getTime() === nowStartOfDay.getTime()) {
|
|
43
|
+
return 'today';
|
|
44
|
+
}
|
|
45
|
+
// Yesterday: previous calendar day
|
|
46
|
+
const yesterdayStartOfDay = new Date(nowStartOfDay);
|
|
47
|
+
yesterdayStartOfDay.setDate(yesterdayStartOfDay.getDate() - 1);
|
|
48
|
+
if (notificationStartOfDay.getTime() === yesterdayStartOfDay.getTime()) {
|
|
49
|
+
return 'yesterday';
|
|
50
|
+
}
|
|
51
|
+
// Past 7 days: within 7 days but not today or yesterday
|
|
52
|
+
const diffInDays = (now.getTime() - notificationDate.getTime()) / (1000 * 60 * 60 * 24);
|
|
53
|
+
if (diffInDays <= 7) {
|
|
54
|
+
return 'past7Days';
|
|
55
|
+
}
|
|
56
|
+
// Earlier: more than 7 days ago
|
|
57
|
+
return 'earlier';
|
|
58
|
+
};
|
|
59
|
+
const NotificationCenterDrawer = (props) => {
|
|
60
|
+
const { children, controlBarAllRadioLabel, controlBarCustomButtonLabel, controlBarDefaultValue, controlBarOnCustomButtonClick, controlBarOnRadioChange, controlBarReadRadioLabel, controlBarShow, controlBarShowUnreadButton, controlBarUnreadRadioLabel, controlBarValue, drawerSize = 'narrow', earlierLabel, emptyNotificationIcon = NotificationIcon, emptyNotificationTitle = '目前沒有新的通知', notificationList, onClose, open, past7DaysLabel, renderControlBar, title, todayLabel, yesterdayLabel, ...restDrawerProps } = props;
|
|
61
|
+
const isEmpty = useMemo(() => {
|
|
62
|
+
if (notificationList) {
|
|
63
|
+
return notificationList.length === 0;
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(children)) {
|
|
66
|
+
return children.length === 0;
|
|
67
|
+
}
|
|
68
|
+
return !children;
|
|
69
|
+
}, [notificationList, children]);
|
|
70
|
+
const renderNotifications = useMemo(() => {
|
|
71
|
+
const renderEmptyNotifications = () => {
|
|
72
|
+
return (jsxs("div", { className: notificationClasses.emptyNotifications, children: [jsx(Icon, { icon: emptyNotificationIcon, size: 28 }), jsx(Typography, { children: emptyNotificationTitle })] }));
|
|
73
|
+
};
|
|
74
|
+
if (isEmpty) {
|
|
75
|
+
return renderEmptyNotifications();
|
|
76
|
+
}
|
|
77
|
+
// Check if notificationList is provided
|
|
78
|
+
if (notificationList) {
|
|
79
|
+
// Sort once by timestamp (newest first), then group while maintaining order
|
|
80
|
+
const sorted = [...notificationList].sort((a, b) => {
|
|
81
|
+
const aTime = getValidTime(a.timeStamp);
|
|
82
|
+
const bTime = getValidTime(b.timeStamp);
|
|
83
|
+
return bTime - aTime;
|
|
84
|
+
});
|
|
85
|
+
// Group sorted notifications
|
|
86
|
+
const now = new Date();
|
|
87
|
+
const grouped = sorted.reduce((acc, notification) => {
|
|
88
|
+
var _a;
|
|
89
|
+
const group = getTimeGroup(notification.timeStamp, now);
|
|
90
|
+
((_a = acc[group]) !== null && _a !== void 0 ? _a : (acc[group] = [])).push(notification);
|
|
91
|
+
return acc;
|
|
92
|
+
}, {});
|
|
93
|
+
// Get time group labels from props or use defaults
|
|
94
|
+
const timeGroupLabels = {
|
|
95
|
+
earlier: earlierLabel !== null && earlierLabel !== void 0 ? earlierLabel : DEFAULT_TIME_GROUP_LABELS.earlier,
|
|
96
|
+
past7Days: past7DaysLabel !== null && past7DaysLabel !== void 0 ? past7DaysLabel : DEFAULT_TIME_GROUP_LABELS.past7Days,
|
|
97
|
+
today: todayLabel !== null && todayLabel !== void 0 ? todayLabel : DEFAULT_TIME_GROUP_LABELS.today,
|
|
98
|
+
yesterday: yesterdayLabel !== null && yesterdayLabel !== void 0 ? yesterdayLabel : DEFAULT_TIME_GROUP_LABELS.yesterday,
|
|
99
|
+
};
|
|
100
|
+
// Render notifications with prependTips for first item in each group
|
|
101
|
+
return TIME_GROUP_ORDER.flatMap((group) => {
|
|
102
|
+
const notifications = grouped[group];
|
|
103
|
+
if (!(notifications === null || notifications === void 0 ? void 0 : notifications.length)) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
return notifications.map((notification, index) => {
|
|
107
|
+
const { key, ...restNotification } = notification;
|
|
108
|
+
return (jsx(NotificationCenter, { ...restNotification, prependTips: index === 0 ? timeGroupLabels[group] : undefined, reference: key, type: "drawer" }, key));
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// Return children (can be single element or array)
|
|
113
|
+
return Array.isArray(children) ? children : children;
|
|
114
|
+
}, [
|
|
115
|
+
isEmpty,
|
|
116
|
+
notificationList,
|
|
117
|
+
children,
|
|
118
|
+
emptyNotificationIcon,
|
|
119
|
+
emptyNotificationTitle,
|
|
120
|
+
earlierLabel,
|
|
121
|
+
past7DaysLabel,
|
|
122
|
+
todayLabel,
|
|
123
|
+
yesterdayLabel,
|
|
124
|
+
]);
|
|
125
|
+
return (jsx(Drawer, { className: notificationClasses.drawer, controlBarAllRadioLabel: controlBarAllRadioLabel, controlBarCustomButtonLabel: controlBarCustomButtonLabel, controlBarDefaultValue: controlBarDefaultValue, controlBarIsEmpty: isEmpty, controlBarOnCustomButtonClick: controlBarOnCustomButtonClick, controlBarOnRadioChange: controlBarOnRadioChange, controlBarReadRadioLabel: controlBarReadRadioLabel, controlBarShow: controlBarShow, controlBarShowUnreadButton: controlBarShowUnreadButton, controlBarUnreadRadioLabel: controlBarUnreadRadioLabel, controlBarValue: controlBarValue, headerTitle: title, isHeaderDisplay: Boolean(title), onClose: onClose, open: open, renderControlBar: renderControlBar, size: drawerSize, ...restDrawerProps, children: renderNotifications }));
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export { NotificationCenterDrawer as default };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export type { NotificationSeverity } from '@mezzanine-ui/core/notification-center';
|
|
2
2
|
export { default } from './NotificationCenter';
|
|
3
3
|
export type { NotificationConfigProps, NotificationData, } from './NotificationCenter';
|
|
4
|
+
export { default as NotificationCenterDrawer } from './NotificationCenterDrawer';
|
|
5
|
+
export type { NotificationCenterDrawerProps } from './NotificationCenterDrawer';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default, OverflowTooltipProps } from './OverflowTooltip';
|
|
2
|
-
export { default as OverflowCounterTag, OverflowCounterTagProps, } from './OverflowCounterTag';
|
|
1
|
+
export { default, type OverflowTooltipProps } from './OverflowTooltip';
|
|
2
|
+
export { default as OverflowCounterTag, type OverflowCounterTagProps, } from './OverflowCounterTag';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InputHTMLAttributes } from 'react';
|
|
2
2
|
import { type UseDateInputFormatterProps } from './useDateInputFormatter';
|
|
3
|
-
export interface FormattedInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'>, Pick<UseDateInputFormatterProps, 'errorMessages' | 'validate' | 'format' | 'onChange'> {
|
|
3
|
+
export interface FormattedInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'>, Pick<UseDateInputFormatterProps, 'errorMessages' | 'validate' | 'format' | 'onChange' | 'onPasteIsoValue'> {
|
|
4
4
|
/**
|
|
5
5
|
* Placeholder to show when not focused and value is empty
|
|
6
6
|
*/
|
package/Picker/FormattedInput.js
CHANGED
|
@@ -14,7 +14,7 @@ const FormattedInput = forwardRef(function FormattedInput(props, ref) {
|
|
|
14
14
|
enabled: true,
|
|
15
15
|
invalidInput: 'Input value is not valid.',
|
|
16
16
|
invalidPaste: 'Pasted content is not valid.',
|
|
17
|
-
}, format, placeholder, validate, value: externalValue, onChange, onFocus, onBlur, ...inputProps } = props;
|
|
17
|
+
}, format, placeholder, validate, value: externalValue, onChange, onFocus, onBlur, onPasteIsoValue, ...inputProps } = props;
|
|
18
18
|
const internalInputRef = useRef(null);
|
|
19
19
|
const composedRef = useComposeRefs([ref, internalInputRef]);
|
|
20
20
|
const { value, focused, handleKeyDown, handleFocus, handleBlur, handlePaste, } = useDateInputFormatter({
|
|
@@ -26,6 +26,7 @@ const FormattedInput = forwardRef(function FormattedInput(props, ref) {
|
|
|
26
26
|
onFocus,
|
|
27
27
|
onBlur,
|
|
28
28
|
validate,
|
|
29
|
+
onPasteIsoValue,
|
|
29
30
|
});
|
|
30
31
|
const segments = useRef(parseFormatSegments(format)).current;
|
|
31
32
|
const renderMixedColorDisplay = () => {
|
|
@@ -63,6 +63,16 @@ export interface PickerTriggerWithSeparatorProps extends Omit<TextFieldProps, 'a
|
|
|
63
63
|
* Can be used to trigger auto-focus to right input.
|
|
64
64
|
*/
|
|
65
65
|
onLeftComplete?: () => void;
|
|
66
|
+
/**
|
|
67
|
+
* Callback when a valid ISO date is pasted into the left input.
|
|
68
|
+
* Allows parent to sync other fields (e.g., update time when date+time is pasted).
|
|
69
|
+
*/
|
|
70
|
+
onPasteIsoValueLeft?: (isoValue: string) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Callback when a valid ISO date is pasted into the right input.
|
|
73
|
+
* Allows parent to sync other fields (e.g., update date when date+time is pasted).
|
|
74
|
+
*/
|
|
75
|
+
onPasteIsoValueRight?: (isoValue: string) => void;
|
|
66
76
|
/**
|
|
67
77
|
* Callback when right input is completed (all mask positions filled with valid value).
|
|
68
78
|
*/
|
|
@@ -12,7 +12,7 @@ import cx from 'clsx';
|
|
|
12
12
|
* typically used for date-time pickers where left is date and right is time.
|
|
13
13
|
*/
|
|
14
14
|
const PickerTriggerWithSeparator = forwardRef(function PickerTriggerWithSeparator(props, ref) {
|
|
15
|
-
const { className, clearable = true, disabled, errorMessagesLeft, errorMessagesRight, formatLeft, formatRight, inputLeftProps, inputLeftRef: inputLeftRefProp, inputRightProps, inputRightRef: inputRightRefProp, onBlurLeft, onBlurRight, onChangeLeft, onChangeRight, onFocusLeft, onFocusRight, onLeftComplete, onRightComplete, placeholderLeft, placeholderRight, readOnly, required, suffix, validateLeft, validateRight, valueLeft, valueRight, ...restTextFieldProps } = props;
|
|
15
|
+
const { className, clearable = true, disabled, errorMessagesLeft, errorMessagesRight, formatLeft, formatRight, inputLeftProps, inputLeftRef: inputLeftRefProp, inputRightProps, inputRightRef: inputRightRefProp, onBlurLeft, onBlurRight, onChangeLeft, onChangeRight, onFocusLeft, onFocusRight, onLeftComplete, onPasteIsoValueLeft, onPasteIsoValueRight, onRightComplete, placeholderLeft, placeholderRight, readOnly, required, suffix, validateLeft, validateRight, valueLeft, valueRight, ...restTextFieldProps } = props;
|
|
16
16
|
const internalLeftRef = useRef(null);
|
|
17
17
|
const internalRightRef = useRef(null);
|
|
18
18
|
const leftRef = useComposeRefs([
|
|
@@ -74,7 +74,7 @@ const PickerTriggerWithSeparator = forwardRef(function PickerTriggerWithSeparato
|
|
|
74
74
|
const handleRightBlur = useCallback((e) => {
|
|
75
75
|
onBlurRight === null || onBlurRight === void 0 ? void 0 : onBlurRight(e);
|
|
76
76
|
}, [onBlurRight]);
|
|
77
|
-
return (jsx(TextField, { ...restTextFieldProps, ...defaultTextFieldProps, ref: ref, className: cx(pickerClasses.host, className), clearable: !readOnly && clearable, suffix: suffix, children: jsxs("div", { className: pickerClasses.separatorInputs, children: [jsx("div", { className: pickerClasses.separatorInput, children: jsx(FormattedInput, { ...inputLeftProps, ref: leftRef, "aria-disabled": disabled, "aria-label": "Date input", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesLeft, format: formatLeft, onBlur: handleLeftBlur, onChange: handleLeftChange, onFocus: handleLeftFocus, placeholder: placeholderLeft, readOnly: readOnly, required: required, validate: validateLeft, value: valueLeft }) }), jsx("div", { className: pickerClasses.separator }), jsx("div", { className: pickerClasses.separatorInput, children: jsx(FormattedInput, { ...inputRightProps, ref: rightRef, "aria-disabled": disabled, "aria-label": "Time input", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesRight, format: formatRight, onBlur: handleRightBlur, onChange: handleRightChange, onFocus: handleRightFocus, placeholder: placeholderRight, readOnly: readOnly, required: required, validate: validateRight, value: valueRight }) })] }) }));
|
|
77
|
+
return (jsx(TextField, { ...restTextFieldProps, ...defaultTextFieldProps, ref: ref, className: cx(pickerClasses.host, className), clearable: !readOnly && clearable, suffix: suffix, children: jsxs("div", { className: pickerClasses.separatorInputs, children: [jsx("div", { className: pickerClasses.separatorInput, children: jsx(FormattedInput, { ...inputLeftProps, ref: leftRef, "aria-disabled": disabled, "aria-label": "Date input", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesLeft, format: formatLeft, onBlur: handleLeftBlur, onChange: handleLeftChange, onFocus: handleLeftFocus, onPasteIsoValue: onPasteIsoValueLeft, placeholder: placeholderLeft, readOnly: readOnly, required: required, validate: validateLeft, value: valueLeft }) }), jsx("div", { className: pickerClasses.separator }), jsx("div", { className: pickerClasses.separatorInput, children: jsx(FormattedInput, { ...inputRightProps, ref: rightRef, "aria-disabled": disabled, "aria-label": "Time input", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesRight, format: formatRight, onBlur: handleRightBlur, onChange: handleRightChange, onFocus: handleRightFocus, onPasteIsoValue: onPasteIsoValueRight, placeholder: placeholderRight, readOnly: readOnly, required: required, validate: validateRight, value: valueRight }) })] }) }));
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
export { PickerTriggerWithSeparator, PickerTriggerWithSeparator as default };
|
|
@@ -69,7 +69,7 @@ const RangePickerTrigger = forwardRef(function RangePickerTrigger(props, ref) {
|
|
|
69
69
|
const handleToBlur = useCallback((e) => {
|
|
70
70
|
onToBlur === null || onToBlur === void 0 ? void 0 : onToBlur(e);
|
|
71
71
|
}, [onToBlur]);
|
|
72
|
-
return (jsxs(TextField, { ...restTextFieldProps, ...defaultTextFieldProps, ref: ref,
|
|
72
|
+
return (jsxs(TextField, { ...restTextFieldProps, ...defaultTextFieldProps, ref: ref, className: cx(pickerClasses.host, className), clearable: !readOnly && clearable, suffix: suffix !== null && suffix !== void 0 ? suffix : defaultSuffix, children: [jsx(FormattedInput, { ...inputFromProps, ref: fromRef, "aria-disabled": disabled, "aria-label": "Start date", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesFrom, format: format, onBlur: handleFromBlur, onChange: handleFromChange, onFocus: handleFromFocus, placeholder: inputFromPlaceholder, readOnly: readOnly, required: required, validate: validateFrom, value: inputFromValue }), jsx(Icon, { icon: LongTailArrowRightIcon, className: pickerClasses.arrowIcon, "aria-hidden": "true" }), jsx(FormattedInput, { ...inputToProps, ref: toRef, "aria-disabled": disabled, "aria-label": "End date", "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, disabled: disabled, errorMessages: errorMessagesTo, format: format, onBlur: handleToBlur, onChange: handleToChange, onFocus: handleToFocus, placeholder: inputToPlaceholder, readOnly: readOnly, required: required, validate: validateTo, value: inputToValue })] }));
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
export { RangePickerTrigger as default };
|
|
@@ -38,6 +38,12 @@ export interface UseDateInputFormatterProps {
|
|
|
38
38
|
* Called after format validation passes.
|
|
39
39
|
*/
|
|
40
40
|
validate?: (isoDate: string) => boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Callback when a valid ISO date is pasted.
|
|
43
|
+
* This allows parent components to handle cross-field updates
|
|
44
|
+
* (e.g., updating time field when date+time is pasted into date field).
|
|
45
|
+
*/
|
|
46
|
+
onPasteIsoValue?: (isoValue: string) => void;
|
|
41
47
|
}
|
|
42
48
|
/**
|
|
43
49
|
* Hook for formatting date/time input with mask format
|
|
@@ -12,7 +12,7 @@ function useDateInputFormatter(props) {
|
|
|
12
12
|
enabled: true,
|
|
13
13
|
invalidInput: 'Input value is not valid.',
|
|
14
14
|
invalidPaste: 'Pasted content is not valid.',
|
|
15
|
-
}, format, value: externalValue = '', onChange, inputRef, onFocus: onFocusProp, onBlur: onBlurProp, validate, } = props;
|
|
15
|
+
}, format, value: externalValue = '', onChange, inputRef, onFocus: onFocusProp, onBlur: onBlurProp, validate, onPasteIsoValue, } = props;
|
|
16
16
|
const { parseFormattedValue, isValid, locale, formatToString } = useCalendarContext();
|
|
17
17
|
const maskFormat = useRef(new MaskFormat(format)).current;
|
|
18
18
|
const [internalValue, setInternalValue] = useState(externalValue || getTemplateWithoutBrackets(format));
|
|
@@ -325,6 +325,8 @@ function useDateInputFormatter(props) {
|
|
|
325
325
|
// If pasted data is a valid ISO date, format it accordingly
|
|
326
326
|
const parsedDate = formatToString(locale, pasteData, format);
|
|
327
327
|
if (parsedDate) {
|
|
328
|
+
// Notify parent about the full ISO value for cross-field sync
|
|
329
|
+
onPasteIsoValue === null || onPasteIsoValue === void 0 ? void 0 : onPasteIsoValue(pasteData);
|
|
328
330
|
triggerChange(parsedDate);
|
|
329
331
|
return;
|
|
330
332
|
}
|
|
@@ -363,6 +365,7 @@ function useDateInputFormatter(props) {
|
|
|
363
365
|
errorMessages,
|
|
364
366
|
internalValue,
|
|
365
367
|
maskFormat,
|
|
368
|
+
onPasteIsoValue,
|
|
366
369
|
triggerChange,
|
|
367
370
|
isValid,
|
|
368
371
|
format,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { ContentHeaderProps } from '../ContentHeader';
|
|
3
|
+
import { FilterAreaProps } from '../FilterArea';
|
|
4
|
+
import { TabProps } from '../Tab';
|
|
5
|
+
export interface SectionProps {
|
|
6
|
+
/**
|
|
7
|
+
* Additional style for the section container.
|
|
8
|
+
*/
|
|
9
|
+
className?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Accept `<ContentHeader />` component from `mezzanine`.
|
|
12
|
+
* Other components will trigger a warning.
|
|
13
|
+
*/
|
|
14
|
+
contentHeader?: ReactElement<ContentHeaderProps>;
|
|
15
|
+
/**
|
|
16
|
+
* Accept `<FilterArea />` component from `mezzanine`.
|
|
17
|
+
* Other components will trigger a warning.
|
|
18
|
+
*/
|
|
19
|
+
filterArea?: ReactElement<FilterAreaProps>;
|
|
20
|
+
/**
|
|
21
|
+
* Accept `<Tab />` component from `mezzanine`.
|
|
22
|
+
* Other components will trigger a warning.
|
|
23
|
+
*/
|
|
24
|
+
tab?: ReactElement<TabProps>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The react component for `mezzanine` section.
|
|
28
|
+
*/
|
|
29
|
+
declare const Section: import("react").ForwardRefExoticComponent<SectionProps & {
|
|
30
|
+
children?: import("react").ReactNode | undefined;
|
|
31
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
32
|
+
export default Section;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { forwardRef, cloneElement, isValidElement } from 'react';
|
|
3
|
+
import { sectionClasses } from '@mezzanine-ui/core/section';
|
|
4
|
+
import ContentHeader from '../ContentHeader/ContentHeader.js';
|
|
5
|
+
import FilterArea from '../FilterArea/FilterArea.js';
|
|
6
|
+
import Tab from '../Tab/Tab.js';
|
|
7
|
+
import cx from 'clsx';
|
|
8
|
+
|
|
9
|
+
function getDisplayName(element) {
|
|
10
|
+
const type = element.type;
|
|
11
|
+
if (typeof type === 'string') {
|
|
12
|
+
return type;
|
|
13
|
+
}
|
|
14
|
+
return type.displayName
|
|
15
|
+
|| type.name
|
|
16
|
+
|| 'Unknown';
|
|
17
|
+
}
|
|
18
|
+
function isContentHeaderElement(element) {
|
|
19
|
+
return isValidElement(element) && element.type === ContentHeader;
|
|
20
|
+
}
|
|
21
|
+
function isFilterAreaElement(element) {
|
|
22
|
+
return isValidElement(element) && element.type === FilterArea;
|
|
23
|
+
}
|
|
24
|
+
function isTabElement(element) {
|
|
25
|
+
return isValidElement(element) && element.type === Tab;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The react component for `mezzanine` section.
|
|
29
|
+
*/
|
|
30
|
+
const Section = forwardRef(function Section(props, ref) {
|
|
31
|
+
const { children, className, contentHeader, filterArea, tab, } = props;
|
|
32
|
+
let renderedContentHeader = null;
|
|
33
|
+
let renderedFilterArea = null;
|
|
34
|
+
let renderedTab = null;
|
|
35
|
+
if (contentHeader) {
|
|
36
|
+
if (isContentHeaderElement(contentHeader)) {
|
|
37
|
+
renderedContentHeader = cloneElement(contentHeader, { size: 'sub' });
|
|
38
|
+
}
|
|
39
|
+
else if (isValidElement(contentHeader)) {
|
|
40
|
+
console.warn(`[Section] Invalid contentHeader type: <${getDisplayName(contentHeader)}>. Only <ContentHeader /> component from @mezzanine-ui/react is allowed.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (filterArea) {
|
|
44
|
+
if (isFilterAreaElement(filterArea)) {
|
|
45
|
+
renderedFilterArea = cloneElement(filterArea, { size: 'sub' });
|
|
46
|
+
}
|
|
47
|
+
else if (isValidElement(filterArea)) {
|
|
48
|
+
console.warn(`[Section] Invalid filterArea type: <${getDisplayName(filterArea)}>. Only <FilterArea /> component from @mezzanine-ui/react is allowed.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (tab) {
|
|
52
|
+
if (isTabElement(tab)) {
|
|
53
|
+
renderedTab = tab;
|
|
54
|
+
}
|
|
55
|
+
else if (isValidElement(tab)) {
|
|
56
|
+
console.warn(`[Section] Invalid tab type: <${getDisplayName(tab)}>. Only <Tab /> component from @mezzanine-ui/react is allowed.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return (jsxs("div", { ref: ref, className: cx(sectionClasses.host, className), children: [renderedContentHeader, renderedFilterArea, renderedTab, children] }));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export { Section as default };
|
package/Select/Select.d.ts
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { DropdownOption, DropdownType } from '@mezzanine-ui/core/dropdown/dropdown';
|
|
2
2
|
import { SelectInputSize } from '@mezzanine-ui/core/select';
|
|
3
|
-
import React, { ReactElement } from 'react';
|
|
4
3
|
import { FormElementFocusHandlers } from '../Form';
|
|
5
4
|
import { SelectTriggerInputProps, SelectTriggerProps, SelectValue } from './typings';
|
|
6
5
|
export interface SelectBaseProps extends Omit<SelectTriggerProps, 'active' | 'inputProps' | 'mode' | 'onBlur' | 'onChange' | 'onClick' | 'onFocus' | 'onKeyDown' | 'onScroll' | 'type' | 'renderValue' | 'value'>, FormElementFocusHandlers {
|
|
7
|
-
/**
|
|
8
|
-
* The children of select (Option components).
|
|
9
|
-
* If `options` is provided, this will be ignored.
|
|
10
|
-
*/
|
|
11
|
-
children?: ReactElement | ReactElement[];
|
|
12
6
|
/**
|
|
13
7
|
* Direct options array for dropdown (supports tree structure).
|
|
14
|
-
* If provided, `
|
|
8
|
+
* If provided, `type` will be automatically set.
|
|
15
9
|
*/
|
|
16
10
|
options?: DropdownOption[];
|
|
17
11
|
/**
|
|
@@ -23,10 +17,6 @@ export interface SelectBaseProps extends Omit<SelectTriggerProps, 'active' | 'in
|
|
|
23
17
|
* The other native props for input element.
|
|
24
18
|
*/
|
|
25
19
|
inputProps?: Omit<SelectTriggerInputProps, 'onBlur' | 'onChange' | 'onFocus' | 'placeholder' | 'role' | 'value' | `aria-${'controls' | 'expanded' | 'owns'}`>;
|
|
26
|
-
/**
|
|
27
|
-
* Whether to disable portal.
|
|
28
|
-
*/
|
|
29
|
-
disablePortal?: boolean;
|
|
30
20
|
/**
|
|
31
21
|
* The max height of the dropdown list.
|
|
32
22
|
*/
|
|
@@ -60,6 +50,15 @@ export interface SelectBaseProps extends Omit<SelectTriggerProps, 'active' | 'in
|
|
|
60
50
|
* The size of input.
|
|
61
51
|
*/
|
|
62
52
|
size?: SelectInputSize;
|
|
53
|
+
/**
|
|
54
|
+
* The z-index of the dropdown.
|
|
55
|
+
*/
|
|
56
|
+
dropdownZIndex?: number | string;
|
|
57
|
+
/**
|
|
58
|
+
* Whether to enable portal for the dropdown.
|
|
59
|
+
* @default true
|
|
60
|
+
*/
|
|
61
|
+
globalPortal?: boolean;
|
|
63
62
|
}
|
|
64
63
|
export type SelectMultipleProps = SelectBaseProps & {
|
|
65
64
|
/**
|
|
@@ -108,5 +107,5 @@ export type SelectSingleProps = SelectBaseProps & {
|
|
|
108
107
|
value?: SelectValue | null;
|
|
109
108
|
};
|
|
110
109
|
export type SelectProps = SelectMultipleProps | SelectSingleProps;
|
|
111
|
-
declare const Select:
|
|
110
|
+
declare const Select: import("react").ForwardRefExoticComponent<SelectProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
112
111
|
export default Select;
|
package/Select/Select.js
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { selectClasses } from '@mezzanine-ui/core/select';
|
|
4
4
|
import isArray from 'lodash/isArray';
|
|
5
|
-
import
|
|
5
|
+
import { forwardRef, useContext, useState, useCallback, useRef, useMemo } from 'react';
|
|
6
6
|
import { useSelectValueControl } from '../Form/useSelectValueControl.js';
|
|
7
7
|
import { useComposeRefs } from '../hooks/useComposeRefs.js';
|
|
8
|
-
import Option from './Option.js';
|
|
9
8
|
import { SelectControlContext } from './SelectControlContext.js';
|
|
10
9
|
import SelectTrigger from './SelectTrigger.js';
|
|
11
10
|
import { FormControlContext } from '../Form/FormControlContext.js';
|
|
@@ -14,7 +13,7 @@ import cx from 'clsx';
|
|
|
14
13
|
|
|
15
14
|
const Select = forwardRef(function Select(props, ref) {
|
|
16
15
|
const { disabled: disabledFromFormControl, fullWidth: fullWidthFromFormControl, required: requiredFromFormControl, severity, } = useContext(FormControlContext) || {};
|
|
17
|
-
const {
|
|
16
|
+
const { className, clearable = false, defaultValue, disabled = disabledFromFormControl || false, error = severity === 'error' || false, fullWidth = fullWidthFromFormControl || false, inputProps, inputRef, menuMaxHeight, mode = 'single', onBlur, onChange: onChangeProp, onClear: onClearProp, onFocus, onScroll, options: optionsProp, placeholder = '', prefix, readOnly = false, renderValue, required = requiredFromFormControl || false, size, suffixActionIcon, type = 'default', value: valueProp, dropdownZIndex, globalPortal = true, } = props;
|
|
18
17
|
const [open, toggleOpen] = useState(false);
|
|
19
18
|
const onOpen = useCallback(() => {
|
|
20
19
|
// Prevent opening when readOnly is true
|
|
@@ -78,39 +77,19 @@ const Select = forwardRef(function Select(props, ref) {
|
|
|
78
77
|
}
|
|
79
78
|
return null;
|
|
80
79
|
}, []);
|
|
81
|
-
//
|
|
82
|
-
// Or use provided options directly
|
|
80
|
+
// Use provided options directly
|
|
83
81
|
const options = useMemo(() => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
82
|
+
if (!optionsProp)
|
|
83
|
+
return [];
|
|
84
|
+
// In tree mode (multiple mode with tree structure), ensure all options have checkbox
|
|
85
|
+
if (mode === 'multiple') {
|
|
86
|
+
const hasTreeStructure = optionsProp.some((opt) => opt.children && opt.children.length > 0);
|
|
87
|
+
if (hasTreeStructure) {
|
|
88
|
+
return addCheckboxToTreeOptions(optionsProp);
|
|
92
89
|
}
|
|
93
|
-
return optionsProp;
|
|
94
90
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return [];
|
|
98
|
-
return Children.toArray(children)
|
|
99
|
-
.filter((child) => {
|
|
100
|
-
var _a;
|
|
101
|
-
return (React.isValidElement(child) &&
|
|
102
|
-
(child.type === Option || ((_a = child.type) === null || _a === void 0 ? void 0 : _a.displayName) === 'Option'));
|
|
103
|
-
})
|
|
104
|
-
.map((child) => {
|
|
105
|
-
const props = child.props;
|
|
106
|
-
return {
|
|
107
|
-
id: props.value,
|
|
108
|
-
name: props.children,
|
|
109
|
-
showCheckbox: mode === 'multiple',
|
|
110
|
-
checkSite: mode === 'multiple' ? 'prefix' : 'suffix',
|
|
111
|
-
};
|
|
112
|
-
});
|
|
113
|
-
}, [children, mode, optionsProp, addCheckboxToTreeOptions]);
|
|
91
|
+
return optionsProp;
|
|
92
|
+
}, [mode, optionsProp, addCheckboxToTreeOptions]);
|
|
114
93
|
// Determine dropdown type based on options structure and mode
|
|
115
94
|
// Tree mode is only available in multiple mode
|
|
116
95
|
const dropdownType = useMemo(() => {
|
|
@@ -232,7 +211,7 @@ const Select = forwardRef(function Select(props, ref) {
|
|
|
232
211
|
onChange,
|
|
233
212
|
value,
|
|
234
213
|
}), [onChange, value]);
|
|
235
|
-
return (jsx(SelectControlContext.Provider, { value: context, children: jsx("div", { ref: nodeRef, className: cx(selectClasses.host, fullWidth && selectClasses.hostFullWidth), children: jsx(Dropdown, { disabled: readOnly || disabled,
|
|
214
|
+
return (jsx(SelectControlContext.Provider, { value: context, children: jsx("div", { ref: nodeRef, className: cx(selectClasses.host, fullWidth && selectClasses.hostFullWidth, mode && selectClasses.hostMode(mode)), children: jsx(Dropdown, { disabled: readOnly || disabled, maxHeight: menuMaxHeight, mode: mode, onScroll: onScroll, onSelect: handleDropdownSelect, onVisibilityChange: handleVisibilityChange, open: readOnly ? false : open, options: options, sameWidth: true, type: dropdownType, value: dropdownValue, zIndex: dropdownZIndex, globalPortal: globalPortal, children: jsx(SelectTrigger, { ref: composedRef, active: !readOnly && open, className: className, clearable: clearable, disabled: disabled, error: error, fullWidth: fullWidth, inputRef: inputRef, mode: mode, onTagClose: onChange, onClear: onClear, onKeyDown: onKeyDownTextField, prefix: prefix, readOnly: readOnly, ...(mode === 'single' && renderValue ? { renderValue } : {}), required: required, inputProps: resolvedInputProps, size: size, suffixActionIcon: suffixActionIcon, value: value === null ? undefined : value }) }) }) }));
|
|
236
215
|
});
|
|
237
216
|
|
|
238
217
|
export { Select as default };
|
package/Select/SelectTrigger.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
-
import { forwardRef } from 'react';
|
|
4
3
|
import { selectClasses } from '@mezzanine-ui/core/select';
|
|
5
4
|
import { ChevronDownIcon } from '@mezzanine-ui/icons';
|
|
5
|
+
import { forwardRef } from 'react';
|
|
6
6
|
import SelectTriggerTags from './SelectTriggerTags.js';
|
|
7
7
|
import Icon from '../Icon/Icon.js';
|
|
8
8
|
import TextField from '../TextField/TextField.js';
|
|
@@ -12,24 +12,36 @@ const isMultipleSelection = (props) => props.mode === 'multiple';
|
|
|
12
12
|
function SelectTriggerComponent(props) {
|
|
13
13
|
var _a, _b, _c;
|
|
14
14
|
const { active, className, disabled, forceHideSuffixActionIcon, inputProps, innerRef, inputRef, isForceClearable = false, mode = 'single', onTagClose, overflowStrategy = 'counter', placeholder, readOnly, required, searchText, size = 'main', showTextInputAfterTags = false, suffixAction, suffixActionIcon: suffixActionIconProp, type = 'default', onClick, ...restTextFieldProps } = props;
|
|
15
|
+
const renderValueProp = 'renderValue' in props ? props.renderValue : undefined;
|
|
16
|
+
// Exclude renderValue to avoid leaking unknown props to DOM.
|
|
17
|
+
const sanitizedTextFieldProps = (() => {
|
|
18
|
+
if ('renderValue' in restTextFieldProps) {
|
|
19
|
+
const { renderValue: _removed, ...rest } = restTextFieldProps;
|
|
20
|
+
return rest;
|
|
21
|
+
}
|
|
22
|
+
return restTextFieldProps;
|
|
23
|
+
})();
|
|
15
24
|
/** Render value to string for single selection trigger input */
|
|
16
25
|
const renderValue = () => {
|
|
17
26
|
var _a, _b;
|
|
18
27
|
if (isMultipleSelection(props))
|
|
19
28
|
return;
|
|
20
|
-
if (typeof
|
|
21
|
-
return
|
|
29
|
+
if (typeof renderValueProp === 'function') {
|
|
30
|
+
return renderValueProp(props.value);
|
|
22
31
|
}
|
|
23
32
|
return (_b = (_a = props.value) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
|
|
24
33
|
};
|
|
25
34
|
/** Compute suffix action icon */
|
|
26
35
|
const suffixActionIcon = suffixActionIconProp || (jsx(Icon, { icon: ChevronDownIcon, onClick: (e) => {
|
|
36
|
+
var _a;
|
|
27
37
|
e.stopPropagation();
|
|
28
38
|
if (suffixAction) {
|
|
29
39
|
suffixAction();
|
|
30
40
|
}
|
|
31
41
|
else {
|
|
32
|
-
|
|
42
|
+
// Delegate to trigger click behavior without fabricating a synthetic event.
|
|
43
|
+
(_a = e.currentTarget
|
|
44
|
+
.closest(`.${selectClasses.trigger}`)) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
33
45
|
}
|
|
34
46
|
}, className: cx(selectClasses.triggerSuffixActionIcon, {
|
|
35
47
|
[selectClasses.triggerSuffixActionIconActive]: active,
|
|
@@ -43,7 +55,7 @@ function SelectTriggerComponent(props) {
|
|
|
43
55
|
}
|
|
44
56
|
return {};
|
|
45
57
|
})();
|
|
46
|
-
return (jsxs(TextField, { ref: innerRef, ...interactiveProps, ...
|
|
58
|
+
return (jsxs(TextField, { ref: innerRef, ...interactiveProps, ...sanitizedTextFieldProps, onClick: onClick, active: active, className: cx(selectClasses.trigger, selectClasses.triggerMode(mode), selectClasses.triggerSelected(Array.isArray(props.value) ? (_a = props.value) === null || _a === void 0 ? void 0 : _a.length : props.value), {
|
|
47
59
|
[selectClasses.triggerReadOnly]: readOnly,
|
|
48
60
|
[selectClasses.triggerDisabled]: disabled,
|
|
49
61
|
}, className), error: type === 'error', size: size, suffix: forceHideSuffixActionIcon ? undefined : suffixActionIcon, clearable: isForceClearable ||
|
|
@@ -53,9 +65,11 @@ function SelectTriggerComponent(props) {
|
|
|
53
65
|
}
|
|
54
66
|
const SelectTrigger = forwardRef((props, ref) => {
|
|
55
67
|
if (props.mode === 'multiple') {
|
|
56
|
-
|
|
68
|
+
const { mode: _mode, value, ...multipleModeProps } = props;
|
|
69
|
+
return (jsx(SelectTriggerComponent, { ...multipleModeProps, innerRef: ref, mode: "multiple", value: Array.isArray(value) ? value : undefined }));
|
|
57
70
|
}
|
|
58
|
-
|
|
71
|
+
const { mode: _mode, overflowStrategy: _overflowStrategy, value, ...singleModeProps } = props;
|
|
72
|
+
return (jsx(SelectTriggerComponent, { ...singleModeProps, innerRef: ref, mode: "single", value: Array.isArray(value) ? undefined : value }));
|
|
59
73
|
});
|
|
60
74
|
|
|
61
75
|
export { SelectTrigger as default };
|
package/Select/index.d.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
export { default as OptionGroup } from '../Menu/MenuItemGroup';
|
|
2
2
|
export type { MenuItemGroupProps as OptionGroupProps } from '../Menu/MenuItemGroup';
|
|
3
|
-
export { default as Option } from './Option';
|
|
4
|
-
export type { OptionProps } from './Option';
|
|
5
3
|
export { default } from './Select';
|
|
6
4
|
export type { SelectProps } from './Select';
|
|
7
5
|
export { SelectControlContext } from './SelectControlContext';
|
|
8
6
|
export { default as SelectTrigger } from './SelectTrigger';
|
|
9
7
|
export { default as SelectTriggerTags } from './SelectTriggerTags';
|
|
10
8
|
export type { SelectTriggerTagsProps } from './SelectTriggerTags';
|
|
11
|
-
export { default as TreeSelect } from './TreeSelect';
|
|
12
|
-
export type { TreeSelectProps } from './TreeSelect';
|
|
13
9
|
export * from './typings';
|
package/Select/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export { default as OptionGroup } from '../Menu/MenuItemGroup.js';
|
|
2
|
-
export { default as Option } from './Option.js';
|
|
3
2
|
export { default } from './Select.js';
|
|
4
3
|
export { SelectControlContext } from './SelectControlContext.js';
|
|
5
4
|
export { default as SelectTrigger } from './SelectTrigger.js';
|
|
6
5
|
export { default as SelectTriggerTags } from './SelectTriggerTags.js';
|
|
7
|
-
export { default as TreeSelect } from './TreeSelect.js';
|
package/Select/typings.d.ts
CHANGED
|
@@ -7,10 +7,6 @@ export interface SelectValue<T = string> {
|
|
|
7
7
|
id: T;
|
|
8
8
|
name: string;
|
|
9
9
|
}
|
|
10
|
-
export interface TreeSelectOption<T = string> extends SelectValue<T> {
|
|
11
|
-
dynamicChildrenFetching?: boolean;
|
|
12
|
-
siblings?: TreeSelectOption<T>[];
|
|
13
|
-
}
|
|
14
10
|
export interface SelectControl<T = string> {
|
|
15
11
|
value: SelectValue<T>[] | SelectValue<T> | null;
|
|
16
12
|
onChange: (v: SelectValue<T> | null) => SelectValue<T>[] | SelectValue<T> | null;
|