@columenlabs/lumen-ui 0.1.1 → 0.1.2

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.
Files changed (65) hide show
  1. package/README.md +1 -1
  2. package/dist/assistant-panel.js +1 -1
  3. package/dist/coverage-calendar-map.js +1 -1
  4. package/dist/coverage-cells.d.ts +2 -2
  5. package/dist/coverage-map.js +4 -10
  6. package/dist/details-table.js +1 -5
  7. package/dist/form-issues.js +1 -1
  8. package/dist/frame-script.js +1 -1
  9. package/dist/growth-chart.d.ts +9 -9
  10. package/dist/joins.d.ts +4 -3
  11. package/dist/joins.js +1 -1
  12. package/dist/lumen-code.js +1 -5
  13. package/dist/lumen-drawer.js +1 -3
  14. package/dist/lumen-filter.js +5 -13
  15. package/dist/lumen-grid.js +2 -4
  16. package/dist/lumen-layout.js +1 -1
  17. package/dist/lumen-links.d.ts +1 -1
  18. package/dist/lumen-selector.js +1 -1
  19. package/dist/lumen-source.js +2 -4
  20. package/dist/lumen-tab-drawer.js +1 -1
  21. package/dist/lumen-toast.d.ts +4 -4
  22. package/dist/lumen-view-card.js +1 -1
  23. package/dist/lumen-view.js +2 -4
  24. package/dist/lumen-widget.d.ts +170 -170
  25. package/dist/lumen-widget.js +4 -8
  26. package/dist/market/indicator-picker.js +1 -1
  27. package/dist/market/live.d.ts +1 -1
  28. package/dist/market/lumen-chart.js +1 -1
  29. package/dist/market/price-chart.d.ts +10 -10
  30. package/dist/nav.js +1 -1
  31. package/dist/notifications.js +1 -3
  32. package/dist/overview.js +1 -1
  33. package/dist/page.js +1 -1
  34. package/dist/pager.js +1 -1
  35. package/dist/prefs.d.ts +25 -25
  36. package/dist/schedules.js +1 -1
  37. package/dist/settings.js +1 -3
  38. package/dist/shell.js +1 -1
  39. package/dist/summary-cards.js +2 -6
  40. package/dist/symbol-sheet.js +1 -1
  41. package/dist/tasks.d.ts +1 -1
  42. package/dist/tasks.js +1 -1
  43. package/dist/tile.js +2 -4
  44. package/dist/ui/badge.d.ts +1 -1
  45. package/dist/ui/button.d.ts +2 -2
  46. package/dist/ui/chart.d.ts +2 -2
  47. package/dist/ui/chart.js +2 -5
  48. package/dist/ui/field.d.ts +1 -1
  49. package/dist/ui/input-group.d.ts +2 -2
  50. package/dist/ui/item.d.ts +3 -3
  51. package/dist/ui/sidebar.d.ts +1 -1
  52. package/dist/ui/sidebar.js +1 -1
  53. package/dist/ui/toggle.d.ts +1 -1
  54. package/dist/view-edit-cell.js +1 -4
  55. package/dist/view-editor.js +1 -1
  56. package/dist/view-formulas.d.ts +1 -1
  57. package/dist/view-model.d.ts +15 -15
  58. package/dist/whats-new.js +1 -1
  59. package/dist/widget-settings.d.ts +139 -139
  60. package/dist/widget-settings.js +4 -4
  61. package/dist/widget-thumbs.d.ts +1 -1
  62. package/dist/widget-thumbs.js +1 -1
  63. package/dist/workspace-keys.d.ts +1 -1
  64. package/dist/workspaces.js +1 -1
  65. package/package.json +5 -5
package/README.md CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  Lumen's components: the app frame (`LumenShell`), pages and views (`LumenLayout`, `LumenView`, `LumenTable`, `LumenWidget`, `LumenCard`), charts (`LumenChart`), `LumenDrawer`, `LumenSelector`, the shadcn parts under `ui/*` and one `theme.css`. Its types are in `@columenlabs/lumen-ui-types`.
4
4
 
5
- See the [Lumen README](https://github.com/columenlabs/lumen#readme) for install and use. MIT.
5
+ See the [Lumen README](https://github.com/columenlabs/lumen-ui#readme) for install and use. MIT.
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // LumenAssistant's frame (was the assistant panel's): what any app's AI assistant sits
3
3
  // in, with nothing of the assistant itself. Docked right of the page on desktop (drag its left edge
4
4
  // for ASSISTANT_WIDTH, never past half the window), a full-height sheet on phone; the header's ✦
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { CalendarDaysIcon } from 'lucide-react';
3
3
  import { useLayoutEffect, useMemo, useRef, useState } from 'react';
4
4
  import { CoverageCell, CoverageLegend, CoverageTip } from './coverage-cells.js';
@@ -27,7 +27,7 @@ export declare function CoverageLegend({ levels, hint }: {
27
27
  * cell made a 100-row map 13,000 tooltips, seconds per render). `label` is the
28
28
  * accessible name and the tooltip's first line; `tip` marks the cell for the shared tooltip.
29
29
  */
30
- export declare const CoverageCell: import("react").NamedExoticComponent<{
30
+ export declare const CoverageCell: import("react").MemoExoticComponent<({ level, label, tip, picked, disabled, pickable, onClick, className, }: {
31
31
  level: CoverageLevel;
32
32
  label: string;
33
33
  /** What `CoverageTip` hands back to its `content` for this cell. */
@@ -38,7 +38,7 @@ export declare const CoverageCell: import("react").NamedExoticComponent<{
38
38
  pickable?: boolean;
39
39
  onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
40
40
  className?: string;
41
- }>;
41
+ }) => import("react").JSX.Element>;
42
42
  /**
43
43
  * The one tooltip of a coverage map: it follows the cell under the pointer or keyboard focus inside
44
44
  * `children` (any element with `data-cell`) and shows `content` for it. Hovering re-renders only
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Link } from '@tanstack/react-router';
3
3
  import { Grid3x3Icon, ListPlusIcon, XIcon } from 'lucide-react';
4
4
  import { isValidElement, memo, useLayoutEffect, useMemo, useRef, useState, } from 'react';
@@ -148,9 +148,7 @@ const SUMMARY_WIDTH = {
148
148
  };
149
149
  /** A grid-shaped skeleton: label column plus empty cells, so nothing jumps when data lands. */
150
150
  function GridSkeleton({ rows = 8 }) {
151
- return (_jsx("div", { "aria-busy": "true", "aria-label": "Loading", className: "flex flex-col gap-[5px] py-1", children: Array.from({ length: rows }, (_, i) => (
152
- // biome-ignore lint/suspicious/noArrayIndexKey: static placeholders
153
- _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Skeleton, { className: "h-4 w-16 shrink-0" }), _jsx(Skeleton, { className: "h-[18px] flex-1" })] }, i))) }));
151
+ return (_jsx("div", { "aria-busy": "true", "aria-label": "Loading", className: "flex flex-col gap-[5px] py-1", children: Array.from({ length: rows }, (_, i) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Skeleton, { className: "h-4 w-16 shrink-0" }), _jsx(Skeleton, { className: "h-[18px] flex-1" })] }, i))) }));
154
152
  }
155
153
  /** `symbols`, `series`: the row title as a count noun. */
156
154
  /** The narrowest a block gets before the map scrolls sideways. */
@@ -321,9 +319,7 @@ export function LumenCoverageMap({ source, title, icon = Grid3x3Icon, rows: rowS
321
319
  const grid = {
322
320
  gridTemplateColumns: `${mobile ? '2.75rem' : '4rem'} repeat(12, minmax(${mobile ? '14px' : '18px'}, 1fr)) ${sumCols}`,
323
321
  };
324
- body = (
325
- // biome-ignore lint/a11y/useKeyWithClickEvents: each cell is a button; this only routes its click.
326
- _jsxs("div", { className: "grid items-center gap-[3px]", style: grid, onClick: onCellClick, children: [_jsx("span", { className: "text-xs text-muted-foreground", children: "Year" }), MON.map((m, i) => (_jsx("span", { className: "text-xs text-muted-foreground", children: mobile ? (i % 3 === 0 ? m : '') : m }, m))), sums.map((s) => (_jsx("span", { className: "pl-3 text-right text-xs text-muted-foreground", children: s === 'rows' ? rowsHead : SUMMARY_HEAD[s] }, s))), years.map((y) => {
322
+ body = (_jsxs("div", { className: "grid items-center gap-[3px]", style: grid, onClick: onCellClick, children: [_jsx("span", { className: "text-xs text-muted-foreground", children: "Year" }), MON.map((m, i) => (_jsx("span", { className: "text-xs text-muted-foreground", children: mobile ? (i % 3 === 0 ? m : '') : m }, m))), sums.map((s) => (_jsx("span", { className: "pl-3 text-right text-xs text-muted-foreground", children: s === 'rows' ? rowsHead : SUMMARY_HEAD[s] }, s))), years.map((y) => {
327
323
  let have = 0;
328
324
  let expected = 0;
329
325
  return [
@@ -367,9 +363,7 @@ export function LumenCoverageMap({ source, title, icon = Grid3x3Icon, rows: rowS
367
363
  }
368
364
  const look = { mobile, groupBy, select, sums, drilled, link: rowSpec.link };
369
365
  let group;
370
- body = (
371
- // biome-ignore lint/a11y/useKeyWithClickEvents: each cell is a button; this only routes its click.
372
- _jsxs("div", { className: "grid min-w-min items-center gap-[3px]", style: grid, onClick: onCellClick, children: [_jsx("span", { className: "sticky left-0 z-1 bg-card text-xs text-muted-foreground", children: mobile ? '' : rowSpec.title }), cols.map((k) => (_jsx("span", { className: "num h-4 overflow-visible text-[11px] whitespace-nowrap text-muted-foreground", children: headLabel(k, block, cols.length) }, k))), sums.map((s) => (_jsx("span", { className: "pl-3 text-right text-xs text-muted-foreground", children: s === 'rows' ? rowsHead : SUMMARY_HEAD[s] }, s))), rowList.flatMap((r) => {
366
+ body = (_jsxs("div", { className: "grid min-w-min items-center gap-[3px]", style: grid, onClick: onCellClick, children: [_jsx("span", { className: "sticky left-0 z-1 bg-card text-xs text-muted-foreground", children: mobile ? '' : rowSpec.title }), cols.map((k) => (_jsx("span", { className: "num h-4 overflow-visible text-[11px] whitespace-nowrap text-muted-foreground", children: headLabel(k, block, cols.length) }, k))), sums.map((s) => (_jsx("span", { className: "pl-3 text-right text-xs text-muted-foreground", children: s === 'rows' ? rowsHead : SUMMARY_HEAD[s] }, s))), rowList.flatMap((r) => {
373
367
  const out = [];
374
368
  const shut = groupBy && folds.has(foldKey + (r.group ?? ''));
375
369
  if (groupBy && r.group !== group) {
@@ -5,11 +5,7 @@ export function DetailsTable({ head, rows, foot }) {
5
5
  const marked = head.findIndex((h) => h.grow);
6
6
  const grow = marked >= 0 ? marked : head.length - 1;
7
7
  const cell = (i) => cn('num', head[i]?.right && 'text-right', i !== grow && 'w-px');
8
- return (_jsx("div", { className: "-mx-1 overflow-x-auto overflow-y-hidden rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsx(TableRow, { children: head.map((h, i) => (_jsx(TableHead, { className: cn(h.right && 'text-right', i !== grow && 'w-px'), children: h.label }, h.label))) }) }), _jsx(TableBody, { children: rows.map((r) => (_jsx(TableRow, { children: r.cells.map((c, i) => (
9
- // biome-ignore lint/suspicious/noArrayIndexKey: cells are positional
10
- _jsx(TableCell, { className: cell(i), children: c }, i))) }, r.key))) }), foot && (_jsx(TableFooter, { children: _jsx(TableRow, { children: foot.map((c, i) => (
11
- // biome-ignore lint/suspicious/noArrayIndexKey: cells are positional
12
- _jsx(TableCell, { className: cell(i), children: c }, i))) }) }))] }) }));
8
+ return (_jsx("div", { className: "-mx-1 overflow-x-auto overflow-y-hidden rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsx(TableRow, { children: head.map((h, i) => (_jsx(TableHead, { className: cn(h.right && 'text-right', i !== grow && 'w-px'), children: h.label }, h.label))) }) }), _jsx(TableBody, { children: rows.map((r) => (_jsx(TableRow, { children: r.cells.map((c, i) => (_jsx(TableCell, { className: cell(i), children: c }, i))) }, r.key))) }), foot && (_jsx(TableFooter, { children: _jsx(TableRow, { children: foot.map((c, i) => (_jsx(TableCell, { className: cell(i), children: c }, i))) }) }))] }) }));
13
9
  }
14
10
  /** Facts as a two-row table: the labels as the header, the values under them. */
15
11
  export function FactsTable({ items }) {
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // Save with issues: a Save that cannot go yet says why. Beside it a chip
3
3
  // counts what needs fixing and lists it; Save, and each line of the list, takes the person to the
4
4
  // issue: the editor opens its section or tab (`reveal`), then the field scrolls into view, takes
@@ -1,4 +1,4 @@
1
- import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3
3
  import { PlayIcon, RotateCcwIcon, WrapTextIcon } from 'lucide-react';
4
4
  import { useEffect, useMemo, useState } from 'react';
@@ -16,17 +16,17 @@ export type Series = {
16
16
  points: [string, number][];
17
17
  };
18
18
  export declare const KEY_DATE_KINDS: readonly [{
19
- readonly kind: "fomc";
20
- readonly label: "FOMC";
21
- readonly color: "var(--key-date-fomc)";
19
+ readonly kind: 'fomc';
20
+ readonly label: 'FOMC';
21
+ readonly color: 'var(--key-date-fomc)';
22
22
  }, {
23
- readonly kind: "cpi";
24
- readonly label: "CPI";
25
- readonly color: "var(--key-date-cpi)";
23
+ readonly kind: 'cpi';
24
+ readonly label: 'CPI';
25
+ readonly color: 'var(--key-date-cpi)';
26
26
  }, {
27
- readonly kind: "jobs";
28
- readonly label: "Jobs";
29
- readonly color: "var(--key-date-jobs)";
27
+ readonly kind: 'jobs';
28
+ readonly label: 'Jobs';
29
+ readonly color: 'var(--key-date-jobs)';
30
30
  }];
31
31
  export type KeyDateKind = (typeof KEY_DATE_KINDS)[number]['kind'];
32
32
  /** A thin vertical line on the chart; its label shows in the tooltip. */
package/dist/joins.d.ts CHANGED
@@ -57,9 +57,10 @@ export interface JoinAction {
57
57
  export declare const asOf: (at: string) => string;
58
58
  /** Your data: the person's own columns. */
59
59
  export declare const YOURS_COLOR = "var(--origin-yours)";
60
+ declare const recipeId: (id: string) => string;
60
61
  /** A frame's group name on a card: `Assistant · Targets`, or `Yours · Notes` for the person's own. */
61
- export declare const frameLabel: (meta: Pick<FrameMeta, "name" | "origin">, assistant?: string) => string;
62
- export declare const frameColor: (meta: Pick<FrameMeta, "origin">) => "var(--origin-assistant)" | "var(--origin-yours)";
62
+ export declare const frameLabel: (meta: Pick<FrameMeta, 'name' | 'origin'>, assistant?: string) => string;
63
+ export declare const frameColor: (meta: Pick<FrameMeta, 'origin'>) => "var(--origin-assistant)" | "var(--origin-yours)";
63
64
  /** The hand-edited cells of a frame, as `column\u0000key` (or `column\u0000#row`). */
64
65
  export declare function editedCells(data: FrameData | undefined): Set<string>;
65
66
  export declare const editedKey: (column: string, key: string | number) => string;
@@ -79,7 +80,7 @@ export declare function useYourData(api: string | null): import("@tanstack/react
79
80
  column: YourColumn;
80
81
  }, unknown>;
81
82
  /** A linked frame's group id in a card's field tree (`recipe:fr_…`). */
82
- export declare const frameGroupId: (id: string) => string;
83
+ export declare const frameGroupId: typeof recipeId;
83
84
  /**
84
85
  * Edit widget's draft of `config.frames`: `domain` (the card's, joined with
85
86
  * its saved frames) with the frames `ids` lists, reading the ones it lacks and dropping the rest.
package/dist/joins.js CHANGED
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { CATALOG, FRAME_LINK, catalogKeys, catalogTables, linkable, } from '@columenlabs/lumen-ui-types/catalog';
3
3
  // Joins: the registry's
4
4
  // join fields, attached to any card's rows by the keys they carry. A domain says how to read a
@@ -71,9 +71,5 @@ export function LumenCode({ code, lang, wrap = false, lineNumbers = false, heade
71
71
  setCopied(true);
72
72
  setTimeout(() => setCopied(false), 1500);
73
73
  }, () => toast.error("Couldn't copy the code"));
74
- return (_jsxs("div", { "data-slot": "lumen-code", "data-highlighted": tokens ? 'true' : 'false', className: cn('lumen-code min-w-0 text-xs leading-relaxed', wrap && 'lumen-code-wrap', lineNumbers && 'lumen-code-numbers', header && 'rounded-lg border bg-muted/40', className), children: [header && (_jsxs("div", { className: "flex h-7 items-center justify-between border-b pr-1 pl-3", children: [_jsx("span", { className: "font-mono text-xs text-muted-foreground", children: lang || 'text' }), _jsx(IconButton, { icon: copied ? CheckIcon : CopyIcon, label: copied ? 'Copied' : 'Copy code', size: "icon-xs", onClick: copy })] })), _jsx("pre", { className: "overflow-x-auto", children: _jsx("code", { children: lines.map((line, i) => (
75
- // biome-ignore lint/suspicious/noArrayIndexKey: lines have no other identity
76
- _jsxs("span", { className: "line", children: [line.map((t, j) => (
77
- // biome-ignore lint/suspicious/noArrayIndexKey: tokens have no other identity
78
- _jsx("span", { style: t.htmlStyle, children: t.content }, j))), '\n'] }, i))) }) })] }));
74
+ return (_jsxs("div", { "data-slot": "lumen-code", "data-highlighted": tokens ? 'true' : 'false', className: cn('lumen-code min-w-0 text-xs leading-relaxed', wrap && 'lumen-code-wrap', lineNumbers && 'lumen-code-numbers', header && 'rounded-lg border bg-muted/40', className), children: [header && (_jsxs("div", { className: "flex h-7 items-center justify-between border-b pr-1 pl-3", children: [_jsx("span", { className: "font-mono text-xs text-muted-foreground", children: lang || 'text' }), _jsx(IconButton, { icon: copied ? CheckIcon : CopyIcon, label: copied ? 'Copied' : 'Copy code', size: "icon-xs", onClick: copy })] })), _jsx("pre", { className: "overflow-x-auto", children: _jsx("code", { children: lines.map((line, i) => (_jsxs("span", { className: "line", children: [line.map((t, j) => (_jsx("span", { style: t.htmlStyle, children: t.content }, j))), '\n'] }, i))) }) })] }));
79
75
  }
@@ -20,9 +20,7 @@ export function LumenDrawer({ open, onClose, title, description, children, foote
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
22
  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", 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" }) })) })] }));
23
- return (
24
- // Not modal on desktop: the assistant, docked beside it, stays usable while the drawer is open.
25
- _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: "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,
23
+ 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: "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,
26
24
  // The resize handle's grab zone is wider than the handle, so a drag can start on the
27
25
  // overlay; the panels library marks that pointerdown handled, and then it doesn't close.
28
26
  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] }) })] }) })) }));
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { CONTAINS_KEY, meetsNumber } from '@columenlabs/lumen-ui-types/views';
3
3
  // The one filter box every view uses, redone after p2e's:
4
4
  // one chip per field in the sans face, `Account IRA, Roth ×`, included or excluded as a whole
@@ -217,9 +217,7 @@ function NumberCondition({ label, current, tall, count, onSet, }) {
217
217
  };
218
218
  const box = cn('min-w-0 flex-1 px-2 tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none', tall ? 'h-10 text-base' : 'h-8 text-sm');
219
219
  const ok = isNumber(a) && (op !== 'between' || isNumber(b));
220
- return (
221
- // Keys stay here: the menu would take Enter and the arrows.
222
- _jsxs("div", { className: "flex flex-col gap-1.5 px-2 py-1", onKeyDown: (e) => {
220
+ return (_jsxs("div", { className: "flex flex-col gap-1.5 px-2 py-1", onKeyDown: (e) => {
223
221
  e.stopPropagation();
224
222
  if (e.key === 'Enter')
225
223
  e.preventDefault();
@@ -466,17 +464,13 @@ export function LumenTokenizedFilter({ filter, placeholder = 'Filter…', label
466
464
  };
467
465
  const activeField = active ? fieldOf(active) : undefined;
468
466
  const activeChip = active ? chipOf(active) : undefined;
469
- const menu = activeField ? (
470
- // One field: Include or Exclude, then its values ticked.
471
- _jsxs(_Fragment, { children: [_jsxs(CommandGroup, { className: "px-1 py-0.5", children: [_jsxs("div", { className: "flex items-center gap-1 px-1 py-1", children: [_jsx(Button, { variant: "ghost", size: "icon-xs", "aria-label": "All filters", onMouseDown: (e) => e.preventDefault(), onClick: () => {
467
+ const menu = activeField ? (_jsxs(_Fragment, { children: [_jsxs(CommandGroup, { className: "px-1 py-0.5", children: [_jsxs("div", { className: "flex items-center gap-1 px-1 py-1", children: [_jsx(Button, { variant: "ghost", size: "icon-xs", "aria-label": "All filters", onMouseDown: (e) => e.preventDefault(), onClick: () => {
472
468
  setField(null);
473
469
  setText('');
474
470
  focus();
475
471
  }, children: _jsx(ChevronLeftIcon, {}) }), _jsx(activeField.icon, { className: "size-4 text-muted-foreground" }), _jsx("span", { className: "font-medium", children: activeField.label }), !activeField.number && (_jsxs(ToggleGroup, { type: "single", variant: "outline", size: "sm", spacing: 0, className: "ml-auto", value: notFor(activeField.key) ? 'exclude' : 'include', onValueChange: (v) => v && setNot(activeField.key, v === 'exclude'), "aria-label": `${activeField.label}: include or exclude`, children: [_jsx(ToggleGroupItem, { value: "include", className: "h-7 px-2 text-xs font-normal", children: "Include" }), _jsx(ToggleGroupItem, { value: "exclude", className: "h-7 px-2 text-xs font-normal", children: "Exclude" })] }))] }), activeField.number && (_jsx(NumberCondition, { label: activeField.label, current: tokens.find((t) => t.key === activeField.key), tall: mobile, count: (op, value) => numberCount(activeField.key, op, value), onSet: (op, value) => setCondition(activeField.key, op, value) }, activeField.key))] }), active === CONTAINS_KEY ? (_jsxs(CommandGroup, { className: "px-1 py-0.5", children: [containsWord && !picked(CONTAINS_KEY, containsWord) && (_jsxs(CommandItem, { value: `${CONTAINS_KEY}:${containsWord}`, onSelect: () => toggle(CONTAINS_KEY, containsWord), className: tall, children: [_jsx(TextSearchIcon, { className: "text-muted-foreground" }), _jsxs("span", { className: "min-w-0 truncate", children: ["\u201C", containsWord, "\u201D"] }), _jsx(CommandShortcut, { className: shortcut, children: wordOf(containsWord, notFor(CONTAINS_KEY)) })] })), tokens
476
472
  .filter((t) => t.key === CONTAINS_KEY)
477
- .map((t) => valueRow(CONTAINS_KEY, t.value, wordOf(t.value, !!t.not)))] })) : (!activeField.number && (_jsx(CommandGroup, { className: "px-1 py-0.5", children: valuesOf(activeField.key, needle, 200).map(([v, n]) => valueRow(activeField.key, v, n)) }))), _jsx(CommandEmpty, { children: "No matching values." })] })) : q ? (
478
- // Typing: free text, the fields it names, and values from every field.
479
- _jsxs(_Fragment, { children: [_jsx(CommandEmpty, { children: "No matching values." }), word && (_jsx(CommandGroup, { className: "px-1 py-0.5", children: _jsxs(CommandItem, { value: `${CONTAINS_KEY}:${word}`, onSelect: () => {
473
+ .map((t) => valueRow(CONTAINS_KEY, t.value, wordOf(t.value, !!t.not)))] })) : (!activeField.number && (_jsx(CommandGroup, { className: "px-1 py-0.5", children: valuesOf(activeField.key, needle, 200).map(([v, n]) => valueRow(activeField.key, v, n)) }))), _jsx(CommandEmpty, { children: "No matching values." })] })) : q ? (_jsxs(_Fragment, { children: [_jsx(CommandEmpty, { children: "No matching values." }), word && (_jsx(CommandGroup, { className: "px-1 py-0.5", children: _jsxs(CommandItem, { value: `${CONTAINS_KEY}:${word}`, onSelect: () => {
480
474
  setTokens([
481
475
  ...tokens.filter((t) => !same(t, { key: CONTAINS_KEY, value: word })),
482
476
  token(CONTAINS_KEY, word, chipOf(CONTAINS_KEY)?.not ?? negate),
@@ -489,9 +483,7 @@ export function LumenTokenizedFilter({ filter, placeholder = 'Filter…', label
489
483
  .map((f) => {
490
484
  const vs = valuesOf(f.key, q, PER_FIELD);
491
485
  return (vs.length > 0 && (_jsx(CommandGroup, { heading: f.label, className: "px-1 py-0.5", children: vs.map(([v, n]) => valueRow(f.key, v, n)) }, f.key)));
492
- })] })) : (
493
- // At rest: every filter on, then the fields to add.
494
- _jsxs(_Fragment, { children: [chips.length > 0 && (_jsx(CommandGroup, { heading: "Filters", className: "px-1 py-0.5", children: chips.map((c) => {
486
+ })] })) : (_jsxs(_Fragment, { children: [chips.length > 0 && (_jsx(CommandGroup, { heading: "Filters", className: "px-1 py-0.5", children: chips.map((c) => {
495
487
  const f = fieldOf(c.key);
496
488
  return (_jsxs(CommandItem, { value: `chip:${c.key}`, onSelect: () => openField(c.key), className: tall, children: [link?.color ? (_jsx(LinkDot, { color: link.color })) : (f && _jsx(f.icon, { className: "text-muted-foreground" })), _jsx("span", { className: "shrink-0", children: f?.label ?? c.key }), summary(c), _jsx(Button, { variant: "ghost", size: "icon-xs", className: "-my-1 shrink-0 text-muted-foreground", "aria-label": `Remove ${f?.label ?? c.key} filter`, onMouseDown: (e) => e.preventDefault(), onClick: (e) => {
497
489
  e.stopPropagation();
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // LumenGrid: an
3
3
  // LumenLayout's cards on a real grid, react-grid-layout underneath. A desktop has 6 columns, a phone
4
4
  // 2; rows are 8px. A card is placed at x, y and sized w by h; a card with no h is as tall as what it
@@ -193,9 +193,7 @@ export function LumenGrid({ lead = [], cards, tail = [], editing, onPlace, }) {
193
193
  parts.map((p) => Array.isArray(p) ? (_jsx(GridRun, { items: p, phone: phone, width: width, cell: (id) => {
194
194
  const c = byId.get(id);
195
195
  return c ? cell(c) : null;
196
- } }, p.map((it) => it.i).join())) : (
197
- // A full-width card that is no table (a note, a chart) stays put while a table scrolls.
198
- _jsx("div", { className: "not-has-[table]:sticky not-has-[table]:left-0 not-has-[table]:w-(--view-w)", children: p.node }, p.id)))] }));
196
+ } }, p.map((it) => it.i).join())) : (_jsx("div", { className: "not-has-[table]:sticky not-has-[table]:left-0 not-has-[table]:w-(--view-w)", children: p.node }, p.id)))] }));
199
197
  }
200
198
  /** Cards between two full-width tables: their own grid, from the row the first starts on. */
201
199
  function GridRun({ items, phone, width, cell, }) {
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // LumenLayout: the page
3
3
  // every app shows. Crumbs and actions in the header, then the filter and Group by switch every
4
4
  // card on the page shares, then an ordered list of cards, each a third, half, two thirds or the full width:
@@ -25,7 +25,7 @@ export declare function useLinkState(saved: Record<string, LinkColor | null>, ke
25
25
  ids: string[];
26
26
  }): {
27
27
  links: Links;
28
- colors: Record<string, "blue" | "lime" | "pink" | "teal" | "amber" | null>;
28
+ colors: Record<string, "amber" | "blue" | "lime" | "pink" | "teal" | null>;
29
29
  };
30
30
  export declare const useCardId: () => string | null;
31
31
  export declare function CardIdProvider({ id, children }: {
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // LumenSelector: the one
3
3
  // picker for every "pick one or more things from a list", on the shell's base-ui Combobox.
4
4
  //
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // The shared loading contract.
3
3
  // Every card and view loads its own data and says so the same way: a skeleton on first load, a thin
4
4
  // bar while a view's query runs, the old data on screen (dimmed) while a refresh someone asked for
@@ -181,9 +181,7 @@ export function LumenError({ error, onRetry }) {
181
181
  }
182
182
  /** Rows of skeleton the height of a table, so nothing jumps when the data lands. */
183
183
  export function LumenSkeleton({ rows = 6, className }) {
184
- return (_jsx("div", { "aria-busy": "true", "aria-label": "Loading", className: cn('flex flex-col gap-2 p-3', className), children: Array.from({ length: rows }, (_, i) => (
185
- // biome-ignore lint/suspicious/noArrayIndexKey: static placeholders
186
- _jsx(Skeleton, { className: "h-7 w-full" }, i))) }));
184
+ return (_jsx("div", { "aria-busy": "true", "aria-label": "Loading", className: cn('flex flex-col gap-2 p-3', className), children: Array.from({ length: rows }, (_, i) => (_jsx(Skeleton, { className: "h-7 w-full" }, i))) }));
187
185
  }
188
186
  /** One component's states from its load: bar (views), skeleton, error with Retry, empty, then the
189
187
  * content, dimmed while it refreshes. Place it at the top of a `relative` card body. */
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Trash2Icon } from 'lucide-react';
3
3
  import { useEffect, useState } from 'react';
4
4
  import { LumenConfirm } from './confirm.js';
@@ -1,10 +1,10 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import { type ExternalToast } from 'sonner';
3
3
  export declare const lumenToast: ((message: ReactNode, options?: ExternalToast) => string | number) & {
4
- success: (message: (ReactNode | (() => React.ReactNode)) | React.ReactNode, data?: ExternalToast) => string | number;
5
- error: (message: (ReactNode | (() => React.ReactNode)) | React.ReactNode, data?: ExternalToast) => string | number;
6
- warning: (message: (ReactNode | (() => React.ReactNode)) | React.ReactNode, data?: ExternalToast) => string | number;
7
- info: (message: (ReactNode | (() => React.ReactNode)) | React.ReactNode, data?: ExternalToast) => string | number;
4
+ success: (message: ((() => React.ReactNode) | ReactNode) | React.ReactNode, data?: ExternalToast) => string | number;
5
+ error: (message: ((() => React.ReactNode) | ReactNode) | React.ReactNode, data?: ExternalToast) => string | number;
6
+ warning: (message: ((() => React.ReactNode) | ReactNode) | React.ReactNode, data?: ExternalToast) => string | number;
7
+ info: (message: ((() => React.ReactNode) | ReactNode) | React.ReactNode, data?: ExternalToast) => string | number;
8
8
  dismiss: (id?: number | string) => string | number;
9
9
  /** A change done, with Undo that puts it back. */
10
10
  undo: (message: ReactNode, onUndo: () => void, options?: ExternalToast) => string | number;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { controlOn } from '@columenlabs/lumen-ui-types/views';
3
3
  import { useEffect, useMemo, useState } from 'react';
4
4
  import { useGroup } from './group-button.js';
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { controlOn, isCountAgg, isDollarFormat, viewPageSizes, viewPaginationSchema, } from '@columenlabs/lumen-ui-types/views';
3
3
  // Custom views: any number of views on any app, one page for all of them.
4
4
  // A data domain (holdings, chains, bars, series, research results) describes its fields once in a
@@ -603,9 +603,7 @@ function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null,
603
603
  ? 'ascending'
604
604
  : h.column.getIsSorted() === 'desc'
605
605
  ? 'descending'
606
- : undefined, children: [i === 0 && groups && (
607
- // Expand or collapse every group at once.
608
- _jsx(IconButton, { icon: anyClosed ? ChevronsUpDownIcon : ChevronsDownUpIcon, size: "icon-xs", className: "-ml-2 mr-1 align-middle", label: anyClosed ? 'Expand all groups' : 'Collapse all groups', onClick: () => setAll(anyClosed) })), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "xs", className: cn('font-medium', !(i === 0 && groups) && '-mx-2'), style: { color: colorOf(domain, shown[i]) ?? undefined }, onClick: h.column.getToggleSortingHandler(), children: [shown[i] ? _jsx(FreshnessMark, { domain: domain, field: shown[i] }) : null, flexRender(h.column.columnDef.header, h.getContext()), _jsx(SortIcon, { dir: h.column.getIsSorted() })] }) }), shown[i] && (domain.groups?.length || freshnessOf(domain, shown[i])) ? (_jsxs(TooltipContent, { children: [domain.groups?.length ? _jsx("div", { children: pathOf(domain, shown[i]) }) : null, freshnessLine(domain, shown[i]) ? (_jsx("div", { children: freshnessLine(domain, shown[i]) })) : null] })) : null] })] }, h.id))), add && (_jsx(TableHead, { className: cn('w-8 pl-1', PINNED_HEAD), children: _jsx(AddColumnMenu, { add: add, fieldOpen: fieldOpen, onFieldOpen: setFieldOpen }) }))] }, hg.id))) }), _jsxs(TableBody, { children: [!rows.length && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: span, className: "py-6 text-center text-muted-foreground", children: "No rows match." }) })), groups && groupBy
606
+ : undefined, children: [i === 0 && groups && (_jsx(IconButton, { icon: anyClosed ? ChevronsUpDownIcon : ChevronsDownUpIcon, size: "icon-xs", className: "-ml-2 mr-1 align-middle", label: anyClosed ? 'Expand all groups' : 'Collapse all groups', onClick: () => setAll(anyClosed) })), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "xs", className: cn('font-medium', !(i === 0 && groups) && '-mx-2'), style: { color: colorOf(domain, shown[i]) ?? undefined }, onClick: h.column.getToggleSortingHandler(), children: [shown[i] ? _jsx(FreshnessMark, { domain: domain, field: shown[i] }) : null, flexRender(h.column.columnDef.header, h.getContext()), _jsx(SortIcon, { dir: h.column.getIsSorted() })] }) }), shown[i] && (domain.groups?.length || freshnessOf(domain, shown[i])) ? (_jsxs(TooltipContent, { children: [domain.groups?.length ? _jsx("div", { children: pathOf(domain, shown[i]) }) : null, freshnessLine(domain, shown[i]) ? (_jsx("div", { children: freshnessLine(domain, shown[i]) })) : null] })) : null] })] }, h.id))), add && (_jsx(TableHead, { className: cn('w-8 pl-1', PINNED_HEAD), children: _jsx(AddColumnMenu, { add: add, fieldOpen: fieldOpen, onFieldOpen: setFieldOpen }) }))] }, hg.id))) }), _jsxs(TableBody, { children: [!rows.length && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: span, className: "py-6 text-center text-muted-foreground", children: "No rows match." }) })), groups && groupBy
609
607
  ? groups.map(([key, members], gi) => {
610
608
  const open = isOpen(key, gi);
611
609
  return (_jsxs(Fragment, { children: [_jsxs(TableRow, { className: ROLLUP, "data-group": key, children: [selection && (_jsx(TableCell, { className: cn('w-8 pr-0', PINNED_GROUP), children: _jsx(Checkbox, { checked: members.every((m) => selection.keys.has(keyOf(m.original)))