@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.
Files changed (117) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +683 -1
  3. package/dist/activity-rings.d.ts +2 -1
  4. package/dist/activity-rings.js +6 -3
  5. package/dist/animation.d.ts +11 -3
  6. package/dist/animation.js +18 -10
  7. package/dist/area-chart.d.ts +3 -1
  8. package/dist/area-chart.js +15 -10
  9. package/dist/area-series.d.ts +9 -1
  10. package/dist/area-series.js +35 -8
  11. package/dist/bar-chart.d.ts +10 -3
  12. package/dist/bar-chart.js +17 -4
  13. package/dist/bar-material.js +2 -3
  14. package/dist/bar-series.d.ts +11 -1
  15. package/dist/bar-series.js +65 -13
  16. package/dist/box-plot.js +2 -2
  17. package/dist/category-cells.d.ts +7 -1
  18. package/dist/category-cells.js +32 -2
  19. package/dist/chart-background-pattern.d.ts +23 -0
  20. package/dist/chart-background-pattern.js +31 -0
  21. package/dist/chart-context.d.ts +6 -2
  22. package/dist/chart-interaction.d.ts +94 -0
  23. package/dist/chart-interaction.js +224 -0
  24. package/dist/combo-chart.d.ts +8 -5
  25. package/dist/combo-chart.js +14 -12
  26. package/dist/configured-line-chart.d.ts +5 -1
  27. package/dist/configured-line-chart.js +8 -5
  28. package/dist/emphasis.d.ts +5 -2
  29. package/dist/emphasis.js +18 -4
  30. package/dist/fill-pattern.d.ts +25 -0
  31. package/dist/fill-pattern.js +23 -0
  32. package/dist/heatmap.d.ts +4 -2
  33. package/dist/heatmap.js +34 -12
  34. package/dist/histogram-chart.js +10 -3
  35. package/dist/histogram-material.js +1 -2
  36. package/dist/index.d.ts +12 -3
  37. package/dist/index.js +8 -1
  38. package/dist/legend.d.ts +2 -0
  39. package/dist/legend.js +28 -7
  40. package/dist/line-chart.d.ts +13 -3
  41. package/dist/line-chart.js +54 -34
  42. package/dist/line-dash.d.ts +8 -0
  43. package/dist/line-dash.js +18 -0
  44. package/dist/line-material.d.ts +1 -1
  45. package/dist/line-material.js +1 -1
  46. package/dist/line-series.d.ts +9 -1
  47. package/dist/line-series.js +37 -11
  48. package/dist/loading-cartesian-designs.d.ts +6 -0
  49. package/dist/loading-cartesian-designs.js +123 -0
  50. package/dist/loading-motion.d.ts +37 -0
  51. package/dist/loading-motion.js +88 -0
  52. package/dist/loading-polar-designs.d.ts +6 -0
  53. package/dist/loading-polar-designs.js +95 -0
  54. package/dist/loading-skeleton.d.ts +29 -0
  55. package/dist/loading-skeleton.js +143 -0
  56. package/dist/loading-standalone-designs.d.ts +5 -0
  57. package/dist/loading-standalone-designs.js +126 -0
  58. package/dist/percent-stack.d.ts +18 -0
  59. package/dist/percent-stack.js +33 -0
  60. package/dist/pie-chart.d.ts +7 -3
  61. package/dist/pie-chart.js +37 -6
  62. package/dist/pie-material.js +1 -1
  63. package/dist/pie-pin-identity.d.ts +4 -0
  64. package/dist/pie-pin-identity.js +10 -0
  65. package/dist/pie-series.d.ts +4 -0
  66. package/dist/pie-series.js +138 -15
  67. package/dist/pie-tooltip-pin.d.ts +4 -0
  68. package/dist/pie-tooltip-pin.js +52 -0
  69. package/dist/point-marker.d.ts +19 -0
  70. package/dist/point-marker.js +19 -0
  71. package/dist/polar-chart.d.ts +14 -5
  72. package/dist/polar-chart.js +41 -10
  73. package/dist/polar-material.js +1 -1
  74. package/dist/polar-series.js +68 -22
  75. package/dist/radar-interaction.js +10 -4
  76. package/dist/radial-category.d.ts +2 -0
  77. package/dist/reveal-clip.d.ts +16 -0
  78. package/dist/reveal-clip.js +18 -0
  79. package/dist/root.d.ts +5 -9
  80. package/dist/root.js +46 -11
  81. package/dist/sankey-chart.d.ts +5 -1
  82. package/dist/sankey-chart.js +64 -13
  83. package/dist/sankey-colors.d.ts +3 -0
  84. package/dist/sankey-finish.d.ts +1 -1
  85. package/dist/sankey-finish.js +1 -1
  86. package/dist/sankey-interaction.d.ts +8 -0
  87. package/dist/sankey-interaction.js +32 -0
  88. package/dist/sankey-legend.d.ts +2 -1
  89. package/dist/sankey-legend.js +18 -3
  90. package/dist/sankey-node-label.d.ts +22 -0
  91. package/dist/sankey-node-label.js +34 -0
  92. package/dist/scatter-chart.d.ts +5 -3
  93. package/dist/scatter-chart.js +14 -4
  94. package/dist/scatter-material.js +1 -1
  95. package/dist/scatter-series.js +5 -3
  96. package/dist/series-color.d.ts +10 -0
  97. package/dist/series-color.js +48 -0
  98. package/dist/series-interaction.d.ts +12 -0
  99. package/dist/series-interaction.js +82 -0
  100. package/dist/series-label.d.ts +7 -0
  101. package/dist/series-label.js +18 -0
  102. package/dist/series-paint.d.ts +8 -0
  103. package/dist/series-paint.js +27 -0
  104. package/dist/styles.css +151 -6
  105. package/dist/stylesheet-warning.d.ts +2 -0
  106. package/dist/stylesheet-warning.js +86 -0
  107. package/dist/surface-material.js +1 -1
  108. package/dist/tooltip-content.d.ts +8 -1
  109. package/dist/tooltip-content.js +15 -4
  110. package/dist/tooltip.d.ts +3 -1
  111. package/dist/tooltip.js +8 -5
  112. package/dist/types.d.ts +11 -2
  113. package/dist/waterfall-chart.d.ts +4 -0
  114. package/dist/waterfall-chart.js +7 -0
  115. package/package.json +2 -2
  116. package/dist/bar-paper.d.ts +0 -2
  117. package/dist/bar-paper.js +0 -6
@@ -0,0 +1,86 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ const warned = new WeakSet();
4
+ const message = 'Kind UI chart styles are missing. Import "@kind-ui/charts/styles.css" once at your application entry (in Next.js, your root layout). If you intentionally supply all chart styles, define --kind-ui-styles-loaded: 1 on your chart roots.';
5
+ /** Runs only for development mounts; never changes chart styles or server markup. */
6
+ export function StylesheetWarning() {
7
+ useEffect(() => {
8
+ const doc = document;
9
+ const view = doc.defaultView;
10
+ if (!view || warned.has(doc))
11
+ return;
12
+ let disposed = false;
13
+ let frame = 0;
14
+ const settled = new WeakSet();
15
+ const removers = [];
16
+ const initialLinks = Array.from(doc.querySelectorAll('link[rel~="stylesheet"]'));
17
+ // Observe failures immediately rather than waiting for the frame check.
18
+ const completed = (event) => {
19
+ const link = event.target;
20
+ if (link instanceof HTMLLinkElement && link.relList.contains("stylesheet")) {
21
+ settled.add(link);
22
+ if (doc.readyState === "complete")
23
+ schedule();
24
+ }
25
+ };
26
+ doc.addEventListener("load", completed, true);
27
+ doc.addEventListener("error", completed, true);
28
+ removers.push(() => {
29
+ doc.removeEventListener("load", completed, true);
30
+ doc.removeEventListener("error", completed, true);
31
+ });
32
+ const check = () => {
33
+ if (disposed)
34
+ return;
35
+ if (warned.has(doc)) {
36
+ for (const remove of removers)
37
+ remove();
38
+ disposed = true;
39
+ return;
40
+ }
41
+ const pending = Array.from(doc.querySelectorAll('link[rel~="stylesheet"]')).filter((link) => !link.disabled &&
42
+ !link.sheet &&
43
+ !settled.has(link) &&
44
+ (!link.media || view.matchMedia(link.media).matches));
45
+ if (pending.length)
46
+ return;
47
+ const missing = Array.from(doc.querySelectorAll('[data-kind-ui="chart"]')).some((root) => view.getComputedStyle(root).getPropertyValue("--kind-ui-styles-loaded").trim() !== "1");
48
+ for (const remove of removers)
49
+ remove();
50
+ disposed = true;
51
+ if (missing) {
52
+ warned.add(doc);
53
+ console.warn(message);
54
+ }
55
+ };
56
+ // Give effects which add a stylesheet time to run and the browser time to apply it.
57
+ const schedule = () => {
58
+ if (disposed)
59
+ return;
60
+ view.cancelAnimationFrame(frame);
61
+ frame = view.requestAnimationFrame(() => {
62
+ frame = view.requestAnimationFrame(check);
63
+ });
64
+ };
65
+ if (doc.readyState === "complete")
66
+ schedule();
67
+ else {
68
+ const loaded = () => {
69
+ // Window load settles every stylesheet which existed at mount, even if
70
+ // its error occurred before this effect could observe it.
71
+ for (const link of initialLinks)
72
+ settled.add(link);
73
+ schedule();
74
+ };
75
+ view.addEventListener("load", loaded, { once: true });
76
+ removers.push(() => view.removeEventListener("load", loaded));
77
+ }
78
+ return () => {
79
+ disposed = true;
80
+ view.cancelAnimationFrame(frame);
81
+ for (const remove of removers)
82
+ remove();
83
+ };
84
+ }, []);
85
+ return null;
86
+ }
@@ -3,5 +3,5 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { AreaClayRelief } from "./area-clay.js";
4
4
  /** Internal filled-surface finish only. Callers own native shapes, IDs and bounds. */
5
5
  export function SurfaceMaterialFilter({ material, id, bounds, family, }) {
6
- return (_jsx("filter", { id: id, filterUnits: "userSpaceOnUse", x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height, colorInterpolationFilters: "sRGB", children: material === "paper" ? (_jsxs(_Fragment, { children: [_jsx("feTurbulence", { type: "fractalNoise", baseFrequency: "0.65 0.3", numOctaves: 1, seed: 7, result: "fiber" }), _jsx("feFlood", { floodColor: `var(--kind-ui-${family}-paper-fiber, #fff)`, floodOpacity: `var(--kind-ui-${family}-paper-grain, 0.32)` }), _jsx("feComposite", { in2: "fiber", operator: "in", result: "texture" }), _jsx("feComposite", { in: "texture", in2: "SourceAlpha", operator: "in", result: "grain" }), _jsxs("feMerge", { children: [_jsx("feMergeNode", { in: "SourceGraphic" }), _jsx("feMergeNode", { in: "grain" })] })] })) : material === "clay" && family === "area" ? (_jsx(AreaClayRelief, {})) : material === "clay" ? (_jsxs(_Fragment, { children: [_jsx("feOffset", { in: "SourceAlpha", dx: 0, dy: 1.5, result: "lower" }), _jsx("feComposite", { in: "SourceAlpha", in2: "lower", operator: "out", result: "topEdge" }), _jsx("feFlood", { floodColor: `var(--kind-ui-${family}-clay-light, #fff)`, floodOpacity: 0.65 }), _jsx("feComposite", { in2: "topEdge", operator: "in", result: "light" }), _jsx("feOffset", { in: "SourceAlpha", dx: 0, dy: -2, result: "upper" }), _jsx("feComposite", { in: "SourceAlpha", in2: "upper", operator: "out", result: "bottomEdge" }), _jsx("feFlood", { floodColor: `var(--kind-ui-${family}-clay-shade, #17212b)`, floodOpacity: 0.38 }), _jsx("feComposite", { in2: "bottomEdge", operator: "in", result: "shade" }), _jsxs("feMerge", { children: [_jsx("feMergeNode", { in: "SourceGraphic" }), _jsx("feMergeNode", { in: "shade" }), _jsx("feMergeNode", { in: "light" })] })] })) : (_jsxs(_Fragment, { children: [_jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: 2.5, result: "halo" }), _jsx("feFlood", { floodOpacity: `var(--kind-ui-${family}-glow-opacity, 0.6)`, result: "strength" }), _jsx("feComposite", { in: "halo", in2: "strength", operator: "in", result: "softHalo" }), _jsx("feMorphology", { in: "SourceAlpha", operator: "erode", radius: 0.8, result: "inside" }), _jsx("feComposite", { in: "SourceAlpha", in2: "inside", operator: "out", result: "edge" }), _jsx("feFlood", { floodColor: `var(--kind-ui-${family}-glow-light, #fff)`, floodOpacity: 0.45 }), _jsx("feComposite", { in2: "edge", operator: "in", result: "light" }), _jsxs("feMerge", { children: [_jsx("feMergeNode", { in: "softHalo" }), _jsx("feMergeNode", { in: "SourceGraphic" }), _jsx("feMergeNode", { in: "light" })] })] })) }));
6
+ return (_jsx("filter", { id: id, filterUnits: "userSpaceOnUse", x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height, colorInterpolationFilters: "sRGB", children: material === "clay" && family === "area" ? (_jsx(AreaClayRelief, {})) : material === "clay" ? (_jsxs(_Fragment, { children: [_jsx("feOffset", { in: "SourceAlpha", dx: 0, dy: 1.5, result: "lower" }), _jsx("feComposite", { in: "SourceAlpha", in2: "lower", operator: "out", result: "topEdge" }), _jsx("feFlood", { floodColor: `var(--kind-ui-${family}-clay-light, #fff)`, floodOpacity: 0.65 }), _jsx("feComposite", { in2: "topEdge", operator: "in", result: "light" }), _jsx("feOffset", { in: "SourceAlpha", dx: 0, dy: -2, result: "upper" }), _jsx("feComposite", { in: "SourceAlpha", in2: "upper", operator: "out", result: "bottomEdge" }), _jsx("feFlood", { floodColor: `var(--kind-ui-${family}-clay-shade, #17212b)`, floodOpacity: 0.38 }), _jsx("feComposite", { in2: "bottomEdge", operator: "in", result: "shade" }), _jsxs("feMerge", { children: [_jsx("feMergeNode", { in: "SourceGraphic" }), _jsx("feMergeNode", { in: "shade" }), _jsx("feMergeNode", { in: "light" })] })] })) : (_jsxs(_Fragment, { children: [_jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: 2.5, result: "halo" }), _jsx("feFlood", { floodOpacity: `var(--kind-ui-${family}-glow-opacity, 0.6)`, result: "strength" }), _jsx("feComposite", { in: "halo", in2: "strength", operator: "in", result: "softHalo" }), _jsx("feMorphology", { in: "SourceAlpha", operator: "erode", radius: 0.8, result: "inside" }), _jsx("feComposite", { in: "SourceAlpha", in2: "inside", operator: "out", result: "edge" }), _jsx("feFlood", { floodColor: `var(--kind-ui-${family}-glow-light, #fff)`, floodOpacity: 0.45 }), _jsx("feComposite", { in2: "edge", operator: "in", result: "light" }), _jsxs("feMerge", { children: [_jsx("feMergeNode", { in: "softHalo" }), _jsx("feMergeNode", { in: "SourceGraphic" }), _jsx("feMergeNode", { in: "light" })] })] })) }));
7
7
  }
@@ -1,9 +1,16 @@
1
1
  import { type ComponentPropsWithRef, type ReactNode } from "react";
2
2
  import type { TooltipContentProps as UpstreamTooltipContentProps } from "recharts";
3
+ import { type NormalizedValue } from "./percent-stack.js";
3
4
  export type TooltipContentProps = Omit<ComponentPropsWithRef<"div">, "children"> & {
4
5
  /** Pass the upstream content callback's props here so engine-only props never reach the DOM. */
5
6
  tooltip: UpstreamTooltipContentProps;
6
7
  missingValue?: ReactNode;
8
+ /** Formatting-only fraction resolver. Default content retains the raw value alongside it. */
9
+ normalizedValue?: NormalizedValue;
10
+ /** Caller-owned projection status; use the same datum identity selection as BarSeries. */
11
+ isProjected?: (entry: UpstreamTooltipContentProps["payload"][number]) => boolean;
12
+ /** Accessible status text appended to projected items. */
13
+ projectedLabel?: ReactNode;
7
14
  /** Opt in to decorative rolling digits for finite numeric text values. Default: off. */
8
15
  valueAnimation?: "shuffle";
9
16
  /** Omit the heading; series labels and values remain accessible. */
@@ -16,4 +23,4 @@ export type TooltipContentProps = Omit<ComponentPropsWithRef<"div">, "children">
16
23
  itemKey?: (entry: UpstreamTooltipContentProps["payload"][number]) => string;
17
24
  };
18
25
  /** Default tooltip UI using the containing chart's labels, formats, colors and visibility. */
19
- export declare function TooltipContent({ tooltip, missingValue, valueAnimation, itemKey, hideLabel, hideIndicator, indicator, ...props }: TooltipContentProps): import("react").JSX.Element | null;
26
+ export declare function TooltipContent({ tooltip, missingValue, normalizedValue, isProjected, projectedLabel, valueAnimation, itemKey, hideLabel, hideIndicator, indicator, ...props }: TooltipContentProps): import("react").JSX.Element | null;
@@ -1,11 +1,13 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
3
  import { use } from "react";
4
4
  import { useChart } from "./chart-context.js";
5
5
  import { LineInteraction } from "./line-chart.js";
6
+ import { formatPercent } from "./percent-stack.js";
7
+ import { colorStopToken } from "./series-color.js";
6
8
  import { TooltipNumber } from "./tooltip-number.js";
7
9
  /** Default tooltip UI using the containing chart's labels, formats, colors and visibility. */
8
- export function TooltipContent({ tooltip, missingValue = "No data", valueAnimation, itemKey, hideLabel = false, hideIndicator = false, indicator = "line", ...props }) {
10
+ export function TooltipContent({ tooltip, missingValue = "No data", normalizedValue, isProjected, projectedLabel = "Projected", valueAnimation, itemKey, hideLabel = false, hideIndicator = false, indicator = "line", ...props }) {
9
11
  const { config, visibleSeries } = useChart();
10
12
  const line = use(LineInteraction);
11
13
  const identity = (entry) => itemKey?.(entry) ??
@@ -23,6 +25,7 @@ export function TooltipContent({ tooltip, missingValue = "No data", valueAnimati
23
25
  const items = entries.map((entry, index) => {
24
26
  const key = identity(entry);
25
27
  const item = Object.hasOwn(config, key) ? config[key] : undefined;
28
+ const projected = entry.payload != null && isProjected?.(entry) === true;
26
29
  let name = item?.label ?? entry.name ?? key;
27
30
  let value = missingValue;
28
31
  if (entry.value != null) {
@@ -42,14 +45,22 @@ export function TooltipContent({ tooltip, missingValue = "No data", valueAnimati
42
45
  : Array.isArray(entry.value)
43
46
  ? entry.value.join(" – ")
44
47
  : entry.value;
48
+ if (!format) {
49
+ const fraction = normalizedValue?.(entry);
50
+ if (fraction !== undefined && Number.isFinite(fraction * 100))
51
+ value = (_jsxs(_Fragment, { children: [formatPercent(fraction), " (", value, ")"] }));
52
+ }
45
53
  hasVisibleValue = true;
46
54
  }
47
- return (_jsxs("li", { "data-kind-ui": "chart-tooltip-item", "data-series": key, children: [!hideIndicator &&
55
+ return (_jsxs("li", { "data-kind-ui": "chart-tooltip-item", "data-series": key, "data-projected": projected || undefined, children: [!hideIndicator &&
48
56
  (item?.icon ? (_jsx("span", { "aria-hidden": "true", "data-kind-ui": "chart-icon", children: _jsx(item.icon, {}) })) : (_jsx("span", { "aria-hidden": "true", "data-kind-ui": "chart-indicator", "data-indicator": indicator, style: {
57
+ "--kind-ui-chart-indicator-background": item
58
+ ? `var(${colorStopToken(key, "gradient")})`
59
+ : (entry.color ?? "currentColor"),
49
60
  "--kind-ui-chart-indicator-color": item
50
61
  ? `var(--color-${key})`
51
62
  : (entry.color ?? "currentColor"),
52
- } }))), _jsx("span", { children: name }), _jsx("strong", { "data-kind-ui": "chart-tooltip-value", children: valueAnimation === "shuffle" &&
63
+ } }))), _jsx("span", { children: name }), projected && _jsx("span", { "data-kind-ui": "projection-status", children: projectedLabel }), _jsx("strong", { "data-kind-ui": "chart-tooltip-value", children: valueAnimation === "shuffle" &&
53
64
  typeof entry.value === "number" &&
54
65
  Number.isFinite(entry.value) &&
55
66
  (typeof value === "string" || (typeof value === "number" && Number.isFinite(value))) ? (_jsx(TooltipNumber, { value: value })) : (value) })] }, entry.graphicalItemId ?? `${key}-${index}`));
package/dist/tooltip.d.ts CHANGED
@@ -8,6 +8,8 @@ export type TooltipProps = Omit<EngineTooltipProps, "position" | "isAnimationAct
8
8
  maxWidth?: number;
9
9
  /** Resolves category identity before the existing series-key fallback. */
10
10
  itemKey?: TooltipContentProps["itemKey"];
11
+ /** Default content only; custom content and explicit formatters retain ownership. */
12
+ normalizedValue?: TooltipContentProps["normalizedValue"];
11
13
  /** Opt in on Kind's default content; custom content owns its own animation. */
12
14
  valueAnimation?: TooltipContentProps["valueAnimation"];
13
15
  };
@@ -22,7 +24,7 @@ export type TooltipFrameProps = {
22
24
  frameProps: TooltipProps["frameProps"];
23
25
  };
24
26
  export declare function StaticTooltipFrame({ x, y, ref, style, frameProps, children }: TooltipFrameProps): import("react").JSX.Element;
25
- export declare function TooltipBase({ ref, content, frameProps, maxWidth, itemKey, valueAnimation, Frame, ...props }: TooltipProps & {
27
+ export declare function TooltipBase({ ref, content, frameProps, maxWidth, itemKey, valueAnimation, normalizedValue, Frame, defaultIndex: nativeDefaultIndex, ...props }: TooltipProps & {
26
28
  Frame?: (props: TooltipFrameProps) => ReactNode;
27
29
  }): import("react").JSX.Element;
28
30
  /** Measured and bounded content; the engine owns payload, selection and Escape dismissal. */
package/dist/tooltip.js CHANGED
@@ -1,14 +1,15 @@
1
1
  "use client";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { cloneElement, createElement, isValidElement, useCallback, useLayoutEffect, useState, } from "react";
3
+ import { cloneElement, createElement, isValidElement, use, useCallback, useLayoutEffect, useState, } from "react";
4
4
  import { Tooltip as EngineTooltip, useChartHeight, useChartWidth, } from "recharts";
5
5
  import { useChart } from "./chart-context.js";
6
6
  import { useLineInteraction } from "./line-chart.js";
7
+ import { PieTooltipPin } from "./pie-tooltip-pin.js";
7
8
  import { TooltipContent } from "./tooltip-content.js";
8
9
  export function StaticTooltipFrame({ x, y, ref, style, frameProps, children }) {
9
10
  return (_jsx("div", { ...frameProps, "data-kind-ui": "tooltip-frame", ref: ref, style: { ...style, ...frameProps?.style, transform: `translate(${x}px, ${y}px)` }, children: children }));
10
11
  }
11
- function PositionedContent({ consumerContent, itemKey, valueAnimation, maxWidth, frameProps, frameRef, Frame, ...tooltip }) {
12
+ function PositionedContent({ consumerContent, itemKey, valueAnimation, normalizedValue, maxWidth, frameProps, frameRef, Frame, ...tooltip }) {
12
13
  const { pointer, seriesKeys } = useLineInteraction();
13
14
  const { visibleSeries } = useChart();
14
15
  // Exiting strokes can remain painted briefly; hidden series leave all tooltip content immediately.
@@ -54,7 +55,7 @@ function PositionedContent({ consumerContent, itemKey, valueAnimation, maxWidth,
54
55
  const offsetY = typeof offset === "number" ? offset : offset.y;
55
56
  const maxX = Math.max(0, width - size.width);
56
57
  const maxY = Math.max(0, height - size.height);
57
- const children = isValidElement(consumerContent) ? (cloneElement(consumerContent, contentProps)) : typeof consumerContent === "function" ? (createElement(consumerContent, contentProps)) : (_jsx(TooltipContent, { tooltip: contentProps, ...(itemKey ? { itemKey } : {}), ...(valueAnimation ? { valueAnimation } : {}) }));
58
+ const children = isValidElement(consumerContent) ? (cloneElement(consumerContent, contentProps)) : typeof consumerContent === "function" ? (createElement(consumerContent, contentProps)) : (_jsx(TooltipContent, { tooltip: contentProps, ...(normalizedValue ? { normalizedValue } : {}), ...(itemKey ? { itemKey } : {}), ...(valueAnimation ? { valueAnimation } : {}) }));
58
59
  return (_jsx(Frame, { x: Math.max(0, Math.min(anchor.x + offsetX, maxX)), y: Math.max(0, Math.min(anchor.y + offsetY, maxY)), maxX: maxX, maxY: maxY, ref: attachRef, style: {
59
60
  width: "max-content",
60
61
  maxWidth: Math.min(Math.max(0, maxWidth), width),
@@ -63,9 +64,11 @@ function PositionedContent({ consumerContent, itemKey, valueAnimation, maxWidth,
63
64
  boxSizing: "border-box",
64
65
  }, frameProps: frameProps, children: children }));
65
66
  }
66
- export function TooltipBase({ ref, content, frameProps, maxWidth = 180, itemKey, valueAnimation, Frame = StaticTooltipFrame, ...props }) {
67
+ export function TooltipBase({ ref, content, frameProps, maxWidth = 180, itemKey, valueAnimation, normalizedValue, Frame = StaticTooltipFrame, defaultIndex: nativeDefaultIndex, ...props }) {
67
68
  useLineInteraction();
68
- return (_jsx(EngineTooltip, { cursor: false, offset: 12, filterNull: false, ...props, position: { x: 0, y: 0 }, isAnimationActive: false, content: _jsx(PositionedContent, { active: false, payload: [], coordinate: undefined, activeIndex: undefined, accessibilityLayer: false, consumerContent: content, itemKey: itemKey, valueAnimation: valueAnimation, maxWidth: maxWidth, frameProps: frameProps, frameRef: ref, Frame: Frame }) }));
69
+ const pinIndex = use(PieTooltipPin);
70
+ const defaultIndex = props.active === undefined ? (nativeDefaultIndex ?? pinIndex) : nativeDefaultIndex;
71
+ return (_jsx(EngineTooltip, { cursor: false, offset: 12, filterNull: false, ...props, ...(defaultIndex === undefined ? {} : { defaultIndex }), position: { x: 0, y: 0 }, isAnimationActive: false, content: _jsx(PositionedContent, { active: false, payload: [], coordinate: undefined, activeIndex: undefined, accessibilityLayer: false, consumerContent: content, itemKey: itemKey, valueAnimation: valueAnimation, normalizedValue: normalizedValue, maxWidth: maxWidth, frameProps: frameProps, frameRef: ref, Frame: Frame }) }));
69
72
  }
70
73
  /** Measured and bounded content; the engine owns payload, selection and Escape dismissal. */
71
74
  export function Tooltip(props) {
package/dist/types.d.ts CHANGED
@@ -1,8 +1,17 @@
1
1
  import type { ComponentProps, ComponentType, ReactNode } from "react";
2
2
  import type { Symbols, TooltipValueType } from "recharts";
3
+ import type { FillPattern } from "./fill-pattern.js";
4
+ /** Arrays are evenly distributed gradient stops, not category palettes. */
5
+ export type SeriesColor = string | readonly string[] | {
6
+ readonly light: string | readonly string[];
7
+ readonly dark: string | readonly string[];
8
+ };
3
9
  export type SeriesConfig = Readonly<Record<string, {
4
- label: string;
5
- color: string;
10
+ /** Inferred from the matching key when omitted; explicit text takes precedence. */
11
+ label?: string;
12
+ color: SeriesColor;
13
+ /** Optional implicit bar paint and built-in legend encoding. */
14
+ pattern?: FillPattern;
6
15
  /** Decorative glyph shared by built-in legend and tooltip content. */
7
16
  icon?: ComponentType;
8
17
  /** Explicit legend-only native symbol; reuse this value for ScatterSeries.shape. */
@@ -0,0 +1,4 @@
1
+ import { type BarChartProps } from "./bar-chart.js";
2
+ export type WaterfallChartProps = BarChartProps;
3
+ /** Native bar composition, with a fixed waterfall silhouette while loading. */
4
+ export declare function WaterfallChart(props: WaterfallChartProps): import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { BarChartImplementation } from "./bar-chart.js";
4
+ /** Native bar composition, with a fixed waterfall silhouette while loading. */
5
+ export function WaterfallChart(props) {
6
+ return _jsx(BarChartImplementation, { chartProps: props, family: "waterfall" });
7
+ }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@kind-ui/charts",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Composable React chart components built on Recharts and Motion.",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/bhaveshchow20/kind-ui.git",
8
8
  "directory": "packages/charts"
9
9
  },
10
- "homepage": "https://github.com/bhaveshchow20/kind-ui/tree/main/packages/charts#readme",
10
+ "homepage": "https://kindui.dev/charts",
11
11
  "bugs": {
12
12
  "url": "https://github.com/bhaveshchow20/kind-ui/issues"
13
13
  },
@@ -1,2 +0,0 @@
1
- /** Uneven inset pencil contours, never displacement or an expanded quantitative mark. */
2
- export declare function BarPaper(): import("react").JSX.Element;
package/dist/bar-paper.js DELETED
@@ -1,6 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- /** Uneven inset pencil contours, never displacement or an expanded quantitative mark. */
4
- export function BarPaper() {
5
- return (_jsxs(_Fragment, { children: [_jsx("feTurbulence", { type: "fractalNoise", baseFrequency: "0.65 0.3", numOctaves: 1, seed: 7, result: "fiber" }), _jsx("feFlood", { floodColor: "var(--kind-ui-bar-paper-fiber, #fff)", floodOpacity: "var(--kind-ui-bar-paper-grain, 0.14)" }), _jsx("feComposite", { in2: "fiber", operator: "in", result: "texture" }), _jsx("feComposite", { in: "texture", in2: "SourceGraphic", operator: "atop", result: "paper" }), _jsx("feMorphology", { in: "SourceAlpha", operator: "erode", radius: 1.2, result: "inside" }), _jsx("feComposite", { in: "SourceAlpha", in2: "inside", operator: "arithmetic", k2: 1, k3: -1, result: "edge" }), _jsx("feTurbulence", { type: "fractalNoise", baseFrequency: "0.08 0.2", numOctaves: 1, seed: 11, result: "pencil" }), _jsx("feColorMatrix", { in: "pencil", type: "luminanceToAlpha", result: "pencilMask" }), _jsx("feComponentTransfer", { in: "pencilMask", result: "sketch", children: _jsx("feFuncA", { type: "linear", slope: 1.6, intercept: -0.15 }) }), _jsx("feComposite", { in: "edge", in2: "sketch", operator: "in", result: "sketchEdge" }), _jsx("feColorMatrix", { in: "SourceGraphic", type: "matrix", values: "0.35 0 0 0 0 0 0.35 0 0 0 0 0 0.35 0 0 0 0 0 1 0", result: "ink" }), _jsx("feComposite", { in: "ink", in2: "sketchEdge", operator: "in", result: "contour" }), _jsx("feComposite", { in: "contour", in2: "paper", operator: "atop" })] }));
6
- }