@astryxdesign/charts 0.0.0-bootstrap.0 → 0.1.4-canary.01e5b29
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 +3 -0
- package/LICENSE +21 -0
- package/README.md +51 -1
- package/dist/Chart.d.ts +31 -0
- package/dist/Chart.d.ts.map +1 -0
- package/dist/Chart.js +292 -0
- package/dist/ChartAxis.d.ts +36 -0
- package/dist/ChartAxis.d.ts.map +1 -0
- package/dist/ChartAxis.js +198 -0
- package/dist/ChartContext.d.ts +4 -0
- package/dist/ChartContext.d.ts.map +1 -0
- package/dist/ChartContext.js +13 -0
- package/dist/ChartGrid.d.ts +26 -0
- package/dist/ChartGrid.d.ts.map +1 -0
- package/dist/ChartGrid.js +94 -0
- package/dist/ChartLegend.d.ts +14 -0
- package/dist/ChartLegend.d.ts.map +1 -0
- package/dist/ChartLegend.js +62 -0
- package/dist/ChartSwatch.d.ts +36 -0
- package/dist/ChartSwatch.d.ts.map +1 -0
- package/dist/ChartSwatch.js +85 -0
- package/dist/ChartTooltip.d.ts +46 -0
- package/dist/ChartTooltip.d.ts.map +1 -0
- package/dist/ChartTooltip.js +291 -0
- package/dist/charts.css +33 -0
- package/dist/formatters.d.ts +37 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +146 -0
- package/dist/getChartColors.d.ts +67 -0
- package/dist/getChartColors.d.ts.map +1 -0
- package/dist/getChartColors.js +191 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/layout.d.ts +34 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +286 -0
- package/dist/legend.d.ts +17 -0
- package/dist/legend.d.ts.map +1 -0
- package/dist/legend.js +40 -0
- package/dist/markColor.d.ts +20 -0
- package/dist/markColor.d.ts.map +1 -0
- package/dist/markColor.js +49 -0
- package/dist/marks/area.d.ts +19 -0
- package/dist/marks/area.d.ts.map +1 -0
- package/dist/marks/area.js +121 -0
- package/dist/marks/band.d.ts +9 -0
- package/dist/marks/band.d.ts.map +1 -0
- package/dist/marks/band.js +69 -0
- package/dist/marks/bar.d.ts +21 -0
- package/dist/marks/bar.d.ts.map +1 -0
- package/dist/marks/bar.js +161 -0
- package/dist/marks/candlestick.d.ts +16 -0
- package/dist/marks/candlestick.d.ts.map +1 -0
- package/dist/marks/candlestick.js +115 -0
- package/dist/marks/dot.d.ts +19 -0
- package/dist/marks/dot.d.ts.map +1 -0
- package/dist/marks/dot.js +95 -0
- package/dist/marks/dotGL.d.ts +16 -0
- package/dist/marks/dotGL.d.ts.map +1 -0
- package/dist/marks/dotGL.js +231 -0
- package/dist/marks/dotGLInteractive.d.ts +35 -0
- package/dist/marks/dotGLInteractive.d.ts.map +1 -0
- package/dist/marks/dotGLInteractive.js +580 -0
- package/dist/marks/errorBar.d.ts +29 -0
- package/dist/marks/errorBar.d.ts.map +1 -0
- package/dist/marks/errorBar.js +98 -0
- package/dist/marks/heatmapGL.d.ts +23 -0
- package/dist/marks/heatmapGL.d.ts.map +1 -0
- package/dist/marks/heatmapGL.js +316 -0
- package/dist/marks/index.d.ts +13 -0
- package/dist/marks/index.d.ts.map +1 -0
- package/dist/marks/index.js +14 -0
- package/dist/marks/line.d.ts +18 -0
- package/dist/marks/line.d.ts.map +1 -0
- package/dist/marks/line.js +83 -0
- package/dist/marks/referenceLine.d.ts +37 -0
- package/dist/marks/referenceLine.d.ts.map +1 -0
- package/dist/marks/referenceLine.js +203 -0
- package/dist/marks/streamGL.d.ts +41 -0
- package/dist/marks/streamGL.d.ts.map +1 -0
- package/dist/marks/streamGL.js +317 -0
- package/dist/tooltip.d.ts +38 -0
- package/dist/tooltip.d.ts.map +1 -0
- package/dist/tooltip.js +57 -0
- package/dist/types.d.ts +159 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +63 -0
- package/dist/useChartColors.d.ts +16 -0
- package/dist/useChartColors.d.ts.map +1 -0
- package/dist/useChartColors.js +37 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +29 -0
- package/dist/webgl.d.ts +90 -0
- package/dist/webgl.d.ts.map +1 -0
- package/dist/webgl.js +236 -0
- package/package.json +66 -5
- package/src/Chart.doc.mjs +16 -0
- package/src/Chart.tsx +363 -0
- package/src/ChartAxis.tsx +250 -0
- package/src/ChartContext.ts +16 -0
- package/src/ChartGrid.tsx +109 -0
- package/src/ChartLegend.tsx +77 -0
- package/src/ChartSwatch.doc.mjs +17 -0
- package/src/ChartSwatch.tsx +89 -0
- package/src/ChartTooltip.tsx +403 -0
- package/src/formatters.ts +157 -0
- package/src/getChartColors.ts +289 -0
- package/src/index.ts +88 -0
- package/src/layout.ts +324 -0
- package/src/legend.ts +44 -0
- package/src/markColor.ts +63 -0
- package/src/marks/area.tsx +142 -0
- package/src/marks/band.tsx +83 -0
- package/src/marks/bar.tsx +210 -0
- package/src/marks/candlestick.tsx +131 -0
- package/src/marks/dot.tsx +116 -0
- package/src/marks/dotGL.tsx +274 -0
- package/src/marks/dotGLInteractive.tsx +656 -0
- package/src/marks/errorBar.tsx +118 -0
- package/src/marks/heatmapGL.tsx +376 -0
- package/src/marks/index.ts +17 -0
- package/src/marks/line.tsx +118 -0
- package/src/marks/referenceLine.tsx +252 -0
- package/src/marks/streamGL.tsx +381 -0
- package/src/tooltip.ts +73 -0
- package/src/types.ts +177 -0
- package/src/useChartColors.ts +41 -0
- package/src/utils.ts +36 -0
- package/src/webgl.ts +263 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Meta Platforms, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,53 @@
|
|
|
1
1
|
# @astryxdesign/charts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Astryx charts — a config-model data visualization library built on d3.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import {Chart, bar, line} from '@astryxdesign/charts';
|
|
7
|
+
|
|
8
|
+
<Chart data={data} xKey="month" series={[bar('revenue'), line('trend')]} />;
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Marks are factory functions (`bar`, `line`, `area`, `dot`, `band`, `candlestick`,
|
|
12
|
+
`errorBar`, `referenceLine`, and WebGL variants) that return config objects passed
|
|
13
|
+
via the `series` prop. The chart root owns **one** x/y scale that every mark, axis,
|
|
14
|
+
and grid line reads, so they can never disagree. It consumes `@astryxdesign/core`
|
|
15
|
+
theme tokens directly (StyleX build mirrors `@astryxdesign/lab`).
|
|
16
|
+
|
|
17
|
+
It ships to npm **only under the `@canary` dist-tag** — there is never a stable
|
|
18
|
+
(`latest`) release yet.
|
|
19
|
+
|
|
20
|
+
> Note: this package is the successor to the experimental `Chart` (formerly
|
|
21
|
+
> `ChartV2`) that used to live in `@astryxdesign/lab`; that code has moved here and
|
|
22
|
+
> d3 is a direct dependency. (Supersedes the original "thin wrappers over a peer
|
|
23
|
+
> engine" framing of the bootstrap scaffold.)
|
|
24
|
+
|
|
25
|
+
## Status
|
|
26
|
+
|
|
27
|
+
Under active development. The config-model chart and its marks/chrome are in place;
|
|
28
|
+
API and visuals are still being refined. See the repo-root `CHARTV2_*` docs for the
|
|
29
|
+
plan, design research, and verification checklist.
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
Inside the monorepo (storybook/sandbox), imports resolve via pnpm workspaces:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import {Chart, bar, line, ChartGrid, ChartAxis} from '@astryxdesign/charts';
|
|
37
|
+
import '@astryxdesign/core/astryx.css';
|
|
38
|
+
import '@astryxdesign/charts/charts.css';
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Trying charts in your own project (canary)
|
|
42
|
+
|
|
43
|
+
`@astryxdesign/charts` is published **only** under the `@canary` dist-tag, so you must request that tag explicitly. There is no `latest` version to install.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @astryxdesign/charts@canary @astryxdesign/core@canary
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
> Canary builds track the latest commit on `main` (`0.x.y-canary.<sha>`). They can break between any two versions — pin an exact version if you need stability.
|
|
50
|
+
|
|
51
|
+
## Why no stable release?
|
|
52
|
+
|
|
53
|
+
`package.json` keeps `"private": true` plus an `"astryx": { "canaryOnly": true }` marker. The release workflow's stable (`latest`) job skips both private and `canaryOnly` packages, while the canary job strips `private` in its ephemeral CI checkout only (never in git) to publish the `@canary` tag. The committed `private: true` is npm's hard guarantee that no stable publish can ever happen — **do not remove it.**
|
package/dist/Chart.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { SeriesDef, YBaseline } from './types';
|
|
3
|
+
import type { ChartMargin } from './types';
|
|
4
|
+
import { type ChartLegendProps } from './ChartLegend';
|
|
5
|
+
import { type ChartTooltipProps } from './ChartTooltip';
|
|
6
|
+
export interface ChartProps {
|
|
7
|
+
data: Record<string, unknown>[];
|
|
8
|
+
xKey: string;
|
|
9
|
+
series: SeriesDef[];
|
|
10
|
+
height?: number;
|
|
11
|
+
margin?: Partial<ChartMargin>;
|
|
12
|
+
/** How the y-domain is derived when `yDomain` is not set. Default `'auto'`. */
|
|
13
|
+
yBaseline?: YBaseline;
|
|
14
|
+
/** Explicit y-domain [min, max]. Authoritative — disables baseline/headroom. */
|
|
15
|
+
yDomain?: [number, number];
|
|
16
|
+
/**
|
|
17
|
+
* Explicit x-domain [min, max] for numeric/linear x. Honored even when `data`
|
|
18
|
+
* is empty (stable streaming window). Ignored for categorical (band) scales.
|
|
19
|
+
*/
|
|
20
|
+
xDomain?: [number, number];
|
|
21
|
+
grid?: ReactNode;
|
|
22
|
+
axes?: ReactNode;
|
|
23
|
+
legend?: boolean | ChartLegendProps;
|
|
24
|
+
tooltip?: boolean | Omit<ChartTooltipProps, 'series'>;
|
|
25
|
+
interactions?: ReactNode;
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
title?: string;
|
|
28
|
+
subtitle?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function Chart({ data, xKey, series, height, margin: marginOverride, yBaseline, yDomain, xDomain, grid, axes, legend, tooltip, interactions, children, title, subtitle, }: ChartProps): import("react").JSX.Element;
|
|
31
|
+
//# sourceMappingURL=Chart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Chart.d.ts","sourceRoot":"","sources":["../src/Chart.tsx"],"names":[],"mappings":"AAeA,OAAO,EACL,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAe,WAAW,EAAoB,MAAM,SAAS,CAAC;AAM1E,OAAO,EAAc,KAAK,gBAAgB,EAAC,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAe,KAAK,iBAAiB,EAAC,MAAM,gBAAgB,CAAC;AAIpE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9B,+EAA+E;IAC/E,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,gFAAgF;IAChF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IACpC,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IACtD,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAkBD,wBAAgB,KAAK,CAAC,EACpB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,MAAY,EACZ,MAAM,EAAE,cAAc,EACtB,SAAS,EACT,OAAO,EACP,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,KAAK,EACL,QAAQ,GACT,EAAE,UAAU,+BA2QZ"}
|
package/dist/Chart.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Chart.tsx (v2)
|
|
5
|
+
* @output Root chart — coordinates layout, rendering, and events
|
|
6
|
+
* @position Top-level; delegates everything to series configs and interaction slots
|
|
7
|
+
*
|
|
8
|
+
* The chart root has ZERO knowledge of mark types. It:
|
|
9
|
+
* 1. Runs the layout engine (scales + stacking + grouping)
|
|
10
|
+
* 2. Calls each series' resolve() and render() methods
|
|
11
|
+
* 3. Provides a single event layer for interaction children
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use client';
|
|
15
|
+
|
|
16
|
+
import { useId, useMemo, useRef, useState, useCallback, useLayoutEffect } from 'react';
|
|
17
|
+
import { computeLayout } from "./layout.js";
|
|
18
|
+
import { ChartProvider } from "./ChartContext.js";
|
|
19
|
+
import { Text } from '@astryxdesign/core';
|
|
20
|
+
import { VStack, HStack } from '@astryxdesign/core';
|
|
21
|
+
import * as stylex from '@stylexjs/stylex';
|
|
22
|
+
import { ChartLegend } from "./ChartLegend.js";
|
|
23
|
+
import { deriveLegendItems } from "./legend.js";
|
|
24
|
+
import { ChartTooltip } from "./ChartTooltip.js";
|
|
25
|
+
import { useChartColors } from "./useChartColors.js";
|
|
26
|
+
import { isUtilityMarkType } from "./types.js";
|
|
27
|
+
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
|
|
28
|
+
const DEFAULT_MARGIN = {
|
|
29
|
+
top: 24,
|
|
30
|
+
right: 24,
|
|
31
|
+
bottom: 32,
|
|
32
|
+
left: 48
|
|
33
|
+
};
|
|
34
|
+
export function Chart({
|
|
35
|
+
data,
|
|
36
|
+
xKey,
|
|
37
|
+
series,
|
|
38
|
+
height = 300,
|
|
39
|
+
margin: marginOverride,
|
|
40
|
+
yBaseline,
|
|
41
|
+
yDomain,
|
|
42
|
+
xDomain,
|
|
43
|
+
grid,
|
|
44
|
+
axes,
|
|
45
|
+
legend,
|
|
46
|
+
tooltip,
|
|
47
|
+
interactions,
|
|
48
|
+
children,
|
|
49
|
+
title,
|
|
50
|
+
subtitle
|
|
51
|
+
}) {
|
|
52
|
+
const chartId = useId();
|
|
53
|
+
const descId = `${chartId}-desc`;
|
|
54
|
+
// useId() can contain ':' which is invalid in an SVG url(#id) reference.
|
|
55
|
+
const clipId = `plot-${chartId.replace(/:/g, '')}`;
|
|
56
|
+
const containerRef = useRef(null);
|
|
57
|
+
const svgRef = useRef(null);
|
|
58
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
59
|
+
const pointerHandlers = useRef(new Set());
|
|
60
|
+
useLayoutEffect(() => {
|
|
61
|
+
if (!containerRef.current) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const observer = new ResizeObserver(entries => {
|
|
65
|
+
const entry = entries[0];
|
|
66
|
+
if (entry) {
|
|
67
|
+
setContainerWidth(entry.contentRect.width);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
observer.observe(containerRef.current);
|
|
71
|
+
return () => observer.disconnect();
|
|
72
|
+
}, []);
|
|
73
|
+
const margin = useMemo(() => ({
|
|
74
|
+
...DEFAULT_MARGIN,
|
|
75
|
+
...marginOverride
|
|
76
|
+
}), [marginOverride]);
|
|
77
|
+
const innerWidth = Math.max(0, containerWidth - margin.left - margin.right);
|
|
78
|
+
const innerHeight = Math.max(0, height - margin.top - margin.bottom);
|
|
79
|
+
|
|
80
|
+
// ─── Color assignment ─────────────────────────────────────────────────
|
|
81
|
+
// Give every primary series that doesn't supply a static color (auto-colored
|
|
82
|
+
// or accessor-colored) a distinct color from the theme's categorical palette.
|
|
83
|
+
// Utility marks (band/errorBar/referenceLine) don't consume palette slots.
|
|
84
|
+
// Assigned during render (like the layout pass annotates `_uid`) so the first
|
|
85
|
+
// paint is already colored; intentionally not a `useMemo` — it mutates the
|
|
86
|
+
// caller's series defs, and useMemo is allowed to drop its cached result.
|
|
87
|
+
const chartColors = useChartColors();
|
|
88
|
+
const needsColor = series.filter(s => !isUtilityMarkType(s.type) && s.color == null);
|
|
89
|
+
const palette = chartColors.categorical(Math.max(needsColor.length, 1));
|
|
90
|
+
for (let i = 0; i < needsColor.length; i++) {
|
|
91
|
+
needsColor[i]._resolvedColor = palette[i % palette.length];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ─── Layout pass ──────────────────────────────────────────────────────
|
|
95
|
+
const layout = useMemo(() => computeLayout({
|
|
96
|
+
data,
|
|
97
|
+
xKey,
|
|
98
|
+
series,
|
|
99
|
+
width: innerWidth,
|
|
100
|
+
height: innerHeight,
|
|
101
|
+
yBaseline,
|
|
102
|
+
yDomain,
|
|
103
|
+
xDomain
|
|
104
|
+
}), [data, xKey, series, innerWidth, innerHeight, yBaseline, yDomain, xDomain]);
|
|
105
|
+
const seriesCtx = useMemo(() => ({
|
|
106
|
+
data,
|
|
107
|
+
xKey,
|
|
108
|
+
xScale: layout.xScale,
|
|
109
|
+
yScale: layout.yScale,
|
|
110
|
+
width: innerWidth,
|
|
111
|
+
height: innerHeight
|
|
112
|
+
}), [data, xKey, layout, innerWidth, innerHeight]);
|
|
113
|
+
|
|
114
|
+
// ─── Event dispatch ───────────────────────────────────────────────────
|
|
115
|
+
const onPointer = useCallback(handler => {
|
|
116
|
+
pointerHandlers.current.add(handler);
|
|
117
|
+
return () => {
|
|
118
|
+
pointerHandlers.current.delete(handler);
|
|
119
|
+
};
|
|
120
|
+
}, []);
|
|
121
|
+
const dispatch = useCallback(e => {
|
|
122
|
+
for (const handler of pointerHandlers.current) {
|
|
123
|
+
handler(e);
|
|
124
|
+
}
|
|
125
|
+
}, []);
|
|
126
|
+
const handlePointerMove = useCallback(e => {
|
|
127
|
+
const svg = svgRef.current;
|
|
128
|
+
if (!svg) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const point = svg.createSVGPoint();
|
|
132
|
+
point.x = e.clientX;
|
|
133
|
+
point.y = e.clientY;
|
|
134
|
+
const ctm = e.currentTarget.getScreenCTM()?.inverse();
|
|
135
|
+
if (!ctm) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const cursor = point.matrixTransform(ctm);
|
|
139
|
+
|
|
140
|
+
// Find nearest point by x-distance only (full vertical column is the hover zone)
|
|
141
|
+
let nearest = null;
|
|
142
|
+
let bestXDist = Infinity;
|
|
143
|
+
for (const [seriesKey, points] of layout.resolved) {
|
|
144
|
+
for (const p of points) {
|
|
145
|
+
const xDist = Math.abs(p.px - cursor.x);
|
|
146
|
+
if (xDist < bestXDist) {
|
|
147
|
+
bestXDist = xDist;
|
|
148
|
+
nearest = {
|
|
149
|
+
...p,
|
|
150
|
+
seriesKey
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
dispatch({
|
|
156
|
+
x: cursor.x,
|
|
157
|
+
y: cursor.y,
|
|
158
|
+
nearest,
|
|
159
|
+
active: e.buttons > 0
|
|
160
|
+
});
|
|
161
|
+
}, [layout.resolved, dispatch]);
|
|
162
|
+
const handlePointerLeave = useCallback(() => {
|
|
163
|
+
dispatch({
|
|
164
|
+
x: -1,
|
|
165
|
+
y: -1,
|
|
166
|
+
nearest: null,
|
|
167
|
+
active: false
|
|
168
|
+
});
|
|
169
|
+
}, [dispatch]);
|
|
170
|
+
|
|
171
|
+
// ─── Context for interactions + v1 chrome ─────────────────────────────
|
|
172
|
+
const ctx = useMemo(() => ({
|
|
173
|
+
width: innerWidth,
|
|
174
|
+
height: innerHeight,
|
|
175
|
+
margin,
|
|
176
|
+
data,
|
|
177
|
+
xKey,
|
|
178
|
+
xScale: layout.xScale,
|
|
179
|
+
yScale: layout.yScale,
|
|
180
|
+
resolved: layout.resolved,
|
|
181
|
+
onPointer,
|
|
182
|
+
svgRef
|
|
183
|
+
}), [innerWidth, innerHeight, margin, data, xKey, layout, onPointer]);
|
|
184
|
+
|
|
185
|
+
// ─── Legend ────────────────────────────────────────────────────────────
|
|
186
|
+
const legendConfig = legend === true ? {} : legend || null;
|
|
187
|
+
const legendElement = legendConfig ? /*#__PURE__*/_jsxDEV(ChartLegend, {
|
|
188
|
+
items: legendConfig.items ?? deriveLegendItems(series),
|
|
189
|
+
position: legendConfig.position,
|
|
190
|
+
alignment: legendConfig.alignment
|
|
191
|
+
}, void 0, false) : null;
|
|
192
|
+
const legendPosition = legendConfig?.position ?? 'bottom';
|
|
193
|
+
const isLegendHorizontal = legendPosition === 'start' || legendPosition === 'end';
|
|
194
|
+
|
|
195
|
+
// ─── Render ───────────────────────────────────────────────────────────
|
|
196
|
+
if (containerWidth === 0) {
|
|
197
|
+
return /*#__PURE__*/_jsxDEV("div", {
|
|
198
|
+
ref: containerRef,
|
|
199
|
+
...{
|
|
200
|
+
className: "xh8yej3"
|
|
201
|
+
},
|
|
202
|
+
style: {
|
|
203
|
+
height
|
|
204
|
+
}
|
|
205
|
+
}, void 0, false);
|
|
206
|
+
}
|
|
207
|
+
return /*#__PURE__*/_jsxDEV("div", {
|
|
208
|
+
ref: containerRef,
|
|
209
|
+
...{
|
|
210
|
+
className: "xh8yej3"
|
|
211
|
+
},
|
|
212
|
+
children: [(title || subtitle) && /*#__PURE__*/_jsxDEV("div", {
|
|
213
|
+
...{
|
|
214
|
+
className: "x1yztbdb"
|
|
215
|
+
},
|
|
216
|
+
children: [title && /*#__PURE__*/_jsxDEV(Text, {
|
|
217
|
+
type: "body",
|
|
218
|
+
weight: "semibold",
|
|
219
|
+
display: "block",
|
|
220
|
+
children: title
|
|
221
|
+
}, void 0, false), subtitle && /*#__PURE__*/_jsxDEV(Text, {
|
|
222
|
+
type: "supporting",
|
|
223
|
+
display: "block",
|
|
224
|
+
children: subtitle
|
|
225
|
+
}, void 0, false)]
|
|
226
|
+
}, void 0, true), /*#__PURE__*/_jsxDEV(ChartProvider, {
|
|
227
|
+
value: ctx,
|
|
228
|
+
children: legendConfig == null ? renderSvg() : isLegendHorizontal ? /*#__PURE__*/_jsxDEV(HStack, {
|
|
229
|
+
gap: 4,
|
|
230
|
+
children: [legendPosition === 'start' && legendElement, /*#__PURE__*/_jsxDEV("div", {
|
|
231
|
+
...{
|
|
232
|
+
className: "x98rzlu xeuugli xb3r6kr"
|
|
233
|
+
},
|
|
234
|
+
children: renderSvg()
|
|
235
|
+
}, void 0, false), legendPosition === 'end' && legendElement]
|
|
236
|
+
}, void 0, true) : /*#__PURE__*/_jsxDEV(VStack, {
|
|
237
|
+
gap: 4,
|
|
238
|
+
children: [legendPosition === 'top' && legendElement, renderSvg(), legendPosition === 'bottom' && legendElement]
|
|
239
|
+
}, void 0, true)
|
|
240
|
+
}, void 0, false)]
|
|
241
|
+
}, void 0, true);
|
|
242
|
+
function renderSvg() {
|
|
243
|
+
return /*#__PURE__*/_jsxDEV("svg", {
|
|
244
|
+
ref: svgRef,
|
|
245
|
+
width: "100%",
|
|
246
|
+
height: height,
|
|
247
|
+
"aria-label": title ?? undefined,
|
|
248
|
+
"aria-describedby": subtitle ? descId : undefined,
|
|
249
|
+
children: [title && /*#__PURE__*/_jsxDEV("title", {
|
|
250
|
+
children: title
|
|
251
|
+
}, void 0, false), subtitle && /*#__PURE__*/_jsxDEV("desc", {
|
|
252
|
+
id: descId,
|
|
253
|
+
children: subtitle
|
|
254
|
+
}, void 0, false), /*#__PURE__*/_jsxDEV("defs", {
|
|
255
|
+
children: /*#__PURE__*/_jsxDEV("clipPath", {
|
|
256
|
+
id: clipId,
|
|
257
|
+
children: /*#__PURE__*/_jsxDEV("rect", {
|
|
258
|
+
x: 0,
|
|
259
|
+
y: 0,
|
|
260
|
+
width: innerWidth,
|
|
261
|
+
height: innerHeight
|
|
262
|
+
}, void 0, false)
|
|
263
|
+
}, void 0, false)
|
|
264
|
+
}, void 0, false), /*#__PURE__*/_jsxDEV("g", {
|
|
265
|
+
transform: `translate(${margin.left},${margin.top})`,
|
|
266
|
+
children: [grid, /*#__PURE__*/_jsxDEV("g", {
|
|
267
|
+
clipPath: `url(#${clipId})`,
|
|
268
|
+
children: series.map(s => {
|
|
269
|
+
const resolved = s._uid ? layout.resolved.get(s._uid) : undefined;
|
|
270
|
+
if (!resolved) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
return /*#__PURE__*/_jsxDEV("g", {
|
|
274
|
+
children: s.render(resolved, seriesCtx)
|
|
275
|
+
}, s._uid, false);
|
|
276
|
+
})
|
|
277
|
+
}, void 0, false), axes, /*#__PURE__*/_jsxDEV("rect", {
|
|
278
|
+
x: 0,
|
|
279
|
+
y: 0,
|
|
280
|
+
width: innerWidth,
|
|
281
|
+
height: innerHeight,
|
|
282
|
+
fill: "transparent",
|
|
283
|
+
onPointerMove: handlePointerMove,
|
|
284
|
+
onPointerLeave: handlePointerLeave
|
|
285
|
+
}, void 0, false), interactions, tooltip && /*#__PURE__*/_jsxDEV(ChartTooltip, {
|
|
286
|
+
series: series,
|
|
287
|
+
...(tooltip === true ? {} : tooltip)
|
|
288
|
+
}, void 0, false), children]
|
|
289
|
+
}, void 0, true)]
|
|
290
|
+
}, void 0, true);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface ChartAxisProps {
|
|
2
|
+
/** Which edge to render the axis on */
|
|
3
|
+
position: 'top' | 'right' | 'bottom' | 'left';
|
|
4
|
+
/** Number of ticks (approximate — d3 decides final count) */
|
|
5
|
+
tickCount?: number;
|
|
6
|
+
/** Maximum number of tick labels to show. Labels are evenly skipped when exceeded. */
|
|
7
|
+
maxTicks?: number;
|
|
8
|
+
/** Custom tick formatter */
|
|
9
|
+
tickFormat?: (value: unknown) => string;
|
|
10
|
+
/** Truncate labels to this many characters (appends "\u2026"). */
|
|
11
|
+
truncate?: number;
|
|
12
|
+
/** Enable smooth transitions for streaming (default: true) */
|
|
13
|
+
animated?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Show the axis edge line. Defaults to `true` for `position="bottom"`,
|
|
16
|
+
* `false` otherwise. Forced to `true` when `showTicks` is enabled.
|
|
17
|
+
* Pair with `<ChartGrid vertical />` and pass `showAxisLine` on the
|
|
18
|
+
* corresponding side axis to keep the visual edge grounded.
|
|
19
|
+
*/
|
|
20
|
+
showAxisLine?: boolean;
|
|
21
|
+
/** Show perpendicular tick marks at each tick label. Default: `false`. */
|
|
22
|
+
showTicks?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Chart axis. Always draws tick labels; the axis edge line and tick marks
|
|
26
|
+
* are independently toggleable. Pair with `<ChartGrid>` for grid lines.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```
|
|
30
|
+
* <ChartAxis position="bottom" /> // edge line + labels
|
|
31
|
+
* <ChartAxis position="left" /> // labels only (no edge line)
|
|
32
|
+
* <ChartAxis position="left" showAxisLine showTicks />
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function ChartAxis({ position, tickCount, maxTicks, tickFormat, truncate, animated, showAxisLine, showTicks, }: ChartAxisProps): import("react").JSX.Element;
|
|
36
|
+
//# sourceMappingURL=ChartAxis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartAxis.d.ts","sourceRoot":"","sources":["../src/ChartAxis.tsx"],"names":[],"mappings":"AA0BA,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC9C,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;IACxC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,SAAa,EACb,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,QAAe,EACf,YAAoC,EACpC,SAAiB,GAClB,EAAE,cAAc,+BAsKhB"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ChartAxis.tsx (v2)
|
|
5
|
+
* @output Renders an axis (top, right, bottom, left) using the chart's scales
|
|
6
|
+
* @position Child of Chart v2; reads scales from chart context
|
|
7
|
+
*
|
|
8
|
+
* The axis edge line and tick marks are independently toggleable so callers
|
|
9
|
+
* can compose: line-only, line + ticks, or line + ticks + grid (paired with
|
|
10
|
+
* `<ChartGrid>`). To stay consistent with most charts, the bottom axis
|
|
11
|
+
* draws its edge line by default and other positions don't.
|
|
12
|
+
*
|
|
13
|
+
* Labels use d3's native tick formatter for continuous scales by default (clean
|
|
14
|
+
* numbers/dates) unless a `tickFormat` is supplied, and are auto-thinned to the
|
|
15
|
+
* available width (horizontal) or height (vertical) to avoid overlap.
|
|
16
|
+
*
|
|
17
|
+
* Ticks use CSS transitions for smooth sliding during streaming updates.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { useCallback, useMemo } from 'react';
|
|
21
|
+
import * as stylex from '@stylexjs/stylex';
|
|
22
|
+
import '@astryxdesign/core/theme/tokens.stylex';
|
|
23
|
+
import { colorVars } from '@astryxdesign/core/theme/tokens.stylex';
|
|
24
|
+
import { useChart } from "./ChartContext.js";
|
|
25
|
+
import { isBandScale } from "./utils.js";
|
|
26
|
+
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
|
|
27
|
+
const TICK_SIZE = 6;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Chart axis. Always draws tick labels; the axis edge line and tick marks
|
|
31
|
+
* are independently toggleable. Pair with `<ChartGrid>` for grid lines.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```
|
|
35
|
+
* <ChartAxis position="bottom" /> // edge line + labels
|
|
36
|
+
* <ChartAxis position="left" /> // labels only (no edge line)
|
|
37
|
+
* <ChartAxis position="left" showAxisLine showTicks />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function ChartAxis({
|
|
41
|
+
position,
|
|
42
|
+
tickCount = 5,
|
|
43
|
+
maxTicks,
|
|
44
|
+
tickFormat,
|
|
45
|
+
truncate,
|
|
46
|
+
animated = true,
|
|
47
|
+
showAxisLine = position === 'bottom',
|
|
48
|
+
showTicks = false
|
|
49
|
+
}) {
|
|
50
|
+
// Tick marks need an axis line to anchor against; force it on when ticks
|
|
51
|
+
// are enabled so the two visuals stay coherent.
|
|
52
|
+
const renderAxisLine = showAxisLine || showTicks;
|
|
53
|
+
const {
|
|
54
|
+
width,
|
|
55
|
+
height,
|
|
56
|
+
xScale,
|
|
57
|
+
yScale
|
|
58
|
+
} = useChart();
|
|
59
|
+
const isHorizontal = position === 'top' || position === 'bottom';
|
|
60
|
+
const scale = isHorizontal ? xScale : yScale;
|
|
61
|
+
|
|
62
|
+
// Default label formatter. For continuous (linear/time) scales, use d3's own
|
|
63
|
+
// tick formatter so numbers get sensible precision (no floating-point dust
|
|
64
|
+
// like "0.30000000000000004") and dates render as calendar labels instead of
|
|
65
|
+
// `String(Date)`. Band scales keep their category strings.
|
|
66
|
+
const autoFormat = useMemo(() => {
|
|
67
|
+
if (tickFormat || isBandScale(scale)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const continuous = scale;
|
|
71
|
+
const fmt = continuous.tickFormat(tickCount);
|
|
72
|
+
return v => fmt(v);
|
|
73
|
+
}, [tickFormat, scale, tickCount]);
|
|
74
|
+
const format = useCallback(value => {
|
|
75
|
+
const str = (tickFormat ?? autoFormat ?? String)(value);
|
|
76
|
+
return truncate && str.length > truncate ? str.slice(0, truncate) + '\u2026' : str;
|
|
77
|
+
}, [tickFormat, autoFormat, truncate]);
|
|
78
|
+
const ticks = useMemo(() => {
|
|
79
|
+
let allTicks;
|
|
80
|
+
if (isBandScale(scale)) {
|
|
81
|
+
allTicks = scale.domain().map(d => ({
|
|
82
|
+
value: d,
|
|
83
|
+
offset: (scale(d) ?? 0) + scale.bandwidth() / 2
|
|
84
|
+
}));
|
|
85
|
+
} else {
|
|
86
|
+
const linearScale = scale;
|
|
87
|
+
allTicks = linearScale.ticks(tickCount).map(d => ({
|
|
88
|
+
value: d,
|
|
89
|
+
offset: linearScale(d)
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Cap label count to avoid overlap. An explicit `maxTicks` always wins.
|
|
94
|
+
// Otherwise derive a cap from the available space and label size so dense
|
|
95
|
+
// axes don't smear into an unreadable blur: width ÷ widest-label for
|
|
96
|
+
// horizontal (e.g. 30 daily categories), height ÷ line-height for vertical
|
|
97
|
+
// (e.g. a categorical y-axis on a horizontal bar chart). Labels are then
|
|
98
|
+
// evenly skipped down to the cap.
|
|
99
|
+
let cap = maxTicks;
|
|
100
|
+
if (cap == null && allTicks.length > 1) {
|
|
101
|
+
if (isHorizontal && width > 0) {
|
|
102
|
+
const widestChars = allTicks.reduce((m, t) => Math.max(m, format(t.value).length), 1);
|
|
103
|
+
const approxLabelPx = widestChars * 7 + 16;
|
|
104
|
+
cap = Math.max(1, Math.floor(width / approxLabelPx));
|
|
105
|
+
} else if (!isHorizontal && height > 0) {
|
|
106
|
+
// ~12px glyph + breathing room keeps stacked labels from touching.
|
|
107
|
+
cap = Math.max(1, Math.floor(height / 18));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (cap && allTicks.length > cap) {
|
|
111
|
+
const step = Math.ceil(allTicks.length / cap);
|
|
112
|
+
allTicks = allTicks.filter((_, i) => i % step === 0);
|
|
113
|
+
}
|
|
114
|
+
return allTicks;
|
|
115
|
+
}, [scale, tickCount, maxTicks, isHorizontal, width, height, format]);
|
|
116
|
+
const transform = position === 'bottom' ? `translate(0,${height})` : position === 'right' ? `translate(${width},0)` : undefined;
|
|
117
|
+
|
|
118
|
+
// For the bottom axis, draw the axis line at y=0 when the domain spans
|
|
119
|
+
// negative values (so the axis line still represents zero, not the chart edge).
|
|
120
|
+
const axisLineY = (() => {
|
|
121
|
+
if (position !== 'bottom') {
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
const domain = yScale.domain();
|
|
125
|
+
if (domain[0] < 0 && domain[1] > 0) {
|
|
126
|
+
return yScale(0) - height;
|
|
127
|
+
}
|
|
128
|
+
return 0;
|
|
129
|
+
})();
|
|
130
|
+
const tickTransition = animated ? 'transform 150ms linear, opacity 150ms ease' : undefined;
|
|
131
|
+
return /*#__PURE__*/_jsxDEV("g", {
|
|
132
|
+
transform: transform,
|
|
133
|
+
role: "group",
|
|
134
|
+
"aria-label": `${position} axis`,
|
|
135
|
+
children: [renderAxisLine && /*#__PURE__*/_jsxDEV("line", {
|
|
136
|
+
x1: 0,
|
|
137
|
+
x2: isHorizontal ? width : 0,
|
|
138
|
+
y1: isHorizontal ? axisLineY : 0,
|
|
139
|
+
y2: isHorizontal ? axisLineY : height,
|
|
140
|
+
...{
|
|
141
|
+
className: "x1lo1t26 xnpr05h"
|
|
142
|
+
}
|
|
143
|
+
}, void 0, false), ticks.map(({
|
|
144
|
+
value,
|
|
145
|
+
offset
|
|
146
|
+
}) => {
|
|
147
|
+
const label = format(value);
|
|
148
|
+
// Key off the raw tick value, not the formatted label: distinct ticks
|
|
149
|
+
// can format (or truncate) to the same string and would collide as keys.
|
|
150
|
+
const key = String(value);
|
|
151
|
+
const isVisible = isHorizontal ? offset >= -10 && offset <= width + 10 : offset >= -10 && offset <= height + 10;
|
|
152
|
+
if (isHorizontal) {
|
|
153
|
+
const y = position === 'bottom' ? TICK_SIZE : -TICK_SIZE;
|
|
154
|
+
return /*#__PURE__*/_jsxDEV("g", {
|
|
155
|
+
style: {
|
|
156
|
+
transform: `translateX(${offset}px)`,
|
|
157
|
+
transition: tickTransition,
|
|
158
|
+
opacity: isVisible ? 1 : 0
|
|
159
|
+
},
|
|
160
|
+
children: [showTicks && /*#__PURE__*/_jsxDEV("line", {
|
|
161
|
+
y2: y,
|
|
162
|
+
...{
|
|
163
|
+
className: "x1lo1t26 xnpr05h"
|
|
164
|
+
}
|
|
165
|
+
}, void 0, false), /*#__PURE__*/_jsxDEV("text", {
|
|
166
|
+
y: position === 'bottom' ? TICK_SIZE + 12 : -(TICK_SIZE + 4),
|
|
167
|
+
textAnchor: "middle",
|
|
168
|
+
fill: "var(--color-text-secondary)",
|
|
169
|
+
fontSize: 12,
|
|
170
|
+
children: label
|
|
171
|
+
}, void 0, false)]
|
|
172
|
+
}, key, true);
|
|
173
|
+
}
|
|
174
|
+
// Vertical axis
|
|
175
|
+
const x = position === 'left' ? -TICK_SIZE : TICK_SIZE;
|
|
176
|
+
return /*#__PURE__*/_jsxDEV("g", {
|
|
177
|
+
style: {
|
|
178
|
+
transform: `translateY(${offset}px)`,
|
|
179
|
+
transition: tickTransition,
|
|
180
|
+
opacity: isVisible ? 1 : 0
|
|
181
|
+
},
|
|
182
|
+
children: [showTicks && /*#__PURE__*/_jsxDEV("line", {
|
|
183
|
+
x2: x,
|
|
184
|
+
...{
|
|
185
|
+
className: "x1lo1t26 xnpr05h"
|
|
186
|
+
}
|
|
187
|
+
}, void 0, false), /*#__PURE__*/_jsxDEV("text", {
|
|
188
|
+
x: position === 'left' ? -(TICK_SIZE + 4) : TICK_SIZE + 4,
|
|
189
|
+
dy: "0.32em",
|
|
190
|
+
textAnchor: position === 'left' ? 'end' : 'start',
|
|
191
|
+
fill: "var(--color-text-secondary)",
|
|
192
|
+
fontSize: 12,
|
|
193
|
+
children: label
|
|
194
|
+
}, void 0, false)]
|
|
195
|
+
}, key, true);
|
|
196
|
+
})]
|
|
197
|
+
}, void 0, true);
|
|
198
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartContext.d.ts","sourceRoot":"","sources":["../src/ChartContext.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,SAAS,CAAC;AAI1C,eAAO,MAAM,aAAa,+CAAe,CAAC;AAE1C,wBAAgB,QAAQ,IAAI,YAAY,CAMvC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext } from 'react';
|
|
4
|
+
const Ctx = /*#__PURE__*/createContext(null);
|
|
5
|
+
Ctx.displayName = 'ChartContext';
|
|
6
|
+
export const ChartProvider = Ctx.Provider;
|
|
7
|
+
export function useChart() {
|
|
8
|
+
const ctx = useContext(Ctx);
|
|
9
|
+
if (!ctx) {
|
|
10
|
+
throw new Error('Must be used inside <Chart>');
|
|
11
|
+
}
|
|
12
|
+
return ctx;
|
|
13
|
+
}
|