@columenlabs/lumen-ui 0.1.15 → 0.1.16
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/dist/lumen-drawer.js +1 -1
- package/dist/settings.js +1 -1
- package/dist/theme.css +11 -0
- package/dist/ui/alert-dialog.js +1 -1
- package/dist/ui/dialog.d.ts +1 -0
- package/dist/ui/dialog.js +3 -2
- package/dist/view-editor.js +1 -1
- package/package.json +2 -2
package/dist/lumen-drawer.js
CHANGED
|
@@ -22,7 +22,7 @@ export function LumenDrawer({ open, onClose, title, description, children, foote
|
|
|
22
22
|
// On a phone the drawer is a full screen and the footer a bar under the header, so the
|
|
23
23
|
// keyboard never covers its actions (Dialog does the same).
|
|
24
24
|
const foot = (_jsxs("footer", { "data-slot": "drawer-footer", className: "flex shrink-0 items-center gap-2 border-t bg-muted/50 px-4 py-2.5 max-md:order-first max-md:border-t-0 max-md:border-b", children: [footerStart && (_jsx("div", { className: "min-w-0 flex-1 truncate text-muted-foreground text-xs", children: footerStart })), _jsx("div", { className: "ml-auto flex items-center gap-2", children: footer ?? (_jsx(SheetClose, { asChild: true, children: _jsx(Button, { type: "button", size: "sm", variant: "outline", children: "Close" }) })) })] }));
|
|
25
|
-
return (_jsx(Sheet, { open: open, onOpenChange: (o) => !o && onClose(), modal: isMobile, children: isMobile ? (_jsxs(SheetContent, { side: "bottom", className: "max-h-[85svh] gap-0 overflow-hidden", children: [_jsx(SheetHeader, { className: "order-first shrink-0 border-b", children: head }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto pt-2", children: body }), foot] })) : (_jsx(SheetContent, { side: "right", showCloseButton: false,
|
|
25
|
+
return (_jsx(Sheet, { open: open, onOpenChange: (o) => !o && onClose(), modal: isMobile, children: isMobile ? (_jsxs(SheetContent, { side: "bottom", className: "max-h-[85svh] gap-0 overflow-hidden", children: [_jsx(SheetHeader, { className: "order-first shrink-0 border-b", children: head }), _jsx("div", { className: "end-fade min-h-0 flex-1 overflow-y-auto pt-2", children: body }), foot] })) : (_jsx(SheetContent, { side: "right", showCloseButton: false,
|
|
26
26
|
// The resize handle's grab zone is wider than the handle, so a drag can start on the
|
|
27
27
|
// overlay; the panels library marks that pointerdown handled, and then it doesn't close.
|
|
28
28
|
onPointerDownOutside: (e) => e.detail.originalEvent.defaultPrevented && e.preventDefault(), className: "pointer-events-none! gap-0 border-0 bg-transparent shadow-none data-[side=right]:left-0 data-[side=right]:w-auto data-[side=right]:border-l-0 data-[side=right]:sm:max-w-none", children: _jsxs(ResizablePanelGroup, { orientation: "horizontal", children: [_jsx(ResizablePanel, { minSize: "40%" }), _jsx(ResizableHandle, { withHandle: true, className: "pointer-events-auto" }), _jsx(ResizablePanel, { defaultSize: defaultSize, minSize: minSize, maxSize: maxSize, "data-slot": "lumen-drawer", className: "pointer-events-auto bg-popover shadow-lg", children: _jsxs("section", { className: "flex h-full flex-col overflow-hidden", children: [_jsxs("header", { className: "flex shrink-0 items-center gap-2 border-b px-4 py-3", children: [head, _jsx(SheetClose, { asChild: true, children: _jsx(IconButton, { icon: XIcon, label: "Close", className: "ml-auto" }) })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto pt-2", children: body }), foot] }) })] }) })) }));
|
package/dist/settings.js
CHANGED
|
@@ -177,5 +177,5 @@ export function LumenSettings({ open, section, onOpen, onClose, appLabel, profil
|
|
|
177
177
|
return (_jsx(ActionsScope, { children: (slot) => (_jsxs("div", { "data-settings-section": s.id, "data-whole": whole, "aria-labelledby": `settings-${s.id}-title`, className: whole
|
|
178
178
|
? 'flex flex-col gap-3'
|
|
179
179
|
: 'hidden flex-col gap-3 has-[[data-slot=setting-row]]:flex', children: [header(s, slot), _jsx(Separator, {}), _jsx(SearchContext.Provider, { value: whole ? '' : q, children: s.content })] })) }, s.id));
|
|
180
|
-
}), !found.length && (_jsxs("p", { className: "text-sm text-muted-foreground", children: ["No settings match \u201C", q, "\u201D."] }))] })) : (_jsx(ActionsScope, { children: (slot, footer) => (_jsxs("section", { "aria-labelledby": `settings-${current.id}-title`, className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [_jsxs("div", { className: "flex shrink-0 flex-col gap-3 px-4 pt-4 md:px-6 md:pt-6", children: [header(current, slot), _jsx(Separator, {})] }), _jsx("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto px-4 pt-3 pb-4 *:shrink-0 md:px-6", children: current.content }), _jsx("div", { ref: footer, "data-slot": "settings-footer", className: "flex min-h-12 shrink-0 items-center justify-end gap-2 border-t px-4 py-2 md:px-6", children: current.footer })] })) }, current.id))] }) }));
|
|
180
|
+
}), !found.length && (_jsxs("p", { className: "text-sm text-muted-foreground", children: ["No settings match \u201C", q, "\u201D."] }))] })) : (_jsx(ActionsScope, { children: (slot, footer) => (_jsxs("section", { "aria-labelledby": `settings-${current.id}-title`, className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [_jsxs("div", { className: "flex shrink-0 flex-col gap-3 px-4 pt-4 md:px-6 md:pt-6", children: [header(current, slot), _jsx(Separator, {})] }), _jsx("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto px-4 pt-3 pb-4 *:shrink-0 md:px-6 [&:has(+[data-slot=settings-footer]:empty)]:end-fade", children: current.content }), _jsx("div", { ref: footer, "data-slot": "settings-footer", className: "flex min-h-12 shrink-0 items-center justify-end gap-2 border-t px-4 py-2 empty:hidden md:px-6", children: current.footer })] })) }, current.id))] }) }));
|
|
181
181
|
}
|
package/dist/theme.css
CHANGED
|
@@ -331,6 +331,17 @@
|
|
|
331
331
|
background-position: calc(-1 * var(--wash-x, 0px)) calc(-1 * var(--wash-y, 0px));
|
|
332
332
|
mask-image: linear-gradient(to bottom, #000 calc(100% - var(--intro-fade)), transparent);
|
|
333
333
|
}
|
|
334
|
+
/* The end of a dialog's or drawer's scrolling body with no buttons under it: its last --end-fade
|
|
335
|
+
(--spacing(4) unless set) fades out, the same affordance as the sticky tab row's --intro-fade, so
|
|
336
|
+
content never stops at a hard edge. The element keeps at least that much padding at its end, so
|
|
337
|
+
its last row clears the fade once scrolled to the bottom. */
|
|
338
|
+
@utility end-fade {
|
|
339
|
+
mask-image: linear-gradient(
|
|
340
|
+
to bottom,
|
|
341
|
+
#000 calc(100% - var(--end-fade, calc(var(--spacing) * 4))),
|
|
342
|
+
transparent
|
|
343
|
+
);
|
|
344
|
+
}
|
|
334
345
|
@keyframes intro-page-in {
|
|
335
346
|
from {
|
|
336
347
|
opacity: 0;
|
package/dist/ui/alert-dialog.js
CHANGED
|
@@ -18,7 +18,7 @@ function AlertDialogOverlay({ className, ...props }) {
|
|
|
18
18
|
function AlertDialogContent({ className, size = 'default', ...props }) {
|
|
19
19
|
// On a phone it is a full screen pinned to the top, its footer a bar at the top (usePhoneScreen).
|
|
20
20
|
const style = usePhoneScreen(props.style);
|
|
21
|
-
return (_jsxs(AlertDialogPortal, { children: [_jsx(AlertDialogOverlay, {}), _jsx(AlertDialogPrimitive.Content, { "data-slot": "alert-dialog-content", "data-size": size, className: cn('data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-popover text-popover-foreground ring-foreground/10 gap-4 rounded-xl p-4 ring-1 duration-100 data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 outline-none max-md:inset-0 max-md:h-full max-md:w-full max-md:max-w-none! max-md:translate-x-0 max-md:translate-y-0 max-md:content-start max-md:overflow-y-auto max-md:rounded-none max-md:pt-[calc(1rem+env(safe-area-inset-top))] max-md:ring-0', className), ...props, style: style })] }));
|
|
21
|
+
return (_jsxs(AlertDialogPortal, { children: [_jsx(AlertDialogOverlay, {}), _jsx(AlertDialogPrimitive.Content, { "data-slot": "alert-dialog-content", "data-size": size, className: cn('data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-popover text-popover-foreground ring-foreground/10 gap-4 rounded-xl p-4 ring-1 duration-100 data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 outline-none max-md:inset-0 max-md:h-full max-md:w-full max-md:max-w-none! max-md:translate-x-0 max-md:translate-y-0 max-md:content-start max-md:overflow-y-auto max-md:rounded-none max-md:pt-[calc(1rem+env(safe-area-inset-top))] max-md:ring-0 max-md:end-fade', className), ...props, style: style })] }));
|
|
22
22
|
}
|
|
23
23
|
function AlertDialogHeader({ className, ...props }) {
|
|
24
24
|
return (_jsx("div", { "data-slot": "alert-dialog-header", className: cn('grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]', className), ...props }));
|
package/dist/ui/dialog.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ declare function DialogHeader({ className, ...props }: React.ComponentProps<'div
|
|
|
14
14
|
* footer bleed by `--dialog-pad`, the content's padding, so a dialog that changes its padding sets
|
|
15
15
|
* that variable (`[--dialog-pad:0px]`), never `p-0`, and they still meet its edges. */
|
|
16
16
|
declare const dialogBody = "-mx-(--dialog-pad) max-h-[60svh] min-h-0 overflow-y-auto px-(--dialog-pad) max-md:max-h-none max-md:overflow-visible";
|
|
17
|
+
/** With no footer under it the body reaches the dialog's bottom edge and fades into it (`end-fade`). */
|
|
17
18
|
declare function DialogBody({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
|
|
18
19
|
declare function DialogFooter({ className, showCloseButton, children, ...props }: React.ComponentProps<'div'> & {
|
|
19
20
|
showCloseButton?: boolean;
|
package/dist/ui/dialog.js
CHANGED
|
@@ -22,7 +22,7 @@ function DialogOverlay({ className, ...props }) {
|
|
|
22
22
|
function DialogContent({ className, children, showCloseButton = true, ...props }) {
|
|
23
23
|
// On a phone it is a full screen pinned to the top, its footer a bar at the top (usePhoneScreen).
|
|
24
24
|
const style = usePhoneScreen(props.style);
|
|
25
|
-
return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { "data-slot": "dialog-content", className: cn('fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-(--dialog-pad) text-sm [--dialog-pad:--spacing(4)] text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm max-md:inset-0 max-md:h-full max-md:max-h-none max-md:w-full max-md:max-w-none max-md:translate-x-0 max-md:translate-y-0 max-md:content-start max-md:overflow-y-auto max-md:rounded-none max-md:pt-[calc(var(--dialog-pad)+env(safe-area-inset-top))] max-md:ring-0 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95', className), ...props, style: style, children: [children, showCloseButton && (_jsx(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true, children: _jsxs(Button, { variant: "ghost", className: "absolute top-2 right-2 max-md:top-[calc(1.25rem+env(safe-area-inset-top))]", size: "icon-sm", children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }) }))] })] }));
|
|
25
|
+
return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { "data-slot": "dialog-content", className: cn('fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-(--dialog-pad) text-sm [--dialog-pad:--spacing(4)] text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm max-md:inset-0 max-md:h-full max-md:max-h-none max-md:w-full max-md:max-w-none max-md:translate-x-0 max-md:translate-y-0 max-md:content-start max-md:overflow-y-auto max-md:rounded-none max-md:pt-[calc(var(--dialog-pad)+env(safe-area-inset-top))] max-md:ring-0 max-md:end-fade max-md:[--end-fade:var(--dialog-pad)] data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95', className), ...props, style: style, children: [children, showCloseButton && (_jsx(DialogPrimitive.Close, { "data-slot": "dialog-close", asChild: true, children: _jsxs(Button, { variant: "ghost", className: "absolute top-2 right-2 max-md:top-[calc(1.25rem+env(safe-area-inset-top))]", size: "icon-sm", children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }) }))] })] }));
|
|
26
26
|
}
|
|
27
27
|
function DialogHeader({ className, ...props }) {
|
|
28
28
|
return (_jsx("div", { "data-slot": "dialog-header", className: cn('flex flex-col gap-2', className), ...props }));
|
|
@@ -32,8 +32,9 @@ function DialogHeader({ className, ...props }) {
|
|
|
32
32
|
* footer bleed by `--dialog-pad`, the content's padding, so a dialog that changes its padding sets
|
|
33
33
|
* that variable (`[--dialog-pad:0px]`), never `p-0`, and they still meet its edges. */
|
|
34
34
|
const dialogBody = '-mx-(--dialog-pad) max-h-[60svh] min-h-0 overflow-y-auto px-(--dialog-pad) max-md:max-h-none max-md:overflow-visible';
|
|
35
|
+
/** With no footer under it the body reaches the dialog's bottom edge and fades into it (`end-fade`). */
|
|
35
36
|
function DialogBody({ className, ...props }) {
|
|
36
|
-
return _jsx("div", { "data-slot": "dialog-body", className: cn(dialogBody, className), ...props });
|
|
37
|
+
return (_jsx("div", { "data-slot": "dialog-body", className: cn(dialogBody, 'last:-mb-(--dialog-pad) last:pb-(--dialog-pad) last:end-fade last:[--end-fade:var(--dialog-pad)]', className), ...props }));
|
|
37
38
|
}
|
|
38
39
|
function DialogFooter({ className, showCloseButton = false, children, ...props }) {
|
|
39
40
|
return (_jsxs("div", { "data-slot": "dialog-footer", className: cn('-mx-(--dialog-pad) -mb-(--dialog-pad) flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end max-md:order-first max-md:-mt-(--dialog-pad) max-md:mb-0 max-md:flex-row max-md:justify-end max-md:rounded-none max-md:border-t-0 max-md:border-b max-md:pr-12', className), ...props, children: [children, showCloseButton && (_jsx(DialogPrimitive.Close, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Close" }) }))] }));
|
package/dist/view-editor.js
CHANGED
|
@@ -653,7 +653,7 @@ export function ViewEditDialog({ open, onOpenChange, domain: pageDomain, config,
|
|
|
653
653
|
onOpenChange(false);
|
|
654
654
|
onDelete();
|
|
655
655
|
}) }) })), parsed && !parsed.success && (_jsxs("p", { id: "view-editor-check", tabIndex: -1, className: "px-3 text-xs text-destructive", children: [parsed.error.issues[0]?.path.join('.'), ": ", parsed.error.issues[0]?.message] }))] }));
|
|
656
|
-
return (_jsxs(Dialog, { open: open, onOpenChange: onOpenChange, children: [_jsxs(DialogContent, { "data-slot": "view-editor", showCloseButton: false, className: "flex h-[min(780px,calc(100svh-2rem))] flex-col gap-0 overflow-hidden p-0 max-md:h-svh max-md:max-w-full max-md:rounded-none max-md:ring-0 sm:max-w-6xl", children: [_jsx(DialogDescription, { className: "sr-only", children: "This widget's type, fields, settings, rows and controls, and the fields it can use." }), _jsxs("header", { className: "flex shrink-0 items-center gap-2 border-b px-3 py-2 md:px-4", children: [isMobile && (_jsx(DialogClose, { asChild: true, children: _jsx(IconButton, { icon: XIcon, label: "Close" }) })), _jsxs(DialogTitle, { className: "min-w-0 truncate text-sm font-semibold", children: ["Edit widget", ' ', _jsxs("span", { className: "font-normal text-muted-foreground", children: ["\u00B7 ", name.trim() || styleLabel(styleId)] })] }), _jsx("span", { className: "flex-1" }), !isMobile && (_jsx(DialogClose, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", children: [_jsx(XIcon, {}), "Cancel"] }) })), _jsx(SaveButton, { issues: issues, onSave: save })] }), isMobile ? (_jsxs(Tabs, { value: tab, onValueChange: (v) => setTab(v), className: "min-h-0 flex-1 gap-0 pt-2", children: [_jsxs(TabsList, { className: "mx-3 w-[calc(100%-1.5rem)]", children: [_jsxs(TabsTrigger, { value: "view", children: [_jsx(LayoutDashboardIcon, {}), "Widget"] }), _jsxs(TabsTrigger, { value: "fields", children: [_jsx(DatabaseIcon, {}), "Data"] })] }), _jsx(TabsContent, { value: "view", className: "min-h-0 overflow-y-auto px-2
|
|
656
|
+
return (_jsxs(Dialog, { open: open, onOpenChange: onOpenChange, children: [_jsxs(DialogContent, { "data-slot": "view-editor", showCloseButton: false, className: "flex h-[min(780px,calc(100svh-2rem))] flex-col gap-0 overflow-hidden p-0 max-md:h-svh max-md:max-w-full max-md:rounded-none max-md:ring-0 max-md:[--dialog-pad:0px] sm:max-w-6xl", children: [_jsx(DialogDescription, { className: "sr-only", children: "This widget's type, fields, settings, rows and controls, and the fields it can use." }), _jsxs("header", { className: "flex shrink-0 items-center gap-2 border-b px-3 py-2 md:px-4", children: [isMobile && (_jsx(DialogClose, { asChild: true, children: _jsx(IconButton, { icon: XIcon, label: "Close" }) })), _jsxs(DialogTitle, { className: "min-w-0 truncate text-sm font-semibold", children: ["Edit widget", ' ', _jsxs("span", { className: "font-normal text-muted-foreground", children: ["\u00B7 ", name.trim() || styleLabel(styleId)] })] }), _jsx("span", { className: "flex-1" }), !isMobile && (_jsx(DialogClose, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", children: [_jsx(XIcon, {}), "Cancel"] }) })), _jsx(SaveButton, { issues: issues, onSave: save })] }), isMobile ? (_jsxs(Tabs, { value: tab, onValueChange: (v) => setTab(v), className: "min-h-0 flex-1 gap-0 pt-2", children: [_jsxs(TabsList, { className: "mx-3 w-[calc(100%-1.5rem)]", children: [_jsxs(TabsTrigger, { value: "view", children: [_jsx(LayoutDashboardIcon, {}), "Widget"] }), _jsxs(TabsTrigger, { value: "fields", children: [_jsx(DatabaseIcon, {}), "Data"] })] }), _jsx(TabsContent, { value: "view", className: "end-fade min-h-0 overflow-y-auto px-2 pt-2 pb-[max(1rem,env(safe-area-inset-bottom))]", children: main }), _jsxs(TabsContent, { value: "fields", className: "end-fade min-h-0 overflow-y-auto px-3 pt-2 pb-4", children: [treeHint, tree] })] })) : (_jsxs("div", { className: "grid min-h-0 flex-1 grid-cols-[minmax(0,1fr)_360px]", children: [_jsx("section", { "aria-label": "Widget", className: "end-fade min-h-0 overflow-y-auto px-3 pt-2 pb-4", children: main }), _jsxs("aside", { "aria-label": "Data", className: "end-fade flex min-h-0 flex-col overflow-y-auto border-l bg-sidebar px-2 pt-2 pb-4", children: [treeHint, tree, _jsxs("p", { className: "mt-auto px-2 pt-4 text-xs text-muted-foreground", children: ["Agents change the same settings with", ' ', _jsx("code", { className: "font-mono", children: card ? 'custom_view_widget_write' : 'custom_view_write' }), "."] })] })] }))] }), _jsx(AddFormulaDialog, { open: addingFormula, onOpenChange: setAddingFormula, domain: withLinks, formulas: formulas, onAdd: (f) => {
|
|
657
657
|
setAddingFormula(false);
|
|
658
658
|
setDraft({
|
|
659
659
|
...draft,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Lumen: shared React components (frame, views, widgets, charts, drawers).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@codemirror/lang-javascript": "6.2.5",
|
|
42
42
|
"@codemirror/lang-json": "6.0.2",
|
|
43
43
|
"@codemirror/lang-sql": "6.10.0",
|
|
44
|
-
"@columenlabs/lumen-ui-types": "0.1.
|
|
44
|
+
"@columenlabs/lumen-ui-types": "0.1.16",
|
|
45
45
|
"@dnd-kit/core": "6.3.1",
|
|
46
46
|
"@dnd-kit/sortable": "10.0.0",
|
|
47
47
|
"@dnd-kit/utilities": "3.2.2",
|