@page-speed/forms 0.4.8 → 0.5.0
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 +89 -21
- 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 +89 -21
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +94 -21
- 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 +89 -21
- package/dist/index.js.map +1 -1
- package/dist/inputs.cjs +935 -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 +932 -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,104 @@ 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
|
-
|
|
650
|
-
|
|
651
|
-
setSearchQuery("");
|
|
652
|
-
setFocusedIndex(-1);
|
|
653
|
-
};
|
|
654
|
-
const handleClear = (e) => {
|
|
655
|
-
e.stopPropagation();
|
|
656
|
-
onChange("");
|
|
657
|
-
setSearchQuery("");
|
|
658
|
-
setFocusedIndex(-1);
|
|
1046
|
+
const selectValue = value ? String(value) : void 0;
|
|
1047
|
+
const handleValueChange = (newValue) => {
|
|
1048
|
+
onChange(newValue);
|
|
659
1049
|
};
|
|
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) {
|
|
1050
|
+
const handleOpenChange = (open) => {
|
|
1051
|
+
if (open) {
|
|
1052
|
+
if (!hasInteracted) {
|
|
1053
|
+
setHasInteracted(true);
|
|
1054
|
+
}
|
|
671
1055
|
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) {
|
|
1056
|
+
} else if (hasInteracted) {
|
|
749
1057
|
onBlur?.();
|
|
750
1058
|
}
|
|
751
1059
|
};
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
1060
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(
|
|
1061
|
+
"input",
|
|
1062
|
+
{
|
|
1063
|
+
type: "hidden",
|
|
1064
|
+
name,
|
|
1065
|
+
value: value ?? "",
|
|
1066
|
+
disabled,
|
|
1067
|
+
required,
|
|
1068
|
+
tabIndex: -1,
|
|
1069
|
+
"aria-hidden": "true",
|
|
1070
|
+
style: {
|
|
1071
|
+
position: "absolute",
|
|
1072
|
+
width: "1px",
|
|
1073
|
+
height: "1px",
|
|
1074
|
+
padding: "0",
|
|
1075
|
+
margin: "-1px",
|
|
1076
|
+
overflow: "hidden",
|
|
1077
|
+
clip: "rect(0, 0, 0, 0)",
|
|
1078
|
+
whiteSpace: "nowrap",
|
|
1079
|
+
border: "0"
|
|
1080
|
+
}
|
|
759
1081
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
capture: true
|
|
763
|
-
});
|
|
764
|
-
const combinedClassName = cn("relative w-full", className);
|
|
765
|
-
return /* @__PURE__ */ React9.createElement(
|
|
766
|
-
"div",
|
|
1082
|
+
), /* @__PURE__ */ React17.createElement(
|
|
1083
|
+
Select,
|
|
767
1084
|
{
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1085
|
+
value: selectValue,
|
|
1086
|
+
onValueChange: handleValueChange,
|
|
1087
|
+
onOpenChange: handleOpenChange,
|
|
1088
|
+
disabled
|
|
771
1089
|
},
|
|
772
|
-
/* @__PURE__ */
|
|
773
|
-
|
|
774
|
-
{
|
|
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",
|
|
1090
|
+
/* @__PURE__ */ React17.createElement(
|
|
1091
|
+
SelectTrigger,
|
|
790
1092
|
{
|
|
791
|
-
ref: triggerRef,
|
|
792
1093
|
className: cn(
|
|
793
|
-
|
|
794
|
-
"cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1094
|
+
// Valid value indicator - ring-2 when has value and no error
|
|
795
1095
|
!error && hasValue && "ring-2 ring-ring",
|
|
796
|
-
|
|
797
|
-
|
|
1096
|
+
// Error state - handled by SelectTrigger via aria-invalid
|
|
1097
|
+
className
|
|
798
1098
|
),
|
|
799
|
-
onClick: handleToggle,
|
|
800
|
-
role: "combobox",
|
|
801
|
-
"aria-expanded": isOpen,
|
|
802
|
-
"aria-controls": dropdownId,
|
|
803
1099
|
"aria-invalid": error || props["aria-invalid"],
|
|
804
1100
|
"aria-describedby": props["aria-describedby"],
|
|
805
|
-
"aria-required": required || props["aria-required"]
|
|
806
|
-
"aria-disabled": disabled,
|
|
807
|
-
tabIndex: disabled ? -1 : 0
|
|
1101
|
+
"aria-required": required || props["aria-required"]
|
|
808
1102
|
},
|
|
809
|
-
/* @__PURE__ */
|
|
810
|
-
|
|
811
|
-
|
|
1103
|
+
/* @__PURE__ */ React17.createElement(SelectValue, { placeholder })
|
|
1104
|
+
),
|
|
1105
|
+
/* @__PURE__ */ React17.createElement(SelectContent, null, optionGroups.length > 0 ? (
|
|
1106
|
+
// Render grouped options
|
|
1107
|
+
optionGroups.map((group, groupIndex) => /* @__PURE__ */ React17.createElement(SelectGroup, { key: groupIndex }, /* @__PURE__ */ React17.createElement(SelectLabel, null, group.label), group.options.map((option) => /* @__PURE__ */ React17.createElement(
|
|
1108
|
+
SelectItem,
|
|
812
1109
|
{
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
"aria-label": "Clear selection",
|
|
817
|
-
tabIndex: -1
|
|
1110
|
+
key: option.value,
|
|
1111
|
+
value: option.value,
|
|
1112
|
+
disabled: option.disabled
|
|
818
1113
|
},
|
|
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",
|
|
1114
|
+
renderOption ? renderOption(option) : option.label
|
|
1115
|
+
))))
|
|
1116
|
+
) : (
|
|
1117
|
+
// Render flat options
|
|
1118
|
+
allOptions.map((option) => /* @__PURE__ */ React17.createElement(
|
|
1119
|
+
SelectItem,
|
|
832
1120
|
{
|
|
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
|
-
})
|
|
1121
|
+
key: option.value,
|
|
1122
|
+
value: option.value,
|
|
1123
|
+
disabled: option.disabled
|
|
1124
|
+
},
|
|
1125
|
+
renderOption ? renderOption(option) : option.label
|
|
891
1126
|
))
|
|
892
|
-
)
|
|
893
|
-
);
|
|
1127
|
+
))
|
|
1128
|
+
));
|
|
894
1129
|
}
|
|
895
|
-
|
|
1130
|
+
Select2.displayName = "Select";
|
|
896
1131
|
function MultiSelect({
|
|
897
1132
|
name,
|
|
898
1133
|
value = [],
|
|
@@ -915,21 +1150,21 @@ function MultiSelect({
|
|
|
915
1150
|
renderValue,
|
|
916
1151
|
...props
|
|
917
1152
|
}) {
|
|
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 =
|
|
1153
|
+
const [isOpen, setIsOpen] = React17.useState(false);
|
|
1154
|
+
const [searchQuery, setSearchQuery] = React17.useState("");
|
|
1155
|
+
const [focusedIndex, setFocusedIndex] = React17.useState(-1);
|
|
1156
|
+
const [hasInteracted, setHasInteracted] = React17.useState(false);
|
|
1157
|
+
const triggerRef = React17.useRef(null);
|
|
1158
|
+
const dropdownRef = React17.useRef(null);
|
|
1159
|
+
const searchInputRef = React17.useRef(null);
|
|
925
1160
|
const dropdownId = `${name}-dropdown`;
|
|
926
|
-
const allOptions =
|
|
1161
|
+
const allOptions = React17.useMemo(() => {
|
|
927
1162
|
if (optionGroups.length > 0) {
|
|
928
1163
|
return optionGroups.flatMap((group) => group.options);
|
|
929
1164
|
}
|
|
930
1165
|
return options;
|
|
931
1166
|
}, [options, optionGroups]);
|
|
932
|
-
const filteredOptions =
|
|
1167
|
+
const filteredOptions = React17.useMemo(() => {
|
|
933
1168
|
if (!searchQuery.trim()) {
|
|
934
1169
|
return allOptions;
|
|
935
1170
|
}
|
|
@@ -939,11 +1174,11 @@ function MultiSelect({
|
|
|
939
1174
|
return label.toLowerCase().includes(query);
|
|
940
1175
|
});
|
|
941
1176
|
}, [allOptions, searchQuery]);
|
|
942
|
-
const selectedOptions =
|
|
1177
|
+
const selectedOptions = React17.useMemo(() => {
|
|
943
1178
|
return allOptions.filter((opt) => value.includes(opt.value));
|
|
944
1179
|
}, [allOptions, value]);
|
|
945
1180
|
const hasValue = value.length > 0;
|
|
946
|
-
const isMaxReached =
|
|
1181
|
+
const isMaxReached = React17.useMemo(() => {
|
|
947
1182
|
return maxSelections !== void 0 && value.length >= maxSelections;
|
|
948
1183
|
}, [maxSelections, value.length]);
|
|
949
1184
|
const handleToggleOption = (optionValue) => {
|
|
@@ -1059,7 +1294,7 @@ function MultiSelect({
|
|
|
1059
1294
|
onBlur?.();
|
|
1060
1295
|
}
|
|
1061
1296
|
};
|
|
1062
|
-
const closeDropdown =
|
|
1297
|
+
const closeDropdown = React17.useCallback(() => {
|
|
1063
1298
|
if (!isOpen) return;
|
|
1064
1299
|
setIsOpen(false);
|
|
1065
1300
|
setSearchQuery("");
|
|
@@ -1072,14 +1307,14 @@ function MultiSelect({
|
|
|
1072
1307
|
capture: true
|
|
1073
1308
|
});
|
|
1074
1309
|
const combinedClassName = cn("relative w-full", className);
|
|
1075
|
-
return /* @__PURE__ */
|
|
1310
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1076
1311
|
"div",
|
|
1077
1312
|
{
|
|
1078
1313
|
className: combinedClassName,
|
|
1079
1314
|
onKeyDown: handleKeyDown,
|
|
1080
1315
|
onBlur: handleBlur
|
|
1081
1316
|
},
|
|
1082
|
-
/* @__PURE__ */
|
|
1317
|
+
/* @__PURE__ */ React17.createElement(
|
|
1083
1318
|
"select",
|
|
1084
1319
|
{
|
|
1085
1320
|
name,
|
|
@@ -1093,10 +1328,10 @@ function MultiSelect({
|
|
|
1093
1328
|
style: { display: "none" },
|
|
1094
1329
|
multiple: true
|
|
1095
1330
|
},
|
|
1096
|
-
/* @__PURE__ */
|
|
1097
|
-
allOptions.map((option) => /* @__PURE__ */
|
|
1331
|
+
/* @__PURE__ */ React17.createElement("option", { value: "" }, "Select..."),
|
|
1332
|
+
allOptions.map((option) => /* @__PURE__ */ React17.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
|
|
1098
1333
|
),
|
|
1099
|
-
/* @__PURE__ */
|
|
1334
|
+
/* @__PURE__ */ React17.createElement(
|
|
1100
1335
|
"div",
|
|
1101
1336
|
{
|
|
1102
1337
|
ref: triggerRef,
|
|
@@ -1117,13 +1352,13 @@ function MultiSelect({
|
|
|
1117
1352
|
"aria-disabled": disabled,
|
|
1118
1353
|
tabIndex: disabled ? -1 : 0
|
|
1119
1354
|
},
|
|
1120
|
-
/* @__PURE__ */
|
|
1355
|
+
/* @__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
1356
|
"span",
|
|
1122
1357
|
{
|
|
1123
1358
|
key: option.value,
|
|
1124
1359
|
className: "inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium"
|
|
1125
1360
|
},
|
|
1126
|
-
renderValue ? renderValue(option) : /* @__PURE__ */
|
|
1361
|
+
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
1362
|
"button",
|
|
1128
1363
|
{
|
|
1129
1364
|
type: "button",
|
|
@@ -1134,8 +1369,8 @@ function MultiSelect({
|
|
|
1134
1369
|
},
|
|
1135
1370
|
"\u2715"
|
|
1136
1371
|
))
|
|
1137
|
-
))) : /* @__PURE__ */
|
|
1138
|
-
/* @__PURE__ */
|
|
1372
|
+
))) : /* @__PURE__ */ React17.createElement("span", { className: "relative" }, placeholder)),
|
|
1373
|
+
/* @__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
1374
|
"button",
|
|
1140
1375
|
{
|
|
1141
1376
|
type: "button",
|
|
@@ -1145,9 +1380,9 @@ function MultiSelect({
|
|
|
1145
1380
|
tabIndex: -1
|
|
1146
1381
|
},
|
|
1147
1382
|
"\u2715"
|
|
1148
|
-
), /* @__PURE__ */
|
|
1383
|
+
), /* @__PURE__ */ React17.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
|
|
1149
1384
|
),
|
|
1150
|
-
isOpen && /* @__PURE__ */
|
|
1385
|
+
isOpen && /* @__PURE__ */ React17.createElement(
|
|
1151
1386
|
"div",
|
|
1152
1387
|
{
|
|
1153
1388
|
ref: dropdownRef,
|
|
@@ -1156,7 +1391,7 @@ function MultiSelect({
|
|
|
1156
1391
|
role: "listbox",
|
|
1157
1392
|
"aria-multiselectable": "true"
|
|
1158
1393
|
},
|
|
1159
|
-
searchable && /* @__PURE__ */
|
|
1394
|
+
searchable && /* @__PURE__ */ React17.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React17.createElement(
|
|
1160
1395
|
"input",
|
|
1161
1396
|
{
|
|
1162
1397
|
ref: searchInputRef,
|
|
@@ -1172,7 +1407,7 @@ function MultiSelect({
|
|
|
1172
1407
|
"aria-label": "Search options"
|
|
1173
1408
|
}
|
|
1174
1409
|
)),
|
|
1175
|
-
showSelectAll && filteredOptions.length > 0 && /* @__PURE__ */
|
|
1410
|
+
showSelectAll && filteredOptions.length > 0 && /* @__PURE__ */ React17.createElement("div", { className: "flex gap-2 p-2 border-b border-border" }, /* @__PURE__ */ React17.createElement(
|
|
1176
1411
|
"button",
|
|
1177
1412
|
{
|
|
1178
1413
|
type: "button",
|
|
@@ -1181,7 +1416,7 @@ function MultiSelect({
|
|
|
1181
1416
|
disabled
|
|
1182
1417
|
},
|
|
1183
1418
|
"Select All"
|
|
1184
|
-
), value.length > 0 && /* @__PURE__ */
|
|
1419
|
+
), value.length > 0 && /* @__PURE__ */ React17.createElement(
|
|
1185
1420
|
"button",
|
|
1186
1421
|
{
|
|
1187
1422
|
type: "button",
|
|
@@ -1191,20 +1426,20 @@ function MultiSelect({
|
|
|
1191
1426
|
},
|
|
1192
1427
|
"Clear All"
|
|
1193
1428
|
)),
|
|
1194
|
-
isMaxReached && /* @__PURE__ */
|
|
1195
|
-
/* @__PURE__ */
|
|
1429
|
+
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"),
|
|
1430
|
+
/* @__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
1431
|
// Render grouped options
|
|
1197
1432
|
optionGroups.map((group, groupIndex) => {
|
|
1198
1433
|
const groupOptions = group.options.filter(
|
|
1199
1434
|
(opt) => filteredOptions.includes(opt)
|
|
1200
1435
|
);
|
|
1201
1436
|
if (groupOptions.length === 0) return null;
|
|
1202
|
-
return /* @__PURE__ */
|
|
1437
|
+
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
1438
|
const globalIndex = filteredOptions.indexOf(option);
|
|
1204
1439
|
const isSelected = value.includes(option.value);
|
|
1205
1440
|
const isFocused = globalIndex === focusedIndex;
|
|
1206
1441
|
const isDisabled = option.disabled || isMaxReached && !isSelected;
|
|
1207
|
-
return /* @__PURE__ */
|
|
1442
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1208
1443
|
"div",
|
|
1209
1444
|
{
|
|
1210
1445
|
key: option.value,
|
|
@@ -1219,8 +1454,8 @@ function MultiSelect({
|
|
|
1219
1454
|
"aria-selected": isSelected,
|
|
1220
1455
|
"aria-disabled": isDisabled
|
|
1221
1456
|
},
|
|
1222
|
-
/* @__PURE__ */
|
|
1223
|
-
/* @__PURE__ */
|
|
1457
|
+
/* @__PURE__ */ React17.createElement("span", { className: "text-base leading-none" }, isSelected ? "\u2611" : "\u2610"),
|
|
1458
|
+
/* @__PURE__ */ React17.createElement("span", { className: "flex-1" }, renderOption ? renderOption(option) : option.label)
|
|
1224
1459
|
);
|
|
1225
1460
|
}));
|
|
1226
1461
|
})
|
|
@@ -1230,7 +1465,7 @@ function MultiSelect({
|
|
|
1230
1465
|
const isSelected = value.includes(option.value);
|
|
1231
1466
|
const isFocused = index === focusedIndex;
|
|
1232
1467
|
const isDisabled = option.disabled || isMaxReached && !isSelected;
|
|
1233
|
-
return /* @__PURE__ */
|
|
1468
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1234
1469
|
"div",
|
|
1235
1470
|
{
|
|
1236
1471
|
key: option.value,
|
|
@@ -1245,8 +1480,8 @@ function MultiSelect({
|
|
|
1245
1480
|
"aria-selected": isSelected,
|
|
1246
1481
|
"aria-disabled": isDisabled
|
|
1247
1482
|
},
|
|
1248
|
-
/* @__PURE__ */
|
|
1249
|
-
/* @__PURE__ */
|
|
1483
|
+
/* @__PURE__ */ React17.createElement("span", { className: "text-base leading-none" }, isSelected ? "\u2611" : "\u2610"),
|
|
1484
|
+
/* @__PURE__ */ React17.createElement("span", { className: "flex-1" }, renderOption ? renderOption(option) : option.label)
|
|
1250
1485
|
);
|
|
1251
1486
|
})
|
|
1252
1487
|
))
|
|
@@ -1279,14 +1514,14 @@ function FileInput({
|
|
|
1279
1514
|
onFileRemove,
|
|
1280
1515
|
...props
|
|
1281
1516
|
}) {
|
|
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 =
|
|
1517
|
+
const inputRef = React17.useRef(null);
|
|
1518
|
+
const [dragActive, setDragActive] = React17.useState(false);
|
|
1519
|
+
const [cropperOpen, setCropperOpen] = React17.useState(false);
|
|
1520
|
+
const [imageToCrop, setImageToCrop] = React17.useState(null);
|
|
1521
|
+
const [crop, setCrop] = React17.useState({ x: 0, y: 0 });
|
|
1522
|
+
const [zoom, setZoom] = React17.useState(1);
|
|
1523
|
+
const [croppedAreaPixels, setCroppedAreaPixels] = React17.useState(null);
|
|
1524
|
+
const validateFile = React17.useCallback(
|
|
1290
1525
|
(file) => {
|
|
1291
1526
|
if (accept) {
|
|
1292
1527
|
const acceptedTypes = accept.split(",").map((t) => t.trim());
|
|
@@ -1321,7 +1556,7 @@ function FileInput({
|
|
|
1321
1556
|
},
|
|
1322
1557
|
[accept, maxSize]
|
|
1323
1558
|
);
|
|
1324
|
-
const handleFiles =
|
|
1559
|
+
const handleFiles = React17.useCallback(
|
|
1325
1560
|
(fileList) => {
|
|
1326
1561
|
if (!fileList || fileList.length === 0) return;
|
|
1327
1562
|
const newFiles = Array.from(fileList);
|
|
@@ -1372,7 +1607,7 @@ function FileInput({
|
|
|
1372
1607
|
onValidationError
|
|
1373
1608
|
]
|
|
1374
1609
|
);
|
|
1375
|
-
const createCroppedImage =
|
|
1610
|
+
const createCroppedImage = React17.useCallback(
|
|
1376
1611
|
async (imageUrl, cropArea) => {
|
|
1377
1612
|
return new Promise((resolve, reject) => {
|
|
1378
1613
|
const image = new Image();
|
|
@@ -1416,7 +1651,7 @@ function FileInput({
|
|
|
1416
1651
|
},
|
|
1417
1652
|
[]
|
|
1418
1653
|
);
|
|
1419
|
-
const handleCropSave =
|
|
1654
|
+
const handleCropSave = React17.useCallback(async () => {
|
|
1420
1655
|
if (!imageToCrop || !croppedAreaPixels) return;
|
|
1421
1656
|
try {
|
|
1422
1657
|
const croppedBlob = await createCroppedImage(
|
|
@@ -1449,7 +1684,7 @@ function FileInput({
|
|
|
1449
1684
|
onChange,
|
|
1450
1685
|
multiple
|
|
1451
1686
|
]);
|
|
1452
|
-
const handleCropCancel =
|
|
1687
|
+
const handleCropCancel = React17.useCallback(() => {
|
|
1453
1688
|
if (imageToCrop) {
|
|
1454
1689
|
URL.revokeObjectURL(imageToCrop.url);
|
|
1455
1690
|
}
|
|
@@ -1459,13 +1694,13 @@ function FileInput({
|
|
|
1459
1694
|
setZoom(1);
|
|
1460
1695
|
setCroppedAreaPixels(null);
|
|
1461
1696
|
}, [imageToCrop]);
|
|
1462
|
-
const onCropChange =
|
|
1697
|
+
const onCropChange = React17.useCallback((crop2) => {
|
|
1463
1698
|
setCrop(crop2);
|
|
1464
1699
|
}, []);
|
|
1465
|
-
const onZoomChange =
|
|
1700
|
+
const onZoomChange = React17.useCallback((zoom2) => {
|
|
1466
1701
|
setZoom(zoom2);
|
|
1467
1702
|
}, []);
|
|
1468
|
-
const onCropCompleteInternal =
|
|
1703
|
+
const onCropCompleteInternal = React17.useCallback(
|
|
1469
1704
|
(_, croppedAreaPixels2) => {
|
|
1470
1705
|
setCroppedAreaPixels(croppedAreaPixels2);
|
|
1471
1706
|
},
|
|
@@ -1526,7 +1761,7 @@ function FileInput({
|
|
|
1526
1761
|
}
|
|
1527
1762
|
return null;
|
|
1528
1763
|
};
|
|
1529
|
-
|
|
1764
|
+
React17.useEffect(() => {
|
|
1530
1765
|
return () => {
|
|
1531
1766
|
value.forEach((file) => {
|
|
1532
1767
|
const previewUrl = getPreviewUrl(file);
|
|
@@ -1540,7 +1775,7 @@ function FileInput({
|
|
|
1540
1775
|
};
|
|
1541
1776
|
}, [value, imageToCrop]);
|
|
1542
1777
|
const combinedClassName = `${className}`.trim();
|
|
1543
|
-
return /* @__PURE__ */
|
|
1778
|
+
return /* @__PURE__ */ React17.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React17.createElement(
|
|
1544
1779
|
"input",
|
|
1545
1780
|
{
|
|
1546
1781
|
ref: inputRef,
|
|
@@ -1557,7 +1792,7 @@ function FileInput({
|
|
|
1557
1792
|
"aria-required": required || props["aria-required"],
|
|
1558
1793
|
style: { display: "none" }
|
|
1559
1794
|
}
|
|
1560
|
-
), /* @__PURE__ */
|
|
1795
|
+
), /* @__PURE__ */ React17.createElement(
|
|
1561
1796
|
"div",
|
|
1562
1797
|
{
|
|
1563
1798
|
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 +1807,7 @@ function FileInput({
|
|
|
1572
1807
|
"aria-label": placeholder,
|
|
1573
1808
|
"aria-disabled": disabled
|
|
1574
1809
|
},
|
|
1575
|
-
/* @__PURE__ */
|
|
1810
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex flex-col items-center gap-2 text-center" }, /* @__PURE__ */ React17.createElement(
|
|
1576
1811
|
"svg",
|
|
1577
1812
|
{
|
|
1578
1813
|
width: "48",
|
|
@@ -1585,19 +1820,19 @@ function FileInput({
|
|
|
1585
1820
|
strokeLinejoin: "round",
|
|
1586
1821
|
"aria-hidden": "true"
|
|
1587
1822
|
},
|
|
1588
|
-
/* @__PURE__ */
|
|
1589
|
-
/* @__PURE__ */
|
|
1590
|
-
/* @__PURE__ */
|
|
1591
|
-
), /* @__PURE__ */
|
|
1592
|
-
), value.length > 0 && /* @__PURE__ */
|
|
1823
|
+
/* @__PURE__ */ React17.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
1824
|
+
/* @__PURE__ */ React17.createElement("polyline", { points: "17 8 12 3 7 8" }),
|
|
1825
|
+
/* @__PURE__ */ React17.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
|
|
1826
|
+
), /* @__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)))
|
|
1827
|
+
), value.length > 0 && /* @__PURE__ */ React17.createElement("ul", { className: "flex flex-col gap-2 mt-4", role: "list" }, value.map((file, index) => {
|
|
1593
1828
|
const previewUrl = showPreview ? getPreviewUrl(file) : null;
|
|
1594
|
-
return /* @__PURE__ */
|
|
1829
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1595
1830
|
"li",
|
|
1596
1831
|
{
|
|
1597
1832
|
key: `${file.name}-${index}`,
|
|
1598
1833
|
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
1834
|
},
|
|
1600
|
-
previewUrl && /* @__PURE__ */
|
|
1835
|
+
previewUrl && /* @__PURE__ */ React17.createElement(
|
|
1601
1836
|
"img",
|
|
1602
1837
|
{
|
|
1603
1838
|
src: previewUrl,
|
|
@@ -1607,7 +1842,7 @@ function FileInput({
|
|
|
1607
1842
|
height: "48"
|
|
1608
1843
|
}
|
|
1609
1844
|
),
|
|
1610
|
-
/* @__PURE__ */
|
|
1845
|
+
/* @__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
1846
|
"div",
|
|
1612
1847
|
{
|
|
1613
1848
|
className: "h-1.5 bg-muted rounded-full overflow-hidden flex-1",
|
|
@@ -1617,15 +1852,15 @@ function FileInput({
|
|
|
1617
1852
|
"aria-valuemax": 100,
|
|
1618
1853
|
"aria-label": `Upload progress: ${uploadProgress[file.name]}%`
|
|
1619
1854
|
},
|
|
1620
|
-
/* @__PURE__ */
|
|
1855
|
+
/* @__PURE__ */ React17.createElement(
|
|
1621
1856
|
"div",
|
|
1622
1857
|
{
|
|
1623
1858
|
className: "h-full bg-primary transition-all",
|
|
1624
1859
|
style: { width: `${uploadProgress[file.name]}%` }
|
|
1625
1860
|
}
|
|
1626
1861
|
)
|
|
1627
|
-
), /* @__PURE__ */
|
|
1628
|
-
enableCropping && file.type.startsWith("image/") && /* @__PURE__ */
|
|
1862
|
+
), /* @__PURE__ */ React17.createElement("span", { className: "text-xs " }, uploadProgress[file.name], "%"))),
|
|
1863
|
+
enableCropping && file.type.startsWith("image/") && /* @__PURE__ */ React17.createElement(
|
|
1629
1864
|
"button",
|
|
1630
1865
|
{
|
|
1631
1866
|
type: "button",
|
|
@@ -1637,7 +1872,7 @@ function FileInput({
|
|
|
1637
1872
|
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
1873
|
"aria-label": `Crop ${file.name}`
|
|
1639
1874
|
},
|
|
1640
|
-
/* @__PURE__ */
|
|
1875
|
+
/* @__PURE__ */ React17.createElement(
|
|
1641
1876
|
"svg",
|
|
1642
1877
|
{
|
|
1643
1878
|
width: "20",
|
|
@@ -1650,11 +1885,11 @@ function FileInput({
|
|
|
1650
1885
|
strokeLinejoin: "round",
|
|
1651
1886
|
"aria-hidden": "true"
|
|
1652
1887
|
},
|
|
1653
|
-
/* @__PURE__ */
|
|
1654
|
-
/* @__PURE__ */
|
|
1888
|
+
/* @__PURE__ */ React17.createElement("path", { d: "M6.13 1L6 16a2 2 0 0 0 2 2h15" }),
|
|
1889
|
+
/* @__PURE__ */ React17.createElement("path", { d: "M1 6.13L16 6a2 2 0 0 1 2 2v15" })
|
|
1655
1890
|
)
|
|
1656
1891
|
),
|
|
1657
|
-
/* @__PURE__ */
|
|
1892
|
+
/* @__PURE__ */ React17.createElement(
|
|
1658
1893
|
"button",
|
|
1659
1894
|
{
|
|
1660
1895
|
type: "button",
|
|
@@ -1666,7 +1901,7 @@ function FileInput({
|
|
|
1666
1901
|
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
1902
|
"aria-label": `Remove ${file.name}`
|
|
1668
1903
|
},
|
|
1669
|
-
/* @__PURE__ */
|
|
1904
|
+
/* @__PURE__ */ React17.createElement(
|
|
1670
1905
|
"svg",
|
|
1671
1906
|
{
|
|
1672
1907
|
width: "20",
|
|
@@ -1679,19 +1914,19 @@ function FileInput({
|
|
|
1679
1914
|
strokeLinejoin: "round",
|
|
1680
1915
|
"aria-hidden": "true"
|
|
1681
1916
|
},
|
|
1682
|
-
/* @__PURE__ */
|
|
1683
|
-
/* @__PURE__ */
|
|
1917
|
+
/* @__PURE__ */ React17.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1918
|
+
/* @__PURE__ */ React17.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1684
1919
|
)
|
|
1685
1920
|
)
|
|
1686
1921
|
);
|
|
1687
|
-
})), cropperOpen && imageToCrop && /* @__PURE__ */
|
|
1922
|
+
})), cropperOpen && imageToCrop && /* @__PURE__ */ React17.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center" }, /* @__PURE__ */ React17.createElement(
|
|
1688
1923
|
"div",
|
|
1689
1924
|
{
|
|
1690
1925
|
className: "absolute inset-0 bg-black/50",
|
|
1691
1926
|
onClick: handleCropCancel,
|
|
1692
1927
|
"aria-label": "Close cropper"
|
|
1693
1928
|
}
|
|
1694
|
-
), /* @__PURE__ */
|
|
1929
|
+
), /* @__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
1930
|
"button",
|
|
1696
1931
|
{
|
|
1697
1932
|
type: "button",
|
|
@@ -1700,7 +1935,7 @@ function FileInput({
|
|
|
1700
1935
|
"aria-label": "Close"
|
|
1701
1936
|
},
|
|
1702
1937
|
"\u2715"
|
|
1703
|
-
)), /* @__PURE__ */
|
|
1938
|
+
)), /* @__PURE__ */ React17.createElement("div", { className: "p-4" }, /* @__PURE__ */ React17.createElement(
|
|
1704
1939
|
"div",
|
|
1705
1940
|
{
|
|
1706
1941
|
className: "relative w-full h-96 bg-muted rounded-md overflow-hidden",
|
|
@@ -1722,7 +1957,7 @@ function FileInput({
|
|
|
1722
1957
|
document.addEventListener("mouseup", handleMouseUp);
|
|
1723
1958
|
}
|
|
1724
1959
|
},
|
|
1725
|
-
/* @__PURE__ */
|
|
1960
|
+
/* @__PURE__ */ React17.createElement(
|
|
1726
1961
|
"img",
|
|
1727
1962
|
{
|
|
1728
1963
|
src: imageToCrop.url,
|
|
@@ -1757,7 +1992,7 @@ function FileInput({
|
|
|
1757
1992
|
}
|
|
1758
1993
|
}
|
|
1759
1994
|
),
|
|
1760
|
-
/* @__PURE__ */
|
|
1995
|
+
/* @__PURE__ */ React17.createElement(
|
|
1761
1996
|
"div",
|
|
1762
1997
|
{
|
|
1763
1998
|
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 +2001,9 @@ function FileInput({
|
|
|
1766
2001
|
aspectRatio: cropAspectRatio ? String(cropAspectRatio) : void 0
|
|
1767
2002
|
}
|
|
1768
2003
|
},
|
|
1769
|
-
/* @__PURE__ */
|
|
2004
|
+
/* @__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
2005
|
)
|
|
1771
|
-
), /* @__PURE__ */
|
|
2006
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-3 mt-4" }, /* @__PURE__ */ React17.createElement(
|
|
1772
2007
|
"label",
|
|
1773
2008
|
{
|
|
1774
2009
|
htmlFor: "zoom-slider",
|
|
@@ -1777,7 +2012,7 @@ function FileInput({
|
|
|
1777
2012
|
"Zoom: ",
|
|
1778
2013
|
zoom.toFixed(1),
|
|
1779
2014
|
"x"
|
|
1780
|
-
), /* @__PURE__ */
|
|
2015
|
+
), /* @__PURE__ */ React17.createElement(
|
|
1781
2016
|
"input",
|
|
1782
2017
|
{
|
|
1783
2018
|
id: "zoom-slider",
|
|
@@ -1790,7 +2025,7 @@ function FileInput({
|
|
|
1790
2025
|
className: "flex-1 h-2 bg-muted rounded-lg appearance-none cursor-pointer",
|
|
1791
2026
|
"aria-label": "Zoom level"
|
|
1792
2027
|
}
|
|
1793
|
-
))), /* @__PURE__ */
|
|
2028
|
+
))), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-end gap-2 p-4 border-t border-border" }, /* @__PURE__ */ React17.createElement(
|
|
1794
2029
|
"button",
|
|
1795
2030
|
{
|
|
1796
2031
|
type: "button",
|
|
@@ -1798,7 +2033,7 @@ function FileInput({
|
|
|
1798
2033
|
onClick: handleCropCancel
|
|
1799
2034
|
},
|
|
1800
2035
|
"Cancel"
|
|
1801
|
-
), /* @__PURE__ */
|
|
2036
|
+
), /* @__PURE__ */ React17.createElement(
|
|
1802
2037
|
"button",
|
|
1803
2038
|
{
|
|
1804
2039
|
type: "button",
|
|
@@ -1840,14 +2075,14 @@ function DatePicker({
|
|
|
1840
2075
|
showIcon = true,
|
|
1841
2076
|
...props
|
|
1842
2077
|
}) {
|
|
1843
|
-
const [isOpen, setIsOpen] =
|
|
1844
|
-
const [hasInteracted, setHasInteracted] =
|
|
1845
|
-
const [selectedMonth, setSelectedMonth] =
|
|
2078
|
+
const [isOpen, setIsOpen] = React17.useState(false);
|
|
2079
|
+
const [hasInteracted, setHasInteracted] = React17.useState(false);
|
|
2080
|
+
const [selectedMonth, setSelectedMonth] = React17.useState(
|
|
1846
2081
|
value || /* @__PURE__ */ new Date()
|
|
1847
2082
|
);
|
|
1848
|
-
const inputRef =
|
|
1849
|
-
const dropdownRef =
|
|
1850
|
-
|
|
2083
|
+
const inputRef = React17.useRef(null);
|
|
2084
|
+
const dropdownRef = React17.useRef(null);
|
|
2085
|
+
React17.useEffect(() => {
|
|
1851
2086
|
if (value) {
|
|
1852
2087
|
setSelectedMonth(value);
|
|
1853
2088
|
}
|
|
@@ -1879,7 +2114,7 @@ function DatePicker({
|
|
|
1879
2114
|
if (isDateDisabled && isDateDisabled(date)) return true;
|
|
1880
2115
|
return false;
|
|
1881
2116
|
};
|
|
1882
|
-
const closeCalendar =
|
|
2117
|
+
const closeCalendar = React17.useCallback(() => {
|
|
1883
2118
|
if (!isOpen) return;
|
|
1884
2119
|
setIsOpen(false);
|
|
1885
2120
|
if (hasInteracted) {
|
|
@@ -1933,7 +2168,7 @@ function DatePicker({
|
|
|
1933
2168
|
const handleNextMonth = () => {
|
|
1934
2169
|
setSelectedMonth(new Date(year, month + 1, 1));
|
|
1935
2170
|
};
|
|
1936
|
-
return /* @__PURE__ */
|
|
2171
|
+
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
2172
|
"button",
|
|
1938
2173
|
{
|
|
1939
2174
|
type: "button",
|
|
@@ -1942,7 +2177,7 @@ function DatePicker({
|
|
|
1942
2177
|
"aria-label": "Previous month"
|
|
1943
2178
|
},
|
|
1944
2179
|
"\u2039"
|
|
1945
|
-
), /* @__PURE__ */
|
|
2180
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React17.createElement(
|
|
1946
2181
|
"button",
|
|
1947
2182
|
{
|
|
1948
2183
|
type: "button",
|
|
@@ -1951,13 +2186,13 @@ function DatePicker({
|
|
|
1951
2186
|
"aria-label": "Next month"
|
|
1952
2187
|
},
|
|
1953
2188
|
"\u203A"
|
|
1954
|
-
)), /* @__PURE__ */
|
|
2189
|
+
)), /* @__PURE__ */ React17.createElement(
|
|
1955
2190
|
"div",
|
|
1956
2191
|
{
|
|
1957
2192
|
className: "grid gap-1 text-xs text-muted-foreground",
|
|
1958
2193
|
style: dayGridStyle
|
|
1959
2194
|
},
|
|
1960
|
-
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */
|
|
2195
|
+
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React17.createElement(
|
|
1961
2196
|
"div",
|
|
1962
2197
|
{
|
|
1963
2198
|
key: day,
|
|
@@ -1965,14 +2200,14 @@ function DatePicker({
|
|
|
1965
2200
|
},
|
|
1966
2201
|
day
|
|
1967
2202
|
))
|
|
1968
|
-
), /* @__PURE__ */
|
|
2203
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
|
|
1969
2204
|
if (!date) {
|
|
1970
|
-
return /* @__PURE__ */
|
|
2205
|
+
return /* @__PURE__ */ React17.createElement("div", { key: `empty-${index}`, className: "h-8 w-8" });
|
|
1971
2206
|
}
|
|
1972
2207
|
const isSelected = value && date.toDateString() === value.toDateString();
|
|
1973
2208
|
const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
|
|
1974
2209
|
const disabled2 = isDisabled(date);
|
|
1975
|
-
return /* @__PURE__ */
|
|
2210
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1976
2211
|
"button",
|
|
1977
2212
|
{
|
|
1978
2213
|
key: date.toISOString(),
|
|
@@ -1993,20 +2228,20 @@ function DatePicker({
|
|
|
1993
2228
|
})));
|
|
1994
2229
|
};
|
|
1995
2230
|
const combinedClassName = cn("relative", className);
|
|
1996
|
-
return /* @__PURE__ */
|
|
2231
|
+
return /* @__PURE__ */ React17.createElement("div", { className: combinedClassName, onBlur: handleBlur }, /* @__PURE__ */ React17.createElement(
|
|
1997
2232
|
"input",
|
|
1998
2233
|
{
|
|
1999
2234
|
type: "hidden",
|
|
2000
2235
|
name,
|
|
2001
2236
|
value: value ? value.toISOString() : ""
|
|
2002
2237
|
}
|
|
2003
|
-
), /* @__PURE__ */
|
|
2238
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React17.createElement(
|
|
2004
2239
|
"span",
|
|
2005
2240
|
{
|
|
2006
2241
|
className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
|
|
2007
2242
|
"aria-hidden": "true"
|
|
2008
2243
|
},
|
|
2009
|
-
/* @__PURE__ */
|
|
2244
|
+
/* @__PURE__ */ React17.createElement(
|
|
2010
2245
|
"svg",
|
|
2011
2246
|
{
|
|
2012
2247
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2019,9 +2254,9 @@ function DatePicker({
|
|
|
2019
2254
|
strokeLinejoin: "round",
|
|
2020
2255
|
strokeWidth: "2"
|
|
2021
2256
|
},
|
|
2022
|
-
/* @__PURE__ */
|
|
2257
|
+
/* @__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
2258
|
)
|
|
2024
|
-
), /* @__PURE__ */
|
|
2259
|
+
), /* @__PURE__ */ React17.createElement(
|
|
2025
2260
|
"input",
|
|
2026
2261
|
{
|
|
2027
2262
|
ref: inputRef,
|
|
@@ -2046,7 +2281,7 @@ function DatePicker({
|
|
|
2046
2281
|
"aria-required": required || props["aria-required"],
|
|
2047
2282
|
readOnly: true
|
|
2048
2283
|
}
|
|
2049
|
-
), clearable && value && !disabled && /* @__PURE__ */
|
|
2284
|
+
), clearable && value && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2050
2285
|
"button",
|
|
2051
2286
|
{
|
|
2052
2287
|
type: "button",
|
|
@@ -2056,7 +2291,7 @@ function DatePicker({
|
|
|
2056
2291
|
tabIndex: -1
|
|
2057
2292
|
},
|
|
2058
2293
|
"\u2715"
|
|
2059
|
-
)), isOpen && !disabled && /* @__PURE__ */
|
|
2294
|
+
)), isOpen && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2060
2295
|
"div",
|
|
2061
2296
|
{
|
|
2062
2297
|
ref: dropdownRef,
|
|
@@ -2123,11 +2358,11 @@ function TimePicker({
|
|
|
2123
2358
|
showIcon = true,
|
|
2124
2359
|
...props
|
|
2125
2360
|
}) {
|
|
2126
|
-
const inputRef =
|
|
2127
|
-
const [nativeValue, setNativeValue] =
|
|
2361
|
+
const inputRef = React17.useRef(null);
|
|
2362
|
+
const [nativeValue, setNativeValue] = React17.useState(
|
|
2128
2363
|
normalizeToNativeTime(value)
|
|
2129
2364
|
);
|
|
2130
|
-
|
|
2365
|
+
React17.useEffect(() => {
|
|
2131
2366
|
setNativeValue(normalizeToNativeTime(value));
|
|
2132
2367
|
}, [value]);
|
|
2133
2368
|
const handleChange = (e) => {
|
|
@@ -2143,13 +2378,13 @@ function TimePicker({
|
|
|
2143
2378
|
};
|
|
2144
2379
|
const hasValue = Boolean(value);
|
|
2145
2380
|
const stepInSeconds = Math.max(1, minuteStep * 60);
|
|
2146
|
-
return /* @__PURE__ */
|
|
2381
|
+
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
2382
|
"span",
|
|
2148
2383
|
{
|
|
2149
2384
|
className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
|
|
2150
2385
|
"aria-hidden": "true"
|
|
2151
2386
|
},
|
|
2152
|
-
/* @__PURE__ */
|
|
2387
|
+
/* @__PURE__ */ React17.createElement(
|
|
2153
2388
|
"svg",
|
|
2154
2389
|
{
|
|
2155
2390
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2162,10 +2397,10 @@ function TimePicker({
|
|
|
2162
2397
|
strokeLinejoin: "round",
|
|
2163
2398
|
strokeWidth: "2"
|
|
2164
2399
|
},
|
|
2165
|
-
/* @__PURE__ */
|
|
2166
|
-
/* @__PURE__ */
|
|
2400
|
+
/* @__PURE__ */ React17.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
2401
|
+
/* @__PURE__ */ React17.createElement("path", { d: "M12 6v6l4 2" })
|
|
2167
2402
|
)
|
|
2168
|
-
), /* @__PURE__ */
|
|
2403
|
+
), /* @__PURE__ */ React17.createElement(
|
|
2169
2404
|
"input",
|
|
2170
2405
|
{
|
|
2171
2406
|
ref: inputRef,
|
|
@@ -2193,7 +2428,7 @@ function TimePicker({
|
|
|
2193
2428
|
"aria-required": required || props["aria-required"],
|
|
2194
2429
|
...props
|
|
2195
2430
|
}
|
|
2196
|
-
), clearable && value && !disabled && /* @__PURE__ */
|
|
2431
|
+
), clearable && value && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2197
2432
|
"button",
|
|
2198
2433
|
{
|
|
2199
2434
|
type: "button",
|
|
@@ -2246,17 +2481,17 @@ function DateRangePicker({
|
|
|
2246
2481
|
separator = " - ",
|
|
2247
2482
|
...props
|
|
2248
2483
|
}) {
|
|
2249
|
-
const [isOpen, setIsOpen] =
|
|
2250
|
-
const [hasInteracted, setHasInteracted] =
|
|
2251
|
-
const [selectedMonth, setSelectedMonth] =
|
|
2484
|
+
const [isOpen, setIsOpen] = React17.useState(false);
|
|
2485
|
+
const [hasInteracted, setHasInteracted] = React17.useState(false);
|
|
2486
|
+
const [selectedMonth, setSelectedMonth] = React17.useState(
|
|
2252
2487
|
value.start || /* @__PURE__ */ new Date()
|
|
2253
2488
|
);
|
|
2254
|
-
const [rangeStart, setRangeStart] =
|
|
2255
|
-
const [rangeEnd, setRangeEnd] =
|
|
2256
|
-
const [hoverDate, setHoverDate] =
|
|
2257
|
-
const triggerRef =
|
|
2258
|
-
const dropdownRef =
|
|
2259
|
-
|
|
2489
|
+
const [rangeStart, setRangeStart] = React17.useState(value.start);
|
|
2490
|
+
const [rangeEnd, setRangeEnd] = React17.useState(value.end);
|
|
2491
|
+
const [hoverDate, setHoverDate] = React17.useState(null);
|
|
2492
|
+
const triggerRef = React17.useRef(null);
|
|
2493
|
+
const dropdownRef = React17.useRef(null);
|
|
2494
|
+
React17.useEffect(() => {
|
|
2260
2495
|
setRangeStart(value.start);
|
|
2261
2496
|
setRangeEnd(value.end);
|
|
2262
2497
|
if (value.start) {
|
|
@@ -2305,7 +2540,7 @@ function DateRangePicker({
|
|
|
2305
2540
|
if (isDateDisabled && isDateDisabled(date)) return true;
|
|
2306
2541
|
return false;
|
|
2307
2542
|
};
|
|
2308
|
-
const closeCalendar =
|
|
2543
|
+
const closeCalendar = React17.useCallback(() => {
|
|
2309
2544
|
if (!isOpen) return;
|
|
2310
2545
|
setIsOpen(false);
|
|
2311
2546
|
if (hasInteracted) {
|
|
@@ -2355,7 +2590,7 @@ function DateRangePicker({
|
|
|
2355
2590
|
for (let day = 1; day <= daysInMonth; day++) {
|
|
2356
2591
|
days.push(new Date(year, month, day));
|
|
2357
2592
|
}
|
|
2358
|
-
return /* @__PURE__ */
|
|
2593
|
+
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
2594
|
"button",
|
|
2360
2595
|
{
|
|
2361
2596
|
type: "button",
|
|
@@ -2364,7 +2599,7 @@ function DateRangePicker({
|
|
|
2364
2599
|
"aria-label": "Previous month"
|
|
2365
2600
|
},
|
|
2366
2601
|
"\u2039"
|
|
2367
|
-
) : /* @__PURE__ */
|
|
2602
|
+
) : /* @__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
2603
|
"button",
|
|
2369
2604
|
{
|
|
2370
2605
|
type: "button",
|
|
@@ -2373,13 +2608,13 @@ function DateRangePicker({
|
|
|
2373
2608
|
"aria-label": "Next month"
|
|
2374
2609
|
},
|
|
2375
2610
|
"\u203A"
|
|
2376
|
-
) : /* @__PURE__ */
|
|
2611
|
+
) : /* @__PURE__ */ React17.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" })), /* @__PURE__ */ React17.createElement(
|
|
2377
2612
|
"div",
|
|
2378
2613
|
{
|
|
2379
2614
|
className: "grid gap-1 text-xs text-muted-foreground",
|
|
2380
2615
|
style: dayGridStyle
|
|
2381
2616
|
},
|
|
2382
|
-
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */
|
|
2617
|
+
["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React17.createElement(
|
|
2383
2618
|
"div",
|
|
2384
2619
|
{
|
|
2385
2620
|
key: `${month}-${day}`,
|
|
@@ -2387,9 +2622,9 @@ function DateRangePicker({
|
|
|
2387
2622
|
},
|
|
2388
2623
|
day
|
|
2389
2624
|
))
|
|
2390
|
-
), /* @__PURE__ */
|
|
2625
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
|
|
2391
2626
|
if (!date) {
|
|
2392
|
-
return /* @__PURE__ */
|
|
2627
|
+
return /* @__PURE__ */ React17.createElement("div", { key: `empty-${month}-${index}`, className: "h-8 w-8" });
|
|
2393
2628
|
}
|
|
2394
2629
|
const isStart = rangeStart && date.toDateString() === rangeStart.toDateString();
|
|
2395
2630
|
const isEnd = rangeEnd && date.toDateString() === rangeEnd.toDateString();
|
|
@@ -2401,7 +2636,7 @@ function DateRangePicker({
|
|
|
2401
2636
|
);
|
|
2402
2637
|
const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
|
|
2403
2638
|
const disabled2 = isDisabled(date);
|
|
2404
|
-
return /* @__PURE__ */
|
|
2639
|
+
return /* @__PURE__ */ React17.createElement(
|
|
2405
2640
|
"button",
|
|
2406
2641
|
{
|
|
2407
2642
|
key: date.toISOString(),
|
|
@@ -2426,27 +2661,27 @@ function DateRangePicker({
|
|
|
2426
2661
|
};
|
|
2427
2662
|
const combinedClassName = cn("relative", className);
|
|
2428
2663
|
const displayValue = rangeStart && rangeEnd ? `${formatDate2(rangeStart, format)}${separator}${formatDate2(rangeEnd, format)}` : rangeStart ? formatDate2(rangeStart, format) : "";
|
|
2429
|
-
return /* @__PURE__ */
|
|
2664
|
+
return /* @__PURE__ */ React17.createElement("div", { className: combinedClassName, onBlur: handleBlur }, /* @__PURE__ */ React17.createElement(
|
|
2430
2665
|
"input",
|
|
2431
2666
|
{
|
|
2432
2667
|
type: "hidden",
|
|
2433
2668
|
name: `${name}[start]`,
|
|
2434
2669
|
value: rangeStart ? rangeStart.toISOString() : ""
|
|
2435
2670
|
}
|
|
2436
|
-
), /* @__PURE__ */
|
|
2671
|
+
), /* @__PURE__ */ React17.createElement(
|
|
2437
2672
|
"input",
|
|
2438
2673
|
{
|
|
2439
2674
|
type: "hidden",
|
|
2440
2675
|
name: `${name}[end]`,
|
|
2441
2676
|
value: rangeEnd ? rangeEnd.toISOString() : ""
|
|
2442
2677
|
}
|
|
2443
|
-
), /* @__PURE__ */
|
|
2678
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React17.createElement(
|
|
2444
2679
|
"span",
|
|
2445
2680
|
{
|
|
2446
2681
|
className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
|
|
2447
2682
|
"aria-hidden": "true"
|
|
2448
2683
|
},
|
|
2449
|
-
/* @__PURE__ */
|
|
2684
|
+
/* @__PURE__ */ React17.createElement(
|
|
2450
2685
|
"svg",
|
|
2451
2686
|
{
|
|
2452
2687
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -2459,9 +2694,9 @@ function DateRangePicker({
|
|
|
2459
2694
|
strokeLinejoin: "round",
|
|
2460
2695
|
strokeWidth: "2"
|
|
2461
2696
|
},
|
|
2462
|
-
/* @__PURE__ */
|
|
2697
|
+
/* @__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
2698
|
)
|
|
2464
|
-
), /* @__PURE__ */
|
|
2699
|
+
), /* @__PURE__ */ React17.createElement(
|
|
2465
2700
|
"input",
|
|
2466
2701
|
{
|
|
2467
2702
|
ref: triggerRef,
|
|
@@ -2486,7 +2721,7 @@ function DateRangePicker({
|
|
|
2486
2721
|
"aria-required": required || props["aria-required"],
|
|
2487
2722
|
readOnly: true
|
|
2488
2723
|
}
|
|
2489
|
-
), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */
|
|
2724
|
+
), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2490
2725
|
"button",
|
|
2491
2726
|
{
|
|
2492
2727
|
type: "button",
|
|
@@ -2496,14 +2731,14 @@ function DateRangePicker({
|
|
|
2496
2731
|
tabIndex: -1
|
|
2497
2732
|
},
|
|
2498
2733
|
"\u2715"
|
|
2499
|
-
)), isOpen && !disabled && /* @__PURE__ */
|
|
2734
|
+
)), isOpen && !disabled && /* @__PURE__ */ React17.createElement(
|
|
2500
2735
|
"div",
|
|
2501
2736
|
{
|
|
2502
2737
|
ref: dropdownRef,
|
|
2503
2738
|
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
2739
|
},
|
|
2505
|
-
/* @__PURE__ */
|
|
2506
|
-
rangeStart && !rangeEnd && /* @__PURE__ */
|
|
2740
|
+
/* @__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 }))),
|
|
2741
|
+
rangeStart && !rangeEnd && /* @__PURE__ */ React17.createElement("div", { className: "text-xs text-center pt-2 border-t border-border mt-2" }, "Select end date")
|
|
2507
2742
|
));
|
|
2508
2743
|
}
|
|
2509
2744
|
DateRangePicker.displayName = "DateRangePicker";
|
|
@@ -2575,11 +2810,11 @@ function RichTextEditor({
|
|
|
2575
2810
|
],
|
|
2576
2811
|
...props
|
|
2577
2812
|
}) {
|
|
2578
|
-
const [currentMode, setCurrentMode] =
|
|
2579
|
-
const [content, setContent] =
|
|
2580
|
-
const editorRef =
|
|
2581
|
-
const textareaRef =
|
|
2582
|
-
|
|
2813
|
+
const [currentMode, setCurrentMode] = React17.useState(mode);
|
|
2814
|
+
const [content, setContent] = React17.useState(value);
|
|
2815
|
+
const editorRef = React17.useRef(null);
|
|
2816
|
+
const textareaRef = React17.useRef(null);
|
|
2817
|
+
React17.useEffect(() => {
|
|
2583
2818
|
setContent(value);
|
|
2584
2819
|
if (currentMode === "wysiwyg" && editorRef.current) {
|
|
2585
2820
|
editorRef.current.innerHTML = value;
|
|
@@ -2667,7 +2902,7 @@ function RichTextEditor({
|
|
|
2667
2902
|
}
|
|
2668
2903
|
}
|
|
2669
2904
|
};
|
|
2670
|
-
const hasValue =
|
|
2905
|
+
const hasValue = React17.useMemo(() => {
|
|
2671
2906
|
if (!content) return false;
|
|
2672
2907
|
const stripped = content.replace(/<[^>]+>/g, "").trim();
|
|
2673
2908
|
return stripped.length > 0;
|
|
@@ -2684,10 +2919,10 @@ function RichTextEditor({
|
|
|
2684
2919
|
maxHeight,
|
|
2685
2920
|
overflowY: maxHeight ? "auto" : void 0
|
|
2686
2921
|
};
|
|
2687
|
-
return /* @__PURE__ */
|
|
2922
|
+
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
2923
|
const button = toolbarConfig[buttonName];
|
|
2689
2924
|
if (!button) return null;
|
|
2690
|
-
return /* @__PURE__ */
|
|
2925
|
+
return /* @__PURE__ */ React17.createElement(
|
|
2691
2926
|
"button",
|
|
2692
2927
|
{
|
|
2693
2928
|
key: buttonName,
|
|
@@ -2700,7 +2935,7 @@ function RichTextEditor({
|
|
|
2700
2935
|
},
|
|
2701
2936
|
button.icon
|
|
2702
2937
|
);
|
|
2703
|
-
})), allowModeSwitch && /* @__PURE__ */
|
|
2938
|
+
})), allowModeSwitch && /* @__PURE__ */ React17.createElement(
|
|
2704
2939
|
"button",
|
|
2705
2940
|
{
|
|
2706
2941
|
type: "button",
|
|
@@ -2711,7 +2946,7 @@ function RichTextEditor({
|
|
|
2711
2946
|
"aria-label": `Switch to ${currentMode === "wysiwyg" ? "Markdown" : "WYSIWYG"}`
|
|
2712
2947
|
},
|
|
2713
2948
|
currentMode === "wysiwyg" ? "MD" : "WYSIWYG"
|
|
2714
|
-
)), /* @__PURE__ */
|
|
2949
|
+
)), /* @__PURE__ */ React17.createElement("div", { style: editorStyle }, currentMode === "wysiwyg" ? /* @__PURE__ */ React17.createElement(
|
|
2715
2950
|
"div",
|
|
2716
2951
|
{
|
|
2717
2952
|
ref: editorRef,
|
|
@@ -2726,7 +2961,7 @@ function RichTextEditor({
|
|
|
2726
2961
|
"aria-required": required || props["aria-required"],
|
|
2727
2962
|
suppressContentEditableWarning: true
|
|
2728
2963
|
}
|
|
2729
|
-
) : /* @__PURE__ */
|
|
2964
|
+
) : /* @__PURE__ */ React17.createElement(
|
|
2730
2965
|
"textarea",
|
|
2731
2966
|
{
|
|
2732
2967
|
ref: textareaRef,
|
|
@@ -2749,6 +2984,6 @@ function RichTextEditor({
|
|
|
2749
2984
|
}
|
|
2750
2985
|
RichTextEditor.displayName = "RichTextEditor";
|
|
2751
2986
|
|
|
2752
|
-
export { Checkbox, CheckboxGroup, DatePicker, DateRangePicker, FileInput, MultiSelect, Radio, RichTextEditor, Select, TextArea, TextInput, TimePicker };
|
|
2987
|
+
export { Checkbox2 as Checkbox, CheckboxGroup, DatePicker, DateRangePicker, FileInput, MultiSelect, Radio, RichTextEditor, Select2 as Select, Switch2 as Switch, TextArea, TextInput, TimePicker };
|
|
2753
2988
|
//# sourceMappingURL=inputs.js.map
|
|
2754
2989
|
//# sourceMappingURL=inputs.js.map
|