@kind-ui/charts 0.1.1 → 0.3.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 +683 -1
- 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-material.js +2 -3
- 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 +4 -2
- package/dist/heatmap.js +34 -12
- package/dist/histogram-chart.js +10 -3
- package/dist/histogram-material.js +1 -2
- 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-material.d.ts +1 -1
- package/dist/line-material.js +1 -1
- package/dist/line-series.d.ts +9 -1
- package/dist/line-series.js +37 -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-material.js +1 -1
- 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 +138 -15
- 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-material.js +1 -1
- 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-finish.d.ts +1 -1
- package/dist/sankey-finish.js +1 -1
- 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-material.js +1 -1
- 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 -6
- package/dist/stylesheet-warning.d.ts +2 -0
- package/dist/stylesheet-warning.js +86 -0
- package/dist/surface-material.js +1 -1
- 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/dist/bar-paper.d.ts +0 -2
- package/dist/bar-paper.js +0 -6
package/README.md
CHANGED
|
@@ -28,7 +28,38 @@ npm install @kind-ui/charts
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Import `@kind-ui/charts/styles.css` once at your application entry. In Next.js,
|
|
31
|
-
place interactive chart code in a client component.
|
|
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.
|
|
35
|
+
|
|
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.
|
|
44
|
+
|
|
45
|
+
## Materials
|
|
46
|
+
|
|
47
|
+
Charts support Default, Clay and Glow. The Default material keeps the public
|
|
48
|
+
`plain` token and native chart paint; `material="clay"` and `material="glow"`
|
|
49
|
+
opt into decorative finishes. Sankey uses the same tokens through `finish`.
|
|
50
|
+
Omitting either prop selects Default. Paper has been removed in the 0.3.0 API;
|
|
51
|
+
replace `material="paper"` or `finish="paper"` with `"plain"`, `"clay"` or `"glow"`.
|
|
52
|
+
Consumer-supplied shapes, filters and paint retain ownership.
|
|
53
|
+
|
|
54
|
+
## Series labels
|
|
55
|
+
|
|
56
|
+
Configuration keys must match the series `dataKey` (or its explicit `seriesKey`).
|
|
57
|
+
When `label` is omitted, built-in labels use the matching key: `visitors` becomes
|
|
58
|
+
`Visitors` and `monthlyVisitors` becomes `Monthly visitors`. Camel-case and acronym
|
|
59
|
+
boundaries, underscores and hyphens become spaces; words are lowercased, then the
|
|
60
|
+
first letter is capitalized. Supply an explicit label to preserve custom casing
|
|
61
|
+
or wording, including an intentionally empty label. Keys and colors are unchanged.
|
|
62
|
+
Category charts use their configured category identity for this inference.
|
|
32
63
|
|
|
33
64
|
## Quick start
|
|
34
65
|
|
|
@@ -80,6 +111,657 @@ for composition and customization. The documentation covers chart selection,
|
|
|
80
111
|
peer requirements, styling, motion and accessibility; applications own their
|
|
81
112
|
data, domains and business state.
|
|
82
113
|
|
|
114
|
+
### Loading chart data
|
|
115
|
+
|
|
116
|
+
All chart families accept `loading?: boolean` alongside `animate`, plus
|
|
117
|
+
`loadingLabel?: string` (default “Loading chart”). Import the default stylesheet.
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<LineChart
|
|
121
|
+
config={config}
|
|
122
|
+
data={rows}
|
|
123
|
+
xDataKey="month"
|
|
124
|
+
height={280}
|
|
125
|
+
aria-label="Monthly sales"
|
|
126
|
+
animate={{ revealDurationMs: 650 }}
|
|
127
|
+
loading={pending}
|
|
128
|
+
loadingLabel="Loading monthly sales"
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Pass the same props directly to composed chart roots inside the existing `Root`
|
|
133
|
+
and native sizing/composition. Supported families: Line, Area, Bar, Combo, Pie,
|
|
134
|
+
Radar, RadialBar, Scatter, Heatmap, Waterfall, Histogram, BoxPlot, ActivityRings
|
|
135
|
+
and Sankey. Each uses its own decorative chart silhouette independent of your data.
|
|
136
|
+
Pulse-based skeletons choose a clearly different bounded profile while fully hidden;
|
|
137
|
+
their geometry stays stable through renders and resize between pulses. A soft leading reveal and
|
|
138
|
+
trailing fade overlap, following the chart’s native entrance duration, easing and
|
|
139
|
+
direction: horizontal paths and left-to-right bar-family windows, angular sectors,
|
|
140
|
+
ordered point/cell opacity or directional flow. Radar keeps two six-vertex polygons
|
|
141
|
+
visible and smoothly morphs between bounded decorative shapes; reduced motion
|
|
142
|
+
holds both still. RadialBar keeps continuous angular velocity through its closing seam. Combo preserves separate family
|
|
143
|
+
reveal options. Pulse timing includes room for the trail to leave and a hidden
|
|
144
|
+
geometry swap; loading never delays actual completion.
|
|
145
|
+
Reduced motion displays a static silhouette.
|
|
146
|
+
|
|
147
|
+
Actual chart content remains mounted, sized, hidden and inert while pending.
|
|
148
|
+
The chart exposes `aria-busy` and a separate live status. Native axes, series,
|
|
149
|
+
refs, style and event ownership stay with the consumer. External legends remain
|
|
150
|
+
available. Heatmap uses its table viewport; Sankey uses its native flow container;
|
|
151
|
+
polar illustrations retain circular proportions. Skeletons have no values,
|
|
152
|
+
labels or tooltip targets.
|
|
153
|
+
|
|
154
|
+
Completion immediately restores actual data and rearms the family’s existing
|
|
155
|
+
entrance when `animate` enables it. There is no forced wait or queued completion.
|
|
156
|
+
Empty data does not imply loading: render an explicit empty-result message after
|
|
157
|
+
completion. Loading does not change validation of supplied chart data. Requests,
|
|
158
|
+
cancellation, retries, partial results, errors and portals outside the native
|
|
159
|
+
chart remain host-owned. Supply an accessible data alternative alongside charts.
|
|
160
|
+
|
|
161
|
+
Run `npm run dev:chart` and open `/loading.html` for all-family replay, load,
|
|
162
|
+
empty-input, resize and interrupted-update controls.
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
## Selective Pie glow
|
|
166
|
+
|
|
167
|
+
`PieSeries` accepts `glowCategories?: readonly string[]` with `categoryKey` and
|
|
168
|
+
explicit data. For a rounded donut, add `glowCategories={["design"]}` to
|
|
169
|
+
`<PieSeries data={data} dataKey="hours" categoryKey="key" nameKey="key"
|
|
170
|
+
innerRadius={58} outerRadius={108} cornerRadius={8} paddingAngle={2} />`.
|
|
171
|
+
The IDs resolve through the existing category config contract. Unknown or removed
|
|
172
|
+
IDs do nothing; reorder/filter preserve colors and membership. Selected default
|
|
173
|
+
sectors use glow; others retain `material` (Default, token `plain`). Native custom paint,
|
|
174
|
+
shapes and handlers retain ownership. Keep labels and a data alternative.
|
|
175
|
+
|
|
83
176
|
## License
|
|
84
177
|
|
|
85
178
|
[MIT](LICENSE) © 2026 Bhavesh Chowdhury.
|
|
179
|
+
|
|
180
|
+
### Patterned bar fills
|
|
181
|
+
|
|
182
|
+
`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.
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
const config = {
|
|
186
|
+
actual: { color: "#789abc", pattern: { kind: "hatch" as const } },
|
|
187
|
+
planned: { color: "#ed79ae", pattern: { kind: "stripe" as const } },
|
|
188
|
+
};
|
|
189
|
+
<Root config={config}>
|
|
190
|
+
<Legend />
|
|
191
|
+
<BarChart data={rows} width={480} height={260}>
|
|
192
|
+
<XAxis dataKey="category" />
|
|
193
|
+
<YAxis />
|
|
194
|
+
<BarSeries dataKey="actual" material="clay" />
|
|
195
|
+
<BarSeries dataKey="planned" pattern={{ kind: "duotone", color: "CanvasText" }} />
|
|
196
|
+
</BarChart>
|
|
197
|
+
</Root>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
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.
|
|
201
|
+
|
|
202
|
+
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.
|
|
203
|
+
|
|
204
|
+
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.
|
|
205
|
+
|
|
206
|
+
### Theme-aware series colors
|
|
207
|
+
|
|
208
|
+
`SeriesColor` accepts a CSS color string, a readonly nonempty array of CSS color
|
|
209
|
+
strings, or `{ light, dark }` containing either shape. Arrays are gradient stops,
|
|
210
|
+
not categorical palettes: supply separate config keys for category identities.
|
|
211
|
+
Stops are evenly distributed from 0 to 100%; a single stop is solid. Each theme's
|
|
212
|
+
spacing is preserved when stop counts differ (intermediate colors use CSS
|
|
213
|
+
`color-mix(in srgb, ...)`). Empty arrays, sparse arrays, empty strings and incomplete
|
|
214
|
+
or unknown theme fields throw. Errors identify the series and color property (including
|
|
215
|
+
the theme and stop index when applicable), without printing color values or unrelated
|
|
216
|
+
config metadata. For example, an empty second dark stop reports
|
|
217
|
+
`config["revenue"].color.dark[1] requires a nonempty color string`.
|
|
218
|
+
CSS color syntax remains the browser's responsibility: CSS variables, `currentColor`
|
|
219
|
+
and modern color functions pass through unchanged, including during server rendering.
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
const config = {
|
|
223
|
+
revenue: {
|
|
224
|
+
color: { light: ["var(--brand)", "#2563eb"], dark: ["#fef3c7", "#f59e0b", "#92400e"] },
|
|
225
|
+
},
|
|
226
|
+
} satisfies SeriesConfig;
|
|
227
|
+
|
|
228
|
+
// Change colorScheme on this host without changing Root's key or remounting it.
|
|
229
|
+
<div style={{ colorScheme: dark ? "dark" : "light", "--brand": "#f59e0b" }}>
|
|
230
|
+
<Root config={config}>
|
|
231
|
+
<Legend />
|
|
232
|
+
<LineChart data={data} width={480} height={240}>
|
|
233
|
+
<XAxis dataKey="month" />
|
|
234
|
+
<YAxis />
|
|
235
|
+
<LineSeries dataKey="revenue" />
|
|
236
|
+
<Tooltip content={(tooltip) => <TooltipContent tooltip={tooltip} />} />
|
|
237
|
+
</LineChart>
|
|
238
|
+
</Root>
|
|
239
|
+
</div>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Themes follow the inherited CSS `color-scheme`, using native `light-dark()`;
|
|
243
|
+
without a host scheme the browser defaults to light. Set `color-scheme: light dark`
|
|
244
|
+
on a host for system preference, or `light`/`dark` for an explicit application
|
|
245
|
+
choice.
|
|
246
|
+
|
|
247
|
+
Browser syntax requirements (from MDN compatibility data):
|
|
248
|
+
|
|
249
|
+
| Generated CSS | Chrome / Edge | Firefox | Safari / iOS Safari |
|
|
250
|
+
| --- | --- | --- | --- |
|
|
251
|
+
| [`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+ |
|
|
252
|
+
| [`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+ |
|
|
253
|
+
| [`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+ |
|
|
254
|
+
|
|
255
|
+
For themed gradients including matching swatches, use Chrome/Edge 123+, Firefox
|
|
256
|
+
127+, or Safari/iOS Safari 17.5+. These are syntax minimums, not a tested-browser
|
|
257
|
+
matrix; supplied color values can have additional requirements.
|
|
258
|
+
|
|
259
|
+
There is no polyfill, feature detection or automatic light/first-stop fallback.
|
|
260
|
+
Unsupported functions make the consuming paint or swatch declaration invalid;
|
|
261
|
+
SVG paints/stops can use their CSS initial or inherited values, and gradient
|
|
262
|
+
swatches can lose their background image. For older browsers, supply supported
|
|
263
|
+
plain color strings (or CSS variables with host-controlled light/dark values)
|
|
264
|
+
instead of themed objects. Unthemed stop arrays avoid generated `light-dark()`
|
|
265
|
+
and `color-mix()`, but their swatches still require the gradient syntax above.
|
|
266
|
+
|
|
267
|
+
Root retains `--color-<key>` as the first stop, emits zero-based
|
|
268
|
+
`--kind-ui-series-<encoded-key>-<index>` stops and a `-gradient` CSS swatch
|
|
269
|
+
token, where encoded keys are hexadecimal Unicode code points joined by hyphens.
|
|
270
|
+
This namespace cannot collide with another series' legacy `--color-<key>`.
|
|
271
|
+
Built-in series/category paints use uniquely scoped resources in each chart SVG; gradients run
|
|
272
|
+
left to right across the SVG viewport (including flat line geometry). Legend and
|
|
273
|
+
solid tooltip markers display the full gradient; dashed tooltip borders use the
|
|
274
|
+
first stop. Explicit native stroke/fill, styles, Cells and shapes retain their
|
|
275
|
+
existing ownership; configured bar patterns take precedence and use the first
|
|
276
|
+
stop as their solid base ink (the legend pattern swatch does the same). Native
|
|
277
|
+
explicit pattern colors remain consumer-owned. Icons keep priority. Strings and one-stop definitions require
|
|
278
|
+
no SVG resource. Consumer Root styles override generated tokens as before; override
|
|
279
|
+
indexed stops to customize a gradient. No theme subscription or remount is needed.
|
|
280
|
+
|
|
281
|
+
The runnable `tests/fixtures/identity-colors` host exercises explicit light/dark
|
|
282
|
+
changes, unequal stops, CSS variable colors, multiple roots and native paint
|
|
283
|
+
precedence (`npm exec vite tests/fixtures/identity-colors`, open `/?theme`).
|
|
284
|
+
|
|
285
|
+
### Area patterns
|
|
286
|
+
|
|
287
|
+
`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`.
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
const config = {
|
|
291
|
+
actual: { color: "#789abc", pattern: { kind: "dots" as const, width: 2 } },
|
|
292
|
+
planned: { color: "var(--area-planned)", pattern: { kind: "lines" as const } },
|
|
293
|
+
};
|
|
294
|
+
<Root config={config}>
|
|
295
|
+
<Legend />
|
|
296
|
+
<AreaChart width={480} height={260} data={rows}>
|
|
297
|
+
<XAxis dataKey="month" />
|
|
298
|
+
<YAxis />
|
|
299
|
+
<AreaSeries dataKey="actual" stackId="total" material="clay" fillOpacity={0.4} />
|
|
300
|
+
<AreaSeries dataKey="planned" stackId="total" fillOpacity={0.4} />
|
|
301
|
+
</AreaChart>
|
|
302
|
+
</Root>;
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
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.
|
|
306
|
+
|
|
307
|
+
The existing Next integration fixture additionally checks real server-rendered
|
|
308
|
+
color resource IDs through hydration and a theme change.
|
|
309
|
+
|
|
310
|
+
## Legend and mark interactions
|
|
311
|
+
|
|
312
|
+
Visibility remains the default. Opt into persistent focus with one Root owner:
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
<Root config={config} interaction={{
|
|
316
|
+
kind: "series", mode: "focus", eligibleKeys: ["revenue", "costs"],
|
|
317
|
+
markActivation: "matching-legend", defaultSelected: "revenue",
|
|
318
|
+
onSelectionChange: (key) => console.log(key),
|
|
319
|
+
}}>
|
|
320
|
+
<BarChart data={rows} width={400} height={240}>
|
|
321
|
+
<BarSeries dataKey="revenue" /><BarSeries dataKey="costs" />
|
|
322
|
+
</BarChart>
|
|
323
|
+
<Legend emphasis="series" />
|
|
324
|
+
</Root>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
`interaction` binds a `kind` (`series`, `category`, or focus-only `node`) to a
|
|
328
|
+
settled `eligibleKeys` snapshot. Include hidden Root items and zero values; exclude
|
|
329
|
+
removed, filtered, unavailable, or native-hidden items. Config-only entries do not
|
|
330
|
+
satisfy the last-visible guard. New bindings require that snapshot; native series
|
|
331
|
+
registration provides compatibility eligibility for existing controlled legends.
|
|
332
|
+
`mode` defaults to `visibility`; `markActivation` defaults to `none`.
|
|
333
|
+
|
|
334
|
+
Focus accepts either `selected` with required `onSelectionChange`, or
|
|
335
|
+
`defaultSelected` with an optional callback. Persistent focus works with
|
|
336
|
+
`emphasis="none"`. Repeated activation or Escape clears it; transient inspection
|
|
337
|
+
never writes selection. Invalid uncontrolled selection clears without a callback.
|
|
338
|
+
An invalid controlled ID paints no selection and resumes if that ID becomes valid.
|
|
339
|
+
Visibility uses existing `visibleSeries`/`onVisibleSeriesChange`, or opt-in
|
|
340
|
+
`defaultVisibleSeries`. An externally empty visibility value remains valid.
|
|
341
|
+
|
|
342
|
+
For categories, use `kind: "category"` and explicitly set
|
|
343
|
+
`interactionBinding="root"` on `PieSeries` or `RadialBarChart`, with `categoryKey`
|
|
344
|
+
and explicit data. Stable unique string keys must match Root config. Hiding filters
|
|
345
|
+
original rows and their positional Cells before layout; Pie re-normalizes angles.
|
|
346
|
+
ActivityRings forwards this binding through category `rootProps.interaction`.
|
|
347
|
+
For Sankey node focus, bind both `SankeyChart` and `SankeyLegend` to a Root with
|
|
348
|
+
`kind: "node", mode: "focus"`; incident links/endpoints remain emphasized.
|
|
349
|
+
Sankey visibility, link selection, and persistent Heatmap cell selection are excluded.
|
|
350
|
+
|
|
351
|
+
`useChartInteraction()` exposes `selected`, `visible`, `mode`, `kind`, `eligible`,
|
|
352
|
+
`activate({kind, key}, "legend" | "mark", event?)`, and `reset(event?)` for custom
|
|
353
|
+
controls. Actions return whether accepted. Consumer native handlers run first;
|
|
354
|
+
`preventDefault()` or `onBeforeInteraction(request)` returning `false` vetoes.
|
|
355
|
+
Reset also runs the before hook. Accepted actions emit one mode-specific callback
|
|
356
|
+
and one scoped polite announcement. Rejected last-hide actions announce the reason
|
|
357
|
+
without changing state or calling the change callback. Custom renderers retain
|
|
358
|
+
ownership and can use the helper to bind their own controls/paint.
|
|
359
|
+
|
|
360
|
+
Radar's existing local `selection="series"` remains a compatibility path, also
|
|
361
|
+
independent of transient emphasis. Combining it or its selection callbacks with
|
|
362
|
+
Root focus throws: choose one owner. Selection ownership stays fixed while mounted;
|
|
363
|
+
remount when changing controlled/uncontrolled ownership.
|
|
364
|
+
|
|
365
|
+
## Decorative chart backgrounds
|
|
366
|
+
|
|
367
|
+
`ChartBackgroundPattern` is optional Cartesian plot chrome, independent of
|
|
368
|
+
`FillPattern` series encoding, legends, visibility and materials. Its transparent
|
|
369
|
+
tiles contain only decorative ink; series are painted above it. It uses Recharts'
|
|
370
|
+
plot area (excluding margins and axes), a scoped clip path and SVG IDs, and the
|
|
371
|
+
[Recharts layer contract](https://recharts.github.io/en-US/guide/zIndex/) just below
|
|
372
|
+
the default grid. Custom negative series/grid z-index overrides remain caller-owned.
|
|
373
|
+
It adds no layout, axes, tooltip payload, animation or accessibility semantics.
|
|
374
|
+
The stylesheet prevents descendant pointer interception.
|
|
375
|
+
|
|
376
|
+
Generated configured LineChart opts in with:
|
|
377
|
+
|
|
378
|
+
```tsx
|
|
379
|
+
<Chart.LineChart
|
|
380
|
+
config={config}
|
|
381
|
+
data={data}
|
|
382
|
+
xDataKey="month"
|
|
383
|
+
aria-label="Monthly totals"
|
|
384
|
+
backgroundPattern={{ pattern: "pinpoints", opacity: 0.15 }}
|
|
385
|
+
/>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Explicit composition uses the part inside the chart. Configured explicit children
|
|
389
|
+
replace generated parts, so do not also pass `backgroundPattern`:
|
|
390
|
+
|
|
391
|
+
```tsx
|
|
392
|
+
<Chart.Root config={config}>
|
|
393
|
+
<Chart.BarChart data={data} responsive style={{ width: "100%", height: 280 }}>
|
|
394
|
+
<Chart.ChartBackgroundPattern pattern="crossings" size={20} opacity={0.12} />
|
|
395
|
+
<Chart.XAxis dataKey="month" />
|
|
396
|
+
<Chart.YAxis />
|
|
397
|
+
<Chart.BarSeries dataKey="total" />
|
|
398
|
+
<Chart.Tooltip />
|
|
399
|
+
</Chart.BarChart>
|
|
400
|
+
</Chart.Root>
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Presets are `pinpoints`, `crossings` and `waves`. `size` is a positive finite tile
|
|
404
|
+
size in SVG user units (default 16), and `opacity` is finite in [0, 1] (default
|
|
405
|
+
0.15). Zero opacity is supported. `color` accepts CSS paint, including theme
|
|
406
|
+
variables; the default is `var(--kind-ui-chart-grid, CanvasText)`. Resize changes
|
|
407
|
+
the plot rectangle and clip, preserving tile density and IDs. Missing or empty
|
|
408
|
+
plot geometry renders nothing; invalid options throw even before geometry exists.
|
|
409
|
+
|
|
410
|
+
Custom registration is consumer-owned and immutable: define reusable patterns in
|
|
411
|
+
a local module or catalog, then pass the definition directly. No global registry,
|
|
412
|
+
provider, series metadata or side-effect registration is required:
|
|
413
|
+
|
|
414
|
+
```tsx
|
|
415
|
+
const cornerMarks = Chart.defineChartBackgroundPattern(({ size, color, idPrefix }) => (
|
|
416
|
+
<g id={`${idPrefix}-tile`}>
|
|
417
|
+
<path d={`M0 ${size / 3}V0H${size / 3}`} fill="none" stroke={color} />
|
|
418
|
+
</g>
|
|
419
|
+
));
|
|
420
|
+
const backgrounds = { cornerMarks }; // optional local catalog
|
|
421
|
+
|
|
422
|
+
<Chart.ChartBackgroundPattern pattern={backgrounds.cornerMarks} size={24} opacity={0.1} />;
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
The render escape hatch returns tile SVG children, not a full chart or pattern
|
|
426
|
+
element. Use the supplied `size`, `color`, and per-instance `idPrefix`; suffix
|
|
427
|
+
custom resource IDs and reference those scoped IDs. Keep custom output decorative:
|
|
428
|
+
no links, focusable elements, event handlers, portals or independent z-index
|
|
429
|
+
layers. The callback is trusted consumer code, not an SVG sanitizer.
|
|
430
|
+
|
|
431
|
+
Supported composition hosts are Line, Bar (including Waterfall), Area, Combo,
|
|
432
|
+
Scatter, Histogram and BoxPlot charts using the native Cartesian plot area.
|
|
433
|
+
Generated configuration is available only for LineChart. Polar, Pie, Sankey,
|
|
434
|
+
Heatmap and ActivityRings are outside this contract. Fixed-size chart SSR retains
|
|
435
|
+
the existing native empty shell; this part does not create server plot geometry.
|
|
436
|
+
### Projected bar rows
|
|
437
|
+
|
|
438
|
+
`BarSeries<DataPoint, Value>.projection` is opt-in:
|
|
439
|
+
`{ isProjected: (datum: DataPoint) => boolean, pattern: FillPattern }`.
|
|
440
|
+
The caller supplies values and selects identity; Kind UI generates no forecasts.
|
|
441
|
+
For a trailing projection, capture the final row's stable ID before filtering or
|
|
442
|
+
reordering, then compare that ID in `isProjected`. It never implicitly marks the
|
|
443
|
+
new last visible row. Multiple selected identities are allowed.
|
|
444
|
+
|
|
445
|
+
```tsx
|
|
446
|
+
const projectedId = originalRows.at(-1)?.id;
|
|
447
|
+
const projection: BarProjection<Row> = {
|
|
448
|
+
isProjected: (row) => projectedId !== undefined && row.id === projectedId,
|
|
449
|
+
pattern: { kind: "hatch" },
|
|
450
|
+
};
|
|
451
|
+
// Use in grouped bars or share it across series with the same stackId.
|
|
452
|
+
<BarSeries<Row, number> dataKey="value" projection={projection} />;
|
|
453
|
+
<Tooltip content={(tooltip) => (
|
|
454
|
+
<TooltipContent tooltip={tooltip}
|
|
455
|
+
isProjected={(entry) => projection.isProjected(entry.payload)} />
|
|
456
|
+
)} />;
|
|
457
|
+
// In the consumer-owned table, alongside the unchanged numeric value:
|
|
458
|
+
<td>{projection.isProjected(row) ? "Projected" : "Observed"}</td>;
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Selection applies to chart rows or explicitly supplied `BarSeries.data` in both
|
|
462
|
+
orientations. Empty chart data produces no marks. Native empty `BarSeries.data` overrides
|
|
463
|
+
inherit chart rows; projection follows the actual displayed payload. Null/undefined
|
|
464
|
+
rows are never passed
|
|
465
|
+
to the selector. Missing values retain native missing-bar behavior, and filtering
|
|
466
|
+
out a selected identity does not select a replacement. Zero remains zero. Keep
|
|
467
|
+
predicates pure and IDs unique; row indices do not offer reorder-stable identity.
|
|
468
|
+
|
|
469
|
+
Projection fills use the existing `FillPattern` seam and native Rectangle shape
|
|
470
|
+
props, so Brush slices cannot shift identity as positional Cells would. Unselected rows retain
|
|
471
|
+
configured/explicit series patterns and full gradient paints. Projection tiles
|
|
472
|
+
use the configured theme's solid first stop (`--color-key`), the same documented
|
|
473
|
+
fallback as ordinary Bar/Area pattern tiles. `pattern={false}` disables automatic
|
|
474
|
+
projection paint. Explicit series `fill`/`style.fill`, native shape options,
|
|
475
|
+
custom shapes/active shapes and any explicit Cell composition retain paint
|
|
476
|
+
ownership. Datum `fill`/`style.fill` also prevents automatic projection paint for
|
|
477
|
+
that row. Compose Cells yourself for custom per-row painting.
|
|
478
|
+
|
|
479
|
+
`TooltipContent.isProjected(entry)` shares caller selection but receives the
|
|
480
|
+
native tooltip entry, including its original payload. Projected items append
|
|
481
|
+
accessible text (`projectedLabel`, default `"Projected"`) without modifying
|
|
482
|
+
values, labels, formatter behavior or config. Custom tooltip content and data
|
|
483
|
+
alternatives must expose status themselves, even when custom paint overrides it.
|
|
484
|
+
The runnable public consumer example is the packed Bar fixture at
|
|
485
|
+
`/?projection` (add `&horizontal` for horizontal bars); it includes table status,
|
|
486
|
+
stacking, filtering, reorder and ownership controls. Configured series metadata
|
|
487
|
+
continues to own ordinary patterns; projection is a per-Series composition prop,
|
|
488
|
+
not global config or a generated-data recipe.
|
|
489
|
+
|
|
490
|
+
### Percentage stack formatting
|
|
491
|
+
|
|
492
|
+
`createPercentStack({ values })` opts into formatting for scalar native
|
|
493
|
+
`stackOffset="expand"` Bar, Area and Combo stacks. Geometry, domains, axes and
|
|
494
|
+
stack membership remain caller-owned. It returns `tickFormatter` and
|
|
495
|
+
`normalizedValue`; no rows, series, native values or native tooltip payloads are
|
|
496
|
+
rewritten. Native Recharts still normalizes geometry exactly once.
|
|
497
|
+
|
|
498
|
+
```tsx
|
|
499
|
+
const percent = createPercentStack({
|
|
500
|
+
values: (entry) => {
|
|
501
|
+
// Select this stack, excluding the Combo's latency line and other axes.
|
|
502
|
+
if (entry.dataKey !== "desktop" && entry.dataKey !== "mobile") return undefined;
|
|
503
|
+
const row = entry.payload as { desktop: number; mobile: number } | undefined;
|
|
504
|
+
return row ? [row.desktop, row.mobile] : undefined;
|
|
505
|
+
},
|
|
506
|
+
});
|
|
507
|
+
// Vertical columns / ordinary Areas: the numeric Y axis only.
|
|
508
|
+
<YAxis yAxisId="share" tickFormatter={percent.tickFormatter} />;
|
|
509
|
+
// Horizontal bars (layout="vertical"): the numeric X axis only.
|
|
510
|
+
<XAxis type="number" tickFormatter={percent.tickFormatter} />;
|
|
511
|
+
<Tooltip normalizedValue={percent.normalizedValue} />;
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
Only attach the formatter to an axis whose units are fractions. Other axes keep
|
|
515
|
+
native ticks. A shared axis containing raw and fraction units needs a caller
|
|
516
|
+
chosen scale/domain; this helper cannot reconcile those units. Custom ticks and
|
|
517
|
+
`tickFormatter` stay native and caller-owned. `formatPercent(fraction)` is also
|
|
518
|
+
exported (one decimal at most, no locale-dependent output).
|
|
519
|
+
|
|
520
|
+
`values(entry)` must return the **raw members of that entry's own stack**, including
|
|
521
|
+
its value, or `undefined` for unrelated entries. Use native datum identity, stack
|
|
522
|
+
and axis selection where keys overlap. Match current native hidden-series
|
|
523
|
+
membership; do not sum the tooltip payload, which can contain unrelated stacks,
|
|
524
|
+
axes or lines. Update membership alongside controlled legends. Range values,
|
|
525
|
+
numeric strings and nonfinite values are outside the helper's scalar contract.
|
|
526
|
+
|
|
527
|
+
The helper uses the signed sum, matching native expand: missing members contribute
|
|
528
|
+
zero to the denominator but remain missing in content; all-zero rows display 0%;
|
|
529
|
+
negative fractions remain signed, with no absolute-value conversion or clamping.
|
|
530
|
+
A cancelling zero sum with nonzero members has no defined share and retains raw
|
|
531
|
+
formatting. Invalid/nonfinite totals or entries also retain raw formatting.
|
|
532
|
+
Native negative geometry/domain behavior remains native; this API does not promise
|
|
533
|
+
a 0–100% domain for negative data or fabricate absent values.
|
|
534
|
+
|
|
535
|
+
`Tooltip` and `TooltipContent` accept `normalizedValue(entry): number | undefined`.
|
|
536
|
+
Default content shows `25% (1)` with the original value in parentheses, using
|
|
537
|
+
configured `formatValue` for that raw text when present. Explicit entry/native
|
|
538
|
+
`formatter` takes precedence, including suppression and tuple results. Custom
|
|
539
|
+
content receives the unchanged native payload and owns its presentation; pass the
|
|
540
|
+
resolver explicitly when composing `TooltipContent`. Missing text, labels,
|
|
541
|
+
projection status, patterns and colors keep their existing contracts. For already
|
|
542
|
+
normalized source data, provide a resolver that returns the existing fraction;
|
|
543
|
+
do not compute another share or apply expand to data already transformed elsewhere.
|
|
544
|
+
Hosts still own raw data tables and accessible alternatives.
|
|
545
|
+
|
|
546
|
+
The source-only example at `/contracts.html` includes vertical/horizontal Bar,
|
|
547
|
+
Area and Combo with a separate raw latency axis and original data tables.
|
|
548
|
+
Recharts 3.10.1 applies native expand to every numeric axis. For mixed-unit Combo
|
|
549
|
+
charts, the example therefore uses caller-selected fraction `dataKey` accessors
|
|
550
|
+
for the stacked bars with `stackOffset="none"`, a `[0, 1]` share axis, and an
|
|
551
|
+
unchanged raw latency line on `[0, 10]`. The raw rows stay intact; an explicit
|
|
552
|
+
native tooltip formatter pairs each fraction with its original row value. Do not
|
|
553
|
+
apply expand or divide again to those fraction accessors. Other families use
|
|
554
|
+
native expand and the formatting helper. The Percent Area recipe retains integer
|
|
555
|
+
tooltip percentages and “No share” for a zero total.
|
|
556
|
+
|
|
557
|
+
### Point marker styles
|
|
558
|
+
|
|
559
|
+
`LineSeries` and `AreaSeries` accept independent `pointStyle` and
|
|
560
|
+
`activePointStyle` values: `"default"`, `"border"`, or `"colored-border"`.
|
|
561
|
+
Omitted/default values keep the existing appearance (including Area's normally
|
|
562
|
+
hidden regular dots). Opting into a regular style enables regular dots. Border
|
|
563
|
+
uses a series-colored center with a surface-colored ring; colored-border uses a
|
|
564
|
+
surface-colored center with a series-colored ring. The surface is
|
|
565
|
+
`--kind-ui-chart-marker-surface`, falling back to `--card` then white; set it on
|
|
566
|
+
Root for your theme. Series paint follows the existing config/theme identity or
|
|
567
|
+
explicit series stroke. Styles introduce no SVG resources or additional motion.
|
|
568
|
+
|
|
569
|
+
```tsx
|
|
570
|
+
<LineSeries dataKey="total" pointStyle="border" activePointStyle="colored-border" />
|
|
571
|
+
<AreaSeries dataKey="total" pointStyle="colored-border" activePointStyle="border" />
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Any explicit native `dot` or `activeDot` value (including false, true, props,
|
|
575
|
+
renderer functions and elements) wins for its respective marker. Configured
|
|
576
|
+
LineChart accepts these options in its existing `series` objects; explicit
|
|
577
|
+
children retain ownership. `PointMarker` is a reusable native Dot renderer with
|
|
578
|
+
`variant` and native Dot props. Its variant paint wins the engine-supplied paint;
|
|
579
|
+
native radius/handlers remain intact, and SVG `style` can override its paint.
|
|
580
|
+
For example, `dot={<PointMarker variant="colored-border" style={{ fill: "white" }} />}`.
|
|
581
|
+
Native active-dot callbacks carry series paint in `fill`, while regular dots carry
|
|
582
|
+
it in `stroke`. When composing PointMarker as an active renderer, forward that
|
|
583
|
+
identity explicitly: `activeDot={(props) => <PointMarker {...props}
|
|
584
|
+
stroke={props.fill} variant="colored-border" />}`. The Series style API handles
|
|
585
|
+
this distinction automatically. Keyboard/pointer inspection remains chart-owned; the active mark retains its
|
|
586
|
+
existing non-intercepting behavior and reduced-motion policy. Radar's selection
|
|
587
|
+
dots and Scatter's symbols have separate contracts and do not accept these
|
|
588
|
+
series options. Bar, Pie and other shape families are outside this API.
|
|
589
|
+
|
|
590
|
+
Run `npm run dev:chart` and visit `/recipes.html#point-markers` for the marker gallery and
|
|
591
|
+
its accessible data table.
|
|
592
|
+
|
|
593
|
+
### Directional Line and Area entrances
|
|
594
|
+
|
|
595
|
+
`LineAnimation` and `AreaAnimation` accept `revealDirection`:
|
|
596
|
+
|
|
597
|
+
- `"left-to-right"` (default): expand from the left edge.
|
|
598
|
+
- `"right-to-left"`: expand from the right edge.
|
|
599
|
+
- `"center-out"`: expand equally from the horizontal center.
|
|
600
|
+
- `"edges-in"`: expand two edge regions toward the horizontal center.
|
|
601
|
+
|
|
602
|
+
Directions are physical horizontal screen-space reveals for both native layouts;
|
|
603
|
+
they do not reverse data order or follow a vertical category axis. Timing remains
|
|
604
|
+
`revealDurationMs` / `revealEasing`. The temporary family clip leaves native paths,
|
|
605
|
+
axes, margins and transforms intact. Explicit directional entrances remove the clip
|
|
606
|
+
on completion or interruption (including resize/data changes). Line with an omitted
|
|
607
|
+
direction preserves its existing completed full-width clip until interruption;
|
|
608
|
+
Area/Combo retain their existing completion removal. Disabled/reduced motion shows
|
|
609
|
+
complete content.
|
|
610
|
+
Existing loading illustrations keep their independent design. Replay uses the
|
|
611
|
+
existing remount or loading-to-ready lifecycle, not hover or color updates.
|
|
612
|
+
|
|
613
|
+
```tsx
|
|
614
|
+
import {
|
|
615
|
+
AreaChart, AreaSeries, ComboChart, LineChart, LineSeries, Root,
|
|
616
|
+
type SeriesConfig,
|
|
617
|
+
} from "@kind-ui/charts";
|
|
618
|
+
import "@kind-ui/charts/styles.css";
|
|
619
|
+
|
|
620
|
+
const data = [
|
|
621
|
+
{ day: "Mon", total: 12, forecast: 16 },
|
|
622
|
+
{ day: "Tue", total: 20, forecast: 24 },
|
|
623
|
+
];
|
|
624
|
+
const config = {
|
|
625
|
+
total: { label: "Total", color: "#3659b8" },
|
|
626
|
+
forecast: { label: "Forecast", color: "#0d9488" },
|
|
627
|
+
} satisfies SeriesConfig;
|
|
628
|
+
|
|
629
|
+
export function DirectionalCharts() {
|
|
630
|
+
return (
|
|
631
|
+
<Root config={config}>
|
|
632
|
+
<LineChart data={data} width={480} height={240} aria-label="Daily total"
|
|
633
|
+
animate={{ revealDirection: "right-to-left", revealDurationMs: 800 }}>
|
|
634
|
+
<LineSeries dataKey="total" pointStyle="border" />
|
|
635
|
+
</LineChart>
|
|
636
|
+
<AreaChart data={data} width={480} height={240} aria-label="Daily forecast"
|
|
637
|
+
animate={{ revealDirection: "center-out" }}>
|
|
638
|
+
<AreaSeries dataKey="forecast" />
|
|
639
|
+
</AreaChart>
|
|
640
|
+
<ComboChart data={data} width={480} height={240} aria-label="Total and forecast"
|
|
641
|
+
animate={{
|
|
642
|
+
revealDirection: "center-out",
|
|
643
|
+
lineReveal: { revealDirection: "right-to-left" },
|
|
644
|
+
areaReveal: { revealDirection: "edges-in", revealDurationMs: 1200 },
|
|
645
|
+
barReveal: false,
|
|
646
|
+
}}>
|
|
647
|
+
<LineSeries dataKey="total" />
|
|
648
|
+
<AreaSeries dataKey="forecast" />
|
|
649
|
+
</ComboChart>
|
|
650
|
+
</Root>
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
Combo inherits the chart direction for Line/Area unless the corresponding family
|
|
656
|
+
object overrides it; `false` disables that family entrance. Bar keeps its existing
|
|
657
|
+
entrance configuration. All managed series in a family share its entrance clip;
|
|
658
|
+
individual series rendering/visibility props remain available, but there is no
|
|
659
|
+
per-series direction prop. Explicit native children and consumer clip/shape
|
|
660
|
+
ownership retain their existing contracts. `RevealDirection` is exported for
|
|
661
|
+
consumer controls. The packed Line/Area motion fixtures accept `?direction=...`
|
|
662
|
+
and the Combo fixture accepts `?directional` to exercise the family overrides.
|
|
663
|
+
|
|
664
|
+
### Animated dashed lines
|
|
665
|
+
|
|
666
|
+
`LineSeries` accepts `dashAnimation={ { durationMs: 1000, direction: "forward" } }`
|
|
667
|
+
(or `false`, the default). Supply a native numeric `strokeDasharray`, such as
|
|
668
|
+
`"6 4"`; duration is milliseconds per full pattern cycle. `reverse` reverses
|
|
669
|
+
travel. Zero, negative or non-finite duration and nonnumeric/CSS/percentage dash
|
|
670
|
+
patterns stay static. Odd lists repeat twice per cycle, matching SVG.
|
|
671
|
+
|
|
672
|
+
```tsx
|
|
673
|
+
<LineChart data={rows} animate>
|
|
674
|
+
<LineSeries dataKey="total" strokeDasharray="6 4" strokeDashoffset={3}
|
|
675
|
+
dashAnimation={{ durationMs: 800 }} material="glow" />
|
|
676
|
+
</LineChart>
|
|
677
|
+
<ComboChart data={rows} animate>
|
|
678
|
+
<AreaSeries dataKey="total" stroke="none" fillOpacity={0.2} />
|
|
679
|
+
<LineSeries dataKey="total" dot={false} strokeDasharray="3 2 1"
|
|
680
|
+
dashAnimation={{ durationMs: 1200, direction: "reverse" }} />
|
|
681
|
+
</ComboChart>
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
Load the package stylesheet. Motion stops with chart `animate={false}`, reduced
|
|
685
|
+
motion, loading, or hidden series. Disabling restores the native dash offset;
|
|
686
|
+
reenabling starts a fresh cycle. Use `dashAnimation={false}` to disable an individual series. Native width, dash array, offset and
|
|
687
|
+
styles remain intact; style dash values take precedence. Custom shapes own their
|
|
688
|
+
animation and are never decorated. Entrance clip reveal timing is independent.
|
|
689
|
+
No geometry or data is changed, and CSS requires no mount timers or cleanup.
|
|
690
|
+
Stylesheets overriding dash paint remain consumer-owned and can change appearance.
|
|
691
|
+
|
|
692
|
+
`AreaSeries` does not accept this option: its closed perimeter includes baseline
|
|
693
|
+
and closing edges. For an open animated outline, overlay `LineSeries` in a
|
|
694
|
+
`ComboChart` as above. Match data keys, interpolation and axes yourself; stacked
|
|
695
|
+
or range areas require an explicitly derived outline dataset. See
|
|
696
|
+
`/contracts.html#dashed-lines` for the interactive line and combo contract examples.
|
|
697
|
+
|
|
698
|
+
### Initial Pie tooltip
|
|
699
|
+
|
|
700
|
+
`PieChart.defaultPinnedCategory="delivery"` opts into an initial tooltip for
|
|
701
|
+
one direct `PieSeries` (Fragments allowed) with explicit `data` and `categoryKey`.
|
|
702
|
+
Pair it with `Tooltip.itemKey={(entry) => entry.payload.id}` when `categoryKey="id"`;
|
|
703
|
+
caller labels, formatters, and the data table remain the source of truth.
|
|
704
|
+
Only Pie/donut compositions whose direct children are one Kind PieSeries and
|
|
705
|
+
one Kind Tooltip (optionally in Fragments) support this default. Native Pie, wrapped series, multiple rings, and other chart families
|
|
706
|
+
are outside this contract; missing category data/identity or multiple direct
|
|
707
|
+
series, duplicate/missing Tooltips, or unsupported direct children throw when resolving a pin.
|
|
708
|
+
|
|
709
|
+
The category string is captured on mount. Reorder resolves its current index;
|
|
710
|
+
unknown, duplicate, removed, hidden, or filtered categories clear the default
|
|
711
|
+
permanently. Restoring rows or changing the default prop does not re-pin; remount
|
|
712
|
+
explicitly to begin again. Pointer movement/down, focus, and any chart key press
|
|
713
|
+
clear the default and hand inspection/dismissal back to Recharts. Escape never
|
|
714
|
+
re-pins. No focus is moved or trapped. The existing tooltip is the sole readout
|
|
715
|
+
and live announcement; Kind adds no announcement region or hover selection.
|
|
716
|
+
Explicit Tooltip `active` and `defaultIndex` retain native ownership and take
|
|
717
|
+
precedence. Custom content owns its markup and accessibility. Omitted defaults
|
|
718
|
+
preserve existing behavior. See the weekly Pie in `examples/chart/pie-recipes.tsx`.
|
|
719
|
+
|
|
720
|
+
### Sankey node labels
|
|
721
|
+
|
|
722
|
+
Compose `SankeyNodeLabel` beside `SankeyNode` in the native `node` callback:
|
|
723
|
+
|
|
724
|
+
```tsx
|
|
725
|
+
node={(node) => (
|
|
726
|
+
<g>
|
|
727
|
+
<SankeyNode {...node} />
|
|
728
|
+
<SankeyNodeLabel node={node} data={data} position="outside" showValues
|
|
729
|
+
valueFormatter={(value) => `${value} MWh`} />
|
|
730
|
+
</g>
|
|
731
|
+
)}
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
Optional `SankeyNodeConfig` entries accept an `icon: ReactNode`. Pass that config
|
|
735
|
+
explicitly as `SankeyNodeLabel`'s `nodeConfig` in your native callback (see the
|
|
736
|
+
energy example in `examples/chart/sankeys.tsx`). Icons use a square `iconSize`
|
|
737
|
+
(default 16 chart units) SVG viewport with `viewBox="0 0 24 24"`; supply SVG
|
|
738
|
+
content, or a nested SVG with its own viewBox. `iconGap` defaults to 4 units.
|
|
739
|
+
Outside icons sit nearest the node and shift the text by size plus gap on either
|
|
740
|
+
side. Inside icons stack above centered text and share its exact rectangle clip;
|
|
741
|
+
small nodes can clip both. Reserve outside margins for the combined content.
|
|
742
|
+
Missing, null, boolean or zero-size icons preserve the existing text layout.
|
|
743
|
+
Sizes and gaps must be finite and nonnegative. Icons are decorative (`aria-hidden`,
|
|
744
|
+
nonfocusable); data names and full name/value titles remain meaningful, and the
|
|
745
|
+
data table remains the accessible alternative. Config labels remain Legend metadata.
|
|
746
|
+
Custom text children compose with the icon; text props/ref still target the text.
|
|
747
|
+
A custom native node renderer owns all rendering: nothing is injected unless it
|
|
748
|
+
chooses this helper, and omitting `nodeConfig` opts out of configured icons.
|
|
749
|
+
|
|
750
|
+
Identity is resolved by `node.payload.id` against `data`, never callback index or
|
|
751
|
+
name. Supply the same data to the chart, label and `SankeyTable`, and reuse the
|
|
752
|
+
formatter as the table's `formatValue`. A node value is the maximum of incoming
|
|
753
|
+
and outgoing flow sums: sources use outgoing, sinks incoming, balanced intermediate
|
|
754
|
+
nodes count throughput once, and disconnected or measured-zero nodes total zero.
|
|
755
|
+
Existing data validation rejects unbalanced intermediate nodes outside its rounding
|
|
756
|
+
tolerance; the larger sum handles that tolerance consistently with native sizing.
|
|
757
|
+
No extra totals or inferred flows are added to the table.
|
|
758
|
+
|
|
759
|
+
`position="inside"` centers text and clips it to the exact node rectangle, including
|
|
760
|
+
small or zero-size nodes. It does not shrink text, expand geometry or avoid collisions.
|
|
761
|
+
Use outside labels for narrow nodes; they default right for sources/intermediates and
|
|
762
|
+
left for sinks. `side`, `offset`, native text props, styles and refs remain consumer-owned.
|
|
763
|
+
Reserve margins for outside text; the native SVG viewport still clips overflow.
|
|
764
|
+
The full name/value remains in a SVG title even when inside text clips. Keep the table
|
|
765
|
+
as the complete accessible data alternative. Custom `children` (including `tspan`)
|
|
766
|
+
replace visual text while preserving the default title. No label or animation is
|
|
767
|
+
installed implicitly. `/sankeys.html` demonstrates both positions.
|