@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/core.cjs +119 -27
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +104 -12
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +119 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +104 -12
- package/dist/index.js.map +1 -1
- package/dist/inputs.cjs +519 -523
- package/dist/inputs.cjs.map +1 -1
- package/dist/inputs.d.cts +21 -54
- package/dist/inputs.d.ts +21 -54
- package/dist/inputs.js +518 -522
- package/dist/inputs.js.map +1 -1
- package/dist/integration.cjs +11 -3
- package/dist/integration.cjs.map +1 -1
- package/dist/integration.js +11 -3
- package/dist/integration.js.map +1 -1
- package/package.json +1 -1
package/dist/inputs.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import * as
|
|
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
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
101
|
-
|
|
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
|
-
|
|
182
|
+
useChoiceCard = false,
|
|
118
183
|
...props
|
|
119
184
|
}) {
|
|
120
|
-
const inputRef =
|
|
185
|
+
const inputRef = React8.useRef(null);
|
|
121
186
|
const checkboxId = props.id || `checkbox-${name}`;
|
|
122
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
250
|
+
/* @__PURE__ */ React8.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
186
251
|
),
|
|
187
|
-
indeterminate && !value && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
-
|
|
209
|
-
|
|
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__ */
|
|
216
|
-
"
|
|
280
|
+
/* @__PURE__ */ React8.createElement(
|
|
281
|
+
"div",
|
|
217
282
|
{
|
|
218
|
-
className:
|
|
219
|
-
|
|
283
|
+
className: cn(
|
|
284
|
+
"flex w-full flex-row gap-2",
|
|
285
|
+
useChoiceCard ? "items-start" : "items-center"
|
|
286
|
+
)
|
|
220
287
|
},
|
|
221
|
-
|
|
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
|
|
257
|
-
if (options
|
|
258
|
-
|
|
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 =
|
|
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 =
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
|
|
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":
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
-
|
|
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__ */
|
|
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
|
-
|
|
425
|
+
useChoiceCard
|
|
342
426
|
}
|
|
343
427
|
);
|
|
344
428
|
}),
|
|
345
|
-
(minSelections || maxSelections) && /* @__PURE__ */
|
|
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__ */
|
|
355
|
-
maxSelections && /* @__PURE__ */
|
|
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 =
|
|
490
|
+
const useChoiceCard = React8.useMemo(() => {
|
|
406
491
|
return options.some((option) => option.description);
|
|
407
492
|
}, [options]);
|
|
408
|
-
const containerClass =
|
|
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
|
-
|
|
416
|
-
|
|
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":
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
554
|
+
isChecked && /* @__PURE__ */ React8.createElement("div", { className: "size-3 rounded-full bg-primary" })
|
|
460
555
|
));
|
|
461
|
-
const labelContent = /* @__PURE__ */
|
|
462
|
-
|
|
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__ */
|
|
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] =
|
|
502
|
-
const [searchQuery, setSearchQuery] =
|
|
503
|
-
const [focusedIndex, setFocusedIndex] =
|
|
504
|
-
const selectRef =
|
|
505
|
-
const searchInputRef =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
622
|
-
|
|
623
|
-
|
|
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
|
-
}
|
|
639
|
-
const
|
|
640
|
-
|
|
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__ */
|
|
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__ */
|
|
662
|
-
allOptions.map((option) => /* @__PURE__ */
|
|
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__ */
|
|
776
|
+
/* @__PURE__ */ React8.createElement(
|
|
665
777
|
"div",
|
|
666
778
|
{
|
|
667
|
-
className:
|
|
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__ */
|
|
679
|
-
/* @__PURE__ */
|
|
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__ */
|
|
807
|
+
), /* @__PURE__ */ React8.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
|
|
690
808
|
),
|
|
691
|
-
isOpen && /* @__PURE__ */
|
|
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__ */
|
|
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:
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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 =
|
|
787
|
-
const [dragActive, setDragActive] =
|
|
788
|
-
const [cropperOpen, setCropperOpen] =
|
|
789
|
-
const [imageToCrop, setImageToCrop] =
|
|
790
|
-
const [crop, setCrop] =
|
|
791
|
-
const [zoom, setZoom] =
|
|
792
|
-
const [croppedAreaPixels, setCroppedAreaPixels] =
|
|
793
|
-
const validateFile =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1087
|
+
const onCropChange = React8.useCallback((crop2) => {
|
|
967
1088
|
setCrop(crop2);
|
|
968
1089
|
}, []);
|
|
969
|
-
const onZoomChange =
|
|
1090
|
+
const onZoomChange = React8.useCallback((zoom2) => {
|
|
970
1091
|
setZoom(zoom2);
|
|
971
1092
|
}, []);
|
|
972
|
-
const onCropCompleteInternal =
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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-
|
|
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__ */
|
|
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__ */
|
|
1093
|
-
/* @__PURE__ */
|
|
1094
|
-
/* @__PURE__ */
|
|
1095
|
-
), /* @__PURE__ */
|
|
1096
|
-
), value.length > 0 && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1132
|
-
enableCropping && file.type.startsWith("image/") && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1158
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1187
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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] =
|
|
1369
|
-
const [
|
|
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 =
|
|
1374
|
-
const inputRef =
|
|
1375
|
-
|
|
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
|
|
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(!
|
|
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
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
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__ */
|
|
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-
|
|
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
|
-
"\
|
|
1468
|
-
), /* @__PURE__ */
|
|
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-
|
|
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
|
-
"\
|
|
1477
|
-
)), /* @__PURE__ */
|
|
1560
|
+
"\u203A"
|
|
1561
|
+
)), /* @__PURE__ */ React8.createElement(
|
|
1478
1562
|
"div",
|
|
1479
1563
|
{
|
|
1480
|
-
|
|
1481
|
-
|
|
1564
|
+
className: "grid gap-1 text-xs text-muted-foreground",
|
|
1565
|
+
style: dayGridStyle
|
|
1482
1566
|
},
|
|
1483
|
-
day
|
|
1484
|
-
|
|
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__ */
|
|
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__ */
|
|
1582
|
+
return /* @__PURE__ */ React8.createElement(
|
|
1492
1583
|
"button",
|
|
1493
1584
|
{
|
|
1494
1585
|
key: date.toISOString(),
|
|
1495
1586
|
type: "button",
|
|
1496
|
-
className:
|
|
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 =
|
|
1506
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1631
|
+
), /* @__PURE__ */ React8.createElement(
|
|
1535
1632
|
"input",
|
|
1536
1633
|
{
|
|
1537
1634
|
ref: inputRef,
|
|
1538
1635
|
type: "text",
|
|
1539
|
-
className:
|
|
1540
|
-
|
|
1541
|
-
|
|
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__ */
|
|
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__ */
|
|
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
|
|
1566
|
-
if (!
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
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
|
-
|
|
1589
|
-
return
|
|
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
|
|
1593
|
-
if (!
|
|
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
|
-
|
|
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
|
|
1623
|
-
const [
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
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
|
|
1664
|
-
|
|
1665
|
-
|
|
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__ */
|
|
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__ */
|
|
1717
|
-
/* @__PURE__ */
|
|
1766
|
+
/* @__PURE__ */ React8.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
1767
|
+
/* @__PURE__ */ React8.createElement("path", { d: "M12 6v6l4 2" })
|
|
1718
1768
|
)
|
|
1719
|
-
), /* @__PURE__ */
|
|
1769
|
+
), /* @__PURE__ */ React8.createElement(
|
|
1720
1770
|
"input",
|
|
1721
1771
|
{
|
|
1722
1772
|
ref: inputRef,
|
|
1723
|
-
type: "
|
|
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 && "
|
|
1782
|
+
!error && hasValue && "ring-2 ring-ring",
|
|
1783
|
+
error && "border-destructive ring-1 ring-destructive"
|
|
1731
1784
|
),
|
|
1732
|
-
value:
|
|
1733
|
-
|
|
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
|
-
|
|
1795
|
+
...props
|
|
1742
1796
|
}
|
|
1743
|
-
), clearable && value && !disabled && /* @__PURE__ */
|
|
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
|
-
))
|
|
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] =
|
|
1871
|
-
const [selectedMonth, setSelectedMonth] =
|
|
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] =
|
|
1875
|
-
const [rangeEnd, setRangeEnd] =
|
|
1876
|
-
const [hoverDate, setHoverDate] =
|
|
1877
|
-
const containerRef =
|
|
1878
|
-
|
|
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(!
|
|
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
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
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
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
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
|
-
|
|
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-
|
|
1972
|
-
onClick:
|
|
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
|
-
"\
|
|
1976
|
-
), /* @__PURE__ */
|
|
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-
|
|
1981
|
-
onClick:
|
|
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
|
-
"\
|
|
1985
|
-
)
|
|
1957
|
+
"\u203A"
|
|
1958
|
+
) : /* @__PURE__ */ React8.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" })), /* @__PURE__ */ React8.createElement(
|
|
1986
1959
|
"div",
|
|
1987
1960
|
{
|
|
1988
|
-
|
|
1989
|
-
|
|
1961
|
+
className: "grid gap-1 text-xs text-muted-foreground",
|
|
1962
|
+
style: dayGridStyle
|
|
1990
1963
|
},
|
|
1991
|
-
day
|
|
1992
|
-
|
|
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__ */
|
|
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__ */
|
|
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-
|
|
2013
|
-
"
|
|
2014
|
-
isRangeEndpoint && "bg-
|
|
2015
|
-
isRangeHighlight && "bg-muted
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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 && "
|
|
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__ */
|
|
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__ */
|
|
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] =
|
|
2171
|
-
const [content, setContent] =
|
|
2172
|
-
const editorRef =
|
|
2173
|
-
const textareaRef =
|
|
2174
|
-
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2303
|
+
) : /* @__PURE__ */ React8.createElement(
|
|
2311
2304
|
"textarea",
|
|
2312
2305
|
{
|
|
2313
2306
|
ref: textareaRef,
|
|
2314
|
-
className:
|
|
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,
|