@misoto22/design 0.5.0 → 0.6.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/README.md +124 -0
- package/bin/misoto22-design.mjs +205 -0
- package/dist/agent/Accordion.md +41 -0
- package/dist/agent/Alert.md +42 -0
- package/dist/agent/AppShell.md +40 -0
- package/dist/agent/AreaChart.md +68 -0
- package/dist/agent/Article.md +41 -0
- package/dist/agent/Avatar.md +32 -0
- package/dist/agent/Badge.md +40 -0
- package/dist/agent/BarChart.md +65 -0
- package/dist/agent/BarList.md +40 -0
- package/dist/agent/BigNumber.md +45 -0
- package/dist/agent/BoxPlot.md +58 -0
- package/dist/agent/Breadcrumb.md +32 -0
- package/dist/agent/BulletChart.md +48 -0
- package/dist/agent/Button.md +56 -0
- package/dist/agent/Calendar.md +42 -0
- package/dist/agent/Card.md +49 -0
- package/dist/agent/Checkbox.md +35 -0
- package/dist/agent/Collapsible.md +46 -0
- package/dist/agent/Combobox.md +50 -0
- package/dist/agent/Command.md +93 -0
- package/dist/agent/ComposedChart.md +57 -0
- package/dist/agent/ContextMenu.md +59 -0
- package/dist/agent/DatePicker.md +75 -0
- package/dist/agent/Diagram.md +46 -0
- package/dist/agent/Dialog.md +52 -0
- package/dist/agent/DropdownMenu.md +70 -0
- package/dist/agent/EmptyState.md +37 -0
- package/dist/agent/ErrorState.md +41 -0
- package/dist/agent/Facet.md +82 -0
- package/dist/agent/Field.md +37 -0
- package/dist/agent/FigureBand.md +37 -0
- package/dist/agent/FloatingIconButton.md +38 -0
- package/dist/agent/FunnelChart.md +52 -0
- package/dist/agent/Heatmap.md +53 -0
- package/dist/agent/Histogram.md +63 -0
- package/dist/agent/Input.md +30 -0
- package/dist/agent/Kbd.md +29 -0
- package/dist/agent/LineChart.md +60 -0
- package/dist/agent/LinkArrow.md +29 -0
- package/dist/agent/NativeSelect.md +40 -0
- package/dist/agent/NavItem.md +35 -0
- package/dist/agent/Pagination.md +43 -0
- package/dist/agent/PieChart.md +55 -0
- package/dist/agent/Popover.md +57 -0
- package/dist/agent/Progress.md +33 -0
- package/dist/agent/RadarChart.md +54 -0
- package/dist/agent/RadialChart.md +57 -0
- package/dist/agent/RadioGroup.md +44 -0
- package/dist/agent/SankeyChart.md +61 -0
- package/dist/agent/ScatterChart.md +54 -0
- package/dist/agent/ScrollArea.md +40 -0
- package/dist/agent/SearchableMenu.md +46 -0
- package/dist/agent/Select.md +75 -0
- package/dist/agent/Separator.md +35 -0
- package/dist/agent/Sheet.md +57 -0
- package/dist/agent/Skeleton.md +73 -0
- package/dist/agent/Slider.md +39 -0
- package/dist/agent/Sparkline.md +45 -0
- package/dist/agent/Spinner.md +39 -0
- package/dist/agent/StatusDot.md +36 -0
- package/dist/agent/StatusPill.md +28 -0
- package/dist/agent/Steps.md +44 -0
- package/dist/agent/Switch.md +29 -0
- package/dist/agent/Table.md +85 -0
- package/dist/agent/Tabs.md +48 -0
- package/dist/agent/Tag.md +35 -0
- package/dist/agent/Textarea.md +26 -0
- package/dist/agent/Toast.md +26 -0
- package/dist/agent/ToggleGroup.md +44 -0
- package/dist/agent/Tooltip.md +51 -0
- package/dist/agent/TreemapChart.md +52 -0
- package/dist/agent/WaterfallChart.md +62 -0
- package/dist/agent/catalog.json +1791 -0
- package/dist/agent/index.md +131 -0
- package/dist/charts/AreaChart/AreaChart.d.ts +191 -0
- package/dist/charts/AreaChart/AreaChart.js +480 -0
- package/dist/charts/AreaChart/AreaChart.js.map +1 -0
- package/dist/charts/BarChart/BarChart.d.ts +179 -0
- package/dist/charts/BarChart/BarChart.js +591 -0
- package/dist/charts/BarChart/BarChart.js.map +1 -0
- package/dist/charts/BarList/BarList.d.ts +57 -0
- package/dist/charts/BarList/BarList.js +71 -0
- package/dist/charts/BarList/BarList.js.map +1 -0
- package/dist/charts/BigNumber/BigNumber.d.ts +56 -0
- package/dist/charts/BigNumber/BigNumber.js +31 -0
- package/dist/charts/BigNumber/BigNumber.js.map +1 -0
- package/dist/charts/BoxPlot/BoxPlot.d.ts +177 -0
- package/dist/charts/BoxPlot/BoxPlot.js +495 -0
- package/dist/charts/BoxPlot/BoxPlot.js.map +1 -0
- package/dist/charts/BulletChart/BulletChart.d.ts +100 -0
- package/dist/charts/BulletChart/BulletChart.js +162 -0
- package/dist/charts/BulletChart/BulletChart.js.map +1 -0
- package/dist/charts/ComposedChart/ComposedChart.d.ts +171 -0
- package/dist/charts/ComposedChart/ComposedChart.js +667 -0
- package/dist/charts/ComposedChart/ComposedChart.js.map +1 -0
- package/dist/charts/Facet/Facet.d.ts +240 -0
- package/dist/charts/Facet/Facet.js +133 -0
- package/dist/charts/Facet/Facet.js.map +1 -0
- package/dist/charts/Facet/panels.d.ts +187 -0
- package/dist/charts/Facet/panels.js +203 -0
- package/dist/charts/Facet/panels.js.map +1 -0
- package/dist/charts/FunnelChart/FunnelChart.d.ts +101 -0
- package/dist/charts/FunnelChart/FunnelChart.js +147 -0
- package/dist/charts/FunnelChart/FunnelChart.js.map +1 -0
- package/dist/charts/Heatmap/Heatmap.d.ts +78 -0
- package/dist/charts/Heatmap/Heatmap.js +108 -0
- package/dist/charts/Heatmap/Heatmap.js.map +1 -0
- package/dist/charts/Histogram/Histogram.d.ts +165 -0
- package/dist/charts/Histogram/Histogram.js +350 -0
- package/dist/charts/Histogram/Histogram.js.map +1 -0
- package/dist/charts/LineChart/LineChart.d.ts +167 -0
- package/dist/charts/LineChart/LineChart.js +486 -0
- package/dist/charts/LineChart/LineChart.js.map +1 -0
- package/dist/charts/PieChart/PieChart.d.ts +128 -0
- package/dist/charts/PieChart/PieChart.js +309 -0
- package/dist/charts/PieChart/PieChart.js.map +1 -0
- package/dist/charts/RadarChart/RadarChart.d.ts +123 -0
- package/dist/charts/RadarChart/RadarChart.js +299 -0
- package/dist/charts/RadarChart/RadarChart.js.map +1 -0
- package/dist/charts/RadialChart/RadialChart.d.ts +124 -0
- package/dist/charts/RadialChart/RadialChart.js +257 -0
- package/dist/charts/RadialChart/RadialChart.js.map +1 -0
- package/dist/charts/SankeyChart/SankeyChart.d.ts +137 -0
- package/dist/charts/SankeyChart/SankeyChart.js +501 -0
- package/dist/charts/SankeyChart/SankeyChart.js.map +1 -0
- package/dist/charts/ScatterChart/ScatterChart.d.ts +128 -0
- package/dist/charts/ScatterChart/ScatterChart.js +269 -0
- package/dist/charts/ScatterChart/ScatterChart.js.map +1 -0
- package/dist/charts/Sparkline/Sparkline.d.ts +53 -0
- package/dist/charts/Sparkline/Sparkline.js +93 -0
- package/dist/charts/Sparkline/Sparkline.js.map +1 -0
- package/dist/charts/TreemapChart/TreemapChart.d.ts +93 -0
- package/dist/charts/TreemapChart/TreemapChart.js +118 -0
- package/dist/charts/TreemapChart/TreemapChart.js.map +1 -0
- package/dist/charts/WaterfallChart/WaterfallChart.d.ts +164 -0
- package/dist/charts/WaterfallChart/WaterfallChart.js +319 -0
- package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -0
- package/dist/charts/index.d.ts +41 -0
- package/dist/charts/index.js +128 -0
- package/dist/charts/index.js.map +1 -0
- package/dist/charts/lib/annotations.d.ts +103 -0
- package/dist/charts/lib/annotations.js +99 -0
- package/dist/charts/lib/annotations.js.map +1 -0
- package/dist/charts/lib/axis.d.ts +18 -0
- package/dist/charts/lib/axis.js +21 -0
- package/dist/charts/lib/axis.js.map +1 -0
- package/dist/charts/lib/background.d.ts +33 -0
- package/dist/charts/lib/background.js +173 -0
- package/dist/charts/lib/background.js.map +1 -0
- package/dist/charts/lib/brush.d.ts +94 -0
- package/dist/charts/lib/brush.js +535 -0
- package/dist/charts/lib/brush.js.map +1 -0
- package/dist/charts/lib/chart.d.ts +94 -0
- package/dist/charts/lib/chart.js +134 -0
- package/dist/charts/lib/chart.js.map +1 -0
- package/dist/charts/lib/dot.d.ts +29 -0
- package/dist/charts/lib/dot.js +78 -0
- package/dist/charts/lib/dot.js.map +1 -0
- package/dist/charts/lib/empty.d.ts +31 -0
- package/dist/charts/lib/empty.js +13 -0
- package/dist/charts/lib/empty.js.map +1 -0
- package/dist/charts/lib/export.d.ts +103 -0
- package/dist/charts/lib/export.js +204 -0
- package/dist/charts/lib/export.js.map +1 -0
- package/dist/charts/lib/figure.d.ts +61 -0
- package/dist/charts/lib/figure.js +59 -0
- package/dist/charts/lib/figure.js.map +1 -0
- package/dist/charts/lib/format.d.ts +46 -0
- package/dist/charts/lib/format.js +56 -0
- package/dist/charts/lib/format.js.map +1 -0
- package/dist/charts/lib/legend.d.ts +45 -0
- package/dist/charts/lib/legend.js +117 -0
- package/dist/charts/lib/legend.js.map +1 -0
- package/dist/charts/lib/loading.d.ts +48 -0
- package/dist/charts/lib/loading.js +105 -0
- package/dist/charts/lib/loading.js.map +1 -0
- package/dist/charts/lib/paint.d.ts +154 -0
- package/dist/charts/lib/paint.js +551 -0
- package/dist/charts/lib/paint.js.map +1 -0
- package/dist/charts/lib/sonify-control.d.ts +163 -0
- package/dist/charts/lib/sonify-control.js +172 -0
- package/dist/charts/lib/sonify-control.js.map +1 -0
- package/dist/charts/lib/sonify.d.ts +248 -0
- package/dist/charts/lib/sonify.js +262 -0
- package/dist/charts/lib/sonify.js.map +1 -0
- package/dist/charts/lib/toolbar.d.ts +143 -0
- package/dist/charts/lib/toolbar.js +156 -0
- package/dist/charts/lib/toolbar.js.map +1 -0
- package/dist/charts/lib/tooltip.d.ts +59 -0
- package/dist/charts/lib/tooltip.js +135 -0
- package/dist/charts/lib/tooltip.js.map +1 -0
- package/dist/charts/lib/values.d.ts +56 -0
- package/dist/charts/lib/values.js +71 -0
- package/dist/charts/lib/values.js.map +1 -0
- package/dist/charts/lib/zoom.d.ts +139 -0
- package/dist/charts/lib/zoom.js +314 -0
- package/dist/charts/lib/zoom.js.map +1 -0
- package/dist/semantic.css +19 -0
- package/dist/styles.css +1 -1
- package/dist/themes.css +50 -0
- package/dist/tokens.css +118 -0
- package/dist/tokens.d.ts +17 -0
- package/dist/tokens.js +101 -0
- package/dist/tokens.json +101 -0
- package/package.json +26 -4
- package/skills/misoto22-design/SKILL.md +171 -0
- package/skills/misoto22-design/evals/claims.json +95 -0
- package/skills/misoto22-design/rules/a11y.md +115 -0
- package/skills/misoto22-design/rules/composition.md +108 -0
- package/skills/misoto22-design/rules/forms.md +128 -0
- package/skills/misoto22-design/rules/naming.md +155 -0
- package/skills/misoto22-design/rules/tokens.md +131 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, ComponentProps, FC } from 'react';
|
|
3
|
+
import { PieChart as PieChart$1, Pie, LabelList } from 'recharts';
|
|
4
|
+
import { ChartConfig } from '../lib/chart.js';
|
|
5
|
+
import { ChartBackgroundVariant } from '../lib/background.js';
|
|
6
|
+
import { ChartTooltipSlotProps, ChartLegendSlotProps } from '../AreaChart/AreaChart.js';
|
|
7
|
+
import '../lib/empty.js';
|
|
8
|
+
import '../lib/values.js';
|
|
9
|
+
import '../lib/sonify-control.js';
|
|
10
|
+
import '../lib/sonify.js';
|
|
11
|
+
import '../lib/brush.js';
|
|
12
|
+
import '../lib/toolbar.js';
|
|
13
|
+
import '../lib/zoom.js';
|
|
14
|
+
import '../lib/figure.js';
|
|
15
|
+
import '../lib/paint.js';
|
|
16
|
+
import '../lib/dot.js';
|
|
17
|
+
import '../lib/legend.js';
|
|
18
|
+
import '../lib/tooltip.js';
|
|
19
|
+
import 'recharts/types/component/DefaultTooltipContent';
|
|
20
|
+
import '../lib/annotations.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* How a sector is painted.
|
|
24
|
+
*
|
|
25
|
+
* One variant, and the honesty is deliberate: a wedge is a small, awkwardly
|
|
26
|
+
* shaped area, and a texture inside one reads as noise rather than as identity.
|
|
27
|
+
* Where a bar chart differentiates by fill, a pie differentiates by the gap
|
|
28
|
+
* between sectors — which is what `paddingAngle` is for — and by its legend.
|
|
29
|
+
*/
|
|
30
|
+
type PieVariant = 'gradient';
|
|
31
|
+
interface PieChartProps<TData extends Record<string, unknown>> {
|
|
32
|
+
/** Sector names → their label and paint. Keys must match the `nameKey` values. */
|
|
33
|
+
config: ChartConfig;
|
|
34
|
+
/** The rows the chart draws. One entry per point, bar or category. */
|
|
35
|
+
data: TData[];
|
|
36
|
+
/** The row field holding each sector's number. */
|
|
37
|
+
dataKey: keyof TData & string;
|
|
38
|
+
/** The row field holding each sector's name. */
|
|
39
|
+
nameKey: keyof TData & string;
|
|
40
|
+
/**
|
|
41
|
+
* What the chart shows, in a sentence a reader could act on. Required, and
|
|
42
|
+
* announced to a screen reader even when it is not printed.
|
|
43
|
+
*/
|
|
44
|
+
title: string;
|
|
45
|
+
/** Prints the title above the plot instead of hiding it from sight. */
|
|
46
|
+
showTitle?: boolean;
|
|
47
|
+
/** A line under the title — the unit, the window, the caveat. */
|
|
48
|
+
description?: ReactNode;
|
|
49
|
+
/**
|
|
50
|
+
* The composed parts — axes, grid, tooltip, legend, and the marks
|
|
51
|
+
* themselves.
|
|
52
|
+
*/
|
|
53
|
+
children: ReactNode;
|
|
54
|
+
/** Merged onto the figure, last, so a call site can size or space it. */
|
|
55
|
+
className?: string;
|
|
56
|
+
/** Escape hatch onto the raw Recharts chart element. */
|
|
57
|
+
chartProps?: ComponentProps<typeof PieChart$1>;
|
|
58
|
+
/** The sector lit on first render. */
|
|
59
|
+
defaultSelectedSector?: string | null;
|
|
60
|
+
/** Fires when the selection changes, and with null when it is cleared. */
|
|
61
|
+
onSelectionChange?: (selection: {
|
|
62
|
+
name: string;
|
|
63
|
+
value: number;
|
|
64
|
+
} | null) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Swaps the marks for an animated skeleton, keeping the measured height so
|
|
67
|
+
* the page does not jump when the data lands.
|
|
68
|
+
*/
|
|
69
|
+
isLoading?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Drops the hidden table view. Only correct when the page prints the data
|
|
72
|
+
* itself.
|
|
73
|
+
*/
|
|
74
|
+
hideDataTable?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Parts of one whole.
|
|
78
|
+
*
|
|
79
|
+
* Worth saying plainly: a pie answers "roughly what share" and nothing more
|
|
80
|
+
* precise. Comparing two adjacent wedges by eye is unreliable past about five
|
|
81
|
+
* of them, and comparing a wedge across two pies is worse. When the reader
|
|
82
|
+
* needs to rank or compare, a `<BarChart>` answers the same question better.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* <PieChart title="Visitors by browser" config={config} data={data} dataKey="visitors" nameKey="browser">
|
|
86
|
+
* <PieChart.Pie innerRadius="55%" />
|
|
87
|
+
* <PieChart.Tooltip />
|
|
88
|
+
* <PieChart.Legend />
|
|
89
|
+
* </PieChart>
|
|
90
|
+
*/
|
|
91
|
+
declare function PieChart<TData extends Record<string, unknown>>({ config, data, dataKey, nameKey, title, showTitle, description, children, className, chartProps, defaultSelectedSector, onSelectionChange, isLoading, hideDataTable, }: PieChartProps<TData>): react.JSX.Element;
|
|
92
|
+
declare namespace PieChart {
|
|
93
|
+
var Pie: ({ variant, innerRadius, outerRadius, cornerRadius, paddingAngle, startAngle, endAngle, isClickable, glowingSectors, children, pieProps, }: PieProps) => react.JSX.Element;
|
|
94
|
+
var Label: FC<PieLabelProps>;
|
|
95
|
+
var Tooltip: ({ variant, roundness, defaultIndex }: ChartTooltipSlotProps) => react.JSX.Element | null;
|
|
96
|
+
var Legend: ({ variant, align, verticalAlign, isClickable, }: ChartLegendSlotProps) => react.JSX.Element;
|
|
97
|
+
var Background: ({ variant }: {
|
|
98
|
+
variant?: ChartBackgroundVariant;
|
|
99
|
+
}) => react.JSX.Element;
|
|
100
|
+
}
|
|
101
|
+
interface PieProps {
|
|
102
|
+
variant?: PieVariant;
|
|
103
|
+
/** Above zero makes it a donut, which is easier to read than a full pie. */
|
|
104
|
+
innerRadius?: number | string;
|
|
105
|
+
outerRadius?: number | string;
|
|
106
|
+
/** Rounds each wedge's corners. */
|
|
107
|
+
cornerRadius?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Degrees between wedges. Negative overlaps them, which the sector's own
|
|
110
|
+
* surface-coloured stroke then separates — the "stacked cards" look.
|
|
111
|
+
*/
|
|
112
|
+
paddingAngle?: number;
|
|
113
|
+
startAngle?: number;
|
|
114
|
+
endAngle?: number;
|
|
115
|
+
isClickable?: boolean;
|
|
116
|
+
/** Sector names drawn with a halo — for the one wedge that is the point. */
|
|
117
|
+
glowingSectors?: string[];
|
|
118
|
+
/** `<PieChart.Label>`. */
|
|
119
|
+
children?: ReactNode;
|
|
120
|
+
pieProps?: Omit<ComponentProps<typeof Pie>, 'data' | 'dataKey' | 'nameKey'>;
|
|
121
|
+
}
|
|
122
|
+
interface PieLabelProps {
|
|
123
|
+
/** The field printed on each wedge. Defaults to the pie's value key. */
|
|
124
|
+
dataKey?: string;
|
|
125
|
+
labelListProps?: Omit<ComponentProps<typeof LabelList>, 'dataKey'>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { PieChart, type PieChartProps, type PieLabelProps, type PieProps, type PieVariant, PieChart as default };
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
Children,
|
|
5
|
+
createContext,
|
|
6
|
+
isValidElement,
|
|
7
|
+
useCallback,
|
|
8
|
+
useContext,
|
|
9
|
+
useId,
|
|
10
|
+
useMemo,
|
|
11
|
+
useState
|
|
12
|
+
} from "react";
|
|
13
|
+
import {
|
|
14
|
+
LabelList as RechartsLabelList,
|
|
15
|
+
Pie as RechartsPie,
|
|
16
|
+
PieChart as RechartsPieChart,
|
|
17
|
+
Sector
|
|
18
|
+
} from "recharts";
|
|
19
|
+
import { motion, useReducedMotion } from "motion/react";
|
|
20
|
+
import { ChartContainer, colorStops, cssName } from "../lib/chart.js";
|
|
21
|
+
import { ChartFigure } from "../lib/figure.js";
|
|
22
|
+
import { ChartBackground } from "../lib/background.js";
|
|
23
|
+
import { ChartLegend, ChartLegendContent } from "../lib/legend.js";
|
|
24
|
+
import { ChartTooltip, ChartTooltipContent } from "../lib/tooltip.js";
|
|
25
|
+
import { LoadingIndicator } from "../lib/loading.js";
|
|
26
|
+
import { ColorStops } from "../lib/paint.js";
|
|
27
|
+
const LOADING_SECTORS = 5;
|
|
28
|
+
const LOADING_PULSE = 2;
|
|
29
|
+
const PieChartContext = createContext(null);
|
|
30
|
+
function usePieChart() {
|
|
31
|
+
const context = useContext(PieChartContext);
|
|
32
|
+
if (!context) throw new Error("A pie chart part must be rendered inside <PieChart>");
|
|
33
|
+
return context;
|
|
34
|
+
}
|
|
35
|
+
function PieChart({
|
|
36
|
+
config,
|
|
37
|
+
data,
|
|
38
|
+
dataKey,
|
|
39
|
+
nameKey,
|
|
40
|
+
title,
|
|
41
|
+
showTitle,
|
|
42
|
+
description,
|
|
43
|
+
children,
|
|
44
|
+
className,
|
|
45
|
+
chartProps,
|
|
46
|
+
defaultSelectedSector = null,
|
|
47
|
+
onSelectionChange,
|
|
48
|
+
isLoading = false,
|
|
49
|
+
hideDataTable = false
|
|
50
|
+
}) {
|
|
51
|
+
const chartId = useId().replace(/:/g, "");
|
|
52
|
+
const [selectedSector, setSelectedSector] = useState(defaultSelectedSector);
|
|
53
|
+
const selectSector = useCallback(
|
|
54
|
+
(name) => {
|
|
55
|
+
setSelectedSector(name);
|
|
56
|
+
if (name === null) {
|
|
57
|
+
onSelectionChange?.(null);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const row = data.find((item) => item[nameKey] === name);
|
|
61
|
+
if (row) onSelectionChange?.({ name, value: row[dataKey] });
|
|
62
|
+
},
|
|
63
|
+
[data, dataKey, nameKey, onSelectionChange]
|
|
64
|
+
);
|
|
65
|
+
const context = useMemo(
|
|
66
|
+
() => ({ config, data, dataKey, nameKey, isLoading, selectedSector, selectSector }),
|
|
67
|
+
[config, data, dataKey, isLoading, nameKey, selectSector, selectedSector]
|
|
68
|
+
);
|
|
69
|
+
return /* @__PURE__ */ jsx(PieChartContext.Provider, { value: context, children: /* @__PURE__ */ jsxs(
|
|
70
|
+
ChartFigure,
|
|
71
|
+
{
|
|
72
|
+
title,
|
|
73
|
+
showTitle,
|
|
74
|
+
description,
|
|
75
|
+
className,
|
|
76
|
+
table: hideDataTable ? false : {
|
|
77
|
+
rows: data,
|
|
78
|
+
rowKey: nameKey,
|
|
79
|
+
columns: [{ key: dataKey, label: "Value" }]
|
|
80
|
+
},
|
|
81
|
+
children: [
|
|
82
|
+
/* @__PURE__ */ jsx(ChartContainer, { config, children: /* @__PURE__ */ jsx(RechartsPieChart, { id: chartId, accessibilityLayer: true, ...chartProps, children }) }),
|
|
83
|
+
/* @__PURE__ */ jsx(LoadingIndicator, { isLoading })
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
) });
|
|
87
|
+
}
|
|
88
|
+
const NO_GLOW = [];
|
|
89
|
+
function Pie({
|
|
90
|
+
variant = "gradient",
|
|
91
|
+
innerRadius = 0,
|
|
92
|
+
outerRadius = "80%",
|
|
93
|
+
cornerRadius = 0,
|
|
94
|
+
paddingAngle = 0,
|
|
95
|
+
startAngle = 0,
|
|
96
|
+
endAngle = 360,
|
|
97
|
+
isClickable = false,
|
|
98
|
+
glowingSectors = NO_GLOW,
|
|
99
|
+
children,
|
|
100
|
+
pieProps
|
|
101
|
+
}) {
|
|
102
|
+
const { config, data, dataKey, nameKey, isLoading, selectedSector, selectSector } = usePieChart();
|
|
103
|
+
const id = useId().replace(/:/g, "");
|
|
104
|
+
if (isLoading) {
|
|
105
|
+
return /* @__PURE__ */ jsx(
|
|
106
|
+
RechartsPie,
|
|
107
|
+
{
|
|
108
|
+
data: LOADING_DATA,
|
|
109
|
+
dataKey: "value",
|
|
110
|
+
nameKey: "name",
|
|
111
|
+
innerRadius,
|
|
112
|
+
outerRadius,
|
|
113
|
+
cornerRadius,
|
|
114
|
+
paddingAngle,
|
|
115
|
+
startAngle,
|
|
116
|
+
endAngle,
|
|
117
|
+
strokeWidth: 0,
|
|
118
|
+
isAnimationActive: false,
|
|
119
|
+
shape: (props) => /* @__PURE__ */ jsx(LoadingSector, { ...props })
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
const label = resolveLabel(children, dataKey);
|
|
124
|
+
const painted = data.map((row) => ({
|
|
125
|
+
...row,
|
|
126
|
+
fill: `url(#${id}-colors-${cssName(String(row[nameKey]))})`
|
|
127
|
+
}));
|
|
128
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
129
|
+
/* @__PURE__ */ jsx(
|
|
130
|
+
RechartsPie,
|
|
131
|
+
{
|
|
132
|
+
data: painted,
|
|
133
|
+
dataKey,
|
|
134
|
+
nameKey,
|
|
135
|
+
innerRadius,
|
|
136
|
+
outerRadius,
|
|
137
|
+
cornerRadius,
|
|
138
|
+
paddingAngle,
|
|
139
|
+
startAngle,
|
|
140
|
+
endAngle,
|
|
141
|
+
strokeWidth: 0,
|
|
142
|
+
style: isClickable ? { cursor: "pointer" } : void 0,
|
|
143
|
+
onClick: (_, index) => {
|
|
144
|
+
if (!isClickable) return;
|
|
145
|
+
const name = data[index]?.[nameKey];
|
|
146
|
+
selectSector(selectedSector === name ? null : name);
|
|
147
|
+
},
|
|
148
|
+
shape: (props) => {
|
|
149
|
+
const name = String(data[props.index ?? 0]?.[nameKey] ?? "");
|
|
150
|
+
const isGlowing = glowingSectors.includes(name);
|
|
151
|
+
const dimmed = isClickable && selectedSector !== null && selectedSector !== name;
|
|
152
|
+
return /* @__PURE__ */ jsx(
|
|
153
|
+
Sector,
|
|
154
|
+
{
|
|
155
|
+
...props,
|
|
156
|
+
fill: `url(#${id}-colors-${cssName(name)})`,
|
|
157
|
+
filter: isGlowing ? `url(#${id}-glow-${cssName(name)})` : void 0,
|
|
158
|
+
stroke: paddingAngle < 0 ? "var(--chart-surface)" : "none",
|
|
159
|
+
strokeWidth: paddingAngle < 0 ? 5 : 0,
|
|
160
|
+
opacity: dimmed ? 0.15 : 1,
|
|
161
|
+
className: "transition-opacity duration-(--duration-base)"
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
},
|
|
165
|
+
...pieProps,
|
|
166
|
+
children: label
|
|
167
|
+
}
|
|
168
|
+
),
|
|
169
|
+
/* @__PURE__ */ jsxs("defs", { children: [
|
|
170
|
+
/* @__PURE__ */ jsx(SectorGradients, { id, config, variant }),
|
|
171
|
+
glowingSectors.map((name) => /* @__PURE__ */ jsxs(
|
|
172
|
+
"filter",
|
|
173
|
+
{
|
|
174
|
+
id: `${id}-glow-${cssName(name)}`,
|
|
175
|
+
x: "-100%",
|
|
176
|
+
y: "-100%",
|
|
177
|
+
width: "300%",
|
|
178
|
+
height: "300%",
|
|
179
|
+
children: [
|
|
180
|
+
/* @__PURE__ */ jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: "8", result: "blur" }),
|
|
181
|
+
/* @__PURE__ */ jsx(
|
|
182
|
+
"feColorMatrix",
|
|
183
|
+
{
|
|
184
|
+
in: "blur",
|
|
185
|
+
type: "matrix",
|
|
186
|
+
values: "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0",
|
|
187
|
+
result: "glow"
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
/* @__PURE__ */ jsxs("feMerge", { children: [
|
|
191
|
+
/* @__PURE__ */ jsx("feMergeNode", { in: "glow" }),
|
|
192
|
+
/* @__PURE__ */ jsx("feMergeNode", { in: "SourceGraphic" })
|
|
193
|
+
] })
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
name
|
|
197
|
+
))
|
|
198
|
+
] })
|
|
199
|
+
] });
|
|
200
|
+
}
|
|
201
|
+
const Label = () => null;
|
|
202
|
+
function resolveLabel(children, valueKey) {
|
|
203
|
+
let label = null;
|
|
204
|
+
Children.forEach(children, (child) => {
|
|
205
|
+
if (!isValidElement(child) || child.type !== Label) return;
|
|
206
|
+
const { dataKey, labelListProps } = child.props;
|
|
207
|
+
label = /* @__PURE__ */ jsx(
|
|
208
|
+
RechartsLabelList,
|
|
209
|
+
{
|
|
210
|
+
dataKey: dataKey ?? valueKey,
|
|
211
|
+
stroke: "none",
|
|
212
|
+
fontSize: 12,
|
|
213
|
+
fontWeight: 500,
|
|
214
|
+
className: "fill-(--chart-surface)",
|
|
215
|
+
...labelListProps
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
return label;
|
|
220
|
+
}
|
|
221
|
+
function SectorGradients({
|
|
222
|
+
id,
|
|
223
|
+
config
|
|
224
|
+
}) {
|
|
225
|
+
return /* @__PURE__ */ jsx(Fragment, { children: Object.entries(config).map(([key, series]) => /* @__PURE__ */ jsx(
|
|
226
|
+
"linearGradient",
|
|
227
|
+
{
|
|
228
|
+
id: `${id}-colors-${cssName(key)}`,
|
|
229
|
+
x1: "0",
|
|
230
|
+
y1: "0",
|
|
231
|
+
x2: "1",
|
|
232
|
+
y2: "1",
|
|
233
|
+
children: /* @__PURE__ */ jsx(ColorStops, { dataKey: cssName(key), stops: colorStops(series) })
|
|
234
|
+
},
|
|
235
|
+
key
|
|
236
|
+
)) });
|
|
237
|
+
}
|
|
238
|
+
function Tooltip({ variant, roundness, defaultIndex }) {
|
|
239
|
+
const { isLoading, nameKey } = usePieChart();
|
|
240
|
+
if (isLoading) return null;
|
|
241
|
+
return /* @__PURE__ */ jsx(
|
|
242
|
+
ChartTooltip,
|
|
243
|
+
{
|
|
244
|
+
defaultIndex,
|
|
245
|
+
content: /* @__PURE__ */ jsx(ChartTooltipContent, { nameKey, hideLabel: true, roundness, variant })
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
function Legend({
|
|
250
|
+
variant,
|
|
251
|
+
align = "center",
|
|
252
|
+
verticalAlign = "bottom",
|
|
253
|
+
isClickable = false
|
|
254
|
+
}) {
|
|
255
|
+
const { nameKey, selectedSector, selectSector } = usePieChart();
|
|
256
|
+
return /* @__PURE__ */ jsx(
|
|
257
|
+
ChartLegend,
|
|
258
|
+
{
|
|
259
|
+
verticalAlign,
|
|
260
|
+
align,
|
|
261
|
+
content: /* @__PURE__ */ jsx(
|
|
262
|
+
ChartLegendContent,
|
|
263
|
+
{
|
|
264
|
+
selected: selectedSector,
|
|
265
|
+
onSelectChange: selectSector,
|
|
266
|
+
isClickable,
|
|
267
|
+
nameKey,
|
|
268
|
+
variant
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
function Background({ variant = "dots" }) {
|
|
275
|
+
return /* @__PURE__ */ jsx(ChartBackground, { variant });
|
|
276
|
+
}
|
|
277
|
+
const LOADING_DATA = Array.from({ length: LOADING_SECTORS }, (_, index) => ({
|
|
278
|
+
name: `loading-${index}`,
|
|
279
|
+
value: 100 / LOADING_SECTORS
|
|
280
|
+
}));
|
|
281
|
+
function LoadingSector(props) {
|
|
282
|
+
const { index = 0, ...sector } = props;
|
|
283
|
+
const reduceMotion = useReducedMotion();
|
|
284
|
+
const delay = index / LOADING_SECTORS * LOADING_PULSE;
|
|
285
|
+
if (reduceMotion) {
|
|
286
|
+
return /* @__PURE__ */ jsx("g", { opacity: 0.3, className: "text-(--ink)", children: /* @__PURE__ */ jsx(Sector, { ...sector, fill: "currentColor" }) });
|
|
287
|
+
}
|
|
288
|
+
return /* @__PURE__ */ jsx(
|
|
289
|
+
motion.g,
|
|
290
|
+
{
|
|
291
|
+
className: "text-(--ink)",
|
|
292
|
+
initial: { opacity: 0.15 },
|
|
293
|
+
animate: { opacity: [0.15, 0.5, 0.15] },
|
|
294
|
+
transition: { duration: LOADING_PULSE, delay, repeat: Infinity, ease: "easeInOut" },
|
|
295
|
+
children: /* @__PURE__ */ jsx(Sector, { ...sector, fill: "currentColor" })
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
PieChart.Pie = Pie;
|
|
300
|
+
PieChart.Label = Label;
|
|
301
|
+
PieChart.Tooltip = Tooltip;
|
|
302
|
+
PieChart.Legend = Legend;
|
|
303
|
+
PieChart.Background = Background;
|
|
304
|
+
var PieChart_default = PieChart;
|
|
305
|
+
export {
|
|
306
|
+
PieChart,
|
|
307
|
+
PieChart_default as default
|
|
308
|
+
};
|
|
309
|
+
//# sourceMappingURL=PieChart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/PieChart/PieChart.tsx"],"sourcesContent":["'use client'\n\nimport {\n Children,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useMemo,\n useState,\n type ComponentProps,\n type FC,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport {\n LabelList as RechartsLabelList,\n Pie as RechartsPie,\n PieChart as RechartsPieChart,\n Sector,\n type PieSectorShapeProps,\n} from 'recharts'\nimport { motion, useReducedMotion } from 'motion/react'\nimport { ChartContainer, colorStops, cssName, type ChartConfig } from '../lib/chart'\nimport { ChartFigure } from '../lib/figure'\nimport { ChartBackground, type ChartBackgroundVariant } from '../lib/background'\nimport { ChartLegend, ChartLegendContent } from '../lib/legend'\nimport { ChartTooltip, ChartTooltipContent } from '../lib/tooltip'\nimport { LoadingIndicator } from '../lib/loading'\nimport { ColorStops } from '../lib/paint'\nimport type { ChartLegendSlotProps, ChartTooltipSlotProps } from '../AreaChart/AreaChart'\n\n/** Equal wedges the skeleton is built from. */\nconst LOADING_SECTORS = 5\n\n/** One full pulse of the loading wave, in seconds. */\nconst LOADING_PULSE = 2\n\n/**\n * How a sector is painted.\n *\n * One variant, and the honesty is deliberate: a wedge is a small, awkwardly\n * shaped area, and a texture inside one reads as noise rather than as identity.\n * Where a bar chart differentiates by fill, a pie differentiates by the gap\n * between sectors — which is what `paddingAngle` is for — and by its legend.\n */\nexport type PieVariant = 'gradient'\n\ninterface PieChartContextValue {\n config: ChartConfig\n data: Record<string, unknown>[]\n dataKey: string\n nameKey: string\n isLoading: boolean\n selectedSector: string | null\n selectSector: (sector: string | null) => void\n}\n\nconst PieChartContext = createContext<PieChartContextValue | null>(null)\n\nfunction usePieChart(): PieChartContextValue {\n const context = useContext(PieChartContext)\n if (!context) throw new Error('A pie chart part must be rendered inside <PieChart>')\n return context\n}\n\nexport interface PieChartProps<TData extends Record<string, unknown>> {\n /** Sector names → their label and paint. Keys must match the `nameKey` values. */\n config: ChartConfig\n /** The rows the chart draws. One entry per point, bar or category. */\n data: TData[]\n /** The row field holding each sector's number. */\n dataKey: keyof TData & string\n /** The row field holding each sector's name. */\n nameKey: keyof TData & string\n /**\n * What the chart shows, in a sentence a reader could act on. Required, and\n * announced to a screen reader even when it is not printed.\n */\n title: string\n /** Prints the title above the plot instead of hiding it from sight. */\n showTitle?: boolean\n /** A line under the title — the unit, the window, the caveat. */\n description?: ReactNode\n /**\n * The composed parts — axes, grid, tooltip, legend, and the marks\n * themselves.\n */\n children: ReactNode\n /** Merged onto the figure, last, so a call site can size or space it. */\n className?: string\n /** Escape hatch onto the raw Recharts chart element. */\n chartProps?: ComponentProps<typeof RechartsPieChart>\n /** The sector lit on first render. */\n defaultSelectedSector?: string | null\n /** Fires when the selection changes, and with null when it is cleared. */\n onSelectionChange?: (selection: { name: string; value: number } | null) => void\n /**\n * Swaps the marks for an animated skeleton, keeping the measured height so\n * the page does not jump when the data lands.\n */\n isLoading?: boolean\n /**\n * Drops the hidden table view. Only correct when the page prints the data\n * itself.\n */\n hideDataTable?: boolean\n}\n\n/**\n * Parts of one whole.\n *\n * Worth saying plainly: a pie answers \"roughly what share\" and nothing more\n * precise. Comparing two adjacent wedges by eye is unreliable past about five\n * of them, and comparing a wedge across two pies is worse. When the reader\n * needs to rank or compare, a `<BarChart>` answers the same question better.\n *\n * @example\n * <PieChart title=\"Visitors by browser\" config={config} data={data} dataKey=\"visitors\" nameKey=\"browser\">\n * <PieChart.Pie innerRadius=\"55%\" />\n * <PieChart.Tooltip />\n * <PieChart.Legend />\n * </PieChart>\n */\nexport function PieChart<TData extends Record<string, unknown>>({\n config,\n data,\n dataKey,\n nameKey,\n title,\n showTitle,\n description,\n children,\n className,\n chartProps,\n defaultSelectedSector = null,\n onSelectionChange,\n isLoading = false,\n hideDataTable = false,\n}: PieChartProps<TData>) {\n // Not a literal. Two pies on one page shared a hard-coded id in the shape\n // this was ported from, so the second one inherited the first one's paint.\n const chartId = useId().replace(/:/g, '')\n const [selectedSector, setSelectedSector] = useState<string | null>(defaultSelectedSector)\n\n const selectSector = useCallback(\n (name: string | null) => {\n setSelectedSector(name)\n\n if (name === null) {\n onSelectionChange?.(null)\n return\n }\n const row = data.find((item) => item[nameKey] === name)\n if (row) onSelectionChange?.({ name, value: row[dataKey] as number })\n },\n [data, dataKey, nameKey, onSelectionChange],\n )\n\n const context = useMemo<PieChartContextValue>(\n () => ({ config, data, dataKey, nameKey, isLoading, selectedSector, selectSector }),\n [config, data, dataKey, isLoading, nameKey, selectSector, selectedSector],\n )\n\n return (\n <PieChartContext.Provider value={context}>\n <ChartFigure\n title={title}\n showTitle={showTitle}\n description={description}\n className={className}\n table={\n hideDataTable\n ? false\n : {\n rows: data,\n rowKey: nameKey,\n columns: [{ key: dataKey, label: 'Value' }],\n }\n }\n >\n <ChartContainer config={config}>\n <RechartsPieChart id={chartId} accessibilityLayer {...chartProps}>\n {children}\n </RechartsPieChart>\n </ChartContainer>\n <LoadingIndicator isLoading={isLoading} />\n </ChartFigure>\n </PieChartContext.Provider>\n )\n}\n\nexport interface PieProps {\n variant?: PieVariant\n /** Above zero makes it a donut, which is easier to read than a full pie. */\n innerRadius?: number | string\n outerRadius?: number | string\n /** Rounds each wedge's corners. */\n cornerRadius?: number\n /**\n * Degrees between wedges. Negative overlaps them, which the sector's own\n * surface-coloured stroke then separates — the \"stacked cards\" look.\n */\n paddingAngle?: number\n startAngle?: number\n endAngle?: number\n isClickable?: boolean\n /** Sector names drawn with a halo — for the one wedge that is the point. */\n glowingSectors?: string[]\n /** `<PieChart.Label>`. */\n children?: ReactNode\n pieProps?: Omit<ComponentProps<typeof RechartsPie>, 'data' | 'dataKey' | 'nameKey'>\n}\n\n/** Stable identity, so the default never re-triggers the memo below. */\nconst NO_GLOW: string[] = []\n\n/** The wedges themselves, with their gradients scoped to this pie's id. */\nfunction Pie({\n variant = 'gradient',\n innerRadius = 0,\n outerRadius = '80%',\n cornerRadius = 0,\n paddingAngle = 0,\n startAngle = 0,\n endAngle = 360,\n isClickable = false,\n glowingSectors = NO_GLOW,\n children,\n pieProps,\n}: PieProps) {\n const { config, data, dataKey, nameKey, isLoading, selectedSector, selectSector } = usePieChart()\n const id = useId().replace(/:/g, '')\n\n if (isLoading) {\n return (\n <RechartsPie\n data={LOADING_DATA}\n dataKey=\"value\"\n nameKey=\"name\"\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n cornerRadius={cornerRadius}\n paddingAngle={paddingAngle}\n startAngle={startAngle}\n endAngle={endAngle}\n strokeWidth={0}\n isAnimationActive={false}\n shape={(props) => <LoadingSector {...props} />}\n />\n )\n }\n\n const label = resolveLabel(children, dataKey)\n const painted = data.map((row) => ({\n ...row,\n fill: `url(#${id}-colors-${cssName(String(row[nameKey]))})`,\n }))\n\n return (\n <>\n <RechartsPie\n data={painted}\n dataKey={dataKey}\n nameKey={nameKey}\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n cornerRadius={cornerRadius}\n paddingAngle={paddingAngle}\n startAngle={startAngle}\n endAngle={endAngle}\n strokeWidth={0}\n style={isClickable ? { cursor: 'pointer' } : undefined}\n onClick={(_, index) => {\n if (!isClickable) return\n const name = data[index]?.[nameKey] as string\n selectSector(selectedSector === name ? null : name)\n }}\n shape={(props: PieSectorShapeProps) => {\n const name = String(data[props.index ?? 0]?.[nameKey] ?? '')\n const isGlowing = glowingSectors.includes(name)\n const dimmed = isClickable && selectedSector !== null && selectedSector !== name\n\n return (\n <Sector\n {...props}\n fill={`url(#${id}-colors-${cssName(name)})`}\n filter={isGlowing ? `url(#${id}-glow-${cssName(name)})` : undefined}\n // A negative padding angle overlaps the wedges; the surface-\n // coloured stroke is what re-separates them into stacked cards.\n stroke={paddingAngle < 0 ? 'var(--chart-surface)' : 'none'}\n strokeWidth={paddingAngle < 0 ? 5 : 0}\n opacity={dimmed ? 0.15 : 1}\n className=\"transition-opacity duration-(--duration-base)\"\n />\n )\n }}\n {...pieProps}\n >\n {label}\n </RechartsPie>\n <defs>\n <SectorGradients id={id} config={config} variant={variant} />\n {glowingSectors.map((name) => (\n <filter\n key={name}\n id={`${id}-glow-${cssName(name)}`}\n x=\"-100%\"\n y=\"-100%\"\n width=\"300%\"\n height=\"300%\"\n >\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"8\" result=\"blur\" />\n <feColorMatrix\n in=\"blur\"\n type=\"matrix\"\n values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0\"\n result=\"glow\"\n />\n <feMerge>\n <feMergeNode in=\"glow\" />\n <feMergeNode in=\"SourceGraphic\" />\n </feMerge>\n </filter>\n ))}\n </defs>\n </>\n )\n}\n\nexport interface PieLabelProps {\n /** The field printed on each wedge. Defaults to the pie's value key. */\n dataKey?: string\n labelListProps?: Omit<ComponentProps<typeof RechartsLabelList>, 'dataKey'>\n}\n\n/**\n * Numbers printed on the wedges. A slot — the parent reads it.\n *\n * Worth reaching for: a pie's whole weakness is that a wedge's angle is hard to\n * read, and a printed number removes the guess entirely.\n */\nconst Label: FC<PieLabelProps> = () => null\n\n/** Lifts a `<Label>` out of the pie's children into a Recharts label list. */\nfunction resolveLabel(children: ReactNode, valueKey: string): ReactNode {\n let label: ReactNode = null\n\n Children.forEach(children, (child) => {\n if (!isValidElement(child) || child.type !== Label) return\n const { dataKey, labelListProps } = (child as ReactElement<PieLabelProps>).props\n\n label = (\n <RechartsLabelList\n dataKey={dataKey ?? valueKey}\n stroke=\"none\"\n fontSize={12}\n fontWeight={500}\n // Reversed out of the wedge, which is the only ground it ever sits on.\n className=\"fill-(--chart-surface)\"\n {...labelListProps}\n />\n )\n })\n\n return label\n}\n\n/**\n * One diagonal gradient per sector.\n *\n * Diagonal rather than horizontal: a wedge is a radial shape, and a gradient\n * running corner to corner reads as light across the whole pie rather than as\n * a seam through each slice.\n */\nfunction SectorGradients({\n id,\n config,\n}: {\n id: string\n config: ChartConfig\n /** Reserved: the pie has one fill variant. See `PieVariant`. */\n variant: PieVariant\n}) {\n return (\n <>\n {Object.entries(config).map(([key, series]) => (\n <linearGradient\n key={key}\n id={`${id}-colors-${cssName(key)}`}\n x1=\"0\"\n y1=\"0\"\n x2=\"1\"\n y2=\"1\"\n >\n <ColorStops dataKey={cssName(key)} stops={colorStops(series)} />\n </linearGradient>\n ))}\n </>\n )\n}\n\n/** The hover panel. No heading: the wedge's own name is the row label. */\nfunction Tooltip({ variant, roundness, defaultIndex }: ChartTooltipSlotProps) {\n const { isLoading, nameKey } = usePieChart()\n if (isLoading) return null\n\n return (\n <ChartTooltip\n defaultIndex={defaultIndex}\n content={\n <ChartTooltipContent nameKey={nameKey} hideLabel roundness={roundness} variant={variant} />\n }\n />\n )\n}\n\n/**\n * The key. Under the pie and centred by default, because a pie's sectors are\n * named nowhere else — unlike a bar chart, which has a category axis.\n */\nfunction Legend({\n variant,\n align = 'center',\n verticalAlign = 'bottom',\n isClickable = false,\n}: ChartLegendSlotProps) {\n const { nameKey, selectedSector, selectSector } = usePieChart()\n\n return (\n <ChartLegend\n verticalAlign={verticalAlign}\n align={align}\n content={\n <ChartLegendContent\n selected={selectedSector}\n onSelectChange={selectSector}\n isClickable={isClickable}\n nameKey={nameKey}\n variant={variant}\n />\n }\n />\n )\n}\n\n/** The decorative plate behind the pie. Compose it before `<Pie>`. */\nfunction Background({ variant = 'dots' }: { variant?: ChartBackgroundVariant }) {\n return <ChartBackground variant={variant} />\n}\n\n/** Equal wedges for the skeleton. */\nconst LOADING_DATA = Array.from({ length: LOADING_SECTORS }, (_, index) => ({\n name: `loading-${index}`,\n value: 100 / LOADING_SECTORS,\n}))\n\n/**\n * One skeleton wedge, pulsing on a stagger so the wave travels round the pie.\n * Under `prefers-reduced-motion` it holds at a flat mid-opacity instead.\n */\nfunction LoadingSector(props: ComponentProps<typeof Sector> & { index?: number }) {\n const { index = 0, ...sector } = props\n const reduceMotion = useReducedMotion()\n const delay = (index / LOADING_SECTORS) * LOADING_PULSE\n\n if (reduceMotion) {\n return (\n <g opacity={0.3} className=\"text-(--ink)\">\n <Sector {...sector} fill=\"currentColor\" />\n </g>\n )\n }\n\n return (\n <motion.g\n className=\"text-(--ink)\"\n initial={{ opacity: 0.15 }}\n animate={{ opacity: [0.15, 0.5, 0.15] }}\n transition={{ duration: LOADING_PULSE, delay, repeat: Infinity, ease: 'easeInOut' }}\n >\n <Sector {...sector} fill=\"currentColor\" />\n </motion.g>\n )\n}\n\nPieChart.Pie = Pie\nPieChart.Label = Label\nPieChart.Tooltip = Tooltip\nPieChart.Legend = Legend\nPieChart.Background = Background\n\nexport default PieChart\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, ComponentProps, FC } from 'react';
|
|
3
|
+
import { RadarChart as RadarChart$1, Radar, PolarGrid, PolarAngleAxis, PolarRadiusAxis } from 'recharts';
|
|
4
|
+
import { ChartConfig } from '../lib/chart.js';
|
|
5
|
+
import { ChartBackgroundVariant } from '../lib/background.js';
|
|
6
|
+
import { ChartDotVariant } from '../lib/dot.js';
|
|
7
|
+
import { ChartTooltipSlotProps, ChartLegendSlotProps } from '../AreaChart/AreaChart.js';
|
|
8
|
+
import '../lib/empty.js';
|
|
9
|
+
import '../lib/values.js';
|
|
10
|
+
import '../lib/sonify-control.js';
|
|
11
|
+
import '../lib/sonify.js';
|
|
12
|
+
import '../lib/brush.js';
|
|
13
|
+
import '../lib/toolbar.js';
|
|
14
|
+
import '../lib/zoom.js';
|
|
15
|
+
import '../lib/figure.js';
|
|
16
|
+
import '../lib/paint.js';
|
|
17
|
+
import '../lib/legend.js';
|
|
18
|
+
import '../lib/tooltip.js';
|
|
19
|
+
import 'recharts/types/component/DefaultTooltipContent';
|
|
20
|
+
import '../lib/annotations.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether a radar is filled or left as an outline.
|
|
24
|
+
*
|
|
25
|
+
* `lines` is the honest default above two series: filled polygons overlap, and
|
|
26
|
+
* the reader is then judging areas through two layers of translucency, which is
|
|
27
|
+
* the one thing a radar is worst at.
|
|
28
|
+
*/
|
|
29
|
+
type RadarVariant = 'filled' | 'lines';
|
|
30
|
+
type ValidateKeys<TData, TConfig> = {
|
|
31
|
+
[K in keyof TConfig]: K extends keyof TData ? ChartConfig[string] : never;
|
|
32
|
+
};
|
|
33
|
+
interface RadarChartProps<TData extends Record<string, unknown>, TConfig extends Record<string, ChartConfig[string]>> {
|
|
34
|
+
config: TConfig & ValidateKeys<TData, TConfig>;
|
|
35
|
+
/** The rows the chart draws. One entry per point, bar or category. */
|
|
36
|
+
data: TData[];
|
|
37
|
+
/**
|
|
38
|
+
* What the chart shows, in a sentence a reader could act on. Required, and
|
|
39
|
+
* announced to a screen reader even when it is not printed.
|
|
40
|
+
*/
|
|
41
|
+
title: string;
|
|
42
|
+
/** Prints the title above the plot instead of hiding it from sight. */
|
|
43
|
+
showTitle?: boolean;
|
|
44
|
+
/** A line under the title — the unit, the window, the caveat. */
|
|
45
|
+
description?: ReactNode;
|
|
46
|
+
/**
|
|
47
|
+
* The composed parts — axes, grid, tooltip, legend, and the marks
|
|
48
|
+
* themselves.
|
|
49
|
+
*/
|
|
50
|
+
children: ReactNode;
|
|
51
|
+
/** Merged onto the figure, last, so a call site can size or space it. */
|
|
52
|
+
className?: string;
|
|
53
|
+
/** Escape hatch onto the raw Recharts chart element. */
|
|
54
|
+
chartProps?: ComponentProps<typeof RadarChart$1>;
|
|
55
|
+
/** The series lit on first render. Selection dims every other series. */
|
|
56
|
+
defaultSelectedDataKey?: string | null;
|
|
57
|
+
/** Fires when the selection changes, and with null when it is cleared. */
|
|
58
|
+
onSelectionChange?: (selectedDataKey: string | null) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Swaps the marks for an animated skeleton, keeping the measured height so
|
|
61
|
+
* the page does not jump when the data lands.
|
|
62
|
+
*/
|
|
63
|
+
isLoading?: boolean;
|
|
64
|
+
/** How many points the skeleton draws. */
|
|
65
|
+
loadingPoints?: number;
|
|
66
|
+
/** The row field naming each spoke. Used by the table view. */
|
|
67
|
+
angleDataKey?: keyof TData & string;
|
|
68
|
+
/**
|
|
69
|
+
* Drops the hidden table view. Only correct when the page prints the data
|
|
70
|
+
* itself.
|
|
71
|
+
*/
|
|
72
|
+
hideDataTable?: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A profile across several named dimensions — the shape for "what is this thing
|
|
76
|
+
* strong and weak at".
|
|
77
|
+
*
|
|
78
|
+
* It reads a SHAPE, not a set of values: the area a radar encloses depends on
|
|
79
|
+
* the order the spokes happen to be in, so it is the wrong chart for comparing
|
|
80
|
+
* magnitudes and the right one for recognising a silhouette. Two or three
|
|
81
|
+
* series at most.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* <RadarChart title="Team skills" config={config} data={data} angleDataKey="skill">
|
|
85
|
+
* <RadarChart.PolarGrid />
|
|
86
|
+
* <RadarChart.PolarAngleAxis dataKey="skill" />
|
|
87
|
+
* <RadarChart.Tooltip />
|
|
88
|
+
* <RadarChart.Radar dataKey="current" />
|
|
89
|
+
* </RadarChart>
|
|
90
|
+
*/
|
|
91
|
+
declare function RadarChart<TData extends Record<string, unknown>, TConfig extends Record<string, ChartConfig[string]>>({ config, data, title, showTitle, description, children, className, chartProps, defaultSelectedDataKey, onSelectionChange, isLoading, loadingPoints, angleDataKey, hideDataTable, }: RadarChartProps<TData, TConfig>): react.JSX.Element;
|
|
92
|
+
declare namespace RadarChart {
|
|
93
|
+
var Radar: ({ dataKey, variant, fillOpacity, glowing, isClickable, children, radarProps, }: RadarProps) => react.JSX.Element | null;
|
|
94
|
+
var Dot: FC<DotProps>;
|
|
95
|
+
var ActiveDot: FC<DotProps>;
|
|
96
|
+
var PolarGrid: ({ gridType, stroke, strokeDasharray, ...rest }: ComponentProps<typeof PolarGrid>) => react.JSX.Element;
|
|
97
|
+
var PolarAngleAxis: ({ tick, tickLine, ...rest }: ComponentProps<typeof PolarAngleAxis>) => react.JSX.Element | null;
|
|
98
|
+
var PolarRadiusAxis: ({ tick, tickLine, axisLine, ...rest }: ComponentProps<typeof PolarRadiusAxis>) => react.JSX.Element | null;
|
|
99
|
+
var Tooltip: ({ variant, roundness, defaultIndex }: ChartTooltipSlotProps) => react.JSX.Element | null;
|
|
100
|
+
var Legend: ({ variant, align, verticalAlign, isClickable, }: ChartLegendSlotProps) => react.JSX.Element | null;
|
|
101
|
+
var Background: ({ variant }: {
|
|
102
|
+
variant?: ChartBackgroundVariant;
|
|
103
|
+
}) => react.JSX.Element | null;
|
|
104
|
+
}
|
|
105
|
+
interface RadarProps {
|
|
106
|
+
dataKey: string;
|
|
107
|
+
variant?: RadarVariant;
|
|
108
|
+
/**
|
|
109
|
+
* How solid the filled area is, 0–1. Left unset it follows `--chart-fill`,
|
|
110
|
+
* which is what keeps it readable on both grounds.
|
|
111
|
+
*/
|
|
112
|
+
fillOpacity?: number;
|
|
113
|
+
/** A halo around the outline — for the one series that is the point. */
|
|
114
|
+
glowing?: boolean;
|
|
115
|
+
isClickable?: boolean;
|
|
116
|
+
children?: ReactNode;
|
|
117
|
+
radarProps?: Omit<ComponentProps<typeof Radar>, 'dataKey'>;
|
|
118
|
+
}
|
|
119
|
+
interface DotProps {
|
|
120
|
+
variant?: ChartDotVariant;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { type DotProps, RadarChart, type RadarChartProps, type RadarProps, type RadarVariant, RadarChart as default };
|