@columenlabs/lumen-ui 0.1.45 → 0.1.47
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/README.md +10 -0
- package/dist/color-dot.d.ts +11 -2
- package/dist/color-dot.js +22 -4
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/lumen-echart.js +24 -2
- package/dist/lumen-filter.js +70 -18
- package/dist/lumen-links.js +3 -1
- package/dist/lumen-selector.js +2 -1
- package/dist/lumen-view.js +2 -2
- package/dist/lumen-widget-charts.js +17 -1
- package/dist/lumen-widget.d.ts +18 -17
- package/dist/nav.d.ts +5 -1
- package/dist/nav.js +50 -9
- package/dist/share-meter.d.ts +12 -0
- package/dist/share-meter.js +6 -0
- package/dist/tile.d.ts +22 -4
- package/dist/tile.js +24 -9
- package/dist/unit-value.d.ts +11 -0
- package/dist/unit-value.js +5 -0
- package/dist/view-edit-cell.d.ts +6 -2
- package/dist/view-edit-cell.js +9 -4
- package/dist/view-editor.js +7 -1
- package/dist/view-model.d.ts +23 -3
- package/dist/view-model.js +10 -2
- package/dist/whats-new.js +7 -5
- package/dist/widget-settings.d.ts +15 -14
- package/package.json +2 -2
package/dist/nav.js
CHANGED
|
@@ -12,9 +12,33 @@ import { useFolded } from './fold.js';
|
|
|
12
12
|
import { cn } from './lib/utils.js';
|
|
13
13
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/collapsible.js';
|
|
14
14
|
import { SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, useSidebar, } from './ui/sidebar.js';
|
|
15
|
+
/**
|
|
16
|
+
* How well a link matches where the person is: -1 when it doesn't, else higher for a closer
|
|
17
|
+
* match. A link's query (`/resources?label=a`) must be in the URL too, and each matched key
|
|
18
|
+
* outranks a bare path, so `?label=a` beats `/resources` on `/resources?label=a`.
|
|
19
|
+
*/
|
|
20
|
+
function useMatch() {
|
|
21
|
+
const { path, search } = useRouterState({
|
|
22
|
+
select: (s) => ({ path: s.location.pathname, search: s.location.searchStr }),
|
|
23
|
+
});
|
|
24
|
+
const here = new URLSearchParams(search);
|
|
25
|
+
return ({ to, exact }) => {
|
|
26
|
+
const [base = '', query] = to.split('?');
|
|
27
|
+
const want = new URLSearchParams(query);
|
|
28
|
+
for (const [k, v] of want)
|
|
29
|
+
if (here.get(k) !== v)
|
|
30
|
+
return -1;
|
|
31
|
+
const keys = [...want.keys()].length;
|
|
32
|
+
if (path === base)
|
|
33
|
+
return 2 + keys * 10;
|
|
34
|
+
if (!exact && path.startsWith(`${base.replace(/\/$/, '')}/`))
|
|
35
|
+
return 1 + keys * 10;
|
|
36
|
+
return -1;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
15
39
|
function useActive() {
|
|
16
|
-
const
|
|
17
|
-
return (
|
|
40
|
+
const match = useMatch();
|
|
41
|
+
return (i) => match(i) >= 0;
|
|
18
42
|
}
|
|
19
43
|
/**
|
|
20
44
|
* A sidebar group whose header folds its items: bold caps, no icon. At rest
|
|
@@ -36,13 +60,13 @@ export function NavGroup({ label, items, pageType, }) {
|
|
|
36
60
|
}
|
|
37
61
|
const SECTION_BADGE = 'num group-data-[collapsible=icon]:hidden';
|
|
38
62
|
/** One section item: a link, its badge, and the chevron and nested items when it has any. */
|
|
39
|
-
function SectionRow({ item,
|
|
63
|
+
function SectionRow({ item, activeId, onRemove, removeLabel, }) {
|
|
40
64
|
const subs = item.items ?? [];
|
|
41
|
-
const subActive =
|
|
42
|
-
const isActive =
|
|
65
|
+
const subActive = activeId?.startsWith(`${item.id}/`) ?? false;
|
|
66
|
+
const isActive = activeId === item.id;
|
|
43
67
|
// The open item shows no trash icon.
|
|
44
68
|
const remove = item.fixed || isActive ? undefined : onRemove;
|
|
45
|
-
const row = (_jsxs(_Fragment, { children: [_jsx(SidebarMenuButton, { asChild: true, tooltip: item.title, isActive: isActive, children: _jsxs(Link, { to: item.to, children: [_jsx(item.icon, {}), _jsx("span", { children: item.title })] }) }), item.badge !== undefined && item.badge !== null && (_jsx(SidebarMenuBadge, { className: cn(SECTION_BADGE,
|
|
69
|
+
const row = (_jsxs(_Fragment, { children: [_jsx(SidebarMenuButton, { asChild: true, tooltip: item.title, isActive: isActive, children: _jsxs(Link, { to: item.to, children: [_jsx(item.icon, {}), _jsx("span", { children: item.title })] }) }), item.badge !== undefined && item.badge !== null && (_jsx(SidebarMenuBadge, { className: cn(SECTION_BADGE,
|
|
46
70
|
// The remove icon shows on hover from md up, and always below it: make room there.
|
|
47
71
|
remove &&
|
|
48
72
|
'max-md:right-7 md:group-focus-within/menu-item:opacity-0 md:group-hover/menu-item:opacity-0'), children: item.badge })), remove && (_jsx(LumenConfirm, { title: `${removeLabel(item)}?`, action: "Remove", onConfirm: () => remove(item), children: _jsx(SidebarMenuAction, { showOnHover: true, "aria-label": removeLabel(item), title: removeLabel(item),
|
|
@@ -50,7 +74,10 @@ function SectionRow({ item, active, onRemove, removeLabel, }) {
|
|
|
50
74
|
className: "text-muted-foreground peer-hover/menu-button:text-muted-foreground hover:bg-transparent hover:text-destructive", children: _jsx(Trash2Icon, {}) }) }))] }));
|
|
51
75
|
if (!subs.length)
|
|
52
76
|
return _jsx(SidebarMenuItem, { children: row });
|
|
53
|
-
return (_jsx(Collapsible, { asChild: true, defaultOpen: item.defaultOpen || subActive ||
|
|
77
|
+
return (_jsx(Collapsible, { asChild: true, defaultOpen: item.defaultOpen || subActive || isActive, className: "group/collapsible", children: _jsxs(SidebarMenuItem, { children: [row, _jsx(CollapsibleTrigger, { asChild: true, children: _jsx(SidebarMenuAction, { "aria-label": `Show or hide ${item.title}`, className: "right-auto left-1.5 bg-sidebar opacity-0 group-hover/menu-item:opacity-100 focus-visible:opacity-100 peer-data-[active=true]/menu-button:bg-sidebar-accent [&>svg]:transition-transform data-[state=open]:[&>svg]:rotate-90", children: _jsx(ChevronRightIcon, {}) }) }), _jsx(CollapsibleContent, { children: _jsx(SidebarMenuSub, { className: "mr-0 pr-0", children: subs.map((sub) => {
|
|
78
|
+
const hasBadge = sub.badge !== undefined && sub.badge !== null;
|
|
79
|
+
return (_jsxs(SidebarMenuSubItem, { children: [_jsx(SidebarMenuSubButton, { asChild: true, isActive: activeId === `${item.id}/${sub.id}`, className: cn(hasBadge && 'pr-8'), children: _jsxs(Link, { to: sub.to, title: sub.title, children: [sub.icon ? (_jsx("span", { "aria-hidden": true, className: "flex shrink-0 [&>svg]:size-4", style: { color: sub.color }, children: _jsx(sub.icon, {}) })) : (sub.color && (_jsx("span", { "aria-hidden": true, className: "mx-1 size-2 shrink-0 rounded-full", style: { background: sub.color } }))), _jsx("span", { children: sub.title })] }) }), hasBadge && (_jsx("span", { className: cn('pointer-events-none absolute top-1 right-1 flex h-5 min-w-5 items-center justify-center px-1 text-xs text-muted-foreground', typeof sub.badge === 'number' && 'num'), children: sub.badge }))] }, sub.id));
|
|
80
|
+
}) }) })] }) }));
|
|
54
81
|
}
|
|
55
82
|
/**
|
|
56
83
|
* A section of things a person keeps (views, trades, a watchlist): `+` adds one, the
|
|
@@ -66,8 +93,22 @@ export function SidebarSection({ label, items, onAdd, addLabel = `Add to ${label
|
|
|
66
93
|
type: assistantSubType ?? 'page',
|
|
67
94
|
})),
|
|
68
95
|
]), label, pageType);
|
|
69
|
-
const
|
|
96
|
+
const match = useMatch();
|
|
97
|
+
// One selected row per section: the closest match wins, the first on a tie, so two items that
|
|
98
|
+
// open the same page never both look selected. An open parent is never selected for being open.
|
|
99
|
+
let activeId = null;
|
|
100
|
+
let best = -1;
|
|
101
|
+
for (const i of items) {
|
|
102
|
+
const own = match({ to: i.to, exact: true });
|
|
103
|
+
if (own > best)
|
|
104
|
+
[best, activeId] = [own, i.id];
|
|
105
|
+
for (const sub of i.items ?? []) {
|
|
106
|
+
const m = match({ to: sub.to, exact: true });
|
|
107
|
+
if (m > best)
|
|
108
|
+
[best, activeId] = [m, `${i.id}/${sub.id}`];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
70
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
|
|
71
112
|
? [0, 1].map((i) => (_jsx(SidebarMenuItem, { children: _jsx(SidebarMenuSkeleton, { showIcon: true }) }, i)))
|
|
72
|
-
: items.map((item) => (_jsx(SectionRow, { item: item,
|
|
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] }) }));
|
|
73
114
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export declare function ShareMeter({ value, label, color, wide, className, }: {
|
|
3
|
+
/** 0 to 1 fills the bar; past 1 it stays full. */
|
|
4
|
+
value: number;
|
|
5
|
+
/** The number beside the bar, e.g. `113%`; left out, the rounded percent. */
|
|
6
|
+
label?: ReactNode;
|
|
7
|
+
/** The bar's colour, a theme token (`var(--loss)` when over). */
|
|
8
|
+
color?: string;
|
|
9
|
+
/** Fills its cell (a list row) instead of the fixed table width. */
|
|
10
|
+
wide?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './lib/utils.js';
|
|
3
|
+
import { Progress } from './ui/progress.js';
|
|
4
|
+
export function ShareMeter({ value, label, color = 'var(--primary)', wide, className, }) {
|
|
5
|
+
return (_jsxs("span", { className: cn('inline-flex items-center gap-2', wide && 'w-full', className), children: [_jsx(Progress, { value: Math.max(0, Math.min(value, 1)) * 100, className: cn('h-1.5 shrink-0 [&>[data-slot=progress-indicator]]:bg-(--meter-color)', wide ? 'w-full shrink' : 'w-14'), style: { '--meter-color': color } }), _jsx("span", { className: "num w-11 shrink-0 text-right text-xs", children: label ?? `${Math.round(value * 100)}%` })] }));
|
|
6
|
+
}
|
package/dist/tile.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
|
|
2
|
+
/** A number's history as a small line and area, scaled to its own range; `color` is a theme
|
|
3
|
+
* token (SVG reads CSS variables, so it follows the theme). Fewer than two points draw nothing. */
|
|
4
|
+
export declare function TileSpark({ values, color, className, }: {
|
|
5
|
+
values: number[];
|
|
6
|
+
color?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
}): import("react").JSX.Element | null;
|
|
9
|
+
export declare function Tile({ label, value, caption, lines, className, valueClassName, spark, sparkColor, }: {
|
|
3
10
|
label: ReactNode;
|
|
4
11
|
value: ReactNode;
|
|
5
12
|
caption?: ReactNode;
|
|
@@ -7,13 +14,19 @@ export declare function Tile({ label, value, caption, lines, className, valueCla
|
|
|
7
14
|
lines?: ReactNode[];
|
|
8
15
|
className?: string;
|
|
9
16
|
valueClassName?: string;
|
|
17
|
+
/** The number's history (oldest first), drawn as a small line under it: a metric card. */
|
|
18
|
+
spark?: number[];
|
|
19
|
+
/** The line's colour, a theme token; left out, `var(--chart-1)`. */
|
|
20
|
+
sparkColor?: string;
|
|
10
21
|
}): import("react").JSX.Element;
|
|
11
22
|
/** Width of every header tile on desktop, toggle tiles and plain Tiles alike; shrinks to fit the row. */
|
|
12
23
|
export declare const TILE_WIDTH = "lg:w-(--tile-width) lg:flex-initial";
|
|
13
|
-
/** A page's header row of tiles: wraps on phones, one line on desktop.
|
|
14
|
-
|
|
24
|
+
/** A page's header row of tiles: wraps on phones, one line on desktop. `fill` shares the row's
|
|
25
|
+
* width between its tiles (a row of metric cards) instead of the fixed tile width. */
|
|
26
|
+
export declare function TileRow({ children, className, fill, ...props }: {
|
|
15
27
|
children: ReactNode;
|
|
16
28
|
className?: string;
|
|
29
|
+
fill?: boolean;
|
|
17
30
|
'aria-label'?: string;
|
|
18
31
|
}): import("react").JSX.Element;
|
|
19
32
|
export interface TileOption {
|
|
@@ -21,14 +34,19 @@ export interface TileOption {
|
|
|
21
34
|
label: string;
|
|
22
35
|
value: ReactNode;
|
|
23
36
|
caption?: ReactNode;
|
|
37
|
+
/** The option's history, a small line under its number (see `Tile`). */
|
|
38
|
+
spark?: number[];
|
|
39
|
+
sparkColor?: string;
|
|
24
40
|
}
|
|
25
|
-
export declare function TileToggleGroup({ options, selected, onSelect, label, className, }: {
|
|
41
|
+
export declare function TileToggleGroup({ options, selected, onSelect, label, className, fill, }: {
|
|
26
42
|
options: TileOption[];
|
|
27
43
|
selected: string;
|
|
28
44
|
onSelect: (id: string) => void;
|
|
29
45
|
/** Accessible name of the group. */
|
|
30
46
|
label: string;
|
|
31
47
|
className?: string;
|
|
48
|
+
/** Spans the row, its tiles sharing the width (see `TileRow`). */
|
|
49
|
+
fill?: boolean;
|
|
32
50
|
}): import("react").JSX.Element;
|
|
33
51
|
/** A compact tile: a small caps label over one short value (a quote strip's IV, expiry and move). */
|
|
34
52
|
export declare function TileChip({ label, value }: {
|
package/dist/tile.js
CHANGED
|
@@ -2,20 +2,35 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
import { cn } from './lib/utils.js';
|
|
3
3
|
import { Card } from './ui/card.js';
|
|
4
4
|
import { ToggleGroup, ToggleGroupItem } from './ui/toggle-group.js';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/** A number's history as a small line and area, scaled to its own range; `color` is a theme
|
|
6
|
+
* token (SVG reads CSS variables, so it follows the theme). Fewer than two points draw nothing. */
|
|
7
|
+
export function TileSpark({ values, color = 'var(--chart-1)', className, }) {
|
|
8
|
+
if (values.length < 2)
|
|
9
|
+
return null;
|
|
10
|
+
const max = Math.max(...values);
|
|
11
|
+
const min = Math.min(0, ...values);
|
|
12
|
+
const span = max - min || 1;
|
|
13
|
+
const pts = values.map((v, i) => `${((i / (values.length - 1)) * 100).toFixed(2)},${(22 - ((v - min) / span) * 20).toFixed(2)}`);
|
|
14
|
+
return (_jsxs("svg", { viewBox: "0 0 100 24", preserveAspectRatio: "none", "aria-hidden": "true",
|
|
15
|
+
// Inline size: a parent's `[&_svg]:size-4` (toggle items, buttons) must not shrink it.
|
|
16
|
+
style: { width: '100%', height: '1.5rem' }, className: cn('overflow-visible', className), children: [_jsx("polygon", { points: `0,24 ${pts.join(' ')} 100,24`, fill: color, fillOpacity: 0.15 }), _jsx("polyline", { points: pts.join(' '), fill: "none", stroke: color, strokeWidth: 1.5, strokeLinejoin: "round", vectorEffect: "non-scaling-stroke" })] }));
|
|
7
17
|
}
|
|
8
|
-
|
|
9
|
-
return (_jsx(
|
|
18
|
+
function TileBody({ label, value, caption, lines, valueClassName, spark, sparkColor, }) {
|
|
19
|
+
return (_jsxs(_Fragment, { children: [_jsx("span", { className: "w-full truncate text-xs text-muted-foreground", children: label }), _jsx("span", { className: cn('num truncate text-xl leading-7 font-semibold', valueClassName), children: value }), caption ? (_jsx("span", { className: "num line-clamp-2 text-xs text-muted-foreground", children: caption })) : null, lines?.map((l, i) => (_jsx("span", { className: "num line-clamp-2 text-xs text-muted-foreground", children: l }, i))), spark ? _jsx(TileSpark, { values: spark, color: sparkColor, className: "mt-1 self-stretch" }) : null] }));
|
|
20
|
+
}
|
|
21
|
+
export function Tile({ label, value, caption, lines, className, valueClassName, spark, sparkColor, }) {
|
|
22
|
+
return (_jsx(Card, { size: "sm", className: cn('min-w-0 flex-1 basis-2/5 gap-0.5 px-3 lg:basis-auto', TILE_WIDTH, className), children: _jsx(TileBody, { label: label, value: value, caption: caption, lines: lines, valueClassName: valueClassName, spark: spark, sparkColor: sparkColor }) }));
|
|
10
23
|
}
|
|
11
24
|
/** Width of every header tile on desktop, toggle tiles and plain Tiles alike; shrinks to fit the row. */
|
|
12
25
|
export const TILE_WIDTH = 'lg:w-(--tile-width) lg:flex-initial';
|
|
13
|
-
/** A page's header row of tiles: wraps on phones, one line on desktop.
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
/** A page's header row of tiles: wraps on phones, one line on desktop. `fill` shares the row's
|
|
27
|
+
* width between its tiles (a row of metric cards) instead of the fixed tile width. */
|
|
28
|
+
export function TileRow({ children, className, fill, ...props }) {
|
|
29
|
+
return (_jsx("div", { className: cn('flex flex-wrap gap-2.5 lg:flex-nowrap', fill && 'lg:*:w-auto lg:*:flex-1', className), ...props, children: children }));
|
|
16
30
|
}
|
|
17
|
-
export function TileToggleGroup({ options, selected, onSelect, label, className, }) {
|
|
18
|
-
return (_jsx(Card, { size: "sm", className: cn('min-w-0 gap-0 bg-border py-0 lg:w-fit lg:flex-initial',
|
|
31
|
+
export function TileToggleGroup({ options, selected, onSelect, label, className, fill, }) {
|
|
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))] gap-px 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))) }) }));
|
|
19
34
|
}
|
|
20
35
|
/** A compact tile: a small caps label over one short value (a quote strip's IV, expiry and move). */
|
|
21
36
|
export function TileChip({ label, value }) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export declare function UnitValue({ value, unit, tone, title, className, }: {
|
|
3
|
+
/** The number, already formatted (`231.4`). */
|
|
4
|
+
value: ReactNode;
|
|
5
|
+
/** Its unit (`GB`, `M`, `/day`); left out, the slot stays empty so the column still lines up. */
|
|
6
|
+
unit?: ReactNode;
|
|
7
|
+
/** Near (`warning`) or past (`loss`) a limit: tints the number and shows a dot. */
|
|
8
|
+
tone?: 'warning' | 'loss';
|
|
9
|
+
title?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './lib/utils.js';
|
|
3
|
+
export function UnitValue({ value, unit, tone, title, className, }) {
|
|
4
|
+
return (_jsxs("span", { title: title, className: cn('inline-flex w-full items-center justify-end gap-1 whitespace-nowrap', className), children: [_jsx("span", { className: cn('num text-right', tone === 'warning' && 'text-warning', tone === 'loss' && 'text-loss'), children: value }), _jsx("span", { className: "w-10 shrink-0 text-left text-muted-foreground text-xs", children: unit }), _jsx("span", { "aria-hidden": "true", className: cn('size-1.5 shrink-0 rounded-full', tone === 'warning' ? 'bg-warning' : tone === 'loss' ? 'bg-loss' : 'bg-transparent') })] }));
|
|
5
|
+
}
|
package/dist/view-edit-cell.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
1
|
+
import { type ComponentType, type ReactNode } from 'react';
|
|
2
2
|
export declare function EditCell({ label, value, options, unused, chip, note, colorOf, fixed, edited, onSave, }: {
|
|
3
3
|
/** The field's name, e.g. `Basket`. */
|
|
4
4
|
label: string;
|
|
@@ -23,13 +23,17 @@ export declare function EditCell({ label, value, options, unused, chip, note, co
|
|
|
23
23
|
* a tap opens a picker that ticks any number and takes a typed name, and closing it saves them all
|
|
24
24
|
* at once. Clicks stay off the row, which opens its details.
|
|
25
25
|
*/
|
|
26
|
-
export declare function EditManyCell({ label, values, options, unused, note, colorOf, onSave, }: {
|
|
26
|
+
export declare function EditManyCell({ label, values, options, unused, note, colorOf, iconOf, onSave, }: {
|
|
27
27
|
label: string;
|
|
28
28
|
values: string[];
|
|
29
29
|
options: string[];
|
|
30
30
|
unused?: string[];
|
|
31
31
|
note?: string;
|
|
32
32
|
colorOf?: (value: string) => string | undefined;
|
|
33
|
+
/** A value's icon (a label's), drawn in its colour on its chip and in the picker. */
|
|
34
|
+
iconOf?: (value: string) => ComponentType<{
|
|
35
|
+
className?: string;
|
|
36
|
+
}> | undefined;
|
|
33
37
|
onSave: (values: string[]) => Promise<unknown>;
|
|
34
38
|
}): import("react").JSX.Element;
|
|
35
39
|
/**
|
package/dist/view-edit-cell.js
CHANGED
|
@@ -4,7 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
// opens its details.
|
|
5
5
|
import { PencilLineIcon, PlusIcon, XIcon } from 'lucide-react';
|
|
6
6
|
import { useEffect, useRef, useState } from 'react';
|
|
7
|
-
import { ColorChip, colorIcon } from './color-dot.js';
|
|
7
|
+
import { ColorChip, colorIcon, tintedIcon } from './color-dot.js';
|
|
8
8
|
import { cn } from './lib/utils.js';
|
|
9
9
|
import { LumenSelector } from './lumen-selector.js';
|
|
10
10
|
import { Input } from './ui/input.js';
|
|
@@ -69,7 +69,7 @@ export function EditCell({ label, value, options, unused = [], chip, note, color
|
|
|
69
69
|
* a tap opens a picker that ticks any number and takes a typed name, and closing it saves them all
|
|
70
70
|
* at once. Clicks stay off the row, which opens its details.
|
|
71
71
|
*/
|
|
72
|
-
export function EditManyCell({ label, values, options, unused = [], note, colorOf, onSave, }) {
|
|
72
|
+
export function EditManyCell({ label, values, options, unused = [], note, colorOf, iconOf, onSave, }) {
|
|
73
73
|
const [open, setOpen] = useState(false);
|
|
74
74
|
const [draft, setDraft] = useState(values);
|
|
75
75
|
const [error, setError] = useState(null);
|
|
@@ -99,7 +99,12 @@ export function EditManyCell({ label, values, options, unused = [], note, colorO
|
|
|
99
99
|
};
|
|
100
100
|
const row = (o) => {
|
|
101
101
|
const c = colorOf?.(o);
|
|
102
|
-
|
|
102
|
+
const i = iconOf?.(o);
|
|
103
|
+
return {
|
|
104
|
+
value: o,
|
|
105
|
+
label: o,
|
|
106
|
+
...(i ? { icon: tintedIcon(i, c) } : c ? { icon: colorIcon(c) } : {}),
|
|
107
|
+
};
|
|
103
108
|
};
|
|
104
109
|
const all = [...options, ...unused];
|
|
105
110
|
const picked = draft.filter((v) => !all.includes(v));
|
|
@@ -107,7 +112,7 @@ export function EditManyCell({ label, values, options, unused = [], note, colorO
|
|
|
107
112
|
{ label: 'In use', options: [...options, ...picked].map(row) },
|
|
108
113
|
{ label: 'Unused', options: unused.map(row) },
|
|
109
114
|
];
|
|
110
|
-
return (_jsxs("span", { className: "inline-flex min-w-0 items-center gap-1", onClick: stop, onKeyDown: stop, children: [values.length > 0 && (_jsx("button", { type: "button", "aria-label": `${label}: ${values.join(', ')}`, className: "flex min-w-0
|
|
115
|
+
return (_jsxs("span", { className: "inline-flex min-w-0 items-center gap-1", onClick: stop, onKeyDown: stop, children: [values.length > 0 && (_jsx("button", { type: "button", "aria-label": `${label}: ${values.join(', ')}`, className: "flex min-w-0 items-center gap-1 overflow-hidden rounded text-left", onClick: start, children: values.map((v) => (_jsx(ColorChip, { color: colorOf?.(v), icon: iconOf?.(v), children: v }, v))) })), _jsx(LumenSelector, { multiple: true, trigger: "icon", icon: values.length ? PencilLineIcon : PlusIcon, size: "sm", label: values.length ? `Change ${label.toLowerCase()}` : `Add ${label.toLowerCase()}`, className: cn('size-6 text-muted-foreground', values.length
|
|
111
116
|
? 'opacity-0 group-hover/row:opacity-100 focus-visible:opacity-100 max-md:opacity-100'
|
|
112
117
|
: '-ml-1'), groups: groups, value: draft, disabled: saving, empty: `Type a ${label.toLowerCase()} name.`, create: (q) => q.trim() || null, createLabel: (q) => `Add “${q.trim()}”`, open: open, onOpenChange: (o) => {
|
|
113
118
|
if (o)
|
package/dist/view-editor.js
CHANGED
|
@@ -1033,7 +1033,13 @@ function ColumnList({ base, domain, draft, setDraft, shownKeys, hiddenKeys, onEd
|
|
|
1033
1033
|
}) }) })) : (_jsx(WhyOff, { note: groupNote(f), children: _jsx(Checkbox, { "aria-label": `Group by ${f.label}`, disabled: true, checked: false }) })), _jsx("span", { className: "max-md:hidden", children: chippable(f) ? (_jsx(LumenSelector, { label: `Show ${f.label} as`, size: "sm", className: "h-7 w-full", options: Object.entries(CHIP_LABELS).map(([v, l]) => ({
|
|
1034
1034
|
value: v,
|
|
1035
1035
|
label: v === 'inline' ? `On ${first?.label ?? 'first'}` : l,
|
|
1036
|
-
})), value: placement(f.key), onChange: (v) => setPlacement(f.key, v) })) : f.
|
|
1036
|
+
})), value: placement(f.key), onChange: (v) => setPlacement(f.key, v) })) : f.showAs && f.showAs.length > 1 ? (_jsx(LumenSelector, { label: `Show ${f.label} as`, size: "sm", className: "h-7 w-full", options: f.showAs.map((o) => ({ value: o.id, label: o.label })), value: draft.shows?.[f.key] ?? f.showAs[0]?.id ?? '', onChange: (v) => {
|
|
1037
|
+
const { [f.key]: _, ...rest } = draft.shows ?? {};
|
|
1038
|
+
setDraft({
|
|
1039
|
+
...draft,
|
|
1040
|
+
shows: v === f.showAs?.[0]?.id ? rest : { ...rest, [f.key]: v },
|
|
1041
|
+
});
|
|
1042
|
+
} })) : f.format !== 'text' ? (_jsx(LumenSelector, { label: `Format of ${f.label}`, size: "sm", className: "h-7 w-full", options: formatOptions(), value: f.format, onChange: (v) => setDraft({
|
|
1037
1043
|
...draft,
|
|
1038
1044
|
formats: {
|
|
1039
1045
|
...draft.formats,
|
package/dist/view-model.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { JoinKey } from '@columenlabs/lumen-ui-types/domains';
|
|
2
2
|
import { type CustomViewConfig, type ViewAgg, type ViewChip, type ViewFormat, type ViewTotalAgg } from '@columenlabs/lumen-ui-types/views';
|
|
3
3
|
import type { LucideIcon } from 'lucide-react';
|
|
4
|
-
import type { ReactNode } from 'react';
|
|
4
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
5
5
|
import type { ChartBand, ChartMarker, Series } from './growth-chart.js';
|
|
6
6
|
export type ViewCellValue = number | string | null;
|
|
7
7
|
/** One field of a data domain: how to read it, show it, filter, group and roll it up. */
|
|
@@ -95,6 +95,22 @@ export interface ViewField<T> {
|
|
|
95
95
|
/** Draws the cell instead of its formatted value (a sparkline); sorting and filters still use
|
|
96
96
|
* `value` (strategy lab). */
|
|
97
97
|
render?: (row: T) => ReactNode;
|
|
98
|
+
/**
|
|
99
|
+
* Draws a group or Total row's cell from its rows instead of the rolled-up number: an amount with
|
|
100
|
+
* its unit, or a share worked out again as the rows' total over their allowance (never a sum of
|
|
101
|
+
* percents). Only where the field rolls up (`aggregate`).
|
|
102
|
+
*/
|
|
103
|
+
rollRender?: (rows: T[]) => ReactNode;
|
|
104
|
+
/**
|
|
105
|
+
* Ways the column can read, picked per column in Edit view ("Show as"), e.g. an amount or its % of
|
|
106
|
+
* an allowance. The first is the field as defined; each other one's `field` replaces those parts
|
|
107
|
+
* of it (value, format, render, aggregate...). The pick saves with the view (`shows`).
|
|
108
|
+
*/
|
|
109
|
+
showAs?: {
|
|
110
|
+
id: string;
|
|
111
|
+
label: string;
|
|
112
|
+
field?: Partial<Omit<ViewField<T>, 'key' | 'showAs'>>;
|
|
113
|
+
}[];
|
|
98
114
|
/** The ticker a click on the cell charts in the app's chart dialog (an option charts its
|
|
99
115
|
* underlying); null leaves the row's cell plain. */
|
|
100
116
|
chart?: (row: T) => string | null;
|
|
@@ -107,6 +123,10 @@ export interface ViewField<T> {
|
|
|
107
123
|
* cell, its chip and the edit picker. A CSS colour; a theme token reads in light and dark.
|
|
108
124
|
*/
|
|
109
125
|
color?: (value: string) => string | undefined;
|
|
126
|
+
/** A text value's icon (a label's), drawn in its `color` on its chip and in the edit picker. */
|
|
127
|
+
iconOf?: (value: string) => ComponentType<{
|
|
128
|
+
className?: string;
|
|
129
|
+
}> | undefined;
|
|
110
130
|
/** The cell's background, a theme colour mix (a P/L heat grid). */
|
|
111
131
|
tint?: (row: T) => string | undefined;
|
|
112
132
|
/** Left out on phones, where the table has no room for it (a returns table's longer windows). */
|
|
@@ -323,7 +343,7 @@ export declare const tilesOf: (c: CustomViewConfig) => ({
|
|
|
323
343
|
key: string;
|
|
324
344
|
value: string;
|
|
325
345
|
not?: boolean | undefined;
|
|
326
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
346
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
327
347
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
328
348
|
}[];
|
|
329
349
|
sign: boolean;
|
|
@@ -336,7 +356,7 @@ export declare const tilesOf: (c: CustomViewConfig) => ({
|
|
|
336
356
|
key: string;
|
|
337
357
|
value: string;
|
|
338
358
|
not?: boolean | undefined;
|
|
339
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
359
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
340
360
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
341
361
|
}[];
|
|
342
362
|
suffix: string;
|
package/dist/view-model.js
CHANGED
|
@@ -101,14 +101,22 @@ export function withViewFields(domain, c) {
|
|
|
101
101
|
const own = takesFormulas(domain) && formulasOf(c).length ? formulaFields(formulasOf(c)) : [];
|
|
102
102
|
const picked = c.formats ?? {};
|
|
103
103
|
const aggs = c.aggs ?? {};
|
|
104
|
-
|
|
104
|
+
const shows = c.shows ?? {};
|
|
105
|
+
if (!own.length &&
|
|
106
|
+
!Object.keys(picked).length &&
|
|
107
|
+
!Object.keys(aggs).length &&
|
|
108
|
+
!Object.keys(shows).length)
|
|
105
109
|
return domain;
|
|
106
110
|
const mine = new Set(own.map((f) => f.key));
|
|
107
111
|
// A text formula groups like any text field: each row's value is the formula
|
|
108
112
|
// over that row alone. One that reads group_sum or total_sum depends on the rows shown, so it
|
|
109
113
|
// cannot pick its own group.
|
|
110
114
|
const rowValue = (f) => (r) => computedOf(full, [r], null).value(f, r);
|
|
111
|
-
const
|
|
115
|
+
const shown = (f) => {
|
|
116
|
+
const alt = f.showAs?.find((o) => o.id === shows[f.key]);
|
|
117
|
+
return alt?.field ? { ...f, ...alt.field } : f;
|
|
118
|
+
};
|
|
119
|
+
const fields = [...domain.fields, ...own].map(shown).map((f) => {
|
|
112
120
|
if (f.format === 'text') {
|
|
113
121
|
if (!mine.has(f.key) || !f.formula)
|
|
114
122
|
return f;
|
package/dist/whats-new.js
CHANGED
|
@@ -3,7 +3,8 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
// every app): the version in the status bar opens the release notes, newest
|
|
4
4
|
// first, each release's Key takeaways only. An app turns it on with LumenShell's `releases`, its
|
|
5
5
|
// releases API (`GET ?limit=&before=` answering `{releases}`), which leaves out what the person can't
|
|
6
|
-
// open; a host that answers 404 (self-host an app) keeps the
|
|
6
|
+
// open; a host that answers 404 (self-host an app) keeps the button hidden. Until the first release
|
|
7
|
+
// the button reads "What's new" and opens an empty state, so a new app shows it from day one. With `apps`, each
|
|
7
8
|
// takeaway carries a chip of the app it is about (`apps` on the takeaway; none: everyone), and a
|
|
8
9
|
// release where one app has `GROUP_AT` or more is split into one sub-section per app.
|
|
9
10
|
import { useInfiniteQuery } from '@tanstack/react-query';
|
|
@@ -50,12 +51,13 @@ export function WhatsNew({ api, apps, everyone = 'Global', }) {
|
|
|
50
51
|
staleTime: 30 * 60_000,
|
|
51
52
|
retry: false,
|
|
52
53
|
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (!latest)
|
|
54
|
+
// Hidden while loading, on an error, and when the host has no releases API (404).
|
|
55
|
+
if (!q.data || q.data.pages[0] === null)
|
|
56
56
|
return null;
|
|
57
|
+
const releases = q.data.pages.flatMap((p) => p ?? []);
|
|
58
|
+
const latest = releases[0];
|
|
57
59
|
const day = (at) => new Date(at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', timeZone });
|
|
58
|
-
return (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", size: "sm", className: "num h-6 px-1.5 text-muted-foreground text-xs", onClick: () => setOpen(true), title: "What's new", children: latest
|
|
60
|
+
return (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", size: "sm", className: "num h-6 px-1.5 text-muted-foreground text-xs", onClick: () => setOpen(true), title: "What's new", children: latest?.tag ?? "What's new" }), _jsxs(LumenDrawer, { open: open, onClose: () => setOpen(false), title: "What's new", description: "Key takeaways of each release, newest first", footerStart: releases.length ? `${releases.length} releases` : undefined, footer: _jsxs(_Fragment, { children: [q.hasNextPage && (_jsx(Button, { variant: "outline", size: "sm", disabled: q.isFetchingNextPage, onClick: () => q.fetchNextPage(), children: "Show more" })), _jsx(Button, { size: "sm", onClick: () => setOpen(false), children: "Close" })] }), children: [!releases.length && (_jsx("p", { className: "py-2 text-muted-foreground text-sm", children: "No releases yet. Each release's key takeaways show here once it ships." })), releases.map((r, i) => (_jsx(DrawerSection, { title: r.tag, hint: day(r.published_at), defaultOpen: i === 0, children: r.takeaways.length ? (_jsx(Notes, { takeaways: r.takeaways, apps: apps, everyone: everyone })) : (_jsx("p", { className: "py-1 pl-1 text-muted-foreground text-sm", children: "Nothing new for you in this one." })) }, r.tag)))] })] }));
|
|
59
61
|
}
|
|
60
62
|
/** One release's takeaways: a flat list, or one sub-section per app once one app has many. */
|
|
61
63
|
function Notes({ takeaways, apps, everyone, }) {
|
|
@@ -72,7 +72,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
72
72
|
key: string;
|
|
73
73
|
value: string;
|
|
74
74
|
not?: boolean | undefined;
|
|
75
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
75
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
76
76
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
77
77
|
}[];
|
|
78
78
|
source?: string | undefined;
|
|
@@ -97,6 +97,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
97
97
|
}[];
|
|
98
98
|
formats?: Record<string, "compact" | "integer" | "number" | "percent" | "price" | "price_rounded" | "price_signed" | "rounded" | "signed" | "weight"> | undefined;
|
|
99
99
|
aggs?: Record<string, "count" | "distinct" | "first" | "last" | "max" | "mean" | "min" | "none" | "sum"> | undefined;
|
|
100
|
+
shows?: Record<string, string> | undefined;
|
|
100
101
|
group: {
|
|
101
102
|
fields: string[];
|
|
102
103
|
default: string | null;
|
|
@@ -135,7 +136,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
135
136
|
key: string;
|
|
136
137
|
value: string;
|
|
137
138
|
not?: boolean | undefined;
|
|
138
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
139
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
139
140
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
140
141
|
}[];
|
|
141
142
|
source?: string | undefined;
|
|
@@ -170,7 +171,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
170
171
|
key: string;
|
|
171
172
|
value: string;
|
|
172
173
|
not?: boolean | undefined;
|
|
173
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
174
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
174
175
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
175
176
|
}[];
|
|
176
177
|
source?: string | undefined;
|
|
@@ -195,7 +196,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
195
196
|
key: string;
|
|
196
197
|
value: string;
|
|
197
198
|
not?: boolean | undefined;
|
|
198
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
199
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
199
200
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
200
201
|
}[];
|
|
201
202
|
sign: boolean;
|
|
@@ -208,7 +209,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
208
209
|
key: string;
|
|
209
210
|
value: string;
|
|
210
211
|
not?: boolean | undefined;
|
|
211
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
212
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
212
213
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
213
214
|
}[];
|
|
214
215
|
suffix: string;
|
|
@@ -246,7 +247,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
246
247
|
key: string;
|
|
247
248
|
value: string;
|
|
248
249
|
not?: boolean | undefined;
|
|
249
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
250
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
250
251
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
251
252
|
}[];
|
|
252
253
|
source?: string | undefined;
|
|
@@ -270,7 +271,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
270
271
|
key: string;
|
|
271
272
|
value: string;
|
|
272
273
|
not?: boolean | undefined;
|
|
273
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
274
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
274
275
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
275
276
|
}[];
|
|
276
277
|
sign: boolean;
|
|
@@ -283,7 +284,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
283
284
|
key: string;
|
|
284
285
|
value: string;
|
|
285
286
|
not?: boolean | undefined;
|
|
286
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
287
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
287
288
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
288
289
|
}[];
|
|
289
290
|
suffix: string;
|
|
@@ -316,7 +317,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
316
317
|
key: string;
|
|
317
318
|
value: string;
|
|
318
319
|
not?: boolean | undefined;
|
|
319
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
320
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
320
321
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
321
322
|
}[];
|
|
322
323
|
source?: string | undefined;
|
|
@@ -353,7 +354,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
353
354
|
key: string;
|
|
354
355
|
value: string;
|
|
355
356
|
not?: boolean | undefined;
|
|
356
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
357
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
357
358
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
358
359
|
}[];
|
|
359
360
|
source?: string | undefined;
|
|
@@ -388,7 +389,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
388
389
|
key: string;
|
|
389
390
|
value: string;
|
|
390
391
|
not?: boolean | undefined;
|
|
391
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
392
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
392
393
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
393
394
|
}[];
|
|
394
395
|
source?: string | undefined;
|
|
@@ -423,7 +424,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
423
424
|
key: string;
|
|
424
425
|
value: string;
|
|
425
426
|
not?: boolean | undefined;
|
|
426
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
427
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
427
428
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
428
429
|
}[];
|
|
429
430
|
source?: string | undefined;
|
|
@@ -461,7 +462,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
461
462
|
key: string;
|
|
462
463
|
value: string;
|
|
463
464
|
not?: boolean | undefined;
|
|
464
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
465
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
465
466
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
466
467
|
}[];
|
|
467
468
|
source?: string | undefined;
|
|
@@ -493,7 +494,7 @@ export declare const readsRows: (card: ViewWidget) => card is {
|
|
|
493
494
|
key: string;
|
|
494
495
|
value: string;
|
|
495
496
|
not?: boolean | undefined;
|
|
496
|
-
op?: "between" | "eq" | "gt" | "lt" | undefined;
|
|
497
|
+
op?: "between" | "empty" | "eq" | "gt" | "lt" | undefined;
|
|
497
498
|
link?: "amber" | "blue" | "lime" | "pink" | "teal" | undefined;
|
|
498
499
|
}[];
|
|
499
500
|
source?: string | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
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.47",
|
|
45
45
|
"@dnd-kit/core": "6.3.1",
|
|
46
46
|
"@dnd-kit/sortable": "10.0.0",
|
|
47
47
|
"@dnd-kit/utilities": "3.2.2",
|