@columenlabs/lumen-ui 0.1.244 → 0.1.246

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.
@@ -22,10 +22,10 @@ import { cardsOnScreen, kindName, pointAt, sectionsOnScreen, targetEl, textOf, }
22
22
  import { Alert, AlertDescription } from '../ui/alert.js';
23
23
  import { Button } from '../ui/button.js';
24
24
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible.js';
25
+ import { InputGroup, InputGroupAddon, InputGroupTextarea } from '../ui/input-group.js';
25
26
  import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover.js';
26
27
  import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '../ui/sheet.js';
27
28
  import { Spinner } from '../ui/spinner.js';
28
- import { Textarea } from '../ui/textarea.js';
29
29
  import { ChatImage } from './chat-image.js';
30
30
  import { chatMarkdown, chatTurns, copyMarkdown, turnMarkdown } from './copy.js';
31
31
  import { ImageCard, ImagePending, toolIs } from './image-card.js';
@@ -880,7 +880,7 @@ export function LumenComposer({ name, busy, queued, queue, canSteer = false, onS
880
880
  const r = sourceItems.get(o.value)?.();
881
881
  if (r)
882
882
  setRefs((p) => [...p, r]);
883
- }, onClose: () => setClosed(`${text}|${caret}`) })), quote && _jsx(QuoteLine, { quote: quote, onRemove: () => setQuote(null) }), images.length > 0 && (_jsx("div", { className: "mb-2 flex flex-wrap gap-1.5", "aria-label": "Images going with your message", children: images.map((img, i) => (_jsxs("span", { className: "relative", children: [_jsx("img", { src: imageUrl(img), alt: `Pasted ${i + 1}`, className: "size-12 rounded-md border object-cover" }), _jsx("button", { type: "button", "aria-label": `Remove image ${i + 1}`, className: "absolute -top-1.5 -right-1.5 grid size-4 place-items-center rounded-full border bg-background text-muted-foreground hover:text-foreground", onClick: () => setImages((p) => p.filter((_, j) => j !== i)), children: _jsx(XIcon, { className: "size-3" }) })] }, `${i}:${img.data.length}`))) })), (tierLabel || refs.length > 0) && (_jsxs("div", { className: "mb-2 flex flex-wrap gap-1", children: [tierLabel && (_jsx(ComposerChip, { sign: TIER, label: tierLabel, onRemove: () => setTier(null) })), refs.map((r, i) => (_jsx(ComposerChip, { sign: POINT, label: r.label, onRemove: () => setRefs((p) => p.filter((_, j) => j !== i)) }, `${r.kind}:${r.label}:${i}`)))] })), _jsxs("div", { className: "relative", children: [_jsx(Textarea, { ref: box, "aria-label": `Message ${name}`, placeholder: `Ask ${name}…${hints.length ? ` (${hints.join(' ')})` : ''}`, className: cn('max-h-48 min-h-11 resize-none', busy && text.trim() && canSteer ? 'pr-18' : 'pr-11', (canAttach || modes.length > 0) && 'pb-9'), value: text, disabled: disabled, onChange: (e) => {
883
+ }, onClose: () => setClosed(`${text}|${caret}`) })), quote && _jsx(QuoteLine, { quote: quote, onRemove: () => setQuote(null) }), images.length > 0 && (_jsx("div", { className: "mb-2 flex flex-wrap gap-1.5", "aria-label": "Images going with your message", children: images.map((img, i) => (_jsxs("span", { className: "relative", children: [_jsx("img", { src: imageUrl(img), alt: `Pasted ${i + 1}`, className: "size-12 rounded-md border object-cover" }), _jsx("button", { type: "button", "aria-label": `Remove image ${i + 1}`, className: "absolute -top-1.5 -right-1.5 grid size-4 place-items-center rounded-full border bg-background text-muted-foreground hover:text-foreground", onClick: () => setImages((p) => p.filter((_, j) => j !== i)), children: _jsx(XIcon, { className: "size-3" }) })] }, `${i}:${img.data.length}`))) })), (tierLabel || refs.length > 0) && (_jsxs("div", { className: "mb-2 flex flex-wrap gap-1", children: [tierLabel && (_jsx(ComposerChip, { sign: TIER, label: tierLabel, onRemove: () => setTier(null) })), refs.map((r, i) => (_jsx(ComposerChip, { sign: POINT, label: r.label, onRemove: () => setRefs((p) => p.filter((_, j) => j !== i)) }, `${r.kind}:${r.label}:${i}`)))] })), _jsxs(InputGroup, { children: [_jsx(InputGroupTextarea, { ref: box, "aria-label": `Message ${name}`, placeholder: `Ask ${name}…${hints.length ? ` (${hints.join(' ')})` : ''}`, className: "max-h-48 min-h-11", value: text, disabled: disabled, onChange: (e) => {
884
884
  setText(e.target.value);
885
885
  setCaret(e.target.selectionStart);
886
886
  }, onSelect: (e) => setCaret(e.currentTarget.selectionStart), onPaste: (e) => {
@@ -900,11 +900,11 @@ export function LumenComposer({ name, busy, queued, queue, canSteer = false, onS
900
900
  e.preventDefault();
901
901
  send(e.altKey ? 'queue' : undefined);
902
902
  }
903
- } }), (canAttach || modes.length > 0) && (_jsxs("div", { className: "absolute bottom-1.5 left-1.5 flex items-center gap-0.5", children: [canAttach && (_jsxs(_Fragment, { children: [_jsx(IconButton, { icon: PaperclipIcon, label: "Attach images", size: "icon-xs", disabled: disabled, onClick: () => filePick.current?.click() }), _jsx("input", { ref: filePick, type: "file", accept: "image/*", multiple: true, hidden: true, onChange: (e) => {
903
+ } }), _jsxs(InputGroupAddon, { align: "block-end", className: "gap-0.5 px-1.5 pb-1.5", children: [canAttach && (_jsxs(_Fragment, { children: [_jsx(IconButton, { icon: PaperclipIcon, label: "Attach images", size: "icon-xs", disabled: disabled, onClick: () => filePick.current?.click() }), _jsx("input", { ref: filePick, type: "file", accept: "image/*", multiple: true, hidden: true, onChange: (e) => {
904
904
  if (e.target.files)
905
905
  attach(e.target.files);
906
906
  e.target.value = '';
907
- } })] })), modes.map((md) => (_jsx(IconButton, { icon: md.icon, label: md.label, size: "icon-xs", variant: use === md.id ? 'secondary' : 'ghost', "aria-pressed": use === md.id, className: cn(use === md.id && 'text-primary'), disabled: disabled, onClick: () => setUse((u) => (u === md.id ? null : md.id)) }, md.id)))] })), _jsx("div", { className: "absolute right-1.5 bottom-1.5", children: busy && !text.trim() ? (_jsx(IconButton, { icon: SquareIcon, label: "Stop", variant: "outline", size: "icon-xs", onClick: onStop })) : busy ? (_jsxs("span", { className: "flex gap-1", children: [_jsx(IconButton, { icon: ListPlusIcon, label: canSteer ? 'Queue for after (⌥↩)' : 'Queue for after (↩)', variant: canSteer ? 'outline' : 'default', size: "icon-xs", disabled: disabled, onClick: () => send('queue') }), canSteer && (_jsx(IconButton, { icon: CornerDownRightIcon, label: "Steer now (\u21A9)", variant: "default", size: "icon-xs", disabled: disabled, onClick: () => send('steer') }))] })) : (_jsx(IconButton, { icon: ArrowUpIcon, label: "Send", variant: "default", size: "icon-xs", disabled: !text.trim() || disabled, onClick: () => send() })) })] })] }));
907
+ } })] })), modes.map((md) => (_jsx(IconButton, { icon: md.icon, label: md.label, size: "icon-xs", variant: use === md.id ? 'secondary' : 'ghost', "aria-pressed": use === md.id, className: cn(use === md.id && 'text-primary'), disabled: disabled, onClick: () => setUse((u) => (u === md.id ? null : md.id)) }, md.id))), _jsx("div", { className: "ml-auto", children: busy && !text.trim() ? (_jsx(IconButton, { icon: SquareIcon, label: "Stop", variant: "outline", size: "icon-xs", onClick: onStop })) : busy ? (_jsxs("span", { className: "flex gap-1", children: [_jsx(IconButton, { icon: ListPlusIcon, label: canSteer ? 'Queue for after (⌥↩)' : 'Queue for after (↩)', variant: canSteer ? 'outline' : 'default', size: "icon-xs", disabled: disabled, onClick: () => send('queue') }), canSteer && (_jsx(IconButton, { icon: CornerDownRightIcon, label: "Steer now (\u21A9)", variant: "default", size: "icon-xs", disabled: disabled, onClick: () => send('steer') }))] })) : (_jsx(IconButton, { icon: ArrowUpIcon, label: "Send", variant: "default", size: "icon-xs", disabled: !text.trim() || disabled, onClick: () => send() })) })] })] })] }));
908
908
  }
909
909
  /**
910
910
  * What waits above the box while an answer runs: steering messages until the answer reads them,
@@ -114,7 +114,6 @@ const wayTest = (k, plan = false) => k?.test
114
114
  }
115
115
  : null;
116
116
  /** A provider's mark: its initial on a tile. */
117
- const mark = (label) => _jsx(ConnectionLogo, { text: label.charAt(0) });
118
117
  /**
119
118
  * Whether the app lets this person use `w` of their own on `p` (the app's `ownWays`, the same
120
119
  * rule the server pays by). A way it does not allow never shows, even when one is still stored:
@@ -161,7 +160,7 @@ function OwnProviderKey({ client, p }) {
161
160
  onRemove: () => apply(`own:${p.id}`, () => client.ownKey(p.id, null), 'Key removed'),
162
161
  removeTitle: `Remove your ${p.label} key?`,
163
162
  });
164
- return (_jsx(LumenConnection, { id: p.id, name: p.label, logo: mark(p.label), ways: ways, use: p.use, onUse: (use) => apply(`use:${p.id}`, () => client.settings({ own_use: { [p.id]: use } })) }));
163
+ return (_jsx(LumenConnection, { id: p.id, name: p.label, ways: ways, use: p.use, onUse: (use) => apply(`use:${p.id}`, () => client.settings({ own_use: { [p.id]: use } })) }));
165
164
  }
166
165
  /** A person's own keys, one row a provider, and what they may spend on them. */
167
166
  function Providers({ client }) {
@@ -171,10 +170,7 @@ function Providers({ client }) {
171
170
  // is exactly what the server may pay with.
172
171
  const rows = s.providers.filter((p) => !p.own_ways || p.own_ways.length > 0);
173
172
  const ownSet = rows.some(ownUsable);
174
- return (_jsxs("div", { className: "flex flex-col", children: [_jsx(LumenExpandList, { children: rows.map((p) => (_jsx(OwnProviderKey, { client: client, p: p }, p.id))) }), ownSet && (_jsx(SettingField, { label: "Answers run on", info: "Your own key or plan first, with the shared credits behind it; or the shared credits first.", children: _jsx(LumenSelector, { label: "Answers run on", size: "sm", className: "w-44", value: s.pay, options: [
175
- { value: 'own', label: 'Your own first' },
176
- { value: 'app', label: 'Shared credits first' },
177
- ], onChange: (pay) => void apply('pay', () => client.settings({ pay: pay })) }) })), ownSet && (_jsx(SettingField, { label: "Your keys may spend", info: "On your keys, every provider together.", children: _jsx(CapInput, { label: "Your monthly cap", value: s.caps.own, onSave: (n) => void apply('own', () => client.ownCap(n)) }) })), ownSet && _jsx(OwnCapUse, { s: s }), _jsx(OwnKeyUsage, { client: client, always: ownSet })] }));
173
+ return (_jsxs("div", { className: "flex flex-col", children: [_jsx(LumenExpandList, { children: rows.map((p) => (_jsx(OwnProviderKey, { client: client, p: p }, p.id))) }), ownSet && (_jsx(SettingField, { label: "Answers run on", info: "Your own key or plan first, with the shared credits behind it; or the shared credits first.", children: _jsxs(ToggleGroup, { type: "single", variant: "outline", size: "sm", spacing: 0, value: s.pay, "aria-label": "Answers run on", onValueChange: (pay) => pay && void apply('pay', () => client.settings({ pay: pay })), children: [_jsx(ToggleGroupItem, { value: "own", children: "Your own first" }), _jsx(ToggleGroupItem, { value: "app", children: "Credits first" })] }) })), ownSet && (_jsx(SettingField, { label: "Your keys may spend", info: "On your keys, every provider together.", children: _jsx(CapInput, { label: "Your monthly cap", value: s.caps.own, onSave: (n) => void apply('own', () => client.ownCap(n)) }) })), ownSet && _jsx(OwnCapUse, { s: s }), _jsx(OwnKeyUsage, { client: client, always: ownSet })] }));
178
174
  } }));
179
175
  }
180
176
  /**
@@ -195,7 +191,7 @@ function OwnCapUse({ s }) {
195
191
  function SharedProviderKey({ client, p }) {
196
192
  const { apply, refresh } = useApply(client);
197
193
  const env = !p.app.set && !!p.app.from_env;
198
- return (_jsx(LumenConnection, { id: p.id, name: p.label, logo: mark(p.label), ways: [
194
+ return (_jsx(LumenConnection, { id: p.id, name: p.label, ways: [
199
195
  {
200
196
  id: 'key',
201
197
  label: 'Shared key',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@columenlabs/lumen-ui",
3
- "version": "0.1.244",
3
+ "version": "0.1.246",
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.244",
52
+ "@columenlabs/lumen-ui-types": "0.1.246",
53
53
  "@dnd-kit/core": "6.3.1",
54
54
  "@dnd-kit/sortable": "10.0.0",
55
55
  "@dnd-kit/utilities": "3.2.2",