@dreamtree-org/twreact-ui 1.3.0 → 1.3.2
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/DESIGN.md +2 -2
- package/README.md +258 -10
- package/ai-skills/dreamtree-ui.md +111 -15
- package/charts/package.json +5 -0
- package/dist/_shared/cn-DPPQUJu1.js +138 -0
- package/dist/ai-schema.json +1252 -179
- package/dist/charts/index.d.ts +9 -0
- package/dist/charts/index.d.ts.map +1 -0
- package/dist/charts/index.js +769 -0
- package/dist/components/charts/AreaChart.d.ts +4 -0
- package/dist/components/charts/AreaChart.d.ts.map +1 -0
- package/dist/components/charts/BarChart.d.ts +4 -0
- package/dist/components/charts/BarChart.d.ts.map +1 -0
- package/dist/components/charts/CartesianChart.d.ts +5 -0
- package/dist/components/charts/CartesianChart.d.ts.map +1 -0
- package/dist/components/charts/ChartFrame.d.ts +18 -0
- package/dist/components/charts/ChartFrame.d.ts.map +1 -0
- package/dist/components/charts/DonutChart.d.ts +4 -0
- package/dist/components/charts/DonutChart.d.ts.map +1 -0
- package/dist/components/charts/LineChart.d.ts +4 -0
- package/dist/components/charts/LineChart.d.ts.map +1 -0
- package/dist/components/charts/Sparkline.d.ts +5 -0
- package/dist/components/charts/Sparkline.d.ts.map +1 -0
- package/dist/components/charts/chartTheme.d.ts +26 -0
- package/dist/components/charts/chartTheme.d.ts.map +1 -0
- package/dist/components/core/Accordion.d.ts.map +1 -1
- package/dist/components/core/Button.d.ts.map +1 -1
- package/dist/components/core/Checkbox.d.ts.map +1 -1
- package/dist/components/core/ColorPicker.d.ts.map +1 -1
- package/dist/components/core/DatePicker.d.ts.map +1 -1
- package/dist/components/core/DateRangePicker.d.ts.map +1 -1
- package/dist/components/core/Form.d.ts.map +1 -1
- package/dist/components/core/Input.d.ts.map +1 -1
- package/dist/components/core/LocationPicker.d.ts.map +1 -1
- package/dist/components/core/Popover.d.ts +4 -0
- package/dist/components/core/Popover.d.ts.map +1 -0
- package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
- package/dist/components/core/ProgressBar.d.ts.map +1 -1
- package/dist/components/core/Radio.d.ts.map +1 -1
- package/dist/components/core/Rate.d.ts.map +1 -1
- package/dist/components/core/Select.d.ts.map +1 -1
- package/dist/components/core/Skeleton.d.ts.map +1 -1
- package/dist/components/core/Slider.d.ts +4 -0
- package/dist/components/core/Slider.d.ts.map +1 -0
- package/dist/components/core/SpeechToText.d.ts.map +1 -1
- package/dist/components/core/Switch.d.ts.map +1 -1
- package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
- package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
- package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
- package/dist/components/core/Table/MobileCard.d.ts +2 -2
- package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
- package/dist/components/core/Table/Table.d.ts.map +1 -1
- package/dist/components/core/Table/TableRow.d.ts +4 -2
- package/dist/components/core/Table/TableRow.d.ts.map +1 -1
- package/dist/components/core/Tabs.d.ts.map +1 -1
- package/dist/components/core/Textarea.d.ts +4 -0
- package/dist/components/core/Textarea.d.ts.map +1 -0
- package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
- package/dist/components/core/Tooltip.d.ts.map +1 -1
- package/dist/components/feedback/Dialog.d.ts.map +1 -1
- package/dist/components/feedback/Drawer.d.ts +4 -0
- package/dist/components/feedback/Drawer.d.ts.map +1 -0
- package/dist/components/feedback/Toast.d.ts +14 -5
- package/dist/components/feedback/Toast.d.ts.map +1 -1
- package/dist/components/feedback/Tour.d.ts +4 -0
- package/dist/components/feedback/Tour.d.ts.map +1 -0
- package/dist/components/feedback/TourSpotlight.d.ts +9 -0
- package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
- package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/navigation/FootNav.d.ts.map +1 -1
- package/dist/components/navigation/Navbar.d.ts.map +1 -1
- package/dist/components/navigation/Sidebar.d.ts +8 -2
- package/dist/components/navigation/Sidebar.d.ts.map +1 -1
- package/dist/components/rich-text/RichTextEditor.d.ts +4 -0
- package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -0
- package/dist/components/rich-text/RichTextToolbar.d.ts +219 -0
- package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -0
- package/dist/components/utility/Badge.d.ts.map +1 -1
- package/dist/components/utility/FileUpload.d.ts.map +1 -1
- package/dist/components/utility/Sortable.d.ts +4 -0
- package/dist/components/utility/Sortable.d.ts.map +1 -0
- package/dist/esm/_vendor/object-assign/index.js +99 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
- package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
- package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
- package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
- package/dist/esm/_vendor/prop-types/index.js +30 -0
- package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
- package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
- package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
- package/dist/esm/_virtual/index.js +3 -0
- package/dist/esm/_virtual/index2.js +3 -0
- package/dist/esm/_virtual/react-is.development.js +3 -0
- package/dist/esm/_virtual/react-is.production.min.js +3 -0
- package/dist/esm/charts/index.js +5 -0
- package/dist/esm/components/blocks/AppShell.js +205 -0
- package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
- package/dist/esm/components/blocks/EmptyState.js +44 -0
- package/dist/esm/components/blocks/ErrorState.js +53 -0
- package/dist/esm/components/blocks/LoadingState.js +134 -0
- package/dist/esm/components/blocks/PageHeader.js +51 -0
- package/dist/esm/components/blocks/StatCard.js +79 -0
- package/dist/esm/components/blocks/StatusPill.js +55 -0
- package/dist/esm/components/charts/AreaChart.js +16 -0
- package/dist/esm/components/charts/BarChart.js +16 -0
- package/dist/esm/components/charts/CartesianChart.js +250 -0
- package/dist/esm/components/charts/ChartFrame.js +170 -0
- package/dist/esm/components/charts/DonutChart.js +119 -0
- package/dist/esm/components/charts/LineChart.js +16 -0
- package/dist/esm/components/charts/Sparkline.js +110 -0
- package/dist/esm/components/charts/chartTheme.js +109 -0
- package/dist/esm/components/core/Accordion.js +260 -0
- package/dist/esm/components/core/Button.js +59 -0
- package/dist/esm/components/core/Checkbox.js +188 -0
- package/dist/esm/components/core/ColorPicker.js +348 -0
- package/dist/esm/components/core/DatePicker.js +436 -0
- package/dist/esm/components/core/DateRangePicker.js +494 -0
- package/dist/esm/components/core/Form.js +522 -0
- package/dist/esm/components/core/Input.js +179 -0
- package/dist/esm/components/core/Loader.js +141 -0
- package/dist/esm/components/core/LocationPicker.js +161 -0
- package/dist/esm/components/core/Popover.js +171 -0
- package/dist/esm/components/core/PriceRangePicker.js +376 -0
- package/dist/esm/components/core/ProgressBar.js +152 -0
- package/dist/esm/components/core/Radio.js +156 -0
- package/dist/esm/components/core/Rate.js +197 -0
- package/dist/esm/components/core/RoundedTag.js +118 -0
- package/dist/esm/components/core/Select.js +857 -0
- package/dist/esm/components/core/Skeleton.js +100 -0
- package/dist/esm/components/core/Slider.js +134 -0
- package/dist/esm/components/core/SpeechToText.js +226 -0
- package/dist/esm/components/core/Switch.js +207 -0
- package/dist/esm/components/core/Table/ActionMenu.js +251 -0
- package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
- package/dist/esm/components/core/Table/FieldInput.js +157 -0
- package/dist/esm/components/core/Table/MobileCard.js +187 -0
- package/dist/esm/components/core/Table/MobileFilters.js +72 -0
- package/dist/esm/components/core/Table/Pagination.js +157 -0
- package/dist/esm/components/core/Table/Table.js +1533 -0
- package/dist/esm/components/core/Table/TableRow.js +254 -0
- package/dist/esm/components/core/Table/constants.js +35 -0
- package/dist/esm/components/core/Table/helpers.js +124 -0
- package/dist/esm/components/core/Table/useClickOutside.js +26 -0
- package/dist/esm/components/core/Tabs.js +289 -0
- package/dist/esm/components/core/TextToSpeech.js +52 -0
- package/dist/esm/components/core/Textarea.js +125 -0
- package/dist/esm/components/core/ThreeDotPopover.js +160 -0
- package/dist/esm/components/core/Tooltip.js +372 -0
- package/dist/esm/components/feedback/Alert.js +96 -0
- package/dist/esm/components/feedback/Dialog.js +200 -0
- package/dist/esm/components/feedback/Drawer.js +171 -0
- package/dist/esm/components/feedback/Toast.js +362 -0
- package/dist/esm/components/feedback/Tour.js +214 -0
- package/dist/esm/components/feedback/TourSpotlight.js +71 -0
- package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
- package/dist/esm/components/navigation/Dropdown.js +53 -0
- package/dist/esm/components/navigation/FootNav.js +51 -0
- package/dist/esm/components/navigation/Navbar.js +437 -0
- package/dist/esm/components/navigation/Sidebar.js +567 -0
- package/dist/esm/components/rich-text/RichTextEditor.js +244 -0
- package/dist/esm/components/rich-text/RichTextToolbar.js +397 -0
- package/dist/esm/components/utility/Avatar.js +89 -0
- package/dist/esm/components/utility/Badge.js +47 -0
- package/dist/esm/components/utility/Card.js +85 -0
- package/dist/esm/components/utility/Carousel.js +97 -0
- package/dist/esm/components/utility/Condition.js +9 -0
- package/dist/esm/components/utility/FileUpload.js +177 -0
- package/dist/esm/components/utility/Pagination.js +111 -0
- package/dist/esm/components/utility/Sortable.js +190 -0
- package/dist/esm/components/utility/Stepper.js +101 -0
- package/dist/esm/hooks/useApi.js +169 -0
- package/dist/esm/hooks/useControllableState.js +32 -0
- package/dist/esm/hooks/useFocusTrap.js +85 -0
- package/dist/esm/hooks/useLatestRef.js +20 -0
- package/dist/esm/hooks/useMixins.js +100 -0
- package/dist/esm/hooks/useScrollLock.js +26 -0
- package/dist/esm/hooks/useSliderValues.js +135 -0
- package/dist/esm/hooks/useSortable.js +188 -0
- package/dist/esm/hooks/useTheme.js +53 -0
- package/dist/esm/hooks/useTourTarget.js +92 -0
- package/dist/esm/index.js +65 -0
- package/dist/esm/rich-text/index.js +1 -0
- package/dist/esm/store/index.js +26 -0
- package/dist/esm/store/store.js +107 -0
- package/dist/esm/store/storeSlice.js +45 -0
- package/dist/esm/utils/cn.js +11 -0
- package/dist/esm/utils/emitter.js +169 -0
- package/dist/esm/utils/helpers.js +161 -0
- package/dist/esm/utils/position.js +134 -0
- package/dist/hooks/useApi.d.ts +2 -1
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/hooks/useControllableState.d.ts +11 -0
- package/dist/hooks/useControllableState.d.ts.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +15 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -0
- package/dist/hooks/useLatestRef.d.ts +8 -0
- package/dist/hooks/useLatestRef.d.ts.map +1 -0
- package/dist/hooks/useMixins.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.d.ts +2 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -0
- package/dist/hooks/useSliderValues.d.ts +43 -0
- package/dist/hooks/useSliderValues.d.ts.map +1 -0
- package/dist/hooks/useSortable.d.ts +32 -0
- package/dist/hooks/useSortable.d.ts.map +1 -0
- package/dist/hooks/useTheme.d.ts.map +1 -1
- package/dist/hooks/useTourTarget.d.ts +15 -0
- package/dist/hooks/useTourTarget.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +4817 -2216
- package/dist/index.js +4822 -2214
- package/dist/rich-text/index.d.ts +5 -0
- package/dist/rich-text/index.d.ts.map +1 -0
- package/dist/rich-text/index.js +654 -0
- package/dist/tokens/brands/studio.css +14 -0
- package/dist/tokens/brands/studio.json +20 -0
- package/dist/types/charts.d.ts +97 -0
- package/dist/types/charts.d.ts.map +1 -0
- package/dist/types/index.d.ts +193 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/rich-text.d.ts +50 -0
- package/dist/types/rich-text.d.ts.map +1 -0
- package/dist/utils/position.d.ts +30 -0
- package/dist/utils/position.d.ts.map +1 -0
- package/doc/README.md +20 -1
- package/mcp/catalog.snapshot.json +2505 -800
- package/mcp/server-core.mjs +30 -1
- package/package.json +51 -3
- package/rich-text/package.json +5 -0
- package/tokens/brands/studio.json +20 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
import React, { useId, useMemo, useState, useRef, useImperativeHandle, useEffect, useLayoutEffect } from 'react';
|
|
5
|
+
import ReactDOM from 'react-dom';
|
|
6
|
+
import { parseISO, startOfMonth, startOfWeek, endOfMonth, endOfWeek, eachDayOfInterval, startOfDay, subMonths, format, addMonths, isSameDay, isSameMonth, isToday, isBefore, isAfter } from 'date-fns';
|
|
7
|
+
import { cn } from '../../utils/cn.js';
|
|
8
|
+
import { ChevronLeft, ChevronRight, X, Calendar } from 'lucide-react';
|
|
9
|
+
|
|
10
|
+
var _excluded = ["value", "onChange", "placeholder", "label", "error", "helperText", "disabled", "required", "minDate", "maxDate", "className", "weekStartsOn", "portal", "displayFormat", "locale", "showClear", "closeOnSelect"];
|
|
11
|
+
var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
|
|
12
|
+
var value = _ref.value,
|
|
13
|
+
onChange = _ref.onChange,
|
|
14
|
+
_ref$placeholder = _ref.placeholder,
|
|
15
|
+
placeholder = _ref$placeholder === void 0 ? "Select date..." : _ref$placeholder,
|
|
16
|
+
label = _ref.label,
|
|
17
|
+
error = _ref.error,
|
|
18
|
+
helperText = _ref.helperText,
|
|
19
|
+
disabled = _ref.disabled,
|
|
20
|
+
required = _ref.required,
|
|
21
|
+
minDate = _ref.minDate,
|
|
22
|
+
maxDate = _ref.maxDate,
|
|
23
|
+
className = _ref.className,
|
|
24
|
+
_ref$weekStartsOn = _ref.weekStartsOn,
|
|
25
|
+
weekStartsOn = _ref$weekStartsOn === void 0 ? 0 : _ref$weekStartsOn,
|
|
26
|
+
_ref$portal = _ref.portal,
|
|
27
|
+
portal = _ref$portal === void 0 ? false : _ref$portal,
|
|
28
|
+
_ref$displayFormat = _ref.displayFormat,
|
|
29
|
+
displayFormat = _ref$displayFormat === void 0 ? "MMM dd, yyyy" : _ref$displayFormat,
|
|
30
|
+
_ref$locale = _ref.locale,
|
|
31
|
+
locale = _ref$locale === void 0 ? undefined : _ref$locale,
|
|
32
|
+
_ref$showClear = _ref.showClear,
|
|
33
|
+
showClear = _ref$showClear === void 0 ? true : _ref$showClear,
|
|
34
|
+
_ref$closeOnSelect = _ref.closeOnSelect,
|
|
35
|
+
closeOnSelect = _ref$closeOnSelect === void 0 ? true : _ref$closeOnSelect,
|
|
36
|
+
props = _objectWithoutProperties(_ref, _excluded);
|
|
37
|
+
// Stable ids wiring label / helper / error to the trigger button.
|
|
38
|
+
// A consumer `id` (spread onto the trigger via ...props) wins.
|
|
39
|
+
var reactId = useId();
|
|
40
|
+
var fieldId = props.id || "datepicker-".concat(reactId);
|
|
41
|
+
var labelId = "".concat(fieldId, "-label");
|
|
42
|
+
var valueId = "".concat(fieldId, "-value");
|
|
43
|
+
var errorId = "".concat(fieldId, "-error");
|
|
44
|
+
var helperId = "".concat(fieldId, "-helper");
|
|
45
|
+
// Normalize incoming value (accept Date or ISO string)
|
|
46
|
+
var selected = useMemo(function () {
|
|
47
|
+
if (!value) return null;
|
|
48
|
+
if (typeof value === "string") {
|
|
49
|
+
try {
|
|
50
|
+
return parseISO(value);
|
|
51
|
+
} catch (e) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return value instanceof Date ? value : null;
|
|
56
|
+
}, [value]);
|
|
57
|
+
var _useState = useState(false),
|
|
58
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
59
|
+
isOpen = _useState2[0],
|
|
60
|
+
setIsOpen = _useState2[1];
|
|
61
|
+
var _useState3 = useState(selected || new Date()),
|
|
62
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
63
|
+
currentMonth = _useState4[0],
|
|
64
|
+
setCurrentMonth = _useState4[1];
|
|
65
|
+
var datePickerRef = useRef(null);
|
|
66
|
+
var popupRef = useRef(null);
|
|
67
|
+
var gridButtonRefs = useRef([]);
|
|
68
|
+
var _useState5 = useState({}),
|
|
69
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
70
|
+
popupStyle = _useState6[0],
|
|
71
|
+
setPopupStyle = _useState6[1];
|
|
72
|
+
useImperativeHandle(forwardedRef, function () {
|
|
73
|
+
return datePickerRef.current;
|
|
74
|
+
}, []);
|
|
75
|
+
// Keep currentMonth in sync with external value changes
|
|
76
|
+
var _useState7 = useState(selected),
|
|
77
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
78
|
+
prevSelected = _useState8[0],
|
|
79
|
+
setPrevSelected = _useState8[1];
|
|
80
|
+
if (selected !== prevSelected) {
|
|
81
|
+
setPrevSelected(selected);
|
|
82
|
+
if (selected) setCurrentMonth(selected);
|
|
83
|
+
}
|
|
84
|
+
// Close on outside click
|
|
85
|
+
useEffect(function () {
|
|
86
|
+
var handleClickOutside = function handleClickOutside(e) {
|
|
87
|
+
if (datePickerRef.current && !datePickerRef.current.contains(e.target) && popupRef.current && !popupRef.current.contains(e.target)) {
|
|
88
|
+
setIsOpen(false);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
92
|
+
return function () {
|
|
93
|
+
return document.removeEventListener("mousedown", handleClickOutside);
|
|
94
|
+
};
|
|
95
|
+
}, []);
|
|
96
|
+
// Close on escape and keyboard navigation when open
|
|
97
|
+
useEffect(function () {
|
|
98
|
+
var handleKey = function handleKey(e) {
|
|
99
|
+
if (!isOpen) return;
|
|
100
|
+
if (e.key === "Escape") {
|
|
101
|
+
setIsOpen(false);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
document.addEventListener("keydown", handleKey);
|
|
105
|
+
return function () {
|
|
106
|
+
return document.removeEventListener("keydown", handleKey);
|
|
107
|
+
};
|
|
108
|
+
}, [isOpen]);
|
|
109
|
+
// compute calendar grid (includes previous/next month's tail days for proper alignment)
|
|
110
|
+
var monthStart = startOfMonth(currentMonth);
|
|
111
|
+
var monthGridStart = startOfWeek(monthStart, {
|
|
112
|
+
weekStartsOn: weekStartsOn
|
|
113
|
+
});
|
|
114
|
+
var monthEnd = endOfMonth(currentMonth);
|
|
115
|
+
var monthGridEnd = endOfWeek(monthEnd, {
|
|
116
|
+
weekStartsOn: weekStartsOn
|
|
117
|
+
});
|
|
118
|
+
var days = useMemo(function () {
|
|
119
|
+
return eachDayOfInterval({
|
|
120
|
+
start: monthGridStart,
|
|
121
|
+
end: monthGridEnd
|
|
122
|
+
});
|
|
123
|
+
}, [monthGridStart, monthGridEnd]);
|
|
124
|
+
// normalize min/max to startOfDay for consistent comparisons
|
|
125
|
+
var min = minDate ? startOfDay(typeof minDate === "string" ? parseISO(minDate) : minDate) : null;
|
|
126
|
+
var max = maxDate ? startOfDay(typeof maxDate === "string" ? parseISO(maxDate) : maxDate) : null;
|
|
127
|
+
var isDateDisabled = function isDateDisabled(date) {
|
|
128
|
+
var d = startOfDay(date);
|
|
129
|
+
if (min && isBefore(d, min)) return true;
|
|
130
|
+
if (max && isAfter(d, max)) return true;
|
|
131
|
+
return false;
|
|
132
|
+
};
|
|
133
|
+
var formatDisplayValue = function formatDisplayValue() {
|
|
134
|
+
if (!selected) return placeholder;
|
|
135
|
+
return format(selected, displayFormat, {
|
|
136
|
+
locale: locale
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
var handleDateSelect = function handleDateSelect(date) {
|
|
140
|
+
if (isDateDisabled(date)) return;
|
|
141
|
+
onChange === null || onChange === void 0 || onChange(date);
|
|
142
|
+
if (closeOnSelect) setIsOpen(false);
|
|
143
|
+
};
|
|
144
|
+
// keyboard navigation inside the calendar grid
|
|
145
|
+
var focusDayAtIndex = function focusDayAtIndex(index) {
|
|
146
|
+
var btn = gridButtonRefs.current[index];
|
|
147
|
+
if (btn && typeof btn.focus === "function") btn.focus();
|
|
148
|
+
};
|
|
149
|
+
var handleGridKeyDown = function handleGridKeyDown(e, idx) {
|
|
150
|
+
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", "Enter"].includes(e.key)) {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
}
|
|
153
|
+
switch (e.key) {
|
|
154
|
+
case "ArrowLeft":
|
|
155
|
+
focusDayAtIndex(Math.max(0, idx - 1));
|
|
156
|
+
break;
|
|
157
|
+
case "ArrowRight":
|
|
158
|
+
focusDayAtIndex(Math.min(days.length - 1, idx + 1));
|
|
159
|
+
break;
|
|
160
|
+
case "ArrowUp":
|
|
161
|
+
focusDayAtIndex(Math.max(0, idx - 7));
|
|
162
|
+
break;
|
|
163
|
+
case "ArrowDown":
|
|
164
|
+
focusDayAtIndex(Math.min(days.length - 1, idx + 7));
|
|
165
|
+
break;
|
|
166
|
+
case "PageUp":
|
|
167
|
+
setCurrentMonth(function (m) {
|
|
168
|
+
return subMonths(m, 1);
|
|
169
|
+
});
|
|
170
|
+
break;
|
|
171
|
+
case "PageDown":
|
|
172
|
+
setCurrentMonth(function (m) {
|
|
173
|
+
return addMonths(m, 1);
|
|
174
|
+
});
|
|
175
|
+
break;
|
|
176
|
+
case "Home":
|
|
177
|
+
focusDayAtIndex(Math.floor(idx / 7) * 7);
|
|
178
|
+
break;
|
|
179
|
+
case "End":
|
|
180
|
+
focusDayAtIndex(Math.min(days.length - 1, Math.floor(idx / 7) * 7 + 6));
|
|
181
|
+
break;
|
|
182
|
+
case "Enter":
|
|
183
|
+
if (!isDateDisabled(days[idx])) handleDateSelect(days[idx]);
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
var openAndFocusSelected = function openAndFocusSelected() {
|
|
188
|
+
setIsOpen(true);
|
|
189
|
+
// focus after opening on next tick
|
|
190
|
+
setTimeout(function () {
|
|
191
|
+
var idx = selected ? days.findIndex(function (d) {
|
|
192
|
+
return isSameDay(d, selected);
|
|
193
|
+
}) : days.findIndex(function (d) {
|
|
194
|
+
return isToday(d);
|
|
195
|
+
});
|
|
196
|
+
if (idx >= 0) focusDayAtIndex(idx);
|
|
197
|
+
}, 0);
|
|
198
|
+
};
|
|
199
|
+
// compute popup position so it's aware of viewport edges (top/bottom/left/right)
|
|
200
|
+
var computePopupPosition = function computePopupPosition() {
|
|
201
|
+
var margin = 8;
|
|
202
|
+
var trigger = datePickerRef.current;
|
|
203
|
+
var popup = popupRef.current;
|
|
204
|
+
if (!trigger || !popup) return;
|
|
205
|
+
var triggerRect = trigger.getBoundingClientRect();
|
|
206
|
+
// measure popup by temporarily making it visible if hidden
|
|
207
|
+
var popupRect = popup.getBoundingClientRect();
|
|
208
|
+
// If the popup is not yet fully measured (width/height 0), try to read offsetWidth/Height
|
|
209
|
+
if (popupRect.width === 0 || popupRect.height === 0) {
|
|
210
|
+
popupRect = {
|
|
211
|
+
width: popup.offsetWidth || 240,
|
|
212
|
+
height: popup.offsetHeight || 300
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
// Decide vertical placement
|
|
216
|
+
var spaceBelow = window.innerHeight - triggerRect.bottom;
|
|
217
|
+
var spaceAbove = triggerRect.top;
|
|
218
|
+
var placeBelow = spaceBelow >= popupRect.height + margin;
|
|
219
|
+
if (!placeBelow && spaceAbove >= popupRect.height + margin) placeBelow = false;
|
|
220
|
+
// If neither side has full space, pick the side with more space
|
|
221
|
+
if (!placeBelow && spaceBelow < popupRect.height + margin && spaceAbove < popupRect.height + margin) {
|
|
222
|
+
placeBelow = spaceBelow >= spaceAbove;
|
|
223
|
+
}
|
|
224
|
+
// compute top coordinate (fixed positioning)
|
|
225
|
+
var top;
|
|
226
|
+
if (placeBelow) {
|
|
227
|
+
top = Math.min(window.innerHeight - margin - popupRect.height, triggerRect.bottom + margin);
|
|
228
|
+
} else {
|
|
229
|
+
top = Math.max(margin, triggerRect.top - popupRect.height - margin);
|
|
230
|
+
}
|
|
231
|
+
// Decide horizontal placement (try align left to trigger)
|
|
232
|
+
var left = triggerRect.left;
|
|
233
|
+
// If overflowing right, shift left
|
|
234
|
+
if (left + popupRect.width > window.innerWidth - margin) {
|
|
235
|
+
left = Math.max(margin, window.innerWidth - margin - popupRect.width);
|
|
236
|
+
}
|
|
237
|
+
// If overflowing left, clamp
|
|
238
|
+
if (left < margin) left = margin;
|
|
239
|
+
var transformOrigin = placeBelow ? "top left" : "bottom left";
|
|
240
|
+
setPopupStyle({
|
|
241
|
+
position: "fixed",
|
|
242
|
+
top: "".concat(Math.round(top), "px"),
|
|
243
|
+
left: "".concat(Math.round(left), "px"),
|
|
244
|
+
zIndex: 9999,
|
|
245
|
+
transformOrigin: transformOrigin
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
// recompute on open, on resize/scroll, and when popup content changes (currentMonth)
|
|
249
|
+
useLayoutEffect(function () {
|
|
250
|
+
if (!isOpen) return;
|
|
251
|
+
// Measuring the DOM and positioning the popup before paint is the
|
|
252
|
+
// intended use of a layout effect, so the setState inside is deliberate.
|
|
253
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
254
|
+
computePopupPosition();
|
|
255
|
+
var handleResize = function handleResize() {
|
|
256
|
+
return computePopupPosition();
|
|
257
|
+
};
|
|
258
|
+
window.addEventListener("resize", handleResize);
|
|
259
|
+
window.addEventListener("scroll", handleResize, true); // capture scrolling in ancestors
|
|
260
|
+
return function () {
|
|
261
|
+
window.removeEventListener("resize", handleResize);
|
|
262
|
+
window.removeEventListener("scroll", handleResize, true);
|
|
263
|
+
};
|
|
264
|
+
}, [isOpen, currentMonth]);
|
|
265
|
+
var header = jsxs("div", {
|
|
266
|
+
className: "mb-4 flex items-center justify-between",
|
|
267
|
+
children: [jsx("button", {
|
|
268
|
+
type: "button",
|
|
269
|
+
className: "rounded-md p-1 hover:bg-gray-100",
|
|
270
|
+
onClick: function onClick() {
|
|
271
|
+
return setCurrentMonth(subMonths(currentMonth, 1));
|
|
272
|
+
},
|
|
273
|
+
"aria-label": "Previous month",
|
|
274
|
+
children: jsx(ChevronLeft, {
|
|
275
|
+
className: "h-4 w-4"
|
|
276
|
+
})
|
|
277
|
+
}), jsx("h3", {
|
|
278
|
+
className: "text-sm font-medium",
|
|
279
|
+
children: format(currentMonth, "MMMM yyyy")
|
|
280
|
+
}), jsx("button", {
|
|
281
|
+
type: "button",
|
|
282
|
+
className: "rounded-md p-1 hover:bg-gray-100",
|
|
283
|
+
onClick: function onClick() {
|
|
284
|
+
return setCurrentMonth(addMonths(currentMonth, 1));
|
|
285
|
+
},
|
|
286
|
+
"aria-label": "Next month",
|
|
287
|
+
children: jsx(ChevronRight, {
|
|
288
|
+
className: "h-4 w-4"
|
|
289
|
+
})
|
|
290
|
+
})]
|
|
291
|
+
});
|
|
292
|
+
var calendarPopup = jsxs("div", {
|
|
293
|
+
ref: popupRef,
|
|
294
|
+
className: "w-80 rounded-md border border-gray-300 bg-white p-4 shadow-lg",
|
|
295
|
+
role: "dialog",
|
|
296
|
+
"aria-modal": "false",
|
|
297
|
+
style: popupStyle,
|
|
298
|
+
children: [header, jsx("div", {
|
|
299
|
+
className: "mb-2 grid grid-cols-7 gap-1",
|
|
300
|
+
children: Array.from({
|
|
301
|
+
length: 7
|
|
302
|
+
}).map(function (_, i) {
|
|
303
|
+
var dayIndex = (i + weekStartsOn) % 7;
|
|
304
|
+
var label = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"][dayIndex];
|
|
305
|
+
return jsx("div", {
|
|
306
|
+
className: "p-2 text-center text-xs font-medium text-primary-500",
|
|
307
|
+
children: label
|
|
308
|
+
}, label);
|
|
309
|
+
})
|
|
310
|
+
}), jsx("div", {
|
|
311
|
+
className: "grid grid-cols-7 gap-1",
|
|
312
|
+
role: "grid",
|
|
313
|
+
children: days.map(function (day, idx) {
|
|
314
|
+
var isSelected = selected && isSameDay(day, selected);
|
|
315
|
+
var isCurrentMonth = isSameMonth(day, currentMonth);
|
|
316
|
+
var isTodayDate = isToday(day);
|
|
317
|
+
var isDisabled = isDateDisabled(day);
|
|
318
|
+
return jsx("button", {
|
|
319
|
+
type: "button",
|
|
320
|
+
ref: function ref(el) {
|
|
321
|
+
return gridButtonRefs.current[idx] = el;
|
|
322
|
+
},
|
|
323
|
+
role: "gridcell",
|
|
324
|
+
tabIndex: isSelected ? 0 : -1,
|
|
325
|
+
"aria-selected": isSelected,
|
|
326
|
+
onKeyDown: function onKeyDown(e) {
|
|
327
|
+
return handleGridKeyDown(e, idx);
|
|
328
|
+
},
|
|
329
|
+
className: cn("h-8 w-8 rounded-md text-sm transition-colors focus:outline-2 focus:outline-offset-1", {
|
|
330
|
+
"text-primary-400": !isCurrentMonth,
|
|
331
|
+
"bg-primary-600 text-white": isSelected,
|
|
332
|
+
"bg-primary-100 text-primary-600": isTodayDate && !isSelected,
|
|
333
|
+
"hover:bg-gray-100": isCurrentMonth && !isSelected && !isDisabled,
|
|
334
|
+
"cursor-not-allowed opacity-50": isDisabled
|
|
335
|
+
}),
|
|
336
|
+
onClick: function onClick() {
|
|
337
|
+
return !isDisabled && handleDateSelect(day);
|
|
338
|
+
},
|
|
339
|
+
disabled: isDisabled,
|
|
340
|
+
children: format(day, "d")
|
|
341
|
+
}, day.toISOString());
|
|
342
|
+
})
|
|
343
|
+
}), jsxs("div", {
|
|
344
|
+
className: "mt-3 flex items-center justify-between",
|
|
345
|
+
children: [jsxs("div", {
|
|
346
|
+
className: "flex gap-2",
|
|
347
|
+
children: [showClear && jsx("button", {
|
|
348
|
+
type: "button",
|
|
349
|
+
className: "rounded-md px-2 py-1 text-xs hover:bg-gray-100",
|
|
350
|
+
onClick: function onClick() {
|
|
351
|
+
onChange === null || onChange === void 0 || onChange(null);
|
|
352
|
+
},
|
|
353
|
+
children: "Clear"
|
|
354
|
+
}), jsx("button", {
|
|
355
|
+
type: "button",
|
|
356
|
+
className: "rounded-md px-2 py-1 text-xs hover:bg-gray-100",
|
|
357
|
+
onClick: function onClick() {
|
|
358
|
+
var t = new Date();
|
|
359
|
+
onChange === null || onChange === void 0 || onChange(t);
|
|
360
|
+
setCurrentMonth(t);
|
|
361
|
+
if (closeOnSelect) setIsOpen(false);
|
|
362
|
+
},
|
|
363
|
+
children: "Today"
|
|
364
|
+
})]
|
|
365
|
+
}), jsx("div", {
|
|
366
|
+
className: "text-xs text-primary-500",
|
|
367
|
+
children: formatDisplayValue()
|
|
368
|
+
})]
|
|
369
|
+
})]
|
|
370
|
+
});
|
|
371
|
+
return jsxs("div", {
|
|
372
|
+
className: "w-full",
|
|
373
|
+
children: [label && jsxs("label", {
|
|
374
|
+
id: labelId,
|
|
375
|
+
htmlFor: fieldId,
|
|
376
|
+
className: "block text-sm font-medium mb-1",
|
|
377
|
+
children: [label, required && jsx("span", {
|
|
378
|
+
className: "text-error-500 ml-1",
|
|
379
|
+
children: "*"
|
|
380
|
+
})]
|
|
381
|
+
}), jsxs("div", {
|
|
382
|
+
ref: datePickerRef,
|
|
383
|
+
className: "relative",
|
|
384
|
+
children: [jsxs("button", _objectSpread2(_objectSpread2({
|
|
385
|
+
type: "button",
|
|
386
|
+
id: fieldId,
|
|
387
|
+
"aria-labelledby": label ? "".concat(labelId, " ").concat(valueId) : valueId,
|
|
388
|
+
"aria-describedby": error ? errorId : helperText ? helperId : undefined,
|
|
389
|
+
"aria-invalid": error ? true : undefined,
|
|
390
|
+
className: cn("flex w-full items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50", {
|
|
391
|
+
"border-error-500 focus:ring-error-500": error,
|
|
392
|
+
"text-primary-500": !selected
|
|
393
|
+
}, className),
|
|
394
|
+
onClick: function onClick() {
|
|
395
|
+
return isOpen ? setIsOpen(false) : openAndFocusSelected();
|
|
396
|
+
},
|
|
397
|
+
disabled: disabled,
|
|
398
|
+
"aria-haspopup": "dialog",
|
|
399
|
+
"aria-expanded": isOpen
|
|
400
|
+
}, props), {}, {
|
|
401
|
+
children: [jsx("span", {
|
|
402
|
+
className: "truncate",
|
|
403
|
+
id: valueId,
|
|
404
|
+
children: formatDisplayValue()
|
|
405
|
+
}), jsxs("div", {
|
|
406
|
+
className: "flex items-center gap-2",
|
|
407
|
+
children: [showClear && selected && jsx("div", {
|
|
408
|
+
type: "button",
|
|
409
|
+
onClick: function onClick(e) {
|
|
410
|
+
e.stopPropagation();
|
|
411
|
+
onChange === null || onChange === void 0 || onChange(null);
|
|
412
|
+
},
|
|
413
|
+
"aria-label": "Clear date",
|
|
414
|
+
className: "p-1",
|
|
415
|
+
children: jsx(X, {
|
|
416
|
+
className: "h-4 w-4 text-primary-400"
|
|
417
|
+
})
|
|
418
|
+
}), jsx(Calendar, {
|
|
419
|
+
className: "h-4 w-4 text-primary-400"
|
|
420
|
+
})]
|
|
421
|
+
})]
|
|
422
|
+
})), isOpen && (portal ? /*#__PURE__*/ReactDOM.createPortal(calendarPopup, document.body) : calendarPopup)]
|
|
423
|
+
}), error ? jsx("p", {
|
|
424
|
+
id: errorId,
|
|
425
|
+
className: "mt-1 text-sm text-error-500",
|
|
426
|
+
children: error
|
|
427
|
+
}) : helperText ? jsx("p", {
|
|
428
|
+
id: helperId,
|
|
429
|
+
className: "mt-1 text-sm text-muted",
|
|
430
|
+
children: helperText
|
|
431
|
+
}) : null]
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
DatePicker.displayName = "DatePicker";
|
|
435
|
+
|
|
436
|
+
export { DatePicker as default };
|