@dynamicnorway/react 1.0.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/README.md +50 -0
- package/dist/index.d.ts +432 -0
- package/dist/index.js +1705 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1705 @@
|
|
|
1
|
+
// src/lib/utils.ts
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
function cn(...inputs) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// src/components/button.tsx
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
var buttonVariantClasses = {
|
|
11
|
+
primary: "bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500 border-transparent",
|
|
12
|
+
secondary: "bg-background-secondary text-text-primary hover:bg-background-tertiary focus:ring-primary-500 border-border-primary",
|
|
13
|
+
outline: "bg-transparent text-text-primary hover:bg-background-tertiary focus:ring-primary-500 border-border-primary",
|
|
14
|
+
danger: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500 border-transparent",
|
|
15
|
+
destructive: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500 border-transparent",
|
|
16
|
+
ghost: "bg-transparent text-text-primary hover:bg-background-tertiary focus:ring-primary-500 border-transparent"
|
|
17
|
+
};
|
|
18
|
+
var buttonSizeClasses = {
|
|
19
|
+
sm: "px-3 py-1.5 text-sm",
|
|
20
|
+
md: "px-4 py-2 text-sm",
|
|
21
|
+
lg: "px-6 py-3 text-base"
|
|
22
|
+
};
|
|
23
|
+
var Button = ({
|
|
24
|
+
className = "",
|
|
25
|
+
variant = "primary",
|
|
26
|
+
size = "md",
|
|
27
|
+
loading = false,
|
|
28
|
+
fullWidth = false,
|
|
29
|
+
disabled,
|
|
30
|
+
children,
|
|
31
|
+
ref,
|
|
32
|
+
...props
|
|
33
|
+
}) => {
|
|
34
|
+
return /* @__PURE__ */ jsxs(
|
|
35
|
+
"button",
|
|
36
|
+
{
|
|
37
|
+
ref,
|
|
38
|
+
disabled: disabled || loading,
|
|
39
|
+
className: `
|
|
40
|
+
inline-flex items-center justify-center
|
|
41
|
+
font-medium rounded-md border
|
|
42
|
+
focus:outline-none focus:ring-2 focus:ring-offset-2
|
|
43
|
+
cursor-pointer
|
|
44
|
+
disabled:opacity-50 disabled:cursor-not-allowed
|
|
45
|
+
transition-colors
|
|
46
|
+
${buttonVariantClasses[variant]}
|
|
47
|
+
${buttonSizeClasses[size]}
|
|
48
|
+
${fullWidth ? "w-full" : ""}
|
|
49
|
+
${className}
|
|
50
|
+
`.trim().replace(/\s+/g, " "),
|
|
51
|
+
...props,
|
|
52
|
+
children: [
|
|
53
|
+
loading && /* @__PURE__ */ jsxs(
|
|
54
|
+
"svg",
|
|
55
|
+
{
|
|
56
|
+
className: "animate-spin -ml-1 mr-2 h-4 w-4",
|
|
57
|
+
fill: "none",
|
|
58
|
+
viewBox: "0 0 24 24",
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ jsx(
|
|
61
|
+
"circle",
|
|
62
|
+
{
|
|
63
|
+
className: "opacity-25",
|
|
64
|
+
cx: "12",
|
|
65
|
+
cy: "12",
|
|
66
|
+
r: "10",
|
|
67
|
+
stroke: "currentColor",
|
|
68
|
+
strokeWidth: "4"
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
"path",
|
|
73
|
+
{
|
|
74
|
+
className: "opacity-75",
|
|
75
|
+
fill: "currentColor",
|
|
76
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
),
|
|
82
|
+
children
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
Button.displayName = "Button";
|
|
88
|
+
|
|
89
|
+
// src/components/form-field.tsx
|
|
90
|
+
import React, { useId } from "react";
|
|
91
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
92
|
+
function FormField({
|
|
93
|
+
label,
|
|
94
|
+
required = false,
|
|
95
|
+
error,
|
|
96
|
+
helperText,
|
|
97
|
+
className = "",
|
|
98
|
+
children,
|
|
99
|
+
htmlFor
|
|
100
|
+
}) {
|
|
101
|
+
const generatedId = useId();
|
|
102
|
+
const inputId = htmlFor || generatedId;
|
|
103
|
+
return /* @__PURE__ */ jsxs2("div", { className: `space-y-1 ${className}`, children: [
|
|
104
|
+
label && /* @__PURE__ */ jsxs2(
|
|
105
|
+
"label",
|
|
106
|
+
{
|
|
107
|
+
htmlFor: inputId,
|
|
108
|
+
className: "block text-sm font-medium text-text-primary",
|
|
109
|
+
children: [
|
|
110
|
+
label,
|
|
111
|
+
required && /* @__PURE__ */ jsx2("span", { className: "text-red-500 ml-1", children: "*" })
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
),
|
|
115
|
+
React.isValidElement(children) ? React.cloneElement(children, {
|
|
116
|
+
id: inputId,
|
|
117
|
+
"aria-invalid": !!error,
|
|
118
|
+
"aria-describedby": error ? `${inputId}-error` : helperText ? `${inputId}-helper` : void 0
|
|
119
|
+
}) : children,
|
|
120
|
+
error && /* @__PURE__ */ jsx2(
|
|
121
|
+
"p",
|
|
122
|
+
{
|
|
123
|
+
id: `${inputId}-error`,
|
|
124
|
+
className: "text-sm text-red-600 dark:text-red-400",
|
|
125
|
+
role: "alert",
|
|
126
|
+
children: error
|
|
127
|
+
}
|
|
128
|
+
),
|
|
129
|
+
!error && helperText && /* @__PURE__ */ jsx2(
|
|
130
|
+
"p",
|
|
131
|
+
{
|
|
132
|
+
id: `${inputId}-helper`,
|
|
133
|
+
className: "text-sm text-text-secondary",
|
|
134
|
+
children: helperText
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
] });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/components/input-styles.ts
|
|
141
|
+
var baseInputClasses = `
|
|
142
|
+
w-full px-3 py-2
|
|
143
|
+
border rounded-md
|
|
144
|
+
text-text-primary
|
|
145
|
+
bg-background-secondary
|
|
146
|
+
border-border-primary
|
|
147
|
+
placeholder-text-tertiary
|
|
148
|
+
focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500
|
|
149
|
+
disabled:bg-background-tertiary disabled:cursor-not-allowed disabled:opacity-60
|
|
150
|
+
transition-colors
|
|
151
|
+
`.trim().replace(/\s+/g, " ");
|
|
152
|
+
var errorInputClasses = `
|
|
153
|
+
border-red-500 dark:border-red-500
|
|
154
|
+
focus:ring-red-500 focus:border-red-500
|
|
155
|
+
`.trim().replace(/\s+/g, " ");
|
|
156
|
+
|
|
157
|
+
// src/components/input.tsx
|
|
158
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
159
|
+
var Input = ({
|
|
160
|
+
className = "",
|
|
161
|
+
hasError = false,
|
|
162
|
+
onKeyDown,
|
|
163
|
+
ref,
|
|
164
|
+
...props
|
|
165
|
+
}) => {
|
|
166
|
+
const handleKeyDown = (e) => {
|
|
167
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "a") {
|
|
168
|
+
e.preventDefault();
|
|
169
|
+
e.currentTarget.select();
|
|
170
|
+
}
|
|
171
|
+
onKeyDown?.(e);
|
|
172
|
+
};
|
|
173
|
+
return /* @__PURE__ */ jsx3(
|
|
174
|
+
"input",
|
|
175
|
+
{
|
|
176
|
+
ref,
|
|
177
|
+
className: `${baseInputClasses} ${hasError ? errorInputClasses : ""} ${className}`,
|
|
178
|
+
onKeyDown: handleKeyDown,
|
|
179
|
+
...props
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
Input.displayName = "Input";
|
|
184
|
+
|
|
185
|
+
// src/components/textarea.tsx
|
|
186
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
187
|
+
var Textarea = ({
|
|
188
|
+
className = "",
|
|
189
|
+
hasError = false,
|
|
190
|
+
autoResize = false,
|
|
191
|
+
onChange,
|
|
192
|
+
onKeyDown,
|
|
193
|
+
ref,
|
|
194
|
+
...props
|
|
195
|
+
}) => {
|
|
196
|
+
const handleChange = (e) => {
|
|
197
|
+
if (autoResize) {
|
|
198
|
+
e.target.style.height = "auto";
|
|
199
|
+
e.target.style.height = `${e.target.scrollHeight}px`;
|
|
200
|
+
}
|
|
201
|
+
onChange?.(e);
|
|
202
|
+
};
|
|
203
|
+
const handleKeyDown = (e) => {
|
|
204
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "a") {
|
|
205
|
+
e.preventDefault();
|
|
206
|
+
e.currentTarget.select();
|
|
207
|
+
}
|
|
208
|
+
onKeyDown?.(e);
|
|
209
|
+
};
|
|
210
|
+
return /* @__PURE__ */ jsx4(
|
|
211
|
+
"textarea",
|
|
212
|
+
{
|
|
213
|
+
ref,
|
|
214
|
+
className: `${baseInputClasses} ${hasError ? errorInputClasses : ""} ${autoResize ? "resize-none overflow-hidden" : ""} ${className}`,
|
|
215
|
+
onChange: handleChange,
|
|
216
|
+
onKeyDown: handleKeyDown,
|
|
217
|
+
...props
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
};
|
|
221
|
+
Textarea.displayName = "Textarea";
|
|
222
|
+
|
|
223
|
+
// src/components/select.tsx
|
|
224
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
225
|
+
var Select = ({
|
|
226
|
+
className = "",
|
|
227
|
+
hasError = false,
|
|
228
|
+
placeholder,
|
|
229
|
+
options,
|
|
230
|
+
children,
|
|
231
|
+
ref,
|
|
232
|
+
...props
|
|
233
|
+
}) => {
|
|
234
|
+
return /* @__PURE__ */ jsxs3(
|
|
235
|
+
"select",
|
|
236
|
+
{
|
|
237
|
+
ref,
|
|
238
|
+
className: `${baseInputClasses} ${hasError ? errorInputClasses : ""} ${className}`,
|
|
239
|
+
...props,
|
|
240
|
+
children: [
|
|
241
|
+
placeholder && /* @__PURE__ */ jsx5("option", { value: "", disabled: true, children: placeholder }),
|
|
242
|
+
options ? options.map((option) => /* @__PURE__ */ jsx5(
|
|
243
|
+
"option",
|
|
244
|
+
{
|
|
245
|
+
value: option.value,
|
|
246
|
+
disabled: option.disabled,
|
|
247
|
+
children: option.label
|
|
248
|
+
},
|
|
249
|
+
option.value
|
|
250
|
+
)) : children
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
};
|
|
255
|
+
Select.displayName = "Select";
|
|
256
|
+
|
|
257
|
+
// src/components/checkbox.tsx
|
|
258
|
+
import { useId as useId2 } from "react";
|
|
259
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
260
|
+
var Checkbox = ({
|
|
261
|
+
className = "",
|
|
262
|
+
label,
|
|
263
|
+
id,
|
|
264
|
+
ref,
|
|
265
|
+
...props
|
|
266
|
+
}) => {
|
|
267
|
+
const generatedId = useId2();
|
|
268
|
+
const checkboxId = id || generatedId;
|
|
269
|
+
return /* @__PURE__ */ jsxs4("div", { className: `flex items-center ${className}`, children: [
|
|
270
|
+
/* @__PURE__ */ jsx6(
|
|
271
|
+
"input",
|
|
272
|
+
{
|
|
273
|
+
ref,
|
|
274
|
+
type: "checkbox",
|
|
275
|
+
id: checkboxId,
|
|
276
|
+
className: "h-4 w-4 rounded border-border-primary text-primary-600 focus:ring-primary-500 bg-background-secondary",
|
|
277
|
+
...props
|
|
278
|
+
}
|
|
279
|
+
),
|
|
280
|
+
label && /* @__PURE__ */ jsx6("label", { htmlFor: checkboxId, className: "ml-2 text-sm text-text-primary", children: label })
|
|
281
|
+
] });
|
|
282
|
+
};
|
|
283
|
+
Checkbox.displayName = "Checkbox";
|
|
284
|
+
|
|
285
|
+
// src/components/dialog.tsx
|
|
286
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
287
|
+
import { X } from "lucide-react";
|
|
288
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
289
|
+
var Dialog = DialogPrimitive.Root;
|
|
290
|
+
var DialogTrigger = DialogPrimitive.Trigger;
|
|
291
|
+
var DialogPortal = DialogPrimitive.Portal;
|
|
292
|
+
var DialogClose = DialogPrimitive.Close;
|
|
293
|
+
var DialogOverlay = ({ className, ref, ...props }) => /* @__PURE__ */ jsx7(
|
|
294
|
+
DialogPrimitive.Overlay,
|
|
295
|
+
{
|
|
296
|
+
ref,
|
|
297
|
+
className: cn(
|
|
298
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
299
|
+
className
|
|
300
|
+
),
|
|
301
|
+
...props
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
305
|
+
var DialogContent = ({
|
|
306
|
+
className,
|
|
307
|
+
children,
|
|
308
|
+
closeLabel = "Close",
|
|
309
|
+
ref,
|
|
310
|
+
...props
|
|
311
|
+
}) => /* @__PURE__ */ jsxs5(DialogPortal, { children: [
|
|
312
|
+
/* @__PURE__ */ jsx7(DialogOverlay, {}),
|
|
313
|
+
/* @__PURE__ */ jsxs5(
|
|
314
|
+
DialogPrimitive.Content,
|
|
315
|
+
{
|
|
316
|
+
ref,
|
|
317
|
+
className: cn(
|
|
318
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-full data-[state=open]:slide-in-from-left-full sm:rounded-lg",
|
|
319
|
+
className
|
|
320
|
+
),
|
|
321
|
+
...props,
|
|
322
|
+
children: [
|
|
323
|
+
children,
|
|
324
|
+
/* @__PURE__ */ jsxs5(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
|
|
325
|
+
/* @__PURE__ */ jsx7(X, { className: "h-4 w-4" }),
|
|
326
|
+
/* @__PURE__ */ jsx7("span", { className: "sr-only", children: closeLabel })
|
|
327
|
+
] })
|
|
328
|
+
]
|
|
329
|
+
}
|
|
330
|
+
)
|
|
331
|
+
] });
|
|
332
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
333
|
+
var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx7("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
|
|
334
|
+
DialogHeader.displayName = "DialogHeader";
|
|
335
|
+
var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx7(
|
|
336
|
+
"div",
|
|
337
|
+
{
|
|
338
|
+
className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
|
|
339
|
+
...props
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
DialogFooter.displayName = "DialogFooter";
|
|
343
|
+
var DialogTitle = ({ className, ref, ...props }) => /* @__PURE__ */ jsx7(
|
|
344
|
+
DialogPrimitive.Title,
|
|
345
|
+
{
|
|
346
|
+
ref,
|
|
347
|
+
className: cn("text-lg font-semibold leading-none tracking-tight", className),
|
|
348
|
+
...props
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
352
|
+
var DialogDescription = ({ className, ref, ...props }) => /* @__PURE__ */ jsx7(
|
|
353
|
+
DialogPrimitive.Description,
|
|
354
|
+
{
|
|
355
|
+
ref,
|
|
356
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
357
|
+
...props
|
|
358
|
+
}
|
|
359
|
+
);
|
|
360
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
361
|
+
var ConfirmDialog = ({
|
|
362
|
+
open,
|
|
363
|
+
onClose,
|
|
364
|
+
onConfirm,
|
|
365
|
+
title,
|
|
366
|
+
message,
|
|
367
|
+
confirmText = "Confirm",
|
|
368
|
+
cancelText = "Cancel",
|
|
369
|
+
variant = "default",
|
|
370
|
+
loading = false,
|
|
371
|
+
loadingText = "Loading..."
|
|
372
|
+
}) => /* @__PURE__ */ jsx7(Dialog, { open, onOpenChange: (isOpen) => !isOpen && onClose(), children: /* @__PURE__ */ jsxs5(DialogContent, { className: "sm:max-w-[500px]", children: [
|
|
373
|
+
/* @__PURE__ */ jsxs5(DialogHeader, { children: [
|
|
374
|
+
/* @__PURE__ */ jsx7(DialogTitle, { children: title }),
|
|
375
|
+
/* @__PURE__ */ jsx7(DialogDescription, { children: message })
|
|
376
|
+
] }),
|
|
377
|
+
/* @__PURE__ */ jsxs5(DialogFooter, { children: [
|
|
378
|
+
/* @__PURE__ */ jsx7(
|
|
379
|
+
"button",
|
|
380
|
+
{
|
|
381
|
+
onClick: onClose,
|
|
382
|
+
disabled: loading,
|
|
383
|
+
className: "px-4 py-2 text-sm font-medium text-text-primary bg-background-secondary border border-border-primary rounded-md hover:bg-background-tertiary focus:outline-none focus:ring-2 focus:ring-primary-500 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
384
|
+
children: cancelText
|
|
385
|
+
}
|
|
386
|
+
),
|
|
387
|
+
/* @__PURE__ */ jsx7(
|
|
388
|
+
"button",
|
|
389
|
+
{
|
|
390
|
+
onClick: onConfirm,
|
|
391
|
+
disabled: loading,
|
|
392
|
+
className: `px-4 py-2 text-sm font-medium text-white rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed ${variant === "danger" ? "bg-red-600 hover:bg-red-700 focus:ring-red-500" : "bg-primary-600 hover:bg-primary-700 focus:ring-primary-500"}`,
|
|
393
|
+
children: loading ? loadingText : confirmText
|
|
394
|
+
}
|
|
395
|
+
)
|
|
396
|
+
] })
|
|
397
|
+
] }) });
|
|
398
|
+
|
|
399
|
+
// src/components/card.tsx
|
|
400
|
+
import React3 from "react";
|
|
401
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
402
|
+
var Card = React3.forwardRef(
|
|
403
|
+
({ children, variant = "default", className = "", onClick }, ref) => {
|
|
404
|
+
const baseStyles = "bg-background-secondary rounded-lg shadow-sm border border-border-primary transition-all duration-150";
|
|
405
|
+
const variantStyles = {
|
|
406
|
+
default: "",
|
|
407
|
+
interactive: "cursor-pointer hover:shadow-md hover:border-primary-300 dark:hover:border-primary-600"
|
|
408
|
+
};
|
|
409
|
+
const buttonResetStyles = onClick ? "w-full text-left p-0 m-0 font-inherit block appearance-none flex flex-col cursor-pointer" : "";
|
|
410
|
+
const Component = onClick ? "button" : "div";
|
|
411
|
+
return /* @__PURE__ */ jsx8(
|
|
412
|
+
Component,
|
|
413
|
+
{
|
|
414
|
+
ref,
|
|
415
|
+
className: `${baseStyles} ${variantStyles[variant]} ${buttonResetStyles} ${className}`,
|
|
416
|
+
onClick,
|
|
417
|
+
children
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
Card.displayName = "Card";
|
|
423
|
+
var CardHeader = ({ children, className = "" }) => /* @__PURE__ */ jsx8("div", { className: `px-6 py-4 border-b border-border-primary ${className}`, children });
|
|
424
|
+
var CardBody = ({ children, className = "" }) => /* @__PURE__ */ jsx8("div", { className: `px-6 py-4 flex flex-col ${className}`, children });
|
|
425
|
+
var CardFooter = ({ children, className = "" }) => /* @__PURE__ */ jsx8("div", { className: `px-6 py-4 border-t border-border-primary ${className}`, children });
|
|
426
|
+
|
|
427
|
+
// src/components/loading-spinner.tsx
|
|
428
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
429
|
+
var LoadingSpinner = ({
|
|
430
|
+
size = "md",
|
|
431
|
+
className = ""
|
|
432
|
+
}) => {
|
|
433
|
+
const sizeStyles = {
|
|
434
|
+
sm: "w-4 h-4",
|
|
435
|
+
md: "w-8 h-8",
|
|
436
|
+
lg: "w-12 h-12"
|
|
437
|
+
};
|
|
438
|
+
return /* @__PURE__ */ jsxs6(
|
|
439
|
+
"svg",
|
|
440
|
+
{
|
|
441
|
+
className: `animate-spin ${sizeStyles[size]} text-primary-600 dark:text-primary-400 ${className}`,
|
|
442
|
+
fill: "none",
|
|
443
|
+
viewBox: "0 0 24 24",
|
|
444
|
+
children: [
|
|
445
|
+
/* @__PURE__ */ jsx9(
|
|
446
|
+
"circle",
|
|
447
|
+
{
|
|
448
|
+
className: "opacity-25",
|
|
449
|
+
cx: "12",
|
|
450
|
+
cy: "12",
|
|
451
|
+
r: "10",
|
|
452
|
+
stroke: "currentColor",
|
|
453
|
+
strokeWidth: "4"
|
|
454
|
+
}
|
|
455
|
+
),
|
|
456
|
+
/* @__PURE__ */ jsx9(
|
|
457
|
+
"path",
|
|
458
|
+
{
|
|
459
|
+
className: "opacity-75",
|
|
460
|
+
fill: "currentColor",
|
|
461
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
462
|
+
}
|
|
463
|
+
)
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
};
|
|
468
|
+
var LoadingScreen = ({
|
|
469
|
+
message = "Loading..."
|
|
470
|
+
}) => /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center min-h-[400px] space-y-4", children: [
|
|
471
|
+
/* @__PURE__ */ jsx9(LoadingSpinner, { size: "lg" }),
|
|
472
|
+
/* @__PURE__ */ jsx9("p", { className: "text-text-secondary", children: message })
|
|
473
|
+
] });
|
|
474
|
+
|
|
475
|
+
// src/components/badge.tsx
|
|
476
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
477
|
+
var Badge = ({
|
|
478
|
+
children,
|
|
479
|
+
variant = "default",
|
|
480
|
+
size = "md",
|
|
481
|
+
className = ""
|
|
482
|
+
}) => {
|
|
483
|
+
const baseStyles = "inline-flex items-center justify-center font-medium rounded-full whitespace-nowrap";
|
|
484
|
+
const variantStyles = {
|
|
485
|
+
default: "bg-background-tertiary text-text-primary",
|
|
486
|
+
success: "bg-primary-100 dark:bg-primary-900 text-primary-700 dark:text-primary-300",
|
|
487
|
+
warning: "bg-amber-100 dark:bg-amber-900 text-amber-700 dark:text-amber-300",
|
|
488
|
+
error: "bg-red-100 dark:bg-red-900 text-red-700 dark:text-red-300",
|
|
489
|
+
info: "bg-blue-100 dark:bg-blue-900 text-blue-700 dark:text-blue-300"
|
|
490
|
+
};
|
|
491
|
+
const sizeStyles = {
|
|
492
|
+
sm: "text-xs px-2 py-0.5",
|
|
493
|
+
md: "text-sm px-2.5 py-1"
|
|
494
|
+
};
|
|
495
|
+
return /* @__PURE__ */ jsx10(
|
|
496
|
+
"span",
|
|
497
|
+
{
|
|
498
|
+
className: `${baseStyles} ${variantStyles[variant]} ${sizeStyles[size]} ${className}`,
|
|
499
|
+
children
|
|
500
|
+
}
|
|
501
|
+
);
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
// src/components/empty-state.tsx
|
|
505
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
506
|
+
var EmptyState = ({
|
|
507
|
+
icon,
|
|
508
|
+
title,
|
|
509
|
+
description,
|
|
510
|
+
action,
|
|
511
|
+
className = ""
|
|
512
|
+
}) => /* @__PURE__ */ jsxs7(
|
|
513
|
+
"div",
|
|
514
|
+
{
|
|
515
|
+
className: `flex flex-col items-center justify-center py-12 px-4 text-center ${className}`,
|
|
516
|
+
children: [
|
|
517
|
+
icon && /* @__PURE__ */ jsx11("div", { className: "mb-4 text-text-tertiary", children: icon }),
|
|
518
|
+
/* @__PURE__ */ jsx11("h3", { className: "text-lg font-semibold text-text-primary mb-2", children: title }),
|
|
519
|
+
description && /* @__PURE__ */ jsx11("p", { className: "text-sm text-text-secondary mb-6 max-w-md", children: description }),
|
|
520
|
+
action && /* @__PURE__ */ jsx11(
|
|
521
|
+
"button",
|
|
522
|
+
{
|
|
523
|
+
onClick: action.onClick,
|
|
524
|
+
className: "px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700 transition-colors cursor-pointer",
|
|
525
|
+
children: action.label
|
|
526
|
+
}
|
|
527
|
+
)
|
|
528
|
+
]
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
// src/components/slide-over.tsx
|
|
533
|
+
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
534
|
+
var sizeClasses = {
|
|
535
|
+
sm: "max-w-sm",
|
|
536
|
+
md: "max-w-md",
|
|
537
|
+
lg: "max-w-lg",
|
|
538
|
+
xl: "max-w-4xl",
|
|
539
|
+
full: "max-w-full"
|
|
540
|
+
};
|
|
541
|
+
function SlideOver({
|
|
542
|
+
open,
|
|
543
|
+
onClose,
|
|
544
|
+
title,
|
|
545
|
+
description,
|
|
546
|
+
children,
|
|
547
|
+
footer,
|
|
548
|
+
size = "md",
|
|
549
|
+
closeLabel = "Close"
|
|
550
|
+
}) {
|
|
551
|
+
return /* @__PURE__ */ jsx12(Dialog, { open, onOpenChange: (isOpen) => !isOpen && onClose(), children: /* @__PURE__ */ jsxs8(DialogContent, { className: cn(sizeClasses[size], "max-h-[90vh] flex flex-col"), closeLabel, children: [
|
|
552
|
+
/* @__PURE__ */ jsxs8(DialogHeader, { children: [
|
|
553
|
+
/* @__PURE__ */ jsx12(DialogTitle, { children: title }),
|
|
554
|
+
description && /* @__PURE__ */ jsx12(DialogDescription, { children: description })
|
|
555
|
+
] }),
|
|
556
|
+
/* @__PURE__ */ jsx12("div", { className: "flex-1 overflow-y-auto min-h-0 px-1", children }),
|
|
557
|
+
footer && /* @__PURE__ */ jsx12(DialogFooter, { className: "mt-4", children: footer })
|
|
558
|
+
] }) });
|
|
559
|
+
}
|
|
560
|
+
function FormSlideOver({
|
|
561
|
+
open,
|
|
562
|
+
onClose,
|
|
563
|
+
title,
|
|
564
|
+
description,
|
|
565
|
+
children,
|
|
566
|
+
submitText = "Save changes",
|
|
567
|
+
cancelText = "Cancel",
|
|
568
|
+
deleteText = "Delete",
|
|
569
|
+
savingText = "Saving...",
|
|
570
|
+
deletingText = "Deleting...",
|
|
571
|
+
unsavedChangesConfirm = "You have unsaved changes. Are you sure you want to close?",
|
|
572
|
+
onSubmit,
|
|
573
|
+
onDelete,
|
|
574
|
+
isSubmitting = false,
|
|
575
|
+
isDeleting = false,
|
|
576
|
+
hasChanges = false,
|
|
577
|
+
size = "md",
|
|
578
|
+
closeLabel
|
|
579
|
+
}) {
|
|
580
|
+
const handleClose = () => {
|
|
581
|
+
if (hasChanges) {
|
|
582
|
+
if (confirm(unsavedChangesConfirm)) {
|
|
583
|
+
onClose();
|
|
584
|
+
}
|
|
585
|
+
} else {
|
|
586
|
+
onClose();
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
return /* @__PURE__ */ jsx12(
|
|
590
|
+
SlideOver,
|
|
591
|
+
{
|
|
592
|
+
open,
|
|
593
|
+
onClose: handleClose,
|
|
594
|
+
title,
|
|
595
|
+
description,
|
|
596
|
+
size,
|
|
597
|
+
closeLabel,
|
|
598
|
+
footer: /* @__PURE__ */ jsxs8("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-between w-full gap-2", children: [
|
|
599
|
+
onDelete && /* @__PURE__ */ jsx12(
|
|
600
|
+
"button",
|
|
601
|
+
{
|
|
602
|
+
type: "button",
|
|
603
|
+
onClick: onDelete,
|
|
604
|
+
disabled: isDeleting || isSubmitting,
|
|
605
|
+
className: "w-full sm:w-auto px-4 py-2 text-sm font-medium text-white bg-red-600 rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 disabled:opacity-50",
|
|
606
|
+
children: isDeleting ? deletingText : deleteText
|
|
607
|
+
}
|
|
608
|
+
),
|
|
609
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-col-reverse sm:flex-row gap-2 sm:ml-auto", children: [
|
|
610
|
+
/* @__PURE__ */ jsx12(
|
|
611
|
+
"button",
|
|
612
|
+
{
|
|
613
|
+
type: "button",
|
|
614
|
+
onClick: handleClose,
|
|
615
|
+
disabled: isSubmitting || isDeleting,
|
|
616
|
+
className: "w-full sm:w-auto px-4 py-2 text-sm font-medium text-text-primary bg-background-secondary border border-border-primary rounded-md hover:bg-background-tertiary focus:outline-none focus:ring-2 focus:ring-primary-500 disabled:opacity-50",
|
|
617
|
+
children: cancelText
|
|
618
|
+
}
|
|
619
|
+
),
|
|
620
|
+
/* @__PURE__ */ jsx12(
|
|
621
|
+
"button",
|
|
622
|
+
{
|
|
623
|
+
type: "button",
|
|
624
|
+
onClick: onSubmit,
|
|
625
|
+
disabled: isSubmitting || isDeleting,
|
|
626
|
+
className: "w-full sm:w-auto px-4 py-2 text-sm font-medium text-white bg-primary-600 rounded-md hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 disabled:opacity-50",
|
|
627
|
+
children: isSubmitting ? savingText : submitText
|
|
628
|
+
}
|
|
629
|
+
)
|
|
630
|
+
] })
|
|
631
|
+
] }),
|
|
632
|
+
children
|
|
633
|
+
}
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// src/components/entity-form.tsx
|
|
638
|
+
import { useRef, useEffect, useCallback } from "react";
|
|
639
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
640
|
+
var EntityForm = ({
|
|
641
|
+
isEdit = false,
|
|
642
|
+
isSaving = false,
|
|
643
|
+
error,
|
|
644
|
+
onSave,
|
|
645
|
+
onCancel,
|
|
646
|
+
onDelete,
|
|
647
|
+
saveLabel = "Save",
|
|
648
|
+
cancelLabel = "Cancel",
|
|
649
|
+
deleteLabel = "Delete",
|
|
650
|
+
savingLabel = "Saving...",
|
|
651
|
+
deleteConfirmMessage = "Are you sure you want to delete this?",
|
|
652
|
+
showDelete = true,
|
|
653
|
+
autoFocus = true,
|
|
654
|
+
className = "",
|
|
655
|
+
children
|
|
656
|
+
}) => {
|
|
657
|
+
const formRef = useRef(null);
|
|
658
|
+
useEffect(() => {
|
|
659
|
+
if (autoFocus && formRef.current) {
|
|
660
|
+
const firstInput = formRef.current.querySelector(
|
|
661
|
+
'input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled])'
|
|
662
|
+
);
|
|
663
|
+
if (firstInput) {
|
|
664
|
+
setTimeout(() => {
|
|
665
|
+
firstInput.focus();
|
|
666
|
+
}, 50);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}, [autoFocus]);
|
|
670
|
+
const handleKeyDown = useCallback(
|
|
671
|
+
(e) => {
|
|
672
|
+
if (isSaving) return;
|
|
673
|
+
if (e.key === "Escape") {
|
|
674
|
+
e.preventDefault();
|
|
675
|
+
onCancel();
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
if (e.key === "Enter" && !(e.target instanceof HTMLTextAreaElement)) {
|
|
679
|
+
if (e.ctrlKey || e.metaKey) {
|
|
680
|
+
e.preventDefault();
|
|
681
|
+
onSave();
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
[isSaving, onSave, onCancel]
|
|
686
|
+
);
|
|
687
|
+
const handleDelete = () => {
|
|
688
|
+
if (onDelete && window.confirm(deleteConfirmMessage)) {
|
|
689
|
+
onDelete();
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
return /* @__PURE__ */ jsxs9(
|
|
693
|
+
"div",
|
|
694
|
+
{
|
|
695
|
+
ref: formRef,
|
|
696
|
+
className: `bg-background-secondary border border-border-primary rounded-lg p-4 ${className}`,
|
|
697
|
+
onKeyDown: handleKeyDown,
|
|
698
|
+
children: [
|
|
699
|
+
/* @__PURE__ */ jsx13("div", { className: "space-y-4", children }),
|
|
700
|
+
error && /* @__PURE__ */ jsx13("div", { className: "mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-md", children: /* @__PURE__ */ jsx13("p", { className: "text-sm text-red-600 dark:text-red-400", children: error }) }),
|
|
701
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-6 flex items-center justify-between", children: [
|
|
702
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
703
|
+
/* @__PURE__ */ jsx13(Button, { type: "button", variant: "primary", onClick: onSave, loading: isSaving, disabled: isSaving, children: isSaving ? savingLabel : saveLabel }),
|
|
704
|
+
/* @__PURE__ */ jsx13(Button, { type: "button", variant: "secondary", onClick: onCancel, disabled: isSaving, children: cancelLabel })
|
|
705
|
+
] }),
|
|
706
|
+
isEdit && showDelete && onDelete && /* @__PURE__ */ jsx13(Button, { type: "button", variant: "danger", onClick: handleDelete, disabled: isSaving, children: deleteLabel })
|
|
707
|
+
] }),
|
|
708
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-3 text-xs text-text-tertiary", children: [
|
|
709
|
+
/* @__PURE__ */ jsx13("kbd", { className: "px-1.5 py-0.5 bg-background-primary rounded", children: "Esc" }),
|
|
710
|
+
" to cancel",
|
|
711
|
+
/* @__PURE__ */ jsx13("span", { className: "mx-2", children: "\xB7" }),
|
|
712
|
+
/* @__PURE__ */ jsx13("kbd", { className: "px-1.5 py-0.5 bg-background-primary rounded", children: "\u2318" }),
|
|
713
|
+
"+",
|
|
714
|
+
/* @__PURE__ */ jsx13("kbd", { className: "px-1.5 py-0.5 bg-background-primary rounded", children: "Enter" }),
|
|
715
|
+
" to save"
|
|
716
|
+
] })
|
|
717
|
+
]
|
|
718
|
+
}
|
|
719
|
+
);
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
// src/components/search-input.tsx
|
|
723
|
+
import { useState, useRef as useRef2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
|
|
724
|
+
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
725
|
+
var sizeClasses2 = {
|
|
726
|
+
sm: {
|
|
727
|
+
input: "h-8 text-sm",
|
|
728
|
+
icon: "w-4 h-4",
|
|
729
|
+
padding: "pl-8 pr-8",
|
|
730
|
+
collapsedWidth: "w-8",
|
|
731
|
+
expandedWidth: "w-48 sm:w-64"
|
|
732
|
+
},
|
|
733
|
+
md: {
|
|
734
|
+
input: "h-10 text-sm",
|
|
735
|
+
icon: "w-5 h-5",
|
|
736
|
+
padding: "pl-10 pr-10",
|
|
737
|
+
collapsedWidth: "w-10",
|
|
738
|
+
expandedWidth: "w-56 sm:w-72"
|
|
739
|
+
},
|
|
740
|
+
lg: {
|
|
741
|
+
input: "h-12 text-base",
|
|
742
|
+
icon: "w-6 h-6",
|
|
743
|
+
padding: "pl-12 pr-12",
|
|
744
|
+
collapsedWidth: "w-12",
|
|
745
|
+
expandedWidth: "w-64 sm:w-80"
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
function SearchInput({
|
|
749
|
+
value,
|
|
750
|
+
onChange,
|
|
751
|
+
placeholder,
|
|
752
|
+
debounceMs = 300,
|
|
753
|
+
expandable = false,
|
|
754
|
+
className = "",
|
|
755
|
+
autoFocus = false,
|
|
756
|
+
size = "md",
|
|
757
|
+
labels = {}
|
|
758
|
+
}) {
|
|
759
|
+
const resolvedPlaceholder = placeholder ?? labels.placeholder ?? "Search";
|
|
760
|
+
const searchHotkeyHint = labels.searchHotkeyHint ?? "Press / to search";
|
|
761
|
+
const openSearchLabel = labels.openSearch ?? "Open search";
|
|
762
|
+
const searchAriaLabel = labels.search ?? "Search";
|
|
763
|
+
const clearSearchLabel = labels.clearSearch ?? "Clear search";
|
|
764
|
+
const [internalValue, setInternalValue] = useState(value);
|
|
765
|
+
const [isExpanded, setIsExpanded] = useState(!expandable || !!value);
|
|
766
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
767
|
+
const inputRef = useRef2(null);
|
|
768
|
+
const debounceTimerRef = useRef2(null);
|
|
769
|
+
const sizes = sizeClasses2[size];
|
|
770
|
+
useEffect2(() => {
|
|
771
|
+
setInternalValue(value);
|
|
772
|
+
if (value && expandable) {
|
|
773
|
+
setIsExpanded(true);
|
|
774
|
+
}
|
|
775
|
+
}, [value, expandable]);
|
|
776
|
+
const debouncedOnChange = useCallback2(
|
|
777
|
+
(newValue) => {
|
|
778
|
+
if (debounceTimerRef.current) {
|
|
779
|
+
clearTimeout(debounceTimerRef.current);
|
|
780
|
+
}
|
|
781
|
+
if (debounceMs > 0) {
|
|
782
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
783
|
+
onChange(newValue);
|
|
784
|
+
}, debounceMs);
|
|
785
|
+
} else {
|
|
786
|
+
onChange(newValue);
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
[onChange, debounceMs]
|
|
790
|
+
);
|
|
791
|
+
useEffect2(() => {
|
|
792
|
+
return () => {
|
|
793
|
+
if (debounceTimerRef.current) {
|
|
794
|
+
clearTimeout(debounceTimerRef.current);
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
}, []);
|
|
798
|
+
const handleChange = (e) => {
|
|
799
|
+
const newValue = e.target.value;
|
|
800
|
+
setInternalValue(newValue);
|
|
801
|
+
debouncedOnChange(newValue);
|
|
802
|
+
};
|
|
803
|
+
const handleClear = () => {
|
|
804
|
+
setInternalValue("");
|
|
805
|
+
onChange("");
|
|
806
|
+
inputRef.current?.focus();
|
|
807
|
+
};
|
|
808
|
+
const handleExpandClick = () => {
|
|
809
|
+
setIsExpanded(true);
|
|
810
|
+
requestAnimationFrame(() => {
|
|
811
|
+
inputRef.current?.focus();
|
|
812
|
+
});
|
|
813
|
+
};
|
|
814
|
+
const handleBlur = () => {
|
|
815
|
+
setIsFocused(false);
|
|
816
|
+
if (expandable && !internalValue) {
|
|
817
|
+
setTimeout(() => {
|
|
818
|
+
if (document.activeElement !== inputRef.current) {
|
|
819
|
+
setIsExpanded(false);
|
|
820
|
+
}
|
|
821
|
+
}, 150);
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
useEffect2(() => {
|
|
825
|
+
const handleKeyDown = (e) => {
|
|
826
|
+
if (e.key === "/" && !["INPUT", "TEXTAREA", "SELECT"].includes(e.target.tagName)) {
|
|
827
|
+
e.preventDefault();
|
|
828
|
+
if (expandable && !isExpanded) {
|
|
829
|
+
setIsExpanded(true);
|
|
830
|
+
}
|
|
831
|
+
requestAnimationFrame(() => {
|
|
832
|
+
inputRef.current?.focus();
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
if (e.key === "Escape" && document.activeElement === inputRef.current) {
|
|
836
|
+
if (internalValue) {
|
|
837
|
+
handleClear();
|
|
838
|
+
} else {
|
|
839
|
+
inputRef.current?.blur();
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
844
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
845
|
+
}, [expandable, isExpanded, internalValue]);
|
|
846
|
+
useEffect2(() => {
|
|
847
|
+
if (autoFocus && inputRef.current) {
|
|
848
|
+
inputRef.current.focus();
|
|
849
|
+
}
|
|
850
|
+
}, [autoFocus]);
|
|
851
|
+
if (expandable && !isExpanded) {
|
|
852
|
+
return /* @__PURE__ */ jsx14(
|
|
853
|
+
"button",
|
|
854
|
+
{
|
|
855
|
+
type: "button",
|
|
856
|
+
onClick: handleExpandClick,
|
|
857
|
+
className: `
|
|
858
|
+
${sizes.collapsedWidth} ${sizes.input}
|
|
859
|
+
flex items-center justify-center
|
|
860
|
+
rounded-md border border-border-primary
|
|
861
|
+
bg-background-secondary
|
|
862
|
+
text-text-tertiary hover:text-text-secondary
|
|
863
|
+
hover:bg-background-tertiary
|
|
864
|
+
focus:outline-none focus:ring-2 focus:ring-primary-500
|
|
865
|
+
transition-all duration-200
|
|
866
|
+
${className}
|
|
867
|
+
`,
|
|
868
|
+
title: searchHotkeyHint,
|
|
869
|
+
"aria-label": openSearchLabel,
|
|
870
|
+
children: /* @__PURE__ */ jsx14("svg", { className: sizes.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx14(
|
|
871
|
+
"path",
|
|
872
|
+
{
|
|
873
|
+
strokeLinecap: "round",
|
|
874
|
+
strokeLinejoin: "round",
|
|
875
|
+
strokeWidth: 2,
|
|
876
|
+
d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
877
|
+
}
|
|
878
|
+
) })
|
|
879
|
+
}
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
return /* @__PURE__ */ jsxs10(
|
|
883
|
+
"div",
|
|
884
|
+
{
|
|
885
|
+
className: `
|
|
886
|
+
relative
|
|
887
|
+
${expandable ? `transition-all duration-200 ${isExpanded ? sizes.expandedWidth : sizes.collapsedWidth}` : "w-full"}
|
|
888
|
+
${className}
|
|
889
|
+
`,
|
|
890
|
+
children: [
|
|
891
|
+
/* @__PURE__ */ jsx14("div", { className: "absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none", children: /* @__PURE__ */ jsx14(
|
|
892
|
+
"svg",
|
|
893
|
+
{
|
|
894
|
+
className: `${sizes.icon} text-text-tertiary`,
|
|
895
|
+
fill: "none",
|
|
896
|
+
stroke: "currentColor",
|
|
897
|
+
viewBox: "0 0 24 24",
|
|
898
|
+
children: /* @__PURE__ */ jsx14(
|
|
899
|
+
"path",
|
|
900
|
+
{
|
|
901
|
+
strokeLinecap: "round",
|
|
902
|
+
strokeLinejoin: "round",
|
|
903
|
+
strokeWidth: 2,
|
|
904
|
+
d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
905
|
+
}
|
|
906
|
+
)
|
|
907
|
+
}
|
|
908
|
+
) }),
|
|
909
|
+
/* @__PURE__ */ jsx14(
|
|
910
|
+
"input",
|
|
911
|
+
{
|
|
912
|
+
ref: inputRef,
|
|
913
|
+
type: "text",
|
|
914
|
+
value: internalValue,
|
|
915
|
+
onChange: handleChange,
|
|
916
|
+
onFocus: () => setIsFocused(true),
|
|
917
|
+
onBlur: handleBlur,
|
|
918
|
+
placeholder: resolvedPlaceholder,
|
|
919
|
+
className: `
|
|
920
|
+
w-full ${sizes.input} ${sizes.padding}
|
|
921
|
+
rounded-md border
|
|
922
|
+
bg-background-secondary
|
|
923
|
+
text-text-primary
|
|
924
|
+
placeholder-text-tertiary
|
|
925
|
+
${isFocused ? "border-primary-500 ring-2 ring-primary-500" : "border-border-primary"}
|
|
926
|
+
focus:outline-none
|
|
927
|
+
transition-colors
|
|
928
|
+
`,
|
|
929
|
+
"aria-label": searchAriaLabel
|
|
930
|
+
}
|
|
931
|
+
),
|
|
932
|
+
internalValue && /* @__PURE__ */ jsx14(
|
|
933
|
+
"button",
|
|
934
|
+
{
|
|
935
|
+
type: "button",
|
|
936
|
+
onClick: handleClear,
|
|
937
|
+
className: "absolute inset-y-0 right-0 flex items-center pr-3 text-text-tertiary hover:text-text-secondary",
|
|
938
|
+
"aria-label": clearSearchLabel,
|
|
939
|
+
children: /* @__PURE__ */ jsx14("svg", { className: sizes.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx14(
|
|
940
|
+
"path",
|
|
941
|
+
{
|
|
942
|
+
strokeLinecap: "round",
|
|
943
|
+
strokeLinejoin: "round",
|
|
944
|
+
strokeWidth: 2,
|
|
945
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
946
|
+
}
|
|
947
|
+
) })
|
|
948
|
+
}
|
|
949
|
+
),
|
|
950
|
+
!internalValue && !isFocused && /* @__PURE__ */ jsx14("div", { className: "absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none", children: /* @__PURE__ */ jsx14("kbd", { className: "hidden sm:inline-flex items-center px-1.5 py-0.5 text-xs font-medium text-text-tertiary bg-background-tertiary rounded border border-border-primary", children: "/" }) })
|
|
951
|
+
]
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// src/components/search-bar.tsx
|
|
957
|
+
import { useEffect as useEffect3, useRef as useRef3, useState as useState2 } from "react";
|
|
958
|
+
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
959
|
+
var SearchBar = ({
|
|
960
|
+
value,
|
|
961
|
+
onChange,
|
|
962
|
+
onClear,
|
|
963
|
+
placeholder = "Search",
|
|
964
|
+
autoFocus = false,
|
|
965
|
+
className = "",
|
|
966
|
+
showShortcutHint = true,
|
|
967
|
+
clearSearchLabel = "Clear search"
|
|
968
|
+
}) => {
|
|
969
|
+
const inputRef = useRef3(null);
|
|
970
|
+
const [isFocused, setIsFocused] = useState2(false);
|
|
971
|
+
useEffect3(() => {
|
|
972
|
+
const handleKeyDown2 = (e) => {
|
|
973
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
974
|
+
e.preventDefault();
|
|
975
|
+
inputRef.current?.focus();
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
window.addEventListener("keydown", handleKeyDown2);
|
|
979
|
+
return () => window.removeEventListener("keydown", handleKeyDown2);
|
|
980
|
+
}, []);
|
|
981
|
+
const handleKeyDown = (e) => {
|
|
982
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "a") {
|
|
983
|
+
e.preventDefault();
|
|
984
|
+
inputRef.current?.select();
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
const handleClear = () => {
|
|
988
|
+
onChange("");
|
|
989
|
+
onClear?.();
|
|
990
|
+
inputRef.current?.focus();
|
|
991
|
+
};
|
|
992
|
+
const hasWhiteBackground = isFocused || value.length > 0;
|
|
993
|
+
return /* @__PURE__ */ jsxs11("div", { className: `relative ${className}`, children: [
|
|
994
|
+
/* @__PURE__ */ jsx15("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx15(
|
|
995
|
+
"svg",
|
|
996
|
+
{
|
|
997
|
+
className: "h-5 w-5 text-text-tertiary",
|
|
998
|
+
fill: "none",
|
|
999
|
+
stroke: "currentColor",
|
|
1000
|
+
viewBox: "0 0 24 24",
|
|
1001
|
+
children: /* @__PURE__ */ jsx15(
|
|
1002
|
+
"path",
|
|
1003
|
+
{
|
|
1004
|
+
strokeLinecap: "round",
|
|
1005
|
+
strokeLinejoin: "round",
|
|
1006
|
+
strokeWidth: 2,
|
|
1007
|
+
d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
1008
|
+
}
|
|
1009
|
+
)
|
|
1010
|
+
}
|
|
1011
|
+
) }),
|
|
1012
|
+
/* @__PURE__ */ jsx15(
|
|
1013
|
+
"input",
|
|
1014
|
+
{
|
|
1015
|
+
ref: inputRef,
|
|
1016
|
+
type: "text",
|
|
1017
|
+
value,
|
|
1018
|
+
onChange: (e) => onChange(e.target.value),
|
|
1019
|
+
onKeyDown: handleKeyDown,
|
|
1020
|
+
onFocus: () => setIsFocused(true),
|
|
1021
|
+
onBlur: () => setIsFocused(false),
|
|
1022
|
+
placeholder,
|
|
1023
|
+
autoFocus,
|
|
1024
|
+
className: `
|
|
1025
|
+
w-full
|
|
1026
|
+
pl-10
|
|
1027
|
+
pr-24
|
|
1028
|
+
py-2
|
|
1029
|
+
${hasWhiteBackground ? "bg-background-tertiary" : "bg-background-secondary"}
|
|
1030
|
+
text-text-primary
|
|
1031
|
+
border
|
|
1032
|
+
border-border-primary
|
|
1033
|
+
rounded-md
|
|
1034
|
+
transition-all
|
|
1035
|
+
duration-150
|
|
1036
|
+
focus:outline-none
|
|
1037
|
+
focus:ring-2
|
|
1038
|
+
focus:ring-primary-500
|
|
1039
|
+
focus:border-primary-500
|
|
1040
|
+
placeholder:text-text-tertiary
|
|
1041
|
+
`
|
|
1042
|
+
}
|
|
1043
|
+
),
|
|
1044
|
+
/* @__PURE__ */ jsxs11("div", { className: "absolute inset-y-0 right-0 flex items-center pr-3 gap-2", children: [
|
|
1045
|
+
showShortcutHint && !value && /* @__PURE__ */ jsx15("kbd", { className: "hidden sm:inline-block px-2 py-1 text-xs text-text-tertiary bg-background-secondary border border-border-primary rounded", children: "\u2318K" }),
|
|
1046
|
+
value && /* @__PURE__ */ jsx15(
|
|
1047
|
+
"button",
|
|
1048
|
+
{
|
|
1049
|
+
type: "button",
|
|
1050
|
+
onClick: handleClear,
|
|
1051
|
+
className: "text-text-tertiary hover:text-text-secondary transition-colors",
|
|
1052
|
+
"aria-label": clearSearchLabel,
|
|
1053
|
+
children: /* @__PURE__ */ jsx15("svg", { className: "h-5 w-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx15(
|
|
1054
|
+
"path",
|
|
1055
|
+
{
|
|
1056
|
+
strokeLinecap: "round",
|
|
1057
|
+
strokeLinejoin: "round",
|
|
1058
|
+
strokeWidth: 2,
|
|
1059
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
1060
|
+
}
|
|
1061
|
+
) })
|
|
1062
|
+
}
|
|
1063
|
+
)
|
|
1064
|
+
] })
|
|
1065
|
+
] });
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1068
|
+
// src/components/breadcrumbs.tsx
|
|
1069
|
+
import React7 from "react";
|
|
1070
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1071
|
+
var Breadcrumbs = ({
|
|
1072
|
+
items,
|
|
1073
|
+
className = "",
|
|
1074
|
+
ariaLabel = "Breadcrumb",
|
|
1075
|
+
renderLink
|
|
1076
|
+
}) => {
|
|
1077
|
+
const linkClassName = "hover:text-primary-600 cursor-pointer inline-block";
|
|
1078
|
+
const renderItemLink = (href, label) => {
|
|
1079
|
+
if (renderLink) {
|
|
1080
|
+
return renderLink({ href, children: label, className: linkClassName });
|
|
1081
|
+
}
|
|
1082
|
+
return /* @__PURE__ */ jsx16("a", { href, className: linkClassName, children: label });
|
|
1083
|
+
};
|
|
1084
|
+
return /* @__PURE__ */ jsx16("nav", { className: `mb-4 text-sm text-text-secondary ${className}`, "aria-label": ariaLabel, children: items.map((item, index) => {
|
|
1085
|
+
const isLast = index === items.length - 1;
|
|
1086
|
+
return /* @__PURE__ */ jsxs12(React7.Fragment, { children: [
|
|
1087
|
+
item.href && !isLast ? renderItemLink(item.href, item.label) : /* @__PURE__ */ jsx16("span", { className: isLast ? "text-text-primary" : "", children: item.label }),
|
|
1088
|
+
!isLast && /* @__PURE__ */ jsx16("span", { className: "mx-2", children: "/" })
|
|
1089
|
+
] }, index);
|
|
1090
|
+
}) });
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
// src/components/table.tsx
|
|
1094
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1095
|
+
var Table = ({ children, className = "" }) => {
|
|
1096
|
+
return /* @__PURE__ */ jsx17("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsx17(
|
|
1097
|
+
"table",
|
|
1098
|
+
{
|
|
1099
|
+
className: `w-full divide-y divide-border-primary ${className}`,
|
|
1100
|
+
children
|
|
1101
|
+
}
|
|
1102
|
+
) });
|
|
1103
|
+
};
|
|
1104
|
+
var TableHeader = ({
|
|
1105
|
+
children,
|
|
1106
|
+
className = ""
|
|
1107
|
+
}) => {
|
|
1108
|
+
return /* @__PURE__ */ jsx17("thead", { className: `bg-background-tertiary ${className}`, children });
|
|
1109
|
+
};
|
|
1110
|
+
var TableBody = ({
|
|
1111
|
+
children,
|
|
1112
|
+
className = ""
|
|
1113
|
+
}) => {
|
|
1114
|
+
return /* @__PURE__ */ jsx17(
|
|
1115
|
+
"tbody",
|
|
1116
|
+
{
|
|
1117
|
+
className: `bg-background-secondary divide-y divide-border-primary ${className}`,
|
|
1118
|
+
children
|
|
1119
|
+
}
|
|
1120
|
+
);
|
|
1121
|
+
};
|
|
1122
|
+
var TableRow = ({
|
|
1123
|
+
children,
|
|
1124
|
+
className = "",
|
|
1125
|
+
onClick,
|
|
1126
|
+
...props
|
|
1127
|
+
}) => {
|
|
1128
|
+
return /* @__PURE__ */ jsx17(
|
|
1129
|
+
"tr",
|
|
1130
|
+
{
|
|
1131
|
+
className: `${onClick ? "cursor-pointer hover:bg-background-tertiary" : ""} ${className}`,
|
|
1132
|
+
onClick,
|
|
1133
|
+
...props,
|
|
1134
|
+
children
|
|
1135
|
+
}
|
|
1136
|
+
);
|
|
1137
|
+
};
|
|
1138
|
+
var TableHead = ({
|
|
1139
|
+
children,
|
|
1140
|
+
className = ""
|
|
1141
|
+
}) => {
|
|
1142
|
+
return /* @__PURE__ */ jsx17(
|
|
1143
|
+
"th",
|
|
1144
|
+
{
|
|
1145
|
+
className: `px-4 py-3 text-left text-xs font-medium text-text-secondary uppercase tracking-wider align-top ${className}`,
|
|
1146
|
+
children
|
|
1147
|
+
}
|
|
1148
|
+
);
|
|
1149
|
+
};
|
|
1150
|
+
var TableCell = ({
|
|
1151
|
+
children,
|
|
1152
|
+
className = "",
|
|
1153
|
+
onClick,
|
|
1154
|
+
colSpan
|
|
1155
|
+
}) => {
|
|
1156
|
+
return /* @__PURE__ */ jsx17(
|
|
1157
|
+
"td",
|
|
1158
|
+
{
|
|
1159
|
+
className: `px-4 py-4 text-sm text-text-primary align-top ${onClick ? "cursor-pointer" : ""} ${className}`,
|
|
1160
|
+
onClick,
|
|
1161
|
+
colSpan,
|
|
1162
|
+
children
|
|
1163
|
+
}
|
|
1164
|
+
);
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
// src/components/tabs.tsx
|
|
1168
|
+
import React8, { useState as useState3, useRef as useRef4 } from "react";
|
|
1169
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1170
|
+
var TabsContext = React8.createContext({
|
|
1171
|
+
value: "",
|
|
1172
|
+
onValueChange: () => {
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
var Tabs = ({
|
|
1176
|
+
children,
|
|
1177
|
+
defaultValue = "",
|
|
1178
|
+
value: controlledValue,
|
|
1179
|
+
onValueChange,
|
|
1180
|
+
className = ""
|
|
1181
|
+
}) => {
|
|
1182
|
+
const [internalValue, setInternalValue] = useState3(defaultValue);
|
|
1183
|
+
const isControlled = controlledValue !== void 0;
|
|
1184
|
+
const value = isControlled ? controlledValue : internalValue;
|
|
1185
|
+
const handleValueChange = (newValue) => {
|
|
1186
|
+
if (!isControlled) {
|
|
1187
|
+
setInternalValue(newValue);
|
|
1188
|
+
}
|
|
1189
|
+
onValueChange?.(newValue);
|
|
1190
|
+
};
|
|
1191
|
+
return /* @__PURE__ */ jsx18(TabsContext.Provider, { value: { value, onValueChange: handleValueChange }, children: /* @__PURE__ */ jsx18("div", { className, children }) });
|
|
1192
|
+
};
|
|
1193
|
+
var TabsList = ({
|
|
1194
|
+
children,
|
|
1195
|
+
className = ""
|
|
1196
|
+
}) => {
|
|
1197
|
+
return /* @__PURE__ */ jsx18(
|
|
1198
|
+
"div",
|
|
1199
|
+
{
|
|
1200
|
+
className: `flex ${className}`,
|
|
1201
|
+
role: "tablist",
|
|
1202
|
+
children
|
|
1203
|
+
}
|
|
1204
|
+
);
|
|
1205
|
+
};
|
|
1206
|
+
var TabsTrigger = ({
|
|
1207
|
+
value,
|
|
1208
|
+
children,
|
|
1209
|
+
className = ""
|
|
1210
|
+
}) => {
|
|
1211
|
+
const context = React8.useContext(TabsContext);
|
|
1212
|
+
const isActive = context.value === value;
|
|
1213
|
+
const buttonRef = useRef4(null);
|
|
1214
|
+
const handleClick = () => {
|
|
1215
|
+
context.onValueChange(value);
|
|
1216
|
+
};
|
|
1217
|
+
const handleKeyDown = (e) => {
|
|
1218
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1219
|
+
e.preventDefault();
|
|
1220
|
+
context.onValueChange(value);
|
|
1221
|
+
}
|
|
1222
|
+
};
|
|
1223
|
+
return /* @__PURE__ */ jsx18(
|
|
1224
|
+
"button",
|
|
1225
|
+
{
|
|
1226
|
+
ref: buttonRef,
|
|
1227
|
+
role: "tab",
|
|
1228
|
+
"aria-selected": isActive,
|
|
1229
|
+
"aria-controls": `tab-content-${value}`,
|
|
1230
|
+
id: `tab-trigger-${value}`,
|
|
1231
|
+
onClick: handleClick,
|
|
1232
|
+
onKeyDown: handleKeyDown,
|
|
1233
|
+
className: `
|
|
1234
|
+
px-4 py-2 text-sm font-medium transition-colors duration-150
|
|
1235
|
+
border-b-2 -mb-px
|
|
1236
|
+
focus:outline-none
|
|
1237
|
+
cursor-pointer
|
|
1238
|
+
${isActive ? "border-primary-600 text-primary-600" : "border-transparent text-text-secondary hover:text-text-primary hover:border-border-secondary"}
|
|
1239
|
+
${className}
|
|
1240
|
+
`,
|
|
1241
|
+
children
|
|
1242
|
+
}
|
|
1243
|
+
);
|
|
1244
|
+
};
|
|
1245
|
+
var TabsContent = ({
|
|
1246
|
+
value,
|
|
1247
|
+
children,
|
|
1248
|
+
className = ""
|
|
1249
|
+
}) => {
|
|
1250
|
+
const context = React8.useContext(TabsContext);
|
|
1251
|
+
const isActive = context.value === value;
|
|
1252
|
+
if (!isActive) {
|
|
1253
|
+
return null;
|
|
1254
|
+
}
|
|
1255
|
+
return /* @__PURE__ */ jsx18(
|
|
1256
|
+
"div",
|
|
1257
|
+
{
|
|
1258
|
+
role: "tabpanel",
|
|
1259
|
+
id: `tab-content-${value}`,
|
|
1260
|
+
"aria-labelledby": `tab-trigger-${value}`,
|
|
1261
|
+
className: `mt-6 ${className}`,
|
|
1262
|
+
children
|
|
1263
|
+
}
|
|
1264
|
+
);
|
|
1265
|
+
};
|
|
1266
|
+
|
|
1267
|
+
// src/components/avatar.tsx
|
|
1268
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
1269
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1270
|
+
var Avatar = ({ className, ref, ...props }) => /* @__PURE__ */ jsx19(
|
|
1271
|
+
AvatarPrimitive.Root,
|
|
1272
|
+
{
|
|
1273
|
+
ref,
|
|
1274
|
+
className: cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className),
|
|
1275
|
+
...props
|
|
1276
|
+
}
|
|
1277
|
+
);
|
|
1278
|
+
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
|
1279
|
+
var AvatarImage = ({ className, ref, ...props }) => /* @__PURE__ */ jsx19(
|
|
1280
|
+
AvatarPrimitive.Image,
|
|
1281
|
+
{
|
|
1282
|
+
ref,
|
|
1283
|
+
className: cn("aspect-square h-full w-full", className),
|
|
1284
|
+
...props
|
|
1285
|
+
}
|
|
1286
|
+
);
|
|
1287
|
+
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
|
1288
|
+
var AvatarFallback = ({ className, ref, ...props }) => /* @__PURE__ */ jsx19(
|
|
1289
|
+
AvatarPrimitive.Fallback,
|
|
1290
|
+
{
|
|
1291
|
+
ref,
|
|
1292
|
+
className: cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className),
|
|
1293
|
+
...props
|
|
1294
|
+
}
|
|
1295
|
+
);
|
|
1296
|
+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
|
1297
|
+
|
|
1298
|
+
// src/components/dropdown-menu.tsx
|
|
1299
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
1300
|
+
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
1301
|
+
import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1302
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
1303
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
1304
|
+
var DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
1305
|
+
var DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
1306
|
+
var DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
1307
|
+
var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
1308
|
+
var DropdownMenuSubTrigger = ({ className, inset, children, ref, ...props }) => /* @__PURE__ */ jsxs13(
|
|
1309
|
+
DropdownMenuPrimitive.SubTrigger,
|
|
1310
|
+
{
|
|
1311
|
+
ref,
|
|
1312
|
+
className: cn(
|
|
1313
|
+
"flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
1314
|
+
inset && "pl-8",
|
|
1315
|
+
className
|
|
1316
|
+
),
|
|
1317
|
+
...props,
|
|
1318
|
+
children: [
|
|
1319
|
+
children,
|
|
1320
|
+
/* @__PURE__ */ jsx20(ChevronRight, { className: "ml-auto" })
|
|
1321
|
+
]
|
|
1322
|
+
}
|
|
1323
|
+
);
|
|
1324
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
1325
|
+
var DropdownMenuSubContent = ({ className, ref, ...props }) => /* @__PURE__ */ jsx20(
|
|
1326
|
+
DropdownMenuPrimitive.SubContent,
|
|
1327
|
+
{
|
|
1328
|
+
ref,
|
|
1329
|
+
className: cn(
|
|
1330
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
1331
|
+
className
|
|
1332
|
+
),
|
|
1333
|
+
...props
|
|
1334
|
+
}
|
|
1335
|
+
);
|
|
1336
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
1337
|
+
var DropdownMenuContent = ({ className, sideOffset = 4, ref, ...props }) => /* @__PURE__ */ jsx20(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx20(
|
|
1338
|
+
DropdownMenuPrimitive.Content,
|
|
1339
|
+
{
|
|
1340
|
+
ref,
|
|
1341
|
+
sideOffset,
|
|
1342
|
+
className: cn(
|
|
1343
|
+
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
|
|
1344
|
+
"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 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
1345
|
+
className
|
|
1346
|
+
),
|
|
1347
|
+
...props
|
|
1348
|
+
}
|
|
1349
|
+
) });
|
|
1350
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
1351
|
+
var DropdownMenuItem = ({ className, inset, ref, ...props }) => /* @__PURE__ */ jsx20(
|
|
1352
|
+
DropdownMenuPrimitive.Item,
|
|
1353
|
+
{
|
|
1354
|
+
ref,
|
|
1355
|
+
className: cn(
|
|
1356
|
+
"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
1357
|
+
inset && "pl-8",
|
|
1358
|
+
className
|
|
1359
|
+
),
|
|
1360
|
+
...props
|
|
1361
|
+
}
|
|
1362
|
+
);
|
|
1363
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
1364
|
+
var DropdownMenuCheckboxItem = ({ className, children, checked, ref, ...props }) => /* @__PURE__ */ jsxs13(
|
|
1365
|
+
DropdownMenuPrimitive.CheckboxItem,
|
|
1366
|
+
{
|
|
1367
|
+
ref,
|
|
1368
|
+
className: cn(
|
|
1369
|
+
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
1370
|
+
className
|
|
1371
|
+
),
|
|
1372
|
+
checked,
|
|
1373
|
+
...props,
|
|
1374
|
+
children: [
|
|
1375
|
+
/* @__PURE__ */ jsx20("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx20(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx20(Check, { className: "h-4 w-4" }) }) }),
|
|
1376
|
+
children
|
|
1377
|
+
]
|
|
1378
|
+
}
|
|
1379
|
+
);
|
|
1380
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
1381
|
+
var DropdownMenuRadioItem = ({ className, children, ref, ...props }) => /* @__PURE__ */ jsxs13(
|
|
1382
|
+
DropdownMenuPrimitive.RadioItem,
|
|
1383
|
+
{
|
|
1384
|
+
ref,
|
|
1385
|
+
className: cn(
|
|
1386
|
+
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
1387
|
+
className
|
|
1388
|
+
),
|
|
1389
|
+
...props,
|
|
1390
|
+
children: [
|
|
1391
|
+
/* @__PURE__ */ jsx20("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx20(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx20(Circle, { className: "h-2 w-2 fill-current" }) }) }),
|
|
1392
|
+
children
|
|
1393
|
+
]
|
|
1394
|
+
}
|
|
1395
|
+
);
|
|
1396
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
1397
|
+
var DropdownMenuLabel = ({ className, inset, ref, ...props }) => /* @__PURE__ */ jsx20(
|
|
1398
|
+
DropdownMenuPrimitive.Label,
|
|
1399
|
+
{
|
|
1400
|
+
ref,
|
|
1401
|
+
className: cn(
|
|
1402
|
+
"px-2 py-1.5 text-sm font-semibold",
|
|
1403
|
+
inset && "pl-8",
|
|
1404
|
+
className
|
|
1405
|
+
),
|
|
1406
|
+
...props
|
|
1407
|
+
}
|
|
1408
|
+
);
|
|
1409
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
1410
|
+
var DropdownMenuSeparator = ({ className, ref, ...props }) => /* @__PURE__ */ jsx20(
|
|
1411
|
+
DropdownMenuPrimitive.Separator,
|
|
1412
|
+
{
|
|
1413
|
+
ref,
|
|
1414
|
+
className: cn("-mx-1 my-1 h-px bg-muted", className),
|
|
1415
|
+
...props
|
|
1416
|
+
}
|
|
1417
|
+
);
|
|
1418
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
1419
|
+
var DropdownMenuShortcut = ({
|
|
1420
|
+
className,
|
|
1421
|
+
...props
|
|
1422
|
+
}) => {
|
|
1423
|
+
return /* @__PURE__ */ jsx20(
|
|
1424
|
+
"span",
|
|
1425
|
+
{
|
|
1426
|
+
className: cn("ml-auto text-xs tracking-widest opacity-60", className),
|
|
1427
|
+
...props
|
|
1428
|
+
}
|
|
1429
|
+
);
|
|
1430
|
+
};
|
|
1431
|
+
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
1432
|
+
|
|
1433
|
+
// src/components/collapsible.tsx
|
|
1434
|
+
import { useState as useState4, useEffect as useEffect4, useRef as useRef5, useCallback as useCallback3 } from "react";
|
|
1435
|
+
import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1436
|
+
function Collapsible({
|
|
1437
|
+
defaultOpen = false,
|
|
1438
|
+
open: controlledOpen,
|
|
1439
|
+
onOpenChange,
|
|
1440
|
+
trigger,
|
|
1441
|
+
children,
|
|
1442
|
+
className = "",
|
|
1443
|
+
storageKey,
|
|
1444
|
+
disabled = false
|
|
1445
|
+
}) {
|
|
1446
|
+
const isControlled = controlledOpen !== void 0;
|
|
1447
|
+
const [internalOpen, setInternalOpen] = useState4(() => {
|
|
1448
|
+
if (storageKey && typeof window !== "undefined") {
|
|
1449
|
+
const stored = localStorage.getItem(`collapsible-${storageKey}`);
|
|
1450
|
+
if (stored !== null) {
|
|
1451
|
+
return stored === "true";
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
return defaultOpen;
|
|
1455
|
+
});
|
|
1456
|
+
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
1457
|
+
const contentRef = useRef5(null);
|
|
1458
|
+
const [contentHeight, setContentHeight] = useState4(void 0);
|
|
1459
|
+
useEffect4(() => {
|
|
1460
|
+
if (contentRef.current) {
|
|
1461
|
+
setContentHeight(contentRef.current.scrollHeight);
|
|
1462
|
+
}
|
|
1463
|
+
}, [children, isOpen]);
|
|
1464
|
+
useEffect4(() => {
|
|
1465
|
+
if (storageKey && !isControlled) {
|
|
1466
|
+
localStorage.setItem(`collapsible-${storageKey}`, String(internalOpen));
|
|
1467
|
+
}
|
|
1468
|
+
}, [storageKey, internalOpen, isControlled]);
|
|
1469
|
+
const handleToggle = useCallback3(() => {
|
|
1470
|
+
if (disabled) return;
|
|
1471
|
+
const newState = !isOpen;
|
|
1472
|
+
if (!isControlled) {
|
|
1473
|
+
setInternalOpen(newState);
|
|
1474
|
+
}
|
|
1475
|
+
onOpenChange?.(newState);
|
|
1476
|
+
}, [disabled, isOpen, isControlled, onOpenChange]);
|
|
1477
|
+
return /* @__PURE__ */ jsxs14("div", { className, children: [
|
|
1478
|
+
/* @__PURE__ */ jsx21(
|
|
1479
|
+
"div",
|
|
1480
|
+
{
|
|
1481
|
+
onClick: handleToggle,
|
|
1482
|
+
onKeyDown: (e) => {
|
|
1483
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1484
|
+
e.preventDefault();
|
|
1485
|
+
handleToggle();
|
|
1486
|
+
}
|
|
1487
|
+
},
|
|
1488
|
+
role: "button",
|
|
1489
|
+
tabIndex: disabled ? -1 : 0,
|
|
1490
|
+
"aria-expanded": isOpen,
|
|
1491
|
+
"aria-disabled": disabled,
|
|
1492
|
+
className: disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer",
|
|
1493
|
+
children: trigger
|
|
1494
|
+
}
|
|
1495
|
+
),
|
|
1496
|
+
/* @__PURE__ */ jsx21(
|
|
1497
|
+
"div",
|
|
1498
|
+
{
|
|
1499
|
+
ref: contentRef,
|
|
1500
|
+
className: "overflow-hidden transition-all duration-300 ease-in-out",
|
|
1501
|
+
style: {
|
|
1502
|
+
maxHeight: isOpen ? contentHeight : 0,
|
|
1503
|
+
opacity: isOpen ? 1 : 0
|
|
1504
|
+
},
|
|
1505
|
+
"aria-hidden": !isOpen,
|
|
1506
|
+
children
|
|
1507
|
+
}
|
|
1508
|
+
)
|
|
1509
|
+
] });
|
|
1510
|
+
}
|
|
1511
|
+
function CollapsibleTrigger({
|
|
1512
|
+
title,
|
|
1513
|
+
subtitle,
|
|
1514
|
+
isOpen,
|
|
1515
|
+
className = "",
|
|
1516
|
+
icon
|
|
1517
|
+
}) {
|
|
1518
|
+
return /* @__PURE__ */ jsxs14(
|
|
1519
|
+
"div",
|
|
1520
|
+
{
|
|
1521
|
+
className: `flex items-center justify-between p-4 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors ${className}`,
|
|
1522
|
+
children: [
|
|
1523
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex-1 min-w-0", children: [
|
|
1524
|
+
/* @__PURE__ */ jsx21("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: title }),
|
|
1525
|
+
subtitle && /* @__PURE__ */ jsx21("p", { className: "text-sm text-gray-500 dark:text-gray-400 truncate", children: subtitle })
|
|
1526
|
+
] }),
|
|
1527
|
+
/* @__PURE__ */ jsx21("div", { className: "ml-4 flex-shrink-0", children: icon || /* @__PURE__ */ jsx21(
|
|
1528
|
+
"svg",
|
|
1529
|
+
{
|
|
1530
|
+
className: `w-5 h-5 text-gray-400 transition-transform duration-300 ${isOpen ? "rotate-180" : ""}`,
|
|
1531
|
+
fill: "none",
|
|
1532
|
+
stroke: "currentColor",
|
|
1533
|
+
viewBox: "0 0 24 24",
|
|
1534
|
+
children: /* @__PURE__ */ jsx21(
|
|
1535
|
+
"path",
|
|
1536
|
+
{
|
|
1537
|
+
strokeLinecap: "round",
|
|
1538
|
+
strokeLinejoin: "round",
|
|
1539
|
+
strokeWidth: 2,
|
|
1540
|
+
d: "M19 9l-7 7-7-7"
|
|
1541
|
+
}
|
|
1542
|
+
)
|
|
1543
|
+
}
|
|
1544
|
+
) })
|
|
1545
|
+
]
|
|
1546
|
+
}
|
|
1547
|
+
);
|
|
1548
|
+
}
|
|
1549
|
+
var bannerVariantClasses = {
|
|
1550
|
+
info: "bg-gradient-to-r from-primary-50 to-blue-50 dark:from-primary-900/20 dark:to-blue-900/20 border-primary-200 dark:border-primary-700",
|
|
1551
|
+
success: "bg-gradient-to-r from-primary-50 to-primary-100 dark:from-primary-900/20 dark:to-primary-800/20 border-primary-200 dark:border-primary-700",
|
|
1552
|
+
warning: "bg-gradient-to-r from-yellow-50 to-amber-50 dark:from-yellow-900/20 dark:to-amber-900/20 border-yellow-200 dark:border-yellow-700",
|
|
1553
|
+
neutral: "bg-gradient-to-r from-gray-50 to-slate-50 dark:from-gray-800 dark:to-slate-800 border-gray-200 dark:border-gray-700",
|
|
1554
|
+
hero: "bg-gradient-to-r from-accent-50 to-accent-100 dark:from-accent-800 dark:to-accent-900 border-accent-200 dark:border-accent-600"
|
|
1555
|
+
};
|
|
1556
|
+
function DismissibleBanner({
|
|
1557
|
+
storageKey,
|
|
1558
|
+
children,
|
|
1559
|
+
dismissText = "Got it",
|
|
1560
|
+
onDismiss,
|
|
1561
|
+
className = "",
|
|
1562
|
+
variant = "info"
|
|
1563
|
+
}) {
|
|
1564
|
+
const [isDismissed, setIsDismissed] = useState4(() => {
|
|
1565
|
+
if (typeof window !== "undefined") {
|
|
1566
|
+
return localStorage.getItem(`banner-${storageKey}-dismissed`) === "true";
|
|
1567
|
+
}
|
|
1568
|
+
return false;
|
|
1569
|
+
});
|
|
1570
|
+
const [isAnimatingOut, setIsAnimatingOut] = useState4(false);
|
|
1571
|
+
const handleDismiss = useCallback3(() => {
|
|
1572
|
+
setIsAnimatingOut(true);
|
|
1573
|
+
setTimeout(() => {
|
|
1574
|
+
setIsDismissed(true);
|
|
1575
|
+
localStorage.setItem(`banner-${storageKey}-dismissed`, "true");
|
|
1576
|
+
onDismiss?.();
|
|
1577
|
+
}, 300);
|
|
1578
|
+
}, [storageKey, onDismiss]);
|
|
1579
|
+
if (isDismissed) {
|
|
1580
|
+
return null;
|
|
1581
|
+
}
|
|
1582
|
+
return /* @__PURE__ */ jsx21(
|
|
1583
|
+
"div",
|
|
1584
|
+
{
|
|
1585
|
+
className: `
|
|
1586
|
+
border rounded-lg p-6 shadow-sm
|
|
1587
|
+
transition-all duration-300 ease-out
|
|
1588
|
+
${isAnimatingOut ? "opacity-0 -translate-y-4 h-0 p-0 overflow-hidden" : "opacity-100 translate-y-0"}
|
|
1589
|
+
${bannerVariantClasses[variant]}
|
|
1590
|
+
${className}
|
|
1591
|
+
`,
|
|
1592
|
+
children: /* @__PURE__ */ jsxs14("div", { className: "flex flex-col", children: [
|
|
1593
|
+
/* @__PURE__ */ jsx21("div", { className: "flex-1", children }),
|
|
1594
|
+
/* @__PURE__ */ jsx21("div", { className: "flex justify-end mt-4", children: /* @__PURE__ */ jsx21(
|
|
1595
|
+
"button",
|
|
1596
|
+
{
|
|
1597
|
+
onClick: handleDismiss,
|
|
1598
|
+
className: `px-4 py-2 text-sm font-medium text-white rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors cursor-pointer ${variant === "hero" ? "bg-accent-600 hover:bg-accent-700 focus:ring-accent-500" : "bg-primary-600 hover:bg-primary-700 focus:ring-primary-500"}`,
|
|
1599
|
+
children: dismissText
|
|
1600
|
+
}
|
|
1601
|
+
) })
|
|
1602
|
+
] })
|
|
1603
|
+
}
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
function useCollapsible(options = {}) {
|
|
1607
|
+
const { defaultOpen = false, storageKey } = options;
|
|
1608
|
+
const [isOpen, setIsOpen] = useState4(() => {
|
|
1609
|
+
if (storageKey && typeof window !== "undefined") {
|
|
1610
|
+
const stored = localStorage.getItem(`collapsible-${storageKey}`);
|
|
1611
|
+
if (stored !== null) {
|
|
1612
|
+
return stored === "true";
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
return defaultOpen;
|
|
1616
|
+
});
|
|
1617
|
+
useEffect4(() => {
|
|
1618
|
+
if (storageKey) {
|
|
1619
|
+
localStorage.setItem(`collapsible-${storageKey}`, String(isOpen));
|
|
1620
|
+
}
|
|
1621
|
+
}, [storageKey, isOpen]);
|
|
1622
|
+
const toggle = useCallback3(() => {
|
|
1623
|
+
setIsOpen((prev) => !prev);
|
|
1624
|
+
}, []);
|
|
1625
|
+
const open = useCallback3(() => {
|
|
1626
|
+
setIsOpen(true);
|
|
1627
|
+
}, []);
|
|
1628
|
+
const close = useCallback3(() => {
|
|
1629
|
+
setIsOpen(false);
|
|
1630
|
+
}, []);
|
|
1631
|
+
return {
|
|
1632
|
+
isOpen,
|
|
1633
|
+
toggle,
|
|
1634
|
+
open,
|
|
1635
|
+
close,
|
|
1636
|
+
setIsOpen
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
export {
|
|
1640
|
+
Avatar,
|
|
1641
|
+
AvatarFallback,
|
|
1642
|
+
AvatarImage,
|
|
1643
|
+
Badge,
|
|
1644
|
+
Breadcrumbs,
|
|
1645
|
+
Button,
|
|
1646
|
+
Card,
|
|
1647
|
+
CardBody,
|
|
1648
|
+
CardFooter,
|
|
1649
|
+
CardHeader,
|
|
1650
|
+
Checkbox,
|
|
1651
|
+
Collapsible,
|
|
1652
|
+
CollapsibleTrigger,
|
|
1653
|
+
ConfirmDialog,
|
|
1654
|
+
Dialog,
|
|
1655
|
+
DialogClose,
|
|
1656
|
+
DialogContent,
|
|
1657
|
+
DialogDescription,
|
|
1658
|
+
DialogFooter,
|
|
1659
|
+
DialogHeader,
|
|
1660
|
+
DialogOverlay,
|
|
1661
|
+
DialogPortal,
|
|
1662
|
+
DialogTitle,
|
|
1663
|
+
DialogTrigger,
|
|
1664
|
+
DismissibleBanner,
|
|
1665
|
+
DropdownMenu,
|
|
1666
|
+
DropdownMenuCheckboxItem,
|
|
1667
|
+
DropdownMenuContent,
|
|
1668
|
+
DropdownMenuGroup,
|
|
1669
|
+
DropdownMenuItem,
|
|
1670
|
+
DropdownMenuLabel,
|
|
1671
|
+
DropdownMenuPortal,
|
|
1672
|
+
DropdownMenuRadioGroup,
|
|
1673
|
+
DropdownMenuRadioItem,
|
|
1674
|
+
DropdownMenuSeparator,
|
|
1675
|
+
DropdownMenuShortcut,
|
|
1676
|
+
DropdownMenuSub,
|
|
1677
|
+
DropdownMenuSubContent,
|
|
1678
|
+
DropdownMenuSubTrigger,
|
|
1679
|
+
DropdownMenuTrigger,
|
|
1680
|
+
EmptyState,
|
|
1681
|
+
EntityForm,
|
|
1682
|
+
FormField,
|
|
1683
|
+
FormSlideOver,
|
|
1684
|
+
Input,
|
|
1685
|
+
LoadingScreen,
|
|
1686
|
+
LoadingSpinner,
|
|
1687
|
+
SearchBar,
|
|
1688
|
+
SearchInput,
|
|
1689
|
+
Select,
|
|
1690
|
+
SlideOver,
|
|
1691
|
+
Table,
|
|
1692
|
+
TableBody,
|
|
1693
|
+
TableCell,
|
|
1694
|
+
TableHead,
|
|
1695
|
+
TableHeader,
|
|
1696
|
+
TableRow,
|
|
1697
|
+
Tabs,
|
|
1698
|
+
TabsContent,
|
|
1699
|
+
TabsList,
|
|
1700
|
+
TabsTrigger,
|
|
1701
|
+
Textarea,
|
|
1702
|
+
cn,
|
|
1703
|
+
useCollapsible
|
|
1704
|
+
};
|
|
1705
|
+
//# sourceMappingURL=index.js.map
|