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/dist/index.cjs CHANGED
@@ -1,32 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var chunkFSHI2ZDB_cjs = require('./chunk-FSHI2ZDB.cjs');
3
+ var chunkSZDU2D3D_cjs = require('./chunk-SZDU2D3D.cjs');
4
+ var chunkF24D6PWY_cjs = require('./chunk-F24D6PWY.cjs');
5
+ require('./chunk-Q7SFCCGT.cjs');
4
6
  var react = require('react');
5
- var reactKlinecharts = require('react-klinecharts');
7
+ var klinecharts = require('klinecharts');
6
8
  var jsxRuntime = require('react/jsx-runtime');
7
9
 
8
- var KlinechartsUIStateContext = react.createContext(null);
9
- var KlinechartsUIDispatchContext = react.createContext(null);
10
- function useKlinechartsUIDispatch() {
11
- const ctx = react.useContext(KlinechartsUIDispatchContext);
12
- if (!ctx) {
13
- throw new Error(
14
- "useKlinechartsUI must be used within a <KlinechartsUIProvider>"
15
- );
16
- }
17
- return ctx;
18
- }
19
- function useKlinechartsUI() {
20
- const state = react.useContext(KlinechartsUIStateContext);
21
- const dispatch = react.useContext(KlinechartsUIDispatchContext);
22
- if (!state || !dispatch) {
23
- throw new Error(
24
- "useKlinechartsUI must be used within a <KlinechartsUIProvider>"
25
- );
26
- }
27
- return { state, ...dispatch };
28
- }
29
-
30
10
  // src/data/periods.ts
31
11
  var DEFAULT_PERIODS = [
32
12
  { span: 1, type: "minute", label: "1m" },
@@ -40,6 +20,50 @@ var DEFAULT_PERIODS = [
40
20
  { span: 1, type: "month", label: "M" },
41
21
  { span: 1, type: "year", label: "Y" }
42
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
+ }
43
67
  function reducer(state, action) {
44
68
  switch (action.type) {
45
69
  case "SET_CHART":
@@ -64,6 +88,25 @@ function reducer(state, action) {
64
88
  return { ...state, indicatorVisibility: action.visibility };
65
89
  case "SET_ALERTS":
66
90
  return { ...state, alerts: action.alerts };
91
+ case "ADD_ALERT":
92
+ return { ...state, alerts: [...state.alerts, action.alert] };
93
+ case "REMOVE_ALERT":
94
+ return {
95
+ ...state,
96
+ alerts: state.alerts.filter((a) => a.id !== action.id)
97
+ };
98
+ case "CLEAR_ALERTS":
99
+ return { ...state, alerts: [] };
100
+ case "MARK_ALERT_TRIGGERED": {
101
+ if (action.ids.length === 0) return state;
102
+ const triggered = new Set(action.ids);
103
+ return {
104
+ ...state,
105
+ alerts: state.alerts.map(
106
+ (a) => triggered.has(a.id) ? { ...a, triggered: true } : a
107
+ )
108
+ };
109
+ }
67
110
  case "SET_MEASURE":
68
111
  return { ...state, measure: { ...state.measure, ...action.measure } };
69
112
  case "SET_REPLAY":
@@ -84,13 +127,16 @@ function KlinechartsUIProvider({
84
127
  defaultPeriod,
85
128
  defaultTheme = "light",
86
129
  defaultTimezone = "Asia/Shanghai",
87
- defaultMainIndicators = ["MA"],
88
- defaultSubIndicators = ["VOL"],
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,
89
134
  defaultLocale = "en-US",
90
135
  periods,
91
136
  styles,
92
137
  registerExtensions: shouldRegister = true,
93
138
  overlays: extraOverlays,
139
+ storage: storageOptions,
94
140
  children,
95
141
  onStateChange,
96
142
  onSymbolChange,
@@ -101,6 +147,11 @@ function KlinechartsUIProvider({
101
147
  onSubIndicatorsChange,
102
148
  onSettingsChange
103
149
  }) {
150
+ const resolvedStorage = react.useMemo(
151
+ () => storageOptions ? resolveStorage(storageOptions) : null,
152
+ // eslint-disable-next-line react-hooks/exhaustive-deps
153
+ []
154
+ );
104
155
  const [state, dispatch] = react.useReducer(
105
156
  reducer,
106
157
  {
@@ -113,47 +164,66 @@ function KlinechartsUIProvider({
113
164
  defaultSubIndicators,
114
165
  defaultLocale,
115
166
  periods,
116
- styles
117
- },
118
- (opts) => ({
119
- chart: null,
120
- datafeed: opts.datafeed,
121
- symbol: opts.defaultSymbol ?? null,
122
- period: opts.defaultPeriod ?? (opts.periods ?? DEFAULT_PERIODS)[0],
123
- theme: opts.defaultTheme ?? "light",
124
- timezone: opts.defaultTimezone ?? "Asia/Shanghai",
125
- isLoading: false,
126
- locale: opts.defaultLocale ?? "en-US",
127
- periods: opts.periods ?? DEFAULT_PERIODS,
128
- mainIndicators: opts.defaultMainIndicators ?? ["MA"],
129
- subIndicators: (opts.defaultSubIndicators ?? ["VOL"]).reduce(
130
- (acc, name) => ({ ...acc, [name]: "" }),
131
- {}
132
- ),
133
- indicatorAxes: {},
134
- indicatorVisibility: {},
135
- alerts: [],
136
- measure: { isActive: false, fromPoint: null, result: null },
137
- replay: {
138
- isReplaying: false,
139
- isPaused: false,
140
- speed: 1,
141
- barIndex: 0,
142
- totalBars: 0
143
- },
144
- styles: opts.styles,
145
- screenshotUrl: null
146
- })
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
+ }
147
218
  );
148
219
  const fullscreenContainerRef = react.useRef(null);
149
220
  const undoRedoListenerRef = react.useRef(null);
150
- const alertTriggeredListenerRef = react.useRef(null);
221
+ const alertTriggeredListenersRef = react.useRef(/* @__PURE__ */ new Set());
151
222
  const replayIntervalRef = react.useRef(null);
152
223
  const replaySavedDataRef = react.useRef([]);
153
224
  const replayIndexRef = react.useRef(0);
154
225
  const alertPrevCloseRef = react.useRef(null);
155
226
  const stateRef = react.useRef(state);
156
- stateRef.current = state;
157
227
  const callbacksRef = react.useRef({
158
228
  onStateChange,
159
229
  onSymbolChange,
@@ -163,15 +233,18 @@ function KlinechartsUIProvider({
163
233
  onMainIndicatorsChange,
164
234
  onSubIndicatorsChange
165
235
  });
166
- callbacksRef.current = {
167
- onStateChange,
168
- onSymbolChange,
169
- onPeriodChange,
170
- onThemeChange,
171
- onTimezoneChange,
172
- onMainIndicatorsChange,
173
- onSubIndicatorsChange
174
- };
236
+ react.useEffect(() => {
237
+ stateRef.current = state;
238
+ callbacksRef.current = {
239
+ onStateChange,
240
+ onSymbolChange,
241
+ onPeriodChange,
242
+ onThemeChange,
243
+ onTimezoneChange,
244
+ onMainIndicatorsChange,
245
+ onSubIndicatorsChange
246
+ };
247
+ });
175
248
  const enhancedDispatch = react.useCallback((action) => {
176
249
  const prevState = stateRef.current;
177
250
  const newState = reducer(prevState, action);
@@ -201,11 +274,17 @@ function KlinechartsUIProvider({
201
274
  }
202
275
  }, []);
203
276
  const extraOverlaysRef = react.useRef(extraOverlays);
277
+ const datafeedRef = react.useRef(datafeed);
278
+ const onSettingsChangeRef = react.useRef(onSettingsChange);
279
+ react.useEffect(() => {
280
+ datafeedRef.current = datafeed;
281
+ onSettingsChangeRef.current = onSettingsChange;
282
+ });
204
283
  react.useEffect(() => {
205
284
  if (shouldRegister) {
206
- chunkFSHI2ZDB_cjs.registerExtensions();
285
+ chunkSZDU2D3D_cjs.registerExtensions();
207
286
  }
208
- extraOverlaysRef.current?.forEach((overlay) => reactKlinecharts.registerOverlay(overlay));
287
+ extraOverlaysRef.current?.forEach((overlay) => klinecharts.registerOverlay(overlay));
209
288
  }, [shouldRegister]);
210
289
  react.useEffect(() => {
211
290
  if (state.chart && state.styles) {
@@ -217,34 +296,97 @@ function KlinechartsUIProvider({
217
296
  const chart = state.chart;
218
297
  if (!chart || !hasAlerts) return;
219
298
  alertPrevCloseRef.current = null;
299
+ const prevValueByAlert = /* @__PURE__ */ new Map();
220
300
  const interval = setInterval(() => {
221
301
  const dataList = chart.getDataList();
222
302
  if (!dataList || dataList.length === 0) return;
223
- const currentClose = dataList[dataList.length - 1].close;
224
- const prevClose = alertPrevCloseRef.current;
225
- alertPrevCloseRef.current = currentClose;
226
- if (prevClose === null) return;
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
+ };
227
324
  const alerts = stateRef.current.alerts;
228
- let changed = false;
229
- const next = alerts.map((alert) => {
230
- if (alert.triggered) return alert;
231
- const crossedUp = prevClose < alert.price && currentClose >= alert.price;
232
- const crossedDown = prevClose > alert.price && currentClose <= alert.price;
325
+ const triggeredIds = [];
326
+ for (const alert of alerts) {
327
+ if (alert.triggered) continue;
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;
233
341
  const shouldTrigger = alert.condition === "crossing_up" ? crossedUp : alert.condition === "crossing_down" ? crossedDown : crossedUp || crossedDown;
234
342
  if (shouldTrigger) {
235
- changed = true;
236
- const triggered = { ...alert, triggered: true };
237
- alertTriggeredListenerRef.current?.(triggered);
238
- return triggered;
343
+ triggeredIds.push(alert.id);
344
+ const fired = { ...alert, triggered: true };
345
+ alertTriggeredListenersRef.current.forEach((cb) => cb(fired));
239
346
  }
240
- return alert;
241
- });
242
- if (changed) {
243
- enhancedDispatch({ type: "SET_ALERTS", alerts: next });
347
+ }
348
+ if (triggeredIds.length > 0) {
349
+ enhancedDispatch({
350
+ type: "MARK_ALERT_TRIGGERED",
351
+ ids: triggeredIds
352
+ });
244
353
  }
245
354
  }, 1e3);
246
355
  return () => clearInterval(interval);
247
356
  }, [state.chart, hasAlerts, enhancedDispatch]);
357
+ react.useEffect(() => {
358
+ alertPrevCloseRef.current = null;
359
+ }, [state.symbol, state.period]);
360
+ const writeNs = react.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
+ react.useEffect(() => {
374
+ writeNs("alerts", state.alerts);
375
+ }, [state.alerts, writeNs]);
376
+ react.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
+ ]);
248
390
  react.useEffect(() => {
249
391
  return () => {
250
392
  if (replayIntervalRef.current !== null) {
@@ -256,21 +398,23 @@ function KlinechartsUIProvider({
256
398
  const dispatchValue = react.useMemo(
257
399
  () => ({
258
400
  dispatch: enhancedDispatch,
259
- datafeed,
260
- onSettingsChange,
401
+ datafeed: datafeedRef.current,
402
+ onSettingsChange: onSettingsChangeRef.current,
261
403
  fullscreenContainerRef,
262
404
  undoRedoListenerRef,
263
- alertTriggeredListenerRef,
405
+ alertTriggeredListenersRef,
264
406
  replayIntervalRef,
265
407
  replaySavedDataRef,
266
- replayIndexRef
408
+ replayIndexRef,
409
+ storage: resolvedStorage
267
410
  }),
268
- [enhancedDispatch, datafeed, onSettingsChange]
411
+ // eslint-disable-next-line react-hooks/exhaustive-deps
412
+ [enhancedDispatch, resolvedStorage]
269
413
  );
270
- return /* @__PURE__ */ jsxRuntime.jsx(KlinechartsUIStateContext.Provider, { value: state, children: /* @__PURE__ */ jsxRuntime.jsx(KlinechartsUIDispatchContext.Provider, { value: dispatchValue, children }) });
414
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkF24D6PWY_cjs.KlinechartsUIStateContext.Provider, { value: state, children: /* @__PURE__ */ jsxRuntime.jsx(chunkF24D6PWY_cjs.KlinechartsUIDispatchContext.Provider, { value: dispatchValue, children }) });
271
415
  }
272
416
  function useKlinechartsUITheme() {
273
- const { state, dispatch } = useKlinechartsUI();
417
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
274
418
  const setTheme = react.useCallback(
275
419
  (theme) => {
276
420
  state.chart?.setStyles(theme);
@@ -291,11 +435,11 @@ function useKlinechartsUITheme() {
291
435
 
292
436
  // src/hooks/useKlinechartsUILoading.ts
293
437
  function useKlinechartsUILoading() {
294
- const { state } = useKlinechartsUI();
438
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
295
439
  return { isLoading: state.isLoading };
296
440
  }
297
441
  function usePeriods() {
298
- const { state, dispatch } = useKlinechartsUI();
442
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
299
443
  const setPeriod = react.useCallback(
300
444
  (period) => {
301
445
  dispatch({ type: "SET_PERIOD", period });
@@ -333,7 +477,7 @@ var TIMEZONES = [
333
477
 
334
478
  // src/hooks/useTimezone.ts
335
479
  function useTimezone() {
336
- const { state, dispatch } = useKlinechartsUI();
480
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
337
481
  const timezones = react.useMemo(
338
482
  () => TIMEZONES.map((tz) => ({
339
483
  key: tz.key,
@@ -355,7 +499,7 @@ function useTimezone() {
355
499
  };
356
500
  }
357
501
  function useSymbolSearch(debounceMs = 300) {
358
- const { state, dispatch, datafeed } = useKlinechartsUI();
502
+ const { state, dispatch, datafeed } = chunkF24D6PWY_cjs.useKlinechartsUI();
359
503
  const [query, setQueryState] = react.useState("");
360
504
  const [results, setResults] = react.useState([]);
361
505
  const [isSearching, setIsSearching] = react.useState(false);
@@ -717,8 +861,8 @@ var INDICATOR_PARAMS = {
717
861
  // src/hooks/useIndicators.ts
718
862
  var COLLAPSED_HEIGHT = 30;
719
863
  function useIndicators() {
720
- const { state, dispatch } = useKlinechartsUI();
721
- const { undoRedoListenerRef } = useKlinechartsUIDispatch();
864
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
865
+ const { undoRedoListenerRef } = chunkF24D6PWY_cjs.useKlinechartsUIDispatch();
722
866
  const paneHeightsRef = react.useRef({});
723
867
  const collapsedPanesRef = react.useRef(/* @__PURE__ */ new Set());
724
868
  const mainIndicators = react.useMemo(() => {
@@ -1215,23 +1359,25 @@ var DRAWING_CATEGORIES = [
1215
1359
  // src/hooks/useDrawingTools.ts
1216
1360
  var DRAWING_GROUP_ID = "drawing_tools";
1217
1361
  function useDrawingTools() {
1218
- const { state } = useKlinechartsUI();
1219
- const { undoRedoListenerRef } = useKlinechartsUIDispatch();
1362
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
1363
+ const { undoRedoListenerRef } = chunkF24D6PWY_cjs.useKlinechartsUIDispatch();
1220
1364
  const [activeTool, setActiveTool] = react.useState(null);
1221
1365
  const [magnetMode, setMagnetModeState] = react.useState("normal");
1222
1366
  const [isLocked, setIsLocked] = react.useState(false);
1223
1367
  const [isVisible, setIsVisible] = react.useState(true);
1224
1368
  const [autoRetrigger, setAutoRetrigger] = react.useState(true);
1225
1369
  const activeToolRef = react.useRef(activeTool);
1226
- activeToolRef.current = activeTool;
1227
1370
  const autoRetriggerRef = react.useRef(autoRetrigger);
1228
- autoRetriggerRef.current = autoRetrigger;
1229
1371
  const isLockedRef = react.useRef(isLocked);
1230
- isLockedRef.current = isLocked;
1231
1372
  const isVisibleRef = react.useRef(isVisible);
1232
- isVisibleRef.current = isVisible;
1233
1373
  const magnetModeRef = react.useRef(magnetMode);
1234
- magnetModeRef.current = magnetMode;
1374
+ react.useEffect(() => {
1375
+ activeToolRef.current = activeTool;
1376
+ autoRetriggerRef.current = autoRetrigger;
1377
+ isLockedRef.current = isLocked;
1378
+ isVisibleRef.current = isVisible;
1379
+ magnetModeRef.current = magnetMode;
1380
+ });
1235
1381
  const categories = react.useMemo(
1236
1382
  () => DRAWING_CATEGORIES.map((cat) => ({
1237
1383
  key: cat.key,
@@ -1242,6 +1388,8 @@ function useDrawingTools() {
1242
1388
  })),
1243
1389
  []
1244
1390
  );
1391
+ const createOverlayForToolRef = react.useRef(() => {
1392
+ });
1245
1393
  const createOverlayForTool = react.useCallback(
1246
1394
  (name) => {
1247
1395
  const mode = magnetModeRef.current === "strong" ? "strong_magnet" : magnetModeRef.current === "weak" ? "weak_magnet" : "normal";
@@ -1267,7 +1415,7 @@ function useDrawingTools() {
1267
1415
  });
1268
1416
  if (autoRetriggerRef.current && activeToolRef.current === name) {
1269
1417
  requestAnimationFrame(() => {
1270
- createOverlayForTool(name);
1418
+ createOverlayForToolRef.current(name);
1271
1419
  });
1272
1420
  }
1273
1421
  }
@@ -1275,6 +1423,9 @@ function useDrawingTools() {
1275
1423
  },
1276
1424
  [state.chart, undoRedoListenerRef]
1277
1425
  );
1426
+ react.useEffect(() => {
1427
+ createOverlayForToolRef.current = createOverlayForTool;
1428
+ });
1278
1429
  const selectTool = react.useCallback(
1279
1430
  (name) => {
1280
1431
  setActiveTool(name);
@@ -1399,8 +1550,18 @@ var defaultSettings = {
1399
1550
  tooltipShowRule: "always"
1400
1551
  };
1401
1552
  function useKlinechartsUISettings() {
1402
- const { state, onSettingsChange } = useKlinechartsUI();
1403
- const [settings, setSettings] = react.useState(defaultSettings);
1553
+ const { state, onSettingsChange } = chunkF24D6PWY_cjs.useKlinechartsUI();
1554
+ const { storage } = chunkF24D6PWY_cjs.useKlinechartsUIDispatch();
1555
+ const [settings, setSettings] = react.useState(() => {
1556
+ if (storage && storage.persists("settings")) {
1557
+ try {
1558
+ const raw = storage.adapter.getItem(storage.key("settings"));
1559
+ if (raw) return { ...defaultSettings, ...JSON.parse(raw) };
1560
+ } catch {
1561
+ }
1562
+ }
1563
+ return defaultSettings;
1564
+ });
1404
1565
  const isInitialMount = react.useRef(true);
1405
1566
  react.useEffect(() => {
1406
1567
  if (isInitialMount.current) {
@@ -1409,6 +1570,14 @@ function useKlinechartsUISettings() {
1409
1570
  }
1410
1571
  onSettingsChange?.({ ...settings });
1411
1572
  }, [settings, onSettingsChange]);
1573
+ react.useEffect(() => {
1574
+ if (!storage || !storage.persists("settings")) return;
1575
+ if (isInitialMount.current) return;
1576
+ try {
1577
+ storage.adapter.setItem(storage.key("settings"), JSON.stringify(settings));
1578
+ } catch {
1579
+ }
1580
+ }, [settings, storage]);
1412
1581
  const candleTypes = react.useMemo(
1413
1582
  () => CANDLE_TYPES.map((ct) => ({
1414
1583
  key: ct.key,
@@ -1650,7 +1819,7 @@ function useKlinechartsUISettings() {
1650
1819
  };
1651
1820
  }
1652
1821
  function useScreenshot() {
1653
- const { state, dispatch } = useKlinechartsUI();
1822
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
1654
1823
  const capture = react.useCallback(() => {
1655
1824
  if (!state.chart) return;
1656
1825
  const url = state.chart.getConvertPictureUrl(true, "jpeg", state.theme === "dark" ? "#151517" : "#ffffff");
@@ -1679,12 +1848,12 @@ function useScreenshot() {
1679
1848
  };
1680
1849
  }
1681
1850
  function useHotkeys() {
1682
- const { state } = useKlinechartsUI();
1851
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
1683
1852
  const registerHotkey = react.useCallback((template) => {
1684
- reactKlinecharts.registerHotkey(template);
1853
+ klinecharts.registerHotkey(template);
1685
1854
  }, []);
1686
1855
  const getHotkey = react.useCallback(
1687
- (name) => reactKlinecharts.getHotkey(name) ?? null,
1856
+ (name) => klinecharts.getHotkey(name) ?? null,
1688
1857
  []
1689
1858
  );
1690
1859
  const setHotkeysEnabled = react.useCallback(
@@ -1702,13 +1871,13 @@ function useHotkeys() {
1702
1871
  return {
1703
1872
  registerHotkey,
1704
1873
  getHotkey,
1705
- supportedHotkeys: reactKlinecharts.getSupportedHotkeys(),
1874
+ supportedHotkeys: klinecharts.getSupportedHotkeys(),
1706
1875
  setHotkeysEnabled,
1707
1876
  getHotkeysConfig
1708
1877
  };
1709
1878
  }
1710
1879
  function useChartAxes() {
1711
- const { state } = useKlinechartsUI();
1880
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
1712
1881
  const overrideXAxis = react.useCallback(
1713
1882
  (override) => {
1714
1883
  if (!state.chart) return;
@@ -1726,27 +1895,33 @@ function useChartAxes() {
1726
1895
  return { overrideXAxis, overrideYAxis };
1727
1896
  }
1728
1897
  function useFullscreen() {
1729
- const { fullscreenContainerRef } = useKlinechartsUIDispatch();
1898
+ const { fullscreenContainerRef } = chunkF24D6PWY_cjs.useKlinechartsUIDispatch();
1730
1899
  const [isFullscreen, setIsFullscreen] = react.useState(false);
1731
1900
  const enter = react.useCallback(() => {
1732
1901
  const el = fullscreenContainerRef.current;
1733
1902
  if (!el) return;
1903
+ let result;
1734
1904
  if (el.requestFullscreen) {
1735
- el.requestFullscreen();
1905
+ result = el.requestFullscreen();
1736
1906
  } else if ("webkitRequestFullscreen" in el) {
1737
1907
  el.webkitRequestFullscreen();
1738
1908
  } else if ("msRequestFullscreen" in el) {
1739
1909
  el.msRequestFullscreen();
1740
1910
  }
1911
+ result?.catch(() => {
1912
+ });
1741
1913
  }, [fullscreenContainerRef]);
1742
1914
  const exit = react.useCallback(() => {
1915
+ let result;
1743
1916
  if (document.exitFullscreen) {
1744
- document.exitFullscreen();
1917
+ result = document.exitFullscreen();
1745
1918
  } else if ("webkitExitFullscreen" in document) {
1746
1919
  document.webkitExitFullscreen();
1747
1920
  } else if ("msExitFullscreen" in document) {
1748
1921
  document.msExitFullscreen();
1749
1922
  }
1923
+ result?.catch(() => {
1924
+ });
1750
1925
  }, []);
1751
1926
  const toggle = react.useCallback(() => {
1752
1927
  if (isFullscreen) {
@@ -1775,8 +1950,9 @@ function useFullscreen() {
1775
1950
  };
1776
1951
  }
1777
1952
  function useOrderLines() {
1778
- const { state } = useKlinechartsUI();
1953
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
1779
1954
  const callbacksRef = react.useRef(/* @__PURE__ */ new Map());
1955
+ const ownedIdsRef = react.useRef(/* @__PURE__ */ new Set());
1780
1956
  const createOrderLine = react.useCallback(
1781
1957
  (options) => {
1782
1958
  if (!state.chart) return null;
@@ -1807,6 +1983,7 @@ function useOrderLines() {
1807
1983
  }
1808
1984
  }
1809
1985
  });
1986
+ ownedIdsRef.current.add(id);
1810
1987
  return id;
1811
1988
  },
1812
1989
  [state.chart]
@@ -1838,12 +2015,28 @@ function useOrderLines() {
1838
2015
  (id) => {
1839
2016
  state.chart?.removeOverlay({ id });
1840
2017
  callbacksRef.current.delete(id);
2018
+ ownedIdsRef.current.delete(id);
1841
2019
  },
1842
2020
  [state.chart]
1843
2021
  );
1844
2022
  const removeAllOrderLines = react.useCallback(() => {
1845
2023
  state.chart?.removeOverlay({ name: "orderLine" });
1846
2024
  callbacksRef.current.clear();
2025
+ ownedIdsRef.current.clear();
2026
+ }, [state.chart]);
2027
+ react.useEffect(() => {
2028
+ const chart = state.chart;
2029
+ const owned = ownedIdsRef.current;
2030
+ return () => {
2031
+ owned.forEach((id) => {
2032
+ try {
2033
+ chart?.removeOverlay({ id });
2034
+ } catch {
2035
+ }
2036
+ });
2037
+ owned.clear();
2038
+ callbacksRef.current.clear();
2039
+ };
1847
2040
  }, [state.chart]);
1848
2041
  return {
1849
2042
  createOrderLine,
@@ -1854,13 +2047,21 @@ function useOrderLines() {
1854
2047
  }
1855
2048
  var DRAWING_GROUP_ID2 = "drawing_tools";
1856
2049
  function useUndoRedo() {
1857
- const { state, dispatch } = useKlinechartsUI();
1858
- const { undoRedoListenerRef } = useKlinechartsUIDispatch();
2050
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
2051
+ const { undoRedoListenerRef } = chunkF24D6PWY_cjs.useKlinechartsUIDispatch();
1859
2052
  const [undoStack, setUndoStack] = react.useState([]);
1860
2053
  const [redoStack, setRedoStack] = react.useState([]);
1861
2054
  const isProcessingRef = react.useRef(false);
1862
2055
  const canUndo = undoStack.length > 0;
1863
2056
  const canRedo = redoStack.length > 0;
2057
+ const undoStackRef = react.useRef([]);
2058
+ const redoStackRef = react.useRef([]);
2059
+ react.useEffect(() => {
2060
+ undoStackRef.current = undoStack;
2061
+ }, [undoStack]);
2062
+ react.useEffect(() => {
2063
+ redoStackRef.current = redoStack;
2064
+ }, [redoStack]);
1864
2065
  const pushAction = react.useCallback((action) => {
1865
2066
  if (isProcessingRef.current) return;
1866
2067
  setUndoStack((prev) => [...prev, action]);
@@ -1877,10 +2078,11 @@ function useUndoRedo() {
1877
2078
  setRedoStack([]);
1878
2079
  }, []);
1879
2080
  const undo = react.useCallback(() => {
1880
- if (undoStack.length === 0 || !state.chart || isProcessingRef.current)
2081
+ const stack = undoStackRef.current;
2082
+ if (stack.length === 0 || !state.chart || isProcessingRef.current)
1881
2083
  return;
1882
2084
  isProcessingRef.current = true;
1883
- const action = undoStack[undoStack.length - 1];
2085
+ const action = stack[stack.length - 1];
1884
2086
  setUndoStack((prev) => prev.slice(0, -1));
1885
2087
  try {
1886
2088
  switch (action.type) {
@@ -2001,12 +2203,13 @@ function useUndoRedo() {
2001
2203
  } finally {
2002
2204
  isProcessingRef.current = false;
2003
2205
  }
2004
- }, [undoStack, state.chart, state.mainIndicators, state.subIndicators, state.indicatorAxes, dispatch]);
2206
+ }, [state.chart, state.mainIndicators, state.subIndicators, state.indicatorAxes, dispatch]);
2005
2207
  const redo = react.useCallback(() => {
2006
- if (redoStack.length === 0 || !state.chart || isProcessingRef.current)
2208
+ const stack = redoStackRef.current;
2209
+ if (stack.length === 0 || !state.chart || isProcessingRef.current)
2007
2210
  return;
2008
2211
  isProcessingRef.current = true;
2009
- const action = redoStack[redoStack.length - 1];
2212
+ const action = stack[stack.length - 1];
2010
2213
  setRedoStack((prev) => prev.slice(0, -1));
2011
2214
  try {
2012
2215
  switch (action.type) {
@@ -2131,7 +2334,7 @@ function useUndoRedo() {
2131
2334
  } finally {
2132
2335
  isProcessingRef.current = false;
2133
2336
  }
2134
- }, [redoStack, state.chart, state.mainIndicators, state.subIndicators, state.indicatorAxes, dispatch]);
2337
+ }, [state.chart, state.mainIndicators, state.subIndicators, state.indicatorAxes, dispatch]);
2135
2338
  react.useEffect(() => {
2136
2339
  const handleKeyDown = (e) => {
2137
2340
  const isCtrlOrMeta = e.ctrlKey || e.metaKey;
@@ -2169,6 +2372,7 @@ function generateId() {
2169
2372
  );
2170
2373
  }
2171
2374
  function getLayoutIds() {
2375
+ if (typeof localStorage === "undefined") return [];
2172
2376
  try {
2173
2377
  const raw = localStorage.getItem(INDEX_KEY);
2174
2378
  return raw ? JSON.parse(raw) : [];
@@ -2177,6 +2381,7 @@ function getLayoutIds() {
2177
2381
  }
2178
2382
  }
2179
2383
  function getEntry(id) {
2384
+ if (typeof localStorage === "undefined") return null;
2180
2385
  try {
2181
2386
  const raw = localStorage.getItem(STORAGE_KEY_PREFIX + id);
2182
2387
  return raw ? JSON.parse(raw) : null;
@@ -2185,36 +2390,32 @@ function getEntry(id) {
2185
2390
  }
2186
2391
  }
2187
2392
  function useLayoutManager() {
2188
- const { state, dispatch } = useKlinechartsUI();
2189
- const [layouts, setLayouts] = react.useState([]);
2393
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
2394
+ const [layouts, setLayouts] = react.useState(
2395
+ () => getLayoutIds().map((id) => getEntry(id)).filter((e) => e !== null)
2396
+ );
2190
2397
  const [autoSaveEnabled, setAutoSaveEnabled] = react.useState(false);
2191
2398
  const autoSaveTimerRef = react.useRef(null);
2192
2399
  const autoSaveIdRef = react.useRef(null);
2193
2400
  const refreshLayouts = react.useCallback(() => {
2194
- const entries = getLayoutIds().map((id) => getEntry(id)).filter((e) => e !== null);
2195
- setLayouts(entries);
2401
+ setLayouts(
2402
+ getLayoutIds().map((id) => getEntry(id)).filter((e) => e !== null)
2403
+ );
2196
2404
  }, []);
2197
- react.useEffect(() => {
2198
- refreshLayouts();
2199
- }, [refreshLayouts]);
2200
2405
  const serializeState = react.useCallback(() => {
2201
2406
  const chart = state.chart;
2202
2407
  if (!chart) return null;
2203
2408
  const indicators2 = [];
2204
- const indicatorMap = chart.getIndicatorByPaneId?.();
2205
- if (indicatorMap) {
2206
- indicatorMap.forEach((paneIndicators, paneId) => {
2207
- paneIndicators.forEach((indicator) => {
2208
- const yAxisId = state.indicatorAxes[indicator.id];
2209
- indicators2.push({
2210
- paneId,
2211
- name: indicator.name,
2212
- calcParams: indicator.calcParams,
2213
- visible: indicator.visible,
2214
- ...indicator.styles ? { styles: indicator.styles } : {},
2215
- ...yAxisId ? { yAxisId } : {}
2216
- });
2217
- });
2409
+ const allIndicators = chart.getIndicators();
2410
+ for (const indicator of allIndicators) {
2411
+ const yAxisId = state.indicatorAxes[indicator.id];
2412
+ indicators2.push({
2413
+ paneId: indicator.paneId,
2414
+ name: indicator.name,
2415
+ calcParams: indicator.calcParams,
2416
+ visible: indicator.visible,
2417
+ ...indicator.styles ? { styles: indicator.styles } : {},
2418
+ ...yAxisId ? { yAxisId } : {}
2218
2419
  });
2219
2420
  }
2220
2421
  const drawings = [];
@@ -2278,13 +2479,8 @@ function useLayoutManager() {
2278
2479
  if (chartState.version !== STATE_VERSION) return false;
2279
2480
  const chart = state.chart;
2280
2481
  chart.removeOverlay();
2281
- const indicatorMap = chart.getIndicatorByPaneId?.();
2282
- if (indicatorMap) {
2283
- indicatorMap.forEach((_paneIndicators, paneId) => {
2284
- _paneIndicators.forEach((_, indicatorName) => {
2285
- chart.removeIndicator({ paneId, name: indicatorName });
2286
- });
2287
- });
2482
+ for (const indicator of chart.getIndicators()) {
2483
+ chart.removeIndicator({ id: indicator.id });
2288
2484
  }
2289
2485
  const newMainIndicators = [];
2290
2486
  const newSubIndicators = {};
@@ -2302,7 +2498,12 @@ function useLayoutManager() {
2302
2498
  visible: ind.visible
2303
2499
  },
2304
2500
  {
2305
- isStack: ind.paneId !== "candle_pane",
2501
+ // Main indicators stack OVER the candle series on the candle
2502
+ // pane (isStack: true), exactly as useIndicators does on the
2503
+ // add path. The previous `ind.paneId !== "candle_pane"` inverted
2504
+ // this, so loading a layout with main indicators replaced the
2505
+ // candles instead of overlaying them.
2506
+ isStack: isMain,
2306
2507
  pane: { id: ind.paneId },
2307
2508
  ...ind.yAxisId ? { yAxis: { id: ind.yAxisId } } : {}
2308
2509
  }
@@ -2493,7 +2694,7 @@ var SHADOW_KEYS = [
2493
2694
  ];
2494
2695
  var scriptCounter = 0;
2495
2696
  function useScriptEditor() {
2496
- const { state } = useKlinechartsUI();
2697
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
2497
2698
  const [code, setCode] = react.useState(DEFAULT_SCRIPT);
2498
2699
  const [scriptName, setScriptName] = react.useState("");
2499
2700
  const [params, setParams] = react.useState("14");
@@ -2502,8 +2703,10 @@ function useScriptEditor() {
2502
2703
  const [status, setStatus] = react.useState("");
2503
2704
  const [isRunning, setIsRunning] = react.useState(false);
2504
2705
  const activeIdRef = react.useRef(null);
2706
+ const [activeName, setActiveName] = react.useState(null);
2505
2707
  const activeNameRef = react.useRef(null);
2506
- const hasActiveScript = activeNameRef.current !== null;
2708
+ activeNameRef.current = activeName;
2709
+ const hasActiveScript = activeName !== null;
2507
2710
  const runScript = react.useCallback(() => {
2508
2711
  const chart = state.chart;
2509
2712
  if (!chart) {
@@ -2524,31 +2727,38 @@ function useScriptEditor() {
2524
2727
  `"use strict";
2525
2728
  ${code}`
2526
2729
  ];
2527
- const fn = new Function(...allArgs);
2730
+ const compiledFn = new Function(...allArgs);
2528
2731
  const shadowValues = SHADOW_KEYS.map(() => void 0);
2529
- const result = fn(...shadowValues, chunkFSHI2ZDB_cjs.TA_default, dataList, parsedParams);
2530
- if (!Array.isArray(result)) {
2732
+ const sampleResult = compiledFn(
2733
+ ...shadowValues,
2734
+ chunkSZDU2D3D_cjs.TA_default,
2735
+ dataList,
2736
+ parsedParams
2737
+ );
2738
+ if (!Array.isArray(sampleResult)) {
2531
2739
  throw new Error("Script must return an Array.");
2532
2740
  }
2533
- const sample = result.find((v) => v !== null && v !== void 0);
2741
+ const sample = sampleResult.find(
2742
+ (v) => v !== null && v !== void 0
2743
+ );
2534
2744
  const seriesKeys = sample ? Object.keys(sample) : ["value"];
2535
2745
  if (seriesKeys.length === 0) {
2536
2746
  throw new Error("Returned objects have no keys.");
2537
2747
  }
2538
2748
  scriptCounter++;
2539
- const indicatorName = `_custom_script_${scriptCounter}`;
2749
+ const indicatorName = `_custom_script_active`;
2540
2750
  const figures = seriesKeys.map((key, i) => ({
2541
2751
  key,
2542
2752
  title: `${key}: `,
2543
2753
  type: "line",
2544
2754
  styles: () => ({ color: SERIES_COLORS[i % SERIES_COLORS.length] })
2545
2755
  }));
2546
- reactKlinecharts.registerIndicator({
2756
+ klinecharts.registerIndicator({
2547
2757
  name: indicatorName,
2548
2758
  shortName: (scriptName.trim() || `Script #${scriptCounter}`) + (placement === "main" ? " (Main)" : " (Sub)"),
2549
2759
  calcParams: parsedParams,
2550
2760
  figures,
2551
- calc: () => result,
2761
+ calc: (liveDataList) => compiledFn(...shadowValues, chunkSZDU2D3D_cjs.TA_default, liveDataList, parsedParams),
2552
2762
  extendData: {
2553
2763
  isCustomScript: true,
2554
2764
  code,
@@ -2574,7 +2784,7 @@ ${code}`
2574
2784
  paneId = chart.createIndicator({ name: indicatorName });
2575
2785
  }
2576
2786
  activeIdRef.current = typeof paneId === "string" ? paneId : null;
2577
- activeNameRef.current = indicatorName;
2787
+ setActiveName(indicatorName);
2578
2788
  const title = scriptName.trim() || `Script #${scriptCounter}`;
2579
2789
  setStatus(
2580
2790
  `${title} applied to ${placement === "main" ? "Main Chart" : "Sub Pane"} \u2014 ${seriesKeys.length} series: ${seriesKeys.join(", ")}`
@@ -2596,7 +2806,7 @@ ${code}`
2596
2806
  } catch {
2597
2807
  }
2598
2808
  activeIdRef.current = null;
2599
- activeNameRef.current = null;
2809
+ setActiveName(null);
2600
2810
  setStatus("Indicator removed.");
2601
2811
  }
2602
2812
  }, [state.chart]);
@@ -2659,7 +2869,7 @@ ${code}`
2659
2869
  };
2660
2870
  }
2661
2871
  function useCrosshair() {
2662
- const { state } = useKlinechartsUI();
2872
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
2663
2873
  const [barData, setBarData] = react.useState(null);
2664
2874
  const rafRef = react.useRef(0);
2665
2875
  const handler = react.useCallback(
@@ -2709,11 +2919,11 @@ function useCrosshair() {
2709
2919
  }
2710
2920
  var alertCounter = 0;
2711
2921
  function useAlerts() {
2712
- const { state, dispatch } = useKlinechartsUI();
2713
- const { alertTriggeredListenerRef } = useKlinechartsUIDispatch();
2922
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
2923
+ const { alertTriggeredListenersRef } = chunkF24D6PWY_cjs.useKlinechartsUIDispatch();
2714
2924
  const alerts = state.alerts;
2715
2925
  const addAlert = react.useCallback(
2716
- (price, condition, message, extendData) => {
2926
+ (price, condition, message, extendData, target) => {
2717
2927
  const id = `alert_${++alertCounter}`;
2718
2928
  const precision = state.chart?.getSymbol()?.pricePrecision ?? 2;
2719
2929
  const resolvedExtendData = {
@@ -2726,11 +2936,14 @@ function useAlerts() {
2726
2936
  condition,
2727
2937
  message,
2728
2938
  triggered: false,
2729
- extendData: resolvedExtendData
2939
+ extendData: resolvedExtendData,
2940
+ // Persist the target only when it's an indicator alert; omit for the
2941
+ // default price target so existing serialized alerts stay compatible.
2942
+ ...target && target.type === "indicator" ? { target } : {}
2730
2943
  };
2731
- dispatch({ type: "SET_ALERTS", alerts: [...state.alerts, alert] });
2944
+ dispatch({ type: "ADD_ALERT", alert });
2732
2945
  if (state.chart) {
2733
- chunkFSHI2ZDB_cjs.ensureAlertLineRegistered();
2946
+ chunkSZDU2D3D_cjs.ensureAlertLineRegistered();
2734
2947
  state.chart.createOverlay({
2735
2948
  name: "alertLine",
2736
2949
  id,
@@ -2742,29 +2955,28 @@ function useAlerts() {
2742
2955
  }
2743
2956
  return id;
2744
2957
  },
2745
- [state.chart, state.alerts, dispatch]
2958
+ [state.chart, dispatch]
2746
2959
  );
2747
2960
  const removeAlert = react.useCallback(
2748
2961
  (id) => {
2749
- dispatch({
2750
- type: "SET_ALERTS",
2751
- alerts: state.alerts.filter((a) => a.id !== id)
2752
- });
2962
+ dispatch({ type: "REMOVE_ALERT", id });
2753
2963
  state.chart?.removeOverlay({ id });
2754
2964
  },
2755
- [state.chart, state.alerts, dispatch]
2965
+ [state.chart, dispatch]
2756
2966
  );
2757
2967
  const clearAlerts = react.useCallback(() => {
2758
- for (const alert of state.alerts) {
2759
- state.chart?.removeOverlay({ id: alert.id });
2760
- }
2761
- dispatch({ type: "SET_ALERTS", alerts: [] });
2762
- }, [state.chart, state.alerts, dispatch]);
2968
+ state.chart?.removeOverlay({ groupId: "price_alerts" });
2969
+ dispatch({ type: "CLEAR_ALERTS" });
2970
+ }, [state.chart, dispatch]);
2763
2971
  const onAlertTriggered = react.useCallback(
2764
2972
  (callback) => {
2765
- alertTriggeredListenerRef.current = callback;
2973
+ const set = alertTriggeredListenersRef.current;
2974
+ set.add(callback);
2975
+ return () => {
2976
+ set.delete(callback);
2977
+ };
2766
2978
  },
2767
- [alertTriggeredListenerRef]
2979
+ [alertTriggeredListenersRef]
2768
2980
  );
2769
2981
  return {
2770
2982
  alerts,
@@ -2775,7 +2987,7 @@ function useAlerts() {
2775
2987
  };
2776
2988
  }
2777
2989
  function useDataExport() {
2778
- const { state } = useKlinechartsUI();
2990
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
2779
2991
  const exportAll = react.useCallback(
2780
2992
  (format) => {
2781
2993
  if (!state.chart) return;
@@ -2841,8 +3053,8 @@ function downloadData(dataList, format, ticker) {
2841
3053
  URL.revokeObjectURL(url);
2842
3054
  }
2843
3055
  function useWatchlist() {
2844
- const { state } = useKlinechartsUI();
2845
- const { dispatch, datafeed } = useKlinechartsUIDispatch();
3056
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
3057
+ const { dispatch, datafeed } = chunkF24D6PWY_cjs.useKlinechartsUIDispatch();
2846
3058
  const [items, setItems] = react.useState([]);
2847
3059
  const subscriptionsRef = react.useRef(/* @__PURE__ */ new Map());
2848
3060
  const activeSymbol = state.symbol?.ticker ?? null;
@@ -2911,8 +3123,8 @@ function useWatchlist() {
2911
3123
  };
2912
3124
  }
2913
3125
  function useReplay() {
2914
- const { state, dispatch } = useKlinechartsUI();
2915
- const { replayIntervalRef, replaySavedDataRef, replayIndexRef } = useKlinechartsUIDispatch();
3126
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
3127
+ const { replayIntervalRef, replaySavedDataRef, replayIndexRef } = chunkF24D6PWY_cjs.useKlinechartsUIDispatch();
2916
3128
  const { isReplaying, isPaused, speed, barIndex, totalBars } = state.replay;
2917
3129
  const clearInterval_ = react.useCallback(() => {
2918
3130
  if (replayIntervalRef.current !== null) {
@@ -2943,6 +3155,7 @@ function useReplay() {
2943
3155
  );
2944
3156
  const startReplay = react.useCallback(() => {
2945
3157
  if (!state.chart) return;
3158
+ if (isReplaying) return;
2946
3159
  const dataList = state.chart.getDataList();
2947
3160
  if (!dataList || dataList.length === 0) return;
2948
3161
  replaySavedDataRef.current = [...dataList];
@@ -2958,7 +3171,12 @@ function useReplay() {
2958
3171
  });
2959
3172
  state.chart.clearData?.();
2960
3173
  startInterval(speed);
2961
- }, [state.chart, speed, startInterval, replaySavedDataRef, replayIndexRef, dispatch]);
3174
+ }, [state.chart, state.symbol, state.period, speed, startInterval, isReplaying, replaySavedDataRef, replayIndexRef, dispatch]);
3175
+ react.useEffect(() => {
3176
+ if (isReplaying) {
3177
+ stopReplay();
3178
+ }
3179
+ }, [state.symbol, state.period]);
2962
3180
  const stopReplay = react.useCallback(() => {
2963
3181
  if (!state.chart) return;
2964
3182
  clearInterval_();
@@ -3054,24 +3272,29 @@ var DEFAULT_COLORS = [
3054
3272
  "#ff5722",
3055
3273
  "#8bc34a"
3056
3274
  ];
3057
- var colorIndex = 0;
3058
- var compareCounter = 0;
3059
3275
  function useCompare() {
3060
- const { state, datafeed } = useKlinechartsUI();
3276
+ const { state, datafeed } = chunkF24D6PWY_cjs.useKlinechartsUI();
3061
3277
  const [symbols, setSymbols] = react.useState([]);
3062
3278
  const indicatorsRef = react.useRef(/* @__PURE__ */ new Map());
3279
+ const instanceSalt = react.useId().replace(/[^a-zA-Z0-9]/g, "");
3063
3280
  const addSymbol = react.useCallback(
3064
3281
  async (ticker, color) => {
3065
3282
  if (!state.chart || !datafeed) return;
3066
3283
  if (indicatorsRef.current.has(ticker)) return;
3067
- const assignedColor = color ?? DEFAULT_COLORS[colorIndex++ % DEFAULT_COLORS.length];
3284
+ const assignedColor = color ?? DEFAULT_COLORS[symbols.length % DEFAULT_COLORS.length];
3068
3285
  const mainDataList = state.chart.getDataList();
3069
3286
  if (!mainDataList || mainDataList.length === 0) return;
3070
3287
  const from = mainDataList[0].timestamp;
3071
3288
  const to = mainDataList[mainDataList.length - 1].timestamp;
3289
+ const mainSymbol = state.symbol;
3290
+ const symbol = {
3291
+ ticker,
3292
+ pricePrecision: mainSymbol?.pricePrecision ?? 2,
3293
+ volumePrecision: mainSymbol?.volumePrecision ?? 8
3294
+ };
3072
3295
  const compareData = await datafeed.getHistoryKLineData(
3073
- { ticker },
3074
- { ...state.period, label: "" },
3296
+ symbol,
3297
+ state.period,
3075
3298
  from,
3076
3299
  to
3077
3300
  );
@@ -3090,14 +3313,8 @@ function useCompare() {
3090
3313
  }
3091
3314
  if (basePrice === null || basePrice === 0) return;
3092
3315
  const bp = basePrice;
3093
- const normalizedData = mainDataList.map((mainBar) => {
3094
- const close = compareMap.get(mainBar.timestamp);
3095
- return {
3096
- pct: close != null ? (close - bp) / bp * 100 : NaN
3097
- };
3098
- });
3099
- const indicatorName = `__cmp_${++compareCounter}_${ticker}`;
3100
- reactKlinecharts.registerIndicator({
3316
+ const indicatorName = `__cmp_${instanceSalt}_${ticker}`;
3317
+ klinecharts.registerIndicator({
3101
3318
  name: indicatorName,
3102
3319
  shortName: ticker,
3103
3320
  figures: [
@@ -3108,7 +3325,16 @@ function useCompare() {
3108
3325
  styles: () => ({ color: assignedColor })
3109
3326
  }
3110
3327
  ],
3111
- calc: () => normalizedData
3328
+ calc: (dataList) => {
3329
+ let lastPct = null;
3330
+ return dataList.map((bar) => {
3331
+ const close = compareMap.get(bar.timestamp);
3332
+ if (close != null) {
3333
+ lastPct = (close - bp) / bp * 100;
3334
+ }
3335
+ return { pct: lastPct };
3336
+ });
3337
+ }
3112
3338
  });
3113
3339
  const paneId = state.chart.createIndicator(
3114
3340
  { name: indicatorName },
@@ -3126,7 +3352,7 @@ function useCompare() {
3126
3352
  ];
3127
3353
  });
3128
3354
  },
3129
- [state.chart, state.period, datafeed]
3355
+ [state.chart, state.symbol, state.period, datafeed, symbols.length, instanceSalt]
3130
3356
  );
3131
3357
  const removeSymbol = react.useCallback(
3132
3358
  (ticker) => {
@@ -3193,7 +3419,7 @@ function computeResult(from, to) {
3193
3419
  return { from, to, priceDiff, pricePercent, bars, timeDiff };
3194
3420
  }
3195
3421
  function useMeasure() {
3196
- const { state, dispatch } = useKlinechartsUI();
3422
+ const { state, dispatch } = chunkF24D6PWY_cjs.useKlinechartsUI();
3197
3423
  const { isActive, fromPoint, result } = state.measure;
3198
3424
  const cleanup = react.useCallback(() => {
3199
3425
  state.chart?.removeOverlay({ id: MEASURE_OVERLAY_ID });
@@ -3274,7 +3500,7 @@ function useMeasure() {
3274
3500
  }
3275
3501
  var annotationCounter = 0;
3276
3502
  function useAnnotations() {
3277
- const { state } = useKlinechartsUI();
3503
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
3278
3504
  const [annotations, setAnnotations] = react.useState([]);
3279
3505
  const addAnnotation = react.useCallback(
3280
3506
  (text, price, timestamp, color) => {
@@ -3336,13 +3562,11 @@ function useAnnotations() {
3336
3562
  [state.chart]
3337
3563
  );
3338
3564
  const clearAnnotations = react.useCallback(() => {
3339
- setAnnotations((prev) => {
3340
- for (const annotation of prev) {
3341
- state.chart?.removeOverlay({ id: annotation.id });
3342
- }
3343
- return [];
3344
- });
3345
- }, [state.chart]);
3565
+ for (const annotation of annotations) {
3566
+ state.chart?.removeOverlay({ id: annotation.id });
3567
+ }
3568
+ setAnnotations([]);
3569
+ }, [state.chart, annotations]);
3346
3570
  react.useEffect(() => {
3347
3571
  return () => {
3348
3572
  state.chart?.removeOverlay({ groupId: "annotations" });
@@ -3356,265 +3580,375 @@ function useAnnotations() {
3356
3580
  clearAnnotations
3357
3581
  };
3358
3582
  }
3583
+ var WorkspaceContext = react.createContext(null);
3584
+ function useWorkspace() {
3585
+ const ctx = react.useContext(WorkspaceContext);
3586
+ if (!ctx) {
3587
+ throw new Error("useWorkspace must be used within a <WorkspaceProvider>");
3588
+ }
3589
+ return ctx;
3590
+ }
3359
3591
 
3360
- // src/utils/createDataLoader.ts
3361
- function createDataLoader(datafeed, dispatch) {
3362
- let oldestTimestamp = null;
3363
- let currentGen = 0;
3364
- return {
3365
- getBars: async (params) => {
3592
+ // src/workspace/types.ts
3593
+ var DEFAULT_SYNC_CONFIG = {
3594
+ crosshair: true,
3595
+ scroll: true,
3596
+ zoom: true,
3597
+ symbol: true,
3598
+ period: true
3599
+ };
3600
+ function reducer2(state, action) {
3601
+ switch (action.type) {
3602
+ case "SET_CELLS":
3603
+ return { ...state, cells: action.cells };
3604
+ case "ADD_CELL":
3605
+ return { ...state, cells: [...state.cells, action.cell] };
3606
+ case "REMOVE_CELL": {
3607
+ const cells = state.cells.filter((c) => c.id !== action.id);
3608
+ return {
3609
+ cells,
3610
+ activeCellId: state.activeCellId === action.id ? cells[0]?.id ?? null : state.activeCellId
3611
+ };
3612
+ }
3613
+ case "SET_CELL_SYMBOL":
3614
+ return {
3615
+ ...state,
3616
+ cells: state.cells.map(
3617
+ (c) => c.id === action.id ? { ...c, symbol: action.symbol } : c
3618
+ )
3619
+ };
3620
+ case "SET_CELL_PERIOD":
3621
+ return {
3622
+ ...state,
3623
+ cells: state.cells.map(
3624
+ (c) => c.id === action.id ? { ...c, period: action.period } : c
3625
+ )
3626
+ };
3627
+ case "SET_ACTIVE_CELL":
3628
+ return { ...state, activeCellId: action.id };
3629
+ default:
3630
+ return state;
3631
+ }
3632
+ }
3633
+ function WorkspaceProvider({
3634
+ defaultCells,
3635
+ sync,
3636
+ children
3637
+ }) {
3638
+ const [state, dispatch] = react.useReducer(reducer2, defaultCells, (cells) => ({
3639
+ cells,
3640
+ activeCellId: cells[0]?.id ?? null
3641
+ }));
3642
+ const chartsRef = react.useRef(/* @__PURE__ */ new Map());
3643
+ const broadcastingRef = react.useRef(false);
3644
+ const resolvedSync = react.useMemo(
3645
+ () => ({ ...DEFAULT_SYNC_CONFIG, ...sync }),
3646
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3647
+ []
3648
+ );
3649
+ const value = react.useMemo(
3650
+ () => ({
3651
+ state,
3652
+ dispatch,
3653
+ chartsRef,
3654
+ broadcastingRef,
3655
+ sync: resolvedSync
3656
+ }),
3657
+ [state, resolvedSync]
3658
+ );
3659
+ return /* @__PURE__ */ jsxRuntime.jsx(WorkspaceContext.Provider, { value, children });
3660
+ }
3661
+ function useChartSync({ cellId }) {
3662
+ const { chartsRef, broadcastingRef, sync, dispatch: workspaceDispatch } = useWorkspace();
3663
+ const { state } = chunkF24D6PWY_cjs.useKlinechartsUI();
3664
+ const chart = state.chart;
3665
+ react.useEffect(() => {
3666
+ if (!chart) return;
3667
+ chartsRef.current.set(cellId, chart);
3668
+ return () => {
3669
+ chartsRef.current.delete(cellId);
3670
+ };
3671
+ }, [chart, cellId, chartsRef]);
3672
+ react.useEffect(() => {
3673
+ if (!chart) return;
3674
+ const broadcast = (fn) => {
3675
+ if (broadcastingRef.current) return;
3676
+ broadcastingRef.current = true;
3366
3677
  try {
3367
- dispatch({ type: "SET_LOADING", isLoading: true });
3368
- if (params.type === "init") {
3369
- oldestTimestamp = null;
3370
- const gen = ++currentGen;
3371
- const data = await datafeed.getHistoryKLineData(
3372
- params.symbol,
3373
- { ...params.period, label: "" },
3374
- 0,
3375
- Date.now()
3376
- );
3377
- if (gen !== currentGen) return;
3378
- if (data.length > 0) {
3379
- oldestTimestamp = data[0].timestamp;
3380
- }
3381
- params.callback(data, {
3382
- forward: data.length > 0,
3383
- backward: false
3384
- });
3385
- } else if (params.type === "forward" && oldestTimestamp !== null) {
3386
- const gen = currentGen;
3387
- const data = await datafeed.getHistoryKLineData(
3388
- params.symbol,
3389
- { ...params.period, label: "" },
3390
- 0,
3391
- oldestTimestamp - 1
3392
- );
3393
- if (gen !== currentGen) return;
3394
- if (data.length > 0) {
3395
- oldestTimestamp = data[0].timestamp;
3678
+ chartsRef.current.forEach((target, id) => {
3679
+ if (id !== cellId) {
3680
+ try {
3681
+ fn(target);
3682
+ } catch {
3683
+ }
3396
3684
  }
3397
- params.callback(data, {
3398
- forward: data.length > 0,
3399
- backward: false
3400
- });
3401
- } else if (params.type === "backward") {
3402
- params.callback([], { forward: false, backward: false });
3403
- }
3404
- } catch (error) {
3405
- console.error("Failed to load chart data:", error);
3406
- params.callback([], { forward: false, backward: false });
3685
+ });
3407
3686
  } finally {
3408
- dispatch({ type: "SET_LOADING", isLoading: false });
3687
+ broadcastingRef.current = false;
3409
3688
  }
3410
- },
3411
- subscribeBar: (params) => {
3412
- datafeed.subscribe(
3413
- params.symbol,
3414
- { ...params.period, label: "" },
3415
- (klineData) => params.callback(klineData)
3689
+ };
3690
+ const onCrosshairChange = (data) => {
3691
+ if (!sync.crosshair) return;
3692
+ const crosshair = data;
3693
+ if (!crosshair) return;
3694
+ broadcast((target) => target.executeAction("onCrosshairChange", crosshair));
3695
+ };
3696
+ const onScroll = () => {
3697
+ if (!sync.scroll) return;
3698
+ let range = null;
3699
+ try {
3700
+ range = chart.getVisibleRange();
3701
+ } catch {
3702
+ return;
3703
+ }
3704
+ if (!range || range.realTo == null) return;
3705
+ broadcast(
3706
+ (target) => target.scrollToTimestamp(range.realTo, 0)
3416
3707
  );
3417
- },
3418
- unsubscribeBar: (params) => {
3419
- datafeed.unsubscribe(params.symbol, { ...params.period, label: "" });
3708
+ };
3709
+ const onZoom = () => {
3710
+ if (!sync.zoom) return;
3711
+ let bar = 0;
3712
+ try {
3713
+ bar = chart.getBarSpace().bar;
3714
+ } catch {
3715
+ return;
3716
+ }
3717
+ broadcast((target) => target.setBarSpace(bar));
3718
+ };
3719
+ chart.subscribeAction("onCrosshairChange", onCrosshairChange);
3720
+ chart.subscribeAction("onScroll", onScroll);
3721
+ chart.subscribeAction("onZoom", onZoom);
3722
+ return () => {
3723
+ chart.unsubscribeAction("onCrosshairChange", onCrosshairChange);
3724
+ chart.unsubscribeAction("onScroll", onScroll);
3725
+ chart.unsubscribeAction("onZoom", onZoom);
3726
+ };
3727
+ }, [chart, cellId, chartsRef, broadcastingRef, sync.crosshair, sync.scroll, sync.zoom]);
3728
+ react.useEffect(() => {
3729
+ if (state.symbol) {
3730
+ workspaceDispatch({ type: "SET_CELL_SYMBOL", id: cellId, symbol: state.symbol });
3420
3731
  }
3421
- };
3732
+ }, [state.symbol]);
3733
+ react.useEffect(() => {
3734
+ workspaceDispatch({ type: "SET_CELL_PERIOD", id: cellId, period: state.period });
3735
+ }, [state.period]);
3422
3736
  }
3423
3737
 
3424
3738
  Object.defineProperty(exports, "TA", {
3425
3739
  enumerable: true,
3426
- get: function () { return chunkFSHI2ZDB_cjs.TA_default; }
3740
+ get: function () { return chunkSZDU2D3D_cjs.TA_default; }
3427
3741
  });
3428
3742
  Object.defineProperty(exports, "abcd", {
3429
3743
  enumerable: true,
3430
- get: function () { return chunkFSHI2ZDB_cjs.abcd_default; }
3744
+ get: function () { return chunkSZDU2D3D_cjs.abcd_default; }
3431
3745
  });
3432
3746
  Object.defineProperty(exports, "alertLine", {
3433
3747
  enumerable: true,
3434
- get: function () { return chunkFSHI2ZDB_cjs.alertLine_default; }
3748
+ get: function () { return chunkSZDU2D3D_cjs.alertLine_default; }
3435
3749
  });
3436
3750
  Object.defineProperty(exports, "anyWaves", {
3437
3751
  enumerable: true,
3438
- get: function () { return chunkFSHI2ZDB_cjs.anyWaves_default; }
3752
+ get: function () { return chunkSZDU2D3D_cjs.anyWaves_default; }
3439
3753
  });
3440
3754
  Object.defineProperty(exports, "arrow", {
3441
3755
  enumerable: true,
3442
- get: function () { return chunkFSHI2ZDB_cjs.arrow_default; }
3756
+ get: function () { return chunkSZDU2D3D_cjs.arrow_default; }
3443
3757
  });
3444
3758
  Object.defineProperty(exports, "bollTv", {
3445
3759
  enumerable: true,
3446
- get: function () { return chunkFSHI2ZDB_cjs.bollTv_default; }
3760
+ get: function () { return chunkSZDU2D3D_cjs.bollTv_default; }
3447
3761
  });
3448
3762
  Object.defineProperty(exports, "brush", {
3449
3763
  enumerable: true,
3450
- get: function () { return chunkFSHI2ZDB_cjs.brush_default; }
3764
+ get: function () { return chunkSZDU2D3D_cjs.brush_default; }
3451
3765
  });
3452
3766
  Object.defineProperty(exports, "cci", {
3453
3767
  enumerable: true,
3454
- get: function () { return chunkFSHI2ZDB_cjs.cci_default; }
3768
+ get: function () { return chunkSZDU2D3D_cjs.cci_default; }
3455
3769
  });
3456
3770
  Object.defineProperty(exports, "circle", {
3457
3771
  enumerable: true,
3458
- get: function () { return chunkFSHI2ZDB_cjs.circle_default; }
3772
+ get: function () { return chunkSZDU2D3D_cjs.circle_default; }
3459
3773
  });
3460
3774
  Object.defineProperty(exports, "depthOverlay", {
3461
3775
  enumerable: true,
3462
- get: function () { return chunkFSHI2ZDB_cjs.depthOverlay_default; }
3776
+ get: function () { return chunkSZDU2D3D_cjs.depthOverlay_default; }
3463
3777
  });
3464
3778
  Object.defineProperty(exports, "eightWaves", {
3465
3779
  enumerable: true,
3466
- get: function () { return chunkFSHI2ZDB_cjs.eightWaves_default; }
3780
+ get: function () { return chunkSZDU2D3D_cjs.eightWaves_default; }
3467
3781
  });
3468
3782
  Object.defineProperty(exports, "elliottWave", {
3469
3783
  enumerable: true,
3470
- get: function () { return chunkFSHI2ZDB_cjs.elliottWave_default; }
3784
+ get: function () { return chunkSZDU2D3D_cjs.elliottWave_default; }
3471
3785
  });
3472
3786
  Object.defineProperty(exports, "fibRetracement", {
3473
3787
  enumerable: true,
3474
- get: function () { return chunkFSHI2ZDB_cjs.fibRetracement_default; }
3788
+ get: function () { return chunkSZDU2D3D_cjs.fibRetracement_default; }
3475
3789
  });
3476
3790
  Object.defineProperty(exports, "fibonacciCircle", {
3477
3791
  enumerable: true,
3478
- get: function () { return chunkFSHI2ZDB_cjs.fibonacciCircle_default; }
3792
+ get: function () { return chunkSZDU2D3D_cjs.fibonacciCircle_default; }
3479
3793
  });
3480
3794
  Object.defineProperty(exports, "fibonacciExtension", {
3481
3795
  enumerable: true,
3482
- get: function () { return chunkFSHI2ZDB_cjs.fibonacciExtension_default; }
3796
+ get: function () { return chunkSZDU2D3D_cjs.fibonacciExtension_default; }
3483
3797
  });
3484
3798
  Object.defineProperty(exports, "fibonacciSegment", {
3485
3799
  enumerable: true,
3486
- get: function () { return chunkFSHI2ZDB_cjs.fibonacciSegment_default; }
3800
+ get: function () { return chunkSZDU2D3D_cjs.fibonacciSegment_default; }
3487
3801
  });
3488
3802
  Object.defineProperty(exports, "fibonacciSpeedResistanceFan", {
3489
3803
  enumerable: true,
3490
- get: function () { return chunkFSHI2ZDB_cjs.fibonacciSpeedResistanceFan_default; }
3804
+ get: function () { return chunkSZDU2D3D_cjs.fibonacciSpeedResistanceFan_default; }
3491
3805
  });
3492
3806
  Object.defineProperty(exports, "fibonacciSpiral", {
3493
3807
  enumerable: true,
3494
- get: function () { return chunkFSHI2ZDB_cjs.fibonacciSpiral_default; }
3808
+ get: function () { return chunkSZDU2D3D_cjs.fibonacciSpiral_default; }
3495
3809
  });
3496
3810
  Object.defineProperty(exports, "fiveWaves", {
3497
3811
  enumerable: true,
3498
- get: function () { return chunkFSHI2ZDB_cjs.fiveWaves_default; }
3812
+ get: function () { return chunkSZDU2D3D_cjs.fiveWaves_default; }
3499
3813
  });
3500
3814
  Object.defineProperty(exports, "gannBox", {
3501
3815
  enumerable: true,
3502
- get: function () { return chunkFSHI2ZDB_cjs.gannBox_default; }
3816
+ get: function () { return chunkSZDU2D3D_cjs.gannBox_default; }
3503
3817
  });
3504
3818
  Object.defineProperty(exports, "gannFan", {
3505
3819
  enumerable: true,
3506
- get: function () { return chunkFSHI2ZDB_cjs.gannFan_default; }
3820
+ get: function () { return chunkSZDU2D3D_cjs.gannFan_default; }
3507
3821
  });
3508
3822
  Object.defineProperty(exports, "hma", {
3509
3823
  enumerable: true,
3510
- get: function () { return chunkFSHI2ZDB_cjs.hma_default; }
3824
+ get: function () { return chunkSZDU2D3D_cjs.hma_default; }
3511
3825
  });
3512
3826
  Object.defineProperty(exports, "ichimoku", {
3513
3827
  enumerable: true,
3514
- get: function () { return chunkFSHI2ZDB_cjs.ichimoku_default; }
3828
+ get: function () { return chunkSZDU2D3D_cjs.ichimoku_default; }
3515
3829
  });
3516
3830
  Object.defineProperty(exports, "indicators", {
3517
3831
  enumerable: true,
3518
- get: function () { return chunkFSHI2ZDB_cjs.indicators; }
3832
+ get: function () { return chunkSZDU2D3D_cjs.indicators; }
3519
3833
  });
3520
3834
  Object.defineProperty(exports, "longPosition", {
3521
3835
  enumerable: true,
3522
- get: function () { return chunkFSHI2ZDB_cjs.longPosition_default; }
3836
+ get: function () { return chunkSZDU2D3D_cjs.longPosition_default; }
3523
3837
  });
3524
3838
  Object.defineProperty(exports, "maRibbon", {
3525
3839
  enumerable: true,
3526
- get: function () { return chunkFSHI2ZDB_cjs.maRibbon_default; }
3840
+ get: function () { return chunkSZDU2D3D_cjs.maRibbon_default; }
3527
3841
  });
3528
3842
  Object.defineProperty(exports, "macdTv", {
3529
3843
  enumerable: true,
3530
- get: function () { return chunkFSHI2ZDB_cjs.macdTv_default; }
3844
+ get: function () { return chunkSZDU2D3D_cjs.macdTv_default; }
3531
3845
  });
3532
3846
  Object.defineProperty(exports, "measure", {
3533
3847
  enumerable: true,
3534
- get: function () { return chunkFSHI2ZDB_cjs.measure_default; }
3848
+ get: function () { return chunkSZDU2D3D_cjs.measure_default; }
3535
3849
  });
3536
3850
  Object.defineProperty(exports, "orderLine", {
3537
3851
  enumerable: true,
3538
- get: function () { return chunkFSHI2ZDB_cjs.orderLine_default; }
3852
+ get: function () { return chunkSZDU2D3D_cjs.orderLine_default; }
3539
3853
  });
3540
3854
  Object.defineProperty(exports, "overlays", {
3541
3855
  enumerable: true,
3542
- get: function () { return chunkFSHI2ZDB_cjs.overlays; }
3856
+ get: function () { return chunkSZDU2D3D_cjs.overlays; }
3543
3857
  });
3544
3858
  Object.defineProperty(exports, "parallelChannel", {
3545
3859
  enumerable: true,
3546
- get: function () { return chunkFSHI2ZDB_cjs.parallelChannel_default; }
3860
+ get: function () { return chunkSZDU2D3D_cjs.parallelChannel_default; }
3547
3861
  });
3548
3862
  Object.defineProperty(exports, "parallelogram", {
3549
3863
  enumerable: true,
3550
- get: function () { return chunkFSHI2ZDB_cjs.parallelogram_default; }
3864
+ get: function () { return chunkSZDU2D3D_cjs.parallelogram_default; }
3551
3865
  });
3552
3866
  Object.defineProperty(exports, "pivotPoints", {
3553
3867
  enumerable: true,
3554
- get: function () { return chunkFSHI2ZDB_cjs.pivotPoints_default; }
3868
+ get: function () { return chunkSZDU2D3D_cjs.pivotPoints_default; }
3555
3869
  });
3556
3870
  Object.defineProperty(exports, "ray", {
3557
3871
  enumerable: true,
3558
- get: function () { return chunkFSHI2ZDB_cjs.ray_default; }
3872
+ get: function () { return chunkSZDU2D3D_cjs.ray_default; }
3559
3873
  });
3560
3874
  Object.defineProperty(exports, "rect", {
3561
3875
  enumerable: true,
3562
- get: function () { return chunkFSHI2ZDB_cjs.rect_default; }
3876
+ get: function () { return chunkSZDU2D3D_cjs.rect_default; }
3563
3877
  });
3564
3878
  Object.defineProperty(exports, "registerExtensions", {
3565
3879
  enumerable: true,
3566
- get: function () { return chunkFSHI2ZDB_cjs.registerExtensions; }
3880
+ get: function () { return chunkSZDU2D3D_cjs.registerExtensions; }
3567
3881
  });
3568
3882
  Object.defineProperty(exports, "rsiTv", {
3569
3883
  enumerable: true,
3570
- get: function () { return chunkFSHI2ZDB_cjs.rsiTv_default; }
3884
+ get: function () { return chunkSZDU2D3D_cjs.rsiTv_default; }
3571
3885
  });
3572
3886
  Object.defineProperty(exports, "shortPosition", {
3573
3887
  enumerable: true,
3574
- get: function () { return chunkFSHI2ZDB_cjs.shortPosition_default; }
3888
+ get: function () { return chunkSZDU2D3D_cjs.shortPosition_default; }
3575
3889
  });
3576
3890
  Object.defineProperty(exports, "stochastic", {
3577
3891
  enumerable: true,
3578
- get: function () { return chunkFSHI2ZDB_cjs.stochastic_default; }
3892
+ get: function () { return chunkSZDU2D3D_cjs.stochastic_default; }
3579
3893
  });
3580
3894
  Object.defineProperty(exports, "superTrend", {
3581
3895
  enumerable: true,
3582
- get: function () { return chunkFSHI2ZDB_cjs.superTrend_default; }
3896
+ get: function () { return chunkSZDU2D3D_cjs.superTrend_default; }
3583
3897
  });
3584
3898
  Object.defineProperty(exports, "threeWaves", {
3585
3899
  enumerable: true,
3586
- get: function () { return chunkFSHI2ZDB_cjs.threeWaves_default; }
3900
+ get: function () { return chunkSZDU2D3D_cjs.threeWaves_default; }
3587
3901
  });
3588
3902
  Object.defineProperty(exports, "triangle", {
3589
3903
  enumerable: true,
3590
- get: function () { return chunkFSHI2ZDB_cjs.triangle_default; }
3904
+ get: function () { return chunkSZDU2D3D_cjs.triangle_default; }
3591
3905
  });
3592
3906
  Object.defineProperty(exports, "vwap", {
3593
3907
  enumerable: true,
3594
- get: function () { return chunkFSHI2ZDB_cjs.vwap_default; }
3908
+ get: function () { return chunkSZDU2D3D_cjs.vwap_default; }
3595
3909
  });
3596
3910
  Object.defineProperty(exports, "xabcd", {
3597
3911
  enumerable: true,
3598
- get: function () { return chunkFSHI2ZDB_cjs.xabcd_default; }
3912
+ get: function () { return chunkSZDU2D3D_cjs.xabcd_default; }
3913
+ });
3914
+ Object.defineProperty(exports, "KlinechartsUIDispatchContext", {
3915
+ enumerable: true,
3916
+ get: function () { return chunkF24D6PWY_cjs.KlinechartsUIDispatchContext; }
3917
+ });
3918
+ Object.defineProperty(exports, "KlinechartsUIStateContext", {
3919
+ enumerable: true,
3920
+ get: function () { return chunkF24D6PWY_cjs.KlinechartsUIStateContext; }
3921
+ });
3922
+ Object.defineProperty(exports, "createDataLoader", {
3923
+ enumerable: true,
3924
+ get: function () { return chunkF24D6PWY_cjs.createDataLoader; }
3925
+ });
3926
+ Object.defineProperty(exports, "useKlinechartsUI", {
3927
+ enumerable: true,
3928
+ get: function () { return chunkF24D6PWY_cjs.useKlinechartsUI; }
3599
3929
  });
3600
3930
  exports.CANDLE_TYPES = CANDLE_TYPES;
3601
3931
  exports.COMPARE_RULES = COMPARE_RULES;
3602
3932
  exports.DEFAULT_PERIODS = DEFAULT_PERIODS;
3933
+ exports.DEFAULT_STORAGE_KEY_PREFIX = DEFAULT_STORAGE_KEY_PREFIX;
3934
+ exports.DEFAULT_STORAGE_NAMESPACES = DEFAULT_STORAGE_NAMESPACES;
3935
+ exports.DEFAULT_SYNC_CONFIG = DEFAULT_SYNC_CONFIG;
3603
3936
  exports.DRAWING_CATEGORIES = DRAWING_CATEGORIES;
3604
3937
  exports.INDICATOR_PARAMS = INDICATOR_PARAMS;
3605
- exports.KlinechartsUIDispatchContext = KlinechartsUIDispatchContext;
3606
3938
  exports.KlinechartsUIProvider = KlinechartsUIProvider;
3607
- exports.KlinechartsUIStateContext = KlinechartsUIStateContext;
3608
3939
  exports.MAIN_INDICATORS = MAIN_INDICATORS;
3609
3940
  exports.PRICE_AXIS_TYPES = PRICE_AXIS_TYPES;
3610
3941
  exports.SUB_INDICATORS = SUB_INDICATORS;
3611
3942
  exports.TIMEZONES = TIMEZONES;
3612
3943
  exports.TOOLTIP_SHOW_RULES = TOOLTIP_SHOW_RULES;
3944
+ exports.WorkspaceProvider = WorkspaceProvider;
3613
3945
  exports.YAXIS_POSITIONS = YAXIS_POSITIONS;
3614
- exports.createDataLoader = createDataLoader;
3946
+ exports.createDefaultStorage = createDefaultStorage;
3947
+ exports.resolveStorage = resolveStorage;
3615
3948
  exports.useAlerts = useAlerts;
3616
3949
  exports.useAnnotations = useAnnotations;
3617
3950
  exports.useChartAxes = useChartAxes;
3951
+ exports.useChartSync = useChartSync;
3618
3952
  exports.useCompare = useCompare;
3619
3953
  exports.useCrosshair = useCrosshair;
3620
3954
  exports.useDataExport = useDataExport;
@@ -3622,7 +3956,6 @@ exports.useDrawingTools = useDrawingTools;
3622
3956
  exports.useFullscreen = useFullscreen;
3623
3957
  exports.useHotkeys = useHotkeys;
3624
3958
  exports.useIndicators = useIndicators;
3625
- exports.useKlinechartsUI = useKlinechartsUI;
3626
3959
  exports.useKlinechartsUILoading = useKlinechartsUILoading;
3627
3960
  exports.useKlinechartsUISettings = useKlinechartsUISettings;
3628
3961
  exports.useKlinechartsUITheme = useKlinechartsUITheme;
@@ -3637,5 +3970,6 @@ exports.useSymbolSearch = useSymbolSearch;
3637
3970
  exports.useTimezone = useTimezone;
3638
3971
  exports.useUndoRedo = useUndoRedo;
3639
3972
  exports.useWatchlist = useWatchlist;
3973
+ exports.useWorkspace = useWorkspace;
3640
3974
  //# sourceMappingURL=index.cjs.map
3641
3975
  //# sourceMappingURL=index.cjs.map