@columenlabs/lumen-ui 0.4.2 → 0.4.4
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.
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
1
2
|
/** The visual viewport while a phone's keyboard covers part of the layout viewport. */
|
|
2
3
|
export interface KeyboardFit {
|
|
3
4
|
/** Top of what is visible, from the layout viewport's top (iOS pans the page to the focused field). */
|
|
@@ -8,8 +9,15 @@ export interface KeyboardFit {
|
|
|
8
9
|
below: number;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
|
-
* Where a fixed
|
|
12
|
-
* the layout viewport fixed elements use, so
|
|
13
|
-
* keyboard
|
|
12
|
+
* Where a fixed overlay must sit while the keyboard is open. iOS shrinks the visual viewport but not
|
|
13
|
+
* the layout viewport fixed elements use, so an overlay sized to the layout viewport runs under the
|
|
14
|
+
* keyboard. Undefined while no keyboard is up.
|
|
14
15
|
*/
|
|
15
16
|
export declare function useKeyboardFit(): KeyboardFit | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* The one phone rule for every overlay (Dialog, AlertDialog, a bottom Sheet): a full screen pinned to
|
|
19
|
+
* the top, its actions in a bar at the top, so the fields a person types in already sit high and the
|
|
20
|
+
* keyboard covers only what is below them. With the keyboard up the screen ends at the keyboard.
|
|
21
|
+
* The classes are `phoneScreen`; this gives the style.
|
|
22
|
+
*/
|
|
23
|
+
export declare function usePhoneScreen(style?: React.CSSProperties): React.CSSProperties | undefined;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { useIsMobile } from './use-mobile.js';
|
|
2
3
|
/**
|
|
3
|
-
* Where a fixed
|
|
4
|
-
* the layout viewport fixed elements use, so
|
|
5
|
-
* keyboard
|
|
4
|
+
* Where a fixed overlay must sit while the keyboard is open. iOS shrinks the visual viewport but not
|
|
5
|
+
* the layout viewport fixed elements use, so an overlay sized to the layout viewport runs under the
|
|
6
|
+
* keyboard. Undefined while no keyboard is up.
|
|
6
7
|
*/
|
|
7
8
|
export function useKeyboardFit() {
|
|
8
9
|
const [fit, setFit] = React.useState();
|
|
@@ -27,3 +28,14 @@ export function useKeyboardFit() {
|
|
|
27
28
|
}, []);
|
|
28
29
|
return fit;
|
|
29
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* The one phone rule for every overlay (Dialog, AlertDialog, a bottom Sheet): a full screen pinned to
|
|
33
|
+
* the top, its actions in a bar at the top, so the fields a person types in already sit high and the
|
|
34
|
+
* keyboard covers only what is below them. With the keyboard up the screen ends at the keyboard.
|
|
35
|
+
* The classes are `phoneScreen`; this gives the style.
|
|
36
|
+
*/
|
|
37
|
+
export function usePhoneScreen(style) {
|
|
38
|
+
const phone = useIsMobile();
|
|
39
|
+
const kb = useKeyboardFit();
|
|
40
|
+
return phone && kb ? { ...style, top: kb.top, height: kb.height, maxHeight: kb.height } : style;
|
|
41
|
+
}
|
package/dist/lumen-drawer.js
CHANGED
|
@@ -19,8 +19,10 @@ export function LumenDrawer({ open, onClose, title, description, children, foote
|
|
|
19
19
|
const body = _jsx("div", { className: "flex flex-col px-4 pb-4", children: children });
|
|
20
20
|
// Every drawer has a footer, styled like a dialog's: the body scrolls above
|
|
21
21
|
// it and always ends on a clear edge. Without actions of its own it offers Close.
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
// On a phone the drawer is a full screen and the footer a bar under the header, so the
|
|
23
|
+
// keyboard never covers its actions (Dialog does the same).
|
|
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,
|
|
24
26
|
// The resize handle's grab zone is wider than the handle, so a drag can start on the
|
|
25
27
|
// overlay; the panels library marks that pointerdown handled, and then it doesn't close.
|
|
26
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/ui/alert-dialog.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from '../lib/utils.js';
|
|
3
3
|
import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
|
|
4
|
+
import { usePhoneScreen } from '../hooks/use-keyboard-fit.js';
|
|
4
5
|
import { Button } from './button.js';
|
|
5
6
|
function AlertDialog({ ...props }) {
|
|
6
7
|
return _jsx(AlertDialogPrimitive.Root, { "data-slot": "alert-dialog", ...props });
|
|
@@ -15,13 +16,15 @@ function AlertDialogOverlay({ className, ...props }) {
|
|
|
15
16
|
return (_jsx(AlertDialogPrimitive.Overlay, { "data-slot": "alert-dialog-overlay", className: cn('data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50', className), ...props }));
|
|
16
17
|
}
|
|
17
18
|
function AlertDialogContent({ className, size = 'default', ...props }) {
|
|
18
|
-
|
|
19
|
+
// On a phone it is a full screen pinned to the top, its footer a bar at the top (usePhoneScreen).
|
|
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 })] }));
|
|
19
22
|
}
|
|
20
23
|
function AlertDialogHeader({ className, ...props }) {
|
|
21
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 }));
|
|
22
25
|
}
|
|
23
26
|
function AlertDialogFooter({ className, ...props }) {
|
|
24
|
-
return (_jsx("div", { "data-slot": "alert-dialog-footer", className: cn('bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4 flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end', className), ...props }));
|
|
27
|
+
return (_jsx("div", { "data-slot": "alert-dialog-footer", className: cn('bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4 flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end max-md:order-first max-md:-mt-4 max-md:mb-0 max-md:flex max-md:flex-row max-md:justify-end max-md:rounded-none max-md:border-t-0 max-md:border-b', className), ...props }));
|
|
25
28
|
}
|
|
26
29
|
function AlertDialogMedia({ className, ...props }) {
|
|
27
30
|
return (_jsx("div", { "data-slot": "alert-dialog-media", className: cn("bg-muted mb-2 inline-flex size-10 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6", className), ...props }));
|
package/dist/ui/dialog.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ declare function DialogHeader({ className, ...props }: React.ComponentProps<'div
|
|
|
13
13
|
* the focus rings of its fields are never cut by the scroll box. It and the
|
|
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
|
-
declare const dialogBody = "-mx-(--dialog-pad) max-h-[60svh] min-h-0 overflow-y-auto px-(--dialog-pad)";
|
|
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
17
|
declare function DialogBody({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
|
|
18
18
|
declare function DialogFooter({ className, showCloseButton, children, ...props }: React.ComponentProps<'div'> & {
|
|
19
19
|
showCloseButton?: boolean;
|
package/dist/ui/dialog.js
CHANGED
|
@@ -3,7 +3,7 @@ import { cn } from '../lib/utils.js';
|
|
|
3
3
|
import { Dialog as DialogPrimitive } from 'radix-ui';
|
|
4
4
|
import { Button } from './button.js';
|
|
5
5
|
import { XIcon } from 'lucide-react';
|
|
6
|
-
import {
|
|
6
|
+
import { usePhoneScreen } from '../hooks/use-keyboard-fit.js';
|
|
7
7
|
function Dialog({ ...props }) {
|
|
8
8
|
return _jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
9
9
|
}
|
|
@@ -20,12 +20,9 @@ function DialogOverlay({ className, ...props }) {
|
|
|
20
20
|
return (_jsx(DialogPrimitive.Overlay, { "data-slot": "dialog-overlay", className: cn('fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0', className), ...props }));
|
|
21
21
|
}
|
|
22
22
|
function DialogContent({ className, children, showCloseButton = true, ...props }) {
|
|
23
|
-
//
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
? { ...props.style, top: kb.top + kb.height / 2, maxHeight: kb.height - 16 }
|
|
27
|
-
: props.style;
|
|
28
|
-
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 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", size: "icon-sm", children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }) }))] })] }));
|
|
23
|
+
// On a phone it is a full screen pinned to the top, its footer a bar at the top (usePhoneScreen).
|
|
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" })] }) }))] })] }));
|
|
29
26
|
}
|
|
30
27
|
function DialogHeader({ className, ...props }) {
|
|
31
28
|
return (_jsx("div", { "data-slot": "dialog-header", className: cn('flex flex-col gap-2', className), ...props }));
|
|
@@ -34,12 +31,12 @@ function DialogHeader({ className, ...props }) {
|
|
|
34
31
|
* the focus rings of its fields are never cut by the scroll box. It and the
|
|
35
32
|
* footer bleed by `--dialog-pad`, the content's padding, so a dialog that changes its padding sets
|
|
36
33
|
* that variable (`[--dialog-pad:0px]`), never `p-0`, and they still meet its edges. */
|
|
37
|
-
const dialogBody = '-mx-(--dialog-pad) max-h-[60svh] min-h-0 overflow-y-auto px-(--dialog-pad)';
|
|
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';
|
|
38
35
|
function DialogBody({ className, ...props }) {
|
|
39
36
|
return _jsx("div", { "data-slot": "dialog-body", className: cn(dialogBody, className), ...props });
|
|
40
37
|
}
|
|
41
38
|
function DialogFooter({ className, showCloseButton = false, children, ...props }) {
|
|
42
|
-
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', className), ...props, children: [children, showCloseButton && (_jsx(DialogPrimitive.Close, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Close" }) }))] }));
|
|
39
|
+
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" }) }))] }));
|
|
43
40
|
}
|
|
44
41
|
function DialogTitle({ className, ...props }) {
|
|
45
42
|
return (_jsx(DialogPrimitive.Title, { "data-slot": "dialog-title", className: cn('font-heading text-base leading-none font-medium', className), ...props }));
|
package/dist/ui/sheet.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Dialog as SheetPrimitive } from 'radix-ui';
|
|
|
4
4
|
import { Button } from './button.js';
|
|
5
5
|
import { XIcon } from 'lucide-react';
|
|
6
6
|
import { useKeyboardFit } from '../hooks/use-keyboard-fit.js';
|
|
7
|
+
import { useIsMobile } from '../hooks/use-mobile.js';
|
|
7
8
|
function Sheet({ ...props }) {
|
|
8
9
|
return _jsx(SheetPrimitive.Root, { "data-slot": "sheet", ...props });
|
|
9
10
|
}
|
|
@@ -20,24 +21,27 @@ function SheetOverlay({ className, ...props }) {
|
|
|
20
21
|
return (_jsx(SheetPrimitive.Overlay, { "data-slot": "sheet-overlay", className: cn('bg-black/10 supports-backdrop-filter:backdrop-blur-xs fixed inset-y-0 left-0 right-(--assistant-docked,0px) z-50 duration-100 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0', className), ...props }));
|
|
21
22
|
}
|
|
22
23
|
function SheetContent({ className, children, side = 'right', showCloseButton = true, ...props }) {
|
|
23
|
-
//
|
|
24
|
-
// a
|
|
24
|
+
// On a phone a bottom sheet is a full screen pinned to the top, like a Dialog (usePhoneScreen), so
|
|
25
|
+
// the fields a person types in sit high. With the keyboard up a top or full screen sheet ends at
|
|
26
|
+
// the keyboard; a side sheet spans only the visible part.
|
|
25
27
|
const kb = useKeyboardFit();
|
|
28
|
+
const phone = useIsMobile();
|
|
29
|
+
const screen = side === 'top' || (side === 'bottom' && phone);
|
|
26
30
|
const style = !kb
|
|
27
31
|
? props.style
|
|
28
|
-
:
|
|
29
|
-
? { ...props.style,
|
|
30
|
-
: side === '
|
|
31
|
-
? { ...props.style,
|
|
32
|
+
: screen
|
|
33
|
+
? { ...props.style, top: kb.top, maxHeight: kb.height, height: kb.height }
|
|
34
|
+
: side === 'bottom'
|
|
35
|
+
? { ...props.style, bottom: kb.below, maxHeight: kb.height - 8 }
|
|
32
36
|
: { ...props.style, top: kb.top, height: kb.height };
|
|
33
|
-
return (_jsxs(SheetPortal, { children: [_jsx(SheetOverlay, {}), _jsxs(SheetPrimitive.Content, { "data-slot": "sheet-content", "data-side": side, className: cn('bg-popover text-popover-foreground fixed z-50 flex flex-col gap-4 bg-clip-padding text-sm shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-(--assistant-docked,0px) data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:animate-out data-closed:fade-out-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=right]:data-closed:slide-out-to-right-10 data-[side=top]:data-closed:slide-out-to-top-10', className), ...props, style: style,
|
|
37
|
+
return (_jsxs(SheetPortal, { children: [_jsx(SheetOverlay, {}), _jsxs(SheetPrimitive.Content, { "data-slot": "sheet-content", "data-side": side, className: cn('group/sheet bg-popover text-popover-foreground fixed z-50 flex flex-col gap-4 bg-clip-padding text-sm shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-(--assistant-docked,0px) data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:border-b max-md:data-[side=bottom]:top-0 max-md:data-[side=bottom]:h-full max-md:data-[side=bottom]:max-h-none max-md:data-[side=bottom]:rounded-none max-md:data-[side=bottom]:border-t-0 max-md:data-[side=bottom]:pt-[env(safe-area-inset-top)] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:animate-out data-closed:fade-out-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=right]:data-closed:slide-out-to-right-10 data-[side=top]:data-closed:slide-out-to-top-10', className), ...props, style: style,
|
|
34
38
|
// A click or focus in the docked the assistant panel leaves the sheet open, so the person can ask
|
|
35
39
|
// about what it shows (LumenShell).
|
|
36
40
|
onInteractOutside: (e) => {
|
|
37
41
|
if (e.target?.closest?.('[data-assistant-docked]'))
|
|
38
42
|
e.preventDefault();
|
|
39
43
|
props.onInteractOutside?.(e);
|
|
40
|
-
}, children: [children, showCloseButton && (_jsx(SheetPrimitive.Close, { "data-slot": "sheet-close", asChild: true, children: _jsxs(Button, { variant: "ghost", className: "absolute top-3 right-3", size: "icon-sm", children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }) }))] })] }));
|
|
44
|
+
}, children: [children, showCloseButton && (_jsx(SheetPrimitive.Close, { "data-slot": "sheet-close", asChild: true, children: _jsxs(Button, { variant: "ghost", className: "absolute top-3 right-3 max-md:group-data-[side=bottom]/sheet:top-[calc(0.75rem+env(safe-area-inset-top))]", size: "icon-sm", children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }) }))] })] }));
|
|
41
45
|
}
|
|
42
46
|
function SheetHeader({ className, ...props }) {
|
|
43
47
|
return (_jsx("div", { "data-slot": "sheet-header", className: cn('gap-0.5 p-4 flex flex-col', className), ...props }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
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.4.
|
|
44
|
+
"@columenlabs/lumen-ui-types": "0.4.4",
|
|
45
45
|
"@dnd-kit/core": "6.3.1",
|
|
46
46
|
"@dnd-kit/sortable": "10.0.0",
|
|
47
47
|
"@dnd-kit/utilities": "3.2.2",
|