@siyahi/ui 0.1.9-next.35 → 0.1.9-next.37
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/DESIGN.md +80 -63
- package/README.md +10 -21
- package/THIRD_PARTY_NOTICES.md +15 -15
- package/agents/examples/chart-panels.tsx +0 -4
- package/agents/examples/metric-strip-headline.tsx +12 -0
- package/agents/examples/{section-cards-select.tsx → metric-strip-select.tsx} +5 -5
- package/agents/examples/metric-strip-trend.tsx +33 -0
- package/agents/examples/overview-dashboard.tsx +4 -4
- package/agents/examples/scatter-chart.tsx +0 -1
- package/agents/examples/stale-blocks.tsx +9 -9
- package/agents/examples/surfaces.tsx +1 -33
- package/agents/manifest.json +38 -53
- package/dist/components/registry/dashboardcn/kpi-row-card.d.ts +20 -6
- package/dist/components/registry/dashboardcn/kpi-row-card.js +52 -33
- package/dist/components/siyahi/callout.js +2 -1
- package/dist/components/siyahi/inline-code.d.ts +1 -1
- package/dist/components/siyahi/inline-code.js +1 -1
- package/dist/components/siyahi/page-header.js +1 -0
- package/dist/components/siyahi/panel-grid.d.ts +4 -6
- package/dist/components/siyahi/panel-grid.js +9 -12
- package/dist/components/siyahi/scatter-chart.d.ts +3 -3
- package/dist/components/siyahi/scatter-chart.js +6 -3
- package/dist/components/siyahi/siyahi-provider.d.ts +5 -15
- package/dist/components/siyahi/siyahi-provider.js +7 -17
- package/dist/index.d.ts +3 -4
- package/dist/index.js +3 -3
- package/dist/lib/chart-frame.d.ts +1 -1
- package/dist/lib/chart-frame.js +4 -2
- package/dist/lib/chart-series.d.ts +10 -2
- package/dist/lib/chart-series.js +10 -0
- package/dist/lib/fit-text.js +1 -1
- package/dist/lib/tone.d.ts +1 -1
- package/dist/lib/tone.js +1 -1
- package/package.json +2 -2
- package/registry.lock.json +0 -8
- package/styles/fallback-fonts.css +13 -13
- package/styles/fonts/m-plus-1-code-latin-ext-wght-normal.woff2 +0 -0
- package/styles/fonts/m-plus-1-code-latin-wght-normal.woff2 +0 -0
- package/styles/m-plus-1-code.css +21 -0
- package/styles/siyahi.css +166 -330
- package/agents/examples/section-cards-trend.tsx +0 -32
- package/agents/examples/section-cards.tsx +0 -48
- package/dist/components/registry/dashboard-01/section-cards.d.ts +0 -30
- package/dist/components/registry/dashboard-01/section-cards.js +0 -74
package/agents/manifest.json
CHANGED
|
@@ -100,26 +100,26 @@
|
|
|
100
100
|
]
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
|
-
"need": "Headline figures with
|
|
104
|
-
"guidance": "`
|
|
103
|
+
"need": "Headline figures, or many figures of equal weight, each with its change and recent run",
|
|
104
|
+
"guidance": "`MetricStrip`",
|
|
105
105
|
"components": [
|
|
106
|
-
"
|
|
107
|
-
"Delta"
|
|
106
|
+
"MetricStrip"
|
|
108
107
|
]
|
|
109
108
|
},
|
|
110
109
|
{
|
|
111
|
-
"need": "
|
|
112
|
-
"guidance": "`MetricStrip`",
|
|
110
|
+
"need": "The two to four figures a page leads with, set large at its top",
|
|
111
|
+
"guidance": "`MetricStrip` with `variant=\"blocks\"`, once per page, under the `PageHeader`",
|
|
113
112
|
"components": [
|
|
114
|
-
"MetricStrip"
|
|
113
|
+
"MetricStrip",
|
|
114
|
+
"PageHeader"
|
|
115
115
|
]
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
118
|
"need": "A run of values beside a figure, in a tile, a strip or a table cell",
|
|
119
|
-
"guidance": "`Sparkline`; in a
|
|
119
|
+
"guidance": "`Sparkline`; in a strip, `MetricStrip`'s `trend`",
|
|
120
120
|
"components": [
|
|
121
121
|
"Sparkline",
|
|
122
|
-
"
|
|
122
|
+
"MetricStrip"
|
|
123
123
|
]
|
|
124
124
|
},
|
|
125
125
|
{
|
|
@@ -228,10 +228,10 @@
|
|
|
228
228
|
]
|
|
229
229
|
},
|
|
230
230
|
{
|
|
231
|
-
"need": "
|
|
232
|
-
"guidance": "`
|
|
231
|
+
"need": "Figures that pick a scope for the page",
|
|
232
|
+
"guidance": "`MetricStrip` with `selected` and `onSelect`",
|
|
233
233
|
"components": [
|
|
234
|
-
"
|
|
234
|
+
"MetricStrip"
|
|
235
235
|
]
|
|
236
236
|
},
|
|
237
237
|
{
|
|
@@ -288,13 +288,6 @@
|
|
|
288
288
|
"PanelGrid"
|
|
289
289
|
]
|
|
290
290
|
},
|
|
291
|
-
{
|
|
292
|
-
"need": "Separate square cards instead of the default ruled panels, or no lines at all, for a page or a part of one",
|
|
293
|
-
"guidance": "`SiyahiProvider` with `surface=\"card\"` or `surface=\"open\"`",
|
|
294
|
-
"components": [
|
|
295
|
-
"SiyahiProvider"
|
|
296
|
-
]
|
|
297
|
-
},
|
|
298
291
|
{
|
|
299
292
|
"need": "A forecast stretch after the latest actual figure, or a marker for today",
|
|
300
293
|
"guidance": "`LineChartCard` or `AreaChartCard` with `forecastFrom` and `today` set to x values",
|
|
@@ -309,10 +302,10 @@
|
|
|
309
302
|
"components": []
|
|
310
303
|
},
|
|
311
304
|
{
|
|
312
|
-
"need": "A chart or
|
|
313
|
-
"guidance": "`stale` on the chart card or the `
|
|
305
|
+
"need": "A chart or figure whose data is old",
|
|
306
|
+
"guidance": "`stale` on the chart card or the `MetricStrip` item, with since when (\"3 Nov\"); `StaleNote` for another kind of block",
|
|
314
307
|
"components": [
|
|
315
|
-
"
|
|
308
|
+
"MetricStrip",
|
|
316
309
|
"StaleNote"
|
|
317
310
|
]
|
|
318
311
|
},
|
|
@@ -1026,6 +1019,28 @@
|
|
|
1026
1019
|
"LocalTime"
|
|
1027
1020
|
]
|
|
1028
1021
|
},
|
|
1022
|
+
{
|
|
1023
|
+
"file": "agents/examples/metric-strip-headline.tsx",
|
|
1024
|
+
"components": [
|
|
1025
|
+
"MetricStrip",
|
|
1026
|
+
"useFormat"
|
|
1027
|
+
]
|
|
1028
|
+
},
|
|
1029
|
+
{
|
|
1030
|
+
"file": "agents/examples/metric-strip-select.tsx",
|
|
1031
|
+
"components": [
|
|
1032
|
+
"Delta",
|
|
1033
|
+
"MetricStrip",
|
|
1034
|
+
"useFormat"
|
|
1035
|
+
]
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
"file": "agents/examples/metric-strip-trend.tsx",
|
|
1039
|
+
"components": [
|
|
1040
|
+
"MetricStrip",
|
|
1041
|
+
"useFormat"
|
|
1042
|
+
]
|
|
1043
|
+
},
|
|
1029
1044
|
{
|
|
1030
1045
|
"file": "agents/examples/metric-strip.tsx",
|
|
1031
1046
|
"components": [
|
|
@@ -1186,31 +1201,6 @@
|
|
|
1186
1201
|
"Separator"
|
|
1187
1202
|
]
|
|
1188
1203
|
},
|
|
1189
|
-
{
|
|
1190
|
-
"file": "agents/examples/section-cards-select.tsx",
|
|
1191
|
-
"components": [
|
|
1192
|
-
"Delta",
|
|
1193
|
-
"SectionCards",
|
|
1194
|
-
"useFormat"
|
|
1195
|
-
]
|
|
1196
|
-
},
|
|
1197
|
-
{
|
|
1198
|
-
"file": "agents/examples/section-cards-trend.tsx",
|
|
1199
|
-
"components": [
|
|
1200
|
-
"Delta",
|
|
1201
|
-
"SectionCards",
|
|
1202
|
-
"Sparkline",
|
|
1203
|
-
"useFormat"
|
|
1204
|
-
]
|
|
1205
|
-
},
|
|
1206
|
-
{
|
|
1207
|
-
"file": "agents/examples/section-cards.tsx",
|
|
1208
|
-
"components": [
|
|
1209
|
-
"Delta",
|
|
1210
|
-
"SectionCards",
|
|
1211
|
-
"useFormat"
|
|
1212
|
-
]
|
|
1213
|
-
},
|
|
1214
1204
|
{
|
|
1215
1205
|
"file": "agents/examples/select.tsx",
|
|
1216
1206
|
"components": [
|
|
@@ -1279,9 +1269,7 @@
|
|
|
1279
1269
|
"file": "agents/examples/stale-blocks.tsx",
|
|
1280
1270
|
"components": [
|
|
1281
1271
|
"AreaChartCard",
|
|
1282
|
-
"
|
|
1283
|
-
"SectionCards",
|
|
1284
|
-
"Sparkline",
|
|
1272
|
+
"MetricStrip",
|
|
1285
1273
|
"useFormat"
|
|
1286
1274
|
]
|
|
1287
1275
|
},
|
|
@@ -1296,15 +1284,12 @@
|
|
|
1296
1284
|
"CardTitle",
|
|
1297
1285
|
"MetricStrip",
|
|
1298
1286
|
"PanelGrid",
|
|
1299
|
-
"SiyahiProvider",
|
|
1300
1287
|
"Table",
|
|
1301
1288
|
"TableBody",
|
|
1302
1289
|
"TableCell",
|
|
1303
1290
|
"TableHead",
|
|
1304
1291
|
"TableHeader",
|
|
1305
1292
|
"TableRow",
|
|
1306
|
-
"ToggleGroup",
|
|
1307
|
-
"ToggleGroupItem",
|
|
1308
1293
|
"useFormat"
|
|
1309
1294
|
]
|
|
1310
1295
|
},
|
|
@@ -2,21 +2,25 @@ import { Card } from "../../ui/card.js";
|
|
|
2
2
|
import * as React$1 from "react";
|
|
3
3
|
//#region src/components/registry/dashboardcn/kpi-row-card.d.ts
|
|
4
4
|
export interface MetricStripItem {
|
|
5
|
-
/**
|
|
5
|
+
/** Small capital label above the figure; it also names the figure's button in a picker. */
|
|
6
6
|
label: string;
|
|
7
7
|
/** The figure, formatted by the page: money(4512300). */
|
|
8
8
|
value: React$1.ReactNode;
|
|
9
9
|
/** The signed change, drawn as a Delta under the figure; its sign colours the trend. For "pct", a fraction. */
|
|
10
10
|
change?: number | undefined;
|
|
11
11
|
changeFormat?: "pct" | "money" | undefined;
|
|
12
|
-
/** Muted words after the change, such as "vs last month". */
|
|
12
|
+
/** Muted words after the change, such as "vs last month", or what the figure covers. */
|
|
13
13
|
note?: React$1.ReactNode;
|
|
14
|
-
/** Recent values, oldest first, drawn as a sparkline
|
|
14
|
+
/** Recent values, oldest first, drawn as a sparkline under the figure. */
|
|
15
15
|
trend?: number[] | undefined;
|
|
16
16
|
/** Marks the figure as the exception on the page: a faint wash of the colour and an outline of it. */
|
|
17
17
|
tone?: "negative" | "warning" | undefined;
|
|
18
|
+
/** Marks the figure's data as old, with since when, such as "3 Nov": it greys out and says so. */
|
|
19
|
+
stale?: React$1.ReactNode;
|
|
20
|
+
/** In a picker, a figure that cannot be picked, such as one with nothing in it: faded, its button disabled. */
|
|
21
|
+
disabled?: boolean | undefined;
|
|
18
22
|
}
|
|
19
|
-
export interface MetricStripProps extends Omit<React$1.ComponentProps<typeof Card>, "title"> {
|
|
23
|
+
export interface MetricStripProps extends Omit<React$1.ComponentProps<typeof Card>, "title" | "onSelect"> {
|
|
20
24
|
title?: React$1.ReactNode;
|
|
21
25
|
description?: React$1.ReactNode;
|
|
22
26
|
/** A range toggle, top right, that changes every figure. */
|
|
@@ -24,8 +28,18 @@ export interface MetricStripProps extends Omit<React$1.ComponentProps<typeof Car
|
|
|
24
28
|
items: MetricStripItem[];
|
|
25
29
|
/** Lines under the strip, such as what the figures cover. */
|
|
26
30
|
footer?: React$1.ReactNode;
|
|
31
|
+
/** The label of the picked figure. */
|
|
32
|
+
selected?: string | undefined;
|
|
33
|
+
/** Makes each figure one button, so keep figure content non-interactive; gets the label of the figure picked. */
|
|
34
|
+
onSelect?: ((label: string) => void) | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* "strip", the default: figures on the page with their sparklines. "blocks": the page's headline, two to four
|
|
37
|
+
* figures each on a solid block with a large value; it draws no sparkline and no tone, so mark an exception in a
|
|
38
|
+
* strip below it. One per page.
|
|
39
|
+
*/
|
|
40
|
+
variant?: "strip" | "blocks" | undefined;
|
|
27
41
|
}
|
|
28
|
-
/** A
|
|
29
|
-
declare function MetricStrip({ title, description, action, items, footer, className, ...props }: MetricStripProps): React$1.JSX.Element;
|
|
42
|
+
/** A row of figures, each with its change and recent run, optionally a picker that scopes the page. */
|
|
43
|
+
declare function MetricStrip({ title, description, action, items, footer, selected, onSelect, variant, className, ...props }: MetricStripProps): React$1.JSX.Element;
|
|
30
44
|
//#endregion
|
|
31
45
|
export { MetricStrip };
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../../ui/card.js";
|
|
2
2
|
import { cn } from "../../../lib/utils.js";
|
|
3
|
+
import { StaleNote } from "../../siyahi/stale-note.js";
|
|
3
4
|
import { Delta } from "../../siyahi/delta.js";
|
|
4
5
|
import { Sparkline } from "./sparkline.js";
|
|
5
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
7
|
import "react";
|
|
7
8
|
//#region src/components/registry/dashboardcn/kpi-row-card.tsx
|
|
8
9
|
const COLUMNS = {
|
|
9
|
-
1: "
|
|
10
|
-
2: "
|
|
11
|
-
3: "
|
|
12
|
-
4: "
|
|
13
|
-
5: "
|
|
14
|
-
6: "
|
|
15
|
-
|
|
10
|
+
1: "",
|
|
11
|
+
2: "@2xs/strip:grid-cols-2",
|
|
12
|
+
3: "@lg/strip:grid-cols-3",
|
|
13
|
+
4: "@2xs/strip:grid-cols-2 @3xl/strip:grid-cols-4",
|
|
14
|
+
5: "@lg/strip:grid-cols-3 @3xl/strip:grid-cols-5",
|
|
15
|
+
6: "@2xs/strip:grid-cols-2 @xl/strip:grid-cols-3 @5xl/strip:grid-cols-6",
|
|
16
|
+
7: "@2xl/strip:grid-cols-4 @7xl/strip:grid-cols-7",
|
|
17
|
+
8: "@2xs/strip:grid-cols-2 @3xl/strip:grid-cols-4 @7xl/strip:grid-cols-8"
|
|
16
18
|
};
|
|
17
19
|
function trendColor(change) {
|
|
18
20
|
if (change === void 0) return "var(--chart-1)";
|
|
@@ -20,9 +22,10 @@ function trendColor(change) {
|
|
|
20
22
|
if (change < 0) return "var(--negative)";
|
|
21
23
|
return "var(--muted-foreground)";
|
|
22
24
|
}
|
|
23
|
-
/** A
|
|
24
|
-
function MetricStrip({ title, description, action, items, footer, className, ...props }) {
|
|
25
|
+
/** A row of figures, each with its change and recent run, optionally a picker that scopes the page. */
|
|
26
|
+
function MetricStrip({ title, description, action, items, footer, selected, onSelect, variant = "strip", className, ...props }) {
|
|
25
27
|
const columns = COLUMNS[Math.min(items.length, 8)] ?? COLUMNS[8];
|
|
28
|
+
const blocks = variant === "blocks";
|
|
26
29
|
return /* @__PURE__ */ jsxs(Card, {
|
|
27
30
|
className: cn("gap-4", className),
|
|
28
31
|
...props,
|
|
@@ -34,40 +37,56 @@ function MetricStrip({ title, description, action, items, footer, className, ...
|
|
|
34
37
|
] }),
|
|
35
38
|
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx("div", {
|
|
36
39
|
"data-slot": "metric-strip",
|
|
37
|
-
|
|
40
|
+
"data-variant": variant,
|
|
41
|
+
className: "@container/strip",
|
|
38
42
|
children: /* @__PURE__ */ jsx("div", {
|
|
39
|
-
className: "-
|
|
43
|
+
className: cn("grid grid-cols-1", blocks ? "gap-0" : "gap-4", columns),
|
|
40
44
|
children: items.map((item) => /* @__PURE__ */ jsxs("div", {
|
|
41
45
|
"data-slot": "metric-strip-item",
|
|
42
|
-
"data-tone": item.tone,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
"data-tone": blocks ? void 0 : item.tone,
|
|
47
|
+
"data-stale": item.stale ? "" : void 0,
|
|
48
|
+
"data-picked": onSelect && item.label === selected ? "" : void 0,
|
|
49
|
+
className: cn("relative grid min-w-0 grid-rows-subgrid gap-y-1", blocks ? "row-span-3 p-4" : "row-span-4", onSelect && item.disabled && "opacity-60"),
|
|
50
|
+
children: [
|
|
51
|
+
onSelect && /* @__PURE__ */ jsx("button", {
|
|
52
|
+
type: "button",
|
|
53
|
+
"aria-label": item.label,
|
|
54
|
+
"aria-pressed": item.label === selected,
|
|
55
|
+
disabled: item.disabled,
|
|
56
|
+
onClick: () => onSelect(item.label),
|
|
57
|
+
className: "absolute -inset-2 z-10 outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
58
|
+
}),
|
|
59
|
+
/* @__PURE__ */ jsx("div", {
|
|
60
|
+
"data-slot": "metric-strip-label",
|
|
61
|
+
className: "font-mono text-2xs tracking-wider break-words text-muted-foreground uppercase",
|
|
62
|
+
children: item.label
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ jsx("div", {
|
|
65
|
+
"data-slot": "metric-strip-value",
|
|
66
|
+
className: cn("font-semibold tabular-nums", blocks ? "mt-2 text-4xl leading-none tracking-tighter" : "text-lg tracking-tight"),
|
|
67
|
+
children: item.value
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ jsxs("div", {
|
|
70
|
+
className: "flex flex-wrap items-center gap-x-1.5 gap-y-1 self-start text-xs",
|
|
71
|
+
children: [
|
|
72
|
+
item.change !== void 0 && /* @__PURE__ */ jsx(Delta, {
|
|
57
73
|
value: item.change,
|
|
58
74
|
format: item.changeFormat
|
|
59
|
-
}),
|
|
75
|
+
}),
|
|
76
|
+
item.note && /* @__PURE__ */ jsx("span", {
|
|
60
77
|
className: "text-muted-foreground",
|
|
61
78
|
children: item.note
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
|
|
79
|
+
}),
|
|
80
|
+
item.stale && /* @__PURE__ */ jsx(StaleNote, { since: item.stale })
|
|
81
|
+
]
|
|
82
|
+
}),
|
|
83
|
+
blocks ? null : item.trend && item.trend.length > 1 ? /* @__PURE__ */ jsx(Sparkline, {
|
|
65
84
|
data: item.trend,
|
|
66
85
|
variant: "line",
|
|
67
86
|
color: trendColor(item.change),
|
|
68
|
-
className: "h-
|
|
69
|
-
})
|
|
70
|
-
|
|
87
|
+
className: "mt-1 h-8 w-full"
|
|
88
|
+
}) : /* @__PURE__ */ jsx("div", {})
|
|
89
|
+
]
|
|
71
90
|
}, item.label))
|
|
72
91
|
})
|
|
73
92
|
}) }),
|
|
@@ -21,9 +21,10 @@ function Callout({ tone = "neutral", icon, title, className, children, ...props
|
|
|
21
21
|
}), /* @__PURE__ */ jsxs("div", {
|
|
22
22
|
className: "flex min-w-0 flex-col gap-1",
|
|
23
23
|
children: [title && /* @__PURE__ */ jsx("p", {
|
|
24
|
-
className: "font-medium",
|
|
24
|
+
className: "font-heading font-medium",
|
|
25
25
|
children: title
|
|
26
26
|
}), /* @__PURE__ */ jsx("div", {
|
|
27
|
+
"data-slot": "callout-description",
|
|
27
28
|
className: "text-pretty text-muted-foreground [&_strong]:text-foreground",
|
|
28
29
|
children
|
|
29
30
|
})]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
//#region src/components/siyahi/inline-code.d.ts
|
|
3
|
-
/** A command, file name or identifier inside prose, in
|
|
3
|
+
/** A command, file name or identifier inside prose, in the mono face on a muted chip, at the size of the text around it. */
|
|
4
4
|
export declare function InlineCode({ children }: {
|
|
5
5
|
children: ReactNode;
|
|
6
6
|
}): import("react").JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
//#region src/components/siyahi/inline-code.tsx
|
|
3
|
-
/** A command, file name or identifier inside prose, in
|
|
3
|
+
/** A command, file name or identifier inside prose, in the mono face on a muted chip, at the size of the text around it. */
|
|
4
4
|
function InlineCode({ children }) {
|
|
5
5
|
return /* @__PURE__ */ jsx("code", {
|
|
6
6
|
className: "rounded-sm bg-muted px-1 font-mono",
|
|
@@ -25,6 +25,7 @@ function PageHeader({ eyebrow, title, lead, detail, actions, mark }) {
|
|
|
25
25
|
children: title
|
|
26
26
|
}),
|
|
27
27
|
(lead || detail) && /* @__PURE__ */ jsxs("div", {
|
|
28
|
+
"data-slot": "page-header-description",
|
|
28
29
|
className: "text-sm text-pretty text-muted-foreground",
|
|
29
30
|
children: [
|
|
30
31
|
lead,
|
|
@@ -9,18 +9,16 @@ declare const COLUMNS: {
|
|
|
9
9
|
export interface PanelGridProps {
|
|
10
10
|
/**
|
|
11
11
|
* Blocks across from a 42rem grid, so three short ones fit a reading column (an article's 55rem); 4 goes two across
|
|
12
|
-
* there and four from 64rem. Below 42rem they sit one under another.
|
|
12
|
+
* there and four from 64rem. Below 42rem they sit one under another. From 140rem a grid of 2 takes a third across,
|
|
13
|
+
* and from 180rem a grid of 2 or 3 a fourth, when it holds that many blocks; 1 stays one.
|
|
13
14
|
*/
|
|
14
15
|
columns?: keyof typeof COLUMNS | undefined;
|
|
15
16
|
children: ReactNode;
|
|
16
17
|
className?: string | undefined;
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
|
-
* Data blocks side by side: chart cards, tables, a MetricStrip.
|
|
20
|
-
* with
|
|
21
|
-
* on its sides; open leaves whitespace between them, and card an 8px gap between boxes. Each block's bottom and end
|
|
22
|
-
* edges carry its rules and the grid clips the ones on its own edges, so an empty cell at the end of a short last row
|
|
23
|
-
* is a blank stretch of the sheet, ruled off like the rest. The theme numbers each block's card title 01, 02.
|
|
20
|
+
* Data blocks side by side: chart cards, tables, a MetricStrip. Space parts the blocks, 16px across and 12px down,
|
|
21
|
+
* with no box and no rule. The theme numbers each block's card title 01, 02.
|
|
24
22
|
*/
|
|
25
23
|
export declare function PanelGrid({ columns, children, className }: PanelGridProps): import("react").JSX.Element;
|
|
26
24
|
//#endregion
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useSurface } from "./siyahi-provider.js";
|
|
2
1
|
import { cn } from "cn";
|
|
3
2
|
import { jsx } from "react/jsx-runtime";
|
|
4
3
|
import { Children } from "react";
|
|
@@ -9,25 +8,23 @@ const COLUMNS = {
|
|
|
9
8
|
3: "@2xl/panels:grid-cols-3",
|
|
10
9
|
4: "@2xl/panels:grid-cols-2 @5xl/panels:grid-cols-4"
|
|
11
10
|
};
|
|
11
|
+
const WIDE_THREE = "@min-[140rem]/panels:grid-cols-3";
|
|
12
|
+
const WIDE_FOUR = "@min-[180rem]/panels:grid-cols-4";
|
|
12
13
|
/**
|
|
13
|
-
* Data blocks side by side: chart cards, tables, a MetricStrip.
|
|
14
|
-
* with
|
|
15
|
-
* on its sides; open leaves whitespace between them, and card an 8px gap between boxes. Each block's bottom and end
|
|
16
|
-
* edges carry its rules and the grid clips the ones on its own edges, so an empty cell at the end of a short last row
|
|
17
|
-
* is a blank stretch of the sheet, ruled off like the rest. The theme numbers each block's card title 01, 02.
|
|
14
|
+
* Data blocks side by side: chart cards, tables, a MetricStrip. Space parts the blocks, 16px across and 12px down,
|
|
15
|
+
* with no box and no rule. The theme numbers each block's card title 01, 02.
|
|
18
16
|
*/
|
|
19
17
|
function PanelGrid({ columns = 2, children, className }) {
|
|
20
|
-
const
|
|
21
|
-
const
|
|
18
|
+
const blocks = Children.toArray(children).length;
|
|
19
|
+
const wide = cn(columns === 2 && blocks >= 3 && WIDE_THREE, (columns === 2 || columns === 3) && blocks >= 4 && WIDE_FOUR);
|
|
22
20
|
return /* @__PURE__ */ jsx("div", {
|
|
23
21
|
"data-slot": "panel-grid",
|
|
24
|
-
"
|
|
25
|
-
className: cn("@container/panels", ruled && "overflow-clip border-y", className),
|
|
22
|
+
className: cn("@container/panels", className),
|
|
26
23
|
children: /* @__PURE__ */ jsx("div", {
|
|
27
|
-
className: cn("grid grid-cols-1
|
|
24
|
+
className: cn("grid grid-cols-1 gap-x-4 gap-y-3", COLUMNS[columns], wide),
|
|
28
25
|
children: Children.map(children, (child) => /* @__PURE__ */ jsx("div", {
|
|
29
26
|
"data-slot": "panel",
|
|
30
|
-
className:
|
|
27
|
+
className: "min-w-0",
|
|
31
28
|
children: child
|
|
32
29
|
}))
|
|
33
30
|
})
|
|
@@ -25,8 +25,8 @@ export interface ScatterChartCardProps<T extends ScatterPoint> {
|
|
|
25
25
|
action?: ReactNode;
|
|
26
26
|
/** Most important first: earlier points take the labels. */
|
|
27
27
|
points: T[];
|
|
28
|
-
/** Height of the plot, in pixels. */
|
|
29
|
-
height
|
|
28
|
+
/** Height of the plot, in pixels. Left out, it follows the plot's width (fittedChartHeight). */
|
|
29
|
+
height?: number | undefined;
|
|
30
30
|
/** What the x axis measures, under it, such as "Share of sales". */
|
|
31
31
|
xLabel: string;
|
|
32
32
|
/** What the y axis measures, beside it, such as "Growth on last year". */
|
|
@@ -64,6 +64,6 @@ export interface ScatterChartCardProps<T extends ScatterPoint> {
|
|
|
64
64
|
sizeFormatter?: ((value: number) => string) | undefined;
|
|
65
65
|
}
|
|
66
66
|
/** Two measures per item as dots, such as size against growth, with the leading names beside their dots. */
|
|
67
|
-
export declare function ScatterChartCard<T extends ScatterPoint>({ title, description, action, points, height, xLabel, yLabel, xScale, xScaleToggle, yScale, yScaleToggle, xFormatter, yFormatter, labels, details, selected, onSelect, footer, quadrants, sizeLabel, sizeFormatter }: ScatterChartCardProps<T>): import("react").JSX.Element;
|
|
67
|
+
export declare function ScatterChartCard<T extends ScatterPoint>({ title, description, action, points, height: fixedHeight, xLabel, yLabel, xScale, xScaleToggle, yScale, yScaleToggle, xFormatter, yFormatter, labels, details, selected, onSelect, footer, quadrants, sizeLabel, sizeFormatter }: ScatterChartCardProps<T>): import("react").JSX.Element;
|
|
68
68
|
//#endregion
|
|
69
69
|
export type { ScatterQuadrants };
|
|
@@ -2,7 +2,9 @@ import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader,
|
|
|
2
2
|
import { ChartContainer } from "../ui/chart.js";
|
|
3
3
|
import { LOG_BLOCKED, useAxisScale } from "./scale-toggle.js";
|
|
4
4
|
import { useLocale } from "./siyahi-provider.js";
|
|
5
|
+
import { fittedChartHeight } from "../../lib/chart-series.js";
|
|
5
6
|
import { fitsLog, ticksFor } from "../../lib/ticks.js";
|
|
7
|
+
import { useElementWidth } from "../../lib/use-element-width.js";
|
|
6
8
|
import { fontLoads, useRenderWhenFontsLoad } from "../../lib/use-render-when-fonts-load.js";
|
|
7
9
|
import { corners, dotSizes, placeLabels, quadrantSplit } from "../../lib/scatter.js";
|
|
8
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -17,11 +19,12 @@ const NAME_BAND = 42;
|
|
|
17
19
|
const TICK = { className: "fill-muted-foreground font-mono" };
|
|
18
20
|
const AXIS_TITLE = "fill-muted-foreground text-xs";
|
|
19
21
|
const keyOf = (point) => point.key ?? point.name;
|
|
20
|
-
const MONO_WIDTH =
|
|
22
|
+
const MONO_WIDTH = 6;
|
|
21
23
|
/** Two measures per item as dots, such as size against growth, with the leading names beside their dots. */
|
|
22
|
-
function ScatterChartCard({ title, description, action, points, height, xLabel, yLabel, xScale = "linear", xScaleToggle = false, yScale = "linear", yScaleToggle = false, xFormatter, yFormatter, labels = 12, details, selected = null, onSelect, footer, quadrants, sizeLabel = "Size", sizeFormatter }) {
|
|
24
|
+
function ScatterChartCard({ title, description, action, points, height: fixedHeight, xLabel, yLabel, xScale = "linear", xScaleToggle = false, yScale = "linear", yScaleToggle = false, xFormatter, yFormatter, labels = 12, details, selected = null, onSelect, footer, quadrants, sizeLabel = "Size", sizeFormatter }) {
|
|
23
25
|
const { numberLocale } = useLocale();
|
|
24
|
-
const plotRef =
|
|
26
|
+
const [plotRef, plotWidth] = useElementWidth();
|
|
27
|
+
const height = fixedHeight ?? fittedChartHeight(plotWidth);
|
|
25
28
|
const [focusedKey, setFocusedKey] = useState(null);
|
|
26
29
|
const keyed = useRef(null);
|
|
27
30
|
useEffect(() => {
|
|
@@ -2,25 +2,15 @@ import { Optional } from "../../lib/optional.js";
|
|
|
2
2
|
import { SiyahiLocale } from "../../lib/locale.js";
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
4
|
//#region src/components/siyahi/siyahi-provider.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* How a data block sits on the page. "ruled", the default: blocks filled with the card colour and parted by hairlines,
|
|
7
|
-
* with a rule above and below each group and none on its sides. "card": a filled square card in a hairline ring, 8px
|
|
8
|
-
* from the next, for a page of separate blocks. "open": no fill and no lines, the block's content level with the
|
|
9
|
-
* page's text.
|
|
10
|
-
*/
|
|
11
|
-
export type Surface = "ruled" | "card" | "open";
|
|
12
5
|
export interface SiyahiProviderProps {
|
|
13
6
|
/** Any setting left out keeps its default: en-IN, INR, Asia/Kolkata. */
|
|
14
7
|
locale?: Optional<SiyahiLocale> | undefined;
|
|
15
|
-
/**
|
|
16
|
-
* Set it on a nested provider for one part of a page. Left out, a provider keeps the surface around it, so a
|
|
17
|
-
* provider that only changes the locale changes nothing else; the outermost default is "ruled".
|
|
18
|
-
*/
|
|
19
|
-
surface?: Surface | undefined;
|
|
20
8
|
children: ReactNode;
|
|
21
9
|
}
|
|
22
|
-
/**
|
|
23
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Wrap the app once. Carries the locale and the tooltip provider shadcn asks for, and draws no element of its own, so
|
|
12
|
+
* a provider that changes the locale for a table's rows can sit inside a <tbody>.
|
|
13
|
+
*/
|
|
14
|
+
export declare function SiyahiProvider({ locale, children }: SiyahiProviderProps): import("react").JSX.Element;
|
|
24
15
|
export declare function useLocale(): SiyahiLocale;
|
|
25
|
-
export declare function useSurface(): Surface;
|
|
26
16
|
//#endregion
|
|
@@ -4,9 +4,11 @@ import { jsx } from "react/jsx-runtime";
|
|
|
4
4
|
import { createContext, use, useMemo } from "react";
|
|
5
5
|
//#region src/components/siyahi/siyahi-provider.tsx
|
|
6
6
|
const LocaleContext = createContext(defaultLocale);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Wrap the app once. Carries the locale and the tooltip provider shadcn asks for, and draws no element of its own, so
|
|
9
|
+
* a provider that changes the locale for a table's rows can sit inside a <tbody>.
|
|
10
|
+
*/
|
|
11
|
+
function SiyahiProvider({ locale, children }) {
|
|
10
12
|
const { numberLocale = defaultLocale.numberLocale, currency = defaultLocale.currency, timeZone = defaultLocale.timeZone } = locale ?? {};
|
|
11
13
|
const value = useMemo(() => ({
|
|
12
14
|
numberLocale,
|
|
@@ -17,25 +19,13 @@ function SiyahiProvider({ locale, surface, children }) {
|
|
|
17
19
|
currency,
|
|
18
20
|
timeZone
|
|
19
21
|
]);
|
|
20
|
-
const around = use(SurfaceContext);
|
|
21
22
|
return /* @__PURE__ */ jsx(LocaleContext, {
|
|
22
23
|
value,
|
|
23
|
-
children: /* @__PURE__ */ jsx(
|
|
24
|
-
value: surface ?? around,
|
|
25
|
-
children: /* @__PURE__ */ jsx(TooltipProvider, { children: surface ? /* @__PURE__ */ jsx("div", {
|
|
26
|
-
"data-slot": "siyahi-provider",
|
|
27
|
-
"data-surface": surface,
|
|
28
|
-
className: "contents",
|
|
29
|
-
children
|
|
30
|
-
}) : children })
|
|
31
|
-
})
|
|
24
|
+
children: /* @__PURE__ */ jsx(TooltipProvider, { children })
|
|
32
25
|
});
|
|
33
26
|
}
|
|
34
27
|
function useLocale() {
|
|
35
28
|
return use(LocaleContext);
|
|
36
29
|
}
|
|
37
|
-
function useSurface() {
|
|
38
|
-
return use(SurfaceContext);
|
|
39
|
-
}
|
|
40
30
|
//#endregion
|
|
41
|
-
export { SiyahiProvider, useLocale
|
|
31
|
+
export { SiyahiProvider, useLocale };
|