avt-rct-lib 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -0
- package/dist/index.cjs +1341 -0
- package/dist/index.d.cts +298 -0
- package/dist/index.d.ts +298 -0
- package/dist/index.js +1266 -0
- package/package.json +54 -0
- package/src/styles/base.css +57 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1266 @@
|
|
|
1
|
+
import React3, { createContext, useState, useReducer, useEffect, useCallback, useRef, useContext } from 'react';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
|
|
5
|
+
// src/components/Button.tsx
|
|
6
|
+
|
|
7
|
+
// src/lib/utils.ts
|
|
8
|
+
function cn(...inputs) {
|
|
9
|
+
const result = [];
|
|
10
|
+
for (const input of inputs) {
|
|
11
|
+
if (!input && input !== 0) continue;
|
|
12
|
+
if (typeof input === "string" || typeof input === "number") {
|
|
13
|
+
result.push(String(input));
|
|
14
|
+
} else if (Array.isArray(input)) {
|
|
15
|
+
const inner = cn(...input);
|
|
16
|
+
if (inner) result.push(inner);
|
|
17
|
+
} else if (typeof input === "object") {
|
|
18
|
+
for (const [key, val] of Object.entries(input)) {
|
|
19
|
+
if (val) result.push(key);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return result.join(" ");
|
|
24
|
+
}
|
|
25
|
+
var colors = {
|
|
26
|
+
blue: "#007AFF",
|
|
27
|
+
green: "#34C759",
|
|
28
|
+
red: "#FF3B30",
|
|
29
|
+
orange: "#FF9500",
|
|
30
|
+
purple: "#AF52DE",
|
|
31
|
+
teal: "#5AC8FA",
|
|
32
|
+
indigo: "#5856D6",
|
|
33
|
+
bg: "#F2F2F7",
|
|
34
|
+
card: "#FFFFFF",
|
|
35
|
+
label: "#1C1C1E",
|
|
36
|
+
label2: "#3C3C43",
|
|
37
|
+
label3: "#8E8E93",
|
|
38
|
+
sep: "#E5E5EA",
|
|
39
|
+
fill: "#F2F2F7",
|
|
40
|
+
fill2: "#E5E5EA",
|
|
41
|
+
fill3: "#D1D1D6"
|
|
42
|
+
};
|
|
43
|
+
function generateId() {
|
|
44
|
+
return Math.random().toString(36).slice(2, 9);
|
|
45
|
+
}
|
|
46
|
+
var base = [
|
|
47
|
+
"inline-flex items-center justify-center gap-2 font-medium select-none",
|
|
48
|
+
"transition-all duration-150 focus-visible:outline-none",
|
|
49
|
+
"focus-visible:ring-2 focus-visible:ring-[#007AFF]/40 focus-visible:ring-offset-1",
|
|
50
|
+
"disabled:pointer-events-none disabled:opacity-40",
|
|
51
|
+
"active:scale-[0.97]"
|
|
52
|
+
].join(" ");
|
|
53
|
+
var variants = {
|
|
54
|
+
primary: "bg-[#007AFF] text-white rounded-xl shadow-[0_2px_8px_rgba(0,122,255,0.28)] hover:bg-[#0071EB] hover:shadow-[0_4px_12px_rgba(0,122,255,0.35)]",
|
|
55
|
+
secondary: "bg-[#F2F2F7] text-[#1C1C1E] rounded-xl hover:bg-[#E5E5EA]",
|
|
56
|
+
ghost: "text-[#007AFF] rounded-xl hover:bg-[#007AFF]/10",
|
|
57
|
+
outline: "border border-[#E5E5EA] bg-white text-[#1C1C1E] rounded-xl hover:bg-[#F2F2F7] shadow-[0_1px_3px_rgba(0,0,0,0.06)]",
|
|
58
|
+
destructive: "bg-[#FF3B30] text-white rounded-xl shadow-[0_2px_8px_rgba(255,59,48,0.25)] hover:bg-[#E0352B]",
|
|
59
|
+
link: "text-[#007AFF] underline-offset-4 hover:underline p-0 h-auto"
|
|
60
|
+
};
|
|
61
|
+
var sizes = {
|
|
62
|
+
xs: "h-7 px-3 text-xs",
|
|
63
|
+
sm: "h-8 px-4 text-sm",
|
|
64
|
+
md: "h-10 px-5 text-sm",
|
|
65
|
+
lg: "h-12 px-7 text-[15px]",
|
|
66
|
+
icon: "h-9 w-9 rounded-xl"
|
|
67
|
+
};
|
|
68
|
+
var Spinner = () => /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [
|
|
69
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3" }),
|
|
70
|
+
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
71
|
+
] });
|
|
72
|
+
var Button = React3.forwardRef(
|
|
73
|
+
({
|
|
74
|
+
variant = "primary",
|
|
75
|
+
size = "md",
|
|
76
|
+
loading = false,
|
|
77
|
+
leftIcon,
|
|
78
|
+
rightIcon,
|
|
79
|
+
fullWidth = false,
|
|
80
|
+
className,
|
|
81
|
+
children,
|
|
82
|
+
disabled,
|
|
83
|
+
...props
|
|
84
|
+
}, ref) => /* @__PURE__ */ jsxs(
|
|
85
|
+
"button",
|
|
86
|
+
{
|
|
87
|
+
ref,
|
|
88
|
+
disabled: disabled || loading,
|
|
89
|
+
className: cn(base, variants[variant], sizes[size], fullWidth && "w-full", className),
|
|
90
|
+
...props,
|
|
91
|
+
children: [
|
|
92
|
+
loading ? /* @__PURE__ */ jsx(Spinner, {}) : leftIcon,
|
|
93
|
+
children,
|
|
94
|
+
!loading && rightIcon
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
Button.displayName = "Button";
|
|
100
|
+
var variants2 = {
|
|
101
|
+
default: "bg-[#007AFF]/10 text-[#007AFF]",
|
|
102
|
+
secondary: "bg-[#F2F2F7] text-[#3C3C43]",
|
|
103
|
+
success: "bg-[#34C759]/12 text-[#1A8C39]",
|
|
104
|
+
warning: "bg-[#FF9500]/12 text-[#B86800]",
|
|
105
|
+
destructive: "bg-[#FF3B30]/10 text-[#D0302A]",
|
|
106
|
+
purple: "bg-[#AF52DE]/10 text-[#8B3BB5]",
|
|
107
|
+
outline: "border border-[#E5E5EA] bg-transparent text-[#3C3C43]"
|
|
108
|
+
};
|
|
109
|
+
var dotColors = {
|
|
110
|
+
default: "bg-[#007AFF]",
|
|
111
|
+
secondary: "bg-[#8E8E93]",
|
|
112
|
+
success: "bg-[#34C759]",
|
|
113
|
+
warning: "bg-[#FF9500]",
|
|
114
|
+
destructive: "bg-[#FF3B30]",
|
|
115
|
+
purple: "bg-[#AF52DE]",
|
|
116
|
+
outline: "bg-[#8E8E93]"
|
|
117
|
+
};
|
|
118
|
+
function Badge({ variant = "default", dot = false, className, children, ...props }) {
|
|
119
|
+
return /* @__PURE__ */ jsxs(
|
|
120
|
+
"span",
|
|
121
|
+
{
|
|
122
|
+
className: cn(
|
|
123
|
+
"inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium select-none",
|
|
124
|
+
variants2[variant],
|
|
125
|
+
className
|
|
126
|
+
),
|
|
127
|
+
...props,
|
|
128
|
+
children: [
|
|
129
|
+
dot && /* @__PURE__ */ jsx("span", { className: cn("h-1.5 w-1.5 flex-shrink-0 rounded-full", dotColors[variant]) }),
|
|
130
|
+
children
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
var Input = React3.forwardRef(
|
|
136
|
+
({ label, hint, error, leftAddon, rightAddon, containerClassName, className, id, ...props }, ref) => {
|
|
137
|
+
const inputId = id ?? label?.toLowerCase().replace(/\s+/g, "-");
|
|
138
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", containerClassName), children: [
|
|
139
|
+
label && /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "text-[13px] font-medium text-[#3C3C43]", children: label }),
|
|
140
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
|
|
141
|
+
leftAddon && /* @__PURE__ */ jsx("div", { className: "absolute left-3.5 flex items-center text-[#8E8E93]", children: leftAddon }),
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
"input",
|
|
144
|
+
{
|
|
145
|
+
id: inputId,
|
|
146
|
+
ref,
|
|
147
|
+
className: cn(
|
|
148
|
+
"flex h-11 w-full rounded-xl bg-[#F2F2F7] text-sm text-[#1C1C1E]",
|
|
149
|
+
"px-4 placeholder:text-[#8E8E93]",
|
|
150
|
+
"border-0 outline-none",
|
|
151
|
+
"transition-all duration-150",
|
|
152
|
+
"focus:bg-white focus:shadow-[0_0_0_2px_rgba(0,122,255,0.22)]",
|
|
153
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
154
|
+
error && "bg-[#FF3B30]/6 focus:shadow-[0_0_0_2px_rgba(255,59,48,0.22)]",
|
|
155
|
+
leftAddon && "pl-9",
|
|
156
|
+
rightAddon && "pr-9",
|
|
157
|
+
className
|
|
158
|
+
),
|
|
159
|
+
...props
|
|
160
|
+
}
|
|
161
|
+
),
|
|
162
|
+
rightAddon && /* @__PURE__ */ jsx("div", { className: "absolute right-3.5 flex items-center text-[#8E8E93]", children: rightAddon })
|
|
163
|
+
] }),
|
|
164
|
+
error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[#FF3B30]", children: error }) : hint ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[#8E8E93]", children: hint }) : null
|
|
165
|
+
] });
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
Input.displayName = "Input";
|
|
169
|
+
var Textarea = React3.forwardRef(
|
|
170
|
+
({ label, hint, error, containerClassName, className, id, ...props }, ref) => {
|
|
171
|
+
const inputId = id ?? label?.toLowerCase().replace(/\s+/g, "-");
|
|
172
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", containerClassName), children: [
|
|
173
|
+
label && /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "text-[13px] font-medium text-[#3C3C43]", children: label }),
|
|
174
|
+
/* @__PURE__ */ jsx(
|
|
175
|
+
"textarea",
|
|
176
|
+
{
|
|
177
|
+
id: inputId,
|
|
178
|
+
ref,
|
|
179
|
+
className: cn(
|
|
180
|
+
"w-full rounded-xl bg-[#F2F2F7] px-4 py-3 text-sm text-[#1C1C1E]",
|
|
181
|
+
"placeholder:text-[#8E8E93] border-0 outline-none resize-none",
|
|
182
|
+
"transition-all duration-150",
|
|
183
|
+
"focus:bg-white focus:shadow-[0_0_0_2px_rgba(0,122,255,0.22)]",
|
|
184
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
185
|
+
error && "bg-[#FF3B30]/6 focus:shadow-[0_0_0_2px_rgba(255,59,48,0.22)]",
|
|
186
|
+
className
|
|
187
|
+
),
|
|
188
|
+
...props
|
|
189
|
+
}
|
|
190
|
+
),
|
|
191
|
+
error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[#FF3B30]", children: error }) : hint ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[#8E8E93]", children: hint }) : null
|
|
192
|
+
] });
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
Textarea.displayName = "Textarea";
|
|
196
|
+
function Card({ hover = false, glass = false, padding = "none", className, ...props }) {
|
|
197
|
+
const paddings = { none: "", sm: "p-4", md: "p-5", lg: "p-6" };
|
|
198
|
+
return /* @__PURE__ */ jsx(
|
|
199
|
+
"div",
|
|
200
|
+
{
|
|
201
|
+
className: cn(
|
|
202
|
+
"rounded-2xl border border-[#E5E5EA]/60",
|
|
203
|
+
glass ? "bg-white/75 backdrop-blur-2xl" : "bg-white",
|
|
204
|
+
"shadow-[0_2px_8px_rgba(0,0,0,0.07),_0_0_1px_rgba(0,0,0,0.04)]",
|
|
205
|
+
hover && "transition-shadow duration-200 hover:shadow-[0_4px_16px_rgba(0,0,0,0.10)] cursor-pointer",
|
|
206
|
+
paddings[padding],
|
|
207
|
+
className
|
|
208
|
+
),
|
|
209
|
+
...props
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
function CardHeader({ className, ...props }) {
|
|
214
|
+
return /* @__PURE__ */ jsx("div", { className: cn("px-5 pt-5 pb-4", className), ...props });
|
|
215
|
+
}
|
|
216
|
+
function CardTitle({ className, ...props }) {
|
|
217
|
+
return /* @__PURE__ */ jsx(
|
|
218
|
+
"h3",
|
|
219
|
+
{
|
|
220
|
+
className: cn("text-[15px] font-semibold tracking-[-0.01em] text-[#1C1C1E]", className),
|
|
221
|
+
...props
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
function CardDescription({ className, ...props }) {
|
|
226
|
+
return /* @__PURE__ */ jsx("p", { className: cn("mt-0.5 text-[13px] text-[#8E8E93]", className), ...props });
|
|
227
|
+
}
|
|
228
|
+
function CardContent({ className, ...props }) {
|
|
229
|
+
return /* @__PURE__ */ jsx("div", { className: cn("px-5 pb-5", className), ...props });
|
|
230
|
+
}
|
|
231
|
+
function CardFooter({ className, ...props }) {
|
|
232
|
+
return /* @__PURE__ */ jsx(
|
|
233
|
+
"div",
|
|
234
|
+
{
|
|
235
|
+
className: cn(
|
|
236
|
+
"flex items-center justify-between px-5 py-3.5",
|
|
237
|
+
"border-t border-[#F2F2F7] bg-[#FAFAFA] rounded-b-2xl",
|
|
238
|
+
className
|
|
239
|
+
),
|
|
240
|
+
...props
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
function CardDivider({ className, ...props }) {
|
|
245
|
+
return /* @__PURE__ */ jsx("hr", { className: cn("border-0 border-t border-[#F2F2F7]", className), ...props });
|
|
246
|
+
}
|
|
247
|
+
function Table({ card = true, className, children, ...props }) {
|
|
248
|
+
const childArray = React3.Children.toArray(children);
|
|
249
|
+
const toolbars = childArray.filter((c) => React3.isValidElement(c) && c.type === TableToolbar);
|
|
250
|
+
const paginations = childArray.filter((c) => React3.isValidElement(c) && c.type === TablePagination);
|
|
251
|
+
const tableNodes = childArray.filter(
|
|
252
|
+
(c) => React3.isValidElement(c) && c.type !== TableToolbar && c.type !== TablePagination
|
|
253
|
+
);
|
|
254
|
+
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
255
|
+
toolbars,
|
|
256
|
+
/* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto avt-scroll", children: /* @__PURE__ */ jsx("table", { className: "w-full caption-bottom text-sm", children: tableNodes }) }),
|
|
257
|
+
paginations
|
|
258
|
+
] });
|
|
259
|
+
if (!card) return /* @__PURE__ */ jsx(Fragment, { children: inner });
|
|
260
|
+
return /* @__PURE__ */ jsx(
|
|
261
|
+
"div",
|
|
262
|
+
{
|
|
263
|
+
className: cn(
|
|
264
|
+
"rounded-2xl border border-[#E5E5EA]/60 bg-white overflow-hidden",
|
|
265
|
+
"shadow-[0_2px_8px_rgba(0,0,0,0.07)]",
|
|
266
|
+
className
|
|
267
|
+
),
|
|
268
|
+
...props,
|
|
269
|
+
children: inner
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
function TableHeader({ className, ...props }) {
|
|
274
|
+
return /* @__PURE__ */ jsx(
|
|
275
|
+
"thead",
|
|
276
|
+
{
|
|
277
|
+
className: cn("bg-[#F9F9F9] border-b border-[#F2F2F7]", className),
|
|
278
|
+
...props
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
function TableBody({ className, ...props }) {
|
|
283
|
+
return /* @__PURE__ */ jsx("tbody", { className: cn("[&_tr:last-child]:border-0", className), ...props });
|
|
284
|
+
}
|
|
285
|
+
function TableFooter({ className, ...props }) {
|
|
286
|
+
return /* @__PURE__ */ jsx(
|
|
287
|
+
"tfoot",
|
|
288
|
+
{
|
|
289
|
+
className: cn("border-t border-[#F2F2F7] bg-[#FAFAFA] font-medium", className),
|
|
290
|
+
...props
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
function TableRow({ className, ...props }) {
|
|
295
|
+
return /* @__PURE__ */ jsx(
|
|
296
|
+
"tr",
|
|
297
|
+
{
|
|
298
|
+
className: cn(
|
|
299
|
+
"border-b border-[#F2F2F7] transition-colors duration-100",
|
|
300
|
+
"hover:bg-[#007AFF]/[0.03]",
|
|
301
|
+
className
|
|
302
|
+
),
|
|
303
|
+
...props
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
function TableHead({ className, ...props }) {
|
|
308
|
+
return /* @__PURE__ */ jsx(
|
|
309
|
+
"th",
|
|
310
|
+
{
|
|
311
|
+
className: cn(
|
|
312
|
+
"h-10 px-4 text-left align-middle",
|
|
313
|
+
"text-[11px] font-semibold text-[#8E8E93] uppercase tracking-wider",
|
|
314
|
+
className
|
|
315
|
+
),
|
|
316
|
+
...props
|
|
317
|
+
}
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
function TableCell({ className, ...props }) {
|
|
321
|
+
return /* @__PURE__ */ jsx("td", { className: cn("px-4 py-3.5 align-middle text-[13px] text-[#1C1C1E]", className), ...props });
|
|
322
|
+
}
|
|
323
|
+
function TableCaption({ className, ...props }) {
|
|
324
|
+
return /* @__PURE__ */ jsx("caption", { className: cn("mt-4 text-xs text-[#8E8E93]", className), ...props });
|
|
325
|
+
}
|
|
326
|
+
function TableToolbar({ className, ...props }) {
|
|
327
|
+
return /* @__PURE__ */ jsx(
|
|
328
|
+
"div",
|
|
329
|
+
{
|
|
330
|
+
className: cn("flex items-center gap-3 px-5 py-3.5 border-b border-[#F2F2F7]", className),
|
|
331
|
+
...props
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
function TablePagination({
|
|
336
|
+
page,
|
|
337
|
+
pageCount,
|
|
338
|
+
canPrev,
|
|
339
|
+
canNext,
|
|
340
|
+
onPrev,
|
|
341
|
+
onNext,
|
|
342
|
+
className
|
|
343
|
+
}) {
|
|
344
|
+
const Btn = ({
|
|
345
|
+
onClick,
|
|
346
|
+
disabled,
|
|
347
|
+
children
|
|
348
|
+
}) => /* @__PURE__ */ jsx(
|
|
349
|
+
"button",
|
|
350
|
+
{
|
|
351
|
+
onClick,
|
|
352
|
+
disabled,
|
|
353
|
+
className: "flex h-7 w-7 items-center justify-center rounded-lg bg-[#F2F2F7] text-[#3C3C43] hover:bg-[#E5E5EA] disabled:opacity-40 transition-colors",
|
|
354
|
+
children
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
return /* @__PURE__ */ jsxs(
|
|
358
|
+
"div",
|
|
359
|
+
{
|
|
360
|
+
className: cn(
|
|
361
|
+
"flex items-center justify-between border-t border-[#F2F2F7] px-5 py-3",
|
|
362
|
+
className
|
|
363
|
+
),
|
|
364
|
+
children: [
|
|
365
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[12px] text-[#8E8E93]", children: [
|
|
366
|
+
"Halaman ",
|
|
367
|
+
page,
|
|
368
|
+
" dari ",
|
|
369
|
+
pageCount || 1
|
|
370
|
+
] }),
|
|
371
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
|
|
372
|
+
/* @__PURE__ */ jsx(Btn, { onClick: onPrev, disabled: !canPrev, children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M15 18l-6-6 6-6" }) }) }),
|
|
373
|
+
/* @__PURE__ */ jsx(Btn, { onClick: onNext, disabled: !canNext, children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M9 18l6-6-6-6" }) }) })
|
|
374
|
+
] })
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
var TabsContext = createContext({
|
|
380
|
+
active: "",
|
|
381
|
+
setActive: () => {
|
|
382
|
+
},
|
|
383
|
+
variant: "pills"
|
|
384
|
+
});
|
|
385
|
+
var useTabs = () => useContext(TabsContext);
|
|
386
|
+
function Tabs({
|
|
387
|
+
defaultValue = "",
|
|
388
|
+
value,
|
|
389
|
+
onValueChange,
|
|
390
|
+
variant = "pills",
|
|
391
|
+
children,
|
|
392
|
+
className
|
|
393
|
+
}) {
|
|
394
|
+
const [internalActive, setInternalActive] = useState(defaultValue);
|
|
395
|
+
const active = value ?? internalActive;
|
|
396
|
+
const setActive = (v) => {
|
|
397
|
+
setInternalActive(v);
|
|
398
|
+
onValueChange?.(v);
|
|
399
|
+
};
|
|
400
|
+
return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { active, setActive, variant }, children: /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", className), children }) });
|
|
401
|
+
}
|
|
402
|
+
function TabsList({ className, children, ...props }) {
|
|
403
|
+
const { variant } = useTabs();
|
|
404
|
+
return /* @__PURE__ */ jsx(
|
|
405
|
+
"div",
|
|
406
|
+
{
|
|
407
|
+
role: "tablist",
|
|
408
|
+
className: cn(
|
|
409
|
+
"flex items-center overflow-x-auto avt-scroll",
|
|
410
|
+
variant === "segment" && "gap-0.5 rounded-xl bg-[#E5E5EA] p-1 min-w-0 flex-shrink-0",
|
|
411
|
+
variant === "pills" && "gap-1",
|
|
412
|
+
variant === "underline" && "gap-0 border-b border-[#E5E5EA]",
|
|
413
|
+
className
|
|
414
|
+
),
|
|
415
|
+
...props,
|
|
416
|
+
children
|
|
417
|
+
}
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
function TabsTrigger({ value, icon, className, children, ...props }) {
|
|
421
|
+
const { active, setActive, variant } = useTabs();
|
|
422
|
+
const isActive = active === value;
|
|
423
|
+
return /* @__PURE__ */ jsxs(
|
|
424
|
+
"button",
|
|
425
|
+
{
|
|
426
|
+
role: "tab",
|
|
427
|
+
"aria-selected": isActive,
|
|
428
|
+
onClick: () => setActive(value),
|
|
429
|
+
className: cn(
|
|
430
|
+
"inline-flex flex-shrink-0 items-center gap-1.5 text-[13px] font-medium transition-all duration-150 select-none whitespace-nowrap",
|
|
431
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#007AFF]/30",
|
|
432
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
433
|
+
variant === "segment" && [
|
|
434
|
+
"flex-1 justify-center rounded-lg px-3 py-2 min-h-[36px]",
|
|
435
|
+
isActive ? "bg-white text-[#1C1C1E] shadow-[0_1px_3px_rgba(0,0,0,0.12)]" : "text-[#8E8E93] hover:text-[#3C3C43]"
|
|
436
|
+
],
|
|
437
|
+
variant === "pills" && [
|
|
438
|
+
"rounded-lg px-3.5 py-2 min-h-[36px]",
|
|
439
|
+
isActive ? "bg-[#007AFF] text-white shadow-[0_2px_6px_rgba(0,122,255,0.25)]" : "text-[#8E8E93] hover:bg-[#F2F2F7] hover:text-[#1C1C1E]"
|
|
440
|
+
],
|
|
441
|
+
variant === "underline" && [
|
|
442
|
+
"relative px-4 py-3 border-b-2 -mb-px min-h-[44px]",
|
|
443
|
+
isActive ? "border-[#007AFF] text-[#007AFF]" : "border-transparent text-[#8E8E93] hover:text-[#3C3C43]"
|
|
444
|
+
],
|
|
445
|
+
className
|
|
446
|
+
),
|
|
447
|
+
...props,
|
|
448
|
+
children: [
|
|
449
|
+
icon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: icon }),
|
|
450
|
+
children
|
|
451
|
+
]
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
function TabsContent({
|
|
456
|
+
value,
|
|
457
|
+
keepMounted = false,
|
|
458
|
+
className,
|
|
459
|
+
children,
|
|
460
|
+
...props
|
|
461
|
+
}) {
|
|
462
|
+
const { active } = useTabs();
|
|
463
|
+
const isActive = active === value;
|
|
464
|
+
if (!keepMounted && !isActive) return null;
|
|
465
|
+
return /* @__PURE__ */ jsx(
|
|
466
|
+
"div",
|
|
467
|
+
{
|
|
468
|
+
role: "tabpanel",
|
|
469
|
+
hidden: !isActive,
|
|
470
|
+
className: cn("avt-animate-fade-in", isActive && "block", className),
|
|
471
|
+
...props,
|
|
472
|
+
children
|
|
473
|
+
}
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
function Scrollbar({
|
|
477
|
+
maxHeight,
|
|
478
|
+
maxWidth,
|
|
479
|
+
direction = "vertical",
|
|
480
|
+
always = false,
|
|
481
|
+
className,
|
|
482
|
+
style,
|
|
483
|
+
...props
|
|
484
|
+
}) {
|
|
485
|
+
const overflow = {
|
|
486
|
+
vertical: "overflow-y-auto overflow-x-hidden",
|
|
487
|
+
horizontal: "overflow-x-auto overflow-y-hidden",
|
|
488
|
+
both: "overflow-auto"
|
|
489
|
+
}[direction];
|
|
490
|
+
return /* @__PURE__ */ jsx(
|
|
491
|
+
"div",
|
|
492
|
+
{
|
|
493
|
+
className: cn(
|
|
494
|
+
"avt-scroll",
|
|
495
|
+
overflow,
|
|
496
|
+
// On hover scroll trick (webkit only - fallback gracefully)
|
|
497
|
+
!always && "hover:avt-scroll",
|
|
498
|
+
className
|
|
499
|
+
),
|
|
500
|
+
style: {
|
|
501
|
+
maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
|
|
502
|
+
maxWidth: typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth,
|
|
503
|
+
...style
|
|
504
|
+
},
|
|
505
|
+
...props
|
|
506
|
+
}
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
function withScrollbar(Component, scrollbarProps) {
|
|
510
|
+
return function ScrollbarWrapped(props) {
|
|
511
|
+
return /* @__PURE__ */ jsx(Scrollbar, { ...scrollbarProps, children: /* @__PURE__ */ jsx(Component, { ...props }) });
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
var storeState = [];
|
|
515
|
+
var storeListeners = /* @__PURE__ */ new Set();
|
|
516
|
+
var timers = /* @__PURE__ */ new Map();
|
|
517
|
+
function dispatch(action) {
|
|
518
|
+
if (action.type === "ADD") {
|
|
519
|
+
storeState = [...storeState, action.payload];
|
|
520
|
+
} else if (action.type === "REMOVE") {
|
|
521
|
+
storeState = storeState.filter((t) => t.id !== action.payload.id);
|
|
522
|
+
const timer = timers.get(action.payload.id);
|
|
523
|
+
if (timer) {
|
|
524
|
+
clearTimeout(timer);
|
|
525
|
+
timers.delete(action.payload.id);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
storeListeners.forEach((l) => l());
|
|
529
|
+
}
|
|
530
|
+
function toast(options) {
|
|
531
|
+
const id = generateId();
|
|
532
|
+
const duration = options.duration ?? 4e3;
|
|
533
|
+
dispatch({ type: "ADD", payload: { id, duration, ...options } });
|
|
534
|
+
if (duration !== Infinity) {
|
|
535
|
+
timers.set(id, setTimeout(() => dispatch({ type: "REMOVE", payload: { id } }), duration));
|
|
536
|
+
}
|
|
537
|
+
return id;
|
|
538
|
+
}
|
|
539
|
+
function dismissToast(id) {
|
|
540
|
+
dispatch({ type: "REMOVE", payload: { id } });
|
|
541
|
+
}
|
|
542
|
+
function useToast() {
|
|
543
|
+
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
544
|
+
useEffect(() => {
|
|
545
|
+
storeListeners.add(forceUpdate);
|
|
546
|
+
return () => {
|
|
547
|
+
storeListeners.delete(forceUpdate);
|
|
548
|
+
};
|
|
549
|
+
}, []);
|
|
550
|
+
return {
|
|
551
|
+
toasts: storeState,
|
|
552
|
+
toast,
|
|
553
|
+
dismiss: dismissToast
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
var IconCheck = () => /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 flex-shrink-0 mt-0.5", viewBox: "0 0 24 24", fill: "none", stroke: "#34C759", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5" }) });
|
|
557
|
+
var IconX = () => /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4 flex-shrink-0 mt-0.5", viewBox: "0 0 24 24", fill: "none", stroke: "#FF3B30", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
558
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
559
|
+
/* @__PURE__ */ jsx("path", { d: "M15 9l-6 6M9 9l6 6" })
|
|
560
|
+
] });
|
|
561
|
+
var IconInfo = () => /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4 flex-shrink-0 mt-0.5", viewBox: "0 0 24 24", fill: "none", stroke: "#007AFF", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
562
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
563
|
+
/* @__PURE__ */ jsx("path", { d: "M12 16v-4M12 8h.01" })
|
|
564
|
+
] });
|
|
565
|
+
var IconWarn = () => /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4 flex-shrink-0 mt-0.5", viewBox: "0 0 24 24", fill: "none", stroke: "#FF9500", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
566
|
+
/* @__PURE__ */ jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }),
|
|
567
|
+
/* @__PURE__ */ jsx("path", { d: "M12 9v4M12 17h.01" })
|
|
568
|
+
] });
|
|
569
|
+
var defaultIcons = {
|
|
570
|
+
default: /* @__PURE__ */ jsx(IconInfo, {}),
|
|
571
|
+
success: /* @__PURE__ */ jsx(IconCheck, {}),
|
|
572
|
+
destructive: /* @__PURE__ */ jsx(IconX, {}),
|
|
573
|
+
warning: /* @__PURE__ */ jsx(IconWarn, {})
|
|
574
|
+
};
|
|
575
|
+
function ToastItemComp({ item, onDismiss }) {
|
|
576
|
+
return /* @__PURE__ */ jsxs(
|
|
577
|
+
"div",
|
|
578
|
+
{
|
|
579
|
+
className: cn(
|
|
580
|
+
"avt-animate-toast",
|
|
581
|
+
"flex w-[calc(100vw-2rem)] sm:w-full max-w-[360px] items-start gap-3 rounded-2xl",
|
|
582
|
+
"border border-[#E5E5EA]/60 bg-white/95 backdrop-blur-2xl",
|
|
583
|
+
"px-4 py-3.5 shadow-[0_8px_24px_rgba(0,0,0,0.12),_0_0_1px_rgba(0,0,0,0.06)]",
|
|
584
|
+
"group cursor-default select-none"
|
|
585
|
+
),
|
|
586
|
+
role: "alert",
|
|
587
|
+
children: [
|
|
588
|
+
item.icon ?? defaultIcons[item.variant ?? "default"],
|
|
589
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
590
|
+
item.title && /* @__PURE__ */ jsx("p", { className: "text-[13px] font-semibold text-[#1C1C1E] leading-snug", children: item.title }),
|
|
591
|
+
item.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[12px] text-[#8E8E93] leading-snug", children: item.description })
|
|
592
|
+
] }),
|
|
593
|
+
/* @__PURE__ */ jsx(
|
|
594
|
+
"button",
|
|
595
|
+
{
|
|
596
|
+
onClick: () => onDismiss(item.id),
|
|
597
|
+
className: cn(
|
|
598
|
+
"flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full",
|
|
599
|
+
"bg-[#F2F2F7] text-[#8E8E93]",
|
|
600
|
+
"opacity-0 group-hover:opacity-100 transition-opacity",
|
|
601
|
+
"hover:bg-[#E5E5EA] hover:text-[#1C1C1E]"
|
|
602
|
+
),
|
|
603
|
+
"aria-label": "Tutup",
|
|
604
|
+
children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
605
|
+
}
|
|
606
|
+
)
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
var positionClasses = {
|
|
612
|
+
"top-right": "top-4 right-4 items-end",
|
|
613
|
+
"top-left": "top-4 left-4 items-start",
|
|
614
|
+
"top-center": "top-4 left-1/2 -translate-x-1/2 items-center",
|
|
615
|
+
"bottom-right": "bottom-4 right-4 sm:right-4 left-4 sm:left-auto items-end",
|
|
616
|
+
"bottom-left": "bottom-4 left-4 items-start",
|
|
617
|
+
"bottom-center": "bottom-4 left-1/2 -translate-x-1/2 items-center"
|
|
618
|
+
};
|
|
619
|
+
function Toaster({ position = "bottom-right" }) {
|
|
620
|
+
const { toasts, dismiss } = useToast();
|
|
621
|
+
if (typeof document === "undefined") return null;
|
|
622
|
+
return createPortal(
|
|
623
|
+
/* @__PURE__ */ jsx(
|
|
624
|
+
"div",
|
|
625
|
+
{
|
|
626
|
+
className: cn(
|
|
627
|
+
"fixed z-[9999] flex flex-col gap-2 pointer-events-none",
|
|
628
|
+
positionClasses[position]
|
|
629
|
+
),
|
|
630
|
+
"aria-live": "polite",
|
|
631
|
+
"aria-label": "Notifications",
|
|
632
|
+
children: toasts.map((item) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(ToastItemComp, { item, onDismiss: dismiss }) }, item.id))
|
|
633
|
+
}
|
|
634
|
+
),
|
|
635
|
+
document.body
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
function useKeydown(key, handler, enabled = true) {
|
|
639
|
+
useEffect(() => {
|
|
640
|
+
if (!enabled) return;
|
|
641
|
+
const listener = (e) => {
|
|
642
|
+
if (e.key === key) handler();
|
|
643
|
+
};
|
|
644
|
+
document.addEventListener("keydown", listener);
|
|
645
|
+
return () => document.removeEventListener("keydown", listener);
|
|
646
|
+
}, [key, handler, enabled]);
|
|
647
|
+
}
|
|
648
|
+
var MenuContext = createContext({
|
|
649
|
+
open: false,
|
|
650
|
+
close: () => {
|
|
651
|
+
},
|
|
652
|
+
rootRef: { current: null },
|
|
653
|
+
contentRef: { current: null }
|
|
654
|
+
});
|
|
655
|
+
var useMenu = () => useContext(MenuContext);
|
|
656
|
+
function MenuRoot({ children, open: controlledOpen, onOpenChange }) {
|
|
657
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
658
|
+
const open = controlledOpen ?? internalOpen;
|
|
659
|
+
const setOpen = (v) => {
|
|
660
|
+
setInternalOpen(v);
|
|
661
|
+
onOpenChange?.(v);
|
|
662
|
+
};
|
|
663
|
+
const close = useCallback(() => setOpen(false), []);
|
|
664
|
+
const toggle = () => setOpen(!open);
|
|
665
|
+
const rootRef = useRef(null);
|
|
666
|
+
const contentRef = useRef(null);
|
|
667
|
+
useKeydown("Escape", close, open);
|
|
668
|
+
useEffect(() => {
|
|
669
|
+
if (!open) return;
|
|
670
|
+
const handler = (e) => {
|
|
671
|
+
const target = e.target;
|
|
672
|
+
if (rootRef.current?.contains(target)) return;
|
|
673
|
+
if (contentRef.current?.contains(target)) return;
|
|
674
|
+
close();
|
|
675
|
+
};
|
|
676
|
+
document.addEventListener("mousedown", handler, true);
|
|
677
|
+
document.addEventListener("touchstart", handler, true);
|
|
678
|
+
return () => {
|
|
679
|
+
document.removeEventListener("mousedown", handler, true);
|
|
680
|
+
document.removeEventListener("touchstart", handler, true);
|
|
681
|
+
};
|
|
682
|
+
}, [open, close]);
|
|
683
|
+
useEffect(() => {
|
|
684
|
+
const el = rootRef.current;
|
|
685
|
+
if (!el) return;
|
|
686
|
+
const handler = () => toggle();
|
|
687
|
+
el.addEventListener("avt-menu-toggle", handler);
|
|
688
|
+
return () => el.removeEventListener("avt-menu-toggle", handler);
|
|
689
|
+
}, [open]);
|
|
690
|
+
return /* @__PURE__ */ jsx(MenuContext.Provider, { value: { open, close, rootRef, contentRef }, children: /* @__PURE__ */ jsx("div", { ref: rootRef, "data-avt-menu": "", className: "relative inline-block", children }) });
|
|
691
|
+
}
|
|
692
|
+
function MenuButton({
|
|
693
|
+
className,
|
|
694
|
+
children,
|
|
695
|
+
...props
|
|
696
|
+
}) {
|
|
697
|
+
const { open } = useMenu();
|
|
698
|
+
const handleClick = (e) => {
|
|
699
|
+
e.stopPropagation();
|
|
700
|
+
props.onClick?.(e);
|
|
701
|
+
const el = e.currentTarget.closest("[data-avt-menu]");
|
|
702
|
+
el?.dispatchEvent(new CustomEvent("avt-menu-toggle", { bubbles: false }));
|
|
703
|
+
};
|
|
704
|
+
return /* @__PURE__ */ jsx(
|
|
705
|
+
"button",
|
|
706
|
+
{
|
|
707
|
+
type: "button",
|
|
708
|
+
"aria-haspopup": "menu",
|
|
709
|
+
"aria-expanded": open,
|
|
710
|
+
className: cn("select-none", className),
|
|
711
|
+
...props,
|
|
712
|
+
onClick: handleClick,
|
|
713
|
+
children
|
|
714
|
+
}
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
function MenuContent({
|
|
718
|
+
align = "start",
|
|
719
|
+
sideOffset = 6,
|
|
720
|
+
minWidth = 180,
|
|
721
|
+
className,
|
|
722
|
+
children,
|
|
723
|
+
style,
|
|
724
|
+
...props
|
|
725
|
+
}) {
|
|
726
|
+
const { open, rootRef, contentRef } = useMenu();
|
|
727
|
+
const [pos, setPos] = useState(null);
|
|
728
|
+
useEffect(() => {
|
|
729
|
+
if (!open) {
|
|
730
|
+
setPos(null);
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const update = () => {
|
|
734
|
+
if (!rootRef.current) return;
|
|
735
|
+
const rect = rootRef.current.getBoundingClientRect();
|
|
736
|
+
const vw = window.innerWidth;
|
|
737
|
+
const vh = window.innerHeight;
|
|
738
|
+
let left;
|
|
739
|
+
if (align === "end") left = rect.right - minWidth;
|
|
740
|
+
else if (align === "center") left = rect.left + rect.width / 2 - minWidth / 2;
|
|
741
|
+
else left = rect.left;
|
|
742
|
+
left = Math.max(8, Math.min(left, vw - minWidth - 8));
|
|
743
|
+
const spaceBelow = vh - rect.bottom - sideOffset - 8;
|
|
744
|
+
const spaceAbove = rect.top - sideOffset - 8;
|
|
745
|
+
const flipUp = spaceBelow < 100 && spaceAbove > spaceBelow;
|
|
746
|
+
const top = flipUp ? rect.top - sideOffset - Math.min(320, spaceAbove) : rect.bottom + sideOffset;
|
|
747
|
+
const maxH = flipUp ? Math.max(60, spaceAbove) : Math.max(60, spaceBelow);
|
|
748
|
+
setPos({ top, left, maxH });
|
|
749
|
+
};
|
|
750
|
+
update();
|
|
751
|
+
window.addEventListener("scroll", update, true);
|
|
752
|
+
window.addEventListener("resize", update);
|
|
753
|
+
return () => {
|
|
754
|
+
window.removeEventListener("scroll", update, true);
|
|
755
|
+
window.removeEventListener("resize", update);
|
|
756
|
+
};
|
|
757
|
+
}, [open, align, sideOffset, minWidth]);
|
|
758
|
+
if (!open || !pos || typeof document === "undefined") return null;
|
|
759
|
+
return createPortal(
|
|
760
|
+
/* @__PURE__ */ jsx(
|
|
761
|
+
"div",
|
|
762
|
+
{
|
|
763
|
+
ref: contentRef,
|
|
764
|
+
role: "menu",
|
|
765
|
+
className: cn(
|
|
766
|
+
"fixed z-[9999] avt-animate-slide-up overflow-y-auto avt-scroll",
|
|
767
|
+
"rounded-xl border border-[#E5E5EA]/60 bg-white/95 backdrop-blur-2xl",
|
|
768
|
+
"shadow-[0_8px_24px_rgba(0,0,0,0.10),_0_0_1px_rgba(0,0,0,0.06)]",
|
|
769
|
+
"py-1.5",
|
|
770
|
+
className
|
|
771
|
+
),
|
|
772
|
+
style: { top: pos.top, left: pos.left, minWidth, maxHeight: pos.maxH, ...style },
|
|
773
|
+
...props,
|
|
774
|
+
children
|
|
775
|
+
}
|
|
776
|
+
),
|
|
777
|
+
document.body
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
function MenuItem({
|
|
781
|
+
icon,
|
|
782
|
+
rightSlot,
|
|
783
|
+
variant = "default",
|
|
784
|
+
disabled,
|
|
785
|
+
className,
|
|
786
|
+
children,
|
|
787
|
+
onClick,
|
|
788
|
+
...props
|
|
789
|
+
}) {
|
|
790
|
+
const { close } = useMenu();
|
|
791
|
+
return /* @__PURE__ */ jsxs(
|
|
792
|
+
"button",
|
|
793
|
+
{
|
|
794
|
+
role: "menuitem",
|
|
795
|
+
type: "button",
|
|
796
|
+
disabled,
|
|
797
|
+
className: cn(
|
|
798
|
+
"flex w-full items-center gap-2.5 px-3.5 py-2.5 text-[13px] font-medium",
|
|
799
|
+
"transition-colors duration-100 outline-none select-none",
|
|
800
|
+
"focus-visible:bg-[#F2F2F7]",
|
|
801
|
+
// Mobile: min touch target
|
|
802
|
+
"min-h-[44px] sm:min-h-0",
|
|
803
|
+
variant === "default" ? "text-[#1C1C1E] hover:bg-[#F2F2F7]" : "text-[#FF3B30] hover:bg-[#FF3B30]/8",
|
|
804
|
+
disabled && "pointer-events-none opacity-40",
|
|
805
|
+
className
|
|
806
|
+
),
|
|
807
|
+
onClick: (e) => {
|
|
808
|
+
onClick?.(e);
|
|
809
|
+
close();
|
|
810
|
+
},
|
|
811
|
+
...props,
|
|
812
|
+
children: [
|
|
813
|
+
icon && /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", variant === "default" ? "text-[#8E8E93]" : "text-[#FF3B30]"), children: icon }),
|
|
814
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children }),
|
|
815
|
+
rightSlot && /* @__PURE__ */ jsx("span", { className: "ml-auto text-[#8E8E93]", children: rightSlot })
|
|
816
|
+
]
|
|
817
|
+
}
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
function MenuSeparator({ className }) {
|
|
821
|
+
return /* @__PURE__ */ jsx("div", { className: cn("my-1 h-px bg-[#F2F2F7]", className), role: "separator" });
|
|
822
|
+
}
|
|
823
|
+
function MenuLabel({ className, children }) {
|
|
824
|
+
return /* @__PURE__ */ jsx("div", { className: cn("px-3.5 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-[#8E8E93]", className), children });
|
|
825
|
+
}
|
|
826
|
+
function MenuTrigger({ children }) {
|
|
827
|
+
return children;
|
|
828
|
+
}
|
|
829
|
+
var slideAnim = {
|
|
830
|
+
right: "avt-animate-slide-right",
|
|
831
|
+
left: "avt-animate-slide-left",
|
|
832
|
+
bottom: "avt-animate-slide-bottom"
|
|
833
|
+
};
|
|
834
|
+
var positionClasses2 = {
|
|
835
|
+
right: "right-0 top-0 h-full",
|
|
836
|
+
left: "left-0 top-0 h-full",
|
|
837
|
+
bottom: "bottom-0 left-0 w-full"
|
|
838
|
+
};
|
|
839
|
+
function Sheet({
|
|
840
|
+
open,
|
|
841
|
+
onClose,
|
|
842
|
+
side = "right",
|
|
843
|
+
width = "420px",
|
|
844
|
+
height = "60vh",
|
|
845
|
+
closeOnOverlay = true,
|
|
846
|
+
children
|
|
847
|
+
}) {
|
|
848
|
+
useKeydown("Escape", onClose, open);
|
|
849
|
+
useEffect(() => {
|
|
850
|
+
if (open) document.body.style.overflow = "hidden";
|
|
851
|
+
else document.body.style.overflow = "";
|
|
852
|
+
return () => {
|
|
853
|
+
document.body.style.overflow = "";
|
|
854
|
+
};
|
|
855
|
+
}, [open]);
|
|
856
|
+
if (!open || typeof document === "undefined") return null;
|
|
857
|
+
const panelStyle = {
|
|
858
|
+
...side !== "bottom" ? { width } : { height }
|
|
859
|
+
};
|
|
860
|
+
return createPortal(
|
|
861
|
+
/* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[999] flex", "aria-modal": "true", role: "dialog", children: [
|
|
862
|
+
/* @__PURE__ */ jsx(
|
|
863
|
+
"div",
|
|
864
|
+
{
|
|
865
|
+
className: "absolute inset-0 bg-black/30 backdrop-blur-[2px] avt-animate-fade-in",
|
|
866
|
+
onClick: closeOnOverlay ? onClose : void 0,
|
|
867
|
+
"aria-hidden": "true"
|
|
868
|
+
}
|
|
869
|
+
),
|
|
870
|
+
/* @__PURE__ */ jsx(
|
|
871
|
+
"div",
|
|
872
|
+
{
|
|
873
|
+
className: cn(
|
|
874
|
+
"absolute z-10 flex flex-col bg-white/95 backdrop-blur-2xl",
|
|
875
|
+
"border-[#E5E5EA]/60 shadow-[0_16px_48px_rgba(0,0,0,0.16)]",
|
|
876
|
+
side === "right" && "border-l rounded-l-2xl",
|
|
877
|
+
side === "left" && "border-r rounded-r-2xl",
|
|
878
|
+
side === "bottom" && "border-t rounded-t-2xl",
|
|
879
|
+
positionClasses2[side],
|
|
880
|
+
slideAnim[side]
|
|
881
|
+
),
|
|
882
|
+
style: panelStyle,
|
|
883
|
+
onClick: (e) => e.stopPropagation(),
|
|
884
|
+
children
|
|
885
|
+
}
|
|
886
|
+
)
|
|
887
|
+
] }),
|
|
888
|
+
document.body
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
function SheetHeader({ showClose, onClose, className, children, ...props }) {
|
|
892
|
+
return /* @__PURE__ */ jsxs(
|
|
893
|
+
"div",
|
|
894
|
+
{
|
|
895
|
+
className: cn("flex items-start justify-between px-6 pt-6 pb-4 border-b border-[#F2F2F7]", className),
|
|
896
|
+
...props,
|
|
897
|
+
children: [
|
|
898
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0 pr-3", children }),
|
|
899
|
+
showClose && onClose && /* @__PURE__ */ jsx(
|
|
900
|
+
"button",
|
|
901
|
+
{
|
|
902
|
+
onClick: onClose,
|
|
903
|
+
className: cn(
|
|
904
|
+
"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full",
|
|
905
|
+
"bg-[#F2F2F7] text-[#8E8E93] hover:bg-[#E5E5EA] hover:text-[#1C1C1E]",
|
|
906
|
+
"transition-colors duration-150"
|
|
907
|
+
),
|
|
908
|
+
"aria-label": "Tutup",
|
|
909
|
+
children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
910
|
+
}
|
|
911
|
+
)
|
|
912
|
+
]
|
|
913
|
+
}
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
function SheetTitle({ className, ...props }) {
|
|
917
|
+
return /* @__PURE__ */ jsx(
|
|
918
|
+
"h2",
|
|
919
|
+
{
|
|
920
|
+
className: cn("text-[15px] font-semibold tracking-[-0.01em] text-[#1C1C1E]", className),
|
|
921
|
+
...props
|
|
922
|
+
}
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
function SheetDescription({ className, ...props }) {
|
|
926
|
+
return /* @__PURE__ */ jsx("p", { className: cn("mt-0.5 text-[13px] text-[#8E8E93]", className), ...props });
|
|
927
|
+
}
|
|
928
|
+
function SheetContent({ className, ...props }) {
|
|
929
|
+
return /* @__PURE__ */ jsx(
|
|
930
|
+
"div",
|
|
931
|
+
{
|
|
932
|
+
className: cn("flex-1 overflow-y-auto px-6 py-5 avt-scroll", className),
|
|
933
|
+
...props
|
|
934
|
+
}
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
function SheetFooter({ className, ...props }) {
|
|
938
|
+
return /* @__PURE__ */ jsx(
|
|
939
|
+
"div",
|
|
940
|
+
{
|
|
941
|
+
className: cn(
|
|
942
|
+
"flex items-center justify-end gap-2 px-6 py-4",
|
|
943
|
+
"border-t border-[#F2F2F7] bg-[#FAFAFA]",
|
|
944
|
+
className
|
|
945
|
+
),
|
|
946
|
+
...props
|
|
947
|
+
}
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
function Drawer({ children, ...props }) {
|
|
951
|
+
return /* @__PURE__ */ jsx(Sheet, { side: "bottom", ...props, children });
|
|
952
|
+
}
|
|
953
|
+
function Navbar({
|
|
954
|
+
glass = true,
|
|
955
|
+
border = true,
|
|
956
|
+
sticky = true,
|
|
957
|
+
height = "h-14",
|
|
958
|
+
className,
|
|
959
|
+
children,
|
|
960
|
+
...props
|
|
961
|
+
}) {
|
|
962
|
+
return /* @__PURE__ */ jsx(
|
|
963
|
+
"header",
|
|
964
|
+
{
|
|
965
|
+
className: cn(
|
|
966
|
+
"w-full z-40",
|
|
967
|
+
sticky && "sticky top-0",
|
|
968
|
+
glass ? "bg-white/80 backdrop-blur-2xl" : "bg-white",
|
|
969
|
+
border && "border-b border-[#E5E5EA]/70",
|
|
970
|
+
height,
|
|
971
|
+
className
|
|
972
|
+
),
|
|
973
|
+
...props,
|
|
974
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex h-full items-center px-5 gap-4", children })
|
|
975
|
+
}
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
function NavbarLeft({ className, ...props }) {
|
|
979
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-3 flex-shrink-0", className), ...props });
|
|
980
|
+
}
|
|
981
|
+
function NavbarCenter({ className, ...props }) {
|
|
982
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-1 items-center justify-center", className), ...props });
|
|
983
|
+
}
|
|
984
|
+
function NavbarRight({ className, ...props }) {
|
|
985
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-2 flex-shrink-0 ml-auto", className), ...props });
|
|
986
|
+
}
|
|
987
|
+
function NavbarBrand({ logo, title, subtitle, className, ...props }) {
|
|
988
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2.5", className), ...props, children: [
|
|
989
|
+
logo && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: logo }),
|
|
990
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
991
|
+
/* @__PURE__ */ jsx("p", { className: "text-[14px] font-semibold tracking-[-0.01em] text-[#1C1C1E] leading-none", children: title }),
|
|
992
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-[#8E8E93] mt-0.5 leading-none", children: subtitle })
|
|
993
|
+
] })
|
|
994
|
+
] });
|
|
995
|
+
}
|
|
996
|
+
var SearchIcon = () => /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
997
|
+
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
|
|
998
|
+
/* @__PURE__ */ jsx("path", { d: "M21 21l-4.35-4.35" })
|
|
999
|
+
] });
|
|
1000
|
+
function NavbarSearch({ icon, className, ...props }) {
|
|
1001
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative w-64", children: [
|
|
1002
|
+
/* @__PURE__ */ jsx("div", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-[#8E8E93]", children: icon ?? /* @__PURE__ */ jsx(SearchIcon, {}) }),
|
|
1003
|
+
/* @__PURE__ */ jsx(
|
|
1004
|
+
"input",
|
|
1005
|
+
{
|
|
1006
|
+
type: "search",
|
|
1007
|
+
className: cn(
|
|
1008
|
+
"h-9 w-full rounded-xl bg-[#F2F2F7] pl-9 pr-4 text-sm text-[#1C1C1E]",
|
|
1009
|
+
"placeholder:text-[#8E8E93] border-0 outline-none",
|
|
1010
|
+
"focus:bg-white focus:shadow-[0_0_0_2px_rgba(0,122,255,0.22)] transition-all duration-150",
|
|
1011
|
+
className
|
|
1012
|
+
),
|
|
1013
|
+
...props
|
|
1014
|
+
}
|
|
1015
|
+
)
|
|
1016
|
+
] });
|
|
1017
|
+
}
|
|
1018
|
+
function NavbarIconButton({
|
|
1019
|
+
badge,
|
|
1020
|
+
tooltip,
|
|
1021
|
+
className,
|
|
1022
|
+
children,
|
|
1023
|
+
...props
|
|
1024
|
+
}) {
|
|
1025
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative", title: tooltip, children: [
|
|
1026
|
+
/* @__PURE__ */ jsx(
|
|
1027
|
+
"button",
|
|
1028
|
+
{
|
|
1029
|
+
type: "button",
|
|
1030
|
+
className: cn(
|
|
1031
|
+
"flex h-9 w-9 items-center justify-center rounded-xl text-[#3C3C43]",
|
|
1032
|
+
"hover:bg-[#F2F2F7] transition-colors duration-150",
|
|
1033
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#007AFF]/30",
|
|
1034
|
+
className
|
|
1035
|
+
),
|
|
1036
|
+
...props,
|
|
1037
|
+
children
|
|
1038
|
+
}
|
|
1039
|
+
),
|
|
1040
|
+
badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "absolute -top-0.5 -right-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-[#FF3B30] px-1 text-[10px] font-bold text-white", children: badge })
|
|
1041
|
+
] });
|
|
1042
|
+
}
|
|
1043
|
+
function NavbarDivider({ className }) {
|
|
1044
|
+
return /* @__PURE__ */ jsx("div", { className: cn("h-5 w-px bg-[#E5E5EA]", className) });
|
|
1045
|
+
}
|
|
1046
|
+
var SidebarContext = createContext({ collapsed: false });
|
|
1047
|
+
var useSidebar = () => useContext(SidebarContext);
|
|
1048
|
+
function Sidebar({
|
|
1049
|
+
collapsed = false,
|
|
1050
|
+
glass = true,
|
|
1051
|
+
width = "240px",
|
|
1052
|
+
collapsedWidth = "64px",
|
|
1053
|
+
overlay = false,
|
|
1054
|
+
onOverlayClose,
|
|
1055
|
+
className,
|
|
1056
|
+
children,
|
|
1057
|
+
style,
|
|
1058
|
+
...props
|
|
1059
|
+
}) {
|
|
1060
|
+
if (overlay) {
|
|
1061
|
+
return /* @__PURE__ */ jsxs(SidebarContext.Provider, { value: { collapsed: false }, children: [
|
|
1062
|
+
/* @__PURE__ */ jsx(
|
|
1063
|
+
"div",
|
|
1064
|
+
{
|
|
1065
|
+
className: cn(
|
|
1066
|
+
"fixed inset-0 z-40 transition-opacity duration-300",
|
|
1067
|
+
collapsed ? "pointer-events-none opacity-0" : "bg-black/30 backdrop-blur-[2px]"
|
|
1068
|
+
),
|
|
1069
|
+
onClick: onOverlayClose,
|
|
1070
|
+
"aria-hidden": "true"
|
|
1071
|
+
}
|
|
1072
|
+
),
|
|
1073
|
+
/* @__PURE__ */ jsx(
|
|
1074
|
+
"aside",
|
|
1075
|
+
{
|
|
1076
|
+
className: cn(
|
|
1077
|
+
"fixed left-0 top-0 z-50 flex h-full flex-col",
|
|
1078
|
+
"border-r border-[#E5E5EA]/70",
|
|
1079
|
+
glass ? "bg-white/90 backdrop-blur-2xl" : "bg-white",
|
|
1080
|
+
"transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]",
|
|
1081
|
+
collapsed ? "-translate-x-full" : "translate-x-0",
|
|
1082
|
+
className
|
|
1083
|
+
),
|
|
1084
|
+
style: { width, ...style },
|
|
1085
|
+
...props,
|
|
1086
|
+
children
|
|
1087
|
+
}
|
|
1088
|
+
)
|
|
1089
|
+
] });
|
|
1090
|
+
}
|
|
1091
|
+
return /* @__PURE__ */ jsx(SidebarContext.Provider, { value: { collapsed }, children: /* @__PURE__ */ jsx(
|
|
1092
|
+
"aside",
|
|
1093
|
+
{
|
|
1094
|
+
className: cn(
|
|
1095
|
+
"flex h-full flex-shrink-0 flex-col",
|
|
1096
|
+
"border-r border-[#E5E5EA]/70",
|
|
1097
|
+
glass ? "bg-white/80 backdrop-blur-2xl" : "bg-white",
|
|
1098
|
+
"transition-[width] duration-200",
|
|
1099
|
+
className
|
|
1100
|
+
),
|
|
1101
|
+
style: { width: collapsed ? collapsedWidth : width, ...style },
|
|
1102
|
+
...props,
|
|
1103
|
+
children
|
|
1104
|
+
}
|
|
1105
|
+
) });
|
|
1106
|
+
}
|
|
1107
|
+
function SidebarHeader({ className, ...props }) {
|
|
1108
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex-shrink-0", className), ...props });
|
|
1109
|
+
}
|
|
1110
|
+
function SidebarBrand({ logo, title, subtitle, className, ...props }) {
|
|
1111
|
+
const { collapsed } = useSidebar();
|
|
1112
|
+
return /* @__PURE__ */ jsxs(
|
|
1113
|
+
"div",
|
|
1114
|
+
{
|
|
1115
|
+
className: cn("flex items-center gap-3 px-4 py-5", collapsed && "justify-center px-0", className),
|
|
1116
|
+
...props,
|
|
1117
|
+
children: [
|
|
1118
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: logo }),
|
|
1119
|
+
!collapsed && /* @__PURE__ */ jsxs("div", { className: "min-w-0 overflow-hidden", children: [
|
|
1120
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-[13px] font-semibold tracking-[-0.01em] text-[#1C1C1E]", children: title }),
|
|
1121
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "truncate text-[11px] text-[#8E8E93]", children: subtitle })
|
|
1122
|
+
] })
|
|
1123
|
+
]
|
|
1124
|
+
}
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1127
|
+
function SidebarDivider({ className }) {
|
|
1128
|
+
return /* @__PURE__ */ jsx("div", { className: cn("mx-3 my-1 h-px bg-[#E5E5EA]", className) });
|
|
1129
|
+
}
|
|
1130
|
+
function SidebarContent({ className, ...props }) {
|
|
1131
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex-1 overflow-y-auto px-2 py-2 avt-scroll space-y-0.5", className), ...props });
|
|
1132
|
+
}
|
|
1133
|
+
function SidebarGroup({ label, className, children, ...props }) {
|
|
1134
|
+
const { collapsed } = useSidebar();
|
|
1135
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("mb-1", className), ...props, children: [
|
|
1136
|
+
label && !collapsed && /* @__PURE__ */ jsx("p", { className: "mb-1 px-3 text-[10px] font-semibold uppercase tracking-widest text-[#C7C7CC]", children: label }),
|
|
1137
|
+
children
|
|
1138
|
+
] });
|
|
1139
|
+
}
|
|
1140
|
+
function SidebarItem({
|
|
1141
|
+
icon,
|
|
1142
|
+
label,
|
|
1143
|
+
active = false,
|
|
1144
|
+
badge,
|
|
1145
|
+
href,
|
|
1146
|
+
as: Tag = "button",
|
|
1147
|
+
className,
|
|
1148
|
+
...props
|
|
1149
|
+
}) {
|
|
1150
|
+
const { collapsed } = useSidebar();
|
|
1151
|
+
const tagProps = href ? { href } : { type: "button" };
|
|
1152
|
+
return /* @__PURE__ */ jsxs(
|
|
1153
|
+
Tag,
|
|
1154
|
+
{
|
|
1155
|
+
...tagProps,
|
|
1156
|
+
title: collapsed ? label : void 0,
|
|
1157
|
+
className: cn(
|
|
1158
|
+
"flex w-full items-center gap-2.5 rounded-xl transition-all duration-150",
|
|
1159
|
+
"text-[13px] font-medium select-none outline-none",
|
|
1160
|
+
"focus-visible:ring-2 focus-visible:ring-[#007AFF]/30",
|
|
1161
|
+
// Mobile-friendly touch target
|
|
1162
|
+
collapsed ? "justify-center px-0 mx-auto w-10 h-10 min-h-[44px] min-w-[44px]" : "px-3 py-2.5 min-h-[44px]",
|
|
1163
|
+
active ? "bg-[#007AFF] text-white shadow-[0_2px_8px_rgba(0,122,255,0.28)]" : "text-[#3C3C43] hover:bg-[#007AFF]/8 hover:text-[#007AFF]",
|
|
1164
|
+
className
|
|
1165
|
+
),
|
|
1166
|
+
...props,
|
|
1167
|
+
children: [
|
|
1168
|
+
icon && /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", !active && "text-[#8E8E93]"), children: icon }),
|
|
1169
|
+
!collapsed && /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: label }),
|
|
1170
|
+
!collapsed && badge !== void 0 && /* @__PURE__ */ jsx(
|
|
1171
|
+
"span",
|
|
1172
|
+
{
|
|
1173
|
+
className: cn(
|
|
1174
|
+
"ml-auto flex h-5 min-w-5 items-center justify-center rounded-full px-1.5",
|
|
1175
|
+
"text-[10px] font-bold",
|
|
1176
|
+
active ? "bg-white/20 text-white" : "bg-[#E5E5EA] text-[#8E8E93]"
|
|
1177
|
+
),
|
|
1178
|
+
children: badge
|
|
1179
|
+
}
|
|
1180
|
+
)
|
|
1181
|
+
]
|
|
1182
|
+
}
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
function SidebarFooter({ className, ...props }) {
|
|
1186
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex-shrink-0 p-3", className), ...props });
|
|
1187
|
+
}
|
|
1188
|
+
function SidebarUser({
|
|
1189
|
+
name,
|
|
1190
|
+
subtitle,
|
|
1191
|
+
avatar,
|
|
1192
|
+
avatarFallback,
|
|
1193
|
+
avatarColor = "from-[#5856D6] to-[#AF52DE]",
|
|
1194
|
+
actions,
|
|
1195
|
+
className,
|
|
1196
|
+
...props
|
|
1197
|
+
}) {
|
|
1198
|
+
const { collapsed } = useSidebar();
|
|
1199
|
+
const avatarNode = avatar ?? /* @__PURE__ */ jsx(
|
|
1200
|
+
"div",
|
|
1201
|
+
{
|
|
1202
|
+
className: cn(
|
|
1203
|
+
"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full",
|
|
1204
|
+
`bg-gradient-to-br ${avatarColor} text-white text-xs font-semibold`
|
|
1205
|
+
),
|
|
1206
|
+
children: avatarFallback ?? name.charAt(0).toUpperCase()
|
|
1207
|
+
}
|
|
1208
|
+
);
|
|
1209
|
+
if (collapsed) {
|
|
1210
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex justify-center", className), ...props, children: avatarNode });
|
|
1211
|
+
}
|
|
1212
|
+
return /* @__PURE__ */ jsx("div", { className: cn("rounded-xl bg-[#F2F2F7] p-3", className), ...props, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
1213
|
+
avatarNode,
|
|
1214
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1215
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-[12px] font-semibold text-[#1C1C1E]", children: name }),
|
|
1216
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "truncate text-[11px] text-[#8E8E93]", children: subtitle })
|
|
1217
|
+
] }),
|
|
1218
|
+
actions && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: actions })
|
|
1219
|
+
] }) });
|
|
1220
|
+
}
|
|
1221
|
+
function SidebarToggle({ collapsed, className, ...props }) {
|
|
1222
|
+
return /* @__PURE__ */ jsx(
|
|
1223
|
+
"button",
|
|
1224
|
+
{
|
|
1225
|
+
type: "button",
|
|
1226
|
+
className: cn(
|
|
1227
|
+
"flex h-7 w-7 items-center justify-center rounded-lg",
|
|
1228
|
+
"text-[#8E8E93] hover:bg-[#F2F2F7] hover:text-[#3C3C43]",
|
|
1229
|
+
"transition-colors duration-150",
|
|
1230
|
+
className
|
|
1231
|
+
),
|
|
1232
|
+
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
1233
|
+
...props,
|
|
1234
|
+
children: /* @__PURE__ */ jsx(
|
|
1235
|
+
"svg",
|
|
1236
|
+
{
|
|
1237
|
+
className: cn("h-4 w-4 transition-transform duration-200", collapsed && "rotate-180"),
|
|
1238
|
+
viewBox: "0 0 24 24",
|
|
1239
|
+
fill: "none",
|
|
1240
|
+
stroke: "currentColor",
|
|
1241
|
+
strokeWidth: "2",
|
|
1242
|
+
strokeLinecap: "round",
|
|
1243
|
+
strokeLinejoin: "round",
|
|
1244
|
+
children: /* @__PURE__ */ jsx("path", { d: "M15 18l-6-6 6-6" })
|
|
1245
|
+
}
|
|
1246
|
+
)
|
|
1247
|
+
}
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
function useClickOutside(ref, handler, enabled = true) {
|
|
1251
|
+
useEffect(() => {
|
|
1252
|
+
if (!enabled) return;
|
|
1253
|
+
const listener = (event) => {
|
|
1254
|
+
if (!ref.current || ref.current.contains(event.target)) return;
|
|
1255
|
+
handler(event);
|
|
1256
|
+
};
|
|
1257
|
+
document.addEventListener("mousedown", listener, true);
|
|
1258
|
+
document.addEventListener("touchstart", listener, true);
|
|
1259
|
+
return () => {
|
|
1260
|
+
document.removeEventListener("mousedown", listener, true);
|
|
1261
|
+
document.removeEventListener("touchstart", listener, true);
|
|
1262
|
+
};
|
|
1263
|
+
}, [ref, handler, enabled]);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
export { Badge, Button, Card, CardContent, CardDescription, CardDivider, CardFooter, CardHeader, CardTitle, Drawer, Input, MenuRoot as Menu, MenuButton, MenuContent, MenuRoot as MenuDropdown, MenuItem, MenuLabel, MenuRoot, MenuSeparator, MenuTrigger, Navbar, NavbarBrand, NavbarCenter, NavbarDivider, NavbarIconButton, NavbarLeft, NavbarRight, NavbarSearch, Scrollbar, Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, Sidebar, SidebarBrand, SidebarContent, SidebarDivider, SidebarFooter, SidebarGroup, SidebarHeader, SidebarItem, SidebarToggle, SidebarUser, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TablePagination, TableRow, TableToolbar, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toaster, cn, colors, dismissToast, generateId, toast, useClickOutside, useKeydown, useToast, withScrollbar };
|