@columenlabs/lumen-ui 0.1.305 → 0.1.306
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-bottom-sheet.js +21 -5
- package/dist/theme.css +7 -0
- package/package.json +2 -2
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Dialog } from 'radix-ui';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { Drawer } from 'vaul';
|
|
5
|
+
import { useKeyboardFit } from './hooks/use-keyboard-fit.js';
|
|
5
6
|
import { cn } from './lib/utils.js';
|
|
6
7
|
/** A snap point in px against a screen `h` px tall. */
|
|
7
8
|
function px(s, h) {
|
|
@@ -27,11 +28,14 @@ function useSafeBottom() {
|
|
|
27
28
|
}, []);
|
|
28
29
|
return inset;
|
|
29
30
|
}
|
|
30
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* The screen's height, kept up to date: the layout viewport, which a phone's keyboard leaves alone
|
|
33
|
+
* (iOS shrinks `innerHeight` with the keyboard, which would shrink the sheet with it).
|
|
34
|
+
*/
|
|
31
35
|
function useScreenHeight() {
|
|
32
|
-
const [h, setH] = React.useState(() => typeof window === 'undefined' ? 800 :
|
|
36
|
+
const [h, setH] = React.useState(() => typeof window === 'undefined' ? 800 : document.documentElement.clientHeight);
|
|
33
37
|
React.useEffect(() => {
|
|
34
|
-
const on = () => setH(
|
|
38
|
+
const on = () => setH(document.documentElement.clientHeight);
|
|
35
39
|
window.addEventListener('resize', on);
|
|
36
40
|
return () => window.removeEventListener('resize', on);
|
|
37
41
|
}, []);
|
|
@@ -51,7 +55,14 @@ export function LumenBottomSheet({ snaps, snap, onSnap, title, children, classNa
|
|
|
51
55
|
const at = snaps.indexOf(snap);
|
|
52
56
|
// The sheet is as tall as the screen and slides down to its snap; what it holds fills only the
|
|
53
57
|
// part on screen, so a composer or footer at its bottom stays in view at every snap.
|
|
54
|
-
const
|
|
58
|
+
const rested = Math.min(h, Math.max(0, px(rest(snap), h)));
|
|
59
|
+
// Typing in the sheet with the keyboard up: the sheet ends at the keyboard, as tall as its snap or
|
|
60
|
+
// what is visible, so the field and the composer sit just above the keys (theme.css holds vaul's
|
|
61
|
+
// slide off while it does). A field above the sheet leaves the sheet where it rests.
|
|
62
|
+
const kb = useKeyboardFit();
|
|
63
|
+
const [typing, setTyping] = React.useState(false);
|
|
64
|
+
const lifted = typing && kb ? Math.min(rested, kb.height) : undefined;
|
|
65
|
+
const shown = lifted ?? rested;
|
|
55
66
|
return (_jsx(Drawer.Root, { open: true, modal: false, dismissible: false, handleOnly: true, snapPoints: rests, activeSnapPoint: rests[at] ?? rest(snap), setActiveSnapPoint: (s) => {
|
|
56
67
|
const i = s == null ? -1 : rests.indexOf(s);
|
|
57
68
|
const next = snaps[i];
|
|
@@ -59,5 +70,10 @@ export function LumenBottomSheet({ snaps, snap, onSnap, title, children, classNa
|
|
|
59
70
|
onSnap(next);
|
|
60
71
|
}, children: _jsx(Dialog.Root, { open: true, modal: false, onOpenChange: () => { }, children: _jsx(Drawer.Portal, { children: _jsxs(Drawer.Content, { "data-slot": "lumen-bottom-sheet", "aria-describedby": undefined,
|
|
61
72
|
// Focus stays where the person was: the sheet is always there, opening it is not a move.
|
|
62
|
-
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
73
|
+
onOpenAutoFocus: (e) => e.preventDefault(), onFocus: () => setTyping(true), onBlur: (e) => {
|
|
74
|
+
if (!e.currentTarget.contains(e.relatedTarget))
|
|
75
|
+
setTyping(false);
|
|
76
|
+
}, "data-lifted": lifted === undefined ? undefined : '', style: lifted === undefined || !kb
|
|
77
|
+
? undefined
|
|
78
|
+
: { top: kb.top + kb.height - lifted, bottom: 'auto', height: lifted }, className: cn('fixed inset-x-0 bottom-0 z-40 flex h-dvh flex-col rounded-t-2xl border-t bg-popover text-popover-foreground shadow-[0_-4px_16px_rgb(0_0_0/0.15)] outline-none', className), children: [_jsx(Drawer.Title, { className: "sr-only", children: title }), _jsxs("div", { className: "flex min-h-0 flex-col overflow-hidden", style: { height: shown }, children: [_jsx(Drawer.Handle, { "aria-label": "Drag to resize", className: "mx-auto! my-2! h-1! w-9! shrink-0 rounded-full! bg-border! opacity-100!" }), _jsx("div", { className: cn('flex min-h-0 flex-1 flex-col', lifted === undefined && 'pb-[env(safe-area-inset-bottom)]'), children: children })] })] }) }) }) }));
|
|
63
79
|
}
|
package/dist/theme.css
CHANGED
|
@@ -974,3 +974,10 @@ body[data-spotlight="nav"] [data-spotlit] {
|
|
|
974
974
|
display: none;
|
|
975
975
|
}
|
|
976
976
|
}
|
|
977
|
+
|
|
978
|
+
/* LumenBottomSheet while the person types in it with the keyboard up: it is placed at the keyboard
|
|
979
|
+
(lumen-bottom-sheet.tsx), so vaul's slide to its snap, set inline, stays off until the keys go. */
|
|
980
|
+
[data-slot="lumen-bottom-sheet"][data-lifted] {
|
|
981
|
+
transform: none !important;
|
|
982
|
+
transition: none !important;
|
|
983
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.306",
|
|
4
4
|
"description": "Lumen: shared React components (frame, views, widgets, charts, drawers).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@codemirror/lang-javascript": "6.2.5",
|
|
50
50
|
"@codemirror/lang-json": "6.0.2",
|
|
51
51
|
"@codemirror/lang-sql": "6.10.0",
|
|
52
|
-
"@columenlabs/lumen-ui-types": "0.1.
|
|
52
|
+
"@columenlabs/lumen-ui-types": "0.1.306",
|
|
53
53
|
"@dnd-kit/core": "6.3.1",
|
|
54
54
|
"@dnd-kit/sortable": "10.0.0",
|
|
55
55
|
"@dnd-kit/utilities": "3.2.2",
|