@crimson_/altarev 1.1.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/LICENSE +21 -0
- package/README.md +155 -0
- package/dist/index.cjs +3011 -0
- package/dist/index.d.cts +527 -0
- package/dist/index.d.ts +527 -0
- package/dist/index.js +2951 -0
- package/dist/styles.css +2 -0
- package/llms.txt +132 -0
- package/package.json +87 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3011 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var clsx = require('clsx');
|
|
5
|
+
var tailwindMerge = require('tailwind-merge');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
8
|
+
var react = require('react');
|
|
9
|
+
var reactDom = require('react-dom');
|
|
10
|
+
var reactDayPicker = require('react-day-picker');
|
|
11
|
+
|
|
12
|
+
// src/lib/cn.ts
|
|
13
|
+
function cn(...inputs) {
|
|
14
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
15
|
+
}
|
|
16
|
+
function Container({ className, ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18
|
+
"div",
|
|
19
|
+
{
|
|
20
|
+
className: cn(
|
|
21
|
+
"mx-auto w-full max-w-container px-4 md:px-6 lg:px-8",
|
|
22
|
+
className
|
|
23
|
+
),
|
|
24
|
+
...props
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
var accordion = classVarianceAuthority.cva(
|
|
29
|
+
"group rounded-[8px] bg-surface text-text border border-border [&[open]>summary>svg]:rotate-180",
|
|
30
|
+
{
|
|
31
|
+
variants: {
|
|
32
|
+
size: {
|
|
33
|
+
sm: "text-xs",
|
|
34
|
+
md: "text-sm",
|
|
35
|
+
lg: "text-sm",
|
|
36
|
+
xl: "text-md"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
defaultVariants: { size: "md" }
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
var PAD = { sm: "p-2", md: "px-3 py-2", lg: "p-3", xl: "p-4" };
|
|
43
|
+
var summary = classVarianceAuthority.cva(
|
|
44
|
+
"flex cursor-pointer list-none items-center gap-2 font-bold marker:hidden outline-none focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2",
|
|
45
|
+
{
|
|
46
|
+
variants: { size: PAD },
|
|
47
|
+
defaultVariants: { size: "md" }
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
function Accordion({
|
|
51
|
+
size = "md",
|
|
52
|
+
title,
|
|
53
|
+
leading,
|
|
54
|
+
children,
|
|
55
|
+
className,
|
|
56
|
+
...props
|
|
57
|
+
}) {
|
|
58
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("details", { className: cn(accordion({ size }), className), ...props, children: [
|
|
59
|
+
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: summary({ size }), children: [
|
|
60
|
+
leading,
|
|
61
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: title }),
|
|
62
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronDown, {})
|
|
63
|
+
] }),
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border" }),
|
|
65
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: PAD[size ?? "md"], children })
|
|
66
|
+
] });
|
|
67
|
+
}
|
|
68
|
+
function ChevronDown() {
|
|
69
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
70
|
+
"svg",
|
|
71
|
+
{
|
|
72
|
+
className: "size-6 shrink-0 transition-transform duration-200 ease-in-out",
|
|
73
|
+
viewBox: "0 0 24 24",
|
|
74
|
+
fill: "none",
|
|
75
|
+
stroke: "currentColor",
|
|
76
|
+
strokeWidth: "2",
|
|
77
|
+
strokeLinecap: "round",
|
|
78
|
+
strokeLinejoin: "round",
|
|
79
|
+
"aria-hidden": true,
|
|
80
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
var alert = classVarianceAuthority.cva(
|
|
85
|
+
"flex items-center gap-3 rounded-[8px] p-4 text-sm [&>svg]:size-6 [&>svg]:shrink-0",
|
|
86
|
+
{
|
|
87
|
+
variants: {
|
|
88
|
+
status: {
|
|
89
|
+
success: "",
|
|
90
|
+
error: "",
|
|
91
|
+
warning: "",
|
|
92
|
+
info: ""
|
|
93
|
+
},
|
|
94
|
+
styleVariant: {
|
|
95
|
+
colourful: "",
|
|
96
|
+
outline: "border",
|
|
97
|
+
generic: "bg-surface text-text"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
compoundVariants: [
|
|
101
|
+
{
|
|
102
|
+
styleVariant: "colourful",
|
|
103
|
+
status: "success",
|
|
104
|
+
class: "bg-success-tint text-success"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
styleVariant: "colourful",
|
|
108
|
+
status: "error",
|
|
109
|
+
class: "bg-error-tint text-error"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
styleVariant: "colourful",
|
|
113
|
+
status: "warning",
|
|
114
|
+
class: "bg-warning-tint text-warning"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
styleVariant: "colourful",
|
|
118
|
+
status: "info",
|
|
119
|
+
class: "bg-info-tint text-info"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
styleVariant: "outline",
|
|
123
|
+
status: "success",
|
|
124
|
+
class: "border-success text-success"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
styleVariant: "outline",
|
|
128
|
+
status: "error",
|
|
129
|
+
class: "border-error text-error"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
styleVariant: "outline",
|
|
133
|
+
status: "warning",
|
|
134
|
+
class: "border-warning text-warning"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
styleVariant: "outline",
|
|
138
|
+
status: "info",
|
|
139
|
+
class: "border-info text-info"
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
defaultVariants: { status: "info", styleVariant: "generic" }
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
function Alert({
|
|
146
|
+
status = "info",
|
|
147
|
+
variant = "generic",
|
|
148
|
+
icon,
|
|
149
|
+
trailing,
|
|
150
|
+
children,
|
|
151
|
+
className,
|
|
152
|
+
...props
|
|
153
|
+
}) {
|
|
154
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
155
|
+
"div",
|
|
156
|
+
{
|
|
157
|
+
role: "alert",
|
|
158
|
+
className: cn(alert({ status, styleVariant: variant }), className),
|
|
159
|
+
...props,
|
|
160
|
+
children: [
|
|
161
|
+
icon,
|
|
162
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children }),
|
|
163
|
+
trailing
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
function EmptyState({
|
|
169
|
+
icon,
|
|
170
|
+
title,
|
|
171
|
+
description,
|
|
172
|
+
children,
|
|
173
|
+
className,
|
|
174
|
+
...props
|
|
175
|
+
}) {
|
|
176
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
177
|
+
"div",
|
|
178
|
+
{
|
|
179
|
+
className: cn(
|
|
180
|
+
"flex w-[374px] max-w-full flex-col items-center gap-2 px-4 text-center",
|
|
181
|
+
className
|
|
182
|
+
),
|
|
183
|
+
...props,
|
|
184
|
+
children: [
|
|
185
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-20 items-center justify-center [&_svg]:size-20", children: icon }),
|
|
186
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 pb-6 text-text", children: [
|
|
187
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-bold leading-8", children: title }),
|
|
188
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base leading-6 text-text", children: description })
|
|
189
|
+
] }),
|
|
190
|
+
children && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-center gap-3", children })
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
var avatar = classVarianceAuthority.cva(
|
|
196
|
+
"relative inline-flex shrink-0 items-center justify-center overflow-visible rounded-full bg-surface font-bold text-text select-none",
|
|
197
|
+
{
|
|
198
|
+
variants: {
|
|
199
|
+
size: {
|
|
200
|
+
xs: "size-6 text-2xs",
|
|
201
|
+
sm: "size-8 text-xs",
|
|
202
|
+
md: "size-10 text-sm",
|
|
203
|
+
lg: "size-12 text-md",
|
|
204
|
+
xl: "size-14 text-md",
|
|
205
|
+
"2xl": "size-16 text-xl"
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
defaultVariants: { size: "md" }
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
var badgeCorner = {
|
|
212
|
+
tr: "top-0 right-0",
|
|
213
|
+
tl: "top-0 left-0",
|
|
214
|
+
br: "bottom-0 right-0",
|
|
215
|
+
bl: "bottom-0 left-0"
|
|
216
|
+
};
|
|
217
|
+
var badgeSize = {
|
|
218
|
+
xs: "size-1 border-2",
|
|
219
|
+
sm: "size-2 border-2",
|
|
220
|
+
md: "size-2 border-2",
|
|
221
|
+
lg: "size-3 border-4",
|
|
222
|
+
xl: "size-3 border-4",
|
|
223
|
+
"2xl": "size-3 border-4"
|
|
224
|
+
};
|
|
225
|
+
function Avatar({
|
|
226
|
+
size = "md",
|
|
227
|
+
src,
|
|
228
|
+
alt = "",
|
|
229
|
+
children,
|
|
230
|
+
badge,
|
|
231
|
+
badgeColor = "bg-success",
|
|
232
|
+
className,
|
|
233
|
+
...props
|
|
234
|
+
}) {
|
|
235
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(avatar({ size }), className), ...props, children: [
|
|
236
|
+
src ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
237
|
+
"img",
|
|
238
|
+
{
|
|
239
|
+
src,
|
|
240
|
+
alt,
|
|
241
|
+
className: "absolute inset-0 size-full rounded-full object-cover"
|
|
242
|
+
}
|
|
243
|
+
) : children,
|
|
244
|
+
badge && /* @__PURE__ */ jsxRuntime.jsx(
|
|
245
|
+
"span",
|
|
246
|
+
{
|
|
247
|
+
className: cn(
|
|
248
|
+
"absolute rounded-full border-background",
|
|
249
|
+
badgeCorner[badge],
|
|
250
|
+
badgeSize[size ?? "md"],
|
|
251
|
+
badgeColor
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
] });
|
|
256
|
+
}
|
|
257
|
+
var cell = classVarianceAuthority.cva(
|
|
258
|
+
"size-14 w-12 rounded-[8px] border bg-surface text-center text-sm text-text outline-none transition-shadow focus:border-[1.5px] focus:border-primary focus:ring-2 focus:ring-primary-tint",
|
|
259
|
+
{
|
|
260
|
+
variants: {
|
|
261
|
+
error: {
|
|
262
|
+
true: "border-[1.5px] border-[var(--color-input-error)] text-[var(--color-input-error)] focus:border-[var(--color-input-error)] focus:ring-0",
|
|
263
|
+
false: "border-border"
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
defaultVariants: { error: false }
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
function splitCode(raw, length) {
|
|
270
|
+
const digits = raw.replace(/\D/g, "").slice(0, length).split("");
|
|
271
|
+
return Array.from({ length }, (_, i) => digits[i] ?? "");
|
|
272
|
+
}
|
|
273
|
+
function AuthCode({
|
|
274
|
+
value,
|
|
275
|
+
onChange,
|
|
276
|
+
length = 6,
|
|
277
|
+
error = false,
|
|
278
|
+
disabled,
|
|
279
|
+
className
|
|
280
|
+
}) {
|
|
281
|
+
const refs = react.useRef([]);
|
|
282
|
+
const cells = splitCode(value, length);
|
|
283
|
+
const hasError = Boolean(error);
|
|
284
|
+
const setCharAt = (index, char) => {
|
|
285
|
+
const next = cells.slice();
|
|
286
|
+
next[index] = char;
|
|
287
|
+
onChange(next.join(""));
|
|
288
|
+
};
|
|
289
|
+
const focusCell = (index) => {
|
|
290
|
+
const el = refs.current[Math.max(0, Math.min(index, length - 1))];
|
|
291
|
+
el?.focus();
|
|
292
|
+
el?.select();
|
|
293
|
+
};
|
|
294
|
+
const handleInput = (index, raw) => {
|
|
295
|
+
const char = raw.replace(/\D/g, "").slice(-1);
|
|
296
|
+
if (!char) return;
|
|
297
|
+
setCharAt(index, char);
|
|
298
|
+
if (index < length - 1) focusCell(index + 1);
|
|
299
|
+
};
|
|
300
|
+
const handleKeyDown = (index, e) => {
|
|
301
|
+
if (e.key === "Backspace") {
|
|
302
|
+
e.preventDefault();
|
|
303
|
+
if (cells[index]) {
|
|
304
|
+
setCharAt(index, "");
|
|
305
|
+
} else if (index > 0) {
|
|
306
|
+
setCharAt(index - 1, "");
|
|
307
|
+
focusCell(index - 1);
|
|
308
|
+
}
|
|
309
|
+
} else if (e.key === "ArrowLeft") {
|
|
310
|
+
focusCell(index - 1);
|
|
311
|
+
} else if (e.key === "ArrowRight") {
|
|
312
|
+
focusCell(index + 1);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
const handlePaste = (index, e) => {
|
|
316
|
+
e.preventDefault();
|
|
317
|
+
const pasted = e.clipboardData.getData("text").replace(/\D/g, "");
|
|
318
|
+
if (!pasted) return;
|
|
319
|
+
const next = cells.slice();
|
|
320
|
+
for (let i = 0; i < pasted.length && index + i < length; i++) {
|
|
321
|
+
next[index + i] = pasted[i];
|
|
322
|
+
}
|
|
323
|
+
onChange(next.join(""));
|
|
324
|
+
focusCell(index + pasted.length);
|
|
325
|
+
};
|
|
326
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
|
|
327
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2", children: cells.map((char, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
328
|
+
"input",
|
|
329
|
+
{
|
|
330
|
+
ref: (el) => {
|
|
331
|
+
refs.current[i] = el;
|
|
332
|
+
},
|
|
333
|
+
value: char,
|
|
334
|
+
disabled,
|
|
335
|
+
inputMode: "numeric",
|
|
336
|
+
autoComplete: "one-time-code",
|
|
337
|
+
"aria-label": `Digit ${i + 1}`,
|
|
338
|
+
"aria-invalid": hasError,
|
|
339
|
+
className: cn(cell({ error: hasError }), "disabled:opacity-50"),
|
|
340
|
+
onChange: (e) => handleInput(i, e.target.value),
|
|
341
|
+
onKeyDown: (e) => handleKeyDown(i, e),
|
|
342
|
+
onPaste: (e) => handlePaste(i, e),
|
|
343
|
+
onFocus: (e) => e.target.select()
|
|
344
|
+
},
|
|
345
|
+
i
|
|
346
|
+
)) }),
|
|
347
|
+
typeof error === "string" && error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 text-center text-xs text-[var(--color-input-error)]", children: error })
|
|
348
|
+
] });
|
|
349
|
+
}
|
|
350
|
+
function Popover({
|
|
351
|
+
trigger,
|
|
352
|
+
children,
|
|
353
|
+
open: controlledOpen,
|
|
354
|
+
onOpenChange,
|
|
355
|
+
align = "start",
|
|
356
|
+
className
|
|
357
|
+
}) {
|
|
358
|
+
const [uncontrolledOpen, setUncontrolledOpen] = react.useState(false);
|
|
359
|
+
const isControlled = controlledOpen !== void 0;
|
|
360
|
+
const open = isControlled ? controlledOpen : uncontrolledOpen;
|
|
361
|
+
const anchorRef = react.useRef(null);
|
|
362
|
+
const panelRef = react.useRef(null);
|
|
363
|
+
const id = react.useId();
|
|
364
|
+
const setOpen = (next) => {
|
|
365
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
366
|
+
onOpenChange?.(next);
|
|
367
|
+
};
|
|
368
|
+
react.useEffect(() => {
|
|
369
|
+
if (!open) return;
|
|
370
|
+
const onPointerDown = (e) => {
|
|
371
|
+
const target = e.target;
|
|
372
|
+
if (!anchorRef.current?.contains(target) && !panelRef.current?.contains(target)) {
|
|
373
|
+
setOpen(false);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
const onKeyDown = (e) => {
|
|
377
|
+
if (e.key === "Escape") setOpen(false);
|
|
378
|
+
};
|
|
379
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
380
|
+
document.addEventListener("keydown", onKeyDown);
|
|
381
|
+
return () => {
|
|
382
|
+
document.removeEventListener("pointerdown", onPointerDown);
|
|
383
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
const triggerEl = react.cloneElement(trigger, {
|
|
387
|
+
onClick: (e) => {
|
|
388
|
+
trigger.props.onClick?.(e);
|
|
389
|
+
setOpen(!open);
|
|
390
|
+
},
|
|
391
|
+
"aria-expanded": open,
|
|
392
|
+
"aria-haspopup": true
|
|
393
|
+
});
|
|
394
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: anchorRef, className: "relative inline-block w-full", children: [
|
|
395
|
+
triggerEl,
|
|
396
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
397
|
+
"div",
|
|
398
|
+
{
|
|
399
|
+
ref: panelRef,
|
|
400
|
+
id,
|
|
401
|
+
role: "listbox",
|
|
402
|
+
className: cn(
|
|
403
|
+
"absolute z-50 mt-1 min-w-full rounded-[12px] border border-border bg-surface p-1 shadow-lg",
|
|
404
|
+
align === "end" ? "right-0" : "left-0",
|
|
405
|
+
className
|
|
406
|
+
),
|
|
407
|
+
children
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
] });
|
|
411
|
+
}
|
|
412
|
+
var ELLIPSIS = /* @__PURE__ */ Symbol("ellipsis");
|
|
413
|
+
function collapseItems(items, maxItems) {
|
|
414
|
+
const indexed = items.map((item, index) => ({ item, index }));
|
|
415
|
+
if (!maxItems || items.length <= maxItems || items.length <= 2) {
|
|
416
|
+
return indexed;
|
|
417
|
+
}
|
|
418
|
+
const tail = Math.max(1, maxItems - 1);
|
|
419
|
+
return [indexed[0], ELLIPSIS, ...indexed.slice(items.length - tail)];
|
|
420
|
+
}
|
|
421
|
+
function ArrowSeparator() {
|
|
422
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
423
|
+
"svg",
|
|
424
|
+
{
|
|
425
|
+
className: "size-4 shrink-0 text-text-muted",
|
|
426
|
+
viewBox: "0 0 16 16",
|
|
427
|
+
fill: "none",
|
|
428
|
+
stroke: "currentColor",
|
|
429
|
+
strokeWidth: "1.5",
|
|
430
|
+
strokeLinecap: "round",
|
|
431
|
+
strokeLinejoin: "round",
|
|
432
|
+
"aria-hidden": true,
|
|
433
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 8h9M9 5l3 3-3 3" })
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
function Breadcrumbs({
|
|
438
|
+
items,
|
|
439
|
+
separator,
|
|
440
|
+
maxItems,
|
|
441
|
+
className,
|
|
442
|
+
...props
|
|
443
|
+
}) {
|
|
444
|
+
const sep = separator ?? /* @__PURE__ */ jsxRuntime.jsx(ArrowSeparator, {});
|
|
445
|
+
const slots = collapseItems(items, maxItems);
|
|
446
|
+
const hidden = slots.includes(ELLIPSIS) && maxItems ? items.slice(1, items.length - Math.max(1, maxItems - 1)) : [];
|
|
447
|
+
return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex items-center gap-2 text-sm", children: slots.map((slot, i) => {
|
|
448
|
+
const isLast = i === slots.length - 1;
|
|
449
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
450
|
+
/* @__PURE__ */ jsxRuntime.jsx("li", { className: "flex items-center", children: slot === ELLIPSIS ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
451
|
+
Popover,
|
|
452
|
+
{
|
|
453
|
+
align: "start",
|
|
454
|
+
trigger: /* @__PURE__ */ jsxRuntime.jsx(
|
|
455
|
+
"button",
|
|
456
|
+
{
|
|
457
|
+
type: "button",
|
|
458
|
+
"aria-label": "Show more",
|
|
459
|
+
className: "rounded-[4px] px-1 text-text-muted hover:text-text focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2",
|
|
460
|
+
children: "\u2026"
|
|
461
|
+
}
|
|
462
|
+
),
|
|
463
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "min-w-32", children: hidden.map((h, hi) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
464
|
+
"a",
|
|
465
|
+
{
|
|
466
|
+
href: h.href,
|
|
467
|
+
className: "block rounded-[8px] px-3 py-2 text-sm text-text hover:bg-hover",
|
|
468
|
+
children: h.label
|
|
469
|
+
}
|
|
470
|
+
) }, hi)) })
|
|
471
|
+
}
|
|
472
|
+
) : isLast || !slot.item.href ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
473
|
+
"span",
|
|
474
|
+
{
|
|
475
|
+
"aria-current": isLast ? "page" : void 0,
|
|
476
|
+
className: cn(
|
|
477
|
+
isLast ? "font-bold text-text" : "text-text-muted"
|
|
478
|
+
),
|
|
479
|
+
children: slot.item.label
|
|
480
|
+
}
|
|
481
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
482
|
+
"a",
|
|
483
|
+
{
|
|
484
|
+
href: slot.item.href,
|
|
485
|
+
className: "text-text-muted hover:text-text hover:underline",
|
|
486
|
+
children: slot.item.label
|
|
487
|
+
}
|
|
488
|
+
) }),
|
|
489
|
+
!isLast && /* @__PURE__ */ jsxRuntime.jsx("li", { "aria-hidden": true, className: "flex items-center text-text-muted", children: sep })
|
|
490
|
+
] }, i);
|
|
491
|
+
}) }) });
|
|
492
|
+
}
|
|
493
|
+
var buttonVariants = classVarianceAuthority.cva(
|
|
494
|
+
"inline-flex shrink-0 items-center justify-center gap-2 rounded-[8px] font-bold whitespace-nowrap transition-colors outline-none focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-95 hover:brightness-95",
|
|
495
|
+
{
|
|
496
|
+
variants: {
|
|
497
|
+
variant: {
|
|
498
|
+
fill: "",
|
|
499
|
+
outline: "border bg-transparent",
|
|
500
|
+
ghost: "bg-transparent",
|
|
501
|
+
text: "bg-transparent hover:underline hover:brightness-100"
|
|
502
|
+
},
|
|
503
|
+
color: {
|
|
504
|
+
primary: "",
|
|
505
|
+
success: "",
|
|
506
|
+
error: "",
|
|
507
|
+
warning: "",
|
|
508
|
+
info: ""
|
|
509
|
+
},
|
|
510
|
+
size: {
|
|
511
|
+
xs: "h-8 px-3 text-xs",
|
|
512
|
+
sm: "h-8 px-3 text-sm",
|
|
513
|
+
md: "h-10 px-4 text-sm",
|
|
514
|
+
lg: "h-12 px-5 text-md",
|
|
515
|
+
xl: "h-14 px-6 text-md"
|
|
516
|
+
},
|
|
517
|
+
iconOnly: {
|
|
518
|
+
true: "aspect-square p-0",
|
|
519
|
+
false: ""
|
|
520
|
+
},
|
|
521
|
+
fullWidth: {
|
|
522
|
+
true: "w-full",
|
|
523
|
+
false: ""
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
compoundVariants: [
|
|
527
|
+
{ variant: "fill", color: "primary", class: "bg-primary text-white" },
|
|
528
|
+
{ variant: "fill", color: "success", class: "bg-success text-white" },
|
|
529
|
+
{ variant: "fill", color: "error", class: "bg-error text-white" },
|
|
530
|
+
{ variant: "fill", color: "warning", class: "bg-warning text-text" },
|
|
531
|
+
{ variant: "fill", color: "info", class: "bg-info text-white" },
|
|
532
|
+
{
|
|
533
|
+
variant: "outline",
|
|
534
|
+
color: "primary",
|
|
535
|
+
class: "border-primary text-primary hover:bg-primary-tint"
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
variant: "outline",
|
|
539
|
+
color: "success",
|
|
540
|
+
class: "border-success text-success hover:bg-success-tint"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
variant: "outline",
|
|
544
|
+
color: "error",
|
|
545
|
+
class: "border-error text-error hover:bg-error-tint"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
variant: "outline",
|
|
549
|
+
color: "warning",
|
|
550
|
+
class: "border-warning text-warning hover:bg-warning-tint"
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
variant: "outline",
|
|
554
|
+
color: "info",
|
|
555
|
+
class: "border-info text-info hover:bg-info-tint"
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
variant: "ghost",
|
|
559
|
+
color: "primary",
|
|
560
|
+
class: "text-primary hover:bg-primary-tint"
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
variant: "ghost",
|
|
564
|
+
color: "success",
|
|
565
|
+
class: "text-success hover:bg-success-tint"
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
variant: "ghost",
|
|
569
|
+
color: "error",
|
|
570
|
+
class: "text-error hover:bg-error-tint"
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
variant: "ghost",
|
|
574
|
+
color: "warning",
|
|
575
|
+
class: "text-warning hover:bg-warning-tint"
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
variant: "ghost",
|
|
579
|
+
color: "info",
|
|
580
|
+
class: "text-info hover:bg-info-tint"
|
|
581
|
+
},
|
|
582
|
+
{ variant: "text", color: "primary", class: "text-primary" },
|
|
583
|
+
{ variant: "text", color: "success", class: "text-success" },
|
|
584
|
+
{ variant: "text", color: "error", class: "text-error" },
|
|
585
|
+
{ variant: "text", color: "warning", class: "text-warning" },
|
|
586
|
+
{ variant: "text", color: "info", class: "text-info" },
|
|
587
|
+
{ iconOnly: true, size: "xs", class: "size-8" },
|
|
588
|
+
{ iconOnly: true, size: "sm", class: "size-8" },
|
|
589
|
+
{ iconOnly: true, size: "md", class: "size-10" },
|
|
590
|
+
{ iconOnly: true, size: "lg", class: "size-12" },
|
|
591
|
+
{ iconOnly: true, size: "xl", class: "size-14" }
|
|
592
|
+
],
|
|
593
|
+
defaultVariants: {
|
|
594
|
+
variant: "fill",
|
|
595
|
+
color: "primary",
|
|
596
|
+
size: "md",
|
|
597
|
+
iconOnly: false,
|
|
598
|
+
fullWidth: false
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
);
|
|
602
|
+
function Button({
|
|
603
|
+
variant = "fill",
|
|
604
|
+
color = "primary",
|
|
605
|
+
size = "md",
|
|
606
|
+
fullWidth = false,
|
|
607
|
+
leftIcon,
|
|
608
|
+
rightIcon,
|
|
609
|
+
className,
|
|
610
|
+
children,
|
|
611
|
+
...props
|
|
612
|
+
}) {
|
|
613
|
+
const iconOnly = !children && Boolean(leftIcon ?? rightIcon);
|
|
614
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
615
|
+
"button",
|
|
616
|
+
{
|
|
617
|
+
className: cn(
|
|
618
|
+
buttonVariants({ variant, color, size, fullWidth, iconOnly }),
|
|
619
|
+
fullWidth && (leftIcon || rightIcon) && "justify-between",
|
|
620
|
+
className
|
|
621
|
+
),
|
|
622
|
+
...props,
|
|
623
|
+
children: [
|
|
624
|
+
leftIcon,
|
|
625
|
+
children,
|
|
626
|
+
rightIcon
|
|
627
|
+
]
|
|
628
|
+
}
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
function nextIndex(current, count, dir, loop) {
|
|
632
|
+
const n = current + dir;
|
|
633
|
+
if (n < 0) return loop ? count - 1 : 0;
|
|
634
|
+
if (n >= count) return loop ? 0 : count - 1;
|
|
635
|
+
return n;
|
|
636
|
+
}
|
|
637
|
+
function Carousel({
|
|
638
|
+
children,
|
|
639
|
+
title,
|
|
640
|
+
description,
|
|
641
|
+
seeAllHref,
|
|
642
|
+
arrows = true,
|
|
643
|
+
indicators = true,
|
|
644
|
+
autoSlide = false,
|
|
645
|
+
interval = 5e3,
|
|
646
|
+
loop = true,
|
|
647
|
+
gap = 16,
|
|
648
|
+
className,
|
|
649
|
+
...props
|
|
650
|
+
}) {
|
|
651
|
+
const trackRef = react.useRef(null);
|
|
652
|
+
const items = react.Children.toArray(children);
|
|
653
|
+
const count = items.length;
|
|
654
|
+
const [active, setActive] = react.useState(0);
|
|
655
|
+
const [progress, setProgress] = react.useState(0);
|
|
656
|
+
const scrollToIndex = react.useCallback((index) => {
|
|
657
|
+
const track2 = trackRef.current;
|
|
658
|
+
if (!track2) return;
|
|
659
|
+
const child = track2.children[index];
|
|
660
|
+
child?.scrollIntoView({
|
|
661
|
+
behavior: "smooth",
|
|
662
|
+
inline: "start",
|
|
663
|
+
block: "nearest"
|
|
664
|
+
});
|
|
665
|
+
}, []);
|
|
666
|
+
const go = react.useCallback(
|
|
667
|
+
(dir) => {
|
|
668
|
+
setActive((cur) => {
|
|
669
|
+
const target = nextIndex(cur, count, dir, loop);
|
|
670
|
+
scrollToIndex(target);
|
|
671
|
+
return target;
|
|
672
|
+
});
|
|
673
|
+
},
|
|
674
|
+
[count, loop, scrollToIndex]
|
|
675
|
+
);
|
|
676
|
+
react.useEffect(() => {
|
|
677
|
+
const track2 = trackRef.current;
|
|
678
|
+
if (!track2) return;
|
|
679
|
+
const observer = new IntersectionObserver(
|
|
680
|
+
(entries) => {
|
|
681
|
+
for (const entry of entries) {
|
|
682
|
+
if (entry.isIntersecting) {
|
|
683
|
+
const idx = Array.prototype.indexOf.call(
|
|
684
|
+
track2.children,
|
|
685
|
+
entry.target
|
|
686
|
+
);
|
|
687
|
+
if (idx >= 0) setActive(idx);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
{ root: track2, threshold: 0.6 }
|
|
692
|
+
);
|
|
693
|
+
for (const child of Array.from(track2.children)) observer.observe(child);
|
|
694
|
+
return () => observer.disconnect();
|
|
695
|
+
}, [count]);
|
|
696
|
+
react.useEffect(() => {
|
|
697
|
+
if (!autoSlide || count <= 1) return;
|
|
698
|
+
const step = 50;
|
|
699
|
+
let elapsed = 0;
|
|
700
|
+
const id = setInterval(() => {
|
|
701
|
+
elapsed += step;
|
|
702
|
+
setProgress(Math.min(1, elapsed / interval));
|
|
703
|
+
if (elapsed >= interval) {
|
|
704
|
+
elapsed = 0;
|
|
705
|
+
go(1);
|
|
706
|
+
}
|
|
707
|
+
}, step);
|
|
708
|
+
return () => clearInterval(id);
|
|
709
|
+
}, [autoSlide, interval, count, active, go]);
|
|
710
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-4", className), ...props, children: [
|
|
711
|
+
(title || description || seeAllHref || arrows) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end justify-between gap-4", children: [
|
|
712
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
713
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-bold text-text", children: title }),
|
|
714
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-text-muted", children: description })
|
|
715
|
+
] }),
|
|
716
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
717
|
+
seeAllHref && /* @__PURE__ */ jsxRuntime.jsx(
|
|
718
|
+
"a",
|
|
719
|
+
{
|
|
720
|
+
href: seeAllHref,
|
|
721
|
+
className: "text-sm font-bold text-primary hover:underline",
|
|
722
|
+
children: "See all"
|
|
723
|
+
}
|
|
724
|
+
),
|
|
725
|
+
arrows && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
726
|
+
/* @__PURE__ */ jsxRuntime.jsx(ArrowButton, { dir: "prev", onClick: () => go(-1) }),
|
|
727
|
+
/* @__PURE__ */ jsxRuntime.jsx(ArrowButton, { dir: "next", onClick: () => go(1) })
|
|
728
|
+
] })
|
|
729
|
+
] })
|
|
730
|
+
] }),
|
|
731
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
732
|
+
"div",
|
|
733
|
+
{
|
|
734
|
+
ref: trackRef,
|
|
735
|
+
className: "flex snap-x snap-mandatory overflow-x-auto scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
736
|
+
style: { gap },
|
|
737
|
+
children: items.map((child, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 snap-start", children: child }, i))
|
|
738
|
+
}
|
|
739
|
+
),
|
|
740
|
+
indicators && count > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center gap-2", children: items.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
741
|
+
"button",
|
|
742
|
+
{
|
|
743
|
+
"aria-label": `Go to slide ${i + 1}`,
|
|
744
|
+
"aria-current": i === active,
|
|
745
|
+
onClick: () => {
|
|
746
|
+
setActive(i);
|
|
747
|
+
scrollToIndex(i);
|
|
748
|
+
},
|
|
749
|
+
className: "relative size-2 overflow-hidden rounded-full bg-border",
|
|
750
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
751
|
+
"span",
|
|
752
|
+
{
|
|
753
|
+
className: cn(
|
|
754
|
+
"absolute inset-0 rounded-full bg-primary transition-transform",
|
|
755
|
+
i === active ? "scale-100" : "scale-0"
|
|
756
|
+
),
|
|
757
|
+
style: autoSlide && i === active ? {
|
|
758
|
+
transform: `scaleX(${progress})`,
|
|
759
|
+
transformOrigin: "left"
|
|
760
|
+
} : void 0
|
|
761
|
+
}
|
|
762
|
+
)
|
|
763
|
+
},
|
|
764
|
+
i
|
|
765
|
+
)) })
|
|
766
|
+
] });
|
|
767
|
+
}
|
|
768
|
+
function ArrowButton({
|
|
769
|
+
dir,
|
|
770
|
+
onClick
|
|
771
|
+
}) {
|
|
772
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
773
|
+
"button",
|
|
774
|
+
{
|
|
775
|
+
type: "button",
|
|
776
|
+
"aria-label": dir === "prev" ? "Previous" : "Next",
|
|
777
|
+
onClick,
|
|
778
|
+
className: "flex size-8 items-center justify-center rounded-full border border-border text-text transition-colors hover:bg-hover",
|
|
779
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
780
|
+
"svg",
|
|
781
|
+
{
|
|
782
|
+
className: cn("size-4", dir === "prev" && "rotate-180"),
|
|
783
|
+
viewBox: "0 0 16 16",
|
|
784
|
+
fill: "none",
|
|
785
|
+
stroke: "currentColor",
|
|
786
|
+
strokeWidth: "1.5",
|
|
787
|
+
strokeLinecap: "round",
|
|
788
|
+
strokeLinejoin: "round",
|
|
789
|
+
"aria-hidden": true,
|
|
790
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 4 4 4-4 4" })
|
|
791
|
+
}
|
|
792
|
+
)
|
|
793
|
+
}
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
function Checkbox({
|
|
797
|
+
label,
|
|
798
|
+
indeterminate = false,
|
|
799
|
+
className,
|
|
800
|
+
disabled,
|
|
801
|
+
...props
|
|
802
|
+
}) {
|
|
803
|
+
const ref = react.useRef(null);
|
|
804
|
+
react.useEffect(() => {
|
|
805
|
+
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
806
|
+
}, [indeterminate]);
|
|
807
|
+
const input = /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex size-6 shrink-0", children: [
|
|
808
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
809
|
+
"input",
|
|
810
|
+
{
|
|
811
|
+
ref,
|
|
812
|
+
type: "checkbox",
|
|
813
|
+
disabled,
|
|
814
|
+
className: cn(
|
|
815
|
+
"peer size-6 cursor-pointer appearance-none rounded-[4px] border-[1.5px] border-text-muted bg-transparent transition-colors",
|
|
816
|
+
"checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary",
|
|
817
|
+
"focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2",
|
|
818
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
819
|
+
className
|
|
820
|
+
),
|
|
821
|
+
...props
|
|
822
|
+
}
|
|
823
|
+
),
|
|
824
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
825
|
+
"svg",
|
|
826
|
+
{
|
|
827
|
+
className: "pointer-events-none absolute inset-0 m-auto hidden size-4 text-white peer-checked:block peer-indeterminate:hidden",
|
|
828
|
+
viewBox: "0 0 16 16",
|
|
829
|
+
fill: "none",
|
|
830
|
+
stroke: "currentColor",
|
|
831
|
+
strokeWidth: "2",
|
|
832
|
+
strokeLinecap: "round",
|
|
833
|
+
strokeLinejoin: "round",
|
|
834
|
+
"aria-hidden": true,
|
|
835
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 8 3.5 3.5L13 5" })
|
|
836
|
+
}
|
|
837
|
+
),
|
|
838
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
839
|
+
"svg",
|
|
840
|
+
{
|
|
841
|
+
className: "pointer-events-none absolute inset-0 m-auto hidden size-4 text-white peer-indeterminate:block",
|
|
842
|
+
viewBox: "0 0 16 16",
|
|
843
|
+
fill: "none",
|
|
844
|
+
stroke: "currentColor",
|
|
845
|
+
strokeWidth: "2",
|
|
846
|
+
strokeLinecap: "round",
|
|
847
|
+
"aria-hidden": true,
|
|
848
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 8h8" })
|
|
849
|
+
}
|
|
850
|
+
)
|
|
851
|
+
] });
|
|
852
|
+
if (!label) return input;
|
|
853
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
854
|
+
"label",
|
|
855
|
+
{
|
|
856
|
+
className: cn(
|
|
857
|
+
"inline-flex items-center gap-2 text-sm text-text",
|
|
858
|
+
disabled && "cursor-not-allowed opacity-50"
|
|
859
|
+
),
|
|
860
|
+
children: [
|
|
861
|
+
input,
|
|
862
|
+
label
|
|
863
|
+
]
|
|
864
|
+
}
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
var chip = classVarianceAuthority.cva(
|
|
868
|
+
"inline-flex items-center gap-2 bg-surface text-text whitespace-nowrap",
|
|
869
|
+
{
|
|
870
|
+
variants: {
|
|
871
|
+
size: {
|
|
872
|
+
sm: "h-8 rounded-[4px] px-2 text-sm [&_svg]:size-4",
|
|
873
|
+
md: "h-10 rounded-[8px] px-3 text-sm [&_svg]:size-6"
|
|
874
|
+
}
|
|
875
|
+
},
|
|
876
|
+
defaultVariants: { size: "md" }
|
|
877
|
+
}
|
|
878
|
+
);
|
|
879
|
+
function Chip({
|
|
880
|
+
size = "md",
|
|
881
|
+
leading,
|
|
882
|
+
trailing,
|
|
883
|
+
onDismiss,
|
|
884
|
+
className,
|
|
885
|
+
children,
|
|
886
|
+
...props
|
|
887
|
+
}) {
|
|
888
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(chip({ size }), className), ...props, children: [
|
|
889
|
+
leading,
|
|
890
|
+
children,
|
|
891
|
+
onDismiss ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
892
|
+
"button",
|
|
893
|
+
{
|
|
894
|
+
type: "button",
|
|
895
|
+
"aria-label": "Remove",
|
|
896
|
+
onClick: onDismiss,
|
|
897
|
+
className: "-mr-1 inline-flex shrink-0 items-center justify-center rounded-full text-text-muted hover:text-text focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2",
|
|
898
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
899
|
+
"svg",
|
|
900
|
+
{
|
|
901
|
+
viewBox: "0 0 24 24",
|
|
902
|
+
fill: "none",
|
|
903
|
+
stroke: "currentColor",
|
|
904
|
+
strokeWidth: "2",
|
|
905
|
+
strokeLinecap: "round",
|
|
906
|
+
"aria-hidden": true,
|
|
907
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 6l12 12M18 6L6 18" })
|
|
908
|
+
}
|
|
909
|
+
)
|
|
910
|
+
}
|
|
911
|
+
) : trailing
|
|
912
|
+
] });
|
|
913
|
+
}
|
|
914
|
+
var tag = classVarianceAuthority.cva(
|
|
915
|
+
"inline-flex items-center gap-1 rounded-[4px] bg-background font-bold text-text whitespace-nowrap",
|
|
916
|
+
{
|
|
917
|
+
variants: {
|
|
918
|
+
size: {
|
|
919
|
+
"2xs": "h-4 px-1 text-[10px] [&_svg]:size-3",
|
|
920
|
+
xs: "h-6 px-2 text-xs [&_svg]:size-4"
|
|
921
|
+
},
|
|
922
|
+
uppercase: {
|
|
923
|
+
true: "uppercase",
|
|
924
|
+
false: ""
|
|
925
|
+
}
|
|
926
|
+
},
|
|
927
|
+
defaultVariants: { size: "xs", uppercase: false }
|
|
928
|
+
}
|
|
929
|
+
);
|
|
930
|
+
function Tag({
|
|
931
|
+
size = "xs",
|
|
932
|
+
uppercase,
|
|
933
|
+
leading,
|
|
934
|
+
trailing,
|
|
935
|
+
className,
|
|
936
|
+
children,
|
|
937
|
+
...props
|
|
938
|
+
}) {
|
|
939
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(tag({ size, uppercase }), className), ...props, children: [
|
|
940
|
+
leading,
|
|
941
|
+
children,
|
|
942
|
+
trailing
|
|
943
|
+
] });
|
|
944
|
+
}
|
|
945
|
+
function Radio({ label, className, disabled, ...props }) {
|
|
946
|
+
const input = /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex size-6 shrink-0", children: [
|
|
947
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
948
|
+
"input",
|
|
949
|
+
{
|
|
950
|
+
type: "radio",
|
|
951
|
+
disabled,
|
|
952
|
+
className: cn(
|
|
953
|
+
"peer size-6 cursor-pointer appearance-none rounded-full border-[1.5px] border-text-muted bg-transparent transition-colors",
|
|
954
|
+
"checked:border-primary",
|
|
955
|
+
"focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2",
|
|
956
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
957
|
+
className
|
|
958
|
+
),
|
|
959
|
+
...props
|
|
960
|
+
}
|
|
961
|
+
),
|
|
962
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-0 m-auto size-3 scale-0 rounded-full bg-primary transition-transform peer-checked:scale-100" })
|
|
963
|
+
] });
|
|
964
|
+
if (!label) return input;
|
|
965
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
966
|
+
"label",
|
|
967
|
+
{
|
|
968
|
+
className: cn(
|
|
969
|
+
"inline-flex items-center gap-2 text-sm text-text",
|
|
970
|
+
disabled && "cursor-not-allowed opacity-50"
|
|
971
|
+
),
|
|
972
|
+
children: [
|
|
973
|
+
input,
|
|
974
|
+
label
|
|
975
|
+
]
|
|
976
|
+
}
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
var loader = classVarianceAuthority.cva(
|
|
980
|
+
"inline-block animate-spin rounded-full border-current border-t-transparent text-primary",
|
|
981
|
+
{
|
|
982
|
+
variants: {
|
|
983
|
+
size: {
|
|
984
|
+
"2xs": "size-4 border-2",
|
|
985
|
+
xs: "size-6 border-2",
|
|
986
|
+
sm: "size-8 border-[3px]",
|
|
987
|
+
md: "size-10 border-4",
|
|
988
|
+
lg: "size-12 border-4"
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
defaultVariants: { size: "md" }
|
|
992
|
+
}
|
|
993
|
+
);
|
|
994
|
+
function Loader({
|
|
995
|
+
size = "md",
|
|
996
|
+
label = "Loading",
|
|
997
|
+
className,
|
|
998
|
+
...props
|
|
999
|
+
}) {
|
|
1000
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1001
|
+
"span",
|
|
1002
|
+
{
|
|
1003
|
+
role: "status",
|
|
1004
|
+
"aria-label": label,
|
|
1005
|
+
className: cn(loader({ size }), className),
|
|
1006
|
+
...props
|
|
1007
|
+
}
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
function Search({
|
|
1011
|
+
value,
|
|
1012
|
+
onValueChange,
|
|
1013
|
+
results,
|
|
1014
|
+
loading = false,
|
|
1015
|
+
emptyState = "No results",
|
|
1016
|
+
resultsTitle = "Search results",
|
|
1017
|
+
shortcut = "\u2318K",
|
|
1018
|
+
mobile = false,
|
|
1019
|
+
open: controlledOpen,
|
|
1020
|
+
onOpenChange,
|
|
1021
|
+
placeholder = "Search\u2026",
|
|
1022
|
+
className,
|
|
1023
|
+
...props
|
|
1024
|
+
}) {
|
|
1025
|
+
const [uncontrolledOpen, setUncontrolledOpen] = react.useState(false);
|
|
1026
|
+
const isControlled = controlledOpen !== void 0;
|
|
1027
|
+
const open = isControlled ? controlledOpen : uncontrolledOpen;
|
|
1028
|
+
const rootRef = react.useRef(null);
|
|
1029
|
+
const inputRef = react.useRef(null);
|
|
1030
|
+
const setOpen = (next) => {
|
|
1031
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
1032
|
+
onOpenChange?.(next);
|
|
1033
|
+
};
|
|
1034
|
+
react.useEffect(() => {
|
|
1035
|
+
if (!open || mobile) return;
|
|
1036
|
+
const onPointerDown = (e) => {
|
|
1037
|
+
if (!rootRef.current?.contains(e.target)) setOpen(false);
|
|
1038
|
+
};
|
|
1039
|
+
const onKey = (e) => {
|
|
1040
|
+
if (e.key === "Escape") setOpen(false);
|
|
1041
|
+
};
|
|
1042
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
1043
|
+
document.addEventListener("keydown", onKey);
|
|
1044
|
+
return () => {
|
|
1045
|
+
document.removeEventListener("pointerdown", onPointerDown);
|
|
1046
|
+
document.removeEventListener("keydown", onKey);
|
|
1047
|
+
};
|
|
1048
|
+
});
|
|
1049
|
+
const hasResults = Boolean(results);
|
|
1050
|
+
const inputRow = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-14 items-center gap-3 px-4", children: [
|
|
1051
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx(Loader, { size: "2xs", className: "text-text-muted" }) : /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "size-6 shrink-0 text-text-muted" }),
|
|
1052
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1053
|
+
"input",
|
|
1054
|
+
{
|
|
1055
|
+
ref: inputRef,
|
|
1056
|
+
type: "search",
|
|
1057
|
+
value,
|
|
1058
|
+
placeholder,
|
|
1059
|
+
role: "searchbox",
|
|
1060
|
+
className: "flex-1 bg-transparent text-sm text-text outline-none placeholder:text-text-muted [&::-webkit-search-cancel-button]:hidden",
|
|
1061
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
1062
|
+
onFocus: () => setOpen(true),
|
|
1063
|
+
...props
|
|
1064
|
+
}
|
|
1065
|
+
),
|
|
1066
|
+
value ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1067
|
+
"button",
|
|
1068
|
+
{
|
|
1069
|
+
type: "button",
|
|
1070
|
+
"aria-label": "Clear search",
|
|
1071
|
+
onClick: () => {
|
|
1072
|
+
onValueChange("");
|
|
1073
|
+
inputRef.current?.focus();
|
|
1074
|
+
},
|
|
1075
|
+
className: "inline-flex size-6 shrink-0 items-center justify-center rounded-full text-text-muted hover:bg-hover hover:text-text",
|
|
1076
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1077
|
+
"svg",
|
|
1078
|
+
{
|
|
1079
|
+
viewBox: "0 0 24 24",
|
|
1080
|
+
className: "size-4",
|
|
1081
|
+
fill: "none",
|
|
1082
|
+
stroke: "currentColor",
|
|
1083
|
+
strokeWidth: "2",
|
|
1084
|
+
strokeLinecap: "round",
|
|
1085
|
+
"aria-hidden": true,
|
|
1086
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 6l12 12M18 6L6 18" })
|
|
1087
|
+
}
|
|
1088
|
+
)
|
|
1089
|
+
}
|
|
1090
|
+
) : shortcut && /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "shrink-0 text-xs text-text-muted", children: shortcut })
|
|
1091
|
+
] });
|
|
1092
|
+
const panel = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1093
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border" }),
|
|
1094
|
+
hasResults && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-3 text-sm font-bold text-text-muted", children: resultsTitle }),
|
|
1095
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-80 overflow-auto p-1", children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(Loader, {}) }) : hasResults ? results : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-8 text-center text-sm text-text-muted", children: emptyState }) })
|
|
1096
|
+
] });
|
|
1097
|
+
if (mobile && open) {
|
|
1098
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 flex flex-col bg-surface", children: [
|
|
1099
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
1100
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: inputRow }),
|
|
1101
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1102
|
+
"button",
|
|
1103
|
+
{
|
|
1104
|
+
type: "button",
|
|
1105
|
+
"aria-label": "Close search",
|
|
1106
|
+
onClick: () => setOpen(false),
|
|
1107
|
+
className: "px-4 text-sm font-bold text-primary",
|
|
1108
|
+
children: "Cancel"
|
|
1109
|
+
}
|
|
1110
|
+
)
|
|
1111
|
+
] }),
|
|
1112
|
+
panel
|
|
1113
|
+
] });
|
|
1114
|
+
}
|
|
1115
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: rootRef, className: cn("relative w-full", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-[12px] border border-border bg-surface", children: [
|
|
1116
|
+
inputRow,
|
|
1117
|
+
open && panel
|
|
1118
|
+
] }) });
|
|
1119
|
+
}
|
|
1120
|
+
function SearchIcon({ className }) {
|
|
1121
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1122
|
+
"svg",
|
|
1123
|
+
{
|
|
1124
|
+
className,
|
|
1125
|
+
viewBox: "0 0 24 24",
|
|
1126
|
+
fill: "none",
|
|
1127
|
+
stroke: "currentColor",
|
|
1128
|
+
strokeWidth: "2",
|
|
1129
|
+
strokeLinecap: "round",
|
|
1130
|
+
strokeLinejoin: "round",
|
|
1131
|
+
"aria-hidden": true,
|
|
1132
|
+
children: [
|
|
1133
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
|
|
1134
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m21 21-4.3-4.3" })
|
|
1135
|
+
]
|
|
1136
|
+
}
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1139
|
+
var container = classVarianceAuthority.cva(
|
|
1140
|
+
"inline-flex items-center gap-1 rounded-[12px] bg-background p-1",
|
|
1141
|
+
{
|
|
1142
|
+
variants: {
|
|
1143
|
+
size: {
|
|
1144
|
+
sm: "h-10",
|
|
1145
|
+
md: "h-12"
|
|
1146
|
+
}
|
|
1147
|
+
},
|
|
1148
|
+
defaultVariants: { size: "md" }
|
|
1149
|
+
}
|
|
1150
|
+
);
|
|
1151
|
+
var segment = classVarianceAuthority.cva(
|
|
1152
|
+
"inline-flex h-full flex-1 items-center justify-center gap-2 rounded-[8px] px-3 text-sm font-bold whitespace-nowrap transition-colors focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2 [&_svg]:size-5",
|
|
1153
|
+
{
|
|
1154
|
+
variants: {
|
|
1155
|
+
active: {
|
|
1156
|
+
true: "bg-surface text-text shadow-sm",
|
|
1157
|
+
false: "text-text-muted hover:text-text"
|
|
1158
|
+
}
|
|
1159
|
+
},
|
|
1160
|
+
defaultVariants: { active: false }
|
|
1161
|
+
}
|
|
1162
|
+
);
|
|
1163
|
+
function SegmentedControl({
|
|
1164
|
+
items,
|
|
1165
|
+
value,
|
|
1166
|
+
onChange,
|
|
1167
|
+
size = "md",
|
|
1168
|
+
className,
|
|
1169
|
+
...props
|
|
1170
|
+
}) {
|
|
1171
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1172
|
+
"div",
|
|
1173
|
+
{
|
|
1174
|
+
role: "tablist",
|
|
1175
|
+
className: cn(container({ size }), className),
|
|
1176
|
+
...props,
|
|
1177
|
+
children: items.map((item) => {
|
|
1178
|
+
const active = item.value === value;
|
|
1179
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1180
|
+
"button",
|
|
1181
|
+
{
|
|
1182
|
+
type: "button",
|
|
1183
|
+
role: "tab",
|
|
1184
|
+
"aria-selected": active,
|
|
1185
|
+
onClick: () => onChange(item.value),
|
|
1186
|
+
className: segment({ active }),
|
|
1187
|
+
children: [
|
|
1188
|
+
item.icon,
|
|
1189
|
+
item.label
|
|
1190
|
+
]
|
|
1191
|
+
},
|
|
1192
|
+
item.value
|
|
1193
|
+
);
|
|
1194
|
+
})
|
|
1195
|
+
}
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
var TabsContext = react.createContext(null);
|
|
1199
|
+
function useTabs() {
|
|
1200
|
+
const ctx = react.useContext(TabsContext);
|
|
1201
|
+
if (!ctx) throw new Error("Tabs components must be used within <Tabs>");
|
|
1202
|
+
return ctx;
|
|
1203
|
+
}
|
|
1204
|
+
function Tabs({
|
|
1205
|
+
value,
|
|
1206
|
+
onValueChange,
|
|
1207
|
+
type = "underline",
|
|
1208
|
+
size = "md",
|
|
1209
|
+
children,
|
|
1210
|
+
className
|
|
1211
|
+
}) {
|
|
1212
|
+
const baseId = react.useId();
|
|
1213
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1214
|
+
TabsContext.Provider,
|
|
1215
|
+
{
|
|
1216
|
+
value: { value, setValue: onValueChange, type, size, baseId },
|
|
1217
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, children })
|
|
1218
|
+
}
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1221
|
+
var list = classVarianceAuthority.cva("flex items-center", {
|
|
1222
|
+
variants: {
|
|
1223
|
+
type: {
|
|
1224
|
+
default: "gap-1",
|
|
1225
|
+
pill: "gap-1 rounded-[12px] bg-background p-1",
|
|
1226
|
+
underline: "gap-1 border-b border-border"
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
defaultVariants: { type: "underline" }
|
|
1230
|
+
});
|
|
1231
|
+
function TabList({
|
|
1232
|
+
children,
|
|
1233
|
+
className
|
|
1234
|
+
}) {
|
|
1235
|
+
const { type } = useTabs();
|
|
1236
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", className: cn(list({ type }), className), children });
|
|
1237
|
+
}
|
|
1238
|
+
var tab = classVarianceAuthority.cva(
|
|
1239
|
+
"inline-flex items-center justify-center gap-2 font-bold whitespace-nowrap transition-colors outline-none focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-5",
|
|
1240
|
+
{
|
|
1241
|
+
variants: {
|
|
1242
|
+
type: {
|
|
1243
|
+
default: "rounded-[8px] px-3",
|
|
1244
|
+
pill: "rounded-[8px] px-3",
|
|
1245
|
+
underline: "-mb-px border-b-2 border-transparent px-3"
|
|
1246
|
+
},
|
|
1247
|
+
size: { sm: "h-8 text-sm", md: "h-10 text-sm" },
|
|
1248
|
+
active: { true: "", false: "text-text-muted hover:text-text" }
|
|
1249
|
+
},
|
|
1250
|
+
compoundVariants: [
|
|
1251
|
+
{ type: "default", active: true, class: "text-primary" },
|
|
1252
|
+
{ type: "pill", active: true, class: "bg-surface text-text shadow-sm" },
|
|
1253
|
+
{ type: "underline", active: true, class: "border-primary text-primary" }
|
|
1254
|
+
],
|
|
1255
|
+
defaultVariants: { type: "underline", size: "md", active: false }
|
|
1256
|
+
}
|
|
1257
|
+
);
|
|
1258
|
+
function Tab({
|
|
1259
|
+
value,
|
|
1260
|
+
leading,
|
|
1261
|
+
trailing,
|
|
1262
|
+
children,
|
|
1263
|
+
className,
|
|
1264
|
+
...props
|
|
1265
|
+
}) {
|
|
1266
|
+
const ctx = useTabs();
|
|
1267
|
+
const active = ctx.value === value;
|
|
1268
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1269
|
+
"button",
|
|
1270
|
+
{
|
|
1271
|
+
type: "button",
|
|
1272
|
+
role: "tab",
|
|
1273
|
+
id: `${ctx.baseId}-tab-${value}`,
|
|
1274
|
+
"aria-selected": active,
|
|
1275
|
+
"aria-controls": `${ctx.baseId}-panel-${value}`,
|
|
1276
|
+
tabIndex: active ? 0 : -1,
|
|
1277
|
+
onClick: () => ctx.setValue(value),
|
|
1278
|
+
onKeyDown: (e) => {
|
|
1279
|
+
if (e.key !== "ArrowRight" && e.key !== "ArrowLeft") return;
|
|
1280
|
+
const tabs = Array.from(
|
|
1281
|
+
e.currentTarget.parentElement?.querySelectorAll(
|
|
1282
|
+
'[role="tab"]'
|
|
1283
|
+
) ?? []
|
|
1284
|
+
);
|
|
1285
|
+
const i = tabs.indexOf(e.currentTarget);
|
|
1286
|
+
const next = e.key === "ArrowRight" ? tabs[i + 1] : tabs[i - 1];
|
|
1287
|
+
next?.focus();
|
|
1288
|
+
next?.click();
|
|
1289
|
+
},
|
|
1290
|
+
className: cn(tab({ type: ctx.type, size: ctx.size, active }), className),
|
|
1291
|
+
...props,
|
|
1292
|
+
children: [
|
|
1293
|
+
leading,
|
|
1294
|
+
children,
|
|
1295
|
+
trailing
|
|
1296
|
+
]
|
|
1297
|
+
}
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
function TabPanel({
|
|
1301
|
+
value,
|
|
1302
|
+
children,
|
|
1303
|
+
className
|
|
1304
|
+
}) {
|
|
1305
|
+
const ctx = useTabs();
|
|
1306
|
+
if (ctx.value !== value) return null;
|
|
1307
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1308
|
+
"div",
|
|
1309
|
+
{
|
|
1310
|
+
role: "tabpanel",
|
|
1311
|
+
id: `${ctx.baseId}-panel-${value}`,
|
|
1312
|
+
"aria-labelledby": `${ctx.baseId}-tab-${value}`,
|
|
1313
|
+
className,
|
|
1314
|
+
children
|
|
1315
|
+
}
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
var field = classVarianceAuthority.cva(
|
|
1319
|
+
"w-full appearance-none rounded-[8px] border bg-surface text-sm text-text outline-none transition-shadow disabled:cursor-not-allowed disabled:opacity-50",
|
|
1320
|
+
{
|
|
1321
|
+
variants: {
|
|
1322
|
+
size: {
|
|
1323
|
+
sm: "h-8 px-2",
|
|
1324
|
+
md: "h-10 px-3",
|
|
1325
|
+
lg: "h-12 px-3",
|
|
1326
|
+
xl: "h-14 px-4"
|
|
1327
|
+
},
|
|
1328
|
+
invalid: {
|
|
1329
|
+
true: "border-[2px] border-[var(--color-input-error)]",
|
|
1330
|
+
false: "border-border hover:border-text-muted focus:border-[1.5px] focus:border-primary focus:ring-2 focus:ring-primary-tint"
|
|
1331
|
+
}
|
|
1332
|
+
},
|
|
1333
|
+
defaultVariants: { size: "md", invalid: false }
|
|
1334
|
+
}
|
|
1335
|
+
);
|
|
1336
|
+
function Select({
|
|
1337
|
+
size = "md",
|
|
1338
|
+
invalid,
|
|
1339
|
+
label,
|
|
1340
|
+
leadingIcon,
|
|
1341
|
+
error,
|
|
1342
|
+
helperText,
|
|
1343
|
+
className,
|
|
1344
|
+
id,
|
|
1345
|
+
disabled,
|
|
1346
|
+
children,
|
|
1347
|
+
...props
|
|
1348
|
+
}) {
|
|
1349
|
+
const isInvalid = invalid ?? Boolean(error);
|
|
1350
|
+
const hint = error ?? helperText;
|
|
1351
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full flex-col gap-1", className), children: [
|
|
1352
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "text-sm font-bold text-text", children: label }),
|
|
1353
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
1354
|
+
leadingIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-y-0 left-3 flex items-center text-text-muted [&_svg]:size-5", children: leadingIcon }),
|
|
1355
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1356
|
+
"select",
|
|
1357
|
+
{
|
|
1358
|
+
id,
|
|
1359
|
+
disabled,
|
|
1360
|
+
"aria-invalid": isInvalid || void 0,
|
|
1361
|
+
className: cn(
|
|
1362
|
+
field({ size, invalid: isInvalid }),
|
|
1363
|
+
leadingIcon && "pl-10",
|
|
1364
|
+
"pr-9"
|
|
1365
|
+
),
|
|
1366
|
+
...props,
|
|
1367
|
+
children
|
|
1368
|
+
}
|
|
1369
|
+
),
|
|
1370
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronDown2, { className: "pointer-events-none absolute inset-y-0 right-3 my-auto size-5 text-text-muted" })
|
|
1371
|
+
] }),
|
|
1372
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1373
|
+
"span",
|
|
1374
|
+
{
|
|
1375
|
+
className: cn(
|
|
1376
|
+
"text-xs",
|
|
1377
|
+
error ? "text-[var(--color-input-error)]" : "text-text-muted"
|
|
1378
|
+
),
|
|
1379
|
+
children: hint
|
|
1380
|
+
}
|
|
1381
|
+
)
|
|
1382
|
+
] });
|
|
1383
|
+
}
|
|
1384
|
+
function ChevronDown2({ className }) {
|
|
1385
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1386
|
+
"svg",
|
|
1387
|
+
{
|
|
1388
|
+
className,
|
|
1389
|
+
viewBox: "0 0 24 24",
|
|
1390
|
+
fill: "none",
|
|
1391
|
+
stroke: "currentColor",
|
|
1392
|
+
strokeWidth: "2",
|
|
1393
|
+
strokeLinecap: "round",
|
|
1394
|
+
strokeLinejoin: "round",
|
|
1395
|
+
"aria-hidden": true,
|
|
1396
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
|
|
1397
|
+
}
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
var field2 = classVarianceAuthority.cva(
|
|
1401
|
+
"w-full appearance-none rounded-[8px] border bg-surface text-sm text-text outline-none transition-shadow placeholder:text-text-muted disabled:cursor-not-allowed disabled:opacity-50",
|
|
1402
|
+
{
|
|
1403
|
+
variants: {
|
|
1404
|
+
size: {
|
|
1405
|
+
sm: "h-8 px-2",
|
|
1406
|
+
md: "h-10 px-3",
|
|
1407
|
+
lg: "h-12 px-3",
|
|
1408
|
+
xl: "h-14 px-4"
|
|
1409
|
+
},
|
|
1410
|
+
invalid: {
|
|
1411
|
+
true: "border-[2px] border-[var(--color-input-error)]",
|
|
1412
|
+
false: "border-border hover:border-text-muted focus:border-[1.5px] focus:border-primary focus:ring-2 focus:ring-primary-tint"
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
defaultVariants: { size: "md", invalid: false }
|
|
1416
|
+
}
|
|
1417
|
+
);
|
|
1418
|
+
function TextInput({
|
|
1419
|
+
size = "md",
|
|
1420
|
+
invalid,
|
|
1421
|
+
label,
|
|
1422
|
+
leadingIcon,
|
|
1423
|
+
trailingIcon,
|
|
1424
|
+
error,
|
|
1425
|
+
helperText,
|
|
1426
|
+
floatingLabel = false,
|
|
1427
|
+
className,
|
|
1428
|
+
id,
|
|
1429
|
+
disabled,
|
|
1430
|
+
placeholder,
|
|
1431
|
+
...props
|
|
1432
|
+
}) {
|
|
1433
|
+
const isInvalid = invalid ?? Boolean(error);
|
|
1434
|
+
const hint = error ?? helperText;
|
|
1435
|
+
const floating = floatingLabel && Boolean(label);
|
|
1436
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full flex-col gap-1", className), children: [
|
|
1437
|
+
label && !floating && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "text-sm font-bold text-text", children: label }),
|
|
1438
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
1439
|
+
leadingIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-y-0 left-3 flex items-center text-text-muted [&_svg]:size-5", children: leadingIcon }),
|
|
1440
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1441
|
+
"input",
|
|
1442
|
+
{
|
|
1443
|
+
id,
|
|
1444
|
+
disabled,
|
|
1445
|
+
placeholder: floating ? " " : placeholder,
|
|
1446
|
+
"aria-invalid": isInvalid || void 0,
|
|
1447
|
+
className: cn(
|
|
1448
|
+
field2({ size, invalid: isInvalid }),
|
|
1449
|
+
"peer",
|
|
1450
|
+
leadingIcon && "pl-10",
|
|
1451
|
+
trailingIcon && "pr-10",
|
|
1452
|
+
floating && "placeholder-shown:[&::placeholder]:opacity-0"
|
|
1453
|
+
),
|
|
1454
|
+
...props
|
|
1455
|
+
}
|
|
1456
|
+
),
|
|
1457
|
+
floating && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1458
|
+
"label",
|
|
1459
|
+
{
|
|
1460
|
+
htmlFor: id,
|
|
1461
|
+
className: cn(
|
|
1462
|
+
"pointer-events-none absolute left-3 top-0 flex h-full origin-left items-center text-sm text-text-muted transition-all peer-focus:top-0 peer-focus:h-auto peer-focus:-translate-y-1/2 peer-focus:text-xs peer-focus:text-primary peer-not-placeholder-shown:top-0 peer-not-placeholder-shown:h-auto peer-not-placeholder-shown:-translate-y-1/2 peer-not-placeholder-shown:text-xs",
|
|
1463
|
+
leadingIcon && "left-10 peer-focus:left-3 peer-not-placeholder-shown:left-3",
|
|
1464
|
+
isInvalid && "peer-focus:text-[var(--color-input-error)]"
|
|
1465
|
+
),
|
|
1466
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-surface px-1", children: label })
|
|
1467
|
+
}
|
|
1468
|
+
),
|
|
1469
|
+
trailingIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-y-0 right-3 flex items-center text-text-muted [&_svg]:size-5", children: trailingIcon })
|
|
1470
|
+
] }),
|
|
1471
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1472
|
+
"span",
|
|
1473
|
+
{
|
|
1474
|
+
className: cn(
|
|
1475
|
+
"px-1 text-xs",
|
|
1476
|
+
error ? "text-[var(--color-input-error)]" : "text-text-muted"
|
|
1477
|
+
),
|
|
1478
|
+
children: hint
|
|
1479
|
+
}
|
|
1480
|
+
)
|
|
1481
|
+
] });
|
|
1482
|
+
}
|
|
1483
|
+
var cellBase = "relative flex w-full items-center rounded-[8px] border-[1.5px] border-transparent";
|
|
1484
|
+
var cellActive = "focus-within:z-10 focus-within:border-primary focus-within:ring-4 focus-within:ring-primary-tint";
|
|
1485
|
+
var cellError = "z-10 border-[var(--color-input-error)] focus-within:border-[var(--color-input-error)]";
|
|
1486
|
+
function GroupField({
|
|
1487
|
+
select,
|
|
1488
|
+
invalid,
|
|
1489
|
+
className,
|
|
1490
|
+
children,
|
|
1491
|
+
...props
|
|
1492
|
+
}) {
|
|
1493
|
+
const cell3 = cn(cellBase, invalid ? cellError : cellActive, className);
|
|
1494
|
+
if (select) {
|
|
1495
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cell3, children: [
|
|
1496
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1497
|
+
"select",
|
|
1498
|
+
{
|
|
1499
|
+
className: "w-full appearance-none bg-transparent px-4 py-4 pr-10 text-base text-text outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
1500
|
+
...props,
|
|
1501
|
+
children
|
|
1502
|
+
}
|
|
1503
|
+
),
|
|
1504
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronDown3, { className: "pointer-events-none absolute right-4 size-5 text-text-muted" })
|
|
1505
|
+
] });
|
|
1506
|
+
}
|
|
1507
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cell3, children: [
|
|
1508
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1509
|
+
"input",
|
|
1510
|
+
{
|
|
1511
|
+
className: "w-full bg-transparent px-4 py-4 text-base text-text outline-none placeholder:text-text-muted disabled:cursor-not-allowed disabled:opacity-50",
|
|
1512
|
+
...props
|
|
1513
|
+
}
|
|
1514
|
+
),
|
|
1515
|
+
children
|
|
1516
|
+
] });
|
|
1517
|
+
}
|
|
1518
|
+
function TextInputGroup({
|
|
1519
|
+
direction = "vertical",
|
|
1520
|
+
errors,
|
|
1521
|
+
className,
|
|
1522
|
+
children,
|
|
1523
|
+
...props
|
|
1524
|
+
}) {
|
|
1525
|
+
const fields = react.Children.toArray(children).filter(react.isValidElement);
|
|
1526
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full flex-col gap-1", className), ...props, children: [
|
|
1527
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1528
|
+
"div",
|
|
1529
|
+
{
|
|
1530
|
+
className: cn(
|
|
1531
|
+
"flex rounded-[8px] border border-border bg-surface",
|
|
1532
|
+
direction === "vertical" ? "flex-col divide-y divide-border" : "flex-row divide-x divide-border"
|
|
1533
|
+
),
|
|
1534
|
+
children: fields.map(
|
|
1535
|
+
(child, i) => react.cloneElement(child, {
|
|
1536
|
+
key: i,
|
|
1537
|
+
className: cn(
|
|
1538
|
+
"-m-px",
|
|
1539
|
+
direction === "horizontal" && "flex-1",
|
|
1540
|
+
child.props.className
|
|
1541
|
+
)
|
|
1542
|
+
})
|
|
1543
|
+
)
|
|
1544
|
+
}
|
|
1545
|
+
),
|
|
1546
|
+
errors?.filter(Boolean).map((msg, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1 text-xs text-[var(--color-input-error)]", children: msg }, i))
|
|
1547
|
+
] });
|
|
1548
|
+
}
|
|
1549
|
+
function ChevronDown3({ className }) {
|
|
1550
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1551
|
+
"svg",
|
|
1552
|
+
{
|
|
1553
|
+
className,
|
|
1554
|
+
viewBox: "0 0 24 24",
|
|
1555
|
+
fill: "none",
|
|
1556
|
+
stroke: "currentColor",
|
|
1557
|
+
strokeWidth: "2",
|
|
1558
|
+
strokeLinecap: "round",
|
|
1559
|
+
strokeLinejoin: "round",
|
|
1560
|
+
"aria-hidden": true,
|
|
1561
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
|
|
1562
|
+
}
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1565
|
+
var field3 = classVarianceAuthority.cva(
|
|
1566
|
+
"w-full rounded-[8px] border bg-surface px-3 py-2 text-sm text-text outline-none transition-shadow placeholder:text-text-muted disabled:cursor-not-allowed disabled:opacity-50",
|
|
1567
|
+
{
|
|
1568
|
+
variants: {
|
|
1569
|
+
invalid: {
|
|
1570
|
+
true: "border-[2px] border-[var(--color-input-error)]",
|
|
1571
|
+
false: "border-border hover:border-text-muted focus:border-[1.5px] focus:border-primary focus:ring-2 focus:ring-primary-tint"
|
|
1572
|
+
}
|
|
1573
|
+
},
|
|
1574
|
+
defaultVariants: { invalid: false }
|
|
1575
|
+
}
|
|
1576
|
+
);
|
|
1577
|
+
function Textarea({
|
|
1578
|
+
invalid,
|
|
1579
|
+
label,
|
|
1580
|
+
error,
|
|
1581
|
+
helperText,
|
|
1582
|
+
autoResize = false,
|
|
1583
|
+
className,
|
|
1584
|
+
id,
|
|
1585
|
+
disabled,
|
|
1586
|
+
value,
|
|
1587
|
+
onChange,
|
|
1588
|
+
rows = 3,
|
|
1589
|
+
...props
|
|
1590
|
+
}) {
|
|
1591
|
+
const ref = react.useRef(null);
|
|
1592
|
+
const isInvalid = invalid ?? Boolean(error);
|
|
1593
|
+
const hint = error ?? helperText;
|
|
1594
|
+
const resize = () => {
|
|
1595
|
+
const el = ref.current;
|
|
1596
|
+
if (!el || !autoResize) return;
|
|
1597
|
+
el.style.height = "auto";
|
|
1598
|
+
el.style.height = `${el.scrollHeight}px`;
|
|
1599
|
+
};
|
|
1600
|
+
react.useEffect(resize, [value, autoResize]);
|
|
1601
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full flex-col gap-1", className), children: [
|
|
1602
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "text-sm font-bold text-text", children: label }),
|
|
1603
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1604
|
+
"textarea",
|
|
1605
|
+
{
|
|
1606
|
+
ref,
|
|
1607
|
+
id,
|
|
1608
|
+
rows,
|
|
1609
|
+
disabled,
|
|
1610
|
+
value,
|
|
1611
|
+
"aria-invalid": isInvalid || void 0,
|
|
1612
|
+
className: cn(
|
|
1613
|
+
field3({ invalid: isInvalid }),
|
|
1614
|
+
autoResize && "resize-none overflow-hidden"
|
|
1615
|
+
),
|
|
1616
|
+
onChange: (e) => {
|
|
1617
|
+
onChange?.(e);
|
|
1618
|
+
resize();
|
|
1619
|
+
},
|
|
1620
|
+
...props
|
|
1621
|
+
}
|
|
1622
|
+
),
|
|
1623
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1624
|
+
"span",
|
|
1625
|
+
{
|
|
1626
|
+
className: cn(
|
|
1627
|
+
"text-xs",
|
|
1628
|
+
error ? "text-[var(--color-input-error)]" : "text-text-muted"
|
|
1629
|
+
),
|
|
1630
|
+
children: hint
|
|
1631
|
+
}
|
|
1632
|
+
)
|
|
1633
|
+
] });
|
|
1634
|
+
}
|
|
1635
|
+
var track = classVarianceAuthority.cva(
|
|
1636
|
+
"peer relative inline-flex shrink-0 cursor-pointer appearance-none items-center rounded-full bg-border transition-colors checked:bg-primary focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
1637
|
+
{
|
|
1638
|
+
variants: {
|
|
1639
|
+
size: {
|
|
1640
|
+
"2xs": "h-4 w-7",
|
|
1641
|
+
xs: "h-6 w-11",
|
|
1642
|
+
sm: "h-8 w-[60px]"
|
|
1643
|
+
}
|
|
1644
|
+
},
|
|
1645
|
+
defaultVariants: { size: "xs" }
|
|
1646
|
+
}
|
|
1647
|
+
);
|
|
1648
|
+
var thumb = classVarianceAuthority.cva(
|
|
1649
|
+
"pointer-events-none absolute left-0.5 rounded-full bg-surface transition-transform",
|
|
1650
|
+
{
|
|
1651
|
+
variants: {
|
|
1652
|
+
size: {
|
|
1653
|
+
"2xs": "size-3 peer-checked:translate-x-3",
|
|
1654
|
+
xs: "size-5 peer-checked:translate-x-5",
|
|
1655
|
+
sm: "size-7 peer-checked:translate-x-7"
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
defaultVariants: { size: "xs" }
|
|
1659
|
+
}
|
|
1660
|
+
);
|
|
1661
|
+
function Switch({
|
|
1662
|
+
size = "xs",
|
|
1663
|
+
label,
|
|
1664
|
+
className,
|
|
1665
|
+
disabled,
|
|
1666
|
+
...props
|
|
1667
|
+
}) {
|
|
1668
|
+
const control = /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex", children: [
|
|
1669
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1670
|
+
"input",
|
|
1671
|
+
{
|
|
1672
|
+
type: "checkbox",
|
|
1673
|
+
role: "switch",
|
|
1674
|
+
disabled,
|
|
1675
|
+
className: cn(track({ size }), className),
|
|
1676
|
+
...props
|
|
1677
|
+
}
|
|
1678
|
+
),
|
|
1679
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: thumb({ size }), "aria-hidden": true })
|
|
1680
|
+
] });
|
|
1681
|
+
if (!label) return control;
|
|
1682
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1683
|
+
"label",
|
|
1684
|
+
{
|
|
1685
|
+
className: cn(
|
|
1686
|
+
"inline-flex items-center gap-2 text-sm text-text",
|
|
1687
|
+
disabled && "cursor-not-allowed opacity-50"
|
|
1688
|
+
),
|
|
1689
|
+
children: [
|
|
1690
|
+
control,
|
|
1691
|
+
label
|
|
1692
|
+
]
|
|
1693
|
+
}
|
|
1694
|
+
);
|
|
1695
|
+
}
|
|
1696
|
+
var cell2 = classVarianceAuthority.cva("px-3 text-left text-sm text-text", {
|
|
1697
|
+
variants: {
|
|
1698
|
+
size: {
|
|
1699
|
+
xs: "h-6",
|
|
1700
|
+
sm: "h-8",
|
|
1701
|
+
md: "h-10",
|
|
1702
|
+
lg: "h-12",
|
|
1703
|
+
xl: "h-14",
|
|
1704
|
+
"2xl": "h-16"
|
|
1705
|
+
}
|
|
1706
|
+
},
|
|
1707
|
+
defaultVariants: { size: "md" }
|
|
1708
|
+
});
|
|
1709
|
+
function Table({
|
|
1710
|
+
className,
|
|
1711
|
+
...props
|
|
1712
|
+
}) {
|
|
1713
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1714
|
+
"table",
|
|
1715
|
+
{
|
|
1716
|
+
className: cn("w-full border-collapse text-text", className),
|
|
1717
|
+
...props
|
|
1718
|
+
}
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
function TableHead({
|
|
1722
|
+
className,
|
|
1723
|
+
...props
|
|
1724
|
+
}) {
|
|
1725
|
+
return /* @__PURE__ */ jsxRuntime.jsx("thead", { className: cn("border-b border-border", className), ...props });
|
|
1726
|
+
}
|
|
1727
|
+
function TableBody(props) {
|
|
1728
|
+
return /* @__PURE__ */ jsxRuntime.jsx("tbody", { ...props });
|
|
1729
|
+
}
|
|
1730
|
+
function TableRow({
|
|
1731
|
+
zebra,
|
|
1732
|
+
hover = true,
|
|
1733
|
+
selected,
|
|
1734
|
+
className,
|
|
1735
|
+
...props
|
|
1736
|
+
}) {
|
|
1737
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1738
|
+
"tr",
|
|
1739
|
+
{
|
|
1740
|
+
"aria-selected": selected || void 0,
|
|
1741
|
+
className: cn(
|
|
1742
|
+
"border-b border-border",
|
|
1743
|
+
zebra && "even:bg-background",
|
|
1744
|
+
hover && "hover:bg-hover",
|
|
1745
|
+
selected && "bg-primary-tint",
|
|
1746
|
+
className
|
|
1747
|
+
),
|
|
1748
|
+
...props
|
|
1749
|
+
}
|
|
1750
|
+
);
|
|
1751
|
+
}
|
|
1752
|
+
function TableCell({
|
|
1753
|
+
size = "md",
|
|
1754
|
+
header,
|
|
1755
|
+
className,
|
|
1756
|
+
...props
|
|
1757
|
+
}) {
|
|
1758
|
+
const Tag2 = header ? "th" : "td";
|
|
1759
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1760
|
+
Tag2,
|
|
1761
|
+
{
|
|
1762
|
+
className: cn(
|
|
1763
|
+
cell2({ size }),
|
|
1764
|
+
header && "font-bold text-text-muted",
|
|
1765
|
+
className
|
|
1766
|
+
),
|
|
1767
|
+
...props
|
|
1768
|
+
}
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
function selectionState(selectedCount, total) {
|
|
1772
|
+
return {
|
|
1773
|
+
checked: total > 0 && selectedCount === total,
|
|
1774
|
+
indeterminate: selectedCount > 0 && selectedCount < total
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
function DataTable({
|
|
1778
|
+
columns,
|
|
1779
|
+
data,
|
|
1780
|
+
rowKey,
|
|
1781
|
+
size = "md",
|
|
1782
|
+
zebra,
|
|
1783
|
+
selectable,
|
|
1784
|
+
selected = [],
|
|
1785
|
+
onSelectedChange,
|
|
1786
|
+
className
|
|
1787
|
+
}) {
|
|
1788
|
+
const allKeys = data.map(rowKey);
|
|
1789
|
+
const { checked, indeterminate } = selectionState(
|
|
1790
|
+
selected.length,
|
|
1791
|
+
allKeys.length
|
|
1792
|
+
);
|
|
1793
|
+
const toggleAll = () => onSelectedChange?.(checked ? [] : allKeys);
|
|
1794
|
+
const toggleRow = (key) => onSelectedChange?.(
|
|
1795
|
+
selected.includes(key) ? selected.filter((k) => k !== key) : [...selected, key]
|
|
1796
|
+
);
|
|
1797
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Table, { className, children: [
|
|
1798
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-border", children: [
|
|
1799
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx(TableCell, { header: true, size, className: "w-px", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1800
|
+
Checkbox,
|
|
1801
|
+
{
|
|
1802
|
+
checked,
|
|
1803
|
+
indeterminate,
|
|
1804
|
+
onChange: toggleAll,
|
|
1805
|
+
"aria-label": "Select all rows"
|
|
1806
|
+
}
|
|
1807
|
+
) }),
|
|
1808
|
+
columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx(TableCell, { header: true, size, children: col.header }, col.key))
|
|
1809
|
+
] }) }),
|
|
1810
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: data.map((row) => {
|
|
1811
|
+
const key = rowKey(row);
|
|
1812
|
+
const isSelected = selected.includes(key);
|
|
1813
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { zebra, selected: isSelected, children: [
|
|
1814
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx(TableCell, { size, className: "w-px", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1815
|
+
Checkbox,
|
|
1816
|
+
{
|
|
1817
|
+
checked: isSelected,
|
|
1818
|
+
onChange: () => toggleRow(key),
|
|
1819
|
+
"aria-label": `Select row`
|
|
1820
|
+
}
|
|
1821
|
+
) }),
|
|
1822
|
+
columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx(TableCell, { size, children: col.cell(row) }, col.key))
|
|
1823
|
+
] }, key);
|
|
1824
|
+
}) })
|
|
1825
|
+
] });
|
|
1826
|
+
}
|
|
1827
|
+
var ToastContext = react.createContext(null);
|
|
1828
|
+
function useToast() {
|
|
1829
|
+
const ctx = react.useContext(ToastContext);
|
|
1830
|
+
if (!ctx) throw new Error("useToast must be used within a ToastProvider");
|
|
1831
|
+
return ctx;
|
|
1832
|
+
}
|
|
1833
|
+
var POSITION_CLASS = {
|
|
1834
|
+
"top-left": "top-4 left-4 items-start",
|
|
1835
|
+
"top-center": "top-4 left-1/2 -translate-x-1/2 items-center",
|
|
1836
|
+
"top-right": "top-4 right-4 items-end",
|
|
1837
|
+
"bottom-left": "bottom-4 left-4 items-start",
|
|
1838
|
+
"bottom-center": "bottom-4 left-1/2 -translate-x-1/2 items-center",
|
|
1839
|
+
"bottom-right": "bottom-4 right-4 items-end"
|
|
1840
|
+
};
|
|
1841
|
+
function ToastProvider({
|
|
1842
|
+
children,
|
|
1843
|
+
position = "bottom-center",
|
|
1844
|
+
defaultDuration = 5e3
|
|
1845
|
+
}) {
|
|
1846
|
+
const [toasts, setToasts] = react.useState([]);
|
|
1847
|
+
const counter = react.useRef(0);
|
|
1848
|
+
const dismiss = react.useCallback((id) => {
|
|
1849
|
+
setToasts((list2) => list2.filter((t) => t.id !== id));
|
|
1850
|
+
}, []);
|
|
1851
|
+
const toast = react.useCallback(
|
|
1852
|
+
(options) => {
|
|
1853
|
+
const id = ++counter.current;
|
|
1854
|
+
setToasts((list2) => [...list2, { ...options, id }]);
|
|
1855
|
+
const duration = options.duration ?? defaultDuration;
|
|
1856
|
+
if (duration > 0 && !options.closable) {
|
|
1857
|
+
setTimeout(() => dismiss(id), duration);
|
|
1858
|
+
}
|
|
1859
|
+
return id;
|
|
1860
|
+
},
|
|
1861
|
+
[defaultDuration, dismiss]
|
|
1862
|
+
);
|
|
1863
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { toast, dismiss }, children: [
|
|
1864
|
+
children,
|
|
1865
|
+
typeof document !== "undefined" && reactDom.createPortal(
|
|
1866
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1867
|
+
"div",
|
|
1868
|
+
{
|
|
1869
|
+
className: cn(
|
|
1870
|
+
"pointer-events-none fixed z-[100] flex flex-col gap-2",
|
|
1871
|
+
POSITION_CLASS[position]
|
|
1872
|
+
),
|
|
1873
|
+
children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1874
|
+
Snackbar,
|
|
1875
|
+
{
|
|
1876
|
+
icon: t.icon,
|
|
1877
|
+
onClose: t.closable ? () => dismiss(t.id) : void 0,
|
|
1878
|
+
className: "pointer-events-auto",
|
|
1879
|
+
children: t.message
|
|
1880
|
+
},
|
|
1881
|
+
t.id
|
|
1882
|
+
))
|
|
1883
|
+
}
|
|
1884
|
+
),
|
|
1885
|
+
document.body
|
|
1886
|
+
)
|
|
1887
|
+
] });
|
|
1888
|
+
}
|
|
1889
|
+
function Snackbar({
|
|
1890
|
+
icon,
|
|
1891
|
+
onClose,
|
|
1892
|
+
children,
|
|
1893
|
+
className,
|
|
1894
|
+
...props
|
|
1895
|
+
}) {
|
|
1896
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1897
|
+
"div",
|
|
1898
|
+
{
|
|
1899
|
+
role: "status",
|
|
1900
|
+
"aria-live": "polite",
|
|
1901
|
+
className: cn(
|
|
1902
|
+
"flex min-w-48 max-w-sm items-center gap-3 rounded-[8px] bg-surface px-4 py-3 text-sm text-text shadow-lg",
|
|
1903
|
+
className
|
|
1904
|
+
),
|
|
1905
|
+
...props,
|
|
1906
|
+
children: [
|
|
1907
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 [&_svg]:size-5", children: icon }),
|
|
1908
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children }),
|
|
1909
|
+
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1910
|
+
"button",
|
|
1911
|
+
{
|
|
1912
|
+
type: "button",
|
|
1913
|
+
"aria-label": "Dismiss",
|
|
1914
|
+
onClick: onClose,
|
|
1915
|
+
className: "-mr-1 inline-flex size-6 shrink-0 items-center justify-center rounded-full text-text-muted hover:bg-hover hover:text-text",
|
|
1916
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1917
|
+
"svg",
|
|
1918
|
+
{
|
|
1919
|
+
viewBox: "0 0 24 24",
|
|
1920
|
+
className: "size-4",
|
|
1921
|
+
fill: "none",
|
|
1922
|
+
stroke: "currentColor",
|
|
1923
|
+
strokeWidth: "2",
|
|
1924
|
+
strokeLinecap: "round",
|
|
1925
|
+
"aria-hidden": true,
|
|
1926
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 6l12 12M18 6L6 18" })
|
|
1927
|
+
}
|
|
1928
|
+
)
|
|
1929
|
+
}
|
|
1930
|
+
)
|
|
1931
|
+
]
|
|
1932
|
+
}
|
|
1933
|
+
);
|
|
1934
|
+
}
|
|
1935
|
+
var bubble = classVarianceAuthority.cva(
|
|
1936
|
+
"pointer-events-none absolute z-50 w-max max-w-xs rounded-[4px] bg-surface px-3 py-3 text-xs leading-4 text-text opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100",
|
|
1937
|
+
{
|
|
1938
|
+
variants: {
|
|
1939
|
+
placement: {
|
|
1940
|
+
top: "bottom-full left-1/2 mb-2 -translate-x-1/2",
|
|
1941
|
+
"top-start": "bottom-full left-0 mb-2",
|
|
1942
|
+
"top-end": "bottom-full right-0 mb-2",
|
|
1943
|
+
bottom: "top-full left-1/2 mt-2 -translate-x-1/2",
|
|
1944
|
+
"bottom-start": "top-full left-0 mt-2",
|
|
1945
|
+
"bottom-end": "top-full right-0 mt-2",
|
|
1946
|
+
left: "right-full top-1/2 mr-2 -translate-y-1/2",
|
|
1947
|
+
right: "left-full top-1/2 ml-2 -translate-y-1/2"
|
|
1948
|
+
},
|
|
1949
|
+
shadow: {
|
|
1950
|
+
true: "shadow-[0_0_1px_rgba(0,0,0,0.4),0_6px_6px_-6px_rgba(0,0,0,0.16)]",
|
|
1951
|
+
false: ""
|
|
1952
|
+
}
|
|
1953
|
+
},
|
|
1954
|
+
defaultVariants: { placement: "top", shadow: true }
|
|
1955
|
+
}
|
|
1956
|
+
);
|
|
1957
|
+
var arrow = classVarianceAuthority.cva("absolute size-2 rotate-45 bg-surface", {
|
|
1958
|
+
variants: {
|
|
1959
|
+
placement: {
|
|
1960
|
+
top: "bottom-[-4px] left-1/2 -translate-x-1/2",
|
|
1961
|
+
"top-start": "bottom-[-4px] left-3",
|
|
1962
|
+
"top-end": "bottom-[-4px] right-3",
|
|
1963
|
+
bottom: "top-[-4px] left-1/2 -translate-x-1/2",
|
|
1964
|
+
"bottom-start": "top-[-4px] left-3",
|
|
1965
|
+
"bottom-end": "top-[-4px] right-3",
|
|
1966
|
+
left: "right-[-4px] top-1/2 -translate-y-1/2",
|
|
1967
|
+
right: "left-[-4px] top-1/2 -translate-y-1/2"
|
|
1968
|
+
}
|
|
1969
|
+
},
|
|
1970
|
+
defaultVariants: { placement: "top" }
|
|
1971
|
+
});
|
|
1972
|
+
function Tooltip({
|
|
1973
|
+
content,
|
|
1974
|
+
placement = "top",
|
|
1975
|
+
shadow = true,
|
|
1976
|
+
pointer = true,
|
|
1977
|
+
children,
|
|
1978
|
+
className
|
|
1979
|
+
}) {
|
|
1980
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("group relative inline-flex", className), children: [
|
|
1981
|
+
children,
|
|
1982
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { role: "tooltip", className: bubble({ placement, shadow }), children: [
|
|
1983
|
+
content,
|
|
1984
|
+
pointer && /* @__PURE__ */ jsxRuntime.jsx("span", { className: arrow({ placement }), "aria-hidden": true })
|
|
1985
|
+
] })
|
|
1986
|
+
] });
|
|
1987
|
+
}
|
|
1988
|
+
var SidebarContext = react.createContext({
|
|
1989
|
+
collapsed: false
|
|
1990
|
+
});
|
|
1991
|
+
function Sidebar({
|
|
1992
|
+
collapsed = false,
|
|
1993
|
+
className,
|
|
1994
|
+
children,
|
|
1995
|
+
...props
|
|
1996
|
+
}) {
|
|
1997
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SidebarContext.Provider, { value: { collapsed }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1998
|
+
"nav",
|
|
1999
|
+
{
|
|
2000
|
+
"data-collapsed": collapsed || void 0,
|
|
2001
|
+
className: cn(
|
|
2002
|
+
"flex h-full flex-col gap-4 bg-surface text-text transition-[width] duration-200",
|
|
2003
|
+
collapsed ? "w-16 p-2" : "w-[280px] p-6",
|
|
2004
|
+
className
|
|
2005
|
+
),
|
|
2006
|
+
...props,
|
|
2007
|
+
children
|
|
2008
|
+
}
|
|
2009
|
+
) });
|
|
2010
|
+
}
|
|
2011
|
+
function SidebarSection({
|
|
2012
|
+
title,
|
|
2013
|
+
divider,
|
|
2014
|
+
className,
|
|
2015
|
+
children,
|
|
2016
|
+
...props
|
|
2017
|
+
}) {
|
|
2018
|
+
const { collapsed } = react.useContext(SidebarContext);
|
|
2019
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2020
|
+
divider && /* @__PURE__ */ jsxRuntime.jsx("hr", { className: "border-t border-border" }),
|
|
2021
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1", className), ...props, children: [
|
|
2022
|
+
title && !collapsed && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 text-sm text-text-muted", children: title }),
|
|
2023
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children })
|
|
2024
|
+
] })
|
|
2025
|
+
] });
|
|
2026
|
+
}
|
|
2027
|
+
function SidebarItem({
|
|
2028
|
+
icon,
|
|
2029
|
+
active,
|
|
2030
|
+
label,
|
|
2031
|
+
href,
|
|
2032
|
+
className,
|
|
2033
|
+
...props
|
|
2034
|
+
}) {
|
|
2035
|
+
const { collapsed } = react.useContext(SidebarContext);
|
|
2036
|
+
const row = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2037
|
+
"a",
|
|
2038
|
+
{
|
|
2039
|
+
href,
|
|
2040
|
+
"aria-current": active ? "page" : void 0,
|
|
2041
|
+
className: cn(
|
|
2042
|
+
"flex items-center gap-3 rounded-[8px] px-2 py-2 text-sm transition-colors outline-none focus-visible:outline-2 focus-visible:outline-primary",
|
|
2043
|
+
collapsed && "justify-center",
|
|
2044
|
+
active ? "bg-primary-tint font-bold text-primary" : "text-text hover:bg-hover",
|
|
2045
|
+
className
|
|
2046
|
+
),
|
|
2047
|
+
...props,
|
|
2048
|
+
children: [
|
|
2049
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-6 shrink-0 items-center justify-center [&_svg]:size-6", children: icon }),
|
|
2050
|
+
!collapsed && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: label })
|
|
2051
|
+
]
|
|
2052
|
+
}
|
|
2053
|
+
);
|
|
2054
|
+
if (collapsed) {
|
|
2055
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2056
|
+
Tooltip,
|
|
2057
|
+
{
|
|
2058
|
+
content: label,
|
|
2059
|
+
placement: "right",
|
|
2060
|
+
className: "w-full [&>a]:w-full",
|
|
2061
|
+
children: row
|
|
2062
|
+
}
|
|
2063
|
+
);
|
|
2064
|
+
}
|
|
2065
|
+
return row;
|
|
2066
|
+
}
|
|
2067
|
+
function Calendar({ className, classNames, ...props }) {
|
|
2068
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2069
|
+
reactDayPicker.DayPicker,
|
|
2070
|
+
{
|
|
2071
|
+
className: cn(
|
|
2072
|
+
"rounded-[12px] bg-surface p-4 text-text [--rdp-day-width:40px] [--rdp-day-height:40px]",
|
|
2073
|
+
className
|
|
2074
|
+
),
|
|
2075
|
+
classNames: {
|
|
2076
|
+
months: "relative flex flex-col gap-4 sm:flex-row",
|
|
2077
|
+
month: "flex flex-col gap-2",
|
|
2078
|
+
month_caption: "relative flex h-10 items-center justify-center",
|
|
2079
|
+
caption_label: "text-sm font-semibold text-text",
|
|
2080
|
+
nav: "absolute inset-x-0 top-0 flex h-10 items-center justify-between px-1",
|
|
2081
|
+
button_previous: "inline-flex size-8 items-center justify-center rounded-[8px] text-text-muted transition-colors hover:bg-hover hover:text-text disabled:opacity-40",
|
|
2082
|
+
button_next: "inline-flex size-8 items-center justify-center rounded-[8px] text-text-muted transition-colors hover:bg-hover hover:text-text disabled:opacity-40",
|
|
2083
|
+
month_grid: "border-collapse",
|
|
2084
|
+
weekdays: "flex",
|
|
2085
|
+
weekday: "flex size-10 items-center justify-center text-xs font-semibold text-text-muted",
|
|
2086
|
+
week: "flex",
|
|
2087
|
+
day: "p-0 text-center text-sm",
|
|
2088
|
+
day_button: "inline-flex size-10 items-center justify-center rounded-full text-text transition-colors hover:bg-hover focus-visible:outline-2 focus-visible:outline-primary aria-selected:font-semibold",
|
|
2089
|
+
today: "font-semibold text-primary",
|
|
2090
|
+
selected: "[&_button]:bg-text [&_button]:text-background [&_button]:hover:bg-text",
|
|
2091
|
+
range_start: "rounded-l-full bg-primary-tint [&_button]:bg-text [&_button]:text-background",
|
|
2092
|
+
range_end: "rounded-r-full bg-primary-tint [&_button]:bg-text [&_button]:text-background",
|
|
2093
|
+
range_middle: "bg-primary-tint [&_button]:rounded-none [&_button]:bg-transparent [&_button]:text-text [&_button]:hover:bg-primary-tint",
|
|
2094
|
+
outside: "text-text-muted opacity-50",
|
|
2095
|
+
disabled: "text-text-muted opacity-40",
|
|
2096
|
+
hidden: "invisible",
|
|
2097
|
+
...classNames
|
|
2098
|
+
},
|
|
2099
|
+
components: {
|
|
2100
|
+
Chevron: ({ orientation, className: cls }) => /* @__PURE__ */ jsxRuntime.jsx(ChevronIcon, { orientation, className: cls })
|
|
2101
|
+
},
|
|
2102
|
+
...props
|
|
2103
|
+
}
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2106
|
+
function ChevronIcon({
|
|
2107
|
+
orientation,
|
|
2108
|
+
className
|
|
2109
|
+
}) {
|
|
2110
|
+
const d = orientation === "left" ? "m15 18-6-6 6-6" : orientation === "right" ? "m9 18 6-6-6-6" : orientation === "up" ? "m18 15-6-6-6 6" : "m6 9 6 6 6-6";
|
|
2111
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2112
|
+
"svg",
|
|
2113
|
+
{
|
|
2114
|
+
className: cn("size-5", className),
|
|
2115
|
+
viewBox: "0 0 24 24",
|
|
2116
|
+
fill: "none",
|
|
2117
|
+
stroke: "currentColor",
|
|
2118
|
+
strokeWidth: "2",
|
|
2119
|
+
strokeLinecap: "round",
|
|
2120
|
+
strokeLinejoin: "round",
|
|
2121
|
+
"aria-hidden": true,
|
|
2122
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d })
|
|
2123
|
+
}
|
|
2124
|
+
);
|
|
2125
|
+
}
|
|
2126
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
2127
|
+
function TimePicker({
|
|
2128
|
+
value,
|
|
2129
|
+
onChange,
|
|
2130
|
+
minuteStep = 1,
|
|
2131
|
+
className
|
|
2132
|
+
}) {
|
|
2133
|
+
const hours = react.useMemo(() => Array.from({ length: 24 }, (_, i) => i), []);
|
|
2134
|
+
const minutes = react.useMemo(
|
|
2135
|
+
() => Array.from(
|
|
2136
|
+
{ length: Math.ceil(60 / minuteStep) },
|
|
2137
|
+
(_, i) => i * minuteStep
|
|
2138
|
+
),
|
|
2139
|
+
[minuteStep]
|
|
2140
|
+
);
|
|
2141
|
+
const set = (next) => onChange?.({
|
|
2142
|
+
hours: next.hours ?? value?.hours ?? 0,
|
|
2143
|
+
minutes: next.minutes ?? value?.minutes ?? 0
|
|
2144
|
+
});
|
|
2145
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2146
|
+
"div",
|
|
2147
|
+
{
|
|
2148
|
+
className: cn(
|
|
2149
|
+
"flex h-[280px] gap-px overflow-hidden rounded-[16px] bg-background p-1",
|
|
2150
|
+
className
|
|
2151
|
+
),
|
|
2152
|
+
children: [
|
|
2153
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2154
|
+
Column,
|
|
2155
|
+
{
|
|
2156
|
+
items: hours,
|
|
2157
|
+
selected: value?.hours,
|
|
2158
|
+
onSelect: (h) => set({ hours: h }),
|
|
2159
|
+
label: "Hours"
|
|
2160
|
+
}
|
|
2161
|
+
),
|
|
2162
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2163
|
+
Column,
|
|
2164
|
+
{
|
|
2165
|
+
items: minutes,
|
|
2166
|
+
selected: value?.minutes,
|
|
2167
|
+
onSelect: (m) => set({ minutes: m }),
|
|
2168
|
+
label: "Minutes"
|
|
2169
|
+
}
|
|
2170
|
+
)
|
|
2171
|
+
]
|
|
2172
|
+
}
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2175
|
+
function Column({
|
|
2176
|
+
items,
|
|
2177
|
+
selected,
|
|
2178
|
+
onSelect,
|
|
2179
|
+
label
|
|
2180
|
+
}) {
|
|
2181
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2182
|
+
"ul",
|
|
2183
|
+
{
|
|
2184
|
+
"aria-label": label,
|
|
2185
|
+
className: "flex w-12 flex-col gap-1 overflow-y-auto scroll-smooth py-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
2186
|
+
children: items.map((n) => {
|
|
2187
|
+
const active = selected === n;
|
|
2188
|
+
return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2189
|
+
"button",
|
|
2190
|
+
{
|
|
2191
|
+
type: "button",
|
|
2192
|
+
"aria-pressed": active,
|
|
2193
|
+
onClick: () => onSelect(n),
|
|
2194
|
+
className: cn(
|
|
2195
|
+
"flex size-9 items-center justify-center rounded-full text-xs font-semibold transition-colors",
|
|
2196
|
+
active ? "bg-text text-background" : "text-text hover:bg-hover"
|
|
2197
|
+
),
|
|
2198
|
+
children: pad(n)
|
|
2199
|
+
}
|
|
2200
|
+
) }, n);
|
|
2201
|
+
})
|
|
2202
|
+
}
|
|
2203
|
+
);
|
|
2204
|
+
}
|
|
2205
|
+
var startOfDay = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
2206
|
+
var addDays = (d, n) => {
|
|
2207
|
+
const r = startOfDay(d);
|
|
2208
|
+
r.setDate(r.getDate() + n);
|
|
2209
|
+
return r;
|
|
2210
|
+
};
|
|
2211
|
+
var startOfWeek = (d) => addDays(d, -((d.getDay() + 6) % 7));
|
|
2212
|
+
var startOfMonth = (d) => new Date(d.getFullYear(), d.getMonth(), 1);
|
|
2213
|
+
var endOfMonth = (d) => new Date(d.getFullYear(), d.getMonth() + 1, 0);
|
|
2214
|
+
function presetRanges(now) {
|
|
2215
|
+
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
|
2216
|
+
return {
|
|
2217
|
+
today: { from: startOfDay(now), to: startOfDay(now) },
|
|
2218
|
+
yesterday: { from: addDays(now, -1), to: addDays(now, -1) },
|
|
2219
|
+
thisWeek: { from: startOfWeek(now), to: startOfDay(now) },
|
|
2220
|
+
lastWeek: {
|
|
2221
|
+
from: addDays(startOfWeek(now), -7),
|
|
2222
|
+
to: addDays(startOfWeek(now), -1)
|
|
2223
|
+
},
|
|
2224
|
+
thisMonth: { from: startOfMonth(now), to: startOfDay(now) },
|
|
2225
|
+
lastMonth: { from: startOfMonth(lastMonth), to: endOfMonth(lastMonth) }
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
var defaultPresets = [
|
|
2229
|
+
{ label: "Today", range: () => presetRanges(/* @__PURE__ */ new Date()).today },
|
|
2230
|
+
{ label: "Yesterday", range: () => presetRanges(/* @__PURE__ */ new Date()).yesterday },
|
|
2231
|
+
{ label: "This week", range: () => presetRanges(/* @__PURE__ */ new Date()).thisWeek },
|
|
2232
|
+
{ label: "Last week", range: () => presetRanges(/* @__PURE__ */ new Date()).lastWeek },
|
|
2233
|
+
{ label: "This month", range: () => presetRanges(/* @__PURE__ */ new Date()).thisMonth },
|
|
2234
|
+
{ label: "Last month", range: () => presetRanges(/* @__PURE__ */ new Date()).lastMonth }
|
|
2235
|
+
];
|
|
2236
|
+
function DateRangePicker({
|
|
2237
|
+
value,
|
|
2238
|
+
onApply,
|
|
2239
|
+
presets = defaultPresets,
|
|
2240
|
+
numberOfMonths = 2,
|
|
2241
|
+
className
|
|
2242
|
+
}) {
|
|
2243
|
+
const [range, setRange] = react.useState(value);
|
|
2244
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2245
|
+
"div",
|
|
2246
|
+
{
|
|
2247
|
+
className: cn(
|
|
2248
|
+
"inline-flex flex-col overflow-hidden rounded-[12px] bg-surface shadow-[0_0_1px_rgba(0,0,0,0.4),0_6px_6px_-6px_rgba(0,0,0,0.16)]",
|
|
2249
|
+
className
|
|
2250
|
+
),
|
|
2251
|
+
children: [
|
|
2252
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
|
|
2253
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex w-40 shrink-0 flex-col gap-1 border-r border-border p-2", children: presets.map((preset, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2254
|
+
"button",
|
|
2255
|
+
{
|
|
2256
|
+
type: "button",
|
|
2257
|
+
onClick: () => setRange(preset.range()),
|
|
2258
|
+
className: "w-full rounded-[8px] px-3 py-2 text-left text-sm text-text transition-colors hover:bg-hover",
|
|
2259
|
+
children: preset.label
|
|
2260
|
+
}
|
|
2261
|
+
) }, i)) }),
|
|
2262
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2263
|
+
Calendar,
|
|
2264
|
+
{
|
|
2265
|
+
mode: "range",
|
|
2266
|
+
numberOfMonths,
|
|
2267
|
+
selected: range,
|
|
2268
|
+
onSelect: setRange,
|
|
2269
|
+
className: "p-3 shadow-none"
|
|
2270
|
+
}
|
|
2271
|
+
)
|
|
2272
|
+
] }),
|
|
2273
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end border-t border-border p-3", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", onClick: () => onApply?.(range), children: "Apply" }) })
|
|
2274
|
+
]
|
|
2275
|
+
}
|
|
2276
|
+
);
|
|
2277
|
+
}
|
|
2278
|
+
var quarters = [1, 2, 3, 4];
|
|
2279
|
+
var monthsOf = (q) => ["Jan\u2013Mar", "Apr\u2013Jun", "Jul\u2013Sep", "Oct\u2013Dec"][q - 1];
|
|
2280
|
+
function QuarterPicker({
|
|
2281
|
+
value,
|
|
2282
|
+
onChange,
|
|
2283
|
+
year = value?.year ?? (/* @__PURE__ */ new Date()).getFullYear(),
|
|
2284
|
+
onYearChange,
|
|
2285
|
+
className
|
|
2286
|
+
}) {
|
|
2287
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2288
|
+
"div",
|
|
2289
|
+
{
|
|
2290
|
+
className: cn(
|
|
2291
|
+
"w-[280px] rounded-[12px] bg-surface p-4 text-text",
|
|
2292
|
+
className
|
|
2293
|
+
),
|
|
2294
|
+
children: [
|
|
2295
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex h-10 items-center justify-between", children: [
|
|
2296
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2297
|
+
NavButton,
|
|
2298
|
+
{
|
|
2299
|
+
label: "Previous year",
|
|
2300
|
+
onClick: () => onYearChange?.(year - 1),
|
|
2301
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" })
|
|
2302
|
+
}
|
|
2303
|
+
),
|
|
2304
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: year }),
|
|
2305
|
+
/* @__PURE__ */ jsxRuntime.jsx(NavButton, { label: "Next year", onClick: () => onYearChange?.(year + 1), children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) })
|
|
2306
|
+
] }),
|
|
2307
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: quarters.map((q) => {
|
|
2308
|
+
const active = value?.year === year && value?.quarter === q;
|
|
2309
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2310
|
+
"button",
|
|
2311
|
+
{
|
|
2312
|
+
type: "button",
|
|
2313
|
+
"aria-pressed": active,
|
|
2314
|
+
onClick: () => onChange?.({ year, quarter: q }),
|
|
2315
|
+
className: cn(
|
|
2316
|
+
"flex flex-col items-center justify-center rounded-[8px] py-4 transition-colors",
|
|
2317
|
+
active ? "bg-text text-background" : "hover:bg-hover"
|
|
2318
|
+
),
|
|
2319
|
+
children: [
|
|
2320
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-semibold", children: [
|
|
2321
|
+
"Q",
|
|
2322
|
+
q
|
|
2323
|
+
] }),
|
|
2324
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2325
|
+
"span",
|
|
2326
|
+
{
|
|
2327
|
+
className: cn(
|
|
2328
|
+
"text-xs",
|
|
2329
|
+
active ? "text-background/70" : "text-text-muted"
|
|
2330
|
+
),
|
|
2331
|
+
children: monthsOf(q)
|
|
2332
|
+
}
|
|
2333
|
+
)
|
|
2334
|
+
]
|
|
2335
|
+
},
|
|
2336
|
+
q
|
|
2337
|
+
);
|
|
2338
|
+
}) })
|
|
2339
|
+
]
|
|
2340
|
+
}
|
|
2341
|
+
);
|
|
2342
|
+
}
|
|
2343
|
+
function NavButton({
|
|
2344
|
+
label,
|
|
2345
|
+
onClick,
|
|
2346
|
+
children
|
|
2347
|
+
}) {
|
|
2348
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2349
|
+
"button",
|
|
2350
|
+
{
|
|
2351
|
+
type: "button",
|
|
2352
|
+
"aria-label": label,
|
|
2353
|
+
onClick,
|
|
2354
|
+
className: "inline-flex size-8 items-center justify-center rounded-[8px] text-text-muted transition-colors hover:bg-hover hover:text-text",
|
|
2355
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2356
|
+
"svg",
|
|
2357
|
+
{
|
|
2358
|
+
className: "size-5",
|
|
2359
|
+
viewBox: "0 0 24 24",
|
|
2360
|
+
fill: "none",
|
|
2361
|
+
stroke: "currentColor",
|
|
2362
|
+
strokeWidth: "2",
|
|
2363
|
+
strokeLinecap: "round",
|
|
2364
|
+
strokeLinejoin: "round",
|
|
2365
|
+
"aria-hidden": true,
|
|
2366
|
+
children
|
|
2367
|
+
}
|
|
2368
|
+
)
|
|
2369
|
+
}
|
|
2370
|
+
);
|
|
2371
|
+
}
|
|
2372
|
+
var drawer = classVarianceAuthority.cva(
|
|
2373
|
+
"fixed bg-surface p-1 shadow-lg backdrop:bg-overlay open:flex flex-col m-0",
|
|
2374
|
+
{
|
|
2375
|
+
variants: {
|
|
2376
|
+
side: {
|
|
2377
|
+
right: "inset-y-0 right-0 h-full w-[448px] max-w-full rounded-l-[8px]",
|
|
2378
|
+
left: "inset-y-0 left-0 h-full w-[448px] max-w-full rounded-r-[8px]",
|
|
2379
|
+
top: "inset-x-0 top-0 h-auto max-h-full w-full rounded-b-[8px]",
|
|
2380
|
+
bottom: "inset-x-0 bottom-0 h-auto max-h-full w-full rounded-t-[8px]"
|
|
2381
|
+
}
|
|
2382
|
+
},
|
|
2383
|
+
defaultVariants: { side: "right" }
|
|
2384
|
+
}
|
|
2385
|
+
);
|
|
2386
|
+
function Drawer({
|
|
2387
|
+
open,
|
|
2388
|
+
onClose,
|
|
2389
|
+
side = "right",
|
|
2390
|
+
className,
|
|
2391
|
+
children,
|
|
2392
|
+
...props
|
|
2393
|
+
}) {
|
|
2394
|
+
const ref = react.useRef(null);
|
|
2395
|
+
react.useEffect(() => {
|
|
2396
|
+
const dialog = ref.current;
|
|
2397
|
+
if (!dialog) return;
|
|
2398
|
+
if (open && !dialog.open) dialog.showModal();
|
|
2399
|
+
else if (!open && dialog.open) dialog.close();
|
|
2400
|
+
}, [open]);
|
|
2401
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2402
|
+
"dialog",
|
|
2403
|
+
{
|
|
2404
|
+
ref,
|
|
2405
|
+
className: cn(drawer({ side }), className),
|
|
2406
|
+
onClose,
|
|
2407
|
+
onClick: (e) => {
|
|
2408
|
+
if (e.target === ref.current) onClose?.();
|
|
2409
|
+
},
|
|
2410
|
+
...props,
|
|
2411
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2412
|
+
"div",
|
|
2413
|
+
{
|
|
2414
|
+
className: "flex size-full flex-col overflow-auto",
|
|
2415
|
+
onClick: (e) => e.stopPropagation(),
|
|
2416
|
+
children
|
|
2417
|
+
}
|
|
2418
|
+
)
|
|
2419
|
+
}
|
|
2420
|
+
);
|
|
2421
|
+
}
|
|
2422
|
+
var modal = classVarianceAuthority.cva(
|
|
2423
|
+
"m-auto w-full rounded-[12px] bg-surface p-0 shadow-lg backdrop:bg-overlay open:flex flex-col",
|
|
2424
|
+
{
|
|
2425
|
+
variants: {
|
|
2426
|
+
size: {
|
|
2427
|
+
sm: "max-w-sm",
|
|
2428
|
+
md: "max-w-md",
|
|
2429
|
+
lg: "max-w-4xl",
|
|
2430
|
+
xl: "max-w-7xl"
|
|
2431
|
+
}
|
|
2432
|
+
},
|
|
2433
|
+
defaultVariants: { size: "md" }
|
|
2434
|
+
}
|
|
2435
|
+
);
|
|
2436
|
+
function Modal({
|
|
2437
|
+
open,
|
|
2438
|
+
onClose,
|
|
2439
|
+
size = "md",
|
|
2440
|
+
title,
|
|
2441
|
+
className,
|
|
2442
|
+
children,
|
|
2443
|
+
...props
|
|
2444
|
+
}) {
|
|
2445
|
+
const ref = react.useRef(null);
|
|
2446
|
+
react.useEffect(() => {
|
|
2447
|
+
const dialog = ref.current;
|
|
2448
|
+
if (!dialog) return;
|
|
2449
|
+
if (open && !dialog.open) dialog.showModal();
|
|
2450
|
+
else if (!open && dialog.open) dialog.close();
|
|
2451
|
+
}, [open]);
|
|
2452
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2453
|
+
"dialog",
|
|
2454
|
+
{
|
|
2455
|
+
ref,
|
|
2456
|
+
className: cn(modal({ size }), className),
|
|
2457
|
+
onClose,
|
|
2458
|
+
onClick: (e) => {
|
|
2459
|
+
if (e.target === ref.current) onClose?.();
|
|
2460
|
+
},
|
|
2461
|
+
...props,
|
|
2462
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", onClick: (e) => e.stopPropagation(), children: [
|
|
2463
|
+
(title || onClose) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4 border-b border-border px-6 py-4", children: [
|
|
2464
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-bold text-text", children: title }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
2465
|
+
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2466
|
+
"button",
|
|
2467
|
+
{
|
|
2468
|
+
type: "button",
|
|
2469
|
+
"aria-label": "Close",
|
|
2470
|
+
onClick: onClose,
|
|
2471
|
+
className: "-mr-2 inline-flex size-8 shrink-0 items-center justify-center rounded-full text-text-muted hover:bg-hover hover:text-text focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2",
|
|
2472
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2473
|
+
"svg",
|
|
2474
|
+
{
|
|
2475
|
+
viewBox: "0 0 24 24",
|
|
2476
|
+
className: "size-5",
|
|
2477
|
+
fill: "none",
|
|
2478
|
+
stroke: "currentColor",
|
|
2479
|
+
strokeWidth: "2",
|
|
2480
|
+
strokeLinecap: "round",
|
|
2481
|
+
"aria-hidden": true,
|
|
2482
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 6l12 12M18 6L6 18" })
|
|
2483
|
+
}
|
|
2484
|
+
)
|
|
2485
|
+
}
|
|
2486
|
+
)
|
|
2487
|
+
] }),
|
|
2488
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children })
|
|
2489
|
+
] })
|
|
2490
|
+
}
|
|
2491
|
+
);
|
|
2492
|
+
}
|
|
2493
|
+
var DOTS = "\u2026";
|
|
2494
|
+
function paginationRange(current, total, siblings = 1) {
|
|
2495
|
+
const totalShown = siblings * 2 + 5;
|
|
2496
|
+
if (total <= totalShown) {
|
|
2497
|
+
return Array.from({ length: total }, (_, i) => i + 1);
|
|
2498
|
+
}
|
|
2499
|
+
const left = Math.max(current - siblings, 1);
|
|
2500
|
+
const right = Math.min(current + siblings, total);
|
|
2501
|
+
const showLeftDots = left > 2;
|
|
2502
|
+
const showRightDots = right < total - 1;
|
|
2503
|
+
if (!showLeftDots && showRightDots) {
|
|
2504
|
+
const len = siblings * 2 + 3;
|
|
2505
|
+
return [...Array.from({ length: len }, (_, i) => i + 1), DOTS, total];
|
|
2506
|
+
}
|
|
2507
|
+
if (showLeftDots && !showRightDots) {
|
|
2508
|
+
const len = siblings * 2 + 3;
|
|
2509
|
+
return [
|
|
2510
|
+
1,
|
|
2511
|
+
DOTS,
|
|
2512
|
+
...Array.from({ length: len }, (_, i) => total - len + 1 + i)
|
|
2513
|
+
];
|
|
2514
|
+
}
|
|
2515
|
+
return [
|
|
2516
|
+
1,
|
|
2517
|
+
DOTS,
|
|
2518
|
+
...Array.from({ length: right - left + 1 }, (_, i) => left + i),
|
|
2519
|
+
DOTS,
|
|
2520
|
+
total
|
|
2521
|
+
];
|
|
2522
|
+
}
|
|
2523
|
+
function Pagination({
|
|
2524
|
+
page,
|
|
2525
|
+
total,
|
|
2526
|
+
siblings = 1,
|
|
2527
|
+
onPageChange,
|
|
2528
|
+
className,
|
|
2529
|
+
...props
|
|
2530
|
+
}) {
|
|
2531
|
+
const range = paginationRange(page, total, siblings);
|
|
2532
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2533
|
+
"nav",
|
|
2534
|
+
{
|
|
2535
|
+
"aria-label": "Pagination",
|
|
2536
|
+
className: cn("flex items-center gap-1", className),
|
|
2537
|
+
...props,
|
|
2538
|
+
children: [
|
|
2539
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2540
|
+
PageButton,
|
|
2541
|
+
{
|
|
2542
|
+
"aria-label": "Previous page",
|
|
2543
|
+
disabled: page <= 1,
|
|
2544
|
+
onClick: () => onPageChange(page - 1),
|
|
2545
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Chevron, { dir: "left" })
|
|
2546
|
+
}
|
|
2547
|
+
),
|
|
2548
|
+
range.map(
|
|
2549
|
+
(item, i) => item === DOTS ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 text-sm text-text-muted", children: DOTS }, `dots-${i}`) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2550
|
+
PageButton,
|
|
2551
|
+
{
|
|
2552
|
+
"aria-label": `Page ${item}`,
|
|
2553
|
+
"aria-current": item === page ? "page" : void 0,
|
|
2554
|
+
selected: item === page,
|
|
2555
|
+
onClick: () => onPageChange(item),
|
|
2556
|
+
children: item
|
|
2557
|
+
},
|
|
2558
|
+
item
|
|
2559
|
+
)
|
|
2560
|
+
),
|
|
2561
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2562
|
+
PageButton,
|
|
2563
|
+
{
|
|
2564
|
+
"aria-label": "Next page",
|
|
2565
|
+
disabled: page >= total,
|
|
2566
|
+
onClick: () => onPageChange(page + 1),
|
|
2567
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Chevron, { dir: "right" })
|
|
2568
|
+
}
|
|
2569
|
+
)
|
|
2570
|
+
]
|
|
2571
|
+
}
|
|
2572
|
+
);
|
|
2573
|
+
}
|
|
2574
|
+
function PageButton({
|
|
2575
|
+
selected,
|
|
2576
|
+
className,
|
|
2577
|
+
...props
|
|
2578
|
+
}) {
|
|
2579
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2580
|
+
"button",
|
|
2581
|
+
{
|
|
2582
|
+
type: "button",
|
|
2583
|
+
className: cn(
|
|
2584
|
+
"inline-flex size-8 items-center justify-center rounded-[8px] text-sm transition-colors",
|
|
2585
|
+
"focus-visible:outline-2 focus-visible:outline-text focus-visible:outline-offset-2",
|
|
2586
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
2587
|
+
selected ? "bg-primary font-bold text-white" : "text-text hover:bg-hover",
|
|
2588
|
+
className
|
|
2589
|
+
),
|
|
2590
|
+
...props
|
|
2591
|
+
}
|
|
2592
|
+
);
|
|
2593
|
+
}
|
|
2594
|
+
function Chevron({ dir }) {
|
|
2595
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2596
|
+
"svg",
|
|
2597
|
+
{
|
|
2598
|
+
className: cn("size-4", dir === "left" && "rotate-180"),
|
|
2599
|
+
viewBox: "0 0 16 16",
|
|
2600
|
+
fill: "none",
|
|
2601
|
+
stroke: "currentColor",
|
|
2602
|
+
strokeWidth: "1.5",
|
|
2603
|
+
strokeLinecap: "round",
|
|
2604
|
+
strokeLinejoin: "round",
|
|
2605
|
+
"aria-hidden": true,
|
|
2606
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 4 4 4-4 4" })
|
|
2607
|
+
}
|
|
2608
|
+
);
|
|
2609
|
+
}
|
|
2610
|
+
function clampPercent(value) {
|
|
2611
|
+
return Math.max(0, Math.min(100, value));
|
|
2612
|
+
}
|
|
2613
|
+
var LINEAR_THICKNESS = {
|
|
2614
|
+
"6xs": "h-0.5",
|
|
2615
|
+
"5xs": "h-1",
|
|
2616
|
+
"4xs": "h-2",
|
|
2617
|
+
"3xs": "h-3",
|
|
2618
|
+
"2xs": "h-4"
|
|
2619
|
+
};
|
|
2620
|
+
var CIRCULAR_SIZE = {
|
|
2621
|
+
"2xs": 16,
|
|
2622
|
+
xs: 24,
|
|
2623
|
+
sm: 32,
|
|
2624
|
+
md: 40,
|
|
2625
|
+
lg: 48
|
|
2626
|
+
};
|
|
2627
|
+
function Progress({
|
|
2628
|
+
value,
|
|
2629
|
+
className,
|
|
2630
|
+
label = "Progress",
|
|
2631
|
+
...rest
|
|
2632
|
+
}) {
|
|
2633
|
+
const pct = clampPercent(value);
|
|
2634
|
+
const common = {
|
|
2635
|
+
role: "progressbar",
|
|
2636
|
+
"aria-label": label,
|
|
2637
|
+
"aria-valuenow": Math.round(pct),
|
|
2638
|
+
"aria-valuemin": 0,
|
|
2639
|
+
"aria-valuemax": 100
|
|
2640
|
+
};
|
|
2641
|
+
if (rest.variant === "circular") {
|
|
2642
|
+
const px = CIRCULAR_SIZE[rest.size ?? "md"];
|
|
2643
|
+
const stroke = Math.max(2, Math.round(px / 8));
|
|
2644
|
+
const r = (px - stroke) / 2;
|
|
2645
|
+
const circumference = 2 * Math.PI * r;
|
|
2646
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2647
|
+
"svg",
|
|
2648
|
+
{
|
|
2649
|
+
...common,
|
|
2650
|
+
width: px,
|
|
2651
|
+
height: px,
|
|
2652
|
+
viewBox: `0 0 ${px} ${px}`,
|
|
2653
|
+
className: cn("-rotate-90", className),
|
|
2654
|
+
children: [
|
|
2655
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2656
|
+
"circle",
|
|
2657
|
+
{
|
|
2658
|
+
cx: px / 2,
|
|
2659
|
+
cy: px / 2,
|
|
2660
|
+
r,
|
|
2661
|
+
fill: "none",
|
|
2662
|
+
strokeWidth: stroke,
|
|
2663
|
+
className: "stroke-background"
|
|
2664
|
+
}
|
|
2665
|
+
),
|
|
2666
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2667
|
+
"circle",
|
|
2668
|
+
{
|
|
2669
|
+
cx: px / 2,
|
|
2670
|
+
cy: px / 2,
|
|
2671
|
+
r,
|
|
2672
|
+
fill: "none",
|
|
2673
|
+
strokeWidth: stroke,
|
|
2674
|
+
strokeLinecap: "round",
|
|
2675
|
+
strokeDasharray: circumference,
|
|
2676
|
+
strokeDashoffset: circumference * (1 - pct / 100),
|
|
2677
|
+
className: "stroke-primary transition-[stroke-dashoffset]"
|
|
2678
|
+
}
|
|
2679
|
+
)
|
|
2680
|
+
]
|
|
2681
|
+
}
|
|
2682
|
+
);
|
|
2683
|
+
}
|
|
2684
|
+
const thickness = LINEAR_THICKNESS[rest.size ?? "4xs"];
|
|
2685
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2686
|
+
"div",
|
|
2687
|
+
{
|
|
2688
|
+
...common,
|
|
2689
|
+
className: cn(
|
|
2690
|
+
"w-full overflow-hidden rounded-full bg-background",
|
|
2691
|
+
thickness,
|
|
2692
|
+
className
|
|
2693
|
+
),
|
|
2694
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2695
|
+
"div",
|
|
2696
|
+
{
|
|
2697
|
+
className: "h-full rounded-full bg-primary transition-[width]",
|
|
2698
|
+
style: { width: `${pct}%` }
|
|
2699
|
+
}
|
|
2700
|
+
)
|
|
2701
|
+
}
|
|
2702
|
+
);
|
|
2703
|
+
}
|
|
2704
|
+
var DropdownContext = react.createContext(null);
|
|
2705
|
+
function Dropdown({
|
|
2706
|
+
trigger,
|
|
2707
|
+
children,
|
|
2708
|
+
align = "start",
|
|
2709
|
+
className
|
|
2710
|
+
}) {
|
|
2711
|
+
const [open, setOpen] = react.useState(false);
|
|
2712
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DropdownContext.Provider, { value: { close: () => setOpen(false) }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2713
|
+
Popover,
|
|
2714
|
+
{
|
|
2715
|
+
trigger,
|
|
2716
|
+
open,
|
|
2717
|
+
onOpenChange: setOpen,
|
|
2718
|
+
align,
|
|
2719
|
+
className: cn("min-w-40", className),
|
|
2720
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { role: "menu", className: "flex flex-col", children })
|
|
2721
|
+
}
|
|
2722
|
+
) });
|
|
2723
|
+
}
|
|
2724
|
+
function DropdownItem({
|
|
2725
|
+
leading,
|
|
2726
|
+
trailing,
|
|
2727
|
+
description,
|
|
2728
|
+
selected,
|
|
2729
|
+
children,
|
|
2730
|
+
className,
|
|
2731
|
+
onClick,
|
|
2732
|
+
disabled,
|
|
2733
|
+
...props
|
|
2734
|
+
}) {
|
|
2735
|
+
const ctx = react.useContext(DropdownContext);
|
|
2736
|
+
const end = trailing ?? (selected ? /* @__PURE__ */ jsxRuntime.jsx(CheckMark, {}) : null);
|
|
2737
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2738
|
+
"button",
|
|
2739
|
+
{
|
|
2740
|
+
type: "button",
|
|
2741
|
+
role: "menuitem",
|
|
2742
|
+
"aria-current": selected || void 0,
|
|
2743
|
+
disabled,
|
|
2744
|
+
onClick: (e) => {
|
|
2745
|
+
onClick?.(e);
|
|
2746
|
+
ctx?.close();
|
|
2747
|
+
},
|
|
2748
|
+
className: cn(
|
|
2749
|
+
"flex w-full gap-2 rounded-[8px] px-3 py-2 text-left text-sm text-text",
|
|
2750
|
+
description ? "items-start" : "items-center",
|
|
2751
|
+
"hover:bg-hover focus-visible:bg-hover focus-visible:outline-none",
|
|
2752
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
2753
|
+
className
|
|
2754
|
+
),
|
|
2755
|
+
...props,
|
|
2756
|
+
children: [
|
|
2757
|
+
leading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: leading }),
|
|
2758
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-1 flex-col", children: [
|
|
2759
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children }),
|
|
2760
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-text-muted", children: description })
|
|
2761
|
+
] }),
|
|
2762
|
+
end && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: end })
|
|
2763
|
+
]
|
|
2764
|
+
}
|
|
2765
|
+
);
|
|
2766
|
+
}
|
|
2767
|
+
function CheckMark() {
|
|
2768
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2769
|
+
"svg",
|
|
2770
|
+
{
|
|
2771
|
+
className: "size-4 text-primary",
|
|
2772
|
+
viewBox: "0 0 24 24",
|
|
2773
|
+
fill: "none",
|
|
2774
|
+
stroke: "currentColor",
|
|
2775
|
+
strokeWidth: "2",
|
|
2776
|
+
strokeLinecap: "round",
|
|
2777
|
+
strokeLinejoin: "round",
|
|
2778
|
+
"aria-hidden": true,
|
|
2779
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" })
|
|
2780
|
+
}
|
|
2781
|
+
);
|
|
2782
|
+
}
|
|
2783
|
+
function filterOptions(options, query) {
|
|
2784
|
+
const q = query.trim().toLowerCase();
|
|
2785
|
+
if (!q) return options;
|
|
2786
|
+
return options.filter((o) => o.label.toLowerCase().includes(q));
|
|
2787
|
+
}
|
|
2788
|
+
function Combobox(props) {
|
|
2789
|
+
const {
|
|
2790
|
+
options,
|
|
2791
|
+
placeholder = "Select\u2026",
|
|
2792
|
+
disabled,
|
|
2793
|
+
className,
|
|
2794
|
+
emptyMessage = "No results"
|
|
2795
|
+
} = props;
|
|
2796
|
+
const [open, setOpen] = react.useState(false);
|
|
2797
|
+
const [query, setQuery] = react.useState("");
|
|
2798
|
+
const [activeIndex, setActiveIndex] = react.useState(0);
|
|
2799
|
+
const filtered = react.useMemo(
|
|
2800
|
+
() => filterOptions(options, query),
|
|
2801
|
+
[options, query]
|
|
2802
|
+
);
|
|
2803
|
+
const selectedValues = props.multiple ? props.value : props.value ? [props.value] : [];
|
|
2804
|
+
const labelFor = (v) => options.find((o) => o.value === v)?.label ?? v;
|
|
2805
|
+
const isSelected = (v) => selectedValues.includes(v);
|
|
2806
|
+
const commit = (v) => {
|
|
2807
|
+
if (props.multiple) {
|
|
2808
|
+
const set = new Set(props.value);
|
|
2809
|
+
if (set.has(v)) set.delete(v);
|
|
2810
|
+
else set.add(v);
|
|
2811
|
+
props.onChange([...set]);
|
|
2812
|
+
setQuery("");
|
|
2813
|
+
} else {
|
|
2814
|
+
props.onChange(v);
|
|
2815
|
+
setQuery("");
|
|
2816
|
+
setOpen(false);
|
|
2817
|
+
}
|
|
2818
|
+
};
|
|
2819
|
+
const onKeyDown = (e) => {
|
|
2820
|
+
if (e.key === "ArrowDown") {
|
|
2821
|
+
e.preventDefault();
|
|
2822
|
+
setOpen(true);
|
|
2823
|
+
setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
|
|
2824
|
+
} else if (e.key === "ArrowUp") {
|
|
2825
|
+
e.preventDefault();
|
|
2826
|
+
setActiveIndex((i) => Math.max(i - 1, 0));
|
|
2827
|
+
} else if (e.key === "Enter") {
|
|
2828
|
+
e.preventDefault();
|
|
2829
|
+
const opt = filtered[activeIndex];
|
|
2830
|
+
if (opt) commit(opt.value);
|
|
2831
|
+
} else if (e.key === "Escape") {
|
|
2832
|
+
setOpen(false);
|
|
2833
|
+
} else if (e.key === "Backspace" && !query && props.multiple && props.value.length) {
|
|
2834
|
+
props.onChange(props.value.slice(0, -1));
|
|
2835
|
+
}
|
|
2836
|
+
};
|
|
2837
|
+
const singleSelectedLabel = !props.multiple && props.value ? labelFor(props.value) : "";
|
|
2838
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative w-full", className), children: [
|
|
2839
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2840
|
+
"div",
|
|
2841
|
+
{
|
|
2842
|
+
className: cn(
|
|
2843
|
+
"flex min-h-10 w-full flex-wrap items-center gap-1 rounded-[8px] border border-border bg-surface px-2 py-1 text-sm",
|
|
2844
|
+
"focus-within:border-[1.5px] focus-within:border-primary",
|
|
2845
|
+
disabled && "pointer-events-none opacity-50"
|
|
2846
|
+
),
|
|
2847
|
+
onClick: () => setOpen(true),
|
|
2848
|
+
children: [
|
|
2849
|
+
props.multiple && props.value.map((v) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2850
|
+
Chip,
|
|
2851
|
+
{
|
|
2852
|
+
size: "sm",
|
|
2853
|
+
onDismiss: () => props.onChange(props.value.filter((x) => x !== v)),
|
|
2854
|
+
children: labelFor(v)
|
|
2855
|
+
},
|
|
2856
|
+
v
|
|
2857
|
+
)),
|
|
2858
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2859
|
+
"input",
|
|
2860
|
+
{
|
|
2861
|
+
className: "min-w-[60px] flex-1 bg-transparent text-text outline-none placeholder:text-text-muted",
|
|
2862
|
+
value: query || (!open ? singleSelectedLabel : ""),
|
|
2863
|
+
placeholder: selectedValues.length ? "" : placeholder,
|
|
2864
|
+
disabled,
|
|
2865
|
+
role: "combobox",
|
|
2866
|
+
"aria-expanded": open,
|
|
2867
|
+
"aria-autocomplete": "list",
|
|
2868
|
+
onChange: (e) => {
|
|
2869
|
+
setQuery(e.target.value);
|
|
2870
|
+
setOpen(true);
|
|
2871
|
+
setActiveIndex(0);
|
|
2872
|
+
},
|
|
2873
|
+
onFocus: () => setOpen(true),
|
|
2874
|
+
onBlur: () => setTimeout(() => setOpen(false), 120),
|
|
2875
|
+
onKeyDown
|
|
2876
|
+
}
|
|
2877
|
+
),
|
|
2878
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2879
|
+
ChevronDown4,
|
|
2880
|
+
{
|
|
2881
|
+
className: cn(
|
|
2882
|
+
"size-5 shrink-0 text-text-muted transition-transform",
|
|
2883
|
+
open && "rotate-180"
|
|
2884
|
+
)
|
|
2885
|
+
}
|
|
2886
|
+
)
|
|
2887
|
+
]
|
|
2888
|
+
}
|
|
2889
|
+
),
|
|
2890
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2891
|
+
"ul",
|
|
2892
|
+
{
|
|
2893
|
+
role: "listbox",
|
|
2894
|
+
className: "absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-[12px] border border-border bg-surface p-1 shadow-lg",
|
|
2895
|
+
children: filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-sm text-text-muted", children: emptyMessage }) : filtered.map((opt, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2896
|
+
"li",
|
|
2897
|
+
{
|
|
2898
|
+
role: "option",
|
|
2899
|
+
"aria-selected": isSelected(opt.value),
|
|
2900
|
+
onMouseEnter: () => setActiveIndex(i),
|
|
2901
|
+
onMouseDown: (e) => {
|
|
2902
|
+
e.preventDefault();
|
|
2903
|
+
commit(opt.value);
|
|
2904
|
+
},
|
|
2905
|
+
className: cn(
|
|
2906
|
+
"flex cursor-pointer items-center justify-between rounded-[8px] px-3 py-2 text-sm text-text",
|
|
2907
|
+
i === activeIndex && "bg-hover"
|
|
2908
|
+
),
|
|
2909
|
+
children: [
|
|
2910
|
+
opt.label,
|
|
2911
|
+
isSelected(opt.value) && /* @__PURE__ */ jsxRuntime.jsx(Check, { className: "size-4 text-primary" })
|
|
2912
|
+
]
|
|
2913
|
+
},
|
|
2914
|
+
opt.value
|
|
2915
|
+
))
|
|
2916
|
+
}
|
|
2917
|
+
)
|
|
2918
|
+
] });
|
|
2919
|
+
}
|
|
2920
|
+
function ChevronDown4({ className }) {
|
|
2921
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2922
|
+
"svg",
|
|
2923
|
+
{
|
|
2924
|
+
className,
|
|
2925
|
+
viewBox: "0 0 24 24",
|
|
2926
|
+
fill: "none",
|
|
2927
|
+
stroke: "currentColor",
|
|
2928
|
+
strokeWidth: "2",
|
|
2929
|
+
strokeLinecap: "round",
|
|
2930
|
+
strokeLinejoin: "round",
|
|
2931
|
+
"aria-hidden": true,
|
|
2932
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
|
|
2933
|
+
}
|
|
2934
|
+
);
|
|
2935
|
+
}
|
|
2936
|
+
function Check({ className }) {
|
|
2937
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2938
|
+
"svg",
|
|
2939
|
+
{
|
|
2940
|
+
className,
|
|
2941
|
+
viewBox: "0 0 24 24",
|
|
2942
|
+
fill: "none",
|
|
2943
|
+
stroke: "currentColor",
|
|
2944
|
+
strokeWidth: "2",
|
|
2945
|
+
strokeLinecap: "round",
|
|
2946
|
+
strokeLinejoin: "round",
|
|
2947
|
+
"aria-hidden": true,
|
|
2948
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" })
|
|
2949
|
+
}
|
|
2950
|
+
);
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
exports.Accordion = Accordion;
|
|
2954
|
+
exports.Alert = Alert;
|
|
2955
|
+
exports.AuthCode = AuthCode;
|
|
2956
|
+
exports.Avatar = Avatar;
|
|
2957
|
+
exports.Breadcrumbs = Breadcrumbs;
|
|
2958
|
+
exports.Button = Button;
|
|
2959
|
+
exports.Calendar = Calendar;
|
|
2960
|
+
exports.Carousel = Carousel;
|
|
2961
|
+
exports.Checkbox = Checkbox;
|
|
2962
|
+
exports.Chip = Chip;
|
|
2963
|
+
exports.Combobox = Combobox;
|
|
2964
|
+
exports.Container = Container;
|
|
2965
|
+
exports.DataTable = DataTable;
|
|
2966
|
+
exports.DateRangePicker = DateRangePicker;
|
|
2967
|
+
exports.Drawer = Drawer;
|
|
2968
|
+
exports.Dropdown = Dropdown;
|
|
2969
|
+
exports.DropdownItem = DropdownItem;
|
|
2970
|
+
exports.EmptyState = EmptyState;
|
|
2971
|
+
exports.GroupField = GroupField;
|
|
2972
|
+
exports.Loader = Loader;
|
|
2973
|
+
exports.Modal = Modal;
|
|
2974
|
+
exports.Pagination = Pagination;
|
|
2975
|
+
exports.Popover = Popover;
|
|
2976
|
+
exports.Progress = Progress;
|
|
2977
|
+
exports.QuarterPicker = QuarterPicker;
|
|
2978
|
+
exports.Radio = Radio;
|
|
2979
|
+
exports.Search = Search;
|
|
2980
|
+
exports.SegmentedControl = SegmentedControl;
|
|
2981
|
+
exports.Select = Select;
|
|
2982
|
+
exports.Sidebar = Sidebar;
|
|
2983
|
+
exports.SidebarItem = SidebarItem;
|
|
2984
|
+
exports.SidebarSection = SidebarSection;
|
|
2985
|
+
exports.Snackbar = Snackbar;
|
|
2986
|
+
exports.Switch = Switch;
|
|
2987
|
+
exports.Tab = Tab;
|
|
2988
|
+
exports.TabList = TabList;
|
|
2989
|
+
exports.TabPanel = TabPanel;
|
|
2990
|
+
exports.Table = Table;
|
|
2991
|
+
exports.TableBody = TableBody;
|
|
2992
|
+
exports.TableCell = TableCell;
|
|
2993
|
+
exports.TableHead = TableHead;
|
|
2994
|
+
exports.TableRow = TableRow;
|
|
2995
|
+
exports.Tabs = Tabs;
|
|
2996
|
+
exports.Tag = Tag;
|
|
2997
|
+
exports.TextInput = TextInput;
|
|
2998
|
+
exports.TextInputGroup = TextInputGroup;
|
|
2999
|
+
exports.Textarea = Textarea;
|
|
3000
|
+
exports.TimePicker = TimePicker;
|
|
3001
|
+
exports.ToastProvider = ToastProvider;
|
|
3002
|
+
exports.Tooltip = Tooltip;
|
|
3003
|
+
exports.buttonVariants = buttonVariants;
|
|
3004
|
+
exports.clampPercent = clampPercent;
|
|
3005
|
+
exports.cn = cn;
|
|
3006
|
+
exports.defaultPresets = defaultPresets;
|
|
3007
|
+
exports.filterOptions = filterOptions;
|
|
3008
|
+
exports.paginationRange = paginationRange;
|
|
3009
|
+
exports.presetRanges = presetRanges;
|
|
3010
|
+
exports.selectionState = selectionState;
|
|
3011
|
+
exports.useToast = useToast;
|