@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,176 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { getDefaultModeFormat, calendarClasses } from '@mezzanine-ui/core/calendar';
|
|
4
|
+
import { multipleDatePickerClasses } from '@mezzanine-ui/core/multiple-date-picker';
|
|
5
|
+
import { CalendarIcon } from '@mezzanine-ui/icons';
|
|
6
|
+
import { forwardRef, useState, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
7
|
+
import CalendarFooterActions from '../Calendar/CalendarFooterActions.js';
|
|
8
|
+
import { useComposeRefs } from '../hooks/useComposeRefs.js';
|
|
9
|
+
import MultipleDatePickerTrigger from './MultipleDatePickerTrigger.js';
|
|
10
|
+
import { useMultipleDatePickerValue } from './useMultipleDatePickerValue.js';
|
|
11
|
+
import { useCalendarContext } from '../Calendar/CalendarContext.js';
|
|
12
|
+
import { useCalendarControls } from '../Calendar/useCalendarControls.js';
|
|
13
|
+
import { usePickerDocumentEventClose } from '../Picker/usePickerDocumentEventClose.js';
|
|
14
|
+
import Icon from '../Icon/Icon.js';
|
|
15
|
+
import InputTriggerPopper from '../_internal/InputTriggerPopper/InputTriggerPopper.js';
|
|
16
|
+
import Calendar from '../Calendar/Calendar.js';
|
|
17
|
+
import cx from 'clsx';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The react component for `mezzanine` multiple date picker.
|
|
21
|
+
* Allows selecting multiple dates from a calendar with manual confirmation.
|
|
22
|
+
* Notice that any component related to date-picker should be used along with `CalendarContext`.
|
|
23
|
+
*/
|
|
24
|
+
const MultipleDatePicker = forwardRef(function MultipleDatePicker(props, ref) {
|
|
25
|
+
const { getNow, locale } = useCalendarContext();
|
|
26
|
+
const { actions: actionsProp, calendarProps, className, clearable = true, disabledMonthSwitch = false, disableOnDoubleNext, disableOnDoublePrev, disableOnNext, disableOnPrev, disabledYearSwitch = false, disabled = false, displayMonthLocale = locale, error = false, format: formatProp, fullWidth = false, isDateDisabled: isDateDisabledProp, maxSelections, onCalendarToggle: onCalendarToggleProp, onChange: onChangeProp, overflowStrategy = 'counter', placeholder, popperProps, prefix, required, readOnly = false, referenceDate: referenceDateProp, size = 'main', value = [], } = props;
|
|
27
|
+
const format = formatProp || getDefaultModeFormat('day');
|
|
28
|
+
const { className: calendarClassName, ...restCalendarProps } = calendarProps || {};
|
|
29
|
+
// Calendar open state
|
|
30
|
+
const [open, setOpen] = useState(false);
|
|
31
|
+
const preventOpen = readOnly || disabled;
|
|
32
|
+
const onCalendarToggle = useCallback((currentOpen) => {
|
|
33
|
+
if (!preventOpen) {
|
|
34
|
+
setOpen(currentOpen);
|
|
35
|
+
onCalendarToggleProp === null || onCalendarToggleProp === void 0 ? void 0 : onCalendarToggleProp(currentOpen);
|
|
36
|
+
}
|
|
37
|
+
}, [onCalendarToggleProp, preventOpen]);
|
|
38
|
+
// Value management hook
|
|
39
|
+
const { clearAll, formatDate, getConfirmValue, internalValue, isDateSelected, isMaxReached, removeDate, revertToValue, toggleDate, } = useMultipleDatePickerValue({
|
|
40
|
+
format,
|
|
41
|
+
maxSelections,
|
|
42
|
+
value,
|
|
43
|
+
});
|
|
44
|
+
// Manage referenceDate internally for stable value
|
|
45
|
+
const [internalReferenceDate, setInternalReferenceDate] = useState(() => referenceDateProp || getNow());
|
|
46
|
+
// Sync referenceDate when prop changes
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (referenceDateProp) {
|
|
49
|
+
setInternalReferenceDate(referenceDateProp);
|
|
50
|
+
}
|
|
51
|
+
}, [referenceDateProp]);
|
|
52
|
+
// Calendar controls - pass stable referenceDate
|
|
53
|
+
const { currentMode, onMonthControlClick, onNext, onPrev, onDoublePrev, onDoubleNext, onYearControlClick, popModeStack, referenceDate, updateReferenceDate, } = useCalendarControls(internalReferenceDate, 'day');
|
|
54
|
+
// Handle mode switching (month/year selection) with value transformation
|
|
55
|
+
const createModeChangeHandler = useMemo(() => {
|
|
56
|
+
return (transformValue) => {
|
|
57
|
+
return (target) => {
|
|
58
|
+
const result = transformValue
|
|
59
|
+
? transformValue(target, referenceDate)
|
|
60
|
+
: target;
|
|
61
|
+
updateReferenceDate(result);
|
|
62
|
+
popModeStack();
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
}, [referenceDate, updateReferenceDate, popModeStack]);
|
|
66
|
+
// Convert internalValue to DateValue[] for trigger display
|
|
67
|
+
const triggerValues = useMemo(() => internalValue.map((date) => ({
|
|
68
|
+
date,
|
|
69
|
+
id: formatDate(date),
|
|
70
|
+
name: formatDate(date),
|
|
71
|
+
})), [internalValue, formatDate]);
|
|
72
|
+
// Handle calendar date click - toggle selection (only in day mode)
|
|
73
|
+
const onCalendarDateChange = useCallback((date) => {
|
|
74
|
+
if (currentMode === 'day') {
|
|
75
|
+
toggleDate(date);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Handle month/year mode switching
|
|
79
|
+
createModeChangeHandler()(date);
|
|
80
|
+
}
|
|
81
|
+
}, [currentMode, toggleDate, createModeChangeHandler]);
|
|
82
|
+
// Handle tag close - remove date
|
|
83
|
+
const onTagClose = useCallback((date) => {
|
|
84
|
+
removeDate(date);
|
|
85
|
+
}, [removeDate]);
|
|
86
|
+
// Handle confirm action
|
|
87
|
+
const onConfirm = useCallback(() => {
|
|
88
|
+
const confirmedValue = getConfirmValue();
|
|
89
|
+
onChangeProp === null || onChangeProp === void 0 ? void 0 : onChangeProp(confirmedValue);
|
|
90
|
+
onCalendarToggle(false);
|
|
91
|
+
}, [getConfirmValue, onChangeProp, onCalendarToggle]);
|
|
92
|
+
// Handle cancel action
|
|
93
|
+
const onCancel = useCallback(() => {
|
|
94
|
+
revertToValue();
|
|
95
|
+
onCalendarToggle(false);
|
|
96
|
+
}, [revertToValue, onCalendarToggle]);
|
|
97
|
+
// Handle clear
|
|
98
|
+
const onClear = useCallback((e) => {
|
|
99
|
+
e.stopPropagation();
|
|
100
|
+
clearAll();
|
|
101
|
+
onChangeProp === null || onChangeProp === void 0 ? void 0 : onChangeProp([]);
|
|
102
|
+
}, [clearAll, onChangeProp]);
|
|
103
|
+
// Auto-generate actions
|
|
104
|
+
const actions = useMemo(() => {
|
|
105
|
+
const hasValue = internalValue.length > 0;
|
|
106
|
+
return {
|
|
107
|
+
primaryButtonProps: {
|
|
108
|
+
children: 'Confirm',
|
|
109
|
+
disabled: !hasValue,
|
|
110
|
+
onClick: onConfirm,
|
|
111
|
+
...actionsProp === null || actionsProp === void 0 ? void 0 : actionsProp.primaryButtonProps,
|
|
112
|
+
},
|
|
113
|
+
secondaryButtonProps: {
|
|
114
|
+
children: 'Cancel',
|
|
115
|
+
onClick: onCancel,
|
|
116
|
+
...actionsProp === null || actionsProp === void 0 ? void 0 : actionsProp.secondaryButtonProps,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}, [actionsProp, internalValue.length, onConfirm, onCancel]);
|
|
120
|
+
// Enhanced isDateDisabled - disable unselected dates when max is reached
|
|
121
|
+
const isDateDisabled = useCallback((date) => {
|
|
122
|
+
// Check user-provided disabled function first
|
|
123
|
+
if (isDateDisabledProp === null || isDateDisabledProp === void 0 ? void 0 : isDateDisabledProp(date)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
// If max is reached and date is not already selected, disable it
|
|
127
|
+
if (isMaxReached && !isDateSelected(date)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}, [isDateDisabledProp, isDateSelected, isMaxReached]);
|
|
132
|
+
// Refs for popper positioning
|
|
133
|
+
const anchorRef = useRef(null);
|
|
134
|
+
const calendarRef = useRef(null);
|
|
135
|
+
const triggerComposedRef = useComposeRefs([ref, anchorRef]);
|
|
136
|
+
// Close handlers for click-away and escape
|
|
137
|
+
const onClose = useCallback(() => {
|
|
138
|
+
revertToValue();
|
|
139
|
+
onCalendarToggle(false);
|
|
140
|
+
}, [revertToValue, onCalendarToggle]);
|
|
141
|
+
const onChangeClose = useCallback(() => {
|
|
142
|
+
// In manual mode, always revert on click-away (don't auto-submit)
|
|
143
|
+
revertToValue();
|
|
144
|
+
onCalendarToggle(false);
|
|
145
|
+
}, [revertToValue, onCalendarToggle]);
|
|
146
|
+
// Use a dummy ref for lastElementRefInFlow since we don't have a focusable input
|
|
147
|
+
const dummyRef = useRef(null);
|
|
148
|
+
usePickerDocumentEventClose({
|
|
149
|
+
anchorRef,
|
|
150
|
+
lastElementRefInFlow: dummyRef,
|
|
151
|
+
onChangeClose,
|
|
152
|
+
onClose,
|
|
153
|
+
open,
|
|
154
|
+
popperRef: calendarRef,
|
|
155
|
+
});
|
|
156
|
+
// Icon click handler
|
|
157
|
+
const onIconClick = useCallback((e) => {
|
|
158
|
+
e.stopPropagation();
|
|
159
|
+
if (open) {
|
|
160
|
+
revertToValue();
|
|
161
|
+
}
|
|
162
|
+
onCalendarToggle(!open);
|
|
163
|
+
}, [open, revertToValue, onCalendarToggle]);
|
|
164
|
+
const suffixActionIcon = (jsx(Icon, { "aria-label": "Open calendar", icon: CalendarIcon, onClick: readOnly || disabled ? undefined : onIconClick }));
|
|
165
|
+
// Trigger click handler
|
|
166
|
+
const onTriggerClick = useCallback(() => {
|
|
167
|
+
if (!preventOpen && !open) {
|
|
168
|
+
onCalendarToggle(true);
|
|
169
|
+
}
|
|
170
|
+
}, [preventOpen, open, onCalendarToggle]);
|
|
171
|
+
return (jsxs(Fragment, { children: [jsx(MultipleDatePickerTrigger, { active: open, className: cx(multipleDatePickerClasses.host, className, {
|
|
172
|
+
[multipleDatePickerClasses.hostFullWidth]: fullWidth,
|
|
173
|
+
}), clearable: clearable, disabled: disabled, error: error, fullWidth: fullWidth, onClick: onTriggerClick, onClear: onClear, onTagClose: onTagClose, overflowStrategy: overflowStrategy, placeholder: placeholder, prefix: prefix, readOnly: readOnly, ref: triggerComposedRef, required: required, size: size, suffix: suffixActionIcon, value: triggerValues }), jsx(InputTriggerPopper, { ...popperProps, anchor: anchorRef, open: open, ref: calendarRef, children: jsx("div", { className: calendarClasses.host, children: jsxs("div", { className: calendarClasses.mainWithFooter, children: [jsx(Calendar, { ...restCalendarProps, className: cx(calendarClasses.noShadowHost, calendarClassName), disabledFooterControl: true, disabledMonthSwitch: disabledMonthSwitch, disableOnDoubleNext: disableOnDoubleNext, disableOnDoublePrev: disableOnDoublePrev, disableOnNext: disableOnNext, disableOnPrev: disableOnPrev, disabledYearSwitch: disabledYearSwitch, displayMonthLocale: displayMonthLocale, isDateDisabled: isDateDisabled, mode: currentMode, onChange: onCalendarDateChange, onMonthControlClick: onMonthControlClick, onNext: onNext, onDoubleNext: onDoubleNext, onPrev: onPrev, onDoublePrev: onDoublePrev, onYearControlClick: onYearControlClick, referenceDate: referenceDate, value: internalValue }), jsx(CalendarFooterActions, { actions: actions })] }) }) })] }));
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
export { MultipleDatePicker as default };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DateType } from '@mezzanine-ui/core/calendar';
|
|
3
|
+
import { TextFieldProps } from '../TextField';
|
|
4
|
+
export interface DateValue {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
date: DateType;
|
|
8
|
+
}
|
|
9
|
+
export interface MultipleDatePickerTriggerProps extends Omit<TextFieldProps, 'active' | 'children' | 'defaultChecked' | 'disabled' | 'readonly' | 'typing'> {
|
|
10
|
+
/**
|
|
11
|
+
* Whether the panel is currently open (for styling)
|
|
12
|
+
*/
|
|
13
|
+
active?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the trigger is disabled.
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Callback when a tag is closed (date removed)
|
|
21
|
+
*/
|
|
22
|
+
onTagClose?: (date: DateType) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Overflow strategy for tags display
|
|
25
|
+
* @default 'counter'
|
|
26
|
+
*/
|
|
27
|
+
overflowStrategy?: 'counter' | 'wrap';
|
|
28
|
+
/**
|
|
29
|
+
* Placeholder text when no dates are selected
|
|
30
|
+
*/
|
|
31
|
+
placeholder?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Whether the trigger is readonly.
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
readOnly?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Whether the input is required.
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
required?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Custom suffix element (e.g., calendar icon)
|
|
44
|
+
*/
|
|
45
|
+
suffix?: ReactNode;
|
|
46
|
+
/**
|
|
47
|
+
* The selected date values for display
|
|
48
|
+
*/
|
|
49
|
+
value?: DateValue[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The trigger component for MultipleDatePicker.
|
|
53
|
+
* Displays selected dates as tags within a TextField.
|
|
54
|
+
*/
|
|
55
|
+
declare const MultipleDatePickerTrigger: import("react").ForwardRefExoticComponent<MultipleDatePickerTriggerProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
56
|
+
export default MultipleDatePickerTrigger;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { forwardRef, useRef, useMemo, useCallback } from 'react';
|
|
4
|
+
import { multipleDatePickerClasses } from '@mezzanine-ui/core/multiple-date-picker';
|
|
5
|
+
import TagGroup from '../Tag/TagGroup.js';
|
|
6
|
+
import { useSelectTriggerTags } from '../Select/useSelectTriggerTags.js';
|
|
7
|
+
import Tag from '../Tag/Tag.js';
|
|
8
|
+
import OverflowCounterTag from '../OverflowTooltip/OverflowCounterTag.js';
|
|
9
|
+
import TextField from '../TextField/TextField.js';
|
|
10
|
+
import cx from 'clsx';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The trigger component for MultipleDatePicker.
|
|
14
|
+
* Displays selected dates as tags within a TextField.
|
|
15
|
+
*/
|
|
16
|
+
const MultipleDatePickerTrigger = forwardRef(function MultipleDatePickerTrigger(props, ref) {
|
|
17
|
+
const { active = false, className, clearable = true, disabled = false, error = false, fullWidth = false, onTagClose, overflowStrategy = 'counter', placeholder, readOnly = false, required = false, size = 'main', suffix, value = [], ...restTextFieldProps } = props;
|
|
18
|
+
const tagsContainerRef = useRef(null);
|
|
19
|
+
const tagsRef = useRef(null);
|
|
20
|
+
const tagSize = size === 'main' ? 'main' : 'sub';
|
|
21
|
+
// Convert DateValue[] to SelectValue[] for useSelectTriggerTags
|
|
22
|
+
const selectValues = useMemo(() => value.map((v) => ({ id: v.id, name: v.name })), [value]);
|
|
23
|
+
const { overflowSelections, renderFakeTags, visibleSelections } = useSelectTriggerTags({
|
|
24
|
+
containerRef: tagsContainerRef,
|
|
25
|
+
enabled: overflowStrategy === 'counter',
|
|
26
|
+
size: tagSize,
|
|
27
|
+
tagsRef,
|
|
28
|
+
value: selectValues,
|
|
29
|
+
});
|
|
30
|
+
const displaySelections = useMemo(() => (overflowStrategy === 'counter' ? visibleSelections : selectValues), [overflowStrategy, selectValues, visibleSelections]);
|
|
31
|
+
// Find the original DateValue by id
|
|
32
|
+
const findDateValue = useCallback((id) => value.find((v) => v.id === id), [value]);
|
|
33
|
+
const handleTagClose = useCallback((id) => (e) => {
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
const dateValue = findDateValue(id);
|
|
36
|
+
if (dateValue && onTagClose) {
|
|
37
|
+
onTagClose(dateValue.date);
|
|
38
|
+
}
|
|
39
|
+
}, [findDateValue, onTagClose]);
|
|
40
|
+
const tagChildren = useMemo(() => {
|
|
41
|
+
const tags = displaySelections.map((selection) => {
|
|
42
|
+
if (readOnly) {
|
|
43
|
+
return (jsx(Tag, { label: selection.name, readOnly: true, size: tagSize, type: "static" }, selection.id));
|
|
44
|
+
}
|
|
45
|
+
return (jsx(Tag, { disabled: disabled, label: selection.name, onClose: handleTagClose(selection.id), size: tagSize, type: "dismissable" }, selection.id));
|
|
46
|
+
});
|
|
47
|
+
if (overflowStrategy === 'counter' && overflowSelections.length) {
|
|
48
|
+
tags.push(jsx(OverflowCounterTag, { disabled: disabled, onClick: (e) => {
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
}, onTagDismiss: (tagIndex) => {
|
|
51
|
+
const target = overflowSelections[tagIndex];
|
|
52
|
+
if (!target)
|
|
53
|
+
return;
|
|
54
|
+
const dateValue = findDateValue(target.id);
|
|
55
|
+
if (dateValue && onTagClose) {
|
|
56
|
+
onTagClose(dateValue.date);
|
|
57
|
+
}
|
|
58
|
+
}, readOnly: readOnly, tagSize: tagSize, tags: overflowSelections.map((s) => s.name) }, "overflow-counter"));
|
|
59
|
+
}
|
|
60
|
+
return tags;
|
|
61
|
+
}, [
|
|
62
|
+
disabled,
|
|
63
|
+
displaySelections,
|
|
64
|
+
findDateValue,
|
|
65
|
+
handleTagClose,
|
|
66
|
+
onTagClose,
|
|
67
|
+
overflowSelections,
|
|
68
|
+
overflowStrategy,
|
|
69
|
+
readOnly,
|
|
70
|
+
tagSize,
|
|
71
|
+
]);
|
|
72
|
+
const hasValue = value.length > 0;
|
|
73
|
+
// TextField requires disabled and readonly to be mutually exclusive
|
|
74
|
+
let interactiveProps = {};
|
|
75
|
+
if (disabled) {
|
|
76
|
+
interactiveProps = { disabled: true };
|
|
77
|
+
}
|
|
78
|
+
else if (readOnly) {
|
|
79
|
+
interactiveProps = { readonly: true };
|
|
80
|
+
}
|
|
81
|
+
return (jsx(TextField, { ...restTextFieldProps, ...interactiveProps, active: active, className: cx(multipleDatePickerClasses.trigger, {
|
|
82
|
+
[multipleDatePickerClasses.triggerSelected]: hasValue,
|
|
83
|
+
[multipleDatePickerClasses.triggerDisabled]: disabled,
|
|
84
|
+
[multipleDatePickerClasses.triggerReadOnly]: readOnly,
|
|
85
|
+
}, className), clearable: !readOnly && clearable && hasValue, error: error, fullWidth: fullWidth, ref: ref, size: size, suffix: suffix, children: jsx("div", { ref: tagsContainerRef, className: cx(multipleDatePickerClasses.triggerTagsWrapper, {
|
|
86
|
+
[multipleDatePickerClasses.triggerTagsWrapperEllipsis]: overflowStrategy === 'counter',
|
|
87
|
+
}), children: hasValue ? (jsxs(Fragment, { children: [jsxs("div", { className: cx(multipleDatePickerClasses.triggerTags, {
|
|
88
|
+
[multipleDatePickerClasses.triggerTagsEllipsis]: overflowStrategy === 'counter',
|
|
89
|
+
}), ref: tagsRef, children: [jsx(TagGroup, { children: tagChildren }), overflowStrategy === 'counter' ? renderFakeTags() : null] }), jsx("input", { "aria-disabled": disabled, "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, className: cx(multipleDatePickerClasses.triggerInput, multipleDatePickerClasses.triggerInputAbsolute), disabled: disabled, readOnly: true, tabIndex: -1, type: "text", value: "" })] })) : (jsx("input", { "aria-disabled": disabled, "aria-multiline": false, "aria-readonly": readOnly, "aria-required": required, className: multipleDatePickerClasses.triggerInput, disabled: disabled, placeholder: placeholder, readOnly: true, tabIndex: -1, type: "text", value: "" })) }) }));
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export { MultipleDatePickerTrigger as default };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default } from './MultipleDatePicker';
|
|
2
|
+
export type { MultipleDatePickerProps } from './MultipleDatePicker';
|
|
3
|
+
export { default as MultipleDatePickerTrigger } from './MultipleDatePickerTrigger';
|
|
4
|
+
export type { DateValue as MultipleDatePickerDateValue, MultipleDatePickerTriggerProps, } from './MultipleDatePickerTrigger';
|
|
5
|
+
export { useMultipleDatePickerValue } from './useMultipleDatePickerValue';
|
|
6
|
+
export type { UseMultipleDatePickerValueProps, UseMultipleDatePickerValueReturn, } from './useMultipleDatePickerValue';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { DateType } from '@mezzanine-ui/core/calendar';
|
|
2
|
+
import { MultipleDatePickerValue } from '@mezzanine-ui/core/multiple-date-picker';
|
|
3
|
+
export interface UseMultipleDatePickerValueProps {
|
|
4
|
+
/**
|
|
5
|
+
* The format pattern for displaying dates (e.g., "YYYY-MM-DD")
|
|
6
|
+
*/
|
|
7
|
+
format: string;
|
|
8
|
+
/**
|
|
9
|
+
* Maximum number of dates that can be selected
|
|
10
|
+
*/
|
|
11
|
+
maxSelections?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Controlled value
|
|
14
|
+
*/
|
|
15
|
+
value?: MultipleDatePickerValue;
|
|
16
|
+
}
|
|
17
|
+
export interface UseMultipleDatePickerValueReturn {
|
|
18
|
+
/**
|
|
19
|
+
* The internal value (pending changes)
|
|
20
|
+
*/
|
|
21
|
+
internalValue: MultipleDatePickerValue;
|
|
22
|
+
/**
|
|
23
|
+
* Toggle a date in/out of selection
|
|
24
|
+
*/
|
|
25
|
+
toggleDate: (date: DateType) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Remove a specific date from selection
|
|
28
|
+
*/
|
|
29
|
+
removeDate: (date: DateType) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Clear all selected dates
|
|
32
|
+
*/
|
|
33
|
+
clearAll: () => void;
|
|
34
|
+
/**
|
|
35
|
+
* Check if a date is currently selected
|
|
36
|
+
*/
|
|
37
|
+
isDateSelected: (date: DateType) => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Check if selection has reached max limit
|
|
40
|
+
*/
|
|
41
|
+
isMaxReached: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Confirm the current selection (returns the value to be passed to onChange)
|
|
44
|
+
*/
|
|
45
|
+
getConfirmValue: () => MultipleDatePickerValue;
|
|
46
|
+
/**
|
|
47
|
+
* Cancel and revert to original value
|
|
48
|
+
*/
|
|
49
|
+
revertToValue: () => void;
|
|
50
|
+
/**
|
|
51
|
+
* Format a date to display string
|
|
52
|
+
*/
|
|
53
|
+
formatDate: (date: DateType) => string;
|
|
54
|
+
}
|
|
55
|
+
export declare function useMultipleDatePickerValue({ format, maxSelections, value, }: UseMultipleDatePickerValueProps): UseMultipleDatePickerValueReturn;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useCallback, useState, useEffect } from 'react';
|
|
3
|
+
import { useCalendarContext } from '../Calendar/CalendarContext.js';
|
|
4
|
+
|
|
5
|
+
function useMultipleDatePickerValue({ format, maxSelections, value = [], }) {
|
|
6
|
+
const { formatToString, isBefore, isSameDate, locale } = useCalendarContext();
|
|
7
|
+
// Sort dates in chronological order
|
|
8
|
+
const sortDates = useCallback((dates) => {
|
|
9
|
+
return [...dates].sort((a, b) => {
|
|
10
|
+
if (isSameDate(a, b))
|
|
11
|
+
return 0;
|
|
12
|
+
return isBefore(a, b) ? -1 : 1;
|
|
13
|
+
});
|
|
14
|
+
}, [isBefore, isSameDate]);
|
|
15
|
+
// Internal state for pending changes
|
|
16
|
+
const [internalValue, setInternalValue] = useState(() => sortDates(value));
|
|
17
|
+
// Sync internal value when controlled value changes
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
setInternalValue(sortDates(value));
|
|
20
|
+
}, [sortDates, value]);
|
|
21
|
+
const formatDate = useCallback((date) => {
|
|
22
|
+
return formatToString(locale, date, format);
|
|
23
|
+
}, [formatToString, locale, format]);
|
|
24
|
+
const isDateSelected = useCallback((date) => {
|
|
25
|
+
return internalValue.some((d) => isSameDate(d, date));
|
|
26
|
+
}, [internalValue, isSameDate]);
|
|
27
|
+
const isMaxReached = typeof maxSelections === 'number' && internalValue.length >= maxSelections;
|
|
28
|
+
const toggleDate = useCallback((date) => {
|
|
29
|
+
setInternalValue((prev) => {
|
|
30
|
+
const existingIndex = prev.findIndex((d) => isSameDate(d, date));
|
|
31
|
+
if (existingIndex >= 0) {
|
|
32
|
+
// Remove the date
|
|
33
|
+
return prev.filter((_, index) => index !== existingIndex);
|
|
34
|
+
}
|
|
35
|
+
// Check max limit before adding
|
|
36
|
+
if (typeof maxSelections === 'number' && prev.length >= maxSelections) {
|
|
37
|
+
return prev;
|
|
38
|
+
}
|
|
39
|
+
// Add the date and sort
|
|
40
|
+
return sortDates([...prev, date]);
|
|
41
|
+
});
|
|
42
|
+
}, [isSameDate, maxSelections, sortDates]);
|
|
43
|
+
const removeDate = useCallback((date) => {
|
|
44
|
+
setInternalValue((prev) => prev.filter((d) => !isSameDate(d, date)));
|
|
45
|
+
}, [isSameDate]);
|
|
46
|
+
const clearAll = useCallback(() => {
|
|
47
|
+
setInternalValue([]);
|
|
48
|
+
}, []);
|
|
49
|
+
const getConfirmValue = useCallback(() => {
|
|
50
|
+
return internalValue;
|
|
51
|
+
}, [internalValue]);
|
|
52
|
+
const revertToValue = useCallback(() => {
|
|
53
|
+
setInternalValue(sortDates(value));
|
|
54
|
+
}, [sortDates, value]);
|
|
55
|
+
return {
|
|
56
|
+
clearAll,
|
|
57
|
+
formatDate,
|
|
58
|
+
getConfirmValue,
|
|
59
|
+
internalValue,
|
|
60
|
+
isDateSelected,
|
|
61
|
+
isMaxReached,
|
|
62
|
+
removeDate,
|
|
63
|
+
revertToValue,
|
|
64
|
+
toggleDate,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { useMultipleDatePickerValue };
|
|
@@ -10,7 +10,7 @@ const NavigationHeader = forwardRef((props, ref) => {
|
|
|
10
10
|
const { children, className, title, onBrandClick, ...rest } = props;
|
|
11
11
|
const { collapsed, handleCollapseChange } = use(NavigationActivatedContext);
|
|
12
12
|
const BrandComponent = onBrandClick ? 'button' : 'span';
|
|
13
|
-
return (jsxs("header", { ...rest, ref: ref, className: cx(navigationHeaderClasses.host, collapsed && navigationHeaderClasses.collapsed, className), children: [jsx(NavigationIconButton, { onClick: () => handleCollapseChange(!collapsed), icon: SiderIcon }), jsxs(BrandComponent, { type: "button", className: navigationHeaderClasses.content, onClick: onBrandClick, children: [children, jsx("span", { className: navigationHeaderClasses.title, children: title })] })] }));
|
|
13
|
+
return (jsxs("header", { ...rest, ref: ref, className: cx(navigationHeaderClasses.host, collapsed && navigationHeaderClasses.collapsed, className), children: [jsx(NavigationIconButton, { onClick: () => handleCollapseChange(!collapsed), icon: SiderIcon }), jsxs(BrandComponent, { type: "button", className: navigationHeaderClasses.content, onClick: onBrandClick, children: [children, jsx("span", { className: navigationHeaderClasses.title, children: collapsed ? title === null || title === void 0 ? void 0 : title[0] : title })] })] }));
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
export { NavigationHeader as default };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ComponentProps, type Key, type ReactElement } from 'react';
|
|
2
2
|
import { DrawerSize } from '@mezzanine-ui/core/drawer';
|
|
3
3
|
import { type IconDefinition } from '@mezzanine-ui/icons';
|
|
4
4
|
import { type DrawerProps } from '../Drawer';
|
|
@@ -7,24 +7,17 @@ type NotificationDataForDrawer = NotificationData & {
|
|
|
7
7
|
key: Key;
|
|
8
8
|
type: 'drawer';
|
|
9
9
|
};
|
|
10
|
-
type NotificationCenterDrawerPropsBase = Pick<DrawerProps, '
|
|
11
|
-
/**
|
|
12
|
-
* The label of the all radio.
|
|
13
|
-
*/
|
|
14
|
-
allRadioLabel?: string;
|
|
15
|
-
/**
|
|
16
|
-
* The label of the custom radio.
|
|
17
|
-
*/
|
|
18
|
-
customRadioLabel?: string;
|
|
19
|
-
/**
|
|
20
|
-
* The default value of the radio group.
|
|
21
|
-
*/
|
|
22
|
-
defaultValue?: string;
|
|
10
|
+
type NotificationCenterDrawerPropsBase = Pick<DrawerProps, 'controlBarAllRadioLabel' | 'controlBarCustomButtonLabel' | 'controlBarDefaultValue' | 'controlBarOnCustomButtonClick' | 'controlBarOnRadioChange' | 'controlBarReadRadioLabel' | 'controlBarShow' | 'controlBarShowUnreadButton' | 'controlBarUnreadRadioLabel' | 'controlBarValue' | 'onClose' | 'open' | 'renderControlBar'> & {
|
|
23
11
|
/**
|
|
24
12
|
* The size of the drawer.
|
|
25
13
|
* @default 'narrow'
|
|
26
14
|
*/
|
|
27
15
|
drawerSize?: DrawerSize;
|
|
16
|
+
/**
|
|
17
|
+
* The label of the "earlier" time group.
|
|
18
|
+
* @default '更早'
|
|
19
|
+
*/
|
|
20
|
+
earlierLabel?: string;
|
|
28
21
|
/**
|
|
29
22
|
* The icon of the empty notification.
|
|
30
23
|
*/
|
|
@@ -34,49 +27,14 @@ type NotificationCenterDrawerPropsBase = Pick<DrawerProps, 'open' | 'onClose'> &
|
|
|
34
27
|
*/
|
|
35
28
|
emptyNotificationTitle?: string;
|
|
36
29
|
/**
|
|
37
|
-
* The
|
|
38
|
-
|
|
39
|
-
onCustomButtonClick?: VoidFunction;
|
|
40
|
-
/**
|
|
41
|
-
* The callback function when the radio group value changes.
|
|
42
|
-
*/
|
|
43
|
-
onRadioChange?: ChangeEventHandler<HTMLInputElement>;
|
|
44
|
-
/**
|
|
45
|
-
* The label of the read radio.
|
|
46
|
-
*/
|
|
47
|
-
readRadioLabel?: string;
|
|
48
|
-
/**
|
|
49
|
-
* Controls whether to display the toolbar.
|
|
50
|
-
* @default true
|
|
51
|
-
*/
|
|
52
|
-
showToolbar?: boolean;
|
|
53
|
-
/**
|
|
54
|
-
* Controls whether to display the unread button.
|
|
55
|
-
* @default false
|
|
30
|
+
* The label for the "past 7 days" time group.
|
|
31
|
+
* @default '過去七天'
|
|
56
32
|
*/
|
|
57
|
-
|
|
33
|
+
past7DaysLabel?: string;
|
|
58
34
|
/**
|
|
59
35
|
* The title of the drawer.
|
|
60
36
|
*/
|
|
61
37
|
title?: string;
|
|
62
|
-
/**
|
|
63
|
-
* The label of the unread radio.
|
|
64
|
-
*/
|
|
65
|
-
unreadRadioLabel?: string;
|
|
66
|
-
/**
|
|
67
|
-
* The value of the radio group.
|
|
68
|
-
*/
|
|
69
|
-
value?: string;
|
|
70
|
-
/**
|
|
71
|
-
* The label for the "earlier" time group.
|
|
72
|
-
* @default '更早'
|
|
73
|
-
*/
|
|
74
|
-
earlierLabel?: string;
|
|
75
|
-
/**
|
|
76
|
-
* The label for the "past 7 days" time group.
|
|
77
|
-
* @default '過去七天'
|
|
78
|
-
*/
|
|
79
|
-
past7DaysLabel?: string;
|
|
80
38
|
/**
|
|
81
39
|
* The label for the "today" time group.
|
|
82
40
|
* @default '今天'
|