@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.
Files changed (234) hide show
  1. package/DESIGN.md +2 -2
  2. package/README.md +258 -10
  3. package/ai-skills/dreamtree-ui.md +111 -15
  4. package/charts/package.json +5 -0
  5. package/dist/_shared/cn-DPPQUJu1.js +138 -0
  6. package/dist/ai-schema.json +1252 -179
  7. package/dist/charts/index.d.ts +9 -0
  8. package/dist/charts/index.d.ts.map +1 -0
  9. package/dist/charts/index.js +769 -0
  10. package/dist/components/charts/AreaChart.d.ts +4 -0
  11. package/dist/components/charts/AreaChart.d.ts.map +1 -0
  12. package/dist/components/charts/BarChart.d.ts +4 -0
  13. package/dist/components/charts/BarChart.d.ts.map +1 -0
  14. package/dist/components/charts/CartesianChart.d.ts +5 -0
  15. package/dist/components/charts/CartesianChart.d.ts.map +1 -0
  16. package/dist/components/charts/ChartFrame.d.ts +18 -0
  17. package/dist/components/charts/ChartFrame.d.ts.map +1 -0
  18. package/dist/components/charts/DonutChart.d.ts +4 -0
  19. package/dist/components/charts/DonutChart.d.ts.map +1 -0
  20. package/dist/components/charts/LineChart.d.ts +4 -0
  21. package/dist/components/charts/LineChart.d.ts.map +1 -0
  22. package/dist/components/charts/Sparkline.d.ts +5 -0
  23. package/dist/components/charts/Sparkline.d.ts.map +1 -0
  24. package/dist/components/charts/chartTheme.d.ts +26 -0
  25. package/dist/components/charts/chartTheme.d.ts.map +1 -0
  26. package/dist/components/core/Accordion.d.ts.map +1 -1
  27. package/dist/components/core/Button.d.ts.map +1 -1
  28. package/dist/components/core/Checkbox.d.ts.map +1 -1
  29. package/dist/components/core/ColorPicker.d.ts.map +1 -1
  30. package/dist/components/core/DatePicker.d.ts.map +1 -1
  31. package/dist/components/core/DateRangePicker.d.ts.map +1 -1
  32. package/dist/components/core/Form.d.ts.map +1 -1
  33. package/dist/components/core/Input.d.ts.map +1 -1
  34. package/dist/components/core/LocationPicker.d.ts.map +1 -1
  35. package/dist/components/core/Popover.d.ts +4 -0
  36. package/dist/components/core/Popover.d.ts.map +1 -0
  37. package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
  38. package/dist/components/core/ProgressBar.d.ts.map +1 -1
  39. package/dist/components/core/Radio.d.ts.map +1 -1
  40. package/dist/components/core/Rate.d.ts.map +1 -1
  41. package/dist/components/core/Select.d.ts.map +1 -1
  42. package/dist/components/core/Skeleton.d.ts.map +1 -1
  43. package/dist/components/core/Slider.d.ts +4 -0
  44. package/dist/components/core/Slider.d.ts.map +1 -0
  45. package/dist/components/core/SpeechToText.d.ts.map +1 -1
  46. package/dist/components/core/Switch.d.ts.map +1 -1
  47. package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
  48. package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
  49. package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
  50. package/dist/components/core/Table/MobileCard.d.ts +2 -2
  51. package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
  52. package/dist/components/core/Table/Table.d.ts.map +1 -1
  53. package/dist/components/core/Table/TableRow.d.ts +4 -2
  54. package/dist/components/core/Table/TableRow.d.ts.map +1 -1
  55. package/dist/components/core/Tabs.d.ts.map +1 -1
  56. package/dist/components/core/Textarea.d.ts +4 -0
  57. package/dist/components/core/Textarea.d.ts.map +1 -0
  58. package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
  59. package/dist/components/core/Tooltip.d.ts.map +1 -1
  60. package/dist/components/feedback/Dialog.d.ts.map +1 -1
  61. package/dist/components/feedback/Drawer.d.ts +4 -0
  62. package/dist/components/feedback/Drawer.d.ts.map +1 -0
  63. package/dist/components/feedback/Toast.d.ts +14 -5
  64. package/dist/components/feedback/Toast.d.ts.map +1 -1
  65. package/dist/components/feedback/Tour.d.ts +4 -0
  66. package/dist/components/feedback/Tour.d.ts.map +1 -0
  67. package/dist/components/feedback/TourSpotlight.d.ts +9 -0
  68. package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
  69. package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
  70. package/dist/components/navigation/FootNav.d.ts.map +1 -1
  71. package/dist/components/navigation/Navbar.d.ts.map +1 -1
  72. package/dist/components/navigation/Sidebar.d.ts +8 -2
  73. package/dist/components/navigation/Sidebar.d.ts.map +1 -1
  74. package/dist/components/rich-text/RichTextEditor.d.ts +4 -0
  75. package/dist/components/rich-text/RichTextEditor.d.ts.map +1 -0
  76. package/dist/components/rich-text/RichTextToolbar.d.ts +219 -0
  77. package/dist/components/rich-text/RichTextToolbar.d.ts.map +1 -0
  78. package/dist/components/utility/Badge.d.ts.map +1 -1
  79. package/dist/components/utility/FileUpload.d.ts.map +1 -1
  80. package/dist/components/utility/Sortable.d.ts +4 -0
  81. package/dist/components/utility/Sortable.d.ts.map +1 -0
  82. package/dist/esm/_vendor/object-assign/index.js +99 -0
  83. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
  84. package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
  85. package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
  86. package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
  87. package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
  88. package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
  89. package/dist/esm/_vendor/prop-types/index.js +30 -0
  90. package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
  91. package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
  92. package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
  93. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
  94. package/dist/esm/_virtual/index.js +3 -0
  95. package/dist/esm/_virtual/index2.js +3 -0
  96. package/dist/esm/_virtual/react-is.development.js +3 -0
  97. package/dist/esm/_virtual/react-is.production.min.js +3 -0
  98. package/dist/esm/charts/index.js +5 -0
  99. package/dist/esm/components/blocks/AppShell.js +205 -0
  100. package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
  101. package/dist/esm/components/blocks/EmptyState.js +44 -0
  102. package/dist/esm/components/blocks/ErrorState.js +53 -0
  103. package/dist/esm/components/blocks/LoadingState.js +134 -0
  104. package/dist/esm/components/blocks/PageHeader.js +51 -0
  105. package/dist/esm/components/blocks/StatCard.js +79 -0
  106. package/dist/esm/components/blocks/StatusPill.js +55 -0
  107. package/dist/esm/components/charts/AreaChart.js +16 -0
  108. package/dist/esm/components/charts/BarChart.js +16 -0
  109. package/dist/esm/components/charts/CartesianChart.js +250 -0
  110. package/dist/esm/components/charts/ChartFrame.js +170 -0
  111. package/dist/esm/components/charts/DonutChart.js +119 -0
  112. package/dist/esm/components/charts/LineChart.js +16 -0
  113. package/dist/esm/components/charts/Sparkline.js +110 -0
  114. package/dist/esm/components/charts/chartTheme.js +109 -0
  115. package/dist/esm/components/core/Accordion.js +260 -0
  116. package/dist/esm/components/core/Button.js +59 -0
  117. package/dist/esm/components/core/Checkbox.js +188 -0
  118. package/dist/esm/components/core/ColorPicker.js +348 -0
  119. package/dist/esm/components/core/DatePicker.js +436 -0
  120. package/dist/esm/components/core/DateRangePicker.js +494 -0
  121. package/dist/esm/components/core/Form.js +522 -0
  122. package/dist/esm/components/core/Input.js +179 -0
  123. package/dist/esm/components/core/Loader.js +141 -0
  124. package/dist/esm/components/core/LocationPicker.js +161 -0
  125. package/dist/esm/components/core/Popover.js +171 -0
  126. package/dist/esm/components/core/PriceRangePicker.js +376 -0
  127. package/dist/esm/components/core/ProgressBar.js +152 -0
  128. package/dist/esm/components/core/Radio.js +156 -0
  129. package/dist/esm/components/core/Rate.js +197 -0
  130. package/dist/esm/components/core/RoundedTag.js +118 -0
  131. package/dist/esm/components/core/Select.js +857 -0
  132. package/dist/esm/components/core/Skeleton.js +100 -0
  133. package/dist/esm/components/core/Slider.js +134 -0
  134. package/dist/esm/components/core/SpeechToText.js +226 -0
  135. package/dist/esm/components/core/Switch.js +207 -0
  136. package/dist/esm/components/core/Table/ActionMenu.js +251 -0
  137. package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
  138. package/dist/esm/components/core/Table/FieldInput.js +157 -0
  139. package/dist/esm/components/core/Table/MobileCard.js +187 -0
  140. package/dist/esm/components/core/Table/MobileFilters.js +72 -0
  141. package/dist/esm/components/core/Table/Pagination.js +157 -0
  142. package/dist/esm/components/core/Table/Table.js +1533 -0
  143. package/dist/esm/components/core/Table/TableRow.js +254 -0
  144. package/dist/esm/components/core/Table/constants.js +35 -0
  145. package/dist/esm/components/core/Table/helpers.js +124 -0
  146. package/dist/esm/components/core/Table/useClickOutside.js +26 -0
  147. package/dist/esm/components/core/Tabs.js +289 -0
  148. package/dist/esm/components/core/TextToSpeech.js +52 -0
  149. package/dist/esm/components/core/Textarea.js +125 -0
  150. package/dist/esm/components/core/ThreeDotPopover.js +160 -0
  151. package/dist/esm/components/core/Tooltip.js +372 -0
  152. package/dist/esm/components/feedback/Alert.js +96 -0
  153. package/dist/esm/components/feedback/Dialog.js +200 -0
  154. package/dist/esm/components/feedback/Drawer.js +171 -0
  155. package/dist/esm/components/feedback/Toast.js +362 -0
  156. package/dist/esm/components/feedback/Tour.js +214 -0
  157. package/dist/esm/components/feedback/TourSpotlight.js +71 -0
  158. package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
  159. package/dist/esm/components/navigation/Dropdown.js +53 -0
  160. package/dist/esm/components/navigation/FootNav.js +51 -0
  161. package/dist/esm/components/navigation/Navbar.js +437 -0
  162. package/dist/esm/components/navigation/Sidebar.js +567 -0
  163. package/dist/esm/components/rich-text/RichTextEditor.js +244 -0
  164. package/dist/esm/components/rich-text/RichTextToolbar.js +397 -0
  165. package/dist/esm/components/utility/Avatar.js +89 -0
  166. package/dist/esm/components/utility/Badge.js +47 -0
  167. package/dist/esm/components/utility/Card.js +85 -0
  168. package/dist/esm/components/utility/Carousel.js +97 -0
  169. package/dist/esm/components/utility/Condition.js +9 -0
  170. package/dist/esm/components/utility/FileUpload.js +177 -0
  171. package/dist/esm/components/utility/Pagination.js +111 -0
  172. package/dist/esm/components/utility/Sortable.js +190 -0
  173. package/dist/esm/components/utility/Stepper.js +101 -0
  174. package/dist/esm/hooks/useApi.js +169 -0
  175. package/dist/esm/hooks/useControllableState.js +32 -0
  176. package/dist/esm/hooks/useFocusTrap.js +85 -0
  177. package/dist/esm/hooks/useLatestRef.js +20 -0
  178. package/dist/esm/hooks/useMixins.js +100 -0
  179. package/dist/esm/hooks/useScrollLock.js +26 -0
  180. package/dist/esm/hooks/useSliderValues.js +135 -0
  181. package/dist/esm/hooks/useSortable.js +188 -0
  182. package/dist/esm/hooks/useTheme.js +53 -0
  183. package/dist/esm/hooks/useTourTarget.js +92 -0
  184. package/dist/esm/index.js +65 -0
  185. package/dist/esm/rich-text/index.js +1 -0
  186. package/dist/esm/store/index.js +26 -0
  187. package/dist/esm/store/store.js +107 -0
  188. package/dist/esm/store/storeSlice.js +45 -0
  189. package/dist/esm/utils/cn.js +11 -0
  190. package/dist/esm/utils/emitter.js +169 -0
  191. package/dist/esm/utils/helpers.js +161 -0
  192. package/dist/esm/utils/position.js +134 -0
  193. package/dist/hooks/useApi.d.ts +2 -1
  194. package/dist/hooks/useApi.d.ts.map +1 -1
  195. package/dist/hooks/useControllableState.d.ts +11 -0
  196. package/dist/hooks/useControllableState.d.ts.map +1 -0
  197. package/dist/hooks/useFocusTrap.d.ts +15 -0
  198. package/dist/hooks/useFocusTrap.d.ts.map +1 -0
  199. package/dist/hooks/useLatestRef.d.ts +8 -0
  200. package/dist/hooks/useLatestRef.d.ts.map +1 -0
  201. package/dist/hooks/useMixins.d.ts.map +1 -1
  202. package/dist/hooks/useScrollLock.d.ts +2 -0
  203. package/dist/hooks/useScrollLock.d.ts.map +1 -0
  204. package/dist/hooks/useSliderValues.d.ts +43 -0
  205. package/dist/hooks/useSliderValues.d.ts.map +1 -0
  206. package/dist/hooks/useSortable.d.ts +32 -0
  207. package/dist/hooks/useSortable.d.ts.map +1 -0
  208. package/dist/hooks/useTheme.d.ts.map +1 -1
  209. package/dist/hooks/useTourTarget.d.ts +15 -0
  210. package/dist/hooks/useTourTarget.d.ts.map +1 -0
  211. package/dist/index.css +1 -1
  212. package/dist/index.d.ts +8 -2
  213. package/dist/index.esm.css +1 -1
  214. package/dist/index.esm.js +4817 -2216
  215. package/dist/index.js +4822 -2214
  216. package/dist/rich-text/index.d.ts +5 -0
  217. package/dist/rich-text/index.d.ts.map +1 -0
  218. package/dist/rich-text/index.js +654 -0
  219. package/dist/tokens/brands/studio.css +14 -0
  220. package/dist/tokens/brands/studio.json +20 -0
  221. package/dist/types/charts.d.ts +97 -0
  222. package/dist/types/charts.d.ts.map +1 -0
  223. package/dist/types/index.d.ts +193 -5
  224. package/dist/types/index.d.ts.map +1 -1
  225. package/dist/types/rich-text.d.ts +50 -0
  226. package/dist/types/rich-text.d.ts.map +1 -0
  227. package/dist/utils/position.d.ts +30 -0
  228. package/dist/utils/position.d.ts.map +1 -0
  229. package/doc/README.md +20 -1
  230. package/mcp/catalog.snapshot.json +2505 -800
  231. package/mcp/server-core.mjs +30 -1
  232. package/package.json +51 -3
  233. package/rich-text/package.json +5 -0
  234. 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 };