@mieweb/ui 0.6.1-dev.167 → 0.6.1-dev.169

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.
@@ -0,0 +1,689 @@
1
+ import { Input } from './chunk-PVUDXJAI.js';
2
+ import { formatDateValue, isValidDate, isDateInFuture, isDateInPast, calculateAge } from './chunk-RC2YMOMS.js';
3
+ import { cn } from './chunk-F3SOEIN2.js';
4
+ import * as React from 'react';
5
+ import { createPortal } from 'react-dom';
6
+ import { Calendar } from 'lucide-react';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+
9
+ var widthClasses = {
10
+ full: "w-full",
11
+ fit: "w-fit",
12
+ fixed: "w-44"
13
+ // ~176px - enough for MM/DD/YYYY + calendar icon
14
+ };
15
+ var sizeClasses = {
16
+ sm: "h-8 text-sm",
17
+ md: "h-10 text-base",
18
+ lg: "h-12 text-lg"
19
+ };
20
+ var MONTH_NAMES = [
21
+ "January",
22
+ "February",
23
+ "March",
24
+ "April",
25
+ "May",
26
+ "June",
27
+ "July",
28
+ "August",
29
+ "September",
30
+ "October",
31
+ "November",
32
+ "December"
33
+ ];
34
+ function isValidPickerDate(year, month, day) {
35
+ return Number.isFinite(year) && month >= 1 && month <= 12 && day >= 1 && day <= new Date(year, month, 0).getDate();
36
+ }
37
+ function parsePickerDate(value, inputType) {
38
+ if (inputType === "datetime-local") {
39
+ const match = /^(\d{4})-(\d{2})-(\d{2})T\d{2}:\d{2}$/.exec(value);
40
+ if (!match) return void 0;
41
+ const year2 = Number(match[1]);
42
+ const month2 = Number(match[2]);
43
+ const day2 = Number(match[3]);
44
+ const [hour, minute] = value.slice(-5).split(":").map(Number);
45
+ if (!isValidPickerDate(year2, month2, day2) || hour > 23 || minute > 59) {
46
+ return void 0;
47
+ }
48
+ return {
49
+ year: year2,
50
+ month: month2 - 1,
51
+ day: day2
52
+ };
53
+ }
54
+ if (inputType === "month") {
55
+ const match = /^(\d{4})-(\d{2})$/.exec(value);
56
+ if (!match) return void 0;
57
+ const year2 = Number(match[1]);
58
+ const month2 = Number(match[2]);
59
+ if (!Number.isFinite(year2) || month2 < 1 || month2 > 12) return void 0;
60
+ return { year: year2, month: month2 - 1, day: null };
61
+ }
62
+ if (!isValidDate(value)) return void 0;
63
+ const [month, day, year] = value.split("/").map(Number);
64
+ return { month: month - 1, year, day };
65
+ }
66
+ function formatPickerValue(value, inputType, timeFormat) {
67
+ if (inputType === "datetime-local") {
68
+ const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}:\d{2})$/.exec(value);
69
+ if (!match) return "";
70
+ if (timeFormat === "12-hour") {
71
+ const [hour, minute] = match[4].split(":").map(Number);
72
+ const displayHour = hour % 12 || 12;
73
+ const meridiem = hour >= 12 ? "PM" : "AM";
74
+ return `${match[2]}/${match[3]}/${match[1]} ${displayHour}:${String(minute).padStart(2, "0")} ${meridiem}`;
75
+ }
76
+ return `${match[2]}/${match[3]}/${match[1]} ${match[4]}`;
77
+ }
78
+ if (inputType === "month") {
79
+ const date = parsePickerDate(value, inputType);
80
+ return date ? `${MONTH_NAMES[date.month]} ${date.year}` : "";
81
+ }
82
+ return value;
83
+ }
84
+ function getValidationError(value, mode, minAge, maxAge) {
85
+ if (!value || value.replace(/\D/g, "").length === 0) {
86
+ return void 0;
87
+ }
88
+ if (!isValidDate(value)) {
89
+ return "Please enter a valid date (MM/DD/YYYY)";
90
+ }
91
+ switch (mode) {
92
+ case "dob": {
93
+ if (!isDateInPast(value)) {
94
+ return "Date of birth must be in the past";
95
+ }
96
+ const age = calculateAge(value);
97
+ if (age !== null) {
98
+ if (minAge !== void 0 && age < minAge) {
99
+ return `Must be at least ${minAge} years old`;
100
+ }
101
+ if (maxAge !== void 0 && age > maxAge) {
102
+ return `Must be no more than ${maxAge} years old`;
103
+ }
104
+ }
105
+ break;
106
+ }
107
+ case "expiration":
108
+ if (!isDateInFuture(value)) {
109
+ return "Expiration date must be in the future";
110
+ }
111
+ break;
112
+ case "past":
113
+ if (!isDateInPast(value)) {
114
+ return "Date must be in the past";
115
+ }
116
+ break;
117
+ case "future":
118
+ if (!isDateInFuture(value)) {
119
+ return "Date must be in the future";
120
+ }
121
+ break;
122
+ }
123
+ return void 0;
124
+ }
125
+ var DateInput = React.forwardRef(
126
+ ({
127
+ value = "",
128
+ onChange,
129
+ inputType = "date",
130
+ timeFormat = "24-hour",
131
+ mode = "default",
132
+ minAge,
133
+ maxAge,
134
+ validateOnBlur,
135
+ showCalendar = false,
136
+ width = "full",
137
+ className,
138
+ onBlur,
139
+ onClick,
140
+ hasError,
141
+ error,
142
+ ...props
143
+ }, ref) => {
144
+ const isFormattedDate = inputType === "date";
145
+ const [displayValue, setDisplayValue] = React.useState(
146
+ () => isFormattedDate ? formatDateValue(value) : value
147
+ );
148
+ const [localError, setLocalError] = React.useState();
149
+ React.useEffect(() => {
150
+ setDisplayValue(isFormattedDate ? formatDateValue(value) : value);
151
+ }, [isFormattedDate, value]);
152
+ const handleChange = (e) => {
153
+ const formatted = formatDateValue(e.target.value);
154
+ setDisplayValue(formatted);
155
+ onChange?.(formatted);
156
+ if (localError) {
157
+ setLocalError(void 0);
158
+ }
159
+ };
160
+ const handleBlur = (e) => {
161
+ onBlur?.(e);
162
+ if (validateOnBlur) {
163
+ const validationError = getValidationError(
164
+ displayValue,
165
+ mode,
166
+ minAge,
167
+ maxAge
168
+ );
169
+ setLocalError(validationError);
170
+ }
171
+ };
172
+ const placeholder = mode === "expiration" ? "MM/DD/YYYY" : "MM/DD/YYYY";
173
+ const autoComplete = mode === "dob" ? "bday" : mode === "expiration" ? "cc-exp" : void 0;
174
+ const generatedId = React.useId();
175
+ const [isCalendarOpen, setIsCalendarOpen] = React.useState(false);
176
+ const calendarRef = React.useRef(null);
177
+ const buttonRef = React.useRef(null);
178
+ const [calendarStyle, setCalendarStyle] = React.useState();
179
+ const updateCalendarPosition = React.useCallback(() => {
180
+ if (!buttonRef.current) return;
181
+ const rect = buttonRef.current.getBoundingClientRect();
182
+ setCalendarStyle({
183
+ position: "fixed",
184
+ top: rect.bottom + 4,
185
+ left: Math.max(8, rect.right - 288),
186
+ zIndex: 9999
187
+ });
188
+ }, []);
189
+ React.useEffect(() => {
190
+ if (!isCalendarOpen) return;
191
+ updateCalendarPosition();
192
+ window.addEventListener("scroll", updateCalendarPosition, true);
193
+ window.addEventListener("resize", updateCalendarPosition);
194
+ return () => {
195
+ window.removeEventListener("scroll", updateCalendarPosition, true);
196
+ window.removeEventListener("resize", updateCalendarPosition);
197
+ };
198
+ }, [isCalendarOpen, updateCalendarPosition]);
199
+ const parsedDate = React.useMemo(() => {
200
+ const fallback = /* @__PURE__ */ new Date();
201
+ return parsePickerDate(displayValue, inputType) ?? {
202
+ month: fallback.getMonth(),
203
+ year: fallback.getFullYear(),
204
+ day: null
205
+ };
206
+ }, [displayValue, inputType]);
207
+ const [calendarMonth, setCalendarMonth] = React.useState(parsedDate.month);
208
+ const [calendarYear, setCalendarYear] = React.useState(parsedDate.year);
209
+ const [selectedTime, setSelectedTime] = React.useState(
210
+ () => inputType === "datetime-local" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(value) ? value.slice(-5) : "00:00"
211
+ );
212
+ React.useEffect(() => {
213
+ const date = parsePickerDate(displayValue, inputType);
214
+ if (!date) return;
215
+ setCalendarMonth(date.month);
216
+ setCalendarYear(date.year);
217
+ if (inputType === "datetime-local") {
218
+ setSelectedTime(displayValue.slice(-5));
219
+ }
220
+ }, [displayValue, inputType]);
221
+ React.useEffect(() => {
222
+ const handleClickOutside = (event) => {
223
+ if (calendarRef.current && !calendarRef.current.contains(event.target) && buttonRef.current && !buttonRef.current.contains(event.target)) {
224
+ setIsCalendarOpen(false);
225
+ }
226
+ };
227
+ if (isCalendarOpen) {
228
+ document.addEventListener("mousedown", handleClickOutside);
229
+ return () => document.removeEventListener("mousedown", handleClickOutside);
230
+ }
231
+ }, [isCalendarOpen]);
232
+ React.useEffect(() => {
233
+ const handleEscape = (event) => {
234
+ if (event.key === "Escape") {
235
+ setIsCalendarOpen(false);
236
+ buttonRef.current?.focus();
237
+ }
238
+ };
239
+ if (isCalendarOpen) {
240
+ document.addEventListener("keydown", handleEscape);
241
+ return () => document.removeEventListener("keydown", handleEscape);
242
+ }
243
+ }, [isCalendarOpen]);
244
+ const handleDateSelect = (day) => {
245
+ const month = String(calendarMonth + 1).padStart(2, "0");
246
+ const dayStr = String(day).padStart(2, "0");
247
+ const year = String(calendarYear);
248
+ const formatted = inputType === "datetime-local" ? `${year}-${month}-${dayStr}T${selectedTime}` : `${month}/${dayStr}/${year}`;
249
+ setDisplayValue(formatted);
250
+ onChange?.(formatted);
251
+ if (inputType === "date") {
252
+ setIsCalendarOpen(false);
253
+ }
254
+ if (inputType === "date" && validateOnBlur) {
255
+ const validationError = getValidationError(
256
+ formatted,
257
+ mode,
258
+ minAge,
259
+ maxAge
260
+ );
261
+ setLocalError(validationError);
262
+ }
263
+ };
264
+ const handleMonthSelect = (month) => {
265
+ const formatted = `${calendarYear}-${String(month + 1).padStart(2, "0")}`;
266
+ setDisplayValue(formatted);
267
+ onChange?.(formatted);
268
+ setIsCalendarOpen(false);
269
+ };
270
+ const handleTimeChange = (part, nextValue) => {
271
+ const [hour, minute] = selectedTime.split(":");
272
+ const nextTime = part === "hour" ? `${nextValue}:${minute}` : `${hour}:${nextValue}`;
273
+ setSelectedTime(nextTime);
274
+ if (parsedDate.day === null) return;
275
+ const month = String(parsedDate.month + 1).padStart(2, "0");
276
+ const day = String(parsedDate.day).padStart(2, "0");
277
+ const formatted = `${parsedDate.year}-${month}-${day}T${nextTime}`;
278
+ setDisplayValue(formatted);
279
+ onChange?.(formatted);
280
+ };
281
+ const handleMeridiemChange = (meridiem) => {
282
+ const [hour] = selectedTime.split(":").map(Number);
283
+ const nextHour = hour % 12 + (meridiem === "PM" ? 12 : 0);
284
+ handleTimeChange("hour", String(nextHour).padStart(2, "0"));
285
+ };
286
+ const getDaysInMonth = (month, year) => {
287
+ return new Date(year, month + 1, 0).getDate();
288
+ };
289
+ const getFirstDayOfMonth = (month, year) => {
290
+ return new Date(year, month, 1).getDay();
291
+ };
292
+ const renderCalendar = () => {
293
+ const daysInMonth = getDaysInMonth(calendarMonth, calendarYear);
294
+ const firstDay = getFirstDayOfMonth(calendarMonth, calendarYear);
295
+ const days = [];
296
+ for (let i = 0; i < firstDay; i++) {
297
+ days.push(null);
298
+ }
299
+ for (let i = 1; i <= daysInMonth; i++) {
300
+ days.push(i);
301
+ }
302
+ const isSelectedDay = (day) => {
303
+ return parsedDate.day === day && parsedDate.month === calendarMonth && parsedDate.year === calendarYear;
304
+ };
305
+ const isToday = (day) => {
306
+ const today = /* @__PURE__ */ new Date();
307
+ return day === today.getDate() && calendarMonth === today.getMonth() && calendarYear === today.getFullYear();
308
+ };
309
+ return /* @__PURE__ */ jsxs(
310
+ "div",
311
+ {
312
+ ref: calendarRef,
313
+ className: cn(
314
+ "bg-background border-border rounded-lg border shadow-lg",
315
+ "w-72 p-3"
316
+ ),
317
+ style: calendarStyle,
318
+ role: "dialog",
319
+ "aria-label": inputType === "month" ? "Choose month" : inputType === "datetime-local" ? "Choose date and time" : "Choose date",
320
+ children: [
321
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center justify-between", children: [
322
+ /* @__PURE__ */ jsx(
323
+ "button",
324
+ {
325
+ type: "button",
326
+ onClick: () => {
327
+ if (inputType === "month") {
328
+ setCalendarYear(calendarYear - 1);
329
+ } else if (calendarMonth === 0) {
330
+ setCalendarMonth(11);
331
+ setCalendarYear(calendarYear - 1);
332
+ } else {
333
+ setCalendarMonth(calendarMonth - 1);
334
+ }
335
+ },
336
+ className: "hover:bg-muted rounded-md p-1 transition-colors",
337
+ "aria-label": inputType === "month" ? "Previous year" : "Previous month",
338
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
339
+ }
340
+ ),
341
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
342
+ inputType !== "month" && /* @__PURE__ */ jsx(
343
+ "select",
344
+ {
345
+ value: calendarMonth,
346
+ onChange: (e) => setCalendarMonth(Number(e.target.value)),
347
+ className: "bg-background border-border rounded border px-2 py-1 text-sm",
348
+ "aria-label": "Select month",
349
+ children: MONTH_NAMES.map((name, i) => /* @__PURE__ */ jsx("option", { value: i, children: name }, name))
350
+ }
351
+ ),
352
+ /* @__PURE__ */ jsx(
353
+ "select",
354
+ {
355
+ value: calendarYear,
356
+ onChange: (e) => setCalendarYear(Number(e.target.value)),
357
+ className: "bg-background border-border rounded border px-2 py-1 text-sm",
358
+ "aria-label": "Select year",
359
+ children: Array.from(
360
+ { length: 150 },
361
+ (_, i) => (/* @__PURE__ */ new Date()).getFullYear() - 100 + i
362
+ ).map((year) => /* @__PURE__ */ jsx("option", { value: year, children: year }, year))
363
+ }
364
+ )
365
+ ] }),
366
+ /* @__PURE__ */ jsx(
367
+ "button",
368
+ {
369
+ type: "button",
370
+ onClick: () => {
371
+ if (inputType === "month") {
372
+ setCalendarYear(calendarYear + 1);
373
+ } else if (calendarMonth === 11) {
374
+ setCalendarMonth(0);
375
+ setCalendarYear(calendarYear + 1);
376
+ } else {
377
+ setCalendarMonth(calendarMonth + 1);
378
+ }
379
+ },
380
+ className: "hover:bg-muted rounded-md p-1 transition-colors",
381
+ "aria-label": inputType === "month" ? "Next year" : "Next month",
382
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
383
+ }
384
+ )
385
+ ] }),
386
+ inputType === "month" ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1", children: MONTH_NAMES.map((name, month) => /* @__PURE__ */ jsx(
387
+ "button",
388
+ {
389
+ type: "button",
390
+ onClick: () => handleMonthSelect(month),
391
+ className: cn(
392
+ "rounded-md px-2 py-2 text-sm transition-colors",
393
+ "focus:ring-ring focus:ring-2 focus:outline-none",
394
+ "hover:bg-muted",
395
+ parsedDate.month === month && parsedDate.year === calendarYear && "bg-primary-800 hover:bg-primary-900 text-white"
396
+ ),
397
+ children: name.slice(0, 3)
398
+ },
399
+ name
400
+ )) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
401
+ /* @__PURE__ */ jsx("div", { className: "mb-1 grid grid-cols-7 gap-1", children: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ jsx(
402
+ "div",
403
+ {
404
+ className: "text-muted-foreground py-1 text-center text-xs font-medium",
405
+ children: day
406
+ },
407
+ day
408
+ )) }),
409
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1", children: days.map((day, index) => /* @__PURE__ */ jsx(
410
+ "button",
411
+ {
412
+ type: "button",
413
+ disabled: day === null,
414
+ onClick: () => day && handleDateSelect(day),
415
+ className: cn(
416
+ "h-8 w-8 rounded-md text-sm transition-colors",
417
+ "focus:ring-ring focus:ring-2 focus:outline-none",
418
+ day === null && "invisible",
419
+ day !== null && "hover:bg-muted",
420
+ isSelectedDay(day) && "bg-primary-800 hover:bg-primary-900 text-white",
421
+ isToday(day) && !isSelectedDay(day) && "border-primary-800 text-primary-800 border"
422
+ ),
423
+ children: day
424
+ },
425
+ index
426
+ )) })
427
+ ] }),
428
+ inputType === "datetime-local" && /* @__PURE__ */ jsxs("div", { className: "border-border mt-3 flex items-center gap-2 border-t pt-3", children: [
429
+ /* @__PURE__ */ jsx(
430
+ "select",
431
+ {
432
+ value: timeFormat === "12-hour" ? String(
433
+ Number(selectedTime.slice(0, 2)) % 12 || 12
434
+ ).padStart(2, "0") : selectedTime.slice(0, 2),
435
+ onChange: (event) => {
436
+ const hour = Number(event.target.value);
437
+ const isPm = Number(selectedTime.slice(0, 2)) >= 12;
438
+ handleTimeChange(
439
+ "hour",
440
+ String(
441
+ timeFormat === "12-hour" ? hour % 12 + (isPm ? 12 : 0) : hour
442
+ ).padStart(2, "0")
443
+ );
444
+ },
445
+ className: "bg-background border-border rounded border px-2 py-1 text-sm",
446
+ "aria-label": "Select hour",
447
+ children: Array.from(
448
+ { length: timeFormat === "12-hour" ? 12 : 24 },
449
+ (_, index) => timeFormat === "12-hour" ? index + 1 : index
450
+ ).map((hour) => /* @__PURE__ */ jsx("option", { value: String(hour).padStart(2, "0"), children: String(hour).padStart(2, "0") }, hour))
451
+ }
452
+ ),
453
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: ":" }),
454
+ /* @__PURE__ */ jsx(
455
+ "select",
456
+ {
457
+ value: selectedTime.slice(3),
458
+ onChange: (event) => handleTimeChange("minute", event.target.value),
459
+ className: "bg-background border-border rounded border px-2 py-1 text-sm",
460
+ "aria-label": "Select minute",
461
+ children: Array.from({ length: 60 }, (_, minute) => /* @__PURE__ */ jsx("option", { value: String(minute).padStart(2, "0"), children: String(minute).padStart(2, "0") }, minute))
462
+ }
463
+ ),
464
+ timeFormat === "12-hour" && /* @__PURE__ */ jsxs(
465
+ "select",
466
+ {
467
+ value: Number(selectedTime.slice(0, 2)) >= 12 ? "PM" : "AM",
468
+ onChange: (event) => handleMeridiemChange(event.target.value),
469
+ className: "bg-background border-border rounded border px-2 py-1 text-sm",
470
+ "aria-label": "Select AM or PM",
471
+ children: [
472
+ /* @__PURE__ */ jsx("option", { value: "AM", children: "AM" }),
473
+ /* @__PURE__ */ jsx("option", { value: "PM", children: "PM" })
474
+ ]
475
+ }
476
+ )
477
+ ] }),
478
+ /* @__PURE__ */ jsxs("div", { className: "border-border mt-3 flex gap-2 border-t pt-3", children: [
479
+ /* @__PURE__ */ jsx(
480
+ "button",
481
+ {
482
+ type: "button",
483
+ onClick: () => {
484
+ const today = /* @__PURE__ */ new Date();
485
+ setCalendarMonth(today.getMonth());
486
+ setCalendarYear(today.getFullYear());
487
+ if (inputType === "month") {
488
+ handleMonthSelect(today.getMonth());
489
+ } else {
490
+ handleDateSelect(today.getDate());
491
+ }
492
+ },
493
+ className: "text-primary-800 flex-1 text-sm hover:underline",
494
+ children: "Today"
495
+ }
496
+ ),
497
+ inputType === "datetime-local" && /* @__PURE__ */ jsx(
498
+ "button",
499
+ {
500
+ type: "button",
501
+ onClick: () => setIsCalendarOpen(false),
502
+ className: "text-primary-800 flex-1 text-sm hover:underline",
503
+ children: "Done"
504
+ }
505
+ )
506
+ ] })
507
+ ]
508
+ }
509
+ );
510
+ };
511
+ if (inputType === "year") {
512
+ return /* @__PURE__ */ jsx(
513
+ Input,
514
+ {
515
+ ref,
516
+ type: inputType === "year" ? "text" : inputType,
517
+ inputMode: inputType === "year" ? "numeric" : void 0,
518
+ pattern: inputType === "year" ? "[0-9]{4}" : void 0,
519
+ maxLength: inputType === "year" ? 4 : void 0,
520
+ placeholder: inputType === "year" ? "YYYY" : void 0,
521
+ value: value.replace(/\D/g, "").slice(0, 4),
522
+ onChange: (event) => onChange?.(event.target.value.replace(/\D/g, "").slice(0, 4)),
523
+ onBlur,
524
+ onClick,
525
+ hasError,
526
+ error,
527
+ className: cn(widthClasses[width], className),
528
+ ...props
529
+ }
530
+ );
531
+ }
532
+ if (showCalendar || inputType !== "date") {
533
+ const { label, helperText, hideLabel, required, size, ...inputProps } = props;
534
+ const resolvedSize = size ?? "md";
535
+ const inputId = inputProps.id || generatedId;
536
+ const errorId = `${inputId}-error`;
537
+ const helperId = `${inputId}-helper`;
538
+ const showError = hasError || !!localError;
539
+ const errorMessage = error || localError;
540
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", widthClasses[width]), children: [
541
+ label && /* @__PURE__ */ jsxs(
542
+ "label",
543
+ {
544
+ htmlFor: inputId,
545
+ className: cn(
546
+ "text-foreground text-sm font-medium",
547
+ hideLabel && "sr-only"
548
+ ),
549
+ children: [
550
+ label,
551
+ required && /* @__PURE__ */ jsx(
552
+ "span",
553
+ {
554
+ className: "ml-1",
555
+ style: { color: "#ef4444" },
556
+ "aria-hidden": "true",
557
+ children: "*"
558
+ }
559
+ )
560
+ ]
561
+ }
562
+ ),
563
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
564
+ /* @__PURE__ */ jsx(
565
+ "input",
566
+ {
567
+ ref,
568
+ id: inputId,
569
+ type: "text",
570
+ inputMode: inputType === "date" ? "numeric" : void 0,
571
+ autoComplete,
572
+ placeholder: inputType === "month" ? "Select month" : inputType === "datetime-local" ? "Select date and time" : placeholder,
573
+ value: formatPickerValue(displayValue, inputType, timeFormat),
574
+ onChange: handleChange,
575
+ onBlur: inputType === "date" ? handleBlur : onBlur,
576
+ onClick: (event) => {
577
+ onClick?.(event);
578
+ setIsCalendarOpen(true);
579
+ },
580
+ readOnly: !isFormattedDate,
581
+ "aria-invalid": showError,
582
+ "aria-describedby": [errorMessage ? errorId : null, helperText ? helperId : null].filter(Boolean).join(" ") || void 0,
583
+ className: cn(
584
+ "w-full px-3 py-2",
585
+ "rounded-lg border",
586
+ "bg-background text-foreground",
587
+ "placeholder:text-muted-foreground",
588
+ "transition-colors duration-200",
589
+ "focus:ring-ring focus:border-transparent focus:ring-2 focus:outline-none",
590
+ "disabled:cursor-not-allowed disabled:opacity-50",
591
+ sizeClasses[resolvedSize],
592
+ showError ? "border-destructive focus:ring-destructive" : "border-input",
593
+ "pr-10",
594
+ className
595
+ ),
596
+ ...inputProps
597
+ }
598
+ ),
599
+ /* @__PURE__ */ jsx(
600
+ "button",
601
+ {
602
+ ref: buttonRef,
603
+ type: "button",
604
+ onClick: () => setIsCalendarOpen(!isCalendarOpen),
605
+ className: cn(
606
+ "absolute top-1/2 right-3 -translate-y-1/2",
607
+ "text-muted-foreground hover:text-foreground",
608
+ "focus:text-foreground focus:outline-none",
609
+ "transition-colors"
610
+ ),
611
+ "aria-label": "Open calendar",
612
+ "aria-expanded": isCalendarOpen,
613
+ "aria-haspopup": "dialog",
614
+ children: /* @__PURE__ */ jsx(Calendar, { size: 18 })
615
+ }
616
+ )
617
+ ] }),
618
+ isCalendarOpen && createPortal(renderCalendar(), document.body),
619
+ errorMessage && /* @__PURE__ */ jsx(
620
+ "p",
621
+ {
622
+ id: errorId,
623
+ className: "text-sm",
624
+ style: { color: "#ef4444" },
625
+ role: "alert",
626
+ children: errorMessage
627
+ }
628
+ ),
629
+ helperText && !errorMessage && /* @__PURE__ */ jsx("p", { id: helperId, className: "text-muted-foreground text-sm", children: helperText })
630
+ ] });
631
+ }
632
+ return /* @__PURE__ */ jsx(
633
+ Input,
634
+ {
635
+ ref,
636
+ type: "text",
637
+ inputMode: "numeric",
638
+ autoComplete,
639
+ placeholder,
640
+ value: displayValue,
641
+ onChange: handleChange,
642
+ onBlur: handleBlur,
643
+ hasError: hasError || !!localError,
644
+ error: error || localError,
645
+ className: cn(widthClasses[width], className),
646
+ ...props
647
+ }
648
+ );
649
+ }
650
+ );
651
+ DateInput.displayName = "DateInput";
652
+ function ChevronLeftIcon() {
653
+ return /* @__PURE__ */ jsx(
654
+ "svg",
655
+ {
656
+ "aria-hidden": "true",
657
+ width: "16",
658
+ height: "16",
659
+ viewBox: "0 0 24 24",
660
+ fill: "none",
661
+ stroke: "currentColor",
662
+ strokeWidth: "2",
663
+ strokeLinecap: "round",
664
+ strokeLinejoin: "round",
665
+ children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" })
666
+ }
667
+ );
668
+ }
669
+ function ChevronRightIcon() {
670
+ return /* @__PURE__ */ jsx(
671
+ "svg",
672
+ {
673
+ "aria-hidden": "true",
674
+ width: "16",
675
+ height: "16",
676
+ viewBox: "0 0 24 24",
677
+ fill: "none",
678
+ stroke: "currentColor",
679
+ strokeWidth: "2",
680
+ strokeLinecap: "round",
681
+ strokeLinejoin: "round",
682
+ children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
683
+ }
684
+ );
685
+ }
686
+
687
+ export { DateInput };
688
+ //# sourceMappingURL=chunk-LIH3IZYK.js.map
689
+ //# sourceMappingURL=chunk-LIH3IZYK.js.map