@orbitlabsui/ui 0.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/README.md +63 -0
- package/dist/index.d.ts +444 -0
- package/dist/index.js +1299 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +70 -0
- package/dist/tailwind-preset.d.ts +5 -0
- package/dist/tailwind-preset.js +60 -0
- package/dist/tailwind-preset.js.map +1 -0
- package/package.json +55 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1299 @@
|
|
|
1
|
+
import { createContext, forwardRef, useState, useEffect, useCallback, useMemo, useContext, useId, useRef, Children, isValidElement, cloneElement } from 'react';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { EyeOffIcon, EyeIcon, BanIcon, ScanSearchIcon, Clock4Icon, ArchiveIcon, CircleDotIcon, CheckCircle2Icon, CircleDashedIcon, PlayCircleIcon, SunIcon, MoonIcon, MonitorIcon, GithubIcon, ExternalLinkIcon, CopyIcon, PlusIcon, XIcon, Loader2Icon, CheckIcon, AlertTriangleIcon, ChevronDownIcon, SearchIcon, InfoIcon, XCircleIcon } from 'lucide-react';
|
|
4
|
+
import { FloatingOverlay, useFloating, autoUpdate, useDismiss, useRole, useInteractions, FloatingPortal, FloatingFocusManager, offset, flip, shift, useHover, useFocus, size } from '@floating-ui/react';
|
|
5
|
+
import { motion, AnimatePresence } from 'framer-motion';
|
|
6
|
+
import toast, { Toaster } from 'react-hot-toast';
|
|
7
|
+
import ReactMarkdown from 'react-markdown';
|
|
8
|
+
import remarkGfm from 'remark-gfm';
|
|
9
|
+
|
|
10
|
+
// src/theme/theme.ts
|
|
11
|
+
var THEME_STORAGE_KEY = "orbit-theme";
|
|
12
|
+
var CHOICES = ["light", "dark", "system"];
|
|
13
|
+
function resolveTheme(choice, prefersDark) {
|
|
14
|
+
if (choice === "system") return prefersDark ? "dark" : "light";
|
|
15
|
+
return choice;
|
|
16
|
+
}
|
|
17
|
+
function getStoredTheme() {
|
|
18
|
+
try {
|
|
19
|
+
const stored = localStorage.getItem(THEME_STORAGE_KEY);
|
|
20
|
+
if (stored && CHOICES.includes(stored)) return stored;
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
return "system";
|
|
24
|
+
}
|
|
25
|
+
function storeTheme(choice) {
|
|
26
|
+
try {
|
|
27
|
+
localStorage.setItem(THEME_STORAGE_KEY, choice);
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function systemPrefersDark() {
|
|
32
|
+
return typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
33
|
+
}
|
|
34
|
+
function applyThemeClass(resolved) {
|
|
35
|
+
const root = document.documentElement;
|
|
36
|
+
root.classList.toggle("dark", resolved === "dark");
|
|
37
|
+
root.style.colorScheme = resolved;
|
|
38
|
+
const bg = getComputedStyle(root).getPropertyValue("--color-bg").trim();
|
|
39
|
+
if (bg) root.style.backgroundColor = bg;
|
|
40
|
+
}
|
|
41
|
+
var ThemeContext = createContext(null);
|
|
42
|
+
function ThemeProvider({ children }) {
|
|
43
|
+
const [theme, setThemeState] = useState(() => getStoredTheme());
|
|
44
|
+
const [prefersDark, setPrefersDark] = useState(() => systemPrefersDark());
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
47
|
+
const onChange = (e) => setPrefersDark(e.matches);
|
|
48
|
+
mq.addEventListener("change", onChange);
|
|
49
|
+
return () => mq.removeEventListener("change", onChange);
|
|
50
|
+
}, []);
|
|
51
|
+
const resolvedTheme = resolveTheme(theme, prefersDark);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
applyThemeClass(resolvedTheme);
|
|
54
|
+
}, [resolvedTheme]);
|
|
55
|
+
const setTheme = useCallback((choice) => {
|
|
56
|
+
storeTheme(choice);
|
|
57
|
+
setThemeState(choice);
|
|
58
|
+
}, []);
|
|
59
|
+
const value = useMemo(
|
|
60
|
+
() => ({ theme, resolvedTheme, setTheme }),
|
|
61
|
+
[theme, resolvedTheme, setTheme]
|
|
62
|
+
);
|
|
63
|
+
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
|
|
64
|
+
}
|
|
65
|
+
function useTheme() {
|
|
66
|
+
const ctx = useContext(ThemeContext);
|
|
67
|
+
if (!ctx) throw new Error("useTheme must be used within a ThemeProvider");
|
|
68
|
+
return ctx;
|
|
69
|
+
}
|
|
70
|
+
var OPTIONS = [
|
|
71
|
+
{ value: "light", label: "Light", Icon: SunIcon },
|
|
72
|
+
{ value: "dark", label: "Dark", Icon: MoonIcon },
|
|
73
|
+
{ value: "system", label: "System", Icon: MonitorIcon }
|
|
74
|
+
];
|
|
75
|
+
function ThemeToggle() {
|
|
76
|
+
const { theme, setTheme } = useTheme();
|
|
77
|
+
return /* @__PURE__ */ jsx(
|
|
78
|
+
"div",
|
|
79
|
+
{
|
|
80
|
+
role: "radiogroup",
|
|
81
|
+
"aria-label": "Theme",
|
|
82
|
+
className: "flex items-center gap-0.5 rounded-md border border-border-strong bg-surface-raised p-0.5",
|
|
83
|
+
children: OPTIONS.map(({ value, label, Icon }) => {
|
|
84
|
+
const active = theme === value;
|
|
85
|
+
return /* @__PURE__ */ jsx(
|
|
86
|
+
"button",
|
|
87
|
+
{
|
|
88
|
+
type: "button",
|
|
89
|
+
role: "radio",
|
|
90
|
+
"aria-checked": active,
|
|
91
|
+
"aria-label": label,
|
|
92
|
+
title: label,
|
|
93
|
+
onClick: () => setTheme(value),
|
|
94
|
+
className: `flex h-6 w-6 items-center justify-center rounded transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${active ? "bg-surface text-fg shadow-sm" : "text-muted hover:text-fg"}`,
|
|
95
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5", strokeWidth: 1.75, "aria-hidden": "true" })
|
|
96
|
+
},
|
|
97
|
+
value
|
|
98
|
+
);
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
var ICONS = {
|
|
104
|
+
plus: PlusIcon,
|
|
105
|
+
copy: CopyIcon,
|
|
106
|
+
"external-link": ExternalLinkIcon,
|
|
107
|
+
github: GithubIcon
|
|
108
|
+
};
|
|
109
|
+
function Button({
|
|
110
|
+
children,
|
|
111
|
+
variant = "primary",
|
|
112
|
+
icon,
|
|
113
|
+
iconPosition = "none",
|
|
114
|
+
onClick,
|
|
115
|
+
disabled = false,
|
|
116
|
+
fullWidth = false
|
|
117
|
+
}) {
|
|
118
|
+
const Icon = icon ? ICONS[icon] : null;
|
|
119
|
+
const showLeading = Icon && iconPosition === "leading";
|
|
120
|
+
const showTrailing = Icon && iconPosition === "trailing";
|
|
121
|
+
const base = `${fullWidth ? "flex w-full" : "inline-flex"} h-[38px] items-center justify-center gap-2.5 rounded px-3.5 font-condensed text-sm font-medium leading-[17.5px] transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60`;
|
|
122
|
+
const variants = {
|
|
123
|
+
primary: "bg-accent text-on-accent hover:bg-accent-hover focus-visible:ring-accent shadow-[inset_0_1px_0_0_rgba(255,255,255,0.25),inset_0_0_0_1px_rgba(255,255,255,0.12)]",
|
|
124
|
+
secondary: "bg-surface text-fg border border-border-strong hover:bg-surface-raised focus-visible:ring-accent",
|
|
125
|
+
// destructive stays hardcoded — themed in a later pass (see plan Global Constraints).
|
|
126
|
+
destructive: "bg-[#DC2626] text-white hover:bg-[#B91C1C] focus-visible:ring-[#DC2626] shadow-[inset_0_1px_0_0_rgba(255,255,255,0.25),inset_0_0_0_1px_rgba(255,255,255,0.12)]"
|
|
127
|
+
};
|
|
128
|
+
return /* @__PURE__ */ jsxs(
|
|
129
|
+
"button",
|
|
130
|
+
{
|
|
131
|
+
type: "button",
|
|
132
|
+
onClick,
|
|
133
|
+
disabled,
|
|
134
|
+
className: `${base} ${variants[variant]}`,
|
|
135
|
+
children: [
|
|
136
|
+
showLeading && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", strokeWidth: 1.33, "aria-hidden": "true" }),
|
|
137
|
+
/* @__PURE__ */ jsx("span", { children }),
|
|
138
|
+
showTrailing && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", strokeWidth: 1.33, "aria-hidden": "true" })
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
var MotionFloatingOverlay = motion(FloatingOverlay);
|
|
144
|
+
var CONTAINER = {
|
|
145
|
+
center: "items-center justify-center p-4",
|
|
146
|
+
right: "justify-end",
|
|
147
|
+
left: "justify-start"
|
|
148
|
+
};
|
|
149
|
+
var PANEL = {
|
|
150
|
+
center: "max-h-[85vh] w-full rounded-lg border-[0.5px] border-border-strong shadow-lg",
|
|
151
|
+
right: "h-full w-full border-l-[0.5px] border-border-strong shadow-xl",
|
|
152
|
+
left: "h-full w-full border-r-[0.5px] border-border-strong shadow-xl"
|
|
153
|
+
};
|
|
154
|
+
var PANEL_MOTION = {
|
|
155
|
+
center: { from: { scale: 0.96, y: 8 }, to: { scale: 1, y: 0 } },
|
|
156
|
+
right: { from: { x: "100%" }, to: { x: 0 } },
|
|
157
|
+
left: { from: { x: "-100%" }, to: { x: 0 } }
|
|
158
|
+
};
|
|
159
|
+
function Overlay({
|
|
160
|
+
open,
|
|
161
|
+
onClose,
|
|
162
|
+
position,
|
|
163
|
+
widthClassName,
|
|
164
|
+
title,
|
|
165
|
+
description,
|
|
166
|
+
footer,
|
|
167
|
+
hideCloseButton = false,
|
|
168
|
+
closeOnBackdrop = true,
|
|
169
|
+
closeOnEsc = true,
|
|
170
|
+
children
|
|
171
|
+
}) {
|
|
172
|
+
const titleId = useId();
|
|
173
|
+
const { refs, context } = useFloating({
|
|
174
|
+
open,
|
|
175
|
+
onOpenChange: (next) => {
|
|
176
|
+
if (!next) onClose();
|
|
177
|
+
},
|
|
178
|
+
whileElementsMounted: autoUpdate
|
|
179
|
+
});
|
|
180
|
+
const dismiss = useDismiss(context, {
|
|
181
|
+
outsidePress: closeOnBackdrop,
|
|
182
|
+
escapeKey: closeOnEsc
|
|
183
|
+
});
|
|
184
|
+
const role = useRole(context, { role: "dialog" });
|
|
185
|
+
const { getFloatingProps } = useInteractions([dismiss, role]);
|
|
186
|
+
const panelMotion = PANEL_MOTION[position];
|
|
187
|
+
const hasHeader = Boolean(title) || !hideCloseButton;
|
|
188
|
+
return /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(
|
|
189
|
+
MotionFloatingOverlay,
|
|
190
|
+
{
|
|
191
|
+
lockScroll: true,
|
|
192
|
+
className: `fixed inset-0 z-50 flex bg-black/40 ${CONTAINER[position]}`,
|
|
193
|
+
initial: { opacity: 0 },
|
|
194
|
+
animate: { opacity: 1 },
|
|
195
|
+
exit: { opacity: 0 },
|
|
196
|
+
transition: { duration: 0.2, ease: "easeOut" },
|
|
197
|
+
children: /* @__PURE__ */ jsx(FloatingFocusManager, { context, modal: true, children: /* @__PURE__ */ jsxs(
|
|
198
|
+
motion.div,
|
|
199
|
+
{
|
|
200
|
+
ref: refs.setFloating,
|
|
201
|
+
...getFloatingProps(),
|
|
202
|
+
role: "dialog",
|
|
203
|
+
"aria-modal": "true",
|
|
204
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
205
|
+
className: `relative flex flex-col overflow-hidden bg-surface font-sans ${PANEL[position]} ${widthClassName}`,
|
|
206
|
+
initial: panelMotion.from,
|
|
207
|
+
animate: panelMotion.to,
|
|
208
|
+
exit: panelMotion.from,
|
|
209
|
+
transition: { duration: 0.2, ease: "easeOut" },
|
|
210
|
+
children: [
|
|
211
|
+
hasHeader && /* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-start justify-between gap-4 border-b-[0.5px] border-border-strong px-6 py-4", children: [
|
|
212
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
213
|
+
title && /* @__PURE__ */ jsx(
|
|
214
|
+
"h2",
|
|
215
|
+
{
|
|
216
|
+
id: titleId,
|
|
217
|
+
className: "font-sans text-lg font-semibold text-fg",
|
|
218
|
+
children: title
|
|
219
|
+
}
|
|
220
|
+
),
|
|
221
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-1 font-sans text-sm text-muted", children: description })
|
|
222
|
+
] }),
|
|
223
|
+
!hideCloseButton && /* @__PURE__ */ jsx(
|
|
224
|
+
"button",
|
|
225
|
+
{
|
|
226
|
+
type: "button",
|
|
227
|
+
onClick: onClose,
|
|
228
|
+
"aria-label": "Close",
|
|
229
|
+
className: "-mr-1.5 flex h-8 w-8 flex-shrink-0 items-center justify-center rounded text-muted transition-colors hover:bg-surface-raised hover:text-fg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
230
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "h-4 w-4", strokeWidth: 2 })
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
] }),
|
|
234
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-6 py-5", children }),
|
|
235
|
+
footer && /* @__PURE__ */ jsx("div", { className: "flex flex-shrink-0 items-center justify-end gap-3 border-t-[0.5px] border-border-strong px-6 py-4", children: footer })
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
) })
|
|
239
|
+
}
|
|
240
|
+
) }) });
|
|
241
|
+
}
|
|
242
|
+
var SIZES = {
|
|
243
|
+
sm: "h-6 w-6 text-[10px]",
|
|
244
|
+
md: "h-7 w-7 text-[11px]",
|
|
245
|
+
lg: "h-9 w-9 text-sm"
|
|
246
|
+
};
|
|
247
|
+
var GRAY = {
|
|
248
|
+
bg: "var(--color-surface-avatar)",
|
|
249
|
+
color: "var(--color-text-secondary)"
|
|
250
|
+
};
|
|
251
|
+
function getInitials(name) {
|
|
252
|
+
const parts = name.trim().split(/\s+/);
|
|
253
|
+
if (parts.length === 1) return (parts[0] ?? "").slice(0, 2).toUpperCase();
|
|
254
|
+
return ((parts[0]?.[0] ?? "") + (parts[parts.length - 1]?.[0] ?? "")).toUpperCase();
|
|
255
|
+
}
|
|
256
|
+
function Avatar({
|
|
257
|
+
name,
|
|
258
|
+
initials,
|
|
259
|
+
size: size2 = "md",
|
|
260
|
+
className = ""
|
|
261
|
+
}) {
|
|
262
|
+
const label = initials ?? getInitials(name);
|
|
263
|
+
return /* @__PURE__ */ jsx(
|
|
264
|
+
"div",
|
|
265
|
+
{
|
|
266
|
+
className: `flex flex-shrink-0 items-center justify-center rounded-full font-medium ${SIZES[size2]} ${className}`,
|
|
267
|
+
style: {
|
|
268
|
+
backgroundColor: GRAY.bg,
|
|
269
|
+
color: GRAY.color
|
|
270
|
+
},
|
|
271
|
+
"aria-hidden": "true",
|
|
272
|
+
title: name,
|
|
273
|
+
children: label
|
|
274
|
+
}
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
var Input = forwardRef(
|
|
278
|
+
({
|
|
279
|
+
label,
|
|
280
|
+
helperText,
|
|
281
|
+
error,
|
|
282
|
+
icon: Icon,
|
|
283
|
+
type = "text",
|
|
284
|
+
className = "",
|
|
285
|
+
disabled,
|
|
286
|
+
...props
|
|
287
|
+
}, ref) => {
|
|
288
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
289
|
+
const isPassword = type === "password";
|
|
290
|
+
const inputType = isPassword ? showPassword ? "text" : "password" : type;
|
|
291
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex w-full flex-col gap-1.5 ${className}`, children: [
|
|
292
|
+
label && /* @__PURE__ */ jsx("label", { className: "font-sans text-sm font-medium text-fg", children: label }),
|
|
293
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex items-center", children: [
|
|
294
|
+
Icon && /* @__PURE__ */ jsx("div", { className: "absolute left-3 text-muted", children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", strokeWidth: 1.5 }) }),
|
|
295
|
+
/* @__PURE__ */ jsx(
|
|
296
|
+
"input",
|
|
297
|
+
{
|
|
298
|
+
ref,
|
|
299
|
+
type: inputType,
|
|
300
|
+
disabled,
|
|
301
|
+
className: `w-full rounded border bg-surface px-3 py-2 font-sans text-sm text-fg placeholder:text-muted transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:bg-surface-raised disabled:text-muted ${Icon ? "pl-9" : ""} ${isPassword ? "pr-9" : ""} ${error ? "border-red-500 focus-visible:border-red-500 focus-visible:ring-red-500" : "border-border hover:border-border-strong focus-visible:border-accent focus-visible:ring-accent"}`,
|
|
302
|
+
...props
|
|
303
|
+
}
|
|
304
|
+
),
|
|
305
|
+
isPassword && /* @__PURE__ */ jsx(
|
|
306
|
+
"button",
|
|
307
|
+
{
|
|
308
|
+
type: "button",
|
|
309
|
+
onClick: () => setShowPassword(!showPassword),
|
|
310
|
+
disabled,
|
|
311
|
+
className: "absolute right-3 text-muted hover:text-fg focus:outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
312
|
+
"aria-label": showPassword ? "Hide password" : "Show password",
|
|
313
|
+
children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, { className: "h-4 w-4", strokeWidth: 1.5 }) : /* @__PURE__ */ jsx(EyeIcon, { className: "h-4 w-4", strokeWidth: 1.5 })
|
|
314
|
+
}
|
|
315
|
+
)
|
|
316
|
+
] }),
|
|
317
|
+
helperText && /* @__PURE__ */ jsx(
|
|
318
|
+
"span",
|
|
319
|
+
{
|
|
320
|
+
className: `font-sans text-xs ${error ? "text-red-500" : "text-muted"}`,
|
|
321
|
+
children: helperText
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
] });
|
|
325
|
+
}
|
|
326
|
+
);
|
|
327
|
+
Input.displayName = "Input";
|
|
328
|
+
var Textarea = forwardRef(
|
|
329
|
+
({ label, helperText, error, className = "", disabled, ...props }, ref) => {
|
|
330
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex w-full flex-col gap-1.5 ${className}`, children: [
|
|
331
|
+
label && /* @__PURE__ */ jsx("label", { className: "font-sans text-sm font-medium text-fg", children: label }),
|
|
332
|
+
/* @__PURE__ */ jsx(
|
|
333
|
+
"textarea",
|
|
334
|
+
{
|
|
335
|
+
ref,
|
|
336
|
+
disabled,
|
|
337
|
+
className: `min-h-[80px] w-full rounded border bg-surface px-3 py-2 font-sans text-sm text-fg placeholder:text-muted transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:bg-surface-raised disabled:text-muted ${error ? "border-red-500 focus-visible:border-red-500 focus-visible:ring-red-500" : "border-border hover:border-border-strong focus-visible:border-accent focus-visible:ring-accent"}`,
|
|
338
|
+
...props
|
|
339
|
+
}
|
|
340
|
+
),
|
|
341
|
+
helperText && /* @__PURE__ */ jsx(
|
|
342
|
+
"span",
|
|
343
|
+
{
|
|
344
|
+
className: `font-sans text-xs ${error ? "text-red-500" : "text-muted"}`,
|
|
345
|
+
children: helperText
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
] });
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
Textarea.displayName = "Textarea";
|
|
352
|
+
function Code({
|
|
353
|
+
children,
|
|
354
|
+
className = ""
|
|
355
|
+
}) {
|
|
356
|
+
return /* @__PURE__ */ jsx("span", { className: `font-condensed text-muted ${className}`, children });
|
|
357
|
+
}
|
|
358
|
+
function Tooltip({ label, children, placement = "top", block }) {
|
|
359
|
+
const [open, setOpen] = useState(false);
|
|
360
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
361
|
+
open,
|
|
362
|
+
onOpenChange: setOpen,
|
|
363
|
+
placement,
|
|
364
|
+
middleware: [offset(6), flip({ padding: 8 }), shift({ padding: 8 })],
|
|
365
|
+
whileElementsMounted: autoUpdate
|
|
366
|
+
});
|
|
367
|
+
const hover = useHover(context, { delay: { open: 250, close: 0 }, move: false });
|
|
368
|
+
const focus = useFocus(context);
|
|
369
|
+
const dismiss = useDismiss(context);
|
|
370
|
+
const role = useRole(context, { role: "tooltip" });
|
|
371
|
+
const { getReferenceProps, getFloatingProps } = useInteractions(
|
|
372
|
+
[
|
|
373
|
+
hover,
|
|
374
|
+
focus,
|
|
375
|
+
dismiss,
|
|
376
|
+
role
|
|
377
|
+
]
|
|
378
|
+
);
|
|
379
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
380
|
+
/* @__PURE__ */ jsx(
|
|
381
|
+
"span",
|
|
382
|
+
{
|
|
383
|
+
ref: refs.setReference,
|
|
384
|
+
...getReferenceProps(),
|
|
385
|
+
className: block ? "block min-w-0 truncate" : "inline-flex",
|
|
386
|
+
children
|
|
387
|
+
}
|
|
388
|
+
),
|
|
389
|
+
open && /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(
|
|
390
|
+
"div",
|
|
391
|
+
{
|
|
392
|
+
ref: refs.setFloating,
|
|
393
|
+
style: floatingStyles,
|
|
394
|
+
...getFloatingProps(),
|
|
395
|
+
className: "z-[60] max-w-xs rounded-md bg-black px-2.5 py-1.5 font-sans text-xs font-medium leading-snug text-white shadow-lg",
|
|
396
|
+
children: label
|
|
397
|
+
}
|
|
398
|
+
) })
|
|
399
|
+
] });
|
|
400
|
+
}
|
|
401
|
+
function Tabs({ items, value, onChange, className = "" }) {
|
|
402
|
+
return /* @__PURE__ */ jsx(
|
|
403
|
+
"div",
|
|
404
|
+
{
|
|
405
|
+
role: "tablist",
|
|
406
|
+
className: `flex items-center gap-1 border-b border-border-strong ${className}`,
|
|
407
|
+
children: items.map((item) => {
|
|
408
|
+
const Icon = item.icon;
|
|
409
|
+
const active = item.id === value;
|
|
410
|
+
return /* @__PURE__ */ jsxs(
|
|
411
|
+
"button",
|
|
412
|
+
{
|
|
413
|
+
type: "button",
|
|
414
|
+
role: "tab",
|
|
415
|
+
"aria-selected": active,
|
|
416
|
+
onClick: () => onChange(item.id),
|
|
417
|
+
className: `-mb-px flex items-center gap-2 border-b-2 px-3 py-2.5 font-sans text-sm font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1 ${active ? "border-accent text-accent" : "border-transparent text-muted hover:text-fg"}`,
|
|
418
|
+
children: [
|
|
419
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", strokeWidth: 1.75 }),
|
|
420
|
+
item.label
|
|
421
|
+
]
|
|
422
|
+
},
|
|
423
|
+
item.id
|
|
424
|
+
);
|
|
425
|
+
})
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
var VARIANT = {
|
|
430
|
+
success: {
|
|
431
|
+
Icon: CheckCircle2Icon,
|
|
432
|
+
fill: "var(--color-success-bg)",
|
|
433
|
+
border: "var(--color-success-border)",
|
|
434
|
+
color: "var(--color-success)"
|
|
435
|
+
},
|
|
436
|
+
error: {
|
|
437
|
+
Icon: XCircleIcon,
|
|
438
|
+
fill: "var(--color-danger-bg)",
|
|
439
|
+
border: "var(--color-danger-border)",
|
|
440
|
+
color: "var(--color-danger)"
|
|
441
|
+
},
|
|
442
|
+
info: {
|
|
443
|
+
Icon: InfoIcon,
|
|
444
|
+
fill: "var(--color-info-bg)",
|
|
445
|
+
border: "var(--color-info-border)",
|
|
446
|
+
color: "var(--color-info)"
|
|
447
|
+
},
|
|
448
|
+
warning: {
|
|
449
|
+
Icon: AlertTriangleIcon,
|
|
450
|
+
fill: "var(--color-warning-bg)",
|
|
451
|
+
border: "var(--color-warning-border)",
|
|
452
|
+
color: "var(--color-warning)"
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
function ToastCard({
|
|
456
|
+
t,
|
|
457
|
+
variant,
|
|
458
|
+
title,
|
|
459
|
+
description
|
|
460
|
+
}) {
|
|
461
|
+
const { Icon, fill, border, color } = VARIANT[variant];
|
|
462
|
+
return /* @__PURE__ */ jsxs(
|
|
463
|
+
"div",
|
|
464
|
+
{
|
|
465
|
+
className: `pointer-events-auto flex w-full max-w-sm items-start gap-3 rounded-lg border border-border-strong bg-surface px-4 py-3 font-sans shadow-lg transition-all duration-200 ${t.visible ? "translate-y-0 opacity-100" : "-translate-y-1 opacity-0"}`,
|
|
466
|
+
role: "status",
|
|
467
|
+
children: [
|
|
468
|
+
/* @__PURE__ */ jsx(
|
|
469
|
+
"span",
|
|
470
|
+
{
|
|
471
|
+
className: "mt-0.5 flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full border",
|
|
472
|
+
style: { backgroundColor: fill, borderColor: border, color },
|
|
473
|
+
"aria-hidden": "true",
|
|
474
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", strokeWidth: 1.5 })
|
|
475
|
+
}
|
|
476
|
+
),
|
|
477
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 pt-0.5", children: [
|
|
478
|
+
/* @__PURE__ */ jsx("p", { className: "font-sans text-sm font-semibold text-fg", children: title }),
|
|
479
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 font-sans text-sm leading-snug text-fg-secondary", children: description })
|
|
480
|
+
] }),
|
|
481
|
+
/* @__PURE__ */ jsx(
|
|
482
|
+
"button",
|
|
483
|
+
{
|
|
484
|
+
type: "button",
|
|
485
|
+
onClick: () => toast.dismiss(t.id),
|
|
486
|
+
"aria-label": "Dismiss",
|
|
487
|
+
className: "-mr-1 flex h-6 w-6 flex-shrink-0 items-center justify-center rounded text-muted transition-colors hover:bg-surface-raised hover:text-fg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
488
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "h-3.5 w-3.5", strokeWidth: 2 })
|
|
489
|
+
}
|
|
490
|
+
)
|
|
491
|
+
]
|
|
492
|
+
}
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
function show(variant, title, options = {}) {
|
|
496
|
+
return toast.custom(
|
|
497
|
+
(t) => /* @__PURE__ */ jsx(
|
|
498
|
+
ToastCard,
|
|
499
|
+
{
|
|
500
|
+
t,
|
|
501
|
+
variant,
|
|
502
|
+
title,
|
|
503
|
+
description: options.description
|
|
504
|
+
}
|
|
505
|
+
),
|
|
506
|
+
{ duration: options.duration }
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
var notify = {
|
|
510
|
+
success: (title, options) => show("success", title, options),
|
|
511
|
+
error: (title, options) => show("error", title, options),
|
|
512
|
+
info: (title, options) => show("info", title, options),
|
|
513
|
+
warning: (title, options) => show("warning", title, options),
|
|
514
|
+
dismiss: (id) => toast.dismiss(id)
|
|
515
|
+
};
|
|
516
|
+
function AppToaster() {
|
|
517
|
+
return /* @__PURE__ */ jsx(
|
|
518
|
+
Toaster,
|
|
519
|
+
{
|
|
520
|
+
position: "bottom-right",
|
|
521
|
+
gutter: 12,
|
|
522
|
+
toastOptions: { duration: 4e3 }
|
|
523
|
+
}
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
var STATUS_CONFIG = {
|
|
527
|
+
backlog: {
|
|
528
|
+
label: "Backlog",
|
|
529
|
+
Icon: Clock4Icon,
|
|
530
|
+
fill: "var(--color-neutral-bg)",
|
|
531
|
+
border: "var(--color-neutral-border)",
|
|
532
|
+
color: "var(--color-neutral)"
|
|
533
|
+
},
|
|
534
|
+
ready: {
|
|
535
|
+
label: "Ready",
|
|
536
|
+
Icon: PlayCircleIcon,
|
|
537
|
+
fill: "var(--color-info-bg)",
|
|
538
|
+
border: "var(--color-info-border)",
|
|
539
|
+
color: "var(--color-info)"
|
|
540
|
+
},
|
|
541
|
+
"in-progress": {
|
|
542
|
+
label: "In progress",
|
|
543
|
+
Icon: CircleDashedIcon,
|
|
544
|
+
fill: "var(--color-warning-bg)",
|
|
545
|
+
border: "var(--color-warning-border)",
|
|
546
|
+
color: "var(--color-warning)"
|
|
547
|
+
},
|
|
548
|
+
"in-review": {
|
|
549
|
+
label: "In Review",
|
|
550
|
+
Icon: ScanSearchIcon,
|
|
551
|
+
fill: "var(--color-review-bg)",
|
|
552
|
+
border: "var(--color-review-border)",
|
|
553
|
+
color: "var(--color-review)"
|
|
554
|
+
},
|
|
555
|
+
blocked: {
|
|
556
|
+
label: "Blocked",
|
|
557
|
+
Icon: BanIcon,
|
|
558
|
+
fill: "var(--color-danger-bg)",
|
|
559
|
+
border: "var(--color-danger-border)",
|
|
560
|
+
color: "var(--color-danger)"
|
|
561
|
+
},
|
|
562
|
+
completed: {
|
|
563
|
+
label: "Completed",
|
|
564
|
+
Icon: CheckCircle2Icon,
|
|
565
|
+
fill: "var(--color-success-bg)",
|
|
566
|
+
border: "var(--color-success-border)",
|
|
567
|
+
color: "var(--color-success)"
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
var PROJECT_STATUS_CONFIG = {
|
|
571
|
+
active: {
|
|
572
|
+
label: "Active",
|
|
573
|
+
Icon: CircleDotIcon,
|
|
574
|
+
fill: "var(--color-success-bg)",
|
|
575
|
+
border: "var(--color-success-border)",
|
|
576
|
+
color: "var(--color-success)"
|
|
577
|
+
},
|
|
578
|
+
archived: {
|
|
579
|
+
label: "Archived",
|
|
580
|
+
Icon: ArchiveIcon,
|
|
581
|
+
fill: "var(--color-neutral-bg)",
|
|
582
|
+
border: "var(--color-neutral-border)",
|
|
583
|
+
color: "var(--color-neutral)"
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
var PLAN_STATUS_CONFIG = {
|
|
587
|
+
backlog: {
|
|
588
|
+
label: "Backlog",
|
|
589
|
+
Icon: Clock4Icon,
|
|
590
|
+
fill: "var(--color-neutral-bg)",
|
|
591
|
+
border: "var(--color-neutral-border)",
|
|
592
|
+
color: "var(--color-neutral)"
|
|
593
|
+
},
|
|
594
|
+
scoped: {
|
|
595
|
+
label: "Scoped",
|
|
596
|
+
Icon: ScanSearchIcon,
|
|
597
|
+
fill: "var(--color-info-bg)",
|
|
598
|
+
border: "var(--color-info-border)",
|
|
599
|
+
color: "var(--color-info)"
|
|
600
|
+
},
|
|
601
|
+
cancelled: {
|
|
602
|
+
label: "Cancelled",
|
|
603
|
+
Icon: BanIcon,
|
|
604
|
+
fill: "var(--color-danger-bg)",
|
|
605
|
+
border: "var(--color-danger-border)",
|
|
606
|
+
color: "var(--color-danger)"
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
var PLAN_STATUS_ORDER = ["backlog", "scoped", "cancelled"];
|
|
610
|
+
var ALL_STATUS_CONFIG = { ...STATUS_CONFIG, ...PROJECT_STATUS_CONFIG, ...PLAN_STATUS_CONFIG };
|
|
611
|
+
function StatusBadge({ status }) {
|
|
612
|
+
const { label, Icon, fill, border, color } = ALL_STATUS_CONFIG[status];
|
|
613
|
+
return /* @__PURE__ */ jsxs(
|
|
614
|
+
"span",
|
|
615
|
+
{
|
|
616
|
+
className: "inline-flex items-center gap-1.5 rounded border px-2 py-1 font-condensed text-xs font-medium leading-[15px]",
|
|
617
|
+
style: {
|
|
618
|
+
backgroundColor: fill,
|
|
619
|
+
borderColor: border,
|
|
620
|
+
color
|
|
621
|
+
},
|
|
622
|
+
children: [
|
|
623
|
+
/* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5", strokeWidth: 1.5, "aria-hidden": "true" }),
|
|
624
|
+
label
|
|
625
|
+
]
|
|
626
|
+
}
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
var NEUTRAL_TONE = {
|
|
630
|
+
bg: "var(--color-surface-strong)",
|
|
631
|
+
border: "var(--color-border-strong)",
|
|
632
|
+
color: "var(--color-text-muted)"
|
|
633
|
+
};
|
|
634
|
+
function EmptyState({
|
|
635
|
+
icon: Icon,
|
|
636
|
+
title,
|
|
637
|
+
description,
|
|
638
|
+
action,
|
|
639
|
+
tone = NEUTRAL_TONE,
|
|
640
|
+
className = ""
|
|
641
|
+
}) {
|
|
642
|
+
return /* @__PURE__ */ jsxs(
|
|
643
|
+
"div",
|
|
644
|
+
{
|
|
645
|
+
className: `flex h-full min-h-[360px] w-full flex-col items-center justify-center px-6 py-12 text-center ${className}`,
|
|
646
|
+
children: [
|
|
647
|
+
/* @__PURE__ */ jsxs("div", { className: "relative mb-5 flex items-center justify-center", children: [
|
|
648
|
+
/* @__PURE__ */ jsx(
|
|
649
|
+
"span",
|
|
650
|
+
{
|
|
651
|
+
className: "absolute h-20 w-20 rounded-3xl opacity-60",
|
|
652
|
+
style: { backgroundColor: tone.bg },
|
|
653
|
+
"aria-hidden": "true"
|
|
654
|
+
}
|
|
655
|
+
),
|
|
656
|
+
/* @__PURE__ */ jsx(
|
|
657
|
+
"span",
|
|
658
|
+
{
|
|
659
|
+
className: "relative flex h-14 w-14 items-center justify-center rounded-2xl border shadow-[0px_1px_2px_rgba(0,0,0,0.06)]",
|
|
660
|
+
style: {
|
|
661
|
+
backgroundColor: "var(--color-surface)",
|
|
662
|
+
borderColor: tone.border,
|
|
663
|
+
color: tone.color
|
|
664
|
+
},
|
|
665
|
+
"aria-hidden": "true",
|
|
666
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "h-6 w-6", strokeWidth: 1.5 })
|
|
667
|
+
}
|
|
668
|
+
)
|
|
669
|
+
] }),
|
|
670
|
+
/* @__PURE__ */ jsx("h2", { className: "font-sans text-lg font-semibold tracking-tight text-fg", children: title }),
|
|
671
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-sm font-sans text-sm leading-relaxed text-muted", children: description }),
|
|
672
|
+
action && /* @__PURE__ */ jsx("div", { className: "mt-6", children: action })
|
|
673
|
+
]
|
|
674
|
+
}
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
function FormSection({
|
|
678
|
+
title,
|
|
679
|
+
description,
|
|
680
|
+
children,
|
|
681
|
+
className = ""
|
|
682
|
+
}) {
|
|
683
|
+
return /* @__PURE__ */ jsxs("section", { className: `flex flex-col gap-4 ${className}`, children: [
|
|
684
|
+
(title || description) && /* @__PURE__ */ jsxs("div", { children: [
|
|
685
|
+
title && /* @__PURE__ */ jsx("h3", { className: "font-sans text-sm font-semibold text-fg", children: title }),
|
|
686
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 font-sans text-sm text-muted", children: description })
|
|
687
|
+
] }),
|
|
688
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children })
|
|
689
|
+
] });
|
|
690
|
+
}
|
|
691
|
+
function Field({ label, htmlFor, help, error, children }) {
|
|
692
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
693
|
+
/* @__PURE__ */ jsx(
|
|
694
|
+
"label",
|
|
695
|
+
{
|
|
696
|
+
htmlFor,
|
|
697
|
+
className: "font-sans text-sm font-medium text-fg",
|
|
698
|
+
children: label
|
|
699
|
+
}
|
|
700
|
+
),
|
|
701
|
+
children,
|
|
702
|
+
error ? /* @__PURE__ */ jsx("span", { className: "font-sans text-xs text-red-500", children: error }) : help ? /* @__PURE__ */ jsx("span", { className: "font-sans text-xs text-muted", children: help }) : null
|
|
703
|
+
] });
|
|
704
|
+
}
|
|
705
|
+
var CONFIG = {
|
|
706
|
+
clean: null,
|
|
707
|
+
dirty: { label: "Unsaved changes", className: "text-warning" },
|
|
708
|
+
saving: { label: "Saving\u2026", className: "text-muted" },
|
|
709
|
+
saved: { label: "Saved", className: "text-success" }
|
|
710
|
+
};
|
|
711
|
+
function DirtyStateIndicator({ state }) {
|
|
712
|
+
const config = CONFIG[state];
|
|
713
|
+
if (!config) return null;
|
|
714
|
+
return /* @__PURE__ */ jsxs(
|
|
715
|
+
"span",
|
|
716
|
+
{
|
|
717
|
+
className: `flex items-center gap-1.5 font-sans text-xs font-medium ${config.className}`,
|
|
718
|
+
"aria-live": "polite",
|
|
719
|
+
children: [
|
|
720
|
+
state === "saving" && /* @__PURE__ */ jsx(Loader2Icon, { className: "h-3.5 w-3.5 animate-spin", strokeWidth: 2 }),
|
|
721
|
+
state === "saved" && /* @__PURE__ */ jsx(CheckIcon, { className: "h-3.5 w-3.5", strokeWidth: 2.5 }),
|
|
722
|
+
state === "dirty" && /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-warning", "aria-hidden": "true" }),
|
|
723
|
+
config.label
|
|
724
|
+
]
|
|
725
|
+
}
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
function RowActions({ actions }) {
|
|
729
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-0.5", children: actions.map((a) => /* @__PURE__ */ jsx(
|
|
730
|
+
"button",
|
|
731
|
+
{
|
|
732
|
+
type: "button",
|
|
733
|
+
"aria-label": a.label,
|
|
734
|
+
title: a.label,
|
|
735
|
+
onClick: (e) => {
|
|
736
|
+
e.stopPropagation();
|
|
737
|
+
a.onClick();
|
|
738
|
+
},
|
|
739
|
+
className: `rounded p-1.5 text-muted transition-colors ${a.danger ? "hover:bg-danger-bg hover:text-danger" : "hover:bg-surface-raised hover:text-fg"}`,
|
|
740
|
+
children: /* @__PURE__ */ jsx(a.icon, { className: "h-4 w-4", strokeWidth: 1.75 })
|
|
741
|
+
},
|
|
742
|
+
a.label
|
|
743
|
+
)) });
|
|
744
|
+
}
|
|
745
|
+
function Markdown({ children }) {
|
|
746
|
+
return /* @__PURE__ */ jsx(
|
|
747
|
+
"div",
|
|
748
|
+
{
|
|
749
|
+
className: [
|
|
750
|
+
"font-sans text-[15px] leading-7 text-fg-secondary",
|
|
751
|
+
"[&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
|
|
752
|
+
"[&_p]:my-3",
|
|
753
|
+
"[&_h1]:mb-3 [&_h1]:mt-8 [&_h1]:text-2xl [&_h1]:font-bold [&_h1]:leading-snug [&_h1]:text-fg",
|
|
754
|
+
"[&_h2]:mb-2.5 [&_h2]:mt-8 [&_h2]:text-xl [&_h2]:font-semibold [&_h2]:leading-snug [&_h2]:text-fg",
|
|
755
|
+
"[&_h3]:mb-2 [&_h3]:mt-6 [&_h3]:text-base [&_h3]:font-semibold [&_h3]:text-fg",
|
|
756
|
+
"[&_ul]:my-3.5 [&_ul]:list-disc [&_ul]:pl-6 [&_ol]:my-3.5 [&_ol]:list-decimal [&_ol]:pl-6",
|
|
757
|
+
"[&_li]:my-1.5 [&_li]:pl-1.5 [&_li>p]:my-0",
|
|
758
|
+
"[&_a]:text-accent [&_a]:underline [&_a]:underline-offset-2 [&_strong]:font-semibold [&_strong]:text-fg",
|
|
759
|
+
"[&_blockquote]:my-4 [&_blockquote]:border-l-2 [&_blockquote]:border-accent [&_blockquote]:pl-4 [&_blockquote]:text-fg-secondary",
|
|
760
|
+
"[&_code]:rounded [&_code]:bg-surface-strong [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[13px] [&_code]:text-fg-secondary",
|
|
761
|
+
"[&_pre]:my-4 [&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:bg-surface-raised [&_pre]:p-4 [&_pre_code]:bg-transparent [&_pre_code]:p-0",
|
|
762
|
+
"[&_hr]:my-7 [&_hr]:border-border-strong",
|
|
763
|
+
"[&_table]:my-4 [&_table]:w-full [&_table]:border-collapse [&_td]:border [&_td]:border-border-strong [&_td]:px-3 [&_td]:py-1.5 [&_th]:border [&_th]:border-border-strong [&_th]:bg-surface-raised [&_th]:px-3 [&_th]:py-1.5 [&_th]:text-left [&_th]:font-semibold"
|
|
764
|
+
].join(" "),
|
|
765
|
+
children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children })
|
|
766
|
+
}
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
var SIZES2 = {
|
|
770
|
+
sm: "max-w-sm",
|
|
771
|
+
md: "max-w-lg",
|
|
772
|
+
lg: "max-w-2xl"
|
|
773
|
+
};
|
|
774
|
+
function Modal({
|
|
775
|
+
open,
|
|
776
|
+
onClose,
|
|
777
|
+
title,
|
|
778
|
+
description,
|
|
779
|
+
footer,
|
|
780
|
+
size: size2 = "md",
|
|
781
|
+
hideCloseButton,
|
|
782
|
+
closeOnBackdrop,
|
|
783
|
+
closeOnEsc,
|
|
784
|
+
children
|
|
785
|
+
}) {
|
|
786
|
+
return /* @__PURE__ */ jsx(
|
|
787
|
+
Overlay,
|
|
788
|
+
{
|
|
789
|
+
open,
|
|
790
|
+
onClose,
|
|
791
|
+
position: "center",
|
|
792
|
+
widthClassName: SIZES2[size2],
|
|
793
|
+
title,
|
|
794
|
+
description,
|
|
795
|
+
footer,
|
|
796
|
+
hideCloseButton,
|
|
797
|
+
closeOnBackdrop,
|
|
798
|
+
closeOnEsc,
|
|
799
|
+
children
|
|
800
|
+
}
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
var SIZES3 = {
|
|
804
|
+
sm: "max-w-sm",
|
|
805
|
+
md: "max-w-md",
|
|
806
|
+
lg: "max-w-lg"
|
|
807
|
+
};
|
|
808
|
+
function Drawer({
|
|
809
|
+
open,
|
|
810
|
+
onClose,
|
|
811
|
+
side = "right",
|
|
812
|
+
title,
|
|
813
|
+
description,
|
|
814
|
+
footer,
|
|
815
|
+
size: size2 = "md",
|
|
816
|
+
hideCloseButton,
|
|
817
|
+
closeOnBackdrop,
|
|
818
|
+
closeOnEsc,
|
|
819
|
+
children
|
|
820
|
+
}) {
|
|
821
|
+
return /* @__PURE__ */ jsx(
|
|
822
|
+
Overlay,
|
|
823
|
+
{
|
|
824
|
+
open,
|
|
825
|
+
onClose,
|
|
826
|
+
position: side,
|
|
827
|
+
widthClassName: SIZES3[size2],
|
|
828
|
+
title,
|
|
829
|
+
description,
|
|
830
|
+
footer,
|
|
831
|
+
hideCloseButton,
|
|
832
|
+
closeOnBackdrop,
|
|
833
|
+
closeOnEsc,
|
|
834
|
+
children
|
|
835
|
+
}
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
function ConfirmDialog({
|
|
839
|
+
open,
|
|
840
|
+
onClose,
|
|
841
|
+
title,
|
|
842
|
+
message,
|
|
843
|
+
confirmLabel = "Confirm",
|
|
844
|
+
cancelLabel = "Cancel",
|
|
845
|
+
onConfirm,
|
|
846
|
+
variant = "default",
|
|
847
|
+
loading = false
|
|
848
|
+
}) {
|
|
849
|
+
const destructive = variant === "destructive";
|
|
850
|
+
return /* @__PURE__ */ jsx(
|
|
851
|
+
Modal,
|
|
852
|
+
{
|
|
853
|
+
open,
|
|
854
|
+
onClose,
|
|
855
|
+
size: "sm",
|
|
856
|
+
title,
|
|
857
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
858
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, disabled: loading, children: cancelLabel }),
|
|
859
|
+
/* @__PURE__ */ jsx(
|
|
860
|
+
Button,
|
|
861
|
+
{
|
|
862
|
+
variant: destructive ? "destructive" : "primary",
|
|
863
|
+
onClick: onConfirm,
|
|
864
|
+
disabled: loading,
|
|
865
|
+
children: loading ? "Working\u2026" : confirmLabel
|
|
866
|
+
}
|
|
867
|
+
)
|
|
868
|
+
] }),
|
|
869
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
870
|
+
destructive && /* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-danger-bg text-danger", children: /* @__PURE__ */ jsx(
|
|
871
|
+
AlertTriangleIcon,
|
|
872
|
+
{
|
|
873
|
+
className: "h-5 w-5",
|
|
874
|
+
strokeWidth: 2,
|
|
875
|
+
"aria-hidden": "true"
|
|
876
|
+
}
|
|
877
|
+
) }),
|
|
878
|
+
/* @__PURE__ */ jsx("p", { className: "font-sans text-sm leading-relaxed text-fg-secondary", children: message })
|
|
879
|
+
] })
|
|
880
|
+
}
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
function SaveBar({
|
|
884
|
+
dirty,
|
|
885
|
+
onSave,
|
|
886
|
+
onDiscard,
|
|
887
|
+
state,
|
|
888
|
+
saveLabel = "Save",
|
|
889
|
+
discardLabel = "Discard"
|
|
890
|
+
}) {
|
|
891
|
+
const resolvedState = state ?? (dirty ? "dirty" : "clean");
|
|
892
|
+
return /* @__PURE__ */ jsxs("div", { className: "sticky bottom-0 z-10 flex items-center justify-between gap-4 border-t border-border-strong bg-surface px-1 py-3 backdrop-blur", children: [
|
|
893
|
+
/* @__PURE__ */ jsx(DirtyStateIndicator, { state: resolvedState }),
|
|
894
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
895
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onDiscard, disabled: !dirty, children: discardLabel }),
|
|
896
|
+
/* @__PURE__ */ jsx(Button, { onClick: onSave, disabled: !dirty, children: saveLabel })
|
|
897
|
+
] })
|
|
898
|
+
] });
|
|
899
|
+
}
|
|
900
|
+
var activeClose = null;
|
|
901
|
+
function usePopover({
|
|
902
|
+
open,
|
|
903
|
+
onOpenChange,
|
|
904
|
+
placement = "bottom-start",
|
|
905
|
+
gap = 6,
|
|
906
|
+
matchWidth = false,
|
|
907
|
+
role = "menu"
|
|
908
|
+
}) {
|
|
909
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
910
|
+
open,
|
|
911
|
+
onOpenChange,
|
|
912
|
+
placement,
|
|
913
|
+
whileElementsMounted: autoUpdate,
|
|
914
|
+
middleware: [
|
|
915
|
+
offset(gap),
|
|
916
|
+
flip({ padding: 8 }),
|
|
917
|
+
shift({ padding: 8 }),
|
|
918
|
+
size({
|
|
919
|
+
padding: 8,
|
|
920
|
+
apply({ availableHeight, rects, elements }) {
|
|
921
|
+
Object.assign(elements.floating.style, {
|
|
922
|
+
maxHeight: `${Math.max(160, availableHeight)}px`,
|
|
923
|
+
...matchWidth ? { width: `${rects.reference.width}px` } : {}
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
})
|
|
927
|
+
]
|
|
928
|
+
});
|
|
929
|
+
const onOpenChangeRef = useRef(onOpenChange);
|
|
930
|
+
onOpenChangeRef.current = onOpenChange;
|
|
931
|
+
const closeSelfRef = useRef();
|
|
932
|
+
if (!closeSelfRef.current) {
|
|
933
|
+
closeSelfRef.current = () => onOpenChangeRef.current(false);
|
|
934
|
+
}
|
|
935
|
+
useEffect(() => {
|
|
936
|
+
if (!open) return;
|
|
937
|
+
if (activeClose && activeClose !== closeSelfRef.current) {
|
|
938
|
+
activeClose();
|
|
939
|
+
}
|
|
940
|
+
activeClose = closeSelfRef.current;
|
|
941
|
+
return () => {
|
|
942
|
+
if (activeClose === closeSelfRef.current) activeClose = null;
|
|
943
|
+
};
|
|
944
|
+
}, [open]);
|
|
945
|
+
const dismiss = useDismiss(context, { outsidePress: true });
|
|
946
|
+
const roleInteraction = useRole(context, { role });
|
|
947
|
+
const { getReferenceProps, getFloatingProps } = useInteractions(
|
|
948
|
+
[
|
|
949
|
+
dismiss,
|
|
950
|
+
roleInteraction
|
|
951
|
+
]
|
|
952
|
+
);
|
|
953
|
+
return {
|
|
954
|
+
refs,
|
|
955
|
+
floatingStyles,
|
|
956
|
+
context,
|
|
957
|
+
getReferenceProps,
|
|
958
|
+
getFloatingProps
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
function Dropdown({
|
|
962
|
+
trigger,
|
|
963
|
+
children,
|
|
964
|
+
align = "left",
|
|
965
|
+
className = ""
|
|
966
|
+
}) {
|
|
967
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
968
|
+
const { refs, floatingStyles, context, getReferenceProps, getFloatingProps } = usePopover({
|
|
969
|
+
open: isOpen,
|
|
970
|
+
onOpenChange: setIsOpen,
|
|
971
|
+
placement: align === "right" ? "bottom-end" : "bottom-start",
|
|
972
|
+
role: "menu"
|
|
973
|
+
});
|
|
974
|
+
return /* @__PURE__ */ jsxs("div", { className: `relative inline-block text-left ${className}`, children: [
|
|
975
|
+
/* @__PURE__ */ jsx(
|
|
976
|
+
"div",
|
|
977
|
+
{
|
|
978
|
+
ref: refs.setReference,
|
|
979
|
+
...getReferenceProps({
|
|
980
|
+
onClick: () => setIsOpen((o) => !o)
|
|
981
|
+
}),
|
|
982
|
+
className: "inline-block",
|
|
983
|
+
children: trigger
|
|
984
|
+
}
|
|
985
|
+
),
|
|
986
|
+
/* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(
|
|
987
|
+
"div",
|
|
988
|
+
{
|
|
989
|
+
ref: refs.setFloating,
|
|
990
|
+
style: floatingStyles,
|
|
991
|
+
...getFloatingProps(),
|
|
992
|
+
className: "z-50",
|
|
993
|
+
children: /* @__PURE__ */ jsx(
|
|
994
|
+
motion.div,
|
|
995
|
+
{
|
|
996
|
+
initial: {
|
|
997
|
+
opacity: 0,
|
|
998
|
+
y: -4,
|
|
999
|
+
scale: 0.98
|
|
1000
|
+
},
|
|
1001
|
+
animate: {
|
|
1002
|
+
opacity: 1,
|
|
1003
|
+
y: 0,
|
|
1004
|
+
scale: 1
|
|
1005
|
+
},
|
|
1006
|
+
exit: {
|
|
1007
|
+
opacity: 0,
|
|
1008
|
+
y: -4,
|
|
1009
|
+
scale: 0.98
|
|
1010
|
+
},
|
|
1011
|
+
transition: {
|
|
1012
|
+
duration: 0.15,
|
|
1013
|
+
ease: "easeOut"
|
|
1014
|
+
},
|
|
1015
|
+
className: "min-w-[200px] overflow-auto rounded-md border border-border bg-surface py-1 shadow-lg",
|
|
1016
|
+
children: Children.map(children, (child) => {
|
|
1017
|
+
if (isValidElement(child)) {
|
|
1018
|
+
return cloneElement(child, {
|
|
1019
|
+
onClick: (e) => {
|
|
1020
|
+
if (child.props.onClick) child.props.onClick(e);
|
|
1021
|
+
setIsOpen(false);
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
return child;
|
|
1026
|
+
})
|
|
1027
|
+
}
|
|
1028
|
+
)
|
|
1029
|
+
}
|
|
1030
|
+
) }) })
|
|
1031
|
+
] });
|
|
1032
|
+
}
|
|
1033
|
+
function DropdownItem({
|
|
1034
|
+
children,
|
|
1035
|
+
icon: Icon,
|
|
1036
|
+
danger,
|
|
1037
|
+
className = "",
|
|
1038
|
+
...props
|
|
1039
|
+
}) {
|
|
1040
|
+
return /* @__PURE__ */ jsxs(
|
|
1041
|
+
"button",
|
|
1042
|
+
{
|
|
1043
|
+
type: "button",
|
|
1044
|
+
role: "menuitem",
|
|
1045
|
+
className: `flex w-full items-center gap-2 px-4 py-2 text-left font-sans text-sm transition-colors hover:bg-surface-raised focus:bg-surface-raised focus:outline-none ${danger ? "text-red-600" : "text-fg"} ${className}`,
|
|
1046
|
+
...props,
|
|
1047
|
+
children: [
|
|
1048
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4", strokeWidth: 1.5 }),
|
|
1049
|
+
children
|
|
1050
|
+
]
|
|
1051
|
+
}
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
function Select({
|
|
1055
|
+
label,
|
|
1056
|
+
placeholder = "Select an option",
|
|
1057
|
+
options,
|
|
1058
|
+
value,
|
|
1059
|
+
onChange,
|
|
1060
|
+
error,
|
|
1061
|
+
helperText,
|
|
1062
|
+
disabled,
|
|
1063
|
+
className = ""
|
|
1064
|
+
}) {
|
|
1065
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1066
|
+
const { refs, floatingStyles, getReferenceProps, getFloatingProps } = usePopover({
|
|
1067
|
+
open: isOpen,
|
|
1068
|
+
onOpenChange: setIsOpen,
|
|
1069
|
+
placement: "bottom-start",
|
|
1070
|
+
matchWidth: true,
|
|
1071
|
+
role: "listbox"
|
|
1072
|
+
});
|
|
1073
|
+
const selectedOption = options.find((opt) => opt.value === value);
|
|
1074
|
+
const handleKeyDown = (e) => {
|
|
1075
|
+
if (disabled) return;
|
|
1076
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1077
|
+
e.preventDefault();
|
|
1078
|
+
setIsOpen(!isOpen);
|
|
1079
|
+
} else if (e.key === "Escape") {
|
|
1080
|
+
setIsOpen(false);
|
|
1081
|
+
}
|
|
1082
|
+
};
|
|
1083
|
+
const handleSelect = (val) => {
|
|
1084
|
+
onChange?.(val);
|
|
1085
|
+
setIsOpen(false);
|
|
1086
|
+
};
|
|
1087
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex w-full flex-col gap-1.5 ${className}`, children: [
|
|
1088
|
+
label && /* @__PURE__ */ jsx("label", { className: "font-sans text-sm font-medium text-fg", children: label }),
|
|
1089
|
+
/* @__PURE__ */ jsxs(
|
|
1090
|
+
"button",
|
|
1091
|
+
{
|
|
1092
|
+
ref: refs.setReference,
|
|
1093
|
+
type: "button",
|
|
1094
|
+
disabled,
|
|
1095
|
+
"aria-haspopup": "listbox",
|
|
1096
|
+
"aria-expanded": isOpen,
|
|
1097
|
+
...getReferenceProps({
|
|
1098
|
+
onClick: () => !disabled && setIsOpen((o) => !o),
|
|
1099
|
+
onKeyDown: handleKeyDown
|
|
1100
|
+
}),
|
|
1101
|
+
className: `flex w-full items-center justify-between rounded border bg-surface px-3 py-2 text-left font-sans text-sm transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:bg-surface-raised disabled:text-muted ${error ? "border-red-500 focus-visible:border-red-500 focus-visible:ring-red-500" : "border-border hover:border-border-strong focus-visible:border-accent focus-visible:ring-accent"}`,
|
|
1102
|
+
children: [
|
|
1103
|
+
/* @__PURE__ */ jsx("span", { className: selectedOption ? "text-fg" : "text-muted", children: selectedOption ? selectedOption.label : placeholder }),
|
|
1104
|
+
/* @__PURE__ */ jsx(
|
|
1105
|
+
ChevronDownIcon,
|
|
1106
|
+
{
|
|
1107
|
+
className: `h-4 w-4 text-muted transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`,
|
|
1108
|
+
strokeWidth: 1.5
|
|
1109
|
+
}
|
|
1110
|
+
)
|
|
1111
|
+
]
|
|
1112
|
+
}
|
|
1113
|
+
),
|
|
1114
|
+
/* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(
|
|
1115
|
+
"div",
|
|
1116
|
+
{
|
|
1117
|
+
ref: refs.setFloating,
|
|
1118
|
+
style: floatingStyles,
|
|
1119
|
+
...getFloatingProps(),
|
|
1120
|
+
className: "z-50",
|
|
1121
|
+
children: /* @__PURE__ */ jsx(
|
|
1122
|
+
motion.ul,
|
|
1123
|
+
{
|
|
1124
|
+
role: "listbox",
|
|
1125
|
+
initial: {
|
|
1126
|
+
opacity: 0,
|
|
1127
|
+
y: -4,
|
|
1128
|
+
scale: 0.98
|
|
1129
|
+
},
|
|
1130
|
+
animate: {
|
|
1131
|
+
opacity: 1,
|
|
1132
|
+
y: 0,
|
|
1133
|
+
scale: 1
|
|
1134
|
+
},
|
|
1135
|
+
exit: {
|
|
1136
|
+
opacity: 0,
|
|
1137
|
+
y: -4,
|
|
1138
|
+
scale: 0.98
|
|
1139
|
+
},
|
|
1140
|
+
transition: {
|
|
1141
|
+
duration: 0.15,
|
|
1142
|
+
ease: "easeOut"
|
|
1143
|
+
},
|
|
1144
|
+
className: "overflow-auto rounded-md border border-border bg-surface py-1 shadow-lg focus:outline-none",
|
|
1145
|
+
children: options.map(
|
|
1146
|
+
(option) => /* @__PURE__ */ jsxs(
|
|
1147
|
+
"li",
|
|
1148
|
+
{
|
|
1149
|
+
role: "option",
|
|
1150
|
+
"aria-selected": value === option.value,
|
|
1151
|
+
onClick: () => handleSelect(option.value),
|
|
1152
|
+
className: `relative flex cursor-pointer select-none items-center py-2 pl-3 pr-9 font-sans text-sm transition-colors hover:bg-surface-raised ${value === option.value ? "bg-surface-raised font-medium text-accent" : "text-fg"}`,
|
|
1153
|
+
children: [
|
|
1154
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate", children: option.label }),
|
|
1155
|
+
value === option.value && /* @__PURE__ */ jsx("span", { className: "absolute inset-y-0 right-0 flex items-center pr-3 text-accent", children: /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4", strokeWidth: 2 }) })
|
|
1156
|
+
]
|
|
1157
|
+
},
|
|
1158
|
+
option.value
|
|
1159
|
+
)
|
|
1160
|
+
)
|
|
1161
|
+
}
|
|
1162
|
+
)
|
|
1163
|
+
}
|
|
1164
|
+
) }) }),
|
|
1165
|
+
helperText && /* @__PURE__ */ jsx(
|
|
1166
|
+
"span",
|
|
1167
|
+
{
|
|
1168
|
+
className: `font-sans text-xs ${error ? "text-red-500" : "text-muted"}`,
|
|
1169
|
+
children: helperText
|
|
1170
|
+
}
|
|
1171
|
+
)
|
|
1172
|
+
] });
|
|
1173
|
+
}
|
|
1174
|
+
function Combobox({
|
|
1175
|
+
label,
|
|
1176
|
+
placeholder = "Search...",
|
|
1177
|
+
options,
|
|
1178
|
+
value,
|
|
1179
|
+
onChange,
|
|
1180
|
+
error,
|
|
1181
|
+
helperText,
|
|
1182
|
+
disabled,
|
|
1183
|
+
className = ""
|
|
1184
|
+
}) {
|
|
1185
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1186
|
+
const [query, setQuery] = useState("");
|
|
1187
|
+
const inputRef = useRef(null);
|
|
1188
|
+
const { refs, floatingStyles, getReferenceProps, getFloatingProps } = usePopover({
|
|
1189
|
+
open: isOpen,
|
|
1190
|
+
onOpenChange: (next) => {
|
|
1191
|
+
setIsOpen(next);
|
|
1192
|
+
if (!next) setQuery("");
|
|
1193
|
+
},
|
|
1194
|
+
placement: "bottom-start",
|
|
1195
|
+
matchWidth: true,
|
|
1196
|
+
role: "listbox"
|
|
1197
|
+
});
|
|
1198
|
+
useEffect(() => {
|
|
1199
|
+
if (isOpen) inputRef.current?.focus();
|
|
1200
|
+
}, [isOpen]);
|
|
1201
|
+
const selectedOption = options.find((opt) => opt.value === value);
|
|
1202
|
+
const filteredOptions = query === "" ? options : options.filter(
|
|
1203
|
+
(option) => option.label.toLowerCase().includes(query.toLowerCase())
|
|
1204
|
+
);
|
|
1205
|
+
const handleSelect = (val) => {
|
|
1206
|
+
onChange?.(val);
|
|
1207
|
+
setIsOpen(false);
|
|
1208
|
+
setQuery("");
|
|
1209
|
+
};
|
|
1210
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex w-full flex-col gap-1.5 ${className}`, children: [
|
|
1211
|
+
label && /* @__PURE__ */ jsx("label", { className: "font-sans text-sm font-medium text-fg", children: label }),
|
|
1212
|
+
/* @__PURE__ */ jsxs(
|
|
1213
|
+
"button",
|
|
1214
|
+
{
|
|
1215
|
+
ref: refs.setReference,
|
|
1216
|
+
type: "button",
|
|
1217
|
+
disabled,
|
|
1218
|
+
"aria-haspopup": "listbox",
|
|
1219
|
+
"aria-expanded": isOpen,
|
|
1220
|
+
...getReferenceProps({
|
|
1221
|
+
onClick: () => !disabled && setIsOpen((o) => !o)
|
|
1222
|
+
}),
|
|
1223
|
+
className: `flex w-full items-center justify-between rounded border bg-surface px-3 py-2 text-left font-sans text-sm transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:bg-surface-raised disabled:text-muted ${error ? "border-red-500 focus-visible:ring-red-500" : "border-border hover:border-border-strong focus-visible:border-accent focus-visible:ring-accent"}`,
|
|
1224
|
+
children: [
|
|
1225
|
+
/* @__PURE__ */ jsx("span", { className: selectedOption ? "text-fg" : "text-muted", children: selectedOption ? selectedOption.label : placeholder }),
|
|
1226
|
+
/* @__PURE__ */ jsx(
|
|
1227
|
+
ChevronDownIcon,
|
|
1228
|
+
{
|
|
1229
|
+
className: `h-4 w-4 text-muted transition-transform duration-200 ${isOpen ? "rotate-180" : ""}`,
|
|
1230
|
+
strokeWidth: 1.5
|
|
1231
|
+
}
|
|
1232
|
+
)
|
|
1233
|
+
]
|
|
1234
|
+
}
|
|
1235
|
+
),
|
|
1236
|
+
/* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(
|
|
1237
|
+
"div",
|
|
1238
|
+
{
|
|
1239
|
+
ref: refs.setFloating,
|
|
1240
|
+
style: floatingStyles,
|
|
1241
|
+
...getFloatingProps(),
|
|
1242
|
+
className: "z-50",
|
|
1243
|
+
children: /* @__PURE__ */ jsxs(
|
|
1244
|
+
motion.div,
|
|
1245
|
+
{
|
|
1246
|
+
initial: { opacity: 0, y: -4, scale: 0.98 },
|
|
1247
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
1248
|
+
exit: { opacity: 0, y: -4, scale: 0.98 },
|
|
1249
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
1250
|
+
className: "overflow-hidden rounded-md border border-border bg-surface shadow-lg",
|
|
1251
|
+
children: [
|
|
1252
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [
|
|
1253
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "h-4 w-4 flex-shrink-0 text-muted", strokeWidth: 1.5 }),
|
|
1254
|
+
/* @__PURE__ */ jsx(
|
|
1255
|
+
"input",
|
|
1256
|
+
{
|
|
1257
|
+
ref: inputRef,
|
|
1258
|
+
type: "text",
|
|
1259
|
+
className: "w-full bg-transparent p-0 font-sans text-sm text-fg placeholder:text-muted focus:outline-none",
|
|
1260
|
+
placeholder,
|
|
1261
|
+
value: query,
|
|
1262
|
+
onChange: (e) => setQuery(e.target.value)
|
|
1263
|
+
}
|
|
1264
|
+
)
|
|
1265
|
+
] }),
|
|
1266
|
+
/* @__PURE__ */ jsx("ul", { role: "listbox", className: "max-h-60 overflow-auto py-1", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("li", { className: "px-3 py-2 font-sans text-sm text-muted", children: "No results found." }) : filteredOptions.map(
|
|
1267
|
+
(option) => /* @__PURE__ */ jsxs(
|
|
1268
|
+
"li",
|
|
1269
|
+
{
|
|
1270
|
+
role: "option",
|
|
1271
|
+
"aria-selected": value === option.value,
|
|
1272
|
+
onClick: () => handleSelect(option.value),
|
|
1273
|
+
className: `relative flex cursor-pointer select-none items-center py-2 pl-3 pr-9 font-sans text-sm transition-colors hover:bg-surface-raised ${value === option.value ? "bg-surface-raised font-medium text-accent" : "text-fg"}`,
|
|
1274
|
+
children: [
|
|
1275
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate", children: option.label }),
|
|
1276
|
+
value === option.value && /* @__PURE__ */ jsx("span", { className: "absolute inset-y-0 right-0 flex items-center pr-3 text-accent", children: /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4", strokeWidth: 2 }) })
|
|
1277
|
+
]
|
|
1278
|
+
},
|
|
1279
|
+
option.value
|
|
1280
|
+
)
|
|
1281
|
+
) })
|
|
1282
|
+
]
|
|
1283
|
+
}
|
|
1284
|
+
)
|
|
1285
|
+
}
|
|
1286
|
+
) }) }),
|
|
1287
|
+
helperText && /* @__PURE__ */ jsx(
|
|
1288
|
+
"span",
|
|
1289
|
+
{
|
|
1290
|
+
className: `font-sans text-xs ${error ? "text-red-500" : "text-muted"}`,
|
|
1291
|
+
children: helperText
|
|
1292
|
+
}
|
|
1293
|
+
)
|
|
1294
|
+
] });
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
export { AppToaster, Avatar, Button, Code, Combobox, ConfirmDialog, DirtyStateIndicator, Drawer, Dropdown, DropdownItem, EmptyState, Field, FormSection, Input, Markdown, Modal, Overlay, PLAN_STATUS_CONFIG, PLAN_STATUS_ORDER, PROJECT_STATUS_CONFIG, RowActions, STATUS_CONFIG, SaveBar, Select, StatusBadge, THEME_STORAGE_KEY, Tabs, Textarea, ThemeProvider, ThemeToggle, Tooltip, applyThemeClass, getStoredTheme, notify, resolveTheme, storeTheme, systemPrefersDark, usePopover, useTheme };
|
|
1298
|
+
//# sourceMappingURL=index.js.map
|
|
1299
|
+
//# sourceMappingURL=index.js.map
|