react-klinecharts-ui 1.0.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 +179 -0
- 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-JD4NBJ5F.js → chunk-RIT2LJQT.js} +4 -9
- package/dist/chunk-RIT2LJQT.js.map +1 -0
- package/dist/{chunk-LGYYJ2GP.cjs → chunk-SZDU2D3D.cjs} +5 -10
- package/dist/chunk-SZDU2D3D.cjs.map +1 -0
- package/dist/extensions.cjs +10 -9
- package/dist/extensions.js +2 -1
- package/dist/index.cjs +459 -211
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +233 -7
- package/dist/index.d.ts +233 -7
- package/dist/index.js +361 -132
- package/dist/index.js.map +1 -1
- package/package.json +19 -2
- package/dist/chunk-JD4NBJ5F.js.map +0 -1
- package/dist/chunk-LGYYJ2GP.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -69,6 +69,17 @@ pnpm add react-klinecharts-ui klinecharts
|
|
|
69
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
|
|
@@ -2084,4 +2259,8 @@ export type {
|
|
|
2084
2259
|
DepthOverlayExtendData,
|
|
2085
2260
|
DepthOverlayRow,
|
|
2086
2261
|
};
|
|
2262
|
+
|
|
2263
|
+
// Chart entry (optional — peer-depends on react-klinecharts).
|
|
2264
|
+
// import from "react-klinecharts-ui/chart"
|
|
2265
|
+
export { ChartCanvas, type ChartCanvasProps };
|
|
2087
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"]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
// src/provider/ChartTerminalContext.ts
|
|
4
|
+
var KlinechartsUIStateContext = createContext(null);
|
|
5
|
+
var KlinechartsUIDispatchContext = createContext(null);
|
|
6
|
+
function useKlinechartsUIDispatch() {
|
|
7
|
+
const ctx = useContext(KlinechartsUIDispatchContext);
|
|
8
|
+
if (!ctx) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
"useKlinechartsUI must be used within a <KlinechartsUIProvider>"
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
return ctx;
|
|
14
|
+
}
|
|
15
|
+
function useKlinechartsUI() {
|
|
16
|
+
const state = useContext(KlinechartsUIStateContext);
|
|
17
|
+
const dispatch = useContext(KlinechartsUIDispatchContext);
|
|
18
|
+
if (!state || !dispatch) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
"useKlinechartsUI must be used within a <KlinechartsUIProvider>"
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
return { state, ...dispatch };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/utils/createDataLoader.ts
|
|
27
|
+
function createDataLoader(datafeed, dispatch) {
|
|
28
|
+
let oldestTimestamp = null;
|
|
29
|
+
let currentGen = 0;
|
|
30
|
+
return {
|
|
31
|
+
getBars: async (params) => {
|
|
32
|
+
try {
|
|
33
|
+
dispatch({ type: "SET_LOADING", isLoading: true });
|
|
34
|
+
if (params.type === "init") {
|
|
35
|
+
oldestTimestamp = null;
|
|
36
|
+
const gen = ++currentGen;
|
|
37
|
+
const data = await datafeed.getHistoryKLineData(
|
|
38
|
+
params.symbol,
|
|
39
|
+
{ ...params.period, label: "" },
|
|
40
|
+
0,
|
|
41
|
+
Date.now()
|
|
42
|
+
);
|
|
43
|
+
if (gen !== currentGen) return;
|
|
44
|
+
if (data.length > 0) {
|
|
45
|
+
oldestTimestamp = data[0].timestamp;
|
|
46
|
+
}
|
|
47
|
+
params.callback(data, {
|
|
48
|
+
forward: data.length > 0,
|
|
49
|
+
backward: false
|
|
50
|
+
});
|
|
51
|
+
} else if (params.type === "forward" && oldestTimestamp !== null) {
|
|
52
|
+
const gen = currentGen;
|
|
53
|
+
const data = await datafeed.getHistoryKLineData(
|
|
54
|
+
params.symbol,
|
|
55
|
+
{ ...params.period, label: "" },
|
|
56
|
+
0,
|
|
57
|
+
oldestTimestamp - 1
|
|
58
|
+
);
|
|
59
|
+
if (gen !== currentGen) return;
|
|
60
|
+
if (data.length > 0) {
|
|
61
|
+
oldestTimestamp = data[0].timestamp;
|
|
62
|
+
}
|
|
63
|
+
params.callback(data, {
|
|
64
|
+
forward: data.length > 0,
|
|
65
|
+
backward: false
|
|
66
|
+
});
|
|
67
|
+
} else if (params.type === "backward") {
|
|
68
|
+
params.callback([], { forward: false, backward: false });
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error("Failed to load chart data:", error);
|
|
72
|
+
params.callback([], { forward: false, backward: false });
|
|
73
|
+
} finally {
|
|
74
|
+
dispatch({ type: "SET_LOADING", isLoading: false });
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
subscribeBar: (params) => {
|
|
78
|
+
datafeed.subscribe(
|
|
79
|
+
params.symbol,
|
|
80
|
+
{ ...params.period, label: "" },
|
|
81
|
+
(klineData) => params.callback(klineData)
|
|
82
|
+
);
|
|
83
|
+
},
|
|
84
|
+
unsubscribeBar: (params) => {
|
|
85
|
+
datafeed.unsubscribe(params.symbol, { ...params.period, label: "" });
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { KlinechartsUIDispatchContext, KlinechartsUIStateContext, createDataLoader, useKlinechartsUI, useKlinechartsUIDispatch };
|
|
91
|
+
//# sourceMappingURL=chunk-O7E57I66.js.map
|
|
92
|
+
//# sourceMappingURL=chunk-O7E57I66.js.map
|