@page-speed/forms 0.4.3 → 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.js CHANGED
@@ -1,6 +1,13 @@
1
- import * as React7 from 'react';
1
+ import * as React8 from 'react';
2
2
  import { clsx } from 'clsx';
3
3
  import { twMerge } from 'tailwind-merge';
4
+ import { useOnClickOutside } from '@opensite/hooks/useOnClickOutside';
5
+
6
+ // src/inputs/TextInput.tsx
7
+ function cn(...inputs) {
8
+ return twMerge(clsx(inputs));
9
+ }
10
+ 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]";
4
11
 
5
12
  // src/inputs/TextInput.tsx
6
13
  function TextInput({
@@ -23,10 +30,17 @@ function TextInput({
23
30
  const handleBlur = () => {
24
31
  onBlur?.();
25
32
  };
26
- const baseClassName = "flex h-9 w-full rounded-md border border-input bg-transparent px-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";
27
- const errorClassName = error ? "border-red-500 ring-1 ring-red-500" : "";
28
- const combinedClassName = `${baseClassName} ${errorClassName} ${className}`.trim();
29
- return /* @__PURE__ */ React7.createElement(
33
+ const hasValue = String(value ?? "").trim().length > 0;
34
+ const combinedClassName = cn(
35
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors",
36
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
37
+ "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
38
+ INPUT_AUTOFILL_RESET_CLASSES,
39
+ !error && hasValue && "ring-2 ring-ring",
40
+ error && "border-destructive ring-1 ring-destructive",
41
+ className
42
+ );
43
+ return /* @__PURE__ */ React8.createElement(
30
44
  "input",
31
45
  {
32
46
  type,
@@ -70,10 +84,17 @@ function TextArea({
70
84
  const handleBlur = () => {
71
85
  onBlur?.();
72
86
  };
73
- 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 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm";
74
- const errorClassName = error ? "border-red-500 ring-1 ring-red-500" : "";
75
- const combinedClassName = `${baseClassName} ${errorClassName} ${className}`.trim();
76
- return /* @__PURE__ */ React7.createElement(
87
+ const hasValue = String(value ?? "").trim().length > 0;
88
+ const combinedClassName = cn(
89
+ "flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm transition-colors",
90
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
91
+ "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
92
+ INPUT_AUTOFILL_RESET_CLASSES,
93
+ !error && hasValue && "ring-2 ring-ring",
94
+ error && "border-destructive ring-1 ring-destructive",
95
+ className
96
+ );
97
+ return /* @__PURE__ */ React8.createElement(
77
98
  "textarea",
78
99
  {
79
100
  name,
@@ -97,9 +118,53 @@ function TextArea({
97
118
  );
98
119
  }
99
120
  TextArea.displayName = "TextArea";
100
- function cn(...inputs) {
101
- return twMerge(clsx(inputs));
102
- }
121
+ var LabelGroup = ({
122
+ labelHtmlFor,
123
+ required = false,
124
+ variant = "label",
125
+ secondaryId,
126
+ secondary,
127
+ primary,
128
+ primaryClassName,
129
+ secondaryClassName
130
+ }) => {
131
+ const primaryClasses = cn(
132
+ "text-sm font-medium leading-snug",
133
+ variant === "legend" ? "mb-1.5" : "mb-1 block",
134
+ primaryClassName
135
+ );
136
+ const requiredIndicator = required ? /* @__PURE__ */ React8.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
137
+ let primaryElement = null;
138
+ if (primary) {
139
+ if (variant === "label") {
140
+ primaryElement = /* @__PURE__ */ React8.createElement(
141
+ "label",
142
+ {
143
+ htmlFor: labelHtmlFor,
144
+ "data-slot": "field-label",
145
+ className: primaryClasses
146
+ },
147
+ primary,
148
+ requiredIndicator
149
+ );
150
+ } else if (variant === "legend") {
151
+ primaryElement = /* @__PURE__ */ React8.createElement("legend", { "data-slot": "field-legend", className: primaryClasses }, primary, requiredIndicator);
152
+ } else {
153
+ primaryElement = /* @__PURE__ */ React8.createElement("div", { "data-slot": "field-label", className: primaryClasses }, primary, requiredIndicator);
154
+ }
155
+ }
156
+ const secondaryElement = secondary ? /* @__PURE__ */ React8.createElement(
157
+ "p",
158
+ {
159
+ "data-slot": "field-description",
160
+ id: secondaryId,
161
+ className: cn("text-sm leading-normal font-normal", secondaryClassName)
162
+ },
163
+ secondary
164
+ ) : null;
165
+ if (!primaryElement && !secondaryElement) return null;
166
+ return /* @__PURE__ */ React8.createElement(React8.Fragment, null, primaryElement, secondaryElement);
167
+ };
103
168
 
104
169
  // src/inputs/Checkbox.tsx
105
170
  function Checkbox({
@@ -114,12 +179,12 @@ function Checkbox({
114
179
  indeterminate = false,
115
180
  label,
116
181
  description,
117
- checkboxVariant = "boxed",
182
+ useChoiceCard = false,
118
183
  ...props
119
184
  }) {
120
- const inputRef = React7.useRef(null);
185
+ const inputRef = React8.useRef(null);
121
186
  const checkboxId = props.id || `checkbox-${name}`;
122
- React7.useEffect(() => {
187
+ React8.useEffect(() => {
123
188
  if (inputRef.current) {
124
189
  inputRef.current.indeterminate = indeterminate;
125
190
  }
@@ -131,7 +196,7 @@ function Checkbox({
131
196
  onBlur?.();
132
197
  };
133
198
  const isActive = value || indeterminate && !value;
134
- const checkbox = /* @__PURE__ */ React7.createElement(
199
+ const checkbox = /* @__PURE__ */ React8.createElement(
135
200
  "div",
136
201
  {
137
202
  className: cn(
@@ -139,7 +204,7 @@ function Checkbox({
139
204
  !label && className
140
205
  )
141
206
  },
142
- /* @__PURE__ */ React7.createElement(
207
+ /* @__PURE__ */ React8.createElement(
143
208
  "input",
144
209
  {
145
210
  ref: inputRef,
@@ -158,7 +223,7 @@ function Checkbox({
158
223
  ...props
159
224
  }
160
225
  ),
161
- /* @__PURE__ */ React7.createElement(
226
+ /* @__PURE__ */ React8.createElement(
162
227
  "div",
163
228
  {
164
229
  className: cn(
@@ -171,7 +236,7 @@ function Checkbox({
171
236
  "peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-1"
172
237
  )
173
238
  },
174
- value && /* @__PURE__ */ React7.createElement(
239
+ value && /* @__PURE__ */ React8.createElement(
175
240
  "svg",
176
241
  {
177
242
  className: "size-3.5",
@@ -182,9 +247,9 @@ function Checkbox({
182
247
  strokeLinecap: "round",
183
248
  strokeLinejoin: "round"
184
249
  },
185
- /* @__PURE__ */ React7.createElement("polyline", { points: "20 6 9 17 4 12" })
250
+ /* @__PURE__ */ React8.createElement("polyline", { points: "20 6 9 17 4 12" })
186
251
  ),
187
- indeterminate && !value && /* @__PURE__ */ React7.createElement(
252
+ indeterminate && !value && /* @__PURE__ */ React8.createElement(
188
253
  "svg",
189
254
  {
190
255
  className: "size-3.5",
@@ -195,31 +260,44 @@ function Checkbox({
195
260
  strokeLinecap: "round",
196
261
  strokeLinejoin: "round"
197
262
  },
198
- /* @__PURE__ */ React7.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
263
+ /* @__PURE__ */ React8.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
199
264
  )
200
265
  )
201
266
  );
202
267
  if (label) {
203
- return /* @__PURE__ */ React7.createElement(
268
+ return /* @__PURE__ */ React8.createElement(
204
269
  "label",
205
270
  {
206
271
  className: cn(
207
272
  "w-full h-full flex gap-3 p-3 duration-200",
208
- checkboxVariant === "boxed" && "border rounded-lg hover:ring-2",
209
- checkboxVariant === "boxed" && value && "ring-2",
273
+ useChoiceCard && "border rounded-lg hover:ring-2",
274
+ useChoiceCard && value && "ring-2",
210
275
  disabled ? "opacity-50 cursor-not-allowed hover:ring-0" : "cursor-pointer",
211
276
  className
212
277
  ),
213
278
  htmlFor: checkboxId
214
279
  },
215
- /* @__PURE__ */ React7.createElement("div", { className: "flex w-full flex-row gap-2" }, checkbox, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col gap-0.5" }, /* @__PURE__ */ React7.createElement("div", { className: "text-sm font-medium" }, label), description && /* @__PURE__ */ React7.createElement(
216
- "p",
280
+ /* @__PURE__ */ React8.createElement(
281
+ "div",
217
282
  {
218
- className: "text-xs opacity-75",
219
- id: `${checkboxId}-description`
283
+ className: cn(
284
+ "flex w-full flex-row gap-2",
285
+ useChoiceCard ? "items-start" : "items-center"
286
+ )
220
287
  },
221
- description
222
- )))
288
+ checkbox,
289
+ /* @__PURE__ */ React8.createElement(
290
+ LabelGroup,
291
+ {
292
+ variant: "text",
293
+ primary: label,
294
+ secondary: description,
295
+ secondaryId: description ? `${checkboxId}-description` : void 0,
296
+ primaryClassName: "mb-0",
297
+ secondaryClassName: "text-xs opacity-75"
298
+ }
299
+ )
300
+ )
223
301
  );
224
302
  }
225
303
  return checkbox;
@@ -253,13 +331,11 @@ function CheckboxGroup({
253
331
  ).length;
254
332
  const allSelected = selectedEnabledCount === enabledOptions.length;
255
333
  const someSelected = selectedEnabledCount > 0 && !allSelected;
256
- const checkboxVariant = React7.useMemo(() => {
257
- if (options.some((opt) => opt.description)) {
258
- return "boxed";
259
- }
260
- return "inline";
334
+ const useChoiceCard = React8.useMemo(() => {
335
+ if (!options) return false;
336
+ return options?.some((opt) => opt.description);
261
337
  }, [options]);
262
- const countableValue = React7.useMemo(() => {
338
+ const countableValue = React8.useMemo(() => {
263
339
  if (value?.length > 0) {
264
340
  return value.length;
265
341
  }
@@ -284,29 +360,37 @@ function CheckboxGroup({
284
360
  onBlur?.();
285
361
  };
286
362
  const maxReached = Boolean(maxSelections && countableValue >= maxSelections);
287
- const containerClass = cn(
288
- "w-full gap-3",
289
- layout === "stacked" && "flex flex-col",
290
- layout === "inline" && "flex flex-row flex-wrap",
291
- layout === "grid" && "grid",
292
- className
293
- );
294
- return /* @__PURE__ */ React7.createElement(
295
- "div",
363
+ const containerClass = React8.useMemo(() => {
364
+ return cn(
365
+ "w-full gap-3 grid grid-cols-1 border-0 m-0 p-0 min-w-0",
366
+ (layout === "grid" || layout === "inline") && "md:grid-cols-2",
367
+ className
368
+ );
369
+ }, [layout, className]);
370
+ const groupDescriptionId = description ? `${name}-description` : void 0;
371
+ const groupAriaDescribedBy = [props["aria-describedby"], groupDescriptionId].filter(Boolean).join(" ") || void 0;
372
+ return /* @__PURE__ */ React8.createElement(
373
+ "fieldset",
296
374
  {
297
375
  className: containerClass,
298
376
  role: "group",
299
377
  "aria-invalid": error || props["aria-invalid"],
300
- "aria-describedby": props["aria-describedby"],
378
+ "aria-describedby": groupAriaDescribedBy,
301
379
  "aria-required": required || props["aria-required"],
302
- "aria-label": typeof label === "string" ? label : props["aria-label"],
303
- style: layout === "grid" ? {
304
- gridTemplateColumns: `repeat(${gridColumns}, 1fr)`
305
- } : void 0
380
+ "aria-label": typeof label === "string" ? label : props["aria-label"]
306
381
  },
307
- label ? /* @__PURE__ */ React7.createElement("div", { className: "text-sm font-medium" }, label) : null,
308
- description ? /* @__PURE__ */ React7.createElement("div", { className: "text-xs opacity-70" }, description) : null,
309
- showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */ React7.createElement(
382
+ /* @__PURE__ */ React8.createElement(
383
+ LabelGroup,
384
+ {
385
+ labelHtmlFor: name,
386
+ required,
387
+ variant: "legend",
388
+ secondaryId: groupDescriptionId,
389
+ secondary: description,
390
+ primary: label
391
+ }
392
+ ),
393
+ showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */ React8.createElement(
310
394
  Checkbox,
311
395
  {
312
396
  name: `${name}-select-all`,
@@ -316,7 +400,7 @@ function CheckboxGroup({
316
400
  onBlur: handleBlur,
317
401
  indeterminate: someSelected,
318
402
  label: selectAllLabel,
319
- checkboxVariant: "inline",
403
+ useChoiceCard,
320
404
  disabled,
321
405
  "aria-label": selectAllLabel
322
406
  }
@@ -324,7 +408,7 @@ function CheckboxGroup({
324
408
  options.map((option) => {
325
409
  const isChecked = value.includes(option.value);
326
410
  const isDisabled = disabled || option.disabled || maxReached && !isChecked;
327
- return /* @__PURE__ */ React7.createElement(
411
+ return /* @__PURE__ */ React8.createElement(
328
412
  Checkbox,
329
413
  {
330
414
  key: option.value,
@@ -338,11 +422,11 @@ function CheckboxGroup({
338
422
  error,
339
423
  label: renderOption ? renderOption(option) : option.label,
340
424
  description: renderOption ? void 0 : option.description,
341
- checkboxVariant
425
+ useChoiceCard
342
426
  }
343
427
  );
344
428
  }),
345
- (minSelections || maxSelections) && /* @__PURE__ */ React7.createElement(
429
+ (minSelections || maxSelections) && /* @__PURE__ */ React8.createElement(
346
430
  "div",
347
431
  {
348
432
  className: cn(
@@ -351,8 +435,8 @@ function CheckboxGroup({
351
435
  ),
352
436
  "aria-live": "polite"
353
437
  },
354
- minSelections && countableValue < minSelections && /* @__PURE__ */ React7.createElement("span", null, "Select at least ", minSelections, " option", minSelections !== 1 ? "s" : ""),
355
- maxSelections && /* @__PURE__ */ React7.createElement("span", null, countableValue, "/", maxSelections, " selected")
438
+ minSelections && countableValue < minSelections && /* @__PURE__ */ React8.createElement("span", null, "Select at least ", minSelections, " option", minSelections !== 1 ? "s" : ""),
439
+ maxSelections && /* @__PURE__ */ React8.createElement("span", null, countableValue, "/", maxSelections, " selected")
356
440
  )
357
441
  );
358
442
  }
@@ -368,6 +452,7 @@ function Radio({
368
452
  className = "",
369
453
  layout = "stacked",
370
454
  label,
455
+ description,
371
456
  options,
372
457
  ...props
373
458
  }) {
@@ -402,33 +487,43 @@ function Radio({
402
487
  const handleBlur = () => {
403
488
  onBlur?.();
404
489
  };
405
- const useChoiceCard = React7.useMemo(() => {
490
+ const useChoiceCard = React8.useMemo(() => {
406
491
  return options.some((option) => option.description);
407
492
  }, [options]);
408
- const containerClass = React7.useMemo(() => {
493
+ const containerClass = React8.useMemo(() => {
409
494
  return cn(
410
- "w-full gap-3 grid grid-cols-1",
411
- layout === "inline" && "md:grid-cols-2",
495
+ "w-full gap-3 grid grid-cols-1 border-0 m-0 p-0 min-w-0",
496
+ (layout === "grid" || layout === "inline") && "md:grid-cols-2",
412
497
  className
413
498
  );
414
499
  }, [layout, className]);
415
- return /* @__PURE__ */ React7.createElement(
416
- "div",
500
+ const groupDescriptionId = description ? `${name}-description` : void 0;
501
+ const groupAriaDescribedBy = [props["aria-describedby"], groupDescriptionId].filter(Boolean).join(" ") || void 0;
502
+ return /* @__PURE__ */ React8.createElement(
503
+ "fieldset",
417
504
  {
418
505
  className: containerClass,
419
506
  role: "radiogroup",
420
507
  "aria-invalid": error || props["aria-invalid"],
421
- "aria-describedby": props["aria-describedby"],
508
+ "aria-describedby": groupAriaDescribedBy,
422
509
  "aria-required": required || props["aria-required"],
423
510
  "aria-label": typeof label === "string" ? label : props["aria-label"]
424
511
  },
425
- label && /* @__PURE__ */ React7.createElement("div", { className: "text-sm font-medium mb-2" }, label),
512
+ /* @__PURE__ */ React8.createElement(
513
+ LabelGroup,
514
+ {
515
+ variant: "legend",
516
+ primary: label,
517
+ secondary: description,
518
+ secondaryId: groupDescriptionId
519
+ }
520
+ ),
426
521
  options.map((option, index) => {
427
522
  const isChecked = value === option.value;
428
523
  const isDisabled = disabled || option.disabled;
429
524
  const radioId = `${name}-${option.value}`;
430
525
  const hasDescription = option.description != null && option.description !== "";
431
- const radioIndicator = /* @__PURE__ */ React7.createElement("div", { className: "relative inline-flex items-center justify-center" }, /* @__PURE__ */ React7.createElement(
526
+ const radioIndicator = /* @__PURE__ */ React8.createElement("div", { className: "relative inline-flex items-center justify-center" }, /* @__PURE__ */ React8.createElement(
432
527
  "input",
433
528
  {
434
529
  type: "radio",
@@ -443,7 +538,7 @@ function Radio({
443
538
  className: "peer sr-only",
444
539
  "aria-describedby": hasDescription ? `${radioId}-description` : props["aria-describedby"]
445
540
  }
446
- ), /* @__PURE__ */ React7.createElement(
541
+ ), /* @__PURE__ */ React8.createElement(
447
542
  "div",
448
543
  {
449
544
  className: cn(
@@ -456,10 +551,20 @@ function Radio({
456
551
  "peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-1"
457
552
  )
458
553
  },
459
- isChecked && /* @__PURE__ */ React7.createElement("div", { className: "size-3 rounded-full bg-primary" })
554
+ isChecked && /* @__PURE__ */ React8.createElement("div", { className: "size-3 rounded-full bg-primary" })
460
555
  ));
461
- const labelContent = /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col gap-0.5" }, /* @__PURE__ */ React7.createElement("div", { className: "text-sm font-medium" }, option.label), hasDescription && /* @__PURE__ */ React7.createElement("p", { className: "text-xs opacity-75", id: `${radioId}-description` }, option.description));
462
- return /* @__PURE__ */ React7.createElement(
556
+ const labelContent = /* @__PURE__ */ React8.createElement(
557
+ LabelGroup,
558
+ {
559
+ variant: "text",
560
+ primary: option.label,
561
+ secondary: hasDescription ? option.description : void 0,
562
+ secondaryId: hasDescription ? `${radioId}-description` : void 0,
563
+ primaryClassName: "mb-0",
564
+ secondaryClassName: "text-xs opacity-75"
565
+ }
566
+ );
567
+ return /* @__PURE__ */ React8.createElement(
463
568
  "label",
464
569
  {
465
570
  key: option.value,
@@ -473,7 +578,18 @@ function Radio({
473
578
  onKeyDown: (e) => handleKeyDown(e, index),
474
579
  tabIndex: isDisabled ? -1 : 0
475
580
  },
476
- /* @__PURE__ */ React7.createElement("div", { className: "flex w-full flex-row items-center gap-2" }, !useChoiceCard && radioIndicator, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-1 flex-col gap-0.5" }, labelContent), useChoiceCard && radioIndicator)
581
+ /* @__PURE__ */ React8.createElement(
582
+ "div",
583
+ {
584
+ className: cn(
585
+ "flex w-full flex-row gap-2",
586
+ useChoiceCard ? "items-start" : "items-center"
587
+ )
588
+ },
589
+ !useChoiceCard && radioIndicator,
590
+ /* @__PURE__ */ React8.createElement("div", { className: "flex flex-1 flex-col gap-0.5" }, labelContent),
591
+ useChoiceCard && radioIndicator
592
+ )
477
593
  );
478
594
  })
479
595
  );
@@ -498,19 +614,19 @@ function Select({
498
614
  renderOption,
499
615
  ...props
500
616
  }) {
501
- const [isOpen, setIsOpen] = React7.useState(false);
502
- const [searchQuery, setSearchQuery] = React7.useState("");
503
- const [focusedIndex, setFocusedIndex] = React7.useState(-1);
504
- const selectRef = React7.useRef(null);
505
- const searchInputRef = React7.useRef(null);
617
+ const [isOpen, setIsOpen] = React8.useState(false);
618
+ const [searchQuery, setSearchQuery] = React8.useState("");
619
+ const [focusedIndex, setFocusedIndex] = React8.useState(-1);
620
+ const selectRef = React8.useRef(null);
621
+ const searchInputRef = React8.useRef(null);
506
622
  const dropdownId = `${name}-dropdown`;
507
- const allOptions = React7.useMemo(() => {
623
+ const allOptions = React8.useMemo(() => {
508
624
  if (optionGroups.length > 0) {
509
625
  return optionGroups.flatMap((group) => group.options);
510
626
  }
511
627
  return options;
512
628
  }, [options, optionGroups]);
513
- const filteredOptions = React7.useMemo(() => {
629
+ const filteredOptions = React8.useMemo(() => {
514
630
  if (!searchQuery.trim()) {
515
631
  return allOptions;
516
632
  }
@@ -520,9 +636,10 @@ function Select({
520
636
  return label.toLowerCase().includes(query);
521
637
  });
522
638
  }, [allOptions, searchQuery]);
523
- const selectedOption = React7.useMemo(() => {
639
+ const selectedOption = React8.useMemo(() => {
524
640
  return allOptions.find((opt) => opt.value === value);
525
641
  }, [allOptions, value]);
642
+ const hasValue = Boolean(value);
526
643
  const handleSelect = (optionValue) => {
527
644
  onChange(optionValue);
528
645
  setIsOpen(false);
@@ -617,27 +734,22 @@ function Select({
617
734
  break;
618
735
  }
619
736
  };
620
- const handleBlur = () => {
621
- onBlur?.();
622
- };
623
- React7.useEffect(() => {
624
- const handleClickOutside = (event) => {
625
- if (selectRef.current && !selectRef.current.contains(event.target)) {
626
- setIsOpen(false);
627
- setSearchQuery("");
628
- setFocusedIndex(-1);
629
- handleBlur();
630
- }
631
- };
632
- if (isOpen) {
633
- document.addEventListener("mousedown", handleClickOutside);
634
- return () => {
635
- document.removeEventListener("mousedown", handleClickOutside);
636
- };
737
+ const handleBlur = (event) => {
738
+ const nextTarget = event?.relatedTarget;
739
+ if (!nextTarget || !selectRef.current?.contains(nextTarget)) {
740
+ onBlur?.();
637
741
  }
638
- }, [isOpen]);
639
- const combinedClassName = `relative w-full ${className}`.trim();
640
- return /* @__PURE__ */ React7.createElement(
742
+ };
743
+ const closeDropdown = React8.useCallback(() => {
744
+ if (!isOpen) return;
745
+ setIsOpen(false);
746
+ setSearchQuery("");
747
+ setFocusedIndex(-1);
748
+ onBlur?.();
749
+ }, [isOpen, onBlur]);
750
+ useOnClickOutside(selectRef, closeDropdown, "pointerdown", true);
751
+ const combinedClassName = cn("relative w-full", className);
752
+ return /* @__PURE__ */ React8.createElement(
641
753
  "div",
642
754
  {
643
755
  ref: selectRef,
@@ -645,7 +757,7 @@ function Select({
645
757
  onKeyDown: handleKeyDown,
646
758
  onBlur: handleBlur
647
759
  },
648
- /* @__PURE__ */ React7.createElement(
760
+ /* @__PURE__ */ React8.createElement(
649
761
  "select",
650
762
  {
651
763
  name,
@@ -658,13 +770,19 @@ function Select({
658
770
  tabIndex: -1,
659
771
  style: { display: "none" }
660
772
  },
661
- /* @__PURE__ */ React7.createElement("option", { value: "" }, "Select..."),
662
- allOptions.map((option) => /* @__PURE__ */ React7.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
773
+ /* @__PURE__ */ React8.createElement("option", { value: "" }, "Select..."),
774
+ allOptions.map((option) => /* @__PURE__ */ React8.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
663
775
  ),
664
- /* @__PURE__ */ React7.createElement(
776
+ /* @__PURE__ */ React8.createElement(
665
777
  "div",
666
778
  {
667
- 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-muted 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" : ""}`,
779
+ className: cn(
780
+ "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",
781
+ "cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
782
+ !error && hasValue && "ring-2 ring-ring",
783
+ disabled && "cursor-not-allowed opacity-50 pointer-events-none",
784
+ error && "border-destructive ring-1 ring-destructive"
785
+ ),
668
786
  onClick: handleToggle,
669
787
  role: "combobox",
670
788
  "aria-expanded": isOpen,
@@ -675,8 +793,8 @@ function Select({
675
793
  "aria-disabled": disabled,
676
794
  tabIndex: disabled ? -1 : 0
677
795
  },
678
- /* @__PURE__ */ React7.createElement("span", { className: "flex items-center flex-1 overflow-hidden text-ellipsis" }, selectedOption ? renderOption ? renderOption(selectedOption) : selectedOption.label : /* @__PURE__ */ React7.createElement("span", { className: "relative" }, placeholder)),
679
- /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-1 ml-2" }, loading && /* @__PURE__ */ React7.createElement("span", { className: "text-xs" }, "\u23F3"), clearable && value && !disabled && !loading && /* @__PURE__ */ React7.createElement(
796
+ /* @__PURE__ */ React8.createElement("span", { className: "flex items-center flex-1 overflow-hidden text-ellipsis" }, selectedOption ? renderOption ? renderOption(selectedOption) : selectedOption.label : /* @__PURE__ */ React8.createElement("span", { className: "relative" }, placeholder)),
797
+ /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-1 ml-2" }, loading && /* @__PURE__ */ React8.createElement("span", { className: "text-xs" }, "\u23F3"), clearable && value && !disabled && !loading && /* @__PURE__ */ React8.createElement(
680
798
  "button",
681
799
  {
682
800
  type: "button",
@@ -686,21 +804,24 @@ function Select({
686
804
  tabIndex: -1
687
805
  },
688
806
  "\u2715"
689
- ), /* @__PURE__ */ React7.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
807
+ ), /* @__PURE__ */ React8.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
690
808
  ),
691
- isOpen && /* @__PURE__ */ React7.createElement(
809
+ isOpen && /* @__PURE__ */ React8.createElement(
692
810
  "div",
693
811
  {
694
812
  id: dropdownId,
695
813
  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",
696
814
  role: "listbox"
697
815
  },
698
- searchable && /* @__PURE__ */ React7.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React7.createElement(
816
+ searchable && /* @__PURE__ */ React8.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React8.createElement(
699
817
  "input",
700
818
  {
701
819
  ref: searchInputRef,
702
820
  type: "text",
703
- className: "w-full border border-input rounded px-2 py-1 text-sm bg-transparent outline-none focus:ring-1 focus:ring-ring",
821
+ className: cn(
822
+ "w-full border border-input rounded px-2 py-1 text-sm bg-transparent outline-none focus:ring-1 focus:ring-ring",
823
+ INPUT_AUTOFILL_RESET_CLASSES
824
+ ),
704
825
  placeholder: "Search...",
705
826
  value: searchQuery,
706
827
  onChange: handleSearchChange,
@@ -708,19 +829,19 @@ function Select({
708
829
  "aria-label": "Search options"
709
830
  }
710
831
  )),
711
- /* @__PURE__ */ React7.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React7.createElement("div", { className: "py-2 px-3 text-center text-sm " }, "No options found") : optionGroups.length > 0 ? (
832
+ /* @__PURE__ */ React8.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React8.createElement("div", { className: "py-2 px-3 text-center text-sm " }, "No options found") : optionGroups.length > 0 ? (
712
833
  // Render grouped options
713
834
  optionGroups.map((group, groupIndex) => {
714
835
  const groupOptions = group.options.filter(
715
836
  (opt) => filteredOptions.includes(opt)
716
837
  );
717
838
  if (groupOptions.length === 0) return null;
718
- return /* @__PURE__ */ React7.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React7.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold " }, group.label), groupOptions.map((option) => {
839
+ return /* @__PURE__ */ React8.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React8.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold " }, group.label), groupOptions.map((option) => {
719
840
  const globalIndex = filteredOptions.indexOf(option);
720
841
  const isSelected = value === option.value;
721
842
  const isFocused = globalIndex === focusedIndex;
722
843
  const isDisabled = option.disabled;
723
- return /* @__PURE__ */ React7.createElement(
844
+ return /* @__PURE__ */ React8.createElement(
724
845
  "div",
725
846
  {
726
847
  key: option.value,
@@ -740,7 +861,7 @@ function Select({
740
861
  const isSelected = value === option.value;
741
862
  const isFocused = index === focusedIndex;
742
863
  const isDisabled = option.disabled;
743
- return /* @__PURE__ */ React7.createElement(
864
+ return /* @__PURE__ */ React8.createElement(
744
865
  "div",
745
866
  {
746
867
  key: option.value,
@@ -783,14 +904,14 @@ function FileInput({
783
904
  onFileRemove,
784
905
  ...props
785
906
  }) {
786
- const inputRef = React7.useRef(null);
787
- const [dragActive, setDragActive] = React7.useState(false);
788
- const [cropperOpen, setCropperOpen] = React7.useState(false);
789
- const [imageToCrop, setImageToCrop] = React7.useState(null);
790
- const [crop, setCrop] = React7.useState({ x: 0, y: 0 });
791
- const [zoom, setZoom] = React7.useState(1);
792
- const [croppedAreaPixels, setCroppedAreaPixels] = React7.useState(null);
793
- const validateFile = React7.useCallback(
907
+ const inputRef = React8.useRef(null);
908
+ const [dragActive, setDragActive] = React8.useState(false);
909
+ const [cropperOpen, setCropperOpen] = React8.useState(false);
910
+ const [imageToCrop, setImageToCrop] = React8.useState(null);
911
+ const [crop, setCrop] = React8.useState({ x: 0, y: 0 });
912
+ const [zoom, setZoom] = React8.useState(1);
913
+ const [croppedAreaPixels, setCroppedAreaPixels] = React8.useState(null);
914
+ const validateFile = React8.useCallback(
794
915
  (file) => {
795
916
  if (accept) {
796
917
  const acceptedTypes = accept.split(",").map((t) => t.trim());
@@ -825,7 +946,7 @@ function FileInput({
825
946
  },
826
947
  [accept, maxSize]
827
948
  );
828
- const handleFiles = React7.useCallback(
949
+ const handleFiles = React8.useCallback(
829
950
  (fileList) => {
830
951
  if (!fileList || fileList.length === 0) return;
831
952
  const newFiles = Array.from(fileList);
@@ -876,7 +997,7 @@ function FileInput({
876
997
  onValidationError
877
998
  ]
878
999
  );
879
- const createCroppedImage = React7.useCallback(
1000
+ const createCroppedImage = React8.useCallback(
880
1001
  async (imageUrl, cropArea) => {
881
1002
  return new Promise((resolve, reject) => {
882
1003
  const image = new Image();
@@ -920,7 +1041,7 @@ function FileInput({
920
1041
  },
921
1042
  []
922
1043
  );
923
- const handleCropSave = React7.useCallback(async () => {
1044
+ const handleCropSave = React8.useCallback(async () => {
924
1045
  if (!imageToCrop || !croppedAreaPixels) return;
925
1046
  try {
926
1047
  const croppedBlob = await createCroppedImage(
@@ -953,7 +1074,7 @@ function FileInput({
953
1074
  onChange,
954
1075
  multiple
955
1076
  ]);
956
- const handleCropCancel = React7.useCallback(() => {
1077
+ const handleCropCancel = React8.useCallback(() => {
957
1078
  if (imageToCrop) {
958
1079
  URL.revokeObjectURL(imageToCrop.url);
959
1080
  }
@@ -963,13 +1084,13 @@ function FileInput({
963
1084
  setZoom(1);
964
1085
  setCroppedAreaPixels(null);
965
1086
  }, [imageToCrop]);
966
- const onCropChange = React7.useCallback((crop2) => {
1087
+ const onCropChange = React8.useCallback((crop2) => {
967
1088
  setCrop(crop2);
968
1089
  }, []);
969
- const onZoomChange = React7.useCallback((zoom2) => {
1090
+ const onZoomChange = React8.useCallback((zoom2) => {
970
1091
  setZoom(zoom2);
971
1092
  }, []);
972
- const onCropCompleteInternal = React7.useCallback(
1093
+ const onCropCompleteInternal = React8.useCallback(
973
1094
  (_, croppedAreaPixels2) => {
974
1095
  setCroppedAreaPixels(croppedAreaPixels2);
975
1096
  },
@@ -1030,7 +1151,7 @@ function FileInput({
1030
1151
  }
1031
1152
  return null;
1032
1153
  };
1033
- React7.useEffect(() => {
1154
+ React8.useEffect(() => {
1034
1155
  return () => {
1035
1156
  value.forEach((file) => {
1036
1157
  const previewUrl = getPreviewUrl(file);
@@ -1044,7 +1165,7 @@ function FileInput({
1044
1165
  };
1045
1166
  }, [value, imageToCrop]);
1046
1167
  const combinedClassName = `${className}`.trim();
1047
- return /* @__PURE__ */ React7.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React7.createElement(
1168
+ return /* @__PURE__ */ React8.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React8.createElement(
1048
1169
  "input",
1049
1170
  {
1050
1171
  ref: inputRef,
@@ -1061,10 +1182,10 @@ function FileInput({
1061
1182
  "aria-required": required || props["aria-required"],
1062
1183
  style: { display: "none" }
1063
1184
  }
1064
- ), /* @__PURE__ */ React7.createElement(
1185
+ ), /* @__PURE__ */ React8.createElement(
1065
1186
  "div",
1066
1187
  {
1067
- 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-red-500" : ""}`,
1188
+ 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" : ""}`,
1068
1189
  onDragEnter: handleDrag,
1069
1190
  onDragLeave: handleDrag,
1070
1191
  onDragOver: handleDrag,
@@ -1076,7 +1197,7 @@ function FileInput({
1076
1197
  "aria-label": placeholder,
1077
1198
  "aria-disabled": disabled
1078
1199
  },
1079
- /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col items-center gap-2 text-center" }, /* @__PURE__ */ React7.createElement(
1200
+ /* @__PURE__ */ React8.createElement("div", { className: "flex flex-col items-center gap-2 text-center" }, /* @__PURE__ */ React8.createElement(
1080
1201
  "svg",
1081
1202
  {
1082
1203
  width: "48",
@@ -1089,19 +1210,19 @@ function FileInput({
1089
1210
  strokeLinejoin: "round",
1090
1211
  "aria-hidden": "true"
1091
1212
  },
1092
- /* @__PURE__ */ React7.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1093
- /* @__PURE__ */ React7.createElement("polyline", { points: "17 8 12 3 7 8" }),
1094
- /* @__PURE__ */ React7.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
1095
- ), /* @__PURE__ */ React7.createElement("p", { className: "text-sm font-medium" }, value.length > 0 ? `${value.length} file(s) selected` : placeholder), accept && /* @__PURE__ */ React7.createElement("p", { className: "text-xs" }, "Accepted: ", accept), maxSize && /* @__PURE__ */ React7.createElement("p", { className: "text-xs " }, "Max size: ", formatFileSize(maxSize)))
1096
- ), value.length > 0 && /* @__PURE__ */ React7.createElement("ul", { className: "flex flex-col gap-2 mt-4", role: "list" }, value.map((file, index) => {
1213
+ /* @__PURE__ */ React8.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1214
+ /* @__PURE__ */ React8.createElement("polyline", { points: "17 8 12 3 7 8" }),
1215
+ /* @__PURE__ */ React8.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
1216
+ ), /* @__PURE__ */ React8.createElement("p", { className: "text-sm font-medium" }, value.length > 0 ? `${value.length} file(s) selected` : placeholder), accept && /* @__PURE__ */ React8.createElement("p", { className: "text-xs" }, "Accepted: ", accept), maxSize && /* @__PURE__ */ React8.createElement("p", { className: "text-xs " }, "Max size: ", formatFileSize(maxSize)))
1217
+ ), value.length > 0 && /* @__PURE__ */ React8.createElement("ul", { className: "flex flex-col gap-2 mt-4", role: "list" }, value.map((file, index) => {
1097
1218
  const previewUrl = showPreview ? getPreviewUrl(file) : null;
1098
- return /* @__PURE__ */ React7.createElement(
1219
+ return /* @__PURE__ */ React8.createElement(
1099
1220
  "li",
1100
1221
  {
1101
1222
  key: `${file.name}-${index}`,
1102
1223
  className: "flex items-center gap-3 p-3 rounded-md border border-border bg-card text-card-foreground hover:bg-primary/50 transition-colors"
1103
1224
  },
1104
- previewUrl && /* @__PURE__ */ React7.createElement(
1225
+ previewUrl && /* @__PURE__ */ React8.createElement(
1105
1226
  "img",
1106
1227
  {
1107
1228
  src: previewUrl,
@@ -1111,7 +1232,7 @@ function FileInput({
1111
1232
  height: "48"
1112
1233
  }
1113
1234
  ),
1114
- /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React7.createElement("span", { className: "text-sm font-medium truncate" }, file.name), /* @__PURE__ */ React7.createElement("span", { className: "text-xs" }, formatFileSize(file.size)), showProgress && uploadProgress[file.name] !== void 0 && /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-2 mt-1" }, /* @__PURE__ */ React7.createElement(
1235
+ /* @__PURE__ */ React8.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React8.createElement("span", { className: "text-sm font-medium truncate" }, file.name), /* @__PURE__ */ React8.createElement("span", { className: "text-xs" }, formatFileSize(file.size)), showProgress && uploadProgress[file.name] !== void 0 && /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-2 mt-1" }, /* @__PURE__ */ React8.createElement(
1115
1236
  "div",
1116
1237
  {
1117
1238
  className: "h-1.5 bg-muted rounded-full overflow-hidden flex-1",
@@ -1121,15 +1242,15 @@ function FileInput({
1121
1242
  "aria-valuemax": 100,
1122
1243
  "aria-label": `Upload progress: ${uploadProgress[file.name]}%`
1123
1244
  },
1124
- /* @__PURE__ */ React7.createElement(
1245
+ /* @__PURE__ */ React8.createElement(
1125
1246
  "div",
1126
1247
  {
1127
1248
  className: "h-full bg-primary transition-all",
1128
1249
  style: { width: `${uploadProgress[file.name]}%` }
1129
1250
  }
1130
1251
  )
1131
- ), /* @__PURE__ */ React7.createElement("span", { className: "text-xs " }, uploadProgress[file.name], "%"))),
1132
- enableCropping && file.type.startsWith("image/") && /* @__PURE__ */ React7.createElement(
1252
+ ), /* @__PURE__ */ React8.createElement("span", { className: "text-xs " }, uploadProgress[file.name], "%"))),
1253
+ enableCropping && file.type.startsWith("image/") && /* @__PURE__ */ React8.createElement(
1133
1254
  "button",
1134
1255
  {
1135
1256
  type: "button",
@@ -1141,7 +1262,7 @@ function FileInput({
1141
1262
  className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
1142
1263
  "aria-label": `Crop ${file.name}`
1143
1264
  },
1144
- /* @__PURE__ */ React7.createElement(
1265
+ /* @__PURE__ */ React8.createElement(
1145
1266
  "svg",
1146
1267
  {
1147
1268
  width: "20",
@@ -1154,11 +1275,11 @@ function FileInput({
1154
1275
  strokeLinejoin: "round",
1155
1276
  "aria-hidden": "true"
1156
1277
  },
1157
- /* @__PURE__ */ React7.createElement("path", { d: "M6.13 1L6 16a2 2 0 0 0 2 2h15" }),
1158
- /* @__PURE__ */ React7.createElement("path", { d: "M1 6.13L16 6a2 2 0 0 1 2 2v15" })
1278
+ /* @__PURE__ */ React8.createElement("path", { d: "M6.13 1L6 16a2 2 0 0 0 2 2h15" }),
1279
+ /* @__PURE__ */ React8.createElement("path", { d: "M1 6.13L16 6a2 2 0 0 1 2 2v15" })
1159
1280
  )
1160
1281
  ),
1161
- /* @__PURE__ */ React7.createElement(
1282
+ /* @__PURE__ */ React8.createElement(
1162
1283
  "button",
1163
1284
  {
1164
1285
  type: "button",
@@ -1170,7 +1291,7 @@ function FileInput({
1170
1291
  className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
1171
1292
  "aria-label": `Remove ${file.name}`
1172
1293
  },
1173
- /* @__PURE__ */ React7.createElement(
1294
+ /* @__PURE__ */ React8.createElement(
1174
1295
  "svg",
1175
1296
  {
1176
1297
  width: "20",
@@ -1183,19 +1304,19 @@ function FileInput({
1183
1304
  strokeLinejoin: "round",
1184
1305
  "aria-hidden": "true"
1185
1306
  },
1186
- /* @__PURE__ */ React7.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1187
- /* @__PURE__ */ React7.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1307
+ /* @__PURE__ */ React8.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1308
+ /* @__PURE__ */ React8.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1188
1309
  )
1189
1310
  )
1190
1311
  );
1191
- })), cropperOpen && imageToCrop && /* @__PURE__ */ React7.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center" }, /* @__PURE__ */ React7.createElement(
1312
+ })), cropperOpen && imageToCrop && /* @__PURE__ */ React8.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center" }, /* @__PURE__ */ React8.createElement(
1192
1313
  "div",
1193
1314
  {
1194
1315
  className: "absolute inset-0 bg-black/50",
1195
1316
  onClick: handleCropCancel,
1196
1317
  "aria-label": "Close cropper"
1197
1318
  }
1198
- ), /* @__PURE__ */ React7.createElement("div", { className: "relative bg-popover border border-border rounded-lg shadow-lg max-w-3xl w-full mx-4" }, /* @__PURE__ */ React7.createElement("div", { className: "flex items-center justify-between p-4 border-b border-border" }, /* @__PURE__ */ React7.createElement("h3", { className: "text-lg font-semibold" }, "Crop Image"), /* @__PURE__ */ React7.createElement(
1319
+ ), /* @__PURE__ */ React8.createElement("div", { className: "relative bg-popover border border-border rounded-lg shadow-lg max-w-3xl w-full mx-4" }, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-between p-4 border-b border-border" }, /* @__PURE__ */ React8.createElement("h3", { className: "text-lg font-semibold" }, "Crop Image"), /* @__PURE__ */ React8.createElement(
1199
1320
  "button",
1200
1321
  {
1201
1322
  type: "button",
@@ -1204,7 +1325,7 @@ function FileInput({
1204
1325
  "aria-label": "Close"
1205
1326
  },
1206
1327
  "\u2715"
1207
- )), /* @__PURE__ */ React7.createElement("div", { className: "p-4" }, /* @__PURE__ */ React7.createElement(
1328
+ )), /* @__PURE__ */ React8.createElement("div", { className: "p-4" }, /* @__PURE__ */ React8.createElement(
1208
1329
  "div",
1209
1330
  {
1210
1331
  className: "relative w-full h-96 bg-muted rounded-md overflow-hidden",
@@ -1226,7 +1347,7 @@ function FileInput({
1226
1347
  document.addEventListener("mouseup", handleMouseUp);
1227
1348
  }
1228
1349
  },
1229
- /* @__PURE__ */ React7.createElement(
1350
+ /* @__PURE__ */ React8.createElement(
1230
1351
  "img",
1231
1352
  {
1232
1353
  src: imageToCrop.url,
@@ -1261,7 +1382,7 @@ function FileInput({
1261
1382
  }
1262
1383
  }
1263
1384
  ),
1264
- /* @__PURE__ */ React7.createElement(
1385
+ /* @__PURE__ */ React8.createElement(
1265
1386
  "div",
1266
1387
  {
1267
1388
  className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 border-2 border-primary rounded pointer-events-none",
@@ -1270,9 +1391,9 @@ function FileInput({
1270
1391
  aspectRatio: cropAspectRatio ? String(cropAspectRatio) : void 0
1271
1392
  }
1272
1393
  },
1273
- /* @__PURE__ */ React7.createElement("div", { className: "absolute inset-0 grid grid-cols-3 grid-rows-3" }, /* @__PURE__ */ React7.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React7.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React7.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React7.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React7.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React7.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React7.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React7.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React7.createElement("div", null))
1394
+ /* @__PURE__ */ React8.createElement("div", { className: "absolute inset-0 grid grid-cols-3 grid-rows-3" }, /* @__PURE__ */ React8.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React8.createElement("div", null))
1274
1395
  )
1275
- ), /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-3 mt-4" }, /* @__PURE__ */ React7.createElement(
1396
+ ), /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-3 mt-4" }, /* @__PURE__ */ React8.createElement(
1276
1397
  "label",
1277
1398
  {
1278
1399
  htmlFor: "zoom-slider",
@@ -1281,7 +1402,7 @@ function FileInput({
1281
1402
  "Zoom: ",
1282
1403
  zoom.toFixed(1),
1283
1404
  "x"
1284
- ), /* @__PURE__ */ React7.createElement(
1405
+ ), /* @__PURE__ */ React8.createElement(
1285
1406
  "input",
1286
1407
  {
1287
1408
  id: "zoom-slider",
@@ -1294,7 +1415,7 @@ function FileInput({
1294
1415
  className: "flex-1 h-2 bg-muted rounded-lg appearance-none cursor-pointer",
1295
1416
  "aria-label": "Zoom level"
1296
1417
  }
1297
- ))), /* @__PURE__ */ React7.createElement("div", { className: "flex items-center justify-end gap-2 p-4 border-t border-border" }, /* @__PURE__ */ React7.createElement(
1418
+ ))), /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-end gap-2 p-4 border-t border-border" }, /* @__PURE__ */ React8.createElement(
1298
1419
  "button",
1299
1420
  {
1300
1421
  type: "button",
@@ -1302,7 +1423,7 @@ function FileInput({
1302
1423
  onClick: handleCropCancel
1303
1424
  },
1304
1425
  "Cancel"
1305
- ), /* @__PURE__ */ React7.createElement(
1426
+ ), /* @__PURE__ */ React8.createElement(
1306
1427
  "button",
1307
1428
  {
1308
1429
  type: "button",
@@ -1321,27 +1442,6 @@ function formatDate(date, format) {
1321
1442
  const year = d.getFullYear();
1322
1443
  return format.replace("MM", month).replace("dd", day).replace("yyyy", String(year)).replace("yy", String(year).slice(2));
1323
1444
  }
1324
- function parseDate(dateString, format) {
1325
- if (!dateString) return null;
1326
- try {
1327
- if (format === "MM/dd/yyyy" || format === "MM-dd-yyyy") {
1328
- const parts = dateString.split(/[/-]/);
1329
- if (parts.length === 3) {
1330
- const month = parseInt(parts[0], 10) - 1;
1331
- const day = parseInt(parts[1], 10);
1332
- const year = parseInt(parts[2], 10);
1333
- const date2 = new Date(year, month, day);
1334
- if (!isNaN(date2.getTime())) {
1335
- return date2;
1336
- }
1337
- }
1338
- }
1339
- const date = new Date(dateString);
1340
- return isNaN(date.getTime()) ? null : date;
1341
- } catch {
1342
- return null;
1343
- }
1344
- }
1345
1445
  function isDateInArray(date, dates) {
1346
1446
  const dateStr = date.toDateString();
1347
1447
  return dates.some((d) => d.toDateString() === dateStr);
@@ -1365,43 +1465,30 @@ function DatePicker({
1365
1465
  showIcon = true,
1366
1466
  ...props
1367
1467
  }) {
1368
- const [isOpen, setIsOpen] = React7.useState(false);
1369
- const [inputValue, setInputValue] = React7.useState("");
1370
- const [selectedMonth, setSelectedMonth] = React7.useState(
1468
+ const [isOpen, setIsOpen] = React8.useState(false);
1469
+ const [selectedMonth, setSelectedMonth] = React8.useState(
1371
1470
  value || /* @__PURE__ */ new Date()
1372
1471
  );
1373
- const containerRef = React7.useRef(null);
1374
- const inputRef = React7.useRef(null);
1375
- React7.useEffect(() => {
1376
- setInputValue(formatDate(value, format));
1472
+ const containerRef = React8.useRef(null);
1473
+ const inputRef = React8.useRef(null);
1474
+ React8.useEffect(() => {
1377
1475
  if (value) {
1378
1476
  setSelectedMonth(value);
1379
1477
  }
1380
- }, [value, format]);
1478
+ }, [value]);
1381
1479
  const handleDateSelect = (date) => {
1382
1480
  onChange(date);
1383
1481
  setIsOpen(false);
1384
1482
  onBlur?.();
1385
1483
  };
1386
- const handleInputChange = (e) => {
1387
- const newValue = e.target.value;
1388
- setInputValue(newValue);
1389
- const parsedDate = parseDate(newValue, format);
1390
- if (parsedDate && !isNaN(parsedDate.getTime())) {
1391
- onChange(parsedDate);
1392
- } else if (newValue === "") {
1393
- onChange(null);
1394
- }
1395
- };
1396
1484
  const handleClear = (e) => {
1397
1485
  e.stopPropagation();
1398
1486
  onChange(null);
1399
- setInputValue("");
1400
1487
  inputRef.current?.focus();
1401
1488
  };
1402
1489
  const handleToggle = () => {
1403
1490
  if (disabled) return;
1404
- setIsOpen(!isOpen);
1491
+ setIsOpen((prev) => !prev);
1405
1492
  };
1406
1493
  const isDisabled = (date) => {
1407
1494
  if (minDate && date < minDate) return true;
@@ -1410,20 +1497,17 @@ function DatePicker({
1410
1497
  if (isDateDisabled && isDateDisabled(date)) return true;
1411
1498
  return false;
1412
1499
  };
1413
- React7.useEffect(() => {
1414
- const handleClickOutside = (event) => {
1415
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1416
- setIsOpen(false);
1417
- onBlur?.();
1418
- }
1419
- };
1420
- if (isOpen) {
1421
- document.addEventListener("mousedown", handleClickOutside);
1422
- return () => {
1423
- document.removeEventListener("mousedown", handleClickOutside);
1424
- };
1425
- }
1500
+ const closeCalendar = React8.useCallback(() => {
1501
+ if (!isOpen) return;
1502
+ setIsOpen(false);
1503
+ onBlur?.();
1426
1504
  }, [isOpen, onBlur]);
1505
+ useOnClickOutside(containerRef, closeCalendar, "pointerdown", true);
1506
+ const dayGridStyle = {
1507
+ gridTemplateColumns: "repeat(7, minmax(0, 1fr))"
1508
+ };
1509
+ const hasValue = Boolean(value);
1510
+ const displayValue = formatDate(value, format);
1427
1511
  const renderCalendar = () => {
1428
1512
  const year = selectedMonth.getFullYear();
1429
1513
  const month = selectedMonth.getMonth();
@@ -1456,44 +1540,57 @@ function DatePicker({
1456
1540
  const handleNextMonth = () => {
1457
1541
  setSelectedMonth(new Date(year, month + 1, 1));
1458
1542
  };
1459
- return /* @__PURE__ */ React7.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React7.createElement("div", { className: "flex items-center justify-between pb-2 border-b border-border" }, /* @__PURE__ */ React7.createElement(
1543
+ return /* @__PURE__ */ React8.createElement("div", { role: "grid", "aria-label": "Calendar", className: "w-[248px] max-w-full" }, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-between pb-3" }, /* @__PURE__ */ React8.createElement(
1460
1544
  "button",
1461
1545
  {
1462
1546
  type: "button",
1463
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground cursor-pointer",
1547
+ className: "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent hover:bg-muted cursor-pointer transition-colors",
1464
1548
  onClick: handlePrevMonth,
1465
1549
  "aria-label": "Previous month"
1466
1550
  },
1467
- "\u2190"
1468
- ), /* @__PURE__ */ React7.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React7.createElement(
1551
+ "\u2039"
1552
+ ), /* @__PURE__ */ React8.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React8.createElement(
1469
1553
  "button",
1470
1554
  {
1471
1555
  type: "button",
1472
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground cursor-pointer",
1556
+ className: "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent hover:bg-muted cursor-pointer transition-colors",
1473
1557
  onClick: handleNextMonth,
1474
1558
  "aria-label": "Next month"
1475
1559
  },
1476
- "\u2192"
1477
- )), /* @__PURE__ */ React7.createElement("div", { className: "grid grid-cols-7 gap-1 mt-2" }, ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React7.createElement(
1560
+ "\u203A"
1561
+ )), /* @__PURE__ */ React8.createElement(
1478
1562
  "div",
1479
1563
  {
1480
- key: day,
1481
- className: "flex items-center justify-center h-8 w-full text-xs font-medium"
1564
+ className: "grid gap-1 text-xs text-muted-foreground",
1565
+ style: dayGridStyle
1482
1566
  },
1483
- day
1484
- ))), /* @__PURE__ */ React7.createElement("div", { className: "grid grid-cols-7 gap-1" }, days.map((date, index) => {
1567
+ ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React8.createElement(
1568
+ "div",
1569
+ {
1570
+ key: day,
1571
+ className: "flex items-center justify-center h-8 w-8 font-medium"
1572
+ },
1573
+ day
1574
+ ))
1575
+ ), /* @__PURE__ */ React8.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
1485
1576
  if (!date) {
1486
- return /* @__PURE__ */ React7.createElement("div", { key: `empty-${index}` });
1577
+ return /* @__PURE__ */ React8.createElement("div", { key: `empty-${index}`, className: "h-8 w-8" });
1487
1578
  }
1488
1579
  const isSelected = value && date.toDateString() === value.toDateString();
1489
1580
  const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
1490
1581
  const disabled2 = isDisabled(date);
1491
- return /* @__PURE__ */ React7.createElement(
1582
+ return /* @__PURE__ */ React8.createElement(
1492
1583
  "button",
1493
1584
  {
1494
1585
  key: date.toISOString(),
1495
1586
  type: "button",
1496
- 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" : ""}`,
1587
+ className: cn(
1588
+ "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent cursor-pointer text-sm transition-colors",
1589
+ "hover:bg-muted",
1590
+ isSelected && "bg-primary text-primary-foreground font-semibold",
1591
+ !isSelected && isToday && "border border-primary",
1592
+ disabled2 && "cursor-not-allowed opacity-50 pointer-events-none"
1593
+ ),
1497
1594
  onClick: () => !disabled2 && handleDateSelect(date),
1498
1595
  disabled: disabled2,
1499
1596
  "aria-label": formatDate(date, format)
@@ -1502,21 +1599,21 @@ function DatePicker({
1502
1599
  );
1503
1600
  })));
1504
1601
  };
1505
- const combinedClassName = `relative ${className}`.trim();
1506
- return /* @__PURE__ */ React7.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React7.createElement(
1602
+ const combinedClassName = cn("relative", className);
1603
+ return /* @__PURE__ */ React8.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React8.createElement(
1507
1604
  "input",
1508
1605
  {
1509
1606
  type: "hidden",
1510
1607
  name,
1511
1608
  value: value ? value.toISOString() : ""
1512
1609
  }
1513
- ), /* @__PURE__ */ React7.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React7.createElement(
1610
+ ), /* @__PURE__ */ React8.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8.createElement(
1514
1611
  "span",
1515
1612
  {
1516
1613
  className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
1517
1614
  "aria-hidden": "true"
1518
1615
  },
1519
- /* @__PURE__ */ React7.createElement(
1616
+ /* @__PURE__ */ React8.createElement(
1520
1617
  "svg",
1521
1618
  {
1522
1619
  xmlns: "http://www.w3.org/2000/svg",
@@ -1529,16 +1626,24 @@ function DatePicker({
1529
1626
  strokeLinejoin: "round",
1530
1627
  strokeWidth: "2"
1531
1628
  },
1532
- /* @__PURE__ */ React7.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" })
1629
+ /* @__PURE__ */ React8.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" })
1533
1630
  )
1534
- ), /* @__PURE__ */ React7.createElement(
1631
+ ), /* @__PURE__ */ React8.createElement(
1535
1632
  "input",
1536
1633
  {
1537
1634
  ref: inputRef,
1538
1635
  type: "text",
1539
- 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" : ""}`,
1540
- value: inputValue,
1541
- onChange: handleInputChange,
1636
+ className: cn(
1637
+ "flex h-9 w-full rounded-md border border-input bg-transparent py-1 text-base shadow-sm transition-colors",
1638
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1639
+ "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1640
+ INPUT_AUTOFILL_RESET_CLASSES,
1641
+ showIcon ? "pl-10" : "pl-3",
1642
+ clearable && value ? "pr-10" : "pr-3",
1643
+ !error && hasValue && "ring-2 ring-ring",
1644
+ error && "border-destructive ring-1 ring-destructive"
1645
+ ),
1646
+ value: displayValue,
1542
1647
  onClick: handleToggle,
1543
1648
  onBlur,
1544
1649
  disabled,
@@ -1549,7 +1654,7 @@ function DatePicker({
1549
1654
  "aria-required": required || props["aria-required"],
1550
1655
  readOnly: true
1551
1656
  }
1552
- ), clearable && value && !disabled && /* @__PURE__ */ React7.createElement(
1657
+ ), clearable && value && !disabled && /* @__PURE__ */ React8.createElement(
1553
1658
  "button",
1554
1659
  {
1555
1660
  type: "button",
@@ -1559,49 +1664,49 @@ function DatePicker({
1559
1664
  tabIndex: -1
1560
1665
  },
1561
1666
  "\u2715"
1562
- )), isOpen && !disabled && /* @__PURE__ */ React7.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()));
1667
+ )), isOpen && !disabled && /* @__PURE__ */ React8.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()));
1563
1668
  }
1564
1669
  DatePicker.displayName = "DatePicker";
1565
- function parseTimeString(timeStr, use24Hour) {
1566
- if (!timeStr) return null;
1567
- try {
1568
- if (use24Hour) {
1569
- const [hourStr, minuteStr] = timeStr.split(":");
1570
- const hour24 = parseInt(hourStr, 10);
1571
- const minute = parseInt(minuteStr, 10);
1572
- if (isNaN(hour24) || isNaN(minute)) return null;
1573
- if (hour24 < 0 || hour24 > 23) return null;
1574
- if (minute < 0 || minute > 59) return null;
1575
- const period = hour24 >= 12 ? "PM" : "AM";
1576
- const hour = hour24 === 0 ? 12 : hour24 > 12 ? hour24 - 12 : hour24;
1577
- return { hour, minute, period };
1578
- } else {
1579
- const match = timeStr.match(/^(\d{1,2}):(\d{2})\s*(AM|PM)$/i);
1580
- if (!match) return null;
1581
- const hour = parseInt(match[1], 10);
1582
- const minute = parseInt(match[2], 10);
1583
- const period = match[3].toUpperCase();
1584
- if (hour < 1 || hour > 12) return null;
1585
- if (minute < 0 || minute > 59) return null;
1586
- return { hour, minute, period };
1670
+ function normalizeToNativeTime(value) {
1671
+ if (!value) return "";
1672
+ const twelveHourMatch = value.match(
1673
+ /^(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(AM|PM)$/i
1674
+ );
1675
+ if (twelveHourMatch) {
1676
+ const rawHour = parseInt(twelveHourMatch[1], 10);
1677
+ const minute = parseInt(twelveHourMatch[2], 10);
1678
+ const period = twelveHourMatch[4].toUpperCase();
1679
+ if (Number.isNaN(rawHour) || Number.isNaN(minute) || rawHour < 1 || rawHour > 12 || minute < 0 || minute > 59) {
1680
+ return "";
1587
1681
  }
1588
- } catch {
1589
- return null;
1682
+ const normalizedHour = period === "PM" ? rawHour === 12 ? 12 : rawHour + 12 : rawHour === 12 ? 0 : rawHour;
1683
+ return `${String(normalizedHour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
1590
1684
  }
1685
+ const twentyFourHourMatch = value.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/);
1686
+ if (twentyFourHourMatch) {
1687
+ const hour = parseInt(twentyFourHourMatch[1], 10);
1688
+ const minute = parseInt(twentyFourHourMatch[2], 10);
1689
+ if (Number.isNaN(hour) || Number.isNaN(minute) || hour < 0 || hour > 23 || minute < 0 || minute > 59) {
1690
+ return "";
1691
+ }
1692
+ return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
1693
+ }
1694
+ return "";
1591
1695
  }
1592
- function formatTimeValue(time, use24Hour) {
1593
- if (!time) return "";
1696
+ function formatFromNativeTime(nativeValue, use24Hour) {
1697
+ if (!nativeValue) return "";
1698
+ const [hourValue, minuteValue] = nativeValue.split(":");
1699
+ const hour = parseInt(hourValue, 10);
1700
+ const minute = parseInt(minuteValue, 10);
1701
+ if (Number.isNaN(hour) || Number.isNaN(minute)) {
1702
+ return "";
1703
+ }
1594
1704
  if (use24Hour) {
1595
- let hour24 = time.hour;
1596
- if (time.period === "PM" && time.hour !== 12) {
1597
- hour24 = time.hour + 12;
1598
- } else if (time.period === "AM" && time.hour === 12) {
1599
- hour24 = 0;
1600
- }
1601
- return `${String(hour24).padStart(2, "0")}:${String(time.minute).padStart(2, "0")}`;
1602
- } else {
1603
- return `${time.hour}:${String(time.minute).padStart(2, "0")} ${time.period}`;
1705
+ return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
1604
1706
  }
1707
+ const period = hour >= 12 ? "PM" : "AM";
1708
+ const hour12 = hour % 12 || 12;
1709
+ return `${hour12}:${String(minute).padStart(2, "0")} ${period}`;
1605
1710
  }
1606
1711
  function TimePicker({
1607
1712
  name,
@@ -1619,88 +1724,33 @@ function TimePicker({
1619
1724
  showIcon = true,
1620
1725
  ...props
1621
1726
  }) {
1622
- const [isOpen, setIsOpen] = React7.useState(false);
1623
- const [timeValue, setTimeValue] = React7.useState(null);
1624
- const containerRef = React7.useRef(null);
1625
- const inputRef = React7.useRef(null);
1626
- React7.useEffect(() => {
1627
- const parsed = parseTimeString(value, use24Hour);
1628
- setTimeValue(parsed);
1629
- }, [value, use24Hour]);
1630
- const handleHourChange = (hour) => {
1631
- const newTime = {
1632
- hour,
1633
- minute: timeValue?.minute || 0,
1634
- period: timeValue?.period || "AM"
1635
- };
1636
- setTimeValue(newTime);
1637
- onChange(formatTimeValue(newTime, use24Hour));
1638
- };
1639
- const handleMinuteChange = (minute) => {
1640
- const newTime = {
1641
- hour: timeValue?.hour || 12,
1642
- minute,
1643
- period: timeValue?.period || "AM"
1644
- };
1645
- setTimeValue(newTime);
1646
- onChange(formatTimeValue(newTime, use24Hour));
1647
- };
1648
- const handlePeriodChange = (period) => {
1649
- const newTime = {
1650
- hour: timeValue?.hour || 12,
1651
- minute: timeValue?.minute || 0,
1652
- period
1653
- };
1654
- setTimeValue(newTime);
1655
- onChange(formatTimeValue(newTime, use24Hour));
1727
+ const inputRef = React8.useRef(null);
1728
+ const [nativeValue, setNativeValue] = React8.useState(
1729
+ normalizeToNativeTime(value)
1730
+ );
1731
+ React8.useEffect(() => {
1732
+ setNativeValue(normalizeToNativeTime(value));
1733
+ }, [value]);
1734
+ const handleChange = (e) => {
1735
+ const nextNativeValue = e.target.value;
1736
+ setNativeValue(nextNativeValue);
1737
+ onChange(formatFromNativeTime(nextNativeValue, use24Hour));
1656
1738
  };
1657
1739
  const handleClear = (e) => {
1658
1740
  e.stopPropagation();
1741
+ setNativeValue("");
1659
1742
  onChange("");
1660
- setTimeValue(null);
1661
1743
  inputRef.current?.focus();
1662
1744
  };
1663
- const handleToggle = () => {
1664
- if (disabled) return;
1665
- setIsOpen(!isOpen);
1666
- };
1667
- React7.useEffect(() => {
1668
- const handleClickOutside = (event) => {
1669
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1670
- setIsOpen(false);
1671
- onBlur?.();
1672
- }
1673
- };
1674
- if (isOpen) {
1675
- document.addEventListener("mousedown", handleClickOutside);
1676
- return () => {
1677
- document.removeEventListener("mousedown", handleClickOutside);
1678
- };
1679
- }
1680
- }, [isOpen, onBlur]);
1681
- const hours = React7.useMemo(() => {
1682
- if (use24Hour) {
1683
- return Array.from({ length: 24 }, (_, i) => i);
1684
- } else {
1685
- return Array.from({ length: 12 }, (_, i) => i + 1);
1686
- }
1687
- }, [use24Hour]);
1688
- const minutes = React7.useMemo(() => {
1689
- const mins = [];
1690
- for (let i = 0; i < 60; i += minuteStep) {
1691
- mins.push(i);
1692
- }
1693
- return mins;
1694
- }, [minuteStep]);
1695
- const combinedClassName = cn("relative", className);
1696
- const displayValue = formatTimeValue(timeValue, use24Hour);
1697
- return /* @__PURE__ */ React7.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React7.createElement("input", { type: "hidden", name, value }), /* @__PURE__ */ React7.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React7.createElement(
1745
+ const hasValue = Boolean(value);
1746
+ const stepInSeconds = Math.max(1, minuteStep * 60);
1747
+ return /* @__PURE__ */ React8.createElement("div", { className: cn("relative", className) }, /* @__PURE__ */ React8.createElement("input", { type: "hidden", name, value }), /* @__PURE__ */ React8.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8.createElement(
1698
1748
  "span",
1699
1749
  {
1700
1750
  className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
1701
1751
  "aria-hidden": "true"
1702
1752
  },
1703
- /* @__PURE__ */ React7.createElement(
1753
+ /* @__PURE__ */ React8.createElement(
1704
1754
  "svg",
1705
1755
  {
1706
1756
  xmlns: "http://www.w3.org/2000/svg",
@@ -1713,34 +1763,38 @@ function TimePicker({
1713
1763
  strokeLinejoin: "round",
1714
1764
  strokeWidth: "2"
1715
1765
  },
1716
- /* @__PURE__ */ React7.createElement("circle", { cx: "12", cy: "12", r: "10" }),
1717
- /* @__PURE__ */ React7.createElement("path", { d: "M12 6v6l4 2" })
1766
+ /* @__PURE__ */ React8.createElement("circle", { cx: "12", cy: "12", r: "10" }),
1767
+ /* @__PURE__ */ React8.createElement("path", { d: "M12 6v6l4 2" })
1718
1768
  )
1719
- ), /* @__PURE__ */ React7.createElement(
1769
+ ), /* @__PURE__ */ React8.createElement(
1720
1770
  "input",
1721
1771
  {
1722
1772
  ref: inputRef,
1723
- type: "text",
1773
+ type: "time",
1724
1774
  className: cn(
1725
1775
  "flex h-9 w-full rounded-md border border-input bg-transparent py-1 text-base shadow-sm transition-colors",
1726
1776
  "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1727
1777
  "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1778
+ "appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none",
1779
+ INPUT_AUTOFILL_RESET_CLASSES,
1728
1780
  showIcon ? "pl-10" : "pl-3",
1729
1781
  clearable && value ? "pr-10" : "pr-3",
1730
- error && "border-red-500 ring-1 ring-red-500"
1782
+ !error && hasValue && "ring-2 ring-ring",
1783
+ error && "border-destructive ring-1 ring-destructive"
1731
1784
  ),
1732
- value: displayValue,
1733
- onClick: handleToggle,
1785
+ value: nativeValue,
1786
+ onChange: handleChange,
1734
1787
  onBlur,
1735
1788
  disabled,
1736
1789
  required,
1790
+ step: stepInSeconds,
1737
1791
  placeholder,
1738
1792
  "aria-invalid": error || props["aria-invalid"] ? "true" : "false",
1739
1793
  "aria-describedby": props["aria-describedby"],
1740
1794
  "aria-required": required || props["aria-required"],
1741
- readOnly: true
1795
+ ...props
1742
1796
  }
1743
- ), clearable && value && !disabled && /* @__PURE__ */ React7.createElement(
1797
+ ), clearable && value && !disabled && /* @__PURE__ */ React8.createElement(
1744
1798
  "button",
1745
1799
  {
1746
1800
  type: "button",
@@ -1750,84 +1804,7 @@ function TimePicker({
1750
1804
  tabIndex: -1
1751
1805
  },
1752
1806
  "\u2715"
1753
- )), isOpen && !disabled && /* @__PURE__ */ React7.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.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col flex-1" }, /* @__PURE__ */ React7.createElement("div", { className: "text-xs font-medium mb-2 text-center" }, use24Hour ? "Hour" : "Hour"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col gap-1 max-h-48 overflow-y-auto" }, hours.map((hour) => {
1754
- const displayHour = use24Hour ? hour : hour;
1755
- const isSelected = use24Hour ? timeValue?.hour === (hour === 0 ? 12 : hour > 12 ? hour - 12 : hour) && timeValue?.period === (hour >= 12 ? "PM" : "AM") : timeValue?.hour === hour;
1756
- return /* @__PURE__ */ React7.createElement(
1757
- "button",
1758
- {
1759
- key: hour,
1760
- type: "button",
1761
- className: cn(
1762
- "flex items-center justify-center h-8 w-full rounded",
1763
- "border-none bg-transparent cursor-pointer text-sm transition-colors",
1764
- "hover:bg-primary hover:text-primary-foreground",
1765
- isSelected ? "bg-primary text-primary-foreground font-semibold" : ""
1766
- ),
1767
- onClick: () => {
1768
- if (use24Hour) {
1769
- const hour12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
1770
- const period = hour >= 12 ? "PM" : "AM";
1771
- const newTime = {
1772
- hour: hour12,
1773
- minute: timeValue?.minute || 0,
1774
- period
1775
- };
1776
- setTimeValue(newTime);
1777
- onChange(formatTimeValue(newTime, use24Hour));
1778
- } else {
1779
- handleHourChange(hour);
1780
- }
1781
- },
1782
- "aria-label": `${String(displayHour).padStart(2, "0")} hours`
1783
- },
1784
- String(displayHour).padStart(2, "0")
1785
- );
1786
- }))), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col flex-1" }, /* @__PURE__ */ React7.createElement("div", { className: "text-xs font-medium mb-2 text-center" }, "Minute"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col gap-1 max-h-48 overflow-y-auto" }, minutes.map((minute) => {
1787
- const isSelected = timeValue?.minute === minute;
1788
- return /* @__PURE__ */ React7.createElement(
1789
- "button",
1790
- {
1791
- key: minute,
1792
- type: "button",
1793
- className: cn(
1794
- "flex items-center justify-center h-8 w-full",
1795
- "rounded border-none bg-transparent cursor-pointer text-sm transition-colors",
1796
- "hover:bg-primary hover:text-primary-foreground",
1797
- isSelected ? "bg-primary text-primary-foreground font-semibold" : ""
1798
- ),
1799
- onClick: () => handleMinuteChange(minute),
1800
- "aria-label": `${String(minute).padStart(2, "0")} minutes`
1801
- },
1802
- String(minute).padStart(2, "0")
1803
- );
1804
- }))), !use24Hour && /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col w-20" }, /* @__PURE__ */ React7.createElement("div", { className: "text-xs font-medium mb-2 text-center" }, "Period"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React7.createElement(
1805
- "button",
1806
- {
1807
- type: "button",
1808
- className: cn(
1809
- "flex items-center justify-center h-8 w-full",
1810
- "rounded border-none bg-transparent cursor-pointer text-sm",
1811
- "transition-colors hover:bg-primary hover:text-primary-foreground",
1812
- timeValue?.period === "AM" ? "bg-muted font-semibold" : ""
1813
- ),
1814
- onClick: () => handlePeriodChange("AM")
1815
- },
1816
- "AM"
1817
- ), /* @__PURE__ */ React7.createElement(
1818
- "button",
1819
- {
1820
- type: "button",
1821
- className: cn(
1822
- "flex items-center justify-center h-8 w-full",
1823
- "rounded border-none bg-transparent cursor-pointer text-sm",
1824
- "transition-colors hover:bg-primary hover:text-primary-foreground",
1825
- timeValue?.period === "PM" ? "bg-muted font-semibold" : ""
1826
- ),
1827
- onClick: () => handlePeriodChange("PM")
1828
- },
1829
- "PM"
1830
- ))))));
1807
+ )));
1831
1808
  }
1832
1809
  TimePicker.displayName = "TimePicker";
1833
1810
  function formatDate2(date, format) {
@@ -1847,6 +1824,9 @@ function isDateInRange(date, start, end) {
1847
1824
  const time = date.getTime();
1848
1825
  return time >= start.getTime() && time <= end.getTime();
1849
1826
  }
1827
+ function addMonths(date, delta) {
1828
+ return new Date(date.getFullYear(), date.getMonth() + delta, 1);
1829
+ }
1850
1830
  function DateRangePicker({
1851
1831
  name,
1852
1832
  value = { start: null, end: null },
@@ -1867,15 +1847,15 @@ function DateRangePicker({
1867
1847
  separator = " - ",
1868
1848
  ...props
1869
1849
  }) {
1870
- const [isOpen, setIsOpen] = React7.useState(false);
1871
- const [selectedMonth, setSelectedMonth] = React7.useState(
1850
+ const [isOpen, setIsOpen] = React8.useState(false);
1851
+ const [selectedMonth, setSelectedMonth] = React8.useState(
1872
1852
  value.start || /* @__PURE__ */ new Date()
1873
1853
  );
1874
- const [rangeStart, setRangeStart] = React7.useState(value.start);
1875
- const [rangeEnd, setRangeEnd] = React7.useState(value.end);
1876
- const [hoverDate, setHoverDate] = React7.useState(null);
1877
- const containerRef = React7.useRef(null);
1878
- React7.useEffect(() => {
1854
+ const [rangeStart, setRangeStart] = React8.useState(value.start);
1855
+ const [rangeEnd, setRangeEnd] = React8.useState(value.end);
1856
+ const [hoverDate, setHoverDate] = React8.useState(null);
1857
+ const containerRef = React8.useRef(null);
1858
+ React8.useEffect(() => {
1879
1859
  setRangeStart(value.start);
1880
1860
  setRangeEnd(value.end);
1881
1861
  if (value.start) {
@@ -1909,7 +1889,7 @@ function DateRangePicker({
1909
1889
  };
1910
1890
  const handleToggle = () => {
1911
1891
  if (disabled) return;
1912
- setIsOpen(!isOpen);
1892
+ setIsOpen((prev) => !prev);
1913
1893
  };
1914
1894
  const isDisabled = (date) => {
1915
1895
  if (minDate && date < minDate) return true;
@@ -1918,23 +1898,36 @@ function DateRangePicker({
1918
1898
  if (isDateDisabled && isDateDisabled(date)) return true;
1919
1899
  return false;
1920
1900
  };
1921
- React7.useEffect(() => {
1922
- const handleClickOutside = (event) => {
1923
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1924
- setIsOpen(false);
1925
- onBlur?.();
1926
- }
1927
- };
1928
- if (isOpen) {
1929
- document.addEventListener("mousedown", handleClickOutside);
1930
- return () => {
1931
- document.removeEventListener("mousedown", handleClickOutside);
1932
- };
1933
- }
1901
+ const closeCalendar = React8.useCallback(() => {
1902
+ if (!isOpen) return;
1903
+ setIsOpen(false);
1904
+ onBlur?.();
1934
1905
  }, [isOpen, onBlur]);
1935
- const renderCalendar = () => {
1936
- const year = selectedMonth.getFullYear();
1937
- const month = selectedMonth.getMonth();
1906
+ useOnClickOutside(containerRef, closeCalendar, "pointerdown", true);
1907
+ const dayGridStyle = {
1908
+ gridTemplateColumns: "repeat(7, minmax(0, 1fr))"
1909
+ };
1910
+ const monthsGridStyle = {
1911
+ gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))"
1912
+ };
1913
+ const monthNames = [
1914
+ "January",
1915
+ "February",
1916
+ "March",
1917
+ "April",
1918
+ "May",
1919
+ "June",
1920
+ "July",
1921
+ "August",
1922
+ "September",
1923
+ "October",
1924
+ "November",
1925
+ "December"
1926
+ ];
1927
+ const hasValue = Boolean(rangeStart || rangeEnd);
1928
+ const renderMonth = (monthDate, controls) => {
1929
+ const year = monthDate.getFullYear();
1930
+ const month = monthDate.getMonth();
1938
1931
  const daysInMonth = new Date(year, month + 1, 0).getDate();
1939
1932
  const firstDayOfMonth = new Date(year, month, 1).getDay();
1940
1933
  const days = [];
@@ -1944,54 +1937,41 @@ function DateRangePicker({
1944
1937
  for (let day = 1; day <= daysInMonth; day++) {
1945
1938
  days.push(new Date(year, month, day));
1946
1939
  }
1947
- const monthNames = [
1948
- "January",
1949
- "February",
1950
- "March",
1951
- "April",
1952
- "May",
1953
- "June",
1954
- "July",
1955
- "August",
1956
- "September",
1957
- "October",
1958
- "November",
1959
- "December"
1960
- ];
1961
- const handlePrevMonth = () => {
1962
- setSelectedMonth(new Date(year, month - 1, 1));
1963
- };
1964
- const handleNextMonth = () => {
1965
- setSelectedMonth(new Date(year, month + 1, 1));
1966
- };
1967
- return /* @__PURE__ */ React7.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React7.createElement("div", { className: "flex items-center justify-between pb-2 border-b border-border" }, /* @__PURE__ */ React7.createElement(
1940
+ return /* @__PURE__ */ React8.createElement("div", { className: "w-[240px] max-w-full" }, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-between pb-3" }, controls?.prev ? /* @__PURE__ */ React8.createElement(
1968
1941
  "button",
1969
1942
  {
1970
1943
  type: "button",
1971
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground cursor-pointer",
1972
- onClick: handlePrevMonth,
1944
+ className: "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent hover:bg-muted cursor-pointer transition-colors",
1945
+ onClick: () => setSelectedMonth((prev) => addMonths(prev, -1)),
1973
1946
  "aria-label": "Previous month"
1974
1947
  },
1975
- "\u2190"
1976
- ), /* @__PURE__ */ React7.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React7.createElement(
1948
+ "\u2039"
1949
+ ) : /* @__PURE__ */ React8.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" }), /* @__PURE__ */ React8.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), controls?.next ? /* @__PURE__ */ React8.createElement(
1977
1950
  "button",
1978
1951
  {
1979
1952
  type: "button",
1980
- className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground cursor-pointer",
1981
- onClick: handleNextMonth,
1953
+ className: "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent hover:bg-muted cursor-pointer transition-colors",
1954
+ onClick: () => setSelectedMonth((prev) => addMonths(prev, 1)),
1982
1955
  "aria-label": "Next month"
1983
1956
  },
1984
- "\u2192"
1985
- )), /* @__PURE__ */ React7.createElement("div", { className: "grid grid-cols-7 gap-1 mt-2" }, ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React7.createElement(
1957
+ "\u203A"
1958
+ ) : /* @__PURE__ */ React8.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" })), /* @__PURE__ */ React8.createElement(
1986
1959
  "div",
1987
1960
  {
1988
- key: day,
1989
- className: "flex items-center justify-center h-8 w-full text-xs font-medium"
1961
+ className: "grid gap-1 text-xs text-muted-foreground",
1962
+ style: dayGridStyle
1990
1963
  },
1991
- day
1992
- ))), /* @__PURE__ */ React7.createElement("div", { className: "grid grid-cols-7 gap-1" }, days.map((date, index) => {
1964
+ ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React8.createElement(
1965
+ "div",
1966
+ {
1967
+ key: `${month}-${day}`,
1968
+ className: "flex items-center justify-center h-8 w-8 font-medium"
1969
+ },
1970
+ day
1971
+ ))
1972
+ ), /* @__PURE__ */ React8.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
1993
1973
  if (!date) {
1994
- return /* @__PURE__ */ React7.createElement("div", { key: `empty-${index}` });
1974
+ return /* @__PURE__ */ React8.createElement("div", { key: `empty-${month}-${index}`, className: "h-8 w-8" });
1995
1975
  }
1996
1976
  const isStart = rangeStart && date.toDateString() === rangeStart.toDateString();
1997
1977
  const isEnd = rangeEnd && date.toDateString() === rangeEnd.toDateString();
@@ -2003,17 +1983,17 @@ function DateRangePicker({
2003
1983
  );
2004
1984
  const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
2005
1985
  const disabled2 = isDisabled(date);
2006
- return /* @__PURE__ */ React7.createElement(
1986
+ return /* @__PURE__ */ React8.createElement(
2007
1987
  "button",
2008
1988
  {
2009
1989
  key: date.toISOString(),
2010
1990
  type: "button",
2011
1991
  className: cn(
2012
- "flex items-center justify-center h-8 w-full rounded border-none bg-transparent",
2013
- "cursor-pointer text-sm transition-colors hover:bg-muted",
2014
- isRangeEndpoint && "bg-muted font-semibold",
2015
- isRangeHighlight && "bg-muted/70",
2016
- isToday && "border border-primary",
1992
+ "flex items-center justify-center h-8 w-8 rounded-md border-none bg-transparent cursor-pointer text-sm transition-colors",
1993
+ "hover:bg-muted",
1994
+ isRangeEndpoint && "bg-primary text-primary-foreground font-semibold",
1995
+ isRangeHighlight && "bg-muted",
1996
+ !isRangeEndpoint && !isRangeHighlight && isToday && "border border-primary",
2017
1997
  disabled2 && "cursor-not-allowed opacity-50 pointer-events-none"
2018
1998
  ),
2019
1999
  onClick: () => !disabled2 && handleDateSelect(date),
@@ -2028,27 +2008,27 @@ function DateRangePicker({
2028
2008
  };
2029
2009
  const combinedClassName = cn("relative", className);
2030
2010
  const displayValue = rangeStart && rangeEnd ? `${formatDate2(rangeStart, format)}${separator}${formatDate2(rangeEnd, format)}` : rangeStart ? formatDate2(rangeStart, format) : "";
2031
- return /* @__PURE__ */ React7.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React7.createElement(
2011
+ return /* @__PURE__ */ React8.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React8.createElement(
2032
2012
  "input",
2033
2013
  {
2034
2014
  type: "hidden",
2035
2015
  name: `${name}[start]`,
2036
2016
  value: rangeStart ? rangeStart.toISOString() : ""
2037
2017
  }
2038
- ), /* @__PURE__ */ React7.createElement(
2018
+ ), /* @__PURE__ */ React8.createElement(
2039
2019
  "input",
2040
2020
  {
2041
2021
  type: "hidden",
2042
2022
  name: `${name}[end]`,
2043
2023
  value: rangeEnd ? rangeEnd.toISOString() : ""
2044
2024
  }
2045
- ), /* @__PURE__ */ React7.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React7.createElement(
2025
+ ), /* @__PURE__ */ React8.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8.createElement(
2046
2026
  "span",
2047
2027
  {
2048
2028
  className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
2049
2029
  "aria-hidden": "true"
2050
2030
  },
2051
- /* @__PURE__ */ React7.createElement(
2031
+ /* @__PURE__ */ React8.createElement(
2052
2032
  "svg",
2053
2033
  {
2054
2034
  xmlns: "http://www.w3.org/2000/svg",
@@ -2061,9 +2041,9 @@ function DateRangePicker({
2061
2041
  strokeLinejoin: "round",
2062
2042
  strokeWidth: "2"
2063
2043
  },
2064
- /* @__PURE__ */ React7.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" })
2044
+ /* @__PURE__ */ React8.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" })
2065
2045
  )
2066
- ), /* @__PURE__ */ React7.createElement(
2046
+ ), /* @__PURE__ */ React8.createElement(
2067
2047
  "input",
2068
2048
  {
2069
2049
  type: "text",
@@ -2071,9 +2051,11 @@ function DateRangePicker({
2071
2051
  "flex h-9 w-full rounded-md border border-input bg-transparent py-1 text-base shadow-sm transition-colors",
2072
2052
  "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
2073
2053
  "disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
2054
+ INPUT_AUTOFILL_RESET_CLASSES,
2074
2055
  showIcon ? "pl-10" : "pl-3",
2075
2056
  clearable && (rangeStart || rangeEnd) ? "pr-10" : "pr-3",
2076
- error && "border-red-500 ring-1 ring-red-500"
2057
+ !error && hasValue && "ring-2 ring-ring",
2058
+ error && "border-destructive ring-1 ring-destructive"
2077
2059
  ),
2078
2060
  value: displayValue,
2079
2061
  onClick: handleToggle,
@@ -2086,7 +2068,7 @@ function DateRangePicker({
2086
2068
  "aria-required": required || props["aria-required"],
2087
2069
  readOnly: true
2088
2070
  }
2089
- ), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */ React7.createElement(
2071
+ ), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */ React8.createElement(
2090
2072
  "button",
2091
2073
  {
2092
2074
  type: "button",
@@ -2096,7 +2078,7 @@ function DateRangePicker({
2096
2078
  tabIndex: -1
2097
2079
  },
2098
2080
  "\u2715"
2099
- )), isOpen && !disabled && /* @__PURE__ */ React7.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.createElement("div", { className: "text-xs text-center pt-2 border-t border-border mt-2" }, "Select end date")));
2081
+ )), isOpen && !disabled && /* @__PURE__ */ React8.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.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React8.createElement("div", { className: "grid gap-4", style: monthsGridStyle }, renderMonth(selectedMonth, { prev: true }), renderMonth(addMonths(selectedMonth, 1), { next: true }))), rangeStart && !rangeEnd && /* @__PURE__ */ React8.createElement("div", { className: "text-xs text-center pt-2 border-t border-border mt-2" }, "Select end date")));
2100
2082
  }
2101
2083
  DateRangePicker.displayName = "DateRangePicker";
2102
2084
  function htmlToMarkdown(html) {
@@ -2167,11 +2149,11 @@ function RichTextEditor({
2167
2149
  ],
2168
2150
  ...props
2169
2151
  }) {
2170
- const [currentMode, setCurrentMode] = React7.useState(mode);
2171
- const [content, setContent] = React7.useState(value);
2172
- const editorRef = React7.useRef(null);
2173
- const textareaRef = React7.useRef(null);
2174
- React7.useEffect(() => {
2152
+ const [currentMode, setCurrentMode] = React8.useState(mode);
2153
+ const [content, setContent] = React8.useState(value);
2154
+ const editorRef = React8.useRef(null);
2155
+ const textareaRef = React8.useRef(null);
2156
+ React8.useEffect(() => {
2175
2157
  setContent(value);
2176
2158
  if (currentMode === "wysiwyg" && editorRef.current) {
2177
2159
  editorRef.current.innerHTML = value;
@@ -2259,16 +2241,27 @@ function RichTextEditor({
2259
2241
  }
2260
2242
  }
2261
2243
  };
2262
- const combinedClassName = `rounded-md border border-input ${error ? "border-red-500 ring-1 ring-red-500" : ""} ${disabled ? "opacity-50 cursor-not-allowed" : ""} ${className}`.trim();
2244
+ const hasValue = React8.useMemo(() => {
2245
+ if (!content) return false;
2246
+ const stripped = content.replace(/<[^>]+>/g, "").trim();
2247
+ return stripped.length > 0;
2248
+ }, [content]);
2249
+ const combinedClassName = cn(
2250
+ "rounded-md border border-input",
2251
+ !error && hasValue && "ring-2 ring-ring",
2252
+ error && "border-destructive ring-1 ring-destructive",
2253
+ disabled && "opacity-50 cursor-not-allowed",
2254
+ className
2255
+ );
2263
2256
  const editorStyle = {
2264
2257
  minHeight,
2265
2258
  maxHeight,
2266
2259
  overflowY: maxHeight ? "auto" : void 0
2267
2260
  };
2268
- return /* @__PURE__ */ React7.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React7.createElement("input", { type: "hidden", name, value: content }), showToolbar && /* @__PURE__ */ React7.createElement("div", { className: "flex items-center justify-between p-2 border-b border-border bg-muted/50" }, /* @__PURE__ */ React7.createElement("div", { className: "flex items-center gap-1" }, toolbarButtons.map((buttonName) => {
2261
+ return /* @__PURE__ */ React8.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React8.createElement("input", { type: "hidden", name, value: content }), showToolbar && /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-between p-2 border-b border-border bg-muted/50" }, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-1" }, toolbarButtons.map((buttonName) => {
2269
2262
  const button = toolbarConfig[buttonName];
2270
2263
  if (!button) return null;
2271
- return /* @__PURE__ */ React7.createElement(
2264
+ return /* @__PURE__ */ React8.createElement(
2272
2265
  "button",
2273
2266
  {
2274
2267
  key: buttonName,
@@ -2281,7 +2274,7 @@ function RichTextEditor({
2281
2274
  },
2282
2275
  button.icon
2283
2276
  );
2284
- })), allowModeSwitch && /* @__PURE__ */ React7.createElement(
2277
+ })), allowModeSwitch && /* @__PURE__ */ React8.createElement(
2285
2278
  "button",
2286
2279
  {
2287
2280
  type: "button",
@@ -2292,7 +2285,7 @@ function RichTextEditor({
2292
2285
  "aria-label": `Switch to ${currentMode === "wysiwyg" ? "Markdown" : "WYSIWYG"}`
2293
2286
  },
2294
2287
  currentMode === "wysiwyg" ? "MD" : "WYSIWYG"
2295
- )), /* @__PURE__ */ React7.createElement("div", { style: editorStyle }, currentMode === "wysiwyg" ? /* @__PURE__ */ React7.createElement(
2288
+ )), /* @__PURE__ */ React8.createElement("div", { style: editorStyle }, currentMode === "wysiwyg" ? /* @__PURE__ */ React8.createElement(
2296
2289
  "div",
2297
2290
  {
2298
2291
  ref: editorRef,
@@ -2307,11 +2300,14 @@ function RichTextEditor({
2307
2300
  "aria-required": required || props["aria-required"],
2308
2301
  suppressContentEditableWarning: true
2309
2302
  }
2310
- ) : /* @__PURE__ */ React7.createElement(
2303
+ ) : /* @__PURE__ */ React8.createElement(
2311
2304
  "textarea",
2312
2305
  {
2313
2306
  ref: textareaRef,
2314
- className: "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",
2307
+ className: cn(
2308
+ "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",
2309
+ INPUT_AUTOFILL_RESET_CLASSES
2310
+ ),
2315
2311
  value: content,
2316
2312
  onChange: handleMarkdownChange,
2317
2313
  onBlur,