@nextlyhq/ui 0.0.2-alpha.51 → 0.0.2-alpha.54
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 +5 -2
- package/dist/index.cjs +565 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +423 -8
- package/dist/index.d.ts +423 -8
- package/dist/index.mjs +547 -16
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.scoped.css +1 -1
- package/dist/tailwind-preset.cjs +7 -0
- package/dist/tailwind-preset.cjs.map +1 -1
- package/dist/tailwind-preset.d.cts +4 -0
- package/dist/tailwind-preset.d.ts +4 -0
- package/dist/tailwind-preset.mjs +7 -0
- package/dist/tailwind-preset.mjs.map +1 -1
- package/dist/theme.css +26 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.mjs.map +1 -1
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -72,8 +72,10 @@ as a Tailwind v3 preset from `@nextlyhq/ui/tailwind-preset`.
|
|
|
72
72
|
**Display:** `Badge`, `Card`, `Alert`, `Separator`, `Skeleton`, `Progress`
|
|
73
73
|
**Toggles:** `Checkbox`, `RadioGroup`, `Switch`, `Collapsible`
|
|
74
74
|
**Layout and disclosure:** `Accordion`, `Avatar`, `Tabs`, `Tooltip`, `Popover`
|
|
75
|
+
**Resizable regions:** `ResizablePanelGroup`, `ResizablePanel`, `ResizableHandle`
|
|
76
|
+
**Hierarchies:** `TreeView` (virtualized, keyboard-operable)
|
|
75
77
|
**Overlays:** `Dialog`, `AlertDialog`, `Sheet`
|
|
76
|
-
**Menus and command palette:** `DropdownMenu`, `Select`, `Command`
|
|
78
|
+
**Menus and command palette:** `DropdownMenu`, `ContextMenu`, `Select`, `Command`
|
|
77
79
|
**Feedback:** `Spinner`, `Toaster` (with `toast()` helper)
|
|
78
80
|
**Tables:** `Table` primitives, `ResponsiveTable`, `TableSearch`, `TablePagination`, `TableSkeleton`, `TableEmpty`, `TableError`, `TableLoading`
|
|
79
81
|
**Providers:** `PortalProvider`, `usePortalContainer`
|
|
@@ -118,7 +120,8 @@ Tailwind's internal `--tw-*` registrations, and the ancestor classes `dark:` and
|
|
|
118
120
|
|
|
119
121
|
### Overlays need a portal container
|
|
120
122
|
|
|
121
|
-
AlertDialog, Command, Dialog, DropdownMenu, Popover, Select, Sheet and
|
|
123
|
+
AlertDialog, Command, ContextMenu, Dialog, DropdownMenu, Popover, Select, Sheet and
|
|
124
|
+
Tooltip render
|
|
122
125
|
their overlay through a portal, which defaults to `document.body` — outside the wrapper,
|
|
123
126
|
where the scoped rules and tokens do not reach. Triggers would look right and the menus
|
|
124
127
|
they open would not. Point them back inside with `PortalProvider`:
|
package/dist/index.cjs
CHANGED
|
@@ -74,6 +74,20 @@ __export(index_exports, {
|
|
|
74
74
|
CommandList: () => CommandList,
|
|
75
75
|
CommandSeparator: () => CommandSeparator,
|
|
76
76
|
CommandShortcut: () => CommandShortcut,
|
|
77
|
+
ContextMenu: () => ContextMenu,
|
|
78
|
+
ContextMenuCheckboxItem: () => ContextMenuCheckboxItem,
|
|
79
|
+
ContextMenuContent: () => ContextMenuContent,
|
|
80
|
+
ContextMenuGroup: () => ContextMenuGroup,
|
|
81
|
+
ContextMenuItem: () => ContextMenuItem,
|
|
82
|
+
ContextMenuLabel: () => ContextMenuLabel,
|
|
83
|
+
ContextMenuRadioGroup: () => ContextMenuRadioGroup,
|
|
84
|
+
ContextMenuRadioItem: () => ContextMenuRadioItem,
|
|
85
|
+
ContextMenuSeparator: () => ContextMenuSeparator,
|
|
86
|
+
ContextMenuShortcut: () => ContextMenuShortcut,
|
|
87
|
+
ContextMenuSub: () => ContextMenuSub,
|
|
88
|
+
ContextMenuSubContent: () => ContextMenuSubContent,
|
|
89
|
+
ContextMenuSubTrigger: () => ContextMenuSubTrigger,
|
|
90
|
+
ContextMenuTrigger: () => ContextMenuTrigger,
|
|
77
91
|
Dialog: () => Dialog,
|
|
78
92
|
DialogClose: () => DialogClose,
|
|
79
93
|
DialogContent: () => DialogContent,
|
|
@@ -111,6 +125,9 @@ __export(index_exports, {
|
|
|
111
125
|
Progress: () => Progress,
|
|
112
126
|
RadioGroup: () => RadioGroup,
|
|
113
127
|
RadioGroupItem: () => RadioGroupItem,
|
|
128
|
+
ResizableHandle: () => ResizableHandle,
|
|
129
|
+
ResizablePanel: () => ResizablePanel,
|
|
130
|
+
ResizablePanelGroup: () => ResizablePanelGroup,
|
|
114
131
|
Select: () => Select,
|
|
115
132
|
SelectContent: () => SelectContent,
|
|
116
133
|
SelectGroup: () => SelectGroup,
|
|
@@ -160,6 +177,7 @@ __export(index_exports, {
|
|
|
160
177
|
TooltipContent: () => TooltipContent,
|
|
161
178
|
TooltipProvider: () => TooltipProvider,
|
|
162
179
|
TooltipTrigger: () => TooltipTrigger,
|
|
180
|
+
TreeView: () => TreeView,
|
|
163
181
|
alertVariants: () => alertVariants,
|
|
164
182
|
avatarVariants: () => avatarVariants,
|
|
165
183
|
badgeVariants: () => badgeVariants,
|
|
@@ -1167,10 +1185,12 @@ var DialogOverlay = (0, import_react14.forwardRef)(({ className, ...props }, ref
|
|
|
1167
1185
|
ref,
|
|
1168
1186
|
"data-slot": "dialog-overlay",
|
|
1169
1187
|
className: cn(
|
|
1170
|
-
// A modal scrim
|
|
1171
|
-
//
|
|
1172
|
-
// make it a white veil in light mode
|
|
1173
|
-
|
|
1188
|
+
// A modal scrim, from the `--nx-overlay` token rather than a surface
|
|
1189
|
+
// token. A black wash is the point — painting it from `background` would
|
|
1190
|
+
// make it a white veil in light mode — but the alpha still has to differ
|
|
1191
|
+
// per mode, because what it composites over is white in one and mid-tone
|
|
1192
|
+
// in the other.
|
|
1193
|
+
"fixed inset-0 z-50 bg-overlay backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1174
1194
|
className
|
|
1175
1195
|
),
|
|
1176
1196
|
...props
|
|
@@ -1287,10 +1307,12 @@ var AlertDialogOverlay = (0, import_react15.forwardRef)(({ className, ...props }
|
|
|
1287
1307
|
{
|
|
1288
1308
|
ref,
|
|
1289
1309
|
className: cn(
|
|
1290
|
-
// A modal scrim
|
|
1291
|
-
//
|
|
1292
|
-
// make it a white veil in light mode
|
|
1293
|
-
|
|
1310
|
+
// A modal scrim, from the `--nx-overlay` token rather than a surface
|
|
1311
|
+
// token. A black wash is the point — painting it from `background` would
|
|
1312
|
+
// make it a white veil in light mode — but the alpha still has to differ
|
|
1313
|
+
// per mode, because what it composites over is white in one and mid-tone
|
|
1314
|
+
// in the other.
|
|
1315
|
+
"fixed inset-0 z-50 bg-overlay backdrop-blur-sm transition-opacity duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1294
1316
|
className
|
|
1295
1317
|
),
|
|
1296
1318
|
...props
|
|
@@ -1712,10 +1734,12 @@ var SheetOverlay = React7.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
1712
1734
|
DialogPrimitive2.Overlay,
|
|
1713
1735
|
{
|
|
1714
1736
|
className: cn(
|
|
1715
|
-
// A modal scrim
|
|
1716
|
-
//
|
|
1717
|
-
// make it a white veil in light mode
|
|
1718
|
-
|
|
1737
|
+
// A modal scrim, from the `--nx-overlay` token rather than a surface
|
|
1738
|
+
// token. A black wash is the point — painting it from `background` would
|
|
1739
|
+
// make it a white veil in light mode — but the alpha still has to differ
|
|
1740
|
+
// per mode, because what it composites over is white in one and mid-tone
|
|
1741
|
+
// in the other.
|
|
1742
|
+
"fixed inset-0 z-50 bg-overlay backdrop-blur-sm",
|
|
1719
1743
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
1720
1744
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1721
1745
|
className
|
|
@@ -1830,10 +1854,12 @@ var CommandDialogOverlay = (0, import_react17.forwardRef)(({ className, ...props
|
|
|
1830
1854
|
{
|
|
1831
1855
|
ref,
|
|
1832
1856
|
className: cn(
|
|
1833
|
-
// A modal scrim
|
|
1834
|
-
//
|
|
1835
|
-
// make it a white veil in light mode
|
|
1836
|
-
|
|
1857
|
+
// A modal scrim, from the `--nx-overlay` token rather than a surface
|
|
1858
|
+
// token. A black wash is the point — painting it from `background` would
|
|
1859
|
+
// make it a white veil in light mode — but the alpha still has to differ
|
|
1860
|
+
// per mode, because what it composites over is white in one and mid-tone
|
|
1861
|
+
// in the other.
|
|
1862
|
+
"fixed inset-0 z-[99] bg-overlay backdrop-blur-sm",
|
|
1837
1863
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
1838
1864
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1839
1865
|
"transition-opacity duration-200",
|
|
@@ -2278,6 +2304,511 @@ var TableSkeleton = ({
|
|
|
2278
2304
|
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "table-wrapper rounded-md border border-border bg-card overflow-hidden", children: content });
|
|
2279
2305
|
};
|
|
2280
2306
|
TableSkeleton.displayName = "TableSkeleton";
|
|
2307
|
+
|
|
2308
|
+
// src/components/context-menu.tsx
|
|
2309
|
+
var ContextMenuPrimitive = __toESM(require("@radix-ui/react-context-menu"), 1);
|
|
2310
|
+
var import_lucide_react12 = require("lucide-react");
|
|
2311
|
+
var React9 = __toESM(require("react"), 1);
|
|
2312
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
2313
|
+
var menuItemBase2 = "cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
|
|
2314
|
+
var menuSurface = "z-50 max-h-[var(--radix-context-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md 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 origin-[--radix-context-menu-content-transform-origin]";
|
|
2315
|
+
var ContextMenu = ContextMenuPrimitive.Root;
|
|
2316
|
+
var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
|
|
2317
|
+
var ContextMenuGroup = ContextMenuPrimitive.Group;
|
|
2318
|
+
var ContextMenuSub = ContextMenuPrimitive.Sub;
|
|
2319
|
+
var ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
|
|
2320
|
+
var ContextMenuSubTrigger = React9.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2321
|
+
ContextMenuPrimitive.SubTrigger,
|
|
2322
|
+
{
|
|
2323
|
+
ref,
|
|
2324
|
+
className: cn(
|
|
2325
|
+
"flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[state=open]:bg-muted [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
2326
|
+
menuItemBase2,
|
|
2327
|
+
inset && "pl-8",
|
|
2328
|
+
className
|
|
2329
|
+
),
|
|
2330
|
+
...props,
|
|
2331
|
+
children: [
|
|
2332
|
+
children,
|
|
2333
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react12.ChevronRight, { className: "ml-auto" })
|
|
2334
|
+
]
|
|
2335
|
+
}
|
|
2336
|
+
));
|
|
2337
|
+
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
|
|
2338
|
+
var ContextMenuSubContent = React9.forwardRef(({ className, ...props }, ref) => {
|
|
2339
|
+
const portalContainer = usePortalContainer();
|
|
2340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2341
|
+
ContextMenuPrimitive.SubContent,
|
|
2342
|
+
{
|
|
2343
|
+
ref,
|
|
2344
|
+
className: cn(menuSurface, className),
|
|
2345
|
+
...props
|
|
2346
|
+
}
|
|
2347
|
+
) });
|
|
2348
|
+
});
|
|
2349
|
+
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
|
|
2350
|
+
var ContextMenuContent = React9.forwardRef(({ className, ...props }, ref) => {
|
|
2351
|
+
const portalContainer = usePortalContainer();
|
|
2352
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2353
|
+
ContextMenuPrimitive.Content,
|
|
2354
|
+
{
|
|
2355
|
+
ref,
|
|
2356
|
+
className: cn(menuSurface, className),
|
|
2357
|
+
...props
|
|
2358
|
+
}
|
|
2359
|
+
) });
|
|
2360
|
+
});
|
|
2361
|
+
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
|
|
2362
|
+
var ContextMenuItem = React9.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2363
|
+
ContextMenuPrimitive.Item,
|
|
2364
|
+
{
|
|
2365
|
+
ref,
|
|
2366
|
+
className: cn(
|
|
2367
|
+
"relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
2368
|
+
menuItemBase2,
|
|
2369
|
+
inset && "pl-8",
|
|
2370
|
+
className
|
|
2371
|
+
),
|
|
2372
|
+
...props
|
|
2373
|
+
}
|
|
2374
|
+
));
|
|
2375
|
+
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
|
|
2376
|
+
var ContextMenuCheckboxItem = React9.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2377
|
+
ContextMenuPrimitive.CheckboxItem,
|
|
2378
|
+
{
|
|
2379
|
+
ref,
|
|
2380
|
+
className: cn(
|
|
2381
|
+
"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
|
|
2382
|
+
menuItemBase2,
|
|
2383
|
+
className
|
|
2384
|
+
),
|
|
2385
|
+
checked,
|
|
2386
|
+
...props,
|
|
2387
|
+
children: [
|
|
2388
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react12.Check, { className: "h-4 w-4" }) }) }),
|
|
2389
|
+
children
|
|
2390
|
+
]
|
|
2391
|
+
}
|
|
2392
|
+
));
|
|
2393
|
+
ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
|
|
2394
|
+
var ContextMenuRadioItem = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2395
|
+
ContextMenuPrimitive.RadioItem,
|
|
2396
|
+
{
|
|
2397
|
+
ref,
|
|
2398
|
+
className: cn(
|
|
2399
|
+
"relative flex select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
|
|
2400
|
+
menuItemBase2,
|
|
2401
|
+
className
|
|
2402
|
+
),
|
|
2403
|
+
...props,
|
|
2404
|
+
children: [
|
|
2405
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react12.Circle, { className: "h-2 w-2 fill-current" }) }) }),
|
|
2406
|
+
children
|
|
2407
|
+
]
|
|
2408
|
+
}
|
|
2409
|
+
));
|
|
2410
|
+
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
|
|
2411
|
+
var ContextMenuLabel = React9.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2412
|
+
ContextMenuPrimitive.Label,
|
|
2413
|
+
{
|
|
2414
|
+
ref,
|
|
2415
|
+
className: cn(
|
|
2416
|
+
"px-2 py-1.5 text-sm font-semibold text-foreground",
|
|
2417
|
+
inset && "pl-8",
|
|
2418
|
+
className
|
|
2419
|
+
),
|
|
2420
|
+
...props
|
|
2421
|
+
}
|
|
2422
|
+
));
|
|
2423
|
+
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
|
|
2424
|
+
var ContextMenuSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2425
|
+
ContextMenuPrimitive.Separator,
|
|
2426
|
+
{
|
|
2427
|
+
ref,
|
|
2428
|
+
className: cn("-mx-1 my-1 h-px bg-border", className),
|
|
2429
|
+
...props
|
|
2430
|
+
}
|
|
2431
|
+
));
|
|
2432
|
+
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
|
|
2433
|
+
var ContextMenuShortcut = ({
|
|
2434
|
+
className,
|
|
2435
|
+
...props
|
|
2436
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2437
|
+
"span",
|
|
2438
|
+
{
|
|
2439
|
+
className: cn(
|
|
2440
|
+
"ml-auto text-xs tracking-widest text-muted-foreground",
|
|
2441
|
+
className
|
|
2442
|
+
),
|
|
2443
|
+
...props
|
|
2444
|
+
}
|
|
2445
|
+
);
|
|
2446
|
+
ContextMenuShortcut.displayName = "ContextMenuShortcut";
|
|
2447
|
+
|
|
2448
|
+
// src/components/resizable.tsx
|
|
2449
|
+
var import_lucide_react13 = require("lucide-react");
|
|
2450
|
+
var ResizablePrimitive = __toESM(require("react-resizable-panels"), 1);
|
|
2451
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
2452
|
+
var ResizablePanelGroup = ({
|
|
2453
|
+
className,
|
|
2454
|
+
...props
|
|
2455
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2456
|
+
ResizablePrimitive.Group,
|
|
2457
|
+
{
|
|
2458
|
+
className: cn("h-full w-full", className),
|
|
2459
|
+
...props
|
|
2460
|
+
}
|
|
2461
|
+
);
|
|
2462
|
+
var ResizablePanel = ResizablePrimitive.Panel;
|
|
2463
|
+
var ResizableHandle = ({
|
|
2464
|
+
withGrip,
|
|
2465
|
+
className,
|
|
2466
|
+
children,
|
|
2467
|
+
...props
|
|
2468
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
2469
|
+
ResizablePrimitive.Separator,
|
|
2470
|
+
{
|
|
2471
|
+
className: cn(
|
|
2472
|
+
// The drawn line is 1px; the element around it is wider and transparent, so the pointer
|
|
2473
|
+
// target is comfortably larger than what it appears to grab (WCAG 2.5.8).
|
|
2474
|
+
"relative flex items-center justify-center bg-border",
|
|
2475
|
+
// Keyed off `aria-orientation`, which is what the separator actually carries, and read as
|
|
2476
|
+
// the ARIA spec defines it: the attribute describes the SEPARATOR, not the group. A
|
|
2477
|
+
// horizontal group puts its panels side by side, so its separator is a vertical line.
|
|
2478
|
+
"aria-[orientation=vertical]:w-px aria-[orientation=horizontal]:h-px",
|
|
2479
|
+
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
|
|
2480
|
+
// Reachable without precision pointing, without drawing a heavier divider: the hit area
|
|
2481
|
+
// grows across the line, so a vertical line widens and a horizontal one deepens.
|
|
2482
|
+
"after:absolute after:inset-0",
|
|
2483
|
+
"aria-[orientation=vertical]:after:-inset-x-1 aria-[orientation=horizontal]:after:-inset-y-1",
|
|
2484
|
+
className
|
|
2485
|
+
),
|
|
2486
|
+
...props,
|
|
2487
|
+
children: [
|
|
2488
|
+
withGrip ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-border bg-border", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react13.GripVertical, { className: "h-2.5 w-2.5 text-muted-foreground" }) }) : null,
|
|
2489
|
+
children
|
|
2490
|
+
]
|
|
2491
|
+
}
|
|
2492
|
+
);
|
|
2493
|
+
|
|
2494
|
+
// src/components/tree-view.tsx
|
|
2495
|
+
var import_react_virtual = require("@tanstack/react-virtual");
|
|
2496
|
+
var import_lucide_react14 = require("lucide-react");
|
|
2497
|
+
var React10 = __toESM(require("react"), 1);
|
|
2498
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2499
|
+
var ROW_HEIGHT = 28;
|
|
2500
|
+
var INDENT_PER_LEVEL = 12;
|
|
2501
|
+
function textOf(node) {
|
|
2502
|
+
if (typeof node.textValue === "string") return node.textValue;
|
|
2503
|
+
return typeof node.label === "string" ? node.label : "";
|
|
2504
|
+
}
|
|
2505
|
+
function flatten(nodes, expanded) {
|
|
2506
|
+
const rows = [];
|
|
2507
|
+
const pending = [{ list: nodes, index: 0, level: 0 }];
|
|
2508
|
+
while (pending.length > 0) {
|
|
2509
|
+
const frame = pending[pending.length - 1];
|
|
2510
|
+
if (frame === void 0 || frame.index >= frame.list.length) {
|
|
2511
|
+
pending.pop();
|
|
2512
|
+
continue;
|
|
2513
|
+
}
|
|
2514
|
+
const node = frame.list[frame.index];
|
|
2515
|
+
const posInSet = frame.index;
|
|
2516
|
+
frame.index += 1;
|
|
2517
|
+
if (node === void 0) continue;
|
|
2518
|
+
const hasChildren = node.children !== void 0;
|
|
2519
|
+
rows.push({
|
|
2520
|
+
node,
|
|
2521
|
+
level: frame.level,
|
|
2522
|
+
setSize: frame.list.length,
|
|
2523
|
+
posInSet,
|
|
2524
|
+
parentId: frame.parentId,
|
|
2525
|
+
hasChildren
|
|
2526
|
+
});
|
|
2527
|
+
if (hasChildren && expanded.has(node.id)) {
|
|
2528
|
+
pending.push({
|
|
2529
|
+
list: node.children ?? [],
|
|
2530
|
+
index: 0,
|
|
2531
|
+
level: frame.level + 1,
|
|
2532
|
+
parentId: node.id
|
|
2533
|
+
});
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
return rows;
|
|
2537
|
+
}
|
|
2538
|
+
function useControllable(controlled, fallback) {
|
|
2539
|
+
const [uncontrolled, setUncontrolled] = React10.useState(fallback);
|
|
2540
|
+
return [
|
|
2541
|
+
controlled === void 0 ? uncontrolled : controlled,
|
|
2542
|
+
setUncontrolled
|
|
2543
|
+
];
|
|
2544
|
+
}
|
|
2545
|
+
var TreeView = React10.forwardRef(
|
|
2546
|
+
({
|
|
2547
|
+
nodes,
|
|
2548
|
+
expandedIds,
|
|
2549
|
+
defaultExpandedIds,
|
|
2550
|
+
onExpandedChange,
|
|
2551
|
+
selectedId,
|
|
2552
|
+
defaultSelectedId,
|
|
2553
|
+
onSelectedChange,
|
|
2554
|
+
className,
|
|
2555
|
+
"aria-label": ariaLabel,
|
|
2556
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2557
|
+
"aria-describedby": ariaDescribedBy,
|
|
2558
|
+
...props
|
|
2559
|
+
}, forwardedRef) => {
|
|
2560
|
+
const scrollRef = React10.useRef(null);
|
|
2561
|
+
const attachScroll = React10.useCallback(
|
|
2562
|
+
(node) => {
|
|
2563
|
+
scrollRef.current = node;
|
|
2564
|
+
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
2565
|
+
else if (forwardedRef !== null && forwardedRef !== void 0) {
|
|
2566
|
+
forwardedRef.current = node;
|
|
2567
|
+
}
|
|
2568
|
+
},
|
|
2569
|
+
[forwardedRef]
|
|
2570
|
+
);
|
|
2571
|
+
const [expandedState, setExpandedState] = useControllable(
|
|
2572
|
+
expandedIds === void 0 ? void 0 : [...expandedIds],
|
|
2573
|
+
[...defaultExpandedIds ?? []]
|
|
2574
|
+
);
|
|
2575
|
+
const expanded = React10.useMemo(
|
|
2576
|
+
() => new Set(expandedIds ?? expandedState),
|
|
2577
|
+
[expandedIds, expandedState]
|
|
2578
|
+
);
|
|
2579
|
+
const [selected, setSelected] = useControllable(
|
|
2580
|
+
selectedId === void 0 ? void 0 : selectedId,
|
|
2581
|
+
defaultSelectedId ?? null
|
|
2582
|
+
);
|
|
2583
|
+
const rows = React10.useMemo(
|
|
2584
|
+
() => flatten(nodes, expanded),
|
|
2585
|
+
[nodes, expanded]
|
|
2586
|
+
);
|
|
2587
|
+
const [activeId, setActiveId] = React10.useState(null);
|
|
2588
|
+
const activeIndex = Math.max(
|
|
2589
|
+
0,
|
|
2590
|
+
rows.findIndex((row) => row.node.id === (activeId ?? selected))
|
|
2591
|
+
);
|
|
2592
|
+
const virtualizer = (0, import_react_virtual.useVirtualizer)({
|
|
2593
|
+
count: rows.length,
|
|
2594
|
+
getScrollElement: () => scrollRef.current,
|
|
2595
|
+
estimateSize: () => ROW_HEIGHT,
|
|
2596
|
+
overscan: 8
|
|
2597
|
+
});
|
|
2598
|
+
const commitExpanded = (next) => {
|
|
2599
|
+
const ids = [...next];
|
|
2600
|
+
if (expandedIds === void 0) setExpandedState(ids);
|
|
2601
|
+
onExpandedChange?.(ids);
|
|
2602
|
+
};
|
|
2603
|
+
const setExpansion = (id, open) => {
|
|
2604
|
+
const next = new Set(expanded);
|
|
2605
|
+
if (open) next.add(id);
|
|
2606
|
+
else next.delete(id);
|
|
2607
|
+
commitExpanded(next);
|
|
2608
|
+
};
|
|
2609
|
+
const choose = (id) => {
|
|
2610
|
+
if (selectedId === void 0) setSelected(id);
|
|
2611
|
+
onSelectedChange?.(id);
|
|
2612
|
+
};
|
|
2613
|
+
const focusRow = (index) => {
|
|
2614
|
+
const row = rows[index];
|
|
2615
|
+
if (row === void 0) return;
|
|
2616
|
+
setActiveId(row.node.id);
|
|
2617
|
+
virtualizer.scrollToIndex(index, { align: "auto" });
|
|
2618
|
+
requestAnimationFrame(() => {
|
|
2619
|
+
const element = scrollRef.current?.querySelector(
|
|
2620
|
+
`[data-tree-index="${index}"]`
|
|
2621
|
+
);
|
|
2622
|
+
element?.focus();
|
|
2623
|
+
});
|
|
2624
|
+
};
|
|
2625
|
+
const step = (from, delta) => {
|
|
2626
|
+
for (let index = from + delta; index >= 0 && index < rows.length; index += delta) {
|
|
2627
|
+
if (rows[index]?.node.disabled !== true) return index;
|
|
2628
|
+
}
|
|
2629
|
+
return from;
|
|
2630
|
+
};
|
|
2631
|
+
const typeahead = React10.useRef({ query: "", at: 0 });
|
|
2632
|
+
const onKeyDown = (event) => {
|
|
2633
|
+
const index = activeIndex;
|
|
2634
|
+
const row = rows[index];
|
|
2635
|
+
if (row === void 0) return;
|
|
2636
|
+
switch (event.key) {
|
|
2637
|
+
case "ArrowDown":
|
|
2638
|
+
event.preventDefault();
|
|
2639
|
+
focusRow(step(index, 1));
|
|
2640
|
+
return;
|
|
2641
|
+
case "ArrowUp":
|
|
2642
|
+
event.preventDefault();
|
|
2643
|
+
focusRow(step(index, -1));
|
|
2644
|
+
return;
|
|
2645
|
+
case "ArrowRight":
|
|
2646
|
+
event.preventDefault();
|
|
2647
|
+
if (row.hasChildren && !expanded.has(row.node.id)) {
|
|
2648
|
+
setExpansion(row.node.id, true);
|
|
2649
|
+
} else if (row.hasChildren) {
|
|
2650
|
+
for (let child = index + 1; child < rows.length && (rows[child]?.level ?? 0) > row.level; child += 1) {
|
|
2651
|
+
if (rows[child]?.parentId === row.node.id && rows[child]?.node.disabled !== true) {
|
|
2652
|
+
focusRow(child);
|
|
2653
|
+
break;
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
return;
|
|
2658
|
+
case "ArrowLeft":
|
|
2659
|
+
event.preventDefault();
|
|
2660
|
+
if (row.hasChildren && expanded.has(row.node.id)) {
|
|
2661
|
+
setExpansion(row.node.id, false);
|
|
2662
|
+
} else if (row.parentId !== void 0) {
|
|
2663
|
+
let ancestor = row.parentId;
|
|
2664
|
+
while (ancestor !== void 0) {
|
|
2665
|
+
const at = rows.findIndex(
|
|
2666
|
+
(candidate) => candidate.node.id === ancestor
|
|
2667
|
+
);
|
|
2668
|
+
if (at < 0) break;
|
|
2669
|
+
if (rows[at]?.node.disabled !== true) {
|
|
2670
|
+
focusRow(at);
|
|
2671
|
+
break;
|
|
2672
|
+
}
|
|
2673
|
+
ancestor = rows[at]?.parentId;
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
return;
|
|
2677
|
+
case "Home":
|
|
2678
|
+
event.preventDefault();
|
|
2679
|
+
focusRow(rows[0]?.node.disabled === true ? step(0, 1) : 0);
|
|
2680
|
+
return;
|
|
2681
|
+
case "End": {
|
|
2682
|
+
event.preventDefault();
|
|
2683
|
+
const last = rows.length - 1;
|
|
2684
|
+
focusRow(rows[last]?.node.disabled === true ? step(last, -1) : last);
|
|
2685
|
+
return;
|
|
2686
|
+
}
|
|
2687
|
+
case "Enter":
|
|
2688
|
+
case " ":
|
|
2689
|
+
event.preventDefault();
|
|
2690
|
+
if (row.node.disabled !== true) choose(row.node.id);
|
|
2691
|
+
return;
|
|
2692
|
+
case "*": {
|
|
2693
|
+
event.preventDefault();
|
|
2694
|
+
const next = new Set(expanded);
|
|
2695
|
+
for (const sibling of rows) {
|
|
2696
|
+
if (sibling.parentId === row.parentId && sibling.hasChildren) {
|
|
2697
|
+
next.add(sibling.node.id);
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
commitExpanded(next);
|
|
2701
|
+
return;
|
|
2702
|
+
}
|
|
2703
|
+
default:
|
|
2704
|
+
break;
|
|
2705
|
+
}
|
|
2706
|
+
if (event.key.length !== 1 || event.metaKey || event.ctrlKey || event.altKey) {
|
|
2707
|
+
return;
|
|
2708
|
+
}
|
|
2709
|
+
event.preventDefault();
|
|
2710
|
+
const now = Date.now();
|
|
2711
|
+
const state = typeahead.current;
|
|
2712
|
+
state.query = now - state.at > 500 ? event.key : state.query + event.key;
|
|
2713
|
+
state.at = now;
|
|
2714
|
+
const query = state.query.toLowerCase();
|
|
2715
|
+
for (let offset = 1; offset <= rows.length; offset += 1) {
|
|
2716
|
+
const candidate = rows[(index + offset) % rows.length];
|
|
2717
|
+
if (candidate === void 0 || candidate.node.disabled === true)
|
|
2718
|
+
continue;
|
|
2719
|
+
if (textOf(candidate.node).toLowerCase().startsWith(query)) {
|
|
2720
|
+
focusRow(rows.indexOf(candidate));
|
|
2721
|
+
return;
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
};
|
|
2725
|
+
const virtualItems = virtualizer.getVirtualItems();
|
|
2726
|
+
const usable = (index) => rows[index]?.node.disabled !== true;
|
|
2727
|
+
const tabStopIndex = virtualItems.some((item) => item.index === activeIndex) && usable(activeIndex) ? activeIndex : virtualItems.find((item) => usable(item.index))?.index ?? -1;
|
|
2728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2729
|
+
"div",
|
|
2730
|
+
{
|
|
2731
|
+
ref: attachScroll,
|
|
2732
|
+
className: cn("overflow-auto", className),
|
|
2733
|
+
...props,
|
|
2734
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2735
|
+
"div",
|
|
2736
|
+
{
|
|
2737
|
+
role: "tree",
|
|
2738
|
+
"aria-label": ariaLabel,
|
|
2739
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2740
|
+
"aria-describedby": ariaDescribedBy,
|
|
2741
|
+
onKeyDown,
|
|
2742
|
+
style: { height: virtualizer.getTotalSize(), position: "relative" },
|
|
2743
|
+
children: virtualItems.map((item) => {
|
|
2744
|
+
const row = rows[item.index];
|
|
2745
|
+
if (row === void 0) return null;
|
|
2746
|
+
const isSelected = selected === row.node.id;
|
|
2747
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
2748
|
+
"div",
|
|
2749
|
+
{
|
|
2750
|
+
"data-tree-index": item.index,
|
|
2751
|
+
role: "treeitem",
|
|
2752
|
+
"aria-level": row.level + 1,
|
|
2753
|
+
"aria-setsize": row.setSize,
|
|
2754
|
+
"aria-posinset": row.posInSet + 1,
|
|
2755
|
+
"aria-selected": isSelected,
|
|
2756
|
+
"aria-expanded": row.hasChildren ? expanded.has(row.node.id) : void 0,
|
|
2757
|
+
"aria-disabled": row.node.disabled === true ? true : void 0,
|
|
2758
|
+
tabIndex: item.index === tabStopIndex ? 0 : -1,
|
|
2759
|
+
onFocus: () => setActiveId(row.node.id),
|
|
2760
|
+
onClick: () => {
|
|
2761
|
+
if (row.node.disabled === true) return;
|
|
2762
|
+
setActiveId(row.node.id);
|
|
2763
|
+
choose(row.node.id);
|
|
2764
|
+
},
|
|
2765
|
+
className: cn(
|
|
2766
|
+
"absolute left-0 flex w-full select-none items-center gap-1 rounded-sm pr-2 text-sm outline-none",
|
|
2767
|
+
"focus-visible:ring-1 focus-visible:ring-ring",
|
|
2768
|
+
row.node.disabled === true ? "pointer-events-none opacity-50" : "cursor-pointer",
|
|
2769
|
+
isSelected ? "bg-muted text-foreground" : "hover:bg-muted/50"
|
|
2770
|
+
),
|
|
2771
|
+
style: {
|
|
2772
|
+
height: item.size,
|
|
2773
|
+
transform: `translateY(${item.start}px)`,
|
|
2774
|
+
paddingLeft: 4 + row.level * INDENT_PER_LEVEL
|
|
2775
|
+
},
|
|
2776
|
+
children: [
|
|
2777
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2778
|
+
"span",
|
|
2779
|
+
{
|
|
2780
|
+
"aria-hidden": "true",
|
|
2781
|
+
className: "flex size-4 shrink-0 items-center justify-center",
|
|
2782
|
+
onClick: (event) => {
|
|
2783
|
+
if (!row.hasChildren) return;
|
|
2784
|
+
event.stopPropagation();
|
|
2785
|
+
setExpansion(row.node.id, !expanded.has(row.node.id));
|
|
2786
|
+
},
|
|
2787
|
+
children: row.hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2788
|
+
import_lucide_react14.ChevronRight,
|
|
2789
|
+
{
|
|
2790
|
+
className: cn(
|
|
2791
|
+
"size-3.5 text-muted-foreground transition-transform",
|
|
2792
|
+
expanded.has(row.node.id) && "rotate-90"
|
|
2793
|
+
)
|
|
2794
|
+
}
|
|
2795
|
+
) : null
|
|
2796
|
+
}
|
|
2797
|
+
),
|
|
2798
|
+
row.node.icon !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "flex size-4 shrink-0 items-center justify-center text-muted-foreground", children: row.node.icon }) : null,
|
|
2799
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "truncate", children: row.node.label })
|
|
2800
|
+
]
|
|
2801
|
+
},
|
|
2802
|
+
row.node.id
|
|
2803
|
+
);
|
|
2804
|
+
})
|
|
2805
|
+
}
|
|
2806
|
+
)
|
|
2807
|
+
}
|
|
2808
|
+
);
|
|
2809
|
+
}
|
|
2810
|
+
);
|
|
2811
|
+
TreeView.displayName = "TreeView";
|
|
2281
2812
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2282
2813
|
0 && (module.exports = {
|
|
2283
2814
|
Accordion,
|
|
@@ -2323,6 +2854,20 @@ TableSkeleton.displayName = "TableSkeleton";
|
|
|
2323
2854
|
CommandList,
|
|
2324
2855
|
CommandSeparator,
|
|
2325
2856
|
CommandShortcut,
|
|
2857
|
+
ContextMenu,
|
|
2858
|
+
ContextMenuCheckboxItem,
|
|
2859
|
+
ContextMenuContent,
|
|
2860
|
+
ContextMenuGroup,
|
|
2861
|
+
ContextMenuItem,
|
|
2862
|
+
ContextMenuLabel,
|
|
2863
|
+
ContextMenuRadioGroup,
|
|
2864
|
+
ContextMenuRadioItem,
|
|
2865
|
+
ContextMenuSeparator,
|
|
2866
|
+
ContextMenuShortcut,
|
|
2867
|
+
ContextMenuSub,
|
|
2868
|
+
ContextMenuSubContent,
|
|
2869
|
+
ContextMenuSubTrigger,
|
|
2870
|
+
ContextMenuTrigger,
|
|
2326
2871
|
Dialog,
|
|
2327
2872
|
DialogClose,
|
|
2328
2873
|
DialogContent,
|
|
@@ -2360,6 +2905,9 @@ TableSkeleton.displayName = "TableSkeleton";
|
|
|
2360
2905
|
Progress,
|
|
2361
2906
|
RadioGroup,
|
|
2362
2907
|
RadioGroupItem,
|
|
2908
|
+
ResizableHandle,
|
|
2909
|
+
ResizablePanel,
|
|
2910
|
+
ResizablePanelGroup,
|
|
2363
2911
|
Select,
|
|
2364
2912
|
SelectContent,
|
|
2365
2913
|
SelectGroup,
|
|
@@ -2409,6 +2957,7 @@ TableSkeleton.displayName = "TableSkeleton";
|
|
|
2409
2957
|
TooltipContent,
|
|
2410
2958
|
TooltipProvider,
|
|
2411
2959
|
TooltipTrigger,
|
|
2960
|
+
TreeView,
|
|
2412
2961
|
alertVariants,
|
|
2413
2962
|
avatarVariants,
|
|
2414
2963
|
badgeVariants,
|