@ai-matrx/design-system 0.1.1 → 0.2.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/CHANGELOG.md +52 -0
- package/README.md +4 -2
- package/dist/index.cjs +1299 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +415 -0
- package/dist/index.d.ts +386 -1
- package/dist/index.js +1172 -15
- package/dist/index.js.map +1 -1
- package/package.json +19 -5
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1299 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var src_exports = {};
|
|
33
|
+
__export(src_exports, {
|
|
34
|
+
Badge: () => Badge,
|
|
35
|
+
BasicInput: () => BasicInput,
|
|
36
|
+
BottomSheet: () => BottomSheet,
|
|
37
|
+
BottomSheetBody: () => BottomSheetBody,
|
|
38
|
+
BottomSheetFooter: () => BottomSheetFooter,
|
|
39
|
+
BottomSheetHeader: () => BottomSheetHeader,
|
|
40
|
+
Button: () => Button,
|
|
41
|
+
DEFAULT_SCORE_THRESHOLDS: () => DEFAULT_SCORE_THRESHOLDS,
|
|
42
|
+
EditableLabel: () => EditableLabel,
|
|
43
|
+
EnterInput: () => EnterInput,
|
|
44
|
+
Input: () => Input,
|
|
45
|
+
InputWithPrefix: () => InputWithPrefix,
|
|
46
|
+
Label: () => Label,
|
|
47
|
+
OverflowToolbar: () => OverflowToolbar,
|
|
48
|
+
Popover: () => Popover,
|
|
49
|
+
PopoverAnchor: () => PopoverAnchor,
|
|
50
|
+
PopoverContent: () => PopoverContent,
|
|
51
|
+
PopoverTrigger: () => PopoverTrigger,
|
|
52
|
+
PortalContainerProvider: () => PortalContainerProvider,
|
|
53
|
+
RadixDialogModalProvider: () => RadixDialogModalProvider,
|
|
54
|
+
ScoreRing: () => ScoreRing,
|
|
55
|
+
SegmentedControl: () => SegmentedControl,
|
|
56
|
+
Separator: () => Separator,
|
|
57
|
+
Sheet: () => Sheet,
|
|
58
|
+
SheetClose: () => SheetClose,
|
|
59
|
+
SheetContent: () => SheetContent,
|
|
60
|
+
SheetDescription: () => SheetDescription,
|
|
61
|
+
SheetFooter: () => SheetFooter,
|
|
62
|
+
SheetHeader: () => SheetHeader,
|
|
63
|
+
SheetOverlay: () => SheetOverlay,
|
|
64
|
+
SheetPortal: () => SheetPortal,
|
|
65
|
+
SheetTitle: () => SheetTitle,
|
|
66
|
+
SheetTrigger: () => SheetTrigger,
|
|
67
|
+
Skeleton: () => Skeleton,
|
|
68
|
+
TabbedBottomSheet: () => TabbedBottomSheet,
|
|
69
|
+
badgeVariants: () => badgeVariants,
|
|
70
|
+
buttonVariants: () => buttonVariants,
|
|
71
|
+
cn: () => cn,
|
|
72
|
+
scoreAccentBgClasses: () => scoreAccentBgClasses,
|
|
73
|
+
scoreRingColorClasses: () => scoreRingColorClasses,
|
|
74
|
+
sheetVariants: () => sheetVariants,
|
|
75
|
+
usePortalContainer: () => usePortalContainer,
|
|
76
|
+
useRadixDialogModal: () => useRadixDialogModal,
|
|
77
|
+
useScrollFade: () => useScrollFade
|
|
78
|
+
});
|
|
79
|
+
module.exports = __toCommonJS(src_exports);
|
|
80
|
+
|
|
81
|
+
// src/badge.tsx
|
|
82
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
83
|
+
|
|
84
|
+
// src/cn.ts
|
|
85
|
+
var import_clsx = require("clsx");
|
|
86
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
87
|
+
function cn(...inputs) {
|
|
88
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/badge.tsx
|
|
92
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
93
|
+
var badgeVariants = (0, import_class_variance_authority.cva)(
|
|
94
|
+
"inline-flex items-center rounded-md border px-2 py-0.5 text-[11px] font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-0",
|
|
95
|
+
{
|
|
96
|
+
variants: {
|
|
97
|
+
variant: {
|
|
98
|
+
default: "border-transparent bg-primary/15 text-primary",
|
|
99
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground",
|
|
100
|
+
destructive: "border-transparent bg-destructive/15 text-destructive",
|
|
101
|
+
outline: "border-border text-foreground",
|
|
102
|
+
success: "border-transparent bg-success/15 text-success",
|
|
103
|
+
warning: "border-transparent bg-warning/15 text-warning",
|
|
104
|
+
info: "border-blue-200 bg-blue-100 text-blue-800",
|
|
105
|
+
error: "border-transparent bg-red-500/15 text-red-700 dark:text-red-400",
|
|
106
|
+
neutral: "border-border bg-muted text-muted-foreground"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
defaultVariants: {
|
|
110
|
+
variant: "default"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
function Badge({ className, variant, ...props }) {
|
|
115
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/bottom-sheet.tsx
|
|
119
|
+
var import_react_visually_hidden = require("@radix-ui/react-visually-hidden");
|
|
120
|
+
var React2 = __toESM(require("react"), 1);
|
|
121
|
+
var import_vaul = require("vaul");
|
|
122
|
+
|
|
123
|
+
// src/icons.tsx
|
|
124
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
125
|
+
function lucideProps(props) {
|
|
126
|
+
return {
|
|
127
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
128
|
+
viewBox: "0 0 24 24",
|
|
129
|
+
fill: "none",
|
|
130
|
+
stroke: "currentColor",
|
|
131
|
+
strokeWidth: 2,
|
|
132
|
+
strokeLinecap: "round",
|
|
133
|
+
strokeLinejoin: "round",
|
|
134
|
+
"aria-hidden": true,
|
|
135
|
+
...props
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function Loader2Icon(props) {
|
|
139
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
|
|
140
|
+
}
|
|
141
|
+
function ChevronLeftIcon(props) {
|
|
142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m15 18-6-6 6-6" }) });
|
|
143
|
+
}
|
|
144
|
+
function ChevronRightIcon(props) {
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m9 18 6-6-6-6" }) });
|
|
146
|
+
}
|
|
147
|
+
function MoreHorizontalIcon(props) {
|
|
148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...lucideProps(props), children: [
|
|
149
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "1" }),
|
|
150
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "19", cy: "12", r: "1" }),
|
|
151
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "5", cy: "12", r: "1" })
|
|
152
|
+
] });
|
|
153
|
+
}
|
|
154
|
+
function Cross2Icon(props) {
|
|
155
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
156
|
+
"svg",
|
|
157
|
+
{
|
|
158
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
159
|
+
viewBox: "0 0 15 15",
|
|
160
|
+
fill: "none",
|
|
161
|
+
"aria-hidden": true,
|
|
162
|
+
...props,
|
|
163
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
164
|
+
"path",
|
|
165
|
+
{
|
|
166
|
+
d: "M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z",
|
|
167
|
+
fill: "currentColor",
|
|
168
|
+
fillRule: "evenodd",
|
|
169
|
+
clipRule: "evenodd"
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/radix-dialog-modal-context.tsx
|
|
177
|
+
var React = __toESM(require("react"), 1);
|
|
178
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
179
|
+
var RadixDialogModalContext = React.createContext(true);
|
|
180
|
+
function RadixDialogModalProvider({
|
|
181
|
+
children,
|
|
182
|
+
modal
|
|
183
|
+
}) {
|
|
184
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RadixDialogModalContext.Provider, { value: modal, children });
|
|
185
|
+
}
|
|
186
|
+
function useRadixDialogModal() {
|
|
187
|
+
return React.useContext(RadixDialogModalContext);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/bottom-sheet.tsx
|
|
191
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
192
|
+
var DrawerRoot = ({
|
|
193
|
+
children,
|
|
194
|
+
shouldScaleBackground = true,
|
|
195
|
+
...props
|
|
196
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RadixDialogModalProvider, { modal: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
197
|
+
import_vaul.Drawer.Root,
|
|
198
|
+
{
|
|
199
|
+
modal: true,
|
|
200
|
+
shouldScaleBackground,
|
|
201
|
+
...props,
|
|
202
|
+
children
|
|
203
|
+
}
|
|
204
|
+
) });
|
|
205
|
+
DrawerRoot.displayName = "DrawerRoot";
|
|
206
|
+
var DrawerContentPrimitive = React2.forwardRef(({ ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_vaul.Drawer.Content, { ...props, ref, "aria-modal": "true" }));
|
|
207
|
+
DrawerContentPrimitive.displayName = "DrawerContentPrimitive";
|
|
208
|
+
function BottomSheet({
|
|
209
|
+
open,
|
|
210
|
+
onOpenChange,
|
|
211
|
+
title = "Bottom Sheet",
|
|
212
|
+
size = "adaptive",
|
|
213
|
+
surface = "glass",
|
|
214
|
+
contentClassName,
|
|
215
|
+
children
|
|
216
|
+
}) {
|
|
217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DrawerRoot, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_vaul.Drawer.Portal, { children: [
|
|
218
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
219
|
+
import_vaul.Drawer.Overlay,
|
|
220
|
+
{
|
|
221
|
+
className: cn("fixed inset-0 z-50 bg-black/80", "fixed inset-0 z-50"),
|
|
222
|
+
style: { background: "rgba(0, 0, 0, 0.08)" }
|
|
223
|
+
}
|
|
224
|
+
),
|
|
225
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
226
|
+
DrawerContentPrimitive,
|
|
227
|
+
{
|
|
228
|
+
className: cn(
|
|
229
|
+
"fixed inset-x-0 bottom-0 z-50 mt-24 flex flex-col rounded-t-2xl overflow-hidden",
|
|
230
|
+
size === "full" ? "h-[92dvh]" : "min-h-[60dvh] max-h-[90dvh]",
|
|
231
|
+
surface === "solid" && "border border-b-0 border-border bg-background shadow-2xl",
|
|
232
|
+
contentClassName
|
|
233
|
+
),
|
|
234
|
+
style: surface === "glass" ? {
|
|
235
|
+
background: "var(--matrx-glass-bg)",
|
|
236
|
+
backdropFilter: "blur(20px) saturate(180%)",
|
|
237
|
+
WebkitBackdropFilter: "blur(20px) saturate(180%)",
|
|
238
|
+
border: "1px solid var(--matrx-glass-border-color)",
|
|
239
|
+
borderBottom: "none"
|
|
240
|
+
} : void 0,
|
|
241
|
+
children: [
|
|
242
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_visually_hidden.VisuallyHidden, { children: [
|
|
243
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_vaul.Drawer.Title, { children: title }),
|
|
244
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_vaul.Drawer.Description, { children: "Bottom sheet panel." })
|
|
245
|
+
] }),
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-auto mt-3 mb-1 h-1.5 w-10 rounded-full bg-muted-foreground/30 flex-shrink-0" }),
|
|
247
|
+
children
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
)
|
|
251
|
+
] }) });
|
|
252
|
+
}
|
|
253
|
+
function BottomSheetHeader({
|
|
254
|
+
title,
|
|
255
|
+
showBack = false,
|
|
256
|
+
onBack,
|
|
257
|
+
trailing
|
|
258
|
+
}) {
|
|
259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center px-2 pt-1 pb-2 flex-shrink-0 min-h-[44px]", children: [
|
|
260
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-w-[44px] flex items-center justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
261
|
+
"button",
|
|
262
|
+
{
|
|
263
|
+
onClick: onBack,
|
|
264
|
+
className: cn(
|
|
265
|
+
"h-8 w-8 rounded-full matrx-glass-thin-border flex items-center justify-center transition-all active:scale-95",
|
|
266
|
+
showBack ? "opacity-100" : "opacity-0 pointer-events-none"
|
|
267
|
+
),
|
|
268
|
+
"aria-hidden": !showBack,
|
|
269
|
+
tabIndex: showBack ? 0 : -1,
|
|
270
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronLeftIcon, { className: "h-4 w-4 text-foreground" })
|
|
271
|
+
}
|
|
272
|
+
) }),
|
|
273
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-[17px] font-semibold flex-1 text-center truncate", children: title }),
|
|
274
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-w-[44px] flex items-center justify-end", children: trailing })
|
|
275
|
+
] });
|
|
276
|
+
}
|
|
277
|
+
function BottomSheetBody({ children, className }) {
|
|
278
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
279
|
+
"div",
|
|
280
|
+
{
|
|
281
|
+
className: cn(
|
|
282
|
+
// min-h-0 is load-bearing: without it a flex child's min-height:auto
|
|
283
|
+
// floors it at content height and the body grows instead of scrolling.
|
|
284
|
+
"min-h-0 flex-1 overflow-y-auto overscroll-contain pb-safe",
|
|
285
|
+
className
|
|
286
|
+
),
|
|
287
|
+
children
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
function BottomSheetFooter({
|
|
292
|
+
children,
|
|
293
|
+
className
|
|
294
|
+
}) {
|
|
295
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
296
|
+
"div",
|
|
297
|
+
{
|
|
298
|
+
className: cn(
|
|
299
|
+
"flex-shrink-0 px-4 py-3 pb-safe border-t border-white/[0.06]",
|
|
300
|
+
className
|
|
301
|
+
),
|
|
302
|
+
children
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/button.tsx
|
|
308
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
309
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
310
|
+
var React3 = __toESM(require("react"), 1);
|
|
311
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
312
|
+
var buttonVariants = (0, import_class_variance_authority2.cva)(
|
|
313
|
+
"inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
314
|
+
{
|
|
315
|
+
variants: {
|
|
316
|
+
variant: {
|
|
317
|
+
default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
|
|
318
|
+
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
319
|
+
outline: "border border-border bg-card shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
320
|
+
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
321
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
322
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
323
|
+
subtle: "border border-transparent bg-muted/50 text-foreground hover:border-border hover:bg-muted"
|
|
324
|
+
},
|
|
325
|
+
size: {
|
|
326
|
+
default: "h-9 px-4 py-2",
|
|
327
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
328
|
+
lg: "h-10 rounded-md px-6",
|
|
329
|
+
icon: "h-9 w-9",
|
|
330
|
+
"icon-sm": "h-7 w-7"
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
defaultVariants: {
|
|
334
|
+
variant: "default",
|
|
335
|
+
size: "default"
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
var Button = React3.forwardRef(
|
|
340
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
341
|
+
const Component = asChild ? import_react_slot.Slot : "button";
|
|
342
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
343
|
+
Component,
|
|
344
|
+
{
|
|
345
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
346
|
+
ref,
|
|
347
|
+
...props
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
);
|
|
352
|
+
Button.displayName = "Button";
|
|
353
|
+
|
|
354
|
+
// src/editable-label.tsx
|
|
355
|
+
var import_react = require("react");
|
|
356
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
357
|
+
function EditableLabel({
|
|
358
|
+
value,
|
|
359
|
+
onCommit,
|
|
360
|
+
commitMode = "optimistic",
|
|
361
|
+
validate,
|
|
362
|
+
emptyFallback,
|
|
363
|
+
maxLength = 120,
|
|
364
|
+
activation = "click",
|
|
365
|
+
editing: editingProp,
|
|
366
|
+
onEditingChange,
|
|
367
|
+
selectOnEdit = true,
|
|
368
|
+
placeholder,
|
|
369
|
+
ariaLabel = "Name",
|
|
370
|
+
truncate = true,
|
|
371
|
+
className,
|
|
372
|
+
displayClassName,
|
|
373
|
+
inputClassName
|
|
374
|
+
}) {
|
|
375
|
+
const controlled = activation === "controlled";
|
|
376
|
+
const [internalEditing, setInternalEditing] = (0, import_react.useState)(false);
|
|
377
|
+
const editing = controlled ? !!editingProp : internalEditing;
|
|
378
|
+
const [draft, setDraft] = (0, import_react.useState)(value);
|
|
379
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
380
|
+
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
381
|
+
const inputRef = (0, import_react.useRef)(null);
|
|
382
|
+
(0, import_react.useEffect)(() => {
|
|
383
|
+
if (!editing) setDraft(value);
|
|
384
|
+
}, [value, editing]);
|
|
385
|
+
(0, import_react.useEffect)(() => {
|
|
386
|
+
if (editing && inputRef.current) {
|
|
387
|
+
inputRef.current.focus();
|
|
388
|
+
if (selectOnEdit) inputRef.current.select();
|
|
389
|
+
}
|
|
390
|
+
}, [editing, selectOnEdit]);
|
|
391
|
+
const setEditing = (0, import_react.useCallback)(
|
|
392
|
+
(next) => {
|
|
393
|
+
if (controlled) {
|
|
394
|
+
onEditingChange?.(next);
|
|
395
|
+
} else {
|
|
396
|
+
setInternalEditing(next);
|
|
397
|
+
onEditingChange?.(next);
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
[controlled, onEditingChange]
|
|
401
|
+
);
|
|
402
|
+
const startEdit = (0, import_react.useCallback)(() => {
|
|
403
|
+
setDraft(value);
|
|
404
|
+
setError(null);
|
|
405
|
+
setEditing(true);
|
|
406
|
+
}, [value, setEditing]);
|
|
407
|
+
const cancel = (0, import_react.useCallback)(() => {
|
|
408
|
+
setDraft(value);
|
|
409
|
+
setError(null);
|
|
410
|
+
setBusy(false);
|
|
411
|
+
setEditing(false);
|
|
412
|
+
}, [value, setEditing]);
|
|
413
|
+
const commit = (0, import_react.useCallback)(() => {
|
|
414
|
+
if (busy) return;
|
|
415
|
+
const trimmed = draft.trim();
|
|
416
|
+
const next = trimmed || emptyFallback;
|
|
417
|
+
if (next === void 0) {
|
|
418
|
+
cancel();
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const validationError = validate?.(next) ?? null;
|
|
422
|
+
if (validationError) {
|
|
423
|
+
setError(validationError);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (next === value) {
|
|
427
|
+
setEditing(false);
|
|
428
|
+
setError(null);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
if (commitMode === "await") {
|
|
432
|
+
const result2 = onCommit(next);
|
|
433
|
+
if (result2 instanceof Promise) {
|
|
434
|
+
setBusy(true);
|
|
435
|
+
result2.then(() => {
|
|
436
|
+
setBusy(false);
|
|
437
|
+
setEditing(false);
|
|
438
|
+
}).catch(() => {
|
|
439
|
+
setBusy(false);
|
|
440
|
+
});
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
setEditing(false);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
setEditing(false);
|
|
447
|
+
setError(null);
|
|
448
|
+
const result = onCommit(next);
|
|
449
|
+
if (result instanceof Promise) result.catch(() => {
|
|
450
|
+
});
|
|
451
|
+
}, [
|
|
452
|
+
busy,
|
|
453
|
+
draft,
|
|
454
|
+
emptyFallback,
|
|
455
|
+
validate,
|
|
456
|
+
value,
|
|
457
|
+
commitMode,
|
|
458
|
+
onCommit,
|
|
459
|
+
cancel,
|
|
460
|
+
setEditing
|
|
461
|
+
]);
|
|
462
|
+
if (editing) {
|
|
463
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: cn("relative flex min-w-0 flex-1 items-center", className), children: [
|
|
464
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
465
|
+
"input",
|
|
466
|
+
{
|
|
467
|
+
ref: inputRef,
|
|
468
|
+
type: "text",
|
|
469
|
+
value: draft,
|
|
470
|
+
disabled: busy,
|
|
471
|
+
placeholder,
|
|
472
|
+
onChange: (e) => {
|
|
473
|
+
setDraft(e.target.value);
|
|
474
|
+
if (error) setError(null);
|
|
475
|
+
},
|
|
476
|
+
onBlur: commit,
|
|
477
|
+
onClick: (e) => e.stopPropagation(),
|
|
478
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
479
|
+
onKeyDown: (e) => {
|
|
480
|
+
if (e.key === "Enter") {
|
|
481
|
+
e.preventDefault();
|
|
482
|
+
e.stopPropagation();
|
|
483
|
+
commit();
|
|
484
|
+
} else if (e.key === "Escape") {
|
|
485
|
+
e.preventDefault();
|
|
486
|
+
e.stopPropagation();
|
|
487
|
+
cancel();
|
|
488
|
+
} else if (e.key === " ") {
|
|
489
|
+
e.stopPropagation();
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
maxLength,
|
|
493
|
+
"aria-label": ariaLabel,
|
|
494
|
+
"aria-invalid": error ? true : void 0,
|
|
495
|
+
className: cn(
|
|
496
|
+
"w-full min-w-0 rounded-sm bg-transparent px-1 outline-none",
|
|
497
|
+
"text-base md:text-sm",
|
|
498
|
+
"focus:bg-background focus:ring-1 focus:ring-ring",
|
|
499
|
+
busy && "opacity-60",
|
|
500
|
+
inputClassName
|
|
501
|
+
)
|
|
502
|
+
}
|
|
503
|
+
),
|
|
504
|
+
busy && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Loader2Icon, { className: "absolute right-1 h-3.5 w-3.5 animate-spin text-muted-foreground" }),
|
|
505
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "absolute left-0 top-full mt-0.5 whitespace-nowrap text-xs text-destructive", children: error })
|
|
506
|
+
] });
|
|
507
|
+
}
|
|
508
|
+
if (controlled) return null;
|
|
509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
510
|
+
"button",
|
|
511
|
+
{
|
|
512
|
+
type: "button",
|
|
513
|
+
onClick: activation === "click" ? (e) => {
|
|
514
|
+
e.stopPropagation();
|
|
515
|
+
startEdit();
|
|
516
|
+
} : void 0,
|
|
517
|
+
onDoubleClick: activation === "doubleClick" ? (e) => {
|
|
518
|
+
e.stopPropagation();
|
|
519
|
+
startEdit();
|
|
520
|
+
} : void 0,
|
|
521
|
+
onKeyDown: (e) => {
|
|
522
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
523
|
+
e.preventDefault();
|
|
524
|
+
e.stopPropagation();
|
|
525
|
+
startEdit();
|
|
526
|
+
}
|
|
527
|
+
},
|
|
528
|
+
title: activation === "doubleClick" ? "Double-click to rename" : "Click to rename",
|
|
529
|
+
"aria-label": `Rename ${ariaLabel.toLowerCase()}: ${value}`,
|
|
530
|
+
className: cn(
|
|
531
|
+
"min-w-0 max-w-full rounded-sm px-1 text-left transition-colors",
|
|
532
|
+
"hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
533
|
+
truncate && "block truncate",
|
|
534
|
+
className,
|
|
535
|
+
displayClassName
|
|
536
|
+
),
|
|
537
|
+
children: value || placeholder || ""
|
|
538
|
+
}
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// src/input.tsx
|
|
543
|
+
var React4 = __toESM(require("react"), 1);
|
|
544
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
545
|
+
var getVariantStyles = (variant = "default") => {
|
|
546
|
+
const baseStyles = `flex h-10 w-full border border-border bg-background text-black dark:text-white shadow-input rounded-md px-3 py-2 text-sm file:border-0 file:bg-transparent
|
|
547
|
+
file:text-sm file:font-medium placeholder:text-neutral-400 dark:placeholder-text-neutral-600
|
|
548
|
+
focus-visible:outline-none focus-visible:ring-[2px] focus-visible:ring-neutral-400 dark:focus-visible:ring-neutral-600
|
|
549
|
+
disabled:cursor-not-allowed disabled:opacity-50
|
|
550
|
+
dark:shadow-[0px_0px_1px_1px_var(--neutral-700)]
|
|
551
|
+
transition duration-400
|
|
552
|
+
[&:-webkit-autofill]:bg-background [&:-webkit-autofill]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] [&:-webkit-autofill]:[caret-color:currentColor]
|
|
553
|
+
dark:[&:-webkit-autofill]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] dark:[&:-webkit-autofill]:[-webkit-text-fill-color:white]
|
|
554
|
+
[&:-webkit-autofill:hover]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:focus]:shadow-[0_0_0_1000px_hsl(var(--background))_inset]`;
|
|
555
|
+
switch (variant) {
|
|
556
|
+
case "destructive":
|
|
557
|
+
return `${baseStyles} bg-destructive text-destructive-foreground`;
|
|
558
|
+
case "outline":
|
|
559
|
+
return `${baseStyles} border-2`;
|
|
560
|
+
case "secondary":
|
|
561
|
+
return `${baseStyles} bg-secondary text-secondary-foreground`;
|
|
562
|
+
case "ghost":
|
|
563
|
+
return `${baseStyles} bg-transparent shadow-none`;
|
|
564
|
+
case "link":
|
|
565
|
+
return `${baseStyles} bg-transparent underline-offset-4 hover:underline`;
|
|
566
|
+
case "primary":
|
|
567
|
+
return `${baseStyles} bg-primary text-primary-foreground`;
|
|
568
|
+
default:
|
|
569
|
+
return baseStyles;
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
var Input = React4.forwardRef(
|
|
573
|
+
({ className, type, variant = "default", ...props }, ref) => {
|
|
574
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
575
|
+
"input",
|
|
576
|
+
{
|
|
577
|
+
type,
|
|
578
|
+
className: cn(getVariantStyles(variant), className),
|
|
579
|
+
ref,
|
|
580
|
+
...props
|
|
581
|
+
}
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
);
|
|
585
|
+
Input.displayName = "Input";
|
|
586
|
+
var EnterInput = React4.forwardRef(
|
|
587
|
+
({ onEnter, ...props }, ref) => {
|
|
588
|
+
const handleKeyDown = (e) => {
|
|
589
|
+
if (e.key === "Enter" && onEnter) {
|
|
590
|
+
e.preventDefault();
|
|
591
|
+
onEnter();
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
595
|
+
Input,
|
|
596
|
+
{
|
|
597
|
+
...props,
|
|
598
|
+
ref,
|
|
599
|
+
onKeyDown: (e) => {
|
|
600
|
+
handleKeyDown(e);
|
|
601
|
+
if (props.onKeyDown) {
|
|
602
|
+
props.onKeyDown(e);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
);
|
|
609
|
+
EnterInput.displayName = "EnterInput";
|
|
610
|
+
var BasicInput = React4.forwardRef(
|
|
611
|
+
// `variant` is accepted (prop-compatible with Input) but intentionally
|
|
612
|
+
// unused — and destructured so it never leaks onto the DOM element.
|
|
613
|
+
({ className, type, variant: _variant = "default", ...props }, ref) => {
|
|
614
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
615
|
+
"input",
|
|
616
|
+
{
|
|
617
|
+
type,
|
|
618
|
+
className: cn(
|
|
619
|
+
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
|
620
|
+
className
|
|
621
|
+
),
|
|
622
|
+
ref,
|
|
623
|
+
...props
|
|
624
|
+
}
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
);
|
|
628
|
+
BasicInput.displayName = "BasicInput";
|
|
629
|
+
var InputWithPrefix = React4.forwardRef(({ prefix, className, wrapperClassName, ...props }, ref) => {
|
|
630
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cn("relative", wrapperClassName), children: [
|
|
631
|
+
prefix && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: prefix }),
|
|
632
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
633
|
+
Input,
|
|
634
|
+
{
|
|
635
|
+
ref,
|
|
636
|
+
className: cn(prefix && "pl-10", className),
|
|
637
|
+
...props
|
|
638
|
+
}
|
|
639
|
+
)
|
|
640
|
+
] });
|
|
641
|
+
});
|
|
642
|
+
InputWithPrefix.displayName = "InputWithPrefix";
|
|
643
|
+
|
|
644
|
+
// src/label.tsx
|
|
645
|
+
var LabelPrimitive = __toESM(require("@radix-ui/react-label"), 1);
|
|
646
|
+
var React5 = __toESM(require("react"), 1);
|
|
647
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
648
|
+
var Label = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
649
|
+
LabelPrimitive.Root,
|
|
650
|
+
{
|
|
651
|
+
ref,
|
|
652
|
+
className: cn(
|
|
653
|
+
"text-sm font-medium leading-none text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
654
|
+
className
|
|
655
|
+
),
|
|
656
|
+
...props
|
|
657
|
+
}
|
|
658
|
+
));
|
|
659
|
+
Label.displayName = LabelPrimitive.Root.displayName;
|
|
660
|
+
|
|
661
|
+
// src/overflow-toolbar.tsx
|
|
662
|
+
var import_react2 = require("react");
|
|
663
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
664
|
+
var GAP_PX = 6;
|
|
665
|
+
var TONE = {
|
|
666
|
+
default: "border border-border bg-background hover:bg-accent text-foreground",
|
|
667
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
668
|
+
destructive: "border border-destructive/40 text-destructive hover:bg-destructive/10"
|
|
669
|
+
};
|
|
670
|
+
function ToolbarButton({
|
|
671
|
+
action,
|
|
672
|
+
enableTooltip = false,
|
|
673
|
+
renderTooltip
|
|
674
|
+
}) {
|
|
675
|
+
const tone = action.tone ?? "default";
|
|
676
|
+
const Icon = action.running ? Loader2Icon : action.icon;
|
|
677
|
+
const showLabel = !action.hideLabel || action.running && action.runningLabel;
|
|
678
|
+
const text = action.running && action.runningLabel ? action.runningLabel : action.label;
|
|
679
|
+
const className = cn(
|
|
680
|
+
"inline-flex items-center gap-1 h-7 rounded-md text-[11px] font-medium transition-colors whitespace-nowrap",
|
|
681
|
+
"disabled:opacity-50 disabled:pointer-events-none",
|
|
682
|
+
action.hideLabel && !action.running ? "w-7 justify-center px-0" : "px-2",
|
|
683
|
+
TONE[tone]
|
|
684
|
+
);
|
|
685
|
+
const inner = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
686
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
687
|
+
Icon,
|
|
688
|
+
{
|
|
689
|
+
className: cn("w-3.5 h-3.5 shrink-0", action.running && "animate-spin")
|
|
690
|
+
}
|
|
691
|
+
),
|
|
692
|
+
showLabel && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: text })
|
|
693
|
+
] });
|
|
694
|
+
const control = action.href && !action.disabled ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
695
|
+
"a",
|
|
696
|
+
{
|
|
697
|
+
href: action.href,
|
|
698
|
+
target: action.target,
|
|
699
|
+
rel: action.target === "_blank" ? "noopener noreferrer" : void 0,
|
|
700
|
+
className,
|
|
701
|
+
"aria-label": action.label,
|
|
702
|
+
children: inner
|
|
703
|
+
}
|
|
704
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
705
|
+
"button",
|
|
706
|
+
{
|
|
707
|
+
type: "button",
|
|
708
|
+
onClick: action.onSelect,
|
|
709
|
+
disabled: action.disabled,
|
|
710
|
+
className,
|
|
711
|
+
"aria-label": action.label,
|
|
712
|
+
children: inner
|
|
713
|
+
}
|
|
714
|
+
);
|
|
715
|
+
if (enableTooltip && action.hideLabel && renderTooltip) {
|
|
716
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: renderTooltip(control, action.label) });
|
|
717
|
+
}
|
|
718
|
+
return control;
|
|
719
|
+
}
|
|
720
|
+
function OverflowTrigger({ ariaLabel }) {
|
|
721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
722
|
+
"button",
|
|
723
|
+
{
|
|
724
|
+
type: "button",
|
|
725
|
+
"aria-label": ariaLabel,
|
|
726
|
+
"aria-haspopup": "menu",
|
|
727
|
+
title: "More actions",
|
|
728
|
+
className: cn(
|
|
729
|
+
"inline-flex items-center justify-center h-7 w-7 rounded-md transition-colors",
|
|
730
|
+
"border border-border bg-background hover:bg-accent text-foreground"
|
|
731
|
+
),
|
|
732
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MoreHorizontalIcon, { className: "w-3.5 h-3.5" })
|
|
733
|
+
}
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
function OverflowToolbar({
|
|
737
|
+
actions,
|
|
738
|
+
leading,
|
|
739
|
+
overflowAriaLabel = "More actions",
|
|
740
|
+
className,
|
|
741
|
+
renderOverflowMenu,
|
|
742
|
+
renderTooltip
|
|
743
|
+
}) {
|
|
744
|
+
const visibleActions = (0, import_react2.useMemo)(
|
|
745
|
+
() => actions.filter((a) => !a.hidden),
|
|
746
|
+
[actions]
|
|
747
|
+
);
|
|
748
|
+
const containerRef = (0, import_react2.useRef)(null);
|
|
749
|
+
const ghostRef = (0, import_react2.useRef)(null);
|
|
750
|
+
const leadingRef = (0, import_react2.useRef)(null);
|
|
751
|
+
const [visibleCount, setVisibleCount] = (0, import_react2.useState)(visibleActions.length);
|
|
752
|
+
const signature = visibleActions.map(
|
|
753
|
+
(a) => `${a.id}:${a.hideLabel ? 1 : 0}:${a.running ? 1 : 0}:${a.runningLabel ?? ""}:${a.label}`
|
|
754
|
+
).join("|");
|
|
755
|
+
(0, import_react2.useLayoutEffect)(() => {
|
|
756
|
+
const container = containerRef.current;
|
|
757
|
+
const ghost = ghostRef.current;
|
|
758
|
+
if (!container || !ghost) return void 0;
|
|
759
|
+
const compute = () => {
|
|
760
|
+
const available = container.clientWidth;
|
|
761
|
+
const n = visibleActions.length;
|
|
762
|
+
const children = Array.from(ghost.children);
|
|
763
|
+
const hasLeading = leading != null;
|
|
764
|
+
const leadingW = hasLeading ? leadingRef.current?.offsetWidth ?? 0 : 0;
|
|
765
|
+
const itemW = (i) => children[i]?.offsetWidth ?? 0;
|
|
766
|
+
const kebabW = children[n]?.offsetWidth ?? 28;
|
|
767
|
+
const base = leadingW + (hasLeading && n > 0 ? GAP_PX : 0);
|
|
768
|
+
let totalAll = base;
|
|
769
|
+
for (let i = 0; i < n; i++) totalAll += itemW(i) + (i > 0 ? GAP_PX : 0);
|
|
770
|
+
if (totalAll <= available) {
|
|
771
|
+
setVisibleCount(n);
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
let used = base;
|
|
775
|
+
let count = 0;
|
|
776
|
+
for (let i = 0; i < n; i++) {
|
|
777
|
+
const add = itemW(i) + (count > 0 ? GAP_PX : 0);
|
|
778
|
+
if (used + add + GAP_PX + kebabW <= available) {
|
|
779
|
+
used += add;
|
|
780
|
+
count += 1;
|
|
781
|
+
} else break;
|
|
782
|
+
}
|
|
783
|
+
setVisibleCount(count);
|
|
784
|
+
};
|
|
785
|
+
compute();
|
|
786
|
+
const ro = new ResizeObserver(compute);
|
|
787
|
+
ro.observe(container);
|
|
788
|
+
return () => ro.disconnect();
|
|
789
|
+
}, [signature, leading != null]);
|
|
790
|
+
const shown = visibleActions.slice(0, visibleCount);
|
|
791
|
+
const hidden = visibleActions.slice(visibleCount);
|
|
792
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { ref: containerRef, className: cn("relative min-w-0", className), children: [
|
|
793
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
794
|
+
"div",
|
|
795
|
+
{
|
|
796
|
+
ref: ghostRef,
|
|
797
|
+
"aria-hidden": true,
|
|
798
|
+
className: "pointer-events-none absolute left-0 top-0 flex items-center gap-1.5 opacity-0",
|
|
799
|
+
children: [
|
|
800
|
+
visibleActions.map((a) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolbarButton, { action: a }, a.id)),
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(OverflowTrigger, { ariaLabel: overflowAriaLabel })
|
|
802
|
+
]
|
|
803
|
+
}
|
|
804
|
+
),
|
|
805
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
806
|
+
leading != null && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { ref: leadingRef, className: "shrink-0", children: leading }),
|
|
807
|
+
shown.map((a) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
808
|
+
ToolbarButton,
|
|
809
|
+
{
|
|
810
|
+
action: a,
|
|
811
|
+
enableTooltip: true,
|
|
812
|
+
renderTooltip
|
|
813
|
+
},
|
|
814
|
+
a.id
|
|
815
|
+
)),
|
|
816
|
+
hidden.length > 0 && renderOverflowMenu({
|
|
817
|
+
actions: hidden,
|
|
818
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(OverflowTrigger, { ariaLabel: overflowAriaLabel })
|
|
819
|
+
})
|
|
820
|
+
] })
|
|
821
|
+
] });
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// src/popover.tsx
|
|
825
|
+
var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"), 1);
|
|
826
|
+
var React8 = __toESM(require("react"), 1);
|
|
827
|
+
|
|
828
|
+
// src/portal-container.tsx
|
|
829
|
+
var React7 = __toESM(require("react"), 1);
|
|
830
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
831
|
+
var PortalContainerContext = React7.createContext(
|
|
832
|
+
void 0
|
|
833
|
+
);
|
|
834
|
+
function PortalContainerProvider({
|
|
835
|
+
container,
|
|
836
|
+
children
|
|
837
|
+
}) {
|
|
838
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PortalContainerContext.Provider, { value: container ?? void 0, children });
|
|
839
|
+
}
|
|
840
|
+
function usePortalContainer(explicit) {
|
|
841
|
+
const injected = React7.useContext(PortalContainerContext);
|
|
842
|
+
if (explicit !== void 0) {
|
|
843
|
+
return explicit ?? void 0;
|
|
844
|
+
}
|
|
845
|
+
return injected ?? void 0;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// src/popover.tsx
|
|
849
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
850
|
+
var Popover = PopoverPrimitive.Root;
|
|
851
|
+
var PopoverTrigger = PopoverPrimitive.Trigger;
|
|
852
|
+
var PopoverAnchor = PopoverPrimitive.Anchor;
|
|
853
|
+
var PopoverContent = React8.forwardRef(
|
|
854
|
+
({ className, align = "center", sideOffset = 4, container, ...props }, ref) => {
|
|
855
|
+
const portalContainer = usePortalContainer(container);
|
|
856
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
857
|
+
PopoverPrimitive.Content,
|
|
858
|
+
{
|
|
859
|
+
ref,
|
|
860
|
+
align,
|
|
861
|
+
sideOffset,
|
|
862
|
+
className: cn(
|
|
863
|
+
// Cap to the viewport space Radix measured and scroll — a popover taller
|
|
864
|
+
// than the screen must never trap the user with unreachable content.
|
|
865
|
+
// z must EQUAL the dialog layer (z-[10000]), never exceed it: with equal
|
|
866
|
+
// z, DOM portal order decides, so a dialog opened FROM a popover stacks
|
|
867
|
+
// above it, and a popover opened from a dialog still stacks above the
|
|
868
|
+
// dialog. z-[10001] buried dialogs behind fullscreen popovers.
|
|
869
|
+
"z-[10000] w-72 max-h-[var(--radix-popover-content-available-height)] overflow-y-auto overscroll-contain rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
870
|
+
className
|
|
871
|
+
),
|
|
872
|
+
...props
|
|
873
|
+
}
|
|
874
|
+
) });
|
|
875
|
+
}
|
|
876
|
+
);
|
|
877
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
878
|
+
|
|
879
|
+
// src/score-ring.tsx
|
|
880
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
881
|
+
var DEFAULT_SCORE_THRESHOLDS = {
|
|
882
|
+
good: 75,
|
|
883
|
+
warning: 50
|
|
884
|
+
};
|
|
885
|
+
function scoreRingColorClasses(pct, thresholds = DEFAULT_SCORE_THRESHOLDS) {
|
|
886
|
+
if (pct === null) return "text-muted-foreground";
|
|
887
|
+
if (pct >= thresholds.good) return "text-green-500";
|
|
888
|
+
if (pct >= thresholds.warning) return "text-orange-500";
|
|
889
|
+
return "text-red-500";
|
|
890
|
+
}
|
|
891
|
+
function scoreAccentBgClasses(pct, thresholds = DEFAULT_SCORE_THRESHOLDS) {
|
|
892
|
+
if (pct === null) return "bg-muted-foreground/30";
|
|
893
|
+
if (pct >= thresholds.good) return "bg-green-500";
|
|
894
|
+
if (pct >= thresholds.warning) return "bg-orange-500";
|
|
895
|
+
return "bg-red-500";
|
|
896
|
+
}
|
|
897
|
+
function ScoreRing({
|
|
898
|
+
pct,
|
|
899
|
+
size = 112,
|
|
900
|
+
strokeWidth = 8,
|
|
901
|
+
label,
|
|
902
|
+
valueClassName,
|
|
903
|
+
className,
|
|
904
|
+
thresholds = DEFAULT_SCORE_THRESHOLDS,
|
|
905
|
+
suffix = "%"
|
|
906
|
+
}) {
|
|
907
|
+
const radius = 50 - strokeWidth / 2;
|
|
908
|
+
const circumference = 2 * Math.PI * radius;
|
|
909
|
+
const boundedPct = pct === null ? 0 : Math.max(0, Math.min(100, pct));
|
|
910
|
+
const dashOffset = circumference * (1 - boundedPct / 100);
|
|
911
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
912
|
+
"div",
|
|
913
|
+
{
|
|
914
|
+
className: cn(
|
|
915
|
+
"relative flex shrink-0 items-center justify-center",
|
|
916
|
+
className
|
|
917
|
+
),
|
|
918
|
+
style: { width: size, height: size },
|
|
919
|
+
role: "img",
|
|
920
|
+
"aria-label": `${label ?? "Score"}: ${pct === null ? "not available" : `${pct} out of 100`}`,
|
|
921
|
+
children: [
|
|
922
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { viewBox: "0 0 100 100", className: "h-full w-full -rotate-90", children: [
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
924
|
+
"circle",
|
|
925
|
+
{
|
|
926
|
+
cx: "50",
|
|
927
|
+
cy: "50",
|
|
928
|
+
r: radius,
|
|
929
|
+
className: "stroke-muted",
|
|
930
|
+
strokeWidth,
|
|
931
|
+
fill: "none"
|
|
932
|
+
}
|
|
933
|
+
),
|
|
934
|
+
pct !== null ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
935
|
+
"circle",
|
|
936
|
+
{
|
|
937
|
+
cx: "50",
|
|
938
|
+
cy: "50",
|
|
939
|
+
r: radius,
|
|
940
|
+
className: cn(
|
|
941
|
+
"transition-[stroke-dashoffset] duration-700 ease-out",
|
|
942
|
+
scoreRingColorClasses(pct, thresholds)
|
|
943
|
+
),
|
|
944
|
+
stroke: "currentColor",
|
|
945
|
+
strokeWidth,
|
|
946
|
+
strokeLinecap: "round",
|
|
947
|
+
fill: "none",
|
|
948
|
+
strokeDasharray: circumference,
|
|
949
|
+
strokeDashoffset: dashOffset
|
|
950
|
+
}
|
|
951
|
+
) : null
|
|
952
|
+
] }),
|
|
953
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "absolute flex flex-col items-center justify-center", children: [
|
|
954
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
955
|
+
"span",
|
|
956
|
+
{
|
|
957
|
+
className: cn(
|
|
958
|
+
"font-bold tabular-nums text-foreground",
|
|
959
|
+
valueClassName ?? "text-2xl"
|
|
960
|
+
),
|
|
961
|
+
children: pct === null ? "\u2014" : `${pct}${suffix}`
|
|
962
|
+
}
|
|
963
|
+
),
|
|
964
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "max-w-[74px] truncate text-[9px] font-semibold uppercase tracking-wide text-muted-foreground", children: label }) : null
|
|
965
|
+
] })
|
|
966
|
+
]
|
|
967
|
+
}
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// src/segmented-control.tsx
|
|
972
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
973
|
+
function SegmentedControl({
|
|
974
|
+
value,
|
|
975
|
+
onValueChange,
|
|
976
|
+
data,
|
|
977
|
+
name: _name,
|
|
978
|
+
className,
|
|
979
|
+
fullWidth = false,
|
|
980
|
+
size = "md"
|
|
981
|
+
}) {
|
|
982
|
+
const sizeClasses = {
|
|
983
|
+
sm: "h-7 text-xs",
|
|
984
|
+
md: "h-9 text-sm",
|
|
985
|
+
lg: "h-10 text-base"
|
|
986
|
+
};
|
|
987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
988
|
+
"div",
|
|
989
|
+
{
|
|
990
|
+
className: cn(
|
|
991
|
+
"inline-flex p-0.5 bg-muted rounded-md",
|
|
992
|
+
fullWidth && "w-full",
|
|
993
|
+
className
|
|
994
|
+
),
|
|
995
|
+
role: "tablist",
|
|
996
|
+
children: data.map((option) => {
|
|
997
|
+
const isActive = value === option.value;
|
|
998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
999
|
+
"button",
|
|
1000
|
+
{
|
|
1001
|
+
type: "button",
|
|
1002
|
+
role: "tab",
|
|
1003
|
+
"aria-selected": isActive,
|
|
1004
|
+
disabled: option.disabled,
|
|
1005
|
+
onClick: () => onValueChange(option.value),
|
|
1006
|
+
className: cn(
|
|
1007
|
+
"relative flex items-center justify-center rounded-[0.2rem] px-3 py-1.5 transition-all",
|
|
1008
|
+
sizeClasses[size],
|
|
1009
|
+
fullWidth && "flex-1",
|
|
1010
|
+
isActive ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground hover:bg-background/50",
|
|
1011
|
+
option.disabled && "opacity-50 cursor-not-allowed"
|
|
1012
|
+
),
|
|
1013
|
+
children: option.label
|
|
1014
|
+
},
|
|
1015
|
+
option.value
|
|
1016
|
+
);
|
|
1017
|
+
})
|
|
1018
|
+
}
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// src/separator.tsx
|
|
1023
|
+
var SeparatorPrimitive = __toESM(require("@radix-ui/react-separator"), 1);
|
|
1024
|
+
var React9 = __toESM(require("react"), 1);
|
|
1025
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1026
|
+
var Separator = React9.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1027
|
+
SeparatorPrimitive.Root,
|
|
1028
|
+
{
|
|
1029
|
+
ref,
|
|
1030
|
+
decorative,
|
|
1031
|
+
orientation,
|
|
1032
|
+
className: cn(
|
|
1033
|
+
"shrink-0 bg-border",
|
|
1034
|
+
orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
|
|
1035
|
+
className
|
|
1036
|
+
),
|
|
1037
|
+
...props
|
|
1038
|
+
}
|
|
1039
|
+
));
|
|
1040
|
+
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
|
1041
|
+
|
|
1042
|
+
// src/sheet.tsx
|
|
1043
|
+
var SheetPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
|
|
1044
|
+
var import_react_tree = require("@ai-matrx/kit/react-tree");
|
|
1045
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
1046
|
+
var React10 = __toESM(require("react"), 1);
|
|
1047
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1048
|
+
var SheetContentBase = React10.forwardRef(({ ...props }, ref) => {
|
|
1049
|
+
const isModal = useRadixDialogModal();
|
|
1050
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1051
|
+
SheetPrimitive.Content,
|
|
1052
|
+
{
|
|
1053
|
+
...props,
|
|
1054
|
+
ref,
|
|
1055
|
+
"aria-modal": isModal || void 0
|
|
1056
|
+
}
|
|
1057
|
+
);
|
|
1058
|
+
});
|
|
1059
|
+
SheetContentBase.displayName = "SheetContentBase";
|
|
1060
|
+
var Sheet = React10.forwardRef(({ children, ...props }, _ref) => {
|
|
1061
|
+
const modal = props.modal ?? true;
|
|
1062
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SheetPrimitive.Root, { ...props, modal, children }) });
|
|
1063
|
+
});
|
|
1064
|
+
Sheet.displayName = "Sheet";
|
|
1065
|
+
var SheetTrigger = SheetPrimitive.Trigger;
|
|
1066
|
+
var SheetClose = SheetPrimitive.Close;
|
|
1067
|
+
var SheetPortal = SheetPrimitive.Portal;
|
|
1068
|
+
var SheetOverlay = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1069
|
+
SheetPrimitive.Overlay,
|
|
1070
|
+
{
|
|
1071
|
+
className: cn(
|
|
1072
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1073
|
+
className
|
|
1074
|
+
),
|
|
1075
|
+
...props,
|
|
1076
|
+
ref
|
|
1077
|
+
}
|
|
1078
|
+
));
|
|
1079
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
|
1080
|
+
var sheetVariants = (0, import_class_variance_authority3.cva)(
|
|
1081
|
+
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
1082
|
+
{
|
|
1083
|
+
variants: {
|
|
1084
|
+
side: {
|
|
1085
|
+
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
1086
|
+
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
1087
|
+
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
|
1088
|
+
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
|
1089
|
+
center: "inset-0 m-auto max-h-full max-w-full border rounded-lg data-[state=closed]:fade-out data-[state=open]:fade-in"
|
|
1090
|
+
}
|
|
1091
|
+
},
|
|
1092
|
+
defaultVariants: {
|
|
1093
|
+
side: "right"
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
var SheetDescription = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1098
|
+
SheetPrimitive.Description,
|
|
1099
|
+
{
|
|
1100
|
+
ref,
|
|
1101
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
1102
|
+
...props
|
|
1103
|
+
}
|
|
1104
|
+
));
|
|
1105
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
1106
|
+
var SheetContent = React10.forwardRef(
|
|
1107
|
+
({
|
|
1108
|
+
side = "right",
|
|
1109
|
+
className,
|
|
1110
|
+
children,
|
|
1111
|
+
hideCloseButton = false,
|
|
1112
|
+
hideOverlay = false,
|
|
1113
|
+
overlayClassName,
|
|
1114
|
+
...props
|
|
1115
|
+
}, ref) => {
|
|
1116
|
+
const hasDescription = (0, import_react_tree.treeContainsComponent)(children, SheetDescription) || (0, import_react_tree.treeContainsComponent)(children, SheetPrimitive.Description);
|
|
1117
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(SheetPortal, { children: [
|
|
1118
|
+
!hideOverlay && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SheetOverlay, { className: overlayClassName }),
|
|
1119
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1120
|
+
SheetContentBase,
|
|
1121
|
+
{
|
|
1122
|
+
ref,
|
|
1123
|
+
className: cn(sheetVariants({ side }), className),
|
|
1124
|
+
...hasDescription ? {} : { "aria-describedby": void 0 },
|
|
1125
|
+
...props,
|
|
1126
|
+
children: [
|
|
1127
|
+
!hideCloseButton && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
|
|
1128
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Cross2Icon, { className: "h-4 w-4" }),
|
|
1129
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "sr-only", children: "Close" })
|
|
1130
|
+
] }),
|
|
1131
|
+
children
|
|
1132
|
+
]
|
|
1133
|
+
}
|
|
1134
|
+
)
|
|
1135
|
+
] });
|
|
1136
|
+
}
|
|
1137
|
+
);
|
|
1138
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
1139
|
+
var SheetHeader = ({
|
|
1140
|
+
className,
|
|
1141
|
+
...props
|
|
1142
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1143
|
+
"div",
|
|
1144
|
+
{
|
|
1145
|
+
className: cn(
|
|
1146
|
+
"flex flex-col space-y-2 text-center sm:text-left",
|
|
1147
|
+
className
|
|
1148
|
+
),
|
|
1149
|
+
...props
|
|
1150
|
+
}
|
|
1151
|
+
);
|
|
1152
|
+
SheetHeader.displayName = "SheetHeader";
|
|
1153
|
+
var SheetFooter = ({
|
|
1154
|
+
className,
|
|
1155
|
+
...props
|
|
1156
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1157
|
+
"div",
|
|
1158
|
+
{
|
|
1159
|
+
className: cn(
|
|
1160
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
1161
|
+
className
|
|
1162
|
+
),
|
|
1163
|
+
...props
|
|
1164
|
+
}
|
|
1165
|
+
);
|
|
1166
|
+
SheetFooter.displayName = "SheetFooter";
|
|
1167
|
+
var SheetTitle = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1168
|
+
SheetPrimitive.Title,
|
|
1169
|
+
{
|
|
1170
|
+
ref,
|
|
1171
|
+
className: cn("text-lg font-semibold text-foreground", className),
|
|
1172
|
+
...props
|
|
1173
|
+
}
|
|
1174
|
+
));
|
|
1175
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
|
1176
|
+
|
|
1177
|
+
// src/skeleton.tsx
|
|
1178
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1179
|
+
function Skeleton({
|
|
1180
|
+
className,
|
|
1181
|
+
...props
|
|
1182
|
+
}) {
|
|
1183
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1184
|
+
"div",
|
|
1185
|
+
{
|
|
1186
|
+
className: cn("animate-pulse rounded-md bg-primary/10", className),
|
|
1187
|
+
...props
|
|
1188
|
+
}
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// src/tabbed-bottom-sheet.tsx
|
|
1193
|
+
var import_react3 = require("react");
|
|
1194
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1195
|
+
function TabbedBottomSheet({
|
|
1196
|
+
open,
|
|
1197
|
+
onOpenChange,
|
|
1198
|
+
title,
|
|
1199
|
+
tabs
|
|
1200
|
+
}) {
|
|
1201
|
+
const [selectedTabId, setSelectedTabId] = (0, import_react3.useState)(null);
|
|
1202
|
+
const [wasOpen, setWasOpen] = (0, import_react3.useState)(open);
|
|
1203
|
+
if (open !== wasOpen) {
|
|
1204
|
+
setWasOpen(open);
|
|
1205
|
+
if (open) setSelectedTabId(null);
|
|
1206
|
+
}
|
|
1207
|
+
const selectedTab = selectedTabId ? tabs.find((tab) => tab.id === selectedTabId) : null;
|
|
1208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1209
|
+
BottomSheet,
|
|
1210
|
+
{
|
|
1211
|
+
open,
|
|
1212
|
+
onOpenChange,
|
|
1213
|
+
title,
|
|
1214
|
+
size: "full",
|
|
1215
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "matrx-mobile-sheet flex min-h-0 flex-1 flex-col", children: [
|
|
1216
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1217
|
+
BottomSheetHeader,
|
|
1218
|
+
{
|
|
1219
|
+
title: selectedTab ? selectedTab.label : title,
|
|
1220
|
+
showBack: !!selectedTab,
|
|
1221
|
+
onBack: () => setSelectedTabId(null)
|
|
1222
|
+
}
|
|
1223
|
+
),
|
|
1224
|
+
selectedTab ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden pb-safe", children: selectedTab.content }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BottomSheetBody, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("ul", { className: "divide-y divide-border", children: tabs.map((tab) => {
|
|
1225
|
+
const Icon = tab.icon;
|
|
1226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
1227
|
+
"button",
|
|
1228
|
+
{
|
|
1229
|
+
type: "button",
|
|
1230
|
+
onClick: () => setSelectedTabId(tab.id),
|
|
1231
|
+
className: "flex w-full items-center gap-3 px-4 py-3.5 text-left transition-colors hover:bg-muted/60 active:bg-muted",
|
|
1232
|
+
children: [
|
|
1233
|
+
Icon ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Icon, { className: "h-5 w-5 shrink-0 text-muted-foreground" }) : null,
|
|
1234
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "min-w-0 flex-1 text-base text-foreground", children: tab.label }),
|
|
1235
|
+
tab.trailing,
|
|
1236
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChevronRightIcon, { className: "h-5 w-5 shrink-0 text-muted-foreground" })
|
|
1237
|
+
]
|
|
1238
|
+
}
|
|
1239
|
+
) }, tab.id);
|
|
1240
|
+
}) }) })
|
|
1241
|
+
] })
|
|
1242
|
+
}
|
|
1243
|
+
);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// src/use-scroll-fade.ts
|
|
1247
|
+
var import_react4 = require("react");
|
|
1248
|
+
var EPSILON = 2;
|
|
1249
|
+
function useScrollFade() {
|
|
1250
|
+
const [state, setState] = (0, import_react4.useState)({
|
|
1251
|
+
top: false,
|
|
1252
|
+
bottom: false
|
|
1253
|
+
});
|
|
1254
|
+
const nodeRef = (0, import_react4.useRef)(null);
|
|
1255
|
+
const cleanupRef = (0, import_react4.useRef)(null);
|
|
1256
|
+
const measure = (0, import_react4.useCallback)(() => {
|
|
1257
|
+
const el = nodeRef.current;
|
|
1258
|
+
if (!el) return;
|
|
1259
|
+
const overflowing = el.scrollHeight - el.clientHeight > EPSILON;
|
|
1260
|
+
const next = {
|
|
1261
|
+
top: overflowing && el.scrollTop > EPSILON,
|
|
1262
|
+
bottom: overflowing && el.scrollTop + el.clientHeight < el.scrollHeight - EPSILON
|
|
1263
|
+
};
|
|
1264
|
+
setState(
|
|
1265
|
+
(prev) => prev.top === next.top && prev.bottom === next.bottom ? prev : next
|
|
1266
|
+
);
|
|
1267
|
+
}, []);
|
|
1268
|
+
const ref = (0, import_react4.useCallback)(
|
|
1269
|
+
(node) => {
|
|
1270
|
+
cleanupRef.current?.();
|
|
1271
|
+
cleanupRef.current = null;
|
|
1272
|
+
nodeRef.current = node;
|
|
1273
|
+
if (!node) return;
|
|
1274
|
+
node.addEventListener("scroll", measure, { passive: true });
|
|
1275
|
+
const ro = new ResizeObserver(measure);
|
|
1276
|
+
ro.observe(node);
|
|
1277
|
+
const mo = new MutationObserver(measure);
|
|
1278
|
+
mo.observe(node, { childList: true, subtree: true });
|
|
1279
|
+
cleanupRef.current = () => {
|
|
1280
|
+
node.removeEventListener("scroll", measure);
|
|
1281
|
+
ro.disconnect();
|
|
1282
|
+
mo.disconnect();
|
|
1283
|
+
};
|
|
1284
|
+
requestAnimationFrame(measure);
|
|
1285
|
+
},
|
|
1286
|
+
[measure]
|
|
1287
|
+
);
|
|
1288
|
+
(0, import_react4.useEffect)(() => () => cleanupRef.current?.(), []);
|
|
1289
|
+
return {
|
|
1290
|
+
ref,
|
|
1291
|
+
state,
|
|
1292
|
+
fadeProps: {
|
|
1293
|
+
"data-fade-top": state.top ? "" : void 0,
|
|
1294
|
+
"data-fade-bottom": state.bottom ? "" : void 0,
|
|
1295
|
+
className: "matrx-scroll-fade"
|
|
1296
|
+
}
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
//# sourceMappingURL=index.cjs.map
|