@columenlabs/lumen-ui 0.1.43 → 0.1.45
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/index.d.ts +1 -1
- package/dist/lumen-layout.js +3 -2
- package/dist/lumen-view.d.ts +33 -2
- package/dist/lumen-view.js +53 -18
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { type CustomViewConfig, LumenTable, type LumenTableProps, LumenView, type LumenViewProps, type ServerPaging, type ViewCellValue, type ViewChipTone, type ViewDomain, type ViewField, type ViewFieldGroup, type ViewSource, CHIP_TONE, RUN_STATE_TONE, FORMULAS_GROUP, ViewValueCell, rollUp, } from './lumen-view.js';
|
|
1
|
+
export { type CustomViewConfig, LumenTable, type LumenTableProps, LumenView, type LumenViewProps, type ServerGroup, type ServerGroups, type ServerPaging, type ViewCellValue, type ViewChipTone, type ViewDomain, type ViewField, type ViewFieldGroup, type ViewSource, CHIP_TONE, RUN_STATE_TONE, FORMULAS_GROUP, ViewValueCell, rollUp, } from './lumen-view.js';
|
|
2
2
|
export { LumenLayout, type LumenLayoutCard, type LumenLayoutProps, type LumenLayoutViewProps, domainKeys, followRows, } from './lumen-layout.js';
|
|
3
3
|
export { LumenViewCard, type LumenViewCardProps } from './lumen-view-card.js';
|
|
4
4
|
export { LumenSelector, LumenSelectorList, type LumenSelectorListHandle, type LumenSelectorProps, type LumenOption, type LumenOptionGroup, SelectorRowContent, } from './lumen-selector.js';
|
package/dist/lumen-layout.js
CHANGED
|
@@ -496,8 +496,9 @@ function ViewLayout({ crumbs, actions, meta, status, intro, cards: extra, lead,
|
|
|
496
496
|
const viewCard = mainTableOf(cards);
|
|
497
497
|
const viewOn = (k) => !viewCard || controlOn(viewCard, k);
|
|
498
498
|
const showBox = !hideFilter && viewOn('filter');
|
|
499
|
-
// A server's page cannot be grouped
|
|
500
|
-
|
|
499
|
+
// A server's page cannot be grouped (a group would bucket the one page only), unless the
|
|
500
|
+
// server groups it.
|
|
501
|
+
const groupButton = viewOn('group') && (!paging || paging.groups) ? group.button : null;
|
|
501
502
|
const viewFilter = !showBox && !groupButton ? undefined : (_jsxs(_Fragment, { children: [showBox && (_jsx(LumenTokenizedFilter, { filter: filter, label: `Filter ${config.name}`, className: "min-w-0 flex-1", saved: config.filters.default, link: {
|
|
502
503
|
color: viewColor,
|
|
503
504
|
onPick: (color) => links.setColor(viewCardId, color),
|
package/dist/lumen-view.d.ts
CHANGED
|
@@ -57,11 +57,39 @@ export interface ServerPaging {
|
|
|
57
57
|
onPage: (page: number) => void;
|
|
58
58
|
onSize?: (size: number) => void;
|
|
59
59
|
sizes?: readonly number[];
|
|
60
|
-
/** The columns the server sorts by; the rest take no header sort, and the view groups nothing
|
|
61
|
-
* since either would order or bucket one page only. */
|
|
60
|
+
/** The columns the server sorts by; the rest take no header sort, and the view groups nothing
|
|
61
|
+
* (unless `groups`), since either would order or bucket one page only. */
|
|
62
62
|
sorts?: readonly string[];
|
|
63
63
|
/** Told the sort held (a header click, a revert), to fetch the rows in that order. */
|
|
64
64
|
onSort?: (sort: CustomViewConfig['sort']) => void;
|
|
65
|
+
/** The server groups the rows: the Group button offers the domain's groupable fields, and a
|
|
66
|
+
* group's rows load when it opens. Without it a server's page groups nothing. */
|
|
67
|
+
groups?: ServerGroups;
|
|
68
|
+
}
|
|
69
|
+
/** One group a server counted: its key (the group field's value as the view shows it), its row
|
|
70
|
+
* count (null: not counted), and, once open, the rows loaded so far. */
|
|
71
|
+
export interface ServerGroup {
|
|
72
|
+
key: string;
|
|
73
|
+
n: number | null;
|
|
74
|
+
open: boolean;
|
|
75
|
+
/** The rows loaded for an open group, in the server's order. */
|
|
76
|
+
rows: unknown[];
|
|
77
|
+
/** The group has rows past those loaded: its Show more row loads the next. */
|
|
78
|
+
more?: () => void;
|
|
79
|
+
/** Its rows are loading. */
|
|
80
|
+
loading?: boolean;
|
|
81
|
+
}
|
|
82
|
+
export interface ServerGroups {
|
|
83
|
+
/** Told the field the person groups by (null: none), to fetch that field's groups. */
|
|
84
|
+
onGroup: (key: string | null) => void;
|
|
85
|
+
/** The picked field's groups, in order; null while they load. */
|
|
86
|
+
list: ServerGroup[] | null;
|
|
87
|
+
/** Groups past those listed: a More groups row asks for them. */
|
|
88
|
+
more?: () => void;
|
|
89
|
+
/** A group header's click: open or close it. */
|
|
90
|
+
onToggle: (key: string) => void;
|
|
91
|
+
/** Expand all (true) or Collapse all (false): open or close every group listed. */
|
|
92
|
+
onToggleAll?: (open: boolean) => void;
|
|
65
93
|
}
|
|
66
94
|
export interface LumenViewProps<T> {
|
|
67
95
|
/** The view's domain, its formula columns included (`withViewFields`). */
|
|
@@ -195,4 +223,7 @@ export interface LumenTableProps<T> {
|
|
|
195
223
|
total?: boolean;
|
|
196
224
|
/** What each row opens under it (`subgroupOf`); null: rows open nothing but their panel. */
|
|
197
225
|
subgroup?: ViewSubgroup<T> | null;
|
|
226
|
+
/** The groups come from a server (`ServerPaging.groups`): their order, counts and open state,
|
|
227
|
+
* and each open group's rows. */
|
|
228
|
+
serverGroups?: ServerGroups | null;
|
|
198
229
|
}
|
package/dist/lumen-view.js
CHANGED
|
@@ -234,8 +234,12 @@ export function LumenView({ domain, config, rows, total = rows.length, paging: s
|
|
|
234
234
|
// scrolls with the page.
|
|
235
235
|
const inLayout = inScroller && !cell;
|
|
236
236
|
const columns = pick(domain.fields, config.columns);
|
|
237
|
-
// A server's page groups and pivots nothing
|
|
238
|
-
|
|
237
|
+
// A server's page groups and pivots nothing (either would cover the one page only), unless the
|
|
238
|
+
// server groups it.
|
|
239
|
+
const groupBy = server && !server.groups ? null : pickedGroup;
|
|
240
|
+
const served = server?.groups && groupBy ? server.groups : null;
|
|
241
|
+
const onGroup = server?.groups?.onGroup;
|
|
242
|
+
useEffect(() => onGroup?.(groupBy?.key ?? null), [onGroup, groupBy?.key]);
|
|
239
243
|
const pivot = server ? false : pickedPivot;
|
|
240
244
|
// Live columns on screen keep their source reading while the market trades (#861).
|
|
241
245
|
const load = useLiveLoad(sourceLoad, columns.some((c) => {
|
|
@@ -243,7 +247,9 @@ export function LumenView({ domain, config, rows, total = rows.length, paging: s
|
|
|
243
247
|
return r === 'live' || r === 'calc';
|
|
244
248
|
}));
|
|
245
249
|
const chips = chipsOf(config);
|
|
246
|
-
|
|
250
|
+
// Server groups: the open groups' rows, each object once (a row in two groups shows in both).
|
|
251
|
+
const groupRows = useMemo(() => served ? [...new Set((served.list ?? []).flatMap((g) => (g.open ? g.rows : [])))] : null, [served]);
|
|
252
|
+
const tableRows = useMemo(() => groupRows ?? mergeRows(domain, rows, groupBy), [groupRows, domain, rows, groupBy]);
|
|
247
253
|
const amountsHidden = useAmountsHidden();
|
|
248
254
|
// Flat tables page their rows, 25 a page unless the view says otherwise; the size picker and
|
|
249
255
|
// the page buttons sit in the card's header. Views saved before then
|
|
@@ -281,9 +287,10 @@ export function LumenView({ domain, config, rows, total = rows.length, paging: s
|
|
|
281
287
|
return [...out].slice(0, MAX_COMPARE);
|
|
282
288
|
}, [selection, chartField, rows, domain]);
|
|
283
289
|
const compare = openChart && picked.length > 1 ? (_jsx(IconButton, { icon: ChartSpline, label: `Compare ${picked.join(', ')}`, variant: "outline", onClick: () => openChart(picked) })) : null;
|
|
284
|
-
// A server's page: the pager counts from the server's total, or the rows seen so far.
|
|
285
|
-
|
|
286
|
-
const
|
|
290
|
+
// A server's page: the pager counts from the server's total, or the rows seen so far. Server
|
|
291
|
+
// groups page themselves: the header counts them.
|
|
292
|
+
const pager = served ? (_jsx("span", { className: "num px-2 text-xs text-muted-foreground", children: served.list ? `${served.list.length.toLocaleString()}${served.more ? '+' : ''} groups` : '' })) : server ? (_jsx(LumenPager, { total: server.total ?? server.page * server.size + rows.length, page: server.page, size: server.size, onPage: server.onPage, onSize: server.onSize ?? (() => { }), sizes: server.sizes ?? [server.size], more: server.total === null && server.more })) : paging ? (_jsx(LumenPager, { total: tableRows.length, page: page, size: pageSize, onPage: setPageIndex, onSize: setPageSize, noun: rows.length === total ? 'rows' : `of ${total} rows` })) : (_jsx("span", { className: "num px-2 text-xs text-muted-foreground", children: count }));
|
|
293
|
+
const table = pivot && config.pivot ? (_jsx(PivotTable, { domain: domain, rows: rows, pivot: config.pivot })) : (_jsx(LumenTable, { domain: domain, columns: columns, rows: tableRows, groupBy: groupBy, subgroup: sub, chips: chips, page: paging ? { index: page, size: pageSize } : null, inView: inLayout, fit: fit, onDetails: onDetails, tapped: tapped, selection: selection, groupActions: groupActions, sort: sort, onSort: onSort, serverSorts: server ? (server.sorts ?? []) : undefined, serverGroups: served, total: config.total !== false, add: onAddColumn || onColumns
|
|
287
294
|
? { ...onAddColumn, field: onColumns && { domain, columns, onColumns } }
|
|
288
295
|
: undefined }));
|
|
289
296
|
return (_jsx(LumenWidget, { id: cardId, kind: "table", style: "table", title: title, controls: controls, tools: state ? (tools) : (_jsxs(_Fragment, { children: [tools, compare, pager, onColumns && !onAddColumn && on('columns') && (_jsx(ColumnPicker, { domain: domain, columns: columns, onColumns: onColumns })), !pivot && on('download') && (_jsx(IconButton, { icon: DownloadIcon, label: "Download CSV", onClick: () => downloadCsv({
|
|
@@ -359,7 +366,7 @@ function sortingOf(sort, columns, serverSorts) {
|
|
|
359
366
|
return [];
|
|
360
367
|
return columns.some((f) => f.key === sort.key) ? [{ id: sort.key, desc: sort.desc }] : [];
|
|
361
368
|
}
|
|
362
|
-
function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null, chips = [], page = null, inView = false, fit = false, onDetails, tapped, selection, groupActions, sort, onSort, serverSorts, total = true, subgroup = null, add, }) {
|
|
369
|
+
function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null, chips = [], page = null, inView = false, fit = false, onDetails, tapped, selection, groupActions, sort, onSort, serverSorts, total = true, subgroup = null, add, serverGroups = null, }) {
|
|
363
370
|
const [sorting, setSorting] = useState(() => sortingOf(sort, columns, serverSorts));
|
|
364
371
|
// A saved sort patched while the table is open (the assistant's card move) applies at once.
|
|
365
372
|
const savedSort = JSON.stringify(sort ?? null);
|
|
@@ -507,6 +514,10 @@ function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null,
|
|
|
507
514
|
const groups = useMemo(() => {
|
|
508
515
|
if (!groupBy)
|
|
509
516
|
return null;
|
|
517
|
+
if (serverGroups) {
|
|
518
|
+
const byRow = new Map(sorted.map((r) => [r.original, r]));
|
|
519
|
+
return (serverGroups.list ?? []).map((g) => [g.key, g.rows.flatMap((o) => byRow.get(o) ?? [])]);
|
|
520
|
+
}
|
|
510
521
|
const m = new Map();
|
|
511
522
|
for (const r of sorted) {
|
|
512
523
|
const k = label(groupBy.value(r.original));
|
|
@@ -514,12 +525,15 @@ function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null,
|
|
|
514
525
|
b ? b.push(r) : m.set(k, [r]);
|
|
515
526
|
}
|
|
516
527
|
return [...m];
|
|
517
|
-
}, [groupBy, sorted]);
|
|
528
|
+
}, [groupBy, sorted, serverGroups]);
|
|
518
529
|
const span = shown.length + (selection ? 1 : 0);
|
|
530
|
+
const served = new Map((serverGroups?.list ?? []).map((g) => [g.key, g]));
|
|
519
531
|
const startsOpen = (i) => rows.length <= OPEN_ALL || i === 0;
|
|
520
|
-
const isOpen = (key, i) => startsOpen(i) !== flipped.has(key);
|
|
532
|
+
const isOpen = (key, i) => serverGroups ? !!served.get(key)?.open : startsOpen(i) !== flipped.has(key);
|
|
521
533
|
const anyClosed = !!groups?.some(([k], i) => !isOpen(k, i));
|
|
522
|
-
const setAll = (open) =>
|
|
534
|
+
const setAll = (open) => serverGroups
|
|
535
|
+
? serverGroups.onToggleAll?.(open)
|
|
536
|
+
: setFlipped(new Set((groups ?? []).filter((_, i) => startsOpen(i) !== open).map(([k]) => k)));
|
|
523
537
|
const keyOf = domain.rowKey;
|
|
524
538
|
const toggle = (keys, on) => {
|
|
525
539
|
if (!selection)
|
|
@@ -534,7 +548,8 @@ function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null,
|
|
|
534
548
|
const someOn = allKeys.some((k) => selection?.keys.has(k));
|
|
535
549
|
const selectCell = (key, name) => selection && (_jsx(TableCell, { className: "w-8 pr-0", onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: selection.keys.has(key), onCheckedChange: (on) => toggle([key], on === true), "aria-label": `Select ${name}` }) }));
|
|
536
550
|
const [openParts, setOpenParts] = useState(new Set());
|
|
537
|
-
|
|
551
|
+
// A server group's roll-ups would add up its loaded rows only, so they and the Total stay off.
|
|
552
|
+
const hasTotal = total && !serverGroups && shown.some(rollsUp);
|
|
538
553
|
// A group row's label spans the leading columns that roll nothing up.
|
|
539
554
|
const rolls = (f) => !f.noRollup && (!!f.aggregate || !!f.rollFormula || !!f.share);
|
|
540
555
|
const lead = Math.max(1, shown.findIndex((f, i) => i > 0 && rolls(f)) < 0
|
|
@@ -608,6 +623,21 @@ function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null,
|
|
|
608
623
|
_jsx(TableRow, { "data-more": true, children: _jsx(TableCell, { colSpan: span, className: "py-1", children: _jsxs(Button, { variant: "ghost", size: "xs", onClick: () => setMore((m) => new Map(m).set(scope, limit + DRAW_STEP)), children: [_jsx(ChevronsDownIcon, {}), "Show ", Math.min(left, DRAW_STEP).toLocaleString(), " more", _jsxs("span", { className: "num font-normal text-muted-foreground", children: ["of ", left.toLocaleString()] })] }) }) }, `${scope}:more`),
|
|
609
624
|
];
|
|
610
625
|
};
|
|
626
|
+
// A server group's rows as loaded, then its Show more (the server's next rows) or loading row.
|
|
627
|
+
const servedRows = (list, key) => {
|
|
628
|
+
const g = served.get(key);
|
|
629
|
+
const out = rowsOf(list, key);
|
|
630
|
+
if (!g?.more && !g?.loading)
|
|
631
|
+
return out.length
|
|
632
|
+
? out
|
|
633
|
+
: [
|
|
634
|
+
_jsx(TableRow, { children: _jsx(TableCell, { colSpan: span, className: "py-2 text-center text-xs text-muted-foreground", children: "No rows match." }) }, `${key}:none`),
|
|
635
|
+
];
|
|
636
|
+
return [
|
|
637
|
+
...out,
|
|
638
|
+
_jsx(TableRow, { "data-more": true, children: _jsx(TableCell, { colSpan: span, className: "py-1", children: g.loading ? (_jsx("span", { className: "px-2 text-xs text-muted-foreground", children: "Loading\u2026" })) : (_jsxs(Button, { variant: "ghost", size: "xs", onClick: g.more, children: [_jsx(ChevronsDownIcon, {}), "Show more", g.n !== null && (_jsxs("span", { className: "num font-normal text-muted-foreground", children: ["of ", (g.n - list.length).toLocaleString()] }))] })) }) }, `${key}:more`),
|
|
639
|
+
];
|
|
640
|
+
};
|
|
611
641
|
const box = useRef(null);
|
|
612
642
|
useFloatingHead(box, !inView);
|
|
613
643
|
return (_jsx("div", { ref: box, className: cn(inView ? IN_VIEW : 'overflow-x-auto overflow-y-hidden [--pin-top:0px]', fit && FIT), children: _jsxs(Table, { children: [_jsx(TableHeader, { children: table.getHeaderGroups().map((hg) => (_jsxs(TableRow, { children: [selection && (_jsx(TableHead, { className: cn('w-8 pr-0', PINNED_HEAD), children: _jsx(Checkbox, { checked: allOn ? true : someOn ? 'indeterminate' : false, onCheckedChange: (on) => toggle(allKeys, on === true), "aria-label": "Select every row" }) })), hg.headers.map((h, i) => (_jsxs(TableHead, { className: cn(colOf(shown[i]), PINNED_HEAD), style: ruleOf(colorOf(domain, shown[i])), onPointerDown: pressStart, onPointerUp: pressEnd, onPointerLeave: pressEnd, onPointerCancel: pressEnd, onContextMenu: (e) => {
|
|
@@ -617,20 +647,25 @@ function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null,
|
|
|
617
647
|
? 'ascending'
|
|
618
648
|
: h.column.getIsSorted() === 'desc'
|
|
619
649
|
? 'descending'
|
|
620
|
-
: 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.getCanSort() ? h.column.getToggleSortingHandler() : undefined, 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
|
|
650
|
+
: undefined, children: [i === 0 && groups && (!serverGroups || serverGroups.onToggleAll) && (_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.getCanSort() ? h.column.getToggleSortingHandler() : undefined, 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 && !serverGroups?.list?.length && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: span, className: "py-6 text-center text-muted-foreground", children: "No rows match." }) })), groups && groupBy
|
|
621
651
|
? groups.map(([key, members], gi) => {
|
|
622
652
|
const open = isOpen(key, gi);
|
|
623
653
|
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)))
|
|
624
654
|
? true
|
|
625
655
|
: members.some((m) => selection.keys.has(keyOf(m.original)))
|
|
626
656
|
? 'indeterminate'
|
|
627
|
-
: false, onCheckedChange: (on) => toggle(members.map((m) => keyOf(m.original)), on === true), "aria-label": `Select every row of ${key}` }) })), shown.slice(lead - 1).map((f, i) => i === 0 ? (_jsxs(TableCell, { colSpan: lead, className: PINNED_GROUP, children: [_jsxs(Button, { variant: "ghost", size: "xs", className: "-mx-2 hover:bg-transparent aria-expanded:bg-transparent", "aria-expanded": open, "aria-label": `${open ? 'Collapse' : 'Expand'} ${key}`, onClick: () =>
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
657
|
+
: false, onCheckedChange: (on) => toggle(members.map((m) => keyOf(m.original)), on === true), "aria-label": `Select every row of ${key}` }) })), shown.slice(lead - 1).map((f, i) => i === 0 ? (_jsxs(TableCell, { colSpan: lead, className: PINNED_GROUP, children: [_jsxs(Button, { variant: "ghost", size: "xs", className: "-mx-2 hover:bg-transparent aria-expanded:bg-transparent", "aria-expanded": open, "aria-label": `${open ? 'Collapse' : 'Expand'} ${key}`, onClick: () => serverGroups
|
|
658
|
+
? serverGroups.onToggle(key)
|
|
659
|
+
: setFlipped((c) => {
|
|
660
|
+
const n = new Set(c);
|
|
661
|
+
n.has(key) ? n.delete(key) : n.add(key);
|
|
662
|
+
return n;
|
|
663
|
+
}), children: [_jsx(ChevronRightIcon, { className: cn('transition-transform', open && 'rotate-90') }), _jsx(groupBy.icon, {}), key, _jsx("span", { className: "num font-normal text-muted-foreground", children: serverGroups
|
|
664
|
+
? (served.get(key)?.n?.toLocaleString() ?? '')
|
|
665
|
+
: members.length })] }), groupActions?.(key, members.map((m) => m.original))] }, f.key)) : (_jsx(TableCell, { className: cn(colOf(f), PINNED_GROUP), children: !serverGroups &&
|
|
666
|
+
rollCell(f, members.map((m) => m.original)) }, f.key)))] }), open && (serverGroups ? servedRows(members, key) : drawn(members, key))] }, key));
|
|
632
667
|
})
|
|
633
|
-
: drawn(sorted, ''), hasTotal && rows.length > 0 && (_jsxs(TableRow, { className: cn(ROLLUP, 'border-t-2'), "data-total": true, children: [selection && _jsx(TableCell, {}), rollCells(rows).map((cell, i) => i === 0 && !(shown[0] && rollsUp(shown[0])) ? (_jsx(TableCell, { children: "Total" }, "total")) : (cell))] }))] })] }) }));
|
|
668
|
+
: drawn(sorted, ''), serverGroups?.more && (_jsx(TableRow, { "data-more": true, children: _jsx(TableCell, { colSpan: span, className: "py-1", children: _jsxs(Button, { variant: "ghost", size: "xs", onClick: serverGroups.more, children: [_jsx(ChevronsDownIcon, {}), "More groups"] }) }) })), hasTotal && rows.length > 0 && (_jsxs(TableRow, { className: cn(ROLLUP, 'border-t-2'), "data-total": true, children: [selection && _jsx(TableCell, {}), rollCells(rows).map((cell, i) => i === 0 && !(shown[0] && rollsUp(shown[0])) ? (_jsx(TableCell, { children: "Total" }, "total")) : (cell))] }))] })] }) }));
|
|
634
669
|
}
|
|
635
670
|
/** One value rolled up into a rows × columns grid, with totals where the roll-up adds. */
|
|
636
671
|
function PivotTable({ domain, rows, pivot, }) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.45",
|
|
4
4
|
"description": "Lumen: shared React components (frame, views, widgets, charts, drawers).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@codemirror/lang-javascript": "6.2.5",
|
|
42
42
|
"@codemirror/lang-json": "6.0.2",
|
|
43
43
|
"@codemirror/lang-sql": "6.10.0",
|
|
44
|
-
"@columenlabs/lumen-ui-types": "0.1.
|
|
44
|
+
"@columenlabs/lumen-ui-types": "0.1.45",
|
|
45
45
|
"@dnd-kit/core": "6.3.1",
|
|
46
46
|
"@dnd-kit/sortable": "10.0.0",
|
|
47
47
|
"@dnd-kit/utilities": "3.2.2",
|