react-klinecharts-ui 0.6.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +186 -6
- package/dist/chart.cjs +70 -0
- package/dist/chart.cjs.map +1 -0
- package/dist/chart.d.cts +45 -0
- package/dist/chart.d.ts +45 -0
- package/dist/chart.js +68 -0
- package/dist/chart.js.map +1 -0
- package/dist/chunk-F24D6PWY.cjs +98 -0
- package/dist/chunk-F24D6PWY.cjs.map +1 -0
- package/dist/chunk-O7E57I66.js +92 -0
- package/dist/chunk-O7E57I66.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +9 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-Q7SFCCGT.cjs +11 -0
- package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
- package/dist/{chunk-MVD3ILJT.js → chunk-RIT2LJQT.js} +35 -22
- package/dist/chunk-RIT2LJQT.js.map +1 -0
- package/dist/{chunk-FSHI2ZDB.cjs → chunk-SZDU2D3D.cjs} +46 -33
- package/dist/chunk-SZDU2D3D.cjs.map +1 -0
- package/dist/extensions.cjs +10 -9
- package/dist/extensions.d.cts +10 -7
- package/dist/extensions.d.ts +10 -7
- package/dist/extensions.js +2 -1
- package/dist/index.cjs +657 -323
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +246 -9
- package/dist/index.d.ts +246 -9
- package/dist/index.js +555 -240
- package/dist/index.js.map +1 -1
- package/package.json +31 -5
- package/dist/chunk-FSHI2ZDB.cjs.map +0 -1
- package/dist/chunk-MVD3ILJT.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**react-klinecharts-ui** is a headless React library for building financial trading terminals on top of [klinecharts](https://github.com/liihuu/KLineChart). It provides a state provider, a set of hooks, and overlay templates. No UI components are included — use any UI framework you prefer.
|
|
4
4
|
|
|
5
|
-
**[Live Demo](https://nemezzizz.github.io/react-klinecharts-ui/)**
|
|
5
|
+
**[Live Demo](https://nemezzizz.github.io/tradedash/)** · **[Examples](https://nemezzizz.github.io/react-klinecharts-ui/examples/)**
|
|
6
6
|
|
|
7
7
|
### Acknowledgments
|
|
8
8
|
|
|
@@ -62,13 +62,24 @@ Many features in this library — including 11 TradingView-style indicators, 9 d
|
|
|
62
62
|
## Installation
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
npm install react-klinecharts-ui
|
|
65
|
+
npm install react-klinecharts-ui klinecharts
|
|
66
66
|
# or with pnpm
|
|
67
|
-
pnpm add react-klinecharts-ui
|
|
67
|
+
pnpm add react-klinecharts-ui klinecharts
|
|
68
68
|
# or with yarn
|
|
69
|
-
yarn add react-klinecharts-ui
|
|
69
|
+
yarn add react-klinecharts-ui klinecharts
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
> **Rendering a chart?** `react-klinecharts-ui` is headless — it does not render
|
|
73
|
+
> the canvas itself. The fastest path is the optional `ChartCanvas` wrapper,
|
|
74
|
+
> which needs `react-klinecharts`:
|
|
75
|
+
>
|
|
76
|
+
> ```bash
|
|
77
|
+
> npm install react-klinecharts-ui klinecharts react-klinecharts
|
|
78
|
+
> ```
|
|
79
|
+
>
|
|
80
|
+
> You can also initialise the chart yourself with `klinecharts.init()` and skip
|
|
81
|
+
> `react-klinecharts` entirely — see [Renderer-agnostic](#renderer-agnostic).
|
|
82
|
+
|
|
72
83
|
---
|
|
73
84
|
|
|
74
85
|
## Concept
|
|
@@ -82,6 +93,170 @@ The library follows a **headless** pattern — all UI is written by the consumer
|
|
|
82
93
|
|
|
83
94
|
All hooks must be called inside `<KlinechartsUIProvider>`.
|
|
84
95
|
|
|
96
|
+
### Renderer-agnostic
|
|
97
|
+
|
|
98
|
+
`react-klinecharts-ui` is **headless** — it owns state (symbol, period, indicators, alerts, replay, …) and drives a klinecharts `Chart` instance, but it does **not** render the canvas. The only bridge between a renderer and the provider is a single dispatch:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
dispatch({ type: "SET_CHART", chart });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Once the chart instance is registered, every hook (`useIndicators`, `useAlerts`, `useReplay`, …) reads and mutates it via `state.chart.*`. You can initialise that instance **three ways**:
|
|
105
|
+
|
|
106
|
+
**1. `ChartCanvas` (fastest, optional peer `react-klinecharts`)** — the thin wrapper shipped at `react-klinecharts-ui/chart` wires the `<KLineChart>` renderer, builds the data loader, forwards symbol/period/theme from provider state, and dispatches `SET_CHART` for you:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import { KlinechartsUIProvider } from "react-klinecharts-ui";
|
|
110
|
+
import { ChartCanvas } from "react-klinecharts-ui/chart";
|
|
111
|
+
|
|
112
|
+
<KlinechartsUIProvider datafeed={datafeed} defaultSymbol={symbol} defaultTheme="dark">
|
|
113
|
+
<ChartCanvas className="h-[500px]" />
|
|
114
|
+
</KlinechartsUIProvider>;
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**2. `<KLineChart>` from `react-klinecharts` directly** — full control over props, at the cost of writing the `onReady` bridge yourself:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { useMemo } from "react";
|
|
121
|
+
import { KLineChart } from "react-klinecharts";
|
|
122
|
+
import { useKlinechartsUI, createDataLoader } from "react-klinecharts-ui";
|
|
123
|
+
|
|
124
|
+
function ChartView() {
|
|
125
|
+
const { state, dispatch, datafeed } = useKlinechartsUI();
|
|
126
|
+
const dataLoader = useMemo(() => createDataLoader(datafeed, dispatch), [datafeed, dispatch]);
|
|
127
|
+
return (
|
|
128
|
+
<KLineChart
|
|
129
|
+
dataLoader={dataLoader}
|
|
130
|
+
symbol={state.symbol ?? undefined}
|
|
131
|
+
period={state.period}
|
|
132
|
+
styles={state.theme}
|
|
133
|
+
onReady={(chart) => dispatch({ type: "SET_CHART", chart })}
|
|
134
|
+
/>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**3. Direct `klinecharts.init()` (no `react-klinecharts` at all)** — for custom lifecycles, SSR/Next.js, or when you want zero extra dependencies:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { useEffect, useRef } from "react";
|
|
143
|
+
import { init, dispose } from "klinecharts";
|
|
144
|
+
import { useKlinechartsUI } from "react-klinecharts-ui";
|
|
145
|
+
|
|
146
|
+
function ChartView() {
|
|
147
|
+
const { dispatch, datafeed } = useKlinechartsUI();
|
|
148
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
const chart = init(ref.current!);
|
|
151
|
+
dispatch({ type: "SET_CHART", chart }); // the bridge
|
|
152
|
+
chart!.applyNewData(/* load bars yourself */);
|
|
153
|
+
return () => dispose(ref.current!);
|
|
154
|
+
}, []);
|
|
155
|
+
return <div ref={ref} style={{ height: 500 }} />;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Whatever route you pick, the hooks work the same — they only care about the `Chart` instance in the store.
|
|
160
|
+
|
|
161
|
+
### Persistence
|
|
162
|
+
|
|
163
|
+
By default, user-facing state (alerts, chart settings, the active indicator
|
|
164
|
+
set) lives only in memory and is **lost on page reload**. Pass a `storage`
|
|
165
|
+
option to the provider to hydrate it on mount and write it back on every
|
|
166
|
+
change. The adapter mirrors the Web Storage API, so `localStorage` works out
|
|
167
|
+
of the box:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<KlinechartsUIProvider datafeed={datafeed} storage={{}}>
|
|
171
|
+
{/* alerts / settings / indicators now survive refresh */}
|
|
172
|
+
</KlinechartsUIProvider>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`storage={{}}` uses the defaults: `localStorage` adapter, the `alerts` /
|
|
176
|
+
`settings` / `indicators` namespaces, and a `"rkui:"` key prefix. You can
|
|
177
|
+
override any of them — e.g. plug in a remote or IndexedDB-backed adapter:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
import type { StorageAdapter } from "react-klinecharts-ui";
|
|
181
|
+
|
|
182
|
+
const remoteAdapter: StorageAdapter = {
|
|
183
|
+
getItem: (key) => mySyncCache.get(key) ?? null,
|
|
184
|
+
setItem: (key, value) => {
|
|
185
|
+
mySyncCache.set(key, value);
|
|
186
|
+
flushToServer(key, value); // async, fire-and-forget
|
|
187
|
+
},
|
|
188
|
+
removeItem: (key) => { mySyncCache.delete(key); deleteFromServer(key); },
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
<KlinechartsUIProvider datafeed={datafeed} storage={{ adapter: remoteAdapter }}>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Scope.** The adapter covers the reducer store today: `alerts`, `settings`
|
|
195
|
+
(`useKlinechartsUISettings`), and `indicators` (the active lists, pane ids,
|
|
196
|
+
axis bindings, and visibility). Per-hook `useState` values — script code
|
|
197
|
+
(`useScriptEditor`), compared symbols (`useCompare`), watchlist, annotations —
|
|
198
|
+
are not yet covered by the adapter and remain in memory. `useLayoutManager`
|
|
199
|
+
(named snapshot presets) is orthogonal: it serializes the whole chart
|
|
200
|
+
(indicators + drawings + meta) on demand to its own keys, independent of the
|
|
201
|
+
live `storage` adapter.
|
|
202
|
+
|
|
203
|
+
The adapter contract is **synchronous** (matching the Web Storage API). For
|
|
204
|
+
async backends, keep a synchronous in-memory cache and flush in the
|
|
205
|
+
background — the provider reads/writes through `getItem`/`setItem` only.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Workspace & multi-chart
|
|
210
|
+
|
|
211
|
+
`KlinechartsUIProvider` owns exactly one chart. To render a **grid** of charts
|
|
212
|
+
that share crosshair / scroll / zoom / symbol / period, wrap several providers
|
|
213
|
+
in a `WorkspaceProvider` and drop a `useChartSync` bridge inside each:
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import {
|
|
217
|
+
KlinechartsUIProvider,
|
|
218
|
+
WorkspaceProvider,
|
|
219
|
+
useChartSync,
|
|
220
|
+
useWorkspace,
|
|
221
|
+
} from "react-klinecharts-ui";
|
|
222
|
+
|
|
223
|
+
const cells = [
|
|
224
|
+
{ id: "a", symbol: { ticker: "BTCUSDT" }, period: { span: 1, type: "minute", label: "1m" } },
|
|
225
|
+
{ id: "b", symbol: { ticker: "ETHUSDT" }, period: { span: 1, type: "minute", label: "1m" } },
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
// Rendered inside each KlinechartsUIProvider — registers its chart with the
|
|
229
|
+
// workspace and mirrors viewport events to siblings.
|
|
230
|
+
function ChartSyncBridge({ cellId }: { cellId: string }) {
|
|
231
|
+
useChartSync({ cellId });
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
<WorkspaceProvider defaultCells={cells}>
|
|
236
|
+
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
|
|
237
|
+
{cells.map((c) => (
|
|
238
|
+
<KlinechartsUIProvider key={c.id} datafeed={datafeed} defaultSymbol={c.symbol} defaultPeriod={c.period}>
|
|
239
|
+
<ChartSyncBridge cellId={c.id} />
|
|
240
|
+
<ChartCanvas />
|
|
241
|
+
</KlinechartsUIProvider>
|
|
242
|
+
))}
|
|
243
|
+
</div>
|
|
244
|
+
</WorkspaceProvider>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
`useChartSync` mirrors crosshair / scroll / zoom between the registered charts
|
|
248
|
+
using only the **public** klinecharts API (`executeAction`, `scrollToTimestamp`,
|
|
249
|
+
`setBarSpace`) — no internal `_chartStore`. A re-entrancy guard prevents
|
|
250
|
+
feedback loops. Per-channel sync can be disabled via the `sync` prop
|
|
251
|
+
(`{ scroll: false }`).
|
|
252
|
+
|
|
253
|
+
> **Scope of this foundation.** Each cell keeps its own alerts, replay, and
|
|
254
|
+
> drawings (per-provider). Hoisting shared alerts/replay/drawings to the
|
|
255
|
+
> workspace level, plus tabbed layouts and server-persisted workspaces, is
|
|
256
|
+
> planned. Read the
|
|
257
|
+
> [multi-chart example](https://nemezzizz.github.io/react-klinecharts-ui/examples/multi-chart/)
|
|
258
|
+
> for a runnable 2×2 grid.
|
|
259
|
+
|
|
85
260
|
---
|
|
86
261
|
|
|
87
262
|
## KlinechartsUIProvider
|
|
@@ -1480,7 +1655,6 @@ import { TA } from "react-klinecharts-ui";
|
|
|
1480
1655
|
| `TA.atr` | `(highs: number[], lows: number[], closes: number[], period: number)` | `number[]` — Average True Range |
|
|
1481
1656
|
| `TA.vwap` | `(highs: number[], lows: number[], closes: number[], volumes: number[])` | `number[]` — Volume Weighted Average Price |
|
|
1482
1657
|
| `TA.cci` | `(highs: number[], lows: number[], closes: number[], period: number)` | `number[]` — Commodity Channel Index |
|
|
1483
|
-
| `TA.stoch` | `(highs: number[], lows: number[], closes: number[], kPeriod?, kSmooth?, dPeriod?)` | `{ k, d }` — each `(number \| null)[]` |
|
|
1484
1658
|
|
|
1485
1659
|
---
|
|
1486
1660
|
|
|
@@ -1692,7 +1866,9 @@ interface OrderLineExtendData {
|
|
|
1692
1866
|
}
|
|
1693
1867
|
|
|
1694
1868
|
interface OrderLineLineStyle {
|
|
1695
|
-
|
|
1869
|
+
// klinecharts only supports "solid" and "dashed"; a dotted effect is done
|
|
1870
|
+
// via `dashedValue` (e.g. [2, 2]).
|
|
1871
|
+
style?: "solid" | "dashed"; // Default: "dashed"
|
|
1696
1872
|
width?: number; // Default: 1
|
|
1697
1873
|
dashedValue?: [number, number]; // Default: [4, 2]
|
|
1698
1874
|
}
|
|
@@ -2083,4 +2259,8 @@ export type {
|
|
|
2083
2259
|
DepthOverlayExtendData,
|
|
2084
2260
|
DepthOverlayRow,
|
|
2085
2261
|
};
|
|
2262
|
+
|
|
2263
|
+
// Chart entry (optional — peer-depends on react-klinecharts).
|
|
2264
|
+
// import from "react-klinecharts-ui/chart"
|
|
2265
|
+
export { ChartCanvas, type ChartCanvasProps };
|
|
2086
2266
|
```
|
package/dist/chart.cjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkF24D6PWY_cjs = require('./chunk-F24D6PWY.cjs');
|
|
4
|
+
require('./chunk-Q7SFCCGT.cjs');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var reactKlinecharts = require('react-klinecharts');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
|
|
9
|
+
function ChartCanvas({
|
|
10
|
+
className,
|
|
11
|
+
children,
|
|
12
|
+
options,
|
|
13
|
+
styles
|
|
14
|
+
}) {
|
|
15
|
+
const { state, dispatch, datafeed } = chunkF24D6PWY_cjs.useKlinechartsUI();
|
|
16
|
+
const dataLoader = react.useMemo(
|
|
17
|
+
() => chunkF24D6PWY_cjs.createDataLoader(datafeed, dispatch),
|
|
18
|
+
[datafeed, dispatch]
|
|
19
|
+
);
|
|
20
|
+
const mainIndicatorsRef = react.useRef(state.mainIndicators);
|
|
21
|
+
const subIndicatorsRef = react.useRef(state.subIndicators);
|
|
22
|
+
react.useEffect(() => {
|
|
23
|
+
mainIndicatorsRef.current = state.mainIndicators;
|
|
24
|
+
subIndicatorsRef.current = state.subIndicators;
|
|
25
|
+
}, [state.mainIndicators, state.subIndicators]);
|
|
26
|
+
const handleReady = react.useCallback(
|
|
27
|
+
(chart) => {
|
|
28
|
+
dispatch({ type: "SET_CHART", chart });
|
|
29
|
+
mainIndicatorsRef.current.forEach((name) => {
|
|
30
|
+
chart.createIndicator(
|
|
31
|
+
{ name, id: `main_${name}` },
|
|
32
|
+
{ isStack: true, pane: { id: "candle_pane" } }
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
const subUpdates = {};
|
|
36
|
+
Object.keys(subIndicatorsRef.current).forEach((name) => {
|
|
37
|
+
const id = `sub_${name}`;
|
|
38
|
+
chart.createIndicator({ name, id });
|
|
39
|
+
const ind = chart.getIndicators({ id })[0];
|
|
40
|
+
if (ind?.paneId) subUpdates[name] = ind.paneId;
|
|
41
|
+
});
|
|
42
|
+
if (Object.keys(subUpdates).length > 0) {
|
|
43
|
+
dispatch({
|
|
44
|
+
type: "SET_SUB_INDICATORS",
|
|
45
|
+
indicators: { ...subIndicatorsRef.current, ...subUpdates }
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
[dispatch]
|
|
50
|
+
);
|
|
51
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
52
|
+
reactKlinecharts.KLineChart,
|
|
53
|
+
{
|
|
54
|
+
className,
|
|
55
|
+
options,
|
|
56
|
+
styles: styles ?? state.theme,
|
|
57
|
+
dataLoader,
|
|
58
|
+
symbol: state.symbol ?? void 0,
|
|
59
|
+
period: state.period,
|
|
60
|
+
locale: state.locale,
|
|
61
|
+
timezone: state.timezone,
|
|
62
|
+
onReady: handleReady,
|
|
63
|
+
children
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
exports.ChartCanvas = ChartCanvas;
|
|
69
|
+
//# sourceMappingURL=chart.cjs.map
|
|
70
|
+
//# sourceMappingURL=chart.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chart/ChartCanvas.tsx"],"names":["useKlinechartsUI","useMemo","createDataLoader","useRef","useEffect","useCallback","jsx","KLineChart"],"mappings":";;;;;;;;AAsDO,SAAS,WAAA,CAAY;AAAA,EAC1B,SAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAgC;AAC9B,EAAA,MAAM,EAAE,KAAA,EAAO,QAAA,EAAU,QAAA,KAAaA,kCAAA,EAAiB;AAEvD,EAAA,MAAM,UAAA,GAAaC,aAAA;AAAA,IACjB,MAAMC,kCAAA,CAAiB,QAAA,EAAU,QAAQ,CAAA;AAAA,IACzC,CAAC,UAAU,QAAQ;AAAA,GACrB;AAKA,EAAA,MAAM,iBAAA,GAAoBC,YAAA,CAAO,KAAA,CAAM,cAAc,CAAA;AACrD,EAAA,MAAM,gBAAA,GAAmBA,YAAA,CAAO,KAAA,CAAM,aAAa,CAAA;AACnD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,iBAAA,CAAkB,UAAU,KAAA,CAAM,cAAA;AAClC,IAAA,gBAAA,CAAiB,UAAU,KAAA,CAAM,aAAA;AAAA,EACnC,GAAG,CAAC,KAAA,CAAM,cAAA,EAAgB,KAAA,CAAM,aAAa,CAAC,CAAA;AAE9C,EAAA,MAAM,WAAA,GAAcC,iBAAA;AAAA,IAClB,CAAC,KAAA,KAAiB;AAEhB,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,CAAA;AAIrC,MAAA,iBAAA,CAAkB,OAAA,CAAQ,OAAA,CAAQ,CAAC,IAAA,KAAS;AAC1C,QAAA,KAAA,CAAM,eAAA;AAAA,UACJ,EAAE,IAAA,EAAM,EAAA,EAAI,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAA,EAAG;AAAA,UAC3B,EAAE,OAAA,EAAS,IAAA,EAAM,MAAM,EAAE,EAAA,EAAI,eAAc;AAAE,SAC/C;AAAA,MACF,CAAC,CAAA;AAED,MAAA,MAAM,aAAqC,EAAC;AAC5C,MAAA,MAAA,CAAO,KAAK,gBAAA,CAAiB,OAAO,CAAA,CAAE,OAAA,CAAQ,CAAC,IAAA,KAAS;AACtD,QAAA,MAAM,EAAA,GAAK,OAAO,IAAI,CAAA,CAAA;AACtB,QAAA,KAAA,CAAM,eAAA,CAAgB,EAAE,IAAA,EAAM,EAAA,EAAI,CAAA;AAClC,QAAA,MAAM,MAAM,KAAA,CAAM,aAAA,CAAc,EAAE,EAAA,EAAI,EAAE,CAAC,CAAA;AACzC,QAAA,IAAI,GAAA,EAAK,MAAA,EAAQ,UAAA,CAAW,IAAI,IAAI,GAAA,CAAI,MAAA;AAAA,MAC1C,CAAC,CAAA;AACD,MAAA,IAAI,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA,CAAE,SAAS,CAAA,EAAG;AACtC,QAAA,QAAA,CAAS;AAAA,UACP,IAAA,EAAM,oBAAA;AAAA,UACN,YAAY,EAAE,GAAG,gBAAA,CAAiB,OAAA,EAAS,GAAG,UAAA;AAAW,SAC1D,CAAA;AAAA,MACH;AAAA,IACF,CAAA;AAAA,IACA,CAAC,QAAQ;AAAA,GACX;AAEA,EAAA,uBACEC,cAAA;AAAA,IAACC,2BAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAA,EAAQ,UAAU,KAAA,CAAM,KAAA;AAAA,MACxB,UAAA;AAAA,MACA,MAAA,EAAQ,MAAM,MAAA,IAAU,MAAA;AAAA,MACxB,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,UAAU,KAAA,CAAM,QAAA;AAAA,MAChB,OAAA,EAAS,WAAA;AAAA,MAER;AAAA;AAAA,GACH;AAEJ","file":"chart.cjs","sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n type ReactNode,\n} from \"react\";\nimport { KLineChart } from \"react-klinecharts\";\nimport type { Chart, Options, DeepPartial, Styles } from \"klinecharts\";\nimport {\n useKlinechartsUI,\n} from \"../provider/ChartTerminalContext\";\nimport { createDataLoader } from \"../utils/createDataLoader\";\n\nexport interface ChartCanvasProps {\n /** className applied to the chart container div. */\n className?: string;\n /**\n * Optional children rendered inside `<KLineChart>` (use the `<Widget>`\n * component from `react-klinecharts` to portal React into chart DOM layers).\n */\n children?: ReactNode;\n /**\n * Chart initialization options, applied once on mount. Forwarded to\n * `<KLineChart>` as the `options` prop.\n */\n options?: Options;\n /**\n * Styles override applied on mount and whenever it changes. Forwarded to\n * `<KLineChart>` as the `styles` prop.\n */\n styles?: string | DeepPartial<Styles>;\n}\n\n/**\n * Thin renderer wrapper for `react-klinecharts-ui`.\n *\n * `react-klinecharts-ui` is **headless / renderer-agnostic**: it only needs a\n * klinecharts `Chart` instance to be registered via\n * `dispatch({ type: \"SET_CHART\", chart })`. This component wires the\n * `<KLineChart>` renderer from `react-klinecharts` to that bridge for you —\n * building the data loader, forwarding symbol/period/theme/locale/timezone\n * from provider state, bootstrapping the default indicators, and dispatching\n * `SET_CHART` on ready.\n *\n * It is the fastest path to a working chart. For full control (custom\n * lifecycle, a different renderer, or direct `klinecharts.init()`), render the\n * chart yourself and dispatch `SET_CHART` — see the README \"Renderer-agnostic\"\n * section.\n *\n * This entry point requires `react-klinecharts` as an optional peer\n * dependency. Install it explicitly when you import from\n * `react-klinecharts-ui/chart`.\n */\nexport function ChartCanvas({\n className,\n children,\n options,\n styles,\n}: ChartCanvasProps): ReactNode {\n const { state, dispatch, datafeed } = useKlinechartsUI();\n\n const dataLoader = useMemo(\n () => createDataLoader(datafeed, dispatch),\n [datafeed, dispatch],\n );\n\n // Keep the latest default indicator lists in refs so `handleReady` stays\n // stable (only depends on `dispatch`) yet reads current values when the\n // chart finishes initializing.\n const mainIndicatorsRef = useRef(state.mainIndicators);\n const subIndicatorsRef = useRef(state.subIndicators);\n useEffect(() => {\n mainIndicatorsRef.current = state.mainIndicators;\n subIndicatorsRef.current = state.subIndicators;\n }, [state.mainIndicators, state.subIndicators]);\n\n const handleReady = useCallback(\n (chart: Chart) => {\n // The bridge: register the chart instance so every hook can drive it.\n dispatch({ type: \"SET_CHART\", chart });\n\n // Bootstrap the provider's default indicators onto the fresh chart,\n // mirroring the canonical pattern in examples/ChartView.tsx.\n mainIndicatorsRef.current.forEach((name) => {\n chart.createIndicator(\n { name, id: `main_${name}` },\n { isStack: true, pane: { id: \"candle_pane\" } },\n );\n });\n\n const subUpdates: Record<string, string> = {};\n Object.keys(subIndicatorsRef.current).forEach((name) => {\n const id = `sub_${name}`;\n chart.createIndicator({ name, id });\n const ind = chart.getIndicators({ id })[0];\n if (ind?.paneId) subUpdates[name] = ind.paneId;\n });\n if (Object.keys(subUpdates).length > 0) {\n dispatch({\n type: \"SET_SUB_INDICATORS\",\n indicators: { ...subIndicatorsRef.current, ...subUpdates },\n });\n }\n },\n [dispatch],\n );\n\n return (\n <KLineChart\n className={className}\n options={options}\n styles={styles ?? state.theme}\n dataLoader={dataLoader}\n symbol={state.symbol ?? undefined}\n period={state.period}\n locale={state.locale}\n timezone={state.timezone}\n onReady={handleReady}\n >\n {children}\n </KLineChart>\n );\n}\n"]}
|
package/dist/chart.d.cts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { Options, DeepPartial, Styles } from 'klinecharts';
|
|
3
|
+
|
|
4
|
+
interface ChartCanvasProps {
|
|
5
|
+
/** className applied to the chart container div. */
|
|
6
|
+
className?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Optional children rendered inside `<KLineChart>` (use the `<Widget>`
|
|
9
|
+
* component from `react-klinecharts` to portal React into chart DOM layers).
|
|
10
|
+
*/
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Chart initialization options, applied once on mount. Forwarded to
|
|
14
|
+
* `<KLineChart>` as the `options` prop.
|
|
15
|
+
*/
|
|
16
|
+
options?: Options;
|
|
17
|
+
/**
|
|
18
|
+
* Styles override applied on mount and whenever it changes. Forwarded to
|
|
19
|
+
* `<KLineChart>` as the `styles` prop.
|
|
20
|
+
*/
|
|
21
|
+
styles?: string | DeepPartial<Styles>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Thin renderer wrapper for `react-klinecharts-ui`.
|
|
25
|
+
*
|
|
26
|
+
* `react-klinecharts-ui` is **headless / renderer-agnostic**: it only needs a
|
|
27
|
+
* klinecharts `Chart` instance to be registered via
|
|
28
|
+
* `dispatch({ type: "SET_CHART", chart })`. This component wires the
|
|
29
|
+
* `<KLineChart>` renderer from `react-klinecharts` to that bridge for you —
|
|
30
|
+
* building the data loader, forwarding symbol/period/theme/locale/timezone
|
|
31
|
+
* from provider state, bootstrapping the default indicators, and dispatching
|
|
32
|
+
* `SET_CHART` on ready.
|
|
33
|
+
*
|
|
34
|
+
* It is the fastest path to a working chart. For full control (custom
|
|
35
|
+
* lifecycle, a different renderer, or direct `klinecharts.init()`), render the
|
|
36
|
+
* chart yourself and dispatch `SET_CHART` — see the README "Renderer-agnostic"
|
|
37
|
+
* section.
|
|
38
|
+
*
|
|
39
|
+
* This entry point requires `react-klinecharts` as an optional peer
|
|
40
|
+
* dependency. Install it explicitly when you import from
|
|
41
|
+
* `react-klinecharts-ui/chart`.
|
|
42
|
+
*/
|
|
43
|
+
declare function ChartCanvas({ className, children, options, styles, }: ChartCanvasProps): ReactNode;
|
|
44
|
+
|
|
45
|
+
export { ChartCanvas, type ChartCanvasProps };
|
package/dist/chart.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { Options, DeepPartial, Styles } from 'klinecharts';
|
|
3
|
+
|
|
4
|
+
interface ChartCanvasProps {
|
|
5
|
+
/** className applied to the chart container div. */
|
|
6
|
+
className?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Optional children rendered inside `<KLineChart>` (use the `<Widget>`
|
|
9
|
+
* component from `react-klinecharts` to portal React into chart DOM layers).
|
|
10
|
+
*/
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Chart initialization options, applied once on mount. Forwarded to
|
|
14
|
+
* `<KLineChart>` as the `options` prop.
|
|
15
|
+
*/
|
|
16
|
+
options?: Options;
|
|
17
|
+
/**
|
|
18
|
+
* Styles override applied on mount and whenever it changes. Forwarded to
|
|
19
|
+
* `<KLineChart>` as the `styles` prop.
|
|
20
|
+
*/
|
|
21
|
+
styles?: string | DeepPartial<Styles>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Thin renderer wrapper for `react-klinecharts-ui`.
|
|
25
|
+
*
|
|
26
|
+
* `react-klinecharts-ui` is **headless / renderer-agnostic**: it only needs a
|
|
27
|
+
* klinecharts `Chart` instance to be registered via
|
|
28
|
+
* `dispatch({ type: "SET_CHART", chart })`. This component wires the
|
|
29
|
+
* `<KLineChart>` renderer from `react-klinecharts` to that bridge for you —
|
|
30
|
+
* building the data loader, forwarding symbol/period/theme/locale/timezone
|
|
31
|
+
* from provider state, bootstrapping the default indicators, and dispatching
|
|
32
|
+
* `SET_CHART` on ready.
|
|
33
|
+
*
|
|
34
|
+
* It is the fastest path to a working chart. For full control (custom
|
|
35
|
+
* lifecycle, a different renderer, or direct `klinecharts.init()`), render the
|
|
36
|
+
* chart yourself and dispatch `SET_CHART` — see the README "Renderer-agnostic"
|
|
37
|
+
* section.
|
|
38
|
+
*
|
|
39
|
+
* This entry point requires `react-klinecharts` as an optional peer
|
|
40
|
+
* dependency. Install it explicitly when you import from
|
|
41
|
+
* `react-klinecharts-ui/chart`.
|
|
42
|
+
*/
|
|
43
|
+
declare function ChartCanvas({ className, children, options, styles, }: ChartCanvasProps): ReactNode;
|
|
44
|
+
|
|
45
|
+
export { ChartCanvas, type ChartCanvasProps };
|
package/dist/chart.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useKlinechartsUI, createDataLoader } from './chunk-O7E57I66.js';
|
|
2
|
+
import './chunk-PZ5AY32C.js';
|
|
3
|
+
import { useMemo, useRef, useEffect, useCallback } from 'react';
|
|
4
|
+
import { KLineChart } from 'react-klinecharts';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function ChartCanvas({
|
|
8
|
+
className,
|
|
9
|
+
children,
|
|
10
|
+
options,
|
|
11
|
+
styles
|
|
12
|
+
}) {
|
|
13
|
+
const { state, dispatch, datafeed } = useKlinechartsUI();
|
|
14
|
+
const dataLoader = useMemo(
|
|
15
|
+
() => createDataLoader(datafeed, dispatch),
|
|
16
|
+
[datafeed, dispatch]
|
|
17
|
+
);
|
|
18
|
+
const mainIndicatorsRef = useRef(state.mainIndicators);
|
|
19
|
+
const subIndicatorsRef = useRef(state.subIndicators);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
mainIndicatorsRef.current = state.mainIndicators;
|
|
22
|
+
subIndicatorsRef.current = state.subIndicators;
|
|
23
|
+
}, [state.mainIndicators, state.subIndicators]);
|
|
24
|
+
const handleReady = useCallback(
|
|
25
|
+
(chart) => {
|
|
26
|
+
dispatch({ type: "SET_CHART", chart });
|
|
27
|
+
mainIndicatorsRef.current.forEach((name) => {
|
|
28
|
+
chart.createIndicator(
|
|
29
|
+
{ name, id: `main_${name}` },
|
|
30
|
+
{ isStack: true, pane: { id: "candle_pane" } }
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
const subUpdates = {};
|
|
34
|
+
Object.keys(subIndicatorsRef.current).forEach((name) => {
|
|
35
|
+
const id = `sub_${name}`;
|
|
36
|
+
chart.createIndicator({ name, id });
|
|
37
|
+
const ind = chart.getIndicators({ id })[0];
|
|
38
|
+
if (ind?.paneId) subUpdates[name] = ind.paneId;
|
|
39
|
+
});
|
|
40
|
+
if (Object.keys(subUpdates).length > 0) {
|
|
41
|
+
dispatch({
|
|
42
|
+
type: "SET_SUB_INDICATORS",
|
|
43
|
+
indicators: { ...subIndicatorsRef.current, ...subUpdates }
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
[dispatch]
|
|
48
|
+
);
|
|
49
|
+
return /* @__PURE__ */ jsx(
|
|
50
|
+
KLineChart,
|
|
51
|
+
{
|
|
52
|
+
className,
|
|
53
|
+
options,
|
|
54
|
+
styles: styles ?? state.theme,
|
|
55
|
+
dataLoader,
|
|
56
|
+
symbol: state.symbol ?? void 0,
|
|
57
|
+
period: state.period,
|
|
58
|
+
locale: state.locale,
|
|
59
|
+
timezone: state.timezone,
|
|
60
|
+
onReady: handleReady,
|
|
61
|
+
children
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { ChartCanvas };
|
|
67
|
+
//# sourceMappingURL=chart.js.map
|
|
68
|
+
//# sourceMappingURL=chart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chart/ChartCanvas.tsx"],"names":[],"mappings":";;;;;;AAsDO,SAAS,WAAA,CAAY;AAAA,EAC1B,SAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAgC;AAC9B,EAAA,MAAM,EAAE,KAAA,EAAO,QAAA,EAAU,QAAA,KAAa,gBAAA,EAAiB;AAEvD,EAAA,MAAM,UAAA,GAAa,OAAA;AAAA,IACjB,MAAM,gBAAA,CAAiB,QAAA,EAAU,QAAQ,CAAA;AAAA,IACzC,CAAC,UAAU,QAAQ;AAAA,GACrB;AAKA,EAAA,MAAM,iBAAA,GAAoB,MAAA,CAAO,KAAA,CAAM,cAAc,CAAA;AACrD,EAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,KAAA,CAAM,aAAa,CAAA;AACnD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,iBAAA,CAAkB,UAAU,KAAA,CAAM,cAAA;AAClC,IAAA,gBAAA,CAAiB,UAAU,KAAA,CAAM,aAAA;AAAA,EACnC,GAAG,CAAC,KAAA,CAAM,cAAA,EAAgB,KAAA,CAAM,aAAa,CAAC,CAAA;AAE9C,EAAA,MAAM,WAAA,GAAc,WAAA;AAAA,IAClB,CAAC,KAAA,KAAiB;AAEhB,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,CAAA;AAIrC,MAAA,iBAAA,CAAkB,OAAA,CAAQ,OAAA,CAAQ,CAAC,IAAA,KAAS;AAC1C,QAAA,KAAA,CAAM,eAAA;AAAA,UACJ,EAAE,IAAA,EAAM,EAAA,EAAI,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAA,EAAG;AAAA,UAC3B,EAAE,OAAA,EAAS,IAAA,EAAM,MAAM,EAAE,EAAA,EAAI,eAAc;AAAE,SAC/C;AAAA,MACF,CAAC,CAAA;AAED,MAAA,MAAM,aAAqC,EAAC;AAC5C,MAAA,MAAA,CAAO,KAAK,gBAAA,CAAiB,OAAO,CAAA,CAAE,OAAA,CAAQ,CAAC,IAAA,KAAS;AACtD,QAAA,MAAM,EAAA,GAAK,OAAO,IAAI,CAAA,CAAA;AACtB,QAAA,KAAA,CAAM,eAAA,CAAgB,EAAE,IAAA,EAAM,EAAA,EAAI,CAAA;AAClC,QAAA,MAAM,MAAM,KAAA,CAAM,aAAA,CAAc,EAAE,EAAA,EAAI,EAAE,CAAC,CAAA;AACzC,QAAA,IAAI,GAAA,EAAK,MAAA,EAAQ,UAAA,CAAW,IAAI,IAAI,GAAA,CAAI,MAAA;AAAA,MAC1C,CAAC,CAAA;AACD,MAAA,IAAI,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA,CAAE,SAAS,CAAA,EAAG;AACtC,QAAA,QAAA,CAAS;AAAA,UACP,IAAA,EAAM,oBAAA;AAAA,UACN,YAAY,EAAE,GAAG,gBAAA,CAAiB,OAAA,EAAS,GAAG,UAAA;AAAW,SAC1D,CAAA;AAAA,MACH;AAAA,IACF,CAAA;AAAA,IACA,CAAC,QAAQ;AAAA,GACX;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAA,EAAQ,UAAU,KAAA,CAAM,KAAA;AAAA,MACxB,UAAA;AAAA,MACA,MAAA,EAAQ,MAAM,MAAA,IAAU,MAAA;AAAA,MACxB,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,UAAU,KAAA,CAAM,QAAA;AAAA,MAChB,OAAA,EAAS,WAAA;AAAA,MAER;AAAA;AAAA,GACH;AAEJ","file":"chart.js","sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n type ReactNode,\n} from \"react\";\nimport { KLineChart } from \"react-klinecharts\";\nimport type { Chart, Options, DeepPartial, Styles } from \"klinecharts\";\nimport {\n useKlinechartsUI,\n} from \"../provider/ChartTerminalContext\";\nimport { createDataLoader } from \"../utils/createDataLoader\";\n\nexport interface ChartCanvasProps {\n /** className applied to the chart container div. */\n className?: string;\n /**\n * Optional children rendered inside `<KLineChart>` (use the `<Widget>`\n * component from `react-klinecharts` to portal React into chart DOM layers).\n */\n children?: ReactNode;\n /**\n * Chart initialization options, applied once on mount. Forwarded to\n * `<KLineChart>` as the `options` prop.\n */\n options?: Options;\n /**\n * Styles override applied on mount and whenever it changes. Forwarded to\n * `<KLineChart>` as the `styles` prop.\n */\n styles?: string | DeepPartial<Styles>;\n}\n\n/**\n * Thin renderer wrapper for `react-klinecharts-ui`.\n *\n * `react-klinecharts-ui` is **headless / renderer-agnostic**: it only needs a\n * klinecharts `Chart` instance to be registered via\n * `dispatch({ type: \"SET_CHART\", chart })`. This component wires the\n * `<KLineChart>` renderer from `react-klinecharts` to that bridge for you —\n * building the data loader, forwarding symbol/period/theme/locale/timezone\n * from provider state, bootstrapping the default indicators, and dispatching\n * `SET_CHART` on ready.\n *\n * It is the fastest path to a working chart. For full control (custom\n * lifecycle, a different renderer, or direct `klinecharts.init()`), render the\n * chart yourself and dispatch `SET_CHART` — see the README \"Renderer-agnostic\"\n * section.\n *\n * This entry point requires `react-klinecharts` as an optional peer\n * dependency. Install it explicitly when you import from\n * `react-klinecharts-ui/chart`.\n */\nexport function ChartCanvas({\n className,\n children,\n options,\n styles,\n}: ChartCanvasProps): ReactNode {\n const { state, dispatch, datafeed } = useKlinechartsUI();\n\n const dataLoader = useMemo(\n () => createDataLoader(datafeed, dispatch),\n [datafeed, dispatch],\n );\n\n // Keep the latest default indicator lists in refs so `handleReady` stays\n // stable (only depends on `dispatch`) yet reads current values when the\n // chart finishes initializing.\n const mainIndicatorsRef = useRef(state.mainIndicators);\n const subIndicatorsRef = useRef(state.subIndicators);\n useEffect(() => {\n mainIndicatorsRef.current = state.mainIndicators;\n subIndicatorsRef.current = state.subIndicators;\n }, [state.mainIndicators, state.subIndicators]);\n\n const handleReady = useCallback(\n (chart: Chart) => {\n // The bridge: register the chart instance so every hook can drive it.\n dispatch({ type: \"SET_CHART\", chart });\n\n // Bootstrap the provider's default indicators onto the fresh chart,\n // mirroring the canonical pattern in examples/ChartView.tsx.\n mainIndicatorsRef.current.forEach((name) => {\n chart.createIndicator(\n { name, id: `main_${name}` },\n { isStack: true, pane: { id: \"candle_pane\" } },\n );\n });\n\n const subUpdates: Record<string, string> = {};\n Object.keys(subIndicatorsRef.current).forEach((name) => {\n const id = `sub_${name}`;\n chart.createIndicator({ name, id });\n const ind = chart.getIndicators({ id })[0];\n if (ind?.paneId) subUpdates[name] = ind.paneId;\n });\n if (Object.keys(subUpdates).length > 0) {\n dispatch({\n type: \"SET_SUB_INDICATORS\",\n indicators: { ...subIndicatorsRef.current, ...subUpdates },\n });\n }\n },\n [dispatch],\n );\n\n return (\n <KLineChart\n className={className}\n options={options}\n styles={styles ?? state.theme}\n dataLoader={dataLoader}\n symbol={state.symbol ?? undefined}\n period={state.period}\n locale={state.locale}\n timezone={state.timezone}\n onReady={handleReady}\n >\n {children}\n </KLineChart>\n );\n}\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
// src/provider/ChartTerminalContext.ts
|
|
6
|
+
var KlinechartsUIStateContext = react.createContext(null);
|
|
7
|
+
var KlinechartsUIDispatchContext = react.createContext(null);
|
|
8
|
+
function useKlinechartsUIDispatch() {
|
|
9
|
+
const ctx = react.useContext(KlinechartsUIDispatchContext);
|
|
10
|
+
if (!ctx) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"useKlinechartsUI must be used within a <KlinechartsUIProvider>"
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return ctx;
|
|
16
|
+
}
|
|
17
|
+
function useKlinechartsUI() {
|
|
18
|
+
const state = react.useContext(KlinechartsUIStateContext);
|
|
19
|
+
const dispatch = react.useContext(KlinechartsUIDispatchContext);
|
|
20
|
+
if (!state || !dispatch) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
"useKlinechartsUI must be used within a <KlinechartsUIProvider>"
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
return { state, ...dispatch };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/utils/createDataLoader.ts
|
|
29
|
+
function createDataLoader(datafeed, dispatch) {
|
|
30
|
+
let oldestTimestamp = null;
|
|
31
|
+
let currentGen = 0;
|
|
32
|
+
return {
|
|
33
|
+
getBars: async (params) => {
|
|
34
|
+
try {
|
|
35
|
+
dispatch({ type: "SET_LOADING", isLoading: true });
|
|
36
|
+
if (params.type === "init") {
|
|
37
|
+
oldestTimestamp = null;
|
|
38
|
+
const gen = ++currentGen;
|
|
39
|
+
const data = await datafeed.getHistoryKLineData(
|
|
40
|
+
params.symbol,
|
|
41
|
+
{ ...params.period, label: "" },
|
|
42
|
+
0,
|
|
43
|
+
Date.now()
|
|
44
|
+
);
|
|
45
|
+
if (gen !== currentGen) return;
|
|
46
|
+
if (data.length > 0) {
|
|
47
|
+
oldestTimestamp = data[0].timestamp;
|
|
48
|
+
}
|
|
49
|
+
params.callback(data, {
|
|
50
|
+
forward: data.length > 0,
|
|
51
|
+
backward: false
|
|
52
|
+
});
|
|
53
|
+
} else if (params.type === "forward" && oldestTimestamp !== null) {
|
|
54
|
+
const gen = currentGen;
|
|
55
|
+
const data = await datafeed.getHistoryKLineData(
|
|
56
|
+
params.symbol,
|
|
57
|
+
{ ...params.period, label: "" },
|
|
58
|
+
0,
|
|
59
|
+
oldestTimestamp - 1
|
|
60
|
+
);
|
|
61
|
+
if (gen !== currentGen) return;
|
|
62
|
+
if (data.length > 0) {
|
|
63
|
+
oldestTimestamp = data[0].timestamp;
|
|
64
|
+
}
|
|
65
|
+
params.callback(data, {
|
|
66
|
+
forward: data.length > 0,
|
|
67
|
+
backward: false
|
|
68
|
+
});
|
|
69
|
+
} else if (params.type === "backward") {
|
|
70
|
+
params.callback([], { forward: false, backward: false });
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error("Failed to load chart data:", error);
|
|
74
|
+
params.callback([], { forward: false, backward: false });
|
|
75
|
+
} finally {
|
|
76
|
+
dispatch({ type: "SET_LOADING", isLoading: false });
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
subscribeBar: (params) => {
|
|
80
|
+
datafeed.subscribe(
|
|
81
|
+
params.symbol,
|
|
82
|
+
{ ...params.period, label: "" },
|
|
83
|
+
(klineData) => params.callback(klineData)
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
unsubscribeBar: (params) => {
|
|
87
|
+
datafeed.unsubscribe(params.symbol, { ...params.period, label: "" });
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
exports.KlinechartsUIDispatchContext = KlinechartsUIDispatchContext;
|
|
93
|
+
exports.KlinechartsUIStateContext = KlinechartsUIStateContext;
|
|
94
|
+
exports.createDataLoader = createDataLoader;
|
|
95
|
+
exports.useKlinechartsUI = useKlinechartsUI;
|
|
96
|
+
exports.useKlinechartsUIDispatch = useKlinechartsUIDispatch;
|
|
97
|
+
//# sourceMappingURL=chunk-F24D6PWY.cjs.map
|
|
98
|
+
//# sourceMappingURL=chunk-F24D6PWY.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/provider/ChartTerminalContext.ts","../src/utils/createDataLoader.ts"],"names":["createContext","useContext"],"mappings":"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","file":"chunk-F24D6PWY.cjs","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type {\n KlinechartsUIState,\n KlinechartsUIContextValue,\n KlinechartsUIDispatchValue,\n} from \"./types\";\n\nexport const KlinechartsUIStateContext =\n createContext<KlinechartsUIState | null>(null);\n\nexport const KlinechartsUIDispatchContext =\n createContext<KlinechartsUIDispatchValue | null>(null);\n\n/**\n * @internal\n * Reads only the stable dispatch slice. Hooks that use this won't re-render\n * when chart state changes (e.g. symbol, period, isLoading).\n */\nexport function useKlinechartsUIDispatch(): KlinechartsUIDispatchValue {\n const ctx = useContext(KlinechartsUIDispatchContext);\n if (!ctx) {\n throw new Error(\n \"useKlinechartsUI must be used within a <KlinechartsUIProvider>\"\n );\n }\n return ctx;\n}\n\n/**\n * Primary hook — returns the full combined context value.\n * For performance-sensitive cases, prefer the two split hooks internally.\n */\nexport function useKlinechartsUI(): KlinechartsUIContextValue {\n const state = useContext(KlinechartsUIStateContext);\n const dispatch = useContext(KlinechartsUIDispatchContext);\n if (!state || !dispatch) {\n throw new Error(\n \"useKlinechartsUI must be used within a <KlinechartsUIProvider>\"\n );\n }\n return { state, ...dispatch };\n}\n","import type { Dispatch } from \"react\";\nimport type { DataLoader, KLineData } from \"klinecharts\";\nimport type { Datafeed, KlinechartsUIAction } from \"../provider/types\";\n\n/**\n * Creates a klinecharts DataLoader from a Datafeed instance.\n * This bridges the react-klinecharts-ui Datafeed interface to the\n * klinecharts native DataLoader format used by KLineChart component.\n *\n * In klinecharts terminology:\n * - \"init\" = initial data load\n * - \"forward\" = load older data (user scrolled left into history)\n * - \"backward\" = load newer data (user scrolled right)\n */\nexport function createDataLoader(\n datafeed: Datafeed,\n dispatch: Dispatch<KlinechartsUIAction>,\n): DataLoader {\n let oldestTimestamp: number | null = null;\n // Incremented on every \"init\" request. Forward requests capture the value at\n // their start and bail out if a newer init has begun while they were in-flight.\n let currentGen = 0;\n\n return {\n getBars: async (params) => {\n try {\n dispatch({ type: \"SET_LOADING\", isLoading: true });\n\n if (params.type === \"init\") {\n oldestTimestamp = null;\n const gen = ++currentGen;\n const data = await datafeed.getHistoryKLineData(\n params.symbol,\n { ...params.period, label: \"\" },\n 0,\n Date.now(),\n );\n if (gen !== currentGen) return; // newer init started — discard stale result\n if (data.length > 0) {\n oldestTimestamp = data[0].timestamp;\n }\n params.callback(data as KLineData[], {\n forward: data.length > 0,\n backward: false,\n });\n } else if (params.type === \"forward\" && oldestTimestamp !== null) {\n const gen = currentGen;\n const data = await datafeed.getHistoryKLineData(\n params.symbol,\n { ...params.period, label: \"\" },\n 0,\n oldestTimestamp - 1,\n );\n if (gen !== currentGen) return; // init for new period started — discard\n if (data.length > 0) {\n oldestTimestamp = data[0].timestamp;\n }\n params.callback(data as KLineData[], {\n forward: data.length > 0,\n backward: false,\n });\n } else if (params.type === \"backward\") {\n // Backward pagination (loading data newer than what we have) is generally\n // not needed in typical terminal usage because we subscribe via ws for real-time.\n params.callback([], { forward: false, backward: false });\n }\n } catch (error) {\n console.error(\"Failed to load chart data:\", error);\n params.callback([], { forward: false, backward: false });\n } finally {\n dispatch({ type: \"SET_LOADING\", isLoading: false });\n }\n },\n subscribeBar: (params) => {\n datafeed.subscribe(\n params.symbol,\n { ...params.period, label: \"\" },\n (klineData) => params.callback(klineData as KLineData),\n );\n },\n unsubscribeBar: (params) => {\n datafeed.unsubscribe(params.symbol, { ...params.period, label: \"\" });\n },\n };\n}\n"]}
|