@columenlabs/lumen-ui 0.1.61 → 0.1.63

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.
@@ -10,7 +10,7 @@ import { controlOn, isCountAgg, isDollarFormat, viewPageSizes, viewPaginationSch
10
10
  import { DndContext, closestCenter } from '@dnd-kit/core';
11
11
  import { SortableContext, rectSortingStrategy } from '@dnd-kit/sortable';
12
12
  import { createPaginatedRowModel, createSortedRowModel, flexRender, rowPaginationFeature, rowSortingFeature, sortFns, tableFeatures, useTable, } from '@tanstack/react-table';
13
- import { ArrowDownIcon, ArrowUpIcon, ChartCandlestick, ChartSpline, ChevronLeftIcon, ChevronRightIcon, ChevronsDownIcon, ChevronsDownUpIcon, ChevronsUpDownIcon, Columns3CogIcon, CornerDownRightIcon, DownloadIcon, Grid3x3Icon, LayoutDashboardIcon, PencilIcon, PlusIcon, Settings2Icon, SigmaIcon, SparklesIcon, TableIcon, UserPenIcon, } from 'lucide-react';
13
+ import { ArrowDownIcon, ArrowUpIcon, ChartCandlestick, ChartSpline, ChevronLeftIcon, ChevronRightIcon, ChevronsDownIcon, ChevronsDownUpIcon, ChevronsUpDownIcon, Columns3CogIcon, CornerDownRightIcon, DownloadIcon, Grid3x3Icon, LayoutDashboardIcon, ListCollapseIcon, PencilIcon, PlusIcon, Settings2Icon, SigmaIcon, SparklesIcon, TableIcon, UserPenIcon, } from 'lucide-react';
14
14
  import Papa from 'papaparse';
15
15
  import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
16
16
  import { useAssistantNote } from './assistant-context.js';
@@ -614,6 +614,22 @@ function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null,
614
614
  const opens = (row) => (domain.panel ? panelOf(row) !== null : partsOf(row).length > 1);
615
615
  const openLabel = () => domain.panel?.label ?? subgroup?.label.toLowerCase() ?? 'parts';
616
616
  const folds = !domain.panel && !!subgroup?.under && !flat;
617
+ // Every folded line's key, so the header's menu can open or close them all at once.
618
+ const foldKeys = () => {
619
+ const under = folds ? subgroup?.under : undefined;
620
+ if (!under || !groups)
621
+ return [];
622
+ return groups.flatMap(([g, ms]) => {
623
+ const counts = new Map();
624
+ for (const r of ms)
625
+ counts.set(under(r.original), (counts.get(under(r.original)) ?? 0) + 1);
626
+ return [...counts]
627
+ .filter(([, n]) => n > 1 || subgroup?.always)
628
+ .map(([k]) => `under:${g}\u0000${k}`);
629
+ });
630
+ };
631
+ const anyFoldClosed = folds && foldKeys().some((k) => !openParts.has(k));
632
+ const setAllParts = (open) => setOpenParts(new Set(open === !!subgroup?.open ? [] : foldKeys()));
617
633
  const flatName = (row) => flat && subgroup?.under ? (_jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [subgroup.mark?.(subgroup.under(row), [row]), _jsx("span", { className: "truncate", children: subgroup.under(row) })] })) : null;
618
634
  const nests = folds || sorted.some((r) => opens(r.original));
619
635
  const chevron = (k, name) => (_jsx(Button, { variant: "ghost", size: "icon-xs", className: "-ml-1", "aria-expanded": openParts.has(k), "aria-label": `${openParts.has(k) ? 'Hide' : 'Show'} ${name}`, onClick: (e) => {
@@ -702,7 +718,16 @@ function LumenTableRows({ domain, columns = domain.fields, rows, groupBy = null,
702
718
  ? 'ascending'
703
719
  : h.column.getIsSorted() === 'desc'
704
720
  ? 'descending'
705
- : 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
721
+ : undefined, children: [i === 0 && groups && folds && !serverGroups && (_jsxs(DropdownMenu, { modal: false, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(IconButton, { icon: anyClosed || anyFoldClosed ? ChevronsUpDownIcon : ChevronsDownUpIcon, size: "icon-xs", className: "-ml-2 mr-1 align-middle", label: "Expand or collapse rows" }) }), _jsxs(DropdownMenuContent, { align: "start", className: "w-52", children: [_jsxs(DropdownMenuItem, { onSelect: () => {
722
+ setAll(true);
723
+ setAllParts(true);
724
+ }, children: [_jsx(ChevronsUpDownIcon, {}), " Expand all"] }), _jsxs(DropdownMenuItem, { onSelect: () => {
725
+ setAll(true);
726
+ setAllParts(false);
727
+ }, children: [_jsx(ListCollapseIcon, {}), " Close every ", subgroup?.label.toLowerCase()] }), _jsxs(DropdownMenuItem, { onSelect: () => setAll(false), children: [_jsx(ChevronsDownUpIcon, {}), " Collapse all"] })] })] })), i === 0 &&
728
+ groups &&
729
+ !(folds && !serverGroups) &&
730
+ (!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
706
731
  ? groups.map(([key, members], gi) => {
707
732
  const open = isOpen(key, gi);
708
733
  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)))
package/dist/nav.d.ts CHANGED
@@ -72,7 +72,7 @@ export declare function SidebarSection({ label, items, onAdd, addLabel, onRemove
72
72
  loading?: boolean;
73
73
  /** Shown when there are no items. */
74
74
  empty?: ReactNode;
75
- /** Extra content under the items (a search box, a retry line). */
75
+ /** Extra content under the items (a search box, a retry line); left out on the icon rail. */
76
76
  children?: ReactNode;
77
77
  /** What its items stand for in the assistant's @ picker; plain pages by default. */
78
78
  pageType?: AssistantPageType;
package/dist/nav.js CHANGED
@@ -110,5 +110,5 @@ export function SidebarSection({ label, items, onAdd, addLabel = `Add to ${label
110
110
  }
111
111
  return (_jsx(FoldGroup, { label: label, action: onAdd && (_jsx(SidebarGroupAction, { title: addLabel, "aria-label": addLabel, onClick: onAdd, children: _jsx(PlusIcon, {}) })), children: _jsxs(SidebarGroupContent, { children: [_jsxs(SidebarMenu, { children: [loading
112
112
  ? [0, 1].map((i) => (_jsx(SidebarMenuItem, { children: _jsx(SidebarMenuSkeleton, { showIcon: true }) }, i)))
113
- : items.map((item) => (_jsx(SectionRow, { item: item, activeId: activeId, onRemove: onRemove, removeLabel: removeLabel }, item.id))), !loading && !items.length && empty && (_jsx("li", { className: "px-2 py-1 text-xs text-muted-foreground group-data-[collapsible=icon]:hidden", children: empty }))] }), children] }) }));
113
+ : items.map((item) => (_jsx(SectionRow, { item: item, activeId: activeId, onRemove: onRemove, removeLabel: removeLabel }, item.id))), !loading && !items.length && empty && (_jsx("li", { className: "px-2 py-1 text-xs text-muted-foreground group-data-[collapsible=icon]:hidden", children: empty }))] }), children && _jsx("div", { className: "group-data-[collapsible=icon]:hidden", children: children })] }) }));
114
114
  }
@@ -112,10 +112,10 @@ function SidebarInput({ className, ...props }) {
112
112
  return (_jsx(Input, { "data-slot": "sidebar-input", "data-sidebar": "input", className: cn('bg-background h-8 w-full shadow-none', className), ...props }));
113
113
  }
114
114
  function SidebarHeader({ className, ...props }) {
115
- return (_jsx("div", { "data-slot": "sidebar-header", "data-sidebar": "header", className: cn('gap-2 p-2 flex flex-col', className), ...props }));
115
+ return (_jsx("div", { "data-slot": "sidebar-header", "data-sidebar": "header", className: cn('gap-2 p-2 flex flex-col group-data-[collapsible=icon]:overflow-hidden group-data-[collapsible=icon]:whitespace-nowrap', className), ...props }));
116
116
  }
117
117
  function SidebarFooter({ className, ...props }) {
118
- return (_jsx("div", { "data-slot": "sidebar-footer", "data-sidebar": "footer", className: cn('gap-2 p-2 flex flex-col', className), ...props }));
118
+ return (_jsx("div", { "data-slot": "sidebar-footer", "data-sidebar": "footer", className: cn('gap-2 p-2 flex flex-col group-data-[collapsible=icon]:overflow-hidden group-data-[collapsible=icon]:whitespace-nowrap', className), ...props }));
119
119
  }
120
120
  function SidebarSeparator({ className, ...props }) {
121
121
  return (_jsx(Separator, { "data-slot": "sidebar-separator", "data-sidebar": "separator", className: cn('bg-sidebar-border mx-2 w-auto', className), ...props }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@columenlabs/lumen-ui",
3
- "version": "0.1.61",
3
+ "version": "0.1.63",
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.61",
44
+ "@columenlabs/lumen-ui-types": "0.1.63",
45
45
  "@dnd-kit/core": "6.3.1",
46
46
  "@dnd-kit/sortable": "10.0.0",
47
47
  "@dnd-kit/utilities": "3.2.2",