cortena-ui 1.11.0 → 1.12.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  Notable changes per release. Versions before 1.6.0 are recorded in the git log
4
4
  and in `../../CONSUMING.md`; this file starts where the changelog does.
5
5
 
6
+ ## 1.12.0
7
+
8
+ ### Changed
9
+
10
+ - **`RenderProp` is exported** from `cortena-ui/core` and the root barrel, so a
11
+ consumer can name the type its wrappers around `Card`, `Breadcrumb` and
12
+ `ButtonLink` already use (DESIGN-51).
13
+ - **`cortena-design` peer range is bounded** at `>=3.4.0 <4`; a future 4.x no
14
+ longer resolves silently (DESIGN-51).
15
+ - **Chart SSR fallbacks match the tokens.** The no-DOM fallbacks for
16
+ `--ds-radius-md` and `--ds-radius-sm` were 6 and 4; the tokens are 12 and 8,
17
+ so a server-rendered Nivo tooltip drew at half radius until hydration. The
18
+ plot margin now reads `--ds-space-2` through `plotMargin()` instead of a raw
19
+ 8. Pixel-identical in the browser; asserted by test (DESIGN-51).
20
+
21
+ ### Removed
22
+
23
+ - `@nivo/bar`, `@nivo/core`, `@nivo/line`, `@nivo/pie`, `@nivo/scatterplot`
24
+ as dependencies — nothing imported them; those chart types render on the
25
+ Recharts side. `@nivo/core` stays as a transitive of the four Nivo charts
26
+ that remain (DESIGN-51).
27
+
6
28
  ## 1.11.0
7
29
 
8
30
  ### Added
package/README.md CHANGED
@@ -122,8 +122,9 @@ regression; `test/chart-bundle.test.tsx` says which line caused it.
122
122
  `text-[color:var(--ds-foreground)]` and `text-[length:var(--ds-text-caption)]`.
123
123
  Backgrounds, borders and radii are unambiguous and need no hint.
124
124
  - **Tested in a real browser.** Tests assert computed pixels against the
125
- token the browser resolved, in light and dark Chromium instances. A dangling
126
- `var()` paints transparent, which the tests catch and jsdom cannot.
125
+ token the browser resolved. A dangling `var()` paints transparent, which the
126
+ tests catch and jsdom cannot. Most tests pin a theme and run once; see
127
+ "Which tests run in both themes".
127
128
  - **Every component appears in the guide.** `guide/sections.tsx` is the visual
128
129
  check in light, dark and system-dark; add an entry with every variant and
129
130
  size when adding a component.
@@ -696,6 +697,22 @@ action is shaped like A2UI's client-to-server `action`, and the catalogue is a
696
697
  schema-per-component registry. Swapping the engine later is mechanical. Nothing
697
698
  from `@a2ui/*` is installed, so `vitest.config.ts` has no entry for it.
698
699
 
700
+ ## Which tests run in both themes
701
+
702
+ `vitest.config.ts` has two projects. **`light`** runs every file once in a
703
+ Chromium whose OS colour scheme is light; **`dark`** runs a second time, in a
704
+ dark Chromium, only the files whose name ends `.theme.test.tsx`. Tag a test with
705
+ that suffix when its result depends on the browser's own colour scheme — that
706
+ is, when it asserts a theme-dependent value while no `data-theme` attribute is
707
+ set, the `@media (prefers-color-scheme: dark)` branch of `tokens.css`. Nothing
708
+ else needs the tag: an explicit `data-theme` always beats the media query, so a
709
+ test that calls `setTheme("light")` or `setTheme("dark")` computes the same
710
+ bytes in either browser, and the `for (const theme of ["light", "dark"])` loops
711
+ already paint both branches and assert that they differ, inside one run. If one
712
+ test in a file needs the tag, move that test to a sibling `*.theme.test.tsx`
713
+ rather than paying for the whole file twice — six such files exist today, and
714
+ `pnpm test:dark` runs exactly them.
715
+
699
716
  ## Commands
700
717
 
701
718
  ```bash
@@ -703,6 +720,7 @@ pnpm check # types
703
720
  pnpm lint:design # no literals where a token exists; no dangling var()
704
721
  pnpm build # dist/ via tsdown (ESM + d.ts); also runs on prepack
705
722
  pnpm test # changed-only: the suites of this package your diff affects
723
+ pnpm test:dark # the dark project alone: *.theme.test.tsx in dark Chromium
706
724
  pnpm test:bundle # bundle budgets alone (builds first, then real Vite apps)
707
725
  pnpm bundle:probe # the size table, printed, without asserting anything
708
726
  pnpm guide # three-theme guide on a local Vite server
@@ -725,6 +743,7 @@ src/styles/index.css what consumers import after the tokens: animation
725
743
  utilities and the Base UI data-attribute variants
726
744
  scripts/bundle-probe.mjs builds a consumer app per entry and weighs it
727
745
  test/ browser tests; setup.css is the consumer recipe verbatim
746
+ *.theme.test.tsx also run in a dark Chromium
728
747
  *.test.mjs are the Node-side bundle budgets
729
748
  guide/ Vite app: ?theme=light|dark|system frames, or all three
730
749
  ```
@@ -3,7 +3,7 @@ import { VariantProps } from "class-variance-authority";
3
3
  import * as React from "react";
4
4
  //#region src/components/badge.d.ts
5
5
  declare const badgeVariants: (props?: ({
6
- variant?: "default" | "success" | "warn" | "destructive" | "danger" | "info" | "warning" | "neutral" | "secondary" | "outline" | null | undefined;
6
+ variant?: "default" | "outline" | "success" | "warn" | "destructive" | "danger" | "info" | "warning" | "secondary" | "neutral" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  export interface BadgeProps extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {}
9
9
  declare function Badge({ className, variant, ...props }: BadgeProps): React.JSX.Element;
@@ -14,7 +14,7 @@ import { Button } from "@base-ui/react/button";
14
14
  * rendered element, which is Base UI's equivalent.
15
15
  */
16
16
  declare const buttonVariants: (props?: ({
17
- variant?: "link" | "destructive" | "secondary" | "outline" | "primary" | "ghost" | "soft" | null | undefined;
17
+ variant?: "link" | "outline" | "destructive" | "primary" | "secondary" | "ghost" | "soft" | null | undefined;
18
18
  size?: "sm" | "md" | "lg" | "icon" | "icon-sm" | null | undefined;
19
19
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
20
20
  export interface ButtonProps extends React.ComponentProps<typeof Button>, VariantProps<typeof buttonVariants> {}
@@ -5,6 +5,24 @@ import { useChart } from "./container.js";
5
5
  import { useMemo } from "react";
6
6
  //#region src/components/chart/nivo-theme.ts
7
7
  /**
8
+ * What these four sizes are when there is no DOM to read them from.
9
+ *
10
+ * `nivoTheme` runs on the server too, where `getComputedStyle` does not exist
11
+ * and every `tokenPx` call comes back undefined. Each number below is the
12
+ * pixel value its token emits at the default scale, so the server markup and
13
+ * the first client paint agree. `chart.test.tsx` asserts them against the
14
+ * live tokens, which is what stops them drifting the way the two radii had:
15
+ * `--ds-radius-md` is 12px and fell back to 6, `--ds-radius-sm` is 8px and
16
+ * fell back to 4, so every server-rendered tooltip drew half-round corners
17
+ * until hydration.
18
+ */
19
+ const NIVO_SIZE_FALLBACK = {
20
+ captionSm: 11,
21
+ caption: 12,
22
+ radiusMd: 12,
23
+ radiusSm: 8
24
+ };
25
+ /**
8
26
  * Build the Nivo theme from the tokens, resolved on `el` (default `<html>`).
9
27
  * Every colour is read from a `--ds-*` custom property and converted to hex,
10
28
  * because Nivo's canvas renderer and its colour derivation cannot read
@@ -15,10 +33,10 @@ import { useMemo } from "react";
15
33
  */
16
34
  function nivoTheme(el) {
17
35
  const fontFamily = readToken("--ds-font-body", el) || "var(--ds-font-body)";
18
- const captionSm = tokenPx("--ds-text-caption-sm", el) ?? 11;
19
- const caption = tokenPx("--ds-text-caption", el) ?? 12;
20
- const radiusMd = tokenPx("--ds-radius-md", el) ?? 6;
21
- const radiusSm = tokenPx("--ds-radius-sm", el) ?? 4;
36
+ const captionSm = tokenPx("--ds-text-caption-sm", el) ?? NIVO_SIZE_FALLBACK.captionSm;
37
+ const caption = tokenPx("--ds-text-caption", el) ?? NIVO_SIZE_FALLBACK.caption;
38
+ const radiusMd = tokenPx("--ds-radius-md", el) ?? NIVO_SIZE_FALLBACK.radiusMd;
39
+ const radiusSm = tokenPx("--ds-radius-sm", el) ?? NIVO_SIZE_FALLBACK.radiusSm;
22
40
  const foreground = resolveColor("--ds-foreground", el);
23
41
  const muted = resolveColor("--ds-muted-foreground", el);
24
42
  const border = resolveColor("--ds-border", el);
@@ -156,6 +174,6 @@ function useNivoTheme() {
156
174
  return useMemo(() => nivoTheme(el), [el, version]);
157
175
  }
158
176
  //#endregion
159
- export { nivoTheme, useNivoTheme };
177
+ export { NIVO_SIZE_FALLBACK, nivoTheme, useNivoTheme };
160
178
 
161
179
  //# sourceMappingURL=nivo-theme.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nivo-theme.js","names":[],"sources":["../../../src/components/chart/nivo-theme.ts"],"sourcesContent":["\"use client\";\n\nimport { useMemo } from \"react\";\nimport { useChart } from \"./container\";\nimport { readToken, resolveColor, tokenPx, useThemeVersion } from \"./tokens\";\n\n/**\n * The Nivo theme object, typed structurally so no `@nivo/*` package is a\n * static import of this module (the Nivo packages are lazy-loaded). It is a\n * subset of `PartialTheme` from `@nivo/theming` and assignable to every\n * chart's `theme` prop.\n */\nexport interface NivoTheme {\n background: string;\n text: { fontFamily: string; fontSize: number; fill: string };\n axis: {\n domain: { line: { stroke: string; strokeWidth: number } };\n ticks: {\n line: { stroke: string; strokeWidth: number };\n text: { fill: string; fontSize: number };\n };\n legend: { text: { fill: string; fontSize: number; fontWeight: number } };\n };\n grid: { line: { stroke: string; strokeWidth: number } };\n crosshair: { line: { stroke: string; strokeWidth: number; strokeOpacity: number; strokeDasharray: string } };\n legends: {\n text: { fill: string; fontSize: number };\n title: { text: { fill: string; fontSize: number } };\n ticks: { line: { stroke: string; strokeWidth: number }; text: { fill: string; fontSize: number } };\n };\n labels: { text: { fill: string; fontSize: number; fontWeight: number } };\n dots: { text: { fill: string; fontSize: number } };\n markers: { lineColor: string; lineStrokeWidth: number; text: { fill: string; fontSize: number } };\n annotations: {\n text: { fill: string; fontSize: number; outlineWidth: number; outlineColor: string };\n link: { stroke: string; strokeWidth: number; outlineWidth: number; outlineColor: string };\n outline: { stroke: string; strokeWidth: number; outlineWidth: number; outlineColor: string };\n symbol: { fill: string; outlineWidth: number; outlineColor: string };\n };\n tooltip: {\n container: {\n background: string;\n color: string;\n fontSize: number;\n fontFamily: string;\n borderRadius: number;\n boxShadow: string;\n border: string;\n padding: string;\n };\n chip: { borderRadius: number };\n };\n}\n\n/**\n * Build the Nivo theme from the tokens, resolved on `el` (default `<html>`).\n * Every colour is read from a `--ds-*` custom property and converted to hex,\n * because Nivo's canvas renderer and its colour derivation cannot read\n * `var()`. Sizes come from the type scale with `--ds-text-caption-sm` (11px)\n * as the floor for ticks and labels.\n *\n * Moved here from cortenaweb's webchat renderer; nothing is hard-coded.\n */\nexport function nivoTheme(el?: Element | null): NivoTheme {\n const fontFamily = readToken(\"--ds-font-body\", el) || \"var(--ds-font-body)\";\n const captionSm = tokenPx(\"--ds-text-caption-sm\", el) ?? 11;\n const caption = tokenPx(\"--ds-text-caption\", el) ?? 12;\n const radiusMd = tokenPx(\"--ds-radius-md\", el) ?? 6;\n const radiusSm = tokenPx(\"--ds-radius-sm\", el) ?? 4;\n const foreground = resolveColor(\"--ds-foreground\", el);\n const muted = resolveColor(\"--ds-muted-foreground\", el);\n const border = resolveColor(\"--ds-border\", el);\n const borderSubtle = resolveColor(\"--ds-border-subtle\", el);\n const borderStrong = resolveColor(\"--ds-border-strong\", el);\n const popover = resolveColor(\"--ds-popover\", el);\n const popoverForeground = resolveColor(\"--ds-popover-foreground\", el);\n const card = resolveColor(\"--ds-card\", el);\n const shadow = readToken(\"--ds-shadow-md\", el) || \"var(--ds-shadow-md)\";\n const space2 = readToken(\"--ds-space-2\", el) || \"var(--ds-space-2)\";\n const space3 = readToken(\"--ds-space-3\", el) || \"var(--ds-space-3)\";\n\n return {\n background: \"transparent\",\n text: { fontFamily, fontSize: captionSm, fill: foreground },\n axis: {\n domain: { line: { stroke: border, strokeWidth: 1 } },\n ticks: {\n line: { stroke: border, strokeWidth: 1 },\n text: { fill: muted, fontSize: captionSm },\n },\n legend: { text: { fill: foreground, fontSize: caption, fontWeight: 500 } },\n },\n grid: { line: { stroke: borderSubtle, strokeWidth: 1 } },\n crosshair: { line: { stroke: borderStrong, strokeWidth: 1, strokeOpacity: 1, strokeDasharray: \"4 4\" } },\n legends: {\n text: { fill: muted, fontSize: captionSm },\n title: { text: { fill: foreground, fontSize: caption } },\n ticks: { line: { stroke: border, strokeWidth: 1 }, text: { fill: muted, fontSize: captionSm } },\n },\n labels: { text: { fill: foreground, fontSize: captionSm, fontWeight: 500 } },\n dots: { text: { fill: foreground, fontSize: captionSm } },\n markers: { lineColor: borderStrong, lineStrokeWidth: 1, text: { fill: muted, fontSize: captionSm } },\n annotations: {\n text: { fill: foreground, fontSize: captionSm, outlineWidth: 2, outlineColor: card },\n link: { stroke: borderStrong, strokeWidth: 1, outlineWidth: 2, outlineColor: card },\n outline: { stroke: borderStrong, strokeWidth: 1, outlineWidth: 2, outlineColor: card },\n symbol: { fill: foreground, outlineWidth: 2, outlineColor: card },\n },\n tooltip: {\n container: {\n background: popover,\n color: popoverForeground,\n fontSize: caption,\n fontFamily,\n borderRadius: radiusMd,\n boxShadow: shadow,\n border: `1px solid ${borderSubtle}`,\n padding: `${space2} ${space3}`,\n },\n chip: { borderRadius: radiusSm },\n },\n };\n}\n\n/**\n * The Nivo theme for the current theme, re-resolved when `data-theme` or the\n * OS scheme flips. Inside a ChartContainer the tokens are read on its element,\n * so a nested theme scope is honoured.\n */\nexport function useNivoTheme(): NivoTheme {\n const version = useThemeVersion();\n const chart = useChart();\n const el = chart?.element ?? null;\n // eslint-disable-next-line react-hooks/exhaustive-deps -- version is the cache key for the DOM read\n return useMemo(() => nivoTheme(el), [el, version]);\n}\n"],"mappings":";;;;;;;;;;;;;;;AA+DA,SAAgB,UAAU,IAAgC;CACxD,MAAM,aAAa,UAAU,kBAAkB,EAAE,KAAK;CACtD,MAAM,YAAY,QAAQ,wBAAwB,EAAE,KAAK;CACzD,MAAM,UAAU,QAAQ,qBAAqB,EAAE,KAAK;CACpD,MAAM,WAAW,QAAQ,kBAAkB,EAAE,KAAK;CAClD,MAAM,WAAW,QAAQ,kBAAkB,EAAE,KAAK;CAClD,MAAM,aAAa,aAAa,mBAAmB,EAAE;CACrD,MAAM,QAAQ,aAAa,yBAAyB,EAAE;CACtD,MAAM,SAAS,aAAa,eAAe,EAAE;CAC7C,MAAM,eAAe,aAAa,sBAAsB,EAAE;CAC1D,MAAM,eAAe,aAAa,sBAAsB,EAAE;CAC1D,MAAM,UAAU,aAAa,gBAAgB,EAAE;CAC/C,MAAM,oBAAoB,aAAa,2BAA2B,EAAE;CACpE,MAAM,OAAO,aAAa,aAAa,EAAE;CACzC,MAAM,SAAS,UAAU,kBAAkB,EAAE,KAAK;CAClD,MAAM,SAAS,UAAU,gBAAgB,EAAE,KAAK;CAChD,MAAM,SAAS,UAAU,gBAAgB,EAAE,KAAK;CAEhD,OAAO;EACL,YAAY;EACZ,MAAM;GAAE;GAAY,UAAU;GAAW,MAAM;EAAW;EAC1D,MAAM;GACJ,QAAQ,EAAE,MAAM;IAAE,QAAQ;IAAQ,aAAa;GAAE,EAAE;GACnD,OAAO;IACL,MAAM;KAAE,QAAQ;KAAQ,aAAa;IAAE;IACvC,MAAM;KAAE,MAAM;KAAO,UAAU;IAAU;GAC3C;GACA,QAAQ,EAAE,MAAM;IAAE,MAAM;IAAY,UAAU;IAAS,YAAY;GAAI,EAAE;EAC3E;EACA,MAAM,EAAE,MAAM;GAAE,QAAQ;GAAc,aAAa;EAAE,EAAE;EACvD,WAAW,EAAE,MAAM;GAAE,QAAQ;GAAc,aAAa;GAAG,eAAe;GAAG,iBAAiB;EAAM,EAAE;EACtG,SAAS;GACP,MAAM;IAAE,MAAM;IAAO,UAAU;GAAU;GACzC,OAAO,EAAE,MAAM;IAAE,MAAM;IAAY,UAAU;GAAQ,EAAE;GACvD,OAAO;IAAE,MAAM;KAAE,QAAQ;KAAQ,aAAa;IAAE;IAAG,MAAM;KAAE,MAAM;KAAO,UAAU;IAAU;GAAE;EAChG;EACA,QAAQ,EAAE,MAAM;GAAE,MAAM;GAAY,UAAU;GAAW,YAAY;EAAI,EAAE;EAC3E,MAAM,EAAE,MAAM;GAAE,MAAM;GAAY,UAAU;EAAU,EAAE;EACxD,SAAS;GAAE,WAAW;GAAc,iBAAiB;GAAG,MAAM;IAAE,MAAM;IAAO,UAAU;GAAU;EAAE;EACnG,aAAa;GACX,MAAM;IAAE,MAAM;IAAY,UAAU;IAAW,cAAc;IAAG,cAAc;GAAK;GACnF,MAAM;IAAE,QAAQ;IAAc,aAAa;IAAG,cAAc;IAAG,cAAc;GAAK;GAClF,SAAS;IAAE,QAAQ;IAAc,aAAa;IAAG,cAAc;IAAG,cAAc;GAAK;GACrF,QAAQ;IAAE,MAAM;IAAY,cAAc;IAAG,cAAc;GAAK;EAClE;EACA,SAAS;GACP,WAAW;IACT,YAAY;IACZ,OAAO;IACP,UAAU;IACV;IACA,cAAc;IACd,WAAW;IACX,QAAQ,aAAa;IACrB,SAAS,GAAG,OAAO,GAAG;GACxB;GACA,MAAM,EAAE,cAAc,SAAS;EACjC;CACF;AACF;;;;;;AAOA,SAAgB,eAA0B;CACxC,MAAM,UAAU,gBAAgB;CAEhC,MAAM,KADQ,SACC,CAAC,EAAE,WAAW;CAE7B,OAAO,cAAc,UAAU,EAAE,GAAG,CAAC,IAAI,OAAO,CAAC;AACnD"}
1
+ {"version":3,"file":"nivo-theme.js","names":[],"sources":["../../../src/components/chart/nivo-theme.ts"],"sourcesContent":["\"use client\";\n\nimport { useMemo } from \"react\";\nimport { useChart } from \"./container\";\nimport { readToken, resolveColor, tokenPx, useThemeVersion } from \"./tokens\";\n\n/**\n * The Nivo theme object, typed structurally so no `@nivo/*` package is a\n * static import of this module (the Nivo packages are lazy-loaded). It is a\n * subset of `PartialTheme` from `@nivo/theming` and assignable to every\n * chart's `theme` prop.\n */\nexport interface NivoTheme {\n background: string;\n text: { fontFamily: string; fontSize: number; fill: string };\n axis: {\n domain: { line: { stroke: string; strokeWidth: number } };\n ticks: {\n line: { stroke: string; strokeWidth: number };\n text: { fill: string; fontSize: number };\n };\n legend: { text: { fill: string; fontSize: number; fontWeight: number } };\n };\n grid: { line: { stroke: string; strokeWidth: number } };\n crosshair: { line: { stroke: string; strokeWidth: number; strokeOpacity: number; strokeDasharray: string } };\n legends: {\n text: { fill: string; fontSize: number };\n title: { text: { fill: string; fontSize: number } };\n ticks: { line: { stroke: string; strokeWidth: number }; text: { fill: string; fontSize: number } };\n };\n labels: { text: { fill: string; fontSize: number; fontWeight: number } };\n dots: { text: { fill: string; fontSize: number } };\n markers: { lineColor: string; lineStrokeWidth: number; text: { fill: string; fontSize: number } };\n annotations: {\n text: { fill: string; fontSize: number; outlineWidth: number; outlineColor: string };\n link: { stroke: string; strokeWidth: number; outlineWidth: number; outlineColor: string };\n outline: { stroke: string; strokeWidth: number; outlineWidth: number; outlineColor: string };\n symbol: { fill: string; outlineWidth: number; outlineColor: string };\n };\n tooltip: {\n container: {\n background: string;\n color: string;\n fontSize: number;\n fontFamily: string;\n borderRadius: number;\n boxShadow: string;\n border: string;\n padding: string;\n };\n chip: { borderRadius: number };\n };\n}\n\n/**\n * What these four sizes are when there is no DOM to read them from.\n *\n * `nivoTheme` runs on the server too, where `getComputedStyle` does not exist\n * and every `tokenPx` call comes back undefined. Each number below is the\n * pixel value its token emits at the default scale, so the server markup and\n * the first client paint agree. `chart.test.tsx` asserts them against the\n * live tokens, which is what stops them drifting the way the two radii had:\n * `--ds-radius-md` is 12px and fell back to 6, `--ds-radius-sm` is 8px and\n * fell back to 4, so every server-rendered tooltip drew half-round corners\n * until hydration.\n */\nexport const NIVO_SIZE_FALLBACK = {\n captionSm: 11,\n caption: 12,\n radiusMd: 12,\n radiusSm: 8,\n} as const;\n\n/**\n * Build the Nivo theme from the tokens, resolved on `el` (default `<html>`).\n * Every colour is read from a `--ds-*` custom property and converted to hex,\n * because Nivo's canvas renderer and its colour derivation cannot read\n * `var()`. Sizes come from the type scale with `--ds-text-caption-sm` (11px)\n * as the floor for ticks and labels.\n *\n * Moved here from cortenaweb's webchat renderer; nothing is hard-coded.\n */\nexport function nivoTheme(el?: Element | null): NivoTheme {\n const fontFamily = readToken(\"--ds-font-body\", el) || \"var(--ds-font-body)\";\n const captionSm = tokenPx(\"--ds-text-caption-sm\", el) ?? NIVO_SIZE_FALLBACK.captionSm;\n const caption = tokenPx(\"--ds-text-caption\", el) ?? NIVO_SIZE_FALLBACK.caption;\n const radiusMd = tokenPx(\"--ds-radius-md\", el) ?? NIVO_SIZE_FALLBACK.radiusMd;\n const radiusSm = tokenPx(\"--ds-radius-sm\", el) ?? NIVO_SIZE_FALLBACK.radiusSm;\n const foreground = resolveColor(\"--ds-foreground\", el);\n const muted = resolveColor(\"--ds-muted-foreground\", el);\n const border = resolveColor(\"--ds-border\", el);\n const borderSubtle = resolveColor(\"--ds-border-subtle\", el);\n const borderStrong = resolveColor(\"--ds-border-strong\", el);\n const popover = resolveColor(\"--ds-popover\", el);\n const popoverForeground = resolveColor(\"--ds-popover-foreground\", el);\n const card = resolveColor(\"--ds-card\", el);\n const shadow = readToken(\"--ds-shadow-md\", el) || \"var(--ds-shadow-md)\";\n const space2 = readToken(\"--ds-space-2\", el) || \"var(--ds-space-2)\";\n const space3 = readToken(\"--ds-space-3\", el) || \"var(--ds-space-3)\";\n\n return {\n background: \"transparent\",\n text: { fontFamily, fontSize: captionSm, fill: foreground },\n axis: {\n domain: { line: { stroke: border, strokeWidth: 1 } },\n ticks: {\n line: { stroke: border, strokeWidth: 1 },\n text: { fill: muted, fontSize: captionSm },\n },\n legend: { text: { fill: foreground, fontSize: caption, fontWeight: 500 } },\n },\n grid: { line: { stroke: borderSubtle, strokeWidth: 1 } },\n crosshair: { line: { stroke: borderStrong, strokeWidth: 1, strokeOpacity: 1, strokeDasharray: \"4 4\" } },\n legends: {\n text: { fill: muted, fontSize: captionSm },\n title: { text: { fill: foreground, fontSize: caption } },\n ticks: { line: { stroke: border, strokeWidth: 1 }, text: { fill: muted, fontSize: captionSm } },\n },\n labels: { text: { fill: foreground, fontSize: captionSm, fontWeight: 500 } },\n dots: { text: { fill: foreground, fontSize: captionSm } },\n markers: { lineColor: borderStrong, lineStrokeWidth: 1, text: { fill: muted, fontSize: captionSm } },\n annotations: {\n text: { fill: foreground, fontSize: captionSm, outlineWidth: 2, outlineColor: card },\n link: { stroke: borderStrong, strokeWidth: 1, outlineWidth: 2, outlineColor: card },\n outline: { stroke: borderStrong, strokeWidth: 1, outlineWidth: 2, outlineColor: card },\n symbol: { fill: foreground, outlineWidth: 2, outlineColor: card },\n },\n tooltip: {\n container: {\n background: popover,\n color: popoverForeground,\n fontSize: caption,\n fontFamily,\n borderRadius: radiusMd,\n boxShadow: shadow,\n border: `1px solid ${borderSubtle}`,\n padding: `${space2} ${space3}`,\n },\n chip: { borderRadius: radiusSm },\n },\n };\n}\n\n/**\n * The Nivo theme for the current theme, re-resolved when `data-theme` or the\n * OS scheme flips. Inside a ChartContainer the tokens are read on its element,\n * so a nested theme scope is honoured.\n */\nexport function useNivoTheme(): NivoTheme {\n const version = useThemeVersion();\n const chart = useChart();\n const el = chart?.element ?? null;\n // eslint-disable-next-line react-hooks/exhaustive-deps -- version is the cache key for the DOM read\n return useMemo(() => nivoTheme(el), [el, version]);\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  "use client";
3
- import { contrastLabel, useThemeVersion } from "./tokens.js";
3
+ import { contrastLabel, plotMargin, useThemeVersion } from "./tokens.js";
4
4
  import { seriesColor, useChart } from "./container.js";
5
5
  import { toRows, toSlices } from "./data.js";
6
6
  import { ChartLegend, ChartTooltip } from "./recharts-parts.js";
@@ -8,12 +8,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import * as React from "react";
9
9
  import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, Funnel, FunnelChart, Line, LineChart, Pie, PieChart, PolarAngleAxis, PolarGrid, PolarRadiusAxis, Radar, RadarChart, Scatter, ScatterChart, XAxis, YAxis } from "recharts";
10
10
  //#region src/components/chart/recharts-charts.tsx
11
- const MARGIN = {
12
- top: 8,
13
- right: 8,
14
- bottom: 0,
15
- left: 0
16
- };
17
11
  /**
18
12
  * Where an arc label sits, as a fraction of the way from the inner radius to
19
13
  * the outer one. Just inside the middle of the band: the arc is widest towards
@@ -69,6 +63,7 @@ function RechartsChart({ type, data, config, indexBy, keys, stacked, legend, gri
69
63
  const themeVersion = useThemeVersion();
70
64
  const element = useChart()?.element ?? null;
71
65
  const colourOn = React.useMemo(() => contrastLabel(element), [element, themeVersion]);
66
+ const margin = React.useMemo(() => plotMargin(element), [element, themeVersion]);
72
67
  const tip = tooltip ? /* @__PURE__ */ jsx(ChartTooltip, { formatter: valueFormatter ? (value) => valueFormatter(Number(value)) : void 0 }) : null;
73
68
  const leg = legend ? /* @__PURE__ */ jsx(ChartLegend, {}) : null;
74
69
  switch (type) {
@@ -76,7 +71,7 @@ function RechartsChart({ type, data, config, indexBy, keys, stacked, legend, gri
76
71
  const { rows, indexBy: index, keys: series } = toRows(data, indexBy, keys);
77
72
  return /* @__PURE__ */ jsxs(BarChart, {
78
73
  data: rows,
79
- margin: MARGIN,
74
+ margin,
80
75
  children: [
81
76
  grid ? /* @__PURE__ */ jsx(CartesianGrid, { vertical: false }) : null,
82
77
  /* @__PURE__ */ jsx(XAxis, {
@@ -112,7 +107,7 @@ function RechartsChart({ type, data, config, indexBy, keys, stacked, legend, gri
112
107
  const { rows, indexBy: index, keys: series } = toRows(data, indexBy, keys);
113
108
  return /* @__PURE__ */ jsxs(LineChart, {
114
109
  data: rows,
115
- margin: MARGIN,
110
+ margin,
116
111
  children: [
117
112
  grid ? /* @__PURE__ */ jsx(CartesianGrid, { vertical: false }) : null,
118
113
  /* @__PURE__ */ jsx(XAxis, {
@@ -144,7 +139,7 @@ function RechartsChart({ type, data, config, indexBy, keys, stacked, legend, gri
144
139
  const { rows, indexBy: index, keys: series } = toRows(data, indexBy, keys);
145
140
  return /* @__PURE__ */ jsxs(AreaChart, {
146
141
  data: rows,
147
- margin: MARGIN,
142
+ margin,
148
143
  children: [
149
144
  grid ? /* @__PURE__ */ jsx(CartesianGrid, { vertical: false }) : null,
150
145
  /* @__PURE__ */ jsx(XAxis, {
@@ -178,7 +173,7 @@ function RechartsChart({ type, data, config, indexBy, keys, stacked, legend, gri
178
173
  const slices = toSlices(data);
179
174
  const fillOf = (i) => seriesColor(config, slices[i]?.id ?? String(i), i);
180
175
  return /* @__PURE__ */ jsxs(PieChart, {
181
- margin: MARGIN,
176
+ margin,
182
177
  children: [
183
178
  tip,
184
179
  leg,
@@ -200,7 +195,7 @@ function RechartsChart({ type, data, config, indexBy, keys, stacked, legend, gri
200
195
  }
201
196
  case "scatter":
202
197
  case "scatterplot": return /* @__PURE__ */ jsxs(ScatterChart, {
203
- margin: MARGIN,
198
+ margin,
204
199
  children: [
205
200
  grid ? /* @__PURE__ */ jsx(CartesianGrid, {}) : null,
206
201
  /* @__PURE__ */ jsx(XAxis, {
@@ -232,7 +227,7 @@ function RechartsChart({ type, data, config, indexBy, keys, stacked, legend, gri
232
227
  const { rows, indexBy: index, keys: series } = toRows(data, indexBy, keys);
233
228
  return /* @__PURE__ */ jsxs(RadarChart, {
234
229
  data: rows,
235
- margin: MARGIN,
230
+ margin,
236
231
  children: [
237
232
  grid ? /* @__PURE__ */ jsx(PolarGrid, {}) : null,
238
233
  /* @__PURE__ */ jsx(PolarAngleAxis, { dataKey: index }),
@@ -256,7 +251,7 @@ function RechartsChart({ type, data, config, indexBy, keys, stacked, legend, gri
256
251
  case "funnel": {
257
252
  const slices = toSlices(data);
258
253
  return /* @__PURE__ */ jsxs(FunnelChart, {
259
- margin: MARGIN,
254
+ margin,
260
255
  children: [
261
256
  tip,
262
257
  leg,
@@ -1 +1 @@
1
- {"version":3,"file":"recharts-charts.js","names":["series"],"sources":["../../../src/components/chart/recharts-charts.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n Funnel,\n FunnelChart,\n Line,\n LineChart,\n Pie,\n PieChart,\n PolarAngleAxis,\n PolarGrid,\n PolarRadiusAxis,\n Radar,\n RadarChart,\n Scatter,\n ScatterChart,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport { seriesColor, useChart } from \"./container\";\nimport { ChartLegend, ChartTooltip } from \"./recharts-parts\";\nimport { toRows, toSlices } from \"./data\";\nimport { contrastLabel, useThemeVersion } from \"./tokens\";\nimport type { ChartConfig, ChartLabels, ChartRow, ChartSeries, ChartSlice, ChartType } from \"./types\";\n\nexport type RechartsType = Extract<\n ChartType,\n \"bar\" | \"line\" | \"area\" | \"pie\" | \"donut\" | \"scatter\" | \"scatterplot\" | \"radar\" | \"funnel\"\n>;\n\nexport interface RechartsRenderProps {\n type: RechartsType;\n data: unknown;\n config: ChartConfig;\n indexBy?: string;\n keys?: string[];\n stacked?: boolean;\n legend: boolean;\n grid: boolean;\n tooltip: boolean;\n /** Per-arc labels for pie and donut. Ignored by every other type. */\n labels: ChartLabels;\n valueFormatter?: (value: number) => string;\n /**\n * Entry animation. Off under `testMode`: Recharts draws pie labels only\n * once the animation has finished, so a test that asserts on them would\n * otherwise be racing the clock.\n */\n animate?: boolean;\n}\n\nconst MARGIN = { top: 8, right: 8, bottom: 0, left: 0 };\n\n/**\n * Where an arc label sits, as a fraction of the way from the inner radius to\n * the outer one. Just inside the middle of the band: the arc is widest towards\n * its outer edge, so a label pushed slightly out has more room than a centred\n * one, without ever touching the rim.\n */\nconst ARC_LABEL_RADIUS = 0.58;\n\n/**\n * Arcs smaller than this share of the whole are left unlabelled.\n *\n * Below roughly a twentieth the arc is narrower than the text it would carry,\n * so the label either overflows into its neighbours or has to be dragged\n * outside on a leader line. Leader lines on a small chart are worse than no\n * label — they collide with each other and with the legend, and the reader\n * still has to trace them. The tooltip covers the slices that fall out.\n */\nconst ARC_LABEL_MIN_FRACTION = 0.05;\n\n/**\n * What Recharts hands a `<Pie label={…}>` renderer. Every geometry field is\n * optional on its side — the same callback types the label of a chart that has\n * not measured itself yet — so each is checked before it is used rather than\n * asserted away.\n */\ninterface ArcLabelProps {\n cx?: number;\n cy?: number;\n midAngle?: number;\n innerRadius?: number;\n outerRadius?: number;\n percent?: number;\n value?: number;\n index?: number;\n}\n\n/**\n * A per-arc label, drawn inside the arc it belongs to.\n *\n * Inside rather than outside so there is nothing to collide: each label is\n * bounded by its own sector, and a sector too thin to hold one simply does not\n * get one. The text colour comes from `contrastLabel`, the same measured\n * ink-or-white choice the Nivo charts make, so a label stays legible on a pale\n * series colour and on a dark one, in either theme.\n */\nfunction arcLabel(\n labels: Exclude<ChartLabels, \"none\">,\n colourOn: (fill: string) => string,\n fillOf: (index: number) => string,\n valueFormatter?: (value: number) => string,\n) {\n return function ArcLabel({ cx, cy, midAngle, innerRadius, outerRadius, percent, value, index }: ArcLabelProps) {\n if (cx == null || cy == null || midAngle == null || innerRadius == null || outerRadius == null) return null;\n if (!(percent != null && percent >= ARC_LABEL_MIN_FRACTION)) return null;\n const radius = innerRadius + (outerRadius - innerRadius) * ARC_LABEL_RADIUS;\n // Recharts measures angles anticlockwise from the positive x-axis, SVG's y\n // grows downward, so the sine is negated to land on the drawn arc.\n const radians = (-midAngle * Math.PI) / 180;\n const text =\n labels === \"percent\"\n ? `${Math.round(percent * 100)}%`\n : (valueFormatter?.(Number(value)) ?? String(value ?? \"\"));\n return (\n <text\n data-slot=\"chart-arc-label\"\n x={cx + radius * Math.cos(radians)}\n y={cy + radius * Math.sin(radians)}\n fill={colourOn(fillOf(index ?? 0))}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"pointer-events-none text-[length:var(--ds-text-caption)] font-medium tabular-nums\"\n >\n {text}\n </text>\n );\n };\n}\n\n/**\n * The Recharts side of `Chart`. Returns a chart element for the\n * ResponsiveContainer inside ChartContainer; colours come from `seriesColor`\n * (config colour or `var(--ds-viz-N)` by series index) and every other visual\n * value from the container's token styling.\n */\nexport function RechartsChart({\n type,\n data,\n config,\n indexBy,\n keys,\n stacked,\n legend,\n grid,\n tooltip,\n labels,\n valueFormatter,\n animate = true,\n}: RechartsRenderProps): React.ReactElement {\n // Arc labels sit on top of a series colour, so their ink depends on which\n // colour and on the theme. `useThemeVersion` is the cache key for that DOM\n // read; `element` scopes it to a nested theme rather than the document.\n const themeVersion = useThemeVersion();\n const element = useChart()?.element ?? null;\n // eslint-disable-next-line react-hooks/exhaustive-deps -- themeVersion is the cache key for the DOM read\n const colourOn = React.useMemo(() => contrastLabel(element), [element, themeVersion]);\n\n const tip = tooltip ? (\n <ChartTooltip\n formatter={valueFormatter ? (value: unknown) => valueFormatter(Number(value)) : undefined}\n />\n ) : null;\n const leg = legend ? <ChartLegend /> : null;\n\n switch (type) {\n case \"bar\": {\n const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);\n return (\n <BarChart data={rows} margin={MARGIN}>\n {grid ? <CartesianGrid vertical={false} /> : null}\n <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />\n <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />\n {tip}\n {leg}\n {series.map((key, i) => (\n <Bar\n key={key}\n dataKey={key}\n name={key}\n fill={seriesColor(config, key, i)}\n stackId={stacked ? \"stack\" : undefined}\n radius={stacked ? 0 : [2, 2, 0, 0]}\n maxBarSize={48}\n />\n ))}\n </BarChart>\n );\n }\n\n case \"line\": {\n const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);\n return (\n <LineChart data={rows} margin={MARGIN}>\n {grid ? <CartesianGrid vertical={false} /> : null}\n <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />\n <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />\n {tip}\n {leg}\n {series.map((key, i) => (\n <Line\n key={key}\n type=\"monotone\"\n dataKey={key}\n name={key}\n stroke={seriesColor(config, key, i)}\n strokeWidth={2}\n dot={false}\n activeDot={{ r: 4 }}\n />\n ))}\n </LineChart>\n );\n }\n\n case \"area\": {\n const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);\n return (\n <AreaChart data={rows} margin={MARGIN}>\n {grid ? <CartesianGrid vertical={false} /> : null}\n <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />\n <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />\n {tip}\n {leg}\n {series.map((key, i) => (\n <Area\n key={key}\n type=\"monotone\"\n dataKey={key}\n name={key}\n stroke={seriesColor(config, key, i)}\n fill={seriesColor(config, key, i)}\n fillOpacity={0.2}\n strokeWidth={2}\n stackId={stacked ? \"stack\" : undefined}\n />\n ))}\n </AreaChart>\n );\n }\n\n case \"pie\":\n case \"donut\": {\n const slices = toSlices(data as ChartSlice[]);\n const fillOf = (i: number) => seriesColor(config, slices[i]?.id ?? String(i), i);\n return (\n <PieChart margin={MARGIN}>\n {tip}\n {leg}\n <Pie\n data={slices}\n dataKey=\"value\"\n nameKey=\"name\"\n innerRadius={type === \"donut\" ? \"55%\" : 0}\n outerRadius=\"80%\"\n paddingAngle={type === \"donut\" ? 2 : 0}\n strokeWidth={1}\n isAnimationActive={animate}\n label={labels === \"none\" ? undefined : arcLabel(labels, colourOn, fillOf, valueFormatter)}\n // The labels are inside their arcs, so there is nothing to lead to.\n labelLine={false}\n >\n {slices.map((slice, i) => (\n <Cell key={slice.id} fill={fillOf(i)} />\n ))}\n </Pie>\n </PieChart>\n );\n }\n\n case \"scatter\":\n case \"scatterplot\": {\n const series = data as ChartSeries[];\n return (\n <ScatterChart margin={MARGIN}>\n {grid ? <CartesianGrid /> : null}\n <XAxis dataKey=\"x\" type=\"number\" name=\"x\" tickLine={false} axisLine={false} tickMargin={8} />\n <YAxis dataKey=\"y\" type=\"number\" name=\"y\" tickLine={false} axisLine={false} tickFormatter={valueFormatter} />\n {tip}\n {leg}\n {series.map((s, i) => (\n <Scatter key={String(s.id)} name={String(s.id)} data={s.data} fill={seriesColor(config, String(s.id), i)} />\n ))}\n </ScatterChart>\n );\n }\n\n case \"radar\": {\n const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);\n return (\n <RadarChart data={rows} margin={MARGIN}>\n {grid ? <PolarGrid /> : null}\n <PolarAngleAxis dataKey={index} />\n <PolarRadiusAxis tick={false} axisLine={false} />\n {tip}\n {leg}\n {series.map((key, i) => (\n <Radar\n key={key}\n dataKey={key}\n name={key}\n stroke={seriesColor(config, key, i)}\n fill={seriesColor(config, key, i)}\n fillOpacity={0.2}\n strokeWidth={2}\n />\n ))}\n </RadarChart>\n );\n }\n\n case \"funnel\": {\n const slices = toSlices(data as ChartSlice[]);\n return (\n <FunnelChart margin={MARGIN}>\n {tip}\n {leg}\n <Funnel data={slices} dataKey=\"value\" nameKey=\"name\">\n {slices.map((slice, i) => (\n <Cell key={slice.id} fill={seriesColor(config, slice.id, i)} />\n ))}\n </Funnel>\n </FunnelChart>\n );\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"recharts-charts.js","names":["series"],"sources":["../../../src/components/chart/recharts-charts.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n Funnel,\n FunnelChart,\n Line,\n LineChart,\n Pie,\n PieChart,\n PolarAngleAxis,\n PolarGrid,\n PolarRadiusAxis,\n Radar,\n RadarChart,\n Scatter,\n ScatterChart,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport { seriesColor, useChart } from \"./container\";\nimport { ChartLegend, ChartTooltip } from \"./recharts-parts\";\nimport { toRows, toSlices } from \"./data\";\nimport { contrastLabel, plotMargin, useThemeVersion } from \"./tokens\";\nimport type { ChartConfig, ChartLabels, ChartRow, ChartSeries, ChartSlice, ChartType } from \"./types\";\n\nexport type RechartsType = Extract<\n ChartType,\n \"bar\" | \"line\" | \"area\" | \"pie\" | \"donut\" | \"scatter\" | \"scatterplot\" | \"radar\" | \"funnel\"\n>;\n\nexport interface RechartsRenderProps {\n type: RechartsType;\n data: unknown;\n config: ChartConfig;\n indexBy?: string;\n keys?: string[];\n stacked?: boolean;\n legend: boolean;\n grid: boolean;\n tooltip: boolean;\n /** Per-arc labels for pie and donut. Ignored by every other type. */\n labels: ChartLabels;\n valueFormatter?: (value: number) => string;\n /**\n * Entry animation. Off under `testMode`: Recharts draws pie labels only\n * once the animation has finished, so a test that asserts on them would\n * otherwise be racing the clock.\n */\n animate?: boolean;\n}\n\n/**\n * Where an arc label sits, as a fraction of the way from the inner radius to\n * the outer one. Just inside the middle of the band: the arc is widest towards\n * its outer edge, so a label pushed slightly out has more room than a centred\n * one, without ever touching the rim.\n */\nconst ARC_LABEL_RADIUS = 0.58;\n\n/**\n * Arcs smaller than this share of the whole are left unlabelled.\n *\n * Below roughly a twentieth the arc is narrower than the text it would carry,\n * so the label either overflows into its neighbours or has to be dragged\n * outside on a leader line. Leader lines on a small chart are worse than no\n * label — they collide with each other and with the legend, and the reader\n * still has to trace them. The tooltip covers the slices that fall out.\n */\nconst ARC_LABEL_MIN_FRACTION = 0.05;\n\n/**\n * What Recharts hands a `<Pie label={…}>` renderer. Every geometry field is\n * optional on its side — the same callback types the label of a chart that has\n * not measured itself yet — so each is checked before it is used rather than\n * asserted away.\n */\ninterface ArcLabelProps {\n cx?: number;\n cy?: number;\n midAngle?: number;\n innerRadius?: number;\n outerRadius?: number;\n percent?: number;\n value?: number;\n index?: number;\n}\n\n/**\n * A per-arc label, drawn inside the arc it belongs to.\n *\n * Inside rather than outside so there is nothing to collide: each label is\n * bounded by its own sector, and a sector too thin to hold one simply does not\n * get one. The text colour comes from `contrastLabel`, the same measured\n * ink-or-white choice the Nivo charts make, so a label stays legible on a pale\n * series colour and on a dark one, in either theme.\n */\nfunction arcLabel(\n labels: Exclude<ChartLabels, \"none\">,\n colourOn: (fill: string) => string,\n fillOf: (index: number) => string,\n valueFormatter?: (value: number) => string,\n) {\n return function ArcLabel({ cx, cy, midAngle, innerRadius, outerRadius, percent, value, index }: ArcLabelProps) {\n if (cx == null || cy == null || midAngle == null || innerRadius == null || outerRadius == null) return null;\n if (!(percent != null && percent >= ARC_LABEL_MIN_FRACTION)) return null;\n const radius = innerRadius + (outerRadius - innerRadius) * ARC_LABEL_RADIUS;\n // Recharts measures angles anticlockwise from the positive x-axis, SVG's y\n // grows downward, so the sine is negated to land on the drawn arc.\n const radians = (-midAngle * Math.PI) / 180;\n const text =\n labels === \"percent\"\n ? `${Math.round(percent * 100)}%`\n : (valueFormatter?.(Number(value)) ?? String(value ?? \"\"));\n return (\n <text\n data-slot=\"chart-arc-label\"\n x={cx + radius * Math.cos(radians)}\n y={cy + radius * Math.sin(radians)}\n fill={colourOn(fillOf(index ?? 0))}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"pointer-events-none text-[length:var(--ds-text-caption)] font-medium tabular-nums\"\n >\n {text}\n </text>\n );\n };\n}\n\n/**\n * The Recharts side of `Chart`. Returns a chart element for the\n * ResponsiveContainer inside ChartContainer; colours come from `seriesColor`\n * (config colour or `var(--ds-viz-N)` by series index) and every other visual\n * value from the container's token styling.\n */\nexport function RechartsChart({\n type,\n data,\n config,\n indexBy,\n keys,\n stacked,\n legend,\n grid,\n tooltip,\n labels,\n valueFormatter,\n animate = true,\n}: RechartsRenderProps): React.ReactElement {\n // Arc labels sit on top of a series colour, so their ink depends on which\n // colour and on the theme. `useThemeVersion` is the cache key for that DOM\n // read; `element` scopes it to a nested theme rather than the document.\n const themeVersion = useThemeVersion();\n const element = useChart()?.element ?? null;\n // eslint-disable-next-line react-hooks/exhaustive-deps -- themeVersion is the cache key for the DOM read\n const colourOn = React.useMemo(() => contrastLabel(element), [element, themeVersion]);\n // The plot margin is `--ds-space-2`, read from the tokens like every colour\n // here rather than frozen as a number, and on the same cache key so a theme\n // or scale change re-reads it.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- themeVersion is the cache key for the DOM read\n const margin = React.useMemo(() => plotMargin(element), [element, themeVersion]);\n\n const tip = tooltip ? (\n <ChartTooltip\n formatter={valueFormatter ? (value: unknown) => valueFormatter(Number(value)) : undefined}\n />\n ) : null;\n const leg = legend ? <ChartLegend /> : null;\n\n switch (type) {\n case \"bar\": {\n const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);\n return (\n <BarChart data={rows} margin={margin}>\n {grid ? <CartesianGrid vertical={false} /> : null}\n <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />\n <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />\n {tip}\n {leg}\n {series.map((key, i) => (\n <Bar\n key={key}\n dataKey={key}\n name={key}\n fill={seriesColor(config, key, i)}\n stackId={stacked ? \"stack\" : undefined}\n radius={stacked ? 0 : [2, 2, 0, 0]}\n maxBarSize={48}\n />\n ))}\n </BarChart>\n );\n }\n\n case \"line\": {\n const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);\n return (\n <LineChart data={rows} margin={margin}>\n {grid ? <CartesianGrid vertical={false} /> : null}\n <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />\n <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />\n {tip}\n {leg}\n {series.map((key, i) => (\n <Line\n key={key}\n type=\"monotone\"\n dataKey={key}\n name={key}\n stroke={seriesColor(config, key, i)}\n strokeWidth={2}\n dot={false}\n activeDot={{ r: 4 }}\n />\n ))}\n </LineChart>\n );\n }\n\n case \"area\": {\n const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);\n return (\n <AreaChart data={rows} margin={margin}>\n {grid ? <CartesianGrid vertical={false} /> : null}\n <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />\n <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />\n {tip}\n {leg}\n {series.map((key, i) => (\n <Area\n key={key}\n type=\"monotone\"\n dataKey={key}\n name={key}\n stroke={seriesColor(config, key, i)}\n fill={seriesColor(config, key, i)}\n fillOpacity={0.2}\n strokeWidth={2}\n stackId={stacked ? \"stack\" : undefined}\n />\n ))}\n </AreaChart>\n );\n }\n\n case \"pie\":\n case \"donut\": {\n const slices = toSlices(data as ChartSlice[]);\n const fillOf = (i: number) => seriesColor(config, slices[i]?.id ?? String(i), i);\n return (\n <PieChart margin={margin}>\n {tip}\n {leg}\n <Pie\n data={slices}\n dataKey=\"value\"\n nameKey=\"name\"\n innerRadius={type === \"donut\" ? \"55%\" : 0}\n outerRadius=\"80%\"\n paddingAngle={type === \"donut\" ? 2 : 0}\n strokeWidth={1}\n isAnimationActive={animate}\n label={labels === \"none\" ? undefined : arcLabel(labels, colourOn, fillOf, valueFormatter)}\n // The labels are inside their arcs, so there is nothing to lead to.\n labelLine={false}\n >\n {slices.map((slice, i) => (\n <Cell key={slice.id} fill={fillOf(i)} />\n ))}\n </Pie>\n </PieChart>\n );\n }\n\n case \"scatter\":\n case \"scatterplot\": {\n const series = data as ChartSeries[];\n return (\n <ScatterChart margin={margin}>\n {grid ? <CartesianGrid /> : null}\n <XAxis dataKey=\"x\" type=\"number\" name=\"x\" tickLine={false} axisLine={false} tickMargin={8} />\n <YAxis dataKey=\"y\" type=\"number\" name=\"y\" tickLine={false} axisLine={false} tickFormatter={valueFormatter} />\n {tip}\n {leg}\n {series.map((s, i) => (\n <Scatter key={String(s.id)} name={String(s.id)} data={s.data} fill={seriesColor(config, String(s.id), i)} />\n ))}\n </ScatterChart>\n );\n }\n\n case \"radar\": {\n const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);\n return (\n <RadarChart data={rows} margin={margin}>\n {grid ? <PolarGrid /> : null}\n <PolarAngleAxis dataKey={index} />\n <PolarRadiusAxis tick={false} axisLine={false} />\n {tip}\n {leg}\n {series.map((key, i) => (\n <Radar\n key={key}\n dataKey={key}\n name={key}\n stroke={seriesColor(config, key, i)}\n fill={seriesColor(config, key, i)}\n fillOpacity={0.2}\n strokeWidth={2}\n />\n ))}\n </RadarChart>\n );\n }\n\n case \"funnel\": {\n const slices = toSlices(data as ChartSlice[]);\n return (\n <FunnelChart margin={margin}>\n {tip}\n {leg}\n <Funnel data={slices} dataKey=\"value\" nameKey=\"name\">\n {slices.map((slice, i) => (\n <Cell key={slice.id} fill={seriesColor(config, slice.id, i)} />\n ))}\n </Funnel>\n </FunnelChart>\n );\n }\n }\n}\n"],"mappings":"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"}
@@ -40,6 +40,26 @@ function tokenPx(name, el) {
40
40
  if (raw.endsWith("rem")) return n * (Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16);
41
41
  return n;
42
42
  }
43
+ /**
44
+ * The margin a Recharts plot is drawn with, in pixels, resolved on `el`
45
+ * (default `<html>`).
46
+ *
47
+ * Recharts takes a margin as numbers rather than CSS, so the token has to be
48
+ * read and handed over already in pixels. It is `--ds-space-2` at the top and
49
+ * on the right, which is what keeps the topmost y tick label and the last x
50
+ * tick label inside the box; the bottom and the left stay zero because the
51
+ * axes draw their own gutter there. Without a DOM — SSR — the fallback is the
52
+ * 8px that token emits at the default scale, asserted in `chart.test.tsx`.
53
+ */
54
+ function plotMargin(el) {
55
+ const space2 = tokenPx("--ds-space-2", el) ?? 8;
56
+ return {
57
+ top: space2,
58
+ right: space2,
59
+ bottom: 0,
60
+ left: 0
61
+ };
62
+ }
43
63
  let probe;
44
64
  function hex2(n) {
45
65
  return n.toString(16).padStart(2, "0");
@@ -187,6 +207,6 @@ function useThemeVersion() {
187
207
  return version;
188
208
  }
189
209
  //#endregion
190
- export { VIZ_SERIES_COUNT, chartScales, contrastLabel, isDarkSurface, piecewiseHex, readToken, resolveColor, resolveVizSeries, toHex, tokenPx, useThemeVersion, vizSeriesVars, vizVar };
210
+ export { VIZ_SERIES_COUNT, chartScales, contrastLabel, isDarkSurface, piecewiseHex, plotMargin, readToken, resolveColor, resolveVizSeries, toHex, tokenPx, useThemeVersion, vizSeriesVars, vizVar };
191
211
 
192
212
  //# sourceMappingURL=tokens.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","names":[],"sources":["../../../src/components/chart/tokens.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { vizSeries } from \"cortena-design/tokens\";\n\n/**\n * Token plumbing for the chart engines.\n *\n * Recharts draws SVG, so it can take `var(--ds-viz-1)` verbatim and the\n * browser resolves it. Nivo cannot: its canvas renderer hands colours to a\n * 2D context, and its SVG renderer runs colours through d3-color for label and\n * border derivation, and neither understands `var()`. So every Nivo value is\n * read from the `--ds-*` custom property at runtime and handed over as a\n * concrete hex. Nothing in this file is a literal; on the server (no DOM) the\n * `var()` form is returned so SSR markup still resolves in the browser.\n */\n\n/** Number of categorical series colours the design system defines (`--ds-viz-1..n`). */\nexport const VIZ_SERIES_COUNT = vizSeries.length;\n\n/** `var(--ds-viz-N)` for a zero-based series index, wrapping past the palette. */\nexport function vizVar(index: number): string {\n const n = VIZ_SERIES_COUNT;\n return `var(--ds-viz-${(((index % n) + n) % n) + 1})`;\n}\n\n/** The categorical palette as `var()` references, in series order. */\nexport const vizSeriesVars: readonly string[] = /* @__PURE__ */ Array.from({ length: VIZ_SERIES_COUNT }, (_, i) =>\n vizVar(i),\n);\n\nfunction hasDom(): boolean {\n return typeof document !== \"undefined\" && typeof getComputedStyle === \"function\";\n}\n\n/** Read a custom property as the browser computes it on `el` (default: `<html>`). */\nexport function readToken(name: string, el?: Element | null): string {\n if (!hasDom()) return \"\";\n return getComputedStyle(el ?? document.documentElement).getPropertyValue(name).trim();\n}\n\n/** A `--ds-text-*` size (rem or px) as a pixel number, for engines that want numbers. */\nexport function tokenPx(name: string, el?: Element | null): number | undefined {\n const raw = readToken(name, el);\n if (!raw) return undefined;\n const n = Number.parseFloat(raw);\n if (Number.isNaN(n)) return undefined;\n if (raw.endsWith(\"rem\")) {\n const root = Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;\n return n * root;\n }\n return n;\n}\n\nlet probe: CanvasRenderingContext2D | null | undefined;\n\nfunction hex2(n: number): string {\n return n.toString(16).padStart(2, \"0\");\n}\n\n/**\n * Convert any CSS colour the browser understands (oklch, color-mix, rgba…) to\n * `#rrggbb`, by painting it into an offscreen 2D context. Alpha is composited\n * against transparent, so translucent tokens come back opaque; chart fills\n * never use those.\n */\nexport function toHex(css: string): string | undefined {\n if (!hasDom() || !css) return undefined;\n if (probe === undefined) {\n probe = document.createElement(\"canvas\").getContext(\"2d\", { willReadFrequently: true });\n }\n if (!probe) return undefined;\n probe.clearRect(0, 0, 1, 1);\n probe.fillStyle = css;\n probe.fillRect(0, 0, 1, 1);\n const d = probe.getImageData(0, 0, 1, 1).data;\n return `#${hex2(d[0] ?? 0)}${hex2(d[1] ?? 0)}${hex2(d[2] ?? 0)}`;\n}\n\n/**\n * A token as a concrete colour. Returns hex in the browser; on the server the\n * `var()` form, which is fine for SVG markup and irrelevant for canvas.\n */\nexport function resolveColor(token: string, el?: Element | null): string {\n return toHex(readToken(token, el)) ?? `var(${token})`;\n}\n\n/** The categorical palette resolved to concrete colours, in series order. */\nexport function resolveVizSeries(el?: Element | null): string[] {\n return vizSeriesVars.map((_, i) => resolveColor(`--ds-viz-${i + 1}`, el));\n}\n\n/** Relative luminance of a `#rrggbb`, for choosing a scale direction. */\nfunction luminance(hex: string): number {\n const c = (i: number) => {\n const v = Number.parseInt(hex.slice(i, i + 2), 16) / 255;\n return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * c(1) + 0.7152 * c(3) + 0.0722 * c(5);\n}\n\n/**\n * A label colour that reads on a given fill: the design system's ink on light\n * fills, its white on dark ones. Nivo cells and arcs paint their labels with\n * this so a value on a deep sequential cell stays legible.\n */\nexport function contrastLabel(el?: Element | null): (fill: string) => string {\n const ink = resolveColor(\"--ds-base-text-ink\", el);\n const white = resolveColor(\"--ds-base-white\", el);\n return (fill: string) => {\n const hex = fill.startsWith(\"#\") && fill.length === 7 ? fill : toHex(fill);\n return hex && luminance(hex) < 0.3 ? white : ink;\n };\n}\n\n/** True when the resolved `--ds-background` is dark, whatever set the theme (attribute or OS). */\nexport function isDarkSurface(el?: Element | null): boolean {\n const bg = toHex(readToken(\"--ds-background\", el));\n return bg ? luminance(bg) < 0.4 : false;\n}\n\n/** Linear interpolation through a list of hex stops; `t` in [0, 1]. */\nexport function piecewiseHex(stops: string[]): (t: number) => string {\n const rgb = stops.map((h) => [1, 3, 5].map((i) => Number.parseInt(h.slice(i, i + 2), 16)));\n return (t: number) => {\n const clamped = Math.min(1, Math.max(0, Number.isNaN(t) ? 0 : t));\n const pos = clamped * (rgb.length - 1);\n const i = Math.max(0, Math.min(rgb.length - 2, Math.floor(pos)));\n const f = pos - i;\n const a = rgb[i] ?? [0, 0, 0];\n const b = rgb[i + 1] ?? a;\n const mix = (k: number) => Math.round((a[k] ?? 0) + ((b[k] ?? 0) - (a[k] ?? 0)) * f);\n return `#${hex2(mix(0))}${hex2(mix(1))}${hex2(mix(2))}`;\n };\n}\n\nexport interface ChartScales {\n /** Low → high, as concrete hex stops. */\n sequential: string[];\n /** Negative → neutral → positive, as concrete hex stops. */\n diverging: string[];\n /** Interpolators over the stops, `t` in [0, 1], for Nivo's `interpolator` configs. */\n sequentialInterpolator: (t: number) => string;\n divergingInterpolator: (t: number) => string;\n /** `n` evenly spaced sequential swatches, for quantised fills like the calendar. */\n sequentialSteps: (n: number) => string[];\n /** Fill for cells with no value. */\n empty: string;\n /** The chart's surface (`--ds-background`), for the gaps between cells and arcs. */\n surface: string;\n}\n\n/**\n * Sequential and diverging scales from the tokens.\n *\n * The token set has only the eight categorical `--ds-viz-*` colours and no\n * sequential ramp, so the sequential scale is derived from the\n * `--ds-primary-100..900` ladder: light surfaces run 100 → 700 (pale to deep),\n * dark surfaces run 900 → 400 (deep to bright), so low values sit near the\n * background in both themes. The diverging scale runs `--ds-viz-5` (rose)\n * through the theme's neutral (`--ds-neutral-200` light, `--ds-neutral-700`\n * dark) to `--ds-viz-1` (blue).\n */\nexport function chartScales(el?: Element | null): ChartScales {\n const dark = isDarkSurface(el);\n const seqTokens = dark\n ? [\"--ds-primary-900\", \"--ds-primary-800\", \"--ds-primary-600\", \"--ds-primary-400\"]\n : [\"--ds-primary-100\", \"--ds-primary-300\", \"--ds-primary-500\", \"--ds-primary-700\"];\n const sequential = seqTokens.map((t) => resolveColor(t, el));\n const diverging = [\"--ds-viz-5\", dark ? \"--ds-neutral-700\" : \"--ds-neutral-200\", \"--ds-viz-1\"].map(\n (t) => resolveColor(t, el),\n );\n const sequentialInterpolator = piecewiseHex(sequential);\n const divergingInterpolator = piecewiseHex(diverging);\n return {\n sequential,\n diverging,\n sequentialInterpolator,\n divergingInterpolator,\n sequentialSteps: (n) =>\n Array.from({ length: n }, (_, i) => sequentialInterpolator(n === 1 ? 1 : i / (n - 1))),\n empty: resolveColor(\"--ds-muted\", el),\n surface: resolveColor(\"--ds-background\", el),\n };\n}\n\n/**\n * A counter that bumps whenever the theme may have changed: the `data-theme`\n * or `class` attribute on `<html>`, or the OS colour scheme. Resolved token\n * values are memoised on it so Nivo re-reads them on a flip.\n */\nexport function useThemeVersion(): number {\n const [version, setVersion] = useState(0);\n useEffect(() => {\n if (!hasDom()) return;\n const bump = () => setVersion((v) => v + 1);\n const observer = new MutationObserver(bump);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-theme\", \"class\", \"style\"],\n });\n const media = window.matchMedia?.(\"(prefers-color-scheme: dark)\");\n media?.addEventListener?.(\"change\", bump);\n return () => {\n observer.disconnect();\n media?.removeEventListener?.(\"change\", bump);\n };\n }, []);\n return version;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tokens.js","names":[],"sources":["../../../src/components/chart/tokens.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { vizSeries } from \"cortena-design/tokens\";\n\n/**\n * Token plumbing for the chart engines.\n *\n * Recharts draws SVG, so it can take `var(--ds-viz-1)` verbatim and the\n * browser resolves it. Nivo cannot: its canvas renderer hands colours to a\n * 2D context, and its SVG renderer runs colours through d3-color for label and\n * border derivation, and neither understands `var()`. So every Nivo value is\n * read from the `--ds-*` custom property at runtime and handed over as a\n * concrete hex. Nothing in this file is a literal; on the server (no DOM) the\n * `var()` form is returned so SSR markup still resolves in the browser.\n */\n\n/** Number of categorical series colours the design system defines (`--ds-viz-1..n`). */\nexport const VIZ_SERIES_COUNT = vizSeries.length;\n\n/** `var(--ds-viz-N)` for a zero-based series index, wrapping past the palette. */\nexport function vizVar(index: number): string {\n const n = VIZ_SERIES_COUNT;\n return `var(--ds-viz-${(((index % n) + n) % n) + 1})`;\n}\n\n/** The categorical palette as `var()` references, in series order. */\nexport const vizSeriesVars: readonly string[] = /* @__PURE__ */ Array.from({ length: VIZ_SERIES_COUNT }, (_, i) =>\n vizVar(i),\n);\n\nfunction hasDom(): boolean {\n return typeof document !== \"undefined\" && typeof getComputedStyle === \"function\";\n}\n\n/** Read a custom property as the browser computes it on `el` (default: `<html>`). */\nexport function readToken(name: string, el?: Element | null): string {\n if (!hasDom()) return \"\";\n return getComputedStyle(el ?? document.documentElement).getPropertyValue(name).trim();\n}\n\n/** A `--ds-text-*` size (rem or px) as a pixel number, for engines that want numbers. */\nexport function tokenPx(name: string, el?: Element | null): number | undefined {\n const raw = readToken(name, el);\n if (!raw) return undefined;\n const n = Number.parseFloat(raw);\n if (Number.isNaN(n)) return undefined;\n if (raw.endsWith(\"rem\")) {\n const root = Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;\n return n * root;\n }\n return n;\n}\n\n/** The plot margin in pixels when there is no DOM: what `--ds-space-2` emits. */\nexport const PLOT_MARGIN_FALLBACK = 8;\n\n/**\n * The margin a Recharts plot is drawn with, in pixels, resolved on `el`\n * (default `<html>`).\n *\n * Recharts takes a margin as numbers rather than CSS, so the token has to be\n * read and handed over already in pixels. It is `--ds-space-2` at the top and\n * on the right, which is what keeps the topmost y tick label and the last x\n * tick label inside the box; the bottom and the left stay zero because the\n * axes draw their own gutter there. Without a DOM — SSR — the fallback is the\n * 8px that token emits at the default scale, asserted in `chart.test.tsx`.\n */\nexport function plotMargin(el?: Element | null): { top: number; right: number; bottom: number; left: number } {\n const space2 = tokenPx(\"--ds-space-2\", el) ?? PLOT_MARGIN_FALLBACK;\n return { top: space2, right: space2, bottom: 0, left: 0 };\n}\n\nlet probe: CanvasRenderingContext2D | null | undefined;\n\nfunction hex2(n: number): string {\n return n.toString(16).padStart(2, \"0\");\n}\n\n/**\n * Convert any CSS colour the browser understands (oklch, color-mix, rgba…) to\n * `#rrggbb`, by painting it into an offscreen 2D context. Alpha is composited\n * against transparent, so translucent tokens come back opaque; chart fills\n * never use those.\n */\nexport function toHex(css: string): string | undefined {\n if (!hasDom() || !css) return undefined;\n if (probe === undefined) {\n probe = document.createElement(\"canvas\").getContext(\"2d\", { willReadFrequently: true });\n }\n if (!probe) return undefined;\n probe.clearRect(0, 0, 1, 1);\n probe.fillStyle = css;\n probe.fillRect(0, 0, 1, 1);\n const d = probe.getImageData(0, 0, 1, 1).data;\n return `#${hex2(d[0] ?? 0)}${hex2(d[1] ?? 0)}${hex2(d[2] ?? 0)}`;\n}\n\n/**\n * A token as a concrete colour. Returns hex in the browser; on the server the\n * `var()` form, which is fine for SVG markup and irrelevant for canvas.\n */\nexport function resolveColor(token: string, el?: Element | null): string {\n return toHex(readToken(token, el)) ?? `var(${token})`;\n}\n\n/** The categorical palette resolved to concrete colours, in series order. */\nexport function resolveVizSeries(el?: Element | null): string[] {\n return vizSeriesVars.map((_, i) => resolveColor(`--ds-viz-${i + 1}`, el));\n}\n\n/** Relative luminance of a `#rrggbb`, for choosing a scale direction. */\nfunction luminance(hex: string): number {\n const c = (i: number) => {\n const v = Number.parseInt(hex.slice(i, i + 2), 16) / 255;\n return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * c(1) + 0.7152 * c(3) + 0.0722 * c(5);\n}\n\n/**\n * A label colour that reads on a given fill: the design system's ink on light\n * fills, its white on dark ones. Nivo cells and arcs paint their labels with\n * this so a value on a deep sequential cell stays legible.\n */\nexport function contrastLabel(el?: Element | null): (fill: string) => string {\n const ink = resolveColor(\"--ds-base-text-ink\", el);\n const white = resolveColor(\"--ds-base-white\", el);\n return (fill: string) => {\n const hex = fill.startsWith(\"#\") && fill.length === 7 ? fill : toHex(fill);\n return hex && luminance(hex) < 0.3 ? white : ink;\n };\n}\n\n/** True when the resolved `--ds-background` is dark, whatever set the theme (attribute or OS). */\nexport function isDarkSurface(el?: Element | null): boolean {\n const bg = toHex(readToken(\"--ds-background\", el));\n return bg ? luminance(bg) < 0.4 : false;\n}\n\n/** Linear interpolation through a list of hex stops; `t` in [0, 1]. */\nexport function piecewiseHex(stops: string[]): (t: number) => string {\n const rgb = stops.map((h) => [1, 3, 5].map((i) => Number.parseInt(h.slice(i, i + 2), 16)));\n return (t: number) => {\n const clamped = Math.min(1, Math.max(0, Number.isNaN(t) ? 0 : t));\n const pos = clamped * (rgb.length - 1);\n const i = Math.max(0, Math.min(rgb.length - 2, Math.floor(pos)));\n const f = pos - i;\n const a = rgb[i] ?? [0, 0, 0];\n const b = rgb[i + 1] ?? a;\n const mix = (k: number) => Math.round((a[k] ?? 0) + ((b[k] ?? 0) - (a[k] ?? 0)) * f);\n return `#${hex2(mix(0))}${hex2(mix(1))}${hex2(mix(2))}`;\n };\n}\n\nexport interface ChartScales {\n /** Low → high, as concrete hex stops. */\n sequential: string[];\n /** Negative → neutral → positive, as concrete hex stops. */\n diverging: string[];\n /** Interpolators over the stops, `t` in [0, 1], for Nivo's `interpolator` configs. */\n sequentialInterpolator: (t: number) => string;\n divergingInterpolator: (t: number) => string;\n /** `n` evenly spaced sequential swatches, for quantised fills like the calendar. */\n sequentialSteps: (n: number) => string[];\n /** Fill for cells with no value. */\n empty: string;\n /** The chart's surface (`--ds-background`), for the gaps between cells and arcs. */\n surface: string;\n}\n\n/**\n * Sequential and diverging scales from the tokens.\n *\n * The token set has only the eight categorical `--ds-viz-*` colours and no\n * sequential ramp, so the sequential scale is derived from the\n * `--ds-primary-100..900` ladder: light surfaces run 100 → 700 (pale to deep),\n * dark surfaces run 900 → 400 (deep to bright), so low values sit near the\n * background in both themes. The diverging scale runs `--ds-viz-5` (rose)\n * through the theme's neutral (`--ds-neutral-200` light, `--ds-neutral-700`\n * dark) to `--ds-viz-1` (blue).\n */\nexport function chartScales(el?: Element | null): ChartScales {\n const dark = isDarkSurface(el);\n const seqTokens = dark\n ? [\"--ds-primary-900\", \"--ds-primary-800\", \"--ds-primary-600\", \"--ds-primary-400\"]\n : [\"--ds-primary-100\", \"--ds-primary-300\", \"--ds-primary-500\", \"--ds-primary-700\"];\n const sequential = seqTokens.map((t) => resolveColor(t, el));\n const diverging = [\"--ds-viz-5\", dark ? \"--ds-neutral-700\" : \"--ds-neutral-200\", \"--ds-viz-1\"].map(\n (t) => resolveColor(t, el),\n );\n const sequentialInterpolator = piecewiseHex(sequential);\n const divergingInterpolator = piecewiseHex(diverging);\n return {\n sequential,\n diverging,\n sequentialInterpolator,\n divergingInterpolator,\n sequentialSteps: (n) =>\n Array.from({ length: n }, (_, i) => sequentialInterpolator(n === 1 ? 1 : i / (n - 1))),\n empty: resolveColor(\"--ds-muted\", el),\n surface: resolveColor(\"--ds-background\", el),\n };\n}\n\n/**\n * A counter that bumps whenever the theme may have changed: the `data-theme`\n * or `class` attribute on `<html>`, or the OS colour scheme. Resolved token\n * values are memoised on it so Nivo re-reads them on a flip.\n */\nexport function useThemeVersion(): number {\n const [version, setVersion] = useState(0);\n useEffect(() => {\n if (!hasDom()) return;\n const bump = () => setVersion((v) => v + 1);\n const observer = new MutationObserver(bump);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-theme\", \"class\", \"style\"],\n });\n const media = window.matchMedia?.(\"(prefers-color-scheme: dark)\");\n media?.addEventListener?.(\"change\", bump);\n return () => {\n observer.disconnect();\n media?.removeEventListener?.(\"change\", bump);\n };\n }, []);\n return version;\n}\n"],"mappings":"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"}
package/dist/core.d.ts CHANGED
@@ -3,6 +3,7 @@ import { Alert, AlertDescription, AlertIcon, AlertProps, AlertTitle, alertVarian
3
3
  import { AppShell, AppShellExtension, AppShellHelp, AppShellProps, AppShellUser, BottomRightCluster, BottomRightClusterProps, BrandMark, BrandMarkProps, HelpButton, HelpButtonProps, HelpPanelSlotProps, ThemeToggle, ThemeToggleProps, documentTitle } from "./components/app-shell.js";
4
4
  import { AuthScreen, AuthScreenBrand, AuthScreenProps, GoogleMark, LoginExtension, LoginMethod, LoginScreen, LoginScreenProps, MicrosoftMark, PasswordCredentials, httpsLogoUrl } from "./components/login-screen.js";
5
5
  import { Badge, BadgeProps, badgeVariants } from "./components/badge.js";
6
+ import { RenderProp } from "./lib/render.js";
6
7
  import { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbLinkProps, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "./components/breadcrumb.js";
7
8
  import { Button, ButtonProps, buttonVariants } from "./components/button.js";
8
9
  import { ButtonLink, ButtonLinkProps } from "./components/button-link.js";
@@ -45,4 +46,4 @@ import { Kbd } from "./components/kbd.js";
45
46
  import { Skeleton } from "./components/skeleton.js";
46
47
  import { Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger } from "./components/tabs.js";
47
48
  import { cn } from "./lib/cn.js";
48
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertIcon, type AlertProps, AlertTitle, AppShell, type AppShellExtension, type AppShellHelp, type AppShellProps, type AppShellUser, AuthScreen, type AuthScreenBrand, type AuthScreenProps, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BottomRightCluster, type BottomRightClusterProps, BrandMark, type BrandMarkProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, type BreadcrumbLinkProps, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonLink, type ButtonLinkProps, type ButtonProps, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, Checkbox, type CheckboxProps, Chip, type ChipProps, Combobox, ComboboxChip, type ComboboxChipProps, ComboboxChips, type ComboboxChipsProps, ComboboxClear, ComboboxCollection, ComboboxContent, type ComboboxContentProps, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, type ComboboxInputProps, ComboboxItem, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandDialog, type CommandDialogProps, CommandEmpty, CommandGroup, CommandInput, CommandItem, type CommandItemProps, CommandList, CommandLoading, CommandSeparator, CommandShortcut, type ConsentClient, type ConsentScope, ConsentScreen, type ConsentScreenProps, type ConsentUser, type CortenaTheme, type CortenaThemeMessage, DEFAULT_SESSION_POLICY, DEFAULT_THEME_STORAGE_KEY, Dialog, DialogBody, DialogClose, DialogContent, type DialogContentProps, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, type DropdownMenuLabelProps, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, type DropdownMenuSubTriggerProps, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ErrorBanner, type ErrorBannerProps, Field, FieldContent, FieldControl, type FieldControlProps, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorItem, type FieldErrorProps, FieldGroup, FieldLabel, type FieldLabelProps, type FieldProps, Fieldset, FieldsetLegend, type FieldsetLegendProps, type FieldsetProps, GoogleMark, HelpButton, type HelpButtonProps, type HelpPanelSlotProps, Input, type InputProps, Kbd, Label, type LabelProps, LoadingSkeleton, type LoadingSkeletonPreset, type LoadingSkeletonProps, type LoginExtension, type LoginMethod, LoginScreen, type LoginScreenProps, MicrosoftMark, PageHeader, type PageHeaderProps, type PasswordCredentials, Popover, PopoverClose, PopoverContent, type PopoverContentProps, PopoverDescription, PopoverTitle, PopoverTrigger, Progress, ProgressIndicator, ProgressLabel, type ProgressProps, ProgressTrack, ProgressValue, RadioGroup, RadioGroupItem, type RadioGroupItemProps, type RadioGroupProps, type ResolvedCortenaTheme, SESSION_CHANNEL_NAME, ScrollArea, type ScrollAreaProps, ScrollBar, SectionCard, type SectionCardProps, Segmented, type SegmentedOption, type SegmentedProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectItem, SelectLabel, type SelectProps, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, Separator, type SeparatorProps, type SessionClaims, SessionExpiryDialog, type SessionExpiryDialogProps, SessionGuard, type SessionGuardMessage, type SessionGuardProps, type SessionPolicy, type SessionSignOutReason, type SessionState, type SessionTimers, type SessionToken, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, type SheetProps, SheetTitle, SheetTrigger, Skeleton, Spinner, type SpinnerProps, StatusDot, type StatusDotProps, type StatusDotTone, Switch, type SwitchProps, THEME_MESSAGE_TYPE, Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger, Textarea, type TextareaProps, ThemeToggle, type ThemeToggleProps, Toast, type ToastProps, Toaster, type ToasterProps, Toolbar, ToolbarEnd, type ToolbarProps, ToolbarSeparator, ToolbarStart, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, type UseCortenaThemeOptions, type UseCortenaThemeResult, type UseSessionGuardOptions, type UseSessionGuardResult, alertVariants, applyStoredTheme, applyTheme, badgeVariants, buttonVariants, chipVariants, cn, decodeSessionClaims, documentTitle, fieldVariants, formatCountdown, getThemeInitScript, httpsLogoUrl, inputClassName, labelVariants, readStoredTheme, sheetVariants, textareaClassName, themeFromBackground, themeFromMessage, themeInitScript, toastVariants, useComboboxFilter, useCortenaTheme, useSessionGuard, useToast };
49
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertIcon, type AlertProps, AlertTitle, AppShell, type AppShellExtension, type AppShellHelp, type AppShellProps, type AppShellUser, AuthScreen, type AuthScreenBrand, type AuthScreenProps, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BottomRightCluster, type BottomRightClusterProps, BrandMark, type BrandMarkProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, type BreadcrumbLinkProps, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonLink, type ButtonLinkProps, type ButtonProps, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, Checkbox, type CheckboxProps, Chip, type ChipProps, Combobox, ComboboxChip, type ComboboxChipProps, ComboboxChips, type ComboboxChipsProps, ComboboxClear, ComboboxCollection, ComboboxContent, type ComboboxContentProps, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, type ComboboxInputProps, ComboboxItem, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandDialog, type CommandDialogProps, CommandEmpty, CommandGroup, CommandInput, CommandItem, type CommandItemProps, CommandList, CommandLoading, CommandSeparator, CommandShortcut, type ConsentClient, type ConsentScope, ConsentScreen, type ConsentScreenProps, type ConsentUser, type CortenaTheme, type CortenaThemeMessage, DEFAULT_SESSION_POLICY, DEFAULT_THEME_STORAGE_KEY, Dialog, DialogBody, DialogClose, DialogContent, type DialogContentProps, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, type DropdownMenuLabelProps, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, type DropdownMenuSubTriggerProps, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ErrorBanner, type ErrorBannerProps, Field, FieldContent, FieldControl, type FieldControlProps, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorItem, type FieldErrorProps, FieldGroup, FieldLabel, type FieldLabelProps, type FieldProps, Fieldset, FieldsetLegend, type FieldsetLegendProps, type FieldsetProps, GoogleMark, HelpButton, type HelpButtonProps, type HelpPanelSlotProps, Input, type InputProps, Kbd, Label, type LabelProps, LoadingSkeleton, type LoadingSkeletonPreset, type LoadingSkeletonProps, type LoginExtension, type LoginMethod, LoginScreen, type LoginScreenProps, MicrosoftMark, PageHeader, type PageHeaderProps, type PasswordCredentials, Popover, PopoverClose, PopoverContent, type PopoverContentProps, PopoverDescription, PopoverTitle, PopoverTrigger, Progress, ProgressIndicator, ProgressLabel, type ProgressProps, ProgressTrack, ProgressValue, RadioGroup, RadioGroupItem, type RadioGroupItemProps, type RadioGroupProps, type RenderProp, type ResolvedCortenaTheme, SESSION_CHANNEL_NAME, ScrollArea, type ScrollAreaProps, ScrollBar, SectionCard, type SectionCardProps, Segmented, type SegmentedOption, type SegmentedProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectItem, SelectLabel, type SelectProps, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, Separator, type SeparatorProps, type SessionClaims, SessionExpiryDialog, type SessionExpiryDialogProps, SessionGuard, type SessionGuardMessage, type SessionGuardProps, type SessionPolicy, type SessionSignOutReason, type SessionState, type SessionTimers, type SessionToken, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, type SheetProps, SheetTitle, SheetTrigger, Skeleton, Spinner, type SpinnerProps, StatusDot, type StatusDotProps, type StatusDotTone, Switch, type SwitchProps, THEME_MESSAGE_TYPE, Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger, Textarea, type TextareaProps, ThemeToggle, type ThemeToggleProps, Toast, type ToastProps, Toaster, type ToasterProps, Toolbar, ToolbarEnd, type ToolbarProps, ToolbarSeparator, ToolbarStart, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, type UseCortenaThemeOptions, type UseCortenaThemeResult, type UseSessionGuardOptions, type UseSessionGuardResult, alertVariants, applyStoredTheme, applyTheme, badgeVariants, buttonVariants, chipVariants, cn, decodeSessionClaims, documentTitle, fieldVariants, formatCountdown, getThemeInitScript, httpsLogoUrl, inputClassName, labelVariants, readStoredTheme, sheetVariants, textareaClassName, themeFromBackground, themeFromMessage, themeInitScript, toastVariants, useComboboxFilter, useCortenaTheme, useSessionGuard, useToast };
package/dist/index.d.ts CHANGED
@@ -23,6 +23,7 @@ import { Alert, AlertDescription, AlertIcon, AlertProps, AlertTitle, alertVarian
23
23
  import { AppShell, AppShellExtension, AppShellHelp, AppShellProps, AppShellUser, BottomRightCluster, BottomRightClusterProps, BrandMark, BrandMarkProps, HelpButton, HelpButtonProps, HelpPanelSlotProps, ThemeToggle, ThemeToggleProps, documentTitle } from "./components/app-shell.js";
24
24
  import { AuthScreen, AuthScreenBrand, AuthScreenProps, GoogleMark, LoginExtension, LoginMethod, LoginScreen, LoginScreenProps, MicrosoftMark, PasswordCredentials, httpsLogoUrl } from "./components/login-screen.js";
25
25
  import { Badge, BadgeProps, badgeVariants } from "./components/badge.js";
26
+ import { RenderProp } from "./lib/render.js";
26
27
  import { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbLinkProps, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "./components/breadcrumb.js";
27
28
  import { Button, ButtonProps, buttonVariants } from "./components/button.js";
28
29
  import { ButtonLink, ButtonLinkProps } from "./components/button-link.js";
@@ -91,4 +92,4 @@ import { MentionItem, MentionQuery, RichTextChip, RichTextEditor, RichTextEditor
91
92
  import "./rich-text-editor.js";
92
93
  import { SortableHandle, SortableHandleProps, SortableList, SortableListProps, SortableRenderState, SortableReorderDetails, arrayMove } from "./components/sortable-list.js";
93
94
  import "./sortable-list.js";
94
- export { type A2UIAction, type A2UIActionSpec, type A2UIBeginRendering, type A2UICatalogue, type A2UICatalogueDoc, type A2UICatalogueEntry, type A2UIChildList, type A2UIChildren, type A2UIColumn, type A2UIComponentDoc, type A2UIComponentSpec, type A2UICreateSurface, type A2UIDataBinding, type A2UIDeleteSurface, A2UIErrorCard, type A2UIExample, type A2UIFoldResult, type A2UIGroup, type A2UIMessage, type A2UIMessageInput, type A2UINodeInfo, type A2UIPropertyValue, A2UIRenderer, type A2UIRendererProps, type A2UIResolvedAction, type A2UIRow, type A2UISurface, type A2UITableSource, type A2UIUpdateComponents, type A2UIUpdateDataModel, type A2UIView, type A2UIViewProps, A2UI_CATALOGUE_ID, A2UI_DEFAULT_SURFACE_ID, A2UI_VERSION, ADMIN_ROUTES, ADMIN_ROUTE_LABELS, type Accept, Accordion, AccordionContent, AccordionItem, AccordionTrigger, type AdminEffectiveRole, type AdminErrorEnvelope, type AdminGroupRef, type AdminGroupRow, type AdminLicence, AdminLicenceScreen, AdminMatrix, type AdminMemberRow, AdminMembers, type AdminPermissionMatrix, AdminPermissions, type AdminPermissionsApi, type AdminPermissionsContextValue, type AdminPermissionsProps, AdminPermissionsProvider, type AdminPrincipal, type AdminRoleSource, AdminRoles, type AdminRoute, Alert, AlertDescription, AlertIcon, type AlertProps, AlertTitle, AppShell, type AppShellExtension, type AppShellHelp, type AppShellProps, type AppShellUser, Area, AreaChart, AuthScreen, type AuthScreenBrand, type AuthScreenProps, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Bar, BarChart, BottomRightCluster, type BottomRightClusterProps, BrandMark, type BrandMarkProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, type BreadcrumbLinkProps, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonLink, type ButtonLinkProps, type ButtonProps, Calendar, CalendarDayButton, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, CartesianGrid, Cell, Chart, type ChartConfig, ChartContainer, type ChartContainerProps, type ChartDataFor, type ChartDay, ChartEmpty, type ChartEngine, ChartError, type ChartLabels, ChartLegend, ChartLegendContent, type ChartLegendContentProps, ChartLoading, type ChartMatrix, type ChartPoint, type ChartProps, type ChartRenderer, type ChartRow, type ChartScale, type ChartScales, type ChartSeries, type ChartSlice, ChartTooltip, ChartTooltipContent, type ChartTooltipContentProps, type ChartTree, type ChartType, Checkbox, type CheckboxProps, Chip, type ChipProps, type ClientSource, type CodeRendererProps, Combobox, ComboboxChip, type ComboboxChipProps, ComboboxChips, type ComboboxChipsProps, ComboboxClear, ComboboxCollection, ComboboxContent, type ComboboxContentProps, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, type ComboboxInputProps, ComboboxItem, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandDialog, type CommandDialogProps, CommandEmpty, CommandGroup, CommandInput, CommandItem, type CommandItemProps, CommandList, CommandLoading, CommandSeparator, CommandShortcut, ComposedChart, type ConsentClient, type ConsentScope, ConsentScreen, type ConsentScreenProps, type ConsentUser, type CortenaTheme, type CortenaThemeMessage, DEFAULT_SESSION_POLICY, DEFAULT_THEME_STORAGE_KEY, type DataSource, DataTable, type DataTableAutoRefresh, type DataTableAutoRefreshState, type DataTableCell, type DataTableColumn, type DataTableColumnDef, DataTableColumnHeader, type DataTableColumnHeaderProps, type DataTableColumnMeta, type DataTableEditable, type DataTableEditingCell, DataTableExportMenu, type DataTableExportMenuProps, DataTableFacetedFilter, type DataTableFacetedFilterOption, type DataTableFacetedFilterProps, type DataTableFeatures, type DataTableHandle, type DataTableInstance, DataTablePagination, type DataTablePaginationMode, type DataTablePaginationProps, type DataTableProps, DataTableRefresh, type DataTableRefreshPause, type DataTableRefreshProps, type DataTableRow, type DataTableState, type DataTableTable, DataTableToolbar, type DataTableToolbarProps, DataTableView, DataTableViewOptions, type DataTableViewOptionsProps, type DataTableViewProps, DateField, type DateFieldProps, DatePicker, type DatePickerProps, DateRangePicker, type DateRangePickerProps, Dialog, DialogBody, DialogClose, DialogContent, type DialogContentProps, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectRoles, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, type DropdownMenuLabelProps, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, type DropdownMenuSubTriggerProps, DropdownMenuTrigger, Dropzone, type DropzoneProps, type DropzoneState, EffectiveRoles, EmptyState, type EmptyStateProps, ErrorBanner, type ErrorBannerProps, type ExportCell, type ExportSheet, Field, FieldContent, FieldControl, type FieldControlProps, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorItem, type FieldErrorProps, FieldGroup, FieldLabel, type FieldLabelProps, type FieldProps, Fieldset, FieldsetLegend, type FieldsetLegendProps, type FieldsetProps, FileList, type FileListProps, type FileRejection, Form, FormControl, type FormControlProps, FormDescription, type FormDescriptionProps, FormField, FormItem, type FormItemProps, FormLabel, type FormLabelProps, FormMessage, type FormMessageProps, Funnel, FunnelChart, GoogleMark, HEADING_LEVELS, HelpButton, type HelpButtonProps, type HelpDocument, HelpHotkeys, type HelpHotkeysOptions, type HelpHotkeysProps, HelpPanel, type HelpPanelProps, type HelpPanelSlotConfig, type HelpPanelSlotProps, type HelpRoute, type HelpSection, type HelpSource, Input, type InputProps, type JsonSchema, Kbd, Label, LabelList, type LabelProps, Line, LineChart, LoadingSkeleton, type LoadingSkeletonPreset, type LoadingSkeletonProps, type LoginExtension, type LoginMethod, LoginScreen, type LoginScreenProps, MENTION_PROTOCOL, Markdown, type Components as MarkdownComponents, type MarkdownProps, type MarkdownSnapshot, MentionChip, type MentionChipAttributes, type MentionItem, type MentionQuery, MicrosoftMark, NIVO_TYPES, type NivoTheme, PageHeader, type PageHeaderProps, type ParsedMarkdown, type PasswordCredentials, Pie, PieChart, PolarAngleAxis, PolarGrid, PolarRadiusAxis, Popover, PopoverClose, PopoverContent, type PopoverContentProps, PopoverDescription, PopoverTitle, PopoverTrigger, Progress, ProgressIndicator, ProgressLabel, type ProgressProps, ProgressTrack, ProgressValue, RECHARTS_TYPES, Radar, RadarChart, RadioGroup, RadioGroupItem, type RadioGroupItemProps, type RadioGroupProps, RawBlock, RechartsLegend, RechartsTooltip, ReferenceLine, type ResolvedCortenaTheme, ResponsiveContainer, type RichTextChip, RichTextEditor, type RichTextEditorProps, type RichTextExtensionOptions, type RichTextExternalChange, type RichTextNode, RichTextToolbar, type RichTextToolbarProps, RoleAssignmentDialog, type RoleAssignmentDialogProps, SESSION_CHANNEL_NAME, Scatter, ScatterChart, ScrollArea, type ScrollAreaProps, ScrollBar, SectionCard, type SectionCardProps, Segmented, type SegmentedOption, type SegmentedProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectItem, SelectLabel, type SelectProps, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, type SelectionActionContext, Separator, type SeparatorProps, type ServerSource, type SessionClaims, SessionExpiryDialog, type SessionExpiryDialogProps, SessionGuard, type SessionGuardMessage, type SessionGuardProps, type SessionPolicy, type SessionSignOutReason, type SessionState, type SessionTimers, type SessionToken, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, type SheetProps, SheetTitle, SheetTrigger, Skeleton, SortableHandle, type SortableHandleProps, SortableList, type SortableListProps, type SortableRenderState, type SortableReorderDetails, Spinner, type SpinnerProps, StatusDot, type StatusDotProps, type StatusDotTone, type SubmitHandler, Switch, type SwitchProps, THEME_MESSAGE_TYPE, type TableQuery, type TableResult, Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger, Textarea, type TextareaProps, ThemeToggle, type ThemeToggleProps, Toast, type ToastProps, Toaster, type ToasterProps, Toolbar, ToolbarEnd, type ToolbarProps, ToolbarSeparator, ToolbarStart, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, type UseCortenaThemeOptions, type UseCortenaThemeResult, type UseDataTableOptions, type UseFormFieldReturn, type UseFormReturn, type UseSessionGuardOptions, type UseSessionGuardResult, VIZ_SERIES_COUNT, XAxis, YAxis, adminErrorMessage, alertVariants, applyStoredTheme, applyTheme, arrayMove, badgeVariants, buttonVariants, catalogueNames, chartEngine, chartScales, chipVariants, cn, createColumnHelper, dataTableFeatures, decodeSessionClaims, defaultCatalogue, documentTitle, downloadCsv, downloadExcel, effectiveRolesOf, fieldVariants, foldMessages, formatCountdown, formatDateDefault, formatDateISO, formatDateLong, formatDateShort, formatFileSize, formatRelative, getAtPointer, getThemeInitScript, helpPanelSlot, httpDocumentUrl, httpsLogoUrl, inputClassName, isDataBinding, labelVariants, markdownSanitizeSchema, parseA2UIMessages, parseDateDefault, parseDateISO, parseHelpDocument, parseMarkdown, pointerSegments, readAction, readChildren, readComponent, readStoredTheme, resolveColor, resolveHelpTarget, resolvePointer, resolveValue, resolveVizSeries, richTextExtensions, serializeMarkdown, seriesColor, setAtPointer, sheetVariants, sourceGroupOf, textareaClassName, themeFromBackground, themeFromMessage, themeInitScript, toCsv, toHex, toSheet, toastVariants, useAdminPermissions, useChart, useComboboxFilter, useCortenaTheme, useDataTable, useForm, useFormField, useHelpHotkeys, useSessionGuard, useToast, vizSeriesVars, vizVar, zodResolver };
95
+ export { type A2UIAction, type A2UIActionSpec, type A2UIBeginRendering, type A2UICatalogue, type A2UICatalogueDoc, type A2UICatalogueEntry, type A2UIChildList, type A2UIChildren, type A2UIColumn, type A2UIComponentDoc, type A2UIComponentSpec, type A2UICreateSurface, type A2UIDataBinding, type A2UIDeleteSurface, A2UIErrorCard, type A2UIExample, type A2UIFoldResult, type A2UIGroup, type A2UIMessage, type A2UIMessageInput, type A2UINodeInfo, type A2UIPropertyValue, A2UIRenderer, type A2UIRendererProps, type A2UIResolvedAction, type A2UIRow, type A2UISurface, type A2UITableSource, type A2UIUpdateComponents, type A2UIUpdateDataModel, type A2UIView, type A2UIViewProps, A2UI_CATALOGUE_ID, A2UI_DEFAULT_SURFACE_ID, A2UI_VERSION, ADMIN_ROUTES, ADMIN_ROUTE_LABELS, type Accept, Accordion, AccordionContent, AccordionItem, AccordionTrigger, type AdminEffectiveRole, type AdminErrorEnvelope, type AdminGroupRef, type AdminGroupRow, type AdminLicence, AdminLicenceScreen, AdminMatrix, type AdminMemberRow, AdminMembers, type AdminPermissionMatrix, AdminPermissions, type AdminPermissionsApi, type AdminPermissionsContextValue, type AdminPermissionsProps, AdminPermissionsProvider, type AdminPrincipal, type AdminRoleSource, AdminRoles, type AdminRoute, Alert, AlertDescription, AlertIcon, type AlertProps, AlertTitle, AppShell, type AppShellExtension, type AppShellHelp, type AppShellProps, type AppShellUser, Area, AreaChart, AuthScreen, type AuthScreenBrand, type AuthScreenProps, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Bar, BarChart, BottomRightCluster, type BottomRightClusterProps, BrandMark, type BrandMarkProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, type BreadcrumbLinkProps, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonLink, type ButtonLinkProps, type ButtonProps, Calendar, CalendarDayButton, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, CartesianGrid, Cell, Chart, type ChartConfig, ChartContainer, type ChartContainerProps, type ChartDataFor, type ChartDay, ChartEmpty, type ChartEngine, ChartError, type ChartLabels, ChartLegend, ChartLegendContent, type ChartLegendContentProps, ChartLoading, type ChartMatrix, type ChartPoint, type ChartProps, type ChartRenderer, type ChartRow, type ChartScale, type ChartScales, type ChartSeries, type ChartSlice, ChartTooltip, ChartTooltipContent, type ChartTooltipContentProps, type ChartTree, type ChartType, Checkbox, type CheckboxProps, Chip, type ChipProps, type ClientSource, type CodeRendererProps, Combobox, ComboboxChip, type ComboboxChipProps, ComboboxChips, type ComboboxChipsProps, ComboboxClear, ComboboxCollection, ComboboxContent, type ComboboxContentProps, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, type ComboboxInputProps, ComboboxItem, ComboboxSeparator, ComboboxStatus, ComboboxTrigger, ComboboxValue, Command, CommandDialog, type CommandDialogProps, CommandEmpty, CommandGroup, CommandInput, CommandItem, type CommandItemProps, CommandList, CommandLoading, CommandSeparator, CommandShortcut, ComposedChart, type ConsentClient, type ConsentScope, ConsentScreen, type ConsentScreenProps, type ConsentUser, type CortenaTheme, type CortenaThemeMessage, DEFAULT_SESSION_POLICY, DEFAULT_THEME_STORAGE_KEY, type DataSource, DataTable, type DataTableAutoRefresh, type DataTableAutoRefreshState, type DataTableCell, type DataTableColumn, type DataTableColumnDef, DataTableColumnHeader, type DataTableColumnHeaderProps, type DataTableColumnMeta, type DataTableEditable, type DataTableEditingCell, DataTableExportMenu, type DataTableExportMenuProps, DataTableFacetedFilter, type DataTableFacetedFilterOption, type DataTableFacetedFilterProps, type DataTableFeatures, type DataTableHandle, type DataTableInstance, DataTablePagination, type DataTablePaginationMode, type DataTablePaginationProps, type DataTableProps, DataTableRefresh, type DataTableRefreshPause, type DataTableRefreshProps, type DataTableRow, type DataTableState, type DataTableTable, DataTableToolbar, type DataTableToolbarProps, DataTableView, DataTableViewOptions, type DataTableViewOptionsProps, type DataTableViewProps, DateField, type DateFieldProps, DatePicker, type DatePickerProps, DateRangePicker, type DateRangePickerProps, Dialog, DialogBody, DialogClose, DialogContent, type DialogContentProps, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectRoles, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, type DropdownMenuLabelProps, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, type DropdownMenuSubTriggerProps, DropdownMenuTrigger, Dropzone, type DropzoneProps, type DropzoneState, EffectiveRoles, EmptyState, type EmptyStateProps, ErrorBanner, type ErrorBannerProps, type ExportCell, type ExportSheet, Field, FieldContent, FieldControl, type FieldControlProps, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorItem, type FieldErrorProps, FieldGroup, FieldLabel, type FieldLabelProps, type FieldProps, Fieldset, FieldsetLegend, type FieldsetLegendProps, type FieldsetProps, FileList, type FileListProps, type FileRejection, Form, FormControl, type FormControlProps, FormDescription, type FormDescriptionProps, FormField, FormItem, type FormItemProps, FormLabel, type FormLabelProps, FormMessage, type FormMessageProps, Funnel, FunnelChart, GoogleMark, HEADING_LEVELS, HelpButton, type HelpButtonProps, type HelpDocument, HelpHotkeys, type HelpHotkeysOptions, type HelpHotkeysProps, HelpPanel, type HelpPanelProps, type HelpPanelSlotConfig, type HelpPanelSlotProps, type HelpRoute, type HelpSection, type HelpSource, Input, type InputProps, type JsonSchema, Kbd, Label, LabelList, type LabelProps, Line, LineChart, LoadingSkeleton, type LoadingSkeletonPreset, type LoadingSkeletonProps, type LoginExtension, type LoginMethod, LoginScreen, type LoginScreenProps, MENTION_PROTOCOL, Markdown, type Components as MarkdownComponents, type MarkdownProps, type MarkdownSnapshot, MentionChip, type MentionChipAttributes, type MentionItem, type MentionQuery, MicrosoftMark, NIVO_TYPES, type NivoTheme, PageHeader, type PageHeaderProps, type ParsedMarkdown, type PasswordCredentials, Pie, PieChart, PolarAngleAxis, PolarGrid, PolarRadiusAxis, Popover, PopoverClose, PopoverContent, type PopoverContentProps, PopoverDescription, PopoverTitle, PopoverTrigger, Progress, ProgressIndicator, ProgressLabel, type ProgressProps, ProgressTrack, ProgressValue, RECHARTS_TYPES, Radar, RadarChart, RadioGroup, RadioGroupItem, type RadioGroupItemProps, type RadioGroupProps, RawBlock, RechartsLegend, RechartsTooltip, ReferenceLine, type RenderProp, type ResolvedCortenaTheme, ResponsiveContainer, type RichTextChip, RichTextEditor, type RichTextEditorProps, type RichTextExtensionOptions, type RichTextExternalChange, type RichTextNode, RichTextToolbar, type RichTextToolbarProps, RoleAssignmentDialog, type RoleAssignmentDialogProps, SESSION_CHANNEL_NAME, Scatter, ScatterChart, ScrollArea, type ScrollAreaProps, ScrollBar, SectionCard, type SectionCardProps, Segmented, type SegmentedOption, type SegmentedProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectItem, SelectLabel, type SelectProps, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, type SelectionActionContext, Separator, type SeparatorProps, type ServerSource, type SessionClaims, SessionExpiryDialog, type SessionExpiryDialogProps, SessionGuard, type SessionGuardMessage, type SessionGuardProps, type SessionPolicy, type SessionSignOutReason, type SessionState, type SessionTimers, type SessionToken, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, type SheetProps, SheetTitle, SheetTrigger, Skeleton, SortableHandle, type SortableHandleProps, SortableList, type SortableListProps, type SortableRenderState, type SortableReorderDetails, Spinner, type SpinnerProps, StatusDot, type StatusDotProps, type StatusDotTone, type SubmitHandler, Switch, type SwitchProps, THEME_MESSAGE_TYPE, type TableQuery, type TableResult, Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger, Textarea, type TextareaProps, ThemeToggle, type ThemeToggleProps, Toast, type ToastProps, Toaster, type ToasterProps, Toolbar, ToolbarEnd, type ToolbarProps, ToolbarSeparator, ToolbarStart, Tooltip, TooltipContent, type TooltipContentProps, TooltipProvider, TooltipTrigger, type UseCortenaThemeOptions, type UseCortenaThemeResult, type UseDataTableOptions, type UseFormFieldReturn, type UseFormReturn, type UseSessionGuardOptions, type UseSessionGuardResult, VIZ_SERIES_COUNT, XAxis, YAxis, adminErrorMessage, alertVariants, applyStoredTheme, applyTheme, arrayMove, badgeVariants, buttonVariants, catalogueNames, chartEngine, chartScales, chipVariants, cn, createColumnHelper, dataTableFeatures, decodeSessionClaims, defaultCatalogue, documentTitle, downloadCsv, downloadExcel, effectiveRolesOf, fieldVariants, foldMessages, formatCountdown, formatDateDefault, formatDateISO, formatDateLong, formatDateShort, formatFileSize, formatRelative, getAtPointer, getThemeInitScript, helpPanelSlot, httpDocumentUrl, httpsLogoUrl, inputClassName, isDataBinding, labelVariants, markdownSanitizeSchema, parseA2UIMessages, parseDateDefault, parseDateISO, parseHelpDocument, parseMarkdown, pointerSegments, readAction, readChildren, readComponent, readStoredTheme, resolveColor, resolveHelpTarget, resolvePointer, resolveValue, resolveVizSeries, richTextExtensions, serializeMarkdown, seriesColor, setAtPointer, sheetVariants, sourceGroupOf, textareaClassName, themeFromBackground, themeFromMessage, themeInitScript, toCsv, toHex, toSheet, toastVariants, useAdminPermissions, useChart, useComboboxFilter, useCortenaTheme, useDataTable, useForm, useFormField, useHelpHotkeys, useSessionGuard, useToast, vizSeriesVars, vizVar, zodResolver };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cortena-ui",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "Cortena UI — the shared React component library for cortenaweb and every Cortena extension. shadcn over Base UI, styled entirely from cortena-design tokens.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {
@@ -71,6 +71,7 @@
71
71
  "check": "tsc --noEmit",
72
72
  "lint:design": "node ../../lint/cli.mjs --exempt chart-import src",
73
73
  "test": "node ../../scripts/test-changed.mjs --package ui",
74
+ "test:dark": "vitest run --config vitest.config.ts --project dark",
74
75
  "guide": "vite --config guide/vite.config.ts",
75
76
  "guide:build": "vite build --config guide/vite.config.ts",
76
77
  "a2ui:catalogue": "node scripts/a2ui-catalogue.mjs",
@@ -81,7 +82,7 @@
81
82
  "peerDependencies": {
82
83
  "@ag-ui/client": "^0.0.59",
83
84
  "@tanstack/react-query": "^5.0.0",
84
- "cortena-design": ">=3.4.0",
85
+ "cortena-design": ">=3.4.0 <4",
85
86
  "react": "^19.0.0",
86
87
  "react-dom": "^19.0.0",
87
88
  "zod": "^3.25.0 || ^4.0.0"
@@ -92,13 +93,8 @@
92
93
  "@dnd-kit/sortable": "^10.0.0",
93
94
  "@dnd-kit/utilities": "^3.2.2",
94
95
  "@hookform/resolvers": "^5.9.1",
95
- "@nivo/bar": "^0.99.0",
96
96
  "@nivo/calendar": "^0.99.0",
97
- "@nivo/core": "^0.99.0",
98
97
  "@nivo/heatmap": "^0.99.0",
99
- "@nivo/line": "^0.99.0",
100
- "@nivo/pie": "^0.99.0",
101
- "@nivo/scatterplot": "^0.99.0",
102
98
  "@nivo/sunburst": "^0.99.0",
103
99
  "@nivo/treemap": "^0.99.0",
104
100
  "@tanstack/react-table": "^9.2.4",
@@ -52,6 +52,25 @@ export interface NivoTheme {
52
52
  };
53
53
  }
54
54
 
55
+ /**
56
+ * What these four sizes are when there is no DOM to read them from.
57
+ *
58
+ * `nivoTheme` runs on the server too, where `getComputedStyle` does not exist
59
+ * and every `tokenPx` call comes back undefined. Each number below is the
60
+ * pixel value its token emits at the default scale, so the server markup and
61
+ * the first client paint agree. `chart.test.tsx` asserts them against the
62
+ * live tokens, which is what stops them drifting the way the two radii had:
63
+ * `--ds-radius-md` is 12px and fell back to 6, `--ds-radius-sm` is 8px and
64
+ * fell back to 4, so every server-rendered tooltip drew half-round corners
65
+ * until hydration.
66
+ */
67
+ export const NIVO_SIZE_FALLBACK = {
68
+ captionSm: 11,
69
+ caption: 12,
70
+ radiusMd: 12,
71
+ radiusSm: 8,
72
+ } as const;
73
+
55
74
  /**
56
75
  * Build the Nivo theme from the tokens, resolved on `el` (default `<html>`).
57
76
  * Every colour is read from a `--ds-*` custom property and converted to hex,
@@ -63,10 +82,10 @@ export interface NivoTheme {
63
82
  */
64
83
  export function nivoTheme(el?: Element | null): NivoTheme {
65
84
  const fontFamily = readToken("--ds-font-body", el) || "var(--ds-font-body)";
66
- const captionSm = tokenPx("--ds-text-caption-sm", el) ?? 11;
67
- const caption = tokenPx("--ds-text-caption", el) ?? 12;
68
- const radiusMd = tokenPx("--ds-radius-md", el) ?? 6;
69
- const radiusSm = tokenPx("--ds-radius-sm", el) ?? 4;
85
+ const captionSm = tokenPx("--ds-text-caption-sm", el) ?? NIVO_SIZE_FALLBACK.captionSm;
86
+ const caption = tokenPx("--ds-text-caption", el) ?? NIVO_SIZE_FALLBACK.caption;
87
+ const radiusMd = tokenPx("--ds-radius-md", el) ?? NIVO_SIZE_FALLBACK.radiusMd;
88
+ const radiusSm = tokenPx("--ds-radius-sm", el) ?? NIVO_SIZE_FALLBACK.radiusSm;
70
89
  const foreground = resolveColor("--ds-foreground", el);
71
90
  const muted = resolveColor("--ds-muted-foreground", el);
72
91
  const border = resolveColor("--ds-border", el);
@@ -27,7 +27,7 @@ import {
27
27
  import { seriesColor, useChart } from "./container";
28
28
  import { ChartLegend, ChartTooltip } from "./recharts-parts";
29
29
  import { toRows, toSlices } from "./data";
30
- import { contrastLabel, useThemeVersion } from "./tokens";
30
+ import { contrastLabel, plotMargin, useThemeVersion } from "./tokens";
31
31
  import type { ChartConfig, ChartLabels, ChartRow, ChartSeries, ChartSlice, ChartType } from "./types";
32
32
 
33
33
  export type RechartsType = Extract<
@@ -56,8 +56,6 @@ export interface RechartsRenderProps {
56
56
  animate?: boolean;
57
57
  }
58
58
 
59
- const MARGIN = { top: 8, right: 8, bottom: 0, left: 0 };
60
-
61
59
  /**
62
60
  * Where an arc label sits, as a fraction of the way from the inner radius to
63
61
  * the outer one. Just inside the middle of the band: the arc is widest towards
@@ -163,6 +161,11 @@ export function RechartsChart({
163
161
  const element = useChart()?.element ?? null;
164
162
  // eslint-disable-next-line react-hooks/exhaustive-deps -- themeVersion is the cache key for the DOM read
165
163
  const colourOn = React.useMemo(() => contrastLabel(element), [element, themeVersion]);
164
+ // The plot margin is `--ds-space-2`, read from the tokens like every colour
165
+ // here rather than frozen as a number, and on the same cache key so a theme
166
+ // or scale change re-reads it.
167
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- themeVersion is the cache key for the DOM read
168
+ const margin = React.useMemo(() => plotMargin(element), [element, themeVersion]);
166
169
 
167
170
  const tip = tooltip ? (
168
171
  <ChartTooltip
@@ -175,7 +178,7 @@ export function RechartsChart({
175
178
  case "bar": {
176
179
  const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);
177
180
  return (
178
- <BarChart data={rows} margin={MARGIN}>
181
+ <BarChart data={rows} margin={margin}>
179
182
  {grid ? <CartesianGrid vertical={false} /> : null}
180
183
  <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />
181
184
  <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />
@@ -199,7 +202,7 @@ export function RechartsChart({
199
202
  case "line": {
200
203
  const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);
201
204
  return (
202
- <LineChart data={rows} margin={MARGIN}>
205
+ <LineChart data={rows} margin={margin}>
203
206
  {grid ? <CartesianGrid vertical={false} /> : null}
204
207
  <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />
205
208
  <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />
@@ -224,7 +227,7 @@ export function RechartsChart({
224
227
  case "area": {
225
228
  const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);
226
229
  return (
227
- <AreaChart data={rows} margin={MARGIN}>
230
+ <AreaChart data={rows} margin={margin}>
228
231
  {grid ? <CartesianGrid vertical={false} /> : null}
229
232
  <XAxis dataKey={index} tickLine={false} axisLine={false} tickMargin={8} />
230
233
  <YAxis tickLine={false} axisLine={false} tickFormatter={valueFormatter} />
@@ -252,7 +255,7 @@ export function RechartsChart({
252
255
  const slices = toSlices(data as ChartSlice[]);
253
256
  const fillOf = (i: number) => seriesColor(config, slices[i]?.id ?? String(i), i);
254
257
  return (
255
- <PieChart margin={MARGIN}>
258
+ <PieChart margin={margin}>
256
259
  {tip}
257
260
  {leg}
258
261
  <Pie
@@ -280,7 +283,7 @@ export function RechartsChart({
280
283
  case "scatterplot": {
281
284
  const series = data as ChartSeries[];
282
285
  return (
283
- <ScatterChart margin={MARGIN}>
286
+ <ScatterChart margin={margin}>
284
287
  {grid ? <CartesianGrid /> : null}
285
288
  <XAxis dataKey="x" type="number" name="x" tickLine={false} axisLine={false} tickMargin={8} />
286
289
  <YAxis dataKey="y" type="number" name="y" tickLine={false} axisLine={false} tickFormatter={valueFormatter} />
@@ -296,7 +299,7 @@ export function RechartsChart({
296
299
  case "radar": {
297
300
  const { rows, indexBy: index, keys: series } = toRows(data as ChartRow[] | ChartSeries[], indexBy, keys);
298
301
  return (
299
- <RadarChart data={rows} margin={MARGIN}>
302
+ <RadarChart data={rows} margin={margin}>
300
303
  {grid ? <PolarGrid /> : null}
301
304
  <PolarAngleAxis dataKey={index} />
302
305
  <PolarRadiusAxis tick={false} axisLine={false} />
@@ -320,7 +323,7 @@ export function RechartsChart({
320
323
  case "funnel": {
321
324
  const slices = toSlices(data as ChartSlice[]);
322
325
  return (
323
- <FunnelChart margin={MARGIN}>
326
+ <FunnelChart margin={margin}>
324
327
  {tip}
325
328
  {leg}
326
329
  <Funnel data={slices} dataKey="value" nameKey="name">
@@ -52,6 +52,25 @@ export function tokenPx(name: string, el?: Element | null): number | undefined {
52
52
  return n;
53
53
  }
54
54
 
55
+ /** The plot margin in pixels when there is no DOM: what `--ds-space-2` emits. */
56
+ export const PLOT_MARGIN_FALLBACK = 8;
57
+
58
+ /**
59
+ * The margin a Recharts plot is drawn with, in pixels, resolved on `el`
60
+ * (default `<html>`).
61
+ *
62
+ * Recharts takes a margin as numbers rather than CSS, so the token has to be
63
+ * read and handed over already in pixels. It is `--ds-space-2` at the top and
64
+ * on the right, which is what keeps the topmost y tick label and the last x
65
+ * tick label inside the box; the bottom and the left stay zero because the
66
+ * axes draw their own gutter there. Without a DOM — SSR — the fallback is the
67
+ * 8px that token emits at the default scale, asserted in `chart.test.tsx`.
68
+ */
69
+ export function plotMargin(el?: Element | null): { top: number; right: number; bottom: number; left: number } {
70
+ const space2 = tokenPx("--ds-space-2", el) ?? PLOT_MARGIN_FALLBACK;
71
+ return { top: space2, right: space2, bottom: 0, left: 0 };
72
+ }
73
+
55
74
  let probe: CanvasRenderingContext2D | null | undefined;
56
75
 
57
76
  function hex2(n: number): string {
@@ -37,6 +37,7 @@ export type { PageHeaderProps } from "@/components/page-header";
37
37
  export type { PopoverContentProps } from "@/components/popover";
38
38
  export type { ProgressProps } from "@/components/progress";
39
39
  export type { RadioGroupItemProps, RadioGroupProps } from "@/components/radio-group";
40
+ export type { RenderProp } from "@/lib/render";
40
41
  export type { ScrollAreaProps } from "@/components/scroll-area";
41
42
  export type { SectionCardProps } from "@/components/section-card";
42
43
  export type { SegmentedOption, SegmentedProps } from "@/components/segmented";