react-klinecharts-ui 0.5.0 → 1.0.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,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkUJNJH3BS_cjs = require('./chunk-UJNJH3BS.cjs');
3
+ var chunkLGYYJ2GP_cjs = require('./chunk-LGYYJ2GP.cjs');
4
4
  var react = require('react');
5
- var reactKlinecharts = require('react-klinecharts');
5
+ var klinecharts = require('klinecharts');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
 
8
8
  var KlinechartsUIStateContext = react.createContext(null);
@@ -64,6 +64,25 @@ function reducer(state, action) {
64
64
  return { ...state, indicatorVisibility: action.visibility };
65
65
  case "SET_ALERTS":
66
66
  return { ...state, alerts: action.alerts };
67
+ case "ADD_ALERT":
68
+ return { ...state, alerts: [...state.alerts, action.alert] };
69
+ case "REMOVE_ALERT":
70
+ return {
71
+ ...state,
72
+ alerts: state.alerts.filter((a) => a.id !== action.id)
73
+ };
74
+ case "CLEAR_ALERTS":
75
+ return { ...state, alerts: [] };
76
+ case "MARK_ALERT_TRIGGERED": {
77
+ if (action.ids.length === 0) return state;
78
+ const triggered = new Set(action.ids);
79
+ return {
80
+ ...state,
81
+ alerts: state.alerts.map(
82
+ (a) => triggered.has(a.id) ? { ...a, triggered: true } : a
83
+ )
84
+ };
85
+ }
67
86
  case "SET_MEASURE":
68
87
  return { ...state, measure: { ...state.measure, ...action.measure } };
69
88
  case "SET_REPLAY":
@@ -153,7 +172,6 @@ function KlinechartsUIProvider({
153
172
  const replayIndexRef = react.useRef(0);
154
173
  const alertPrevCloseRef = react.useRef(null);
155
174
  const stateRef = react.useRef(state);
156
- stateRef.current = state;
157
175
  const callbacksRef = react.useRef({
158
176
  onStateChange,
159
177
  onSymbolChange,
@@ -163,15 +181,18 @@ function KlinechartsUIProvider({
163
181
  onMainIndicatorsChange,
164
182
  onSubIndicatorsChange
165
183
  });
166
- callbacksRef.current = {
167
- onStateChange,
168
- onSymbolChange,
169
- onPeriodChange,
170
- onThemeChange,
171
- onTimezoneChange,
172
- onMainIndicatorsChange,
173
- onSubIndicatorsChange
174
- };
184
+ react.useEffect(() => {
185
+ stateRef.current = state;
186
+ callbacksRef.current = {
187
+ onStateChange,
188
+ onSymbolChange,
189
+ onPeriodChange,
190
+ onThemeChange,
191
+ onTimezoneChange,
192
+ onMainIndicatorsChange,
193
+ onSubIndicatorsChange
194
+ };
195
+ });
175
196
  const enhancedDispatch = react.useCallback((action) => {
176
197
  const prevState = stateRef.current;
177
198
  const newState = reducer(prevState, action);
@@ -201,11 +222,17 @@ function KlinechartsUIProvider({
201
222
  }
202
223
  }, []);
203
224
  const extraOverlaysRef = react.useRef(extraOverlays);
225
+ const datafeedRef = react.useRef(datafeed);
226
+ const onSettingsChangeRef = react.useRef(onSettingsChange);
227
+ react.useEffect(() => {
228
+ datafeedRef.current = datafeed;
229
+ onSettingsChangeRef.current = onSettingsChange;
230
+ });
204
231
  react.useEffect(() => {
205
232
  if (shouldRegister) {
206
- chunkUJNJH3BS_cjs.registerExtensions();
233
+ chunkLGYYJ2GP_cjs.registerExtensions();
207
234
  }
208
- extraOverlaysRef.current?.forEach((overlay) => reactKlinecharts.registerOverlay(overlay));
235
+ extraOverlaysRef.current?.forEach((overlay) => klinecharts.registerOverlay(overlay));
209
236
  }, [shouldRegister]);
210
237
  react.useEffect(() => {
211
238
  if (state.chart && state.styles) {
@@ -225,26 +252,29 @@ function KlinechartsUIProvider({
225
252
  alertPrevCloseRef.current = currentClose;
226
253
  if (prevClose === null) return;
227
254
  const alerts = stateRef.current.alerts;
228
- let changed = false;
229
- const next = alerts.map((alert) => {
230
- if (alert.triggered) return alert;
255
+ const triggeredIds = [];
256
+ for (const alert of alerts) {
257
+ if (alert.triggered) continue;
231
258
  const crossedUp = prevClose < alert.price && currentClose >= alert.price;
232
259
  const crossedDown = prevClose > alert.price && currentClose <= alert.price;
233
260
  const shouldTrigger = alert.condition === "crossing_up" ? crossedUp : alert.condition === "crossing_down" ? crossedDown : crossedUp || crossedDown;
234
261
  if (shouldTrigger) {
235
- changed = true;
236
- const triggered = { ...alert, triggered: true };
237
- alertTriggeredListenerRef.current?.(triggered);
238
- return triggered;
262
+ triggeredIds.push(alert.id);
263
+ alertTriggeredListenerRef.current?.({ ...alert, triggered: true });
239
264
  }
240
- return alert;
241
- });
242
- if (changed) {
243
- enhancedDispatch({ type: "SET_ALERTS", alerts: next });
265
+ }
266
+ if (triggeredIds.length > 0) {
267
+ enhancedDispatch({
268
+ type: "MARK_ALERT_TRIGGERED",
269
+ ids: triggeredIds
270
+ });
244
271
  }
245
272
  }, 1e3);
246
273
  return () => clearInterval(interval);
247
274
  }, [state.chart, hasAlerts, enhancedDispatch]);
275
+ react.useEffect(() => {
276
+ alertPrevCloseRef.current = null;
277
+ }, [state.symbol, state.period]);
248
278
  react.useEffect(() => {
249
279
  return () => {
250
280
  if (replayIntervalRef.current !== null) {
@@ -256,8 +286,8 @@ function KlinechartsUIProvider({
256
286
  const dispatchValue = react.useMemo(
257
287
  () => ({
258
288
  dispatch: enhancedDispatch,
259
- datafeed,
260
- onSettingsChange,
289
+ datafeed: datafeedRef.current,
290
+ onSettingsChange: onSettingsChangeRef.current,
261
291
  fullscreenContainerRef,
262
292
  undoRedoListenerRef,
263
293
  alertTriggeredListenerRef,
@@ -265,7 +295,8 @@ function KlinechartsUIProvider({
265
295
  replaySavedDataRef,
266
296
  replayIndexRef
267
297
  }),
268
- [enhancedDispatch, datafeed, onSettingsChange]
298
+ // eslint-disable-next-line react-hooks/exhaustive-deps
299
+ [enhancedDispatch]
269
300
  );
270
301
  return /* @__PURE__ */ jsxRuntime.jsx(KlinechartsUIStateContext.Provider, { value: state, children: /* @__PURE__ */ jsxRuntime.jsx(KlinechartsUIDispatchContext.Provider, { value: dispatchValue, children }) });
271
302
  }
@@ -1223,15 +1254,17 @@ function useDrawingTools() {
1223
1254
  const [isVisible, setIsVisible] = react.useState(true);
1224
1255
  const [autoRetrigger, setAutoRetrigger] = react.useState(true);
1225
1256
  const activeToolRef = react.useRef(activeTool);
1226
- activeToolRef.current = activeTool;
1227
1257
  const autoRetriggerRef = react.useRef(autoRetrigger);
1228
- autoRetriggerRef.current = autoRetrigger;
1229
1258
  const isLockedRef = react.useRef(isLocked);
1230
- isLockedRef.current = isLocked;
1231
1259
  const isVisibleRef = react.useRef(isVisible);
1232
- isVisibleRef.current = isVisible;
1233
1260
  const magnetModeRef = react.useRef(magnetMode);
1234
- magnetModeRef.current = magnetMode;
1261
+ react.useEffect(() => {
1262
+ activeToolRef.current = activeTool;
1263
+ autoRetriggerRef.current = autoRetrigger;
1264
+ isLockedRef.current = isLocked;
1265
+ isVisibleRef.current = isVisible;
1266
+ magnetModeRef.current = magnetMode;
1267
+ });
1235
1268
  const categories = react.useMemo(
1236
1269
  () => DRAWING_CATEGORIES.map((cat) => ({
1237
1270
  key: cat.key,
@@ -1242,6 +1275,8 @@ function useDrawingTools() {
1242
1275
  })),
1243
1276
  []
1244
1277
  );
1278
+ const createOverlayForToolRef = react.useRef(() => {
1279
+ });
1245
1280
  const createOverlayForTool = react.useCallback(
1246
1281
  (name) => {
1247
1282
  const mode = magnetModeRef.current === "strong" ? "strong_magnet" : magnetModeRef.current === "weak" ? "weak_magnet" : "normal";
@@ -1267,7 +1302,7 @@ function useDrawingTools() {
1267
1302
  });
1268
1303
  if (autoRetriggerRef.current && activeToolRef.current === name) {
1269
1304
  requestAnimationFrame(() => {
1270
- createOverlayForTool(name);
1305
+ createOverlayForToolRef.current(name);
1271
1306
  });
1272
1307
  }
1273
1308
  }
@@ -1275,6 +1310,9 @@ function useDrawingTools() {
1275
1310
  },
1276
1311
  [state.chart, undoRedoListenerRef]
1277
1312
  );
1313
+ react.useEffect(() => {
1314
+ createOverlayForToolRef.current = createOverlayForTool;
1315
+ });
1278
1316
  const selectTool = react.useCallback(
1279
1317
  (name) => {
1280
1318
  setActiveTool(name);
@@ -1678,28 +1716,81 @@ function useScreenshot() {
1678
1716
  clear
1679
1717
  };
1680
1718
  }
1719
+ function useHotkeys() {
1720
+ const { state } = useKlinechartsUI();
1721
+ const registerHotkey = react.useCallback((template) => {
1722
+ klinecharts.registerHotkey(template);
1723
+ }, []);
1724
+ const getHotkey = react.useCallback(
1725
+ (name) => klinecharts.getHotkey(name) ?? null,
1726
+ []
1727
+ );
1728
+ const setHotkeysEnabled = react.useCallback(
1729
+ (enabled, exclude) => {
1730
+ state.chart?.setHotkey(
1731
+ exclude ? { enabled, exclude } : { enabled }
1732
+ );
1733
+ },
1734
+ [state.chart]
1735
+ );
1736
+ const getHotkeysConfig = react.useCallback(
1737
+ () => state.chart?.getHotkey() ?? null,
1738
+ [state.chart]
1739
+ );
1740
+ return {
1741
+ registerHotkey,
1742
+ getHotkey,
1743
+ supportedHotkeys: klinecharts.getSupportedHotkeys(),
1744
+ setHotkeysEnabled,
1745
+ getHotkeysConfig
1746
+ };
1747
+ }
1748
+ function useChartAxes() {
1749
+ const { state } = useKlinechartsUI();
1750
+ const overrideXAxis = react.useCallback(
1751
+ (override) => {
1752
+ if (!state.chart) return;
1753
+ state.chart.overrideXAxis(override);
1754
+ },
1755
+ [state.chart]
1756
+ );
1757
+ const overrideYAxis = react.useCallback(
1758
+ (override) => {
1759
+ if (!state.chart) return;
1760
+ state.chart.overrideYAxis(override);
1761
+ },
1762
+ [state.chart]
1763
+ );
1764
+ return { overrideXAxis, overrideYAxis };
1765
+ }
1681
1766
  function useFullscreen() {
1682
1767
  const { fullscreenContainerRef } = useKlinechartsUIDispatch();
1683
1768
  const [isFullscreen, setIsFullscreen] = react.useState(false);
1684
1769
  const enter = react.useCallback(() => {
1685
1770
  const el = fullscreenContainerRef.current;
1686
1771
  if (!el) return;
1772
+ let result;
1687
1773
  if (el.requestFullscreen) {
1688
- el.requestFullscreen();
1774
+ result = el.requestFullscreen();
1689
1775
  } else if ("webkitRequestFullscreen" in el) {
1690
1776
  el.webkitRequestFullscreen();
1691
1777
  } else if ("msRequestFullscreen" in el) {
1692
1778
  el.msRequestFullscreen();
1693
1779
  }
1780
+ result?.catch(() => {
1781
+ });
1694
1782
  }, [fullscreenContainerRef]);
1695
1783
  const exit = react.useCallback(() => {
1784
+ let result;
1696
1785
  if (document.exitFullscreen) {
1697
- document.exitFullscreen();
1786
+ result = document.exitFullscreen();
1698
1787
  } else if ("webkitExitFullscreen" in document) {
1699
1788
  document.webkitExitFullscreen();
1700
1789
  } else if ("msExitFullscreen" in document) {
1701
1790
  document.msExitFullscreen();
1702
1791
  }
1792
+ result?.catch(() => {
1793
+ });
1703
1794
  }, []);
1704
1795
  const toggle = react.useCallback(() => {
1705
1796
  if (isFullscreen) {
@@ -1730,6 +1821,7 @@ function useFullscreen() {
1730
1821
  function useOrderLines() {
1731
1822
  const { state } = useKlinechartsUI();
1732
1823
  const callbacksRef = react.useRef(/* @__PURE__ */ new Map());
1824
+ const ownedIdsRef = react.useRef(/* @__PURE__ */ new Set());
1733
1825
  const createOrderLine = react.useCallback(
1734
1826
  (options) => {
1735
1827
  if (!state.chart) return null;
@@ -1760,6 +1852,7 @@ function useOrderLines() {
1760
1852
  }
1761
1853
  }
1762
1854
  });
1855
+ ownedIdsRef.current.add(id);
1763
1856
  return id;
1764
1857
  },
1765
1858
  [state.chart]
@@ -1791,12 +1884,28 @@ function useOrderLines() {
1791
1884
  (id) => {
1792
1885
  state.chart?.removeOverlay({ id });
1793
1886
  callbacksRef.current.delete(id);
1887
+ ownedIdsRef.current.delete(id);
1794
1888
  },
1795
1889
  [state.chart]
1796
1890
  );
1797
1891
  const removeAllOrderLines = react.useCallback(() => {
1798
1892
  state.chart?.removeOverlay({ name: "orderLine" });
1799
1893
  callbacksRef.current.clear();
1894
+ ownedIdsRef.current.clear();
1895
+ }, [state.chart]);
1896
+ react.useEffect(() => {
1897
+ const chart = state.chart;
1898
+ const owned = ownedIdsRef.current;
1899
+ return () => {
1900
+ owned.forEach((id) => {
1901
+ try {
1902
+ chart?.removeOverlay({ id });
1903
+ } catch {
1904
+ }
1905
+ });
1906
+ owned.clear();
1907
+ callbacksRef.current.clear();
1908
+ };
1800
1909
  }, [state.chart]);
1801
1910
  return {
1802
1911
  createOrderLine,
@@ -1814,6 +1923,14 @@ function useUndoRedo() {
1814
1923
  const isProcessingRef = react.useRef(false);
1815
1924
  const canUndo = undoStack.length > 0;
1816
1925
  const canRedo = redoStack.length > 0;
1926
+ const undoStackRef = react.useRef([]);
1927
+ const redoStackRef = react.useRef([]);
1928
+ react.useEffect(() => {
1929
+ undoStackRef.current = undoStack;
1930
+ }, [undoStack]);
1931
+ react.useEffect(() => {
1932
+ redoStackRef.current = redoStack;
1933
+ }, [redoStack]);
1817
1934
  const pushAction = react.useCallback((action) => {
1818
1935
  if (isProcessingRef.current) return;
1819
1936
  setUndoStack((prev) => [...prev, action]);
@@ -1830,10 +1947,11 @@ function useUndoRedo() {
1830
1947
  setRedoStack([]);
1831
1948
  }, []);
1832
1949
  const undo = react.useCallback(() => {
1833
- if (undoStack.length === 0 || !state.chart || isProcessingRef.current)
1950
+ const stack = undoStackRef.current;
1951
+ if (stack.length === 0 || !state.chart || isProcessingRef.current)
1834
1952
  return;
1835
1953
  isProcessingRef.current = true;
1836
- const action = undoStack[undoStack.length - 1];
1954
+ const action = stack[stack.length - 1];
1837
1955
  setUndoStack((prev) => prev.slice(0, -1));
1838
1956
  try {
1839
1957
  switch (action.type) {
@@ -1954,12 +2072,13 @@ function useUndoRedo() {
1954
2072
  } finally {
1955
2073
  isProcessingRef.current = false;
1956
2074
  }
1957
- }, [undoStack, state.chart, state.mainIndicators, state.subIndicators, state.indicatorAxes, dispatch]);
2075
+ }, [state.chart, state.mainIndicators, state.subIndicators, state.indicatorAxes, dispatch]);
1958
2076
  const redo = react.useCallback(() => {
1959
- if (redoStack.length === 0 || !state.chart || isProcessingRef.current)
2077
+ const stack = redoStackRef.current;
2078
+ if (stack.length === 0 || !state.chart || isProcessingRef.current)
1960
2079
  return;
1961
2080
  isProcessingRef.current = true;
1962
- const action = redoStack[redoStack.length - 1];
2081
+ const action = stack[stack.length - 1];
1963
2082
  setRedoStack((prev) => prev.slice(0, -1));
1964
2083
  try {
1965
2084
  switch (action.type) {
@@ -2084,7 +2203,7 @@ function useUndoRedo() {
2084
2203
  } finally {
2085
2204
  isProcessingRef.current = false;
2086
2205
  }
2087
- }, [redoStack, state.chart, state.mainIndicators, state.subIndicators, state.indicatorAxes, dispatch]);
2206
+ }, [state.chart, state.mainIndicators, state.subIndicators, state.indicatorAxes, dispatch]);
2088
2207
  react.useEffect(() => {
2089
2208
  const handleKeyDown = (e) => {
2090
2209
  const isCtrlOrMeta = e.ctrlKey || e.metaKey;
@@ -2122,6 +2241,7 @@ function generateId() {
2122
2241
  );
2123
2242
  }
2124
2243
  function getLayoutIds() {
2244
+ if (typeof localStorage === "undefined") return [];
2125
2245
  try {
2126
2246
  const raw = localStorage.getItem(INDEX_KEY);
2127
2247
  return raw ? JSON.parse(raw) : [];
@@ -2130,6 +2250,7 @@ function getLayoutIds() {
2130
2250
  }
2131
2251
  }
2132
2252
  function getEntry(id) {
2253
+ if (typeof localStorage === "undefined") return null;
2133
2254
  try {
2134
2255
  const raw = localStorage.getItem(STORAGE_KEY_PREFIX + id);
2135
2256
  return raw ? JSON.parse(raw) : null;
@@ -2139,35 +2260,31 @@ function getEntry(id) {
2139
2260
  }
2140
2261
  function useLayoutManager() {
2141
2262
  const { state, dispatch } = useKlinechartsUI();
2142
- const [layouts, setLayouts] = react.useState([]);
2263
+ const [layouts, setLayouts] = react.useState(
2264
+ () => getLayoutIds().map((id) => getEntry(id)).filter((e) => e !== null)
2265
+ );
2143
2266
  const [autoSaveEnabled, setAutoSaveEnabled] = react.useState(false);
2144
2267
  const autoSaveTimerRef = react.useRef(null);
2145
2268
  const autoSaveIdRef = react.useRef(null);
2146
2269
  const refreshLayouts = react.useCallback(() => {
2147
- const entries = getLayoutIds().map((id) => getEntry(id)).filter((e) => e !== null);
2148
- setLayouts(entries);
2270
+ setLayouts(
2271
+ getLayoutIds().map((id) => getEntry(id)).filter((e) => e !== null)
2272
+ );
2149
2273
  }, []);
2150
- react.useEffect(() => {
2151
- refreshLayouts();
2152
- }, [refreshLayouts]);
2153
2274
  const serializeState = react.useCallback(() => {
2154
2275
  const chart = state.chart;
2155
2276
  if (!chart) return null;
2156
2277
  const indicators2 = [];
2157
- const indicatorMap = chart.getIndicatorByPaneId?.();
2158
- if (indicatorMap) {
2159
- indicatorMap.forEach((paneIndicators, paneId) => {
2160
- paneIndicators.forEach((indicator) => {
2161
- const yAxisId = state.indicatorAxes[indicator.id];
2162
- indicators2.push({
2163
- paneId,
2164
- name: indicator.name,
2165
- calcParams: indicator.calcParams,
2166
- visible: indicator.visible,
2167
- ...indicator.styles ? { styles: indicator.styles } : {},
2168
- ...yAxisId ? { yAxisId } : {}
2169
- });
2170
- });
2278
+ const allIndicators = chart.getIndicators();
2279
+ for (const indicator of allIndicators) {
2280
+ const yAxisId = state.indicatorAxes[indicator.id];
2281
+ indicators2.push({
2282
+ paneId: indicator.paneId,
2283
+ name: indicator.name,
2284
+ calcParams: indicator.calcParams,
2285
+ visible: indicator.visible,
2286
+ ...indicator.styles ? { styles: indicator.styles } : {},
2287
+ ...yAxisId ? { yAxisId } : {}
2171
2288
  });
2172
2289
  }
2173
2290
  const drawings = [];
@@ -2231,13 +2348,8 @@ function useLayoutManager() {
2231
2348
  if (chartState.version !== STATE_VERSION) return false;
2232
2349
  const chart = state.chart;
2233
2350
  chart.removeOverlay();
2234
- const indicatorMap = chart.getIndicatorByPaneId?.();
2235
- if (indicatorMap) {
2236
- indicatorMap.forEach((_paneIndicators, paneId) => {
2237
- _paneIndicators.forEach((_, indicatorName) => {
2238
- chart.removeIndicator({ paneId, name: indicatorName });
2239
- });
2240
- });
2351
+ for (const indicator of chart.getIndicators()) {
2352
+ chart.removeIndicator({ id: indicator.id });
2241
2353
  }
2242
2354
  const newMainIndicators = [];
2243
2355
  const newSubIndicators = {};
@@ -2255,7 +2367,12 @@ function useLayoutManager() {
2255
2367
  visible: ind.visible
2256
2368
  },
2257
2369
  {
2258
- isStack: ind.paneId !== "candle_pane",
2370
+ // Main indicators stack OVER the candle series on the candle
2371
+ // pane (isStack: true), exactly as useIndicators does on the
2372
+ // add path. The previous `ind.paneId !== "candle_pane"` inverted
2373
+ // this, so loading a layout with main indicators replaced the
2374
+ // candles instead of overlaying them.
2375
+ isStack: isMain,
2259
2376
  pane: { id: ind.paneId },
2260
2377
  ...ind.yAxisId ? { yAxis: { id: ind.yAxisId } } : {}
2261
2378
  }
@@ -2455,8 +2572,10 @@ function useScriptEditor() {
2455
2572
  const [status, setStatus] = react.useState("");
2456
2573
  const [isRunning, setIsRunning] = react.useState(false);
2457
2574
  const activeIdRef = react.useRef(null);
2575
+ const [activeName, setActiveName] = react.useState(null);
2458
2576
  const activeNameRef = react.useRef(null);
2459
- const hasActiveScript = activeNameRef.current !== null;
2577
+ activeNameRef.current = activeName;
2578
+ const hasActiveScript = activeName !== null;
2460
2579
  const runScript = react.useCallback(() => {
2461
2580
  const chart = state.chart;
2462
2581
  if (!chart) {
@@ -2477,31 +2596,38 @@ function useScriptEditor() {
2477
2596
  `"use strict";
2478
2597
  ${code}`
2479
2598
  ];
2480
- const fn = new Function(...allArgs);
2599
+ const compiledFn = new Function(...allArgs);
2481
2600
  const shadowValues = SHADOW_KEYS.map(() => void 0);
2482
- const result = fn(...shadowValues, chunkUJNJH3BS_cjs.TA_default, dataList, parsedParams);
2483
- if (!Array.isArray(result)) {
2601
+ const sampleResult = compiledFn(
2602
+ ...shadowValues,
2603
+ chunkLGYYJ2GP_cjs.TA_default,
2604
+ dataList,
2605
+ parsedParams
2606
+ );
2607
+ if (!Array.isArray(sampleResult)) {
2484
2608
  throw new Error("Script must return an Array.");
2485
2609
  }
2486
- const sample = result.find((v) => v !== null && v !== void 0);
2610
+ const sample = sampleResult.find(
2611
+ (v) => v !== null && v !== void 0
2612
+ );
2487
2613
  const seriesKeys = sample ? Object.keys(sample) : ["value"];
2488
2614
  if (seriesKeys.length === 0) {
2489
2615
  throw new Error("Returned objects have no keys.");
2490
2616
  }
2491
2617
  scriptCounter++;
2492
- const indicatorName = `_custom_script_${scriptCounter}`;
2618
+ const indicatorName = `_custom_script_active`;
2493
2619
  const figures = seriesKeys.map((key, i) => ({
2494
2620
  key,
2495
2621
  title: `${key}: `,
2496
2622
  type: "line",
2497
2623
  styles: () => ({ color: SERIES_COLORS[i % SERIES_COLORS.length] })
2498
2624
  }));
2499
- reactKlinecharts.registerIndicator({
2625
+ klinecharts.registerIndicator({
2500
2626
  name: indicatorName,
2501
2627
  shortName: (scriptName.trim() || `Script #${scriptCounter}`) + (placement === "main" ? " (Main)" : " (Sub)"),
2502
2628
  calcParams: parsedParams,
2503
2629
  figures,
2504
- calc: () => result,
2630
+ calc: (liveDataList) => compiledFn(...shadowValues, chunkLGYYJ2GP_cjs.TA_default, liveDataList, parsedParams),
2505
2631
  extendData: {
2506
2632
  isCustomScript: true,
2507
2633
  code,
@@ -2527,7 +2653,7 @@ ${code}`
2527
2653
  paneId = chart.createIndicator({ name: indicatorName });
2528
2654
  }
2529
2655
  activeIdRef.current = typeof paneId === "string" ? paneId : null;
2530
- activeNameRef.current = indicatorName;
2656
+ setActiveName(indicatorName);
2531
2657
  const title = scriptName.trim() || `Script #${scriptCounter}`;
2532
2658
  setStatus(
2533
2659
  `${title} applied to ${placement === "main" ? "Main Chart" : "Sub Pane"} \u2014 ${seriesKeys.length} series: ${seriesKeys.join(", ")}`
@@ -2549,7 +2675,7 @@ ${code}`
2549
2675
  } catch {
2550
2676
  }
2551
2677
  activeIdRef.current = null;
2552
- activeNameRef.current = null;
2678
+ setActiveName(null);
2553
2679
  setStatus("Indicator removed.");
2554
2680
  }
2555
2681
  }, [state.chart]);
@@ -2666,52 +2792,48 @@ function useAlerts() {
2666
2792
  const { alertTriggeredListenerRef } = useKlinechartsUIDispatch();
2667
2793
  const alerts = state.alerts;
2668
2794
  const addAlert = react.useCallback(
2669
- (price, condition, message) => {
2795
+ (price, condition, message, extendData) => {
2670
2796
  const id = `alert_${++alertCounter}`;
2797
+ const precision = state.chart?.getSymbol()?.pricePrecision ?? 2;
2798
+ const resolvedExtendData = {
2799
+ ...extendData,
2800
+ text: extendData?.text ?? message ?? price.toFixed(precision)
2801
+ };
2671
2802
  const alert = {
2672
2803
  id,
2673
2804
  price,
2674
2805
  condition,
2675
2806
  message,
2676
- triggered: false
2807
+ triggered: false,
2808
+ extendData: resolvedExtendData
2677
2809
  };
2678
- dispatch({ type: "SET_ALERTS", alerts: [...state.alerts, alert] });
2810
+ dispatch({ type: "ADD_ALERT", alert });
2679
2811
  if (state.chart) {
2812
+ chunkLGYYJ2GP_cjs.ensureAlertLineRegistered();
2680
2813
  state.chart.createOverlay({
2681
- name: "horizontalStraightLine",
2814
+ name: "alertLine",
2682
2815
  id,
2683
2816
  groupId: "price_alerts",
2684
2817
  points: [{ value: price }],
2685
- styles: {
2686
- line: {
2687
- style: "dashed",
2688
- color: "#ff9800",
2689
- size: 1
2690
- }
2691
- },
2818
+ extendData: resolvedExtendData,
2692
2819
  lock: true
2693
2820
  });
2694
2821
  }
2695
2822
  return id;
2696
2823
  },
2697
- [state.chart, state.alerts, dispatch]
2824
+ [state.chart, dispatch]
2698
2825
  );
2699
2826
  const removeAlert = react.useCallback(
2700
2827
  (id) => {
2701
- dispatch({
2702
- type: "SET_ALERTS",
2703
- alerts: state.alerts.filter((a) => a.id !== id)
2704
- });
2828
+ dispatch({ type: "REMOVE_ALERT", id });
2705
2829
  state.chart?.removeOverlay({ id });
2706
2830
  },
2707
- [state.chart, state.alerts, dispatch]
2831
+ [state.chart, dispatch]
2708
2832
  );
2709
2833
  const clearAlerts = react.useCallback(() => {
2710
- for (const alert of state.alerts) {
2711
- state.chart?.removeOverlay({ id: alert.id });
2712
- }
2713
- dispatch({ type: "SET_ALERTS", alerts: [] });
2714
- }, [state.chart, state.alerts, dispatch]);
2834
+ state.chart?.removeOverlay({ groupId: "price_alerts" });
2835
+ dispatch({ type: "CLEAR_ALERTS" });
2836
+ }, [state.chart, dispatch]);
2715
2837
  const onAlertTriggered = react.useCallback(
2716
2838
  (callback) => {
2717
2839
  alertTriggeredListenerRef.current = callback;
@@ -2895,6 +3017,7 @@ function useReplay() {
2895
3017
  );
2896
3018
  const startReplay = react.useCallback(() => {
2897
3019
  if (!state.chart) return;
3020
+ if (isReplaying) return;
2898
3021
  const dataList = state.chart.getDataList();
2899
3022
  if (!dataList || dataList.length === 0) return;
2900
3023
  replaySavedDataRef.current = [...dataList];
@@ -2910,7 +3033,12 @@ function useReplay() {
2910
3033
  });
2911
3034
  state.chart.clearData?.();
2912
3035
  startInterval(speed);
2913
- }, [state.chart, speed, startInterval, replaySavedDataRef, replayIndexRef, dispatch]);
3036
+ }, [state.chart, state.symbol, state.period, speed, startInterval, isReplaying, replaySavedDataRef, replayIndexRef, dispatch]);
3037
+ react.useEffect(() => {
3038
+ if (isReplaying) {
3039
+ stopReplay();
3040
+ }
3041
+ }, [state.symbol, state.period]);
2914
3042
  const stopReplay = react.useCallback(() => {
2915
3043
  if (!state.chart) return;
2916
3044
  clearInterval_();
@@ -3006,24 +3134,29 @@ var DEFAULT_COLORS = [
3006
3134
  "#ff5722",
3007
3135
  "#8bc34a"
3008
3136
  ];
3009
- var colorIndex = 0;
3010
- var compareCounter = 0;
3011
3137
  function useCompare() {
3012
3138
  const { state, datafeed } = useKlinechartsUI();
3013
3139
  const [symbols, setSymbols] = react.useState([]);
3014
3140
  const indicatorsRef = react.useRef(/* @__PURE__ */ new Map());
3141
+ const instanceSalt = react.useId().replace(/[^a-zA-Z0-9]/g, "");
3015
3142
  const addSymbol = react.useCallback(
3016
3143
  async (ticker, color) => {
3017
3144
  if (!state.chart || !datafeed) return;
3018
3145
  if (indicatorsRef.current.has(ticker)) return;
3019
- const assignedColor = color ?? DEFAULT_COLORS[colorIndex++ % DEFAULT_COLORS.length];
3146
+ const assignedColor = color ?? DEFAULT_COLORS[symbols.length % DEFAULT_COLORS.length];
3020
3147
  const mainDataList = state.chart.getDataList();
3021
3148
  if (!mainDataList || mainDataList.length === 0) return;
3022
3149
  const from = mainDataList[0].timestamp;
3023
3150
  const to = mainDataList[mainDataList.length - 1].timestamp;
3151
+ const mainSymbol = state.symbol;
3152
+ const symbol = {
3153
+ ticker,
3154
+ pricePrecision: mainSymbol?.pricePrecision ?? 2,
3155
+ volumePrecision: mainSymbol?.volumePrecision ?? 8
3156
+ };
3024
3157
  const compareData = await datafeed.getHistoryKLineData(
3025
- { ticker },
3026
- { ...state.period, label: "" },
3158
+ symbol,
3159
+ state.period,
3027
3160
  from,
3028
3161
  to
3029
3162
  );
@@ -3042,14 +3175,8 @@ function useCompare() {
3042
3175
  }
3043
3176
  if (basePrice === null || basePrice === 0) return;
3044
3177
  const bp = basePrice;
3045
- const normalizedData = mainDataList.map((mainBar) => {
3046
- const close = compareMap.get(mainBar.timestamp);
3047
- return {
3048
- pct: close != null ? (close - bp) / bp * 100 : NaN
3049
- };
3050
- });
3051
- const indicatorName = `__cmp_${++compareCounter}_${ticker}`;
3052
- reactKlinecharts.registerIndicator({
3178
+ const indicatorName = `__cmp_${instanceSalt}_${ticker}`;
3179
+ klinecharts.registerIndicator({
3053
3180
  name: indicatorName,
3054
3181
  shortName: ticker,
3055
3182
  figures: [
@@ -3060,7 +3187,16 @@ function useCompare() {
3060
3187
  styles: () => ({ color: assignedColor })
3061
3188
  }
3062
3189
  ],
3063
- calc: () => normalizedData
3190
+ calc: (dataList) => {
3191
+ let lastPct = null;
3192
+ return dataList.map((bar) => {
3193
+ const close = compareMap.get(bar.timestamp);
3194
+ if (close != null) {
3195
+ lastPct = (close - bp) / bp * 100;
3196
+ }
3197
+ return { pct: lastPct };
3198
+ });
3199
+ }
3064
3200
  });
3065
3201
  const paneId = state.chart.createIndicator(
3066
3202
  { name: indicatorName },
@@ -3078,7 +3214,7 @@ function useCompare() {
3078
3214
  ];
3079
3215
  });
3080
3216
  },
3081
- [state.chart, state.period, datafeed]
3217
+ [state.chart, state.symbol, state.period, datafeed, symbols.length, instanceSalt]
3082
3218
  );
3083
3219
  const removeSymbol = react.useCallback(
3084
3220
  (ticker) => {
@@ -3288,13 +3424,11 @@ function useAnnotations() {
3288
3424
  [state.chart]
3289
3425
  );
3290
3426
  const clearAnnotations = react.useCallback(() => {
3291
- setAnnotations((prev) => {
3292
- for (const annotation of prev) {
3293
- state.chart?.removeOverlay({ id: annotation.id });
3294
- }
3295
- return [];
3296
- });
3297
- }, [state.chart]);
3427
+ for (const annotation of annotations) {
3428
+ state.chart?.removeOverlay({ id: annotation.id });
3429
+ }
3430
+ setAnnotations([]);
3431
+ }, [state.chart, annotations]);
3298
3432
  react.useEffect(() => {
3299
3433
  return () => {
3300
3434
  state.chart?.removeOverlay({ groupId: "annotations" });
@@ -3375,175 +3509,179 @@ function createDataLoader(datafeed, dispatch) {
3375
3509
 
3376
3510
  Object.defineProperty(exports, "TA", {
3377
3511
  enumerable: true,
3378
- get: function () { return chunkUJNJH3BS_cjs.TA_default; }
3512
+ get: function () { return chunkLGYYJ2GP_cjs.TA_default; }
3379
3513
  });
3380
3514
  Object.defineProperty(exports, "abcd", {
3381
3515
  enumerable: true,
3382
- get: function () { return chunkUJNJH3BS_cjs.abcd_default; }
3516
+ get: function () { return chunkLGYYJ2GP_cjs.abcd_default; }
3517
+ });
3518
+ Object.defineProperty(exports, "alertLine", {
3519
+ enumerable: true,
3520
+ get: function () { return chunkLGYYJ2GP_cjs.alertLine_default; }
3383
3521
  });
3384
3522
  Object.defineProperty(exports, "anyWaves", {
3385
3523
  enumerable: true,
3386
- get: function () { return chunkUJNJH3BS_cjs.anyWaves_default; }
3524
+ get: function () { return chunkLGYYJ2GP_cjs.anyWaves_default; }
3387
3525
  });
3388
3526
  Object.defineProperty(exports, "arrow", {
3389
3527
  enumerable: true,
3390
- get: function () { return chunkUJNJH3BS_cjs.arrow_default; }
3528
+ get: function () { return chunkLGYYJ2GP_cjs.arrow_default; }
3391
3529
  });
3392
3530
  Object.defineProperty(exports, "bollTv", {
3393
3531
  enumerable: true,
3394
- get: function () { return chunkUJNJH3BS_cjs.bollTv_default; }
3532
+ get: function () { return chunkLGYYJ2GP_cjs.bollTv_default; }
3395
3533
  });
3396
3534
  Object.defineProperty(exports, "brush", {
3397
3535
  enumerable: true,
3398
- get: function () { return chunkUJNJH3BS_cjs.brush_default; }
3536
+ get: function () { return chunkLGYYJ2GP_cjs.brush_default; }
3399
3537
  });
3400
3538
  Object.defineProperty(exports, "cci", {
3401
3539
  enumerable: true,
3402
- get: function () { return chunkUJNJH3BS_cjs.cci_default; }
3540
+ get: function () { return chunkLGYYJ2GP_cjs.cci_default; }
3403
3541
  });
3404
3542
  Object.defineProperty(exports, "circle", {
3405
3543
  enumerable: true,
3406
- get: function () { return chunkUJNJH3BS_cjs.circle_default; }
3544
+ get: function () { return chunkLGYYJ2GP_cjs.circle_default; }
3407
3545
  });
3408
3546
  Object.defineProperty(exports, "depthOverlay", {
3409
3547
  enumerable: true,
3410
- get: function () { return chunkUJNJH3BS_cjs.depthOverlay_default; }
3548
+ get: function () { return chunkLGYYJ2GP_cjs.depthOverlay_default; }
3411
3549
  });
3412
3550
  Object.defineProperty(exports, "eightWaves", {
3413
3551
  enumerable: true,
3414
- get: function () { return chunkUJNJH3BS_cjs.eightWaves_default; }
3552
+ get: function () { return chunkLGYYJ2GP_cjs.eightWaves_default; }
3415
3553
  });
3416
3554
  Object.defineProperty(exports, "elliottWave", {
3417
3555
  enumerable: true,
3418
- get: function () { return chunkUJNJH3BS_cjs.elliottWave_default; }
3556
+ get: function () { return chunkLGYYJ2GP_cjs.elliottWave_default; }
3419
3557
  });
3420
3558
  Object.defineProperty(exports, "fibRetracement", {
3421
3559
  enumerable: true,
3422
- get: function () { return chunkUJNJH3BS_cjs.fibRetracement_default; }
3560
+ get: function () { return chunkLGYYJ2GP_cjs.fibRetracement_default; }
3423
3561
  });
3424
3562
  Object.defineProperty(exports, "fibonacciCircle", {
3425
3563
  enumerable: true,
3426
- get: function () { return chunkUJNJH3BS_cjs.fibonacciCircle_default; }
3564
+ get: function () { return chunkLGYYJ2GP_cjs.fibonacciCircle_default; }
3427
3565
  });
3428
3566
  Object.defineProperty(exports, "fibonacciExtension", {
3429
3567
  enumerable: true,
3430
- get: function () { return chunkUJNJH3BS_cjs.fibonacciExtension_default; }
3568
+ get: function () { return chunkLGYYJ2GP_cjs.fibonacciExtension_default; }
3431
3569
  });
3432
3570
  Object.defineProperty(exports, "fibonacciSegment", {
3433
3571
  enumerable: true,
3434
- get: function () { return chunkUJNJH3BS_cjs.fibonacciSegment_default; }
3572
+ get: function () { return chunkLGYYJ2GP_cjs.fibonacciSegment_default; }
3435
3573
  });
3436
3574
  Object.defineProperty(exports, "fibonacciSpeedResistanceFan", {
3437
3575
  enumerable: true,
3438
- get: function () { return chunkUJNJH3BS_cjs.fibonacciSpeedResistanceFan_default; }
3576
+ get: function () { return chunkLGYYJ2GP_cjs.fibonacciSpeedResistanceFan_default; }
3439
3577
  });
3440
3578
  Object.defineProperty(exports, "fibonacciSpiral", {
3441
3579
  enumerable: true,
3442
- get: function () { return chunkUJNJH3BS_cjs.fibonacciSpiral_default; }
3580
+ get: function () { return chunkLGYYJ2GP_cjs.fibonacciSpiral_default; }
3443
3581
  });
3444
3582
  Object.defineProperty(exports, "fiveWaves", {
3445
3583
  enumerable: true,
3446
- get: function () { return chunkUJNJH3BS_cjs.fiveWaves_default; }
3584
+ get: function () { return chunkLGYYJ2GP_cjs.fiveWaves_default; }
3447
3585
  });
3448
3586
  Object.defineProperty(exports, "gannBox", {
3449
3587
  enumerable: true,
3450
- get: function () { return chunkUJNJH3BS_cjs.gannBox_default; }
3588
+ get: function () { return chunkLGYYJ2GP_cjs.gannBox_default; }
3451
3589
  });
3452
3590
  Object.defineProperty(exports, "gannFan", {
3453
3591
  enumerable: true,
3454
- get: function () { return chunkUJNJH3BS_cjs.gannFan_default; }
3592
+ get: function () { return chunkLGYYJ2GP_cjs.gannFan_default; }
3455
3593
  });
3456
3594
  Object.defineProperty(exports, "hma", {
3457
3595
  enumerable: true,
3458
- get: function () { return chunkUJNJH3BS_cjs.hma_default; }
3596
+ get: function () { return chunkLGYYJ2GP_cjs.hma_default; }
3459
3597
  });
3460
3598
  Object.defineProperty(exports, "ichimoku", {
3461
3599
  enumerable: true,
3462
- get: function () { return chunkUJNJH3BS_cjs.ichimoku_default; }
3600
+ get: function () { return chunkLGYYJ2GP_cjs.ichimoku_default; }
3463
3601
  });
3464
3602
  Object.defineProperty(exports, "indicators", {
3465
3603
  enumerable: true,
3466
- get: function () { return chunkUJNJH3BS_cjs.indicators; }
3604
+ get: function () { return chunkLGYYJ2GP_cjs.indicators; }
3467
3605
  });
3468
3606
  Object.defineProperty(exports, "longPosition", {
3469
3607
  enumerable: true,
3470
- get: function () { return chunkUJNJH3BS_cjs.longPosition_default; }
3608
+ get: function () { return chunkLGYYJ2GP_cjs.longPosition_default; }
3471
3609
  });
3472
3610
  Object.defineProperty(exports, "maRibbon", {
3473
3611
  enumerable: true,
3474
- get: function () { return chunkUJNJH3BS_cjs.maRibbon_default; }
3612
+ get: function () { return chunkLGYYJ2GP_cjs.maRibbon_default; }
3475
3613
  });
3476
3614
  Object.defineProperty(exports, "macdTv", {
3477
3615
  enumerable: true,
3478
- get: function () { return chunkUJNJH3BS_cjs.macdTv_default; }
3616
+ get: function () { return chunkLGYYJ2GP_cjs.macdTv_default; }
3479
3617
  });
3480
3618
  Object.defineProperty(exports, "measure", {
3481
3619
  enumerable: true,
3482
- get: function () { return chunkUJNJH3BS_cjs.measure_default; }
3620
+ get: function () { return chunkLGYYJ2GP_cjs.measure_default; }
3483
3621
  });
3484
3622
  Object.defineProperty(exports, "orderLine", {
3485
3623
  enumerable: true,
3486
- get: function () { return chunkUJNJH3BS_cjs.orderLine_default; }
3624
+ get: function () { return chunkLGYYJ2GP_cjs.orderLine_default; }
3487
3625
  });
3488
3626
  Object.defineProperty(exports, "overlays", {
3489
3627
  enumerable: true,
3490
- get: function () { return chunkUJNJH3BS_cjs.overlays; }
3628
+ get: function () { return chunkLGYYJ2GP_cjs.overlays; }
3491
3629
  });
3492
3630
  Object.defineProperty(exports, "parallelChannel", {
3493
3631
  enumerable: true,
3494
- get: function () { return chunkUJNJH3BS_cjs.parallelChannel_default; }
3632
+ get: function () { return chunkLGYYJ2GP_cjs.parallelChannel_default; }
3495
3633
  });
3496
3634
  Object.defineProperty(exports, "parallelogram", {
3497
3635
  enumerable: true,
3498
- get: function () { return chunkUJNJH3BS_cjs.parallelogram_default; }
3636
+ get: function () { return chunkLGYYJ2GP_cjs.parallelogram_default; }
3499
3637
  });
3500
3638
  Object.defineProperty(exports, "pivotPoints", {
3501
3639
  enumerable: true,
3502
- get: function () { return chunkUJNJH3BS_cjs.pivotPoints_default; }
3640
+ get: function () { return chunkLGYYJ2GP_cjs.pivotPoints_default; }
3503
3641
  });
3504
3642
  Object.defineProperty(exports, "ray", {
3505
3643
  enumerable: true,
3506
- get: function () { return chunkUJNJH3BS_cjs.ray_default; }
3644
+ get: function () { return chunkLGYYJ2GP_cjs.ray_default; }
3507
3645
  });
3508
3646
  Object.defineProperty(exports, "rect", {
3509
3647
  enumerable: true,
3510
- get: function () { return chunkUJNJH3BS_cjs.rect_default; }
3648
+ get: function () { return chunkLGYYJ2GP_cjs.rect_default; }
3511
3649
  });
3512
3650
  Object.defineProperty(exports, "registerExtensions", {
3513
3651
  enumerable: true,
3514
- get: function () { return chunkUJNJH3BS_cjs.registerExtensions; }
3652
+ get: function () { return chunkLGYYJ2GP_cjs.registerExtensions; }
3515
3653
  });
3516
3654
  Object.defineProperty(exports, "rsiTv", {
3517
3655
  enumerable: true,
3518
- get: function () { return chunkUJNJH3BS_cjs.rsiTv_default; }
3656
+ get: function () { return chunkLGYYJ2GP_cjs.rsiTv_default; }
3519
3657
  });
3520
3658
  Object.defineProperty(exports, "shortPosition", {
3521
3659
  enumerable: true,
3522
- get: function () { return chunkUJNJH3BS_cjs.shortPosition_default; }
3660
+ get: function () { return chunkLGYYJ2GP_cjs.shortPosition_default; }
3523
3661
  });
3524
3662
  Object.defineProperty(exports, "stochastic", {
3525
3663
  enumerable: true,
3526
- get: function () { return chunkUJNJH3BS_cjs.stochastic_default; }
3664
+ get: function () { return chunkLGYYJ2GP_cjs.stochastic_default; }
3527
3665
  });
3528
3666
  Object.defineProperty(exports, "superTrend", {
3529
3667
  enumerable: true,
3530
- get: function () { return chunkUJNJH3BS_cjs.superTrend_default; }
3668
+ get: function () { return chunkLGYYJ2GP_cjs.superTrend_default; }
3531
3669
  });
3532
3670
  Object.defineProperty(exports, "threeWaves", {
3533
3671
  enumerable: true,
3534
- get: function () { return chunkUJNJH3BS_cjs.threeWaves_default; }
3672
+ get: function () { return chunkLGYYJ2GP_cjs.threeWaves_default; }
3535
3673
  });
3536
3674
  Object.defineProperty(exports, "triangle", {
3537
3675
  enumerable: true,
3538
- get: function () { return chunkUJNJH3BS_cjs.triangle_default; }
3676
+ get: function () { return chunkLGYYJ2GP_cjs.triangle_default; }
3539
3677
  });
3540
3678
  Object.defineProperty(exports, "vwap", {
3541
3679
  enumerable: true,
3542
- get: function () { return chunkUJNJH3BS_cjs.vwap_default; }
3680
+ get: function () { return chunkLGYYJ2GP_cjs.vwap_default; }
3543
3681
  });
3544
3682
  Object.defineProperty(exports, "xabcd", {
3545
3683
  enumerable: true,
3546
- get: function () { return chunkUJNJH3BS_cjs.xabcd_default; }
3684
+ get: function () { return chunkLGYYJ2GP_cjs.xabcd_default; }
3547
3685
  });
3548
3686
  exports.CANDLE_TYPES = CANDLE_TYPES;
3549
3687
  exports.COMPARE_RULES = COMPARE_RULES;
@@ -3562,11 +3700,13 @@ exports.YAXIS_POSITIONS = YAXIS_POSITIONS;
3562
3700
  exports.createDataLoader = createDataLoader;
3563
3701
  exports.useAlerts = useAlerts;
3564
3702
  exports.useAnnotations = useAnnotations;
3703
+ exports.useChartAxes = useChartAxes;
3565
3704
  exports.useCompare = useCompare;
3566
3705
  exports.useCrosshair = useCrosshair;
3567
3706
  exports.useDataExport = useDataExport;
3568
3707
  exports.useDrawingTools = useDrawingTools;
3569
3708
  exports.useFullscreen = useFullscreen;
3709
+ exports.useHotkeys = useHotkeys;
3570
3710
  exports.useIndicators = useIndicators;
3571
3711
  exports.useKlinechartsUI = useKlinechartsUI;
3572
3712
  exports.useKlinechartsUILoading = useKlinechartsUILoading;