@page-speed/forms 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/inputs.cjs CHANGED
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var React7 = require('react');
3
+ var React8 = require('react');
4
4
  var clsx = require('clsx');
5
5
  var tailwindMerge = require('tailwind-merge');
6
+ var useOnClickOutside = require('@opensite/hooks/useOnClickOutside');
6
7
 
7
8
  function _interopNamespace(e) {
8
9
  if (e && e.__esModule) return e;
@@ -22,7 +23,13 @@ function _interopNamespace(e) {
22
23
  return Object.freeze(n);
23
24
  }
24
25
 
25
- var React7__namespace = /*#__PURE__*/_interopNamespace(React7);
26
+ var React8__namespace = /*#__PURE__*/_interopNamespace(React8);
27
+
28
+ // src/inputs/TextInput.tsx
29
+ function cn(...inputs) {
30
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
31
+ }
32
+ var INPUT_AUTOFILL_RESET_CLASSES = "autofill:bg-transparent autofill:text-foreground [&:-webkit-autofill]:[-webkit-text-fill-color:hsl(var(--foreground))] [&:-webkit-autofill]:[caret-color:hsl(var(--foreground))] [&:-webkit-autofill]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:hover]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:focus]:[box-shadow:0_0_0px_1000px_hsl(var(--background))_inset] [&:-webkit-autofill]:[transition:background-color_9999s_ease-out,color_9999s_ease-out]";
26
33
 
27
34
  // src/inputs/TextInput.tsx
28
35
  function TextInput({
@@ -45,10 +52,17 @@ function TextInput({
45
52
  const handleBlur = () => {
46
53
  onBlur?.();
47
54
  };
48
- const baseClassName = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm";
49
- const errorClassName = error ? "border-red-500 ring-1 ring-red-500" : "";
50
- const combinedClassName = `${baseClassName} ${errorClassName} ${className}`.trim();
51
- return /* @__PURE__ */ React7__namespace.createElement(
55
+ const hasValue = String(value ?? "").trim().length > 0;
56
+ const combinedClassName = cn(
57
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors",
58
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
59
+ "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
60
+ INPUT_AUTOFILL_RESET_CLASSES,
61
+ !error && hasValue && "ring-2 ring-ring",
62
+ error && "border-destructive ring-1 ring-destructive",
63
+ className
64
+ );
65
+ return /* @__PURE__ */ React8__namespace.createElement(
52
66
  "input",
53
67
  {
54
68
  type,
@@ -92,10 +106,17 @@ function TextArea({
92
106
  const handleBlur = () => {
93
107
  onBlur?.();
94
108
  };
95
- const baseClassName = "flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm";
96
- const errorClassName = error ? "border-red-500 ring-1 ring-red-500" : "";
97
- const combinedClassName = `${baseClassName} ${errorClassName} ${className}`.trim();
98
- return /* @__PURE__ */ React7__namespace.createElement(
109
+ const hasValue = String(value ?? "").trim().length > 0;
110
+ const combinedClassName = cn(
111
+ "flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm transition-colors",
112
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
113
+ "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
114
+ INPUT_AUTOFILL_RESET_CLASSES,
115
+ !error && hasValue && "ring-2 ring-ring",
116
+ error && "border-destructive ring-1 ring-destructive",
117
+ className
118
+ );
119
+ return /* @__PURE__ */ React8__namespace.createElement(
99
120
  "textarea",
100
121
  {
101
122
  name,
@@ -119,9 +140,53 @@ function TextArea({
119
140
  );
120
141
  }
121
142
  TextArea.displayName = "TextArea";
122
- function cn(...inputs) {
123
- return tailwindMerge.twMerge(clsx.clsx(inputs));
124
- }
143
+ var LabelGroup = ({
144
+ labelHtmlFor,
145
+ required = false,
146
+ variant = "label",
147
+ secondaryId,
148
+ secondary,
149
+ primary,
150
+ primaryClassName,
151
+ secondaryClassName
152
+ }) => {
153
+ const primaryClasses = cn(
154
+ "text-sm font-medium leading-snug",
155
+ variant === "legend" ? "mb-1.5" : "mb-1 block",
156
+ primaryClassName
157
+ );
158
+ const requiredIndicator = required ? /* @__PURE__ */ React8__namespace.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
159
+ let primaryElement = null;
160
+ if (primary) {
161
+ if (variant === "label") {
162
+ primaryElement = /* @__PURE__ */ React8__namespace.createElement(
163
+ "label",
164
+ {
165
+ htmlFor: labelHtmlFor,
166
+ "data-slot": "field-label",
167
+ className: primaryClasses
168
+ },
169
+ primary,
170
+ requiredIndicator
171
+ );
172
+ } else if (variant === "legend") {
173
+ primaryElement = /* @__PURE__ */ React8__namespace.createElement("legend", { "data-slot": "field-legend", className: primaryClasses }, primary, requiredIndicator);
174
+ } else {
175
+ primaryElement = /* @__PURE__ */ React8__namespace.createElement("div", { "data-slot": "field-label", className: primaryClasses }, primary, requiredIndicator);
176
+ }
177
+ }
178
+ const secondaryElement = secondary ? /* @__PURE__ */ React8__namespace.createElement(
179
+ "p",
180
+ {
181
+ "data-slot": "field-description",
182
+ id: secondaryId,
183
+ className: cn("text-sm leading-normal font-normal", secondaryClassName)
184
+ },
185
+ secondary
186
+ ) : null;
187
+ if (!primaryElement && !secondaryElement) return null;
188
+ return /* @__PURE__ */ React8__namespace.createElement(React8__namespace.Fragment, null, primaryElement, secondaryElement);
189
+ };
125
190
 
126
191
  // src/inputs/Checkbox.tsx
127
192
  function Checkbox({
@@ -136,12 +201,12 @@ function Checkbox({
136
201
  indeterminate = false,
137
202
  label,
138
203
  description,
139
- checkboxVariant = "boxed",
204
+ useChoiceCard = false,
140
205
  ...props
141
206
  }) {
142
- const inputRef = React7__namespace.useRef(null);
207
+ const inputRef = React8__namespace.useRef(null);
143
208
  const checkboxId = props.id || `checkbox-${name}`;
144
- React7__namespace.useEffect(() => {
209
+ React8__namespace.useEffect(() => {
145
210
  if (inputRef.current) {
146
211
  inputRef.current.indeterminate = indeterminate;
147
212
  }
@@ -153,7 +218,7 @@ function Checkbox({
153
218
  onBlur?.();
154
219
  };
155
220
  const isActive = value || indeterminate && !value;
156
- const checkbox = /* @__PURE__ */ React7__namespace.createElement(
221
+ const checkbox = /* @__PURE__ */ React8__namespace.createElement(
157
222
  "div",
158
223
  {
159
224
  className: cn(
@@ -161,7 +226,7 @@ function Checkbox({
161
226
  !label && className
162
227
  )
163
228
  },
164
- /* @__PURE__ */ React7__namespace.createElement(
229
+ /* @__PURE__ */ React8__namespace.createElement(
165
230
  "input",
166
231
  {
167
232
  ref: inputRef,
@@ -180,7 +245,7 @@ function Checkbox({
180
245
  ...props
181
246
  }
182
247
  ),
183
- /* @__PURE__ */ React7__namespace.createElement(
248
+ /* @__PURE__ */ React8__namespace.createElement(
184
249
  "div",
185
250
  {
186
251
  className: cn(
@@ -193,7 +258,7 @@ function Checkbox({
193
258
  "peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-1"
194
259
  )
195
260
  },
196
- value && /* @__PURE__ */ React7__namespace.createElement(
261
+ value && /* @__PURE__ */ React8__namespace.createElement(
197
262
  "svg",
198
263
  {
199
264
  className: "size-3.5",
@@ -204,9 +269,9 @@ function Checkbox({
204
269
  strokeLinecap: "round",
205
270
  strokeLinejoin: "round"
206
271
  },
207
- /* @__PURE__ */ React7__namespace.createElement("polyline", { points: "20 6 9 17 4 12" })
272
+ /* @__PURE__ */ React8__namespace.createElement("polyline", { points: "20 6 9 17 4 12" })
208
273
  ),
209
- indeterminate && !value && /* @__PURE__ */ React7__namespace.createElement(
274
+ indeterminate && !value && /* @__PURE__ */ React8__namespace.createElement(
210
275
  "svg",
211
276
  {
212
277
  className: "size-3.5",
@@ -217,31 +282,44 @@ function Checkbox({
217
282
  strokeLinecap: "round",
218
283
  strokeLinejoin: "round"
219
284
  },
220
- /* @__PURE__ */ React7__namespace.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
285
+ /* @__PURE__ */ React8__namespace.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
221
286
  )
222
287
  )
223
288
  );
224
289
  if (label) {
225
- return /* @__PURE__ */ React7__namespace.createElement(
290
+ return /* @__PURE__ */ React8__namespace.createElement(
226
291
  "label",
227
292
  {
228
293
  className: cn(
229
294
  "w-full h-full flex gap-3 p-3 duration-200",
230
- checkboxVariant === "boxed" && "border rounded-lg hover:ring-2",
231
- checkboxVariant === "boxed" && value && "ring-2",
295
+ useChoiceCard && "border rounded-lg hover:ring-2",
296
+ useChoiceCard && value && "ring-2",
232
297
  disabled ? "opacity-50 cursor-not-allowed hover:ring-0" : "cursor-pointer",
233
298
  className
234
299
  ),
235
300
  htmlFor: checkboxId
236
301
  },
237
- /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex w-full flex-row gap-2" }, checkbox, /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col gap-0.5" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-sm font-medium" }, label), description && /* @__PURE__ */ React7__namespace.createElement(
238
- "p",
302
+ /* @__PURE__ */ React8__namespace.createElement(
303
+ "div",
239
304
  {
240
- className: "text-xs opacity-75",
241
- id: `${checkboxId}-description`
305
+ className: cn(
306
+ "flex w-full flex-row gap-2",
307
+ useChoiceCard ? "items-start" : "items-center"
308
+ )
242
309
  },
243
- description
244
- )))
310
+ checkbox,
311
+ /* @__PURE__ */ React8__namespace.createElement(
312
+ LabelGroup,
313
+ {
314
+ variant: "text",
315
+ primary: label,
316
+ secondary: description,
317
+ secondaryId: description ? `${checkboxId}-description` : void 0,
318
+ primaryClassName: "mb-0",
319
+ secondaryClassName: "text-xs opacity-75"
320
+ }
321
+ )
322
+ )
245
323
  );
246
324
  }
247
325
  return checkbox;
@@ -275,13 +353,11 @@ function CheckboxGroup({
275
353
  ).length;
276
354
  const allSelected = selectedEnabledCount === enabledOptions.length;
277
355
  const someSelected = selectedEnabledCount > 0 && !allSelected;
278
- const checkboxVariant = React7__namespace.useMemo(() => {
279
- if (options.some((opt) => opt.description)) {
280
- return "boxed";
281
- }
282
- return "inline";
356
+ const useChoiceCard = React8__namespace.useMemo(() => {
357
+ if (!options) return false;
358
+ return options?.some((opt) => opt.description);
283
359
  }, [options]);
284
- const countableValue = React7__namespace.useMemo(() => {
360
+ const countableValue = React8__namespace.useMemo(() => {
285
361
  if (value?.length > 0) {
286
362
  return value.length;
287
363
  }
@@ -306,29 +382,37 @@ function CheckboxGroup({
306
382
  onBlur?.();
307
383
  };
308
384
  const maxReached = Boolean(maxSelections && countableValue >= maxSelections);
309
- const containerClass = cn(
310
- "w-full gap-3",
311
- layout === "stacked" && "flex flex-col",
312
- layout === "inline" && "flex flex-row flex-wrap",
313
- layout === "grid" && "grid",
314
- className
315
- );
316
- return /* @__PURE__ */ React7__namespace.createElement(
317
- "div",
385
+ const containerClass = React8__namespace.useMemo(() => {
386
+ return cn(
387
+ "w-full gap-3 grid grid-cols-1 border-0 m-0 p-0 min-w-0",
388
+ (layout === "grid" || layout === "inline") && "md:grid-cols-2",
389
+ className
390
+ );
391
+ }, [layout, className]);
392
+ const groupDescriptionId = description ? `${name}-description` : void 0;
393
+ const groupAriaDescribedBy = [props["aria-describedby"], groupDescriptionId].filter(Boolean).join(" ") || void 0;
394
+ return /* @__PURE__ */ React8__namespace.createElement(
395
+ "fieldset",
318
396
  {
319
397
  className: containerClass,
320
398
  role: "group",
321
399
  "aria-invalid": error || props["aria-invalid"],
322
- "aria-describedby": props["aria-describedby"],
400
+ "aria-describedby": groupAriaDescribedBy,
323
401
  "aria-required": required || props["aria-required"],
324
- "aria-label": typeof label === "string" ? label : props["aria-label"],
325
- style: layout === "grid" ? {
326
- gridTemplateColumns: `repeat(${gridColumns}, 1fr)`
327
- } : void 0
402
+ "aria-label": typeof label === "string" ? label : props["aria-label"]
328
403
  },
329
- label && /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-sm font-medium" }, label),
330
- description && /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-muted-foreground text-sm" }, description),
331
- showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */ React7__namespace.createElement(
404
+ /* @__PURE__ */ React8__namespace.createElement(
405
+ LabelGroup,
406
+ {
407
+ labelHtmlFor: name,
408
+ required,
409
+ variant: "legend",
410
+ secondaryId: groupDescriptionId,
411
+ secondary: description,
412
+ primary: label
413
+ }
414
+ ),
415
+ showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */ React8__namespace.createElement(
332
416
  Checkbox,
333
417
  {
334
418
  name: `${name}-select-all`,
@@ -338,7 +422,7 @@ function CheckboxGroup({
338
422
  onBlur: handleBlur,
339
423
  indeterminate: someSelected,
340
424
  label: selectAllLabel,
341
- checkboxVariant: "inline",
425
+ useChoiceCard,
342
426
  disabled,
343
427
  "aria-label": selectAllLabel
344
428
  }
@@ -346,7 +430,7 @@ function CheckboxGroup({
346
430
  options.map((option) => {
347
431
  const isChecked = value.includes(option.value);
348
432
  const isDisabled = disabled || option.disabled || maxReached && !isChecked;
349
- return /* @__PURE__ */ React7__namespace.createElement(
433
+ return /* @__PURE__ */ React8__namespace.createElement(
350
434
  Checkbox,
351
435
  {
352
436
  key: option.value,
@@ -360,11 +444,11 @@ function CheckboxGroup({
360
444
  error,
361
445
  label: renderOption ? renderOption(option) : option.label,
362
446
  description: renderOption ? void 0 : option.description,
363
- checkboxVariant
447
+ useChoiceCard
364
448
  }
365
449
  );
366
450
  }),
367
- (minSelections || maxSelections) && /* @__PURE__ */ React7__namespace.createElement(
451
+ (minSelections || maxSelections) && /* @__PURE__ */ React8__namespace.createElement(
368
452
  "div",
369
453
  {
370
454
  className: cn(
@@ -373,8 +457,8 @@ function CheckboxGroup({
373
457
  ),
374
458
  "aria-live": "polite"
375
459
  },
376
- minSelections && countableValue < minSelections && /* @__PURE__ */ React7__namespace.createElement("span", null, "Select at least ", minSelections, " option", minSelections !== 1 ? "s" : ""),
377
- maxSelections && /* @__PURE__ */ React7__namespace.createElement("span", null, countableValue, "/", maxSelections, " selected")
460
+ minSelections && countableValue < minSelections && /* @__PURE__ */ React8__namespace.createElement("span", null, "Select at least ", minSelections, " option", minSelections !== 1 ? "s" : ""),
461
+ maxSelections && /* @__PURE__ */ React8__namespace.createElement("span", null, countableValue, "/", maxSelections, " selected")
378
462
  )
379
463
  );
380
464
  }
@@ -389,8 +473,8 @@ function Radio({
389
473
  error = false,
390
474
  className = "",
391
475
  layout = "stacked",
392
- radioVariant = "inline",
393
476
  label,
477
+ description,
394
478
  options,
395
479
  ...props
396
480
  }) {
@@ -425,29 +509,43 @@ function Radio({
425
509
  const handleBlur = () => {
426
510
  onBlur?.();
427
511
  };
428
- const containerClass = cn(
429
- "w-full gap-3",
430
- layout === "stacked" && "flex flex-col",
431
- layout === "inline" && "flex flex-row flex-wrap",
432
- className
433
- );
434
- return /* @__PURE__ */ React7__namespace.createElement(
435
- "div",
512
+ const useChoiceCard = React8__namespace.useMemo(() => {
513
+ return options.some((option) => option.description);
514
+ }, [options]);
515
+ const containerClass = React8__namespace.useMemo(() => {
516
+ return cn(
517
+ "w-full gap-3 grid grid-cols-1 border-0 m-0 p-0 min-w-0",
518
+ (layout === "grid" || layout === "inline") && "md:grid-cols-2",
519
+ className
520
+ );
521
+ }, [layout, className]);
522
+ const groupDescriptionId = description ? `${name}-description` : void 0;
523
+ const groupAriaDescribedBy = [props["aria-describedby"], groupDescriptionId].filter(Boolean).join(" ") || void 0;
524
+ return /* @__PURE__ */ React8__namespace.createElement(
525
+ "fieldset",
436
526
  {
437
527
  className: containerClass,
438
528
  role: "radiogroup",
439
529
  "aria-invalid": error || props["aria-invalid"],
440
- "aria-describedby": props["aria-describedby"],
530
+ "aria-describedby": groupAriaDescribedBy,
441
531
  "aria-required": required || props["aria-required"],
442
532
  "aria-label": typeof label === "string" ? label : props["aria-label"]
443
533
  },
444
- label && /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-sm font-medium mb-2" }, label),
534
+ /* @__PURE__ */ React8__namespace.createElement(
535
+ LabelGroup,
536
+ {
537
+ variant: "legend",
538
+ primary: label,
539
+ secondary: description,
540
+ secondaryId: groupDescriptionId
541
+ }
542
+ ),
445
543
  options.map((option, index) => {
446
544
  const isChecked = value === option.value;
447
545
  const isDisabled = disabled || option.disabled;
448
546
  const radioId = `${name}-${option.value}`;
449
547
  const hasDescription = option.description != null && option.description !== "";
450
- const radioIndicator = /* @__PURE__ */ React7__namespace.createElement("div", { className: "relative inline-flex items-center justify-center" }, /* @__PURE__ */ React7__namespace.createElement(
548
+ const radioIndicator = /* @__PURE__ */ React8__namespace.createElement("div", { className: "relative inline-flex items-center justify-center" }, /* @__PURE__ */ React8__namespace.createElement(
451
549
  "input",
452
550
  {
453
551
  type: "radio",
@@ -462,7 +560,7 @@ function Radio({
462
560
  className: "peer sr-only",
463
561
  "aria-describedby": hasDescription ? `${radioId}-description` : props["aria-describedby"]
464
562
  }
465
- ), /* @__PURE__ */ React7__namespace.createElement(
563
+ ), /* @__PURE__ */ React8__namespace.createElement(
466
564
  "div",
467
565
  {
468
566
  className: cn(
@@ -475,31 +573,45 @@ function Radio({
475
573
  "peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-1"
476
574
  )
477
575
  },
478
- isChecked && /* @__PURE__ */ React7__namespace.createElement("div", { className: "size-3 rounded-full bg-primary" })
576
+ isChecked && /* @__PURE__ */ React8__namespace.createElement("div", { className: "size-3 rounded-full bg-primary" })
479
577
  ));
480
- const labelContent = /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col gap-0.5" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-sm font-medium" }, option.label), hasDescription && /* @__PURE__ */ React7__namespace.createElement(
481
- "p",
578
+ const labelContent = /* @__PURE__ */ React8__namespace.createElement(
579
+ LabelGroup,
482
580
  {
483
- className: "text-xs opacity-75",
484
- id: `${radioId}-description`
485
- },
486
- option.description
487
- ));
488
- return /* @__PURE__ */ React7__namespace.createElement(
581
+ variant: "text",
582
+ primary: option.label,
583
+ secondary: hasDescription ? option.description : void 0,
584
+ secondaryId: hasDescription ? `${radioId}-description` : void 0,
585
+ primaryClassName: "mb-0",
586
+ secondaryClassName: "text-xs opacity-75"
587
+ }
588
+ );
589
+ return /* @__PURE__ */ React8__namespace.createElement(
489
590
  "label",
490
591
  {
491
592
  key: option.value,
492
593
  className: cn(
493
594
  "w-full h-full flex gap-3 p-3 duration-200",
494
- radioVariant === "boxed" && "border rounded-lg hover:ring-2",
495
- radioVariant === "boxed" && isChecked && "ring-2",
595
+ useChoiceCard && "border rounded-lg hover:ring-2",
596
+ useChoiceCard && isChecked && "ring-2",
496
597
  isDisabled ? "opacity-50 cursor-not-allowed hover:ring-0" : "cursor-pointer"
497
598
  ),
498
599
  htmlFor: radioId,
499
600
  onKeyDown: (e) => handleKeyDown(e, index),
500
601
  tabIndex: isDisabled ? -1 : 0
501
602
  },
502
- /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex w-full flex-row items-center gap-2" }, radioVariant === "inline" && radioIndicator, /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-1 flex-col gap-0.5" }, labelContent), radioVariant === "boxed" && radioIndicator)
603
+ /* @__PURE__ */ React8__namespace.createElement(
604
+ "div",
605
+ {
606
+ className: cn(
607
+ "flex w-full flex-row gap-2",
608
+ useChoiceCard ? "items-start" : "items-center"
609
+ )
610
+ },
611
+ !useChoiceCard && radioIndicator,
612
+ /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex flex-1 flex-col gap-0.5" }, labelContent),
613
+ useChoiceCard && radioIndicator
614
+ )
503
615
  );
504
616
  })
505
617
  );
@@ -524,19 +636,19 @@ function Select({
524
636
  renderOption,
525
637
  ...props
526
638
  }) {
527
- const [isOpen, setIsOpen] = React7__namespace.useState(false);
528
- const [searchQuery, setSearchQuery] = React7__namespace.useState("");
529
- const [focusedIndex, setFocusedIndex] = React7__namespace.useState(-1);
530
- const selectRef = React7__namespace.useRef(null);
531
- const searchInputRef = React7__namespace.useRef(null);
639
+ const [isOpen, setIsOpen] = React8__namespace.useState(false);
640
+ const [searchQuery, setSearchQuery] = React8__namespace.useState("");
641
+ const [focusedIndex, setFocusedIndex] = React8__namespace.useState(-1);
642
+ const selectRef = React8__namespace.useRef(null);
643
+ const searchInputRef = React8__namespace.useRef(null);
532
644
  const dropdownId = `${name}-dropdown`;
533
- const allOptions = React7__namespace.useMemo(() => {
645
+ const allOptions = React8__namespace.useMemo(() => {
534
646
  if (optionGroups.length > 0) {
535
647
  return optionGroups.flatMap((group) => group.options);
536
648
  }
537
649
  return options;
538
650
  }, [options, optionGroups]);
539
- const filteredOptions = React7__namespace.useMemo(() => {
651
+ const filteredOptions = React8__namespace.useMemo(() => {
540
652
  if (!searchQuery.trim()) {
541
653
  return allOptions;
542
654
  }
@@ -546,9 +658,10 @@ function Select({
546
658
  return label.toLowerCase().includes(query);
547
659
  });
548
660
  }, [allOptions, searchQuery]);
549
- const selectedOption = React7__namespace.useMemo(() => {
661
+ const selectedOption = React8__namespace.useMemo(() => {
550
662
  return allOptions.find((opt) => opt.value === value);
551
663
  }, [allOptions, value]);
664
+ const hasValue = Boolean(value);
552
665
  const handleSelect = (optionValue) => {
553
666
  onChange(optionValue);
554
667
  setIsOpen(false);
@@ -589,9 +702,7 @@ function Select({
589
702
  if (enabledOptions.length > 0) {
590
703
  const currentIndexInFiltered = focusedIndex;
591
704
  const nextIndex = (currentIndexInFiltered + 1) % enabledOptions.length;
592
- setFocusedIndex(
593
- filteredOptions.indexOf(enabledOptions[nextIndex])
594
- );
705
+ setFocusedIndex(filteredOptions.indexOf(enabledOptions[nextIndex]));
595
706
  }
596
707
  }
597
708
  break;
@@ -602,9 +713,7 @@ function Select({
602
713
  if (enabledOptions.length > 0) {
603
714
  const currentIndexInFiltered = focusedIndex;
604
715
  const prevIndex = (currentIndexInFiltered - 1 + enabledOptions.length) % enabledOptions.length;
605
- setFocusedIndex(
606
- filteredOptions.indexOf(enabledOptions[prevIndex])
607
- );
716
+ setFocusedIndex(filteredOptions.indexOf(enabledOptions[prevIndex]));
608
717
  }
609
718
  }
610
719
  break;
@@ -647,27 +756,22 @@ function Select({
647
756
  break;
648
757
  }
649
758
  };
650
- const handleBlur = () => {
651
- onBlur?.();
652
- };
653
- React7__namespace.useEffect(() => {
654
- const handleClickOutside = (event) => {
655
- if (selectRef.current && !selectRef.current.contains(event.target)) {
656
- setIsOpen(false);
657
- setSearchQuery("");
658
- setFocusedIndex(-1);
659
- handleBlur();
660
- }
661
- };
662
- if (isOpen) {
663
- document.addEventListener("mousedown", handleClickOutside);
664
- return () => {
665
- document.removeEventListener("mousedown", handleClickOutside);
666
- };
759
+ const handleBlur = (event) => {
760
+ const nextTarget = event?.relatedTarget;
761
+ if (!nextTarget || !selectRef.current?.contains(nextTarget)) {
762
+ onBlur?.();
667
763
  }
668
- }, [isOpen]);
669
- const combinedClassName = `relative w-full ${className}`.trim();
670
- return /* @__PURE__ */ React7__namespace.createElement(
764
+ };
765
+ const closeDropdown = React8__namespace.useCallback(() => {
766
+ if (!isOpen) return;
767
+ setIsOpen(false);
768
+ setSearchQuery("");
769
+ setFocusedIndex(-1);
770
+ onBlur?.();
771
+ }, [isOpen, onBlur]);
772
+ useOnClickOutside.useOnClickOutside(selectRef, closeDropdown, "pointerdown", true);
773
+ const combinedClassName = cn("relative w-full", className);
774
+ return /* @__PURE__ */ React8__namespace.createElement(
671
775
  "div",
672
776
  {
673
777
  ref: selectRef,
@@ -675,7 +779,7 @@ function Select({
675
779
  onKeyDown: handleKeyDown,
676
780
  onBlur: handleBlur
677
781
  },
678
- /* @__PURE__ */ React7__namespace.createElement(
782
+ /* @__PURE__ */ React8__namespace.createElement(
679
783
  "select",
680
784
  {
681
785
  name,
@@ -688,13 +792,19 @@ function Select({
688
792
  tabIndex: -1,
689
793
  style: { display: "none" }
690
794
  },
691
- /* @__PURE__ */ React7__namespace.createElement("option", { value: "" }, "Select..."),
692
- allOptions.map((option) => /* @__PURE__ */ React7__namespace.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
795
+ /* @__PURE__ */ React8__namespace.createElement("option", { value: "" }, "Select..."),
796
+ allOptions.map((option) => /* @__PURE__ */ React8__namespace.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
693
797
  ),
694
- /* @__PURE__ */ React7__namespace.createElement(
798
+ /* @__PURE__ */ React8__namespace.createElement(
695
799
  "div",
696
800
  {
697
- className: `flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm cursor-pointer transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring ${disabled ? "cursor-not-allowed opacity-50 pointer-events-none" : ""} ${error ? "border-red-500 ring-1 ring-red-500" : ""}`,
801
+ className: cn(
802
+ "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm",
803
+ "cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
804
+ !error && hasValue && "ring-2 ring-ring",
805
+ disabled && "cursor-not-allowed opacity-50 pointer-events-none",
806
+ error && "border-destructive ring-1 ring-destructive"
807
+ ),
698
808
  onClick: handleToggle,
699
809
  role: "combobox",
700
810
  "aria-expanded": isOpen,
@@ -705,48 +815,79 @@ function Select({
705
815
  "aria-disabled": disabled,
706
816
  tabIndex: disabled ? -1 : 0
707
817
  },
708
- /* @__PURE__ */ React7__namespace.createElement("span", { className: "flex items-center flex-1 overflow-hidden text-ellipsis" }, selectedOption ? renderOption ? renderOption(selectedOption) : selectedOption.label : /* @__PURE__ */ React7__namespace.createElement("span", { className: "text-muted-foreground" }, placeholder)),
709
- /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center gap-1 ml-2" }, loading && /* @__PURE__ */ React7__namespace.createElement("span", { className: "text-xs" }, "\u23F3"), clearable && value && !disabled && !loading && /* @__PURE__ */ React7__namespace.createElement(
818
+ /* @__PURE__ */ React8__namespace.createElement("span", { className: "flex items-center flex-1 overflow-hidden text-ellipsis" }, selectedOption ? renderOption ? renderOption(selectedOption) : selectedOption.label : /* @__PURE__ */ React8__namespace.createElement("span", { className: "relative" }, placeholder)),
819
+ /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center gap-1 ml-2" }, loading && /* @__PURE__ */ React8__namespace.createElement("span", { className: "text-xs" }, "\u23F3"), clearable && value && !disabled && !loading && /* @__PURE__ */ React8__namespace.createElement(
710
820
  "button",
711
821
  {
712
822
  type: "button",
713
- className: "flex items-center justify-center h-4 w-4 rounded-sm border-none bg-transparent text-muted-foreground cursor-pointer text-xs p-0 transition-opacity hover:opacity-70",
823
+ className: "flex items-center justify-center h-4 w-4 rounded-sm border-none bg-transparent cursor-pointer text-xs p-0 transition-opacity hover:opacity-70",
714
824
  onClick: handleClear,
715
825
  "aria-label": "Clear selection",
716
826
  tabIndex: -1
717
827
  },
718
828
  "\u2715"
719
- ), /* @__PURE__ */ React7__namespace.createElement("span", { className: "text-muted-foreground text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
829
+ ), /* @__PURE__ */ React8__namespace.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
720
830
  ),
721
- isOpen && /* @__PURE__ */ React7__namespace.createElement("div", { id: dropdownId, className: "absolute z-50 top-full mt-1 min-w-full overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md", role: "listbox" }, searchable && /* @__PURE__ */ React7__namespace.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React7__namespace.createElement(
722
- "input",
831
+ isOpen && /* @__PURE__ */ React8__namespace.createElement(
832
+ "div",
723
833
  {
724
- ref: searchInputRef,
725
- type: "text",
726
- className: "w-full border border-input rounded px-2 py-1 text-sm bg-transparent outline-none focus:ring-1 focus:ring-ring",
727
- placeholder: "Search...",
728
- value: searchQuery,
729
- onChange: handleSearchChange,
730
- onClick: (e) => e.stopPropagation(),
731
- "aria-label": "Search options"
732
- }
733
- )), /* @__PURE__ */ React7__namespace.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React7__namespace.createElement("div", { className: "py-2 px-3 text-center text-sm text-muted-foreground" }, "No options found") : optionGroups.length > 0 ? (
734
- // Render grouped options
735
- optionGroups.map((group, groupIndex) => {
736
- const groupOptions = group.options.filter(
737
- (opt) => filteredOptions.includes(opt)
738
- );
739
- if (groupOptions.length === 0) return null;
740
- return /* @__PURE__ */ React7__namespace.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold text-muted-foreground" }, group.label), groupOptions.map((option) => {
741
- const globalIndex = filteredOptions.indexOf(option);
834
+ id: dropdownId,
835
+ className: "absolute z-50 top-full mt-1 min-w-full overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md",
836
+ role: "listbox"
837
+ },
838
+ searchable && /* @__PURE__ */ React8__namespace.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React8__namespace.createElement(
839
+ "input",
840
+ {
841
+ ref: searchInputRef,
842
+ type: "text",
843
+ className: cn(
844
+ "w-full border border-input rounded px-2 py-1 text-sm bg-transparent outline-none focus:ring-1 focus:ring-ring",
845
+ INPUT_AUTOFILL_RESET_CLASSES
846
+ ),
847
+ placeholder: "Search...",
848
+ value: searchQuery,
849
+ onChange: handleSearchChange,
850
+ onClick: (e) => e.stopPropagation(),
851
+ "aria-label": "Search options"
852
+ }
853
+ )),
854
+ /* @__PURE__ */ React8__namespace.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React8__namespace.createElement("div", { className: "py-2 px-3 text-center text-sm " }, "No options found") : optionGroups.length > 0 ? (
855
+ // Render grouped options
856
+ optionGroups.map((group, groupIndex) => {
857
+ const groupOptions = group.options.filter(
858
+ (opt) => filteredOptions.includes(opt)
859
+ );
860
+ if (groupOptions.length === 0) return null;
861
+ return /* @__PURE__ */ React8__namespace.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React8__namespace.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold " }, group.label), groupOptions.map((option) => {
862
+ const globalIndex = filteredOptions.indexOf(option);
863
+ const isSelected = value === option.value;
864
+ const isFocused = globalIndex === focusedIndex;
865
+ const isDisabled = option.disabled;
866
+ return /* @__PURE__ */ React8__namespace.createElement(
867
+ "div",
868
+ {
869
+ key: option.value,
870
+ className: `relative flex w-full cursor-pointer items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-muted ${isFocused ? "bg-muted" : ""} ${isSelected ? "font-medium bg-muted" : ""} ${isDisabled ? "pointer-events-none opacity-50" : ""}`,
871
+ onClick: () => !isDisabled && handleSelect(option.value),
872
+ role: "option",
873
+ "aria-selected": isSelected,
874
+ "aria-disabled": isDisabled
875
+ },
876
+ renderOption ? renderOption(option) : option.label
877
+ );
878
+ }));
879
+ })
880
+ ) : (
881
+ // Render flat options
882
+ filteredOptions.map((option, index) => {
742
883
  const isSelected = value === option.value;
743
- const isFocused = globalIndex === focusedIndex;
884
+ const isFocused = index === focusedIndex;
744
885
  const isDisabled = option.disabled;
745
- return /* @__PURE__ */ React7__namespace.createElement(
886
+ return /* @__PURE__ */ React8__namespace.createElement(
746
887
  "div",
747
888
  {
748
889
  key: option.value,
749
- className: `relative flex w-full cursor-pointer items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground ${isFocused ? "bg-accent text-accent-foreground" : ""} ${isSelected ? "font-medium bg-accent" : ""} ${isDisabled ? "pointer-events-none opacity-50" : ""}`,
890
+ className: `relative flex w-full cursor-pointer items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-muted ${isFocused ? "bg-muted" : ""} ${isSelected ? "font-medium bg-muted" : ""} ${isDisabled ? "pointer-events-none opacity-50" : ""}`,
750
891
  onClick: () => !isDisabled && handleSelect(option.value),
751
892
  role: "option",
752
893
  "aria-selected": isSelected,
@@ -754,28 +895,9 @@ function Select({
754
895
  },
755
896
  renderOption ? renderOption(option) : option.label
756
897
  );
757
- }));
758
- })
759
- ) : (
760
- // Render flat options
761
- filteredOptions.map((option, index) => {
762
- const isSelected = value === option.value;
763
- const isFocused = index === focusedIndex;
764
- const isDisabled = option.disabled;
765
- return /* @__PURE__ */ React7__namespace.createElement(
766
- "div",
767
- {
768
- key: option.value,
769
- className: `relative flex w-full cursor-pointer items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground ${isFocused ? "bg-accent text-accent-foreground" : ""} ${isSelected ? "font-medium bg-accent" : ""} ${isDisabled ? "pointer-events-none opacity-50" : ""}`,
770
- onClick: () => !isDisabled && handleSelect(option.value),
771
- role: "option",
772
- "aria-selected": isSelected,
773
- "aria-disabled": isDisabled
774
- },
775
- renderOption ? renderOption(option) : option.label
776
- );
777
- })
778
- )))
898
+ })
899
+ ))
900
+ )
779
901
  );
780
902
  }
781
903
  Select.displayName = "Select";
@@ -784,7 +906,7 @@ function FileInput({
784
906
  value = [],
785
907
  onChange,
786
908
  onBlur,
787
- placeholder = "Choose file(s)...",
909
+ placeholder = "Choose file...",
788
910
  disabled = false,
789
911
  required = false,
790
912
  error = false,
@@ -804,14 +926,14 @@ function FileInput({
804
926
  onFileRemove,
805
927
  ...props
806
928
  }) {
807
- const inputRef = React7__namespace.useRef(null);
808
- const [dragActive, setDragActive] = React7__namespace.useState(false);
809
- const [cropperOpen, setCropperOpen] = React7__namespace.useState(false);
810
- const [imageToCrop, setImageToCrop] = React7__namespace.useState(null);
811
- const [crop, setCrop] = React7__namespace.useState({ x: 0, y: 0 });
812
- const [zoom, setZoom] = React7__namespace.useState(1);
813
- const [croppedAreaPixels, setCroppedAreaPixels] = React7__namespace.useState(null);
814
- const validateFile = React7__namespace.useCallback(
929
+ const inputRef = React8__namespace.useRef(null);
930
+ const [dragActive, setDragActive] = React8__namespace.useState(false);
931
+ const [cropperOpen, setCropperOpen] = React8__namespace.useState(false);
932
+ const [imageToCrop, setImageToCrop] = React8__namespace.useState(null);
933
+ const [crop, setCrop] = React8__namespace.useState({ x: 0, y: 0 });
934
+ const [zoom, setZoom] = React8__namespace.useState(1);
935
+ const [croppedAreaPixels, setCroppedAreaPixels] = React8__namespace.useState(null);
936
+ const validateFile = React8__namespace.useCallback(
815
937
  (file) => {
816
938
  if (accept) {
817
939
  const acceptedTypes = accept.split(",").map((t) => t.trim());
@@ -846,7 +968,7 @@ function FileInput({
846
968
  },
847
969
  [accept, maxSize]
848
970
  );
849
- const handleFiles = React7__namespace.useCallback(
971
+ const handleFiles = React8__namespace.useCallback(
850
972
  (fileList) => {
851
973
  if (!fileList || fileList.length === 0) return;
852
974
  const newFiles = Array.from(fileList);
@@ -887,9 +1009,17 @@ function FileInput({
887
1009
  inputRef.current.value = "";
888
1010
  }
889
1011
  },
890
- [value, onChange, validateFile, maxFiles, multiple, enableCropping, onValidationError]
1012
+ [
1013
+ value,
1014
+ onChange,
1015
+ validateFile,
1016
+ maxFiles,
1017
+ multiple,
1018
+ enableCropping,
1019
+ onValidationError
1020
+ ]
891
1021
  );
892
- const createCroppedImage = React7__namespace.useCallback(
1022
+ const createCroppedImage = React8__namespace.useCallback(
893
1023
  async (imageUrl, cropArea) => {
894
1024
  return new Promise((resolve, reject) => {
895
1025
  const image = new Image();
@@ -913,13 +1043,17 @@ function FileInput({
913
1043
  cropArea.width,
914
1044
  cropArea.height
915
1045
  );
916
- canvas.toBlob((blob) => {
917
- if (blob) {
918
- resolve(blob);
919
- } else {
920
- reject(new Error("Failed to create blob from canvas"));
921
- }
922
- }, "image/jpeg", 0.95);
1046
+ canvas.toBlob(
1047
+ (blob) => {
1048
+ if (blob) {
1049
+ resolve(blob);
1050
+ } else {
1051
+ reject(new Error("Failed to create blob from canvas"));
1052
+ }
1053
+ },
1054
+ "image/jpeg",
1055
+ 0.95
1056
+ );
923
1057
  };
924
1058
  image.onerror = () => {
925
1059
  reject(new Error("Failed to load image"));
@@ -929,7 +1063,7 @@ function FileInput({
929
1063
  },
930
1064
  []
931
1065
  );
932
- const handleCropSave = React7__namespace.useCallback(async () => {
1066
+ const handleCropSave = React8__namespace.useCallback(async () => {
933
1067
  if (!imageToCrop || !croppedAreaPixels) return;
934
1068
  try {
935
1069
  const croppedBlob = await createCroppedImage(
@@ -939,11 +1073,9 @@ function FileInput({
939
1073
  if (onCropComplete) {
940
1074
  onCropComplete(croppedBlob, imageToCrop.file);
941
1075
  }
942
- const croppedFile = new File(
943
- [croppedBlob],
944
- imageToCrop.file.name,
945
- { type: "image/jpeg" }
946
- );
1076
+ const croppedFile = new File([croppedBlob], imageToCrop.file.name, {
1077
+ type: "image/jpeg"
1078
+ });
947
1079
  const updatedFiles = multiple ? [...value, croppedFile] : [croppedFile];
948
1080
  onChange(updatedFiles);
949
1081
  setCropperOpen(false);
@@ -955,8 +1087,16 @@ function FileInput({
955
1087
  } catch (error2) {
956
1088
  console.error("Failed to crop image:", error2);
957
1089
  }
958
- }, [imageToCrop, croppedAreaPixels, createCroppedImage, onCropComplete, value, onChange, multiple]);
959
- const handleCropCancel = React7__namespace.useCallback(() => {
1090
+ }, [
1091
+ imageToCrop,
1092
+ croppedAreaPixels,
1093
+ createCroppedImage,
1094
+ onCropComplete,
1095
+ value,
1096
+ onChange,
1097
+ multiple
1098
+ ]);
1099
+ const handleCropCancel = React8__namespace.useCallback(() => {
960
1100
  if (imageToCrop) {
961
1101
  URL.revokeObjectURL(imageToCrop.url);
962
1102
  }
@@ -966,13 +1106,13 @@ function FileInput({
966
1106
  setZoom(1);
967
1107
  setCroppedAreaPixels(null);
968
1108
  }, [imageToCrop]);
969
- const onCropChange = React7__namespace.useCallback((crop2) => {
1109
+ const onCropChange = React8__namespace.useCallback((crop2) => {
970
1110
  setCrop(crop2);
971
1111
  }, []);
972
- const onZoomChange = React7__namespace.useCallback((zoom2) => {
1112
+ const onZoomChange = React8__namespace.useCallback((zoom2) => {
973
1113
  setZoom(zoom2);
974
1114
  }, []);
975
- const onCropCompleteInternal = React7__namespace.useCallback(
1115
+ const onCropCompleteInternal = React8__namespace.useCallback(
976
1116
  (_, croppedAreaPixels2) => {
977
1117
  setCroppedAreaPixels(croppedAreaPixels2);
978
1118
  },
@@ -1033,7 +1173,7 @@ function FileInput({
1033
1173
  }
1034
1174
  return null;
1035
1175
  };
1036
- React7__namespace.useEffect(() => {
1176
+ React8__namespace.useEffect(() => {
1037
1177
  return () => {
1038
1178
  value.forEach((file) => {
1039
1179
  const previewUrl = getPreviewUrl(file);
@@ -1047,7 +1187,7 @@ function FileInput({
1047
1187
  };
1048
1188
  }, [value, imageToCrop]);
1049
1189
  const combinedClassName = `${className}`.trim();
1050
- return /* @__PURE__ */ React7__namespace.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React7__namespace.createElement(
1190
+ return /* @__PURE__ */ React8__namespace.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React8__namespace.createElement(
1051
1191
  "input",
1052
1192
  {
1053
1193
  ref: inputRef,
@@ -1064,10 +1204,10 @@ function FileInput({
1064
1204
  "aria-required": required || props["aria-required"],
1065
1205
  style: { display: "none" }
1066
1206
  }
1067
- ), /* @__PURE__ */ React7__namespace.createElement(
1207
+ ), /* @__PURE__ */ React8__namespace.createElement(
1068
1208
  "div",
1069
1209
  {
1070
- className: `flex min-h-32 w-full cursor-pointer items-center justify-center rounded-md border-2 border-dashed border-input bg-transparent p-6 transition-colors hover:bg-accent/50 hover:border-ring ${dragActive ? "bg-accent border-ring" : ""} ${disabled ? "cursor-not-allowed opacity-50" : ""} ${error ? "border-red-500" : ""}`,
1210
+ className: `flex min-h-32 w-full cursor-pointer items-center justify-center rounded-md border-2 border-dashed border-input bg-transparent p-6 transition-colors hover:bg-primary/50 hover:border-ring ${dragActive ? "bg-primary text-primary-foreground border-ring" : ""} ${disabled ? "cursor-not-allowed opacity-50" : ""} ${error ? "border-destructive" : ""}`,
1071
1211
  onDragEnter: handleDrag,
1072
1212
  onDragLeave: handleDrag,
1073
1213
  onDragOver: handleDrag,
@@ -1079,10 +1219,9 @@ function FileInput({
1079
1219
  "aria-label": placeholder,
1080
1220
  "aria-disabled": disabled
1081
1221
  },
1082
- /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col items-center gap-2 text-center" }, /* @__PURE__ */ React7__namespace.createElement(
1222
+ /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex flex-col items-center gap-2 text-center" }, /* @__PURE__ */ React8__namespace.createElement(
1083
1223
  "svg",
1084
1224
  {
1085
- className: "text-muted-foreground",
1086
1225
  width: "48",
1087
1226
  height: "48",
1088
1227
  viewBox: "0 0 24 24",
@@ -1093,112 +1232,122 @@ function FileInput({
1093
1232
  strokeLinejoin: "round",
1094
1233
  "aria-hidden": "true"
1095
1234
  },
1096
- /* @__PURE__ */ React7__namespace.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1097
- /* @__PURE__ */ React7__namespace.createElement("polyline", { points: "17 8 12 3 7 8" }),
1098
- /* @__PURE__ */ React7__namespace.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
1099
- ), /* @__PURE__ */ React7__namespace.createElement("p", { className: "text-sm font-medium" }, value.length > 0 ? `${value.length} file(s) selected` : placeholder), accept && /* @__PURE__ */ React7__namespace.createElement("p", { className: "text-xs text-muted-foreground" }, "Accepted: ", accept), maxSize && /* @__PURE__ */ React7__namespace.createElement("p", { className: "text-xs text-muted-foreground" }, "Max size: ", formatFileSize(maxSize)))
1100
- ), value.length > 0 && /* @__PURE__ */ React7__namespace.createElement("ul", { className: "flex flex-col gap-2 mt-4", role: "list" }, value.map((file, index) => {
1235
+ /* @__PURE__ */ React8__namespace.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1236
+ /* @__PURE__ */ React8__namespace.createElement("polyline", { points: "17 8 12 3 7 8" }),
1237
+ /* @__PURE__ */ React8__namespace.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
1238
+ ), /* @__PURE__ */ React8__namespace.createElement("p", { className: "text-sm font-medium" }, value.length > 0 ? `${value.length} file(s) selected` : placeholder), accept && /* @__PURE__ */ React8__namespace.createElement("p", { className: "text-xs" }, "Accepted: ", accept), maxSize && /* @__PURE__ */ React8__namespace.createElement("p", { className: "text-xs " }, "Max size: ", formatFileSize(maxSize)))
1239
+ ), value.length > 0 && /* @__PURE__ */ React8__namespace.createElement("ul", { className: "flex flex-col gap-2 mt-4", role: "list" }, value.map((file, index) => {
1101
1240
  const previewUrl = showPreview ? getPreviewUrl(file) : null;
1102
- return /* @__PURE__ */ React7__namespace.createElement("li", { key: `${file.name}-${index}`, className: "flex items-center gap-3 p-3 rounded-md border border-border bg-card hover:bg-accent/50 transition-colors" }, previewUrl && /* @__PURE__ */ React7__namespace.createElement(
1103
- "img",
1104
- {
1105
- src: previewUrl,
1106
- alt: file.name,
1107
- className: "w-12 h-12 rounded object-cover",
1108
- width: "48",
1109
- height: "48"
1110
- }
1111
- ), /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React7__namespace.createElement("span", { className: "text-sm font-medium truncate" }, file.name), /* @__PURE__ */ React7__namespace.createElement("span", { className: "text-xs text-muted-foreground" }, formatFileSize(file.size)), showProgress && uploadProgress[file.name] !== void 0 && /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center gap-2 mt-1" }, /* @__PURE__ */ React7__namespace.createElement(
1112
- "div",
1241
+ return /* @__PURE__ */ React8__namespace.createElement(
1242
+ "li",
1113
1243
  {
1114
- className: "h-1.5 bg-muted rounded-full overflow-hidden flex-1",
1115
- role: "progressbar",
1116
- "aria-valuenow": uploadProgress[file.name],
1117
- "aria-valuemin": 0,
1118
- "aria-valuemax": 100,
1119
- "aria-label": `Upload progress: ${uploadProgress[file.name]}%`
1244
+ key: `${file.name}-${index}`,
1245
+ className: "flex items-center gap-3 p-3 rounded-md border border-border bg-card text-card-foreground hover:bg-primary/50 transition-colors"
1120
1246
  },
1121
- /* @__PURE__ */ React7__namespace.createElement(
1122
- "div",
1247
+ previewUrl && /* @__PURE__ */ React8__namespace.createElement(
1248
+ "img",
1123
1249
  {
1124
- className: "h-full bg-primary transition-all",
1125
- style: { width: `${uploadProgress[file.name]}%` }
1250
+ src: previewUrl,
1251
+ alt: file.name,
1252
+ className: "w-12 h-12 rounded object-cover",
1253
+ width: "48",
1254
+ height: "48"
1126
1255
  }
1127
- )
1128
- ), /* @__PURE__ */ React7__namespace.createElement("span", { className: "text-xs text-muted-foreground" }, uploadProgress[file.name], "%"))), enableCropping && file.type.startsWith("image/") && /* @__PURE__ */ React7__namespace.createElement(
1129
- "button",
1130
- {
1131
- type: "button",
1132
- onClick: (e) => {
1133
- e.stopPropagation();
1134
- handleCrop(file);
1135
- },
1136
- disabled,
1137
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
1138
- "aria-label": `Crop ${file.name}`
1139
- },
1140
- /* @__PURE__ */ React7__namespace.createElement(
1141
- "svg",
1256
+ ),
1257
+ /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React8__namespace.createElement("span", { className: "text-sm font-medium truncate" }, file.name), /* @__PURE__ */ React8__namespace.createElement("span", { className: "text-xs" }, formatFileSize(file.size)), showProgress && uploadProgress[file.name] !== void 0 && /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center gap-2 mt-1" }, /* @__PURE__ */ React8__namespace.createElement(
1258
+ "div",
1142
1259
  {
1143
- width: "20",
1144
- height: "20",
1145
- viewBox: "0 0 24 24",
1146
- fill: "none",
1147
- stroke: "currentColor",
1148
- strokeWidth: "2",
1149
- strokeLinecap: "round",
1150
- strokeLinejoin: "round",
1151
- "aria-hidden": "true"
1260
+ className: "h-1.5 bg-muted rounded-full overflow-hidden flex-1",
1261
+ role: "progressbar",
1262
+ "aria-valuenow": uploadProgress[file.name],
1263
+ "aria-valuemin": 0,
1264
+ "aria-valuemax": 100,
1265
+ "aria-label": `Upload progress: ${uploadProgress[file.name]}%`
1152
1266
  },
1153
- /* @__PURE__ */ React7__namespace.createElement("path", { d: "M6.13 1L6 16a2 2 0 0 0 2 2h15" }),
1154
- /* @__PURE__ */ React7__namespace.createElement("path", { d: "M1 6.13L16 6a2 2 0 0 1 2 2v15" })
1155
- )
1156
- ), /* @__PURE__ */ React7__namespace.createElement(
1157
- "button",
1158
- {
1159
- type: "button",
1160
- onClick: (e) => {
1161
- e.stopPropagation();
1162
- handleRemove(index);
1267
+ /* @__PURE__ */ React8__namespace.createElement(
1268
+ "div",
1269
+ {
1270
+ className: "h-full bg-primary transition-all",
1271
+ style: { width: `${uploadProgress[file.name]}%` }
1272
+ }
1273
+ )
1274
+ ), /* @__PURE__ */ React8__namespace.createElement("span", { className: "text-xs " }, uploadProgress[file.name], "%"))),
1275
+ enableCropping && file.type.startsWith("image/") && /* @__PURE__ */ React8__namespace.createElement(
1276
+ "button",
1277
+ {
1278
+ type: "button",
1279
+ onClick: (e) => {
1280
+ e.stopPropagation();
1281
+ handleCrop(file);
1282
+ },
1283
+ disabled,
1284
+ className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
1285
+ "aria-label": `Crop ${file.name}`
1163
1286
  },
1164
- disabled,
1165
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
1166
- "aria-label": `Remove ${file.name}`
1167
- },
1168
- /* @__PURE__ */ React7__namespace.createElement(
1169
- "svg",
1287
+ /* @__PURE__ */ React8__namespace.createElement(
1288
+ "svg",
1289
+ {
1290
+ width: "20",
1291
+ height: "20",
1292
+ viewBox: "0 0 24 24",
1293
+ fill: "none",
1294
+ stroke: "currentColor",
1295
+ strokeWidth: "2",
1296
+ strokeLinecap: "round",
1297
+ strokeLinejoin: "round",
1298
+ "aria-hidden": "true"
1299
+ },
1300
+ /* @__PURE__ */ React8__namespace.createElement("path", { d: "M6.13 1L6 16a2 2 0 0 0 2 2h15" }),
1301
+ /* @__PURE__ */ React8__namespace.createElement("path", { d: "M1 6.13L16 6a2 2 0 0 1 2 2v15" })
1302
+ )
1303
+ ),
1304
+ /* @__PURE__ */ React8__namespace.createElement(
1305
+ "button",
1170
1306
  {
1171
- width: "20",
1172
- height: "20",
1173
- viewBox: "0 0 24 24",
1174
- fill: "none",
1175
- stroke: "currentColor",
1176
- strokeWidth: "2",
1177
- strokeLinecap: "round",
1178
- strokeLinejoin: "round",
1179
- "aria-hidden": "true"
1307
+ type: "button",
1308
+ onClick: (e) => {
1309
+ e.stopPropagation();
1310
+ handleRemove(index);
1311
+ },
1312
+ disabled,
1313
+ className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
1314
+ "aria-label": `Remove ${file.name}`
1180
1315
  },
1181
- /* @__PURE__ */ React7__namespace.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1182
- /* @__PURE__ */ React7__namespace.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1316
+ /* @__PURE__ */ React8__namespace.createElement(
1317
+ "svg",
1318
+ {
1319
+ width: "20",
1320
+ height: "20",
1321
+ viewBox: "0 0 24 24",
1322
+ fill: "none",
1323
+ stroke: "currentColor",
1324
+ strokeWidth: "2",
1325
+ strokeLinecap: "round",
1326
+ strokeLinejoin: "round",
1327
+ "aria-hidden": "true"
1328
+ },
1329
+ /* @__PURE__ */ React8__namespace.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1330
+ /* @__PURE__ */ React8__namespace.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1331
+ )
1183
1332
  )
1184
- ));
1185
- })), cropperOpen && imageToCrop && /* @__PURE__ */ React7__namespace.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center" }, /* @__PURE__ */ React7__namespace.createElement(
1333
+ );
1334
+ })), cropperOpen && imageToCrop && /* @__PURE__ */ React8__namespace.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center" }, /* @__PURE__ */ React8__namespace.createElement(
1186
1335
  "div",
1187
1336
  {
1188
1337
  className: "absolute inset-0 bg-black/50",
1189
1338
  onClick: handleCropCancel,
1190
1339
  "aria-label": "Close cropper"
1191
1340
  }
1192
- ), /* @__PURE__ */ React7__namespace.createElement("div", { className: "relative bg-popover border border-border rounded-lg shadow-lg max-w-3xl w-full mx-4" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center justify-between p-4 border-b border-border" }, /* @__PURE__ */ React7__namespace.createElement("h3", { className: "text-lg font-semibold" }, "Crop Image"), /* @__PURE__ */ React7__namespace.createElement(
1341
+ ), /* @__PURE__ */ React8__namespace.createElement("div", { className: "relative bg-popover border border-border rounded-lg shadow-lg max-w-3xl w-full mx-4" }, /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center justify-between p-4 border-b border-border" }, /* @__PURE__ */ React8__namespace.createElement("h3", { className: "text-lg font-semibold" }, "Crop Image"), /* @__PURE__ */ React8__namespace.createElement(
1193
1342
  "button",
1194
1343
  {
1195
1344
  type: "button",
1196
- className: "flex items-center justify-center h-8 w-8 rounded hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
1345
+ className: "flex items-center justify-center h-8 w-8 rounded hover:bg-primary hover:text-primary-foreground transition-colors",
1197
1346
  onClick: handleCropCancel,
1198
1347
  "aria-label": "Close"
1199
1348
  },
1200
1349
  "\u2715"
1201
- )), /* @__PURE__ */ React7__namespace.createElement("div", { className: "p-4" }, /* @__PURE__ */ React7__namespace.createElement(
1350
+ )), /* @__PURE__ */ React8__namespace.createElement("div", { className: "p-4" }, /* @__PURE__ */ React8__namespace.createElement(
1202
1351
  "div",
1203
1352
  {
1204
1353
  className: "relative w-full h-96 bg-muted rounded-md overflow-hidden",
@@ -1220,7 +1369,7 @@ function FileInput({
1220
1369
  document.addEventListener("mouseup", handleMouseUp);
1221
1370
  }
1222
1371
  },
1223
- /* @__PURE__ */ React7__namespace.createElement(
1372
+ /* @__PURE__ */ React8__namespace.createElement(
1224
1373
  "img",
1225
1374
  {
1226
1375
  src: imageToCrop.url,
@@ -1234,7 +1383,10 @@ function FileInput({
1234
1383
  const img = e.currentTarget;
1235
1384
  const containerWidth = 600;
1236
1385
  const containerHeight = 400;
1237
- const cropWidth = cropAspectRatio ? Math.min(containerWidth * 0.8, containerHeight * 0.8 * cropAspectRatio) : containerWidth * 0.8;
1386
+ const cropWidth = cropAspectRatio ? Math.min(
1387
+ containerWidth * 0.8,
1388
+ containerHeight * 0.8 * cropAspectRatio
1389
+ ) : containerWidth * 0.8;
1238
1390
  const cropHeight = cropAspectRatio ? cropWidth / cropAspectRatio : containerHeight * 0.8;
1239
1391
  const scale = zoom;
1240
1392
  const imgWidth = img.naturalWidth;
@@ -1252,7 +1404,7 @@ function FileInput({
1252
1404
  }
1253
1405
  }
1254
1406
  ),
1255
- /* @__PURE__ */ React7__namespace.createElement(
1407
+ /* @__PURE__ */ React8__namespace.createElement(
1256
1408
  "div",
1257
1409
  {
1258
1410
  className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 border-2 border-primary rounded pointer-events-none",
@@ -1261,9 +1413,18 @@ function FileInput({
1261
1413
  aspectRatio: cropAspectRatio ? String(cropAspectRatio) : void 0
1262
1414
  }
1263
1415
  },
1264
- /* @__PURE__ */ React7__namespace.createElement("div", { className: "absolute inset-0 grid grid-cols-3 grid-rows-3" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React7__namespace.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React7__namespace.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React7__namespace.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React7__namespace.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React7__namespace.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React7__namespace.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React7__namespace.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React7__namespace.createElement("div", null))
1416
+ /* @__PURE__ */ React8__namespace.createElement("div", { className: "absolute inset-0 grid grid-cols-3 grid-rows-3" }, /* @__PURE__ */ React8__namespace.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React8__namespace.createElement("div", null))
1265
1417
  )
1266
- ), /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center gap-3 mt-4" }, /* @__PURE__ */ React7__namespace.createElement("label", { htmlFor: "zoom-slider", className: "text-sm font-medium whitespace-nowrap" }, "Zoom: ", zoom.toFixed(1), "x"), /* @__PURE__ */ React7__namespace.createElement(
1418
+ ), /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center gap-3 mt-4" }, /* @__PURE__ */ React8__namespace.createElement(
1419
+ "label",
1420
+ {
1421
+ htmlFor: "zoom-slider",
1422
+ className: "text-sm font-medium whitespace-nowrap"
1423
+ },
1424
+ "Zoom: ",
1425
+ zoom.toFixed(1),
1426
+ "x"
1427
+ ), /* @__PURE__ */ React8__namespace.createElement(
1267
1428
  "input",
1268
1429
  {
1269
1430
  id: "zoom-slider",
@@ -1276,15 +1437,15 @@ function FileInput({
1276
1437
  className: "flex-1 h-2 bg-muted rounded-lg appearance-none cursor-pointer",
1277
1438
  "aria-label": "Zoom level"
1278
1439
  }
1279
- ))), /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center justify-end gap-2 p-4 border-t border-border" }, /* @__PURE__ */ React7__namespace.createElement(
1440
+ ))), /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center justify-end gap-2 p-4 border-t border-border" }, /* @__PURE__ */ React8__namespace.createElement(
1280
1441
  "button",
1281
1442
  {
1282
1443
  type: "button",
1283
- className: "inline-flex items-center justify-center h-9 rounded-md px-4 text-sm font-medium border border-input bg-transparent hover:bg-accent hover:text-accent-foreground transition-colors",
1444
+ className: "inline-flex items-center justify-center h-9 rounded-md px-4 text-sm font-medium border border-input bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
1284
1445
  onClick: handleCropCancel
1285
1446
  },
1286
1447
  "Cancel"
1287
- ), /* @__PURE__ */ React7__namespace.createElement(
1448
+ ), /* @__PURE__ */ React8__namespace.createElement(
1288
1449
  "button",
1289
1450
  {
1290
1451
  type: "button",
@@ -1303,27 +1464,6 @@ function formatDate(date, format) {
1303
1464
  const year = d.getFullYear();
1304
1465
  return format.replace("MM", month).replace("dd", day).replace("yyyy", String(year)).replace("yy", String(year).slice(2));
1305
1466
  }
1306
- function parseDate(dateString, format) {
1307
- if (!dateString) return null;
1308
- try {
1309
- if (format === "MM/dd/yyyy" || format === "MM-dd-yyyy") {
1310
- const parts = dateString.split(/[/-]/);
1311
- if (parts.length === 3) {
1312
- const month = parseInt(parts[0], 10) - 1;
1313
- const day = parseInt(parts[1], 10);
1314
- const year = parseInt(parts[2], 10);
1315
- const date2 = new Date(year, month, day);
1316
- if (!isNaN(date2.getTime())) {
1317
- return date2;
1318
- }
1319
- }
1320
- }
1321
- const date = new Date(dateString);
1322
- return isNaN(date.getTime()) ? null : date;
1323
- } catch {
1324
- return null;
1325
- }
1326
- }
1327
1467
  function isDateInArray(date, dates) {
1328
1468
  const dateStr = date.toDateString();
1329
1469
  return dates.some((d) => d.toDateString() === dateStr);
@@ -1347,43 +1487,30 @@ function DatePicker({
1347
1487
  showIcon = true,
1348
1488
  ...props
1349
1489
  }) {
1350
- const [isOpen, setIsOpen] = React7__namespace.useState(false);
1351
- const [inputValue, setInputValue] = React7__namespace.useState("");
1352
- const [selectedMonth, setSelectedMonth] = React7__namespace.useState(
1490
+ const [isOpen, setIsOpen] = React8__namespace.useState(false);
1491
+ const [selectedMonth, setSelectedMonth] = React8__namespace.useState(
1353
1492
  value || /* @__PURE__ */ new Date()
1354
1493
  );
1355
- const containerRef = React7__namespace.useRef(null);
1356
- const inputRef = React7__namespace.useRef(null);
1357
- React7__namespace.useEffect(() => {
1358
- setInputValue(formatDate(value, format));
1494
+ const containerRef = React8__namespace.useRef(null);
1495
+ const inputRef = React8__namespace.useRef(null);
1496
+ React8__namespace.useEffect(() => {
1359
1497
  if (value) {
1360
1498
  setSelectedMonth(value);
1361
1499
  }
1362
- }, [value, format]);
1500
+ }, [value]);
1363
1501
  const handleDateSelect = (date) => {
1364
1502
  onChange(date);
1365
1503
  setIsOpen(false);
1366
1504
  onBlur?.();
1367
1505
  };
1368
- const handleInputChange = (e) => {
1369
- const newValue = e.target.value;
1370
- setInputValue(newValue);
1371
- const parsedDate = parseDate(newValue, format);
1372
- if (parsedDate && !isNaN(parsedDate.getTime())) {
1373
- onChange(parsedDate);
1374
- } else if (newValue === "") {
1375
- onChange(null);
1376
- }
1377
- };
1378
1506
  const handleClear = (e) => {
1379
1507
  e.stopPropagation();
1380
1508
  onChange(null);
1381
- setInputValue("");
1382
1509
  inputRef.current?.focus();
1383
1510
  };
1384
1511
  const handleToggle = () => {
1385
1512
  if (disabled) return;
1386
- setIsOpen(!isOpen);
1513
+ setIsOpen((prev) => !prev);
1387
1514
  };
1388
1515
  const isDisabled = (date) => {
1389
1516
  if (minDate && date < minDate) return true;
@@ -1392,20 +1519,17 @@ function DatePicker({
1392
1519
  if (isDateDisabled && isDateDisabled(date)) return true;
1393
1520
  return false;
1394
1521
  };
1395
- React7__namespace.useEffect(() => {
1396
- const handleClickOutside = (event) => {
1397
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1398
- setIsOpen(false);
1399
- onBlur?.();
1400
- }
1401
- };
1402
- if (isOpen) {
1403
- document.addEventListener("mousedown", handleClickOutside);
1404
- return () => {
1405
- document.removeEventListener("mousedown", handleClickOutside);
1406
- };
1407
- }
1522
+ const closeCalendar = React8__namespace.useCallback(() => {
1523
+ if (!isOpen) return;
1524
+ setIsOpen(false);
1525
+ onBlur?.();
1408
1526
  }, [isOpen, onBlur]);
1527
+ useOnClickOutside.useOnClickOutside(containerRef, closeCalendar, "pointerdown", true);
1528
+ const dayGridStyle = {
1529
+ gridTemplateColumns: "repeat(7, minmax(0, 1fr))"
1530
+ };
1531
+ const hasValue = Boolean(value);
1532
+ const displayValue = formatDate(value, format);
1409
1533
  const renderCalendar = () => {
1410
1534
  const year = selectedMonth.getFullYear();
1411
1535
  const month = selectedMonth.getMonth();
@@ -1438,44 +1562,57 @@ function DatePicker({
1438
1562
  const handleNextMonth = () => {
1439
1563
  setSelectedMonth(new Date(year, month + 1, 1));
1440
1564
  };
1441
- return /* @__PURE__ */ React7__namespace.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center justify-between pb-2 border-b border-border" }, /* @__PURE__ */ React7__namespace.createElement(
1565
+ return /* @__PURE__ */ React8__namespace.createElement("div", { role: "grid", "aria-label": "Calendar", className: "w-[248px] max-w-full" }, /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center justify-between pb-3" }, /* @__PURE__ */ React8__namespace.createElement(
1442
1566
  "button",
1443
1567
  {
1444
1568
  type: "button",
1445
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground cursor-pointer",
1569
+ className: "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent hover:bg-muted cursor-pointer transition-colors",
1446
1570
  onClick: handlePrevMonth,
1447
1571
  "aria-label": "Previous month"
1448
1572
  },
1449
- "\u2190"
1450
- ), /* @__PURE__ */ React7__namespace.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React7__namespace.createElement(
1573
+ "\u2039"
1574
+ ), /* @__PURE__ */ React8__namespace.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React8__namespace.createElement(
1451
1575
  "button",
1452
1576
  {
1453
1577
  type: "button",
1454
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground cursor-pointer",
1578
+ className: "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent hover:bg-muted cursor-pointer transition-colors",
1455
1579
  onClick: handleNextMonth,
1456
1580
  "aria-label": "Next month"
1457
1581
  },
1458
- "\u2192"
1459
- )), /* @__PURE__ */ React7__namespace.createElement("div", { className: "grid grid-cols-7 gap-1 mt-2" }, ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React7__namespace.createElement(
1582
+ "\u203A"
1583
+ )), /* @__PURE__ */ React8__namespace.createElement(
1460
1584
  "div",
1461
1585
  {
1462
- key: day,
1463
- className: "flex items-center justify-center h-8 w-full text-xs font-medium"
1586
+ className: "grid gap-1 text-xs text-muted-foreground",
1587
+ style: dayGridStyle
1464
1588
  },
1465
- day
1466
- ))), /* @__PURE__ */ React7__namespace.createElement("div", { className: "grid grid-cols-7 gap-1" }, days.map((date, index) => {
1589
+ ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React8__namespace.createElement(
1590
+ "div",
1591
+ {
1592
+ key: day,
1593
+ className: "flex items-center justify-center h-8 w-8 font-medium"
1594
+ },
1595
+ day
1596
+ ))
1597
+ ), /* @__PURE__ */ React8__namespace.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
1467
1598
  if (!date) {
1468
- return /* @__PURE__ */ React7__namespace.createElement("div", { key: `empty-${index}` });
1599
+ return /* @__PURE__ */ React8__namespace.createElement("div", { key: `empty-${index}`, className: "h-8 w-8" });
1469
1600
  }
1470
1601
  const isSelected = value && date.toDateString() === value.toDateString();
1471
1602
  const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
1472
1603
  const disabled2 = isDisabled(date);
1473
- return /* @__PURE__ */ React7__namespace.createElement(
1604
+ return /* @__PURE__ */ React8__namespace.createElement(
1474
1605
  "button",
1475
1606
  {
1476
1607
  key: date.toISOString(),
1477
1608
  type: "button",
1478
- className: `flex items-center justify-center h-8 w-full rounded border-none bg-transparent cursor-pointer text-sm transition-colors hover:bg-primary hover:text-primary-foreground ${isSelected ? "bg-primary text-primary-foreground font-semibold" : ""} ${isToday ? "border border-primary" : ""} ${disabled2 ? "cursor-not-allowed opacity-50 pointer-events-none" : ""}`,
1609
+ className: cn(
1610
+ "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent cursor-pointer text-sm transition-colors",
1611
+ "hover:bg-muted",
1612
+ isSelected && "bg-primary text-primary-foreground font-semibold",
1613
+ !isSelected && isToday && "border border-primary",
1614
+ disabled2 && "cursor-not-allowed opacity-50 pointer-events-none"
1615
+ ),
1479
1616
  onClick: () => !disabled2 && handleDateSelect(date),
1480
1617
  disabled: disabled2,
1481
1618
  "aria-label": formatDate(date, format)
@@ -1484,21 +1621,21 @@ function DatePicker({
1484
1621
  );
1485
1622
  })));
1486
1623
  };
1487
- const combinedClassName = `relative ${className}`.trim();
1488
- return /* @__PURE__ */ React7__namespace.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React7__namespace.createElement(
1624
+ const combinedClassName = cn("relative", className);
1625
+ return /* @__PURE__ */ React8__namespace.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React8__namespace.createElement(
1489
1626
  "input",
1490
1627
  {
1491
1628
  type: "hidden",
1492
1629
  name,
1493
1630
  value: value ? value.toISOString() : ""
1494
1631
  }
1495
- ), /* @__PURE__ */ React7__namespace.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React7__namespace.createElement(
1632
+ ), /* @__PURE__ */ React8__namespace.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8__namespace.createElement(
1496
1633
  "span",
1497
1634
  {
1498
1635
  className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
1499
1636
  "aria-hidden": "true"
1500
1637
  },
1501
- /* @__PURE__ */ React7__namespace.createElement(
1638
+ /* @__PURE__ */ React8__namespace.createElement(
1502
1639
  "svg",
1503
1640
  {
1504
1641
  xmlns: "http://www.w3.org/2000/svg",
@@ -1511,16 +1648,24 @@ function DatePicker({
1511
1648
  strokeLinejoin: "round",
1512
1649
  strokeWidth: "2"
1513
1650
  },
1514
- /* @__PURE__ */ React7__namespace.createElement("path", { d: "M8 2v4m8-4v4m5 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8M3 10h18m-5 10l2 2l4-4" })
1651
+ /* @__PURE__ */ React8__namespace.createElement("path", { d: "M8 2v4m8-4v4m5 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8M3 10h18m-5 10l2 2l4-4" })
1515
1652
  )
1516
- ), /* @__PURE__ */ React7__namespace.createElement(
1653
+ ), /* @__PURE__ */ React8__namespace.createElement(
1517
1654
  "input",
1518
1655
  {
1519
1656
  ref: inputRef,
1520
1657
  type: "text",
1521
- className: `flex h-9 w-full rounded-md border border-input bg-transparent ${showIcon ? "pl-10" : "pl-3"} ${clearable && value ? "pr-10" : "pr-3"} py-1 text-base shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm ${error ? "border-red-500 ring-1 ring-red-500" : ""}`,
1522
- value: inputValue,
1523
- onChange: handleInputChange,
1658
+ className: cn(
1659
+ "flex h-9 w-full rounded-md border border-input bg-transparent py-1 text-base shadow-sm transition-colors",
1660
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1661
+ "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1662
+ INPUT_AUTOFILL_RESET_CLASSES,
1663
+ showIcon ? "pl-10" : "pl-3",
1664
+ clearable && value ? "pr-10" : "pr-3",
1665
+ !error && hasValue && "ring-2 ring-ring",
1666
+ error && "border-destructive ring-1 ring-destructive"
1667
+ ),
1668
+ value: displayValue,
1524
1669
  onClick: handleToggle,
1525
1670
  onBlur,
1526
1671
  disabled,
@@ -1531,7 +1676,7 @@ function DatePicker({
1531
1676
  "aria-required": required || props["aria-required"],
1532
1677
  readOnly: true
1533
1678
  }
1534
- ), clearable && value && !disabled && /* @__PURE__ */ React7__namespace.createElement(
1679
+ ), clearable && value && !disabled && /* @__PURE__ */ React8__namespace.createElement(
1535
1680
  "button",
1536
1681
  {
1537
1682
  type: "button",
@@ -1541,49 +1686,49 @@ function DatePicker({
1541
1686
  tabIndex: -1
1542
1687
  },
1543
1688
  "\u2715"
1544
- )), isOpen && !disabled && /* @__PURE__ */ React7__namespace.createElement("div", { className: "absolute z-50 top-full mt-1 min-w-full rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3" }, renderCalendar()));
1689
+ )), isOpen && !disabled && /* @__PURE__ */ React8__namespace.createElement("div", { className: "absolute z-50 top-full mt-1 w-fit rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3" }, renderCalendar()));
1545
1690
  }
1546
1691
  DatePicker.displayName = "DatePicker";
1547
- function parseTimeString(timeStr, use24Hour) {
1548
- if (!timeStr) return null;
1549
- try {
1550
- if (use24Hour) {
1551
- const [hourStr, minuteStr] = timeStr.split(":");
1552
- const hour24 = parseInt(hourStr, 10);
1553
- const minute = parseInt(minuteStr, 10);
1554
- if (isNaN(hour24) || isNaN(minute)) return null;
1555
- if (hour24 < 0 || hour24 > 23) return null;
1556
- if (minute < 0 || minute > 59) return null;
1557
- const period = hour24 >= 12 ? "PM" : "AM";
1558
- const hour = hour24 === 0 ? 12 : hour24 > 12 ? hour24 - 12 : hour24;
1559
- return { hour, minute, period };
1560
- } else {
1561
- const match = timeStr.match(/^(\d{1,2}):(\d{2})\s*(AM|PM)$/i);
1562
- if (!match) return null;
1563
- const hour = parseInt(match[1], 10);
1564
- const minute = parseInt(match[2], 10);
1565
- const period = match[3].toUpperCase();
1566
- if (hour < 1 || hour > 12) return null;
1567
- if (minute < 0 || minute > 59) return null;
1568
- return { hour, minute, period };
1692
+ function normalizeToNativeTime(value) {
1693
+ if (!value) return "";
1694
+ const twelveHourMatch = value.match(
1695
+ /^(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(AM|PM)$/i
1696
+ );
1697
+ if (twelveHourMatch) {
1698
+ const rawHour = parseInt(twelveHourMatch[1], 10);
1699
+ const minute = parseInt(twelveHourMatch[2], 10);
1700
+ const period = twelveHourMatch[4].toUpperCase();
1701
+ if (Number.isNaN(rawHour) || Number.isNaN(minute) || rawHour < 1 || rawHour > 12 || minute < 0 || minute > 59) {
1702
+ return "";
1569
1703
  }
1570
- } catch {
1571
- return null;
1704
+ const normalizedHour = period === "PM" ? rawHour === 12 ? 12 : rawHour + 12 : rawHour === 12 ? 0 : rawHour;
1705
+ return `${String(normalizedHour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
1706
+ }
1707
+ const twentyFourHourMatch = value.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/);
1708
+ if (twentyFourHourMatch) {
1709
+ const hour = parseInt(twentyFourHourMatch[1], 10);
1710
+ const minute = parseInt(twentyFourHourMatch[2], 10);
1711
+ if (Number.isNaN(hour) || Number.isNaN(minute) || hour < 0 || hour > 23 || minute < 0 || minute > 59) {
1712
+ return "";
1713
+ }
1714
+ return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
1572
1715
  }
1716
+ return "";
1573
1717
  }
1574
- function formatTimeValue(time, use24Hour) {
1575
- if (!time) return "";
1718
+ function formatFromNativeTime(nativeValue, use24Hour) {
1719
+ if (!nativeValue) return "";
1720
+ const [hourValue, minuteValue] = nativeValue.split(":");
1721
+ const hour = parseInt(hourValue, 10);
1722
+ const minute = parseInt(minuteValue, 10);
1723
+ if (Number.isNaN(hour) || Number.isNaN(minute)) {
1724
+ return "";
1725
+ }
1576
1726
  if (use24Hour) {
1577
- let hour24 = time.hour;
1578
- if (time.period === "PM" && time.hour !== 12) {
1579
- hour24 = time.hour + 12;
1580
- } else if (time.period === "AM" && time.hour === 12) {
1581
- hour24 = 0;
1582
- }
1583
- return `${String(hour24).padStart(2, "0")}:${String(time.minute).padStart(2, "0")}`;
1584
- } else {
1585
- return `${time.hour}:${String(time.minute).padStart(2, "0")} ${time.period}`;
1727
+ return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
1586
1728
  }
1729
+ const period = hour >= 12 ? "PM" : "AM";
1730
+ const hour12 = hour % 12 || 12;
1731
+ return `${hour12}:${String(minute).padStart(2, "0")} ${period}`;
1587
1732
  }
1588
1733
  function TimePicker({
1589
1734
  name,
@@ -1601,188 +1746,87 @@ function TimePicker({
1601
1746
  showIcon = true,
1602
1747
  ...props
1603
1748
  }) {
1604
- const [isOpen, setIsOpen] = React7__namespace.useState(false);
1605
- const [timeValue, setTimeValue] = React7__namespace.useState(null);
1606
- const containerRef = React7__namespace.useRef(null);
1607
- const inputRef = React7__namespace.useRef(null);
1608
- React7__namespace.useEffect(() => {
1609
- const parsed = parseTimeString(value, use24Hour);
1610
- setTimeValue(parsed);
1611
- }, [value, use24Hour]);
1612
- const handleHourChange = (hour) => {
1613
- const newTime = {
1614
- hour,
1615
- minute: timeValue?.minute || 0,
1616
- period: timeValue?.period || "AM"
1617
- };
1618
- setTimeValue(newTime);
1619
- onChange(formatTimeValue(newTime, use24Hour));
1620
- };
1621
- const handleMinuteChange = (minute) => {
1622
- const newTime = {
1623
- hour: timeValue?.hour || 12,
1624
- minute,
1625
- period: timeValue?.period || "AM"
1626
- };
1627
- setTimeValue(newTime);
1628
- onChange(formatTimeValue(newTime, use24Hour));
1629
- };
1630
- const handlePeriodChange = (period) => {
1631
- const newTime = {
1632
- hour: timeValue?.hour || 12,
1633
- minute: timeValue?.minute || 0,
1634
- period
1635
- };
1636
- setTimeValue(newTime);
1637
- onChange(formatTimeValue(newTime, use24Hour));
1749
+ const inputRef = React8__namespace.useRef(null);
1750
+ const [nativeValue, setNativeValue] = React8__namespace.useState(
1751
+ normalizeToNativeTime(value)
1752
+ );
1753
+ React8__namespace.useEffect(() => {
1754
+ setNativeValue(normalizeToNativeTime(value));
1755
+ }, [value]);
1756
+ const handleChange = (e) => {
1757
+ const nextNativeValue = e.target.value;
1758
+ setNativeValue(nextNativeValue);
1759
+ onChange(formatFromNativeTime(nextNativeValue, use24Hour));
1638
1760
  };
1639
1761
  const handleClear = (e) => {
1640
1762
  e.stopPropagation();
1763
+ setNativeValue("");
1641
1764
  onChange("");
1642
- setTimeValue(null);
1643
1765
  inputRef.current?.focus();
1644
1766
  };
1645
- const handleToggle = () => {
1646
- if (disabled) return;
1647
- setIsOpen(!isOpen);
1648
- };
1649
- React7__namespace.useEffect(() => {
1650
- const handleClickOutside = (event) => {
1651
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1652
- setIsOpen(false);
1653
- onBlur?.();
1654
- }
1655
- };
1656
- if (isOpen) {
1657
- document.addEventListener("mousedown", handleClickOutside);
1658
- return () => {
1659
- document.removeEventListener("mousedown", handleClickOutside);
1660
- };
1661
- }
1662
- }, [isOpen, onBlur]);
1663
- const hours = React7__namespace.useMemo(() => {
1664
- if (use24Hour) {
1665
- return Array.from({ length: 24 }, (_, i) => i);
1666
- } else {
1667
- return Array.from({ length: 12 }, (_, i) => i + 1);
1668
- }
1669
- }, [use24Hour]);
1670
- const minutes = React7__namespace.useMemo(() => {
1671
- const mins = [];
1672
- for (let i = 0; i < 60; i += minuteStep) {
1673
- mins.push(i);
1674
- }
1675
- return mins;
1676
- }, [minuteStep]);
1677
- const combinedClassName = `relative ${className}`.trim();
1678
- const displayValue = formatTimeValue(timeValue, use24Hour);
1679
- return /* @__PURE__ */ React7__namespace.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React7__namespace.createElement(
1680
- "input",
1681
- {
1682
- type: "hidden",
1683
- name,
1684
- value
1685
- }
1686
- ), /* @__PURE__ */ React7__namespace.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React7__namespace.createElement("span", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none", "aria-hidden": "true" }, /* @__PURE__ */ React7__namespace.createElement(
1687
- "svg",
1767
+ const hasValue = Boolean(value);
1768
+ const stepInSeconds = Math.max(1, minuteStep * 60);
1769
+ return /* @__PURE__ */ React8__namespace.createElement("div", { className: cn("relative", className) }, /* @__PURE__ */ React8__namespace.createElement("input", { type: "hidden", name, value }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8__namespace.createElement(
1770
+ "span",
1688
1771
  {
1689
- xmlns: "http://www.w3.org/2000/svg",
1690
- width: "18",
1691
- height: "18",
1692
- viewBox: "0 0 24 24",
1693
- fill: "none",
1694
- stroke: "currentColor",
1695
- strokeLinecap: "round",
1696
- strokeLinejoin: "round",
1697
- strokeWidth: "2"
1772
+ className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
1773
+ "aria-hidden": "true"
1698
1774
  },
1699
- /* @__PURE__ */ React7__namespace.createElement("circle", { cx: "12", cy: "12", r: "10" }),
1700
- /* @__PURE__ */ React7__namespace.createElement("path", { d: "M12 6v6l4 2" })
1701
- )), /* @__PURE__ */ React7__namespace.createElement(
1775
+ /* @__PURE__ */ React8__namespace.createElement(
1776
+ "svg",
1777
+ {
1778
+ xmlns: "http://www.w3.org/2000/svg",
1779
+ width: "18",
1780
+ height: "18",
1781
+ viewBox: "0 0 24 24",
1782
+ fill: "none",
1783
+ stroke: "currentColor",
1784
+ strokeLinecap: "round",
1785
+ strokeLinejoin: "round",
1786
+ strokeWidth: "2"
1787
+ },
1788
+ /* @__PURE__ */ React8__namespace.createElement("circle", { cx: "12", cy: "12", r: "10" }),
1789
+ /* @__PURE__ */ React8__namespace.createElement("path", { d: "M12 6v6l4 2" })
1790
+ )
1791
+ ), /* @__PURE__ */ React8__namespace.createElement(
1702
1792
  "input",
1703
1793
  {
1704
1794
  ref: inputRef,
1705
- type: "text",
1706
- className: `flex h-9 w-full rounded-md border border-input bg-transparent ${showIcon ? "pl-10" : "pl-3"} ${clearable && value ? "pr-10" : "pr-3"} py-1 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm ${error ? "border-red-500 ring-1 ring-red-500" : ""}`,
1707
- value: displayValue,
1708
- onClick: handleToggle,
1795
+ type: "time",
1796
+ className: cn(
1797
+ "flex h-9 w-full rounded-md border border-input bg-transparent py-1 text-base shadow-sm transition-colors",
1798
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1799
+ "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1800
+ "appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none",
1801
+ INPUT_AUTOFILL_RESET_CLASSES,
1802
+ showIcon ? "pl-10" : "pl-3",
1803
+ clearable && value ? "pr-10" : "pr-3",
1804
+ !error && hasValue && "ring-2 ring-ring",
1805
+ error && "border-destructive ring-1 ring-destructive"
1806
+ ),
1807
+ value: nativeValue,
1808
+ onChange: handleChange,
1709
1809
  onBlur,
1710
1810
  disabled,
1711
1811
  required,
1812
+ step: stepInSeconds,
1712
1813
  placeholder,
1713
1814
  "aria-invalid": error || props["aria-invalid"] ? "true" : "false",
1714
1815
  "aria-describedby": props["aria-describedby"],
1715
1816
  "aria-required": required || props["aria-required"],
1716
- readOnly: true
1817
+ ...props
1717
1818
  }
1718
- ), clearable && value && !disabled && /* @__PURE__ */ React7__namespace.createElement(
1819
+ ), clearable && value && !disabled && /* @__PURE__ */ React8__namespace.createElement(
1719
1820
  "button",
1720
1821
  {
1721
1822
  type: "button",
1722
- className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors",
1823
+ className: "absolute right-3 top-1/2 -translate-y-1/2 transition-colors",
1723
1824
  onClick: handleClear,
1724
1825
  "aria-label": "Clear time",
1725
1826
  tabIndex: -1
1726
1827
  },
1727
1828
  "\u2715"
1728
- )), isOpen && !disabled && /* @__PURE__ */ React7__namespace.createElement("div", { className: "absolute z-50 top-full mt-1 min-w-full rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col flex-1" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-xs font-medium text-muted-foreground mb-2 text-center" }, use24Hour ? "Hour" : "Hour"), /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col gap-1 max-h-48 overflow-y-auto" }, hours.map((hour) => {
1729
- const displayHour = use24Hour ? hour : hour;
1730
- const isSelected = use24Hour ? timeValue?.hour === (hour === 0 ? 12 : hour > 12 ? hour - 12 : hour) && timeValue?.period === (hour >= 12 ? "PM" : "AM") : timeValue?.hour === hour;
1731
- return /* @__PURE__ */ React7__namespace.createElement(
1732
- "button",
1733
- {
1734
- key: hour,
1735
- type: "button",
1736
- className: `flex items-center justify-center h-8 w-full rounded border-none bg-transparent cursor-pointer text-sm transition-colors hover:bg-accent hover:text-accent-foreground ${isSelected ? "bg-primary text-primary-foreground font-semibold" : ""}`,
1737
- onClick: () => {
1738
- if (use24Hour) {
1739
- const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
1740
- const period = hour >= 12 ? "PM" : "AM";
1741
- const newTime = {
1742
- hour: hour12,
1743
- minute: timeValue?.minute || 0,
1744
- period
1745
- };
1746
- setTimeValue(newTime);
1747
- onChange(formatTimeValue(newTime, use24Hour));
1748
- } else {
1749
- handleHourChange(hour);
1750
- }
1751
- },
1752
- "aria-label": `${String(displayHour).padStart(2, "0")} hours`
1753
- },
1754
- String(displayHour).padStart(2, "0")
1755
- );
1756
- }))), /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col flex-1" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-xs font-medium text-muted-foreground mb-2 text-center" }, "Minute"), /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col gap-1 max-h-48 overflow-y-auto" }, minutes.map((minute) => {
1757
- const isSelected = timeValue?.minute === minute;
1758
- return /* @__PURE__ */ React7__namespace.createElement(
1759
- "button",
1760
- {
1761
- key: minute,
1762
- type: "button",
1763
- className: `flex items-center justify-center h-8 w-full rounded border-none bg-transparent cursor-pointer text-sm transition-colors hover:bg-accent hover:text-accent-foreground ${isSelected ? "bg-primary text-primary-foreground font-semibold" : ""}`,
1764
- onClick: () => handleMinuteChange(minute),
1765
- "aria-label": `${String(minute).padStart(2, "0")} minutes`
1766
- },
1767
- String(minute).padStart(2, "0")
1768
- );
1769
- }))), !use24Hour && /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col w-20" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-xs font-medium text-muted-foreground mb-2 text-center" }, "Period"), /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React7__namespace.createElement(
1770
- "button",
1771
- {
1772
- type: "button",
1773
- className: `flex items-center justify-center h-8 w-full rounded border-none bg-transparent cursor-pointer text-sm transition-colors hover:bg-accent hover:text-accent-foreground ${timeValue?.period === "AM" ? "bg-primary text-primary-foreground font-semibold" : ""}`,
1774
- onClick: () => handlePeriodChange("AM")
1775
- },
1776
- "AM"
1777
- ), /* @__PURE__ */ React7__namespace.createElement(
1778
- "button",
1779
- {
1780
- type: "button",
1781
- className: `flex items-center justify-center h-8 w-full rounded border-none bg-transparent cursor-pointer text-sm transition-colors hover:bg-accent hover:text-accent-foreground ${timeValue?.period === "PM" ? "bg-primary text-primary-foreground font-semibold" : ""}`,
1782
- onClick: () => handlePeriodChange("PM")
1783
- },
1784
- "PM"
1785
- ))))));
1829
+ )));
1786
1830
  }
1787
1831
  TimePicker.displayName = "TimePicker";
1788
1832
  function formatDate2(date, format) {
@@ -1802,6 +1846,9 @@ function isDateInRange(date, start, end) {
1802
1846
  const time = date.getTime();
1803
1847
  return time >= start.getTime() && time <= end.getTime();
1804
1848
  }
1849
+ function addMonths(date, delta) {
1850
+ return new Date(date.getFullYear(), date.getMonth() + delta, 1);
1851
+ }
1805
1852
  function DateRangePicker({
1806
1853
  name,
1807
1854
  value = { start: null, end: null },
@@ -1822,13 +1869,15 @@ function DateRangePicker({
1822
1869
  separator = " - ",
1823
1870
  ...props
1824
1871
  }) {
1825
- const [isOpen, setIsOpen] = React7__namespace.useState(false);
1826
- const [selectedMonth, setSelectedMonth] = React7__namespace.useState(value.start || /* @__PURE__ */ new Date());
1827
- const [rangeStart, setRangeStart] = React7__namespace.useState(value.start);
1828
- const [rangeEnd, setRangeEnd] = React7__namespace.useState(value.end);
1829
- const [hoverDate, setHoverDate] = React7__namespace.useState(null);
1830
- const containerRef = React7__namespace.useRef(null);
1831
- React7__namespace.useEffect(() => {
1872
+ const [isOpen, setIsOpen] = React8__namespace.useState(false);
1873
+ const [selectedMonth, setSelectedMonth] = React8__namespace.useState(
1874
+ value.start || /* @__PURE__ */ new Date()
1875
+ );
1876
+ const [rangeStart, setRangeStart] = React8__namespace.useState(value.start);
1877
+ const [rangeEnd, setRangeEnd] = React8__namespace.useState(value.end);
1878
+ const [hoverDate, setHoverDate] = React8__namespace.useState(null);
1879
+ const containerRef = React8__namespace.useRef(null);
1880
+ React8__namespace.useEffect(() => {
1832
1881
  setRangeStart(value.start);
1833
1882
  setRangeEnd(value.end);
1834
1883
  if (value.start) {
@@ -1862,7 +1911,7 @@ function DateRangePicker({
1862
1911
  };
1863
1912
  const handleToggle = () => {
1864
1913
  if (disabled) return;
1865
- setIsOpen(!isOpen);
1914
+ setIsOpen((prev) => !prev);
1866
1915
  };
1867
1916
  const isDisabled = (date) => {
1868
1917
  if (minDate && date < minDate) return true;
@@ -1871,23 +1920,36 @@ function DateRangePicker({
1871
1920
  if (isDateDisabled && isDateDisabled(date)) return true;
1872
1921
  return false;
1873
1922
  };
1874
- React7__namespace.useEffect(() => {
1875
- const handleClickOutside = (event) => {
1876
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1877
- setIsOpen(false);
1878
- onBlur?.();
1879
- }
1880
- };
1881
- if (isOpen) {
1882
- document.addEventListener("mousedown", handleClickOutside);
1883
- return () => {
1884
- document.removeEventListener("mousedown", handleClickOutside);
1885
- };
1886
- }
1923
+ const closeCalendar = React8__namespace.useCallback(() => {
1924
+ if (!isOpen) return;
1925
+ setIsOpen(false);
1926
+ onBlur?.();
1887
1927
  }, [isOpen, onBlur]);
1888
- const renderCalendar = () => {
1889
- const year = selectedMonth.getFullYear();
1890
- const month = selectedMonth.getMonth();
1928
+ useOnClickOutside.useOnClickOutside(containerRef, closeCalendar, "pointerdown", true);
1929
+ const dayGridStyle = {
1930
+ gridTemplateColumns: "repeat(7, minmax(0, 1fr))"
1931
+ };
1932
+ const monthsGridStyle = {
1933
+ gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))"
1934
+ };
1935
+ const monthNames = [
1936
+ "January",
1937
+ "February",
1938
+ "March",
1939
+ "April",
1940
+ "May",
1941
+ "June",
1942
+ "July",
1943
+ "August",
1944
+ "September",
1945
+ "October",
1946
+ "November",
1947
+ "December"
1948
+ ];
1949
+ const hasValue = Boolean(rangeStart || rangeEnd);
1950
+ const renderMonth = (monthDate, controls) => {
1951
+ const year = monthDate.getFullYear();
1952
+ const month = monthDate.getMonth();
1891
1953
  const daysInMonth = new Date(year, month + 1, 0).getDate();
1892
1954
  const firstDayOfMonth = new Date(year, month, 1).getDay();
1893
1955
  const days = [];
@@ -1897,60 +1959,65 @@ function DateRangePicker({
1897
1959
  for (let day = 1; day <= daysInMonth; day++) {
1898
1960
  days.push(new Date(year, month, day));
1899
1961
  }
1900
- const monthNames = [
1901
- "January",
1902
- "February",
1903
- "March",
1904
- "April",
1905
- "May",
1906
- "June",
1907
- "July",
1908
- "August",
1909
- "September",
1910
- "October",
1911
- "November",
1912
- "December"
1913
- ];
1914
- const handlePrevMonth = () => {
1915
- setSelectedMonth(new Date(year, month - 1, 1));
1916
- };
1917
- const handleNextMonth = () => {
1918
- setSelectedMonth(new Date(year, month + 1, 1));
1919
- };
1920
- return /* @__PURE__ */ React7__namespace.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center justify-between pb-2 border-b border-border" }, /* @__PURE__ */ React7__namespace.createElement(
1962
+ return /* @__PURE__ */ React8__namespace.createElement("div", { className: "w-[240px] max-w-full" }, /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center justify-between pb-3" }, controls?.prev ? /* @__PURE__ */ React8__namespace.createElement(
1921
1963
  "button",
1922
1964
  {
1923
1965
  type: "button",
1924
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-accent cursor-pointer",
1925
- onClick: handlePrevMonth,
1966
+ className: "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent hover:bg-muted cursor-pointer transition-colors",
1967
+ onClick: () => setSelectedMonth((prev) => addMonths(prev, -1)),
1926
1968
  "aria-label": "Previous month"
1927
1969
  },
1928
- "\u2190"
1929
- ), /* @__PURE__ */ React7__namespace.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React7__namespace.createElement(
1970
+ "\u2039"
1971
+ ) : /* @__PURE__ */ React8__namespace.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" }), /* @__PURE__ */ React8__namespace.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), controls?.next ? /* @__PURE__ */ React8__namespace.createElement(
1930
1972
  "button",
1931
1973
  {
1932
1974
  type: "button",
1933
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-accent cursor-pointer",
1934
- onClick: handleNextMonth,
1975
+ className: "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent hover:bg-muted cursor-pointer transition-colors",
1976
+ onClick: () => setSelectedMonth((prev) => addMonths(prev, 1)),
1935
1977
  "aria-label": "Next month"
1936
1978
  },
1937
- "\u2192"
1938
- )), /* @__PURE__ */ React7__namespace.createElement("div", { className: "grid grid-cols-7 gap-1 mt-2" }, ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React7__namespace.createElement("div", { key: day, className: "flex items-center justify-center h-8 w-full text-xs text-muted-foreground font-medium" }, day))), /* @__PURE__ */ React7__namespace.createElement("div", { className: "grid grid-cols-7 gap-1" }, days.map((date, index) => {
1979
+ "\u203A"
1980
+ ) : /* @__PURE__ */ React8__namespace.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" })), /* @__PURE__ */ React8__namespace.createElement(
1981
+ "div",
1982
+ {
1983
+ className: "grid gap-1 text-xs text-muted-foreground",
1984
+ style: dayGridStyle
1985
+ },
1986
+ ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React8__namespace.createElement(
1987
+ "div",
1988
+ {
1989
+ key: `${month}-${day}`,
1990
+ className: "flex items-center justify-center h-8 w-8 font-medium"
1991
+ },
1992
+ day
1993
+ ))
1994
+ ), /* @__PURE__ */ React8__namespace.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
1939
1995
  if (!date) {
1940
- return /* @__PURE__ */ React7__namespace.createElement("div", { key: `empty-${index}` });
1996
+ return /* @__PURE__ */ React8__namespace.createElement("div", { key: `empty-${month}-${index}`, className: "h-8 w-8" });
1941
1997
  }
1942
1998
  const isStart = rangeStart && date.toDateString() === rangeStart.toDateString();
1943
1999
  const isEnd = rangeEnd && date.toDateString() === rangeEnd.toDateString();
2000
+ const isRangeEndpoint = Boolean(isStart || isEnd);
1944
2001
  const isInRange = rangeStart && rangeEnd && isDateInRange(date, rangeStart, rangeEnd);
1945
2002
  const isInHoverRange = rangeStart && !rangeEnd && hoverDate && (date >= rangeStart && date <= hoverDate || date <= rangeStart && date >= hoverDate);
2003
+ const isRangeHighlight = Boolean(
2004
+ (isInRange || isInHoverRange) && !isRangeEndpoint
2005
+ );
1946
2006
  const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
1947
2007
  const disabled2 = isDisabled(date);
1948
- return /* @__PURE__ */ React7__namespace.createElement(
2008
+ return /* @__PURE__ */ React8__namespace.createElement(
1949
2009
  "button",
1950
2010
  {
1951
2011
  key: date.toISOString(),
1952
2012
  type: "button",
1953
- className: `flex items-center justify-center h-8 w-full rounded border-none bg-transparent cursor-pointer text-sm transition-colors hover:bg-accent hover:text-accent-foreground ${isStart || isEnd ? "bg-primary text-primary-foreground font-semibold" : ""} ${isInRange || isInHoverRange ? "bg-accent/50" : ""} ${isToday ? "border border-primary" : ""} ${disabled2 ? "cursor-not-allowed opacity-50 pointer-events-none" : ""}`,
2013
+ className: cn(
2014
+ "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent cursor-pointer text-sm transition-colors",
2015
+ "hover:bg-muted",
2016
+ isRangeEndpoint && "bg-primary text-primary-foreground font-semibold",
2017
+ isRangeHighlight && "bg-muted",
2018
+ !isRangeEndpoint && !isRangeHighlight && isToday && "border border-primary",
2019
+ disabled2 && "cursor-not-allowed opacity-50 pointer-events-none"
2020
+ ),
1954
2021
  onClick: () => !disabled2 && handleDateSelect(date),
1955
2022
  onMouseEnter: () => setHoverDate(date),
1956
2023
  onMouseLeave: () => setHoverDate(null),
@@ -1961,41 +2028,57 @@ function DateRangePicker({
1961
2028
  );
1962
2029
  })));
1963
2030
  };
1964
- const combinedClassName = `relative ${className}`.trim();
2031
+ const combinedClassName = cn("relative", className);
1965
2032
  const displayValue = rangeStart && rangeEnd ? `${formatDate2(rangeStart, format)}${separator}${formatDate2(rangeEnd, format)}` : rangeStart ? formatDate2(rangeStart, format) : "";
1966
- return /* @__PURE__ */ React7__namespace.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React7__namespace.createElement(
2033
+ return /* @__PURE__ */ React8__namespace.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React8__namespace.createElement(
1967
2034
  "input",
1968
2035
  {
1969
2036
  type: "hidden",
1970
2037
  name: `${name}[start]`,
1971
2038
  value: rangeStart ? rangeStart.toISOString() : ""
1972
2039
  }
1973
- ), /* @__PURE__ */ React7__namespace.createElement(
2040
+ ), /* @__PURE__ */ React8__namespace.createElement(
1974
2041
  "input",
1975
2042
  {
1976
2043
  type: "hidden",
1977
2044
  name: `${name}[end]`,
1978
2045
  value: rangeEnd ? rangeEnd.toISOString() : ""
1979
2046
  }
1980
- ), /* @__PURE__ */ React7__namespace.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React7__namespace.createElement("span", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none", "aria-hidden": "true" }, /* @__PURE__ */ React7__namespace.createElement(
1981
- "svg",
2047
+ ), /* @__PURE__ */ React8__namespace.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8__namespace.createElement(
2048
+ "span",
1982
2049
  {
1983
- xmlns: "http://www.w3.org/2000/svg",
1984
- width: "18",
1985
- height: "18",
1986
- viewBox: "0 0 24 24",
1987
- fill: "none",
1988
- stroke: "currentColor",
1989
- strokeLinecap: "round",
1990
- strokeLinejoin: "round",
1991
- strokeWidth: "2"
2050
+ className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
2051
+ "aria-hidden": "true"
1992
2052
  },
1993
- /* @__PURE__ */ React7__namespace.createElement("path", { d: "M8 2v4m8-4v4m5 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8M3 10h18m-5 10l2 2l4-4" })
1994
- )), /* @__PURE__ */ React7__namespace.createElement(
2053
+ /* @__PURE__ */ React8__namespace.createElement(
2054
+ "svg",
2055
+ {
2056
+ xmlns: "http://www.w3.org/2000/svg",
2057
+ width: "18",
2058
+ height: "18",
2059
+ viewBox: "0 0 24 24",
2060
+ fill: "none",
2061
+ stroke: "currentColor",
2062
+ strokeLinecap: "round",
2063
+ strokeLinejoin: "round",
2064
+ strokeWidth: "2"
2065
+ },
2066
+ /* @__PURE__ */ React8__namespace.createElement("path", { d: "M8 2v4m8-4v4m5 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8M3 10h18m-5 10l2 2l4-4" })
2067
+ )
2068
+ ), /* @__PURE__ */ React8__namespace.createElement(
1995
2069
  "input",
1996
2070
  {
1997
2071
  type: "text",
1998
- className: `flex h-9 w-full rounded-md border border-input bg-transparent ${showIcon ? "pl-10" : "pl-3"} ${clearable && (rangeStart || rangeEnd) ? "pr-10" : "pr-3"} py-1 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm ${error ? "border-red-500 ring-1 ring-red-500" : ""}`,
2072
+ className: cn(
2073
+ "flex h-9 w-full rounded-md border border-input bg-transparent py-1 text-base shadow-sm transition-colors",
2074
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
2075
+ "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
2076
+ INPUT_AUTOFILL_RESET_CLASSES,
2077
+ showIcon ? "pl-10" : "pl-3",
2078
+ clearable && (rangeStart || rangeEnd) ? "pr-10" : "pr-3",
2079
+ !error && hasValue && "ring-2 ring-ring",
2080
+ error && "border-destructive ring-1 ring-destructive"
2081
+ ),
1999
2082
  value: displayValue,
2000
2083
  onClick: handleToggle,
2001
2084
  onBlur,
@@ -2007,17 +2090,17 @@ function DateRangePicker({
2007
2090
  "aria-required": required || props["aria-required"],
2008
2091
  readOnly: true
2009
2092
  }
2010
- ), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */ React7__namespace.createElement(
2093
+ ), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */ React8__namespace.createElement(
2011
2094
  "button",
2012
2095
  {
2013
2096
  type: "button",
2014
- className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors",
2097
+ className: "absolute right-3 top-1/2 -translate-y-1/2 transition-colors",
2015
2098
  onClick: handleClear,
2016
2099
  "aria-label": "Clear date range",
2017
2100
  tabIndex: -1
2018
2101
  },
2019
2102
  "\u2715"
2020
- )), isOpen && !disabled && /* @__PURE__ */ React7__namespace.createElement("div", { className: "absolute z-50 top-full mt-1 min-w-full rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3" }, renderCalendar(), rangeStart && !rangeEnd && /* @__PURE__ */ React7__namespace.createElement("div", { className: "text-xs text-muted-foreground text-center pt-2 border-t border-border mt-2" }, "Select end date")));
2103
+ )), isOpen && !disabled && /* @__PURE__ */ React8__namespace.createElement("div", { className: "absolute z-50 top-full mt-1 w-fit rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3" }, /* @__PURE__ */ React8__namespace.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React8__namespace.createElement("div", { className: "grid gap-4", style: monthsGridStyle }, renderMonth(selectedMonth, { prev: true }), renderMonth(addMonths(selectedMonth, 1), { next: true }))), rangeStart && !rangeEnd && /* @__PURE__ */ React8__namespace.createElement("div", { className: "text-xs text-center pt-2 border-t border-border mt-2" }, "Select end date")));
2021
2104
  }
2022
2105
  DateRangePicker.displayName = "DateRangePicker";
2023
2106
  function htmlToMarkdown(html) {
@@ -2073,18 +2156,26 @@ function RichTextEditor({
2073
2156
  className = "",
2074
2157
  mode = "wysiwyg",
2075
2158
  allowModeSwitch = false,
2076
- placeholder = "Start typing...",
2159
+ placeholder = "Your message...",
2077
2160
  minHeight = "200px",
2078
2161
  maxHeight,
2079
2162
  showToolbar = true,
2080
- toolbarButtons = ["bold", "italic", "underline", "heading", "bulletList", "orderedList", "link"],
2163
+ toolbarButtons = [
2164
+ "bold",
2165
+ "italic",
2166
+ "underline",
2167
+ "heading",
2168
+ "bulletList",
2169
+ "orderedList",
2170
+ "link"
2171
+ ],
2081
2172
  ...props
2082
2173
  }) {
2083
- const [currentMode, setCurrentMode] = React7__namespace.useState(mode);
2084
- const [content, setContent] = React7__namespace.useState(value);
2085
- const editorRef = React7__namespace.useRef(null);
2086
- const textareaRef = React7__namespace.useRef(null);
2087
- React7__namespace.useEffect(() => {
2174
+ const [currentMode, setCurrentMode] = React8__namespace.useState(mode);
2175
+ const [content, setContent] = React8__namespace.useState(value);
2176
+ const editorRef = React8__namespace.useRef(null);
2177
+ const textareaRef = React8__namespace.useRef(null);
2178
+ React8__namespace.useEffect(() => {
2088
2179
  setContent(value);
2089
2180
  if (currentMode === "wysiwyg" && editorRef.current) {
2090
2181
  editorRef.current.innerHTML = value;
@@ -2172,21 +2263,32 @@ function RichTextEditor({
2172
2263
  }
2173
2264
  }
2174
2265
  };
2175
- const combinedClassName = `rounded-md border border-input ${error ? "border-red-500 ring-1 ring-red-500" : ""} ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className}`.trim();
2266
+ const hasValue = React8__namespace.useMemo(() => {
2267
+ if (!content) return false;
2268
+ const stripped = content.replace(/<[^>]+>/g, "").trim();
2269
+ return stripped.length > 0;
2270
+ }, [content]);
2271
+ const combinedClassName = cn(
2272
+ "rounded-md border border-input",
2273
+ !error && hasValue && "ring-2 ring-ring",
2274
+ error && "border-destructive ring-1 ring-destructive",
2275
+ disabled && "opacity-50 cursor-not-allowed",
2276
+ className
2277
+ );
2176
2278
  const editorStyle = {
2177
2279
  minHeight,
2178
2280
  maxHeight,
2179
2281
  overflowY: maxHeight ? "auto" : void 0
2180
2282
  };
2181
- return /* @__PURE__ */ React7__namespace.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React7__namespace.createElement("input", { type: "hidden", name, value: content }), showToolbar && /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center justify-between p-2 border-b border-border bg-muted/50" }, /* @__PURE__ */ React7__namespace.createElement("div", { className: "flex items-center gap-1" }, toolbarButtons.map((buttonName) => {
2283
+ return /* @__PURE__ */ React8__namespace.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React8__namespace.createElement("input", { type: "hidden", name, value: content }), showToolbar && /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center justify-between p-2 border-b border-border bg-muted/50" }, /* @__PURE__ */ React8__namespace.createElement("div", { className: "flex items-center gap-1" }, toolbarButtons.map((buttonName) => {
2182
2284
  const button = toolbarConfig[buttonName];
2183
2285
  if (!button) return null;
2184
- return /* @__PURE__ */ React7__namespace.createElement(
2286
+ return /* @__PURE__ */ React8__namespace.createElement(
2185
2287
  "button",
2186
2288
  {
2187
2289
  key: buttonName,
2188
2290
  type: "button",
2189
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-accent text-muted-foreground hover:text-foreground cursor-pointer transition-colors disabled:cursor-not-allowed disabled:opacity-50",
2291
+ className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-muted cursor-pointer transition-colors disabled:cursor-not-allowed disabled:opacity-50",
2190
2292
  onClick: () => editorRef.current && button.action(editorRef.current),
2191
2293
  title: button.title,
2192
2294
  disabled: disabled || currentMode === "markdown",
@@ -2194,22 +2296,22 @@ function RichTextEditor({
2194
2296
  },
2195
2297
  button.icon
2196
2298
  );
2197
- })), allowModeSwitch && /* @__PURE__ */ React7__namespace.createElement(
2299
+ })), allowModeSwitch && /* @__PURE__ */ React8__namespace.createElement(
2198
2300
  "button",
2199
2301
  {
2200
2302
  type: "button",
2201
- className: "flex items-center justify-center h-8 px-3 rounded border-none bg-transparent hover:bg-accent text-xs font-medium text-muted-foreground hover:text-foreground cursor-pointer transition-colors disabled:cursor-not-allowed disabled:opacity-50",
2303
+ className: "flex items-center justify-center h-8 px-3 rounded border-none bg-transparent hover:bg-muted text-xs font-medium cursor-pointer transition-colors disabled:cursor-not-allowed disabled:opacity-50",
2202
2304
  onClick: handleModeToggle,
2203
2305
  disabled,
2204
2306
  title: `Switch to ${currentMode === "wysiwyg" ? "Markdown" : "WYSIWYG"}`,
2205
2307
  "aria-label": `Switch to ${currentMode === "wysiwyg" ? "Markdown" : "WYSIWYG"}`
2206
2308
  },
2207
2309
  currentMode === "wysiwyg" ? "MD" : "WYSIWYG"
2208
- )), /* @__PURE__ */ React7__namespace.createElement("div", { style: editorStyle }, currentMode === "wysiwyg" ? /* @__PURE__ */ React7__namespace.createElement(
2310
+ )), /* @__PURE__ */ React8__namespace.createElement("div", { style: editorStyle }, currentMode === "wysiwyg" ? /* @__PURE__ */ React8__namespace.createElement(
2209
2311
  "div",
2210
2312
  {
2211
2313
  ref: editorRef,
2212
- className: "w-full p-3 text-base md:text-sm outline-none bg-transparent focus-visible:outline-none [&:empty:before]:content-[attr(data-placeholder)] [&:empty:before]:text-muted-foreground",
2314
+ className: "w-full p-3 text-base md:text-sm outline-none bg-transparent focus-visible:outline-none [&:empty:before]:content-[attr(data-placeholder)]",
2213
2315
  role: "textbox",
2214
2316
  contentEditable: !disabled,
2215
2317
  onInput: handleWysiwygChange,
@@ -2220,11 +2322,14 @@ function RichTextEditor({
2220
2322
  "aria-required": required || props["aria-required"],
2221
2323
  suppressContentEditableWarning: true
2222
2324
  }
2223
- ) : /* @__PURE__ */ React7__namespace.createElement(
2325
+ ) : /* @__PURE__ */ React8__namespace.createElement(
2224
2326
  "textarea",
2225
2327
  {
2226
2328
  ref: textareaRef,
2227
- className: "w-full p-3 text-base md:text-sm outline-none bg-transparent resize-none focus-visible:outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
2329
+ className: cn(
2330
+ "w-full p-3 text-base md:text-sm outline-none bg-transparent resize-none focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
2331
+ INPUT_AUTOFILL_RESET_CLASSES
2332
+ ),
2228
2333
  value: content,
2229
2334
  onChange: handleMarkdownChange,
2230
2335
  onBlur,