@nadicodeai/ui 12.1.116 → 12.1.118

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.
Files changed (32) hide show
  1. package/dist/components/chart-bar-stacked.d.ts +2 -2
  2. package/dist/components/chart-bar-stacked.d.ts.map +1 -1
  3. package/dist/components/chart-bar-stacked.js +4 -6
  4. package/dist/components/chart-card.d.ts +10 -6
  5. package/dist/components/chart-card.d.ts.map +1 -1
  6. package/dist/components/chart-card.js +12 -12
  7. package/dist/components/chart-ranking.d.ts +35 -0
  8. package/dist/components/chart-ranking.d.ts.map +1 -0
  9. package/dist/components/chart-ranking.js +27 -0
  10. package/dist/components/collection-page.d.ts +3 -1
  11. package/dist/components/collection-page.d.ts.map +1 -1
  12. package/dist/components/collection-page.js +3 -3
  13. package/dist/components/scope-switcher.d.ts +5 -3
  14. package/dist/components/scope-switcher.d.ts.map +1 -1
  15. package/dist/components/scope-switcher.js +9 -7
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -1
  19. package/dist/showcase/specimens/charts.d.ts +1 -0
  20. package/dist/showcase/specimens/charts.d.ts.map +1 -1
  21. package/dist/showcase/specimens/charts.js +10 -0
  22. package/dist/showcase/specimens/feedback.d.ts +0 -2
  23. package/dist/showcase/specimens/feedback.d.ts.map +1 -1
  24. package/dist/showcase/specimens/feedback.js +0 -6
  25. package/dist/showcase/specimens/index.d.ts +1 -1
  26. package/dist/showcase/usage.generated.d.ts +1 -1
  27. package/dist/showcase/usage.generated.d.ts.map +1 -1
  28. package/dist/showcase/usage.generated.js +16 -16
  29. package/package.json +2 -2
  30. package/dist/components/picture-label.d.ts +0 -30
  31. package/dist/components/picture-label.d.ts.map +0 -1
  32. package/dist/components/picture-label.js +0 -26
@@ -5,11 +5,11 @@ import { type ChartCardProps } from "./chart-card.js";
5
5
  * @family Charts
6
6
  * @when How a total moved over time split by Customer, member account or model; with `share`, what part of one total each holds, with no time axis.
7
7
  * @instead For a continuous volume in three series or fewer use `ChartAreaStacked`. Two measures side by side use `ChartBarMultiple`. Exact lookup is a table.
8
- * @behaviour Stacked in series order, bottom segment rounded below and top above at 4 px, bars at most 48 px. The Portal names five entities and folds the rest into "Everything else". The share plot is 64 px, legend included.
8
+ * @behaviour Stacked in series order, bottom segment rounded below and top above at 4 px, bars at most 48 px. The summary variant has square bars and no dot legend: its adjacent ChartRanking identifies the series with share bars. The Portal names five entities and folds the rest into "Everything else". The share plot is 64 px, legend included.
9
9
  * @words Entity names as the reader knows them, never ids. The neutral remainder is "Everything else". Values through the page's shared money formatter.
10
10
  * @access The plot is an image named by the card title; the tooltip and legend are read with it. The share bar sits above the full-width table that carries each figure.
11
11
  */
12
- declare function ChartBarStacked({ title, period, controls, link, summary, aside, footer, headingLevel, data, xKey, series, entityColorMap, valueFormatter, axisFormatter, otherLabel, emptyState, size, share, className, }: ChartCardProps & {
12
+ declare function ChartBarStacked({ variant, title, period, controls, link, summary, aside, footer, headingLevel, data, xKey, series, entityColorMap, valueFormatter, axisFormatter, otherLabel, emptyState, size, share, className, }: ChartCardProps & {
13
13
  /**
14
14
  * One bar across the card, each entity a segment of 100%: the share of a
15
15
  * total with no time axis. `data` is then a single row keyed by series id.
@@ -1 +1 @@
1
- {"version":3,"file":"chart-bar-stacked.d.ts","sourceRoot":"","sources":["../../src/components/chart-bar-stacked.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAmBjC;;;;;;;;;GASG;AACH,iBAAS,eAAe,CAAC,EACvB,KAAK,EACL,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,KAAK,EACL,MAAM,EACN,YAAY,EACZ,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,cAAc,EACd,cAAsC,EACtC,aAAa,EACb,UAAU,EACV,UAAU,EACV,IAAgB,EAChB,KAAa,EACb,SAAS,GACV,EAAE,cAAc,GAAG;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,+BAuGA;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"chart-bar-stacked.d.ts","sourceRoot":"","sources":["../../src/components/chart-bar-stacked.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAiBjC;;;;;;;;;GASG;AACH,iBAAS,eAAe,CAAC,EACvB,OAAmB,EACnB,KAAK,EACL,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,KAAK,EACL,MAAM,EACN,YAAY,EACZ,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,cAAc,EACd,cAAsC,EACtC,aAAa,EACb,UAAU,EACV,UAAU,EACV,IAAgB,EAChB,KAAa,EACb,SAAS,GACV,EAAE,cAAc,GAAG;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,+BA4GA;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -7,7 +7,6 @@ import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartToo
7
7
  import { CHART_X_AXIS_TICKS, CHART_Y_AXIS_TICK_COUNT, niceAxisTicks, stackedAxisMax, } from "./chart-axis.js";
8
8
  import { CHART_LEGEND_CLASS, ChartCard, chartPlotClassName, chartSeriesConfig, defaultValueFormatter, foldOtherSeries, } from "./chart-card.js";
9
9
  import { entityColor } from "./chart-entity-colors.js";
10
- /** Stock stacked-bar corner radius: the bottom bar rounds down, the top bar up. */
11
10
  function stackRadius(index, count) {
12
11
  if (count === 1)
13
12
  return [4, 4, 4, 4];
@@ -17,7 +16,6 @@ function stackRadius(index, count) {
17
16
  return [4, 4, 0, 0];
18
17
  return [0, 0, 0, 0];
19
18
  }
20
- /** The same stock rounding, turned on its side: the first segment rounds left, the last right. */
21
19
  function shareRadius(index, count) {
22
20
  if (count === 1)
23
21
  return [4, 4, 4, 4];
@@ -33,19 +31,19 @@ function shareRadius(index, count) {
33
31
  * @family Charts
34
32
  * @when How a total moved over time split by Customer, member account or model; with `share`, what part of one total each holds, with no time axis.
35
33
  * @instead For a continuous volume in three series or fewer use `ChartAreaStacked`. Two measures side by side use `ChartBarMultiple`. Exact lookup is a table.
36
- * @behaviour Stacked in series order, bottom segment rounded below and top above at 4 px, bars at most 48 px. The Portal names five entities and folds the rest into "Everything else". The share plot is 64 px, legend included.
34
+ * @behaviour Stacked in series order, bottom segment rounded below and top above at 4 px, bars at most 48 px. The summary variant has square bars and no dot legend: its adjacent ChartRanking identifies the series with share bars. The Portal names five entities and folds the rest into "Everything else". The share plot is 64 px, legend included.
37
35
  * @words Entity names as the reader knows them, never ids. The neutral remainder is "Everything else". Values through the page's shared money formatter.
38
36
  * @access The plot is an image named by the card title; the tooltip and legend are read with it. The share bar sits above the full-width table that carries each figure.
39
37
  */
40
- function ChartBarStacked({ title, period, controls, link, summary, aside, footer, headingLevel, data, xKey, series, entityColorMap, valueFormatter = defaultValueFormatter, axisFormatter, otherLabel, emptyState, size = "default", share = false, className, }) {
38
+ function ChartBarStacked({ variant = "default", title, period, controls, link, summary, aside, footer, headingLevel, data, xKey, series, entityColorMap, valueFormatter = defaultValueFormatter, axisFormatter, otherLabel, emptyState, size = "default", share = false, className, }) {
41
39
  const folded = foldOtherSeries(series, data, entityColorMap, otherLabel);
42
40
  const chartConfig = chartSeriesConfig(folded.series, entityColorMap);
43
41
  const domainMax = stackedAxisMax(folded.data, folded.series.map((entry) => entry.id));
44
- return (_jsx(ChartCard, { title: title, period: period, controls: controls, ...(link ? { link } : {}), summary: summary, aside: aside, ...(footer ? { footer } : {}), ...(headingLevel ? { headingLevel } : {}), className: className, children: (titleId) => emptyState && data.length === 0 ? (emptyState) : share ? (_jsx(ChartContainer, { config: chartConfig, className: "aspect-auto h-16 w-full", children: _jsxs(BarChart, { accessibilityLayer: true, "aria-labelledby": titleId, data: folded.data, layout: "vertical", stackOffset: "expand", children: [_jsx(XAxis, { type: "number", hide: true }), _jsx(YAxis, { type: "category", dataKey: xKey, hide: true }), _jsx(ChartTooltip, { cursor: false, content: _jsx(ChartTooltipContent, { hideLabel: true, indicator: "line", valueFormatter: valueFormatter }) }), _jsx(ChartLegend, { itemSorter: null, content: _jsx(ChartLegendContent, { className: CHART_LEGEND_CLASS }) }), folded.series.map((entry, index) => (_jsx(Bar, { dataKey: entry.id, stackId: "a", fill: entityColor(entityColorMap, entry.id), radius: shareRadius(index, folded.series.length) }, entry.id)))] }) })) : (_jsx(ChartContainer, { config: chartConfig, className: chartPlotClassName(size), children: _jsxs(BarChart, { accessibilityLayer: true, "aria-labelledby": titleId, data: folded.data, children: [_jsx(CartesianGrid, { strokeDasharray: "3 3" }), _jsx(XAxis, { dataKey: xKey, tickLine: false, tickMargin: 10, axisLine: false, ...CHART_X_AXIS_TICKS }), _jsx(YAxis, { width: "auto", tickLine: false, axisLine: false, tickMargin: 8, tickCount: CHART_Y_AXIS_TICK_COUNT, ...(domainMax === undefined
42
+ return (_jsx(ChartCard, { variant: variant, title: title, period: period, controls: controls, ...(link ? { link } : {}), summary: summary, aside: aside, ...(footer ? { footer } : {}), ...(headingLevel ? { headingLevel } : {}), className: className, children: (titleId) => emptyState && data.length === 0 ? (emptyState) : share ? (_jsx(ChartContainer, { config: chartConfig, className: "aspect-auto h-16 w-full", children: _jsxs(BarChart, { accessibilityLayer: true, "aria-labelledby": titleId, data: folded.data, layout: "vertical", stackOffset: "expand", children: [_jsx(XAxis, { type: "number", hide: true }), _jsx(YAxis, { type: "category", dataKey: xKey, hide: true }), _jsx(ChartTooltip, { cursor: false, content: _jsx(ChartTooltipContent, { hideLabel: true, indicator: "line", valueFormatter: valueFormatter }) }), variant === "summary" ? null : (_jsx(ChartLegend, { itemSorter: null, content: _jsx(ChartLegendContent, { className: CHART_LEGEND_CLASS }) })), folded.series.map((entry, index) => (_jsx(Bar, { dataKey: entry.id, stackId: "a", fill: entityColor(entityColorMap, entry.id), radius: shareRadius(index, folded.series.length) }, entry.id)))] }) })) : (_jsx(ChartContainer, { config: chartConfig, className: chartPlotClassName(size), children: _jsxs(BarChart, { accessibilityLayer: true, "aria-labelledby": titleId, data: folded.data, children: [_jsx(CartesianGrid, { strokeDasharray: "3 3" }), _jsx(XAxis, { dataKey: xKey, tickLine: false, tickMargin: 10, axisLine: false, ...CHART_X_AXIS_TICKS }), _jsx(YAxis, { width: "auto", tickLine: false, axisLine: false, tickMargin: 8, tickCount: CHART_Y_AXIS_TICK_COUNT, ...(domainMax === undefined
45
43
  ? {}
46
44
  : {
47
45
  domain: [0, domainMax],
48
46
  ticks: niceAxisTicks(domainMax),
49
- }), tickFormatter: (value) => (axisFormatter ?? valueFormatter)(Number(value)) }), _jsx(ChartTooltip, { content: _jsx(ChartTooltipContent, { indicator: "line", valueFormatter: valueFormatter }) }), _jsx(ChartLegend, { itemSorter: null, content: _jsx(ChartLegendContent, { className: CHART_LEGEND_CLASS }) }), folded.series.map((entry, index) => (_jsx(Bar, { dataKey: entry.id, stackId: "a", fill: entityColor(entityColorMap, entry.id), radius: stackRadius(index, folded.series.length), maxBarSize: 48 }, entry.id)))] }) })) }));
47
+ }), tickFormatter: (value) => (axisFormatter ?? valueFormatter)(Number(value)) }), _jsx(ChartTooltip, { content: _jsx(ChartTooltipContent, { indicator: "line", valueFormatter: valueFormatter }) }), variant === "summary" ? null : (_jsx(ChartLegend, { itemSorter: null, content: _jsx(ChartLegendContent, { className: CHART_LEGEND_CLASS }) })), folded.series.map((entry, index) => (_jsx(Bar, { dataKey: entry.id, stackId: "a", fill: entityColor(entityColorMap, entry.id), radius: variant === "summary" ? 0 : stackRadius(index, folded.series.length), maxBarSize: 48 }, entry.id)))] }) })) }));
50
48
  }
51
49
  export { ChartBarStacked };
@@ -10,6 +10,7 @@ type ChartSeries = {
10
10
  };
11
11
  type ChartDatum = Record<string, number | string>;
12
12
  type ChartCardSize = "default" | "lg";
13
+ type ChartCardVariant = "default" | "summary";
13
14
  type ChartSummaryTrend = {
14
15
  value: React.ReactNode;
15
16
  direction: TrendDirection;
@@ -24,6 +25,7 @@ type ChartSummaryProps = {
24
25
  valueSize?: ChartCardSize;
25
26
  trend?: ChartSummaryTrend;
26
27
  status?: React.ReactNode;
28
+ variant?: ChartCardVariant;
27
29
  };
28
30
  /** The footer strip: when the reading was taken, left; a command on the reading itself, right. */
29
31
  type ChartCardFooter = {
@@ -42,15 +44,17 @@ type ChartCardLink = {
42
44
  link: React.ReactElement;
43
45
  };
44
46
  type ChartCardProps = {
47
+ /** Summary places controls beside the title and the total above the plot, alongside its ranking. */
48
+ variant?: ChartCardVariant;
45
49
  /** Names the measure and its split: "Model spend by Customer". */
46
50
  title: React.ReactNode;
47
- /** Under the title: "Per day · today is partial", "30 September to 13 October 2026". */
51
+ /** Bucket or date context under the title by default, beside the total in the summary variant. */
48
52
  period?: React.ReactNode;
49
53
  /** The title's heading level in the page outline. Defaults to 2. */
50
54
  headingLevel?: 2 | 3 | 4;
51
- /** At the header's trailing edge: the metric `ToggleGroup`, and a period `Select` where the page has none. */
55
+ /** Metric and period controls: at the trailing edge by default, immediately after the summary title. */
52
56
  controls?: React.ReactNode;
53
- /** After the controls at the header's trailing edge: the way to the reading's owner. */
57
+ /** The way to the reading's owner, at the header's trailing edge. */
54
58
  link?: ChartCardLink;
55
59
  /** A `ChartSummary` between the header and the plot. */
56
60
  summary?: React.ReactNode;
@@ -97,15 +101,15 @@ declare function foldOtherSeries(series: readonly ChartSeries[], data: readonly
97
101
  * @family Charts
98
102
  * @when Every chart and every reading built around one: the frame a page never builds by hand. A chart is a named section of its page.
99
103
  * @instead A single figure is a `KpiCard`, never nested inside a chart. A ranking beside the plot goes in the card's `aside`, not a second card.
100
- * @behaviour Header grid: title and period in the first column, controls and then the link to the reading's owner (a small ghost button ending in a chevron, as OpenRouter's "Explore ›") in the second from a 28 rem card width, under the title below it; a link with no controls stays at the trailing edge at every width. Summary, plot, legend, footer in that order. An empty dataset shows its `emptyState` in the plot's place. The footer is a recessed strip behind a hairline: the reading's time left, at most one command on the reading (Refresh) right.
104
+ * @behaviour The default header puts controls at the trailing edge on wide cards, below the title on narrow cards. The summary variant keeps controls immediately after the title, the owner link at the trailing edge, and the total and period above the plot. The ranking sits beside the plot only when the card itself reaches 48 rem; narrower cards keep a full-width plot and put the ranking below it. Controls wrap on narrow cards. An empty dataset shows its `emptyState` in the plot's place. The footer carries the reading time and at most one command on that reading.
101
105
  * @words Title names the measure and its split: "Model spend by Customer". Period as dates. The link: "Explore", or "Open in Analytics" where the owner is another page. Footer: the reading's time, "Updated 4 minutes ago" or "Read at 12:42". Sentence case throughout.
102
106
  * @access The title is a heading at the page's level (default 2) and labels the plot. The plot is focusable and shows the 2 px focus outline only on keyboard focus.
103
107
  */
104
- declare function ChartCard({ title, period, controls, link, summary, aside, footer, headingLevel, className, children, }: Pick<ChartCardProps, "title" | "period" | "controls" | "link" | "summary" | "aside" | "footer" | "headingLevel" | "className"> & {
108
+ declare function ChartCard({ variant, title, period, controls, link, summary, aside, footer, headingLevel, className, children, }: Pick<ChartCardProps, "title" | "variant" | "period" | "controls" | "link" | "summary" | "aside" | "footer" | "headingLevel" | "className"> & {
105
109
  /** Receives the title's id, which the plot takes as `aria-labelledby`. */
106
110
  children: (titleId: string) => React.ReactNode;
107
111
  }): React.JSX.Element;
108
- declare function ChartSummary({ label, value, valueTitle, valueSize, trend, status, }: ChartSummaryProps): React.JSX.Element;
112
+ declare function ChartSummary({ variant, label, value, valueTitle, valueSize, trend, status, }: ChartSummaryProps): React.JSX.Element;
109
113
  /** The plot frame class: fixed height, no aspect ratio, full width. */
110
114
  declare function chartPlotClassName(size: ChartCardSize): string;
111
115
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"chart-card.d.ts","sourceRoot":"","sources":["../../src/components/chart-card.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chart-card.d.ts","sourceRoot":"","sources":["../../src/components/chart-card.tsx"],"names":[],"mappings":"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"}
@@ -9,17 +9,11 @@ import { CHART_ENTITY_OTHER_COLOR, entityColor, } from "./chart-entity-colors.js
9
9
  import { PageCommandButton } from "./page-actions.js";
10
10
  import { TrendBadge } from "./trend-badge.js";
11
11
  import { FooterStrip } from "../internal/footer-strip.js";
12
- /** Fixed plot heights, so charts on a page share one register. */
13
12
  const chartSizes = {
14
13
  default: "h-64",
15
14
  lg: "h-80",
16
15
  };
17
- /**
18
- * Below a 28 rem card the controls drop under the title; a lone link stays at the
19
- * header's trailing edge, as the ranking cards beside it keep theirs.
20
- */
21
16
  const CONTROLS_UNDER_TITLE_WHEN_NARROW = "has-data-[slot=card-action]:grid-cols-1 [&>[data-slot=card-action]]:col-start-1 [&>[data-slot=card-action]]:row-span-1 [&>[data-slot=card-action]]:row-start-3 [&>[data-slot=card-action]]:justify-self-start @md/chart-card:has-data-[slot=card-action]:grid-cols-[1fr_auto] @md/chart-card:[&>[data-slot=card-action]]:col-start-2 @md/chart-card:[&>[data-slot=card-action]]:row-span-2 @md/chart-card:[&>[data-slot=card-action]]:row-start-1 @md/chart-card:[&>[data-slot=card-action]]:justify-self-end";
22
- /** Synthetic key for the aggregated neutral series. */
23
17
  const OTHER_SERIES_ID = "__nc-other-series__";
24
18
  function defaultValueFormatter(value) {
25
19
  return value.toLocaleString();
@@ -69,17 +63,23 @@ function foldOtherSeries(series, data, entityColorMap, otherLabel) {
69
63
  * @family Charts
70
64
  * @when Every chart and every reading built around one: the frame a page never builds by hand. A chart is a named section of its page.
71
65
  * @instead A single figure is a `KpiCard`, never nested inside a chart. A ranking beside the plot goes in the card's `aside`, not a second card.
72
- * @behaviour Header grid: title and period in the first column, controls and then the link to the reading's owner (a small ghost button ending in a chevron, as OpenRouter's "Explore ›") in the second from a 28 rem card width, under the title below it; a link with no controls stays at the trailing edge at every width. Summary, plot, legend, footer in that order. An empty dataset shows its `emptyState` in the plot's place. The footer is a recessed strip behind a hairline: the reading's time left, at most one command on the reading (Refresh) right.
66
+ * @behaviour The default header puts controls at the trailing edge on wide cards, below the title on narrow cards. The summary variant keeps controls immediately after the title, the owner link at the trailing edge, and the total and period above the plot. The ranking sits beside the plot only when the card itself reaches 48 rem; narrower cards keep a full-width plot and put the ranking below it. Controls wrap on narrow cards. An empty dataset shows its `emptyState` in the plot's place. The footer carries the reading time and at most one command on that reading.
73
67
  * @words Title names the measure and its split: "Model spend by Customer". Period as dates. The link: "Explore", or "Open in Analytics" where the owner is another page. Footer: the reading's time, "Updated 4 minutes ago" or "Read at 12:42". Sentence case throughout.
74
68
  * @access The title is a heading at the page's level (default 2) and labels the plot. The plot is focusable and shows the 2 px focus outline only on keyboard focus.
75
69
  */
76
- function ChartCard({ title, period, controls, link, summary, aside, footer, headingLevel = 2, className, children, }) {
70
+ function ChartCard({ variant = "default", title, period, controls, link, summary, aside, footer, headingLevel = 2, className, children, }) {
77
71
  const titleId = React.useId();
78
- return (_jsxs(Card, { "data-slot": "chart-card", className: cn("@container/chart-card", className), children: [_jsxs(CardHeader, { className: cn(controls && CONTROLS_UNDER_TITLE_WHEN_NARROW), children: [_jsx(CardTitle, { id: titleId, role: "heading", "aria-level": headingLevel, children: title }), period ? _jsx(CardDescription, { children: period }) : null, controls || link ? (_jsxs(CardAction, { className: "flex flex-wrap items-center gap-2", children: [controls, link ? (_jsx(ButtonLink, { variant: "ghost", size: "sm", suffix: _jsx(ChevronRight, { "aria-hidden": "true" }), "aria-label": link.accessibleName, render: link.link, children: link.label })) : null] })) : null] }), summary ? (_jsx("div", { "data-slot": "chart-card-summary", className: "px-(--card-spacing)", children: summary })) : null, _jsxs(CardContent, { className: cn(aside &&
79
- "grid min-w-0 gap-(--card-spacing) lg:grid-cols-[minmax(0,2fr)_minmax(16rem,1fr)]"), children: [_jsx("div", { className: "min-w-0", children: children(titleId) }), aside ? (_jsx("aside", { "data-slot": "chart-card-aside", className: "min-w-0 border-t border-border pt-(--card-spacing) lg:border-t-0 lg:border-l lg:pt-0 lg:pl-(--card-spacing)", children: aside })) : null] }), footer ? (_jsx(FooterStrip, { hint: footer.reading, hintSlot: "chart-card-reading", children: footer.link ? _jsx(PageCommandButton, { command: footer.link, variant: "ghost" }) : null })) : null] }));
72
+ return (_jsxs(Card, { "data-slot": "chart-card", className: cn("@container/chart-card", className), children: [_jsxs(CardHeader, { className: cn(variant === "summary"
73
+ ? "flex flex-wrap items-center gap-3"
74
+ : controls && CONTROLS_UNDER_TITLE_WHEN_NARROW), children: [_jsx(CardTitle, { id: titleId, role: "heading", "aria-level": headingLevel, className: variant === "summary" ? "text-heading-xs" : undefined, children: title }), variant === "summary" ? controls : null, period && variant !== "summary" ? _jsx(CardDescription, { children: period }) : null, (variant === "summary" ? link : controls || link) ? (_jsxs(CardAction, { className: cn("flex flex-wrap items-center gap-2", variant === "summary" && "ml-auto"), children: [variant === "summary" ? null : controls, link ? (_jsx(ButtonLink, { variant: "ghost", size: "sm", suffix: _jsx(ChevronRight, { "aria-hidden": "true" }), "aria-label": link.accessibleName, render: link.link, children: link.label })) : null] })) : null] }), summary && variant !== "summary" ? (_jsx("div", { "data-slot": "chart-card-summary", className: "px-(--card-spacing)", children: summary })) : null, _jsxs(CardContent, { className: cn(aside &&
75
+ "grid min-w-0 gap-(--card-spacing) @3xl/chart-card:grid-cols-[minmax(0,2fr)_minmax(16rem,1fr)]"), children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [variant === "summary" && (summary || period) ? (_jsxs("div", { "data-slot": "chart-card-summary", className: "flex flex-wrap items-start justify-between gap-3", children: [summary, period ? _jsx(CardDescription, { children: period }) : null] })) : null, children(titleId)] }), aside ? (_jsx("aside", { "data-slot": "chart-card-aside", className: "min-w-0 border-t border-border pt-(--card-spacing) @3xl/chart-card:border-t-0 @3xl/chart-card:border-l @3xl/chart-card:pt-0 @3xl/chart-card:pl-(--card-spacing)", children: aside })) : null] }), footer ? (_jsx(FooterStrip, { hint: footer.reading, hintSlot: "chart-card-reading", children: footer.link ? _jsx(PageCommandButton, { command: footer.link, variant: "ghost" }) : null })) : null] }));
80
76
  }
81
- function ChartSummary({ label, value, valueTitle, valueSize = "default", trend, status, }) {
82
- return (_jsxs("div", { "data-slot": "chart-summary", className: "flex flex-col items-start gap-2", children: [_jsx("div", { className: "text-muted-foreground text-sm", children: label }), _jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-3", children: [_jsx("div", { "data-slot": "chart-summary-value", className: cn("truncate tabular-nums", valueSize === "lg" ? "text-heading-lg" : "text-heading-md"), title: valueTitle, children: value }), trend ? (_jsx(TrendBadge, { direction: trend.direction, directionLabel: trend.directionLabel, tone: trend.tone, value: trend.value })) : null, status] }), trend ? (_jsx("div", { "data-slot": "chart-summary-comparison", className: "text-muted-foreground text-sm", children: trend.comparison })) : null] }));
77
+ function ChartSummary({ variant = "default", label, value, valueTitle, valueSize = "default", trend, status, }) {
78
+ return (_jsxs("div", { "data-slot": "chart-summary", className: "flex flex-col items-start gap-2", children: [_jsx("div", { className: cn(variant === "summary" ? "sr-only" : "text-muted-foreground text-sm"), children: label }), _jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-3", children: [_jsx("div", { "data-slot": "chart-summary-value", className: cn("truncate tabular-nums", variant === "summary"
79
+ ? "text-display-md"
80
+ : valueSize === "lg"
81
+ ? "text-heading-lg"
82
+ : "text-heading-md"), title: valueTitle, children: value }), trend && variant !== "summary" ? (_jsx(TrendBadge, { direction: trend.direction, directionLabel: trend.directionLabel, tone: trend.tone, value: trend.value })) : null, status] }), trend ? (_jsxs("div", { "data-slot": "chart-summary-comparison", className: "flex flex-wrap items-center gap-2 text-muted-foreground text-sm", children: [variant === "summary" ? (_jsx(TrendBadge, { direction: trend.direction, directionLabel: trend.directionLabel, tone: trend.tone, value: trend.value })) : null, trend.comparison] })) : null] }));
83
83
  }
84
84
  /** The plot frame class: fixed height, no aspect ratio, full width. */
85
85
  function chartPlotClassName(size) {
@@ -0,0 +1,35 @@
1
+ import { type ReactNode } from "react";
2
+ import { type EntityColorMap } from "./chart-entity-colors.js";
3
+ type ChartRankingRow = {
4
+ id: string;
5
+ label: ReactNode;
6
+ display: string;
7
+ exactDisplay?: string;
8
+ value: number;
9
+ };
10
+ /**
11
+ * The leading entities beside a usage chart, with the complete ranking one step away.
12
+ *
13
+ * @family Charts
14
+ * @when A chart summary needs a ranking beside its plot.
15
+ * @instead Exact breakdown columns belong in a DataTable. This list compares shares of one nonnegative total.
16
+ * @behaviour Shows the first five rows and an optional aggregate remainder, each identity and figure above its coloured share bar. The remainder identifies the neutral plot segment; View all expands the named entities rather than repeating their aggregate. View all opens the complete supplied ranking in a dialog. Rows arrive already sorted and share one total and colour map with the chart.
17
+ * @words The product supplies the title, metric description, View all count, dialog description and close label.
18
+ * @access Each share bar is named by its entity. The dialog is named by the ranking title and retains the selected period and metric.
19
+ */
20
+ declare function ChartRanking({ title, description, rows, remainder, total, entityColorMap, disclosure, }: {
21
+ title: string;
22
+ description?: ReactNode;
23
+ rows: readonly ChartRankingRow[];
24
+ remainder?: ChartRankingRow;
25
+ total: number;
26
+ entityColorMap: EntityColorMap;
27
+ disclosure: {
28
+ label: string;
29
+ description: string;
30
+ closeLabel: string;
31
+ };
32
+ }): import("react").JSX.Element;
33
+ export { ChartRanking };
34
+ export type { ChartRankingRow };
35
+ //# sourceMappingURL=chart-ranking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-ranking.d.ts","sourceRoot":"","sources":["../../src/components/chart-ranking.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAI9C,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAYpF,KAAK,eAAe,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAsCF;;;;;;;;;GASG;AACH,iBAAS,YAAY,CAAC,EACpB,KAAK,EACL,WAAW,EACX,IAAI,EACJ,SAAS,EACT,KAAK,EACL,cAAc,EACd,UAAU,GACX,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,IAAI,EAAE,SAAS,eAAe,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE,+BAuCA;AAED,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId } from "react";
4
+ import { ChevronRight } from "lucide-react";
5
+ import { Button } from "./button.js";
6
+ import { entityColor } from "./chart-entity-colors.js";
7
+ import { Dialog, DialogBody, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "./dialog.js";
8
+ import { Progress } from "./progress.js";
9
+ function RankingRows({ rows, title, total, entityColorMap, }) {
10
+ const id = useId();
11
+ return (_jsx("ol", { "aria-label": title, className: "flex min-w-0 flex-col gap-4", children: rows.map((row, index) => (_jsxs("li", { className: "flex min-w-0 flex-col gap-2", children: [_jsxs("div", { className: "flex min-w-0 items-center justify-between gap-3 text-sm", children: [_jsx("span", { id: `${id}-${index}`, className: "min-w-0 truncate", children: row.label }), _jsx("span", { className: "shrink-0 tabular-nums", title: row.exactDisplay, children: row.display })] }), _jsx(Progress, { "aria-labelledby": `${id}-${index}`, value: total > 0 ? (row.value / total) * 100 : 0, indicatorColor: entityColor(entityColorMap, row.id), size: "sm" })] }, row.id))) }));
12
+ }
13
+ /**
14
+ * The leading entities beside a usage chart, with the complete ranking one step away.
15
+ *
16
+ * @family Charts
17
+ * @when A chart summary needs a ranking beside its plot.
18
+ * @instead Exact breakdown columns belong in a DataTable. This list compares shares of one nonnegative total.
19
+ * @behaviour Shows the first five rows and an optional aggregate remainder, each identity and figure above its coloured share bar. The remainder identifies the neutral plot segment; View all expands the named entities rather than repeating their aggregate. View all opens the complete supplied ranking in a dialog. Rows arrive already sorted and share one total and colour map with the chart.
20
+ * @words The product supplies the title, metric description, View all count, dialog description and close label.
21
+ * @access Each share bar is named by its entity. The dialog is named by the ranking title and retains the selected period and metric.
22
+ */
23
+ function ChartRanking({ title, description, rows, remainder, total, entityColorMap, disclosure, }) {
24
+ const list = { title, total, entityColorMap };
25
+ return (_jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [_jsx("h3", { className: "text-heading-xs", children: title }), description ? _jsx("span", { className: "text-muted-foreground text-sm", children: description }) : null] }), _jsx(RankingRows, { ...list, rows: remainder ? [...rows.slice(0, 5), remainder] : rows.slice(0, 5) }), rows.length > 0 ? (_jsxs(Dialog, { children: [_jsx(DialogTrigger, { render: _jsx(Button, { variant: "ghost", size: "sm", className: "self-end", suffix: _jsx(ChevronRight, { "aria-hidden": "true" }) }), children: disclosure.label }), _jsxs(DialogContent, { closeLabel: disclosure.closeLabel, children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: disclosure.description })] }), _jsx(DialogBody, { children: _jsx(RankingRows, { ...list, rows: rows }) })] })] })) : null] }));
26
+ }
27
+ export { ChartRanking };
@@ -23,6 +23,8 @@ export type CollectionPageProps<TRecord extends RowData> = RecordListWithout<TRe
23
23
  actions?: Omit<PageActionsProps, "period">;
24
24
  /** The page's sibling collections, under the title row: `TabsNav variant="line"`. */
25
25
  tabs?: ReactElement;
26
+ /** Actionable conditions above the toolbar, independent of sibling navigation. */
27
+ attention?: ReactNode;
26
28
  search?: CollectionSearchProps;
27
29
  filters?: CollectionFiltersProps;
28
30
  sort?: CollectionSortProps;
@@ -47,7 +49,7 @@ export type CollectionPageProps<TRecord extends RowData> = RecordListWithout<TRe
47
49
  * @when “Use `<Entity>` for a row of descriptive content paired with one or two controls (member rows, integration rows, domain rows).” (https://vercel.com/geist/entity)
48
50
  * Ours: a list of entity rows a person finds one of, opens and acts on: Customers, Agents, Skills, Apps, MCP servers, Mailboxes, domains, environment variables (a row with an `editor` expands into its form). Its rows are a `RecordList`'s, so a row has a mark, a name over a muted line and at most three facts; anything wider is not this page.
49
51
  * “Projects”: Vercel's Projects page stands a column of titled cards (Usage, Alerts, Recent Previews) at the left of its list. (https://vercel.com/dashboard)
50
- * Ours: a collection whose reader also needs to know what is waiting on them across all its records, such as nadicode's Customers and Partners and a Partner's Customers, takes that column as its `rail`.
52
+ * Ours: Customers and Partners use the full-width list, with actionable attention above the toolbar when present. Business summaries belong on Dashboard and Analytics. A rail remains available for context that belongs to the collection itself, such as the selected Library hub.
51
53
  * @instead “For tabular data with sortable columns and shared row shape, use `Table` instead.” (https://vercel.com/geist/entity)
52
54
  * Ours: records compared across columns, read by their headings, are a `DataTable` under the page's own title and toolbar. A list inside another page's section is a `RecordList` with its `heading`.
53
55
  * @behaviour With a `rail`, the toolbar spans the page and under it stand two columns from 1280 px: the rail, 300 px, then the records' card, its top level with the rail's first title and named by the page's title alone, never a second heading, and the records' rows are `RecordList`'s `line` rows; below 1280 px the records come first and the rail follows them. Each rail card has its title above it at 16 px, an optional 44 px muted summary row with its one outline button at its end (a button never stands in a row of its own, so a card with an `action` has a `summary`), then its items: a figure is one 36 px row, its title and its number at the trailing edge; a record is its 24 px mark, a title over a muted line that wraps to a second before it is cut, and a figure or a status at its end, the whole item opening its record; a card with no items draws its `empty` inside it as one 44 px row like an item. While the rail's read is in flight a card's `items` are undefined and it holds its place with three placeholder lines, so the two columns stand from the first frame; a rail whose read `failed` is one card saying so, and the records beside it stay. Under the title sits only the `description`, when the collection's kind needs explaining; otherwise nothing. The title row holds at most one secondary, the primary, then the three dots, which open only for two commands or more. The primary stays in the title row whether the collection is empty or not, filled, as Vercel's Flags keeps Create Flag; a first use repeats it as the filled button in its card. One toolbar holds the search, which grows, then the filters, then the sort; it shows while there are records or a search or filter is set, and is glass only where the rows scroll under it. While a new search, filter or sort is read, the toolbar is busy and, after a second, shows the one waiting line, while the last rows stay. The rows, their states and their loading are the RecordList's; no match is offered only while a search or filter is set.
@@ -1 +1 @@
1
- {"version":3,"file":"collection-page.d.ts","sourceRoot":"","sources":["../../src/components/collection-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACjG,OAAO,EAAoB,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC9F,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE9E,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,4BAA4B,CAAC;AAEvF,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,4BAA4B,CAAC;AAEpC,KAAK,eAAe,GAChB;IACE,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB,GACD;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,WAAW,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAE/C,MAAM,MAAM,mBAAmB,CAAC,OAAO,SAAS,OAAO,IAAI,iBAAiB,CAC1E,OAAO,EACP,SAAS,GAAG,SAAS,GAAG,QAAQ,CACjC,GACC,eAAe,GAAG;IAChB,6HAA6H;IAC7H,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IAC3C,qFAAqF;IACrF,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACnC,iDAAiD;IACjD,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;IACpD,oGAAoG;IACpG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEJ;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,OAAO,SAAS,OAAO,EAAE,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,+BAyD1F"}
1
+ {"version":3,"file":"collection-page.d.ts","sourceRoot":"","sources":["../../src/components/collection-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,EAAqB,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACjG,OAAO,EAAoB,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC9F,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE9E,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,4BAA4B,CAAC;AAEvF,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,4BAA4B,CAAC;AAEpC,KAAK,eAAe,GAChB;IACE,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB,GACD;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,WAAW,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAE/C,MAAM,MAAM,mBAAmB,CAAC,OAAO,SAAS,OAAO,IAAI,iBAAiB,CAC1E,OAAO,EACP,SAAS,GAAG,SAAS,GAAG,QAAQ,CACjC,GACC,eAAe,GAAG;IAChB,6HAA6H;IAC7H,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IAC3C,qFAAqF;IACrF,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,kFAAkF;IAClF,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACnC,iDAAiD;IACjD,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;IACpD,oGAAoG;IACpG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEJ;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,OAAO,SAAS,OAAO,EAAE,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,+BA2D1F"}
@@ -17,7 +17,7 @@ import { CollectionRailColumn } from "../internal/collection-rail.js";
17
17
  * @when “Use `<Entity>` for a row of descriptive content paired with one or two controls (member rows, integration rows, domain rows).” (https://vercel.com/geist/entity)
18
18
  * Ours: a list of entity rows a person finds one of, opens and acts on: Customers, Agents, Skills, Apps, MCP servers, Mailboxes, domains, environment variables (a row with an `editor` expands into its form). Its rows are a `RecordList`'s, so a row has a mark, a name over a muted line and at most three facts; anything wider is not this page.
19
19
  * “Projects”: Vercel's Projects page stands a column of titled cards (Usage, Alerts, Recent Previews) at the left of its list. (https://vercel.com/dashboard)
20
- * Ours: a collection whose reader also needs to know what is waiting on them across all its records, such as nadicode's Customers and Partners and a Partner's Customers, takes that column as its `rail`.
20
+ * Ours: Customers and Partners use the full-width list, with actionable attention above the toolbar when present. Business summaries belong on Dashboard and Analytics. A rail remains available for context that belongs to the collection itself, such as the selected Library hub.
21
21
  * @instead “For tabular data with sortable columns and shared row shape, use `Table` instead.” (https://vercel.com/geist/entity)
22
22
  * Ours: records compared across columns, read by their headings, are a `DataTable` under the page's own title and toolbar. A list inside another page's section is a `RecordList` with its `heading`.
23
23
  * @behaviour With a `rail`, the toolbar spans the page and under it stand two columns from 1280 px: the rail, 300 px, then the records' card, its top level with the rail's first title and named by the page's title alone, never a second heading, and the records' rows are `RecordList`'s `line` rows; below 1280 px the records come first and the rail follows them. Each rail card has its title above it at 16 px, an optional 44 px muted summary row with its one outline button at its end (a button never stands in a row of its own, so a card with an `action` has a `summary`), then its items: a figure is one 36 px row, its title and its number at the trailing edge; a record is its 24 px mark, a title over a muted line that wraps to a second before it is cut, and a figure or a status at its end, the whole item opening its record; a card with no items draws its `empty` inside it as one 44 px row like an item. While the rail's read is in flight a card's `items` are undefined and it holds its place with three placeholder lines, so the two columns stand from the first frame; a rail whose read `failed` is one card saying so, and the records beside it stay. Under the title sits only the `description`, when the collection's kind needs explaining; otherwise nothing. The title row holds at most one secondary, the primary, then the three dots, which open only for two commands or more. The primary stays in the title row whether the collection is empty or not, filled, as Vercel's Flags keeps Create Flag; a first use repeats it as the filled button in its card. One toolbar holds the search, which grows, then the filters, then the sort; it shows while there are records or a search or filter is set, and is glass only where the rows scroll under it. While a new search, filter or sort is read, the toolbar is busy and, after a second, shows the one waiting line, while the last rows stay. The rows, their states and their loading are the RecordList's; no match is offered only while a search or filter is set.
@@ -27,9 +27,9 @@ import { CollectionRailColumn } from "../internal/collection-rail.js";
27
27
  * Ours: the rows' region is the RecordList's, which holds it. The title is the page's h1 when the composition draws it. The toolbar is named by `label` and busy while `pending`; the rows are the RecordList's table, named by `label`.
28
28
  */
29
29
  export function CollectionPage(props) {
30
- const { title, description, actions, tabs, search, filters, sort, toolbarSurface, noMatch, pending, rail, ...list } = props;
30
+ const { title, description, actions, tabs, attention, search, filters, sort, toolbarSurface, noMatch, pending, rail, ...list } = props;
31
31
  const hasRecords = list.records !== undefined && list.records.length > 0;
32
32
  const narrowed = Boolean(search?.value) || (filters?.facets.some((facet) => facet.value) ?? false);
33
- const page = (_jsxs("div", { className: "grid min-w-0 gap-4", "data-slot": "collection-page", children: [title ? _jsx(PageHeader, { description: description, title: title }) : null, actions ? _jsx(PageActions, { ...actions }) : null, tabs, (search || filters || sort) && (hasRecords || narrowed) ? (_jsx(CollectionToolbar, { actions: filters || sort ? (_jsxs(_Fragment, { children: [filters ? _jsx(CollectionFilters, { ...filters }) : null, sort ? _jsx(CollectionSort, { ...sort }) : null] })) : undefined, "aria-busy": pending || undefined, label: list.label, search: search ? _jsx(CollectionSearch, { ...search }) : undefined, status: pending ? _jsx(WaitingLine, { className: "w-24", decorative: true }) : null, surface: toolbarSurface ?? "plain" })) : null, rail ? (_jsxs("div", { className: "grid min-w-0 gap-6 xl:grid-cols-[18.75rem_minmax(0,1fr)] xl:items-start", "data-slot": "collection-columns", children: [_jsx("div", { className: "min-w-0 xl:col-start-2 xl:row-start-1", children: _jsx(RecordList, { ...list, layout: "line", noMatch: narrowed ? noMatch : undefined }) }), _jsx(CollectionRailColumn, { className: "xl:col-start-1 xl:row-start-1", rail: rail })] })) : (_jsx(RecordList, { ...list, noMatch: narrowed ? noMatch : undefined }))] }));
33
+ const page = (_jsxs("div", { className: "grid min-w-0 gap-4", "data-slot": "collection-page", children: [title ? _jsx(PageHeader, { description: description, title: title }) : null, actions ? _jsx(PageActions, { ...actions }) : null, tabs, attention, (search || filters || sort) && (hasRecords || narrowed) ? (_jsx(CollectionToolbar, { actions: filters || sort ? (_jsxs(_Fragment, { children: [filters ? _jsx(CollectionFilters, { ...filters }) : null, sort ? _jsx(CollectionSort, { ...sort }) : null] })) : undefined, "aria-busy": pending || undefined, label: list.label, search: search ? _jsx(CollectionSearch, { ...search }) : undefined, status: pending ? _jsx(WaitingLine, { className: "w-24", decorative: true }) : null, surface: toolbarSurface ?? "plain" })) : null, rail ? (_jsxs("div", { className: "grid min-w-0 gap-6 xl:grid-cols-[18.75rem_minmax(0,1fr)] xl:items-start", "data-slot": "collection-columns", children: [_jsx("div", { className: "min-w-0 xl:col-start-2 xl:row-start-1", children: _jsx(RecordList, { ...list, layout: "line", noMatch: narrowed ? noMatch : undefined }) }), _jsx(CollectionRailColumn, { className: "xl:col-start-1 xl:row-start-1", rail: rail })] })) : (_jsx(RecordList, { ...list, noMatch: narrowed ? noMatch : undefined }))] }));
34
34
  return title ? _jsx(PageActionsHostProvider, { children: page }) : page;
35
35
  }
@@ -4,6 +4,7 @@ export type ScopeOption = {
4
4
  label: string;
5
5
  group?: string;
6
6
  keywords?: readonly string[];
7
+ mark?: React.ReactNode;
7
8
  };
8
9
  export type ScopeSwitcherCopy = {
9
10
  label: string;
@@ -22,16 +23,17 @@ export type ScopeSwitcherProps = {
22
23
  label: string;
23
24
  onSelect: () => void;
24
25
  };
26
+ variant?: "scope" | "navigation";
25
27
  };
26
28
  /**
27
29
  * Says which part of the account a page reads, and changes it.
28
30
  *
29
31
  * @family Navigation
30
- * @when Changing which part of the account a page reads, such as Analytics' scope: the whole fleet, one partner, one customer. Only when the viewer has more than one.
32
+ * @when Changing which part of the account a page reads, such as Analytics' scope, or switching between objects from the shell's top bar with `variant="navigation"`.
31
33
  * @instead A viewer with one scope and nothing to create reads its name with no control, which this draws by itself. Finding anything is `CommandDialog`; narrowing rows is `CollectionFilters`.
32
- * @behaviour A ghost trigger, at most 16rem, opens a 288 px popover with focus in its search. Type to filter, Enter chooses and closes; choosing the current one changes nothing. The caller writes the choice to the URL in `onValueChange`, so sibling pages keep it. An optional create command sits last.
34
+ * @behaviour A ghost trigger, at most 16rem, opens a 288 px popover with focus in its search. Navigation omits the visible prefix, carries each option's identity mark and opens a 384 px popover constrained to the viewport. Type to filter, Enter chooses and closes; choosing the current one changes nothing. The caller writes the choice to the URL in `onValueChange`, so sibling pages keep it. An optional create command sits last.
33
35
  * @words `copy.label` names what is chosen ("Scope") beside the current scope's name. Search and empty lines name the thing: "Find a scope", "No scope matches".
34
36
  * @access The trigger reads "Scope: All customers"; the popover has a hidden title; options are a listbox with the current one checked.
35
37
  */
36
- export declare function ScopeSwitcher({ value, options, onValueChange, copy, create }: ScopeSwitcherProps): React.JSX.Element;
38
+ export declare function ScopeSwitcher({ value, options, onValueChange, copy, create, variant, }: ScopeSwitcherProps): React.JSX.Element;
37
39
  //# sourceMappingURL=scope-switcher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope-switcher.d.ts","sourceRoot":"","sources":["../../src/components/scope-switcher.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAe/B,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,+FAA+F;IAC/F,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC,8DAA8D;IAC9D,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAClD,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,kBAAkB,qBA6FhG"}
1
+ {"version":3,"file":"scope-switcher.d.ts","sourceRoot":"","sources":["../../src/components/scope-switcher.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAgB/B,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,+FAA+F;IAC/F,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC,8DAA8D;IAC9D,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IACjD,OAAO,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;CAClC,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,EACP,aAAa,EACb,IAAI,EACJ,MAAM,EACN,OAAiB,GAClB,EAAE,kBAAkB,qBA0GpB"}
@@ -5,20 +5,22 @@ import { ChevronsUpDown, Plus } from "lucide-react";
5
5
  import { Button } from "./button.js";
6
6
  import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, } from "./command.js";
7
7
  import { Popover, PopoverContent, PopoverTitle, PopoverTrigger } from "./popover.js";
8
+ import { cn } from "../lib/utils.js";
8
9
  /**
9
10
  * Says which part of the account a page reads, and changes it.
10
11
  *
11
12
  * @family Navigation
12
- * @when Changing which part of the account a page reads, such as Analytics' scope: the whole fleet, one partner, one customer. Only when the viewer has more than one.
13
+ * @when Changing which part of the account a page reads, such as Analytics' scope, or switching between objects from the shell's top bar with `variant="navigation"`.
13
14
  * @instead A viewer with one scope and nothing to create reads its name with no control, which this draws by itself. Finding anything is `CommandDialog`; narrowing rows is `CollectionFilters`.
14
- * @behaviour A ghost trigger, at most 16rem, opens a 288 px popover with focus in its search. Type to filter, Enter chooses and closes; choosing the current one changes nothing. The caller writes the choice to the URL in `onValueChange`, so sibling pages keep it. An optional create command sits last.
15
+ * @behaviour A ghost trigger, at most 16rem, opens a 288 px popover with focus in its search. Navigation omits the visible prefix, carries each option's identity mark and opens a 384 px popover constrained to the viewport. Type to filter, Enter chooses and closes; choosing the current one changes nothing. The caller writes the choice to the URL in `onValueChange`, so sibling pages keep it. An optional create command sits last.
15
16
  * @words `copy.label` names what is chosen ("Scope") beside the current scope's name. Search and empty lines name the thing: "Find a scope", "No scope matches".
16
17
  * @access The trigger reads "Scope: All customers"; the popover has a hidden title; options are a listbox with the current one checked.
17
18
  */
18
- export function ScopeSwitcher({ value, options, onValueChange, copy, create }) {
19
+ export function ScopeSwitcher({ value, options, onValueChange, copy, create, variant = "scope", }) {
19
20
  const [open, setOpen] = React.useState(false);
20
21
  const search = React.useRef(null);
21
- const currentLabel = options.find((option) => option.value === value)?.label ?? value;
22
+ const current = options.find((option) => option.value === value);
23
+ const currentLabel = current?.label ?? value;
22
24
  const groups = React.useMemo(() => {
23
25
  const byGroup = new Map();
24
26
  for (const option of options) {
@@ -34,12 +36,12 @@ export function ScopeSwitcher({ value, options, onValueChange, copy, create }) {
34
36
  onValueChange(next);
35
37
  };
36
38
  const switchable = options.length > 1 || create !== undefined;
37
- return (_jsxs("span", { "data-slot": "scope-switcher", className: "flex min-w-0 items-center gap-2", children: [_jsx("span", { "aria-hidden": switchable ? "true" : undefined, className: "text-xs font-medium text-muted-foreground", children: copy.label }), switchable ? (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsxs(PopoverTrigger, { render: _jsx(Button, { variant: "ghost", className: "max-w-64", suffix: _jsx(ChevronsUpDown, { "aria-hidden": "true" }) }), children: [_jsxs("span", { className: "sr-only", children: [copy.label, ":"] }), " ", _jsx("span", { className: "truncate", children: currentLabel })] }), _jsxs(PopoverContent, { align: "start", className: "w-72 p-0", initialFocus: search, children: [_jsx(PopoverTitle, { className: "sr-only", children: copy.label }), _jsxs(Command, { label: copy.search, resultCount: copy.results, children: [_jsx(CommandInput, { ref: search, "aria-label": copy.search, placeholder: copy.search }), _jsxs(CommandList, { label: copy.label, children: [_jsx(CommandEmpty, { children: copy.empty }), groups.map(([group, items]) => (_jsx(CommandGroup, { heading: group, children: items.map((option) => (_jsx(CommandItem, { value: option.value, keywords: [
39
+ return (_jsxs("span", { "data-slot": "scope-switcher", className: "flex min-w-0 items-center gap-2", children: [_jsx("span", { "aria-hidden": switchable ? "true" : undefined, className: cn("text-xs font-medium text-muted-foreground", variant === "navigation" && "sr-only"), children: copy.label }), switchable ? (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsxs(PopoverTrigger, { render: _jsx(Button, { variant: "ghost", className: "min-w-0 max-w-64 shrink", prefix: current?.mark ? _jsx("span", { "aria-hidden": "true", children: current.mark }) : undefined, suffix: _jsx(ChevronsUpDown, { "aria-hidden": "true" }) }), children: [_jsxs("span", { className: "sr-only", children: [copy.label, ":"] }), " ", _jsx("span", { className: "truncate", children: currentLabel })] }), _jsxs(PopoverContent, { align: "start", className: cn("w-72 max-w-[calc(100vw-2rem)] p-0", variant === "navigation" && "w-96"), initialFocus: search, children: [_jsx(PopoverTitle, { className: "sr-only", children: copy.label }), _jsxs(Command, { label: copy.search, resultCount: copy.results, children: [_jsx(CommandInput, { ref: search, "aria-label": copy.search, placeholder: copy.search }), _jsxs(CommandList, { label: copy.label, children: [_jsx(CommandEmpty, { children: copy.empty }), groups.map(([group, items]) => (_jsx(CommandGroup, { heading: group, children: items.map((option) => (_jsxs(CommandItem, { value: option.value, keywords: [
38
40
  option.label,
39
41
  ...(option.group ? [option.group] : []),
40
42
  ...(option.keywords ?? []),
41
- ], "data-checked": option.value === value, onSelect: () => choose(option.value), children: _jsx("span", { className: "truncate", children: option.label }) }, option.value))) }, group ?? ""))), create ? (_jsxs(_Fragment, { children: [_jsx(CommandSeparator, { alwaysRender: true }), _jsx(CommandGroup, { forceMount: true, heading: undefined, children: _jsxs(CommandItem, { value: `create ${create.label}`, forceMount: true, onSelect: () => {
43
+ ], "data-checked": option.value === value, onSelect: () => choose(option.value), children: [option.mark ? _jsx("span", { "aria-hidden": "true", children: option.mark }) : null, _jsx("span", { className: "truncate", children: option.label })] }, option.value))) }, group ?? ""))), create ? (_jsxs(_Fragment, { children: [_jsx(CommandSeparator, { alwaysRender: true }), _jsx(CommandGroup, { forceMount: true, heading: undefined, children: _jsxs(CommandItem, { value: `create ${create.label}`, forceMount: true, onSelect: () => {
42
44
  setOpen(false);
43
45
  create.onSelect();
44
- }, children: [_jsx(Plus, { "aria-hidden": "true" }), create.label] }) })] })) : null] })] })] })] })) : (_jsx("span", { className: "truncate px-3 text-sm", children: currentLabel }))] }));
46
+ }, children: [_jsx(Plus, { "aria-hidden": "true" }), create.label] }) })] })) : null] })] })] })] })) : (_jsxs("span", { className: "flex min-w-0 items-center gap-2 px-3 text-sm", children: [current?.mark ? _jsx("span", { "aria-hidden": "true", children: current.mark }) : null, _jsx("span", { className: "truncate", children: currentLabel })] }))] }));
45
47
  }
package/dist/index.d.ts CHANGED
@@ -32,6 +32,7 @@ export * from "./components/chart-bar-stacked.js";
32
32
  export * from "./components/chart-card.js";
33
33
  export * from "./components/chart-date-range-control.js";
34
34
  export * from "./components/chart-entity-colors.js";
35
+ export * from "./components/chart-ranking.js";
35
36
  export * from "./components/chart-sparkline.js";
36
37
  export * from "./components/check-counts.js";
37
38
  export * from "./components/checkbox.js";
@@ -97,7 +98,6 @@ export * from "./components/page-actions.js";
97
98
  export * from "./components/page-header.js";
98
99
  export * from "./components/pairing-code.js";
99
100
  export * from "./components/pending-label.js";
100
- export * from "./components/picture-label.js";
101
101
  export * from "./components/platform-mark.js";
102
102
  export * from "./components/popover.js";
103
103
  export * from "./components/portal-sidebar-frame.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ export * from "./components/chart-bar-stacked.js";
32
32
  export * from "./components/chart-card.js";
33
33
  export * from "./components/chart-date-range-control.js";
34
34
  export * from "./components/chart-entity-colors.js";
35
+ export * from "./components/chart-ranking.js";
35
36
  export * from "./components/chart-sparkline.js";
36
37
  export * from "./components/check-counts.js";
37
38
  export * from "./components/checkbox.js";
@@ -97,7 +98,6 @@ export * from "./components/page-actions.js";
97
98
  export * from "./components/page-header.js";
98
99
  export * from "./components/pairing-code.js";
99
100
  export * from "./components/pending-label.js";
100
- export * from "./components/picture-label.js";
101
101
  export * from "./components/platform-mark.js";
102
102
  export * from "./components/popover.js";
103
103
  export * from "./components/portal-sidebar-frame.js";
@@ -1,5 +1,6 @@
1
1
  declare function DateRangeControlSpecimen(): import("react").JSX.Element;
2
2
  export declare const CHARTS: {
3
+ ChartRanking: () => import("react").JSX.Element;
3
4
  ActivityCalendar: () => import("react").JSX.Element;
4
5
  ChartAreaStacked: () => import("react").JSX.Element;
5
6
  ChartBarHorizontal: () => import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"charts.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/charts.tsx"],"names":[],"mappings":"AAmFA,iBAAS,wBAAwB,gCA0BhC;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;;;CAwLQ,CAAC"}
1
+ {"version":3,"file":"charts.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/charts.tsx"],"names":[],"mappings":"AAoFA,iBAAS,wBAAwB,gCA0BhC;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;;;;CA4MQ,CAAC"}
@@ -12,6 +12,7 @@ import { ChartCard, ChartSummary } from "../../components/chart-card.js";
12
12
  import { DateRangeControl } from "../../components/chart-date-range-control.js";
13
13
  import { createEntityColorMap } from "../../components/chart-entity-colors.js";
14
14
  import { ChartSparkline } from "../../components/chart-sparkline.js";
15
+ import { ChartRanking } from "../../components/chart-ranking.js";
15
16
  import { KpiCard } from "../../components/kpi-card.js";
16
17
  import { TrendBadge, trendTone } from "../../components/trend-badge.js";
17
18
  const euro = (value) => new Intl.NumberFormat("en", { style: "currency", currency: "EUR" }).format(value);
@@ -69,6 +70,15 @@ function DateRangeControlSpecimen() {
69
70
  return (_jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsx(DateRangeControl, { formatCustomValue: ({ from, to }) => `${from} – ${to}`, label: "Date range", maxValue: RETENTION_TO, minValue: RETENTION_FROM, onChange: setRange, presetLabels: RANGE_PRESET_LABELS, value: range }), _jsx(DateRangeControl, { formatCustomValue: ({ from, to }) => `${from} – ${to}`, label: "Date range, small", maxValue: RETENTION_TO, minValue: RETENTION_FROM, onChange: setSmallRange, presetLabels: RANGE_PRESET_LABELS, size: "sm", value: smallRange })] }));
70
71
  }
71
72
  export const CHARTS = {
73
+ ChartRanking: () => (_jsx(ChartRanking, { title: "Top customers", description: "by spend", total: 356, rows: SPEND.slice(-1).flatMap((reading) => CUSTOMERS.map((customer) => ({
74
+ ...customer,
75
+ value: reading[customer.id],
76
+ display: euro(reading[customer.id]),
77
+ }))), entityColorMap: CUSTOMER_COLORS, disclosure: {
78
+ label: "View all (3)",
79
+ description: "Ranked by spend over the selected period",
80
+ closeLabel: "Close",
81
+ } })),
72
82
  ActivityCalendar: () => (_jsx(ActivityCalendar, { data: ACTIVITY, from: "2026-08-16", labels: {
73
83
  ariaLabel: "Requests per day",
74
84
  unavailable: "Not measured",
@@ -1,5 +1,4 @@
1
1
  declare function EmptyStateSpecimen(): import("react").JSX.Element;
2
- declare function LabelledPictureSpecimen(): import("react").JSX.Element;
3
2
  declare function PendingLabelSpecimen(): import("react").JSX.Element;
4
3
  declare function ToasterSpecimen(): import("react").JSX.Element;
5
4
  declare function UpdateCardSpecimen(): import("react").JSX.Element;
@@ -10,7 +9,6 @@ export declare const FEEDBACK: {
10
9
  EntryProgress: () => import("react").JSX.Element;
11
10
  EntryStageList: () => import("react").JSX.Element;
12
11
  HoverCard: () => import("react").JSX.Element;
13
- LabelledPicture: typeof LabelledPictureSpecimen;
14
12
  MessageNotice: () => import("react").JSX.Element;
15
13
  NoticeBanner: () => import("react").JSX.Element;
16
14
  PendingLabel: typeof PendingLabelSpecimen;
@@ -1 +1 @@
1
- {"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/feedback.tsx"],"names":[],"mappings":"AA8CA,iBAAS,kBAAkB,gCAoE1B;AAED,iBAAS,uBAAuB,gCAW/B;AAED,iBAAS,oBAAoB,gCAkB5B;AAED,iBAAS,eAAe,gCAyBvB;AAED,iBAAS,kBAAkB,gCA8B1B;AAED,iBAAS,sBAAsB,gCAwB9B;AAED,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;CA8LM,CAAC"}
1
+ {"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../../src/showcase/specimens/feedback.tsx"],"names":[],"mappings":"AA6CA,iBAAS,kBAAkB,gCAoE1B;AAED,iBAAS,oBAAoB,gCAkB5B;AAED,iBAAS,eAAe,gCAyBvB;AAED,iBAAS,kBAAkB,gCA8B1B;AAED,iBAAS,sBAAsB,gCAwB9B;AAED,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;CA6LM,CAAC"}
@@ -11,7 +11,6 @@ import { HoverCard, HoverCardContent, HoverCardSummary, HoverCardTrigger, } from
11
11
  import { Kbd } from "../../components/kbd.js";
12
12
  import { MessageNotice } from "../../components/message-notice.js";
13
13
  import { NoticeBanner } from "../../components/notice-banner.js";
14
- import { LabelledPicture, PictureLabel } from "../../components/picture-label.js";
15
14
  import { RecordTime } from "../../components/record-time.js";
16
15
  import { Skeleton, SkeletonRegion } from "../../components/skeleton.js";
17
16
  import { Toaster } from "../../components/sonner.js";
@@ -38,10 +37,6 @@ function EmptyStateSpecimen() {
38
37
  copyFailedLabel: "Couldn't copy",
39
38
  }, scope: "region" }) }), _jsx(Captioned, { caption: "Failed, in a card: the answer of an ErrorCard", children: _jsx(EmptyState, { kind: "failed", message: FAILED_READ, scope: "card" }) })] }));
40
39
  }
41
- function LabelledPictureSpecimen() {
42
- const art = useEmptyArt();
43
- return (_jsx(LabelledPicture, { label: _jsx(PictureLabel, { details: "Ink and watercolour, 2026", title: "A letter that lost its address" }), children: _jsx("img", { alt: "", className: "size-64 object-contain", src: art.mail }) }));
44
- }
45
40
  function PendingLabelSpecimen() {
46
41
  const [pending, setPending] = useState(false);
47
42
  return (_jsxs(DropdownMenu, { onOpenChange: (open) => (open ? undefined : setPending(false)), children: [_jsx(DropdownMenuTrigger, { render: _jsx(Button, { variant: "outline" }), children: "Account" }), _jsx(DropdownMenuContent, { align: "start", children: _jsx(DropdownMenuCommand, { closeOnClick: false, icon: _jsx(LogOut, {}), loading: pending, loadingLabel: "Signing out", onClick: () => setPending(true), children: "Sign out" }) })] }));
@@ -71,7 +66,6 @@ export const FEEDBACK = {
71
66
  { label: "Region", value: "Frankfurt" },
72
67
  { label: "Last active", value: null },
73
68
  ], missingLabel: "Not reported", name: "Portal" }) })] })] })),
74
- LabelledPicture: LabelledPictureSpecimen,
75
69
  MessageNotice: () => (_jsxs("div", { className: "grid max-w-lg gap-4", children: [_jsx(MessageNotice, { message: sampleMessage("Couldn't remove pec@acme.it", "The mailbox is still connected.", [
76
70
  { label: "Try again", onClick: nothing },
77
71
  ]), placement: "action" }), _jsx(MessageNotice, { message: sampleMessage("Billing is paused", "Agents stop at the end of the cycle.", [
@@ -15,6 +15,7 @@ export declare const SPECIMENS: {
15
15
  ScrollArea: () => import("react").JSX.Element;
16
16
  Separator: () => import("react").JSX.Element;
17
17
  ToolIcon: () => import("react").JSX.Element;
18
+ ChartRanking: () => import("react").JSX.Element;
18
19
  ActivityCalendar: () => import("react").JSX.Element;
19
20
  ChartAreaStacked: () => import("react").JSX.Element;
20
21
  ChartBarHorizontal: () => import("react").JSX.Element;
@@ -45,7 +46,6 @@ export declare const SPECIMENS: {
45
46
  EntryProgress: () => import("react").JSX.Element;
46
47
  EntryStageList: () => import("react").JSX.Element;
47
48
  HoverCard: () => import("react").JSX.Element;
48
- LabelledPicture: () => import("react").JSX.Element;
49
49
  MessageNotice: () => import("react").JSX.Element;
50
50
  NoticeBanner: () => import("react").JSX.Element;
51
51
  PendingLabel: () => import("react").JSX.Element;
@@ -1,4 +1,4 @@
1
- export type UsageName = "ActivityFeed" | "AgentProfileCard" | "CatalogDrawer" | "CollectionFilters" | "CollectionPage" | "CollectionToolbar" | "ConfirmDialog" | "EntryScene" | "FormDialog" | "FormDrawer" | "LibraryShelf" | "ObjectPage" | "ObjectSection" | "OverviewPage" | "PageHeader" | "RecordList" | "RecordSheet" | "RowEditForm" | "SettingsPage" | "SettingsSection" | "Button" | "ButtonGroup" | "ButtonLink" | "CopyButton" | "LoadMoreButton" | "PageActions" | "Calendar" | "ClearableInput" | "CollectionSearch" | "Field" | "Input" | "InputGroup" | "InputOTP" | "Label" | "NativeSelect" | "SettingsField" | "SettingsRows" | "Slider" | "Textarea" | "Checkbox" | "ChoiceboxGroup" | "CollectionSort" | "Combobox" | "ModelSelect" | "MultiSelect" | "RadioGroup" | "SegmentedChoice" | "SegmentedControl" | "Select" | "Switch" | "ThemeModeSegments" | "ThemeModeSwitcher" | "Toggle" | "ToggleGroup" | "ActionStatus" | "AgentOrb" | "AppMark" | "ArchIcon" | "Avatar" | "Badge" | "BrandWordmark" | "CheckCounts" | "FileTypeIcon" | "IdentityMark" | "ModelIdentity" | "ModelMark" | "PlatformMark" | "ProgressChecklist" | "RecordIdentity" | "StatusBadge" | "StatusDot" | "Tag" | "AgentListRow" | "Breadcrumb" | "CommandDialog" | "Footer" | "PortalSidebarFrame" | "ScopeSwitcher" | "Sidebar" | "SidebarBrand" | "SidebarFind" | "SidebarFrame" | "SidebarMenuChevron" | "SidebarSections" | "Tabs" | "TabsNav" | "textLinkVariants" | "AgentCard" | "Card" | "CardRow" | "CodeBlock" | "DataTable" | "DiffCount" | "DisclosureRow" | "FileDiff" | "Gauge" | "Item" | "Kbd" | "MiddleTruncate" | "ObjectFacts" | "PairingCode" | "Progress" | "QrCode" | "RecordTime" | "RunTimeline" | "SettingsFactsSection" | "Snippet" | "Table" | "TableCard" | "TableValue" | "TextWithCopyButton" | "UsageMeter" | "Alert" | "EmptyState" | "EntryProgress" | "EntryStageList" | "HoverCard" | "LabelledPicture" | "MessageNotice" | "NoticeBanner" | "PendingLabel" | "Skeleton" | "SkeletonRegion" | "Toaster" | "Tooltip" | "UpdateCard" | "WaitingLine" | "AccountMenu" | "ActionContextMenu" | "ActionMenu" | "AlertDialog" | "ContextMenu" | "Dialog" | "Drawer" | "DropdownMenu" | "GlassControl" | "MenuChoiceRow" | "Popover" | "Sheet" | "ThemeModeMenu" | "ActivityCalendar" | "ChartAreaStacked" | "ChartBarHorizontal" | "ChartBarMultiple" | "ChartBarStacked" | "ChartCard" | "ChartContainer" | "ChartSparkline" | "DateRangeControl" | "KpiCard" | "TrendBadge" | "createEntityColorMap" | "Accordion" | "AspectRatio" | "BrandField" | "Carousel" | "Collapsible" | "CompanyCard" | "Disclosure" | "HiveScene" | "NadiaPresence" | "NumberedSteps" | "Prose" | "ReadingColumn" | "ResizablePanelGroup" | "ScrollArea" | "Separator" | "ToolIcon";
1
+ export type UsageName = "ActivityFeed" | "AgentProfileCard" | "CatalogDrawer" | "CollectionFilters" | "CollectionPage" | "CollectionToolbar" | "ConfirmDialog" | "EntryScene" | "FormDialog" | "FormDrawer" | "LibraryShelf" | "ObjectPage" | "ObjectSection" | "OverviewPage" | "PageHeader" | "RecordList" | "RecordSheet" | "RowEditForm" | "SettingsPage" | "SettingsSection" | "Button" | "ButtonGroup" | "ButtonLink" | "CopyButton" | "LoadMoreButton" | "PageActions" | "Calendar" | "ClearableInput" | "CollectionSearch" | "Field" | "Input" | "InputGroup" | "InputOTP" | "Label" | "NativeSelect" | "SettingsField" | "SettingsRows" | "Slider" | "Textarea" | "Checkbox" | "ChoiceboxGroup" | "CollectionSort" | "Combobox" | "ModelSelect" | "MultiSelect" | "RadioGroup" | "SegmentedChoice" | "SegmentedControl" | "Select" | "Switch" | "ThemeModeSegments" | "ThemeModeSwitcher" | "Toggle" | "ToggleGroup" | "ActionStatus" | "AgentOrb" | "AppMark" | "ArchIcon" | "Avatar" | "Badge" | "BrandWordmark" | "CheckCounts" | "FileTypeIcon" | "IdentityMark" | "ModelIdentity" | "ModelMark" | "PlatformMark" | "ProgressChecklist" | "RecordIdentity" | "StatusBadge" | "StatusDot" | "Tag" | "AgentListRow" | "Breadcrumb" | "CommandDialog" | "Footer" | "PortalSidebarFrame" | "ScopeSwitcher" | "Sidebar" | "SidebarBrand" | "SidebarFind" | "SidebarFrame" | "SidebarMenuChevron" | "SidebarSections" | "Tabs" | "TabsNav" | "textLinkVariants" | "AgentCard" | "Card" | "CardRow" | "CodeBlock" | "DataTable" | "DiffCount" | "DisclosureRow" | "FileDiff" | "Gauge" | "Item" | "Kbd" | "MiddleTruncate" | "ObjectFacts" | "PairingCode" | "Progress" | "QrCode" | "RecordTime" | "RunTimeline" | "SettingsFactsSection" | "Snippet" | "Table" | "TableCard" | "TableValue" | "TextWithCopyButton" | "UsageMeter" | "Alert" | "EmptyState" | "EntryProgress" | "EntryStageList" | "HoverCard" | "MessageNotice" | "NoticeBanner" | "PendingLabel" | "Skeleton" | "SkeletonRegion" | "Toaster" | "Tooltip" | "UpdateCard" | "WaitingLine" | "AccountMenu" | "ActionContextMenu" | "ActionMenu" | "AlertDialog" | "ContextMenu" | "Dialog" | "Drawer" | "DropdownMenu" | "GlassControl" | "MenuChoiceRow" | "Popover" | "Sheet" | "ThemeModeMenu" | "ActivityCalendar" | "ChartAreaStacked" | "ChartBarHorizontal" | "ChartBarMultiple" | "ChartBarStacked" | "ChartCard" | "ChartContainer" | "ChartRanking" | "ChartSparkline" | "DateRangeControl" | "KpiCard" | "TrendBadge" | "createEntityColorMap" | "Accordion" | "AspectRatio" | "BrandField" | "Carousel" | "Collapsible" | "CompanyCard" | "Disclosure" | "HiveScene" | "NadiaPresence" | "NumberedSteps" | "Prose" | "ReadingColumn" | "ResizablePanelGroup" | "ScrollArea" | "Separator" | "ToolIcon";
2
2
  export type UsageFamily = "Compositions" | "Actions" | "Inputs" | "Choices" | "Status" | "Navigation" | "Data" | "Feedback" | "Menus" | "Charts" | "Other";
3
3
  export type ComponentUsage = {
4
4
  name: UsageName;
@@ -1 +1 @@
1
- {"version":3,"file":"usage.generated.d.ts","sourceRoot":"","sources":["../../src/showcase/usage.generated.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"usage.generated.d.ts","sourceRoot":"","sources":["../../src/showcase/usage.generated.ts"],"names":[],"mappings":"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"}
@@ -63,7 +63,7 @@ export const USAGE = [
63
63
  module: "collection-page",
64
64
  family: "Compositions",
65
65
  summary: "A page whose job is a list of records: its title with the page's actions on one row, its sibling collections, one toolbar, then one line per record.",
66
- when: "“Use `<Entity>` for a row of descriptive content paired with one or two controls (member rows, integration rows, domain rows).” (https://vercel.com/geist/entity) Ours: a list of entity rows a person finds one of, opens and acts on: Customers, Agents, Skills, Apps, MCP servers, Mailboxes, domains, environment variables (a row with an `editor` expands into its form). Its rows are a `RecordList`'s, so a row has a mark, a name over a muted line and at most three facts; anything wider is not this page. “Projects”: Vercel's Projects page stands a column of titled cards (Usage, Alerts, Recent Previews) at the left of its list. (https://vercel.com/dashboard) Ours: a collection whose reader also needs to know what is waiting on them across all its records, such as nadicode's Customers and Partners and a Partner's Customers, takes that column as its `rail`.",
66
+ when: "“Use `<Entity>` for a row of descriptive content paired with one or two controls (member rows, integration rows, domain rows).” (https://vercel.com/geist/entity) Ours: a list of entity rows a person finds one of, opens and acts on: Customers, Agents, Skills, Apps, MCP servers, Mailboxes, domains, environment variables (a row with an `editor` expands into its form). Its rows are a `RecordList`'s, so a row has a mark, a name over a muted line and at most three facts; anything wider is not this page. “Projects”: Vercel's Projects page stands a column of titled cards (Usage, Alerts, Recent Previews) at the left of its list. (https://vercel.com/dashboard) Ours: Customers and Partners use the full-width list, with actionable attention above the toolbar when present. Business summaries belong on Dashboard and Analytics. A rail remains available for context that belongs to the collection itself, such as the selected Library hub.",
67
67
  instead: "“For tabular data with sortable columns and shared row shape, use `Table` instead.” (https://vercel.com/geist/entity) Ours: records compared across columns, read by their headings, are a `DataTable` under the page's own title and toolbar. A list inside another page's section is a `RecordList` with its `heading`.",
68
68
  behaviour: "With a `rail`, the toolbar spans the page and under it stand two columns from 1280 px: the rail, 300 px, then the records' card, its top level with the rail's first title and named by the page's title alone, never a second heading, and the records' rows are `RecordList`'s `line` rows; below 1280 px the records come first and the rail follows them. Each rail card has its title above it at 16 px, an optional 44 px muted summary row with its one outline button at its end (a button never stands in a row of its own, so a card with an `action` has a `summary`), then its items: a figure is one 36 px row, its title and its number at the trailing edge; a record is its 24 px mark, a title over a muted line that wraps to a second before it is cut, and a figure or a status at its end, the whole item opening its record; a card with no items draws its `empty` inside it as one 44 px row like an item. While the rail's read is in flight a card's `items` are undefined and it holds its place with three placeholder lines, so the two columns stand from the first frame; a rail whose read `failed` is one card saying so, and the records beside it stay. Under the title sits only the `description`, when the collection's kind needs explaining; otherwise nothing. The title row holds at most one secondary, the primary, then the three dots, which open only for two commands or more. The primary stays in the title row whether the collection is empty or not, filled, as Vercel's Flags keeps Create Flag; a first use repeats it as the filled button in its card. One toolbar holds the search, which grows, then the filters, then the sort; it shows while there are records or a search or filter is set, and is glass only where the rows scroll under it. While a new search, filter or sort is read, the toolbar is busy and, after a second, shows the one waiting line, while the last rows stay. The rows, their states and their loading are the RecordList's; no match is offered only while a search or filter is set.",
69
69
  words: '“For multi-facet filters use the plural template `No {Items} Match Your Filters` and suggest widening or clearing.” (https://vercel.com/geist/empty-state) Ours: every string is the product\'s, in sentence case. The title names the collection in the plural ("Agents"); the search says what it finds ("Find a skill"); no match says what found nothing and offers to clear it ("Clear search", "Clear filters").',
@@ -866,9 +866,9 @@ export const USAGE = [
866
866
  module: "scope-switcher",
867
867
  family: "Navigation",
868
868
  summary: "Says which part of the account a page reads, and changes it.",
869
- when: "Changing which part of the account a page reads, such as Analytics' scope: the whole fleet, one partner, one customer. Only when the viewer has more than one.",
869
+ when: "Changing which part of the account a page reads, such as Analytics' scope, or switching between objects from the shell's top bar with `variant=\"navigation\"`.",
870
870
  instead: "A viewer with one scope and nothing to create reads its name with no control, which this draws by itself. Finding anything is `CommandDialog`; narrowing rows is `CollectionFilters`.",
871
- behaviour: "A ghost trigger, at most 16rem, opens a 288 px popover with focus in its search. Type to filter, Enter chooses and closes; choosing the current one changes nothing. The caller writes the choice to the URL in `onValueChange`, so sibling pages keep it. An optional create command sits last.",
871
+ behaviour: "A ghost trigger, at most 16rem, opens a 288 px popover with focus in its search. Navigation omits the visible prefix, carries each option's identity mark and opens a 384 px popover constrained to the viewport. Type to filter, Enter chooses and closes; choosing the current one changes nothing. The caller writes the choice to the URL in `onValueChange`, so sibling pages keep it. An optional create command sits last.",
872
872
  words: '`copy.label` names what is chosen ("Scope") beside the current scope\'s name. Search and empty lines name the thing: "Find a scope", "No scope matches".',
873
873
  access: 'The trigger reads "Scope: All customers"; the popover has a hidden title; options are a listbox with the current one checked.',
874
874
  },
@@ -1301,17 +1301,6 @@ export const USAGE = [
1301
1301
  words: '"Lead with the entity name as a Title Case heading and one identifying line in sentence case underneath (team slug, owner, deployment URL)." "Follow with 2–4 metadata rows of `Label: value`." "Keys are Title Case noun phrases (`Last Active`, `Created`, `Plan`); values follow the same formatting rules as table cells." "Use the em-dash character `—` for unknown values, never `N/A` or `null`." "Don’t restate what the trigger already showed." "If the row already renders the deployment URL, don’t repeat it as the first card line." (https://vercel.com/geist/context-card) Ours: the name and the keys are in sentence case (*Last active*). A time\'s card leads with the relative label, and its trigger keeps its verb sentence: *Updated 3 hours ago*.',
1302
1302
  access: '"The trigger keeps its own accessible name; the card is supplementary and shouldn’t replace it." "Card content is reachable by keyboard once the trigger has focus; Escape closes the card and returns focus to the trigger." (https://vercel.com/geist/context-card) Ours: the trigger is a real element (a `time` with its `datetime` for a moment), so the facts never depend on hover. Keyboard opening is tested, not assumed.',
1303
1303
  },
1304
- {
1305
- name: "LabelledPicture",
1306
- module: "picture-label",
1307
- family: "Feedback",
1308
- summary: "A failure page's picture with its label, the way a museum labels a work.",
1309
- when: "A page that cannot show what was asked for: an address or record that is not there (absence), or a request the product stopped (fault). `PictureLabel` is its label.",
1310
- instead: "For one region that failed inside a working page use `EmptyState failed`; the rest of the page stays. Never turn the whole page into an error because one card failed.",
1311
- behaviour: "Picture 256 px, 320 from sm, 384 from lg. The label stands centred under the picture at every width, on the same centre line as the words below. Still.",
1312
- words: "Never apologise, never name the mechanism. The label's title says what the figure in the picture is doing, which is the page's one joke; the second line, in mono, gives its materials and year.",
1313
- access: "The picture is decorative; the label is a `figcaption`, read once. The page's heading is its `h1`; its actions are real links.",
1314
- },
1315
1304
  {
1316
1305
  name: "MessageNotice",
1317
1306
  module: "message-notice",
@@ -1605,7 +1594,7 @@ export const USAGE = [
1605
1594
  summary: "One total over time, each bar split by entity; with `share`, one bar split to 100%.",
1606
1595
  when: "How a total moved over time split by Customer, member account or model; with `share`, what part of one total each holds, with no time axis.",
1607
1596
  instead: "For a continuous volume in three series or fewer use `ChartAreaStacked`. Two measures side by side use `ChartBarMultiple`. Exact lookup is a table.",
1608
- behaviour: 'Stacked in series order, bottom segment rounded below and top above at 4 px, bars at most 48 px. The Portal names five entities and folds the rest into "Everything else". The share plot is 64 px, legend included.',
1597
+ behaviour: 'Stacked in series order, bottom segment rounded below and top above at 4 px, bars at most 48 px. The summary variant has square bars and no dot legend: its adjacent ChartRanking identifies the series with share bars. The Portal names five entities and folds the rest into "Everything else". The share plot is 64 px, legend included.',
1609
1598
  words: 'Entity names as the reader knows them, never ids. The neutral remainder is "Everything else". Values through the page\'s shared money formatter.',
1610
1599
  access: "The plot is an image named by the card title; the tooltip and legend are read with it. The share bar sits above the full-width table that carries each figure.",
1611
1600
  },
@@ -1616,7 +1605,7 @@ export const USAGE = [
1616
1605
  summary: "The card every chart in the kit renders: one header, the summary, the plot, its legend and the reading's time. The plots (`ChartBarStacked`, `ChartAreaStacked`, `ChartBarMultiple`, `ChartBarHorizontal`) hold only their own plot; a page never builds a chart card frame by hand.",
1617
1606
  when: "Every chart and every reading built around one: the frame a page never builds by hand. A chart is a named section of its page.",
1618
1607
  instead: "A single figure is a `KpiCard`, never nested inside a chart. A ranking beside the plot goes in the card's `aside`, not a second card.",
1619
- behaviour: "Header grid: title and period in the first column, controls and then the link to the reading's owner (a small ghost button ending in a chevron, as OpenRouter's \"Explore ›\") in the second from a 28 rem card width, under the title below it; a link with no controls stays at the trailing edge at every width. Summary, plot, legend, footer in that order. An empty dataset shows its `emptyState` in the plot's place. The footer is a recessed strip behind a hairline: the reading's time left, at most one command on the reading (Refresh) right.",
1608
+ behaviour: "The default header puts controls at the trailing edge on wide cards, below the title on narrow cards. The summary variant keeps controls immediately after the title, the owner link at the trailing edge, and the total and period above the plot. The ranking sits beside the plot only when the card itself reaches 48 rem; narrower cards keep a full-width plot and put the ranking below it. Controls wrap on narrow cards. An empty dataset shows its `emptyState` in the plot's place. The footer carries the reading time and at most one command on that reading.",
1620
1609
  words: 'Title names the measure and its split: "Model spend by Customer". Period as dates. The link: "Explore", or "Open in Analytics" where the owner is another page. Footer: the reading\'s time, "Updated 4 minutes ago" or "Read at 12:42". Sentence case throughout.',
1621
1610
  access: "The title is a heading at the page's level (default 2) and labels the plot. The plot is focusable and shows the 2 px focus outline only on keyboard focus.",
1622
1611
  },
@@ -1631,6 +1620,17 @@ export const USAGE = [
1631
1620
  words: "None of its own: series labels come from the config the plot builds from the page's words.",
1632
1621
  access: "The plot it holds is named by the card title through `aria-labelledby`; Recharts' accessibility layer makes it keyboard focusable.",
1633
1622
  },
1623
+ {
1624
+ name: "ChartRanking",
1625
+ module: "chart-ranking",
1626
+ family: "Charts",
1627
+ summary: "The leading entities beside a usage chart, with the complete ranking one step away.",
1628
+ when: "A chart summary needs a ranking beside its plot.",
1629
+ instead: "Exact breakdown columns belong in a DataTable. This list compares shares of one nonnegative total.",
1630
+ behaviour: "Shows the first five rows and an optional aggregate remainder, each identity and figure above its coloured share bar. The remainder identifies the neutral plot segment; View all expands the named entities rather than repeating their aggregate. View all opens the complete supplied ranking in a dialog. Rows arrive already sorted and share one total and colour map with the chart.",
1631
+ words: "The product supplies the title, metric description, View all count, dialog description and close label.",
1632
+ access: "Each share bar is named by its entity. The dialog is named by the ranking title and retains the selected period and metric.",
1633
+ },
1634
1634
  {
1635
1635
  name: "ChartSparkline",
1636
1636
  module: "chart-sparkline",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/ui",
3
- "version": "12.1.116",
3
+ "version": "12.1.118",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -82,7 +82,7 @@
82
82
  "@base-ui/react": "^1.9.0",
83
83
  "@iconify-icons/logos": "^2.0.3",
84
84
  "@iconify/react": "^6.0.2",
85
- "@nadicodeai/design-system": "12.1.116",
85
+ "@nadicodeai/design-system": "12.1.118",
86
86
  "@tanstack/react-table": "^9.3.1",
87
87
  "@vgpu/wgsl": "0.6.0",
88
88
  "class-variance-authority": "^0.7.1",
@@ -1,30 +0,0 @@
1
- import type { ReactNode } from "react";
2
- /**
3
- * A failure page's picture with its label, the way a museum labels a work.
4
- *
5
- * DESIGN.md: [Failure surfaces](../../../design-system/DESIGN.md#failure-surfaces).
6
- *
7
- * @family Feedback
8
- * @when A page that cannot show what was asked for: an address or record that is not there
9
- * (absence), or a request the product stopped (fault). `PictureLabel` is its label.
10
- * @instead For one region that failed inside a working page use `EmptyState failed`; the rest of
11
- * the page stays. Never turn the whole page into an error because one card failed.
12
- * @behaviour Picture 256 px, 320 from sm, 384 from lg. The label stands centred under the picture at
13
- * every width, on the same centre line as the words below. Still.
14
- * @words Never apologise, never name the mechanism. The label's title says what the figure in the
15
- * picture is doing, which is the page's one joke; the second line, in mono, gives its materials and
16
- * year.
17
- * @access The picture is decorative; the label is a `figcaption`, read once. The page's heading is
18
- * its `h1`; its actions are real links.
19
- */
20
- export declare function LabelledPicture({ children, label, className, }: {
21
- children: ReactNode;
22
- /** The `PictureLabel`, or a boundary that streams it in. */
23
- label: ReactNode;
24
- className?: string;
25
- }): import("react").JSX.Element;
26
- export declare function PictureLabel({ title, details }: {
27
- title: string;
28
- details: string;
29
- }): import("react").JSX.Element;
30
- //# sourceMappingURL=picture-label.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"picture-label.d.ts","sourceRoot":"","sources":["../../src/components/picture-label.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,KAAK,EACL,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,4DAA4D;IAC5D,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAUA;AAED,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,+BASlF"}
@@ -1,26 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cn } from "../lib/utils.js";
3
- /**
4
- * A failure page's picture with its label, the way a museum labels a work.
5
- *
6
- * DESIGN.md: [Failure surfaces](../../../design-system/DESIGN.md#failure-surfaces).
7
- *
8
- * @family Feedback
9
- * @when A page that cannot show what was asked for: an address or record that is not there
10
- * (absence), or a request the product stopped (fault). `PictureLabel` is its label.
11
- * @instead For one region that failed inside a working page use `EmptyState failed`; the rest of
12
- * the page stays. Never turn the whole page into an error because one card failed.
13
- * @behaviour Picture 256 px, 320 from sm, 384 from lg. The label stands centred under the picture at
14
- * every width, on the same centre line as the words below. Still.
15
- * @words Never apologise, never name the mechanism. The label's title says what the figure in the
16
- * picture is doing, which is the page's one joke; the second line, in mono, gives its materials and
17
- * year.
18
- * @access The picture is decorative; the label is a `figcaption`, read once. The page's heading is
19
- * its `h1`; its actions are real links.
20
- */
21
- export function LabelledPicture({ children, label, className, }) {
22
- return (_jsxs("figure", { className: cn("m-0 grid w-full max-w-4xl justify-items-center gap-4", className), "data-slot": "labelled-picture", children: [_jsx("div", { children: children }), _jsx("figcaption", { className: "max-w-72 text-center", children: label })] }));
23
- }
24
- export function PictureLabel({ title, details }) {
25
- return (_jsxs("span", { className: "grid gap-1", children: [_jsx("span", { className: "text-body-sm text-balance font-medium", children: title }), _jsx("span", { className: "font-label-mono text-label-mono text-balance text-muted-foreground", children: details })] }));
26
- }