@page-speed/forms 0.4.8 → 0.4.9
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 +15 -2
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +15 -2
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +86 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +82 -3
- package/dist/index.js.map +1 -1
- package/dist/inputs.cjs +914 -699
- package/dist/inputs.cjs.map +1 -1
- package/dist/inputs.d.cts +93 -182
- package/dist/inputs.d.ts +93 -182
- package/dist/inputs.js +911 -697
- package/dist/inputs.js.map +1 -1
- package/dist/{types-4ppM117e.d.cts → types-DuX3q6A4.d.cts} +1 -1
- package/dist/{types-4ppM117e.d.ts → types-DuX3q6A4.d.ts} +1 -1
- package/dist/validation-rules.d.cts +1 -1
- package/dist/validation-rules.d.ts +1 -1
- package/dist/validation-utils.d.cts +1 -1
- package/dist/validation-utils.d.ts +1 -1
- package/dist/validation-valibot.d.cts +1 -1
- package/dist/validation-valibot.d.ts +1 -1
- package/dist/validation.d.cts +1 -1
- package/dist/validation.d.ts +1 -1
- package/package.json +12 -2
package/dist/inputs.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as React17 from 'react';
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
import { Checkbox as Checkbox$1, Label as Label$1, RadioGroup as RadioGroup$1, Switch as Switch$1, Select as Select$1 } from 'radix-ui';
|
|
4
5
|
import { useOnClickOutside } from '@opensite/hooks/useOnClickOutside';
|
|
5
6
|
|
|
6
7
|
// src/inputs/TextInput.tsx
|
|
@@ -9,6 +10,36 @@ function cn(...inputs) {
|
|
|
9
10
|
}
|
|
10
11
|
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]";
|
|
11
12
|
|
|
13
|
+
// src/components/ui/input.tsx
|
|
14
|
+
function Input({ className, type, ...props }) {
|
|
15
|
+
return /* @__PURE__ */ React17.createElement(
|
|
16
|
+
"input",
|
|
17
|
+
{
|
|
18
|
+
type,
|
|
19
|
+
"data-slot": "input",
|
|
20
|
+
className: cn(
|
|
21
|
+
// Core structure - no hardcoded colors, uses CSS variables
|
|
22
|
+
"flex h-9 w-full min-w-0 rounded-md border border-input",
|
|
23
|
+
"bg-transparent px-3 py-1 text-base shadow-sm",
|
|
24
|
+
"transition-colors outline-none md:text-sm",
|
|
25
|
+
// Focus state - uses ring-ring CSS variable (adapts to theme)
|
|
26
|
+
"focus-visible:ring-1 focus-visible:ring-ring",
|
|
27
|
+
// Error state - uses destructive CSS variables (adapts to theme)
|
|
28
|
+
"aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive",
|
|
29
|
+
// Disabled state - no color hardcoding
|
|
30
|
+
"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
31
|
+
// File input specific - inherits text color from parent
|
|
32
|
+
"file:inline-flex file:h-7 file:border-0 file:bg-transparent",
|
|
33
|
+
"file:text-sm file:font-medium",
|
|
34
|
+
// Autofill reset - prevents browser from overriding our dynamic colors
|
|
35
|
+
INPUT_AUTOFILL_RESET_CLASSES,
|
|
36
|
+
className
|
|
37
|
+
),
|
|
38
|
+
...props
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
12
43
|
// src/inputs/TextInput.tsx
|
|
13
44
|
function TextInput({
|
|
14
45
|
name,
|
|
@@ -31,17 +62,8 @@ function TextInput({
|
|
|
31
62
|
onBlur?.();
|
|
32
63
|
};
|
|
33
64
|
const hasValue = String(value ?? "").trim().length > 0;
|
|
34
|
-
|
|
35
|
-
|
|
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__ */ React9.createElement(
|
|
44
|
-
"input",
|
|
65
|
+
return /* @__PURE__ */ React17.createElement(
|
|
66
|
+
Input,
|
|
45
67
|
{
|
|
46
68
|
type,
|
|
47
69
|
id,
|
|
@@ -52,7 +74,12 @@ function TextInput({
|
|
|
52
74
|
placeholder,
|
|
53
75
|
disabled,
|
|
54
76
|
required,
|
|
55
|
-
className:
|
|
77
|
+
className: cn(
|
|
78
|
+
// Valid value indicator - ring-2 when has value and no error
|
|
79
|
+
!error && hasValue && "ring-2 ring-ring",
|
|
80
|
+
// Error state - handled by Input component via aria-invalid
|
|
81
|
+
className
|
|
82
|
+
),
|
|
56
83
|
"aria-invalid": error || props["aria-invalid"],
|
|
57
84
|
"aria-describedby": props["aria-describedby"],
|
|
58
85
|
"aria-required": required || props["aria-required"],
|
|
@@ -61,6 +88,30 @@ function TextInput({
|
|
|
61
88
|
);
|
|
62
89
|
}
|
|
63
90
|
TextInput.displayName = "TextInput";
|
|
91
|
+
function Textarea({ className, ...props }) {
|
|
92
|
+
return /* @__PURE__ */ React17.createElement(
|
|
93
|
+
"textarea",
|
|
94
|
+
{
|
|
95
|
+
"data-slot": "textarea",
|
|
96
|
+
className: cn(
|
|
97
|
+
// Core structure - uses CSS variables only
|
|
98
|
+
"flex field-sizing-content min-h-16 w-full rounded-md border border-input",
|
|
99
|
+
"bg-transparent px-3 py-2 text-base shadow-xs",
|
|
100
|
+
"transition-[color,box-shadow] outline-none md:text-sm",
|
|
101
|
+
// Focus state - uses ring-ring CSS variable
|
|
102
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
103
|
+
// Error state - uses destructive CSS variables
|
|
104
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20",
|
|
105
|
+
// Disabled state
|
|
106
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
107
|
+
className
|
|
108
|
+
),
|
|
109
|
+
...props
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/inputs/TextArea.tsx
|
|
64
115
|
function TextArea({
|
|
65
116
|
name,
|
|
66
117
|
value,
|
|
@@ -85,17 +136,8 @@ function TextArea({
|
|
|
85
136
|
onBlur?.();
|
|
86
137
|
};
|
|
87
138
|
const hasValue = String(value ?? "").trim().length > 0;
|
|
88
|
-
|
|
89
|
-
|
|
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__ */ React9.createElement(
|
|
98
|
-
"textarea",
|
|
139
|
+
return /* @__PURE__ */ React17.createElement(
|
|
140
|
+
Textarea,
|
|
99
141
|
{
|
|
100
142
|
name,
|
|
101
143
|
value: value ?? "",
|
|
@@ -104,7 +146,12 @@ function TextArea({
|
|
|
104
146
|
placeholder,
|
|
105
147
|
disabled,
|
|
106
148
|
required,
|
|
107
|
-
className:
|
|
149
|
+
className: cn(
|
|
150
|
+
// Valid value indicator - ring-2 when has value and no error
|
|
151
|
+
!error && hasValue && "ring-2 ring-ring",
|
|
152
|
+
// Error state - handled by Textarea component via aria-invalid
|
|
153
|
+
className
|
|
154
|
+
),
|
|
108
155
|
rows,
|
|
109
156
|
cols,
|
|
110
157
|
maxLength,
|
|
@@ -118,6 +165,175 @@ function TextArea({
|
|
|
118
165
|
);
|
|
119
166
|
}
|
|
120
167
|
TextArea.displayName = "TextArea";
|
|
168
|
+
function Checkbox({
|
|
169
|
+
className,
|
|
170
|
+
...props
|
|
171
|
+
}) {
|
|
172
|
+
return /* @__PURE__ */ React17.createElement(
|
|
173
|
+
Checkbox$1.Root,
|
|
174
|
+
{
|
|
175
|
+
"data-slot": "checkbox",
|
|
176
|
+
className: cn(
|
|
177
|
+
// Core structure - uses CSS variables
|
|
178
|
+
"peer size-4 shrink-0 rounded-[4px] border border-input bg-transparent shadow-xs",
|
|
179
|
+
"transition-shadow outline-none",
|
|
180
|
+
// Checked state - uses primary CSS variables
|
|
181
|
+
"data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
182
|
+
"data-[state=checked]:border-primary",
|
|
183
|
+
// Focus state - uses ring-ring CSS variable
|
|
184
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
185
|
+
// Error state - uses destructive CSS variables
|
|
186
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20",
|
|
187
|
+
// Disabled state
|
|
188
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
189
|
+
className
|
|
190
|
+
),
|
|
191
|
+
...props
|
|
192
|
+
},
|
|
193
|
+
/* @__PURE__ */ React17.createElement(
|
|
194
|
+
Checkbox$1.Indicator,
|
|
195
|
+
{
|
|
196
|
+
"data-slot": "checkbox-indicator",
|
|
197
|
+
className: "grid place-content-center text-current transition-none"
|
|
198
|
+
},
|
|
199
|
+
/* @__PURE__ */ React17.createElement(
|
|
200
|
+
"svg",
|
|
201
|
+
{
|
|
202
|
+
className: "size-3.5",
|
|
203
|
+
viewBox: "0 0 24 24",
|
|
204
|
+
fill: "none",
|
|
205
|
+
stroke: "currentColor",
|
|
206
|
+
strokeWidth: "3",
|
|
207
|
+
strokeLinecap: "round",
|
|
208
|
+
strokeLinejoin: "round"
|
|
209
|
+
},
|
|
210
|
+
/* @__PURE__ */ React17.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
function Label({
|
|
216
|
+
className,
|
|
217
|
+
...props
|
|
218
|
+
}) {
|
|
219
|
+
return /* @__PURE__ */ React17.createElement(
|
|
220
|
+
Label$1.Root,
|
|
221
|
+
{
|
|
222
|
+
"data-slot": "label",
|
|
223
|
+
className: cn(
|
|
224
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
225
|
+
className
|
|
226
|
+
),
|
|
227
|
+
...props
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/inputs/Checkbox.tsx
|
|
233
|
+
function Checkbox2({
|
|
234
|
+
name,
|
|
235
|
+
value,
|
|
236
|
+
onChange,
|
|
237
|
+
onBlur,
|
|
238
|
+
disabled = false,
|
|
239
|
+
required = false,
|
|
240
|
+
error = false,
|
|
241
|
+
className = "",
|
|
242
|
+
label,
|
|
243
|
+
description,
|
|
244
|
+
useChoiceCard = false,
|
|
245
|
+
...props
|
|
246
|
+
}) {
|
|
247
|
+
const checkboxId = props.id || `checkbox-${name}`;
|
|
248
|
+
const handleCheckedChange = (checked) => {
|
|
249
|
+
onChange(checked);
|
|
250
|
+
};
|
|
251
|
+
const handleBlur = () => {
|
|
252
|
+
onBlur?.();
|
|
253
|
+
};
|
|
254
|
+
const showChoiceCard = useChoiceCard || !!description;
|
|
255
|
+
const checkbox = /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(
|
|
256
|
+
"input",
|
|
257
|
+
{
|
|
258
|
+
type: "checkbox",
|
|
259
|
+
name,
|
|
260
|
+
checked: value,
|
|
261
|
+
onChange: () => {
|
|
262
|
+
},
|
|
263
|
+
disabled,
|
|
264
|
+
required,
|
|
265
|
+
tabIndex: -1,
|
|
266
|
+
"aria-hidden": "true",
|
|
267
|
+
style: {
|
|
268
|
+
position: "absolute",
|
|
269
|
+
width: "1px",
|
|
270
|
+
height: "1px",
|
|
271
|
+
padding: 0,
|
|
272
|
+
margin: "-1px",
|
|
273
|
+
overflow: "hidden",
|
|
274
|
+
clip: "rect(0, 0, 0, 0)",
|
|
275
|
+
whiteSpace: "nowrap",
|
|
276
|
+
border: 0
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
), /* @__PURE__ */ React17.createElement(
|
|
280
|
+
Checkbox,
|
|
281
|
+
{
|
|
282
|
+
id: checkboxId,
|
|
283
|
+
checked: value,
|
|
284
|
+
onCheckedChange: handleCheckedChange,
|
|
285
|
+
onBlur: handleBlur,
|
|
286
|
+
disabled,
|
|
287
|
+
"aria-invalid": error || props["aria-invalid"],
|
|
288
|
+
"aria-describedby": description ? `${checkboxId}-description` : props["aria-describedby"],
|
|
289
|
+
"aria-required": required || props["aria-required"],
|
|
290
|
+
...props
|
|
291
|
+
}
|
|
292
|
+
));
|
|
293
|
+
if (!label) {
|
|
294
|
+
return /* @__PURE__ */ React17.createElement("div", { className }, checkbox);
|
|
295
|
+
}
|
|
296
|
+
return /* @__PURE__ */ React17.createElement(
|
|
297
|
+
"label",
|
|
298
|
+
{
|
|
299
|
+
htmlFor: checkboxId,
|
|
300
|
+
className: cn(
|
|
301
|
+
"flex gap-3 p-3 duration-200",
|
|
302
|
+
showChoiceCard && "border rounded-lg hover:ring-2 hover:ring-ring/50",
|
|
303
|
+
showChoiceCard && value && "ring-2 ring-ring",
|
|
304
|
+
showChoiceCard && error && "border-destructive",
|
|
305
|
+
disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
|
|
306
|
+
className
|
|
307
|
+
)
|
|
308
|
+
},
|
|
309
|
+
/* @__PURE__ */ React17.createElement(
|
|
310
|
+
"div",
|
|
311
|
+
{
|
|
312
|
+
className: cn(
|
|
313
|
+
"flex w-full gap-3",
|
|
314
|
+
showChoiceCard ? "items-start" : "items-center"
|
|
315
|
+
)
|
|
316
|
+
},
|
|
317
|
+
checkbox,
|
|
318
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React17.createElement(
|
|
319
|
+
Label,
|
|
320
|
+
{
|
|
321
|
+
htmlFor: checkboxId,
|
|
322
|
+
className: "cursor-pointer font-medium leading-none"
|
|
323
|
+
},
|
|
324
|
+
label
|
|
325
|
+
), description && /* @__PURE__ */ React17.createElement(
|
|
326
|
+
"p",
|
|
327
|
+
{
|
|
328
|
+
id: `${checkboxId}-description`,
|
|
329
|
+
className: "text-sm opacity-70 leading-snug"
|
|
330
|
+
},
|
|
331
|
+
description
|
|
332
|
+
))
|
|
333
|
+
)
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
Checkbox2.displayName = "Checkbox";
|
|
121
337
|
var LabelGroup = ({
|
|
122
338
|
labelHtmlFor,
|
|
123
339
|
required = false,
|
|
@@ -133,11 +349,11 @@ var LabelGroup = ({
|
|
|
133
349
|
variant === "legend" ? "mb-1.5" : "mb-1 block",
|
|
134
350
|
primaryClassName
|
|
135
351
|
);
|
|
136
|
-
const requiredIndicator = required ? /* @__PURE__ */
|
|
352
|
+
const requiredIndicator = required ? /* @__PURE__ */ React17.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
|
|
137
353
|
let primaryElement = null;
|
|
138
354
|
if (primary) {
|
|
139
355
|
if (variant === "label") {
|
|
140
|
-
primaryElement = /* @__PURE__ */
|
|
356
|
+
primaryElement = /* @__PURE__ */ React17.createElement(
|
|
141
357
|
"label",
|
|
142
358
|
{
|
|
143
359
|
htmlFor: labelHtmlFor,
|
|
@@ -148,12 +364,12 @@ var LabelGroup = ({
|
|
|
148
364
|
requiredIndicator
|
|
149
365
|
);
|
|
150
366
|
} else if (variant === "legend") {
|
|
151
|
-
primaryElement = /* @__PURE__ */
|
|
367
|
+
primaryElement = /* @__PURE__ */ React17.createElement("legend", { "data-slot": "field-legend", className: primaryClasses }, primary, requiredIndicator);
|
|
152
368
|
} else {
|
|
153
|
-
primaryElement = /* @__PURE__ */
|
|
369
|
+
primaryElement = /* @__PURE__ */ React17.createElement("div", { "data-slot": "field-label", className: primaryClasses }, primary, requiredIndicator);
|
|
154
370
|
}
|
|
155
371
|
}
|
|
156
|
-
const secondaryElement = secondary ? /* @__PURE__ */
|
|
372
|
+
const secondaryElement = secondary ? /* @__PURE__ */ React17.createElement(
|
|
157
373
|
"p",
|
|
158
374
|
{
|
|
159
375
|
"data-slot": "field-description",
|
|
@@ -164,148 +380,12 @@ var LabelGroup = ({
|
|
|
164
380
|
) : null;
|
|
165
381
|
if (!primaryElement && !secondaryElement) return null;
|
|
166
382
|
if (variant === "legend") {
|
|
167
|
-
return /* @__PURE__ */
|
|
383
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, primaryElement, secondaryElement);
|
|
168
384
|
}
|
|
169
|
-
return /* @__PURE__ */
|
|
385
|
+
return /* @__PURE__ */ React17.createElement("div", { className: "flex flex-1 flex-col gap-0.5" }, primaryElement, secondaryElement);
|
|
170
386
|
};
|
|
171
387
|
|
|
172
|
-
// src/inputs/
|
|
173
|
-
function Checkbox({
|
|
174
|
-
name,
|
|
175
|
-
value,
|
|
176
|
-
onChange,
|
|
177
|
-
onBlur,
|
|
178
|
-
disabled = false,
|
|
179
|
-
required = false,
|
|
180
|
-
error = false,
|
|
181
|
-
className = "",
|
|
182
|
-
indeterminate = false,
|
|
183
|
-
label,
|
|
184
|
-
description,
|
|
185
|
-
useChoiceCard = false,
|
|
186
|
-
...props
|
|
187
|
-
}) {
|
|
188
|
-
const inputRef = React9.useRef(null);
|
|
189
|
-
const checkboxId = props.id || `checkbox-${name}`;
|
|
190
|
-
React9.useEffect(() => {
|
|
191
|
-
if (inputRef.current) {
|
|
192
|
-
inputRef.current.indeterminate = indeterminate;
|
|
193
|
-
}
|
|
194
|
-
}, [indeterminate]);
|
|
195
|
-
const handleChange = (e) => {
|
|
196
|
-
onChange(e.target.checked);
|
|
197
|
-
};
|
|
198
|
-
const handleBlur = () => {
|
|
199
|
-
onBlur?.();
|
|
200
|
-
};
|
|
201
|
-
const isActive = value || indeterminate && !value;
|
|
202
|
-
const checkbox = /* @__PURE__ */ React9.createElement(
|
|
203
|
-
"div",
|
|
204
|
-
{
|
|
205
|
-
className: cn(
|
|
206
|
-
"relative inline-flex items-center justify-center",
|
|
207
|
-
!label && className
|
|
208
|
-
)
|
|
209
|
-
},
|
|
210
|
-
/* @__PURE__ */ React9.createElement(
|
|
211
|
-
"input",
|
|
212
|
-
{
|
|
213
|
-
ref: inputRef,
|
|
214
|
-
type: "checkbox",
|
|
215
|
-
id: checkboxId,
|
|
216
|
-
name,
|
|
217
|
-
checked: value,
|
|
218
|
-
onChange: handleChange,
|
|
219
|
-
onBlur: handleBlur,
|
|
220
|
-
disabled,
|
|
221
|
-
required,
|
|
222
|
-
className: "peer sr-only",
|
|
223
|
-
"aria-invalid": error || props["aria-invalid"],
|
|
224
|
-
"aria-describedby": description ? `${checkboxId}-description` : props["aria-describedby"],
|
|
225
|
-
"aria-required": required || props["aria-required"],
|
|
226
|
-
...props
|
|
227
|
-
}
|
|
228
|
-
),
|
|
229
|
-
/* @__PURE__ */ React9.createElement(
|
|
230
|
-
"div",
|
|
231
|
-
{
|
|
232
|
-
className: cn(
|
|
233
|
-
"flex shrink-0 items-center justify-center rounded-full border-2 transition-colors size-6",
|
|
234
|
-
!error && isActive && "border-primary bg-primary text-primary-foreground",
|
|
235
|
-
!error && !isActive && "border-input bg-transparent",
|
|
236
|
-
error && isActive && "border-destructive bg-destructive text-destructive-foreground",
|
|
237
|
-
error && !isActive && "border-destructive bg-transparent",
|
|
238
|
-
disabled && "opacity-50",
|
|
239
|
-
"peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-1"
|
|
240
|
-
)
|
|
241
|
-
},
|
|
242
|
-
value && /* @__PURE__ */ React9.createElement(
|
|
243
|
-
"svg",
|
|
244
|
-
{
|
|
245
|
-
className: "size-3.5",
|
|
246
|
-
viewBox: "0 0 24 24",
|
|
247
|
-
fill: "none",
|
|
248
|
-
stroke: "currentColor",
|
|
249
|
-
strokeWidth: "3",
|
|
250
|
-
strokeLinecap: "round",
|
|
251
|
-
strokeLinejoin: "round"
|
|
252
|
-
},
|
|
253
|
-
/* @__PURE__ */ React9.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
254
|
-
),
|
|
255
|
-
indeterminate && !value && /* @__PURE__ */ React9.createElement(
|
|
256
|
-
"svg",
|
|
257
|
-
{
|
|
258
|
-
className: "size-3.5",
|
|
259
|
-
viewBox: "0 0 24 24",
|
|
260
|
-
fill: "none",
|
|
261
|
-
stroke: "currentColor",
|
|
262
|
-
strokeWidth: "3",
|
|
263
|
-
strokeLinecap: "round",
|
|
264
|
-
strokeLinejoin: "round"
|
|
265
|
-
},
|
|
266
|
-
/* @__PURE__ */ React9.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
267
|
-
)
|
|
268
|
-
)
|
|
269
|
-
);
|
|
270
|
-
if (label) {
|
|
271
|
-
return /* @__PURE__ */ React9.createElement(
|
|
272
|
-
"label",
|
|
273
|
-
{
|
|
274
|
-
className: cn(
|
|
275
|
-
"w-full h-full flex gap-3 p-3 duration-200",
|
|
276
|
-
useChoiceCard && "border rounded-lg hover:ring-2",
|
|
277
|
-
useChoiceCard && value && "ring-2",
|
|
278
|
-
disabled ? "opacity-50 cursor-not-allowed hover:ring-0" : "cursor-pointer",
|
|
279
|
-
className
|
|
280
|
-
),
|
|
281
|
-
htmlFor: checkboxId
|
|
282
|
-
},
|
|
283
|
-
/* @__PURE__ */ React9.createElement(
|
|
284
|
-
"div",
|
|
285
|
-
{
|
|
286
|
-
className: cn(
|
|
287
|
-
"flex w-full flex-row gap-2",
|
|
288
|
-
useChoiceCard ? "items-start" : "items-center"
|
|
289
|
-
)
|
|
290
|
-
},
|
|
291
|
-
checkbox,
|
|
292
|
-
/* @__PURE__ */ React9.createElement(
|
|
293
|
-
LabelGroup,
|
|
294
|
-
{
|
|
295
|
-
variant: "text",
|
|
296
|
-
primary: label,
|
|
297
|
-
secondary: description,
|
|
298
|
-
secondaryId: description ? `${checkboxId}-description` : void 0,
|
|
299
|
-
primaryClassName: "mb-0",
|
|
300
|
-
secondaryClassName: "text-xs opacity-75"
|
|
301
|
-
}
|
|
302
|
-
)
|
|
303
|
-
)
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
return checkbox;
|
|
307
|
-
}
|
|
308
|
-
Checkbox.displayName = "Checkbox";
|
|
388
|
+
// src/inputs/CheckboxGroup.tsx
|
|
309
389
|
function CheckboxGroup({
|
|
310
390
|
name,
|
|
311
391
|
value = [],
|
|
@@ -334,11 +414,11 @@ function CheckboxGroup({
|
|
|
334
414
|
).length;
|
|
335
415
|
const allSelected = selectedEnabledCount === enabledOptions.length;
|
|
336
416
|
const someSelected = selectedEnabledCount > 0 && !allSelected;
|
|
337
|
-
const useChoiceCard =
|
|
417
|
+
const useChoiceCard = React17.useMemo(() => {
|
|
338
418
|
if (!options) return false;
|
|
339
419
|
return options?.some((opt) => opt.description);
|
|
340
420
|
}, [options]);
|
|
341
|
-
const countableValue =
|
|
421
|
+
const countableValue = React17.useMemo(() => {
|
|
342
422
|
if (value?.length > 0) {
|
|
343
423
|
return value.length;
|
|
344
424
|
}
|
|
@@ -363,7 +443,7 @@ function CheckboxGroup({
|
|
|
363
443
|
onBlur?.();
|
|
364
444
|
};
|
|
365
445
|
const maxReached = Boolean(maxSelections && countableValue >= maxSelections);
|
|
366
|
-
const containerClass =
|
|
446
|
+
const containerClass = React17.useMemo(() => {
|
|
367
447
|
return cn(
|
|
368
448
|
"w-full gap-3 grid grid-cols-1 border-0 m-0 p-0 min-w-0",
|
|
369
449
|
(layout === "grid" || layout === "inline") && "md:grid-cols-2",
|
|
@@ -372,7 +452,7 @@ function CheckboxGroup({
|
|
|
372
452
|
}, [layout, className]);
|
|
373
453
|
const groupDescriptionId = description ? `${name}-description` : void 0;
|
|
374
454
|
const groupAriaDescribedBy = [props["aria-describedby"], groupDescriptionId].filter(Boolean).join(" ") || void 0;
|
|
375
|
-
return /* @__PURE__ */
|
|
455
|
+
return /* @__PURE__ */ React17.createElement(
|
|
376
456
|
"fieldset",
|
|
377
457
|
{
|
|
378
458
|
className: containerClass,
|
|
@@ -382,7 +462,7 @@ function CheckboxGroup({
|
|
|
382
462
|
"aria-required": required || props["aria-required"],
|
|
383
463
|
"aria-label": typeof label === "string" ? label : props["aria-label"]
|
|
384
464
|
},
|
|
385
|
-
/* @__PURE__ */
|
|
465
|
+
/* @__PURE__ */ React17.createElement(
|
|
386
466
|
LabelGroup,
|
|
387
467
|
{
|
|
388
468
|
labelHtmlFor: name,
|
|
@@ -393,8 +473,8 @@ function CheckboxGroup({
|
|
|
393
473
|
primary: label
|
|
394
474
|
}
|
|
395
475
|
),
|
|
396
|
-
showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */
|
|
397
|
-
|
|
476
|
+
showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */ React17.createElement(
|
|
477
|
+
Checkbox2,
|
|
398
478
|
{
|
|
399
479
|
name: `${name}-select-all`,
|
|
400
480
|
id: `${name}-select-all`,
|
|
@@ -411,8 +491,8 @@ function CheckboxGroup({
|
|
|
411
491
|
options.map((option) => {
|
|
412
492
|
const isChecked = value.includes(option.value);
|
|
413
493
|
const isDisabled = disabled || option.disabled || maxReached && !isChecked;
|
|
414
|
-
return /* @__PURE__ */
|
|
415
|
-
|
|
494
|
+
return /* @__PURE__ */ React17.createElement(
|
|
495
|
+
Checkbox2,
|
|
416
496
|
{
|
|
417
497
|
key: option.value,
|
|
418
498
|
name,
|
|
@@ -429,7 +509,7 @@ function CheckboxGroup({
|
|
|
429
509
|
}
|
|
430
510
|
);
|
|
431
511
|
}),
|
|
432
|
-
(minSelections || maxSelections) && /* @__PURE__ */
|
|
512
|
+
(minSelections || maxSelections) && /* @__PURE__ */ React17.createElement(
|
|
433
513
|
"div",
|
|
434
514
|
{
|
|
435
515
|
className: cn(
|
|
@@ -438,12 +518,66 @@ function CheckboxGroup({
|
|
|
438
518
|
),
|
|
439
519
|
"aria-live": "polite"
|
|
440
520
|
},
|
|
441
|
-
minSelections && countableValue < minSelections && /* @__PURE__ */
|
|
442
|
-
maxSelections && /* @__PURE__ */
|
|
521
|
+
minSelections && countableValue < minSelections && /* @__PURE__ */ React17.createElement("span", null, "Select at least ", minSelections, " option", minSelections !== 1 ? "s" : ""),
|
|
522
|
+
maxSelections && /* @__PURE__ */ React17.createElement("span", null, countableValue, "/", maxSelections, " selected")
|
|
443
523
|
)
|
|
444
524
|
);
|
|
445
525
|
}
|
|
446
526
|
CheckboxGroup.displayName = "CheckboxGroup";
|
|
527
|
+
function RadioGroup({
|
|
528
|
+
className,
|
|
529
|
+
...props
|
|
530
|
+
}) {
|
|
531
|
+
return /* @__PURE__ */ React17.createElement(
|
|
532
|
+
RadioGroup$1.Root,
|
|
533
|
+
{
|
|
534
|
+
"data-slot": "radio-group",
|
|
535
|
+
className: cn("grid gap-3", className),
|
|
536
|
+
...props
|
|
537
|
+
}
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
function RadioGroupItem({
|
|
541
|
+
className,
|
|
542
|
+
...props
|
|
543
|
+
}) {
|
|
544
|
+
return /* @__PURE__ */ React17.createElement(
|
|
545
|
+
RadioGroup$1.Item,
|
|
546
|
+
{
|
|
547
|
+
"data-slot": "radio-group-item",
|
|
548
|
+
className: cn(
|
|
549
|
+
// Core structure - uses CSS variables
|
|
550
|
+
"aspect-square size-4 shrink-0 rounded-full border border-input bg-transparent shadow-xs",
|
|
551
|
+
"text-primary transition-[color,box-shadow] outline-none",
|
|
552
|
+
// Focus state - uses ring-ring CSS variable
|
|
553
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
554
|
+
// Error state - uses destructive CSS variables
|
|
555
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20",
|
|
556
|
+
// Disabled state
|
|
557
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
558
|
+
className
|
|
559
|
+
),
|
|
560
|
+
...props
|
|
561
|
+
},
|
|
562
|
+
/* @__PURE__ */ React17.createElement(
|
|
563
|
+
RadioGroup$1.Indicator,
|
|
564
|
+
{
|
|
565
|
+
"data-slot": "radio-group-indicator",
|
|
566
|
+
className: "relative flex items-center justify-center"
|
|
567
|
+
},
|
|
568
|
+
/* @__PURE__ */ React17.createElement(
|
|
569
|
+
"svg",
|
|
570
|
+
{
|
|
571
|
+
className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2",
|
|
572
|
+
viewBox: "0 0 24 24"
|
|
573
|
+
},
|
|
574
|
+
/* @__PURE__ */ React17.createElement("circle", { cx: "12", cy: "12", r: "12" })
|
|
575
|
+
)
|
|
576
|
+
)
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// src/inputs/Radio.tsx
|
|
447
581
|
function Radio({
|
|
448
582
|
name,
|
|
449
583
|
value,
|
|
@@ -459,146 +593,433 @@ function Radio({
|
|
|
459
593
|
options,
|
|
460
594
|
...props
|
|
461
595
|
}) {
|
|
462
|
-
const
|
|
463
|
-
onChange(
|
|
464
|
-
};
|
|
465
|
-
const handleKeyDown = (e, currentIndex) => {
|
|
466
|
-
if (e.key === "ArrowDown" || e.key === "ArrowRight") {
|
|
467
|
-
e.preventDefault();
|
|
468
|
-
let nextIndex = (currentIndex + 1) % options.length;
|
|
469
|
-
let attempts = 0;
|
|
470
|
-
while (options[nextIndex].disabled && attempts < options.length && !disabled) {
|
|
471
|
-
nextIndex = (nextIndex + 1) % options.length;
|
|
472
|
-
attempts++;
|
|
473
|
-
}
|
|
474
|
-
if (!options[nextIndex].disabled) {
|
|
475
|
-
handleChange(options[nextIndex].value);
|
|
476
|
-
}
|
|
477
|
-
} else if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
|
|
478
|
-
e.preventDefault();
|
|
479
|
-
let prevIndex = (currentIndex - 1 + options.length) % options.length;
|
|
480
|
-
let attempts = 0;
|
|
481
|
-
while (options[prevIndex].disabled && attempts < options.length && !disabled) {
|
|
482
|
-
prevIndex = (prevIndex - 1 + options.length) % options.length;
|
|
483
|
-
attempts++;
|
|
484
|
-
}
|
|
485
|
-
if (!options[prevIndex].disabled) {
|
|
486
|
-
handleChange(options[prevIndex].value);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
596
|
+
const handleValueChange = (selectedValue) => {
|
|
597
|
+
onChange(selectedValue);
|
|
489
598
|
};
|
|
490
599
|
const handleBlur = () => {
|
|
491
600
|
onBlur?.();
|
|
492
601
|
};
|
|
493
|
-
const useChoiceCard =
|
|
602
|
+
const useChoiceCard = React17.useMemo(() => {
|
|
494
603
|
return options.some((option) => option.description);
|
|
495
604
|
}, [options]);
|
|
496
|
-
const containerClass = React9.useMemo(() => {
|
|
497
|
-
return cn(
|
|
498
|
-
"w-full gap-3 grid grid-cols-1 border-0 m-0 p-0 min-w-0",
|
|
499
|
-
(layout === "grid" || layout === "inline") && "md:grid-cols-2",
|
|
500
|
-
className
|
|
501
|
-
);
|
|
502
|
-
}, [layout, className]);
|
|
503
605
|
const groupDescriptionId = description ? `${name}-description` : void 0;
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
"fieldset",
|
|
606
|
+
return /* @__PURE__ */ React17.createElement("div", { className: cn("w-full", className) }, (label || description) && /* @__PURE__ */ React17.createElement("div", { className: "mb-3" }, label && /* @__PURE__ */ React17.createElement(Label, { className: "text-base font-medium block mb-1" }, label), description && /* @__PURE__ */ React17.createElement(
|
|
607
|
+
"p",
|
|
507
608
|
{
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
"aria-invalid": error || props["aria-invalid"],
|
|
511
|
-
"aria-describedby": groupAriaDescribedBy,
|
|
512
|
-
"aria-required": required || props["aria-required"],
|
|
513
|
-
"aria-label": typeof label === "string" ? label : props["aria-label"]
|
|
609
|
+
id: groupDescriptionId,
|
|
610
|
+
className: "text-sm opacity-70"
|
|
514
611
|
},
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
612
|
+
description
|
|
613
|
+
)), /* @__PURE__ */ React17.createElement(
|
|
614
|
+
RadioGroup,
|
|
615
|
+
{
|
|
616
|
+
name,
|
|
617
|
+
value,
|
|
618
|
+
onValueChange: handleValueChange,
|
|
619
|
+
onBlur: handleBlur,
|
|
620
|
+
disabled,
|
|
621
|
+
required,
|
|
622
|
+
className: cn(
|
|
623
|
+
"gap-3",
|
|
624
|
+
layout === "grid" && "grid grid-cols-1 md:grid-cols-2",
|
|
625
|
+
layout === "inline" && "flex flex-wrap"
|
|
626
|
+
),
|
|
627
|
+
"aria-invalid": error || props["aria-invalid"],
|
|
628
|
+
"aria-describedby": groupDescriptionId || props["aria-describedby"],
|
|
629
|
+
"aria-required": required || props["aria-required"]
|
|
630
|
+
},
|
|
631
|
+
options.map((option) => {
|
|
632
|
+
const isSelected = value === option.value;
|
|
526
633
|
const isDisabled = disabled || option.disabled;
|
|
527
634
|
const radioId = `${name}-${option.value}`;
|
|
528
|
-
const hasDescription = option.description
|
|
529
|
-
|
|
530
|
-
"input",
|
|
531
|
-
{
|
|
532
|
-
type: "radio",
|
|
533
|
-
id: radioId,
|
|
534
|
-
name,
|
|
535
|
-
value: option.value,
|
|
536
|
-
checked: isChecked,
|
|
537
|
-
onChange: (e) => handleChange(e.target.value),
|
|
538
|
-
onBlur: handleBlur,
|
|
539
|
-
disabled: isDisabled,
|
|
540
|
-
required,
|
|
541
|
-
className: "peer sr-only",
|
|
542
|
-
"aria-describedby": hasDescription ? `${radioId}-description` : props["aria-describedby"]
|
|
543
|
-
}
|
|
544
|
-
), /* @__PURE__ */ React9.createElement(
|
|
545
|
-
"div",
|
|
546
|
-
{
|
|
547
|
-
className: cn(
|
|
548
|
-
"flex shrink-0 items-center justify-center rounded-full border-2 transition-colors size-6",
|
|
549
|
-
!error && isChecked && "border-primary bg-transparent",
|
|
550
|
-
!error && !isChecked && "border-input bg-transparent",
|
|
551
|
-
error && isChecked && "border-destructive bg-transparent",
|
|
552
|
-
error && !isChecked && "border-destructive bg-transparent",
|
|
553
|
-
isDisabled && "opacity-50",
|
|
554
|
-
"peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-1"
|
|
555
|
-
)
|
|
556
|
-
},
|
|
557
|
-
isChecked && /* @__PURE__ */ React9.createElement("div", { className: "size-3 rounded-full bg-primary" })
|
|
558
|
-
));
|
|
559
|
-
const labelContent = /* @__PURE__ */ React9.createElement(
|
|
560
|
-
LabelGroup,
|
|
561
|
-
{
|
|
562
|
-
variant: "text",
|
|
563
|
-
primary: option.label,
|
|
564
|
-
secondary: hasDescription ? option.description : void 0,
|
|
565
|
-
secondaryId: hasDescription ? `${radioId}-description` : void 0,
|
|
566
|
-
primaryClassName: "mb-0",
|
|
567
|
-
secondaryClassName: "text-xs opacity-75"
|
|
568
|
-
}
|
|
569
|
-
);
|
|
570
|
-
return /* @__PURE__ */ React9.createElement(
|
|
635
|
+
const hasDescription = !!option.description;
|
|
636
|
+
return /* @__PURE__ */ React17.createElement(
|
|
571
637
|
"label",
|
|
572
638
|
{
|
|
573
639
|
key: option.value,
|
|
574
|
-
className: cn(
|
|
575
|
-
"w-full h-full flex gap-3 p-3 duration-200",
|
|
576
|
-
useChoiceCard && "border rounded-lg hover:ring-2",
|
|
577
|
-
useChoiceCard && isChecked && "ring-2",
|
|
578
|
-
isDisabled ? "opacity-50 cursor-not-allowed hover:ring-0" : "cursor-pointer"
|
|
579
|
-
),
|
|
580
640
|
htmlFor: radioId,
|
|
581
|
-
|
|
582
|
-
|
|
641
|
+
className: cn(
|
|
642
|
+
"flex gap-3 p-3 duration-200",
|
|
643
|
+
useChoiceCard && "border rounded-lg hover:ring-2 hover:ring-ring/50",
|
|
644
|
+
useChoiceCard && isSelected && "ring-2 ring-ring",
|
|
645
|
+
useChoiceCard && error && "border-destructive",
|
|
646
|
+
isDisabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"
|
|
647
|
+
)
|
|
583
648
|
},
|
|
584
|
-
/* @__PURE__ */
|
|
649
|
+
/* @__PURE__ */ React17.createElement(
|
|
585
650
|
"div",
|
|
586
651
|
{
|
|
587
652
|
className: cn(
|
|
588
|
-
"flex w-full
|
|
653
|
+
"flex w-full gap-3",
|
|
589
654
|
useChoiceCard ? "items-start" : "items-center"
|
|
590
655
|
)
|
|
591
656
|
},
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
657
|
+
/* @__PURE__ */ React17.createElement(
|
|
658
|
+
RadioGroupItem,
|
|
659
|
+
{
|
|
660
|
+
value: option.value,
|
|
661
|
+
id: radioId,
|
|
662
|
+
disabled: isDisabled,
|
|
663
|
+
className: "mt-0.5",
|
|
664
|
+
"aria-describedby": hasDescription ? `${radioId}-description` : void 0
|
|
665
|
+
}
|
|
666
|
+
),
|
|
667
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-1 flex-1" }, /* @__PURE__ */ React17.createElement(
|
|
668
|
+
Label,
|
|
669
|
+
{
|
|
670
|
+
htmlFor: radioId,
|
|
671
|
+
className: "cursor-pointer font-medium leading-none"
|
|
672
|
+
},
|
|
673
|
+
option.label
|
|
674
|
+
), option.description && /* @__PURE__ */ React17.createElement(
|
|
675
|
+
"p",
|
|
676
|
+
{
|
|
677
|
+
id: `${radioId}-description`,
|
|
678
|
+
className: "text-sm opacity-70 leading-snug"
|
|
679
|
+
},
|
|
680
|
+
option.description
|
|
681
|
+
))
|
|
595
682
|
)
|
|
596
683
|
);
|
|
597
684
|
})
|
|
598
|
-
);
|
|
685
|
+
));
|
|
599
686
|
}
|
|
600
687
|
Radio.displayName = "Radio";
|
|
688
|
+
function Switch({
|
|
689
|
+
className,
|
|
690
|
+
size = "default",
|
|
691
|
+
...props
|
|
692
|
+
}) {
|
|
693
|
+
return /* @__PURE__ */ React17.createElement(
|
|
694
|
+
Switch$1.Root,
|
|
695
|
+
{
|
|
696
|
+
"data-slot": "switch",
|
|
697
|
+
"data-size": size,
|
|
698
|
+
className: cn(
|
|
699
|
+
// Core structure - uses CSS variables
|
|
700
|
+
"peer group/switch inline-flex shrink-0 items-center rounded-full",
|
|
701
|
+
"border border-transparent shadow-xs transition-all outline-none",
|
|
702
|
+
// State-based backgrounds - use CSS variables
|
|
703
|
+
"data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
|
704
|
+
// Focus state
|
|
705
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
706
|
+
// Disabled state
|
|
707
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
708
|
+
// Size variants
|
|
709
|
+
"data-[size=default]:h-[1.15rem] data-[size=default]:w-8",
|
|
710
|
+
"data-[size=sm]:h-3.5 data-[size=sm]:w-6",
|
|
711
|
+
className
|
|
712
|
+
),
|
|
713
|
+
...props
|
|
714
|
+
},
|
|
715
|
+
/* @__PURE__ */ React17.createElement(
|
|
716
|
+
Switch$1.Thumb,
|
|
717
|
+
{
|
|
718
|
+
"data-slot": "switch-thumb",
|
|
719
|
+
className: cn(
|
|
720
|
+
// Thumb appearance - inherits from parent theme
|
|
721
|
+
"bg-background pointer-events-none block rounded-full ring-0 transition-transform",
|
|
722
|
+
// Size variants
|
|
723
|
+
"group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3",
|
|
724
|
+
// Position based on state
|
|
725
|
+
"data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
|
|
726
|
+
)
|
|
727
|
+
}
|
|
728
|
+
)
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// src/inputs/Switch.tsx
|
|
733
|
+
function Switch2({
|
|
734
|
+
name,
|
|
735
|
+
value,
|
|
736
|
+
onChange,
|
|
737
|
+
onBlur,
|
|
738
|
+
disabled = false,
|
|
739
|
+
required = false,
|
|
740
|
+
error = false,
|
|
741
|
+
className = "",
|
|
742
|
+
label,
|
|
743
|
+
description,
|
|
744
|
+
size = "default",
|
|
745
|
+
...props
|
|
746
|
+
}) {
|
|
747
|
+
const switchId = props.id || `switch-${name}`;
|
|
748
|
+
const handleCheckedChange = (checked) => {
|
|
749
|
+
onChange(checked);
|
|
750
|
+
};
|
|
751
|
+
const handleBlur = () => {
|
|
752
|
+
onBlur?.();
|
|
753
|
+
};
|
|
754
|
+
const switchElement = /* @__PURE__ */ React17.createElement(
|
|
755
|
+
Switch,
|
|
756
|
+
{
|
|
757
|
+
id: switchId,
|
|
758
|
+
checked: value,
|
|
759
|
+
onCheckedChange: handleCheckedChange,
|
|
760
|
+
onBlur: handleBlur,
|
|
761
|
+
disabled,
|
|
762
|
+
size,
|
|
763
|
+
"aria-invalid": error || props["aria-invalid"],
|
|
764
|
+
"aria-describedby": description ? `${switchId}-description` : props["aria-describedby"],
|
|
765
|
+
"aria-required": required || props["aria-required"],
|
|
766
|
+
...props
|
|
767
|
+
}
|
|
768
|
+
);
|
|
769
|
+
if (!label) {
|
|
770
|
+
return /* @__PURE__ */ React17.createElement("div", { className }, switchElement);
|
|
771
|
+
}
|
|
772
|
+
return /* @__PURE__ */ React17.createElement(
|
|
773
|
+
"label",
|
|
774
|
+
{
|
|
775
|
+
htmlFor: switchId,
|
|
776
|
+
className: cn(
|
|
777
|
+
"flex items-center gap-3 cursor-pointer",
|
|
778
|
+
disabled && "opacity-50 cursor-not-allowed",
|
|
779
|
+
className
|
|
780
|
+
)
|
|
781
|
+
},
|
|
782
|
+
switchElement,
|
|
783
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React17.createElement(
|
|
784
|
+
Label,
|
|
785
|
+
{
|
|
786
|
+
htmlFor: switchId,
|
|
787
|
+
className: "cursor-pointer font-medium leading-none"
|
|
788
|
+
},
|
|
789
|
+
label
|
|
790
|
+
), description && /* @__PURE__ */ React17.createElement(
|
|
791
|
+
"p",
|
|
792
|
+
{
|
|
793
|
+
id: `${switchId}-description`,
|
|
794
|
+
className: "text-sm opacity-70 leading-snug"
|
|
795
|
+
},
|
|
796
|
+
description
|
|
797
|
+
))
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
Switch2.displayName = "Switch";
|
|
601
801
|
function Select({
|
|
802
|
+
...props
|
|
803
|
+
}) {
|
|
804
|
+
return /* @__PURE__ */ React17.createElement(Select$1.Root, { "data-slot": "select", ...props });
|
|
805
|
+
}
|
|
806
|
+
function SelectGroup({
|
|
807
|
+
...props
|
|
808
|
+
}) {
|
|
809
|
+
return /* @__PURE__ */ React17.createElement(Select$1.Group, { "data-slot": "select-group", ...props });
|
|
810
|
+
}
|
|
811
|
+
function SelectValue({
|
|
812
|
+
...props
|
|
813
|
+
}) {
|
|
814
|
+
return /* @__PURE__ */ React17.createElement(Select$1.Value, { "data-slot": "select-value", ...props });
|
|
815
|
+
}
|
|
816
|
+
function SelectTrigger({
|
|
817
|
+
className,
|
|
818
|
+
size = "default",
|
|
819
|
+
children,
|
|
820
|
+
...props
|
|
821
|
+
}) {
|
|
822
|
+
return /* @__PURE__ */ React17.createElement(
|
|
823
|
+
Select$1.Trigger,
|
|
824
|
+
{
|
|
825
|
+
"data-slot": "select-trigger",
|
|
826
|
+
"data-size": size,
|
|
827
|
+
className: cn(
|
|
828
|
+
// Core structure - uses CSS variables
|
|
829
|
+
"flex w-fit items-center justify-between gap-2 rounded-md border border-input",
|
|
830
|
+
"bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs",
|
|
831
|
+
"transition-[color,box-shadow] outline-none",
|
|
832
|
+
// Focus state
|
|
833
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
834
|
+
// Error state
|
|
835
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20",
|
|
836
|
+
// Disabled state
|
|
837
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
838
|
+
// Size variants
|
|
839
|
+
"data-[size=default]:h-9 data-[size=sm]:h-8",
|
|
840
|
+
// Value styling
|
|
841
|
+
"*:data-[slot=select-value]:line-clamp-1",
|
|
842
|
+
"*:data-[slot=select-value]:flex",
|
|
843
|
+
"*:data-[slot=select-value]:items-center",
|
|
844
|
+
"*:data-[slot=select-value]:gap-2",
|
|
845
|
+
// SVG styling
|
|
846
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
847
|
+
className
|
|
848
|
+
),
|
|
849
|
+
...props
|
|
850
|
+
},
|
|
851
|
+
children,
|
|
852
|
+
/* @__PURE__ */ React17.createElement(Select$1.Icon, { asChild: true }, /* @__PURE__ */ React17.createElement(
|
|
853
|
+
"svg",
|
|
854
|
+
{
|
|
855
|
+
className: "size-4 opacity-50",
|
|
856
|
+
viewBox: "0 0 24 24",
|
|
857
|
+
fill: "none",
|
|
858
|
+
stroke: "currentColor",
|
|
859
|
+
strokeWidth: "2",
|
|
860
|
+
strokeLinecap: "round",
|
|
861
|
+
strokeLinejoin: "round"
|
|
862
|
+
},
|
|
863
|
+
/* @__PURE__ */ React17.createElement("polyline", { points: "6 9 12 15 18 9" })
|
|
864
|
+
))
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
function SelectContent({
|
|
868
|
+
className,
|
|
869
|
+
children,
|
|
870
|
+
position = "item-aligned",
|
|
871
|
+
align = "center",
|
|
872
|
+
...props
|
|
873
|
+
}) {
|
|
874
|
+
return /* @__PURE__ */ React17.createElement(Select$1.Portal, null, /* @__PURE__ */ React17.createElement(
|
|
875
|
+
Select$1.Content,
|
|
876
|
+
{
|
|
877
|
+
"data-slot": "select-content",
|
|
878
|
+
className: cn(
|
|
879
|
+
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
|
880
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
881
|
+
className
|
|
882
|
+
),
|
|
883
|
+
position,
|
|
884
|
+
align,
|
|
885
|
+
...props
|
|
886
|
+
},
|
|
887
|
+
/* @__PURE__ */ React17.createElement(SelectScrollUpButton, null),
|
|
888
|
+
/* @__PURE__ */ React17.createElement(
|
|
889
|
+
Select$1.Viewport,
|
|
890
|
+
{
|
|
891
|
+
className: cn(
|
|
892
|
+
"p-1",
|
|
893
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
|
894
|
+
)
|
|
895
|
+
},
|
|
896
|
+
children
|
|
897
|
+
),
|
|
898
|
+
/* @__PURE__ */ React17.createElement(SelectScrollDownButton, null)
|
|
899
|
+
));
|
|
900
|
+
}
|
|
901
|
+
function SelectLabel({
|
|
902
|
+
className,
|
|
903
|
+
...props
|
|
904
|
+
}) {
|
|
905
|
+
return /* @__PURE__ */ React17.createElement(
|
|
906
|
+
Select$1.Label,
|
|
907
|
+
{
|
|
908
|
+
"data-slot": "select-label",
|
|
909
|
+
className: cn("px-2 py-1.5 text-xs opacity-70", className),
|
|
910
|
+
...props
|
|
911
|
+
}
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
function SelectItem({
|
|
915
|
+
className,
|
|
916
|
+
children,
|
|
917
|
+
...props
|
|
918
|
+
}) {
|
|
919
|
+
return /* @__PURE__ */ React17.createElement(
|
|
920
|
+
Select$1.Item,
|
|
921
|
+
{
|
|
922
|
+
"data-slot": "select-item",
|
|
923
|
+
className: cn(
|
|
924
|
+
// Core structure - inherits text color
|
|
925
|
+
"relative flex w-full cursor-default items-center gap-2 rounded-sm",
|
|
926
|
+
"py-1.5 pr-8 pl-2 text-sm outline-hidden select-none",
|
|
927
|
+
// Focus state - uses accent CSS variable
|
|
928
|
+
"focus:bg-accent focus:text-accent-foreground",
|
|
929
|
+
// Disabled state
|
|
930
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
931
|
+
// SVG styling
|
|
932
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
933
|
+
// Span styling
|
|
934
|
+
"*:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
935
|
+
className
|
|
936
|
+
),
|
|
937
|
+
...props
|
|
938
|
+
},
|
|
939
|
+
/* @__PURE__ */ React17.createElement(
|
|
940
|
+
"span",
|
|
941
|
+
{
|
|
942
|
+
"data-slot": "select-item-indicator",
|
|
943
|
+
className: "absolute right-2 flex size-3.5 items-center justify-center"
|
|
944
|
+
},
|
|
945
|
+
/* @__PURE__ */ React17.createElement(Select$1.ItemIndicator, null, /* @__PURE__ */ React17.createElement(
|
|
946
|
+
"svg",
|
|
947
|
+
{
|
|
948
|
+
className: "size-4",
|
|
949
|
+
viewBox: "0 0 24 24",
|
|
950
|
+
fill: "none",
|
|
951
|
+
stroke: "currentColor",
|
|
952
|
+
strokeWidth: "3",
|
|
953
|
+
strokeLinecap: "round",
|
|
954
|
+
strokeLinejoin: "round"
|
|
955
|
+
},
|
|
956
|
+
/* @__PURE__ */ React17.createElement("polyline", { points: "20 6 9 17 4 12" })
|
|
957
|
+
))
|
|
958
|
+
),
|
|
959
|
+
/* @__PURE__ */ React17.createElement(Select$1.ItemText, null, children)
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
function SelectScrollUpButton({
|
|
963
|
+
className,
|
|
964
|
+
...props
|
|
965
|
+
}) {
|
|
966
|
+
return /* @__PURE__ */ React17.createElement(
|
|
967
|
+
Select$1.ScrollUpButton,
|
|
968
|
+
{
|
|
969
|
+
"data-slot": "select-scroll-up-button",
|
|
970
|
+
className: cn(
|
|
971
|
+
"flex cursor-default items-center justify-center py-1",
|
|
972
|
+
className
|
|
973
|
+
),
|
|
974
|
+
...props
|
|
975
|
+
},
|
|
976
|
+
/* @__PURE__ */ React17.createElement(
|
|
977
|
+
"svg",
|
|
978
|
+
{
|
|
979
|
+
className: "size-4",
|
|
980
|
+
viewBox: "0 0 24 24",
|
|
981
|
+
fill: "none",
|
|
982
|
+
stroke: "currentColor",
|
|
983
|
+
strokeWidth: "2",
|
|
984
|
+
strokeLinecap: "round",
|
|
985
|
+
strokeLinejoin: "round"
|
|
986
|
+
},
|
|
987
|
+
/* @__PURE__ */ React17.createElement("polyline", { points: "18 15 12 9 6 15" })
|
|
988
|
+
)
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
function SelectScrollDownButton({
|
|
992
|
+
className,
|
|
993
|
+
...props
|
|
994
|
+
}) {
|
|
995
|
+
return /* @__PURE__ */ React17.createElement(
|
|
996
|
+
Select$1.ScrollDownButton,
|
|
997
|
+
{
|
|
998
|
+
"data-slot": "select-scroll-down-button",
|
|
999
|
+
className: cn(
|
|
1000
|
+
"flex cursor-default items-center justify-center py-1",
|
|
1001
|
+
className
|
|
1002
|
+
),
|
|
1003
|
+
...props
|
|
1004
|
+
},
|
|
1005
|
+
/* @__PURE__ */ React17.createElement(
|
|
1006
|
+
"svg",
|
|
1007
|
+
{
|
|
1008
|
+
className: "size-4",
|
|
1009
|
+
viewBox: "0 0 24 24",
|
|
1010
|
+
fill: "none",
|
|
1011
|
+
stroke: "currentColor",
|
|
1012
|
+
strokeWidth: "2",
|
|
1013
|
+
strokeLinecap: "round",
|
|
1014
|
+
strokeLinejoin: "round"
|
|
1015
|
+
},
|
|
1016
|
+
/* @__PURE__ */ React17.createElement("polyline", { points: "6 9 12 15 18 9" })
|
|
1017
|
+
)
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// src/inputs/Select.tsx
|
|
1022
|
+
function Select2({
|
|
602
1023
|
name,
|
|
603
1024
|
value,
|
|
604
1025
|
onChange,
|
|
@@ -609,290 +1030,83 @@ function Select({
|
|
|
609
1030
|
error = false,
|
|
610
1031
|
className = "",
|
|
611
1032
|
placeholder = "Select...",
|
|
612
|
-
searchable = true,
|
|
613
|
-
clearable = true,
|
|
614
|
-
loading = false,
|
|
615
1033
|
options = [],
|
|
616
1034
|
optionGroups = [],
|
|
617
1035
|
renderOption,
|
|
618
1036
|
...props
|
|
619
1037
|
}) {
|
|
620
|
-
const [
|
|
621
|
-
const
|
|
622
|
-
const [focusedIndex, setFocusedIndex] = React9.useState(-1);
|
|
623
|
-
const [hasInteracted, setHasInteracted] = React9.useState(false);
|
|
624
|
-
const triggerRef = React9.useRef(null);
|
|
625
|
-
const dropdownRef = React9.useRef(null);
|
|
626
|
-
const searchInputRef = React9.useRef(null);
|
|
627
|
-
const dropdownId = `${name}-dropdown`;
|
|
628
|
-
const allOptions = React9.useMemo(() => {
|
|
1038
|
+
const [hasInteracted, setHasInteracted] = React17.useState(false);
|
|
1039
|
+
const allOptions = React17.useMemo(() => {
|
|
629
1040
|
if (optionGroups.length > 0) {
|
|
630
1041
|
return optionGroups.flatMap((group) => group.options);
|
|
631
1042
|
}
|
|
632
1043
|
return options;
|
|
633
1044
|
}, [options, optionGroups]);
|
|
634
|
-
const filteredOptions = React9.useMemo(() => {
|
|
635
|
-
if (!searchQuery.trim()) {
|
|
636
|
-
return allOptions;
|
|
637
|
-
}
|
|
638
|
-
const query = searchQuery.toLowerCase();
|
|
639
|
-
return allOptions.filter((option) => {
|
|
640
|
-
const label = typeof option.label === "string" ? option.label : String(option.label);
|
|
641
|
-
return label.toLowerCase().includes(query);
|
|
642
|
-
});
|
|
643
|
-
}, [allOptions, searchQuery]);
|
|
644
|
-
const selectedOption = React9.useMemo(() => {
|
|
645
|
-
return allOptions.find((opt) => opt.value === value);
|
|
646
|
-
}, [allOptions, value]);
|
|
647
1045
|
const hasValue = Boolean(value);
|
|
648
|
-
const
|
|
649
|
-
onChange(
|
|
650
|
-
setIsOpen(false);
|
|
651
|
-
setSearchQuery("");
|
|
652
|
-
setFocusedIndex(-1);
|
|
653
|
-
};
|
|
654
|
-
const handleClear = (e) => {
|
|
655
|
-
e.stopPropagation();
|
|
656
|
-
onChange("");
|
|
657
|
-
setSearchQuery("");
|
|
658
|
-
setFocusedIndex(-1);
|
|
1046
|
+
const handleValueChange = (newValue) => {
|
|
1047
|
+
onChange(newValue);
|
|
659
1048
|
};
|
|
660
|
-
const
|
|
661
|
-
if (
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
setHasInteracted(true);
|
|
666
|
-
}
|
|
667
|
-
if (newIsOpen && searchable && searchInputRef.current) {
|
|
668
|
-
setTimeout(() => searchInputRef.current?.focus(), 0);
|
|
669
|
-
}
|
|
670
|
-
if (newIsOpen) {
|
|
1049
|
+
const handleOpenChange = (open) => {
|
|
1050
|
+
if (open) {
|
|
1051
|
+
if (!hasInteracted) {
|
|
1052
|
+
setHasInteracted(true);
|
|
1053
|
+
}
|
|
671
1054
|
onFocus?.();
|
|
672
|
-
}
|
|
673
|
-
};
|
|
674
|
-
const handleSearchChange = (e) => {
|
|
675
|
-
setSearchQuery(e.target.value);
|
|
676
|
-
setFocusedIndex(0);
|
|
677
|
-
};
|
|
678
|
-
const handleKeyDown = (e) => {
|
|
679
|
-
if (disabled) return;
|
|
680
|
-
switch (e.key) {
|
|
681
|
-
case "ArrowDown":
|
|
682
|
-
e.preventDefault();
|
|
683
|
-
if (!isOpen) {
|
|
684
|
-
setIsOpen(true);
|
|
685
|
-
setFocusedIndex(0);
|
|
686
|
-
} else {
|
|
687
|
-
const enabledOptions = filteredOptions.filter((opt) => !opt.disabled);
|
|
688
|
-
if (enabledOptions.length > 0) {
|
|
689
|
-
const currentIndexInFiltered = focusedIndex;
|
|
690
|
-
const nextIndex = (currentIndexInFiltered + 1) % enabledOptions.length;
|
|
691
|
-
setFocusedIndex(filteredOptions.indexOf(enabledOptions[nextIndex]));
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
break;
|
|
695
|
-
case "ArrowUp":
|
|
696
|
-
e.preventDefault();
|
|
697
|
-
if (isOpen) {
|
|
698
|
-
const enabledOptions = filteredOptions.filter((opt) => !opt.disabled);
|
|
699
|
-
if (enabledOptions.length > 0) {
|
|
700
|
-
const currentIndexInFiltered = focusedIndex;
|
|
701
|
-
const prevIndex = (currentIndexInFiltered - 1 + enabledOptions.length) % enabledOptions.length;
|
|
702
|
-
setFocusedIndex(filteredOptions.indexOf(enabledOptions[prevIndex]));
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
break;
|
|
706
|
-
case "Enter":
|
|
707
|
-
e.preventDefault();
|
|
708
|
-
if (isOpen && focusedIndex >= 0 && focusedIndex < filteredOptions.length) {
|
|
709
|
-
const focusedOption = filteredOptions[focusedIndex];
|
|
710
|
-
if (!focusedOption.disabled) {
|
|
711
|
-
handleSelect(focusedOption.value);
|
|
712
|
-
}
|
|
713
|
-
} else if (!isOpen) {
|
|
714
|
-
setIsOpen(true);
|
|
715
|
-
}
|
|
716
|
-
break;
|
|
717
|
-
case "Escape":
|
|
718
|
-
e.preventDefault();
|
|
719
|
-
if (isOpen) {
|
|
720
|
-
setIsOpen(false);
|
|
721
|
-
setSearchQuery("");
|
|
722
|
-
setFocusedIndex(-1);
|
|
723
|
-
}
|
|
724
|
-
break;
|
|
725
|
-
case " ":
|
|
726
|
-
if (!isOpen && !searchable) {
|
|
727
|
-
e.preventDefault();
|
|
728
|
-
setIsOpen(true);
|
|
729
|
-
}
|
|
730
|
-
break;
|
|
731
|
-
default:
|
|
732
|
-
if (!searchable && e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
|
|
733
|
-
const char = e.key.toLowerCase();
|
|
734
|
-
const matchingOption = filteredOptions.find((opt) => {
|
|
735
|
-
const label = typeof opt.label === "string" ? opt.label : String(opt.label);
|
|
736
|
-
return label.toLowerCase().startsWith(char) && !opt.disabled;
|
|
737
|
-
});
|
|
738
|
-
if (matchingOption) {
|
|
739
|
-
handleSelect(matchingOption.value);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
break;
|
|
743
|
-
}
|
|
744
|
-
};
|
|
745
|
-
const handleBlur = (event) => {
|
|
746
|
-
const nextTarget = event?.relatedTarget;
|
|
747
|
-
const focusStayedInside = !!triggerRef.current && triggerRef.current.contains(nextTarget) || !!dropdownRef.current && dropdownRef.current.contains(nextTarget);
|
|
748
|
-
if (!nextTarget || !focusStayedInside) {
|
|
1055
|
+
} else if (hasInteracted) {
|
|
749
1056
|
onBlur?.();
|
|
750
1057
|
}
|
|
751
1058
|
};
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
setIsOpen(false);
|
|
755
|
-
setSearchQuery("");
|
|
756
|
-
setFocusedIndex(-1);
|
|
757
|
-
if (hasInteracted) {
|
|
758
|
-
onBlur?.();
|
|
759
|
-
}
|
|
760
|
-
}, [isOpen, hasInteracted, onBlur]);
|
|
761
|
-
useOnClickOutside([triggerRef, dropdownRef], closeDropdown, void 0, {
|
|
762
|
-
capture: true
|
|
763
|
-
});
|
|
764
|
-
const combinedClassName = cn("relative w-full", className);
|
|
765
|
-
return /* @__PURE__ */ React9.createElement(
|
|
766
|
-
"div",
|
|
1059
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1060
|
+
Select,
|
|
767
1061
|
{
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1062
|
+
name,
|
|
1063
|
+
value,
|
|
1064
|
+
onValueChange: handleValueChange,
|
|
1065
|
+
onOpenChange: handleOpenChange,
|
|
1066
|
+
disabled,
|
|
1067
|
+
required
|
|
771
1068
|
},
|
|
772
|
-
/* @__PURE__ */
|
|
773
|
-
|
|
1069
|
+
/* @__PURE__ */ React17.createElement(
|
|
1070
|
+
SelectTrigger,
|
|
774
1071
|
{
|
|
775
|
-
name,
|
|
776
|
-
value,
|
|
777
|
-
onChange: () => {
|
|
778
|
-
},
|
|
779
|
-
disabled,
|
|
780
|
-
required,
|
|
781
|
-
"aria-hidden": "true",
|
|
782
|
-
tabIndex: -1,
|
|
783
|
-
style: { display: "none" }
|
|
784
|
-
},
|
|
785
|
-
/* @__PURE__ */ React9.createElement("option", { value: "" }, "Select..."),
|
|
786
|
-
allOptions.map((option) => /* @__PURE__ */ React9.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
|
|
787
|
-
),
|
|
788
|
-
/* @__PURE__ */ React9.createElement(
|
|
789
|
-
"div",
|
|
790
|
-
{
|
|
791
|
-
ref: triggerRef,
|
|
792
1072
|
className: cn(
|
|
793
|
-
|
|
794
|
-
"cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1073
|
+
// Valid value indicator - ring-2 when has value and no error
|
|
795
1074
|
!error && hasValue && "ring-2 ring-ring",
|
|
796
|
-
|
|
797
|
-
|
|
1075
|
+
// Error state - handled by SelectTrigger via aria-invalid
|
|
1076
|
+
className
|
|
798
1077
|
),
|
|
799
|
-
onClick: handleToggle,
|
|
800
|
-
role: "combobox",
|
|
801
|
-
"aria-expanded": isOpen,
|
|
802
|
-
"aria-controls": dropdownId,
|
|
803
1078
|
"aria-invalid": error || props["aria-invalid"],
|
|
804
1079
|
"aria-describedby": props["aria-describedby"],
|
|
805
|
-
"aria-required": required || props["aria-required"]
|
|
806
|
-
"aria-disabled": disabled,
|
|
807
|
-
tabIndex: disabled ? -1 : 0
|
|
1080
|
+
"aria-required": required || props["aria-required"]
|
|
808
1081
|
},
|
|
809
|
-
/* @__PURE__ */
|
|
810
|
-
|
|
811
|
-
|
|
1082
|
+
/* @__PURE__ */ React17.createElement(SelectValue, { placeholder })
|
|
1083
|
+
),
|
|
1084
|
+
/* @__PURE__ */ React17.createElement(SelectContent, null, optionGroups.length > 0 ? (
|
|
1085
|
+
// Render grouped options
|
|
1086
|
+
optionGroups.map((group, groupIndex) => /* @__PURE__ */ React17.createElement(SelectGroup, { key: groupIndex }, /* @__PURE__ */ React17.createElement(SelectLabel, null, group.label), group.options.map((option) => /* @__PURE__ */ React17.createElement(
|
|
1087
|
+
SelectItem,
|
|
812
1088
|
{
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
"aria-label": "Clear selection",
|
|
817
|
-
tabIndex: -1
|
|
1089
|
+
key: option.value,
|
|
1090
|
+
value: option.value,
|
|
1091
|
+
disabled: option.disabled
|
|
818
1092
|
},
|
|
819
|
-
|
|
820
|
-
)
|
|
821
|
-
)
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
ref: dropdownRef,
|
|
826
|
-
id: dropdownId,
|
|
827
|
-
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",
|
|
828
|
-
role: "listbox"
|
|
829
|
-
},
|
|
830
|
-
searchable && /* @__PURE__ */ React9.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React9.createElement(
|
|
831
|
-
"input",
|
|
1093
|
+
renderOption ? renderOption(option) : option.label
|
|
1094
|
+
))))
|
|
1095
|
+
) : (
|
|
1096
|
+
// Render flat options
|
|
1097
|
+
allOptions.map((option) => /* @__PURE__ */ React17.createElement(
|
|
1098
|
+
SelectItem,
|
|
832
1099
|
{
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
),
|
|
839
|
-
placeholder: "Search...",
|
|
840
|
-
value: searchQuery,
|
|
841
|
-
onChange: handleSearchChange,
|
|
842
|
-
onClick: (e) => e.stopPropagation(),
|
|
843
|
-
"aria-label": "Search options"
|
|
844
|
-
}
|
|
845
|
-
)),
|
|
846
|
-
/* @__PURE__ */ React9.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React9.createElement("div", { className: "py-2 px-3 text-center text-sm " }, "No options found") : optionGroups.length > 0 ? (
|
|
847
|
-
// Render grouped options
|
|
848
|
-
optionGroups.map((group, groupIndex) => {
|
|
849
|
-
const groupOptions = group.options.filter(
|
|
850
|
-
(opt) => filteredOptions.includes(opt)
|
|
851
|
-
);
|
|
852
|
-
if (groupOptions.length === 0) return null;
|
|
853
|
-
return /* @__PURE__ */ React9.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React9.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold " }, group.label), groupOptions.map((option) => {
|
|
854
|
-
const globalIndex = filteredOptions.indexOf(option);
|
|
855
|
-
const isSelected = value === option.value;
|
|
856
|
-
const isFocused = globalIndex === focusedIndex;
|
|
857
|
-
const isDisabled = option.disabled;
|
|
858
|
-
return /* @__PURE__ */ React9.createElement(
|
|
859
|
-
"div",
|
|
860
|
-
{
|
|
861
|
-
key: option.value,
|
|
862
|
-
className: `relative flex w-full cursor-pointer items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-muted ${isFocused ? "bg-muted" : ""} ${isSelected ? "font-medium bg-muted" : ""} ${isDisabled ? "pointer-events-none opacity-50" : ""}`,
|
|
863
|
-
onClick: () => !isDisabled && handleSelect(option.value),
|
|
864
|
-
role: "option",
|
|
865
|
-
"aria-selected": isSelected,
|
|
866
|
-
"aria-disabled": isDisabled
|
|
867
|
-
},
|
|
868
|
-
renderOption ? renderOption(option) : option.label
|
|
869
|
-
);
|
|
870
|
-
}));
|
|
871
|
-
})
|
|
872
|
-
) : (
|
|
873
|
-
// Render flat options
|
|
874
|
-
filteredOptions.map((option, index) => {
|
|
875
|
-
const isSelected = value === option.value;
|
|
876
|
-
const isFocused = index === focusedIndex;
|
|
877
|
-
const isDisabled = option.disabled;
|
|
878
|
-
return /* @__PURE__ */ React9.createElement(
|
|
879
|
-
"div",
|
|
880
|
-
{
|
|
881
|
-
key: option.value,
|
|
882
|
-
className: `relative flex w-full cursor-pointer items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-muted ${isFocused ? "bg-muted" : ""} ${isSelected ? "font-medium bg-muted" : ""} ${isDisabled ? "pointer-events-none opacity-50" : ""}`,
|
|
883
|
-
onClick: () => !isDisabled && handleSelect(option.value),
|
|
884
|
-
role: "option",
|
|
885
|
-
"aria-selected": isSelected,
|
|
886
|
-
"aria-disabled": isDisabled
|
|
887
|
-
},
|
|
888
|
-
renderOption ? renderOption(option) : option.label
|
|
889
|
-
);
|
|
890
|
-
})
|
|
1100
|
+
key: option.value,
|
|
1101
|
+
value: option.value,
|
|
1102
|
+
disabled: option.disabled
|
|
1103
|
+
},
|
|
1104
|
+
renderOption ? renderOption(option) : option.label
|
|
891
1105
|
))
|
|
892
|
-
)
|
|
1106
|
+
))
|
|
893
1107
|
);
|
|
894
1108
|
}
|
|
895
|
-
|
|
1109
|
+
Select2.displayName = "Select";
|
|
896
1110
|
function MultiSelect({
|
|
897
1111
|
name,
|
|
898
1112
|
value = [],
|
|
@@ -915,21 +1129,21 @@ function MultiSelect({
|
|
|
915
1129
|
renderValue,
|
|
916
1130
|
...props
|
|
917
1131
|
}) {
|
|
918
|
-
const [isOpen, setIsOpen] =
|
|
919
|
-
const [searchQuery, setSearchQuery] =
|
|
920
|
-
const [focusedIndex, setFocusedIndex] =
|
|
921
|
-
const [hasInteracted, setHasInteracted] =
|
|
922
|
-
const triggerRef =
|
|
923
|
-
const dropdownRef =
|
|
924
|
-
const searchInputRef =
|
|
1132
|
+
const [isOpen, setIsOpen] = React17.useState(false);
|
|
1133
|
+
const [searchQuery, setSearchQuery] = React17.useState("");
|
|
1134
|
+
const [focusedIndex, setFocusedIndex] = React17.useState(-1);
|
|
1135
|
+
const [hasInteracted, setHasInteracted] = React17.useState(false);
|
|
1136
|
+
const triggerRef = React17.useRef(null);
|
|
1137
|
+
const dropdownRef = React17.useRef(null);
|
|
1138
|
+
const searchInputRef = React17.useRef(null);
|
|
925
1139
|
const dropdownId = `${name}-dropdown`;
|
|
926
|
-
const allOptions =
|
|
1140
|
+
const allOptions = React17.useMemo(() => {
|
|
927
1141
|
if (optionGroups.length > 0) {
|
|
928
1142
|
return optionGroups.flatMap((group) => group.options);
|
|
929
1143
|
}
|
|
930
1144
|
return options;
|
|
931
1145
|
}, [options, optionGroups]);
|
|
932
|
-
const filteredOptions =
|
|
1146
|
+
const filteredOptions = React17.useMemo(() => {
|
|
933
1147
|
if (!searchQuery.trim()) {
|
|
934
1148
|
return allOptions;
|
|
935
1149
|
}
|
|
@@ -939,11 +1153,11 @@ function MultiSelect({
|
|
|
939
1153
|
return label.toLowerCase().includes(query);
|
|
940
1154
|
});
|
|
941
1155
|
}, [allOptions, searchQuery]);
|
|
942
|
-
const selectedOptions =
|
|
1156
|
+
const selectedOptions = React17.useMemo(() => {
|
|
943
1157
|
return allOptions.filter((opt) => value.includes(opt.value));
|
|
944
1158
|
}, [allOptions, value]);
|
|
945
1159
|
const hasValue = value.length > 0;
|
|
946
|
-
const isMaxReached =
|
|
1160
|
+
const isMaxReached = React17.useMemo(() => {
|
|
947
1161
|
return maxSelections !== void 0 && value.length >= maxSelections;
|
|
948
1162
|
}, [maxSelections, value.length]);
|
|
949
1163
|
const handleToggleOption = (optionValue) => {
|
|
@@ -1059,7 +1273,7 @@ function MultiSelect({
|
|
|
1059
1273
|
onBlur?.();
|
|
1060
1274
|
}
|
|
1061
1275
|
};
|
|
1062
|
-
const closeDropdown =
|
|
1276
|
+
const closeDropdown = React17.useCallback(() => {
|
|
1063
1277
|
if (!isOpen) return;
|
|
1064
1278
|
setIsOpen(false);
|
|
1065
1279
|
setSearchQuery("");
|
|
@@ -1072,14 +1286,14 @@ function MultiSelect({
|
|
|
1072
1286
|
capture: true
|
|
1073
1287
|
});
|
|
1074
1288
|
const combinedClassName = cn("relative w-full", className);
|
|
1075
|
-
return /* @__PURE__ */
|
|
1289
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1076
1290
|
"div",
|
|
1077
1291
|
{
|
|
1078
1292
|
className: combinedClassName,
|
|
1079
1293
|
onKeyDown: handleKeyDown,
|
|
1080
1294
|
onBlur: handleBlur
|
|
1081
1295
|
},
|
|
1082
|
-
/* @__PURE__ */
|
|
1296
|
+
/* @__PURE__ */ React17.createElement(
|
|
1083
1297
|
"select",
|
|
1084
1298
|
{
|
|
1085
1299
|
name,
|
|
@@ -1093,10 +1307,10 @@ function MultiSelect({
|
|
|
1093
1307
|
style: { display: "none" },
|
|
1094
1308
|
multiple: true
|
|
1095
1309
|
},
|
|
1096
|
-
/* @__PURE__ */
|
|
1097
|
-
allOptions.map((option) => /* @__PURE__ */
|
|
1310
|
+
/* @__PURE__ */ React17.createElement("option", { value: "" }, "Select..."),
|
|
1311
|
+
allOptions.map((option) => /* @__PURE__ */ React17.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
|
|
1098
1312
|
),
|
|
1099
|
-
/* @__PURE__ */
|
|
1313
|
+
/* @__PURE__ */ React17.createElement(
|
|
1100
1314
|
"div",
|
|
1101
1315
|
{
|
|
1102
1316
|
ref: triggerRef,
|
|
@@ -1117,13 +1331,13 @@ function MultiSelect({
|
|
|
1117
1331
|
"aria-disabled": disabled,
|
|
1118
1332
|
tabIndex: disabled ? -1 : 0
|
|
1119
1333
|
},
|
|
1120
|
-
/* @__PURE__ */
|
|
1334
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex items-center flex-1 overflow-hidden" }, selectedOptions.length > 0 ? /* @__PURE__ */ React17.createElement("div", { className: "flex flex-wrap gap-1" }, selectedOptions.map((option) => /* @__PURE__ */ React17.createElement(
|
|
1121
1335
|
"span",
|
|
1122
1336
|
{
|
|
1123
1337
|
key: option.value,
|
|
1124
1338
|
className: "inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium"
|
|
1125
1339
|
},
|
|
1126
|
-
renderValue ? renderValue(option) : /* @__PURE__ */
|
|
1340
|
+
renderValue ? renderValue(option) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("span", { className: "max-w-40 overflow-hidden text-ellipsis whitespace-nowrap" }, option.label), !disabled && /* @__PURE__ */ React17.createElement(
|
|
1127
1341
|
"button",
|
|
1128
1342
|
{
|
|
1129
1343
|
type: "button",
|
|
@@ -1134,8 +1348,8 @@ function MultiSelect({
|
|
|
1134
1348
|
},
|
|
1135
1349
|
"\u2715"
|
|
1136
1350
|
))
|
|
1137
|
-
))) : /* @__PURE__ */
|
|
1138
|
-
/* @__PURE__ */
|
|
1351
|
+
))) : /* @__PURE__ */ React17.createElement("span", { className: "relative" }, placeholder)),
|
|
1352
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-1 ml-2" }, loading && /* @__PURE__ */ React17.createElement("span", { className: "text-xs" }, "\u23F3"), clearable && value.length > 0 && !disabled && !loading && /* @__PURE__ */ React17.createElement(
|
|
1139
1353
|
"button",
|
|
1140
1354
|
{
|
|
1141
1355
|
type: "button",
|
|
@@ -1145,9 +1359,9 @@ function MultiSelect({
|
|
|
1145
1359
|
tabIndex: -1
|
|
1146
1360
|
},
|
|
1147
1361
|
"\u2715"
|
|
1148
|
-
), /* @__PURE__ */
|
|
1362
|
+
), /* @__PURE__ */ React17.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
|
|
1149
1363
|
),
|
|
1150
|
-
isOpen && /* @__PURE__ */
|
|
1364
|
+
isOpen && /* @__PURE__ */ React17.createElement(
|
|
1151
1365
|
"div",
|
|
1152
1366
|
{
|
|
1153
1367
|
ref: dropdownRef,
|
|
@@ -1156,7 +1370,7 @@ function MultiSelect({
|
|
|
1156
1370
|
role: "listbox",
|
|
1157
1371
|
"aria-multiselectable": "true"
|
|
1158
1372
|
},
|
|
1159
|
-
searchable && /* @__PURE__ */
|
|
1373
|
+
searchable && /* @__PURE__ */ React17.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React17.createElement(
|
|
1160
1374
|
"input",
|
|
1161
1375
|
{
|
|
1162
1376
|
ref: searchInputRef,
|
|
@@ -1172,7 +1386,7 @@ function MultiSelect({
|
|
|
1172
1386
|
"aria-label": "Search options"
|
|
1173
1387
|
}
|
|
1174
1388
|
)),
|
|
1175
|
-
showSelectAll && filteredOptions.length > 0 && /* @__PURE__ */
|
|
1389
|
+
showSelectAll && filteredOptions.length > 0 && /* @__PURE__ */ React17.createElement("div", { className: "flex gap-2 p-2 border-b border-border" }, /* @__PURE__ */ React17.createElement(
|
|
1176
1390
|
"button",
|
|
1177
1391
|
{
|
|
1178
1392
|
type: "button",
|
|
@@ -1181,7 +1395,7 @@ function MultiSelect({
|
|
|
1181
1395
|
disabled
|
|
1182
1396
|
},
|
|
1183
1397
|
"Select All"
|
|
1184
|
-
), value.length > 0 && /* @__PURE__ */
|
|
1398
|
+
), value.length > 0 && /* @__PURE__ */ React17.createElement(
|
|
1185
1399
|
"button",
|
|
1186
1400
|
{
|
|
1187
1401
|
type: "button",
|
|
@@ -1191,20 +1405,20 @@ function MultiSelect({
|
|
|
1191
1405
|
},
|
|
1192
1406
|
"Clear All"
|
|
1193
1407
|
)),
|
|
1194
|
-
isMaxReached && /* @__PURE__ */
|
|
1195
|
-
/* @__PURE__ */
|
|
1408
|
+
isMaxReached && /* @__PURE__ */ React17.createElement("div", { className: "px-2 py-1 text-xs font-medium text-amber-600 bg-destructive/80 text-destructive-foreground border-b border-destructive" }, "Maximum ", maxSelections, " selection", maxSelections !== 1 ? "s" : "", " ", "reached"),
|
|
1409
|
+
/* @__PURE__ */ React17.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React17.createElement("div", { className: "px-2 py-1 text-center text-sm" }, "No options found") : optionGroups.length > 0 ? (
|
|
1196
1410
|
// Render grouped options
|
|
1197
1411
|
optionGroups.map((group, groupIndex) => {
|
|
1198
1412
|
const groupOptions = group.options.filter(
|
|
1199
1413
|
(opt) => filteredOptions.includes(opt)
|
|
1200
1414
|
);
|
|
1201
1415
|
if (groupOptions.length === 0) return null;
|
|
1202
|
-
return /* @__PURE__ */
|
|
1416
|
+
return /* @__PURE__ */ React17.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React17.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold " }, group.label), groupOptions.map((option) => {
|
|
1203
1417
|
const globalIndex = filteredOptions.indexOf(option);
|
|
1204
1418
|
const isSelected = value.includes(option.value);
|
|
1205
1419
|
const isFocused = globalIndex === focusedIndex;
|
|
1206
1420
|
const isDisabled = option.disabled || isMaxReached && !isSelected;
|
|
1207
|
-
return /* @__PURE__ */
|
|
1421
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1208
1422
|
"div",
|
|
1209
1423
|
{
|
|
1210
1424
|
key: option.value,
|
|
@@ -1219,8 +1433,8 @@ function MultiSelect({
|
|
|
1219
1433
|
"aria-selected": isSelected,
|
|
1220
1434
|
"aria-disabled": isDisabled
|
|
1221
1435
|
},
|
|
1222
|
-
/* @__PURE__ */
|
|
1223
|
-
/* @__PURE__ */
|
|
1436
|
+
/* @__PURE__ */ React17.createElement("span", { className: "text-base leading-none" }, isSelected ? "\u2611" : "\u2610"),
|
|
1437
|
+
/* @__PURE__ */ React17.createElement("span", { className: "flex-1" }, renderOption ? renderOption(option) : option.label)
|
|
1224
1438
|
);
|
|
1225
1439
|
}));
|
|
1226
1440
|
})
|
|
@@ -1230,7 +1444,7 @@ function MultiSelect({
|
|
|
1230
1444
|
const isSelected = value.includes(option.value);
|
|
1231
1445
|
const isFocused = index === focusedIndex;
|
|
1232
1446
|
const isDisabled = option.disabled || isMaxReached && !isSelected;
|
|
1233
|
-
return /* @__PURE__ */
|
|
1447
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1234
1448
|
"div",
|
|
1235
1449
|
{
|
|
1236
1450
|
key: option.value,
|
|
@@ -1245,8 +1459,8 @@ function MultiSelect({
|
|
|
1245
1459
|
"aria-selected": isSelected,
|
|
1246
1460
|
"aria-disabled": isDisabled
|
|
1247
1461
|
},
|
|
1248
|
-
/* @__PURE__ */
|
|
1249
|
-
/* @__PURE__ */
|
|
1462
|
+
/* @__PURE__ */ React17.createElement("span", { className: "text-base leading-none" }, isSelected ? "\u2611" : "\u2610"),
|
|
1463
|
+
/* @__PURE__ */ React17.createElement("span", { className: "flex-1" }, renderOption ? renderOption(option) : option.label)
|
|
1250
1464
|
);
|
|
1251
1465
|
})
|
|
1252
1466
|
))
|
|
@@ -1279,14 +1493,14 @@ function FileInput({
|
|
|
1279
1493
|
onFileRemove,
|
|
1280
1494
|
...props
|
|
1281
1495
|
}) {
|
|
1282
|
-
const inputRef =
|
|
1283
|
-
const [dragActive, setDragActive] =
|
|
1284
|
-
const [cropperOpen, setCropperOpen] =
|
|
1285
|
-
const [imageToCrop, setImageToCrop] =
|
|
1286
|
-
const [crop, setCrop] =
|
|
1287
|
-
const [zoom, setZoom] =
|
|
1288
|
-
const [croppedAreaPixels, setCroppedAreaPixels] =
|
|
1289
|
-
const validateFile =
|
|
1496
|
+
const inputRef = React17.useRef(null);
|
|
1497
|
+
const [dragActive, setDragActive] = React17.useState(false);
|
|
1498
|
+
const [cropperOpen, setCropperOpen] = React17.useState(false);
|
|
1499
|
+
const [imageToCrop, setImageToCrop] = React17.useState(null);
|
|
1500
|
+
const [crop, setCrop] = React17.useState({ x: 0, y: 0 });
|
|
1501
|
+
const [zoom, setZoom] = React17.useState(1);
|
|
1502
|
+
const [croppedAreaPixels, setCroppedAreaPixels] = React17.useState(null);
|
|
1503
|
+
const validateFile = React17.useCallback(
|
|
1290
1504
|
(file) => {
|
|
1291
1505
|
if (accept) {
|
|
1292
1506
|
const acceptedTypes = accept.split(",").map((t) => t.trim());
|
|
@@ -1321,7 +1535,7 @@ function FileInput({
|
|
|
1321
1535
|
},
|
|
1322
1536
|
[accept, maxSize]
|
|
1323
1537
|
);
|
|
1324
|
-
const handleFiles =
|
|
1538
|
+
const handleFiles = React17.useCallback(
|
|
1325
1539
|
(fileList) => {
|
|
1326
1540
|
if (!fileList || fileList.length === 0) return;
|
|
1327
1541
|
const newFiles = Array.from(fileList);
|
|
@@ -1372,7 +1586,7 @@ function FileInput({
|
|
|
1372
1586
|
onValidationError
|
|
1373
1587
|
]
|
|
1374
1588
|
);
|
|
1375
|
-
const createCroppedImage =
|
|
1589
|
+
const createCroppedImage = React17.useCallback(
|
|
1376
1590
|
async (imageUrl, cropArea) => {
|
|
1377
1591
|
return new Promise((resolve, reject) => {
|
|
1378
1592
|
const image = new Image();
|
|
@@ -1416,7 +1630,7 @@ function FileInput({
|
|
|
1416
1630
|
},
|
|
1417
1631
|
[]
|
|
1418
1632
|
);
|
|
1419
|
-
const handleCropSave =
|
|
1633
|
+
const handleCropSave = React17.useCallback(async () => {
|
|
1420
1634
|
if (!imageToCrop || !croppedAreaPixels) return;
|
|
1421
1635
|
try {
|
|
1422
1636
|
const croppedBlob = await createCroppedImage(
|
|
@@ -1449,7 +1663,7 @@ function FileInput({
|
|
|
1449
1663
|
onChange,
|
|
1450
1664
|
multiple
|
|
1451
1665
|
]);
|
|
1452
|
-
const handleCropCancel =
|
|
1666
|
+
const handleCropCancel = React17.useCallback(() => {
|
|
1453
1667
|
if (imageToCrop) {
|
|
1454
1668
|
URL.revokeObjectURL(imageToCrop.url);
|
|
1455
1669
|
}
|
|
@@ -1459,13 +1673,13 @@ function FileInput({
|
|
|
1459
1673
|
setZoom(1);
|
|
1460
1674
|
setCroppedAreaPixels(null);
|
|
1461
1675
|
}, [imageToCrop]);
|
|
1462
|
-
const onCropChange =
|
|
1676
|
+
const onCropChange = React17.useCallback((crop2) => {
|
|
1463
1677
|
setCrop(crop2);
|
|
1464
1678
|
}, []);
|
|
1465
|
-
const onZoomChange =
|
|
1679
|
+
const onZoomChange = React17.useCallback((zoom2) => {
|
|
1466
1680
|
setZoom(zoom2);
|
|
1467
1681
|
}, []);
|
|
1468
|
-
const onCropCompleteInternal =
|
|
1682
|
+
const onCropCompleteInternal = React17.useCallback(
|
|
1469
1683
|
(_, croppedAreaPixels2) => {
|
|
1470
1684
|
setCroppedAreaPixels(croppedAreaPixels2);
|
|
1471
1685
|
},
|
|
@@ -1526,7 +1740,7 @@ function FileInput({
|
|
|
1526
1740
|
}
|
|
1527
1741
|
return null;
|
|
1528
1742
|
};
|
|
1529
|
-
|
|
1743
|
+
React17.useEffect(() => {
|
|
1530
1744
|
return () => {
|
|
1531
1745
|
value.forEach((file) => {
|
|
1532
1746
|
const previewUrl = getPreviewUrl(file);
|
|
@@ -1540,7 +1754,7 @@ function FileInput({
|
|
|
1540
1754
|
};
|
|
1541
1755
|
}, [value, imageToCrop]);
|
|
1542
1756
|
const combinedClassName = `${className}`.trim();
|
|
1543
|
-
return /* @__PURE__ */
|
|
1757
|
+
return /* @__PURE__ */ React17.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React17.createElement(
|
|
1544
1758
|
"input",
|
|
1545
1759
|
{
|
|
1546
1760
|
ref: inputRef,
|
|
@@ -1557,7 +1771,7 @@ function FileInput({
|
|
|
1557
1771
|
"aria-required": required || props["aria-required"],
|
|
1558
1772
|
style: { display: "none" }
|
|
1559
1773
|
}
|
|
1560
|
-
), /* @__PURE__ */
|
|
1774
|
+
), /* @__PURE__ */ React17.createElement(
|
|
1561
1775
|
"div",
|
|
1562
1776
|
{
|
|
1563
1777
|
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" : ""}`,
|
|
@@ -1572,7 +1786,7 @@ function FileInput({
|
|
|
1572
1786
|
"aria-label": placeholder,
|
|
1573
1787
|
"aria-disabled": disabled
|
|
1574
1788
|
},
|
|
1575
|
-
/* @__PURE__ */
|
|
1789
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex flex-col items-center gap-2 text-center" }, /* @__PURE__ */ React17.createElement(
|
|
1576
1790
|
"svg",
|
|
1577
1791
|
{
|
|
1578
1792
|
width: "48",
|
|
@@ -1585,19 +1799,19 @@ function FileInput({
|
|
|
1585
1799
|
strokeLinejoin: "round",
|
|
1586
1800
|
"aria-hidden": "true"
|
|
1587
1801
|
},
|
|
1588
|
-
/* @__PURE__ */
|
|
1589
|
-
/* @__PURE__ */
|
|
1590
|
-
/* @__PURE__ */
|
|
1591
|
-
), /* @__PURE__ */
|
|
1592
|
-
), value.length > 0 && /* @__PURE__ */
|
|
1802
|
+
/* @__PURE__ */ React17.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
1803
|
+
/* @__PURE__ */ React17.createElement("polyline", { points: "17 8 12 3 7 8" }),
|
|
1804
|
+
/* @__PURE__ */ React17.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
|
|
1805
|
+
), /* @__PURE__ */ React17.createElement("p", { className: "text-sm font-medium" }, value.length > 0 ? `${value.length} file(s) selected` : placeholder), accept && /* @__PURE__ */ React17.createElement("p", { className: "text-xs" }, "Accepted: ", accept), maxSize && /* @__PURE__ */ React17.createElement("p", { className: "text-xs " }, "Max size: ", formatFileSize(maxSize)))
|
|
1806
|
+
), value.length > 0 && /* @__PURE__ */ React17.createElement("ul", { className: "flex flex-col gap-2 mt-4", role: "list" }, value.map((file, index) => {
|
|
1593
1807
|
const previewUrl = showPreview ? getPreviewUrl(file) : null;
|
|
1594
|
-
return /* @__PURE__ */
|
|
1808
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1595
1809
|
"li",
|
|
1596
1810
|
{
|
|
1597
1811
|
key: `${file.name}-${index}`,
|
|
1598
1812
|
className: "flex items-center gap-3 p-3 rounded-md border border-border bg-card text-card-foreground hover:bg-primary/50 transition-colors"
|
|
1599
1813
|
},
|
|
1600
|
-
previewUrl && /* @__PURE__ */
|
|
1814
|
+
previewUrl && /* @__PURE__ */ React17.createElement(
|
|
1601
1815
|
"img",
|
|
1602
1816
|
{
|
|
1603
1817
|
src: previewUrl,
|
|
@@ -1607,7 +1821,7 @@ function FileInput({
|
|
|
1607
1821
|
height: "48"
|
|
1608
1822
|
}
|
|
1609
1823
|
),
|
|
1610
|
-
/* @__PURE__ */
|
|
1824
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React17.createElement("span", { className: "text-sm font-medium truncate" }, file.name), /* @__PURE__ */ React17.createElement("span", { className: "text-xs" }, formatFileSize(file.size)), showProgress && uploadProgress[file.name] !== void 0 && /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 mt-1" }, /* @__PURE__ */ React17.createElement(
|
|
1611
1825
|
"div",
|
|
1612
1826
|
{
|
|
1613
1827
|
className: "h-1.5 bg-muted rounded-full overflow-hidden flex-1",
|
|
@@ -1617,15 +1831,15 @@ function FileInput({
|
|
|
1617
1831
|
"aria-valuemax": 100,
|
|
1618
1832
|
"aria-label": `Upload progress: ${uploadProgress[file.name]}%`
|
|
1619
1833
|
},
|
|
1620
|
-
/* @__PURE__ */
|
|
1834
|
+
/* @__PURE__ */ React17.createElement(
|
|
1621
1835
|
"div",
|
|
1622
1836
|
{
|
|
1623
1837
|
className: "h-full bg-primary transition-all",
|
|
1624
1838
|
style: { width: `${uploadProgress[file.name]}%` }
|
|
1625
1839
|
}
|
|
1626
1840
|
)
|
|
1627
|
-
), /* @__PURE__ */
|
|
1628
|
-
enableCropping && file.type.startsWith("image/") && /* @__PURE__ */
|
|
1841
|
+
), /* @__PURE__ */ React17.createElement("span", { className: "text-xs " }, uploadProgress[file.name], "%"))),
|
|
1842
|
+
enableCropping && file.type.startsWith("image/") && /* @__PURE__ */ React17.createElement(
|
|
1629
1843
|
"button",
|
|
1630
1844
|
{
|
|
1631
1845
|
type: "button",
|
|
@@ -1637,7 +1851,7 @@ function FileInput({
|
|
|
1637
1851
|
className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
|
|
1638
1852
|
"aria-label": `Crop ${file.name}`
|
|
1639
1853
|
},
|
|
1640
|
-
/* @__PURE__ */
|
|
1854
|
+
/* @__PURE__ */ React17.createElement(
|
|
1641
1855
|
"svg",
|
|
1642
1856
|
{
|
|
1643
1857
|
width: "20",
|
|
@@ -1650,11 +1864,11 @@ function FileInput({
|
|
|
1650
1864
|
strokeLinejoin: "round",
|
|
1651
1865
|
"aria-hidden": "true"
|
|
1652
1866
|
},
|
|
1653
|
-
/* @__PURE__ */
|
|
1654
|
-
/* @__PURE__ */
|
|
1867
|
+
/* @__PURE__ */ React17.createElement("path", { d: "M6.13 1L6 16a2 2 0 0 0 2 2h15" }),
|
|
1868
|
+
/* @__PURE__ */ React17.createElement("path", { d: "M1 6.13L16 6a2 2 0 0 1 2 2v15" })
|
|
1655
1869
|
)
|
|
1656
1870
|
),
|
|
1657
|
-
/* @__PURE__ */
|
|
1871
|
+
/* @__PURE__ */ React17.createElement(
|
|
1658
1872
|
"button",
|
|
1659
1873
|
{
|
|
1660
1874
|
type: "button",
|
|
@@ -1666,7 +1880,7 @@ function FileInput({
|
|
|
1666
1880
|
className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
|
|
1667
1881
|
"aria-label": `Remove ${file.name}`
|
|
1668
1882
|
},
|
|
1669
|
-
/* @__PURE__ */
|
|
1883
|
+
/* @__PURE__ */ React17.createElement(
|
|
1670
1884
|
"svg",
|
|
1671
1885
|
{
|
|
1672
1886
|
width: "20",
|
|
@@ -1679,19 +1893,19 @@ function FileInput({
|
|
|
1679
1893
|
strokeLinejoin: "round",
|
|
1680
1894
|
"aria-hidden": "true"
|
|
1681
1895
|
},
|
|
1682
|
-
/* @__PURE__ */
|
|
1683
|
-
/* @__PURE__ */
|
|
1896
|
+
/* @__PURE__ */ React17.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1897
|
+
/* @__PURE__ */ React17.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1684
1898
|
)
|
|
1685
1899
|
)
|
|
1686
1900
|
);
|
|
1687
|
-
})), cropperOpen && imageToCrop && /* @__PURE__ */
|
|
1901
|
+
})), cropperOpen && imageToCrop && /* @__PURE__ */ React17.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center" }, /* @__PURE__ */ React17.createElement(
|
|
1688
1902
|
"div",
|
|
1689
1903
|
{
|
|
1690
1904
|
className: "absolute inset-0 bg-black/50",
|
|
1691
1905
|
onClick: handleCropCancel,
|
|
1692
1906
|
"aria-label": "Close cropper"
|
|
1693
1907
|
}
|
|
1694
|
-
), /* @__PURE__ */
|
|
1908
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "relative bg-popover border border-border rounded-lg shadow-lg max-w-3xl w-full mx-4" }, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-between p-4 border-b border-border" }, /* @__PURE__ */ React17.createElement("h3", { className: "text-lg font-semibold" }, "Crop Image"), /* @__PURE__ */ React17.createElement(
|
|
1695
1909
|
"button",
|
|
1696
1910
|
{
|
|
1697
1911
|
type: "button",
|
|
@@ -1700,7 +1914,7 @@ function FileInput({
|
|
|
1700
1914
|
"aria-label": "Close"
|
|
1701
1915
|
},
|
|
1702
1916
|
"\u2715"
|
|
1703
|
-
)), /* @__PURE__ */
|
|
1917
|
+
)), /* @__PURE__ */ React17.createElement("div", { className: "p-4" }, /* @__PURE__ */ React17.createElement(
|
|
1704
1918
|
"div",
|
|
1705
1919
|
{
|
|
1706
1920
|
className: "relative w-full h-96 bg-muted rounded-md overflow-hidden",
|
|
@@ -1722,7 +1936,7 @@ function FileInput({
|
|
|
1722
1936
|
document.addEventListener("mouseup", handleMouseUp);
|
|
1723
1937
|
}
|
|
1724
1938
|
},
|
|
1725
|
-
/* @__PURE__ */
|
|
1939
|
+
/* @__PURE__ */ React17.createElement(
|
|
1726
1940
|
"img",
|
|
1727
1941
|
{
|
|
1728
1942
|
src: imageToCrop.url,
|
|
@@ -1757,7 +1971,7 @@ function FileInput({
|
|
|
1757
1971
|
}
|
|
1758
1972
|
}
|
|
1759
1973
|
),
|
|
1760
|
-
/* @__PURE__ */
|
|
1974
|
+
/* @__PURE__ */ React17.createElement(
|
|
1761
1975
|
"div",
|
|
1762
1976
|
{
|
|
1763
1977
|
className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 border-2 border-primary rounded pointer-events-none",
|
|
@@ -1766,9 +1980,9 @@ function FileInput({
|
|
|
1766
1980
|
aspectRatio: cropAspectRatio ? String(cropAspectRatio) : void 0
|
|
1767
1981
|
}
|
|
1768
1982
|
},
|
|
1769
|
-
/* @__PURE__ */
|
|
1983
|
+
/* @__PURE__ */ React17.createElement("div", { className: "absolute inset-0 grid grid-cols-3 grid-rows-3" }, /* @__PURE__ */ React17.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React17.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React17.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React17.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React17.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React17.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React17.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React17.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React17.createElement("div", null))
|
|
1770
1984
|
)
|
|
1771
|
-
), /* @__PURE__ */
|
|
1985
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-3 mt-4" }, /* @__PURE__ */ React17.createElement(
|
|
1772
1986
|
"label",
|
|
1773
1987
|
{
|
|
1774
1988
|
htmlFor: "zoom-slider",
|
|
@@ -1777,7 +1991,7 @@ function FileInput({
|
|
|
1777
1991
|
"Zoom: ",
|
|
1778
1992
|
zoom.toFixed(1),
|
|
1779
1993
|
"x"
|
|
1780
|
-
), /* @__PURE__ */
|
|
1994
|
+
), /* @__PURE__ */ React17.createElement(
|
|
1781
1995
|
"input",
|
|
1782
1996
|
{
|
|
1783
1997
|
id: "zoom-slider",
|
|
@@ -1790,7 +2004,7 @@ function FileInput({
|
|
|
1790
2004
|
className: "flex-1 h-2 bg-muted rounded-lg appearance-none cursor-pointer",
|
|
1791
2005
|
"aria-label": "Zoom level"
|
|
1792
2006
|
}
|
|
1793
|
-
))), /* @__PURE__ */
|
|
2007
|
+
))), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-end gap-2 p-4 border-t border-border" }, /* @__PURE__ */ React17.createElement(
|
|
1794
2008
|
"button",
|
|
1795
2009
|
{
|
|
1796
2010
|
type: "button",
|
|
@@ -1798,7 +2012,7 @@ function FileInput({
|
|
|
1798
2012
|
onClick: handleCropCancel
|
|
1799
2013
|
},
|
|
1800
2014
|
"Cancel"
|
|
1801
|
-
), /* @__PURE__ */
|
|
2015
|
+
), /* @__PURE__ */ React17.createElement(
|
|
1802
2016
|
"button",
|
|
1803
2017
|
{
|
|
1804
2018
|
type: "button",
|
|
@@ -1840,14 +2054,14 @@ function DatePicker({
|
|
|
1840
2054
|
showIcon = true,
|
|
1841
2055
|
...props
|
|
1842
2056
|
}) {
|
|
1843
|
-
const [isOpen, setIsOpen] =
|
|
1844
|
-
const [hasInteracted, setHasInteracted] =
|
|
1845
|
-
const [selectedMonth, setSelectedMonth] =
|
|
2057
|
+
const [isOpen, setIsOpen] = React17.useState(false);
|
|
2058
|
+
const [hasInteracted, setHasInteracted] = React17.useState(false);
|
|
2059
|
+
const [selectedMonth, setSelectedMonth] = React17.useState(
|
|
1846
2060
|
value || /* @__PURE__ */ new Date()
|
|
1847
2061
|
);
|
|
1848
|
-
const inputRef =
|
|
1849
|
-
const dropdownRef =
|
|
1850
|
-
|
|
2062
|
+
const inputRef = React17.useRef(null);
|
|
2063
|
+
const dropdownRef = React17.useRef(null);
|
|
2064
|
+
React17.useEffect(() => {
|
|
1851
2065
|
if (value) {
|
|
1852
2066
|
setSelectedMonth(value);
|
|
1853
2067
|
}
|
|
@@ -1879,7 +2093,7 @@ function DatePicker({
|
|
|
1879
2093
|
if (isDateDisabled && isDateDisabled(date)) return true;
|
|
1880
2094
|
return false;
|
|
1881
2095
|
};
|
|
1882
|
-
const closeCalendar =
|
|
2096
|
+
const closeCalendar = React17.useCallback(() => {
|
|
1883
2097
|
if (!isOpen) return;
|
|
1884
2098
|
setIsOpen(false);
|
|
1885
2099
|
if (hasInteracted) {
|
|
@@ -1933,7 +2147,7 @@ function DatePicker({
|
|
|
1933
2147
|
const handleNextMonth = () => {
|
|
1934
2148
|
setSelectedMonth(new Date(year, month + 1, 1));
|
|
1935
2149
|
};
|
|
1936
|
-
return /* @__PURE__ */
|
|
2150
|
+
return /* @__PURE__ */ React17.createElement("div", { role: "grid", "aria-label": "Calendar", className: "w-[248px] max-w-full" }, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-between pb-3" }, /* @__PURE__ */ React17.createElement(
|
|
1937
2151
|
"button",
|
|
1938
2152
|
{
|
|
1939
2153
|
type: "button",
|
|
@@ -1942,7 +2156,7 @@ function DatePicker({
|
|
|
1942
2156
|
"aria-label": "Previous month"
|
|
1943
2157
|
},
|
|
1944
2158
|
"\u2039"
|
|
1945
|
-
), /* @__PURE__ */
|
|
2159
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React17.createElement(
|
|
1946
2160
|
"button",
|
|
1947
2161
|
{
|
|
1948
2162
|
type: "button",
|
|
@@ -1951,13 +2165,13 @@ function DatePicker({
|
|
|
1951
2165
|
"aria-label": "Next month"
|
|
1952
2166
|
},
|
|
1953
2167
|
"\u203A"
|
|
1954
|
-
)), /* @__PURE__ */
|
|
2168
|
+
)), /* @__PURE__ */ React17.createElement(
|
|
1955
2169
|
"div",
|
|
1956
2170
|
{
|
|
1957
2171
|
className: "grid gap-1 text-xs text-muted-foreground",
|
|
1958
2172
|
style: dayGridStyle
|
|
1959
2173
|
},
|
|
1960
|
-
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */
|
|
2174
|
+
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React17.createElement(
|
|
1961
2175
|
"div",
|
|
1962
2176
|
{
|
|
1963
2177
|
key: day,
|
|
@@ -1965,14 +2179,14 @@ function DatePicker({
|
|
|
1965
2179
|
},
|
|
1966
2180
|
day
|
|
1967
2181
|
))
|
|
1968
|
-
), /* @__PURE__ */
|
|
2182
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
|
|
1969
2183
|
if (!date) {
|
|
1970
|
-
return /* @__PURE__ */
|
|
2184
|
+
return /* @__PURE__ */ React17.createElement("div", { key: `empty-${index}`, className: "h-8 w-8" });
|
|
1971
2185
|
}
|
|
1972
2186
|
const isSelected = value && date.toDateString() === value.toDateString();
|
|
1973
2187
|
const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
|
|
1974
2188
|
const disabled2 = isDisabled(date);
|
|
1975
|
-
return /* @__PURE__ */
|
|
2189
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1976
2190
|
"button",
|
|
1977
2191
|
{
|
|
1978
2192
|
key: date.toISOString(),
|
|
@@ -1993,20 +2207,20 @@ function DatePicker({
|
|
|
1993
2207
|
})));
|
|
1994
2208
|
};
|
|
1995
2209
|
const combinedClassName = cn("relative", className);
|
|
1996
|
-
return /* @__PURE__ */
|
|
2210
|
+
return /* @__PURE__ */ React17.createElement("div", { className: combinedClassName, onBlur: handleBlur }, /* @__PURE__ */ React17.createElement(
|
|
1997
2211
|
"input",
|
|
1998
2212
|
{
|
|
1999
2213
|
type: "hidden",
|
|
2000
2214
|
name,
|
|
2001
2215
|
value: value ? value.toISOString() : ""
|
|
2002
2216
|
}
|
|
2003
|
-
), /* @__PURE__ */
|
|
2217
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React17.createElement(
|
|
2004
2218
|
"span",
|
|
2005
2219
|
{
|
|
2006
2220
|
className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
|
|
2007
2221
|
"aria-hidden": "true"
|
|
2008
2222
|
},
|
|
2009
|
-
/* @__PURE__ */
|
|
2223
|
+
/* @__PURE__ */ React17.createElement(
|
|
2010
2224
|
"svg",
|
|
2011
2225
|
{
|
|
2012
2226
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2019,9 +2233,9 @@ function DatePicker({
|
|
|
2019
2233
|
strokeLinejoin: "round",
|
|
2020
2234
|
strokeWidth: "2"
|
|
2021
2235
|
},
|
|
2022
|
-
/* @__PURE__ */
|
|
2236
|
+
/* @__PURE__ */ React17.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" })
|
|
2023
2237
|
)
|
|
2024
|
-
), /* @__PURE__ */
|
|
2238
|
+
), /* @__PURE__ */ React17.createElement(
|
|
2025
2239
|
"input",
|
|
2026
2240
|
{
|
|
2027
2241
|
ref: inputRef,
|
|
@@ -2046,7 +2260,7 @@ function DatePicker({
|
|
|
2046
2260
|
"aria-required": required || props["aria-required"],
|
|
2047
2261
|
readOnly: true
|
|
2048
2262
|
}
|
|
2049
|
-
), clearable && value && !disabled && /* @__PURE__ */
|
|
2263
|
+
), clearable && value && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2050
2264
|
"button",
|
|
2051
2265
|
{
|
|
2052
2266
|
type: "button",
|
|
@@ -2056,7 +2270,7 @@ function DatePicker({
|
|
|
2056
2270
|
tabIndex: -1
|
|
2057
2271
|
},
|
|
2058
2272
|
"\u2715"
|
|
2059
|
-
)), isOpen && !disabled && /* @__PURE__ */
|
|
2273
|
+
)), isOpen && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2060
2274
|
"div",
|
|
2061
2275
|
{
|
|
2062
2276
|
ref: dropdownRef,
|
|
@@ -2123,11 +2337,11 @@ function TimePicker({
|
|
|
2123
2337
|
showIcon = true,
|
|
2124
2338
|
...props
|
|
2125
2339
|
}) {
|
|
2126
|
-
const inputRef =
|
|
2127
|
-
const [nativeValue, setNativeValue] =
|
|
2340
|
+
const inputRef = React17.useRef(null);
|
|
2341
|
+
const [nativeValue, setNativeValue] = React17.useState(
|
|
2128
2342
|
normalizeToNativeTime(value)
|
|
2129
2343
|
);
|
|
2130
|
-
|
|
2344
|
+
React17.useEffect(() => {
|
|
2131
2345
|
setNativeValue(normalizeToNativeTime(value));
|
|
2132
2346
|
}, [value]);
|
|
2133
2347
|
const handleChange = (e) => {
|
|
@@ -2143,13 +2357,13 @@ function TimePicker({
|
|
|
2143
2357
|
};
|
|
2144
2358
|
const hasValue = Boolean(value);
|
|
2145
2359
|
const stepInSeconds = Math.max(1, minuteStep * 60);
|
|
2146
|
-
return /* @__PURE__ */
|
|
2360
|
+
return /* @__PURE__ */ React17.createElement("div", { className: cn("relative", className) }, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name, value }), /* @__PURE__ */ React17.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React17.createElement(
|
|
2147
2361
|
"span",
|
|
2148
2362
|
{
|
|
2149
2363
|
className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
|
|
2150
2364
|
"aria-hidden": "true"
|
|
2151
2365
|
},
|
|
2152
|
-
/* @__PURE__ */
|
|
2366
|
+
/* @__PURE__ */ React17.createElement(
|
|
2153
2367
|
"svg",
|
|
2154
2368
|
{
|
|
2155
2369
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2162,10 +2376,10 @@ function TimePicker({
|
|
|
2162
2376
|
strokeLinejoin: "round",
|
|
2163
2377
|
strokeWidth: "2"
|
|
2164
2378
|
},
|
|
2165
|
-
/* @__PURE__ */
|
|
2166
|
-
/* @__PURE__ */
|
|
2379
|
+
/* @__PURE__ */ React17.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
2380
|
+
/* @__PURE__ */ React17.createElement("path", { d: "M12 6v6l4 2" })
|
|
2167
2381
|
)
|
|
2168
|
-
), /* @__PURE__ */
|
|
2382
|
+
), /* @__PURE__ */ React17.createElement(
|
|
2169
2383
|
"input",
|
|
2170
2384
|
{
|
|
2171
2385
|
ref: inputRef,
|
|
@@ -2193,7 +2407,7 @@ function TimePicker({
|
|
|
2193
2407
|
"aria-required": required || props["aria-required"],
|
|
2194
2408
|
...props
|
|
2195
2409
|
}
|
|
2196
|
-
), clearable && value && !disabled && /* @__PURE__ */
|
|
2410
|
+
), clearable && value && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2197
2411
|
"button",
|
|
2198
2412
|
{
|
|
2199
2413
|
type: "button",
|
|
@@ -2246,17 +2460,17 @@ function DateRangePicker({
|
|
|
2246
2460
|
separator = " - ",
|
|
2247
2461
|
...props
|
|
2248
2462
|
}) {
|
|
2249
|
-
const [isOpen, setIsOpen] =
|
|
2250
|
-
const [hasInteracted, setHasInteracted] =
|
|
2251
|
-
const [selectedMonth, setSelectedMonth] =
|
|
2463
|
+
const [isOpen, setIsOpen] = React17.useState(false);
|
|
2464
|
+
const [hasInteracted, setHasInteracted] = React17.useState(false);
|
|
2465
|
+
const [selectedMonth, setSelectedMonth] = React17.useState(
|
|
2252
2466
|
value.start || /* @__PURE__ */ new Date()
|
|
2253
2467
|
);
|
|
2254
|
-
const [rangeStart, setRangeStart] =
|
|
2255
|
-
const [rangeEnd, setRangeEnd] =
|
|
2256
|
-
const [hoverDate, setHoverDate] =
|
|
2257
|
-
const triggerRef =
|
|
2258
|
-
const dropdownRef =
|
|
2259
|
-
|
|
2468
|
+
const [rangeStart, setRangeStart] = React17.useState(value.start);
|
|
2469
|
+
const [rangeEnd, setRangeEnd] = React17.useState(value.end);
|
|
2470
|
+
const [hoverDate, setHoverDate] = React17.useState(null);
|
|
2471
|
+
const triggerRef = React17.useRef(null);
|
|
2472
|
+
const dropdownRef = React17.useRef(null);
|
|
2473
|
+
React17.useEffect(() => {
|
|
2260
2474
|
setRangeStart(value.start);
|
|
2261
2475
|
setRangeEnd(value.end);
|
|
2262
2476
|
if (value.start) {
|
|
@@ -2305,7 +2519,7 @@ function DateRangePicker({
|
|
|
2305
2519
|
if (isDateDisabled && isDateDisabled(date)) return true;
|
|
2306
2520
|
return false;
|
|
2307
2521
|
};
|
|
2308
|
-
const closeCalendar =
|
|
2522
|
+
const closeCalendar = React17.useCallback(() => {
|
|
2309
2523
|
if (!isOpen) return;
|
|
2310
2524
|
setIsOpen(false);
|
|
2311
2525
|
if (hasInteracted) {
|
|
@@ -2355,7 +2569,7 @@ function DateRangePicker({
|
|
|
2355
2569
|
for (let day = 1; day <= daysInMonth; day++) {
|
|
2356
2570
|
days.push(new Date(year, month, day));
|
|
2357
2571
|
}
|
|
2358
|
-
return /* @__PURE__ */
|
|
2572
|
+
return /* @__PURE__ */ React17.createElement("div", { className: "w-[240px] max-w-full" }, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-between pb-3" }, controls?.prev ? /* @__PURE__ */ React17.createElement(
|
|
2359
2573
|
"button",
|
|
2360
2574
|
{
|
|
2361
2575
|
type: "button",
|
|
@@ -2364,7 +2578,7 @@ function DateRangePicker({
|
|
|
2364
2578
|
"aria-label": "Previous month"
|
|
2365
2579
|
},
|
|
2366
2580
|
"\u2039"
|
|
2367
|
-
) : /* @__PURE__ */
|
|
2581
|
+
) : /* @__PURE__ */ React17.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" }), /* @__PURE__ */ React17.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), controls?.next ? /* @__PURE__ */ React17.createElement(
|
|
2368
2582
|
"button",
|
|
2369
2583
|
{
|
|
2370
2584
|
type: "button",
|
|
@@ -2373,13 +2587,13 @@ function DateRangePicker({
|
|
|
2373
2587
|
"aria-label": "Next month"
|
|
2374
2588
|
},
|
|
2375
2589
|
"\u203A"
|
|
2376
|
-
) : /* @__PURE__ */
|
|
2590
|
+
) : /* @__PURE__ */ React17.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" })), /* @__PURE__ */ React17.createElement(
|
|
2377
2591
|
"div",
|
|
2378
2592
|
{
|
|
2379
2593
|
className: "grid gap-1 text-xs text-muted-foreground",
|
|
2380
2594
|
style: dayGridStyle
|
|
2381
2595
|
},
|
|
2382
|
-
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */
|
|
2596
|
+
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React17.createElement(
|
|
2383
2597
|
"div",
|
|
2384
2598
|
{
|
|
2385
2599
|
key: `${month}-${day}`,
|
|
@@ -2387,9 +2601,9 @@ function DateRangePicker({
|
|
|
2387
2601
|
},
|
|
2388
2602
|
day
|
|
2389
2603
|
))
|
|
2390
|
-
), /* @__PURE__ */
|
|
2604
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
|
|
2391
2605
|
if (!date) {
|
|
2392
|
-
return /* @__PURE__ */
|
|
2606
|
+
return /* @__PURE__ */ React17.createElement("div", { key: `empty-${month}-${index}`, className: "h-8 w-8" });
|
|
2393
2607
|
}
|
|
2394
2608
|
const isStart = rangeStart && date.toDateString() === rangeStart.toDateString();
|
|
2395
2609
|
const isEnd = rangeEnd && date.toDateString() === rangeEnd.toDateString();
|
|
@@ -2401,7 +2615,7 @@ function DateRangePicker({
|
|
|
2401
2615
|
);
|
|
2402
2616
|
const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
|
|
2403
2617
|
const disabled2 = isDisabled(date);
|
|
2404
|
-
return /* @__PURE__ */
|
|
2618
|
+
return /* @__PURE__ */ React17.createElement(
|
|
2405
2619
|
"button",
|
|
2406
2620
|
{
|
|
2407
2621
|
key: date.toISOString(),
|
|
@@ -2426,27 +2640,27 @@ function DateRangePicker({
|
|
|
2426
2640
|
};
|
|
2427
2641
|
const combinedClassName = cn("relative", className);
|
|
2428
2642
|
const displayValue = rangeStart && rangeEnd ? `${formatDate2(rangeStart, format)}${separator}${formatDate2(rangeEnd, format)}` : rangeStart ? formatDate2(rangeStart, format) : "";
|
|
2429
|
-
return /* @__PURE__ */
|
|
2643
|
+
return /* @__PURE__ */ React17.createElement("div", { className: combinedClassName, onBlur: handleBlur }, /* @__PURE__ */ React17.createElement(
|
|
2430
2644
|
"input",
|
|
2431
2645
|
{
|
|
2432
2646
|
type: "hidden",
|
|
2433
2647
|
name: `${name}[start]`,
|
|
2434
2648
|
value: rangeStart ? rangeStart.toISOString() : ""
|
|
2435
2649
|
}
|
|
2436
|
-
), /* @__PURE__ */
|
|
2650
|
+
), /* @__PURE__ */ React17.createElement(
|
|
2437
2651
|
"input",
|
|
2438
2652
|
{
|
|
2439
2653
|
type: "hidden",
|
|
2440
2654
|
name: `${name}[end]`,
|
|
2441
2655
|
value: rangeEnd ? rangeEnd.toISOString() : ""
|
|
2442
2656
|
}
|
|
2443
|
-
), /* @__PURE__ */
|
|
2657
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React17.createElement(
|
|
2444
2658
|
"span",
|
|
2445
2659
|
{
|
|
2446
2660
|
className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
|
|
2447
2661
|
"aria-hidden": "true"
|
|
2448
2662
|
},
|
|
2449
|
-
/* @__PURE__ */
|
|
2663
|
+
/* @__PURE__ */ React17.createElement(
|
|
2450
2664
|
"svg",
|
|
2451
2665
|
{
|
|
2452
2666
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2459,9 +2673,9 @@ function DateRangePicker({
|
|
|
2459
2673
|
strokeLinejoin: "round",
|
|
2460
2674
|
strokeWidth: "2"
|
|
2461
2675
|
},
|
|
2462
|
-
/* @__PURE__ */
|
|
2676
|
+
/* @__PURE__ */ React17.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" })
|
|
2463
2677
|
)
|
|
2464
|
-
), /* @__PURE__ */
|
|
2678
|
+
), /* @__PURE__ */ React17.createElement(
|
|
2465
2679
|
"input",
|
|
2466
2680
|
{
|
|
2467
2681
|
ref: triggerRef,
|
|
@@ -2486,7 +2700,7 @@ function DateRangePicker({
|
|
|
2486
2700
|
"aria-required": required || props["aria-required"],
|
|
2487
2701
|
readOnly: true
|
|
2488
2702
|
}
|
|
2489
|
-
), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */
|
|
2703
|
+
), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2490
2704
|
"button",
|
|
2491
2705
|
{
|
|
2492
2706
|
type: "button",
|
|
@@ -2496,14 +2710,14 @@ function DateRangePicker({
|
|
|
2496
2710
|
tabIndex: -1
|
|
2497
2711
|
},
|
|
2498
2712
|
"\u2715"
|
|
2499
|
-
)), isOpen && !disabled && /* @__PURE__ */
|
|
2713
|
+
)), isOpen && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2500
2714
|
"div",
|
|
2501
2715
|
{
|
|
2502
2716
|
ref: dropdownRef,
|
|
2503
2717
|
className: "absolute z-50 top-full mt-1 w-fit rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3"
|
|
2504
2718
|
},
|
|
2505
|
-
/* @__PURE__ */
|
|
2506
|
-
rangeStart && !rangeEnd && /* @__PURE__ */
|
|
2719
|
+
/* @__PURE__ */ React17.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React17.createElement("div", { className: "grid gap-4", style: monthsGridStyle }, renderMonth(selectedMonth, { prev: true }), renderMonth(addMonths(selectedMonth, 1), { next: true }))),
|
|
2720
|
+
rangeStart && !rangeEnd && /* @__PURE__ */ React17.createElement("div", { className: "text-xs text-center pt-2 border-t border-border mt-2" }, "Select end date")
|
|
2507
2721
|
));
|
|
2508
2722
|
}
|
|
2509
2723
|
DateRangePicker.displayName = "DateRangePicker";
|
|
@@ -2575,11 +2789,11 @@ function RichTextEditor({
|
|
|
2575
2789
|
],
|
|
2576
2790
|
...props
|
|
2577
2791
|
}) {
|
|
2578
|
-
const [currentMode, setCurrentMode] =
|
|
2579
|
-
const [content, setContent] =
|
|
2580
|
-
const editorRef =
|
|
2581
|
-
const textareaRef =
|
|
2582
|
-
|
|
2792
|
+
const [currentMode, setCurrentMode] = React17.useState(mode);
|
|
2793
|
+
const [content, setContent] = React17.useState(value);
|
|
2794
|
+
const editorRef = React17.useRef(null);
|
|
2795
|
+
const textareaRef = React17.useRef(null);
|
|
2796
|
+
React17.useEffect(() => {
|
|
2583
2797
|
setContent(value);
|
|
2584
2798
|
if (currentMode === "wysiwyg" && editorRef.current) {
|
|
2585
2799
|
editorRef.current.innerHTML = value;
|
|
@@ -2667,7 +2881,7 @@ function RichTextEditor({
|
|
|
2667
2881
|
}
|
|
2668
2882
|
}
|
|
2669
2883
|
};
|
|
2670
|
-
const hasValue =
|
|
2884
|
+
const hasValue = React17.useMemo(() => {
|
|
2671
2885
|
if (!content) return false;
|
|
2672
2886
|
const stripped = content.replace(/<[^>]+>/g, "").trim();
|
|
2673
2887
|
return stripped.length > 0;
|
|
@@ -2684,10 +2898,10 @@ function RichTextEditor({
|
|
|
2684
2898
|
maxHeight,
|
|
2685
2899
|
overflowY: maxHeight ? "auto" : void 0
|
|
2686
2900
|
};
|
|
2687
|
-
return /* @__PURE__ */
|
|
2901
|
+
return /* @__PURE__ */ React17.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name, value: content }), showToolbar && /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-between p-2 border-b border-border bg-muted/50" }, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-1" }, toolbarButtons.map((buttonName) => {
|
|
2688
2902
|
const button = toolbarConfig[buttonName];
|
|
2689
2903
|
if (!button) return null;
|
|
2690
|
-
return /* @__PURE__ */
|
|
2904
|
+
return /* @__PURE__ */ React17.createElement(
|
|
2691
2905
|
"button",
|
|
2692
2906
|
{
|
|
2693
2907
|
key: buttonName,
|
|
@@ -2700,7 +2914,7 @@ function RichTextEditor({
|
|
|
2700
2914
|
},
|
|
2701
2915
|
button.icon
|
|
2702
2916
|
);
|
|
2703
|
-
})), allowModeSwitch && /* @__PURE__ */
|
|
2917
|
+
})), allowModeSwitch && /* @__PURE__ */ React17.createElement(
|
|
2704
2918
|
"button",
|
|
2705
2919
|
{
|
|
2706
2920
|
type: "button",
|
|
@@ -2711,7 +2925,7 @@ function RichTextEditor({
|
|
|
2711
2925
|
"aria-label": `Switch to ${currentMode === "wysiwyg" ? "Markdown" : "WYSIWYG"}`
|
|
2712
2926
|
},
|
|
2713
2927
|
currentMode === "wysiwyg" ? "MD" : "WYSIWYG"
|
|
2714
|
-
)), /* @__PURE__ */
|
|
2928
|
+
)), /* @__PURE__ */ React17.createElement("div", { style: editorStyle }, currentMode === "wysiwyg" ? /* @__PURE__ */ React17.createElement(
|
|
2715
2929
|
"div",
|
|
2716
2930
|
{
|
|
2717
2931
|
ref: editorRef,
|
|
@@ -2726,7 +2940,7 @@ function RichTextEditor({
|
|
|
2726
2940
|
"aria-required": required || props["aria-required"],
|
|
2727
2941
|
suppressContentEditableWarning: true
|
|
2728
2942
|
}
|
|
2729
|
-
) : /* @__PURE__ */
|
|
2943
|
+
) : /* @__PURE__ */ React17.createElement(
|
|
2730
2944
|
"textarea",
|
|
2731
2945
|
{
|
|
2732
2946
|
ref: textareaRef,
|
|
@@ -2749,6 +2963,6 @@ function RichTextEditor({
|
|
|
2749
2963
|
}
|
|
2750
2964
|
RichTextEditor.displayName = "RichTextEditor";
|
|
2751
2965
|
|
|
2752
|
-
export { Checkbox, CheckboxGroup, DatePicker, DateRangePicker, FileInput, MultiSelect, Radio, RichTextEditor, Select, TextArea, TextInput, TimePicker };
|
|
2966
|
+
export { Checkbox2 as Checkbox, CheckboxGroup, DatePicker, DateRangePicker, FileInput, MultiSelect, Radio, RichTextEditor, Select2 as Select, Switch2 as Switch, TextArea, TextInput, TimePicker };
|
|
2753
2967
|
//# sourceMappingURL=inputs.js.map
|
|
2754
2968
|
//# sourceMappingURL=inputs.js.map
|