@columenlabs/lumen-ui 0.1.304 → 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/assistant/copy.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ChatItem } from '@columenlabs/lumen-ui-types/assistant';
|
|
2
2
|
/** The whole chat, its title as the heading. */
|
|
3
3
|
export declare function chatMarkdown(title: string, items: ChatItem[], name: string): string;
|
|
4
4
|
/** One turn: a message and everything the assistant did for it. */
|
package/dist/assistant/copy.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// A chat as Markdown, for Copy chat and each turn's copy icon: every message, tool line and card as
|
|
2
|
+
// it shows, so a chat can be pasted into an issue, a doc or another agent.
|
|
3
|
+
import { stepLineText } from '@columenlabs/lumen-ui-types/assistant';
|
|
1
4
|
import { lumenToast } from '../lumen-toast.js';
|
|
2
5
|
/** The whole chat, its title as the heading. */
|
|
3
6
|
export function chatMarkdown(title, items, name) {
|
|
@@ -52,7 +55,7 @@ function itemMarkdown(i, depth, name) {
|
|
|
52
55
|
i.ms ? `${(i.ms / 1000).toFixed(1)} s` : '',
|
|
53
56
|
i.write ? i.write.status : '',
|
|
54
57
|
].filter(Boolean);
|
|
55
|
-
return `**${i.ok ? 'Tool' : 'Failed'}: ${i.title}** (${facts.join(', ')})${i.error ? `\n\nError: ${i.error}` : ''}`;
|
|
58
|
+
return `**${i.ok ? 'Tool' : 'Failed'}: ${stepLineText(i.title)}** (${facts.join(', ')})${i.error ? `\n\nError: ${i.error}` : ''}`;
|
|
56
59
|
}
|
|
57
60
|
case 'draft':
|
|
58
61
|
return [
|
|
@@ -4,7 +4,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
4
4
|
// (the person's messages, the answer as it streams, each tool call as a line, drafted changes as
|
|
5
5
|
// cards to Save or Dismiss, work handed to a higher tier in its own section); and the composer,
|
|
6
6
|
// with Stop, a queued message and the chat's cost and context under it.
|
|
7
|
-
import { ASSISTANT_IMAGES_MAX, ASSISTANT_IMAGE_CHARS, COMPACT_AT, } from '@columenlabs/lumen-ui-types/assistant';
|
|
7
|
+
import { ASSISTANT_IMAGES_MAX, ASSISTANT_IMAGE_CHARS, COMPACT_AT, stepLineParts, stepLineText, } from '@columenlabs/lumen-ui-types/assistant';
|
|
8
8
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|
9
9
|
import { ArrowUpIcon, CheckCheckIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ChevronUpIcon, CircleAlertIcon, CircleCheckIcon, CircleXIcon, CopyIcon, CornerDownRightIcon, CrosshairIcon, FileTextIcon, GlobeIcon, HandIcon, LightbulbIcon, ListPlusIcon, LoaderCircleIcon, MonitorIcon, PaperclipIcon, PencilIcon, PlusIcon, RefreshCwIcon, ReplyIcon, SearchIcon, SparklesIcon, SquareIcon, TriangleAlertIcon, Undo2Icon, WrenchIcon, XIcon, } from 'lucide-react';
|
|
10
10
|
import { Fragment, createContext, useContext, useEffect, useRef, useState, } from 'react';
|
|
@@ -464,7 +464,7 @@ function ToolStep({ step, live }) {
|
|
|
464
464
|
step.rows !== undefined ? `${step.rows} row${step.rows === 1 ? '' : 's'}` : '',
|
|
465
465
|
seconds(step.ms),
|
|
466
466
|
].filter(Boolean);
|
|
467
|
-
return (_jsxs("p", { "data-slot": "chat-step", "data-ok": ok, className: cn('flex min-w-0 items-center gap-1.5 text-xs', ok ? 'text-muted-foreground' : 'text-loss'), children: [live ? (_jsx(Spinner, { className: "size-3" })) : !ok ? (_jsx(CircleAlertIcon, { className: "size-3.5 shrink-0" })) : w ? (_jsx(PencilIcon, { className: "size-3.5 shrink-0" })) : (_jsx(WrenchIcon, { className: "size-3.5 shrink-0" })), _jsx("span", { className: "truncate", title: step.title, children: step.title }), !live && facts.length > 0 && (_jsx("span", { className: "shrink-0 tabular-nums", children: facts.join(' · ') })), (step.error || w?.error) && (_jsxs("span", { className: "truncate", title: step.error ?? w?.error, children: ["\u00B7 ", step.error ?? w?.error] })), w?.status === 'undone' ? (_jsx("span", { className: "shrink-0", children: "\u00B7 Undone" })) : (w?.undo &&
|
|
467
|
+
return (_jsxs("p", { "data-slot": "chat-step", "data-ok": ok, className: cn('flex min-w-0 items-center gap-1.5 text-xs', ok ? 'text-muted-foreground' : 'text-loss'), children: [live ? (_jsx(Spinner, { className: "size-3" })) : !ok ? (_jsx(CircleAlertIcon, { className: "size-3.5 shrink-0" })) : w ? (_jsx(PencilIcon, { className: "size-3.5 shrink-0" })) : (_jsx(WrenchIcon, { className: "size-3.5 shrink-0" })), _jsx("span", { className: "truncate", title: stepLineText(step.title), children: stepLineParts(step.title).map((part, i) => part.name ? (_jsx("span", { "data-step-name": true, className: cn('rounded px-1 font-medium', ok ? 'bg-primary/10 text-primary' : 'bg-loss/10'), children: part.text }, i)) : (part.text)) }), !live && facts.length > 0 && (_jsx("span", { className: "shrink-0 tabular-nums", children: facts.join(' · ') })), (step.error || w?.error) && (_jsxs("span", { className: "truncate", title: step.error ?? w?.error, children: ["\u00B7 ", step.error ?? w?.error] })), w?.status === 'undone' ? (_jsx("span", { className: "shrink-0", children: "\u00B7 Undone" })) : (w?.undo &&
|
|
468
468
|
undo && (_jsxs(Button, { size: "sm", variant: "ghost", className: "ml-auto h-6 shrink-0 px-2 text-xs", disabled: undoing, onClick: () => void take(), children: [undoing ? _jsx(Spinner, {}) : _jsx(Undo2Icon, {}), "Undo"] })))] }));
|
|
469
469
|
}
|
|
470
470
|
/** The arguments as short lines: `name: value`. */
|
|
@@ -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",
|