@columenlabs/lumen-ui 0.1.99 → 0.1.100
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/details-table.js +1 -1
- package/dist/lumen-echart.js +23 -2
- package/dist/lumen-grid.js +6 -1
- package/dist/page.js +1 -1
- package/dist/shell.js +1 -1
- package/dist/summary-cards.js +3 -1
- package/dist/tile.js +1 -1
- package/package.json +2 -2
package/dist/details-table.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, Table
|
|
|
4
4
|
export function DetailsTable({ head, rows, foot, selected, onSelect }) {
|
|
5
5
|
const marked = head.findIndex((h) => h.grow);
|
|
6
6
|
const grow = marked >= 0 ? marked : head.length - 1;
|
|
7
|
-
const cell = (i) => cn(
|
|
7
|
+
const cell = (i) => cn(head[i]?.right && 'num text-right', i !== grow && 'w-px', head[i]?.hideOnPhone && 'max-md:hidden');
|
|
8
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', h.hideOnPhone && 'max-md:hidden'), children: h.label }, h.label))) }) }), _jsx(TableBody, { children: rows.map((r) => (_jsx(TableRow, { "data-state": r.key === selected ? 'selected' : undefined, "aria-current": r.key === selected || undefined, tabIndex: onSelect ? 0 : undefined, className: cn(onSelect &&
|
|
9
9
|
'cursor-pointer focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring'), onClick: onSelect && (() => onSelect(r.key)), onKeyDown: onSelect &&
|
|
10
10
|
((e) => {
|
package/dist/lumen-echart.js
CHANGED
|
@@ -99,6 +99,28 @@ export function axisStyle(t) {
|
|
|
99
99
|
nameTextStyle: { color: t.muted, fontSize: 11 },
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
+
/** `over` laid on `under`, plain objects merged key by key: what the chart sets wins. */
|
|
103
|
+
function layer(under, over) {
|
|
104
|
+
const plain = (v) => !!v && typeof v === 'object' && Object.getPrototypeOf(v) === Object.prototype;
|
|
105
|
+
if (!plain(under) || !plain(over))
|
|
106
|
+
return over === undefined ? under : over;
|
|
107
|
+
const out = { ...under };
|
|
108
|
+
for (const [k, v] of Object.entries(over))
|
|
109
|
+
out[k] = layer(under[k], v);
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
/** `option` with its axes in the theme's colours under whatever the chart sets itself, so a chart
|
|
113
|
+
* that names no axis colours still draws its grid lines faint in dark mode too. */
|
|
114
|
+
function themedAxes(option, t) {
|
|
115
|
+
const style = axisStyle(t);
|
|
116
|
+
const theme = (a) => Array.isArray(a) ? a.map((x) => layer(style, x)) : layer(style, a);
|
|
117
|
+
const o = option;
|
|
118
|
+
return {
|
|
119
|
+
...option,
|
|
120
|
+
...(o.xAxis ? { xAxis: theme(o.xAxis) } : {}),
|
|
121
|
+
...(o.yAxis ? { yAxis: theme(o.yAxis) } : {}),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
102
124
|
export function LumenEChart({ option, height = 260, on, className, label, }) {
|
|
103
125
|
const box = useRef(null);
|
|
104
126
|
const chart = useRef(null);
|
|
@@ -132,12 +154,11 @@ export function LumenEChart({ option, height = 260, on, className, label, }) {
|
|
|
132
154
|
const tokens = useChartTokens();
|
|
133
155
|
// An app re-rendering hands a new but equal option (a hover, a refetch): drawing it again
|
|
134
156
|
// replays the line's entry animation, so the chart blanks under the tooltip. Only a change redraws.
|
|
135
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: tokens change when the theme flips.
|
|
136
157
|
useEffect(() => {
|
|
137
158
|
const c = chart.current;
|
|
138
159
|
if (!ready || !c)
|
|
139
160
|
return;
|
|
140
|
-
const next = resolveVars(option);
|
|
161
|
+
const next = resolveVars(themedAxes(option, tokens));
|
|
141
162
|
const key = JSON.stringify(next);
|
|
142
163
|
if (key === drawn.current)
|
|
143
164
|
return;
|
package/dist/lumen-grid.js
CHANGED
|
@@ -21,6 +21,11 @@ const GUESS = GRID_BLOCK_ROWS * 2;
|
|
|
21
21
|
const GridCellContext = createContext(null);
|
|
22
22
|
export const useGridCell = () => useContext(GridCellContext);
|
|
23
23
|
const CARD = '[data-slot=lumen-card]';
|
|
24
|
+
/** What a card's part adds to its height: nothing when it floats (a card's corner actions). */
|
|
25
|
+
const flowHeight = (el) => {
|
|
26
|
+
const at = getComputedStyle(el).position;
|
|
27
|
+
return at === 'absolute' || at === 'fixed' ? 0 : el.offsetHeight;
|
|
28
|
+
};
|
|
24
29
|
const rowsOf = (px) => Math.max(2, Math.ceil((px + GRID_GAP) / GRID_ROW_PX));
|
|
25
30
|
const byPlace = (a, b) => a.y - b.y || a.x - b.x;
|
|
26
31
|
/** Cards placed where they say and, in order after them, the ones that do not, row by row. */
|
|
@@ -120,7 +125,7 @@ function Cell({ id, fixed, report, children, }) {
|
|
|
120
125
|
// filter, body and footer, plus whatever else the wrapper holds.
|
|
121
126
|
const card = el.matches(CARD) ? el : el.querySelector(`:scope > ${CARD}`);
|
|
122
127
|
const px = card
|
|
123
|
-
? [...card.children].reduce((s, c) => s + c
|
|
128
|
+
? [...card.children].reduce((s, c) => s + flowHeight(c), 0) +
|
|
124
129
|
(card.offsetHeight - card.clientHeight) +
|
|
125
130
|
(el.offsetHeight - card.offsetHeight)
|
|
126
131
|
: el.offsetHeight;
|
package/dist/page.js
CHANGED
|
@@ -31,7 +31,7 @@ export function PageHeader({ crumbs, actions, layout, meta, status }) {
|
|
|
31
31
|
label: current ? crumbName(current) : '',
|
|
32
32
|
data: { page: crumbs.map(crumbName).filter(Boolean).join(' › ') },
|
|
33
33
|
});
|
|
34
|
-
return (_jsxs(_Fragment, { children: [_jsxs("header", { "data-slot": "shell-header", className: "sticky top-0 z-20 flex h-(--shell-header-height) shrink-0 items-center gap-2 overflow-hidden border-b bg-background px-(--shell-gutter)", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(SidebarTrigger, { className: "-ml-1" }) }), _jsx(TooltipContent, { children: "Toggle sidebar" })] }), _jsx(Separator, { orientation: "vertical", className: "hidden data-vertical:h-4 data-vertical:self-center md:block" }), parent && (_jsx(IconButton, { icon: ChevronLeftIcon, label: `Back to ${crumbName(parent)}`, className: "md:hidden", onClick: () => router.navigate({ to: parent.to }) })), !isMobile && (_jsx(Breadcrumb, { className: "min-w-0", children: _jsx(BreadcrumbList, { className: "flex-nowrap", children: crumbs.map((c, i) => (_jsxs(Fragment, { children: [i > 0 && _jsx(BreadcrumbSeparator, {}), _jsx(BreadcrumbItem, { className: "min-w-0", children: c.to && i < crumbs.length - 1 ? (_jsx(BreadcrumbLink, { asChild: true, children: _jsx(Link, { to: c.to, children: c.label }) })) : i === crumbs.length - 1 ? (_jsx(BreadcrumbPage, { className: "truncate", children: _jsx("h1", { className: "flex min-w-0 items-center gap-2 truncate font-semibold", children: c.label }) })) : (_jsx("span", { className: "truncate", children: c.label })) })] }, `${i}-${crumbName(c)}`))) }) })), isMobile && (_jsxs("div", { className: "min-w-0", children: [_jsx("h1", { className: "flex min-w-0 items-center gap-2 truncate text-sm leading-tight font-semibold", children: current?.label }), meta && (_jsx("div", { className: "flex items-center gap-1.5
|
|
34
|
+
return (_jsxs(_Fragment, { children: [_jsxs("header", { "data-slot": "shell-header", className: "sticky top-0 z-20 flex h-(--shell-header-height) shrink-0 items-center gap-2 overflow-hidden border-b bg-background px-(--shell-gutter)", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(SidebarTrigger, { className: "-ml-1" }) }), _jsx(TooltipContent, { children: "Toggle sidebar" })] }), _jsx(Separator, { orientation: "vertical", className: "hidden data-vertical:h-4 data-vertical:self-center md:block" }), parent && (_jsx(IconButton, { icon: ChevronLeftIcon, label: `Back to ${crumbName(parent)}`, className: "md:hidden", onClick: () => router.navigate({ to: parent.to }) })), !isMobile && (_jsx(Breadcrumb, { className: "min-w-0", children: _jsx(BreadcrumbList, { className: "flex-nowrap", children: crumbs.map((c, i) => (_jsxs(Fragment, { children: [i > 0 && _jsx(BreadcrumbSeparator, {}), _jsx(BreadcrumbItem, { className: "min-w-0", children: c.to && i < crumbs.length - 1 ? (_jsx(BreadcrumbLink, { asChild: true, children: _jsx(Link, { to: c.to, children: c.label }) })) : i === crumbs.length - 1 ? (_jsx(BreadcrumbPage, { className: "truncate", children: _jsx("h1", { className: "flex min-w-0 items-center gap-2 truncate font-semibold", children: c.label }) })) : (_jsx("span", { className: "truncate", children: c.label })) })] }, `${i}-${crumbName(c)}`))) }) })), isMobile && (_jsxs("div", { className: "min-w-0", children: [_jsx("h1", { className: "flex min-w-0 items-center gap-2 truncate text-sm leading-tight font-semibold", children: current?.label }), meta && (_jsx("div", { className: "flex min-w-0 items-center gap-1.5 text-[11px] leading-tight text-muted-foreground", children: _jsx("span", { className: "truncate", children: meta }) }))] })), meta && !isMobile && (_jsx("div", { className: "ml-1 hidden min-w-0 shrink items-center gap-2 truncate border-l pl-3 text-xs text-muted-foreground md:flex", children: meta })), _jsxs("div", { className: cn('ml-auto flex shrink-0 items-center gap-0.5',
|
|
35
35
|
// Phone: a page's text buttons show as icons too; their text stays as the accessible name.
|
|
36
36
|
isMobile &&
|
|
37
37
|
'[&_[data-slot=button]]:size-8 [&_[data-slot=button]]:gap-0 [&_[data-slot=button]]:px-0 [&_[data-slot=button]]:text-[0px]'), children: [actions && (_jsxs(_Fragment, { children: [_jsx("div", { "data-slot": "shell-page-actions", className: "flex items-center gap-0.5", children: actions }), _jsx(Separator, { orientation: "vertical", className: "mx-2 data-vertical:h-5 data-vertical:self-center" })] })), _jsxs("div", { "data-slot": "shell-actions", className: "flex items-center gap-0.5", children: [layout, _jsx(LumenFinderButton, {}), hideAmounts && (_jsx(IconButton, { icon: hidden ? EyeOffIcon : EyeIcon, label: hidden ? 'Show amounts' : 'Hide amounts', "aria-pressed": hidden, onClick: () => setPref('hideAmounts', !hidden) })), refresh && (_jsx(IconButton, { icon: RefreshCwIcon, busy: refreshing, label: "Refresh (skip cache)", disabled: refreshing, onClick: () => void refresh() })), headerActions] })] })] }), status && statusSlot && createPortal(status, statusSlot)] }));
|
package/dist/shell.js
CHANGED
|
@@ -143,5 +143,5 @@ export function LumenShell({ app, appLabel, brand, nav, status, health, statusEn
|
|
|
143
143
|
}
|
|
144
144
|
/** A status bar entry: an optional health dot, a label and a mono value. */
|
|
145
145
|
export function StatusItem({ label, value, ok, className, }) {
|
|
146
|
-
return (_jsxs("span", { className: cn('flex items-center gap-1.5', className), children: [ok !== undefined && (_jsx("span", { "aria-hidden": true, className: cn('size-2 rounded-full', ok === null ? 'bg-muted-foreground/40' : ok ? 'bg-gain' : 'bg-destructive') })), label, value !== undefined && (_jsxs(_Fragment, { children: [' ', _jsx("span", { className: "num text-foreground/80", children: value })] }))] }));
|
|
146
|
+
return (_jsxs("span", { className: cn('flex items-center gap-1.5', value === undefined && 'min-w-0', className), children: [ok !== undefined && (_jsx("span", { "aria-hidden": true, className: cn('size-2 shrink-0 rounded-full', ok === null ? 'bg-muted-foreground/40' : ok ? 'bg-gain' : 'bg-destructive') })), _jsx("span", { className: value === undefined ? 'min-w-0 truncate' : 'max-md:hidden', children: label }), value !== undefined && (_jsxs(_Fragment, { children: [' ', _jsx("span", { className: "num shrink-0 text-foreground/80", children: value })] }))] }));
|
|
147
147
|
}
|
package/dist/summary-cards.js
CHANGED
|
@@ -131,7 +131,9 @@ export function SummaryTiles({ domain, tiles, rows, fields, tile, loading, }) {
|
|
|
131
131
|
const grid = 'grid grid-cols-2 gap-(--shell-section-gap) md:auto-cols-fr md:grid-flow-col lg:*:*:w-auto';
|
|
132
132
|
if (loading)
|
|
133
133
|
return (_jsx("div", { "data-slot": "view-tiles", "aria-busy": "true", className: grid, children: shown.map((t) => (_jsx(Skeleton, { className: "h-[4.5rem] w-full rounded-xl" }, t.key))) }));
|
|
134
|
-
return (_jsx("div", { "data-slot": "view-tiles", className: cn(grid,
|
|
134
|
+
return (_jsx("div", { "data-slot": "view-tiles", className: cn(grid,
|
|
135
|
+
// Each tile sits in a `contents` holder, so the odd last one's span goes on what it holds.
|
|
136
|
+
'[&>*:last-child:nth-child(odd)>*]:col-span-2 md:[&>*:last-child:nth-child(odd)>*]:col-span-1'), children: shown.map((t) => (_jsx("div", { className: "contents", children: isOwnTile(t) ? (_jsx(OwnTile, { domain: domain, tile: t, rows: rows, fields: fields })) : (tile?.(t.key, rows)) }, t.key))) }));
|
|
135
137
|
}
|
|
136
138
|
// ── Edit ───────────────────────────────────────────────────────────────────────────────────────
|
|
137
139
|
const dragOptions = { activationConstraint: { distance: 4 } };
|
package/dist/tile.js
CHANGED
|
@@ -30,7 +30,7 @@ export function TileRow({ children, className, fill, ...props }) {
|
|
|
30
30
|
}
|
|
31
31
|
export function TileToggleGroup({ options, selected, onSelect, label, className, fill, }) {
|
|
32
32
|
return (_jsx(Card, { size: "sm", className: cn('min-w-0 gap-0 bg-border py-0 lg:w-fit lg:flex-initial', fill &&
|
|
33
|
-
'lg:w-full lg:*:data-[slot=toggle-group]:w-full lg:**:data-[slot=toggle-group-item]:flex-1', className), children: _jsx(ToggleGroup, { type: "single", spacing: 0, value: selected, onValueChange: (v) => v && onSelect(v), "aria-label": label, className: "grid w-full grid-cols-[repeat(auto-fit,minmax(6.5rem,1fr))]
|
|
33
|
+
'lg:w-full lg:*:data-[slot=toggle-group]:w-full lg:**:data-[slot=toggle-group-item]:flex-1', className), children: _jsx(ToggleGroup, { type: "single", spacing: 0, value: selected, onValueChange: (v) => v && onSelect(v), "aria-label": label, className: "grid w-full grid-cols-2 gap-px max-sm:[&>*:last-child:nth-child(odd)]:col-span-2 sm:grid-cols-[repeat(auto-fit,minmax(6.5rem,1fr))] lg:flex lg:w-fit", children: options.map((o) => (_jsx(ToggleGroupItem, { value: o.id, "aria-label": o.label, className: "h-auto min-w-0 flex-col lg:w-(--tile-width) lg:shrink items-start justify-start gap-0.5 rounded-none! bg-card px-3 py-3 text-left font-normal data-[state=on]:bg-primary/5 data-[state=on]:shadow-[inset_0_-2px_0_var(--primary)]", children: _jsx(TileBody, { label: o.label, value: o.value, caption: o.caption, spark: o.spark, sparkColor: o.sparkColor }) }, o.id))) }) }));
|
|
34
34
|
}
|
|
35
35
|
/** A compact tile: a small caps label over one short value (a quote strip's IV, expiry and move). */
|
|
36
36
|
export function TileChip({ label, value }) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.100",
|
|
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.100",
|
|
53
53
|
"@dnd-kit/core": "6.3.1",
|
|
54
54
|
"@dnd-kit/sortable": "10.0.0",
|
|
55
55
|
"@dnd-kit/utilities": "3.2.2",
|