@seekalfred/primitives 0.5.1 → 0.6.0

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 (215) hide show
  1. package/README.md +664 -9
  2. package/dist/accordion/accordion.js +10 -4
  3. package/dist/accordion/accordion.js.map +1 -1
  4. package/dist/action-button/action-button.d.ts +50 -0
  5. package/dist/action-button/action-button.js +159 -0
  6. package/dist/action-button/action-button.js.map +1 -0
  7. package/dist/action-button/index.d.ts +2 -0
  8. package/dist/action-button/index.js +2 -0
  9. package/dist/alert/alert.d.ts +15 -1
  10. package/dist/alert/alert.js +116 -20
  11. package/dist/alert/alert.js.map +1 -1
  12. package/dist/avatar/avatar.d.ts +6 -0
  13. package/dist/avatar/avatar.js +47 -16
  14. package/dist/avatar/avatar.js.map +1 -1
  15. package/dist/badge/badge.d.ts +11 -4
  16. package/dist/badge/badge.js +35 -5
  17. package/dist/badge/badge.js.map +1 -1
  18. package/dist/breadcrumb/breadcrumb.d.ts +0 -27
  19. package/dist/breadcrumb/breadcrumb.js +20 -6
  20. package/dist/breadcrumb/breadcrumb.js.map +1 -1
  21. package/dist/button/button.d.ts +35 -22
  22. package/dist/button/button.js +177 -34
  23. package/dist/button/button.js.map +1 -1
  24. package/dist/button-group/button-group.d.ts +76 -0
  25. package/dist/button-group/button-group.js +403 -0
  26. package/dist/button-group/button-group.js.map +1 -0
  27. package/dist/button-group/index.d.ts +2 -0
  28. package/dist/button-group/index.js +2 -0
  29. package/dist/calendar/calendar.d.ts +1 -1
  30. package/dist/calendar/calendar.js +257 -30
  31. package/dist/calendar/calendar.js.map +1 -1
  32. package/dist/card/card.d.ts +9 -2
  33. package/dist/card/card.js +15 -4
  34. package/dist/card/card.js.map +1 -1
  35. package/dist/checkbox/checkbox.d.ts +0 -7
  36. package/dist/checkbox/checkbox.js +24 -27
  37. package/dist/checkbox/checkbox.js.map +1 -1
  38. package/dist/confirm-morph/confirm-morph.d.ts +85 -0
  39. package/dist/confirm-morph/confirm-morph.js +652 -0
  40. package/dist/confirm-morph/confirm-morph.js.map +1 -0
  41. package/dist/confirm-morph/index.d.ts +2 -0
  42. package/dist/confirm-morph/index.js +2 -0
  43. package/dist/copy-button/copy-button.d.ts +32 -0
  44. package/dist/copy-button/copy-button.js +134 -0
  45. package/dist/copy-button/copy-button.js.map +1 -0
  46. package/dist/copy-button/index.d.ts +2 -0
  47. package/dist/copy-button/index.js +2 -0
  48. package/dist/date-picker/date-picker.d.ts +51 -0
  49. package/dist/date-picker/date-picker.js +241 -0
  50. package/dist/date-picker/date-picker.js.map +1 -0
  51. package/dist/date-picker/date-range-picker.d.ts +78 -0
  52. package/dist/date-picker/date-range-picker.js +1015 -0
  53. package/dist/date-picker/date-range-picker.js.map +1 -0
  54. package/dist/date-picker/index.d.ts +4 -0
  55. package/dist/date-picker/index.js +4 -0
  56. package/dist/date-picker/picker-parts.d.ts +46 -0
  57. package/dist/date-picker/picker-parts.js +135 -0
  58. package/dist/date-picker/picker-parts.js.map +1 -0
  59. package/dist/dialog/dialog.d.ts +10 -14
  60. package/dist/dialog/dialog.js +39 -11
  61. package/dist/dialog/dialog.js.map +1 -1
  62. package/dist/empty-state/empty-state.d.ts +44 -0
  63. package/dist/empty-state/empty-state.js +83 -0
  64. package/dist/empty-state/empty-state.js.map +1 -0
  65. package/dist/empty-state/index.d.ts +2 -0
  66. package/dist/empty-state/index.js +2 -0
  67. package/dist/expanding-button-group/expanding-button-group.d.ts +54 -0
  68. package/dist/expanding-button-group/expanding-button-group.js +350 -0
  69. package/dist/expanding-button-group/expanding-button-group.js.map +1 -0
  70. package/dist/expanding-button-group/index.d.ts +2 -0
  71. package/dist/expanding-button-group/index.js +2 -0
  72. package/dist/file-drop-zone/file-drop-zone.d.ts +71 -0
  73. package/dist/file-drop-zone/file-drop-zone.js +116 -0
  74. package/dist/file-drop-zone/file-drop-zone.js.map +1 -0
  75. package/dist/file-drop-zone/index.d.ts +2 -0
  76. package/dist/file-drop-zone/index.js +2 -0
  77. package/dist/filter-bar/filter-bar.d.ts +121 -0
  78. package/dist/filter-bar/filter-bar.js +300 -0
  79. package/dist/filter-bar/filter-bar.js.map +1 -0
  80. package/dist/filter-bar/index.d.ts +2 -0
  81. package/dist/filter-bar/index.js +2 -0
  82. package/dist/floating-button-group/floating-button-group.d.ts +61 -0
  83. package/dist/floating-button-group/floating-button-group.js +340 -0
  84. package/dist/floating-button-group/floating-button-group.js.map +1 -0
  85. package/dist/floating-button-group/index.d.ts +2 -0
  86. package/dist/floating-button-group/index.js +2 -0
  87. package/dist/icon-morph/icon-morph.d.ts +55 -0
  88. package/dist/icon-morph/icon-morph.js +331 -0
  89. package/dist/icon-morph/icon-morph.js.map +1 -0
  90. package/dist/icon-morph/index.d.ts +2 -0
  91. package/dist/icon-morph/index.js +2 -0
  92. package/dist/index.d.ts +24 -2
  93. package/dist/index.js +29 -7
  94. package/dist/input/input.d.ts +22 -0
  95. package/dist/input/input.js +36 -12
  96. package/dist/input/input.js.map +1 -1
  97. package/dist/lib/count-to.js +113 -0
  98. package/dist/lib/count-to.js.map +1 -0
  99. package/dist/lib/eye-morph.js +62 -0
  100. package/dist/lib/eye-morph.js.map +1 -0
  101. package/dist/lib/field-message.js +336 -0
  102. package/dist/lib/field-message.js.map +1 -0
  103. package/dist/lib/field-shell.js +81 -0
  104. package/dist/lib/field-shell.js.map +1 -0
  105. package/dist/lib/field-surface.js +4 -2
  106. package/dist/lib/field-surface.js.map +1 -1
  107. package/dist/lib/flip.js +80 -0
  108. package/dist/lib/flip.js.map +1 -0
  109. package/dist/lib/height-follow.js +59 -0
  110. package/dist/lib/height-follow.js.map +1 -0
  111. package/dist/lib/icon-swap.js +47 -0
  112. package/dist/lib/icon-swap.js.map +1 -0
  113. package/dist/lib/leaving-list.js +57 -0
  114. package/dist/lib/leaving-list.js.map +1 -0
  115. package/dist/lib/merge-refs.js +3 -3
  116. package/dist/lib/merge-refs.js.map +1 -1
  117. package/dist/lib/morph-text.js +128 -0
  118. package/dist/lib/morph-text.js.map +1 -0
  119. package/dist/lib/motion.js +162 -0
  120. package/dist/lib/motion.js.map +1 -0
  121. package/dist/lib/pausable-timeout.js +67 -0
  122. package/dist/lib/pausable-timeout.js.map +1 -0
  123. package/dist/lib/rolling-value.js +31 -0
  124. package/dist/lib/rolling-value.js.map +1 -0
  125. package/dist/lib/spring-progress.js +114 -0
  126. package/dist/lib/spring-progress.js.map +1 -0
  127. package/dist/lib/svg-id.js +10 -0
  128. package/dist/lib/svg-id.js.map +1 -0
  129. package/dist/lib/swap-text.js +77 -0
  130. package/dist/lib/swap-text.js.map +1 -0
  131. package/dist/lib/use-copy-feedback.js +36 -0
  132. package/dist/lib/use-copy-feedback.js.map +1 -0
  133. package/dist/page-header/index.d.ts +2 -0
  134. package/dist/page-header/index.js +2 -0
  135. package/dist/page-header/page-header.d.ts +75 -0
  136. package/dist/page-header/page-header.js +83 -0
  137. package/dist/page-header/page-header.js.map +1 -0
  138. package/dist/password-field/index.d.ts +2 -0
  139. package/dist/password-field/index.js +2 -0
  140. package/dist/password-field/password-field.d.ts +37 -0
  141. package/dist/password-field/password-field.js +101 -0
  142. package/dist/password-field/password-field.js.map +1 -0
  143. package/dist/password-strength/index.d.ts +2 -0
  144. package/dist/password-strength/index.js +2 -0
  145. package/dist/password-strength/password-strength.d.ts +127 -0
  146. package/dist/password-strength/password-strength.js +455 -0
  147. package/dist/password-strength/password-strength.js.map +1 -0
  148. package/dist/popover/popover.d.ts +8 -0
  149. package/dist/popover/popover.js +3 -3
  150. package/dist/popover/popover.js.map +1 -1
  151. package/dist/progress/progress.js +46 -5
  152. package/dist/progress/progress.js.map +1 -1
  153. package/dist/radio-group/radio-group.js +7 -6
  154. package/dist/radio-group/radio-group.js.map +1 -1
  155. package/dist/scroll-area/scroll-area.d.ts +10 -0
  156. package/dist/scroll-area/scroll-area.js +25 -3
  157. package/dist/scroll-area/scroll-area.js.map +1 -1
  158. package/dist/search-field/index.d.ts +2 -0
  159. package/dist/search-field/index.js +2 -0
  160. package/dist/search-field/search-field.d.ts +26 -0
  161. package/dist/search-field/search-field.js +155 -0
  162. package/dist/search-field/search-field.js.map +1 -0
  163. package/dist/select/select.js +79 -21
  164. package/dist/select/select.js.map +1 -1
  165. package/dist/sheet/sheet.js +2 -1
  166. package/dist/sheet/sheet.js.map +1 -1
  167. package/dist/side-nav/index.d.ts +2 -0
  168. package/dist/side-nav/index.js +2 -0
  169. package/dist/side-nav/side-nav.d.ts +72 -0
  170. package/dist/side-nav/side-nav.js +142 -0
  171. package/dist/side-nav/side-nav.js.map +1 -0
  172. package/dist/skeleton/skeleton.d.ts +8 -2
  173. package/dist/skeleton/skeleton.js +6 -2
  174. package/dist/skeleton/skeleton.js.map +1 -1
  175. package/dist/slider/slider.js +61 -7
  176. package/dist/slider/slider.js.map +1 -1
  177. package/dist/split-button/index.d.ts +2 -0
  178. package/dist/split-button/index.js +2 -0
  179. package/dist/split-button/split-button.d.ts +46 -0
  180. package/dist/split-button/split-button.js +122 -0
  181. package/dist/split-button/split-button.js.map +1 -0
  182. package/dist/stat-card/index.d.ts +2 -0
  183. package/dist/stat-card/index.js +2 -0
  184. package/dist/stat-card/stat-card.d.ts +81 -0
  185. package/dist/stat-card/stat-card.js +152 -0
  186. package/dist/stat-card/stat-card.js.map +1 -0
  187. package/dist/styles.css +1 -1
  188. package/dist/switch/switch.js +9 -8
  189. package/dist/switch/switch.js.map +1 -1
  190. package/dist/table/index.d.ts +2 -2
  191. package/dist/table/index.js +2 -2
  192. package/dist/table/table.d.ts +36 -5
  193. package/dist/table/table.js +112 -11
  194. package/dist/table/table.js.map +1 -1
  195. package/dist/tabs/tabs.js +142 -6
  196. package/dist/tabs/tabs.js.map +1 -1
  197. package/dist/textarea/textarea.d.ts +23 -0
  198. package/dist/textarea/textarea.js +24 -2
  199. package/dist/textarea/textarea.js.map +1 -1
  200. package/dist/theme-switch/index.d.ts +2 -0
  201. package/dist/theme-switch/index.js +2 -0
  202. package/dist/theme-switch/theme-switch.d.ts +37 -0
  203. package/dist/theme-switch/theme-switch.js +123 -0
  204. package/dist/theme-switch/theme-switch.js.map +1 -0
  205. package/dist/time-picker/index.d.ts +2 -0
  206. package/dist/time-picker/index.js +2 -0
  207. package/dist/time-picker/time-picker.d.ts +54 -0
  208. package/dist/time-picker/time-picker.js +201 -0
  209. package/dist/time-picker/time-picker.js.map +1 -0
  210. package/dist/toast/toast.js +58 -38
  211. package/dist/toast/toast.js.map +1 -1
  212. package/dist/tooltip/tooltip.d.ts +1 -1
  213. package/dist/tooltip/tooltip.js +63 -14
  214. package/dist/tooltip/tooltip.js.map +1 -1
  215. package/package.json +83 -3
@@ -0,0 +1,1015 @@
1
+ "use client";
2
+ import { cnAll } from "../lib/cn.js";
3
+ import { prefersReducedMotion, useExitBackstop, useIsomorphicLayoutEffect } from "../lib/motion.js";
4
+ import { Button as Button$1 } from "../button/button.js";
5
+ import { SwapText } from "../lib/swap-text.js";
6
+ import { calendarCellVariants, calendarGridVariants, calendarHeaderCellVariants, calendarNavVariants } from "../calendar/calendar.js";
7
+ import { CalendarGlyph, Chevron, TypedDate, datePickerLabelVariants, datePickerVariants, descriptionClass, errorClass, useDayFormat, useValue } from "./picker-parts.js";
8
+ import { Fragment, forwardRef, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
9
+ import { Button, CalendarCell, CalendarGrid, CalendarGridBody, CalendarGridHeader, CalendarHeaderCell, CalendarHeading, RangeCalendar, RangeCalendarStateContext, useLocale } from "react-aria-components";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ import { getLocalTimeZone, today } from "@internationalized/date";
12
+ //#region src/date-picker/date-range-picker.tsx
13
+ const defaultMessages = {
14
+ presets: "Presets",
15
+ apply: "Apply",
16
+ cancel: "Cancel",
17
+ clear: "Clear",
18
+ previousMonth: "Previous month",
19
+ nextMonth: "Next month",
20
+ noDates: "No dates",
21
+ pickEnd: "Pick an end date",
22
+ days: (count) => `${count} ${count === 1 ? "day" : "days"}`,
23
+ startChosen: (start) => `Start ${start}. Choose an end date.`
24
+ };
25
+ /** Shortcuts for the rail: today back to the start of the year. */
26
+ const defaultDateRangePresets = [
27
+ {
28
+ label: "Today",
29
+ range: (today) => ({
30
+ start: today,
31
+ end: today
32
+ })
33
+ },
34
+ {
35
+ label: "Yesterday",
36
+ range: (today) => ({
37
+ start: today.subtract({ days: 1 }),
38
+ end: today.subtract({ days: 1 })
39
+ })
40
+ },
41
+ {
42
+ label: "Last 7 days",
43
+ range: (today) => ({
44
+ start: today.subtract({ days: 6 }),
45
+ end: today
46
+ })
47
+ },
48
+ {
49
+ label: "Last 30 days",
50
+ range: (today) => ({
51
+ start: today.subtract({ days: 29 }),
52
+ end: today
53
+ })
54
+ },
55
+ {
56
+ label: "This month",
57
+ range: (today) => ({
58
+ start: today.set({ day: 1 }),
59
+ end: today
60
+ })
61
+ },
62
+ {
63
+ label: "Last month",
64
+ range: (today) => {
65
+ const first = today.subtract({ months: 1 }).set({ day: 1 });
66
+ return {
67
+ start: first,
68
+ end: first.set({ day: first.calendar.getDaysInMonth(first) })
69
+ };
70
+ }
71
+ },
72
+ {
73
+ label: "This quarter",
74
+ range: (today) => ({
75
+ start: today.set({
76
+ month: Math.floor((today.month - 1) / 3) * 3 + 1,
77
+ day: 1
78
+ }),
79
+ end: today
80
+ })
81
+ },
82
+ {
83
+ label: "Year to date",
84
+ range: (today) => ({
85
+ start: today.set({
86
+ month: 1,
87
+ day: 1
88
+ }),
89
+ end: today
90
+ })
91
+ }
92
+ ];
93
+ const NO_RANGE = {
94
+ start: null,
95
+ end: null
96
+ };
97
+ const WIDE_MIN = 712;
98
+ const WIDE_CELL = 36;
99
+ const EDGE = 8;
100
+ const RADIUS_CLOSED = "var(--radius-md)";
101
+ const RADIUS_OPEN = "var(--radius-xl)";
102
+ const triggerSize = {
103
+ sm: "h-(--density-control-h-sm) px-(--density-control-pad-sm)",
104
+ md: "h-(--density-control-h-md) px-(--density-control-pad-md)",
105
+ lg: "h-(--density-control-h-lg) px-(--density-control-pad-lg)"
106
+ };
107
+ const rootSize = {
108
+ sm: "h-(--density-control-h-sm)",
109
+ md: "h-(--density-control-h-md)",
110
+ lg: "h-(--density-control-h-lg)"
111
+ };
112
+ /** A stamp that grows with time, so a range can be compared and given a direction. */
113
+ const stamp = (value) => value ? value.toDate("UTC").getTime() : 0;
114
+ const rangeStamp = (range) => range && range.start && range.end ? stamp(range.start) * 2 + stamp(range.end) : null;
115
+ const sameRange = (a, b) => Boolean(a?.start && a.end && b?.start && b.end && a.start.compare(b.start) === 0 && a.end.compare(b.end) === 0);
116
+ /** Which way a range moved in time, so its words roll in that direction. */
117
+ function useDirection(range) {
118
+ const stampNow = rangeStamp(range);
119
+ const [previous, setPrevious] = useState(stampNow);
120
+ const [direction, setDirection] = useState(1);
121
+ if (stampNow !== previous) {
122
+ setPrevious(stampNow);
123
+ setDirection(stampNow === null || previous === null || stampNow >= previous ? 1 : -1);
124
+ }
125
+ return direction;
126
+ }
127
+ /**
128
+ * Words roll one by one: a later date rises from below, an earlier one drops from
129
+ * above, and a word that stays the same holds still. The copy is `aria-hidden`; the
130
+ * caller keeps the plain text for screen readers.
131
+ */
132
+ function RollingWords({ text, direction }) {
133
+ const words = text.split(/\s+/).filter(Boolean);
134
+ return /* @__PURE__ */ jsx("span", {
135
+ "aria-hidden": "true",
136
+ className: "inline-flex gap-1 whitespace-nowrap",
137
+ children: words.map((word, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 ? " " : null, /* @__PURE__ */ jsx(SwapText, {
138
+ swapKey: word,
139
+ dir: direction,
140
+ motion: "word",
141
+ className: "inline-block",
142
+ children: word
143
+ })] }, index))
144
+ });
145
+ }
146
+ /** Moves an element from where it was to where it is now, on a spring: a value that flies between the trigger and the footer. */
147
+ function flyFrom(el, from, spring) {
148
+ const to = el.getBoundingClientRect();
149
+ const dx = from.left - to.left;
150
+ const dy = from.top - to.top;
151
+ if (Math.abs(dx) < 1 && Math.abs(dy) < 1) return;
152
+ el.style.transition = "none";
153
+ el.style.translate = `${dx}px ${dy}px`;
154
+ el.offsetWidth;
155
+ el.style.transition = `translate var(--duration-${spring}) var(--ease-${spring})`;
156
+ el.style.translate = "";
157
+ el.addEventListener("transitionend", () => {
158
+ el.style.transition = "";
159
+ }, { once: true });
160
+ }
161
+ /** Hands the calendar's anchor and highlighted range to the picker, which owns the footer. */
162
+ function CalendarBridge({ onSnapshot }) {
163
+ const state = useContext(RangeCalendarStateContext);
164
+ const anchor = state?.anchorDate ?? null;
165
+ const highlighted = state?.highlightedRange ?? null;
166
+ const key = `${anchor?.toString() ?? ""}|${highlighted?.start.toString() ?? ""}|${highlighted?.end.toString() ?? ""}`;
167
+ const latest = useRef(key);
168
+ useIsomorphicLayoutEffect(() => {
169
+ if (latest.current === key && latest.current !== "||") return;
170
+ latest.current = key;
171
+ onSnapshot({
172
+ anchor,
173
+ highlighted: highlighted ? {
174
+ start: highlighted.start,
175
+ end: highlighted.end
176
+ } : null
177
+ });
178
+ }, [key]);
179
+ return null;
180
+ }
181
+ /**
182
+ * Places the range's highlight under the days: one bar per week, which stretches
183
+ * and slides on its spring from the edge the range arrives from, and a solid end at
184
+ * each side, which glides from day to day and only fades when its end leaves the
185
+ * month. Everything is measured from the cells React Aria rendered, so it follows
186
+ * the real layout. Nothing animates until a bar or an end has been shown once.
187
+ */
188
+ function RangeDriver() {
189
+ const marker = useRef(null);
190
+ useContext(RangeCalendarStateContext);
191
+ useIsomorphicLayoutEffect(() => {
192
+ const root = marker.current?.parentElement;
193
+ if (!root) return;
194
+ for (const block of root.querySelectorAll("[data-slot=\"range-month\"]")) {
195
+ const layer = block.querySelector("[data-slot=\"range-layer\"]");
196
+ const rows = block.querySelector("tbody")?.rows;
197
+ if (!layer || !rows) continue;
198
+ const layerBox = layer.getBoundingClientRect();
199
+ const bars = [...layer.querySelectorAll("[data-slot=\"range-bar\"]")];
200
+ const thumbs = [...layer.querySelectorAll("[data-slot=\"range-thumb\"]")];
201
+ const inMonth = (row) => [...row.querySelectorAll("[data-slot=\"calendar-cell\"]")].filter((cell) => !cell.hasAttribute("data-outside-month"));
202
+ const selected = [...rows].map((row) => inMonth(row).filter((cell) => cell.hasAttribute("data-selected")));
203
+ const firstRow = selected.findIndex((cells) => cells.length > 0);
204
+ const fresh = block.dataset.driven === void 0;
205
+ block.dataset.driven = "";
206
+ const place = (el, x, y, width, height) => {
207
+ const hidden = el.dataset.visible === void 0;
208
+ if (width !== void 0) el.style.width = `${width}px`;
209
+ if (height !== void 0) el.style.height = `${height}px`;
210
+ if (hidden) {
211
+ el.style.transition = "none";
212
+ el.style.translate = `${x}px ${y}px`;
213
+ if (fresh) el.dataset.visible = "";
214
+ el.offsetWidth;
215
+ el.style.transition = "";
216
+ el.dataset.visible = "";
217
+ } else el.style.translate = `${x}px ${y}px`;
218
+ };
219
+ const hide = (el) => {
220
+ delete el.dataset.visible;
221
+ };
222
+ bars.forEach((bar, index) => {
223
+ const row = rows[index];
224
+ const cells = row ? inMonth(row) : [];
225
+ if (firstRow < 0 || !row || cells.length === 0) return hide(bar);
226
+ const rowBox = cells[0].getBoundingClientRect();
227
+ const top = rowBox.top - layerBox.top + 3;
228
+ const height = rowBox.height - 6;
229
+ const span = selected[index];
230
+ if (span.length > 0) {
231
+ const a = span[0].getBoundingClientRect();
232
+ const b = span[span.length - 1].getBoundingClientRect();
233
+ bar.style.top = `${top}px`;
234
+ bar.style.height = `${height}px`;
235
+ place(bar, a.left - layerBox.left, 0, b.right - a.left);
236
+ } else {
237
+ const edge = index < firstRow ? cells[cells.length - 1].getBoundingClientRect().right : cells[0].getBoundingClientRect().left;
238
+ bar.style.top = `${top}px`;
239
+ bar.style.height = `${height}px`;
240
+ place(bar, edge - layerBox.left, 0, 0);
241
+ }
242
+ });
243
+ const start = block.querySelector("[data-slot=\"calendar-cell\"][data-selection-start]:not([data-outside-month])");
244
+ const end = block.querySelector("[data-slot=\"calendar-cell\"][data-selection-end]:not([data-outside-month])");
245
+ const ends = [start, end && end !== start ? end : null];
246
+ thumbs.forEach((thumb, index) => {
247
+ const cell = ends[index];
248
+ if (!cell) return hide(thumb);
249
+ const box = cell.getBoundingClientRect();
250
+ const x = box.left - layerBox.left - (box.width - cell.offsetWidth) / 2;
251
+ const y = box.top - layerBox.top - (box.height - cell.offsetHeight) / 2;
252
+ place(thumb, x + 3, y + 3, cell.offsetWidth - 6, cell.offsetHeight - 6);
253
+ });
254
+ }
255
+ });
256
+ return /* @__PURE__ */ jsx("span", {
257
+ ref: marker,
258
+ hidden: true,
259
+ "data-slot": "range-driver"
260
+ });
261
+ }
262
+ /** One month: its title, a grid, and the layer of bars and ends under the days. */
263
+ function RangeMonth({ offset }) {
264
+ return /* @__PURE__ */ jsxs("div", {
265
+ "data-slot": "range-month",
266
+ className: "w-[calc(var(--cell)*7)]",
267
+ children: [/* @__PURE__ */ jsx(CalendarHeading, {
268
+ offset: { months: offset },
269
+ className: "m-0 h-8 text-center text-sm font-medium leading-8 whitespace-nowrap text-foreground"
270
+ }), /* @__PURE__ */ jsxs("div", {
271
+ className: "relative",
272
+ children: [/* @__PURE__ */ jsxs("span", {
273
+ "aria-hidden": "true",
274
+ "data-slot": "range-layer",
275
+ className: "pointer-events-none absolute inset-0",
276
+ children: [
277
+ [
278
+ 0,
279
+ 1,
280
+ 2,
281
+ 3,
282
+ 4,
283
+ 5
284
+ ].map((row) => /* @__PURE__ */ jsx("span", {
285
+ "data-slot": "range-bar",
286
+ className: "range-bar"
287
+ }, row)),
288
+ /* @__PURE__ */ jsx("span", {
289
+ "data-slot": "range-thumb",
290
+ className: "range-thumb"
291
+ }),
292
+ /* @__PURE__ */ jsx("span", {
293
+ "data-slot": "range-thumb",
294
+ className: "range-thumb"
295
+ })
296
+ ]
297
+ }), /* @__PURE__ */ jsxs(CalendarGrid, {
298
+ offset: { months: offset },
299
+ className: cnAll(calendarGridVariants(), "relative"),
300
+ children: [/* @__PURE__ */ jsx(CalendarGridHeader, { children: (weekday) => /* @__PURE__ */ jsx(CalendarHeaderCell, {
301
+ className: calendarHeaderCellVariants(),
302
+ children: weekday
303
+ }) }), /* @__PURE__ */ jsx(CalendarGridBody, { children: (date) => /* @__PURE__ */ jsx(CalendarCell, {
304
+ date,
305
+ "data-slot": "calendar-cell",
306
+ className: calendarCellVariants({ selection: "band" })
307
+ }) })]
308
+ })]
309
+ })]
310
+ });
311
+ }
312
+ /**
313
+ * The visible months travel together. The set in view arrives from the side the
314
+ * calendar travels to while the old set, kept where it stood, slides away the other
315
+ * way; the leaving set is inert so focus and queries only find the current one.
316
+ */
317
+ function MonthSets({ count, onNavigate }) {
318
+ const start = useContext(RangeCalendarStateContext)?.visibleRange.start;
319
+ const key = start ? `${start.era}-${start.year}-${start.month}-${count}` : "";
320
+ const [shown, setShown] = useState(start);
321
+ const [shownKey, setShownKey] = useState(key);
322
+ const [dir, setDir] = useState(0);
323
+ const [leaving, setLeaving] = useState([]);
324
+ const nextId = useRef(0);
325
+ if (start && shown && key !== shownKey) {
326
+ const months = (shown.year - start.year) * 12 + (shown.month - start.month);
327
+ setLeaving((list) => [...list, {
328
+ id: nextId.current++,
329
+ offset: months,
330
+ dir: months < 0 ? 1 : -1
331
+ }]);
332
+ setDir(months < 0 ? 1 : -1);
333
+ setShown(start);
334
+ setShownKey(key);
335
+ }
336
+ const remove = useCallback((id) => setLeaving((list) => list.filter((set) => set.id !== id)), []);
337
+ useEffect(() => {
338
+ onNavigate?.();
339
+ }, [key, onNavigate]);
340
+ return /* @__PURE__ */ jsxs("div", {
341
+ className: "relative overflow-clip [overflow-clip-margin:2px]",
342
+ children: [leaving.map((set) => /* @__PURE__ */ jsx(LeavingMonths, {
343
+ set,
344
+ count,
345
+ onDone: remove
346
+ }, set.id)), /* @__PURE__ */ jsx("div", {
347
+ "data-slot": "range-months",
348
+ "data-current": "",
349
+ style: { "--dir": dir },
350
+ className: cnAll("flex gap-6", dir !== 0 && "motion-safe:animate-range-slide-in motion-reduce:animate-range-face-fade-in"),
351
+ children: Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx(RangeMonth, { offset: index }, index))
352
+ }, key)]
353
+ });
354
+ }
355
+ function LeavingMonths({ set, count, onDone }) {
356
+ const remove = useCallback(() => onDone(set.id), [onDone, set.id]);
357
+ useExitBackstop(true, remove, 900);
358
+ useIsomorphicLayoutEffect(() => {
359
+ if (prefersReducedMotion()) {
360
+ const timer = window.setTimeout(remove, 80);
361
+ return () => window.clearTimeout(timer);
362
+ }
363
+ }, [remove]);
364
+ return /* @__PURE__ */ jsx("div", {
365
+ ref: (node) => node?.setAttribute("inert", ""),
366
+ "aria-hidden": "true",
367
+ "data-slot": "range-months-leaving",
368
+ style: { "--dir": set.dir },
369
+ onAnimationEnd: (event) => {
370
+ if (event.target === event.currentTarget && event.animationName === "range-slide-x-out") remove();
371
+ },
372
+ className: "pointer-events-none absolute inset-0 flex gap-6 motion-safe:animate-range-slide-out motion-reduce:animate-range-word-fade-out",
373
+ children: Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx(RangeMonth, { offset: index + set.offset }, index))
374
+ });
375
+ }
376
+ /** The rail of shortcuts, with one highlight that glides to the active one. */
377
+ function PresetRail({ presets, active, compact, label, onChoose }) {
378
+ const rail = useRef(null);
379
+ const highlight = useRef(null);
380
+ useIsomorphicLayoutEffect(() => {
381
+ const el = rail.current;
382
+ const mark = highlight.current;
383
+ const node = active < 0 ? null : el?.querySelector(`[data-preset="${active}"]`);
384
+ if (!el || !mark) return;
385
+ if (!node) {
386
+ delete mark.dataset.visible;
387
+ return;
388
+ }
389
+ mark.style.width = `${node.offsetWidth}px`;
390
+ mark.style.height = `${node.offsetHeight}px`;
391
+ if (mark.dataset.visible === void 0) {
392
+ mark.style.transition = "none";
393
+ mark.style.translate = `${node.offsetLeft}px ${node.offsetTop}px`;
394
+ mark.offsetWidth;
395
+ mark.style.transition = "";
396
+ mark.dataset.visible = "";
397
+ } else mark.style.translate = `${node.offsetLeft}px ${node.offsetTop}px`;
398
+ if (compact && (node.offsetLeft < el.scrollLeft || node.offsetLeft + node.offsetWidth > el.scrollLeft + el.clientWidth)) el.scrollTo({
399
+ left: node.offsetLeft - 12,
400
+ behavior: prefersReducedMotion() ? "auto" : "smooth"
401
+ });
402
+ }, [
403
+ active,
404
+ compact,
405
+ presets
406
+ ]);
407
+ const onKeyDown = (event) => {
408
+ const keys = compact ? ["ArrowLeft", "ArrowRight"] : ["ArrowUp", "ArrowDown"];
409
+ if (!keys.includes(event.key)) return;
410
+ const buttons = [...event.currentTarget.querySelectorAll("[data-preset]")];
411
+ const at = buttons.indexOf(document.activeElement);
412
+ if (at < 0) return;
413
+ event.preventDefault();
414
+ buttons[(at + (event.key === keys[1] ? 1 : -1) + buttons.length) % buttons.length]?.focus();
415
+ };
416
+ return /* @__PURE__ */ jsxs("div", {
417
+ ref: rail,
418
+ role: "group",
419
+ "aria-label": label,
420
+ "data-slot": "range-rail",
421
+ onKeyDown,
422
+ className: cnAll("relative flex flex-none gap-0.5 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", compact ? "-mx-2 flex-row overflow-x-auto overscroll-x-contain border-b-(length:--border-width) border-border px-2 pb-2" : "w-37 flex-col border-e-(length:--border-width) border-border pe-2.5"),
423
+ children: [/* @__PURE__ */ jsx("span", {
424
+ ref: highlight,
425
+ "aria-hidden": "true",
426
+ "data-slot": "range-highlight",
427
+ className: "range-highlight"
428
+ }), presets.map((preset, index) => /* @__PURE__ */ jsx("button", {
429
+ type: "button",
430
+ "data-preset": index,
431
+ "aria-pressed": index === active,
432
+ onClick: () => onChoose(preset),
433
+ className: cnAll("relative flex h-8 flex-none cursor-pointer items-center rounded-md border-0 bg-transparent px-3 text-start text-sm whitespace-nowrap outline-none", "motion-safe:transition-colors motion-safe:duration-(--duration-quick) motion-safe:ease-settle", "text-muted-foreground hover:text-foreground aria-pressed:font-medium aria-pressed:text-foreground", "focus-visible:outline-solid focus-visible:outline-(length:--focus-ring-width) focus-visible:outline-offset-(--focus-ring-offset) focus-visible:outline-(--color-ring)"),
434
+ children: preset.label
435
+ }, preset.label))]
436
+ });
437
+ }
438
+ const DateRangePicker = forwardRef(function DateRangePicker({ value, defaultValue = NO_RANGE, onChange, startLabel = "From", endLabel = "To", presets = defaultDateRangePresets, months = "auto", boundary, messages: messageOverrides, ...props }, ref) {
439
+ const messages = useMemo(() => ({
440
+ ...defaultMessages,
441
+ ...messageOverrides
442
+ }), [messageOverrides]);
443
+ const { locale } = useLocale();
444
+ const uid = useId();
445
+ const labelId = `${uid}-label`;
446
+ const valueId = `${uid}-value`;
447
+ const panelId = `${uid}-panel`;
448
+ const descriptionId = `${uid}-description`;
449
+ const errorId = `${uid}-error`;
450
+ const [committed, setCommitted] = useValue(value, defaultValue, onChange);
451
+ const [open, setOpen] = useState(false);
452
+ const [mounted, setMounted] = useState(false);
453
+ const [compact, setCompact] = useState(false);
454
+ const [panelWidth, setPanelWidth] = useState(0);
455
+ const [draft, setDraft] = useState(committed);
456
+ const [focus, setFocus] = useState(null);
457
+ const [snapshot, setSnapshot] = useState({
458
+ anchor: null,
459
+ highlighted: null
460
+ });
461
+ if (open && !mounted) setMounted(true);
462
+ const closing = mounted && !open;
463
+ const unmount = useCallback(() => setMounted(false), []);
464
+ useExitBackstop(closing, unmount, 140);
465
+ useIsomorphicLayoutEffect(() => {
466
+ if (closing && prefersReducedMotion()) unmount();
467
+ }, [closing, unmount]);
468
+ const rootRef = useRef(null);
469
+ const triggerRef = useRef(null);
470
+ const surfaceRef = useRef(null);
471
+ const panelRef = useRef(null);
472
+ const restingRef = useRef(null);
473
+ const summaryRef = useRef(null);
474
+ const summaryRect = useRef(null);
475
+ const pendingFocus = useRef(null);
476
+ const mergedRef = useCallback((node) => {
477
+ triggerRef.current = node;
478
+ if (typeof ref === "function") ref(node);
479
+ else if (ref) ref.current = node;
480
+ }, [ref]);
481
+ const [todayValue, setTodayValue] = useState(() => today(getLocalTimeZone()));
482
+ const dayFormat = useDayFormat();
483
+ const format = props.formatValue ?? dayFormat;
484
+ const rangeFormat = useMemo(() => new Intl.DateTimeFormat(locale, {
485
+ month: "short",
486
+ day: "numeric",
487
+ year: "numeric",
488
+ timeZone: "UTC"
489
+ }), [locale]);
490
+ const describe = useCallback((range) => {
491
+ const start = range?.start ?? null;
492
+ const end = range?.end ?? null;
493
+ if (start && end) {
494
+ if (start.compare(end) === 0) return props.formatValue ? format(start) : rangeFormat.format(start.toDate("UTC"));
495
+ return props.formatValue ? `${format(start)} – ${format(end)}` : rangeFormat.formatRange(start.toDate("UTC"), end.toDate("UTC"));
496
+ }
497
+ if (start) return `${startLabel} ${format(start)}`;
498
+ if (end) return `${endLabel} ${format(end)}`;
499
+ return "";
500
+ }, [
501
+ endLabel,
502
+ format,
503
+ props.formatValue,
504
+ rangeFormat,
505
+ startLabel
506
+ ]);
507
+ const placeholder = props.placeholder ?? "Select dates";
508
+ const committedText = describe(committed) || placeholder;
509
+ const complete = draft.start && draft.end ? {
510
+ start: draft.start,
511
+ end: draft.end
512
+ } : null;
513
+ const shown = snapshot.highlighted ?? (draft.start || draft.end ? draft : null);
514
+ const shownComplete = shown?.start && shown.end ? shown : null;
515
+ const days = shownComplete ? Math.round((stamp(shownComplete.end) - stamp(shownComplete.start)) / 864e5) + 1 : 0;
516
+ const shownText = shown ? describe(shown) : messages.noDates;
517
+ const countText = shownComplete ? snapshot.anchor && snapshot.highlighted?.start && snapshot.highlighted.end && snapshot.highlighted.start.compare(snapshot.highlighted.end) === 0 ? messages.pickEnd : messages.days(days) : "";
518
+ const status = !open ? "" : snapshot.anchor ? messages.startChosen(rangeFormat.format(snapshot.anchor.toDate("UTC"))) : shownComplete ? `${shownText}, ${countText}` : "";
519
+ const committedDirection = useDirection(committed);
520
+ const shownDirection = useDirection(shownComplete);
521
+ const activePreset = open && !snapshot.anchor ? presets.findIndex((preset) => sameRange(preset.range(todayValue), draft)) : -1;
522
+ const sizes = useRef({
523
+ trigger: {
524
+ w: 0,
525
+ h: 0
526
+ },
527
+ panel: null
528
+ });
529
+ const live = useRef({ open: false });
530
+ const boundaryRef = useRef(boundary);
531
+ useLayoutEffect(() => {
532
+ boundaryRef.current = boundary;
533
+ }, [boundary]);
534
+ const bounds = useCallback(() => {
535
+ const viewport = {
536
+ left: 0,
537
+ right: document.documentElement.clientWidth
538
+ };
539
+ const element = boundaryRef.current?.();
540
+ if (!element) return viewport;
541
+ const rect = element.getBoundingClientRect();
542
+ return {
543
+ left: Math.max(viewport.left, rect.left),
544
+ right: Math.min(viewport.right, rect.right)
545
+ };
546
+ }, []);
547
+ const update = useCallback(() => {
548
+ const surface = surfaceRef.current;
549
+ const { trigger, panel } = sizes.current;
550
+ if (!surface || !trigger.w) return;
551
+ const target = live.current.open && panel ? panel : trigger;
552
+ let offset = 0;
553
+ if (live.current.open && panel && rootRef.current) {
554
+ const rect = rootRef.current.getBoundingClientRect();
555
+ const box = bounds();
556
+ offset = Math.min(0, box.right - EDGE - (rect.left + panel.w));
557
+ offset = Math.max(offset, box.left + EDGE - rect.left);
558
+ }
559
+ const first = surface.dataset.ready === void 0;
560
+ surface.style.width = `${target.w}px`;
561
+ surface.style.height = `${target.h}px`;
562
+ surface.style.borderRadius = live.current.open && panel ? RADIUS_OPEN : RADIUS_CLOSED;
563
+ surface.style.translate = `${offset}px 0`;
564
+ if (first) {
565
+ surface.offsetWidth;
566
+ surface.dataset.ready = "";
567
+ }
568
+ }, [bounds]);
569
+ const queued = useRef(false);
570
+ const schedule = useCallback(() => {
571
+ if (queued.current) return;
572
+ queued.current = true;
573
+ queueMicrotask(() => {
574
+ queued.current = false;
575
+ update();
576
+ });
577
+ }, [update]);
578
+ useLayoutEffect(() => {
579
+ live.current.open = open;
580
+ if (!open) sizes.current.panel = null;
581
+ schedule();
582
+ }, [open, schedule]);
583
+ useLayoutEffect(() => {
584
+ const node = triggerRef.current;
585
+ if (!node) return;
586
+ const read = () => {
587
+ sizes.current.trigger = {
588
+ w: node.offsetWidth,
589
+ h: node.offsetHeight
590
+ };
591
+ schedule();
592
+ };
593
+ read();
594
+ if (typeof ResizeObserver === "undefined") return;
595
+ const observer = new ResizeObserver(read);
596
+ observer.observe(node);
597
+ return () => observer.disconnect();
598
+ }, [schedule]);
599
+ useLayoutEffect(() => {
600
+ const node = panelRef.current;
601
+ if (!open || !node) return;
602
+ const read = () => {
603
+ sizes.current.panel = {
604
+ w: node.offsetWidth,
605
+ h: node.offsetHeight
606
+ };
607
+ schedule();
608
+ };
609
+ read();
610
+ if (typeof ResizeObserver === "undefined") return;
611
+ const observer = new ResizeObserver(read);
612
+ observer.observe(node);
613
+ return () => observer.disconnect();
614
+ }, [
615
+ open,
616
+ mounted,
617
+ schedule
618
+ ]);
619
+ useEffect(() => {
620
+ if (!open) return;
621
+ const frame = requestAnimationFrame(() => {
622
+ const node = panelRef.current;
623
+ if (!node) return;
624
+ const rect = node.getBoundingClientRect();
625
+ const overflow = rect.bottom - (window.innerHeight - EDGE);
626
+ if (overflow <= 0) return;
627
+ window.scrollBy({
628
+ top: Math.min(overflow, Math.max(0, rect.top - EDGE)),
629
+ behavior: prefersReducedMotion() ? "instant" : "smooth"
630
+ });
631
+ });
632
+ return () => cancelAnimationFrame(frame);
633
+ }, [open]);
634
+ useEffect(() => {
635
+ if (open) return;
636
+ const trigger = triggerRef.current;
637
+ if (!trigger) return;
638
+ const rect = trigger.getBoundingClientRect();
639
+ if (rect.bottom < 0 || rect.top > window.innerHeight) trigger.scrollIntoView({
640
+ block: "center",
641
+ behavior: prefersReducedMotion() ? "instant" : "smooth"
642
+ });
643
+ }, [open]);
644
+ const measureLayout = useCallback(() => {
645
+ const box = bounds();
646
+ const available = Math.max(0, box.right - box.left - 16);
647
+ return {
648
+ single: months === 1 || months === "auto" && available < WIDE_MIN,
649
+ width: Math.min(352, available)
650
+ };
651
+ }, [bounds, months]);
652
+ useEffect(() => {
653
+ if (!open) return;
654
+ const onResize = () => {
655
+ const next = measureLayout();
656
+ setCompact(next.single);
657
+ setPanelWidth(next.width);
658
+ schedule();
659
+ };
660
+ window.addEventListener("resize", onResize);
661
+ return () => window.removeEventListener("resize", onResize);
662
+ }, [
663
+ measureLayout,
664
+ open,
665
+ schedule
666
+ ]);
667
+ const count = compact ? 1 : 2;
668
+ const cellSize = compact && panelWidth ? Math.max(32, Math.min(42, Math.floor((panelWidth - 24) / 7))) : WIDE_CELL;
669
+ /** The month the calendar opens on: the range's end, with the month before it beside it when two show. */
670
+ const viewFor = (range, single) => {
671
+ const end = (range.end ?? range.start ?? today(getLocalTimeZone())).set({ day: 1 });
672
+ return single ? end : end.subtract({ months: 1 });
673
+ };
674
+ const openPanel = () => {
675
+ setTodayValue(today(getLocalTimeZone()));
676
+ const layout = measureLayout();
677
+ setCompact(layout.single);
678
+ setPanelWidth(layout.width);
679
+ setDraft(committed);
680
+ setSnapshot({
681
+ anchor: null,
682
+ highlighted: null
683
+ });
684
+ setFocus(viewFor(committed, layout.single));
685
+ setOpen(true);
686
+ };
687
+ const close = useCallback((focusTrigger) => {
688
+ if (focusTrigger) pendingFocus.current = "trigger";
689
+ summaryRect.current = summaryRef.current?.getBoundingClientRect() ?? null;
690
+ setOpen(false);
691
+ setSnapshot({
692
+ anchor: null,
693
+ highlighted: null
694
+ });
695
+ }, []);
696
+ const apply = () => {
697
+ const next = snapshot.anchor ? {
698
+ start: snapshot.anchor,
699
+ end: snapshot.anchor
700
+ } : draft;
701
+ if (!next.start && !next.end && !props.clearable) return;
702
+ setCommitted(next);
703
+ close(true);
704
+ };
705
+ useLayoutEffect(() => {
706
+ if (prefersReducedMotion()) return;
707
+ if (open && summaryRef.current && restingRef.current) flyFrom(summaryRef.current, restingRef.current.getBoundingClientRect(), "grow");
708
+ }, [open, mounted]);
709
+ useLayoutEffect(() => {
710
+ if (!open && summaryRect.current && restingRef.current && !prefersReducedMotion()) {
711
+ flyFrom(restingRef.current, summaryRect.current, "shrink");
712
+ summaryRect.current = null;
713
+ }
714
+ }, [open]);
715
+ useLayoutEffect(() => {
716
+ if (pendingFocus.current === "trigger" && !open) {
717
+ pendingFocus.current = null;
718
+ triggerRef.current?.focus({ preventScroll: true });
719
+ }
720
+ }, [open]);
721
+ useEffect(() => {
722
+ if (!open) return;
723
+ const down = (event) => {
724
+ if (!rootRef.current?.contains(event.target)) close(false);
725
+ };
726
+ document.addEventListener("pointerdown", down);
727
+ return () => document.removeEventListener("pointerdown", down);
728
+ }, [close, open]);
729
+ useEffect(() => {
730
+ if (!open || !mounted) return;
731
+ const frame = requestAnimationFrame(() => {
732
+ const panel = panelRef.current;
733
+ if (!panel || panel.contains(document.activeElement)) return;
734
+ (panel.querySelector("[data-slot=\"calendar-cell\"][data-selection-start]:not([data-outside-month])") ?? panel.querySelector("[data-slot=\"calendar-cell\"][data-selection-end]:not([data-outside-month])") ?? panel.querySelector("[data-slot=\"calendar-cell\"]:not([data-outside-month]):not([data-disabled])"))?.focus({ preventScroll: true });
735
+ });
736
+ return () => cancelAnimationFrame(frame);
737
+ }, [open, mounted]);
738
+ const choosePreset = (preset) => {
739
+ const range = preset.range(todayValue);
740
+ setDraft(range);
741
+ setSnapshot({
742
+ anchor: null,
743
+ highlighted: null
744
+ });
745
+ setFocus(viewFor(range, compact));
746
+ };
747
+ const invalid = props.errorMessage != null;
748
+ const describedBy = [props.description != null && descriptionId, invalid && errorId].filter(Boolean).join(" ");
749
+ const size = props.size ?? "md";
750
+ const disabled = Boolean(props.isDisabled);
751
+ return /* @__PURE__ */ jsxs("div", {
752
+ "data-slot": "date-range-picker",
753
+ "data-invalid": invalid || void 0,
754
+ className: cnAll(datePickerVariants(), props.className),
755
+ children: [
756
+ /* @__PURE__ */ jsx("span", {
757
+ id: labelId,
758
+ className: cnAll(datePickerLabelVariants(), props.labelHidden && "sr-only"),
759
+ children: props.label
760
+ }),
761
+ /* @__PURE__ */ jsxs("div", {
762
+ ref: rootRef,
763
+ "data-open": open || void 0,
764
+ "data-disabled": disabled || void 0,
765
+ "data-invalid": invalid || void 0,
766
+ className: cnAll("range-root", rootSize[size]),
767
+ onKeyDown: (event) => {
768
+ if (event.key === "Escape" && open) {
769
+ event.preventDefault();
770
+ event.stopPropagation();
771
+ close(true);
772
+ }
773
+ },
774
+ onBlur: (event) => {
775
+ const next = event.relatedTarget;
776
+ if (open && next && !event.currentTarget.contains(next)) close(false);
777
+ },
778
+ children: [/* @__PURE__ */ jsxs("button", {
779
+ ref: (node) => {
780
+ mergedRef(node);
781
+ if (!node) return;
782
+ if (open) node.setAttribute("inert", "");
783
+ else node.removeAttribute("inert");
784
+ },
785
+ type: "button",
786
+ "data-slot": "range-trigger",
787
+ disabled,
788
+ "aria-haspopup": "dialog",
789
+ "aria-expanded": open,
790
+ "aria-controls": open ? panelId : void 0,
791
+ "aria-labelledby": `${labelId} ${valueId}`,
792
+ "aria-describedby": describedBy || void 0,
793
+ onClick: openPanel,
794
+ className: cnAll("relative z-10 flex w-full cursor-pointer items-center gap-2 border-0 bg-transparent text-start text-base leading-(--leading-normal) text-foreground outline-none", "disabled:cursor-not-allowed", triggerSize[size]),
795
+ children: [
796
+ /* @__PURE__ */ jsx("span", {
797
+ className: "range-quiet flex flex-none text-muted-foreground [&_svg]:size-(--icon-sm)",
798
+ children: /* @__PURE__ */ jsx(CalendarGlyph, {})
799
+ }),
800
+ /* @__PURE__ */ jsx("span", {
801
+ id: valueId,
802
+ className: "sr-only",
803
+ children: committedText
804
+ }),
805
+ /* @__PURE__ */ jsx("span", {
806
+ ref: restingRef,
807
+ "data-slot": "range-value",
808
+ className: cnAll("range-quiet flex min-w-0 flex-1 overflow-hidden tabular-nums", !(committed.start || committed.end) && "text-muted-foreground"),
809
+ children: /* @__PURE__ */ jsx(RollingWords, {
810
+ text: committedText,
811
+ direction: committedDirection
812
+ })
813
+ }),
814
+ /* @__PURE__ */ jsx("span", {
815
+ className: "range-quiet flex flex-none text-muted-foreground [&_svg]:size-(--icon-sm)",
816
+ children: /* @__PURE__ */ jsx(Chevron, {})
817
+ })
818
+ ]
819
+ }), /* @__PURE__ */ jsx("div", {
820
+ ref: surfaceRef,
821
+ "data-slot": "range-surface",
822
+ className: cnAll("range-surface", disabled && "bg-muted opacity-(--opacity-disabled)", invalid && "border-destructive-strong"),
823
+ style: { borderRadius: RADIUS_CLOSED },
824
+ children: mounted ? /* @__PURE__ */ jsxs("div", {
825
+ ref: panelRef,
826
+ id: panelId,
827
+ role: "dialog",
828
+ "aria-label": props.label,
829
+ "data-slot": "range-panel",
830
+ "data-compact": compact || void 0,
831
+ style: {
832
+ "--cell": `${cellSize}px`,
833
+ width: compact && panelWidth ? panelWidth : void 0
834
+ },
835
+ className: cnAll("absolute top-0 start-0 box-border w-[max-content] text-sm leading-(--leading-normal) text-foreground", compact ? "p-2" : "p-2.5"),
836
+ children: [
837
+ /* @__PURE__ */ jsxs("div", {
838
+ "data-slot": "range-body",
839
+ className: cnAll("flex", compact ? "flex-col gap-2" : "gap-2.5", closing ? "motion-safe:animate-range-face-out motion-reduce:animate-range-face-fade-out" : "motion-safe:animate-range-face-in motion-reduce:animate-range-face-fade-in"),
840
+ children: [/* @__PURE__ */ jsx(PresetRail, {
841
+ presets,
842
+ active: activePreset,
843
+ compact,
844
+ label: messages.presets,
845
+ onChoose: choosePreset
846
+ }), /* @__PURE__ */ jsxs("div", {
847
+ className: "flex min-w-0 flex-col gap-3",
848
+ children: [/* @__PURE__ */ jsxs("div", {
849
+ className: "flex gap-2",
850
+ children: [/* @__PURE__ */ jsx(TypedDate, {
851
+ label: startLabel,
852
+ value: draft.start,
853
+ minValue: props.minValue,
854
+ maxValue: props.maxValue,
855
+ onChange: (next) => {
856
+ if (next || props.clearable) setDraft({
857
+ start: next,
858
+ end: draft.end
859
+ });
860
+ }
861
+ }), /* @__PURE__ */ jsx(TypedDate, {
862
+ label: endLabel,
863
+ value: draft.end,
864
+ minValue: props.minValue,
865
+ maxValue: props.maxValue,
866
+ onChange: (next) => {
867
+ if (next || props.clearable) setDraft({
868
+ start: draft.start,
869
+ end: next
870
+ });
871
+ }
872
+ })]
873
+ }), /* @__PURE__ */ jsxs(RangeCalendar, {
874
+ "aria-label": props.label,
875
+ value: complete,
876
+ onChange: (next) => setDraft({
877
+ start: next.start,
878
+ end: next.end
879
+ }),
880
+ focusedValue: focus ?? void 0,
881
+ onFocusChange: setFocus,
882
+ minValue: props.minValue,
883
+ maxValue: props.maxValue,
884
+ visibleDuration: { months: count },
885
+ pageBehavior: "single",
886
+ selectionAlignment: "start",
887
+ "data-slot": "range-calendar",
888
+ style: { "--density-control-h-sm": "var(--cell)" },
889
+ className: cnAll("relative flex flex-col font-sans", compact && "self-center"),
890
+ children: [
891
+ /* @__PURE__ */ jsx(CalendarBridge, { onSnapshot: setSnapshot }),
892
+ /* @__PURE__ */ jsx(RangeDriver, {}),
893
+ /* @__PURE__ */ jsxs("div", {
894
+ className: "relative",
895
+ children: [
896
+ /* @__PURE__ */ jsx(Button, {
897
+ slot: "previous",
898
+ "aria-label": messages.previousMonth,
899
+ className: cnAll(calendarNavVariants(), "absolute start-0 top-0 z-20 size-8"),
900
+ children: /* @__PURE__ */ jsx("svg", {
901
+ viewBox: "0 0 24 24",
902
+ fill: "none",
903
+ stroke: "currentColor",
904
+ strokeWidth: "2",
905
+ "aria-hidden": "true",
906
+ children: /* @__PURE__ */ jsx("path", {
907
+ d: "m15 18-6-6 6-6",
908
+ strokeLinecap: "round",
909
+ strokeLinejoin: "round"
910
+ })
911
+ })
912
+ }),
913
+ /* @__PURE__ */ jsx(Button, {
914
+ slot: "next",
915
+ "aria-label": messages.nextMonth,
916
+ className: cnAll(calendarNavVariants(), "absolute end-0 top-0 z-20 size-8"),
917
+ children: /* @__PURE__ */ jsx("svg", {
918
+ viewBox: "0 0 24 24",
919
+ fill: "none",
920
+ stroke: "currentColor",
921
+ strokeWidth: "2",
922
+ "aria-hidden": "true",
923
+ children: /* @__PURE__ */ jsx("path", {
924
+ d: "m9 18 6-6-6-6",
925
+ strokeLinecap: "round",
926
+ strokeLinejoin: "round"
927
+ })
928
+ })
929
+ }),
930
+ /* @__PURE__ */ jsx(MonthSets, { count })
931
+ ]
932
+ })
933
+ ]
934
+ })]
935
+ })]
936
+ }),
937
+ /* @__PURE__ */ jsxs("div", {
938
+ "data-slot": "range-footer",
939
+ className: cnAll("mt-2.5 flex items-center justify-between gap-3 border-t-(length:--border-width) border-border pt-2.5 ps-3", compact && "flex-wrap"),
940
+ children: [/* @__PURE__ */ jsxs("div", {
941
+ className: cnAll("grid min-w-0 gap-px", compact && "flex-[1_1_8rem]"),
942
+ children: [/* @__PURE__ */ jsx("span", {
943
+ ref: summaryRef,
944
+ "data-slot": "range-summary",
945
+ className: "inline-flex w-[max-content] font-medium tabular-nums",
946
+ children: /* @__PURE__ */ jsx(RollingWords, {
947
+ text: shownText,
948
+ direction: shownDirection
949
+ })
950
+ }), /* @__PURE__ */ jsx("span", {
951
+ className: "inline-flex min-h-4.5 text-xs text-muted-foreground tabular-nums",
952
+ children: countText ? /* @__PURE__ */ jsx(RollingWords, {
953
+ text: countText,
954
+ direction: shownDirection
955
+ }) : null
956
+ })]
957
+ }), /* @__PURE__ */ jsxs("div", {
958
+ className: cnAll("flex flex-none items-center gap-1.5", compact && "ms-auto"),
959
+ children: [
960
+ props.clearable ? /* @__PURE__ */ jsx(Button$1, {
961
+ variant: "ghost",
962
+ size: "sm",
963
+ onPress: () => {
964
+ setDraft(NO_RANGE);
965
+ setSnapshot({
966
+ anchor: null,
967
+ highlighted: null
968
+ });
969
+ },
970
+ children: messages.clear
971
+ }) : null,
972
+ /* @__PURE__ */ jsx(Button$1, {
973
+ variant: "ghost",
974
+ size: "sm",
975
+ onPress: () => close(true),
976
+ children: messages.cancel
977
+ }),
978
+ /* @__PURE__ */ jsx(Button$1, {
979
+ variant: "primary",
980
+ size: "sm",
981
+ onPress: apply,
982
+ isDisabled: !shown && !(props.clearable && (committed.start || committed.end)),
983
+ children: messages.apply
984
+ })
985
+ ]
986
+ })]
987
+ }),
988
+ /* @__PURE__ */ jsx("p", {
989
+ className: "sr-only",
990
+ "aria-live": "polite",
991
+ children: status
992
+ })
993
+ ]
994
+ }) : null
995
+ })]
996
+ }),
997
+ props.description == null ? null : /* @__PURE__ */ jsx("span", {
998
+ id: descriptionId,
999
+ "data-slot": "date-range-picker-description",
1000
+ className: descriptionClass,
1001
+ children: props.description
1002
+ }),
1003
+ invalid ? /* @__PURE__ */ jsx("span", {
1004
+ id: errorId,
1005
+ "data-slot": "date-range-picker-error",
1006
+ className: errorClass,
1007
+ children: props.errorMessage
1008
+ }) : null
1009
+ ]
1010
+ });
1011
+ });
1012
+ //#endregion
1013
+ export { DateRangePicker, defaultDateRangePresets };
1014
+
1015
+ //# sourceMappingURL=date-range-picker.js.map