@dreamtree-org/twreact-ui 1.3.11 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.md +40 -6
  2. package/ai-skills/dreamtree-ui.md +47 -9
  3. package/codemods/v2.cjs +198 -0
  4. package/dist/ai-schema.json +609 -33
  5. package/dist/components/blocks/AppShell.d.ts.map +1 -1
  6. package/dist/components/blocks/BottomActionBar.d.ts +6 -0
  7. package/dist/components/blocks/BottomActionBar.d.ts.map +1 -0
  8. package/dist/components/blocks/ConfirmDialog.d.ts.map +1 -1
  9. package/dist/components/blocks/PageHeader.d.ts.map +1 -1
  10. package/dist/components/core/Checkbox.d.ts.map +1 -1
  11. package/dist/components/core/DatePicker.d.ts.map +1 -1
  12. package/dist/components/core/DateRangePicker.d.ts.map +1 -1
  13. package/dist/components/core/Form.d.ts.map +1 -1
  14. package/dist/components/core/Input.d.ts.map +1 -1
  15. package/dist/components/core/Popover.d.ts.map +1 -1
  16. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  17. package/dist/components/core/Rate.d.ts.map +1 -1
  18. package/dist/components/core/SearchField.d.ts +9 -0
  19. package/dist/components/core/SearchField.d.ts.map +1 -0
  20. package/dist/components/core/SegmentedControl.d.ts +8 -0
  21. package/dist/components/core/SegmentedControl.d.ts.map +1 -0
  22. package/dist/components/core/Select.d.ts.map +1 -1
  23. package/dist/components/core/SwipeableListItem.d.ts +4 -0
  24. package/dist/components/core/SwipeableListItem.d.ts.map +1 -0
  25. package/dist/components/core/SwipeableListItemGesture.d.ts +58 -0
  26. package/dist/components/core/SwipeableListItemGesture.d.ts.map +1 -0
  27. package/dist/components/core/Switch.d.ts.map +1 -1
  28. package/dist/components/core/Table/ActionMenu.d.ts +10 -3
  29. package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
  30. package/dist/components/core/Table/MobileCard.d.ts +10 -1
  31. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  32. package/dist/components/core/Table/MobileFilters.d.ts +8 -2
  33. package/dist/components/core/Table/MobileFilters.d.ts.map +1 -1
  34. package/dist/components/core/Table/Table.d.ts.map +1 -1
  35. package/dist/components/core/Table/TableRow.d.ts +2 -1
  36. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  37. package/dist/components/core/Tabs.d.ts +3 -3
  38. package/dist/components/core/Tabs.d.ts.map +1 -1
  39. package/dist/components/core/ThreeDotPopover.d.ts +10 -22
  40. package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
  41. package/dist/components/core/Tooltip.d.ts +2 -1
  42. package/dist/components/core/Tooltip.d.ts.map +1 -1
  43. package/dist/components/core/internal/Calendar.d.ts +77 -0
  44. package/dist/components/core/internal/Calendar.d.ts.map +1 -0
  45. package/dist/components/core/menu/ActionMenuSurface.d.ts +42 -0
  46. package/dist/components/core/menu/ActionMenuSurface.d.ts.map +1 -0
  47. package/dist/components/core/menu/ActionSheetMenu.d.ts +17 -0
  48. package/dist/components/core/menu/ActionSheetMenu.d.ts.map +1 -0
  49. package/dist/components/core/menu/MenuPopover.d.ts +21 -0
  50. package/dist/components/core/menu/MenuPopover.d.ts.map +1 -0
  51. package/dist/components/core/menu/menuItems.d.ts +21 -0
  52. package/dist/components/core/menu/menuItems.d.ts.map +1 -0
  53. package/dist/components/core/menu/menuKeyboard.d.ts +16 -0
  54. package/dist/components/core/menu/menuKeyboard.d.ts.map +1 -0
  55. package/dist/components/feedback/ActionSheet.d.ts +4 -0
  56. package/dist/components/feedback/ActionSheet.d.ts.map +1 -0
  57. package/dist/components/feedback/Alert.d.ts.map +1 -1
  58. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  59. package/dist/components/feedback/Drawer.d.ts.map +1 -1
  60. package/dist/components/feedback/Sheet.d.ts +4 -0
  61. package/dist/components/feedback/Sheet.d.ts.map +1 -0
  62. package/dist/components/feedback/Toast.d.ts +4 -3
  63. package/dist/components/feedback/Toast.d.ts.map +1 -1
  64. package/dist/components/feedback/ToastItem.d.ts +47 -0
  65. package/dist/components/feedback/ToastItem.d.ts.map +1 -0
  66. package/dist/components/feedback/ToastStack.d.ts +20 -0
  67. package/dist/components/feedback/ToastStack.d.ts.map +1 -0
  68. package/dist/components/feedback/ToastSwipe.d.ts +22 -0
  69. package/dist/components/feedback/ToastSwipe.d.ts.map +1 -0
  70. package/dist/components/feedback/Tour.d.ts.map +1 -1
  71. package/dist/components/feedback/sheetCore.d.ts +30 -0
  72. package/dist/components/feedback/sheetCore.d.ts.map +1 -0
  73. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  74. package/dist/components/navigation/Sidebar.d.ts +6 -0
  75. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  76. package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -1
  77. package/dist/components/rich-text/RichTextToolbar.d.ts +6 -2
  78. package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -1
  79. package/dist/components/utility/PullToRefresh.d.ts +5 -0
  80. package/dist/components/utility/PullToRefresh.d.ts.map +1 -0
  81. package/dist/esm/components/blocks/AppShell.js +97 -90
  82. package/dist/esm/components/blocks/BottomActionBar.js +132 -0
  83. package/dist/esm/components/blocks/ConfirmDialog.js +40 -4
  84. package/dist/esm/components/blocks/PageHeader.js +16 -3
  85. package/dist/esm/components/core/Checkbox.js +13 -24
  86. package/dist/esm/components/core/DatePicker.js +117 -304
  87. package/dist/esm/components/core/DateRangePicker.js +260 -308
  88. package/dist/esm/components/core/Form.js +11 -2
  89. package/dist/esm/components/core/Input.js +13 -18
  90. package/dist/esm/components/core/Popover.js +59 -48
  91. package/dist/esm/components/core/ProgressBar.js +36 -64
  92. package/dist/esm/components/core/Rate.js +5 -10
  93. package/dist/esm/components/core/SearchField.js +311 -0
  94. package/dist/esm/components/core/SegmentedControl.js +189 -0
  95. package/dist/esm/components/core/Select.js +185 -190
  96. package/dist/esm/components/core/SwipeableListItem.js +286 -0
  97. package/dist/esm/components/core/SwipeableListItemGesture.js +219 -0
  98. package/dist/esm/components/core/Switch.js +11 -13
  99. package/dist/esm/components/core/Table/ActionMenu.js +45 -231
  100. package/dist/esm/components/core/Table/ColumnMenu.js +1 -1
  101. package/dist/esm/components/core/Table/MobileCard.js +66 -16
  102. package/dist/esm/components/core/Table/MobileFilters.js +181 -10
  103. package/dist/esm/components/core/Table/Table.js +149 -102
  104. package/dist/esm/components/core/Table/TableRow.js +10 -2
  105. package/dist/esm/components/core/Tabs.js +7 -7
  106. package/dist/esm/components/core/ThreeDotPopover.js +93 -99
  107. package/dist/esm/components/core/Tooltip.js +138 -145
  108. package/dist/esm/components/core/internal/Calendar.js +381 -0
  109. package/dist/esm/components/core/menu/ActionMenuSurface.js +110 -0
  110. package/dist/esm/components/core/menu/ActionSheetMenu.js +140 -0
  111. package/dist/esm/components/core/menu/MenuPopover.js +177 -0
  112. package/dist/esm/components/core/menu/menuItems.js +61 -0
  113. package/dist/esm/components/core/menu/menuKeyboard.js +54 -0
  114. package/dist/esm/components/feedback/ActionSheet.js +55 -0
  115. package/dist/esm/components/feedback/Alert.js +63 -53
  116. package/dist/esm/components/feedback/Dialog.js +141 -53
  117. package/dist/esm/components/feedback/Drawer.js +130 -132
  118. package/dist/esm/components/feedback/Sheet.js +125 -0
  119. package/dist/esm/components/feedback/Toast.js +21 -291
  120. package/dist/esm/components/feedback/ToastItem.js +348 -0
  121. package/dist/esm/components/feedback/ToastStack.js +130 -0
  122. package/dist/esm/components/feedback/ToastSwipe.js +52 -0
  123. package/dist/esm/components/feedback/Tour.js +107 -30
  124. package/dist/esm/components/feedback/sheetCore.js +494 -0
  125. package/dist/esm/components/navigation/Dropdown.js +1 -1
  126. package/dist/esm/components/navigation/Navbar.js +172 -37
  127. package/dist/esm/components/navigation/Sidebar.js +263 -111
  128. package/dist/esm/components/rich-text/RichTextEditor.js +9 -3
  129. package/dist/esm/components/rich-text/RichTextToolbar.js +29 -9
  130. package/dist/esm/components/utility/Portal.js +31 -0
  131. package/dist/esm/components/utility/PullToRefresh.js +229 -0
  132. package/dist/esm/hooks/useFloatingPosition.js +82 -0
  133. package/dist/esm/hooks/useHaptics.js +65 -0
  134. package/dist/esm/hooks/usePresence.js +58 -0
  135. package/dist/esm/hooks/usePresentation.js +21 -0
  136. package/dist/esm/hooks/useSheetDrag.js +220 -0
  137. package/dist/esm/index.js +13 -2
  138. package/dist/esm/utils/position.js +10 -63
  139. package/dist/hooks/useFloatingPosition.d.ts +8 -4
  140. package/dist/hooks/useFloatingPosition.d.ts.map +1 -1
  141. package/dist/hooks/useHaptics.d.ts +19 -0
  142. package/dist/hooks/useHaptics.d.ts.map +1 -0
  143. package/dist/hooks/useSheetDrag.d.ts +31 -0
  144. package/dist/hooks/useSheetDrag.d.ts.map +1 -0
  145. package/dist/index.css +1 -1
  146. package/dist/index.d.ts +9 -1
  147. package/dist/index.esm.css +1 -1
  148. package/dist/index.esm.js +8851 -3198
  149. package/dist/index.js +8856 -3195
  150. package/dist/rich-text/index.js +41 -11
  151. package/dist/types/blocks.d.ts +32 -2
  152. package/dist/types/blocks.d.ts.map +1 -1
  153. package/dist/types/index.d.ts +353 -19
  154. package/dist/types/index.d.ts.map +1 -1
  155. package/dist/types/rich-text.d.ts +5 -0
  156. package/dist/types/rich-text.d.ts.map +1 -1
  157. package/dist/utils/position.d.ts +0 -15
  158. package/dist/utils/position.d.ts.map +1 -1
  159. package/doc/README.md +15 -0
  160. package/mcp/catalog.snapshot.json +1398 -464
  161. package/package.json +7 -2
  162. package/dist/esm/hooks/useSwipeToClose.js +0 -66
  163. package/dist/hooks/useSwipeToClose.d.ts +0 -24
  164. package/dist/hooks/useSwipeToClose.d.ts.map +0 -1
@@ -1,14 +1,15 @@
1
1
  'use client';
2
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, isSameDay, subMonths, format, addMonths, isSameMonth, isToday, isBefore, isAfter, addDays } from 'date-fns';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+ import React, { useId, useMemo, useState, useRef, useCallback, useImperativeHandle, useEffect } from 'react';
5
+ import { isSameDay, format } from 'date-fns';
6
+ import { Calendar as Calendar$1, X } from 'lucide-react';
7
7
  import { cn } from '../../utils/cn.js';
8
- import { TOUCH_TARGET } from '../../utils/touchTarget.js';
9
- import { ChevronLeft, ChevronRight, Calendar, X } from 'lucide-react';
8
+ import { usePresentation } from '../../hooks/usePresentation.js';
9
+ import { useFloatingPosition } from '../../hooks/useFloatingPosition.js';
10
+ import { normalizeDate, useActiveDayFocusRef, makeIsDisabled, Calendar, PickerSurface } from './internal/Calendar.js';
10
11
 
11
- var _excluded = ["value", "onChange", "placeholder", "label", "error", "helperText", "disabled", "required", "minDate", "maxDate", "className", "weekStartsOn", "portal", "displayFormat", "locale", "showClear", "closeOnSelect"];
12
+ var _excluded = ["value", "onChange", "placeholder", "label", "error", "helperText", "disabled", "required", "minDate", "maxDate", "className", "weekStartsOn", "portal", "displayFormat", "locale", "showClear", "closeOnSelect", "presentation"];
12
13
  var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
13
14
  var value = _ref.value,
14
15
  onChange = _ref.onChange,
@@ -34,6 +35,8 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
34
35
  showClear = _ref$showClear === void 0 ? true : _ref$showClear,
35
36
  _ref$closeOnSelect = _ref.closeOnSelect,
36
37
  closeOnSelect = _ref$closeOnSelect === void 0 ? true : _ref$closeOnSelect,
38
+ _ref$presentation = _ref.presentation,
39
+ presentation = _ref$presentation === void 0 ? "auto" : _ref$presentation,
37
40
  props = _objectWithoutProperties(_ref, _excluded);
38
41
  // Stable ids wiring label / helper / error to the trigger button.
39
42
  // A consumer `id` (spread onto the trigger via ...props) wins.
@@ -43,17 +46,11 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
43
46
  var valueId = "".concat(fieldId, "-value");
44
47
  var errorId = "".concat(fieldId, "-error");
45
48
  var helperId = "".concat(fieldId, "-helper");
49
+ var mode = usePresentation(presentation);
50
+ var isSheet = mode === "sheet";
46
51
  // Normalize incoming value (accept Date or ISO string)
47
52
  var selected = useMemo(function () {
48
- if (!value) return null;
49
- if (typeof value === "string") {
50
- try {
51
- return parseISO(value);
52
- } catch (e) {
53
- return null;
54
- }
55
- }
56
- return value instanceof Date ? value : null;
53
+ return normalizeDate(value);
57
54
  }, [value]);
58
55
  var _useState = useState(false),
59
56
  _useState2 = _slicedToArray(_useState, 2),
@@ -66,32 +63,41 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
66
63
  var datePickerRef = useRef(null);
67
64
  var popupRef = useRef(null);
68
65
  var triggerRef = useRef(null);
69
- var gridButtonRefs = useRef([]);
70
- // Roving tabindex: the day the user moved to with the keyboard (or focused).
71
- var _useState5 = useState(null),
72
- _useState6 = _slicedToArray(_useState5, 2),
73
- focusedDate = _useState6[0],
74
- setFocusedDate = _useState6[1];
75
- // Set when a keyboard action / open should move DOM focus to the active day.
76
- var pendingFocusRef = useRef(false);
77
- var _useState7 = useState({}),
78
- _useState8 = _slicedToArray(_useState7, 2),
79
- popupStyle = _useState8[0],
80
- setPopupStyle = _useState8[1];
66
+ var gridRef = useRef(null);
67
+ var initialFocus = useActiveDayFocusRef(gridRef);
68
+ var _useFloatingPosition = useFloatingPosition({
69
+ placement: "bottom-start",
70
+ offset: 8,
71
+ open: isOpen && !isSheet
72
+ }),
73
+ refs = _useFloatingPosition.refs,
74
+ floatingStyles = _useFloatingPosition.floatingStyles,
75
+ isPositioned = _useFloatingPosition.isPositioned;
76
+ var setReference = refs.setReference,
77
+ setFloating = refs.setFloating;
78
+ var fieldRef = useCallback(function (node) {
79
+ datePickerRef.current = node;
80
+ setReference(node);
81
+ }, [setReference]);
82
+ var floatingRef = useCallback(function (node) {
83
+ popupRef.current = node;
84
+ setFloating(node);
85
+ }, [setFloating]);
81
86
  useImperativeHandle(forwardedRef, function () {
82
87
  return datePickerRef.current;
83
88
  }, []);
84
89
  // Keep currentMonth in sync with external value changes
85
- var _useState9 = useState(selected),
86
- _useState0 = _slicedToArray(_useState9, 2),
87
- prevSelected = _useState0[0],
88
- setPrevSelected = _useState0[1];
90
+ var _useState5 = useState(selected),
91
+ _useState6 = _slicedToArray(_useState5, 2),
92
+ prevSelected = _useState6[0],
93
+ setPrevSelected = _useState6[1];
89
94
  if (selected !== prevSelected) {
90
95
  setPrevSelected(selected);
91
96
  if (selected) setCurrentMonth(selected);
92
97
  }
93
- // Close on outside click
98
+ // Popover only: close on outside click (the sheet has its own backdrop).
94
99
  useEffect(function () {
100
+ if (isSheet) return undefined;
95
101
  var handleClickOutside = function handleClickOutside(e) {
96
102
  if (datePickerRef.current && !datePickerRef.current.contains(e.target) && popupRef.current && !popupRef.current.contains(e.target)) {
97
103
  setIsOpen(false);
@@ -101,9 +107,11 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
101
107
  return function () {
102
108
  return document.removeEventListener("mousedown", handleClickOutside);
103
109
  };
104
- }, []);
105
- // Close on escape and keyboard navigation when open
110
+ }, [isSheet]);
111
+ // Popover only: Escape closes and returns focus to the field (the sheet's
112
+ // focus trap handles Escape itself).
106
113
  useEffect(function () {
114
+ if (isSheet) return undefined;
107
115
  var handleKey = function handleKey(e) {
108
116
  if (!isOpen) return;
109
117
  if (e.key === "Escape") {
@@ -117,290 +125,68 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
117
125
  return function () {
118
126
  return document.removeEventListener("keydown", handleKey);
119
127
  };
120
- }, [isOpen]);
121
- // compute calendar grid (includes previous/next month's tail days for proper alignment)
122
- var monthStart = startOfMonth(currentMonth);
123
- var monthGridStart = startOfWeek(monthStart, {
124
- weekStartsOn: weekStartsOn
125
- });
126
- var monthEnd = endOfMonth(currentMonth);
127
- var monthGridEnd = endOfWeek(monthEnd, {
128
- weekStartsOn: weekStartsOn
129
- });
130
- var days = useMemo(function () {
131
- return eachDayOfInterval({
132
- start: monthGridStart,
133
- end: monthGridEnd
134
- });
135
- }, [monthGridStart, monthGridEnd]);
136
- // normalize min/max to startOfDay for consistent comparisons
137
- var min = minDate ? startOfDay(typeof minDate === "string" ? parseISO(minDate) : minDate) : null;
138
- var max = maxDate ? startOfDay(typeof maxDate === "string" ? parseISO(maxDate) : maxDate) : null;
139
- var isDateDisabled = function isDateDisabled(date) {
140
- var d = startOfDay(date);
141
- if (min && isBefore(d, min)) return true;
142
- if (max && isAfter(d, max)) return true;
143
- return false;
144
- };
128
+ }, [isOpen, isSheet]);
129
+ var isDateDisabled = makeIsDisabled(minDate, maxDate);
145
130
  var formatDisplayValue = function formatDisplayValue() {
146
131
  if (!selected) return placeholder;
147
132
  return format(selected, displayFormat, {
148
133
  locale: locale
149
134
  });
150
135
  };
136
+ var close = function close() {
137
+ var _triggerRef$current2;
138
+ setIsOpen(false);
139
+ // The focused day unmounts with the popup; keep focus on the field.
140
+ (_triggerRef$current2 = triggerRef.current) === null || _triggerRef$current2 === void 0 || _triggerRef$current2.focus();
141
+ };
151
142
  var handleDateSelect = function handleDateSelect(date) {
152
143
  if (isDateDisabled(date)) return;
153
144
  onChange === null || onChange === void 0 || onChange(date);
154
- if (closeOnSelect) {
155
- var _triggerRef$current2;
156
- setIsOpen(false);
157
- // The focused day unmounts with the popup; keep focus on the field.
158
- (_triggerRef$current2 = triggerRef.current) === null || _triggerRef$current2 === void 0 || _triggerRef$current2.focus();
159
- }
160
- };
161
- // Roving tabindex target: exactly one enabled day in the grid is tabbable.
162
- // Priority: keyboard-focused day ?? selected ?? today (if shown & enabled)
163
- // ?? first enabled day of the visible month ?? first enabled grid day.
164
- var isUsable = function isUsable(d) {
165
- return d && isSameMonth(d, currentMonth) && !isDateDisabled(d);
166
- };
167
- var activeDate = null;
168
- if (isUsable(focusedDate)) activeDate = focusedDate;else if (isUsable(selected)) activeDate = selected;else if (isUsable(new Date())) activeDate = new Date();else activeDate = days.find(function (d) {
169
- return isUsable(d);
170
- }) || days.find(function (d) {
171
- return !isDateDisabled(d);
172
- }) || null;
173
- var activeIndex = activeDate ? days.findIndex(function (d) {
174
- return isSameDay(d, activeDate);
175
- }) : -1;
176
- // Move DOM focus to the active day after a keyboard action / open.
177
- useEffect(function () {
178
- if (!isOpen || !pendingFocusRef.current) return;
179
- pendingFocusRef.current = false;
180
- var btn = gridButtonRefs.current[activeIndex];
181
- if (btn && typeof btn.focus === "function") btn.focus();
182
- });
183
- var moveFocusTo = function moveFocusTo(date) {
184
- if (!date || isDateDisabled(date)) return;
185
- if (!isSameMonth(date, currentMonth)) setCurrentMonth(date);
186
- setFocusedDate(date);
187
- pendingFocusRef.current = true;
188
- };
189
- var handleGridKeyDown = function handleGridKeyDown(e, idx) {
190
- var day = days[idx];
191
- if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", "Enter"].includes(e.key)) {
192
- e.preventDefault();
193
- }
194
- switch (e.key) {
195
- case "ArrowLeft":
196
- moveFocusTo(addDays(day, -1));
197
- break;
198
- case "ArrowRight":
199
- moveFocusTo(addDays(day, 1));
200
- break;
201
- case "ArrowUp":
202
- moveFocusTo(addDays(day, -7));
203
- break;
204
- case "ArrowDown":
205
- moveFocusTo(addDays(day, 7));
206
- break;
207
- case "PageUp":
208
- moveFocusTo(subMonths(day, 1));
209
- break;
210
- case "PageDown":
211
- moveFocusTo(addMonths(day, 1));
212
- break;
213
- case "Home":
214
- moveFocusTo(days[Math.floor(idx / 7) * 7]);
215
- break;
216
- case "End":
217
- moveFocusTo(days[Math.min(days.length - 1, Math.floor(idx / 7) * 7 + 6)]);
218
- break;
219
- case "Enter":
220
- if (!isDateDisabled(day)) handleDateSelect(day);
221
- break;
222
- }
145
+ if (closeOnSelect) close();
223
146
  };
224
- var openAndFocusSelected = function openAndFocusSelected() {
225
- setFocusedDate(null);
226
- setIsOpen(true);
227
- // the active-day effect moves focus once the grid has rendered
228
- pendingFocusRef.current = true;
147
+ var selectToday = function selectToday() {
148
+ var t = new Date();
149
+ onChange === null || onChange === void 0 || onChange(t);
150
+ setCurrentMonth(t);
151
+ if (closeOnSelect) close();
229
152
  };
230
- // compute popup position so it's aware of viewport edges (top/bottom/left/right)
231
- var computePopupPosition = function computePopupPosition() {
232
- var margin = 8;
233
- var trigger = datePickerRef.current;
234
- var popup = popupRef.current;
235
- if (!trigger || !popup) return;
236
- var triggerRect = trigger.getBoundingClientRect();
237
- // measure popup by temporarily making it visible if hidden
238
- var popupRect = popup.getBoundingClientRect();
239
- // If the popup is not yet fully measured (width/height 0), try to read offsetWidth/Height
240
- if (popupRect.width === 0 || popupRect.height === 0) {
241
- popupRect = {
242
- width: popup.offsetWidth || 240,
243
- height: popup.offsetHeight || 300
244
- };
245
- }
246
- // Decide vertical placement
247
- var spaceBelow = window.innerHeight - triggerRect.bottom;
248
- var spaceAbove = triggerRect.top;
249
- var placeBelow = spaceBelow >= popupRect.height + margin;
250
- if (!placeBelow && spaceAbove >= popupRect.height + margin) placeBelow = false;
251
- // If neither side has full space, pick the side with more space
252
- if (!placeBelow && spaceBelow < popupRect.height + margin && spaceAbove < popupRect.height + margin) {
253
- placeBelow = spaceBelow >= spaceAbove;
254
- }
255
- // compute top coordinate (fixed positioning)
256
- var top;
257
- if (placeBelow) {
258
- top = Math.min(window.innerHeight - margin - popupRect.height, triggerRect.bottom + margin);
259
- } else {
260
- top = Math.max(margin, triggerRect.top - popupRect.height - margin);
261
- }
262
- // Decide horizontal placement (try align left to trigger)
263
- var left = triggerRect.left;
264
- // If overflowing right, shift left
265
- if (left + popupRect.width > window.innerWidth - margin) {
266
- left = Math.max(margin, window.innerWidth - margin - popupRect.width);
267
- }
268
- // If overflowing left, clamp
269
- if (left < margin) left = margin;
270
- var transformOrigin = placeBelow ? "top left" : "bottom left";
271
- setPopupStyle({
272
- position: "fixed",
273
- top: "".concat(Math.round(top), "px"),
274
- left: "".concat(Math.round(left), "px"),
275
- zIndex: 9999,
276
- transformOrigin: transformOrigin
277
- });
278
- };
279
- // recompute on open, on resize/scroll, and when popup content changes (currentMonth)
280
- useLayoutEffect(function () {
281
- if (!isOpen) return;
282
- // Measuring the DOM and positioning the popup before paint is the
283
- // intended use of a layout effect, so the setState inside is deliberate.
284
- // eslint-disable-next-line react-hooks/set-state-in-effect
285
- computePopupPosition();
286
- var handleResize = function handleResize() {
287
- return computePopupPosition();
288
- };
289
- window.addEventListener("resize", handleResize);
290
- window.addEventListener("scroll", handleResize, true); // capture scrolling in ancestors
291
- return function () {
292
- window.removeEventListener("resize", handleResize);
293
- window.removeEventListener("scroll", handleResize, true);
153
+ var getDayState = function getDayState(d) {
154
+ var isSel = Boolean(selected && isSameDay(d, selected));
155
+ return {
156
+ selected: isSel,
157
+ edge: isSel
294
158
  };
295
- }, [isOpen, currentMonth]);
296
- var header = jsxs("div", {
297
- className: "mb-4 flex items-center justify-between",
298
- children: [jsx("button", {
159
+ };
160
+ var actionClass = isSheet ? "rounded-md px-3 py-2 text-sm hover:bg-gray-100" : "rounded-md px-2 py-1 text-xs hover:bg-gray-100";
161
+ var actions = jsxs("div", {
162
+ className: "flex gap-2",
163
+ children: [showClear && jsx("button", {
299
164
  type: "button",
300
- className: cn("inline-flex items-center justify-center rounded-md p-1 hover:bg-gray-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", TOUCH_TARGET),
165
+ className: actionClass,
301
166
  onClick: function onClick() {
302
- return setCurrentMonth(subMonths(currentMonth, 1));
167
+ onChange === null || onChange === void 0 || onChange(null);
303
168
  },
304
- "aria-label": "Previous month",
305
- children: jsx(ChevronLeft, {
306
- className: "h-4 w-4"
307
- })
308
- }), jsx("h3", {
309
- className: "text-sm font-medium",
310
- children: format(currentMonth, "MMMM yyyy")
169
+ children: "Clear"
311
170
  }), jsx("button", {
312
171
  type: "button",
313
- className: cn("inline-flex items-center justify-center rounded-md p-1 hover:bg-gray-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", TOUCH_TARGET),
314
- onClick: function onClick() {
315
- return setCurrentMonth(addMonths(currentMonth, 1));
316
- },
317
- "aria-label": "Next month",
318
- children: jsx(ChevronRight, {
319
- className: "h-4 w-4"
320
- })
172
+ className: actionClass,
173
+ onClick: selectToday,
174
+ children: "Today"
321
175
  })]
322
176
  });
323
- var calendarPopup = jsxs("div", {
324
- ref: popupRef,
325
- className: "w-80 rounded-md border border-gray-300 bg-white p-4 shadow-lg",
326
- role: "dialog",
327
- "aria-modal": "false",
328
- style: popupStyle,
329
- children: [header, jsx("div", {
330
- className: "mb-2 grid grid-cols-7 gap-1",
331
- children: Array.from({
332
- length: 7
333
- }).map(function (_, i) {
334
- var dayIndex = (i + weekStartsOn) % 7;
335
- var label = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"][dayIndex];
336
- return jsx("div", {
337
- className: "p-2 text-center text-xs font-medium text-primary-500",
338
- children: label
339
- }, label);
340
- })
341
- }), jsx("div", {
342
- className: "grid grid-cols-7 gap-1",
343
- role: "grid",
344
- children: days.map(function (day, idx) {
345
- var isSelected = selected && isSameDay(day, selected);
346
- var isCurrentMonth = isSameMonth(day, currentMonth);
347
- var isTodayDate = isToday(day);
348
- var isDisabled = isDateDisabled(day);
349
- return jsx("button", {
350
- type: "button",
351
- ref: function ref(el) {
352
- return gridButtonRefs.current[idx] = el;
353
- },
354
- role: "gridcell",
355
- tabIndex: idx === activeIndex ? 0 : -1,
356
- "aria-selected": Boolean(isSelected),
357
- onKeyDown: function onKeyDown(e) {
358
- return handleGridKeyDown(e, idx);
359
- },
360
- onFocus: function onFocus() {
361
- if (!focusedDate || !isSameDay(focusedDate, day)) setFocusedDate(day);
362
- },
363
- className: cn("h-8 w-8 rounded-md text-sm transition-colors motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-1", {
364
- "text-primary-400": !isCurrentMonth,
365
- "bg-primary-600 text-white": isSelected,
366
- "bg-primary-100 text-primary-600": isTodayDate && !isSelected,
367
- "hover:bg-gray-100": isCurrentMonth && !isSelected && !isDisabled,
368
- "cursor-not-allowed opacity-50": isDisabled
369
- }),
370
- onClick: function onClick() {
371
- return !isDisabled && handleDateSelect(day);
372
- },
373
- disabled: isDisabled,
374
- children: format(day, "d")
375
- }, day.toISOString());
376
- })
377
- }), jsxs("div", {
378
- className: "mt-3 flex items-center justify-between",
379
- children: [jsxs("div", {
380
- className: "flex gap-2",
381
- children: [showClear && jsx("button", {
382
- type: "button",
383
- className: "rounded-md px-2 py-1 text-xs hover:bg-gray-100",
384
- onClick: function onClick() {
385
- onChange === null || onChange === void 0 || onChange(null);
386
- },
387
- children: "Clear"
388
- }), jsx("button", {
389
- type: "button",
390
- className: "rounded-md px-2 py-1 text-xs hover:bg-gray-100",
391
- onClick: function onClick() {
392
- var t = new Date();
393
- onChange === null || onChange === void 0 || onChange(t);
394
- setCurrentMonth(t);
395
- if (closeOnSelect) setIsOpen(false);
396
- },
397
- children: "Today"
398
- })]
399
- }), jsx("div", {
400
- className: "text-xs text-primary-500",
401
- children: formatDisplayValue()
402
- })]
403
- })]
177
+ var calendar = jsx(Calendar, {
178
+ month: currentMonth,
179
+ onMonthChange: setCurrentMonth,
180
+ weekStartsOn: weekStartsOn,
181
+ isDisabled: isDateDisabled,
182
+ getDayState: getDayState,
183
+ onSelect: handleDateSelect,
184
+ preferredDate: selected,
185
+ size: mode,
186
+ swipe: isSheet,
187
+ autoFocus: !isSheet,
188
+ locale: locale,
189
+ gridRef: gridRef
404
190
  });
405
191
  return jsxs("div", {
406
192
  className: "w-full",
@@ -413,7 +199,7 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
413
199
  children: "*"
414
200
  })]
415
201
  }), jsxs("div", {
416
- ref: datePickerRef,
202
+ ref: fieldRef,
417
203
  className: "relative",
418
204
  children: [jsxs("button", _objectSpread2(_objectSpread2({
419
205
  ref: triggerRef,
@@ -429,7 +215,9 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
429
215
  "pr-16": showClear && selected
430
216
  }, className),
431
217
  onClick: function onClick() {
432
- return isOpen ? setIsOpen(false) : openAndFocusSelected();
218
+ return setIsOpen(function (open) {
219
+ return !open;
220
+ });
433
221
  },
434
222
  disabled: disabled,
435
223
  "aria-haspopup": "dialog",
@@ -439,7 +227,7 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
439
227
  className: "truncate",
440
228
  id: valueId,
441
229
  children: formatDisplayValue()
442
- }), jsx(Calendar, {
230
+ }), jsx(Calendar$1, {
443
231
  className: "h-4 w-4 shrink-0 text-primary-400",
444
232
  "aria-hidden": "true"
445
233
  })]
@@ -458,7 +246,32 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
458
246
  className: "h-4 w-4",
459
247
  "aria-hidden": "true"
460
248
  })
461
- }), isOpen && (portal ? /*#__PURE__*/ReactDOM.createPortal(calendarPopup, document.body) : calendarPopup)]
249
+ }), jsxs(PickerSurface, {
250
+ mode: mode,
251
+ open: isOpen,
252
+ onClose: function onClose() {
253
+ return setIsOpen(false);
254
+ },
255
+ title: label || "Select date",
256
+ portal: portal,
257
+ floatingRef: floatingRef,
258
+ floatingStyles: floatingStyles,
259
+ isPositioned: isPositioned,
260
+ initialFocus: initialFocus,
261
+ sheetFooter: jsxs(Fragment, {
262
+ children: [actions, jsx("div", {
263
+ className: "text-sm text-primary-500",
264
+ children: formatDisplayValue()
265
+ })]
266
+ }),
267
+ children: [calendar, !isSheet && jsxs("div", {
268
+ className: "mt-3 flex items-center justify-between",
269
+ children: [actions, jsx("div", {
270
+ className: "text-xs text-primary-500",
271
+ children: formatDisplayValue()
272
+ })]
273
+ })]
274
+ })]
462
275
  }), error ? jsx("p", {
463
276
  id: errorId,
464
277
  className: "mt-1 text-sm text-error-500",