@siyahi/ui 0.1.9-next.36 → 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 CHANGED
@@ -10,13 +10,14 @@ component; this file says how to use them.
10
10
  Colour is placed, not spread. A page is neutral greys plus colour that carries
11
11
  a meaning:
12
12
 
13
- - **Ink indigo** is the accent: links, the selected sidebar item, the first
14
- chart series, a chart's "today" rule and an `accent` `Callout`. Buttons, badges, toggles and focus
15
- stay monochrome.
13
+ - **Terminal amber** is the accent: links, the page's eyebrow and panel
14
+ numbers, the selected sidebar item and an `accent` `Callout`. Buttons,
15
+ badges, toggles and focus stay monochrome. Charts keep their own five-hue
16
+ palette, indigo first.
16
17
  - **Green and red** mean a gain and a loss. A signed figure is `Delta`: the figure in the text colour with its
17
18
  `+` or `−`, and only a small trend icon in green or red. In plain text (labels, tooltips) write the sign; never
18
19
  colour a run of figures green and red.
19
- **Amber** means caution. None of them decorates.
20
+ **Yellow** means caution, kept apart from the amber accent. None of them decorates.
20
21
  - **Emphasis tints the whole surface.** A notice is `StatusAlert` in its tone (an
21
22
  error reads like a warning, only red); a state is `StatusBadge`; a point set
22
23
  apart is `Callout` (`neutral`, `accent`, `warning`, `positive`,
@@ -42,8 +43,8 @@ a meaning:
42
43
  fill alike. A field shows it as its own edge, 2px in the text colour; a chart
43
44
  mark as a dashed stroke, apart from a picked mark's solid one. A destructive
44
45
  control and an invalid field focus in the destructive red. Menu items show
45
- focus as their highlight. A selected
46
- toggle or pill tab fills with the foreground. A chart bar that a selection
46
+ focus as their highlight. A selected toggle or pill tab fills with the
47
+ foreground, as stock's faint grey cannot be told from the rest. A chart bar that a selection
47
48
  dims keeps its full-colour outline and fades only inside.
48
49
  - **Destructive is not loss.** `--destructive` (delete, an invalid field) is a
49
50
  deeper red than `--negative` (a loss figure), so its label reads on its own
@@ -62,19 +63,13 @@ a meaning:
62
63
 
63
64
  ## Surfaces
64
65
 
65
- `SiyahiProvider`'s `surface` sets how a data block sits on the page. The page
66
- and card colours are fixed: never tint the canvas.
67
-
68
- - **`open`** (the default, with or without a provider): no fill, no ring and
69
- no padding, so a block's content sits level with the page's text. Space, not
70
- a box or a rule, parts the blocks: 24px across and 16px down in a
71
- `PanelGrid`, 24px between `MetricStrip` figures. A lighter box on the canvas
72
- cuts off abruptly and spends room on its own padding, so data sits on the
73
- page. Set nothing to get it.
74
- - **`card`**: tight square cards, for a page of separate blocks, such as an
75
- index of links. Each block is filled with the card colour inside a hairline
76
- ring, with no shadow, 8px from the next in a `PanelGrid`. Ask for it with
77
- `surface="card"`.
66
+ A data block sits open on the page: a `Card` has no fill, no ring and no
67
+ padding, so its content sits level with the page's text. Space, not a box or a
68
+ rule, parts the blocks: 16px across and 12px down in a `PanelGrid`, 16px
69
+ between `MetricStrip` figures. A lighter box on the canvas cuts off abruptly
70
+ and spends room on its own padding, so data sits on the page. `--card` is the
71
+ page colour, so what a block's marks mix into is what lies under them. The
72
+ page colour is fixed: never tint the canvas.
78
73
 
79
74
  ## Density
80
75
 
@@ -102,24 +97,30 @@ mono face and the link colour, so the text can point to one.
102
97
 
103
98
  ## Shape
104
99
 
105
- - **Square corners everywhere**: panels, cards, buttons, fields, badges,
106
- toggles, menus, bars and tracks (data bars, progress, a slider's track and
107
- thumb, a scrollbar's thumb), heatmap cells, treemap tiles and the colour
108
- chips of charts and legends alike (`--radius` is 0). Only what is round by
109
- nature stays round: an avatar, a radio, a status dot, a line's end dot, a
110
- spinner, and a signed calendar heatmap's loss day, whose shape carries its
111
- sign. The theme squares every other rounding, on any component.
112
- Never add a `rounded-*` class to a box.
113
- - **Floating surfaces lie flat.** Nothing casts a drop shadow: a menu, a
114
- list, a popover, a dialog, a sheet, a hover card and a chart's tooltip take
115
- the card's hairline for their edge, so they read as a sheet of the page.
116
- - **Joined toggles.** The items of a `ToggleGroup` sit flush and share their
117
- borders, one control; the pressed item fills with the foreground.
118
- - **A code block's copy button sits in a header row** (`CodeBlockHeader`),
119
- beside its title or alone, never floating over the code, where it would
120
- cover the end of a line. An untitled snippet takes the extra row.
100
+ - **The look is shadcn's, set by tokens.** Siyahi sets colours, fonts,
101
+ `--radius` and shadows; stock components keep the shape and states shadcn
102
+ gives them. Beyond the terminal's type (Type, below), the theme restyles a
103
+ stock component only to fix a measured problem (contrast, clipping, touch
104
+ targets, density), never for taste.
105
+ - **Square corners**: `--radius` is 0, so every corner a component takes from
106
+ the theme is square. A part shadcn rounds fully (a dot, a pill, a switch)
107
+ stays round. Never add a `rounded-*` class to a box.
108
+ - **Floating surfaces lie flat.** Nothing casts a drop shadow: every shadow
109
+ size is transparent.
121
110
  - Badges stay boxed (an outline), the primary button and the pressed toggle
122
- black (white in dark), titles in the sans face, at normal spacing.
111
+ black (white in dark).
112
+
113
+ ## Type
114
+
115
+ Siyahi reads as a terminal. The page is set in M PLUS 1 Code, a mono half a
116
+ font size wide, so a table fits its columns and a row its words on one line:
117
+ figures, labels, controls, titles and tables share one grid. Tables set it at
118
+ 13px. Text that reads as sentences, a
119
+ paragraph, a quote or a description, is set in Geist, where mono
120
+ tires the eye over a line; the theme switches it by element, so a page writes
121
+ no font classes. Labels over data (a `MetricStrip` figure's label, a table's
122
+ column heads, a sidebar group's label, a group's label in a menu) are small
123
+ capitals, muted. Never set a figure or a title in them.
123
124
 
124
125
  ## Page header
125
126
 
@@ -127,6 +128,12 @@ An app page opens on its masthead, `PageHeader`: a small mark and eyebrow in the
127
128
  mono face and link colour, the title, one muted line saying what the page is,
128
129
  the actions at the right, and a hairline under it. One per page; no hero card.
129
130
 
131
+ A page may lead with its two to four main figures as a headline, under the
132
+ masthead: `MetricStrip` with `variant="blocks"`, each figure on a solid block
133
+ (the headline orange, then the text colour, then a grey), touching, its value
134
+ large and every word in the block's own ink. One per page. It draws no
135
+ sparkline and no tone, so an exception goes in a strip below it.
136
+
130
137
  ## Words
131
138
 
132
139
  A page is read by someone who acts on its figures. Its words are plain English,
@@ -210,13 +217,9 @@ from the catalogue.
210
217
 
211
218
  ## Labels and totals
212
219
 
213
- - **Labels are small monospaced capitals**: a `MetricStrip` figure's label, a table's column heads, a sidebar group's
214
- label, a group's label in a menu, a select's list or the command palette,
215
- and a form field's label (muted, above the field). The components and
216
- the theme set them; never set a label in this style by hand elsewhere, and
217
- never set a figure or a title in it.
218
- - **A total row reads as a ledger's**: in `TableFooter`, one rule above it and
219
- a double rule under it in the text colour, no band.
220
+ - **Labels over data are small capitals** (Type, above). The components and
221
+ the theme set them; never set a label in this style by hand.
222
+ - **A total row** goes in `TableFooter`.
220
223
 
221
224
  ## Charts
222
225
 
@@ -259,13 +262,11 @@ from the catalogue.
259
262
 
260
263
  ## Tables
261
264
 
262
- Tables are dense, as a ledger is: compact rows, a 1px rule in the text colour
263
- under the column heads, the first column (what the row is) in medium weight,
264
- and figures in the mono face. A figure is a cell marked `data-numeric`, which
265
- also right-aligns it (the data table marks its number columns; a plain
266
- `TableCell` or `TableHead` takes the attribute), and any `Delta` in a cell.
267
- Alignment alone is not a figure. Row hairlines stay; never stripes, never
268
- column rules.
265
+ Tables are dense: compact rows, and column heads in small muted capitals.
266
+ A number column is marked
267
+ `data-numeric`, which right-aligns it, so figures line up by their units (the
268
+ data table marks its number columns; a plain `TableCell` or `TableHead` takes
269
+ the attribute). Row hairlines stay; never stripes, never column rules.
269
270
 
270
271
  ## Forms
271
272
 
@@ -278,5 +279,5 @@ column rules.
278
279
  ## Sidebar
279
280
 
280
281
  The sidebar is parted from the page by a hairline on its page-side edge, its
281
- group labels are small monospaced capitals and its rows are compact. Its fill,
282
- icons and the current page's mark stay as shadcn draws them.
282
+ group labels are small capitals and its rows are compact. Everything else
283
+ stays as shadcn draws it.
package/README.md CHANGED
@@ -56,7 +56,7 @@ createRoot(root).render(
56
56
  );
57
57
  ```
58
58
 
59
- `preloadFonts()` loads Geist and Geist Mono with the scripts. Add `lucide-react`
59
+ `preloadFonts()` loads Geist and M PLUS 1 Code with the scripts. Add `lucide-react`
60
60
  only when your own code imports icons. Next.js compiles the stylesheet through
61
61
  `@tailwindcss/postcss` instead of the Vite plugin. To host one page as a single
62
62
  HTML file, build it with `siyahi-page` from `@siyahi/tools`.
@@ -98,22 +98,13 @@ and support one keyboard entry with arrow navigation. `WeekdayHeatmap` accepts
98
98
 
99
99
  ## Surfaces
100
100
 
101
- `SiyahiProvider` sets how data blocks sit on the page:
101
+ Data blocks sit open on the page: a `Card` has no fill, box or rule, and no
102
+ padding, so a block's content sits level with the page's text. Space parts
103
+ the blocks: 16px across and 12px down in a `PanelGrid`. The rest of the look
104
+ is stock shadcn, set by the theme's tokens; `DESIGN.md` has the masthead and
105
+ exception tones.
102
106
 
103
- - `surface="open"` (default, even outside a provider): no fill, box or rule,
104
- and no card padding, so a block's content sits level with the page's text.
105
- Space parts the blocks: 24px across and 16px down in a `PanelGrid`.
106
- - `surface="card"`: tight square cards, each filled inside a hairline, 8px
107
- apart, no shadow, for a page of separate blocks.
108
-
109
- `DESIGN.md` has the rest of the look: square corners, mono capital labels,
110
- ledger totals, the masthead and exception tones.
111
-
112
- Nest a provider to change one section. A dialog, sheet or popover renders
113
- outside the page's provider element: `PanelGrid` carries
114
- their surface into it, but a lone `Card` there is open unless the popup's
115
- content sits in its own provider with an explicit surface, such as
116
- `<SiyahiProvider surface="card">`; a provider without one draws no element. Stack `PageSection` blocks with
107
+ Stack `PageSection` blocks with
117
108
  `flex flex-col gap-6` and the blocks inside one with `gap-4`; use `PanelGrid`
118
109
  for blocks side by side. Categories use
119
110
  neutral outline badges, leaving colour for meaning and chart series.
@@ -21,10 +21,11 @@ file as copied; `packages/ui/registry.lock.json` lists them all and
21
21
 
22
22
  ## Runtime dependencies with attribution terms
23
23
 
24
- | Package | Licence | Note |
25
- | --------------------------------------------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
26
- | `lightweight-charts` (TradingView) | Apache-2.0 | `PriceChart` keeps the library's attribution logo on by default; see https://github.com/tradingview/lightweight-charts/blob/master/NOTICE |
27
- | `@fontsource-variable/geist`, `@fontsource-variable/geist-mono` | SIL Open Font License 1.1 (fonts), MIT (packaging) | Geist by Vercel |
24
+ | Package | Licence | Note |
25
+ | ------------------------------------ | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
26
+ | `lightweight-charts` (TradingView) | Apache-2.0 | `PriceChart` keeps the library's attribution logo on by default; see https://github.com/tradingview/lightweight-charts/blob/master/NOTICE |
27
+ | `@fontsource-variable/geist` | SIL Open Font License 1.1 (fonts), MIT (packaging) | Geist by Vercel |
28
+ | `@fontsource-variable/m-plus-1-code` | SIL Open Font License 1.1 (fonts), MIT (packaging) | M PLUS 1 Code by The M+ FONTS Project Authors |
28
29
 
29
30
  Every other dependency is installed from npm under its own licence and is not
30
31
  copied into this repository.
@@ -0,0 +1,12 @@
1
+ import { MetricStrip, useFormat, type MetricStripItem } from "@siyahi/ui";
2
+
3
+ export default function MetricStripHeadlineExample() {
4
+ const { money, moneyCompact } = useFormat();
5
+ // The page's headline: three figures on solid blocks. An exception goes in a strip below, not here.
6
+ const items: MetricStripItem[] = [
7
+ { label: "Net worth", value: moneyCompact(4185700), change: 0.091, note: "on the year" },
8
+ { label: "Equity share", value: "74%", note: "plan 65%" },
9
+ { label: "Cash flow this year", value: money(-61200), note: "since April" },
10
+ ];
11
+ return <MetricStrip variant="blocks" items={items} />;
12
+ }
@@ -7,20 +7,15 @@ import {
7
7
  CardTitle,
8
8
  MetricStrip,
9
9
  PanelGrid,
10
- SiyahiProvider,
11
10
  Table,
12
11
  TableBody,
13
12
  TableCell,
14
13
  TableHead,
15
14
  TableHeader,
16
15
  TableRow,
17
- ToggleGroup,
18
- ToggleGroupItem,
19
16
  useFormat,
20
17
  type MetricStripItem,
21
- type Surface,
22
18
  } from "@siyahi/ui";
23
- import { useState } from "react";
24
19
 
25
20
  const orders = [
26
21
  { hour: 9, orders: 42 },
@@ -38,7 +33,7 @@ const products = [
38
33
  { product: "Bookshelf", revenue: 166000 },
39
34
  ];
40
35
 
41
- function Dashboard() {
36
+ export default function SurfacesExample() {
42
37
  const { money, moneyCompact, pct } = useFormat();
43
38
  const kpis: MetricStripItem[] = [
44
39
  { label: "Revenue", value: money(4512300), change: 0.031 },
@@ -87,29 +82,3 @@ function Dashboard() {
87
82
  </div>
88
83
  );
89
84
  }
90
-
91
- export default function SurfacesExample() {
92
- const [surface, setSurface] = useState<Surface>("open");
93
- return (
94
- <div className="flex flex-col gap-4">
95
- <ToggleGroup
96
- value={[surface]}
97
- onValueChange={([next]) => {
98
- // Pressing the selected surface again would leave none selected; keep it.
99
- if (next) setSurface(next as Surface);
100
- }}
101
- variant="outline"
102
- size="sm"
103
- aria-label="Surface"
104
- >
105
- {/* The default first. */}
106
- <ToggleGroupItem value="open">Open</ToggleGroupItem>
107
- <ToggleGroupItem value="card">Card</ToggleGroupItem>
108
- </ToggleGroup>
109
- {/* A nested provider sets the surface for its part of the page. */}
110
- <SiyahiProvider surface={surface}>
111
- <Dashboard />
112
- </SiyahiProvider>
113
- </div>
114
- );
115
- }
@@ -106,6 +106,14 @@
106
106
  "MetricStrip"
107
107
  ]
108
108
  },
109
+ {
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`",
112
+ "components": [
113
+ "MetricStrip",
114
+ "PageHeader"
115
+ ]
116
+ },
109
117
  {
110
118
  "need": "A run of values beside a figure, in a tile, a strip or a table cell",
111
119
  "guidance": "`Sparkline`; in a strip, `MetricStrip`'s `trend`",
@@ -280,13 +288,6 @@
280
288
  "PanelGrid"
281
289
  ]
282
290
  },
283
- {
284
- "need": "Separate square cards instead of the default open blocks, for a page or a part of one",
285
- "guidance": "`SiyahiProvider` with `surface=\"card\"`",
286
- "components": [
287
- "SiyahiProvider"
288
- ]
289
- },
290
291
  {
291
292
  "need": "A forecast stretch after the latest actual figure, or a marker for today",
292
293
  "guidance": "`LineChartCard` or `AreaChartCard` with `forecastFrom` and `today` set to x values",
@@ -1018,6 +1019,13 @@
1018
1019
  "LocalTime"
1019
1020
  ]
1020
1021
  },
1022
+ {
1023
+ "file": "agents/examples/metric-strip-headline.tsx",
1024
+ "components": [
1025
+ "MetricStrip",
1026
+ "useFormat"
1027
+ ]
1028
+ },
1021
1029
  {
1022
1030
  "file": "agents/examples/metric-strip-select.tsx",
1023
1031
  "components": [
@@ -1276,15 +1284,12 @@
1276
1284
  "CardTitle",
1277
1285
  "MetricStrip",
1278
1286
  "PanelGrid",
1279
- "SiyahiProvider",
1280
1287
  "Table",
1281
1288
  "TableBody",
1282
1289
  "TableCell",
1283
1290
  "TableHead",
1284
1291
  "TableHeader",
1285
1292
  "TableRow",
1286
- "ToggleGroup",
1287
- "ToggleGroupItem",
1288
1293
  "useFormat"
1289
1294
  ]
1290
1295
  },
@@ -32,8 +32,14 @@ export interface MetricStripProps extends Omit<React$1.ComponentProps<typeof Car
32
32
  selected?: string | undefined;
33
33
  /** Makes each figure one button, so keep figure content non-interactive; gets the label of the figure picked. */
34
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;
35
41
  }
36
42
  /** A row of figures, each with its change and recent run, optionally a picker that scopes the page. */
37
- declare function MetricStrip({ title, description, action, items, footer, selected, onSelect, className, ...props }: MetricStripProps): React$1.JSX.Element;
43
+ declare function MetricStrip({ title, description, action, items, footer, selected, onSelect, variant, className, ...props }: MetricStripProps): React$1.JSX.Element;
38
44
  //#endregion
39
45
  export { MetricStrip };
@@ -23,8 +23,9 @@ function trendColor(change) {
23
23
  return "var(--muted-foreground)";
24
24
  }
25
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, className, ...props }) {
26
+ function MetricStrip({ title, description, action, items, footer, selected, onSelect, variant = "strip", className, ...props }) {
27
27
  const columns = COLUMNS[Math.min(items.length, 8)] ?? COLUMNS[8];
28
+ const blocks = variant === "blocks";
28
29
  return /* @__PURE__ */ jsxs(Card, {
29
30
  className: cn("gap-4", className),
30
31
  ...props,
@@ -36,15 +37,16 @@ function MetricStrip({ title, description, action, items, footer, selected, onSe
36
37
  ] }),
37
38
  /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx("div", {
38
39
  "data-slot": "metric-strip",
40
+ "data-variant": variant,
39
41
  className: "@container/strip",
40
42
  children: /* @__PURE__ */ jsx("div", {
41
- className: cn("grid grid-cols-1 gap-x-6 gap-y-5", columns),
43
+ className: cn("grid grid-cols-1", blocks ? "gap-0" : "gap-4", columns),
42
44
  children: items.map((item) => /* @__PURE__ */ jsxs("div", {
43
45
  "data-slot": "metric-strip-item",
44
- "data-tone": item.tone,
46
+ "data-tone": blocks ? void 0 : item.tone,
45
47
  "data-stale": item.stale ? "" : void 0,
46
48
  "data-picked": onSelect && item.label === selected ? "" : void 0,
47
- className: cn("relative row-span-4 grid min-w-0 grid-rows-subgrid gap-y-1", onSelect && item.disabled && "opacity-60"),
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"),
48
50
  children: [
49
51
  onSelect && /* @__PURE__ */ jsx("button", {
50
52
  type: "button",
@@ -61,7 +63,7 @@ function MetricStrip({ title, description, action, items, footer, selected, onSe
61
63
  }),
62
64
  /* @__PURE__ */ jsx("div", {
63
65
  "data-slot": "metric-strip-value",
64
- className: "text-xl font-semibold tracking-tight tabular-nums",
66
+ className: cn("font-semibold tabular-nums", blocks ? "mt-2 text-4xl leading-none tracking-tighter" : "text-lg tracking-tight"),
65
67
  children: item.value
66
68
  }),
67
69
  /* @__PURE__ */ jsxs("div", {
@@ -78,7 +80,7 @@ function MetricStrip({ title, description, action, items, footer, selected, onSe
78
80
  item.stale && /* @__PURE__ */ jsx(StaleNote, { since: item.stale })
79
81
  ]
80
82
  }),
81
- item.trend && item.trend.length > 1 ? /* @__PURE__ */ jsx(Sparkline, {
83
+ blocks ? null : item.trend && item.trend.length > 1 ? /* @__PURE__ */ jsx(Sparkline, {
82
84
  data: item.trend,
83
85
  variant: "line",
84
86
  color: trendColor(item.change),
@@ -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 Geist Mono on a muted chip, at the size of the text around it. */
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 Geist Mono on a muted chip, at the size of the text around it. */
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,
@@ -17,9 +17,8 @@ export interface PanelGridProps {
17
17
  className?: string | undefined;
18
18
  }
19
19
  /**
20
- * Data blocks side by side: chart cards, tables, a MetricStrip. On an open surface, the default, space parts the
21
- * blocks: 24px across and 16px down, no box and no rule. A card surface sets them 8px apart, each in its own box. The
22
- * 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.
23
22
  */
24
23
  export declare function PanelGrid({ columns, children, className }: PanelGridProps): import("react").JSX.Element;
25
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";
@@ -12,20 +11,17 @@ const COLUMNS = {
12
11
  const WIDE_THREE = "@min-[140rem]/panels:grid-cols-3";
13
12
  const WIDE_FOUR = "@min-[180rem]/panels:grid-cols-4";
14
13
  /**
15
- * Data blocks side by side: chart cards, tables, a MetricStrip. On an open surface, the default, space parts the
16
- * blocks: 24px across and 16px down, no box and no rule. A card surface sets them 8px apart, each in its own box. The
17
- * 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 surface = useSurface();
21
18
  const blocks = Children.toArray(children).length;
22
19
  const wide = cn(columns === 2 && blocks >= 3 && WIDE_THREE, (columns === 2 || columns === 3) && blocks >= 4 && WIDE_FOUR);
23
20
  return /* @__PURE__ */ jsx("div", {
24
21
  "data-slot": "panel-grid",
25
- "data-surface": surface,
26
22
  className: cn("@container/panels", className),
27
23
  children: /* @__PURE__ */ jsx("div", {
28
- className: cn("grid grid-cols-1", COLUMNS[columns], wide, surface === "open" ? "gap-x-6 gap-y-4" : "gap-2"),
24
+ className: cn("grid grid-cols-1 gap-x-4 gap-y-3", COLUMNS[columns], wide),
29
25
  children: Children.map(children, (child) => /* @__PURE__ */ jsx("div", {
30
26
  "data-slot": "panel",
31
27
  className: "min-w-0",
@@ -19,7 +19,7 @@ const NAME_BAND = 42;
19
19
  const TICK = { className: "fill-muted-foreground font-mono" };
20
20
  const AXIS_TITLE = "fill-muted-foreground text-xs";
21
21
  const keyOf = (point) => point.key ?? point.name;
22
- const MONO_WIDTH = 7.2;
22
+ const MONO_WIDTH = 6;
23
23
  /** Two measures per item as dots, such as size against growth, with the leading names beside their dots. */
24
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 }) {
25
25
  const { numberLocale } = useLocale();
@@ -2,24 +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. "open", the default: no fill, no lines and no padding, the block's content level
7
- * with the page's text and parted from the next by space. "card": a filled square card in a hairline ring, 8px from
8
- * the next, for a page of separate blocks.
9
- */
10
- export type Surface = "open" | "card";
11
5
  export interface SiyahiProviderProps {
12
6
  /** Any setting left out keeps its default: en-IN, INR, Asia/Kolkata. */
13
7
  locale?: Optional<SiyahiLocale> | undefined;
14
- /**
15
- * Set it on a nested provider for one part of a page. Left out, a provider keeps the surface around it, so a
16
- * provider that only changes the locale changes nothing else; the outermost default is "open".
17
- */
18
- surface?: Surface | undefined;
19
8
  children: ReactNode;
20
9
  }
21
- /** Wrap the app once. Carries the locale, the surface and the tooltip provider shadcn asks for. */
22
- export declare function SiyahiProvider({ locale, surface, children }: SiyahiProviderProps): import("react").JSX.Element;
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;
23
15
  export declare function useLocale(): SiyahiLocale;
24
- export declare function useSurface(): Surface;
25
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
- const SurfaceContext = createContext("open");
8
- /** Wrap the app once. Carries the locale, the surface and the tooltip provider shadcn asks for. */
9
- function SiyahiProvider({ locale, surface, children }) {
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(SurfaceContext, {
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, useSurface };
31
+ export { SiyahiProvider, useLocale };