react-klinecharts-ui 1.0.0 → 1.2.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 +233 -15
- 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 +550 -224
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +268 -7
- package/dist/index.d.ts +268 -7
- package/dist/index.js +451 -145
- 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/dist/index.js
CHANGED
|
@@ -1,31 +1,12 @@
|
|
|
1
|
-
import { registerExtensions, TA_default, ensureAlertLineRegistered } from './chunk-
|
|
2
|
-
export { TA_default as TA, abcd_default as abcd, alertLine_default as alertLine, anyWaves_default as anyWaves, arrow_default as arrow, bollTv_default as bollTv, brush_default as brush, cci_default as cci, circle_default as circle, depthOverlay_default as depthOverlay, eightWaves_default as eightWaves, elliottWave_default as elliottWave, fibRetracement_default as fibRetracement, fibonacciCircle_default as fibonacciCircle, fibonacciExtension_default as fibonacciExtension, fibonacciSegment_default as fibonacciSegment, fibonacciSpeedResistanceFan_default as fibonacciSpeedResistanceFan, fibonacciSpiral_default as fibonacciSpiral, fiveWaves_default as fiveWaves, gannBox_default as gannBox, gannFan_default as gannFan, hma_default as hma, ichimoku_default as ichimoku, indicators, longPosition_default as longPosition, maRibbon_default as maRibbon, macdTv_default as macdTv, measure_default as measure, orderLine_default as orderLine, overlays, parallelChannel_default as parallelChannel, parallelogram_default as parallelogram, pivotPoints_default as pivotPoints, ray_default as ray, rect_default as rect, registerExtensions, rsiTv_default as rsiTv, shortPosition_default as shortPosition, stochastic_default as stochastic, superTrend_default as superTrend, threeWaves_default as threeWaves, triangle_default as triangle, vwap_default as vwap, xabcd_default as xabcd } from './chunk-
|
|
3
|
-
import {
|
|
1
|
+
import { registerExtensions, TA_default, ensureAlertLineRegistered } from './chunk-RIT2LJQT.js';
|
|
2
|
+
export { TA_default as TA, abcd_default as abcd, alertLine_default as alertLine, anyWaves_default as anyWaves, arrow_default as arrow, bollTv_default as bollTv, brush_default as brush, cci_default as cci, circle_default as circle, depthOverlay_default as depthOverlay, eightWaves_default as eightWaves, elliottWave_default as elliottWave, fibRetracement_default as fibRetracement, fibonacciCircle_default as fibonacciCircle, fibonacciExtension_default as fibonacciExtension, fibonacciSegment_default as fibonacciSegment, fibonacciSpeedResistanceFan_default as fibonacciSpeedResistanceFan, fibonacciSpiral_default as fibonacciSpiral, fiveWaves_default as fiveWaves, gannBox_default as gannBox, gannFan_default as gannFan, hma_default as hma, ichimoku_default as ichimoku, indicators, longPosition_default as longPosition, maRibbon_default as maRibbon, macdTv_default as macdTv, measure_default as measure, orderLine_default as orderLine, overlays, parallelChannel_default as parallelChannel, parallelogram_default as parallelogram, pivotPoints_default as pivotPoints, ray_default as ray, rect_default as rect, registerExtensions, rsiTv_default as rsiTv, shortPosition_default as shortPosition, stochastic_default as stochastic, superTrend_default as superTrend, threeWaves_default as threeWaves, triangle_default as triangle, vwap_default as vwap, xabcd_default as xabcd } from './chunk-RIT2LJQT.js';
|
|
3
|
+
import { KlinechartsUIStateContext, KlinechartsUIDispatchContext, useKlinechartsUI, useKlinechartsUIDispatch } from './chunk-O7E57I66.js';
|
|
4
|
+
export { KlinechartsUIDispatchContext, KlinechartsUIStateContext, createDataLoader, useKlinechartsUI } from './chunk-O7E57I66.js';
|
|
5
|
+
import './chunk-PZ5AY32C.js';
|
|
6
|
+
import { createContext, useMemo, useReducer, useRef, useEffect, useCallback, useState, useId, useContext } from 'react';
|
|
4
7
|
import { registerOverlay, registerHotkey, getHotkey, getSupportedHotkeys, registerIndicator } from 'klinecharts';
|
|
5
8
|
import { jsx } from 'react/jsx-runtime';
|
|
6
9
|
|
|
7
|
-
var KlinechartsUIStateContext = createContext(null);
|
|
8
|
-
var KlinechartsUIDispatchContext = createContext(null);
|
|
9
|
-
function useKlinechartsUIDispatch() {
|
|
10
|
-
const ctx = useContext(KlinechartsUIDispatchContext);
|
|
11
|
-
if (!ctx) {
|
|
12
|
-
throw new Error(
|
|
13
|
-
"useKlinechartsUI must be used within a <KlinechartsUIProvider>"
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
return ctx;
|
|
17
|
-
}
|
|
18
|
-
function useKlinechartsUI() {
|
|
19
|
-
const state = useContext(KlinechartsUIStateContext);
|
|
20
|
-
const dispatch = useContext(KlinechartsUIDispatchContext);
|
|
21
|
-
if (!state || !dispatch) {
|
|
22
|
-
throw new Error(
|
|
23
|
-
"useKlinechartsUI must be used within a <KlinechartsUIProvider>"
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
return { state, ...dispatch };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
10
|
// src/data/periods.ts
|
|
30
11
|
var DEFAULT_PERIODS = [
|
|
31
12
|
{ span: 1, type: "minute", label: "1m" },
|
|
@@ -39,6 +20,50 @@ var DEFAULT_PERIODS = [
|
|
|
39
20
|
{ span: 1, type: "month", label: "M" },
|
|
40
21
|
{ span: 1, type: "year", label: "Y" }
|
|
41
22
|
];
|
|
23
|
+
|
|
24
|
+
// src/storage/types.ts
|
|
25
|
+
var DEFAULT_STORAGE_NAMESPACES = [
|
|
26
|
+
"alerts",
|
|
27
|
+
"settings",
|
|
28
|
+
"indicators"
|
|
29
|
+
];
|
|
30
|
+
var DEFAULT_STORAGE_KEY_PREFIX = "rkui:";
|
|
31
|
+
|
|
32
|
+
// src/storage/createDefaultStorage.ts
|
|
33
|
+
var NOOP_ADAPTER = {
|
|
34
|
+
getItem: () => null,
|
|
35
|
+
setItem: () => {
|
|
36
|
+
},
|
|
37
|
+
removeItem: () => {
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
function createDefaultStorage() {
|
|
41
|
+
if (typeof localStorage === "undefined") return NOOP_ADAPTER;
|
|
42
|
+
try {
|
|
43
|
+
const probe = localStorage.getItem("__rkui_probe__");
|
|
44
|
+
return probe === null ? localStorage : localStorage;
|
|
45
|
+
} catch {
|
|
46
|
+
return NOOP_ADAPTER;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function resolveStorage(options) {
|
|
50
|
+
const adapter = options?.adapter ?? createDefaultStorage();
|
|
51
|
+
const keyPrefix = options?.keyPrefix ?? DEFAULT_STORAGE_KEY_PREFIX;
|
|
52
|
+
const namespaces = new Set(
|
|
53
|
+
options?.namespaces ?? DEFAULT_STORAGE_NAMESPACES
|
|
54
|
+
);
|
|
55
|
+
return {
|
|
56
|
+
adapter,
|
|
57
|
+
namespaces,
|
|
58
|
+
keyPrefix,
|
|
59
|
+
key(namespace) {
|
|
60
|
+
return `${keyPrefix}${namespace}`;
|
|
61
|
+
},
|
|
62
|
+
persists(namespace) {
|
|
63
|
+
return namespaces.has(namespace);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
42
67
|
function reducer(state, action) {
|
|
43
68
|
switch (action.type) {
|
|
44
69
|
case "SET_CHART":
|
|
@@ -102,13 +127,16 @@ function KlinechartsUIProvider({
|
|
|
102
127
|
defaultPeriod,
|
|
103
128
|
defaultTheme = "light",
|
|
104
129
|
defaultTimezone = "Asia/Shanghai",
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
// NOTE: no destructuring default here — the init function must distinguish
|
|
131
|
+
// "consumer passed default*" (wins) from "use stored value" (hydrate).
|
|
132
|
+
defaultMainIndicators,
|
|
133
|
+
defaultSubIndicators,
|
|
107
134
|
defaultLocale = "en-US",
|
|
108
135
|
periods,
|
|
109
136
|
styles,
|
|
110
137
|
registerExtensions: shouldRegister = true,
|
|
111
138
|
overlays: extraOverlays,
|
|
139
|
+
storage: storageOptions,
|
|
112
140
|
children,
|
|
113
141
|
onStateChange,
|
|
114
142
|
onSymbolChange,
|
|
@@ -119,6 +147,11 @@ function KlinechartsUIProvider({
|
|
|
119
147
|
onSubIndicatorsChange,
|
|
120
148
|
onSettingsChange
|
|
121
149
|
}) {
|
|
150
|
+
const resolvedStorage = useMemo(
|
|
151
|
+
() => storageOptions ? resolveStorage(storageOptions) : null,
|
|
152
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
153
|
+
[]
|
|
154
|
+
);
|
|
122
155
|
const [state, dispatch] = useReducer(
|
|
123
156
|
reducer,
|
|
124
157
|
{
|
|
@@ -131,41 +164,61 @@ function KlinechartsUIProvider({
|
|
|
131
164
|
defaultSubIndicators,
|
|
132
165
|
defaultLocale,
|
|
133
166
|
periods,
|
|
134
|
-
styles
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
167
|
+
styles,
|
|
168
|
+
storage: resolvedStorage
|
|
169
|
+
},
|
|
170
|
+
(opts) => {
|
|
171
|
+
const s = opts.storage;
|
|
172
|
+
const read = (ns, fallback) => {
|
|
173
|
+
if (!s || !s.persists(ns)) return fallback;
|
|
174
|
+
try {
|
|
175
|
+
const raw = s.adapter.getItem(s.key(ns));
|
|
176
|
+
return raw ? JSON.parse(raw) : fallback;
|
|
177
|
+
} catch {
|
|
178
|
+
return fallback;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const storedIndicators = read("indicators", {});
|
|
182
|
+
return {
|
|
183
|
+
chart: null,
|
|
184
|
+
datafeed: opts.datafeed,
|
|
185
|
+
symbol: opts.defaultSymbol ?? null,
|
|
186
|
+
period: opts.defaultPeriod ?? (opts.periods ?? DEFAULT_PERIODS)[0],
|
|
187
|
+
theme: opts.defaultTheme ?? "light",
|
|
188
|
+
timezone: opts.defaultTimezone ?? "Asia/Shanghai",
|
|
189
|
+
isLoading: false,
|
|
190
|
+
locale: opts.defaultLocale ?? "en-US",
|
|
191
|
+
periods: opts.periods ?? DEFAULT_PERIODS,
|
|
192
|
+
// Persistence semantics: STORED values win over `default*` props —
|
|
193
|
+
// the user's saved configuration should survive reload even when the
|
|
194
|
+
// app passes defaults. Only when storage is empty/unconfigured do the
|
|
195
|
+
// `default*` props apply, falling back to the built-ins last.
|
|
196
|
+
// (Settings live in useKlinechartsUISettings useState and hydrate
|
|
197
|
+
// separately via the dispatch-context `storage`.)
|
|
198
|
+
mainIndicators: storedIndicators.main ?? opts.defaultMainIndicators ?? ["MA"],
|
|
199
|
+
subIndicators: storedIndicators.sub ?? (opts.defaultSubIndicators ? opts.defaultSubIndicators.reduce(
|
|
200
|
+
(acc, name) => ({ ...acc, [name]: "" }),
|
|
201
|
+
{}
|
|
202
|
+
) : { VOL: "" }),
|
|
203
|
+
indicatorAxes: storedIndicators.axes ?? {},
|
|
204
|
+
indicatorVisibility: storedIndicators.visibility ?? {},
|
|
205
|
+
alerts: read("alerts", []),
|
|
206
|
+
measure: { isActive: false, fromPoint: null, result: null },
|
|
207
|
+
replay: {
|
|
208
|
+
isReplaying: false,
|
|
209
|
+
isPaused: false,
|
|
210
|
+
speed: 1,
|
|
211
|
+
barIndex: 0,
|
|
212
|
+
totalBars: 0
|
|
213
|
+
},
|
|
214
|
+
styles: opts.styles,
|
|
215
|
+
screenshotUrl: null
|
|
216
|
+
};
|
|
217
|
+
}
|
|
165
218
|
);
|
|
166
219
|
const fullscreenContainerRef = useRef(null);
|
|
167
220
|
const undoRedoListenerRef = useRef(null);
|
|
168
|
-
const
|
|
221
|
+
const alertTriggeredListenersRef = useRef(/* @__PURE__ */ new Set());
|
|
169
222
|
const replayIntervalRef = useRef(null);
|
|
170
223
|
const replaySavedDataRef = useRef([]);
|
|
171
224
|
const replayIndexRef = useRef(0);
|
|
@@ -243,23 +296,53 @@ function KlinechartsUIProvider({
|
|
|
243
296
|
const chart = state.chart;
|
|
244
297
|
if (!chart || !hasAlerts) return;
|
|
245
298
|
alertPrevCloseRef.current = null;
|
|
299
|
+
const prevValueByAlert = /* @__PURE__ */ new Map();
|
|
246
300
|
const interval = setInterval(() => {
|
|
247
301
|
const dataList = chart.getDataList();
|
|
248
302
|
if (!dataList || dataList.length === 0) return;
|
|
249
|
-
const
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
303
|
+
const lastIdx = dataList.length - 1;
|
|
304
|
+
const indicatorCache = /* @__PURE__ */ new Map();
|
|
305
|
+
const readIndicatorValue = (indicatorId, figureKey) => {
|
|
306
|
+
const cacheKey = `${indicatorId}:${figureKey}`;
|
|
307
|
+
if (indicatorCache.has(cacheKey)) return indicatorCache.get(cacheKey);
|
|
308
|
+
let value = null;
|
|
309
|
+
try {
|
|
310
|
+
const indicators2 = chart.getIndicators({ id: indicatorId });
|
|
311
|
+
const ind = indicators2?.[0];
|
|
312
|
+
const result = ind?.result;
|
|
313
|
+
const last = Array.isArray(result) ? result[lastIdx] : null;
|
|
314
|
+
if (last && typeof last === "object") {
|
|
315
|
+
const v = last[figureKey];
|
|
316
|
+
value = typeof v === "number" ? v : null;
|
|
317
|
+
}
|
|
318
|
+
} catch {
|
|
319
|
+
value = null;
|
|
320
|
+
}
|
|
321
|
+
indicatorCache.set(cacheKey, value);
|
|
322
|
+
return value;
|
|
323
|
+
};
|
|
253
324
|
const alerts = stateRef.current.alerts;
|
|
254
325
|
const triggeredIds = [];
|
|
255
326
|
for (const alert of alerts) {
|
|
256
327
|
if (alert.triggered) continue;
|
|
257
|
-
const
|
|
258
|
-
|
|
328
|
+
const target = alert.target ?? { type: "price" };
|
|
329
|
+
let currentValue;
|
|
330
|
+
if (target.type === "indicator") {
|
|
331
|
+
currentValue = readIndicatorValue(target.indicatorId, target.figureKey);
|
|
332
|
+
} else {
|
|
333
|
+
currentValue = dataList[lastIdx].close;
|
|
334
|
+
}
|
|
335
|
+
if (currentValue === null || !Number.isFinite(currentValue)) continue;
|
|
336
|
+
const prevValue = prevValueByAlert.get(alert.id) ?? null;
|
|
337
|
+
prevValueByAlert.set(alert.id, currentValue);
|
|
338
|
+
if (prevValue === null) continue;
|
|
339
|
+
const crossedUp = prevValue < alert.price && currentValue >= alert.price;
|
|
340
|
+
const crossedDown = prevValue > alert.price && currentValue <= alert.price;
|
|
259
341
|
const shouldTrigger = alert.condition === "crossing_up" ? crossedUp : alert.condition === "crossing_down" ? crossedDown : crossedUp || crossedDown;
|
|
260
342
|
if (shouldTrigger) {
|
|
261
343
|
triggeredIds.push(alert.id);
|
|
262
|
-
|
|
344
|
+
const fired = { ...alert, triggered: true };
|
|
345
|
+
alertTriggeredListenersRef.current.forEach((cb) => cb(fired));
|
|
263
346
|
}
|
|
264
347
|
}
|
|
265
348
|
if (triggeredIds.length > 0) {
|
|
@@ -274,6 +357,36 @@ function KlinechartsUIProvider({
|
|
|
274
357
|
useEffect(() => {
|
|
275
358
|
alertPrevCloseRef.current = null;
|
|
276
359
|
}, [state.symbol, state.period]);
|
|
360
|
+
const writeNs = useCallback(
|
|
361
|
+
(ns, value) => {
|
|
362
|
+
if (!resolvedStorage || !resolvedStorage.persists(ns)) return;
|
|
363
|
+
try {
|
|
364
|
+
resolvedStorage.adapter.setItem(
|
|
365
|
+
resolvedStorage.key(ns),
|
|
366
|
+
JSON.stringify(value)
|
|
367
|
+
);
|
|
368
|
+
} catch {
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
[resolvedStorage]
|
|
372
|
+
);
|
|
373
|
+
useEffect(() => {
|
|
374
|
+
writeNs("alerts", state.alerts);
|
|
375
|
+
}, [state.alerts, writeNs]);
|
|
376
|
+
useEffect(() => {
|
|
377
|
+
writeNs("indicators", {
|
|
378
|
+
main: state.mainIndicators,
|
|
379
|
+
sub: state.subIndicators,
|
|
380
|
+
axes: state.indicatorAxes,
|
|
381
|
+
visibility: state.indicatorVisibility
|
|
382
|
+
});
|
|
383
|
+
}, [
|
|
384
|
+
state.mainIndicators,
|
|
385
|
+
state.subIndicators,
|
|
386
|
+
state.indicatorAxes,
|
|
387
|
+
state.indicatorVisibility,
|
|
388
|
+
writeNs
|
|
389
|
+
]);
|
|
277
390
|
useEffect(() => {
|
|
278
391
|
return () => {
|
|
279
392
|
if (replayIntervalRef.current !== null) {
|
|
@@ -289,13 +402,14 @@ function KlinechartsUIProvider({
|
|
|
289
402
|
onSettingsChange: onSettingsChangeRef.current,
|
|
290
403
|
fullscreenContainerRef,
|
|
291
404
|
undoRedoListenerRef,
|
|
292
|
-
|
|
405
|
+
alertTriggeredListenersRef,
|
|
293
406
|
replayIntervalRef,
|
|
294
407
|
replaySavedDataRef,
|
|
295
|
-
replayIndexRef
|
|
408
|
+
replayIndexRef,
|
|
409
|
+
storage: resolvedStorage
|
|
296
410
|
}),
|
|
297
411
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
298
|
-
[enhancedDispatch]
|
|
412
|
+
[enhancedDispatch, resolvedStorage]
|
|
299
413
|
);
|
|
300
414
|
return /* @__PURE__ */ jsx(KlinechartsUIStateContext.Provider, { value: state, children: /* @__PURE__ */ jsx(KlinechartsUIDispatchContext.Provider, { value: dispatchValue, children }) });
|
|
301
415
|
}
|
|
@@ -1244,6 +1358,25 @@ var DRAWING_CATEGORIES = [
|
|
|
1244
1358
|
|
|
1245
1359
|
// src/hooks/useDrawingTools.ts
|
|
1246
1360
|
var DRAWING_GROUP_ID = "drawing_tools";
|
|
1361
|
+
var DRAWING_NAME_TO_LOCALE_KEY = new Map(
|
|
1362
|
+
DRAWING_CATEGORIES.flatMap(
|
|
1363
|
+
(cat) => cat.tools.map((tool) => [tool.name, tool.localeKey])
|
|
1364
|
+
)
|
|
1365
|
+
);
|
|
1366
|
+
function drawingLabel(name) {
|
|
1367
|
+
return DRAWING_NAME_TO_LOCALE_KEY.get(name) ?? name;
|
|
1368
|
+
}
|
|
1369
|
+
function overlaysEqual(a, b) {
|
|
1370
|
+
if (a.length !== b.length) return false;
|
|
1371
|
+
for (let i = 0; i < a.length; i++) {
|
|
1372
|
+
const x = a[i];
|
|
1373
|
+
const y = b[i];
|
|
1374
|
+
if (x.id !== y.id || x.name !== y.name || x.paneId !== y.paneId || x.locked !== y.locked || x.visible !== y.visible) {
|
|
1375
|
+
return false;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
return true;
|
|
1379
|
+
}
|
|
1247
1380
|
function useDrawingTools() {
|
|
1248
1381
|
const { state } = useKlinechartsUI();
|
|
1249
1382
|
const { undoRedoListenerRef } = useKlinechartsUIDispatch();
|
|
@@ -1264,6 +1397,34 @@ function useDrawingTools() {
|
|
|
1264
1397
|
isVisibleRef.current = isVisible;
|
|
1265
1398
|
magnetModeRef.current = magnetMode;
|
|
1266
1399
|
});
|
|
1400
|
+
const [overlays2, setOverlays] = useState([]);
|
|
1401
|
+
const refreshOverlays = useCallback(() => {
|
|
1402
|
+
if (!state.chart) {
|
|
1403
|
+
setOverlays((prev) => prev.length === 0 ? prev : []);
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
const list = state.chart.getOverlays({ groupId: DRAWING_GROUP_ID });
|
|
1407
|
+
const next = list.map((o) => ({
|
|
1408
|
+
id: o.id,
|
|
1409
|
+
name: o.name,
|
|
1410
|
+
paneId: o.paneId,
|
|
1411
|
+
locked: !!o.lock,
|
|
1412
|
+
visible: o.visible !== false
|
|
1413
|
+
// klinecharts default = true
|
|
1414
|
+
}));
|
|
1415
|
+
setOverlays((prev) => overlaysEqual(prev, next) ? prev : next);
|
|
1416
|
+
}, [state.chart]);
|
|
1417
|
+
const refreshOverlaysRef = useRef(() => {
|
|
1418
|
+
});
|
|
1419
|
+
useEffect(() => {
|
|
1420
|
+
refreshOverlaysRef.current = refreshOverlays;
|
|
1421
|
+
});
|
|
1422
|
+
useEffect(() => {
|
|
1423
|
+
if (!state.chart) return;
|
|
1424
|
+
queueMicrotask(() => refreshOverlaysRef.current());
|
|
1425
|
+
const interval = setInterval(() => refreshOverlaysRef.current(), 1e3);
|
|
1426
|
+
return () => clearInterval(interval);
|
|
1427
|
+
}, [state.chart, refreshOverlays]);
|
|
1267
1428
|
const categories = useMemo(
|
|
1268
1429
|
() => DRAWING_CATEGORIES.map((cat) => ({
|
|
1269
1430
|
key: cat.key,
|
|
@@ -1299,6 +1460,7 @@ function useDrawingTools() {
|
|
|
1299
1460
|
}
|
|
1300
1461
|
}
|
|
1301
1462
|
});
|
|
1463
|
+
refreshOverlaysRef.current();
|
|
1302
1464
|
if (autoRetriggerRef.current && activeToolRef.current === name) {
|
|
1303
1465
|
requestAnimationFrame(() => {
|
|
1304
1466
|
createOverlayForToolRef.current(name);
|
|
@@ -1325,49 +1487,52 @@ function useDrawingTools() {
|
|
|
1325
1487
|
const setMagnetMode = useCallback(
|
|
1326
1488
|
(mode) => {
|
|
1327
1489
|
setMagnetModeState(mode);
|
|
1328
|
-
const
|
|
1329
|
-
if (
|
|
1490
|
+
const overlays3 = state.chart?.getOverlays({ groupId: DRAWING_GROUP_ID });
|
|
1491
|
+
if (overlays3) {
|
|
1330
1492
|
const overlayMode = mode === "strong" ? "strong_magnet" : mode === "weak" ? "weak_magnet" : "normal";
|
|
1331
|
-
|
|
1493
|
+
overlays3.forEach((overlay) => {
|
|
1332
1494
|
state.chart?.overrideOverlay({
|
|
1333
1495
|
id: overlay.id,
|
|
1334
1496
|
mode: overlayMode
|
|
1335
1497
|
});
|
|
1336
1498
|
});
|
|
1337
1499
|
}
|
|
1500
|
+
refreshOverlaysRef.current();
|
|
1338
1501
|
},
|
|
1339
1502
|
[state.chart]
|
|
1340
1503
|
);
|
|
1341
1504
|
const toggleLock = useCallback(() => {
|
|
1342
1505
|
const newLocked = !isLocked;
|
|
1343
1506
|
setIsLocked(newLocked);
|
|
1344
|
-
const
|
|
1345
|
-
if (
|
|
1346
|
-
|
|
1507
|
+
const overlays3 = state.chart?.getOverlays({ groupId: DRAWING_GROUP_ID });
|
|
1508
|
+
if (overlays3) {
|
|
1509
|
+
overlays3.forEach((overlay) => {
|
|
1347
1510
|
state.chart?.overrideOverlay({
|
|
1348
1511
|
id: overlay.id,
|
|
1349
1512
|
lock: newLocked
|
|
1350
1513
|
});
|
|
1351
1514
|
});
|
|
1352
1515
|
}
|
|
1516
|
+
refreshOverlaysRef.current();
|
|
1353
1517
|
}, [state.chart, isLocked]);
|
|
1354
1518
|
const toggleVisibility = useCallback(() => {
|
|
1355
1519
|
const newVisible = !isVisible;
|
|
1356
1520
|
setIsVisible(newVisible);
|
|
1357
|
-
const
|
|
1358
|
-
if (
|
|
1359
|
-
|
|
1521
|
+
const overlays3 = state.chart?.getOverlays({ groupId: DRAWING_GROUP_ID });
|
|
1522
|
+
if (overlays3) {
|
|
1523
|
+
overlays3.forEach((overlay) => {
|
|
1360
1524
|
state.chart?.overrideOverlay({
|
|
1361
1525
|
id: overlay.id,
|
|
1362
1526
|
visible: newVisible
|
|
1363
1527
|
});
|
|
1364
1528
|
});
|
|
1365
1529
|
}
|
|
1530
|
+
refreshOverlaysRef.current();
|
|
1366
1531
|
}, [state.chart, isVisible]);
|
|
1367
1532
|
const removeAllDrawings = useCallback(() => {
|
|
1368
|
-
const
|
|
1369
|
-
if (
|
|
1370
|
-
const snapshot =
|
|
1533
|
+
const overlays3 = state.chart?.getOverlays({ groupId: DRAWING_GROUP_ID });
|
|
1534
|
+
if (overlays3 && overlays3.length > 0) {
|
|
1535
|
+
const snapshot = overlays3.map((o) => ({
|
|
1371
1536
|
name: o.name,
|
|
1372
1537
|
id: o.id,
|
|
1373
1538
|
points: o.points,
|
|
@@ -1381,7 +1546,29 @@ function useDrawingTools() {
|
|
|
1381
1546
|
}
|
|
1382
1547
|
state.chart?.removeOverlay({ groupId: DRAWING_GROUP_ID });
|
|
1383
1548
|
setActiveTool(null);
|
|
1549
|
+
refreshOverlaysRef.current();
|
|
1384
1550
|
}, [state.chart, undoRedoListenerRef]);
|
|
1551
|
+
const removeDrawing = useCallback(
|
|
1552
|
+
(id) => {
|
|
1553
|
+
state.chart?.removeOverlay({ id, groupId: DRAWING_GROUP_ID });
|
|
1554
|
+
refreshOverlaysRef.current();
|
|
1555
|
+
},
|
|
1556
|
+
[state.chart]
|
|
1557
|
+
);
|
|
1558
|
+
const setDrawingVisible = useCallback(
|
|
1559
|
+
(id, visible) => {
|
|
1560
|
+
state.chart?.overrideOverlay({ id, visible });
|
|
1561
|
+
refreshOverlaysRef.current();
|
|
1562
|
+
},
|
|
1563
|
+
[state.chart]
|
|
1564
|
+
);
|
|
1565
|
+
const setDrawingLocked = useCallback(
|
|
1566
|
+
(id, locked) => {
|
|
1567
|
+
state.chart?.overrideOverlay({ id, lock: locked });
|
|
1568
|
+
refreshOverlaysRef.current();
|
|
1569
|
+
},
|
|
1570
|
+
[state.chart]
|
|
1571
|
+
);
|
|
1385
1572
|
return {
|
|
1386
1573
|
categories,
|
|
1387
1574
|
activeTool,
|
|
@@ -1389,13 +1576,17 @@ function useDrawingTools() {
|
|
|
1389
1576
|
isLocked,
|
|
1390
1577
|
isVisible,
|
|
1391
1578
|
autoRetrigger,
|
|
1579
|
+
overlays: overlays2,
|
|
1392
1580
|
selectTool,
|
|
1393
1581
|
clearActiveTool,
|
|
1394
1582
|
setMagnetMode,
|
|
1395
1583
|
toggleLock,
|
|
1396
1584
|
toggleVisibility,
|
|
1397
1585
|
removeAllDrawings,
|
|
1398
|
-
setAutoRetrigger
|
|
1586
|
+
setAutoRetrigger,
|
|
1587
|
+
removeDrawing,
|
|
1588
|
+
setDrawingVisible,
|
|
1589
|
+
setDrawingLocked
|
|
1399
1590
|
};
|
|
1400
1591
|
}
|
|
1401
1592
|
|
|
@@ -1437,7 +1628,17 @@ var defaultSettings = {
|
|
|
1437
1628
|
};
|
|
1438
1629
|
function useKlinechartsUISettings() {
|
|
1439
1630
|
const { state, onSettingsChange } = useKlinechartsUI();
|
|
1440
|
-
const
|
|
1631
|
+
const { storage } = useKlinechartsUIDispatch();
|
|
1632
|
+
const [settings, setSettings] = useState(() => {
|
|
1633
|
+
if (storage && storage.persists("settings")) {
|
|
1634
|
+
try {
|
|
1635
|
+
const raw = storage.adapter.getItem(storage.key("settings"));
|
|
1636
|
+
if (raw) return { ...defaultSettings, ...JSON.parse(raw) };
|
|
1637
|
+
} catch {
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
return defaultSettings;
|
|
1641
|
+
});
|
|
1441
1642
|
const isInitialMount = useRef(true);
|
|
1442
1643
|
useEffect(() => {
|
|
1443
1644
|
if (isInitialMount.current) {
|
|
@@ -1446,6 +1647,14 @@ function useKlinechartsUISettings() {
|
|
|
1446
1647
|
}
|
|
1447
1648
|
onSettingsChange?.({ ...settings });
|
|
1448
1649
|
}, [settings, onSettingsChange]);
|
|
1650
|
+
useEffect(() => {
|
|
1651
|
+
if (!storage || !storage.persists("settings")) return;
|
|
1652
|
+
if (isInitialMount.current) return;
|
|
1653
|
+
try {
|
|
1654
|
+
storage.adapter.setItem(storage.key("settings"), JSON.stringify(settings));
|
|
1655
|
+
} catch {
|
|
1656
|
+
}
|
|
1657
|
+
}, [settings, storage]);
|
|
1449
1658
|
const candleTypes = useMemo(
|
|
1450
1659
|
() => CANDLE_TYPES.map((ct) => ({
|
|
1451
1660
|
key: ct.key,
|
|
@@ -2788,10 +2997,10 @@ function useCrosshair() {
|
|
|
2788
2997
|
var alertCounter = 0;
|
|
2789
2998
|
function useAlerts() {
|
|
2790
2999
|
const { state, dispatch } = useKlinechartsUI();
|
|
2791
|
-
const {
|
|
3000
|
+
const { alertTriggeredListenersRef } = useKlinechartsUIDispatch();
|
|
2792
3001
|
const alerts = state.alerts;
|
|
2793
3002
|
const addAlert = useCallback(
|
|
2794
|
-
(price, condition, message, extendData) => {
|
|
3003
|
+
(price, condition, message, extendData, target) => {
|
|
2795
3004
|
const id = `alert_${++alertCounter}`;
|
|
2796
3005
|
const precision = state.chart?.getSymbol()?.pricePrecision ?? 2;
|
|
2797
3006
|
const resolvedExtendData = {
|
|
@@ -2804,7 +3013,10 @@ function useAlerts() {
|
|
|
2804
3013
|
condition,
|
|
2805
3014
|
message,
|
|
2806
3015
|
triggered: false,
|
|
2807
|
-
extendData: resolvedExtendData
|
|
3016
|
+
extendData: resolvedExtendData,
|
|
3017
|
+
// Persist the target only when it's an indicator alert; omit for the
|
|
3018
|
+
// default price target so existing serialized alerts stay compatible.
|
|
3019
|
+
...target && target.type === "indicator" ? { target } : {}
|
|
2808
3020
|
};
|
|
2809
3021
|
dispatch({ type: "ADD_ALERT", alert });
|
|
2810
3022
|
if (state.chart) {
|
|
@@ -2835,9 +3047,13 @@ function useAlerts() {
|
|
|
2835
3047
|
}, [state.chart, dispatch]);
|
|
2836
3048
|
const onAlertTriggered = useCallback(
|
|
2837
3049
|
(callback) => {
|
|
2838
|
-
|
|
3050
|
+
const set = alertTriggeredListenersRef.current;
|
|
3051
|
+
set.add(callback);
|
|
3052
|
+
return () => {
|
|
3053
|
+
set.delete(callback);
|
|
3054
|
+
};
|
|
2839
3055
|
},
|
|
2840
|
-
[
|
|
3056
|
+
[alertTriggeredListenersRef]
|
|
2841
3057
|
);
|
|
2842
3058
|
return {
|
|
2843
3059
|
alerts,
|
|
@@ -3441,71 +3657,161 @@ function useAnnotations() {
|
|
|
3441
3657
|
clearAnnotations
|
|
3442
3658
|
};
|
|
3443
3659
|
}
|
|
3660
|
+
var WorkspaceContext = createContext(null);
|
|
3661
|
+
function useWorkspace() {
|
|
3662
|
+
const ctx = useContext(WorkspaceContext);
|
|
3663
|
+
if (!ctx) {
|
|
3664
|
+
throw new Error("useWorkspace must be used within a <WorkspaceProvider>");
|
|
3665
|
+
}
|
|
3666
|
+
return ctx;
|
|
3667
|
+
}
|
|
3444
3668
|
|
|
3445
|
-
// src/
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3669
|
+
// src/workspace/types.ts
|
|
3670
|
+
var DEFAULT_SYNC_CONFIG = {
|
|
3671
|
+
crosshair: true,
|
|
3672
|
+
scroll: true,
|
|
3673
|
+
zoom: true,
|
|
3674
|
+
symbol: true,
|
|
3675
|
+
period: true
|
|
3676
|
+
};
|
|
3677
|
+
function reducer2(state, action) {
|
|
3678
|
+
switch (action.type) {
|
|
3679
|
+
case "SET_CELLS":
|
|
3680
|
+
return { ...state, cells: action.cells };
|
|
3681
|
+
case "ADD_CELL":
|
|
3682
|
+
return { ...state, cells: [...state.cells, action.cell] };
|
|
3683
|
+
case "REMOVE_CELL": {
|
|
3684
|
+
const cells = state.cells.filter((c) => c.id !== action.id);
|
|
3685
|
+
return {
|
|
3686
|
+
cells,
|
|
3687
|
+
activeCellId: state.activeCellId === action.id ? cells[0]?.id ?? null : state.activeCellId
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
case "SET_CELL_SYMBOL":
|
|
3691
|
+
return {
|
|
3692
|
+
...state,
|
|
3693
|
+
cells: state.cells.map(
|
|
3694
|
+
(c) => c.id === action.id ? { ...c, symbol: action.symbol } : c
|
|
3695
|
+
)
|
|
3696
|
+
};
|
|
3697
|
+
case "SET_CELL_PERIOD":
|
|
3698
|
+
return {
|
|
3699
|
+
...state,
|
|
3700
|
+
cells: state.cells.map(
|
|
3701
|
+
(c) => c.id === action.id ? { ...c, period: action.period } : c
|
|
3702
|
+
)
|
|
3703
|
+
};
|
|
3704
|
+
case "SET_ACTIVE_CELL":
|
|
3705
|
+
return { ...state, activeCellId: action.id };
|
|
3706
|
+
default:
|
|
3707
|
+
return state;
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
function WorkspaceProvider({
|
|
3711
|
+
defaultCells,
|
|
3712
|
+
sync,
|
|
3713
|
+
children
|
|
3714
|
+
}) {
|
|
3715
|
+
const [state, dispatch] = useReducer(reducer2, defaultCells, (cells) => ({
|
|
3716
|
+
cells,
|
|
3717
|
+
activeCellId: cells[0]?.id ?? null
|
|
3718
|
+
}));
|
|
3719
|
+
const chartsRef = useRef(/* @__PURE__ */ new Map());
|
|
3720
|
+
const broadcastingRef = useRef(false);
|
|
3721
|
+
const resolvedSync = useMemo(
|
|
3722
|
+
() => ({ ...DEFAULT_SYNC_CONFIG, ...sync }),
|
|
3723
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3724
|
+
[]
|
|
3725
|
+
);
|
|
3726
|
+
const value = useMemo(
|
|
3727
|
+
() => ({
|
|
3728
|
+
state,
|
|
3729
|
+
dispatch,
|
|
3730
|
+
chartsRef,
|
|
3731
|
+
broadcastingRef,
|
|
3732
|
+
sync: resolvedSync
|
|
3733
|
+
}),
|
|
3734
|
+
[state, resolvedSync]
|
|
3735
|
+
);
|
|
3736
|
+
return /* @__PURE__ */ jsx(WorkspaceContext.Provider, { value, children });
|
|
3737
|
+
}
|
|
3738
|
+
function useChartSync({ cellId }) {
|
|
3739
|
+
const { chartsRef, broadcastingRef, sync, dispatch: workspaceDispatch } = useWorkspace();
|
|
3740
|
+
const { state } = useKlinechartsUI();
|
|
3741
|
+
const chart = state.chart;
|
|
3742
|
+
useEffect(() => {
|
|
3743
|
+
if (!chart) return;
|
|
3744
|
+
chartsRef.current.set(cellId, chart);
|
|
3745
|
+
return () => {
|
|
3746
|
+
chartsRef.current.delete(cellId);
|
|
3747
|
+
};
|
|
3748
|
+
}, [chart, cellId, chartsRef]);
|
|
3749
|
+
useEffect(() => {
|
|
3750
|
+
if (!chart) return;
|
|
3751
|
+
const broadcast = (fn) => {
|
|
3752
|
+
if (broadcastingRef.current) return;
|
|
3753
|
+
broadcastingRef.current = true;
|
|
3451
3754
|
try {
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
{ ...params.period, label: "" },
|
|
3459
|
-
0,
|
|
3460
|
-
Date.now()
|
|
3461
|
-
);
|
|
3462
|
-
if (gen !== currentGen) return;
|
|
3463
|
-
if (data.length > 0) {
|
|
3464
|
-
oldestTimestamp = data[0].timestamp;
|
|
3465
|
-
}
|
|
3466
|
-
params.callback(data, {
|
|
3467
|
-
forward: data.length > 0,
|
|
3468
|
-
backward: false
|
|
3469
|
-
});
|
|
3470
|
-
} else if (params.type === "forward" && oldestTimestamp !== null) {
|
|
3471
|
-
const gen = currentGen;
|
|
3472
|
-
const data = await datafeed.getHistoryKLineData(
|
|
3473
|
-
params.symbol,
|
|
3474
|
-
{ ...params.period, label: "" },
|
|
3475
|
-
0,
|
|
3476
|
-
oldestTimestamp - 1
|
|
3477
|
-
);
|
|
3478
|
-
if (gen !== currentGen) return;
|
|
3479
|
-
if (data.length > 0) {
|
|
3480
|
-
oldestTimestamp = data[0].timestamp;
|
|
3755
|
+
chartsRef.current.forEach((target, id) => {
|
|
3756
|
+
if (id !== cellId) {
|
|
3757
|
+
try {
|
|
3758
|
+
fn(target);
|
|
3759
|
+
} catch {
|
|
3760
|
+
}
|
|
3481
3761
|
}
|
|
3482
|
-
|
|
3483
|
-
forward: data.length > 0,
|
|
3484
|
-
backward: false
|
|
3485
|
-
});
|
|
3486
|
-
} else if (params.type === "backward") {
|
|
3487
|
-
params.callback([], { forward: false, backward: false });
|
|
3488
|
-
}
|
|
3489
|
-
} catch (error) {
|
|
3490
|
-
console.error("Failed to load chart data:", error);
|
|
3491
|
-
params.callback([], { forward: false, backward: false });
|
|
3762
|
+
});
|
|
3492
3763
|
} finally {
|
|
3493
|
-
|
|
3764
|
+
broadcastingRef.current = false;
|
|
3494
3765
|
}
|
|
3495
|
-
}
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3766
|
+
};
|
|
3767
|
+
const onCrosshairChange = (data) => {
|
|
3768
|
+
if (!sync.crosshair) return;
|
|
3769
|
+
const crosshair = data;
|
|
3770
|
+
if (!crosshair) return;
|
|
3771
|
+
broadcast((target) => target.executeAction("onCrosshairChange", crosshair));
|
|
3772
|
+
};
|
|
3773
|
+
const onScroll = () => {
|
|
3774
|
+
if (!sync.scroll) return;
|
|
3775
|
+
let range = null;
|
|
3776
|
+
try {
|
|
3777
|
+
range = chart.getVisibleRange();
|
|
3778
|
+
} catch {
|
|
3779
|
+
return;
|
|
3780
|
+
}
|
|
3781
|
+
if (!range || range.realTo == null) return;
|
|
3782
|
+
broadcast(
|
|
3783
|
+
(target) => target.scrollToTimestamp(range.realTo, 0)
|
|
3501
3784
|
);
|
|
3502
|
-
}
|
|
3503
|
-
|
|
3504
|
-
|
|
3785
|
+
};
|
|
3786
|
+
const onZoom = () => {
|
|
3787
|
+
if (!sync.zoom) return;
|
|
3788
|
+
let bar = 0;
|
|
3789
|
+
try {
|
|
3790
|
+
bar = chart.getBarSpace().bar;
|
|
3791
|
+
} catch {
|
|
3792
|
+
return;
|
|
3793
|
+
}
|
|
3794
|
+
broadcast((target) => target.setBarSpace(bar));
|
|
3795
|
+
};
|
|
3796
|
+
chart.subscribeAction("onCrosshairChange", onCrosshairChange);
|
|
3797
|
+
chart.subscribeAction("onScroll", onScroll);
|
|
3798
|
+
chart.subscribeAction("onZoom", onZoom);
|
|
3799
|
+
return () => {
|
|
3800
|
+
chart.unsubscribeAction("onCrosshairChange", onCrosshairChange);
|
|
3801
|
+
chart.unsubscribeAction("onScroll", onScroll);
|
|
3802
|
+
chart.unsubscribeAction("onZoom", onZoom);
|
|
3803
|
+
};
|
|
3804
|
+
}, [chart, cellId, chartsRef, broadcastingRef, sync.crosshair, sync.scroll, sync.zoom]);
|
|
3805
|
+
useEffect(() => {
|
|
3806
|
+
if (state.symbol) {
|
|
3807
|
+
workspaceDispatch({ type: "SET_CELL_SYMBOL", id: cellId, symbol: state.symbol });
|
|
3505
3808
|
}
|
|
3506
|
-
};
|
|
3809
|
+
}, [state.symbol]);
|
|
3810
|
+
useEffect(() => {
|
|
3811
|
+
workspaceDispatch({ type: "SET_CELL_PERIOD", id: cellId, period: state.period });
|
|
3812
|
+
}, [state.period]);
|
|
3507
3813
|
}
|
|
3508
3814
|
|
|
3509
|
-
export { CANDLE_TYPES, COMPARE_RULES, DEFAULT_PERIODS,
|
|
3815
|
+
export { CANDLE_TYPES, COMPARE_RULES, DEFAULT_PERIODS, DEFAULT_STORAGE_KEY_PREFIX, DEFAULT_STORAGE_NAMESPACES, DEFAULT_SYNC_CONFIG, DRAWING_CATEGORIES, INDICATOR_PARAMS, KlinechartsUIProvider, MAIN_INDICATORS, PRICE_AXIS_TYPES, SUB_INDICATORS, TIMEZONES, TOOLTIP_SHOW_RULES, WorkspaceProvider, YAXIS_POSITIONS, createDefaultStorage, drawingLabel, resolveStorage, useAlerts, useAnnotations, useChartAxes, useChartSync, useCompare, useCrosshair, useDataExport, useDrawingTools, useFullscreen, useHotkeys, useIndicators, useKlinechartsUILoading, useKlinechartsUISettings, useKlinechartsUITheme, useLayoutManager, useMeasure, useOrderLines, usePeriods, useReplay, useScreenshot, useScriptEditor, useSymbolSearch, useTimezone, useUndoRedo, useWatchlist, useWorkspace };
|
|
3510
3816
|
//# sourceMappingURL=index.js.map
|
|
3511
3817
|
//# sourceMappingURL=index.js.map
|