@kind-ui/charts 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +657 -865
- package/dist/activity-rings.d.ts +2 -1
- package/dist/activity-rings.js +6 -3
- package/dist/animation.d.ts +11 -3
- package/dist/animation.js +18 -10
- package/dist/area-chart.d.ts +3 -1
- package/dist/area-chart.js +15 -10
- package/dist/area-series.d.ts +9 -1
- package/dist/area-series.js +35 -8
- package/dist/bar-chart.d.ts +10 -3
- package/dist/bar-chart.js +17 -4
- package/dist/bar-series.d.ts +11 -1
- package/dist/bar-series.js +65 -13
- package/dist/box-plot.js +2 -2
- package/dist/category-cells.d.ts +7 -1
- package/dist/category-cells.js +32 -2
- package/dist/chart-background-pattern.d.ts +23 -0
- package/dist/chart-background-pattern.js +31 -0
- package/dist/chart-context.d.ts +6 -2
- package/dist/chart-interaction.d.ts +94 -0
- package/dist/chart-interaction.js +224 -0
- package/dist/combo-chart.d.ts +8 -5
- package/dist/combo-chart.js +14 -12
- package/dist/configured-line-chart.d.ts +5 -1
- package/dist/configured-line-chart.js +8 -5
- package/dist/emphasis.d.ts +5 -2
- package/dist/emphasis.js +18 -4
- package/dist/fill-pattern.d.ts +25 -0
- package/dist/fill-pattern.js +23 -0
- package/dist/heatmap.d.ts +3 -1
- package/dist/heatmap.js +34 -12
- package/dist/histogram-chart.js +10 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +8 -1
- package/dist/legend.d.ts +2 -0
- package/dist/legend.js +28 -7
- package/dist/line-chart.d.ts +13 -3
- package/dist/line-chart.js +54 -34
- package/dist/line-dash.d.ts +8 -0
- package/dist/line-dash.js +18 -0
- package/dist/line-series.d.ts +9 -1
- package/dist/line-series.js +38 -11
- package/dist/loading-cartesian-designs.d.ts +6 -0
- package/dist/loading-cartesian-designs.js +123 -0
- package/dist/loading-motion.d.ts +37 -0
- package/dist/loading-motion.js +88 -0
- package/dist/loading-polar-designs.d.ts +6 -0
- package/dist/loading-polar-designs.js +95 -0
- package/dist/loading-skeleton.d.ts +29 -0
- package/dist/loading-skeleton.js +143 -0
- package/dist/loading-standalone-designs.d.ts +5 -0
- package/dist/loading-standalone-designs.js +126 -0
- package/dist/percent-stack.d.ts +18 -0
- package/dist/percent-stack.js +33 -0
- package/dist/pie-chart.d.ts +7 -3
- package/dist/pie-chart.js +37 -6
- package/dist/pie-pin-identity.d.ts +4 -0
- package/dist/pie-pin-identity.js +10 -0
- package/dist/pie-series.d.ts +4 -0
- package/dist/pie-series.js +137 -14
- package/dist/pie-tooltip-pin.d.ts +4 -0
- package/dist/pie-tooltip-pin.js +52 -0
- package/dist/point-marker.d.ts +19 -0
- package/dist/point-marker.js +19 -0
- package/dist/polar-chart.d.ts +14 -5
- package/dist/polar-chart.js +41 -10
- package/dist/polar-series.js +68 -22
- package/dist/radar-interaction.js +10 -4
- package/dist/radial-category.d.ts +2 -0
- package/dist/reveal-clip.d.ts +16 -0
- package/dist/reveal-clip.js +18 -0
- package/dist/root.d.ts +5 -9
- package/dist/root.js +46 -11
- package/dist/sankey-chart.d.ts +5 -1
- package/dist/sankey-chart.js +64 -13
- package/dist/sankey-colors.d.ts +3 -0
- package/dist/sankey-interaction.d.ts +8 -0
- package/dist/sankey-interaction.js +32 -0
- package/dist/sankey-legend.d.ts +2 -1
- package/dist/sankey-legend.js +18 -3
- package/dist/sankey-node-label.d.ts +22 -0
- package/dist/sankey-node-label.js +34 -0
- package/dist/scatter-chart.d.ts +5 -3
- package/dist/scatter-chart.js +14 -4
- package/dist/scatter-series.js +5 -3
- package/dist/series-color.d.ts +10 -0
- package/dist/series-color.js +48 -0
- package/dist/series-interaction.d.ts +12 -0
- package/dist/series-interaction.js +82 -0
- package/dist/series-label.d.ts +7 -0
- package/dist/series-label.js +18 -0
- package/dist/series-paint.d.ts +8 -0
- package/dist/series-paint.js +27 -0
- package/dist/styles.css +151 -1
- package/dist/stylesheet-warning.d.ts +2 -0
- package/dist/stylesheet-warning.js +86 -0
- package/dist/tooltip-content.d.ts +8 -1
- package/dist/tooltip-content.js +15 -4
- package/dist/tooltip.d.ts +3 -1
- package/dist/tooltip.js +8 -5
- package/dist/types.d.ts +11 -2
- package/dist/waterfall-chart.d.ts +4 -0
- package/dist/waterfall-chart.js +7 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,966 +1,758 @@
|
|
|
1
1
|
# Kind UI charts
|
|
2
2
|
|
|
3
|
-
React
|
|
3
|
+
Composable React charts built on Recharts and Motion, with shared interaction,
|
|
4
|
+
controlled visibility and optional animation. Start with a complete chart, then
|
|
5
|
+
customize its parts through public components and typed props.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
[Website](https://kindui.dev/charts) ·
|
|
8
|
+
[Documentation](https://kindui.dev/charts/docs/) ·
|
|
9
|
+
[Examples](https://github.com/bhaveshchow20/kind-ui/tree/main/examples/chart) ·
|
|
10
|
+
[GitHub](https://github.com/bhaveshchow20/kind-ui)
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
npm install @kind-ui/charts react react-dom recharts motion
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Import components and types from `@kind-ui/charts` and import
|
|
12
|
-
`@kind-ui/charts/styles.css` once at the application entry. The package is ESM
|
|
13
|
-
and requires React/React DOM `^19.3.0`, Recharts `^3.10.1` and Motion `^13.4.6`.
|
|
14
|
-
Motion remains required when animation is disabled. TypeScript consumers use
|
|
15
|
-
NodeNext or Bundler resolution. Next applications need a client component
|
|
16
|
-
boundary for callbacks, refs and state. Provide an accessible name and a
|
|
17
|
-
host-owned data alternative.
|
|
18
|
-
|
|
19
|
-
See the [changelog](CHANGELOG.md) for API changes.
|
|
20
|
-
|
|
21
|
-
## Identity, layout and activity components
|
|
22
|
-
|
|
23
|
-
- `HeatmapGrid.layout` accepts `cellSize`, `gap`, `rowLabels` and `columnLabels`. Omission retains the fluid table. Visual label hiding preserves native header associations; custom content/styles can enlarge native table cells. Keep the horizontal scroll host width-constrained and import the stylesheet. This is programmatic Chromium validation, not manual screen-reader conformance.
|
|
24
|
-
- `PieSeries.categoryKey` (with explicit series data) and `RadialBarChart.categoryKey` resolve own top-level fields or typed accessors to string keys in `Root.config`. Colors follow IDs through reorder/filtering; explicit series/datum/Cell paint remains authoritative. Category filtering remains consumer-owned. `SankeyChart.nodeConfig` supplies node metadata and source/target link colors, with standalone static `SankeyLegend`; it does not create flow selection or rewrite custom SVG renderers.
|
|
25
|
-
- `ActivityRings` owns Root and accepts ordered `rings`, `config` and an accessible name. A ring has a unique config `key`, finite `value`, optional domain and native `cellProps`. Default domain is `[0, 100]`; visual progress clamps while raw values remain in tooltip payloads. `series`, `labels`, `legend`, `tooltip` and native chart geometry provide bounded overrides. Do not nest it inside Root; use explicit `RadialBarChart` composition for that case. Hosts still own data alternatives and sizing.
|
|
12
|
+
## Chart types
|
|
26
13
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
| Family | Charts |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| Cartesian | Line, Area, Bar, Combo |
|
|
17
|
+
| Polar | Pie/Donut, Radar, Radial/ActivityRings |
|
|
18
|
+
| Relationships | Scatter/Bubble, Heatmap |
|
|
19
|
+
| Distributions | Histogram, BoxPlot |
|
|
20
|
+
| Flow & change | Sankey, Waterfall |
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
import { useState } from "react";
|
|
33
|
-
import * as Chart from "@kind-ui/charts";
|
|
34
|
-
import { ResponsiveContainer, XAxis } from "@kind-ui/charts";
|
|
35
|
-
import "@kind-ui/charts/styles.css";
|
|
22
|
+
Donut and Bubble use `PieChart` and `ScatterChart` composition.
|
|
36
23
|
|
|
37
|
-
|
|
38
|
-
tasks: { label: "Tasks", color: "#3659b8", formatValue: (value) => `${value} tasks` },
|
|
39
|
-
} satisfies Chart.SeriesConfig;
|
|
24
|
+
## Install
|
|
40
25
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<Chart.Root config={config} visibleSeries={visible} onVisibleSeriesChange={setVisible}>
|
|
45
|
-
<Chart.Legend aria-label="Visible series" />
|
|
46
|
-
<ResponsiveContainer width="100%" height={240}>
|
|
47
|
-
<Chart.LineChart data={[{ day: "Mon", tasks: 0 }, { day: "Tue", tasks: null }]} accessibilityLayer aria-label="Tasks by day">
|
|
48
|
-
<XAxis dataKey="day" />
|
|
49
|
-
<Chart.LineSeries dataKey="tasks" connectNulls={false} />
|
|
50
|
-
<Chart.Tooltip />
|
|
51
|
-
</Chart.LineChart>
|
|
52
|
-
</ResponsiveContainer>
|
|
53
|
-
</Chart.Root>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
26
|
+
```sh
|
|
27
|
+
npm install @kind-ui/charts
|
|
56
28
|
```
|
|
57
29
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
30
|
+
Import `@kind-ui/charts/styles.css` once at your application entry. In Next.js,
|
|
31
|
+
import it in the root layout and place interactive chart code in a client component.
|
|
32
|
+
Development builds warn once per document if mounted chart roots lack the stylesheet,
|
|
33
|
+
after the document and pending stylesheets load. The warning does not run during SSR
|
|
34
|
+
or in production. Keep the import in copied examples.
|
|
61
35
|
|
|
62
|
-
|
|
36
|
+
CSS remains explicit: importing it from the ESM entry would break plain Node imports;
|
|
37
|
+
runtime injection would change CSS layer ordering and require inline-style CSP permission.
|
|
38
|
+
No styles are injected or fetched. Core styles and tokens remain in the stylesheet;
|
|
39
|
+
consumer overrides still win. If you intentionally replace all chart styles, set
|
|
40
|
+
`--kind-ui-styles-loaded: 1` on your chart roots to acknowledge that setup.
|
|
41
|
+
The diagnostic conservatively waits on unresolved stylesheet links. A link which
|
|
42
|
+
failed before mounting after document load can therefore defer the warning; it
|
|
43
|
+
does not guess a timeout and warn while a slow stylesheet is still loading.
|
|
63
44
|
|
|
64
|
-
|
|
65
|
-
| --- | --- |
|
|
66
|
-
| Axes, grids and sizing | `XAxis`, `YAxis`, `ZAxis`, `CartesianGrid`, `PolarAngleAxis`, `PolarRadiusAxis`, `PolarGrid`, `ResponsiveContainer` |
|
|
67
|
-
| Labels and series composition | `Label`, `LabelList`, `Cell`, `BarStack` |
|
|
68
|
-
| Reference marks and range selection | `ReferenceLine`, `ReferenceDot`, `ReferenceArea`, `Brush`, `ErrorBar` |
|
|
69
|
-
| Custom shapes | `Dot`, `Curve`, `Rectangle`, `Sector`, `Polygon`, `Symbols`, `AreaRevealShape`, `LineDrawShape` |
|
|
45
|
+
## Series labels
|
|
70
46
|
|
|
71
|
-
|
|
47
|
+
Configuration keys must match the series `dataKey` (or its explicit `seriesKey`).
|
|
48
|
+
When `label` is omitted, built-in labels use the matching key: `visitors` becomes
|
|
49
|
+
`Visitors` and `monthlyVisitors` becomes `Monthly visitors`. Camel-case and acronym
|
|
50
|
+
boundaries, underscores and hyphens become spaces; words are lowercased, then the
|
|
51
|
+
first letter is capitalized. Supply an explicit label to preserve custom casing
|
|
52
|
+
or wording, including an intentionally empty label. Keys and colors are unchanged.
|
|
53
|
+
Category charts use their configured category identity for this inference.
|
|
72
54
|
|
|
73
|
-
|
|
55
|
+
## Quick start
|
|
74
56
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
For Next, import the package from a client component when supplying callbacks, accessors, refs or stateful content. The packed entry retains `"use client"`; consolidation does not make function props serializable across a server boundary. Charts still need an accessible name and a host-owned data alternative; native SSR can render an empty chart wrapper before client layout.
|
|
78
|
-
|
|
79
|
-
## Configured Line Component
|
|
80
|
-
|
|
81
|
-
Passing `config` opts the existing `LineChart` into package-owned composition. Provide `data`, `config` and an accessible name (`aria-label` or `aria-labelledby`); add `xDataKey` when generating parts and omit it when supplying explicit children. Do not add a surrounding `Root`.
|
|
57
|
+
Configured `LineChart` supplies responsive sizing, axes, series, tooltip and
|
|
58
|
+
legend. Give the chart an accessible name and include a data alternative:
|
|
82
59
|
|
|
83
60
|
```tsx
|
|
61
|
+
"use client";
|
|
62
|
+
|
|
84
63
|
import { LineChart, type SeriesConfig } from "@kind-ui/charts";
|
|
85
64
|
import "@kind-ui/charts/styles.css";
|
|
86
65
|
|
|
66
|
+
const data = [
|
|
67
|
+
{ day: "Mon", tasks: 0 },
|
|
68
|
+
{ day: "Tue", tasks: 12 },
|
|
69
|
+
{ day: "Wed", tasks: 8 },
|
|
70
|
+
];
|
|
87
71
|
const config = {
|
|
88
72
|
tasks: { label: "Tasks", color: "#3659b8" },
|
|
89
73
|
} satisfies SeriesConfig;
|
|
90
74
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
For legacy composition without `config`, render `LineChart` inside `Root`, and `LineSeries`/`Tooltip` inside `LineChart`. Engine children such as `XAxis`, `YAxis`, `CartesianGrid`, `ReferenceLine`, `LabelList` and `ErrorBar` keep their native composition path. There is no prescribed data schema, card or layout. The wrappers render registered Recharts components, rather than inspecting child display names or wrapping native composition parts.
|
|
114
|
-
|
|
115
|
-
- `LineChart`: native Recharts chart props and SVG ref. Kind composes `onMouseMove`/`onMouseLeave` with its own pointer tracking and captures focus/keyboard changes without replacing Root handlers. The ref targets `SVGSVGElement`, including React 19 callback cleanup. The internal frame uses `display: contents` so sizing stays with the engine or `ResponsiveContainer`.
|
|
116
|
-
- `LineSeries`: native `Line` props/children/custom `dot`, `activeDot`, `shape` and handlers. Motion owns animation, so `isAnimationActive` is excluded and Recharts animation is always disabled. `stroke` defaults to Root's color. A Root-hidden series stays hidden even with `hide={false}`; `hide={true}` additionally hides a series. String `dataKey` is the default metadata identity. Use `seriesKey` for function/numeric data keys, required with controlled visibility. Native tooltip payloads remain unchanged; Kind's default content resolves registered identities for metadata and filtering. Recharts Line has no public component ref in 3.10.1: use refs on your custom mark/shape nodes, retaining the engine shape's `pathRef` where needed.
|
|
117
|
-
- `Tooltip`: native selection/formatting/cursor/trigger/style props and element/function `content`, plus `maxWidth` (180 by default), native `frameProps` and a ref to the measured div. Kind owns `position`, `isAnimationActive`, the chart portal and bounds/translation options (`allowEscapeViewBox`, `reverseDirection`, `useTranslate3d`); those props are excluded. `offset` is honored as a number or x/y pair, defaulting to 12. It measures width and height with ResizeObserver, follows the pointer, and uses the engine coordinate after keyboard interaction. Oversized content gets chart-sized width/height limits and scrolling. Frame styles/classes may customize presentation; overriding sizing, margins or transforms can change bounds. A custom content component receives native engine props and owns its accessible feedback. Defaults are `cursor={false}`, `filterNull={false}` and `TooltipContent`.
|
|
118
|
-
|
|
119
|
-
Custom shape/content functions should be stable component types defined outside render when they retain state. Engine `wrapperStyle`, axes, IDs and native refs keep their upstream semantics. Custom tooltip portals/anchors can instead use a native Recharts Tooltip; it can share Root's `TooltipContent` metadata.
|
|
120
|
-
|
|
121
|
-
## Line animation
|
|
122
|
-
|
|
123
|
-
Import the same components from `@kind-ui/charts` in every mode. `LineChart` accepts `animate`, defaulting to `false` in legacy Root + LineChart composition and `true` in configured mode: `false` renders immediately, `true` enables defaults, and a `LineAnimation` object enables animation with overrides. It exposes `revealDurationMs` (1000 by default), Motion `revealEasing` and `hoverTransition` (spring by default). Import the stylesheet for shared SVG reveal clipping:
|
|
124
|
-
|
|
125
|
-
```tsx
|
|
126
|
-
import { Root, LineChart, LineSeries, Tooltip } from "@kind-ui/charts";
|
|
127
|
-
import { XAxis } from "@kind-ui/charts";
|
|
128
|
-
import "@kind-ui/charts/styles.css";
|
|
129
|
-
|
|
130
|
-
<Root config={{ count: { label: "Count", color: "#345" } }}>
|
|
131
|
-
<LineChart width={400} height={220} data={points}
|
|
132
|
-
animate={{ revealDurationMs: 900, revealEasing: "easeOut", hoverTransition: { duration: 0.2 } }}>
|
|
133
|
-
<XAxis dataKey="day" />
|
|
134
|
-
<LineSeries dataKey="count" />
|
|
135
|
-
<Tooltip />
|
|
136
|
-
</LineChart>
|
|
137
|
-
</Root>
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
Motion is a required peer, including when `animate={false}`. This prop controls behavior; it does not remove Motion installation or bundle bytes. We use synchronous `motion/react` imports to keep component identities and customization stable across modes, without asynchronous loading/error states. Motion's [LazyMotion](https://motion.dev/docs/react-lazy-motion) can defer features, but that is a separate loading/bundle strategy, not a consequence of disabling animation. Use root imports with `animate` and `LineAnimation`; there is no `/motion` entry.
|
|
141
|
-
|
|
142
|
-
The single-prop mode follows the familiar behavioral toggle in [Nivo](https://nivo.rocks/line/); [EvilCharts](https://evilcharts.com/docs/recharts/line-chart/static) also exposes a disabled intro mode. These are API references, not reused implementations or additional renderers. Recharts still owns geometry and selection. Motion owns one chart-space clip for all line strokes and resting dots, the default active marker and tooltip translation. Engine animation is forced off and excluded from `LineSeriesProps`. Custom marks/shapes/content retain consumer ownership; custom active dots replace the default animated mark. Arbitrary path morphing and animation of axes are outside this contract.
|
|
143
|
-
|
|
144
|
-
The package subscribes reactively to reduced motion and starts disabled during server rendering. Reduced motion or explicit off snaps in-flight hover targets immediately. Focus, keyboard or pointer interaction finishes entrance; chart or per-series data/visibility identity, effective series visibility (including native `hide`), or measured size changes also cancel entrance, discard stale pointer pixels and snap existing hover targets. Hover motion resumes on the next pointer/keyboard input. Ordinary hover retargets the same mounted marks and tooltip. Entrance does not replay after interaction/update; remount to request a fresh entrance. Palette changes preserve chart state. Controlled Root visibility fades each line curve and resting dots over 180ms without replaying entrance or replacing the chart. Rapid reversals retarget the current opacity; hidden series leave tooltip content and pointer interaction immediately. Completion also invalidates geometry after an automatic-domain update. Off/reduced-motion modes snap visibility. Native `hide`, independently portaled labels/error bars and custom active marks retain native behavior. Keep an all-hidden message outside the mounted chart to preserve its interaction state. The clip requires the stylesheet; pointer/keyboard state and tooltip measurement work without it.
|
|
145
|
-
|
|
146
|
-
## Line materials
|
|
147
|
-
|
|
148
|
-
The existing `/recipes.html` line showcase has a compact Plain/Paper/Clay/Glow selector alongside palette and Motion controls. It applies this public API to all eight existing recipes while retaining their data, markers, labels and visibility.
|
|
149
|
-
|
|
150
|
-
`LineSeries material="plain" | "paper" | "clay" | "glow"` changes the default SVG curve's surface independently of color and animation. The exported `LineMaterial` type names these options. Plain is the existing default. Paper adds static fine fiber variation inside the ink stroke (2.5px by default); Clay adds a rounded, softly lit bevel, inner shade and a small neutral cast shadow (6px by default). Glow adds close and soft series-colored halos around a crisp 3px stroke, with a narrow neutral light core. All materials retain the engine's original quantitative path: no displacement, rough geometry or path morphing. Thin Clay strokes show less relief; use `strokeWidth` to choose thickness explicitly. Material defaults use round joins and solid-line caps; dashed lines use butt caps to keep their gaps visible. Native `strokeLinecap`, `strokeLinejoin`, dash patterns and handlers remain available.
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
<Root config={{ count: { label: "Count", color: "var(--color-count-ink)" } }}>
|
|
154
|
-
<LineChart width={400} height={220} data={points} animate={false}>
|
|
155
|
-
<LineSeries dataKey="count" material="clay" strokeWidth={5} dot={false} />
|
|
156
|
-
<Tooltip />
|
|
157
|
-
</LineChart>
|
|
158
|
-
</Root>
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Keep colors in `SeriesConfig`, CSS variables or an explicit `stroke`. For Tailwind CSS 4, for example, define `@theme { --color-count-ink: #8b5040; }` in the host stylesheet. A material does not choose a palette or theme surrounding UI. Legend/tooltip indicators still represent the series' unlit color; when setting a different explicit `stroke`, keep the config color consistent if indicators should match it.
|
|
162
|
-
|
|
163
|
-
| CSS variable (inherit from Root or host) | Default | Purpose |
|
|
164
|
-
| --- | --- | --- |
|
|
165
|
-
| `--kind-ui-line-paper-fiber` | `#fff` | Fiber tint, composited inside the ink |
|
|
166
|
-
| `--kind-ui-line-paper-grain` | `0.38` | Fiber opacity, use a number from 0 to 1 |
|
|
167
|
-
| `--kind-ui-line-clay-light` | `#fff` | Neutral bevel light |
|
|
168
|
-
| `--kind-ui-line-clay-shade` | `#17212b` | Neutral inner and cast shade |
|
|
169
|
-
| `--kind-ui-line-glow-light` | `#fff` | Narrow luminous core tint |
|
|
170
|
-
| `--kind-ui-line-glow-opacity` | `0.5` | Close and outer halo opacity, use a number from 0 to 1 |
|
|
171
|
-
|
|
172
|
-
These tokens work in plain CSS and Tailwind arbitrary properties, such as `[--kind-ui-line-paper-grain:0.2]` on Root. Existing component tokens independently style the restrained legend and tooltip. The defaults are original SVG compositions; [PaperCSS](https://www.getpapercss.com/) and [clay.css](https://github.com/codeAdrian/clay.css) are visual references for HTML surfaces, not dependencies or copied code. SVG [specular lighting](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feSpecularLighting) supplies Clay's bevel; [Tailwind theme variables](https://tailwindcss.com/docs/theme) can supply host colors.
|
|
173
|
-
|
|
174
|
-
Materials apply only to the default line shape. An explicit native `shape` or `filter` takes precedence, disables built-in material rendering and retains consumer ownership. Dots, active marks, error bars, axes, labels, tooltip content and legends keep their existing rendering; custom shapes need their own surface treatment. The filtered curve retains the engine pathRef and plot clipping, and Motion still controls the shared reveal clip and hover motion. Off/reduced-motion modes keep static materials. Hidden series allocate no rendered filters after their visibility exit completes. Each mounted series has its own filter ID independent of a supplied Line ID; separately mounted React roots should use React's `identifierPrefix` to avoid document-wide ID collisions.
|
|
175
|
-
|
|
176
|
-
Only curves are filtered, with bounds padded by half the numeric `strokeWidth` plus 6 SVG units (a 12-unit width allowance for nonnumeric widths). Set a numeric `strokeWidth` for unusually wide strokes instead of overriding it only in CSS. Bounds use engine point extents, so custom curve interpolation that overshoots those extents may require a consumer shape/filter. Paper uses one static turbulence octave; Clay uses alpha blur and lighting; Glow uses two small static painted-stroke blurs and a light core composited inside the original stroke. No filter time animation, shader engine, additional dependency or canvas-wide filter is introduced. Filters add browser raster work proportional to each curve's bounding rectangle; many long overlapping series can be costly. Plain avoids this work. Current visual/interaction evidence covers Chromium, including narrow, flat and colored lines; other browsers, print/export renderers and dark host surfaces need their own verification.
|
|
177
|
-
|
|
178
|
-
## Contracts
|
|
179
|
-
|
|
180
|
-
- `SeriesConfig`: a record keyed by a string `dataKey` or explicit `seriesKey`. Each entry has a string `label`, CSS `color`, optional `formatValue(value)` returning React content, optional decorative `icon: ComponentType`, and optional legend-only `legendShape` (see Scatter below). Built-in legend and tooltip content render the icon inside an aria-hidden wrapper; keep visible string labels meaningful. Keys start with a letter and contain letters, numbers, underscores, or hyphens. No data normalization or scales are introduced.
|
|
181
|
-
- `Root`: scopes config and `--color-{key}` CSS variables. It forwards native div props/ref. The default stylesheet provides full width with `min-width: 0`. Set chart height explicitly through the underlying chart or `ResponsiveContainer`. Nested or adjacent containers keep separate metadata and colors.
|
|
182
|
-
- `visibleSeries` is optional and consumer-owned. A callback requires this value; the legend requests the next array but never changes it itself. `LineSeries` applies this visibility automatically; keep native engine marks' `hide` props in sync when using them directly. Omit the callback for a static legend. An empty array means all series are hidden; the example owns that empty-state message.
|
|
183
|
-
- `Legend`: renders a native list; with a callback, it renders native toggle buttons with `aria-pressed`. It forwards ul props/ref. Space/Enter work through normal button behavior; focus stays on the button. Style its root with `className`/`style`, or set `--chart-legend-background` on buttons. Marker priority is configured `icon`, then explicit `legendShape`, then the existing square color swatch. `hideIcon` bypasses both icon and shape and restores that square swatch. Optional `children={({ key, label, visible, marker }) => ...}` owns each item's final content inside the existing list item and button/static span; it may reuse or replace `marker`. Include meaningful label text; return noninteractive content only (no buttons, links, inputs, tab stops or click handlers). Kind retains the controlled toggle and keyboard ownership. Use a separate host legend when you need different interaction semantics.
|
|
184
|
-
- `TooltipContent`: pass the upstream callback's props as `tooltip`. Native div props/ref, classes, and style remain separate and are forwarded. Upstream `formatter`, per-entry formatter, and `labelFormatter` work; per-entry formatters take precedence over the upstream formatter, which takes precedence over the config formatter. An upstream formatter returning null/undefined suppresses that entry. Formatters run for zero but not null/undefined; those display `missingValue` (default “No data”) alongside other available values. Inactive, empty, or entirely missing visible payloads render no tooltip; zero remains valid data. `hideLabel` omits the heading and its formatter, retaining series names/values and the live region. `indicator="dot" | "line" | "dashed"` changes the color marker; the default remains the existing slim `line`. Configured icons take precedence over marker choices; `hideIndicator` hides all decorative tooltip markers, including icons. These are content props: pass them to `TooltipContent` through the native `content` callback. Custom content keeps native formatter/content ownership and receives no injected presentation options.
|
|
185
|
-
- `Tooltip` and `TooltipContent` accept optional `itemKey(entry)` to resolve metadata/visibility identity before registered series keys or native dataKey/name. Pass the same resolver to both when composing content for categories such as pie slices. Keep category IDs stable; `labelFormatter` owns heading presentation independently. This avoids adding a second nameKey/labelKey identity convention.
|
|
186
|
-
- `valueAnimation="shuffle"` optionally rolls numeric tooltip digits vertically, matching a calendar's changing hover values. It is off by default and independent of chart entrance/position animation. `Tooltip` forwards it only to its built-in content; `TooltipContent`, `ScatterTooltip`, `ScatterTooltipContent`, and `HeatmapTooltip` accept the same prop. Finite numeric raw values with string/number formatted output are eligible; missing/nonfinite values, arrays, numeric strings and arbitrary React nodes retain their existing rendering. Non-ASCII digits and bidi strings fall back to plain text. Exact final formatter output is immediately accessible; decorative reels are hidden from assistive technology. Reduced motion (including changes during a transition) uses plain final text. Rapid updates stop and retarget the current reel, and leaving/unmounting cancels it. Repeated identical digits do not restart. The value retains its widest measured width during a visible session and smoothly grows for wider values; this avoids shrinking as digit counts change. Import the existing default stylesheet for the reel's clipping/layout.
|
|
187
|
-
|
|
188
|
-
```tsx
|
|
189
|
-
<Chart.Tooltip valueAnimation="shuffle" />
|
|
190
|
-
<Chart.ScatterTooltip valueAnimation="shuffle" />
|
|
191
|
-
// The independent categorical-grid/calendar tooltip uses the same opt-in.
|
|
192
|
-
<Chart.HeatmapChart rows={days} columns={weeks} data={activity} scale={scale}
|
|
193
|
-
formatValue={(value) => `${value} commits`}>
|
|
194
|
-
<Chart.HeatmapGrid caption="Activity by day" />
|
|
195
|
-
<Chart.HeatmapTooltip valueAnimation="shuffle" />
|
|
196
|
-
</Chart.HeatmapChart>
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
Custom `Tooltip.content` and Heatmap `Content` remain fully consumer-owned and receive no injected animation prop. Compose `<TooltipContent tooltip={props} valueAnimation="shuffle" />` or `<ScatterTooltipContent ... />` explicitly if desired. Native/custom-owned Sankey tooltips, chart labels, legends and data tables are outside this optional behavior. The public-only calendar/line/Scatter preview is in `tests/fixtures/number-shuffle`; the package gate builds it from the installed tarball, with focused browser coverage in `tests/number-shuffle.spec.ts`.
|
|
200
|
-
- Tooltip entries marked hidden or `type: "none"` are excluded, as are consumer-hidden series. Use `filterNull={false}` on the upstream Tooltip when missing values should appear. Unknown keys fall back to upstream names/colors/values. No tooltip payload is mutated.
|
|
201
|
-
- Keyboard positioning, Escape/blur dismissal, focus and live-region orchestration remain with the upstream chart/Tooltip. Content supplies its default `role="status"` and live-region attributes when the upstream accessibility layer is enabled. Preserve equivalent feedback when overriding these attributes.
|
|
202
|
-
|
|
203
|
-
Provide a named chart, keyboard instructions and a semantic data alternative appropriate to your application. The data alternative stays application-owned and should preserve hidden series in its table. Browser tests are evidence for this example, not a screen-reader compatibility or WCAG claim. No cross-framework or SSR/hydration support claim is made yet.
|
|
204
|
-
|
|
205
|
-
Consumer checks use `strict: true` with `skipLibCheck: false` in NodeNext and Bundler modes. Adding `exactOptionalPropertyTypes: true` with full dependency checking currently fails in upstream declarations, even without importing Kind UI; that stricter combination is not claimed yet.
|
|
206
|
-
|
|
207
|
-
The usage example has black monochrome and color palettes, a compact Tailwind CSS 4 layout, and a self-hosted Latin Geist font. Its series use solid/circle and dashed/diamond marks, so color is not the only distinction. Switching palettes preserves chart state. The font's OFL license is included with the example. Component defaults use host `border`, `radius`, `popover` and `popover-foreground` variables when present, with native CSS fallbacks. Tailwind and the font are example tooling, not runtime dependencies or required styling choices for package consumers.
|
|
208
|
-
|
|
209
|
-
## Styling
|
|
210
|
-
|
|
211
|
-
Import `@kind-ui/charts/styles.css` once for the default appearance. The JavaScript entry does not import CSS, so Node consumers can still import the components directly. The stylesheet contains only scoped component rules in the `kind-ui` cascade layer; it adds no page reset, theme or font. Omitting it leaves presentation to the host. All component defaults ship in this one CSS asset.
|
|
212
|
-
|
|
213
|
-
For plain CSS, import the stylesheet before your application stylesheet. Normal unlayered application rules override its layered defaults. With Tailwind CSS 4, declare the order before both imports in your application CSS:
|
|
214
|
-
|
|
215
|
-
```css
|
|
216
|
-
@layer theme, base, kind-ui, components, utilities;
|
|
217
|
-
@import "tailwindcss";
|
|
218
|
-
@import "@kind-ui/charts/styles.css";
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
This order lets normal utility classes override component defaults without `!important`. Low selector specificity alone cannot override an incorrectly ordered cascade layer. Native `style` props on `Root`, `Legend` and `TooltipContent` still take precedence over normal stylesheet rules.
|
|
222
|
-
|
|
223
|
-
Theme the components with `--kind-ui-chart-border`, `--kind-ui-chart-radius`, `--kind-ui-chart-popover`, `--kind-ui-chart-popover-foreground` and `--kind-ui-chart-legend-background`. They fall back to the existing host tokens; `--chart-legend-background` remains supported. Fixed layout/spacing values can be overridden through classes or CSS rather than a variable for every declaration.
|
|
224
|
-
|
|
225
|
-
Default legends use 8px markers and 11px labels; interactive legend buttons retain native semantics with a minimum 28px height. Hidden legend buttons use readable muted text and markers with no strikethrough, preserving `aria-pressed`. The default tooltip uses compact 12px text, slim series markers, aligned tabular values and measured content width capped by `maxWidth` (180px by default). Host metadata owns concise labels and units; formatter and custom content overrides remain supported. Override the scoped styles or theme tokens as needed. `Tooltip` supplies mouse-following placement with measured boundary clamping and keyboard fallback. A guide is independent of tooltip content: use `<Tooltip cursor={{ stroke: "var(--muted-foreground)", strokeDasharray: "2 4", strokeWidth: 1 }} />` for a dotted hover line or `cursor={false}` (the default) to hide only the guide. The existing recipes demonstrate this with a Hover guide toggle.
|
|
226
|
-
|
|
227
|
-
Stable `data-kind-ui` hooks are `chart`, `chart-legend`, `chart-legend-item`, `chart-legend-button`, `chart-indicator`, `chart-tooltip`, `chart-tooltip-label`, `chart-tooltip-list`, `chart-tooltip-item` and `chart-tooltip-value`. Decorative configured glyph wrappers expose `chart-icon`; color markers expose `data-indicator` in tooltips. Line components additionally expose `line-frame`, `tooltip-frame`, `tooltip-motion` and `active-marker`. Legend and tooltip items also expose `data-series` with their series key. Use that identity for series-specific styles instead of positional selectors; tooltip entries may be reordered or hidden. Interactive legend buttons retain `aria-pressed` for state styling. For example:
|
|
228
|
-
|
|
229
|
-
```css
|
|
230
|
-
.my-chart [data-series="tasks"] [data-kind-ui="chart-indicator"] {
|
|
231
|
-
border-radius: 50%;
|
|
75
|
+
export function TasksChart() {
|
|
76
|
+
return (
|
|
77
|
+
<section>
|
|
78
|
+
<LineChart
|
|
79
|
+
data={data}
|
|
80
|
+
config={config}
|
|
81
|
+
xDataKey="day"
|
|
82
|
+
aria-label="Tasks by day"
|
|
83
|
+
/>
|
|
84
|
+
<table>
|
|
85
|
+
<caption>Tasks by day</caption>
|
|
86
|
+
<thead>
|
|
87
|
+
<tr><th scope="col">Day</th><th scope="col">Tasks</th></tr>
|
|
88
|
+
</thead>
|
|
89
|
+
<tbody>
|
|
90
|
+
{data.map(({ day, tasks }) => (
|
|
91
|
+
<tr key={day}><th scope="row">{day}</th><td>{tasks}</td></tr>
|
|
92
|
+
))}
|
|
93
|
+
</tbody>
|
|
94
|
+
</table>
|
|
95
|
+
</section>
|
|
96
|
+
);
|
|
232
97
|
}
|
|
233
98
|
```
|
|
234
99
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
At the repository root: `npm ci`, then `npm exec playwright install -- --with-deps chromium` (Linux dependencies may need administrator permission). Run `npm run dev:chart` for the example, or `npm run check` for library, packed-consumer, type and browser checks.
|
|
240
|
-
|
|
241
|
-
The pack lifecycle rebuilds from clean output and rejects missing runtime modules, declarations, CSS or documentation. Recipe links below use the repository recipe pages so they remain available outside the repository. The packed check creates an actual tarball, installs it and the pinned peer/type dependencies into an isolated consumer, then checks public APIs with NodeNext and Bundler resolution. With the required Motion peer installed, it checks root imports/declarations and builds disabled and animated line/area consumers using the same exports; it also proves the removed `/motion` path cannot resolve. The bar consumer and a combined area/bar consumer use the same tarball and strict resolution checks. The combined browser proof checks native geometry, unique material filter IDs and independent visibility when both families share a page. These fixtures contain only public package imports and host data/extensions; no example implementation is copied into the proof. Migrated area and bar host recipes are typechecked separately. It also builds a plain-CSS production consumer for the browser checks, verifying CSS delivery and application overrides. Peer installation can require npm registry access; the package under test always comes from the local tarball, never a workspace link or registry copy.
|
|
242
|
-
|
|
243
|
-
## Area ownership and API
|
|
244
|
-
|
|
245
|
-
`AreaChart` and `AreaSeries` use the same Root, Legend and Tooltip exports as lines. Recharts owns area geometry, native interpolation (`monotone`, `linear`, `stepAfter`), baseline (`baseValue`), stacking (`stackId`) and normalization (`stackOffset="expand"`). Kind owns registered metadata, Root-controlled visibility, bounded pointer/keyboard tooltip placement, and Motion reveal/default active marks. Hosts own labels, axes, data, formatting, gradients and reference thresholds.
|
|
246
|
-
|
|
247
|
-
`AreaChart` accepts native Recharts AreaChart props, SVG ref, caller handlers and `animate={false | true | AreaAnimation}`. AreaAnimation has the same fields and defaults as LineAnimation. Data, size, controlled visibility and native `hide` changes discard stale pointer coordinates, cancel entrance and snap owned hover motion. Reduced-motion preference changes disable owned animation. Custom marks/content remain mounted when animation changes.
|
|
248
|
-
|
|
249
|
-
`AreaSeries<DataPoint, Value>` accepts native Area props and children except `isAnimationActive`; Recharts animation is always disabled. String data keys identify Root metadata automatically. Use `seriesKey` for numeric/function keys; it is required for controlled visibility. Native `hide={true}` and Root visibility both apply. Stroke and fill default to Root color; explicit native overrides win. Custom `dot`, `activeDot`, `shape`, handlers and nested LabelList retain native composition. Recharts Area has no public component ref; place refs on host marks or shapes.
|
|
250
|
-
|
|
251
|
-
```tsx
|
|
252
|
-
<Chart.Root config={{ visits: { label: "Visits", color: "#3659b8" } }}>
|
|
253
|
-
<Chart.AreaChart width={400} height={220} data={points} animate={true} accessibilityLayer aria-label="Visits">
|
|
254
|
-
<XAxis dataKey="day" />
|
|
255
|
-
<Chart.AreaSeries dataKey="visits" type="monotone" connectNulls={false} fillOpacity={0.2} />
|
|
256
|
-
<Chart.Tooltip />
|
|
257
|
-
</Chart.AreaChart>
|
|
258
|
-
</Chart.Root>
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
Missing/null values remain gaps by default; numeric zero remains data. Hosts may explicitly choose `connectNulls`. The eight migrated area recipes are host compositions of these exports. Stacked/percent recipe examples use complete nonnegative inputs; percent axis labels and tooltip formatting belong to the host, use visible payload totals, and show “No share” for an all-zero row. The package does not impute, validate or mutate stack data.
|
|
262
|
-
|
|
263
|
-
Implementation references: [Recharts AreaChart](https://recharts.github.io/en-US/api/AreaChart/), [Recharts Area](https://recharts.github.io/en-US/api/Area/) and [Motion values](https://motion.dev/docs/react-motion-value).
|
|
100
|
+
Use the [Line guide](https://kindui.dev/charts/docs/components/line/)
|
|
101
|
+
for composition and customization. The documentation covers chart selection,
|
|
102
|
+
peer requirements, styling, motion and accessibility; applications own their
|
|
103
|
+
data, domains and business state.
|
|
264
104
|
|
|
265
|
-
###
|
|
105
|
+
### Loading chart data
|
|
266
106
|
|
|
267
|
-
|
|
107
|
+
All chart families accept `loading?: boolean` alongside `animate`, plus
|
|
108
|
+
`loadingLabel?: string` (default “Loading chart”). Import the default stylesheet.
|
|
268
109
|
|
|
269
110
|
```tsx
|
|
270
|
-
<
|
|
271
|
-
|
|
272
|
-
|
|
111
|
+
<LineChart
|
|
112
|
+
config={config}
|
|
113
|
+
data={rows}
|
|
114
|
+
xDataKey="month"
|
|
115
|
+
height={280}
|
|
116
|
+
aria-label="Monthly sales"
|
|
117
|
+
animate={{ revealDurationMs: 650 }}
|
|
118
|
+
loading={pending}
|
|
119
|
+
loadingLabel="Loading monthly sales"
|
|
120
|
+
/>
|
|
273
121
|
```
|
|
274
122
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
123
|
+
Pass the same props directly to composed chart roots inside the existing `Root`
|
|
124
|
+
and native sizing/composition. Supported families: Line, Area, Bar, Combo, Pie,
|
|
125
|
+
Radar, RadialBar, Scatter, Heatmap, Waterfall, Histogram, BoxPlot, ActivityRings
|
|
126
|
+
and Sankey. Each uses its own decorative chart silhouette independent of your data.
|
|
127
|
+
Pulse-based skeletons choose a clearly different bounded profile while fully hidden;
|
|
128
|
+
their geometry stays stable through renders and resize between pulses. A soft leading reveal and
|
|
129
|
+
trailing fade overlap, following the chart’s native entrance duration, easing and
|
|
130
|
+
direction: horizontal paths and left-to-right bar-family windows, angular sectors,
|
|
131
|
+
ordered point/cell opacity or directional flow. Radar keeps two six-vertex polygons
|
|
132
|
+
visible and smoothly morphs between bounded decorative shapes; reduced motion
|
|
133
|
+
holds both still. RadialBar keeps continuous angular velocity through its closing seam. Combo preserves separate family
|
|
134
|
+
reveal options. Pulse timing includes room for the trail to leave and a hidden
|
|
135
|
+
geometry swap; loading never delays actual completion.
|
|
136
|
+
Reduced motion displays a static silhouette.
|
|
137
|
+
|
|
138
|
+
Actual chart content remains mounted, sized, hidden and inert while pending.
|
|
139
|
+
The chart exposes `aria-busy` and a separate live status. Native axes, series,
|
|
140
|
+
refs, style and event ownership stay with the consumer. External legends remain
|
|
141
|
+
available. Heatmap uses its table viewport; Sankey uses its native flow container;
|
|
142
|
+
polar illustrations retain circular proportions. Skeletons have no values,
|
|
143
|
+
labels or tooltip targets.
|
|
144
|
+
|
|
145
|
+
Completion immediately restores actual data and rearms the family’s existing
|
|
146
|
+
entrance when `animate` enables it. There is no forced wait or queued completion.
|
|
147
|
+
Empty data does not imply loading: render an explicit empty-result message after
|
|
148
|
+
completion. Loading does not change validation of supplied chart data. Requests,
|
|
149
|
+
cancellation, retries, partial results, errors and portals outside the native
|
|
150
|
+
chart remain host-owned. Supply an accessible data alternative alongside charts.
|
|
151
|
+
|
|
152
|
+
Run `npm run dev:chart` and open `/loading.html` for all-family replay, load,
|
|
153
|
+
empty-input, resize and interrupted-update controls.
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
## Selective Pie glow
|
|
157
|
+
|
|
158
|
+
`PieSeries` accepts `glowCategories?: readonly string[]` with `categoryKey` and
|
|
159
|
+
explicit data. For a rounded donut, add `glowCategories={["design"]}` to
|
|
160
|
+
`<PieSeries data={data} dataKey="hours" categoryKey="key" nameKey="key"
|
|
161
|
+
innerRadius={58} outerRadius={108} cornerRadius={8} paddingAngle={2} />`.
|
|
162
|
+
The IDs resolve through the existing category config contract. Unknown or removed
|
|
163
|
+
IDs do nothing; reorder/filter preserve colors and membership. Selected default
|
|
164
|
+
sectors use glow; others retain `material` (default plain). Native custom paint,
|
|
165
|
+
shapes and handlers retain ownership. Keep labels and a data alternative.
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
[MIT](LICENSE) © 2026 Bhavesh Chowdhury.
|
|
170
|
+
|
|
171
|
+
### Patterned bar fills
|
|
172
|
+
|
|
173
|
+
`FillPattern` is static SVG paint independent of `material`: `{ kind: "hatch" | "stripe" | "duotone", color?, size?, width?, angle? }`. `size` is a positive SVG-unit tile size (8 by default); `width` is positive and at most `size` (1 for hatch, 2 for stripe). `angle` defaults to 45 degrees for hatch and 0 otherwise. Duotone divides the tile equally between the series color and second ink; width does not affect its split.
|
|
280
174
|
|
|
281
175
|
```tsx
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
<Root config={
|
|
287
|
-
<
|
|
288
|
-
|
|
176
|
+
const config = {
|
|
177
|
+
actual: { color: "#789abc", pattern: { kind: "hatch" as const } },
|
|
178
|
+
planned: { color: "#ed79ae", pattern: { kind: "stripe" as const } },
|
|
179
|
+
};
|
|
180
|
+
<Root config={config}>
|
|
181
|
+
<Legend />
|
|
182
|
+
<BarChart data={rows} width={480} height={260}>
|
|
183
|
+
<XAxis dataKey="category" />
|
|
289
184
|
<YAxis />
|
|
290
|
-
<BarSeries dataKey="
|
|
291
|
-
|
|
292
|
-
</BarSeries>
|
|
293
|
-
<Tooltip />
|
|
185
|
+
<BarSeries dataKey="actual" material="clay" />
|
|
186
|
+
<BarSeries dataKey="planned" pattern={{ kind: "duotone", color: "CanvasText" }} />
|
|
294
187
|
</BarChart>
|
|
295
188
|
</Root>
|
|
296
189
|
```
|
|
297
190
|
|
|
298
|
-
|
|
299
|
-
- `BarSeriesProps` retains native Bar props, children, cells, shapes, active bars, backgrounds, label/error-bar composition and handlers. It excludes `isAnimationActive`; Motion owns animation and the engine tween is always disabled. `fill` defaults to the Root color, with explicit fill and Cell overrides retaining native semantics. String data keys supply the metadata identity; set `seriesKey` for controlled numeric/function keys. Root visibility and native `hide` combine exactly as on `LineSeries`. Recharts Bar has no public component ref in the tested version; refs belong on custom shape nodes.
|
|
300
|
-
- Group bars by composing series; stack them with matching native axis IDs and `stackId`. Use `stackOffset="sign"` for separate positive/negative stacks, and native `LabelList`, `Cell`, `Rectangle`, `ReferenceLine` and `activeBar` for labels, category colors, highlights and signed baselines. The public API does not impose category/value field names or coerce null/zero values. Default tooltip content shows null as missing alongside available series, retains zero and signed values, and suppresses entirely missing categories.
|
|
301
|
-
|
|
302
|
-
`BarChart animate` accepts `false` (default), `true`, or `BarAnimation` with the same `revealDurationMs`, `revealEasing` and `hoverTransition` options as line. Each series opens a plot clip outward from the engine's zero coordinate (or nearest domain edge when zero is excluded) on its own numeric axis ID; negative values and both orientations retain their geometry. Grouped and stacked series share chart timing. A scale without a finite zero coordinate renders immediately. Initial axis registration and automatic tick-width measurement settle before geometry changes count as entrance interruptions; later font/label measurements that move the plot still finish the entrance immediately. Ranged bars retain native geometry; their reveal also opens from numeric zero. Custom labels outside the plot appear fully when reveal completes.
|
|
191
|
+
Config patterns supply implicit bar paint and legend swatches. `BarSeries.pattern` overrides config; `false` opts out. For an explicit override, compose `FillPatternSwatch` through `Legend.children` with the same pattern and color. Icons and native legend symbols take precedence; `hideIcon` requests solid swatches. Explicit series `fill` (including gradients), `style.fill`, and `Cell` fills retain native ownership. Custom shapes or custom active bars disable automatic series patterns; compose your own SVG paint for those shapes. Existing material/filter rules apply independently.
|
|
303
192
|
|
|
304
|
-
|
|
193
|
+
Grouped/stacked and horizontal/vertical charts share the same user-space tile; changing orientation does not rotate the encoding automatically. The base ink keeps the configured CSS color. Second ink defaults to `CanvasText`, following the host's `color-scheme`; choose contrasting theme-aware colors deliberately. With the stylesheet, forced colors use `Canvas`/`CanvasText` while retaining the pattern geometry. Patterns are decorative, static and unchanged by reduced motion or print; printer color settings can still affect contrast. Keep text labels and a data alternative, and verify the chosen ink combination in print and each theme.
|
|
305
194
|
|
|
306
|
-
|
|
195
|
+
Resources use React IDs, independently of consumer series IDs, and are stable through matching SSR/hydration trees. Hosts using multiple independent React roots must supply distinct `identifierPrefix` values to server rendering and hydration, as required by React. Recharts retains its native SSR shell; a server-visible legend and data alternative do not imply server-rendered bar geometry.
|
|
307
196
|
|
|
308
|
-
|
|
197
|
+
### Theme-aware series colors
|
|
309
198
|
|
|
310
|
-
`
|
|
199
|
+
`SeriesColor` accepts a CSS color string, a readonly nonempty array of CSS color
|
|
200
|
+
strings, or `{ light, dark }` containing either shape. Arrays are gradient stops,
|
|
201
|
+
not categorical palettes: supply separate config keys for category identities.
|
|
202
|
+
Stops are evenly distributed from 0 to 100%; a single stop is solid. Each theme's
|
|
203
|
+
spacing is preserved when stop counts differ (intermediate colors use CSS
|
|
204
|
+
`color-mix(in srgb, ...)`). Empty arrays, sparse arrays, empty strings and incomplete
|
|
205
|
+
or unknown theme fields throw. Errors identify the series and color property (including
|
|
206
|
+
the theme and stop index when applicable), without printing color values or unrelated
|
|
207
|
+
config metadata. For example, an empty second dark stop reports
|
|
208
|
+
`config["revenue"].color.dark[1] requires a nonempty color string`.
|
|
209
|
+
CSS color syntax remains the browser's responsibility: CSS variables, `currentColor`
|
|
210
|
+
and modern color functions pass through unchanged, including during server rendering.
|
|
311
211
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
212
|
+
```tsx
|
|
213
|
+
const config = {
|
|
214
|
+
revenue: {
|
|
215
|
+
color: { light: ["var(--brand)", "#2563eb"], dark: ["#fef3c7", "#f59e0b", "#92400e"] },
|
|
216
|
+
},
|
|
217
|
+
} satisfies SeriesConfig;
|
|
317
218
|
|
|
318
|
-
|
|
219
|
+
// Change colorScheme on this host without changing Root's key or remounting it.
|
|
220
|
+
<div style={{ colorScheme: dark ? "dark" : "light", "--brand": "#f59e0b" }}>
|
|
221
|
+
<Root config={config}>
|
|
222
|
+
<Legend />
|
|
223
|
+
<LineChart data={data} width={480} height={240}>
|
|
224
|
+
<XAxis dataKey="month" />
|
|
225
|
+
<YAxis />
|
|
226
|
+
<LineSeries dataKey="revenue" />
|
|
227
|
+
<Tooltip content={(tooltip) => <TooltipContent tooltip={tooltip} />} />
|
|
228
|
+
</LineChart>
|
|
229
|
+
</Root>
|
|
230
|
+
</div>
|
|
231
|
+
```
|
|
319
232
|
|
|
320
|
-
|
|
233
|
+
Themes follow the inherited CSS `color-scheme`, using native `light-dark()`;
|
|
234
|
+
without a host scheme the browser defaults to light. Set `color-scheme: light dark`
|
|
235
|
+
on a host for system preference, or `light`/`dark` for an explicit application
|
|
236
|
+
choice.
|
|
237
|
+
|
|
238
|
+
Browser syntax requirements (from MDN compatibility data):
|
|
239
|
+
|
|
240
|
+
| Generated CSS | Chrome / Edge | Firefox | Safari / iOS Safari |
|
|
241
|
+
| --- | --- | --- | --- |
|
|
242
|
+
| [`light-dark()`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/light-dark) for every `{ light, dark }` definition | 123+ | 120+ | 17.5+ |
|
|
243
|
+
| [`color-mix()`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/color-mix) for interpolated stops when theme spacing differs | 111+ | 113+ | 16.2+ |
|
|
244
|
+
| [`linear-gradient(... in srgb, ...)`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/gradient/linear-gradient#browser_compatibility) for gradient legend/tooltip swatches | 111+ | 127+ | 16.2+ |
|
|
245
|
+
|
|
246
|
+
For themed gradients including matching swatches, use Chrome/Edge 123+, Firefox
|
|
247
|
+
127+, or Safari/iOS Safari 17.5+. These are syntax minimums, not a tested-browser
|
|
248
|
+
matrix; supplied color values can have additional requirements.
|
|
249
|
+
|
|
250
|
+
There is no polyfill, feature detection or automatic light/first-stop fallback.
|
|
251
|
+
Unsupported functions make the consuming paint or swatch declaration invalid;
|
|
252
|
+
SVG paints/stops can use their CSS initial or inherited values, and gradient
|
|
253
|
+
swatches can lose their background image. For older browsers, supply supported
|
|
254
|
+
plain color strings (or CSS variables with host-controlled light/dark values)
|
|
255
|
+
instead of themed objects. Unthemed stop arrays avoid generated `light-dark()`
|
|
256
|
+
and `color-mix()`, but their swatches still require the gradient syntax above.
|
|
257
|
+
|
|
258
|
+
Root retains `--color-<key>` as the first stop, emits zero-based
|
|
259
|
+
`--kind-ui-series-<encoded-key>-<index>` stops and a `-gradient` CSS swatch
|
|
260
|
+
token, where encoded keys are hexadecimal Unicode code points joined by hyphens.
|
|
261
|
+
This namespace cannot collide with another series' legacy `--color-<key>`.
|
|
262
|
+
Built-in series/category paints use uniquely scoped resources in each chart SVG; gradients run
|
|
263
|
+
left to right across the SVG viewport (including flat line geometry). Legend and
|
|
264
|
+
solid tooltip markers display the full gradient; dashed tooltip borders use the
|
|
265
|
+
first stop. Explicit native stroke/fill, styles, Cells and shapes retain their
|
|
266
|
+
existing ownership; configured bar patterns take precedence and use the first
|
|
267
|
+
stop as their solid base ink (the legend pattern swatch does the same). Native
|
|
268
|
+
explicit pattern colors remain consumer-owned. Icons keep priority. Strings and one-stop definitions require
|
|
269
|
+
no SVG resource. Consumer Root styles override generated tokens as before; override
|
|
270
|
+
indexed stops to customize a gradient. No theme subscription or remount is needed.
|
|
271
|
+
|
|
272
|
+
The runnable `tests/fixtures/identity-colors` host exercises explicit light/dark
|
|
273
|
+
changes, unequal stops, CSS variable colors, multiple roots and native paint
|
|
274
|
+
precedence (`npm exec vite tests/fixtures/identity-colors`, open `/?theme`).
|
|
275
|
+
|
|
276
|
+
### Area patterns
|
|
277
|
+
|
|
278
|
+
`AreaSeries` accepts the shared `FillPattern` through `pattern` or `Root.config[key].pattern`, independently of `material`. The additive `dots` kind uses `width` as dot diameter (default 1); `lines` uses stroke width (default 1) and defaults to angle 0. Both use size 8 by default. Existing hatch, stripe and duotone encodings retain their defaults. These kinds also work with bars and `FillPatternSwatch`.
|
|
321
279
|
|
|
322
280
|
```tsx
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
<Root config={{ tasks: { label: "Tasks", color: "#7c5ce7", legendShape: taskShape } }}>
|
|
281
|
+
const config = {
|
|
282
|
+
actual: { color: "#789abc", pattern: { kind: "dots" as const, width: 2 } },
|
|
283
|
+
planned: { color: "var(--area-planned)", pattern: { kind: "lines" as const } },
|
|
284
|
+
};
|
|
285
|
+
<Root config={config}>
|
|
329
286
|
<Legend />
|
|
330
|
-
<
|
|
331
|
-
<
|
|
332
|
-
<
|
|
333
|
-
<
|
|
334
|
-
<
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
record && typeof record === "object" && "id" in record ? String(record.id) : "Task"
|
|
338
|
-
} />
|
|
339
|
-
</ScatterChart>
|
|
340
|
-
</Root>
|
|
287
|
+
<AreaChart width={480} height={260} data={rows}>
|
|
288
|
+
<XAxis dataKey="month" />
|
|
289
|
+
<YAxis />
|
|
290
|
+
<AreaSeries dataKey="actual" stackId="total" material="clay" fillOpacity={0.4} />
|
|
291
|
+
<AreaSeries dataKey="planned" stackId="total" fillOpacity={0.4} />
|
|
292
|
+
</AreaChart>
|
|
293
|
+
</Root>;
|
|
341
294
|
```
|
|
342
295
|
|
|
343
|
-
|
|
296
|
+
Configured `StackedArea`, `PercentArea` and `InteractiveArea` host recipes also accept these patterns through their `config`. Omit `stackId` for unstacked explicit areas. Explicit composition can instead use `pattern={{ kind: "hatch", angle: 45 }}` on each `AreaSeries`. Series patterns override configuration; `pattern={false}` opts out. Explicit `fill` (including gradients), `style.fill`, and custom `shape` retain ownership and disable automatic pattern resources. With a configured gradient, pattern tiles use the solid first-stop `--color-key` ink; unpatterned areas use the complete chart-local gradient. Explicit stroke still supplies the pattern base when provided. Native `fillOpacity`, filters, geometry and existing material rules remain in effect. Configuration drives default legend swatches; when overriding a series pattern, compose `FillPatternSwatch` through `Legend.children` with the matching pattern/color. Icon/symbol priority and theme/forced-colors behavior follow the shared bar pattern contract above. The mounted packed area fixture at `static.html?patterns` demonstrates overrides, materials, stacking, themes and two independent charts.
|
|
344
297
|
|
|
345
|
-
|
|
298
|
+
The existing Next integration fixture additionally checks real server-rendered
|
|
299
|
+
color resource IDs through hydration and a theme change.
|
|
346
300
|
|
|
347
|
-
|
|
301
|
+
## Legend and mark interactions
|
|
348
302
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
Effects scale with the square root of native area, with upper bounds (pencil rim 0.9px, Clay offset 3px/blur 2px, Glow blur 1.8px), **no minimum radius or size substitution**. Subpixel marks retain exact geometry and alpha but cannot show a full grain/relief pattern; the small-scale effect becomes tonal and may be indistinguishable below raster resolution. Nonpositive/unresolved sizes render through native Symbols without a finish. A declared nonnumeric stroke width or a stroke extent exceeding the square root of native area also uses unchanged native rendering instead of cropping paint; stroke-aware exclusion can suppress a small Glow halo while retaining its luminous body. This bounded fallback is covered with a 12px transparent gradient stroke, including `style.strokeWidth`. Glow's filter region is limited to three times each native symbol's bounding box and keeps native plot clipping, so extreme consumer strokes, registered custom symbol factories or boundary marks may crop decorative light. This is a bounded SVG finish for the seven built-in symbols, not an arbitrary custom-renderer guarantee.
|
|
352
|
-
|
|
353
|
-
Native Recharts owns numeric axes, ZAxis area mapping and per-point selection. Use `ScatterTooltip` instead of the category-oriented default `TooltipContent`: its default content displays the actual selected record's dimension values, names and units; a point label comes from the supplied callback or configured series title. Optional metadata for a dimension's string dataKey uses the same `Root.config` `label`/`formatValue` contract; native `entry.formatter`/tooltip `formatter` takes precedence. `Legend` shows all config entries, so use native axis names/units or a tooltip formatter when dimension entries should not appear in the legend. Custom `content`, `frameProps`, frame refs, bounded positioning and shared Motion are retained. Use `<ScatterTooltipContent tooltip={nativeContentProps} />` to compose the default UI inside your own native content.
|
|
354
|
-
|
|
355
|
-
No missing/zero/negative values are coerced or deduplicated by Kind. Default native symbols omit unresolvable x/y coordinates; custom shapes receive native nullable geometry and must guard it themselves. Recharts 3.10.1 uses the minimum Z range and omits the Z tooltip entry for both zero and missing z; default content displays only the native entries and does not invent a z value. Supply `zDimension={{ dataKey: "requests", name: "Requests", unit: "k" }}` to recover zero or missing size in maintained default content from the actual point record. `ScatterSizeDimension<Row>` also accepts a typed `(record: Row) => number | null | undefined` accessor without casts; reuse the accessor used by your ZAxis. String keys read own top-level properties only; use a function for nested paths. When native Recharts supplies a nonzero Z entry it remains intact, with its native formatter/name/unit. Mapping name/unit supplies the omitted entry, existing tooltip/series formatter and dimension config formatting apply, and missing entries use `missingValue` (default “No data”). No field is guessed when mapping is omitted. A table remains appropriate for all observations. Negative z is passed to the native scale; validate count domains in the host. Duplicate coordinates overlap but keep distinct record payloads/indexes. Custom Cells may override native geometry, exactly as with Recharts Scatter.
|
|
356
|
-
|
|
357
|
-
Motion fades native marks without moving their coordinates; native geometry animation is disabled to avoid two animation engines. Shared tooltip positioning can animate. Reduced motion renders final client geometry with Motion off. With the pinned Recharts 3.10.1, server rendering a fixed-size Scatter chart produces an empty chart wrapper, without SVG axes or point marks; geometry appears after client mount. Keep a host-owned table or summary available in the server HTML. Motion starts off during SSR; this is not an SSR geometry or hydration support guarantee. On the client, interaction, x/y geometry, data/visibility changes and resize settle entrance, and stale pointer placement is discarded on geometry changes. Off/config switches preserve consumer content and handlers. Entrance does not replay after interaction. Consumers own input validation, data tables, errors/loading states and immutable data updates.
|
|
358
|
-
|
|
359
|
-
For custom X axis IDs, set the matching native `ScatterTooltip axisId` so Recharts can resolve keyboard navigation. Native keyboard navigation visits points in the first registered series, in data order. Hover can select any series; arrows do not perform spatial or all-series navigation. Provide a keyboard-accessible data alternative for every series, especially overlapping points and missing measurements. Browser coverage is Chromium at the pinned peer versions; it is not a screen-reader/browser conformance claim or a large-dataset performance promise. See the [four bounded recipes](https://github.com/bhaveshchow20/kind-ui/blob/main/examples/chart/SCATTERS.md) and the isolated tarball consumer/browser proof in `tests/fixtures/scatter` and `tests/packed-scatter.spec.ts`.
|
|
360
|
-
|
|
361
|
-
The internal frame reuses the approved standalone generic `engine + chartProps` seam shared by polar and Combo charts.
|
|
362
|
-
|
|
363
|
-
## Combo / Composed charts
|
|
364
|
-
|
|
365
|
-
`ComboChart`, `ComboChartProps`, and `ComboAnimation` are public root exports.
|
|
366
|
-
`ComboChart` uses Recharts `ComposedChart` and accepts its native props, SVG ref,
|
|
367
|
-
handlers, axes, margins, layout, stacks, and children. Compose the existing
|
|
368
|
-
`LineSeries`, `AreaSeries`, and `BarSeries` under one `Root`; one `Tooltip` shows
|
|
369
|
-
all registered visible series at the selected category. `Legend` uses the same
|
|
370
|
-
consumer-owned `visibleSeries` and `onVisibleSeriesChange` contract.
|
|
303
|
+
Visibility remains the default. Opt into persistent focus with one Root owner:
|
|
371
304
|
|
|
372
305
|
```tsx
|
|
373
|
-
<Root config={config}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
<
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
<AreaSeries dataKey="queued" yAxisId="count" fillOpacity={0.2} />
|
|
383
|
-
<BarSeries dataKey="completed" yAxisId="count" />
|
|
384
|
-
<LineSeries dataKey="latency" yAxisId="ms" dot={false} />
|
|
385
|
-
<Tooltip />
|
|
386
|
-
</ComboChart>
|
|
387
|
-
</ResponsiveContainer>
|
|
306
|
+
<Root config={config} interaction={{
|
|
307
|
+
kind: "series", mode: "focus", eligibleKeys: ["revenue", "costs"],
|
|
308
|
+
markActivation: "matching-legend", defaultSelected: "revenue",
|
|
309
|
+
onSelectionChange: (key) => console.log(key),
|
|
310
|
+
}}>
|
|
311
|
+
<BarChart data={rows} width={400} height={240}>
|
|
312
|
+
<BarSeries dataKey="revenue" /><BarSeries dataKey="costs" />
|
|
313
|
+
</BarChart>
|
|
314
|
+
<Legend emphasis="series" />
|
|
388
315
|
</Root>
|
|
389
316
|
```
|
|
390
317
|
|
|
391
|
-
`
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
318
|
+
`interaction` binds a `kind` (`series`, `category`, or focus-only `node`) to a
|
|
319
|
+
settled `eligibleKeys` snapshot. Include hidden Root items and zero values; exclude
|
|
320
|
+
removed, filtered, unavailable, or native-hidden items. Config-only entries do not
|
|
321
|
+
satisfy the last-visible guard. New bindings require that snapshot; native series
|
|
322
|
+
registration provides compatibility eligibility for existing controlled legends.
|
|
323
|
+
`mode` defaults to `visibility`; `markActivation` defaults to `none`.
|
|
324
|
+
|
|
325
|
+
Focus accepts either `selected` with required `onSelectionChange`, or
|
|
326
|
+
`defaultSelected` with an optional callback. Persistent focus works with
|
|
327
|
+
`emphasis="none"`. Repeated activation or Escape clears it; transient inspection
|
|
328
|
+
never writes selection. Invalid uncontrolled selection clears without a callback.
|
|
329
|
+
An invalid controlled ID paints no selection and resumes if that ID becomes valid.
|
|
330
|
+
Visibility uses existing `visibleSeries`/`onVisibleSeriesChange`, or opt-in
|
|
331
|
+
`defaultVisibleSeries`. An externally empty visibility value remains valid.
|
|
332
|
+
|
|
333
|
+
For categories, use `kind: "category"` and explicitly set
|
|
334
|
+
`interactionBinding="root"` on `PieSeries` or `RadialBarChart`, with `categoryKey`
|
|
335
|
+
and explicit data. Stable unique string keys must match Root config. Hiding filters
|
|
336
|
+
original rows and their positional Cells before layout; Pie re-normalizes angles.
|
|
337
|
+
ActivityRings forwards this binding through category `rootProps.interaction`.
|
|
338
|
+
For Sankey node focus, bind both `SankeyChart` and `SankeyLegend` to a Root with
|
|
339
|
+
`kind: "node", mode: "focus"`; incident links/endpoints remain emphasized.
|
|
340
|
+
Sankey visibility, link selection, and persistent Heatmap cell selection are excluded.
|
|
341
|
+
|
|
342
|
+
`useChartInteraction()` exposes `selected`, `visible`, `mode`, `kind`, `eligible`,
|
|
343
|
+
`activate({kind, key}, "legend" | "mark", event?)`, and `reset(event?)` for custom
|
|
344
|
+
controls. Actions return whether accepted. Consumer native handlers run first;
|
|
345
|
+
`preventDefault()` or `onBeforeInteraction(request)` returning `false` vetoes.
|
|
346
|
+
Reset also runs the before hook. Accepted actions emit one mode-specific callback
|
|
347
|
+
and one scoped polite announcement. Rejected last-hide actions announce the reason
|
|
348
|
+
without changing state or calling the change callback. Custom renderers retain
|
|
349
|
+
ownership and can use the helper to bind their own controls/paint.
|
|
350
|
+
|
|
351
|
+
Radar's existing local `selection="series"` remains a compatibility path, also
|
|
352
|
+
independent of transient emphasis. Combining it or its selection callbacks with
|
|
353
|
+
Root focus throws: choose one owner. Selection ownership stays fixed while mounted;
|
|
354
|
+
remount when changing controlled/uncontrolled ownership.
|
|
355
|
+
|
|
356
|
+
## Decorative chart backgrounds
|
|
357
|
+
|
|
358
|
+
`ChartBackgroundPattern` is optional Cartesian plot chrome, independent of
|
|
359
|
+
`FillPattern` series encoding, legends, visibility and materials. Its transparent
|
|
360
|
+
tiles contain only decorative ink; series are painted above it. It uses Recharts'
|
|
361
|
+
plot area (excluding margins and axes), a scoped clip path and SVG IDs, and the
|
|
362
|
+
[Recharts layer contract](https://recharts.github.io/en-US/guide/zIndex/) just below
|
|
363
|
+
the default grid. Custom negative series/grid z-index overrides remain caller-owned.
|
|
364
|
+
It adds no layout, axes, tooltip payload, animation or accessibility semantics.
|
|
365
|
+
The stylesheet prevents descendant pointer interception.
|
|
366
|
+
|
|
367
|
+
Generated configured LineChart opts in with:
|
|
431
368
|
|
|
432
369
|
```tsx
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
<Label position="center" value="Capacity" />
|
|
441
|
-
</Chart.PieSeries>
|
|
442
|
-
<Chart.Tooltip itemKey={itemKey} />
|
|
443
|
-
</Chart.PieChart>
|
|
444
|
-
<Chart.Legend />
|
|
445
|
-
</Chart.Root>
|
|
370
|
+
<Chart.LineChart
|
|
371
|
+
config={config}
|
|
372
|
+
data={data}
|
|
373
|
+
xDataKey="month"
|
|
374
|
+
aria-label="Monthly totals"
|
|
375
|
+
backgroundPattern={{ pattern: "pinpoints", opacity: 0.15 }}
|
|
376
|
+
/>
|
|
446
377
|
```
|
|
447
378
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
Category visibility and Cells are consumer-owned: filter data and generate Cells from that same array so index alignment survives filtering and reordering. Root/Legend never change polar data or silently recompute shares. `PieSeries` defaults to a continuous allocation: native padding/corner defaults remain zero, and its default stroke is `none`. Explicit series/Cell strokes, padding angles and corner radii remain consumer customizations. `PieSeries.hide` hides the whole native Pie independently of category state. Multiple native Pies, native Tooltip selection/`defaultIndex`/`trigger`, `nameKey`, function/numeric `dataKey`, numeric/percentage/function radii, angles, padding, corner radius, labels, custom shapes, Cells, SVG attributes and sector handlers remain available. Chart SVG refs retain the native ref contract. Recharts does not expose a Pie component ref.
|
|
451
|
-
|
|
452
|
-
`animate={false | true | config}` uses the established duration/easing/tooltip hover transition shape. Recharts animation is disabled in `PieSeries`; Motion grows each default sector from its own start angle within its native angular footprint on entrance. Labels remain at their final native positions. Custom `shape`, `activeShape` and `inactiveShape` retain ownership; Kind does not animate those custom marks. Motion stops and snaps to final geometry on pointer/keyboard interaction, data/visibility/geometry changes, resize or disabling animation. Reduced motion renders final geometry and bounded tooltip placement without motion. Entrance does not replay after an interruption; remount the chart for an intentional new entrance.
|
|
453
|
-
|
|
454
|
-
Use nonnegative, finite values for meaningful proportional data. Kind preserves native values rather than inventing allocations: empty/all-zero inputs paint no allocation, and zero/missing categories remain distinguishable in the consumer-owned table. A zero category has no visible angular area; expose it in the legend/data alternative rather than imposing a minimum fake share. Provide readable labels and a table/list; SVG plus tooltip alone is not a complete data alternative. [Recharts Pie API](https://recharts.github.io/en-US/api/Pie/) and the pinned `recharts@3.10.1` source (`polar/Pie.js`, `shape/Sector.d.ts`) informed the payload, Cell and polar geometry integration. Motion cancellation uses [animation playback controls](https://motion.dev/docs/animate).
|
|
455
|
-
|
|
456
|
-
`examples/chart/pies.html` contains two bounded recipes: a pie allocation and a donut capacity summary. Both consume these public APIs and share existing tooltip/legend/formatting/accessibility behavior. The isolated tarball host in `tests/fixtures/pie` is separate from the recipes and is checked with strict NodeNext/Bundler declarations, a production build and browser contracts.
|
|
457
|
-
|
|
458
|
-
### Pie and donut finishes
|
|
459
|
-
|
|
460
|
-
`PieSeries` accepts `material="plain" | "paper" | "clay" | "glow"` (`PieMaterial`),
|
|
461
|
-
independently of native fill/Cells and the chart’s `animate` prop. Plain is the default.
|
|
462
|
-
Paper adds faint fibers and an uneven inset pencil contour; Clay gives soft convex
|
|
463
|
-
matte relief; Glow emits a soft colored halo around the crisp native sector. All finishes preserve native
|
|
464
|
-
angles, radii, path, paint alpha, continuous zero-padding/no-stroke defaults and labels.
|
|
465
|
-
Donuts use the same prop with native `innerRadius`.
|
|
466
|
-
|
|
467
|
-
Custom shapes (including active/inactive shapes) remain consumer-owned. Explicit
|
|
468
|
-
sector `filter` or `style.filter`, including Cell overrides, bypasses the built-in
|
|
469
|
-
finish on that sector. Native gradients, clipping, IDs and handlers remain available.
|
|
470
|
-
Paper/Clay remain inset. Glow’s decorative halo can overlap adjacent sectors/rings;
|
|
471
|
-
it does not change quantitative geometry or native body alpha. No finish displaces paths.
|
|
472
|
-
Per-sector filter/mask/source IDs are instance-scoped. Native paint masks retain
|
|
473
|
-
Paper/Clay alpha at curved edges; Glow keeps the native body separate from its
|
|
474
|
-
decorative halo. The halo follows the painted footprint, including gradient fades. Switching finishes during entrance snaps
|
|
475
|
-
to final geometry using the existing interruption contract.
|
|
476
|
-
|
|
477
|
-
Optional CSS variables: `--kind-ui-pie-clay-light`, `--kind-ui-pie-clay-highlight`,
|
|
478
|
-
`--kind-ui-pie-clay-shade`, `--kind-ui-pie-clay-shadow`, `--kind-ui-pie-paper-fiber`,
|
|
479
|
-
`--kind-ui-pie-paper-grain`, `--kind-ui-pie-paper-ink`,
|
|
480
|
-
and `--kind-ui-pie-glow-opacity`. Lighting adapts locally to native radius and ring
|
|
481
|
-
thickness. The pie/donut recipes expose the material control and keep category totals
|
|
482
|
-
and selection consumer-controlled.
|
|
483
|
-
|
|
484
|
-
## Radar and radial bars
|
|
485
|
-
|
|
486
|
-
`RadarChart` / `RadarSeries` and `RadialBarChart` / `RadialBarSeries` are maintained public exports. Their generic chart `*Props<DataPoint>` and series `*Props<DataPoint, Value>` types retain native typed data keys. The charts accept their native polar chart props and SVG refs, including `layout="centric" | "radial"`, centers, radii, angles, synchronization and event handlers. The series accept native shapes, dots/active marks, Cells, backgrounds, labels, axis IDs, stack IDs, z-order and handlers. Recharts 3.10.1 exposes no series component ref; place refs on custom SVG marks. Recharts owns polar geometry and native category payloads.
|
|
379
|
+
Explicit composition uses the part inside the chart. Configured explicit children
|
|
380
|
+
replace generated parts, so do not also pass `backgroundPattern`:
|
|
487
381
|
|
|
488
382
|
```tsx
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
<Chart.
|
|
494
|
-
|
|
495
|
-
<PolarGrid />
|
|
496
|
-
<PolarAngleAxis dataKey="dimension" />
|
|
497
|
-
<PolarRadiusAxis domain={[0, 100]} />
|
|
498
|
-
<Chart.RadarSeries dataKey="score" fillOpacity={0.2} />
|
|
383
|
+
<Chart.Root config={config}>
|
|
384
|
+
<Chart.BarChart data={data} responsive style={{ width: "100%", height: 280 }}>
|
|
385
|
+
<Chart.ChartBackgroundPattern pattern="crossings" size={20} opacity={0.12} />
|
|
386
|
+
<Chart.XAxis dataKey="month" />
|
|
387
|
+
<Chart.YAxis />
|
|
388
|
+
<Chart.BarSeries dataKey="total" />
|
|
499
389
|
<Chart.Tooltip />
|
|
500
|
-
</Chart.
|
|
390
|
+
</Chart.BarChart>
|
|
501
391
|
</Chart.Root>
|
|
502
392
|
```
|
|
503
393
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
The shared `Legend`, `Tooltip` and `TooltipContent` provide the same formatting, measured bounds and controlled visibility as Cartesian charts. Recharts 3.10.1 provides polar keyboard traversal with Left/Right, Enter toggling, and Escape dismissal. Give each chart an accessible name and provide a value table; native keyboard behavior is preserved rather than replaced. Empty and zero data retain native behavior.
|
|
511
|
-
|
|
512
|
-
The `/polar.html` showcase uses public APIs for comparison, outline and range radar, grouped rings, stacked arcs and a half-circle gauge. It includes explicit domains, controlled legends, Motion/data/update controls and value tables. `tests/fixtures/polar` installs the actual tarball in an isolated consumer, checks strict NodeNext/Bundler declarations and production builds, and compares browser paths against native Recharts charts.
|
|
513
|
-
|
|
514
|
-
First-party references: [Radar API](https://recharts.github.io/en-US/api/Radar/), [RadialBar API](https://recharts.github.io/en-US/api/RadialBar/), and the tested package's `types/polar` and `es6/polar` sources.
|
|
515
|
-
|
|
516
|
-
### Radial band labels
|
|
517
|
-
|
|
518
|
-
Use native `LabelList dataKey="dimension" fill="white" content={<Chart.RadialBarLabel show={showText} />}` inside `RadialBarSeries`. `RadialBarLabel` is maintained label content, not a sector renderer. It consumes Recharts' native polar viewBox, follows the mid-radius within that sector's endpoints, reverses the path for upright reading, and checks measured glyph bounds. `fontSize` defaults to 11 numeric pixels, `minFontSize` to 9 and `padding` to 2. Thin/short/zero/invalid sectors and values that cannot fit omit or hide text. The native LabelList can inject fill; set its fill explicitly for contrast. `formatter`, SVG presentation/events and SVG text `ref`/`labelRef` (including React 19 cleanup) remain available. Layout coordinates/transform are excluded because the helper owns arc placement. Oversized CSS font overrides also fail the fit guard.
|
|
519
|
-
|
|
520
|
-
`show={false}` controls only this visual label; it does not filter series, data, tooltip payload or Root metadata. Control tooltip visibility independently with native `Tooltip active={false}`. Labels render hidden during SSR until client SVG measurement; retain a value table for an immediate data alternative. Arbitrary geometry transforms or inherited letter/word styling can change available space; measurement conservatively hides labels when their glyph bounding boxes exceed the native sector.
|
|
521
|
-
|
|
522
|
-
The [polar gallery audit](https://github.com/bhaveshchow20/kind-ui/blob/main/examples/chart/POLAR-GALLERY.md) maps all eighteen current first-party shadcn radar/radial variations to runnable public compositions.
|
|
523
|
-
|
|
524
|
-
## Histogram family
|
|
394
|
+
Presets are `pinpoints`, `crossings` and `waves`. `size` is a positive finite tile
|
|
395
|
+
size in SVG user units (default 16), and `opacity` is finite in [0, 1] (default
|
|
396
|
+
0.15). Zero opacity is supported. `color` accepts CSS paint, including theme
|
|
397
|
+
variables; the default is `var(--kind-ui-chart-grid, CanvasText)`. Resize changes
|
|
398
|
+
the plot rectangle and clip, preserving tile density and IDs. Missing or empty
|
|
399
|
+
plot geometry renders nothing; invalid options throw even before geometry exists.
|
|
525
400
|
|
|
526
|
-
|
|
401
|
+
Custom registration is consumer-owned and immutable: define reusable patterns in
|
|
402
|
+
a local module or catalog, then pass the definition directly. No global registry,
|
|
403
|
+
provider, series metadata or side-effect registration is required:
|
|
527
404
|
|
|
528
405
|
```tsx
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
<Chart.HistogramSeries />
|
|
538
|
-
<Chart.Tooltip shared={false} labelFormatter={(_label, entries) => {
|
|
539
|
-
const bin = entries[0]?.payload;
|
|
540
|
-
return bin ? `[${bin.lower}, ${bin.upper}${bin.upper === 3 ? "]" : ")"} ms` : "";
|
|
541
|
-
}} />
|
|
542
|
-
</Chart.HistogramChart>
|
|
543
|
-
</Chart.Root>;
|
|
406
|
+
const cornerMarks = Chart.defineChartBackgroundPattern(({ size, color, idPrefix }) => (
|
|
407
|
+
<g id={`${idPrefix}-tile`}>
|
|
408
|
+
<path d={`M0 ${size / 3}V0H${size / 3}`} fill="none" stroke={color} />
|
|
409
|
+
</g>
|
|
410
|
+
));
|
|
411
|
+
const backgrounds = { cornerMarks }; // optional local catalog
|
|
412
|
+
|
|
413
|
+
<Chart.ChartBackgroundPattern pattern={backgrounds.cornerMarks} size={24} opacity={0.1} />;
|
|
544
414
|
```
|
|
545
415
|
|
|
546
|
-
The
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
416
|
+
The render escape hatch returns tile SVG children, not a full chart or pattern
|
|
417
|
+
element. Use the supplied `size`, `color`, and per-instance `idPrefix`; suffix
|
|
418
|
+
custom resource IDs and reference those scoped IDs. Keep custom output decorative:
|
|
419
|
+
no links, focusable elements, event handlers, portals or independent z-index
|
|
420
|
+
layers. The callback is trusted consumer code, not an SVG sanitizer.
|
|
421
|
+
|
|
422
|
+
Supported composition hosts are Line, Bar (including Waterfall), Area, Combo,
|
|
423
|
+
Scatter, Histogram and BoxPlot charts using the native Cartesian plot area.
|
|
424
|
+
Generated configuration is available only for LineChart. Polar, Pie, Sankey,
|
|
425
|
+
Heatmap and ActivityRings are outside this contract. Fixed-size chart SSR retains
|
|
426
|
+
the existing native empty shell; this part does not create server plot geometry.
|
|
427
|
+
### Projected bar rows
|
|
428
|
+
|
|
429
|
+
`BarSeries<DataPoint, Value>.projection` is opt-in:
|
|
430
|
+
`{ isProjected: (datum: DataPoint) => boolean, pattern: FillPattern }`.
|
|
431
|
+
The caller supplies values and selects identity; Kind UI generates no forecasts.
|
|
432
|
+
For a trailing projection, capture the final row's stable ID before filtering or
|
|
433
|
+
reordering, then compare that ID in `isProjected`. It never implicitly marks the
|
|
434
|
+
new last visible row. Multiple selected identities are allowed.
|
|
565
435
|
|
|
566
436
|
```tsx
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
437
|
+
const projectedId = originalRows.at(-1)?.id;
|
|
438
|
+
const projection: BarProjection<Row> = {
|
|
439
|
+
isProjected: (row) => projectedId !== undefined && row.id === projectedId,
|
|
440
|
+
pattern: { kind: "hatch" },
|
|
441
|
+
};
|
|
442
|
+
// Use in grouped bars or share it across series with the same stackId.
|
|
443
|
+
<BarSeries<Row, number> dataKey="value" projection={projection} />;
|
|
444
|
+
<Tooltip content={(tooltip) => (
|
|
445
|
+
<TooltipContent tooltip={tooltip}
|
|
446
|
+
isProjected={(entry) => projection.isProjected(entry.payload)} />
|
|
447
|
+
)} />;
|
|
448
|
+
// In the consumer-owned table, alongside the unchanged numeric value:
|
|
449
|
+
<td>{projection.isProjected(row) ? "Projected" : "Observed"}</td>;
|
|
578
450
|
```
|
|
579
451
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
Initial scope: linear numeric axes, categorical groups, two orientations, optional
|
|
617
|
-
Bar reveal Motion with reduced-motion/interruption behavior. Stacking, minimum
|
|
618
|
-
numeric sizes, native rectangle backgrounds/radius, native
|
|
619
|
-
active-bar duplication, raw-sample estimators, weighted quartiles, notches,
|
|
620
|
-
variable-width-by-sample-size boxes, and quantitative category positioning are
|
|
621
|
-
outside this family. Nonlinear numeric axes, Brush, mixed-series composition and
|
|
622
|
-
performance at large sample/group counts are not verified. Custom SVG marks are
|
|
623
|
-
consumer-owned.
|
|
624
|
-
|
|
625
|
-
References: [NIST box plot definitions and variants](https://www.itl.nist.gov/div898/handbook/eda/section3/boxplot.htm),
|
|
626
|
-
[Recharts Bar](https://recharts.github.io/en-US/api/Bar/),
|
|
627
|
-
[public X scale](https://recharts.github.io/en-US/api/useXAxisScale/),
|
|
628
|
-
[public Y scale](https://recharts.github.io/en-US/api/useYAxisScale/).
|
|
629
|
-
The sample estimator and whisker definition deliberately remain caller-owned.
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
### Box plot materials
|
|
633
|
-
|
|
634
|
-
`BoxPlotSeries` and the screen-space `BoxPlotMark` accept `material="plain" | "paper" | "clay" | "glow"` (`BoxPlotMaterial`). Plain is the default. Paper uses the existing bar grain and uneven inset pencil contour; Clay uses bar soft convex matte relief; Glow adds an exterior painted halo and a crisp lightened body. These static finishes are independent of color and Motion and preserve every whisker, quartile, median and outlier coordinate. Native stroke width/dashes remain the input silhouette. No extra minimum extent is introduced: all-equal and tiny marks receive a line finish; missing rows still have no marks.
|
|
635
|
-
|
|
636
|
-
Each present native mark has its own React-generated filter ID and user-space region, including outliers and resolved child stroke widths/miter limits, so line-only summaries do not require nonzero bounding boxes. Use React `identifierPrefix` for independently mounted roots. Box finishes reuse the `--kind-ui-bar-*` tokens documented above. Body alpha is preserved, including zero fill opacity; glow/cast effects can paint only outside the native footprint. Tiny marks have less room for visible grain/relief. Bounds are refreshed for React updates, stylesheet edits/loads, ancestor theme classes, viewport changes and pointer entry/exit. Direct CSSOM rule mutations without one of those signals are not observed. The default box fill remains `0.18`; an explicit `fillOpacity` (for example `0.65`) makes broad surfaces easier to see.
|
|
637
|
-
|
|
638
|
-
An explicit series/Cell/mark `filter`, or `style.filter`, including `none`, disables the built-in finish for that mark. Custom `shape` owns its markup and is not automatically materialized; it may explicitly return a materialized `BoxPlotMark`. Cells, gradients, native paint/opacity, mark styles, clipping, masks, visibility, refs, handlers and labels retain ownership. Filters run on the original consumer mark group (parts remain direct children) and existing reveal/plot clips, which may trim decorative halos. Chromium is verified; other SVG engines and print renderers remain unverified. No shared helper changes, dependencies, workflow changes or releases accompany this material stack.
|
|
639
|
-
### Shared presentation example
|
|
640
|
-
|
|
641
|
-
`examples/chart/presentation.html` demonstrates the same public options for line, area and bar, icon/swatch fallback, composed legend labels, native formatter tuples/suppression, custom content and light/dark host CSS variables. It enables motion by default while following live reduced-motion preferences, and includes keyboard instructions and all-series table values. Its source is also compiled against an independently installed tarball, with guarded public imports, strict NodeNext/Bundler checks, and Chromium interactions. Theme colors remain host-owned CSS variables; this change does not add automatic light/dark config mapping. String labels/colors remain required.
|
|
452
|
+
Selection applies to chart rows or explicitly supplied `BarSeries.data` in both
|
|
453
|
+
orientations. Empty chart data produces no marks. Native empty `BarSeries.data` overrides
|
|
454
|
+
inherit chart rows; projection follows the actual displayed payload. Null/undefined
|
|
455
|
+
rows are never passed
|
|
456
|
+
to the selector. Missing values retain native missing-bar behavior, and filtering
|
|
457
|
+
out a selected identity does not select a replacement. Zero remains zero. Keep
|
|
458
|
+
predicates pure and IDs unique; row indices do not offer reorder-stable identity.
|
|
459
|
+
|
|
460
|
+
Projection fills use the existing `FillPattern` seam and native Rectangle shape
|
|
461
|
+
props, so Brush slices cannot shift identity as positional Cells would. Unselected rows retain
|
|
462
|
+
configured/explicit series patterns and full gradient paints. Projection tiles
|
|
463
|
+
use the configured theme's solid first stop (`--color-key`), the same documented
|
|
464
|
+
fallback as ordinary Bar/Area pattern tiles. `pattern={false}` disables automatic
|
|
465
|
+
projection paint. Explicit series `fill`/`style.fill`, native shape options,
|
|
466
|
+
custom shapes/active shapes and any explicit Cell composition retain paint
|
|
467
|
+
ownership. Datum `fill`/`style.fill` also prevents automatic projection paint for
|
|
468
|
+
that row. Compose Cells yourself for custom per-row painting.
|
|
469
|
+
|
|
470
|
+
`TooltipContent.isProjected(entry)` shares caller selection but receives the
|
|
471
|
+
native tooltip entry, including its original payload. Projected items append
|
|
472
|
+
accessible text (`projectedLabel`, default `"Projected"`) without modifying
|
|
473
|
+
values, labels, formatter behavior or config. Custom tooltip content and data
|
|
474
|
+
alternatives must expose status themselves, even when custom paint overrides it.
|
|
475
|
+
The runnable public consumer example is the packed Bar fixture at
|
|
476
|
+
`/?projection` (add `&horizontal` for horizontal bars); it includes table status,
|
|
477
|
+
stacking, filtering, reorder and ownership controls. Configured series metadata
|
|
478
|
+
continues to own ordinary patterns; projection is a per-Series composition prop,
|
|
479
|
+
not global config or a generated-data recipe.
|
|
480
|
+
|
|
481
|
+
### Percentage stack formatting
|
|
482
|
+
|
|
483
|
+
`createPercentStack({ values })` opts into formatting for scalar native
|
|
484
|
+
`stackOffset="expand"` Bar, Area and Combo stacks. Geometry, domains, axes and
|
|
485
|
+
stack membership remain caller-owned. It returns `tickFormatter` and
|
|
486
|
+
`normalizedValue`; no rows, series, native values or native tooltip payloads are
|
|
487
|
+
rewritten. Native Recharts still normalizes geometry exactly once.
|
|
642
488
|
|
|
643
489
|
```tsx
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
The polar recipes/gallery share a Material control and enable Motion by default, respecting reduced motion. Gauge text remains large in the center whitespace; ordinary radial labels remain at band center with independent Chart text visibility.
|
|
659
|
-
|
|
660
|
-
## Waterfall
|
|
661
|
-
|
|
662
|
-
`computeWaterfallData(entries, initialBalance = 0)` returns fresh ordered rows for
|
|
663
|
-
native numeric range bars. Each entry has a unique nonempty `id`, a `label`, and
|
|
664
|
-
one of these explicit kinds:
|
|
665
|
-
|
|
666
|
-
| Kind | Supplied value | Meaning |
|
|
667
|
-
| --- | --- | --- |
|
|
668
|
-
| `start`, `total`, `end` | finite number or `null` | Checkpoint: draw zero → value and establish the running balance. A checkpoint can intentionally disagree with the preceding balance. |
|
|
669
|
-
| `delta` | finite signed number or `null` | Draw previous balance → balance + value. |
|
|
670
|
-
| `subtotal` | none | Draw zero → current balance; do not add it again or reset it. |
|
|
671
|
-
|
|
672
|
-
The default starting balance is explicitly zero; pass `null` for an unknown
|
|
673
|
-
opening balance. Kind names express intent, not positional restrictions: an
|
|
674
|
-
`end` is an explicit supplied total, never an automatically inferred final sum.
|
|
675
|
-
A missing delta makes subsequent geometry/balances unknown until a known
|
|
676
|
-
checkpoint restores them. Its known successors still retain their original
|
|
677
|
-
values. A missing checkpoint also establishes an unknown balance. Zero remains
|
|
678
|
-
numeric (`[balance, balance]` for a zero delta), with no invented minimum height.
|
|
679
|
-
Nonfinite values, omitted values, duplicate/empty ids, supplied subtotal values,
|
|
680
|
-
unknown kinds and arithmetic overflow throw. Inputs are not mutated.
|
|
681
|
-
|
|
682
|
-
```tsx
|
|
683
|
-
import * as Chart from "@kind-ui/charts";
|
|
684
|
-
import { Cell, ReferenceLine, XAxis, YAxis } from "@kind-ui/charts";
|
|
685
|
-
|
|
686
|
-
const data = Chart.computeWaterfallData([
|
|
687
|
-
{ id: "opening", label: "Opening", kind: "start", value: 80 },
|
|
688
|
-
{ id: "cost", label: "Cost", kind: "delta", value: -100 },
|
|
689
|
-
{ id: "net", label: "Net", kind: "subtotal" },
|
|
690
|
-
{ id: "closing", label: "Closing", kind: "end", value: -20 },
|
|
691
|
-
]);
|
|
692
|
-
|
|
693
|
-
<Chart.Root config={{ range: { label: "Balance", color: "#3478ae" } }}>
|
|
694
|
-
<Chart.WaterfallChart data={data} width={480} height={280} animate>
|
|
695
|
-
<XAxis dataKey="id" />
|
|
696
|
-
<YAxis domain={["auto", "auto"]} />
|
|
697
|
-
<ReferenceLine y={0} />
|
|
698
|
-
<Chart.WaterfallConnectors data={data} />
|
|
699
|
-
<Chart.WaterfallSeries material="paper">
|
|
700
|
-
{data.map(row => <Cell key={row.id} fill={row.kind === "delta" ? "#b54d46" : "#3478ae"} />)}
|
|
701
|
-
</Chart.WaterfallSeries>
|
|
702
|
-
</Chart.WaterfallChart>
|
|
703
|
-
</Chart.Root>;
|
|
490
|
+
const percent = createPercentStack({
|
|
491
|
+
values: (entry) => {
|
|
492
|
+
// Select this stack, excluding the Combo's latency line and other axes.
|
|
493
|
+
if (entry.dataKey !== "desktop" && entry.dataKey !== "mobile") return undefined;
|
|
494
|
+
const row = entry.payload as { desktop: number; mobile: number } | undefined;
|
|
495
|
+
return row ? [row.desktop, row.mobile] : undefined;
|
|
496
|
+
},
|
|
497
|
+
});
|
|
498
|
+
// Vertical columns / ordinary Areas: the numeric Y axis only.
|
|
499
|
+
<YAxis yAxisId="share" tickFormatter={percent.tickFormatter} />;
|
|
500
|
+
// Horizontal bars (layout="vertical"): the numeric X axis only.
|
|
501
|
+
<XAxis type="number" tickFormatter={percent.tickFormatter} />;
|
|
502
|
+
<Tooltip normalizedValue={percent.normalizedValue} />;
|
|
704
503
|
```
|
|
705
504
|
|
|
706
|
-
|
|
707
|
-
native
|
|
708
|
-
|
|
709
|
-
`
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
`
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
`SankeyChart` excludes them from native layout. All-zero and empty charts display
|
|
761
|
-
`empty` (default `No positive flows`). Native callback indices address this
|
|
762
|
-
filtered rendering array. Renderer/event payloads retain typed `id` identities,
|
|
763
|
-
including source/target node IDs on links. Native layout owns derived node
|
|
764
|
-
values (maximum input/output). Never use a render index as an input identity.
|
|
765
|
-
|
|
766
|
-
Finite values can still exceed native floating-point layout limits. At the
|
|
767
|
-
native drawable height H, with N positive-flow nodes, the chart conservatively requires finite aggregate
|
|
768
|
-
positive flow T, finite positive H/T, finite T*H and nonzero v*((H - (N-1)*padding)/T) for every
|
|
769
|
-
positive link. It throws an explicit renderer-limit error rather than changing
|
|
770
|
-
values. Supply explicitly rescaled units at your data boundary if necessary.
|
|
771
|
-
Equal-value parallel positive links also throw a renderer-limit error because
|
|
772
|
-
Recharts keys links by source, target and value. Distinct-value parallel links
|
|
773
|
-
are supported; semantic validation and the table accept either. No duplicate
|
|
774
|
-
flow is silently combined. These checks are separate from semantic validation. A frame too small for the
|
|
775
|
-
conservative node-padding budget displays `Insufficient space for flows; use
|
|
776
|
-
the data table` instead of negative native geometry. SSR and unmeasured frames
|
|
777
|
-
also use this status until measured. Native ResponsiveContainer remains usable.
|
|
778
|
-
|
|
779
|
-
`SankeyNode` and `SankeyLink` are optional native callback/element shapes, not
|
|
780
|
-
series components. They accept SVG presentation/handlers and `rectProps` or
|
|
781
|
-
`pathProps`. Computed coordinates, dimensions and link width win over supplied
|
|
782
|
-
presentation attributes; link width also wins over inline CSS stroke width.
|
|
783
|
-
`SankeyLink.material="solid" | "gradient"` remains the paint API, using native
|
|
784
|
-
cubic coordinates and proportional stroke widths. Separately,
|
|
785
|
-
`SankeyLink.finish` and `SankeyNode.finish` accept exported `SankeyFinish`:
|
|
786
|
-
`"plain"` (default), `"paper"`, `"clay"`, or `"glow"`. No chart-level finish
|
|
787
|
-
is injected into custom renderers. Set finishes explicitly on the optional marks:
|
|
505
|
+
Only attach the formatter to an axis whose units are fractions. Other axes keep
|
|
506
|
+
native ticks. A shared axis containing raw and fraction units needs a caller
|
|
507
|
+
chosen scale/domain; this helper cannot reconcile those units. Custom ticks and
|
|
508
|
+
`tickFormatter` stay native and caller-owned. `formatPercent(fraction)` is also
|
|
509
|
+
exported (one decimal at most, no locale-dependent output).
|
|
510
|
+
|
|
511
|
+
`values(entry)` must return the **raw members of that entry's own stack**, including
|
|
512
|
+
its value, or `undefined` for unrelated entries. Use native datum identity, stack
|
|
513
|
+
and axis selection where keys overlap. Match current native hidden-series
|
|
514
|
+
membership; do not sum the tooltip payload, which can contain unrelated stacks,
|
|
515
|
+
axes or lines. Update membership alongside controlled legends. Range values,
|
|
516
|
+
numeric strings and nonfinite values are outside the helper's scalar contract.
|
|
517
|
+
|
|
518
|
+
The helper uses the signed sum, matching native expand: missing members contribute
|
|
519
|
+
zero to the denominator but remain missing in content; all-zero rows display 0%;
|
|
520
|
+
negative fractions remain signed, with no absolute-value conversion or clamping.
|
|
521
|
+
A cancelling zero sum with nonzero members has no defined share and retains raw
|
|
522
|
+
formatting. Invalid/nonfinite totals or entries also retain raw formatting.
|
|
523
|
+
Native negative geometry/domain behavior remains native; this API does not promise
|
|
524
|
+
a 0–100% domain for negative data or fabricate absent values.
|
|
525
|
+
|
|
526
|
+
`Tooltip` and `TooltipContent` accept `normalizedValue(entry): number | undefined`.
|
|
527
|
+
Default content shows `25% (1)` with the original value in parentheses, using
|
|
528
|
+
configured `formatValue` for that raw text when present. Explicit entry/native
|
|
529
|
+
`formatter` takes precedence, including suppression and tuple results. Custom
|
|
530
|
+
content receives the unchanged native payload and owns its presentation; pass the
|
|
531
|
+
resolver explicitly when composing `TooltipContent`. Missing text, labels,
|
|
532
|
+
projection status, patterns and colors keep their existing contracts. For already
|
|
533
|
+
normalized source data, provide a resolver that returns the existing fraction;
|
|
534
|
+
do not compute another share or apply expand to data already transformed elsewhere.
|
|
535
|
+
Hosts still own raw data tables and accessible alternatives.
|
|
536
|
+
|
|
537
|
+
The source-only example at `/contracts.html` includes vertical/horizontal Bar,
|
|
538
|
+
Area and Combo with a separate raw latency axis and original data tables.
|
|
539
|
+
Recharts 3.10.1 applies native expand to every numeric axis. For mixed-unit Combo
|
|
540
|
+
charts, the example therefore uses caller-selected fraction `dataKey` accessors
|
|
541
|
+
for the stacked bars with `stackOffset="none"`, a `[0, 1]` share axis, and an
|
|
542
|
+
unchanged raw latency line on `[0, 10]`. The raw rows stay intact; an explicit
|
|
543
|
+
native tooltip formatter pairs each fraction with its original row value. Do not
|
|
544
|
+
apply expand or divide again to those fraction accessors. Other families use
|
|
545
|
+
native expand and the formatting helper. The Percent Area recipe retains integer
|
|
546
|
+
tooltip percentages and “No share” for a zero total.
|
|
547
|
+
|
|
548
|
+
### Point marker styles
|
|
549
|
+
|
|
550
|
+
`LineSeries` and `AreaSeries` accept independent `pointStyle` and
|
|
551
|
+
`activePointStyle` values: `"default"`, `"border"`, or `"colored-border"`.
|
|
552
|
+
Omitted/default values keep the existing appearance (including Area's normally
|
|
553
|
+
hidden regular dots). Opting into a regular style enables regular dots. Border
|
|
554
|
+
uses a series-colored center with a surface-colored ring; colored-border uses a
|
|
555
|
+
surface-colored center with a series-colored ring. The surface is
|
|
556
|
+
`--kind-ui-chart-marker-surface`, falling back to `--card` then white; set it on
|
|
557
|
+
Root for your theme. Series paint follows the existing config/theme identity or
|
|
558
|
+
explicit series stroke. Styles introduce no SVG resources or additional motion.
|
|
788
559
|
|
|
789
560
|
```tsx
|
|
790
|
-
<
|
|
791
|
-
|
|
792
|
-
link={(props) => <SankeyLink {...props} material="gradient" finish="paper" />}
|
|
793
|
-
/>
|
|
561
|
+
<LineSeries dataKey="total" pointStyle="border" activePointStyle="colored-border" />
|
|
562
|
+
<AreaSeries dataKey="total" pointStyle="colored-border" activePointStyle="border" />
|
|
794
563
|
```
|
|
795
564
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
`
|
|
818
|
-
|
|
819
|
-
`
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
`
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
## Heatmap
|
|
836
|
-
|
|
837
|
-
`HeatmapChart`, `HeatmapGrid`, `HeatmapLegend`, `HeatmapTooltip`, and `HeatmapDataTable` compose a two-dimensional categorical grid using native HTML table layout. They are independent of `Root` and Recharts chart contexts. The browser owns equal-cell geometry; ordered domains and data are consumer-owned. No new dependency or existing chart API change is required.
|
|
565
|
+
Any explicit native `dot` or `activeDot` value (including false, true, props,
|
|
566
|
+
renderer functions and elements) wins for its respective marker. Configured
|
|
567
|
+
LineChart accepts these options in its existing `series` objects; explicit
|
|
568
|
+
children retain ownership. `PointMarker` is a reusable native Dot renderer with
|
|
569
|
+
`variant` and native Dot props. Its variant paint wins the engine-supplied paint;
|
|
570
|
+
native radius/handlers remain intact, and SVG `style` can override its paint.
|
|
571
|
+
For example, `dot={<PointMarker variant="colored-border" style={{ fill: "white" }} />}`.
|
|
572
|
+
Native active-dot callbacks carry series paint in `fill`, while regular dots carry
|
|
573
|
+
it in `stroke`. When composing PointMarker as an active renderer, forward that
|
|
574
|
+
identity explicitly: `activeDot={(props) => <PointMarker {...props}
|
|
575
|
+
stroke={props.fill} variant="colored-border" />}`. The Series style API handles
|
|
576
|
+
this distinction automatically. Keyboard/pointer inspection remains chart-owned; the active mark retains its
|
|
577
|
+
existing non-intercepting behavior and reduced-motion policy. Radar's selection
|
|
578
|
+
dots and Scatter's symbols have separate contracts and do not accept these
|
|
579
|
+
series options. Bar, Pie and other shape families are outside this API.
|
|
580
|
+
|
|
581
|
+
Run `npm run dev:chart` and visit `/recipes.html#point-markers` for the marker gallery and
|
|
582
|
+
its accessible data table.
|
|
583
|
+
|
|
584
|
+
### Directional Line and Area entrances
|
|
585
|
+
|
|
586
|
+
`LineAnimation` and `AreaAnimation` accept `revealDirection`:
|
|
587
|
+
|
|
588
|
+
- `"left-to-right"` (default): expand from the left edge.
|
|
589
|
+
- `"right-to-left"`: expand from the right edge.
|
|
590
|
+
- `"center-out"`: expand equally from the horizontal center.
|
|
591
|
+
- `"edges-in"`: expand two edge regions toward the horizontal center.
|
|
592
|
+
|
|
593
|
+
Directions are physical horizontal screen-space reveals for both native layouts;
|
|
594
|
+
they do not reverse data order or follow a vertical category axis. Timing remains
|
|
595
|
+
`revealDurationMs` / `revealEasing`. The temporary family clip leaves native paths,
|
|
596
|
+
axes, margins and transforms intact. Explicit directional entrances remove the clip
|
|
597
|
+
on completion or interruption (including resize/data changes). Line with an omitted
|
|
598
|
+
direction preserves its existing completed full-width clip until interruption;
|
|
599
|
+
Area/Combo retain their existing completion removal. Disabled/reduced motion shows
|
|
600
|
+
complete content.
|
|
601
|
+
Existing loading illustrations keep their independent design. Replay uses the
|
|
602
|
+
existing remount or loading-to-ready lifecycle, not hover or color updates.
|
|
838
603
|
|
|
839
604
|
```tsx
|
|
840
605
|
import {
|
|
841
|
-
|
|
842
|
-
|
|
606
|
+
AreaChart, AreaSeries, ComboChart, LineChart, LineSeries, Root,
|
|
607
|
+
type SeriesConfig,
|
|
843
608
|
} from "@kind-ui/charts";
|
|
844
609
|
import "@kind-ui/charts/styles.css";
|
|
845
610
|
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
611
|
+
const data = [
|
|
612
|
+
{ day: "Mon", total: 12, forecast: 16 },
|
|
613
|
+
{ day: "Tue", total: 20, forecast: 24 },
|
|
614
|
+
];
|
|
615
|
+
const config = {
|
|
616
|
+
total: { label: "Total", color: "#3659b8" },
|
|
617
|
+
forecast: { label: "Forecast", color: "#0d9488" },
|
|
618
|
+
} satisfies SeriesConfig;
|
|
619
|
+
|
|
620
|
+
export function DirectionalCharts() {
|
|
621
|
+
return (
|
|
622
|
+
<Root config={config}>
|
|
623
|
+
<LineChart data={data} width={480} height={240} aria-label="Daily total"
|
|
624
|
+
animate={{ revealDirection: "right-to-left", revealDurationMs: 800 }}>
|
|
625
|
+
<LineSeries dataKey="total" pointStyle="border" />
|
|
626
|
+
</LineChart>
|
|
627
|
+
<AreaChart data={data} width={480} height={240} aria-label="Daily forecast"
|
|
628
|
+
animate={{ revealDirection: "center-out" }}>
|
|
629
|
+
<AreaSeries dataKey="forecast" />
|
|
630
|
+
</AreaChart>
|
|
631
|
+
<ComboChart data={data} width={480} height={240} aria-label="Total and forecast"
|
|
632
|
+
animate={{
|
|
633
|
+
revealDirection: "center-out",
|
|
634
|
+
lineReveal: { revealDirection: "right-to-left" },
|
|
635
|
+
areaReveal: { revealDirection: "edges-in", revealDurationMs: 1200 },
|
|
636
|
+
barReveal: false,
|
|
637
|
+
}}>
|
|
638
|
+
<LineSeries dataKey="total" />
|
|
639
|
+
<AreaSeries dataKey="forecast" />
|
|
640
|
+
</ComboChart>
|
|
641
|
+
</Root>
|
|
642
|
+
);
|
|
643
|
+
}
|
|
869
644
|
```
|
|
870
645
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
646
|
+
Combo inherits the chart direction for Line/Area unless the corresponding family
|
|
647
|
+
object overrides it; `false` disables that family entrance. Bar keeps its existing
|
|
648
|
+
entrance configuration. All managed series in a family share its entrance clip;
|
|
649
|
+
individual series rendering/visibility props remain available, but there is no
|
|
650
|
+
per-series direction prop. Explicit native children and consumer clip/shape
|
|
651
|
+
ownership retain their existing contracts. `RevealDirection` is exported for
|
|
652
|
+
consumer controls. The packed Line/Area motion fixtures accept `?direction=...`
|
|
653
|
+
and the Combo fixture accepts `?directional` to exercise the family overrides.
|
|
879
654
|
|
|
880
|
-
|
|
655
|
+
### Animated dashed lines
|
|
881
656
|
|
|
882
|
-
|
|
657
|
+
`LineSeries` accepts `dashAnimation={ { durationMs: 1000, direction: "forward" } }`
|
|
658
|
+
(or `false`, the default). Supply a native numeric `strokeDasharray`, such as
|
|
659
|
+
`"6 4"`; duration is milliseconds per full pattern cycle. `reverse` reverses
|
|
660
|
+
travel. Zero, negative or non-finite duration and nonnumeric/CSS/percentage dash
|
|
661
|
+
patterns stay static. Odd lists repeat twice per cycle, matching SVG.
|
|
883
662
|
|
|
884
|
-
|
|
663
|
+
```tsx
|
|
664
|
+
<LineChart data={rows} animate>
|
|
665
|
+
<LineSeries dataKey="total" strokeDasharray="6 4" strokeDashoffset={3}
|
|
666
|
+
dashAnimation={{ durationMs: 800 }} material="glow" />
|
|
667
|
+
</LineChart>
|
|
668
|
+
<ComboChart data={rows} animate>
|
|
669
|
+
<AreaSeries dataKey="total" stroke="none" fillOpacity={0.2} />
|
|
670
|
+
<LineSeries dataKey="total" dot={false} strokeDasharray="3 2 1"
|
|
671
|
+
dashAnimation={{ durationMs: 1200, direction: "reverse" }} />
|
|
672
|
+
</ComboChart>
|
|
673
|
+
```
|
|
885
674
|
|
|
886
|
-
|
|
675
|
+
Load the package stylesheet. Motion stops with chart `animate={false}`, reduced
|
|
676
|
+
motion, loading, or hidden series. Disabling restores the native dash offset;
|
|
677
|
+
reenabling starts a fresh cycle. Use `dashAnimation={false}` to disable an individual series. Native width, dash array, offset and
|
|
678
|
+
styles remain intact; style dash values take precedence. Custom shapes own their
|
|
679
|
+
animation and are never decorated. Entrance clip reveal timing is independent.
|
|
680
|
+
No geometry or data is changed, and CSS requires no mount timers or cleanup.
|
|
681
|
+
Stylesheets overriding dash paint remain consumer-owned and can change appearance.
|
|
682
|
+
|
|
683
|
+
`AreaSeries` does not accept this option: its closed perimeter includes baseline
|
|
684
|
+
and closing edges. For an open animated outline, overlay `LineSeries` in a
|
|
685
|
+
`ComboChart` as above. Match data keys, interpolation and axes yourself; stacked
|
|
686
|
+
or range areas require an explicitly derived outline dataset. See
|
|
687
|
+
`/contracts.html#dashed-lines` for the interactive line and combo contract examples.
|
|
688
|
+
|
|
689
|
+
### Initial Pie tooltip
|
|
690
|
+
|
|
691
|
+
`PieChart.defaultPinnedCategory="delivery"` opts into an initial tooltip for
|
|
692
|
+
one direct `PieSeries` (Fragments allowed) with explicit `data` and `categoryKey`.
|
|
693
|
+
Pair it with `Tooltip.itemKey={(entry) => entry.payload.id}` when `categoryKey="id"`;
|
|
694
|
+
caller labels, formatters, and the data table remain the source of truth.
|
|
695
|
+
Only Pie/donut compositions whose direct children are one Kind PieSeries and
|
|
696
|
+
one Kind Tooltip (optionally in Fragments) support this default. Native Pie, wrapped series, multiple rings, and other chart families
|
|
697
|
+
are outside this contract; missing category data/identity or multiple direct
|
|
698
|
+
series, duplicate/missing Tooltips, or unsupported direct children throw when resolving a pin.
|
|
699
|
+
|
|
700
|
+
The category string is captured on mount. Reorder resolves its current index;
|
|
701
|
+
unknown, duplicate, removed, hidden, or filtered categories clear the default
|
|
702
|
+
permanently. Restoring rows or changing the default prop does not re-pin; remount
|
|
703
|
+
explicitly to begin again. Pointer movement/down, focus, and any chart key press
|
|
704
|
+
clear the default and hand inspection/dismissal back to Recharts. Escape never
|
|
705
|
+
re-pins. No focus is moved or trapped. The existing tooltip is the sole readout
|
|
706
|
+
and live announcement; Kind adds no announcement region or hover selection.
|
|
707
|
+
Explicit Tooltip `active` and `defaultIndex` retain native ownership and take
|
|
708
|
+
precedence. Custom content owns its markup and accessibility. Omitted defaults
|
|
709
|
+
preserve existing behavior. See the weekly Pie in `examples/chart/pie-recipes.tsx`.
|
|
710
|
+
|
|
711
|
+
### Sankey node labels
|
|
712
|
+
|
|
713
|
+
Compose `SankeyNodeLabel` beside `SankeyNode` in the native `node` callback:
|
|
887
714
|
|
|
888
|
-
|
|
889
|
-
|
|
715
|
+
```tsx
|
|
716
|
+
node={(node) => (
|
|
717
|
+
<g>
|
|
718
|
+
<SankeyNode {...node} />
|
|
719
|
+
<SankeyNodeLabel node={node} data={data} position="outside" showValues
|
|
720
|
+
valueFormatter={(value) => `${value} MWh`} />
|
|
721
|
+
</g>
|
|
722
|
+
)}
|
|
723
|
+
```
|
|
890
724
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
`active`, `dimmed`, `factor`, `enter("pointer" | "keyboard")`, and `leave(channel)`
|
|
926
|
-
for renderers needing their own decoration. Apply `factor` through an extra paint
|
|
927
|
-
layer so existing opacity, transparent fills and motion multiply exactly once.
|
|
928
|
-
Neither API uses descendant rewriting or global selectors.
|
|
929
|
-
|
|
930
|
-
`Legend emphasis="series"` opts into series hover/focus emphasis for participating
|
|
931
|
-
marks with `seriesKey`; controlled visibility click behavior and custom item content
|
|
932
|
-
remain unchanged. Other chart families require an explicit mark adapter before
|
|
933
|
-
legend emphasis paints them. The default Legend does not emphasize series.
|
|
934
|
-
|
|
935
|
-
Pointer leave restores the retained keyboard candidate. Explicit legend/custom keyboard/focus
|
|
936
|
-
emphasis supersedes hover; Escape clears transient emphasis without changing
|
|
937
|
-
controlled selection. Touch has no new tap/click behavior. Dimming keeps marks
|
|
938
|
-
hittable and uses a 160ms interruptible opacity transition; reduced motion removes
|
|
939
|
-
the transition. Import `@kind-ui/charts/styles.css` for these defaults.
|
|
940
|
-
|
|
941
|
-
The public packed recipe in `tests/fixtures/emphasis` demonstrates category,
|
|
942
|
-
sector, custom portal, visibility, and independent-plot composition. Supported adapters are listed in the matrix above.
|
|
943
|
-
|
|
944
|
-
Identity relationships: `dataKey` selects measured values; it is not a category ID.
|
|
945
|
-
`seriesKey` selects Root metadata and controlled series visibility (or a string
|
|
946
|
-
`dataKey` supplies that series key). `emphasisKey` selects the stable datum ID.
|
|
947
|
-
Pie sector visibility remains consumer-owned through its supplied data/Cells;
|
|
948
|
-
Root visibility does not rewrite Pie data. A custom mark must use `enabled={false}`
|
|
949
|
-
when its owning consumer hides or removes it. Emphasis registration represents
|
|
950
|
-
paint that is currently present, rather than a second persistent selection model.
|
|
951
|
-
|
|
952
|
-
A pointer candidate temporarily takes precedence over a retained keyboard
|
|
953
|
-
candidate. A new explicit legend/custom keyboard/focus action supersedes pointer emphasis;
|
|
954
|
-
leaving that hover restores the retained candidate. Native chart focus/blur and
|
|
955
|
-
Escape reconcile these transient candidates without invoking selection callbacks.
|
|
956
|
-
Touch-induced focus does not create keyboard emphasis. Native active marks may
|
|
957
|
-
move between Recharts portals; clearing uses semantic identity across that move.
|
|
958
|
-
|
|
959
|
-
Native overlap limitation: Recharts' public tooltip inspection prioritizes an
|
|
960
|
-
active mouse hover over keyboard state. When the pointer remains on category A
|
|
961
|
-
and keyboard arrows run, native tooltip data and Kind emphasis can both remain
|
|
962
|
-
on A. Clean keyboard entry advances normally. Kind does not maintain a second
|
|
963
|
-
keyboard index, dispatch synthetic consumer events, or use private engine state.
|
|
964
|
-
Full pointer/keyboard equivalence is not claimed. After pointer exit, retained
|
|
965
|
-
keyboard emphasis represents the last eligible inspection candidate; the native
|
|
966
|
-
tooltip may close. This bounded preview follows native selection ownership.
|
|
725
|
+
Optional `SankeyNodeConfig` entries accept an `icon: ReactNode`. Pass that config
|
|
726
|
+
explicitly as `SankeyNodeLabel`'s `nodeConfig` in your native callback (see the
|
|
727
|
+
energy example in `examples/chart/sankeys.tsx`). Icons use a square `iconSize`
|
|
728
|
+
(default 16 chart units) SVG viewport with `viewBox="0 0 24 24"`; supply SVG
|
|
729
|
+
content, or a nested SVG with its own viewBox. `iconGap` defaults to 4 units.
|
|
730
|
+
Outside icons sit nearest the node and shift the text by size plus gap on either
|
|
731
|
+
side. Inside icons stack above centered text and share its exact rectangle clip;
|
|
732
|
+
small nodes can clip both. Reserve outside margins for the combined content.
|
|
733
|
+
Missing, null, boolean or zero-size icons preserve the existing text layout.
|
|
734
|
+
Sizes and gaps must be finite and nonnegative. Icons are decorative (`aria-hidden`,
|
|
735
|
+
nonfocusable); data names and full name/value titles remain meaningful, and the
|
|
736
|
+
data table remains the accessible alternative. Config labels remain Legend metadata.
|
|
737
|
+
Custom text children compose with the icon; text props/ref still target the text.
|
|
738
|
+
A custom native node renderer owns all rendering: nothing is injected unless it
|
|
739
|
+
chooses this helper, and omitting `nodeConfig` opts out of configured icons.
|
|
740
|
+
|
|
741
|
+
Identity is resolved by `node.payload.id` against `data`, never callback index or
|
|
742
|
+
name. Supply the same data to the chart, label and `SankeyTable`, and reuse the
|
|
743
|
+
formatter as the table's `formatValue`. A node value is the maximum of incoming
|
|
744
|
+
and outgoing flow sums: sources use outgoing, sinks incoming, balanced intermediate
|
|
745
|
+
nodes count throughput once, and disconnected or measured-zero nodes total zero.
|
|
746
|
+
Existing data validation rejects unbalanced intermediate nodes outside its rounding
|
|
747
|
+
tolerance; the larger sum handles that tolerance consistently with native sizing.
|
|
748
|
+
No extra totals or inferred flows are added to the table.
|
|
749
|
+
|
|
750
|
+
`position="inside"` centers text and clips it to the exact node rectangle, including
|
|
751
|
+
small or zero-size nodes. It does not shrink text, expand geometry or avoid collisions.
|
|
752
|
+
Use outside labels for narrow nodes; they default right for sources/intermediates and
|
|
753
|
+
left for sinks. `side`, `offset`, native text props, styles and refs remain consumer-owned.
|
|
754
|
+
Reserve margins for outside text; the native SVG viewport still clips overflow.
|
|
755
|
+
The full name/value remains in a SVG title even when inside text clips. Keep the table
|
|
756
|
+
as the complete accessible data alternative. Custom `children` (including `tspan`)
|
|
757
|
+
replace visual text while preserving the default title. No label or animation is
|
|
758
|
+
installed implicitly. `/sankeys.html` demonstrates both positions.
|