@wick-charts/react 0.3.1 → 0.3.2
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/dist/index.cjs +2 -2
- package/dist/index.d.ts +267 -3
- package/dist/index.js +2366 -1841
- package/package.json +2 -2
- package/src/BarSeries.tsx +1 -0
- package/src/CandlestickSeries.tsx +2 -0
- package/src/ChartContainer.tsx +39 -6
- package/src/LineSeries.tsx +1 -0
- package/src/PieSeries.tsx +2 -0
- package/src/index.ts +9 -0
- package/src/ui/Navigator.tsx +84 -0
- package/src/ui/NumberFlow.tsx +5 -0
- package/src/ui/Sparkline.tsx +6 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wick-charts/react",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "High-performance canvas timeseries charts for React — candlestick, line, bar, pie. Tree-shakeable, zero runtime deps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"react-dom": ">=18.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@wick-charts/core": "^0.3.
|
|
52
|
+
"@wick-charts/core": "^0.3.2"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build": "vite build"
|
package/src/BarSeries.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { useChartInstance } from './context';
|
|
|
7
7
|
export interface BarSeriesProps {
|
|
8
8
|
/** Array of datasets — one per layer. A single-layer bar chart uses `[data]`. */
|
|
9
9
|
data: TimePoint[][];
|
|
10
|
+
/** Visual options override — colours per layer, bar-width ratio, stacking, entrance animation, smoothing. */
|
|
10
11
|
options?: Partial<BarSeriesOptions>;
|
|
11
12
|
/** Stable series ID — same value across remounts. */
|
|
12
13
|
id?: string;
|
|
@@ -12,7 +12,9 @@ import { useChartInstance } from './context';
|
|
|
12
12
|
const BULK_THRESHOLD = 20;
|
|
13
13
|
|
|
14
14
|
export interface CandlestickSeriesProps {
|
|
15
|
+
/** OHLC candles to render. Each element carries `time/open/high/low/close` and an optional `volume`. */
|
|
15
16
|
data: OHLCInput[];
|
|
17
|
+
/** Visual options override — colours, body width, entrance animation, smoothing. Merged onto theme defaults. */
|
|
16
18
|
options?: Partial<CandlestickSeriesOptions>;
|
|
17
19
|
/** Stable series ID — same value across remounts. */
|
|
18
20
|
id?: string;
|
package/src/ChartContainer.tsx
CHANGED
|
@@ -19,6 +19,7 @@ import { ChartContext } from './context';
|
|
|
19
19
|
import { ThemeProvider, useThemeOptional } from './ThemeContext';
|
|
20
20
|
import { InfoBar } from './ui/InfoBar';
|
|
21
21
|
import { Legend, type LegendProps } from './ui/Legend';
|
|
22
|
+
import { Navigator } from './ui/Navigator';
|
|
22
23
|
import { PieLegend, type PieLegendProps } from './ui/PieLegend';
|
|
23
24
|
import { Title } from './ui/Title';
|
|
24
25
|
|
|
@@ -31,14 +32,28 @@ export interface ChartContainerProps {
|
|
|
31
32
|
/** Grouped axis configuration (Y/X visibility, bounds, sizing). */
|
|
32
33
|
axis?: AxisConfig;
|
|
33
34
|
/**
|
|
34
|
-
* Viewport padding
|
|
35
|
-
*
|
|
36
|
-
*
|
|
35
|
+
* Viewport padding around the plot area. Applied on mount only — changing
|
|
36
|
+
* this prop after mount is ignored. Set every side to `0` for an
|
|
37
|
+
* edge-to-edge sparkline.
|
|
38
|
+
*
|
|
39
|
+
* @default `{ top: 20, bottom: 20, right: { intervals: 3 }, left: { intervals: 0 } }`
|
|
37
40
|
*/
|
|
38
41
|
padding?: {
|
|
42
|
+
/** Pixels of empty space above the plot area. Default `20`. */
|
|
39
43
|
top?: number;
|
|
44
|
+
/** Pixels of empty space below the plot area. Default `20`. */
|
|
40
45
|
bottom?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Empty space on the right edge. A `number` is pixels (e.g. `50`); an
|
|
48
|
+
* object pads by data intervals on the time axis (e.g. `{ intervals: 3 }`
|
|
49
|
+
* leaves room for three more bars/candles past the latest point). Default
|
|
50
|
+
* `{ intervals: 3 }`.
|
|
51
|
+
*/
|
|
41
52
|
right?: number | { intervals: number };
|
|
53
|
+
/**
|
|
54
|
+
* Empty space on the left edge. A `number` is pixels; an object pads by
|
|
55
|
+
* data intervals on the time axis. Default `{ intervals: 0 }`.
|
|
56
|
+
*/
|
|
42
57
|
left?: number | { intervals: number };
|
|
43
58
|
};
|
|
44
59
|
/** Show the chart background gradient. Defaults to true. */
|
|
@@ -46,7 +61,10 @@ export interface ChartContainerProps {
|
|
|
46
61
|
/** Enable zoom, pan, and crosshair interactions. Defaults to true. */
|
|
47
62
|
interactive?: boolean;
|
|
48
63
|
/** Background grid configuration. Default: `{ visible: true }`. */
|
|
49
|
-
grid?: {
|
|
64
|
+
grid?: {
|
|
65
|
+
/** Whether the background grid is rendered. Default: `true`. */
|
|
66
|
+
visible: boolean;
|
|
67
|
+
};
|
|
50
68
|
/**
|
|
51
69
|
* How `<Title>` and `<InfoBar>` are positioned relative to the canvas.
|
|
52
70
|
* - `'overlay'` (default): absolute overlays on top of the canvas — the grid
|
|
@@ -66,7 +84,9 @@ export interface ChartContainerProps {
|
|
|
66
84
|
* Only read at mount; changing this prop after the chart is created is ignored.
|
|
67
85
|
*/
|
|
68
86
|
perf?: PerfOption;
|
|
87
|
+
/** Inline style for the chart's outer wrapper element. */
|
|
69
88
|
style?: CSSProperties;
|
|
89
|
+
/** Extra class for the chart's outer wrapper element. */
|
|
70
90
|
className?: string;
|
|
71
91
|
}
|
|
72
92
|
|
|
@@ -88,12 +108,14 @@ export function siftContainerChildren(children: ReactNode): {
|
|
|
88
108
|
legendEl: ReactElement<LegendProps> | null;
|
|
89
109
|
pieLegendEl: ReactElement<PieLegendProps> | null;
|
|
90
110
|
tooltipLegendEl: ReactElement | null;
|
|
111
|
+
navigatorEl: ReactElement | null;
|
|
91
112
|
overlay: ReactNode[];
|
|
92
113
|
} {
|
|
93
114
|
let titleEl: ReactElement | null = null;
|
|
94
115
|
let legendEl: ReactElement<LegendProps> | null = null;
|
|
95
116
|
let pieLegendEl: ReactElement<PieLegendProps> | null = null;
|
|
96
117
|
let tooltipLegendEl: ReactElement | null = null;
|
|
118
|
+
let navigatorEl: ReactElement | null = null;
|
|
97
119
|
const overlay: ReactNode[] = [];
|
|
98
120
|
|
|
99
121
|
const visit = (child: ReactNode): void => {
|
|
@@ -127,12 +149,16 @@ export function siftContainerChildren(children: ReactNode): {
|
|
|
127
149
|
tooltipLegendEl = child;
|
|
128
150
|
return;
|
|
129
151
|
}
|
|
152
|
+
if (child.type === Navigator) {
|
|
153
|
+
navigatorEl = child;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
130
156
|
}
|
|
131
157
|
overlay.push(child);
|
|
132
158
|
};
|
|
133
159
|
|
|
134
160
|
Children.forEach(children, visit);
|
|
135
|
-
return { titleEl, legendEl, pieLegendEl, tooltipLegendEl, overlay };
|
|
161
|
+
return { titleEl, legendEl, pieLegendEl, tooltipLegendEl, navigatorEl, overlay };
|
|
136
162
|
}
|
|
137
163
|
|
|
138
164
|
/**
|
|
@@ -254,7 +280,7 @@ export function ChartContainer({
|
|
|
254
280
|
|
|
255
281
|
const chart = chartRef.current;
|
|
256
282
|
|
|
257
|
-
const { titleEl, legendEl, pieLegendEl, tooltipLegendEl, overlay } = siftContainerChildren(children);
|
|
283
|
+
const { titleEl, legendEl, pieLegendEl, tooltipLegendEl, navigatorEl, overlay } = siftContainerChildren(children);
|
|
258
284
|
const legendPosition = legendEl?.props.position ?? 'bottom';
|
|
259
285
|
const pieLegendPosition = pieLegendEl?.props.position ?? 'bottom';
|
|
260
286
|
// Either legend type can pull the layout into row-mode. `Legend` and
|
|
@@ -390,6 +416,12 @@ export function ChartContainer({
|
|
|
390
416
|
</ChartContext.Provider>
|
|
391
417
|
);
|
|
392
418
|
|
|
419
|
+
const hoistedNavigator = chart && navigatorEl && (
|
|
420
|
+
<ChartContext.Provider value={chart}>
|
|
421
|
+
<ThemeProvider value={resolvedTheme ?? chart.getTheme()}>{navigatorEl}</ThemeProvider>
|
|
422
|
+
</ChartContext.Provider>
|
|
423
|
+
);
|
|
424
|
+
|
|
393
425
|
return (
|
|
394
426
|
<div
|
|
395
427
|
className={className}
|
|
@@ -422,6 +454,7 @@ export function ChartContainer({
|
|
|
422
454
|
{hoistedLegend}
|
|
423
455
|
{hoistedPieLegend}
|
|
424
456
|
</div>
|
|
457
|
+
{hoistedNavigator}
|
|
425
458
|
</div>
|
|
426
459
|
);
|
|
427
460
|
}
|
package/src/LineSeries.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { useChartInstance } from './context';
|
|
|
7
7
|
export interface LineSeriesProps {
|
|
8
8
|
/** Array of datasets — one per layer. A single line uses `[data]`. */
|
|
9
9
|
data: TimePoint[][];
|
|
10
|
+
/** Visual options override — colours per layer, stroke width, area fill, stacking, entrance animation, smoothing. */
|
|
10
11
|
options?: Partial<LineSeriesOptions>;
|
|
11
12
|
/** Stable series ID — same value across remounts. */
|
|
12
13
|
id?: string;
|
package/src/PieSeries.tsx
CHANGED
|
@@ -5,7 +5,9 @@ import type { PieSeriesOptions, PieSliceData } from '@wick-charts/core';
|
|
|
5
5
|
import { useChartInstance } from './context';
|
|
6
6
|
|
|
7
7
|
export interface PieSeriesProps {
|
|
8
|
+
/** Slices to render. A flat array of `{ label, value, color? }` entries. */
|
|
8
9
|
data: PieSliceData[];
|
|
10
|
+
/** Visual options override — palette, donut hole, slice gap, label rendering, hover/entrance animations. */
|
|
9
11
|
options?: Partial<PieSeriesOptions>;
|
|
10
12
|
/** Stable series ID — same value across remounts. */
|
|
11
13
|
id?: string;
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,12 @@ export type {
|
|
|
26
26
|
/** @deprecated Use {@link TimePoint} instead. */
|
|
27
27
|
LineData,
|
|
28
28
|
LineSeriesOptions,
|
|
29
|
+
NavigatorCandlePoint,
|
|
30
|
+
NavigatorControllerParams,
|
|
31
|
+
NavigatorData,
|
|
32
|
+
NavigatorLinePoint,
|
|
33
|
+
NavigatorOptions,
|
|
34
|
+
NavigatorSeriesType,
|
|
29
35
|
OHLCData,
|
|
30
36
|
OHLCInput,
|
|
31
37
|
PieSeriesOptions,
|
|
@@ -53,6 +59,7 @@ export type {
|
|
|
53
59
|
} from '@wick-charts/core';
|
|
54
60
|
export {
|
|
55
61
|
ChartInstance,
|
|
62
|
+
NavigatorController,
|
|
56
63
|
andromeda,
|
|
57
64
|
autoGradient,
|
|
58
65
|
ayuMirage,
|
|
@@ -115,6 +122,8 @@ export { InfoBar } from './ui/InfoBar';
|
|
|
115
122
|
export type { LegendItemOverride, LegendProps } from './ui/Legend';
|
|
116
123
|
// Legend
|
|
117
124
|
export { Legend } from './ui/Legend';
|
|
125
|
+
export type { NavigatorProps } from './ui/Navigator';
|
|
126
|
+
export { Navigator } from './ui/Navigator';
|
|
118
127
|
export { NumberFlow } from './ui/NumberFlow';
|
|
119
128
|
export type { PieLegendMode, PieLegendPosition, PieLegendProps, PieLegendRenderContext } from './ui/PieLegend';
|
|
120
129
|
export { PieLegend } from './ui/PieLegend';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type CSSProperties, useEffect, useLayoutEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { NavigatorController, type NavigatorData } from '@wick-charts/core';
|
|
4
|
+
|
|
5
|
+
import { useChartInstance } from '../context';
|
|
6
|
+
import { useTheme } from '../ThemeContext';
|
|
7
|
+
|
|
8
|
+
export interface NavigatorProps {
|
|
9
|
+
/**
|
|
10
|
+
* Data to render in the miniature view. Shape:
|
|
11
|
+
* { type: 'line' | 'bar', points: { time, value }[] }
|
|
12
|
+
* { type: 'candlestick', points: { time, open, high, low, close }[] }
|
|
13
|
+
*
|
|
14
|
+
* Usually the same series you feed into the main chart.
|
|
15
|
+
*/
|
|
16
|
+
data: NavigatorData;
|
|
17
|
+
/** Strip height in CSS pixels. Defaults to `theme.navigator.height` (60). */
|
|
18
|
+
height?: number;
|
|
19
|
+
/** Style override for the outer wrapper div. */
|
|
20
|
+
style?: CSSProperties;
|
|
21
|
+
/** Extra class on the outer wrapper div. */
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Miniature navigator strip with a draggable window indicator for the main
|
|
27
|
+
* chart's visible range. Must be rendered as a child of `<ChartContainer>`
|
|
28
|
+
* so the chart instance is available via context.
|
|
29
|
+
*
|
|
30
|
+
* `ChartContainer` sifts this element out of its children and places it as a
|
|
31
|
+
* flex sibling below the canvas area — it does not render inline.
|
|
32
|
+
*/
|
|
33
|
+
export function Navigator({ data, height, style, className }: NavigatorProps) {
|
|
34
|
+
const chart = useChartInstance();
|
|
35
|
+
// Subscribe to theme via context so a `<ThemeProvider>` swap re-renders the
|
|
36
|
+
// strip with the new default height. Reading from `chart.getTheme()` would
|
|
37
|
+
// miss those updates because the chart instance reference is stable.
|
|
38
|
+
const theme = useTheme();
|
|
39
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
40
|
+
const controllerRef = useRef<NavigatorController | null>(null);
|
|
41
|
+
|
|
42
|
+
useLayoutEffect(() => {
|
|
43
|
+
if (!containerRef.current) return;
|
|
44
|
+
const controller = new NavigatorController({
|
|
45
|
+
container: containerRef.current,
|
|
46
|
+
chart,
|
|
47
|
+
data,
|
|
48
|
+
options: height !== undefined ? { height } : undefined,
|
|
49
|
+
});
|
|
50
|
+
controllerRef.current = controller;
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
controller.destroy();
|
|
54
|
+
controllerRef.current = null;
|
|
55
|
+
};
|
|
56
|
+
// Mount-only. Data/height changes are synced by the two effects below.
|
|
57
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
58
|
+
}, [chart]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
controllerRef.current?.setData(data);
|
|
62
|
+
}, [data]);
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
controllerRef.current?.setOptions(height !== undefined ? { height } : {});
|
|
66
|
+
}, [height]);
|
|
67
|
+
|
|
68
|
+
const resolvedHeight = height ?? theme.navigator.height;
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<div
|
|
72
|
+
ref={containerRef}
|
|
73
|
+
className={className}
|
|
74
|
+
data-chart-navigator=""
|
|
75
|
+
style={{
|
|
76
|
+
position: 'relative',
|
|
77
|
+
width: '100%',
|
|
78
|
+
height: resolvedHeight,
|
|
79
|
+
flexShrink: 0,
|
|
80
|
+
...style,
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
}
|
package/src/ui/NumberFlow.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type CSSProperties, useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
|
|
3
3
|
export interface NumberFlowProps {
|
|
4
|
+
/** Numeric value to display. Each digit that changes between renders animates with a vertical spin. */
|
|
4
5
|
value: number;
|
|
5
6
|
/**
|
|
6
7
|
* Value-to-string formatter. Defaults to the current locale's
|
|
@@ -12,9 +13,13 @@ export interface NumberFlowProps {
|
|
|
12
13
|
* from before this prop was a function.
|
|
13
14
|
*/
|
|
14
15
|
format?: ((value: number) => string) | Intl.NumberFormatOptions;
|
|
16
|
+
/** BCP 47 locale tag used by the default formatter. Defaults to `'en-US'`. */
|
|
15
17
|
locale?: string;
|
|
18
|
+
/** Per-digit spin animation duration in milliseconds. Defaults to `350`. */
|
|
16
19
|
spinDuration?: number;
|
|
20
|
+
/** Extra class on the root `<span>`. */
|
|
17
21
|
className?: string;
|
|
22
|
+
/** Inline style on the root `<span>`. Useful for `fontVariantNumeric: 'tabular-nums'`. */
|
|
18
23
|
style?: CSSProperties;
|
|
19
24
|
}
|
|
20
25
|
|
package/src/ui/Sparkline.tsx
CHANGED
|
@@ -10,7 +10,9 @@ export type SparklineVariant = 'line' | 'bar';
|
|
|
10
10
|
export type SparklineValuePosition = 'left' | 'right' | 'none';
|
|
11
11
|
|
|
12
12
|
export interface SparklineProps {
|
|
13
|
+
/** Data points plotted by the sparkline. A flat `TimePoint[]` — the sparkline only ever shows one tiny line/bar. */
|
|
13
14
|
data: TimePoint[];
|
|
15
|
+
/** Visual theme. Drives series colour, background gradient, and the change-direction colours used in the value block. */
|
|
14
16
|
theme: ChartTheme;
|
|
15
17
|
/** 'line' (default) or 'bar' */
|
|
16
18
|
variant?: SparklineVariant;
|
|
@@ -27,7 +29,10 @@ export interface SparklineProps {
|
|
|
27
29
|
/** Secondary color for negative bars */
|
|
28
30
|
negativeColor?: string;
|
|
29
31
|
/** Show area fill under line */
|
|
30
|
-
area?: {
|
|
32
|
+
area?: {
|
|
33
|
+
/** Whether the area fill is rendered under the sparkline. Defaults to `true`. */
|
|
34
|
+
visible: boolean;
|
|
35
|
+
};
|
|
31
36
|
/** @deprecated Use {@link area} instead. */
|
|
32
37
|
areaFill?: boolean;
|
|
33
38
|
/** Chart width (default: 140) */
|