@kind-ui/charts 0.1.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 +20 -0
- package/LICENSE +21 -0
- package/README.md +966 -0
- package/dist/activity-rings.d.ts +47 -0
- package/dist/activity-rings.js +55 -0
- package/dist/animation.d.ts +27 -0
- package/dist/animation.js +102 -0
- package/dist/area-chart.d.ts +9 -0
- package/dist/area-chart.js +33 -0
- package/dist/area-clay.d.ts +2 -0
- package/dist/area-clay.js +6 -0
- package/dist/area-material.d.ts +8 -0
- package/dist/area-material.js +66 -0
- package/dist/area-series.d.ts +11 -0
- package/dist/area-series.js +34 -0
- package/dist/bar-category.d.ts +5 -0
- package/dist/bar-category.js +35 -0
- package/dist/bar-chart.d.ts +17 -0
- package/dist/bar-chart.js +42 -0
- package/dist/bar-clay.d.ts +4 -0
- package/dist/bar-clay.js +6 -0
- package/dist/bar-material.d.ts +8 -0
- package/dist/bar-material.js +19 -0
- package/dist/bar-paper.d.ts +2 -0
- package/dist/bar-paper.js +6 -0
- package/dist/bar-series.d.ts +13 -0
- package/dist/bar-series.js +178 -0
- package/dist/box-material.d.ts +14 -0
- package/dist/box-material.js +30 -0
- package/dist/box-plot.d.ts +50 -0
- package/dist/box-plot.js +218 -0
- package/dist/category-cells.d.ts +6 -0
- package/dist/category-cells.js +41 -0
- package/dist/chart-context.d.ts +11 -0
- package/dist/chart-context.js +9 -0
- package/dist/combo-chart.d.ts +16 -0
- package/dist/combo-chart.js +64 -0
- package/dist/configured-line-chart.d.ts +79 -0
- package/dist/configured-line-chart.js +77 -0
- package/dist/emphasis.d.ts +44 -0
- package/dist/emphasis.js +128 -0
- package/dist/heatmap-model.d.ts +38 -0
- package/dist/heatmap-model.js +73 -0
- package/dist/heatmap.d.ts +56 -0
- package/dist/heatmap.js +366 -0
- package/dist/histogram-chart.d.ts +14 -0
- package/dist/histogram-chart.js +27 -0
- package/dist/histogram-data.d.ts +17 -0
- package/dist/histogram-data.js +66 -0
- package/dist/histogram-material.d.ts +13 -0
- package/dist/histogram-material.js +8 -0
- package/dist/histogram-series.d.ts +16 -0
- package/dist/histogram-series.js +67 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +36 -0
- package/dist/legend.d.ts +16 -0
- package/dist/legend.js +30 -0
- package/dist/line-chart.d.ts +41 -0
- package/dist/line-chart.js +160 -0
- package/dist/line-material.d.ts +9 -0
- package/dist/line-material.js +24 -0
- package/dist/line-series.d.ts +15 -0
- package/dist/line-series.js +40 -0
- package/dist/pie-chart.d.ts +17 -0
- package/dist/pie-chart.js +68 -0
- package/dist/pie-material.d.ts +19 -0
- package/dist/pie-material.js +16 -0
- package/dist/pie-series.d.ts +14 -0
- package/dist/pie-series.js +208 -0
- package/dist/polar-chart.d.ts +33 -0
- package/dist/polar-chart.js +145 -0
- package/dist/polar-material.d.ts +7 -0
- package/dist/polar-material.js +9 -0
- package/dist/polar-series.d.ts +17 -0
- package/dist/polar-series.js +169 -0
- package/dist/radar-interaction.d.ts +29 -0
- package/dist/radar-interaction.js +138 -0
- package/dist/radial-bar-label.d.ts +15 -0
- package/dist/radial-bar-label.js +136 -0
- package/dist/radial-category.d.ts +4 -0
- package/dist/radial-category.js +4 -0
- package/dist/root.d.ts +14 -0
- package/dist/root.js +29 -0
- package/dist/sankey-chart.d.ts +33 -0
- package/dist/sankey-chart.js +142 -0
- package/dist/sankey-colors.d.ts +10 -0
- package/dist/sankey-colors.js +6 -0
- package/dist/sankey-data.d.ts +30 -0
- package/dist/sankey-data.js +65 -0
- package/dist/sankey-finish.d.ts +13 -0
- package/dist/sankey-finish.js +10 -0
- package/dist/sankey-legend.d.ts +14 -0
- package/dist/sankey-legend.js +9 -0
- package/dist/sankey-marks.d.ts +31 -0
- package/dist/sankey-marks.js +67 -0
- package/dist/sankey-table.d.ts +11 -0
- package/dist/sankey-table.js +8 -0
- package/dist/scatter-chart.d.ts +16 -0
- package/dist/scatter-chart.js +64 -0
- package/dist/scatter-material.d.ts +8 -0
- package/dist/scatter-material.js +39 -0
- package/dist/scatter-series.d.ts +11 -0
- package/dist/scatter-series.js +74 -0
- package/dist/scatter-tooltip.d.ts +24 -0
- package/dist/scatter-tooltip.js +96 -0
- package/dist/styles.css +443 -0
- package/dist/surface-material.d.ts +13 -0
- package/dist/surface-material.js +7 -0
- package/dist/tooltip-content.d.ts +19 -0
- package/dist/tooltip-content.js +60 -0
- package/dist/tooltip-number.d.ts +4 -0
- package/dist/tooltip-number.js +68 -0
- package/dist/tooltip.d.ts +29 -0
- package/dist/tooltip.js +73 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +1 -0
- package/dist/waterfall-data.d.ts +24 -0
- package/dist/waterfall-data.js +45 -0
- package/dist/waterfall-series.d.ts +15 -0
- package/dist/waterfall-series.js +35 -0
- package/package.json +49 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ComponentProps } from "react";
|
|
2
|
+
import { Cell, LabelList } from "recharts";
|
|
3
|
+
import { type TooltipProps } from "./animation.js";
|
|
4
|
+
import { type LegendProps } from "./legend.js";
|
|
5
|
+
import { type RadialBarChartProps } from "./polar-chart.js";
|
|
6
|
+
import { type RadialBarSeriesProps } from "./polar-series.js";
|
|
7
|
+
import { type RootProps } from "./root.js";
|
|
8
|
+
import type { SeriesConfig } from "./types.js";
|
|
9
|
+
export type ActivityRing = {
|
|
10
|
+
/** Stable metadata identity in config. Array order controls ring order. */
|
|
11
|
+
key: string;
|
|
12
|
+
value: number;
|
|
13
|
+
/** Inclusive finite bounds; values outside them are clamped visually only. */
|
|
14
|
+
domain?: readonly [number, number];
|
|
15
|
+
/** Native per-ring paint and handlers override configured paint. */
|
|
16
|
+
cellProps?: ComponentProps<typeof Cell>;
|
|
17
|
+
};
|
|
18
|
+
export type ActivityRingDatum = ActivityRing & {
|
|
19
|
+
label: string;
|
|
20
|
+
progress: number;
|
|
21
|
+
/** Preserved through native computed sector payloads, whose value is normalized. */
|
|
22
|
+
rawValue: number;
|
|
23
|
+
};
|
|
24
|
+
type Name = {
|
|
25
|
+
"aria-label": string;
|
|
26
|
+
"aria-labelledby"?: string;
|
|
27
|
+
} | {
|
|
28
|
+
"aria-labelledby": string;
|
|
29
|
+
"aria-label"?: string;
|
|
30
|
+
};
|
|
31
|
+
export type ActivityRingsProps = Omit<RadialBarChartProps<ActivityRingDatum>, "data" | "children" | "layout" | "categoryKey"> & Name & {
|
|
32
|
+
"aria-describedby"?: string;
|
|
33
|
+
rings: readonly ActivityRing[];
|
|
34
|
+
config: SeriesConfig;
|
|
35
|
+
/** Default domain for rings without their own domain. Defaults to [0, 100]. */
|
|
36
|
+
domain?: readonly [number, number];
|
|
37
|
+
/** Native chart geometry remains available: radii, center, angles and gaps. */
|
|
38
|
+
series?: Omit<RadialBarSeriesProps<ActivityRingDatum, number>, "data" | "dataKey" | "seriesKey" | "children" | "angleAxisId" | "radiusAxisId">;
|
|
39
|
+
labels?: false | Omit<ComponentProps<typeof LabelList>, "dataKey">;
|
|
40
|
+
legend?: false | LegendProps;
|
|
41
|
+
/** Custom content receives native payload with original value and normalized progress. */
|
|
42
|
+
tooltip?: false | TooltipProps;
|
|
43
|
+
rootProps?: Omit<RootProps, "config" | "children" | "visibleSeries" | "onVisibleSeriesChange">;
|
|
44
|
+
};
|
|
45
|
+
/** A narrow progress recipe; native RadialBarChart remains the full composition escape hatch. */
|
|
46
|
+
export declare function ActivityRings({ rings, config, domain, series, labels, legend, tooltip, rootProps, width, height, style, className, responsive, accessibilityLayer, ...chartProps }: ActivityRingsProps): import("react").JSX.Element;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useContext, useId } from "react";
|
|
4
|
+
import { Cell, LabelList, PolarAngleAxis, PolarRadiusAxis } from "recharts";
|
|
5
|
+
import { Tooltip } from "./animation.js";
|
|
6
|
+
import { ChartContext } from "./chart-context.js";
|
|
7
|
+
import { Legend } from "./legend.js";
|
|
8
|
+
import { RadialBarChart } from "./polar-chart.js";
|
|
9
|
+
import { RadialBarSeries } from "./polar-series.js";
|
|
10
|
+
import { RadialBarLabel } from "./radial-bar-label.js";
|
|
11
|
+
import { Root } from "./root.js";
|
|
12
|
+
import { TooltipContent } from "./tooltip-content.js";
|
|
13
|
+
/** A narrow progress recipe; native RadialBarChart remains the full composition escape hatch. */
|
|
14
|
+
export function ActivityRings({ rings, config, domain = [0, 100], series, labels = false, legend, tooltip, rootProps, width, height, style, className, responsive = true, accessibilityLayer = true, ...chartProps }) {
|
|
15
|
+
const parent = useContext(ChartContext);
|
|
16
|
+
const tooltipOptions = tooltip === false ? undefined : tooltip;
|
|
17
|
+
const descriptionId = useId();
|
|
18
|
+
if (parent)
|
|
19
|
+
throw new Error("ActivityRings owns Root; use native RadialBarChart inside Root instead");
|
|
20
|
+
if (!chartProps["aria-label"]?.trim() && !chartProps["aria-labelledby"]?.trim())
|
|
21
|
+
throw new Error("ActivityRings requires aria-label or aria-labelledby");
|
|
22
|
+
const keys = rings.map((ring) => ring.key);
|
|
23
|
+
if (new Set(keys).size !== keys.length)
|
|
24
|
+
throw new Error("ActivityRings ring keys must be unique");
|
|
25
|
+
const data = rings.map((ring) => {
|
|
26
|
+
if (!Object.hasOwn(config, ring.key))
|
|
27
|
+
throw new Error(`ActivityRings ring key "${ring.key}" must exist in config`);
|
|
28
|
+
const [min, max] = ring.domain ?? domain;
|
|
29
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min || !Number.isFinite(max - min))
|
|
30
|
+
throw new Error("ActivityRings domains require finite increasing bounds");
|
|
31
|
+
if (!Number.isFinite(ring.value))
|
|
32
|
+
throw new Error("ActivityRings values must be finite numbers");
|
|
33
|
+
return {
|
|
34
|
+
...ring,
|
|
35
|
+
// biome-ignore lint/style/noNonNullAssertion: Object.hasOwn above rejects ring keys absent from config.
|
|
36
|
+
label: config[ring.key].label,
|
|
37
|
+
rawValue: ring.value,
|
|
38
|
+
progress: Math.max(0, Math.min(100, ((ring.value - min) / (max - min)) * 100)),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
// biome-ignore lint/style/noNonNullAssertion: Every key was validated against config while constructing data.
|
|
42
|
+
const activeConfig = Object.fromEntries(keys.map((key) => [key, config[key]]));
|
|
43
|
+
const describedBy = [chartProps["aria-describedby"], descriptionId].filter(Boolean).join(" ");
|
|
44
|
+
return (_jsxs(Root, { ...rootProps, config: activeConfig, children: [_jsx("dl", { id: descriptionId, "data-kind-ui": "chart-instructions", children: data.map((ring) => (_jsxs("div", { children: [_jsx("dt", { children: ring.label }), _jsx("dd", { children: config[ring.key].formatValue?.(ring.rawValue) ?? ring.rawValue })] }, ring.key))) }), _jsxs(RadialBarChart, { innerRadius: "30%", outerRadius: "90%", startAngle: 90, endAngle: -270, barCategoryGap: "15%", ...chartProps, "aria-describedby": describedBy, data: data, categoryKey: "key", layout: "radial", accessibilityLayer: accessibilityLayer, responsive: responsive, ...(width !== undefined ? { width } : {}), ...(height !== undefined ? { height } : {}), className: ["kind-ui-activity-rings", className].filter(Boolean).join(" "), style: { width: width ?? "100%", height: height ?? 300, ...style }, children: [_jsx(PolarAngleAxis, { type: "number", domain: [0, 100], tick: false, axisLine: false }), _jsx(PolarRadiusAxis, { type: "category", dataKey: "key", tick: false, axisLine: false }), _jsxs(RadialBarSeries, { background: true, cornerRadius: "50%", ...series, dataKey: "progress", children: [data.some((ring) => ring.cellProps !== undefined) &&
|
|
45
|
+
data.map((ring) => _jsx(Cell, { ...ring.cellProps }, ring.key)), labels !== false && (_jsx(LabelList, { content: _jsx(RadialBarLabel, {}), ...labels, dataKey: "label" }))] }), tooltip !== false && (_jsx(Tooltip, { content: (native) => (_jsx(TooltipContent, { tooltip: {
|
|
46
|
+
...native,
|
|
47
|
+
payload: native.payload.map((entry) => {
|
|
48
|
+
const rawValue = entry.payload?.rawValue;
|
|
49
|
+
return rawValue === undefined ? entry : { ...entry, value: rawValue };
|
|
50
|
+
}),
|
|
51
|
+
}, itemKey: tooltipOptions?.itemKey ??
|
|
52
|
+
((entry) => entry.payload?.key ?? String(entry.dataKey)), ...(tooltipOptions?.valueAnimation
|
|
53
|
+
? { valueAnimation: tooltipOptions.valueAnimation }
|
|
54
|
+
: {}), hideLabel: true })), ...tooltipOptions }))] }), legend !== false && _jsx(Legend, { ...legend })] }));
|
|
55
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type Transition } from "motion/react";
|
|
2
|
+
import { type ReactElement } from "react";
|
|
3
|
+
import { type DotProps } from "recharts";
|
|
4
|
+
import { type LineChartProps as StaticLineChartProps } from "./line-chart.js";
|
|
5
|
+
import { type LineSeriesProps as StaticLineSeriesProps } from "./line-series.js";
|
|
6
|
+
import { type TooltipProps } from "./tooltip.js";
|
|
7
|
+
export type LineAnimation = {
|
|
8
|
+
revealDurationMs?: number;
|
|
9
|
+
revealEasing?: Transition["ease"];
|
|
10
|
+
hoverTransition?: Transition;
|
|
11
|
+
};
|
|
12
|
+
type DefaultLineDataKey = Extract<StaticLineSeriesProps["dataKey"], (row: never) => unknown>;
|
|
13
|
+
export type LineSeriesProps<DataPoint = Parameters<DefaultLineDataKey>[0], Value = ReturnType<DefaultLineDataKey>> = Omit<StaticLineSeriesProps<DataPoint, Value>, "isAnimationActive">;
|
|
14
|
+
export type LineChartProps = StaticLineChartProps & {
|
|
15
|
+
animate?: boolean | LineAnimation | undefined;
|
|
16
|
+
};
|
|
17
|
+
export declare const MotionContext: import("react").Context<{
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
transition: Transition;
|
|
20
|
+
}>;
|
|
21
|
+
/** Motion owns the shared entrance clip and default active marks. */
|
|
22
|
+
export declare function LineChart({ animate, children, ...props }: LineChartProps): import("react").JSX.Element;
|
|
23
|
+
export declare function ActiveMarker({ cx, cy, fill, stroke }: DotProps): import("react").JSX.Element | null;
|
|
24
|
+
export declare function LineSeries<DataPoint = Parameters<DefaultLineDataKey>[0], Value = ReturnType<DefaultLineDataKey>>(props: LineSeriesProps<DataPoint, Value>): ReactElement;
|
|
25
|
+
export declare function LineSeries(props: LineSeriesProps): ReactElement;
|
|
26
|
+
export declare function Tooltip(props: TooltipProps): import("react").JSX.Element;
|
|
27
|
+
export type { TooltipProps };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { animate as animateValue, motion, useMotionValue } from "motion/react";
|
|
4
|
+
import { createContext, use, useCallback, useId, useLayoutEffect, useRef, useState, useSyncExternalStore, } from "react";
|
|
5
|
+
import { DefaultZIndexes, LineChart as EngineLineChart, ZIndexLayer, } from "recharts";
|
|
6
|
+
import { useChart } from "./chart-context.js";
|
|
7
|
+
import { LineChartFrame, useLineInteraction, } from "./line-chart.js";
|
|
8
|
+
import { LineSeries as StaticLineSeries, } from "./line-series.js";
|
|
9
|
+
import { TooltipBase } from "./tooltip.js";
|
|
10
|
+
const defaultHover = { type: "spring", stiffness: 210, damping: 28, mass: 0.8 };
|
|
11
|
+
export const MotionContext = createContext({ enabled: false, transition: defaultHover });
|
|
12
|
+
const query = "(prefers-reduced-motion: reduce)";
|
|
13
|
+
function subscribe(change) {
|
|
14
|
+
const media = window.matchMedia(query);
|
|
15
|
+
media.addEventListener("change", change);
|
|
16
|
+
return () => media.removeEventListener("change", change);
|
|
17
|
+
}
|
|
18
|
+
const snapshot = () => window.matchMedia(query).matches;
|
|
19
|
+
const serverSnapshot = () => true;
|
|
20
|
+
/** Motion owns the shared entrance clip and default active marks. */
|
|
21
|
+
export function LineChart({ animate = false, children, ...props }) {
|
|
22
|
+
const id = useId();
|
|
23
|
+
const reduced = useSyncExternalStore(subscribe, snapshot, serverSnapshot);
|
|
24
|
+
const [interacted, setInteracted] = useState(false);
|
|
25
|
+
const options = typeof animate === "object" ? animate : {};
|
|
26
|
+
const enabled = animate !== false && !reduced;
|
|
27
|
+
const interrupt = useCallback(() => setInteracted(true), []);
|
|
28
|
+
const reveal = enabled && !interacted;
|
|
29
|
+
const transition = options.hoverTransition ?? defaultHover;
|
|
30
|
+
return (_jsx(MotionContext, { value: { enabled, transition }, children: _jsxs(LineChartFrame, { chartProps: props, engine: EngineLineChart, motionEnabled: enabled, interrupt: interrupt, ...(reveal ? { clip: `url(#${id}-reveal)` } : {}), children: [reveal && (_jsx("defs", { children: _jsx("clipPath", { id: `${id}-reveal`, clipPathUnits: "userSpaceOnUse", children: _jsx(motion.rect, { x: 0, y: 0, height: "100%", initial: { width: "0%" }, animate: { width: "100%" }, transition: {
|
|
31
|
+
duration: Math.max(0, options.revealDurationMs ?? 1000) / 1000,
|
|
32
|
+
ease: options.revealEasing ?? [0.25, 0.1, 0.25, 1],
|
|
33
|
+
} }) }) })), children] }) }));
|
|
34
|
+
}
|
|
35
|
+
// Stop the previous target before retargeting or snapping, without remounting consumer DOM.
|
|
36
|
+
function useAnimatedCoordinate(target, enabled, transition) {
|
|
37
|
+
const value = useMotionValue(target);
|
|
38
|
+
useLayoutEffect(() => {
|
|
39
|
+
if (!enabled) {
|
|
40
|
+
value.set(target);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const controls = animateValue(value, target, transition);
|
|
44
|
+
return () => controls.stop();
|
|
45
|
+
}, [value, target, enabled, transition]);
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
export function ActiveMarker({ cx, cy, fill, stroke }) {
|
|
49
|
+
const { enabled, transition } = use(MotionContext);
|
|
50
|
+
const { motionReady } = useLineInteraction();
|
|
51
|
+
const animate = enabled && motionReady;
|
|
52
|
+
const x = useAnimatedCoordinate(cx ?? 0, animate, transition);
|
|
53
|
+
const y = useAnimatedCoordinate(cy ?? 0, animate, transition);
|
|
54
|
+
if (cx == null || cy == null)
|
|
55
|
+
return null;
|
|
56
|
+
return (_jsx(motion.circle, { "data-kind-ui": "active-marker", initial: false, cx: x, cy: y, r: 5, fill: fill ?? stroke, stroke: "var(--card, white)", strokeWidth: 2, strokeDasharray: "none", pointerEvents: "none" }));
|
|
57
|
+
}
|
|
58
|
+
export function LineSeries(props) {
|
|
59
|
+
const { enabled } = use(MotionContext);
|
|
60
|
+
const { visibleSeries } = useChart();
|
|
61
|
+
const key = props.seriesKey ?? (typeof props.dataKey === "string" ? props.dataKey : undefined);
|
|
62
|
+
const visible = visibleSeries === undefined || (key !== undefined && visibleSeries.includes(key));
|
|
63
|
+
const opacity = useMotionValue(visible ? 1 : 0);
|
|
64
|
+
const [drawn, setDrawn] = useState(visible);
|
|
65
|
+
const previous = useRef(visible);
|
|
66
|
+
const run = useRef(0);
|
|
67
|
+
useLayoutEffect(() => {
|
|
68
|
+
const changed = previous.current !== visible;
|
|
69
|
+
previous.current = visible;
|
|
70
|
+
const token = ++run.current;
|
|
71
|
+
if (!enabled) {
|
|
72
|
+
opacity.set(visible ? 1 : 0);
|
|
73
|
+
setDrawn(visible);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (!changed)
|
|
77
|
+
return;
|
|
78
|
+
if (visible)
|
|
79
|
+
setDrawn(true);
|
|
80
|
+
const controls = animateValue(opacity, visible ? 1 : 0, {
|
|
81
|
+
duration: 0.18,
|
|
82
|
+
ease: "easeOut",
|
|
83
|
+
onComplete: () => {
|
|
84
|
+
if (!visible && run.current === token)
|
|
85
|
+
setDrawn(false);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
return () => controls.stop();
|
|
89
|
+
}, [visible, enabled, opacity]);
|
|
90
|
+
return (_jsx(ZIndexLayer, { zIndex: props.zIndex ?? DefaultZIndexes.line, children: _jsx(motion.g, { initial: false, style: { opacity }, pointerEvents: visible ? undefined : "none", "aria-hidden": visible ? undefined : true, children: _jsx(StaticLineSeries, { ...props, activeDot: visible ? (props.activeDot ?? _jsx(ActiveMarker, {})) : false, zIndex: 0, renderWhileHidden: enabled && drawn, isAnimationActive: false }) }) }));
|
|
91
|
+
}
|
|
92
|
+
function MovingFrame({ x, y, maxX, maxY, ref, style, frameProps, children }) {
|
|
93
|
+
const { enabled, transition } = use(MotionContext);
|
|
94
|
+
const { motionReady } = useLineInteraction();
|
|
95
|
+
const animate = enabled && motionReady;
|
|
96
|
+
const movingX = useAnimatedCoordinate(x, animate, transition);
|
|
97
|
+
const movingY = useAnimatedCoordinate(y, animate, transition);
|
|
98
|
+
return (_jsx(motion.div, { "data-kind-ui": "tooltip-motion", initial: false, style: { x: movingX, y: movingY }, transformTemplate: ({ x = 0, y = 0 }) => `translate(clamp(0px, ${typeof x === "number" ? `${x}px` : x}, ${maxX}px), clamp(0px, ${typeof y === "number" ? `${y}px` : y}, ${maxY}px))`, children: _jsx("div", { ...frameProps, "data-kind-ui": "tooltip-frame", ref: ref, style: { ...style, ...frameProps?.style }, children: children }) }));
|
|
99
|
+
}
|
|
100
|
+
export function Tooltip(props) {
|
|
101
|
+
return _jsx(TooltipBase, { ...props, Frame: MovingFrame });
|
|
102
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ComponentProps } from "react";
|
|
2
|
+
import { AreaChart as EngineAreaChart } from "recharts";
|
|
3
|
+
import { type LineAnimation } from "./animation.js";
|
|
4
|
+
export type AreaAnimation = LineAnimation;
|
|
5
|
+
export type AreaChartProps = ComponentProps<typeof EngineAreaChart> & {
|
|
6
|
+
animate?: boolean | AreaAnimation | undefined;
|
|
7
|
+
};
|
|
8
|
+
/** Native Recharts geometry and composition with a shared Motion entrance and tooltip. */
|
|
9
|
+
export declare function AreaChart({ animate, children, ...props }: AreaChartProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { motion } from "motion/react";
|
|
4
|
+
import { useCallback, useId, useState, useSyncExternalStore } from "react";
|
|
5
|
+
import { AreaChart as EngineAreaChart } from "recharts";
|
|
6
|
+
import { MotionContext } from "./animation.js";
|
|
7
|
+
import { LineChartFrame } from "./line-chart.js";
|
|
8
|
+
const defaultHover = { type: "spring", stiffness: 210, damping: 28, mass: 0.8 };
|
|
9
|
+
const query = "(prefers-reduced-motion: reduce)";
|
|
10
|
+
function subscribe(change) {
|
|
11
|
+
const media = window.matchMedia(query);
|
|
12
|
+
media.addEventListener("change", change);
|
|
13
|
+
return () => media.removeEventListener("change", change);
|
|
14
|
+
}
|
|
15
|
+
const snapshot = () => window.matchMedia(query).matches;
|
|
16
|
+
const serverSnapshot = () => true;
|
|
17
|
+
/** Native Recharts geometry and composition with a shared Motion entrance and tooltip. */
|
|
18
|
+
export function AreaChart({ animate = false, children, ...props }) {
|
|
19
|
+
const id = useId();
|
|
20
|
+
const reduced = useSyncExternalStore(subscribe, snapshot, serverSnapshot);
|
|
21
|
+
const [interacted, setInteracted] = useState(false);
|
|
22
|
+
const options = typeof animate === "object" ? animate : {};
|
|
23
|
+
const enabled = animate !== false && reduced === false;
|
|
24
|
+
const interrupt = useCallback(() => setInteracted(true), []);
|
|
25
|
+
const reveal = enabled && !interacted;
|
|
26
|
+
return (_jsx(MotionContext, { value: { enabled, transition: options.hoverTransition ?? defaultHover }, children: _jsxs(LineChartFrame, { chartProps: {
|
|
27
|
+
...props,
|
|
28
|
+
className: ["kind-ui-area-chart", props.className].filter(Boolean).join(" "),
|
|
29
|
+
}, engine: EngineAreaChart, motionEnabled: enabled, interrupt: interrupt, ...(reveal ? { clip: `url(#${id}-area-reveal)` } : {}), children: [reveal && (_jsx("defs", { children: _jsx("clipPath", { id: `${id}-area-reveal`, clipPathUnits: "userSpaceOnUse", children: _jsx(motion.rect, { "data-area-reveal": "", x: 0, y: 0, height: "100%", initial: { width: "0%" }, animate: { width: "100%" }, onAnimationComplete: interrupt, transition: {
|
|
30
|
+
duration: Math.max(0, options.revealDurationMs ?? 1000) / 1000,
|
|
31
|
+
ease: options.revealEasing ?? [0.25, 0.1, 0.25, 1],
|
|
32
|
+
} }) }) })), children] }) }));
|
|
33
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
/** Soft convex matte relief for filled areas; native body alpha is preserved. */
|
|
4
|
+
export function AreaClayRelief() {
|
|
5
|
+
return (_jsxs(_Fragment, { children: [_jsx("feComponentTransfer", { in: "SourceAlpha", result: "silhouette", children: _jsx("feFuncA", { type: "linear", slope: 1000 }) }), _jsx("feGaussianBlur", { in: "silhouette", stdDeviation: 6, result: "rounded" }), _jsx("feDiffuseLighting", { in: "rounded", surfaceScale: 6, diffuseConstant: 1.22, lightingColor: "#fff", result: "matteLight", children: _jsx("feDistantLight", { azimuth: 225, elevation: 55 }) }), _jsx("feComposite", { in: "SourceGraphic", in2: "matteLight", operator: "arithmetic", k1: 0.35, k2: 0.65, result: "matteBody" }), _jsx("feOffset", { in: "rounded", dx: 5, dy: 7, result: "lower" }), _jsx("feComposite", { in: "silhouette", in2: "lower", operator: "out", result: "topRim" }), _jsx("feComposite", { in: "topRim", in2: "SourceAlpha", operator: "in", result: "topPaint" }), _jsx("feFlood", { floodColor: "var(--kind-ui-area-clay-light, #fff)", floodOpacity: "var(--kind-ui-area-clay-highlight, 0.48)" }), _jsx("feComposite", { in2: "topPaint", operator: "in", result: "light" }), _jsx("feOffset", { in: "rounded", dx: -6, dy: -8, result: "upper" }), _jsx("feComposite", { in: "silhouette", in2: "upper", operator: "out", result: "bottomRim" }), _jsx("feComposite", { in: "bottomRim", in2: "SourceAlpha", operator: "in", result: "bottomPaint" }), _jsx("feFlood", { floodColor: "var(--kind-ui-area-clay-shade, #17212b)", floodOpacity: "var(--kind-ui-area-clay-shadow, 0.28)" }), _jsx("feComposite", { in2: "bottomPaint", operator: "in", result: "shade" }), _jsx("feComposite", { in: "shade", in2: "matteBody", operator: "atop", result: "shaded" }), _jsx("feComposite", { in: "light", in2: "shaded", operator: "atop", result: "body" }), _jsx("feGaussianBlur", { in: "SourceAlpha", stdDeviation: 1.5, result: "castBlur" }), _jsx("feOffset", { in: "castBlur", dx: 1, dy: 1.5, result: "castOffset" }), _jsx("feFlood", { floodColor: "var(--kind-ui-area-clay-shade, #17212b)", floodOpacity: "var(--kind-ui-area-clay-cast, 0.12)" }), _jsx("feComposite", { in2: "castOffset", operator: "in", result: "castPaint" }), _jsx("feComposite", { in: "castPaint", in2: "silhouette", operator: "out", result: "cast" }), _jsxs("feMerge", { children: [_jsx("feMergeNode", { in: "cast" }), _jsx("feMergeNode", { in: "body" })] })] }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type AreaRevealShapeProps } from "recharts";
|
|
2
|
+
import type { LineMaterial } from "./line-material.js";
|
|
3
|
+
/** The same finish vocabulary as lines, applied to the complete native area. */
|
|
4
|
+
export type AreaMaterial = LineMaterial;
|
|
5
|
+
export declare function MaterialArea({ material, filterId, ...props }: AreaRevealShapeProps & {
|
|
6
|
+
material: Exclude<AreaMaterial, "plain">;
|
|
7
|
+
filterId: string;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
4
|
+
import { AreaRevealShape } from "recharts";
|
|
5
|
+
import { SurfaceMaterialFilter } from "./surface-material.js";
|
|
6
|
+
export function MaterialArea({ material, filterId, ...props }) {
|
|
7
|
+
const nativeShape = useRef(null);
|
|
8
|
+
const [envelope, setEnvelope] = useState();
|
|
9
|
+
// A native/custom curve interpolation can overshoot its data points. Measure the
|
|
10
|
+
// unchanged SVG geometry before paint rather than reimplementing Recharts paths.
|
|
11
|
+
useLayoutEffect(() => {
|
|
12
|
+
const box = nativeShape.current?.getBBox();
|
|
13
|
+
if (!box || ![box.x, box.y, box.width, box.height].every(Number.isFinite))
|
|
14
|
+
return;
|
|
15
|
+
setEnvelope((previous) => previous &&
|
|
16
|
+
previous.x === box.x &&
|
|
17
|
+
previous.y === box.y &&
|
|
18
|
+
previous.width === box.width &&
|
|
19
|
+
previous.height === box.height
|
|
20
|
+
? previous
|
|
21
|
+
: { x: box.x, y: box.y, width: box.width, height: box.height });
|
|
22
|
+
});
|
|
23
|
+
// Include the engine's baseline: stacks, ranges and vertical areas do not share a flat Y.
|
|
24
|
+
const points = [
|
|
25
|
+
...(props.points ?? []),
|
|
26
|
+
...(Array.isArray(props.baseLine) ? props.baseLine : []),
|
|
27
|
+
];
|
|
28
|
+
let minX = Infinity;
|
|
29
|
+
let minY = Infinity;
|
|
30
|
+
let maxX = -Infinity;
|
|
31
|
+
let maxY = -Infinity;
|
|
32
|
+
for (const point of points) {
|
|
33
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y))
|
|
34
|
+
continue;
|
|
35
|
+
minX = Math.min(minX, point.x);
|
|
36
|
+
minY = Math.min(minY, point.y);
|
|
37
|
+
maxX = Math.max(maxX, point.x);
|
|
38
|
+
maxY = Math.max(maxY, point.y);
|
|
39
|
+
}
|
|
40
|
+
if (!Number.isFinite(minX))
|
|
41
|
+
return _jsx(AreaRevealShape, { ...props });
|
|
42
|
+
if (typeof props.baseLine === "number" && Number.isFinite(props.baseLine)) {
|
|
43
|
+
if (props.layout === "vertical") {
|
|
44
|
+
minX = Math.min(minX, props.baseLine);
|
|
45
|
+
maxX = Math.max(maxX, props.baseLine);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
minY = Math.min(minY, props.baseLine);
|
|
49
|
+
maxY = Math.max(maxY, props.baseLine);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (envelope) {
|
|
53
|
+
minX = Math.min(minX, envelope.x);
|
|
54
|
+
minY = Math.min(minY, envelope.y);
|
|
55
|
+
maxX = Math.max(maxX, envelope.x + envelope.width);
|
|
56
|
+
maxY = Math.max(maxY, envelope.y + envelope.height);
|
|
57
|
+
}
|
|
58
|
+
const width = Number(props.strokeWidth ?? 1);
|
|
59
|
+
const pad = (Number.isFinite(width) ? Math.abs(width) : 12) / 2 + 8;
|
|
60
|
+
return (_jsxs("g", { "data-kind-ui": "area-material", "data-material": material, children: [_jsx("defs", { pointerEvents: "none", children: _jsx(SurfaceMaterialFilter, { material: material, id: filterId, family: "area", bounds: {
|
|
61
|
+
x: minX - pad,
|
|
62
|
+
y: minY - pad,
|
|
63
|
+
width: maxX - minX + 2 * pad,
|
|
64
|
+
height: maxY - minY + 2 * pad,
|
|
65
|
+
} }) }), _jsx("g", { ref: nativeShape, filter: `url(#${filterId})`, children: _jsx(AreaRevealShape, { ...props }) })] }));
|
|
66
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ComponentProps } from "react";
|
|
2
|
+
import { Area } from "recharts";
|
|
3
|
+
import { type AreaMaterial } from "./area-material.js";
|
|
4
|
+
export type AreaSeriesProps<DataPoint = unknown, Value = unknown> = Omit<ComponentProps<typeof Area<DataPoint, Value>>, "isAnimationActive"> & {
|
|
5
|
+
/** Metadata/visibility key, required only for function or numeric data keys. */
|
|
6
|
+
seriesKey?: string;
|
|
7
|
+
/** Finish on the native area; explicit shape/filter retain consumer ownership. */
|
|
8
|
+
material?: AreaMaterial;
|
|
9
|
+
};
|
|
10
|
+
/** A registered Recharts Area with Root colors and controlled visibility. */
|
|
11
|
+
export declare function AreaSeries<DataPoint = unknown, Value = unknown>({ seriesKey, material, hide, stroke, fill, className, ...props }: AreaSeriesProps<DataPoint, Value>): import("react").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useId, useLayoutEffect, useRef } from "react";
|
|
4
|
+
import { Area } from "recharts";
|
|
5
|
+
import { ActiveMarker } from "./animation.js";
|
|
6
|
+
import { MaterialArea } from "./area-material.js";
|
|
7
|
+
import { useChart } from "./chart-context.js";
|
|
8
|
+
import { useLineInteraction } from "./line-chart.js";
|
|
9
|
+
/** A registered Recharts Area with Root colors and controlled visibility. */
|
|
10
|
+
export function AreaSeries({ seriesKey, material = "plain", hide, stroke, fill, className, ...props }) {
|
|
11
|
+
const { config, visibleSeries } = useChart();
|
|
12
|
+
const { registerSeries, invalidate } = useLineInteraction();
|
|
13
|
+
const generatedId = useId();
|
|
14
|
+
const id = props.id || generatedId;
|
|
15
|
+
const key = seriesKey ?? (typeof props.dataKey === "string" ? props.dataKey : undefined);
|
|
16
|
+
const effectiveHide = hide === true || (visibleSeries !== undefined && !visibleSeries.includes(key ?? ""));
|
|
17
|
+
const previous = useRef({ data: props.data, hide: effectiveHide });
|
|
18
|
+
useLayoutEffect(() => {
|
|
19
|
+
if (props.data !== previous.current.data || effectiveHide !== previous.current.hide)
|
|
20
|
+
invalidate();
|
|
21
|
+
previous.current = { data: props.data, hide: effectiveHide };
|
|
22
|
+
}, [props.data, effectiveHide, invalidate]);
|
|
23
|
+
useLayoutEffect(() => {
|
|
24
|
+
if (key === undefined)
|
|
25
|
+
return;
|
|
26
|
+
return registerSeries(id, key);
|
|
27
|
+
}, [id, key, registerSeries]);
|
|
28
|
+
if (key === undefined && visibleSeries !== undefined)
|
|
29
|
+
throw new Error("AreaSeries requires seriesKey for controlled non-string dataKey");
|
|
30
|
+
const color = stroke ?? (key && Object.hasOwn(config, key) ? `var(--color-${key})` : undefined);
|
|
31
|
+
return (_jsx(Area, { activeDot: _jsx(ActiveMarker, {}), ...props, ...(material !== "plain" && props.shape === undefined && props.filter === undefined
|
|
32
|
+
? { shape: _jsx(MaterialArea, { material: material, filterId: `${generatedId}-area-material` }) }
|
|
33
|
+
: {}), isAnimationActive: false, id: id, hide: effectiveHide, ...(color !== undefined ? { stroke: color } : {}), ...(fill !== undefined ? { fill } : color !== undefined ? { fill: color } : {}), className: ["kind-ui-area-series", className].filter(Boolean).join(" ") }));
|
|
34
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Observe real pointer modality without rerendering native shapes during down/click. */
|
|
2
|
+
export declare function BarCategoryBoundary({ children }: {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
}): import("react").JSX.Element;
|
|
5
|
+
export declare function useBarCategoryHover(): boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, use, useState, useSyncExternalStore } from "react";
|
|
4
|
+
function createPointerModality() {
|
|
5
|
+
let hover = false;
|
|
6
|
+
const listeners = new Set();
|
|
7
|
+
return {
|
|
8
|
+
snapshot: () => hover,
|
|
9
|
+
subscribe: (listener) => {
|
|
10
|
+
listeners.add(listener);
|
|
11
|
+
return () => {
|
|
12
|
+
listeners.delete(listener);
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
set: (next) => {
|
|
16
|
+
if (hover === next)
|
|
17
|
+
return;
|
|
18
|
+
hover = next;
|
|
19
|
+
for (const listener of listeners)
|
|
20
|
+
listener();
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const Context = createContext(null);
|
|
25
|
+
/** Observe real pointer modality without rerendering native shapes during down/click. */
|
|
26
|
+
export function BarCategoryBoundary({ children }) {
|
|
27
|
+
const [modality] = useState(createPointerModality);
|
|
28
|
+
return (_jsx(Context, { value: modality, children: _jsx("div", { style: { display: "contents" }, onPointerOverCapture: (event) => modality.set(event.pointerType !== "touch"), onPointerMoveCapture: (event) => modality.set(event.pointerType !== "touch"), onPointerDownCapture: (event) => modality.set(event.pointerType !== "touch"), children: children }) }));
|
|
29
|
+
}
|
|
30
|
+
export function useBarCategoryHover() {
|
|
31
|
+
const modality = use(Context);
|
|
32
|
+
if (!modality)
|
|
33
|
+
throw new Error("Bar category marks must be inside BarChart");
|
|
34
|
+
return useSyncExternalStore(modality.subscribe, modality.snapshot, () => false);
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ComponentProps } from "react";
|
|
2
|
+
import { BarChart as EngineBarChart } from "recharts";
|
|
3
|
+
import { type LineAnimation } from "./animation.js";
|
|
4
|
+
export type BarAnimation = LineAnimation;
|
|
5
|
+
export type BarChartProps = ComponentProps<typeof EngineBarChart> & {
|
|
6
|
+
animate?: boolean | BarAnimation | undefined;
|
|
7
|
+
/** Opt in only for complete native category comparisons; any unsafe visible peer falls back. */
|
|
8
|
+
emphasis?: "none" | "category" | undefined;
|
|
9
|
+
};
|
|
10
|
+
export declare const BarMotion: import("react").Context<{
|
|
11
|
+
reveal: boolean;
|
|
12
|
+
options: BarAnimation;
|
|
13
|
+
finish: () => void;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function BarLifecycle({ layout, barGap, barCategoryGap, barSize, stackOffset, reverseStackOrder, }: BarChartProps): null;
|
|
16
|
+
/** Native Recharts composition with Kind interaction and optional Motion. */
|
|
17
|
+
export declare function BarChart({ animate, emphasis, children, ...props }: BarChartProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useCallback, useLayoutEffect, useRef, useState, useSyncExternalStore, } from "react";
|
|
4
|
+
import { BarChart as EngineBarChart } from "recharts";
|
|
5
|
+
import { MotionContext } from "./animation.js";
|
|
6
|
+
import { BarCategoryBoundary } from "./bar-category.js";
|
|
7
|
+
import { LineChartFrame, useLineInteraction } from "./line-chart.js";
|
|
8
|
+
export const BarMotion = createContext({
|
|
9
|
+
reveal: false,
|
|
10
|
+
options: {},
|
|
11
|
+
finish: () => { },
|
|
12
|
+
});
|
|
13
|
+
const query = "(prefers-reduced-motion: reduce)";
|
|
14
|
+
function subscribe(change) {
|
|
15
|
+
const media = window.matchMedia(query);
|
|
16
|
+
media.addEventListener("change", change);
|
|
17
|
+
return () => media.removeEventListener("change", change);
|
|
18
|
+
}
|
|
19
|
+
const snapshot = () => window.matchMedia(query).matches;
|
|
20
|
+
const serverSnapshot = () => true;
|
|
21
|
+
const defaultHover = { type: "spring", stiffness: 210, damping: 28, mass: 0.8 };
|
|
22
|
+
// Chart layout props may move bars without changing the plot or numeric zero.
|
|
23
|
+
export function BarLifecycle({ layout, barGap, barCategoryGap, barSize, stackOffset, reverseStackOrder, }) {
|
|
24
|
+
const { invalidate } = useLineInteraction();
|
|
25
|
+
const inputs = [layout, barGap, barCategoryGap, barSize, stackOffset, reverseStackOrder];
|
|
26
|
+
const previous = useRef(inputs);
|
|
27
|
+
useLayoutEffect(() => {
|
|
28
|
+
if (inputs.some((value, index) => value !== previous.current[index]))
|
|
29
|
+
invalidate();
|
|
30
|
+
previous.current = inputs;
|
|
31
|
+
});
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
/** Native Recharts composition with Kind interaction and optional Motion. */
|
|
35
|
+
export function BarChart({ animate = false, emphasis = "none", children, ...props }) {
|
|
36
|
+
const reduced = useSyncExternalStore(subscribe, snapshot, serverSnapshot);
|
|
37
|
+
const [interacted, setInteracted] = useState(false);
|
|
38
|
+
const finish = useCallback(() => setInteracted(true), []);
|
|
39
|
+
const enabled = animate !== false && !reduced;
|
|
40
|
+
const options = typeof animate === "object" ? animate : {};
|
|
41
|
+
return (_jsx(MotionContext, { value: { enabled, transition: options.hoverTransition ?? defaultHover }, children: _jsx(BarMotion, { value: { reveal: enabled && !interacted, options, finish }, children: _jsx(BarCategoryBoundary, { children: _jsxs(LineChartFrame, { chartProps: props, categoryEmphasis: emphasis === "category", engine: EngineBarChart, motionEnabled: enabled, interrupt: finish, children: [_jsx(BarLifecycle, { ...props }), children] }) }) }) }));
|
|
42
|
+
}
|
package/dist/bar-clay.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
/** Convex matte relief, lit from upper left; the native paint keeps its alpha. */
|
|
4
|
+
export function BarClay({ horizontal }) {
|
|
5
|
+
return (_jsxs(_Fragment, { children: [_jsx("feComponentTransfer", { in: "SourceAlpha", result: "footprint", children: _jsx("feFuncA", { type: "linear", slope: 100000 }) }), _jsx("feOffset", { in: "footprint", dx: horizontal ? 2 : 4, dy: horizontal ? 4 : 2, result: "lower" }), _jsx("feComposite", { in: "footprint", in2: "lower", operator: "arithmetic", k2: 1, k3: -1, result: "top" }), _jsx("feGaussianBlur", { in: "top", stdDeviation: horizontal ? "2.7 3.2" : "3.2 2.7", result: "softTop" }), _jsx("feFlood", { floodColor: "var(--kind-ui-bar-clay-light, #fff)", floodOpacity: "var(--kind-ui-bar-clay-highlight, 0.48)" }), _jsx("feComposite", { in2: "softTop", operator: "in", result: "light" }), _jsx("feOffset", { in: "footprint", dx: horizontal ? -2 : -4, dy: horizontal ? -4 : -2, result: "upper" }), _jsx("feComposite", { in: "footprint", in2: "upper", operator: "arithmetic", k2: 1, k3: -1, result: "bottom" }), _jsx("feGaussianBlur", { in: "bottom", stdDeviation: horizontal ? "2.7 3.2" : "3.2 2.7", result: "softBottom" }), _jsx("feFlood", { floodColor: "var(--kind-ui-bar-clay-shade, #17212b)", floodOpacity: "var(--kind-ui-bar-clay-shadow, 0.26)" }), _jsx("feComposite", { in2: "softBottom", operator: "in", result: "shade" }), _jsx("feComposite", { in: "shade", in2: "SourceGraphic", operator: "atop", result: "shaded" }), _jsx("feComposite", { in: "light", in2: "shaded", operator: "atop", result: "body" }), _jsx("feTurbulence", { type: "fractalNoise", baseFrequency: 0.7, numOctaves: 1, seed: 17, result: "grain" }), _jsx("feFlood", { floodColor: "var(--kind-ui-bar-clay-light, #fff)", floodOpacity: 0.025 }), _jsx("feComposite", { in2: "grain", operator: "in", result: "texture" }), _jsx("feComposite", { in: "texture", in2: "body", operator: "atop", result: "matte" }), _jsx("feGaussianBlur", { in: "SourceAlpha", stdDeviation: horizontal ? "0 2.5" : "2.5 0", result: "soft" }), _jsx("feOffset", { in: "soft", dx: horizontal ? 0 : 1.5, dy: horizontal ? 1.5 : 0, result: "dropped" }), _jsx("feFlood", { floodColor: "var(--kind-ui-bar-clay-shade, #17212b)", floodOpacity: 0.16 }), _jsx("feComposite", { in2: "dropped", operator: "in", result: "cast" }), _jsx("feComposite", { in: "cast", in2: "footprint", operator: "out", result: "shadow" }), _jsxs("feMerge", { children: [_jsx("feMergeNode", { in: "shadow" }), _jsx("feMergeNode", { in: "matte" })] })] }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LineMaterial } from "./line-material.js";
|
|
2
|
+
export type BarMaterial = LineMaterial;
|
|
3
|
+
/** Native rectangles apply this filter independently to their own object bounds. */
|
|
4
|
+
export declare function BarMaterialFilter({ material, id, horizontal, }: {
|
|
5
|
+
material: Exclude<BarMaterial, "plain">;
|
|
6
|
+
id: string;
|
|
7
|
+
horizontal: boolean;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cloneElement } from "react";
|
|
4
|
+
import { BarClay } from "./bar-clay.js";
|
|
5
|
+
import { BarPaper } from "./bar-paper.js";
|
|
6
|
+
import { SurfaceMaterialFilter } from "./surface-material.js";
|
|
7
|
+
/** Native rectangles apply this filter independently to their own object bounds. */
|
|
8
|
+
export function BarMaterialFilter({ material, id, horizontal, }) {
|
|
9
|
+
if (material !== "glow")
|
|
10
|
+
return (_jsx("filter", { id: id, filterUnits: "objectBoundingBox", primitiveUnits: "userSpaceOnUse", x: -0.5, y: -0.5, width: 2, height: 2, colorInterpolationFilters: "sRGB", children: material === "clay" ? _jsx(BarClay, { horizontal: horizontal }) : _jsx(BarPaper, {}) }));
|
|
11
|
+
// The shared pure helper returns a native filter. Only bar coordinate units change;
|
|
12
|
+
// pixel-sized primitives and the area's user-space bounds retain their semantics.
|
|
13
|
+
return cloneElement(SurfaceMaterialFilter({
|
|
14
|
+
material,
|
|
15
|
+
id,
|
|
16
|
+
family: "bar",
|
|
17
|
+
bounds: { x: -0.5, y: -0.5, width: 2, height: 2 },
|
|
18
|
+
}), { filterUnits: "objectBoundingBox", primitiveUnits: "userSpaceOnUse" });
|
|
19
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ComponentProps } from "react";
|
|
2
|
+
import { Bar } from "recharts";
|
|
3
|
+
import { type BarMaterial } from "./bar-material.js";
|
|
4
|
+
export type BarSeriesProps<DataPoint = unknown, Value = unknown> = Omit<ComponentProps<typeof Bar<DataPoint, Value>>, "isAnimationActive"> & {
|
|
5
|
+
/** Metadata/visibility key, required for controlled function or numeric data keys. */
|
|
6
|
+
seriesKey?: string;
|
|
7
|
+
/** Stable category identity for numeric domains or independently supplied series rows. */
|
|
8
|
+
emphasisKey?: ((payload: unknown) => string | number | undefined) | undefined;
|
|
9
|
+
/** Finish on native rectangles; custom shapes and filters retain ownership. */
|
|
10
|
+
material?: BarMaterial | undefined;
|
|
11
|
+
};
|
|
12
|
+
/** A registered native Bar; axes, shape, cells, labels and handlers stay consumer-owned. */
|
|
13
|
+
export declare function BarSeries<DataPoint = unknown, Value = unknown>({ seriesKey, emphasisKey, hide, fill, className, style, material, ...props }: BarSeriesProps<DataPoint, Value>): import("react").JSX.Element;
|