react-klinecharts-ui 0.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 ADDED
@@ -0,0 +1,1497 @@
1
+ 'use strict';
2
+
3
+ var chunkSLTXNLKN_cjs = require('./chunk-SLTXNLKN.cjs');
4
+ var react = require('react');
5
+ var reactKlinecharts = require('react-klinecharts');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
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
+ // src/data/periods.ts
31
+ var DEFAULT_PERIODS = [
32
+ { span: 1, type: "minute", label: "1m" },
33
+ { span: 5, type: "minute", label: "5m" },
34
+ { span: 15, type: "minute", label: "15m" },
35
+ { span: 1, type: "hour", label: "1H" },
36
+ { span: 2, type: "hour", label: "2H" },
37
+ { span: 4, type: "hour", label: "4H" },
38
+ { span: 1, type: "day", label: "D" },
39
+ { span: 1, type: "week", label: "W" },
40
+ { span: 1, type: "month", label: "M" },
41
+ { span: 1, type: "year", label: "Y" }
42
+ ];
43
+ function reducer(state, action) {
44
+ switch (action.type) {
45
+ case "SET_CHART":
46
+ return { ...state, chart: action.chart };
47
+ case "SET_SYMBOL":
48
+ return { ...state, symbol: action.symbol };
49
+ case "SET_PERIOD":
50
+ return { ...state, period: action.period };
51
+ case "SET_THEME":
52
+ return { ...state, theme: action.theme };
53
+ case "SET_TIMEZONE":
54
+ return { ...state, timezone: action.timezone };
55
+ case "SET_LOADING":
56
+ return { ...state, isLoading: action.isLoading };
57
+ case "SET_MAIN_INDICATORS":
58
+ return { ...state, mainIndicators: action.indicators };
59
+ case "SET_SUB_INDICATORS":
60
+ return { ...state, subIndicators: action.indicators };
61
+ case "SET_STYLES":
62
+ return { ...state, styles: action.styles };
63
+ case "SET_LOCALE":
64
+ return { ...state, locale: action.locale };
65
+ case "SET_SCREENSHOT_URL":
66
+ return { ...state, screenshotUrl: action.url };
67
+ default:
68
+ return state;
69
+ }
70
+ }
71
+ function KlinechartsUIProvider({
72
+ datafeed,
73
+ defaultSymbol,
74
+ defaultPeriod,
75
+ defaultTheme = "light",
76
+ defaultTimezone = "Asia/Shanghai",
77
+ defaultMainIndicators = ["MA"],
78
+ defaultSubIndicators = ["VOL"],
79
+ defaultLocale = "en-US",
80
+ periods,
81
+ styles,
82
+ registerExtensions: shouldRegister = true,
83
+ overlays: extraOverlays,
84
+ children,
85
+ onStateChange,
86
+ onSymbolChange,
87
+ onPeriodChange,
88
+ onThemeChange,
89
+ onTimezoneChange,
90
+ onMainIndicatorsChange,
91
+ onSubIndicatorsChange,
92
+ onSettingsChange
93
+ }) {
94
+ const [state, dispatch] = react.useReducer(
95
+ reducer,
96
+ {
97
+ datafeed,
98
+ defaultSymbol,
99
+ defaultPeriod,
100
+ defaultTheme,
101
+ defaultTimezone,
102
+ defaultMainIndicators,
103
+ defaultSubIndicators,
104
+ defaultLocale,
105
+ periods,
106
+ styles
107
+ },
108
+ (opts) => ({
109
+ chart: null,
110
+ datafeed: opts.datafeed,
111
+ symbol: opts.defaultSymbol ?? null,
112
+ period: opts.defaultPeriod ?? (opts.periods ?? DEFAULT_PERIODS)[0],
113
+ theme: opts.defaultTheme ?? "light",
114
+ timezone: opts.defaultTimezone ?? "Asia/Shanghai",
115
+ isLoading: false,
116
+ locale: opts.defaultLocale ?? "en-US",
117
+ periods: opts.periods ?? DEFAULT_PERIODS,
118
+ mainIndicators: opts.defaultMainIndicators ?? ["MA"],
119
+ subIndicators: (opts.defaultSubIndicators ?? ["VOL"]).reduce(
120
+ (acc, name) => ({ ...acc, [name]: "" }),
121
+ {}
122
+ ),
123
+ styles: opts.styles,
124
+ screenshotUrl: null
125
+ })
126
+ );
127
+ const fullscreenContainerRef = react.useRef(null);
128
+ const stateRef = react.useRef(state);
129
+ stateRef.current = state;
130
+ const callbacksRef = react.useRef({
131
+ onStateChange,
132
+ onSymbolChange,
133
+ onPeriodChange,
134
+ onThemeChange,
135
+ onTimezoneChange,
136
+ onMainIndicatorsChange,
137
+ onSubIndicatorsChange
138
+ });
139
+ callbacksRef.current = {
140
+ onStateChange,
141
+ onSymbolChange,
142
+ onPeriodChange,
143
+ onThemeChange,
144
+ onTimezoneChange,
145
+ onMainIndicatorsChange,
146
+ onSubIndicatorsChange
147
+ };
148
+ const enhancedDispatch = react.useCallback((action) => {
149
+ const prevState = stateRef.current;
150
+ const newState = reducer(prevState, action);
151
+ stateRef.current = newState;
152
+ dispatch(action);
153
+ const cbs = callbacksRef.current;
154
+ cbs.onStateChange?.(action, newState, prevState);
155
+ switch (action.type) {
156
+ case "SET_SYMBOL":
157
+ cbs.onSymbolChange?.(action.symbol);
158
+ break;
159
+ case "SET_PERIOD":
160
+ cbs.onPeriodChange?.(action.period);
161
+ break;
162
+ case "SET_THEME":
163
+ cbs.onThemeChange?.(action.theme);
164
+ break;
165
+ case "SET_TIMEZONE":
166
+ cbs.onTimezoneChange?.(action.timezone);
167
+ break;
168
+ case "SET_MAIN_INDICATORS":
169
+ cbs.onMainIndicatorsChange?.(action.indicators);
170
+ break;
171
+ case "SET_SUB_INDICATORS":
172
+ cbs.onSubIndicatorsChange?.(action.indicators);
173
+ break;
174
+ }
175
+ }, []);
176
+ const extraOverlaysRef = react.useRef(extraOverlays);
177
+ react.useEffect(() => {
178
+ if (shouldRegister) {
179
+ chunkSLTXNLKN_cjs.registerExtensions();
180
+ }
181
+ extraOverlaysRef.current?.forEach((overlay) => reactKlinecharts.registerOverlay(overlay));
182
+ }, [shouldRegister]);
183
+ react.useEffect(() => {
184
+ if (state.chart && state.styles) {
185
+ state.chart.setStyles(state.styles);
186
+ }
187
+ }, [state.chart, state.styles]);
188
+ const dispatchValue = react.useMemo(
189
+ () => ({
190
+ dispatch: enhancedDispatch,
191
+ datafeed,
192
+ onSettingsChange,
193
+ fullscreenContainerRef
194
+ }),
195
+ [enhancedDispatch, datafeed, onSettingsChange]
196
+ );
197
+ return /* @__PURE__ */ jsxRuntime.jsx(KlinechartsUIStateContext.Provider, { value: state, children: /* @__PURE__ */ jsxRuntime.jsx(KlinechartsUIDispatchContext.Provider, { value: dispatchValue, children }) });
198
+ }
199
+ function useKlinechartsUITheme() {
200
+ const { state, dispatch } = useKlinechartsUI();
201
+ const setTheme = react.useCallback(
202
+ (theme) => {
203
+ state.chart?.setStyles(theme);
204
+ dispatch({ type: "SET_THEME", theme });
205
+ },
206
+ [state.chart, dispatch]
207
+ );
208
+ const toggleTheme = react.useCallback(() => {
209
+ const newTheme = state.theme === "light" ? "dark" : "light";
210
+ setTheme(newTheme);
211
+ }, [state.theme, setTheme]);
212
+ return {
213
+ theme: state.theme,
214
+ setTheme,
215
+ toggleTheme
216
+ };
217
+ }
218
+
219
+ // src/hooks/useKlinechartsUILoading.ts
220
+ function useKlinechartsUILoading() {
221
+ const { state } = useKlinechartsUI();
222
+ return { isLoading: state.isLoading };
223
+ }
224
+ function usePeriods() {
225
+ const { state, dispatch } = useKlinechartsUI();
226
+ const setPeriod = react.useCallback(
227
+ (period) => {
228
+ dispatch({ type: "SET_PERIOD", period });
229
+ },
230
+ [dispatch]
231
+ );
232
+ return {
233
+ periods: state.periods,
234
+ activePeriod: state.period,
235
+ setPeriod
236
+ };
237
+ }
238
+
239
+ // src/data/timezones.ts
240
+ var TIMEZONES = [
241
+ { key: "Etc/UTC", localeKey: "utc" },
242
+ { key: "Pacific/Honolulu", localeKey: "honolulu" },
243
+ { key: "America/Juneau", localeKey: "juneau" },
244
+ { key: "America/Los_Angeles", localeKey: "los_angeles" },
245
+ { key: "America/Chicago", localeKey: "chicago" },
246
+ { key: "America/Toronto", localeKey: "toronto" },
247
+ { key: "America/Sao_Paulo", localeKey: "sao_paulo" },
248
+ { key: "Europe/London", localeKey: "london" },
249
+ { key: "Europe/Berlin", localeKey: "berlin" },
250
+ { key: "Asia/Bahrain", localeKey: "bahrain" },
251
+ { key: "Asia/Dubai", localeKey: "dubai" },
252
+ { key: "Asia/Ashkhabad", localeKey: "ashkhabad" },
253
+ { key: "Asia/Almaty", localeKey: "almaty" },
254
+ { key: "Asia/Bangkok", localeKey: "bangkok" },
255
+ { key: "Asia/Shanghai", localeKey: "shanghai" },
256
+ { key: "Asia/Tokyo", localeKey: "tokyo" },
257
+ { key: "Australia/Sydney", localeKey: "sydney" },
258
+ { key: "Pacific/Norfolk", localeKey: "norfolk" }
259
+ ];
260
+
261
+ // src/hooks/useTimezone.ts
262
+ function useTimezone() {
263
+ const { state, dispatch } = useKlinechartsUI();
264
+ const timezones = react.useMemo(
265
+ () => TIMEZONES.map((tz) => ({
266
+ key: tz.key,
267
+ localeKey: tz.localeKey
268
+ })),
269
+ []
270
+ );
271
+ const setTimezone = react.useCallback(
272
+ (timezone) => {
273
+ state.chart?.setTimezone(timezone);
274
+ dispatch({ type: "SET_TIMEZONE", timezone });
275
+ },
276
+ [state.chart, dispatch]
277
+ );
278
+ return {
279
+ timezones,
280
+ activeTimezone: state.timezone,
281
+ setTimezone
282
+ };
283
+ }
284
+ function useSymbolSearch(debounceMs = 300) {
285
+ const { state, dispatch, datafeed } = useKlinechartsUI();
286
+ const [query, setQueryState] = react.useState("");
287
+ const [results, setResults] = react.useState([]);
288
+ const [isSearching, setIsSearching] = react.useState(false);
289
+ const timerRef = react.useRef(null);
290
+ const abortRef = react.useRef(null);
291
+ const setQuery = react.useCallback(
292
+ (q) => {
293
+ setQueryState(q);
294
+ if (timerRef.current) clearTimeout(timerRef.current);
295
+ abortRef.current?.abort();
296
+ abortRef.current = null;
297
+ if (!q.trim()) {
298
+ setResults([]);
299
+ setIsSearching(false);
300
+ return;
301
+ }
302
+ setIsSearching(true);
303
+ timerRef.current = setTimeout(async () => {
304
+ const controller = new AbortController();
305
+ abortRef.current = controller;
306
+ try {
307
+ const data = await datafeed.searchSymbols(q, controller.signal);
308
+ if (!controller.signal.aborted) {
309
+ setResults(data);
310
+ }
311
+ } catch {
312
+ if (!controller.signal.aborted) {
313
+ setResults([]);
314
+ }
315
+ } finally {
316
+ if (!controller.signal.aborted) {
317
+ setIsSearching(false);
318
+ }
319
+ }
320
+ }, debounceMs);
321
+ },
322
+ [datafeed, debounceMs]
323
+ );
324
+ const selectSymbol = react.useCallback(
325
+ (symbol) => {
326
+ dispatch({ type: "SET_SYMBOL", symbol });
327
+ setQueryState("");
328
+ setResults([]);
329
+ },
330
+ [dispatch]
331
+ );
332
+ const clearResults = react.useCallback(() => {
333
+ setQueryState("");
334
+ setResults([]);
335
+ setIsSearching(false);
336
+ }, []);
337
+ react.useEffect(() => {
338
+ return () => {
339
+ if (timerRef.current) clearTimeout(timerRef.current);
340
+ abortRef.current?.abort();
341
+ };
342
+ }, []);
343
+ return {
344
+ query,
345
+ results,
346
+ isSearching,
347
+ activeSymbol: state.symbol,
348
+ setQuery,
349
+ selectSymbol,
350
+ clearResults
351
+ };
352
+ }
353
+
354
+ // src/data/indicators.ts
355
+ var MAIN_INDICATORS = [
356
+ "MA",
357
+ "EMA",
358
+ "SMA",
359
+ "BOLL",
360
+ "SAR",
361
+ "BBI"
362
+ ];
363
+ var SUB_INDICATORS = [
364
+ "MA",
365
+ "EMA",
366
+ "VOL",
367
+ "MACD",
368
+ "BOLL",
369
+ "KDJ",
370
+ "RSI",
371
+ "BIAS",
372
+ "BRAR",
373
+ "CCI",
374
+ "DMI",
375
+ "CR",
376
+ "PSY",
377
+ "DMA",
378
+ "TRIX",
379
+ "OBV",
380
+ "VR",
381
+ "WR",
382
+ "MTM",
383
+ "EMV",
384
+ "SAR",
385
+ "SMA",
386
+ "ROC",
387
+ "PVT",
388
+ "BBI",
389
+ "AO"
390
+ ];
391
+ var INDICATOR_PARAMS = {
392
+ SMA: {
393
+ name: "SMA",
394
+ localeKey: "sma",
395
+ params: [
396
+ { label: "params_1", defaultValue: 12 },
397
+ { label: "params_2", defaultValue: 2 }
398
+ ]
399
+ },
400
+ BOLL: {
401
+ name: "BOLL",
402
+ localeKey: "boll",
403
+ params: [
404
+ { label: "period", defaultValue: 20 },
405
+ { label: "standard_deviation", defaultValue: 2 }
406
+ ]
407
+ },
408
+ SAR: {
409
+ name: "SAR",
410
+ localeKey: "sar",
411
+ params: [
412
+ { label: "params_1", defaultValue: 2 },
413
+ { label: "params_2", defaultValue: 2 },
414
+ { label: "params_3", defaultValue: 20 }
415
+ ]
416
+ },
417
+ BBI: {
418
+ name: "BBI",
419
+ localeKey: "bbi",
420
+ params: [
421
+ { label: "params_1", defaultValue: 3 },
422
+ { label: "params_2", defaultValue: 6 },
423
+ { label: "params_3", defaultValue: 12 },
424
+ { label: "params_4", defaultValue: 24 }
425
+ ]
426
+ },
427
+ MACD: {
428
+ name: "MACD",
429
+ localeKey: "macd",
430
+ params: [
431
+ { label: "params_1", defaultValue: 12 },
432
+ { label: "params_2", defaultValue: 26 },
433
+ { label: "params_3", defaultValue: 9 }
434
+ ]
435
+ },
436
+ KDJ: {
437
+ name: "KDJ",
438
+ localeKey: "kdj",
439
+ params: [
440
+ { label: "params_1", defaultValue: 9 },
441
+ { label: "params_2", defaultValue: 3 },
442
+ { label: "params_3", defaultValue: 3 }
443
+ ]
444
+ },
445
+ BRAR: {
446
+ name: "BRAR",
447
+ localeKey: "brar",
448
+ params: [{ label: "params_1", defaultValue: 26 }]
449
+ },
450
+ CCI: {
451
+ name: "CCI",
452
+ localeKey: "cci",
453
+ params: [{ label: "params_1", defaultValue: 20 }]
454
+ },
455
+ DMI: {
456
+ name: "DMI",
457
+ localeKey: "dmi",
458
+ params: [
459
+ { label: "params_1", defaultValue: 14 },
460
+ { label: "params_2", defaultValue: 6 }
461
+ ]
462
+ },
463
+ CR: {
464
+ name: "CR",
465
+ localeKey: "cr",
466
+ params: [
467
+ { label: "params_1", defaultValue: 26 },
468
+ { label: "params_2", defaultValue: 10 },
469
+ { label: "params_3", defaultValue: 20 },
470
+ { label: "params_4", defaultValue: 40 },
471
+ { label: "params_5", defaultValue: 60 }
472
+ ]
473
+ },
474
+ PSY: {
475
+ name: "PSY",
476
+ localeKey: "psy",
477
+ params: [
478
+ { label: "params_1", defaultValue: 12 },
479
+ { label: "params_2", defaultValue: 6 }
480
+ ]
481
+ },
482
+ DMA: {
483
+ name: "DMA",
484
+ localeKey: "dma",
485
+ params: [
486
+ { label: "params_1", defaultValue: 10 },
487
+ { label: "params_2", defaultValue: 50 },
488
+ { label: "params_3", defaultValue: 10 }
489
+ ]
490
+ },
491
+ TRIX: {
492
+ name: "TRIX",
493
+ localeKey: "trix",
494
+ params: [
495
+ { label: "params_1", defaultValue: 12 },
496
+ { label: "params_2", defaultValue: 9 }
497
+ ]
498
+ },
499
+ OBV: {
500
+ name: "OBV",
501
+ localeKey: "obv",
502
+ params: [{ label: "params_1", defaultValue: 30 }]
503
+ },
504
+ VR: {
505
+ name: "VR",
506
+ localeKey: "vr",
507
+ params: [
508
+ { label: "params_1", defaultValue: 26 },
509
+ { label: "params_2", defaultValue: 6 }
510
+ ]
511
+ },
512
+ MTM: {
513
+ name: "MTM",
514
+ localeKey: "mtm",
515
+ params: [
516
+ { label: "params_1", defaultValue: 12 },
517
+ { label: "params_2", defaultValue: 6 }
518
+ ]
519
+ },
520
+ EMV: {
521
+ name: "EMV",
522
+ localeKey: "emv",
523
+ params: [
524
+ { label: "params_1", defaultValue: 14 },
525
+ { label: "params_2", defaultValue: 9 }
526
+ ]
527
+ },
528
+ ROC: {
529
+ name: "ROC",
530
+ localeKey: "roc",
531
+ params: [
532
+ { label: "params_1", defaultValue: 12 },
533
+ { label: "params_2", defaultValue: 6 }
534
+ ]
535
+ },
536
+ PVT: {
537
+ name: "PVT",
538
+ localeKey: "pvt",
539
+ params: []
540
+ },
541
+ AO: {
542
+ name: "AO",
543
+ localeKey: "ao",
544
+ params: [
545
+ { label: "params_1", defaultValue: 5 },
546
+ { label: "params_2", defaultValue: 34 }
547
+ ]
548
+ }
549
+ };
550
+
551
+ // src/hooks/useIndicators.ts
552
+ function useIndicators() {
553
+ const { state, dispatch } = useKlinechartsUI();
554
+ const mainIndicators = react.useMemo(() => {
555
+ const activeNames = state.mainIndicators;
556
+ const inactive = MAIN_INDICATORS.filter((n) => !activeNames.includes(n));
557
+ return [
558
+ ...activeNames.map((name) => ({ name, isActive: true })),
559
+ ...inactive.map((name) => ({ name, isActive: false }))
560
+ ];
561
+ }, [state.mainIndicators]);
562
+ const subIndicators = react.useMemo(() => {
563
+ const activeNames = Object.keys(state.subIndicators);
564
+ const inactive = SUB_INDICATORS.filter((n) => !activeNames.includes(n));
565
+ return [
566
+ ...activeNames.map((name) => ({ name, isActive: true })),
567
+ ...inactive.map((name) => ({ name, isActive: false }))
568
+ ];
569
+ }, [state.subIndicators]);
570
+ const addMainIndicator = react.useCallback(
571
+ (name) => {
572
+ if (state.mainIndicators.includes(name)) return;
573
+ state.chart?.createIndicator(
574
+ { name, id: `main_${name}`, paneId: "candle_pane" },
575
+ true,
576
+ { id: "candle_pane" }
577
+ );
578
+ const newIndicators = [...state.mainIndicators, name];
579
+ dispatch({ type: "SET_MAIN_INDICATORS", indicators: newIndicators });
580
+ },
581
+ [state.chart, state.mainIndicators, dispatch]
582
+ );
583
+ const removeMainIndicator = react.useCallback(
584
+ (name) => {
585
+ state.chart?.removeIndicator({ id: `main_${name}` });
586
+ const newIndicators = state.mainIndicators.filter((n) => n !== name);
587
+ dispatch({ type: "SET_MAIN_INDICATORS", indicators: newIndicators });
588
+ },
589
+ [state.chart, state.mainIndicators, dispatch]
590
+ );
591
+ const addSubIndicator = react.useCallback(
592
+ (name) => {
593
+ if (name in state.subIndicators) return;
594
+ const id = `sub_${name}`;
595
+ state.chart?.createIndicator({ name, id });
596
+ const paneId = state.chart?.getIndicators({ id })?.[0]?.paneId ?? "";
597
+ const newIndicators = { ...state.subIndicators, [name]: paneId };
598
+ dispatch({ type: "SET_SUB_INDICATORS", indicators: newIndicators });
599
+ },
600
+ [state.chart, state.subIndicators, dispatch]
601
+ );
602
+ const removeSubIndicator = react.useCallback(
603
+ (name) => {
604
+ state.chart?.removeIndicator({ id: `sub_${name}` });
605
+ const newIndicators = { ...state.subIndicators };
606
+ delete newIndicators[name];
607
+ dispatch({ type: "SET_SUB_INDICATORS", indicators: newIndicators });
608
+ },
609
+ [state.chart, state.subIndicators, dispatch]
610
+ );
611
+ const toggleMainIndicator = react.useCallback(
612
+ (name) => {
613
+ if (state.mainIndicators.includes(name)) {
614
+ removeMainIndicator(name);
615
+ } else {
616
+ addMainIndicator(name);
617
+ }
618
+ },
619
+ [state.mainIndicators, addMainIndicator, removeMainIndicator]
620
+ );
621
+ const toggleSubIndicator = react.useCallback(
622
+ (name) => {
623
+ if (name in state.subIndicators) {
624
+ removeSubIndicator(name);
625
+ } else {
626
+ addSubIndicator(name);
627
+ }
628
+ },
629
+ [state.subIndicators, addSubIndicator, removeSubIndicator]
630
+ );
631
+ const setIndicatorVisible = react.useCallback(
632
+ (name, isMain, visible) => {
633
+ const id = isMain ? `main_${name}` : `sub_${name}`;
634
+ state.chart?.overrideIndicator({ name, id, visible });
635
+ },
636
+ [state.chart]
637
+ );
638
+ const updateIndicatorParams = react.useCallback(
639
+ (name, paneId, params) => {
640
+ state.chart?.overrideIndicator({ name, paneId, calcParams: params });
641
+ },
642
+ [state.chart]
643
+ );
644
+ const getIndicatorParams = react.useCallback((name) => {
645
+ const config = INDICATOR_PARAMS[name];
646
+ if (!config) return [];
647
+ return config.params.map((p) => ({
648
+ label: p.label,
649
+ defaultValue: p.defaultValue
650
+ }));
651
+ }, []);
652
+ const moveToMain = react.useCallback(
653
+ (name) => {
654
+ if (!state.chart) return;
655
+ state.chart.removeIndicator({ id: `sub_${name}` });
656
+ state.chart.createIndicator(
657
+ { name, id: `main_${name}`, paneId: "candle_pane" },
658
+ true,
659
+ { id: "candle_pane" }
660
+ );
661
+ const newSub = { ...state.subIndicators };
662
+ delete newSub[name];
663
+ dispatch({ type: "SET_SUB_INDICATORS", indicators: newSub });
664
+ dispatch({
665
+ type: "SET_MAIN_INDICATORS",
666
+ indicators: [...state.mainIndicators, name]
667
+ });
668
+ },
669
+ [state.chart, state.mainIndicators, state.subIndicators, dispatch]
670
+ );
671
+ const moveToSub = react.useCallback(
672
+ (name) => {
673
+ if (!state.chart) return;
674
+ state.chart.removeIndicator({ id: `main_${name}` });
675
+ const subId = `sub_${name}`;
676
+ state.chart.createIndicator({ name, id: subId });
677
+ const paneId = state.chart.getIndicators({ id: subId })?.[0]?.paneId ?? "";
678
+ const newMain = state.mainIndicators.filter((n) => n !== name);
679
+ dispatch({ type: "SET_MAIN_INDICATORS", indicators: newMain });
680
+ dispatch({
681
+ type: "SET_SUB_INDICATORS",
682
+ indicators: { ...state.subIndicators, [name]: paneId }
683
+ });
684
+ },
685
+ [state.chart, state.mainIndicators, state.subIndicators, dispatch]
686
+ );
687
+ const isMainIndicatorActive = react.useCallback(
688
+ (name) => state.mainIndicators.includes(name),
689
+ [state.mainIndicators]
690
+ );
691
+ const isSubIndicatorActive = react.useCallback(
692
+ (name) => name in state.subIndicators,
693
+ [state.subIndicators]
694
+ );
695
+ return {
696
+ mainIndicators,
697
+ subIndicators,
698
+ activeMainIndicators: state.mainIndicators,
699
+ activeSubIndicators: state.subIndicators,
700
+ availableMainIndicators: MAIN_INDICATORS,
701
+ availableSubIndicators: SUB_INDICATORS,
702
+ addMainIndicator,
703
+ removeMainIndicator,
704
+ addSubIndicator,
705
+ removeSubIndicator,
706
+ toggleMainIndicator,
707
+ toggleSubIndicator,
708
+ moveToMain,
709
+ moveToSub,
710
+ setIndicatorVisible,
711
+ updateIndicatorParams,
712
+ getIndicatorParams,
713
+ isMainIndicatorActive,
714
+ isSubIndicatorActive
715
+ };
716
+ }
717
+
718
+ // src/data/drawings.ts
719
+ var DRAWING_CATEGORIES = [
720
+ {
721
+ key: "singleLine",
722
+ tools: [
723
+ { name: "horizontalStraightLine", localeKey: "horizontal_straight_line" },
724
+ { name: "horizontalRayLine", localeKey: "horizontal_ray_line" },
725
+ { name: "horizontalSegment", localeKey: "horizontal_segment" },
726
+ { name: "verticalStraightLine", localeKey: "vertical_straight_line" },
727
+ { name: "verticalRayLine", localeKey: "vertical_ray_line" },
728
+ { name: "verticalSegment", localeKey: "vertical_segment" },
729
+ { name: "straightLine", localeKey: "straight_line" },
730
+ { name: "rayLine", localeKey: "ray_line" },
731
+ { name: "segment", localeKey: "segment" },
732
+ { name: "arrow", localeKey: "arrow" },
733
+ { name: "priceLine", localeKey: "price_line" }
734
+ ]
735
+ },
736
+ {
737
+ key: "moreLine",
738
+ tools: [
739
+ { name: "priceChannelLine", localeKey: "price_channel_line" },
740
+ { name: "parallelStraightLine", localeKey: "parallel_straight_line" }
741
+ ]
742
+ },
743
+ {
744
+ key: "polygon",
745
+ tools: [
746
+ { name: "circle", localeKey: "circle" },
747
+ { name: "rect", localeKey: "rect" },
748
+ { name: "parallelogram", localeKey: "parallelogram" },
749
+ { name: "triangle", localeKey: "triangle" }
750
+ ]
751
+ },
752
+ {
753
+ key: "fibonacci",
754
+ tools: [
755
+ { name: "fibonacciLine", localeKey: "fibonacci_line" },
756
+ { name: "fibonacciSegment", localeKey: "fibonacci_segment" },
757
+ { name: "fibonacciCircle", localeKey: "fibonacci_circle" },
758
+ { name: "fibonacciSpiral", localeKey: "fibonacci_spiral" },
759
+ {
760
+ name: "fibonacciSpeedResistanceFan",
761
+ localeKey: "fibonacci_speed_resistance_fan"
762
+ },
763
+ { name: "fibonacciExtension", localeKey: "fibonacci_extension" },
764
+ { name: "gannBox", localeKey: "gann_box" }
765
+ ]
766
+ },
767
+ {
768
+ key: "wave",
769
+ tools: [
770
+ { name: "xabcd", localeKey: "xabcd" },
771
+ { name: "abcd", localeKey: "abcd" },
772
+ { name: "threeWaves", localeKey: "three_waves" },
773
+ { name: "fiveWaves", localeKey: "five_waves" },
774
+ { name: "eightWaves", localeKey: "eight_waves" },
775
+ { name: "anyWaves", localeKey: "any_waves" }
776
+ ]
777
+ }
778
+ ];
779
+
780
+ // src/hooks/useDrawingTools.ts
781
+ var DRAWING_GROUP_ID = "drawing_tools";
782
+ function useDrawingTools() {
783
+ const { state } = useKlinechartsUI();
784
+ const [activeTool, setActiveTool] = react.useState(null);
785
+ const [magnetMode, setMagnetModeState] = react.useState("normal");
786
+ const [isLocked, setIsLocked] = react.useState(false);
787
+ const [isVisible, setIsVisible] = react.useState(true);
788
+ const categories = react.useMemo(
789
+ () => DRAWING_CATEGORIES.map((cat) => ({
790
+ key: cat.key,
791
+ tools: cat.tools.map((tool) => ({
792
+ name: tool.name,
793
+ localeKey: tool.localeKey
794
+ }))
795
+ })),
796
+ []
797
+ );
798
+ const selectTool = react.useCallback(
799
+ (name) => {
800
+ setActiveTool(name);
801
+ state.chart?.createOverlay({
802
+ name,
803
+ groupId: DRAWING_GROUP_ID,
804
+ lock: isLocked,
805
+ visible: isVisible,
806
+ mode: magnetMode === "strong" ? "strong_magnet" : magnetMode === "weak" ? "weak_magnet" : "normal"
807
+ });
808
+ },
809
+ [state.chart, isLocked, isVisible, magnetMode]
810
+ );
811
+ const clearActiveTool = react.useCallback(() => {
812
+ setActiveTool(null);
813
+ }, []);
814
+ const setMagnetMode = react.useCallback(
815
+ (mode) => {
816
+ setMagnetModeState(mode);
817
+ const overlays2 = state.chart?.getOverlays({ groupId: DRAWING_GROUP_ID });
818
+ if (overlays2) {
819
+ const overlayMode = mode === "strong" ? "strong_magnet" : mode === "weak" ? "weak_magnet" : "normal";
820
+ overlays2.forEach((overlay) => {
821
+ state.chart?.overrideOverlay({
822
+ id: overlay.id,
823
+ mode: overlayMode
824
+ });
825
+ });
826
+ }
827
+ },
828
+ [state.chart]
829
+ );
830
+ const toggleLock = react.useCallback(() => {
831
+ const newLocked = !isLocked;
832
+ setIsLocked(newLocked);
833
+ const overlays2 = state.chart?.getOverlays({ groupId: DRAWING_GROUP_ID });
834
+ if (overlays2) {
835
+ overlays2.forEach((overlay) => {
836
+ state.chart?.overrideOverlay({
837
+ id: overlay.id,
838
+ lock: newLocked
839
+ });
840
+ });
841
+ }
842
+ }, [state.chart, isLocked]);
843
+ const toggleVisibility = react.useCallback(() => {
844
+ const newVisible = !isVisible;
845
+ setIsVisible(newVisible);
846
+ const overlays2 = state.chart?.getOverlays({ groupId: DRAWING_GROUP_ID });
847
+ if (overlays2) {
848
+ overlays2.forEach((overlay) => {
849
+ state.chart?.overrideOverlay({
850
+ id: overlay.id,
851
+ visible: newVisible
852
+ });
853
+ });
854
+ }
855
+ }, [state.chart, isVisible]);
856
+ const removeAllDrawings = react.useCallback(() => {
857
+ state.chart?.removeOverlay({ groupId: DRAWING_GROUP_ID });
858
+ setActiveTool(null);
859
+ }, [state.chart]);
860
+ return {
861
+ categories,
862
+ activeTool,
863
+ magnetMode,
864
+ isLocked,
865
+ isVisible,
866
+ selectTool,
867
+ clearActiveTool,
868
+ setMagnetMode,
869
+ toggleLock,
870
+ toggleVisibility,
871
+ removeAllDrawings
872
+ };
873
+ }
874
+
875
+ // src/data/candle-types.ts
876
+ var CANDLE_TYPES = [
877
+ { key: "candle_solid", localeKey: "candle_solid" },
878
+ { key: "candle_stroke", localeKey: "candle_stroke" },
879
+ { key: "candle_up_stroke", localeKey: "candle_up_stroke" },
880
+ { key: "candle_down_stroke", localeKey: "candle_down_stroke" },
881
+ { key: "ohlc", localeKey: "ohlc" },
882
+ { key: "area", localeKey: "area" }
883
+ ];
884
+ var PRICE_AXIS_TYPES = ["normal", "percentage", "logarithm"];
885
+ var YAXIS_POSITIONS = ["left", "right"];
886
+ var COMPARE_RULES = ["current_open", "prev_close"];
887
+ var TOOLTIP_SHOW_RULES = ["always", "follow_cross", "none"];
888
+
889
+ // src/hooks/useKlinechartsUISettings.ts
890
+ var defaultSettings = {
891
+ candleType: "candle_solid",
892
+ candleUpColor: "#2DC08E",
893
+ candleDownColor: "#F92855",
894
+ compareRule: "current_open",
895
+ showLastPrice: true,
896
+ showLastPriceLine: true,
897
+ showHighPrice: true,
898
+ showLowPrice: true,
899
+ showIndicatorLastValue: true,
900
+ priceAxisType: "normal",
901
+ yAxisPosition: "right",
902
+ yAxisInside: false,
903
+ reverseCoordinate: false,
904
+ showTimeAxis: true,
905
+ showGrid: true,
906
+ showCrosshair: true,
907
+ showCandleTooltip: true,
908
+ showIndicatorTooltip: true,
909
+ tooltipShowRule: "always"
910
+ };
911
+ function useKlinechartsUISettings() {
912
+ const { state, onSettingsChange } = useKlinechartsUI();
913
+ const [settings, setSettings] = react.useState(defaultSettings);
914
+ const isInitialMount = react.useRef(true);
915
+ react.useEffect(() => {
916
+ if (isInitialMount.current) {
917
+ isInitialMount.current = false;
918
+ return;
919
+ }
920
+ onSettingsChange?.({ ...settings });
921
+ }, [settings, onSettingsChange]);
922
+ const candleTypes = react.useMemo(
923
+ () => CANDLE_TYPES.map((ct) => ({
924
+ key: ct.key,
925
+ localeKey: ct.localeKey
926
+ })),
927
+ []
928
+ );
929
+ const priceAxisTypes = react.useMemo(
930
+ () => PRICE_AXIS_TYPES.map((pat) => ({ key: pat, localeKey: pat })),
931
+ []
932
+ );
933
+ const yAxisPositions = react.useMemo(
934
+ () => YAXIS_POSITIONS.map((p) => ({ key: p, localeKey: p })),
935
+ []
936
+ );
937
+ const compareRules = react.useMemo(
938
+ () => COMPARE_RULES.map((r) => ({ key: r, localeKey: r })),
939
+ []
940
+ );
941
+ const tooltipShowRules = react.useMemo(
942
+ () => TOOLTIP_SHOW_RULES.map((r) => ({ key: r, localeKey: r })),
943
+ []
944
+ );
945
+ const hasAppliedInitial = react.useRef(false);
946
+ react.useEffect(() => {
947
+ if (!state.chart || hasAppliedInitial.current) return;
948
+ hasAppliedInitial.current = true;
949
+ const needsPaneOptions = settings.reverseCoordinate || settings.priceAxisType !== "normal" || settings.yAxisPosition !== "right" || settings.yAxisInside;
950
+ if (needsPaneOptions) {
951
+ state.chart.setPaneOptions({
952
+ id: "candle_pane",
953
+ axis: {
954
+ ...settings.priceAxisType !== "normal" && { name: settings.priceAxisType },
955
+ ...settings.reverseCoordinate && { reverse: true },
956
+ ...settings.yAxisPosition !== "right" && { position: settings.yAxisPosition },
957
+ ...settings.yAxisInside && { inside: true }
958
+ }
959
+ });
960
+ }
961
+ if (settings.showIndicatorLastValue) {
962
+ state.chart.setStyles({
963
+ indicator: { lastValueMark: { show: true } }
964
+ });
965
+ }
966
+ }, [state.chart]);
967
+ const applyStyle = react.useCallback(
968
+ (path, value) => {
969
+ const parts = path.split(".");
970
+ const styleObj = {};
971
+ let current = styleObj;
972
+ for (let i = 0; i < parts.length - 1; i++) {
973
+ current[parts[i]] = {};
974
+ current = current[parts[i]];
975
+ }
976
+ current[parts[parts.length - 1]] = value;
977
+ state.chart?.setStyles(styleObj);
978
+ },
979
+ [state.chart]
980
+ );
981
+ const applyPaneAxis = react.useCallback(
982
+ (axis) => {
983
+ state.chart?.setPaneOptions({ id: "candle_pane", axis });
984
+ },
985
+ [state.chart]
986
+ );
987
+ const setCandleType = react.useCallback(
988
+ (type) => {
989
+ applyStyle("candle.type", type);
990
+ setSettings((s) => ({ ...s, candleType: type }));
991
+ },
992
+ [applyStyle]
993
+ );
994
+ const setCandleUpColor = react.useCallback(
995
+ (color) => {
996
+ state.chart?.setStyles({
997
+ candle: {
998
+ bar: { upColor: color, upBorderColor: color, upWickColor: color }
999
+ }
1000
+ });
1001
+ setSettings((s) => ({ ...s, candleUpColor: color }));
1002
+ },
1003
+ [state.chart]
1004
+ );
1005
+ const setCandleDownColor = react.useCallback(
1006
+ (color) => {
1007
+ state.chart?.setStyles({
1008
+ candle: {
1009
+ bar: { downColor: color, downBorderColor: color, downWickColor: color }
1010
+ }
1011
+ });
1012
+ setSettings((s) => ({ ...s, candleDownColor: color }));
1013
+ },
1014
+ [state.chart]
1015
+ );
1016
+ const setCompareRule = react.useCallback(
1017
+ (rule) => {
1018
+ applyStyle("candle.bar.compareRule", rule);
1019
+ setSettings((s) => ({ ...s, compareRule: rule }));
1020
+ },
1021
+ [applyStyle]
1022
+ );
1023
+ const setShowLastPrice = react.useCallback(
1024
+ (show) => {
1025
+ applyStyle("candle.priceMark.last.show", show);
1026
+ setSettings((s) => ({ ...s, showLastPrice: show }));
1027
+ },
1028
+ [applyStyle]
1029
+ );
1030
+ const setShowLastPriceLine = react.useCallback(
1031
+ (show) => {
1032
+ applyStyle("candle.priceMark.last.line.show", show);
1033
+ setSettings((s) => ({ ...s, showLastPriceLine: show }));
1034
+ },
1035
+ [applyStyle]
1036
+ );
1037
+ const setShowHighPrice = react.useCallback(
1038
+ (show) => {
1039
+ applyStyle("candle.priceMark.high.show", show);
1040
+ setSettings((s) => ({ ...s, showHighPrice: show }));
1041
+ },
1042
+ [applyStyle]
1043
+ );
1044
+ const setShowLowPrice = react.useCallback(
1045
+ (show) => {
1046
+ applyStyle("candle.priceMark.low.show", show);
1047
+ setSettings((s) => ({ ...s, showLowPrice: show }));
1048
+ },
1049
+ [applyStyle]
1050
+ );
1051
+ const setShowIndicatorLastValue = react.useCallback(
1052
+ (show) => {
1053
+ applyStyle("indicator.lastValueMark.show", show);
1054
+ setSettings((s) => ({ ...s, showIndicatorLastValue: show }));
1055
+ },
1056
+ [applyStyle]
1057
+ );
1058
+ const setPriceAxisType = react.useCallback(
1059
+ (type) => {
1060
+ applyPaneAxis({ name: type });
1061
+ setSettings((s) => ({ ...s, priceAxisType: type }));
1062
+ },
1063
+ [applyPaneAxis]
1064
+ );
1065
+ const setYAxisPosition = react.useCallback(
1066
+ (position) => {
1067
+ applyPaneAxis({ position });
1068
+ setSettings((s) => ({ ...s, yAxisPosition: position }));
1069
+ },
1070
+ [applyPaneAxis]
1071
+ );
1072
+ const setYAxisInside = react.useCallback(
1073
+ (inside) => {
1074
+ applyPaneAxis({ inside });
1075
+ setSettings((s) => ({ ...s, yAxisInside: inside }));
1076
+ },
1077
+ [applyPaneAxis]
1078
+ );
1079
+ const setReverseCoordinate = react.useCallback(
1080
+ (reverse) => {
1081
+ applyPaneAxis({ reverse });
1082
+ setSettings((s) => ({ ...s, reverseCoordinate: reverse }));
1083
+ },
1084
+ [applyPaneAxis]
1085
+ );
1086
+ const setShowGrid = react.useCallback(
1087
+ (show) => {
1088
+ applyStyle("grid.show", show);
1089
+ setSettings((s) => ({ ...s, showGrid: show }));
1090
+ },
1091
+ [applyStyle]
1092
+ );
1093
+ const setShowTimeAxis = react.useCallback(
1094
+ (show) => {
1095
+ applyStyle("xAxis.show", show);
1096
+ setSettings((s) => ({ ...s, showTimeAxis: show }));
1097
+ },
1098
+ [applyStyle]
1099
+ );
1100
+ const setShowCrosshair = react.useCallback(
1101
+ (show) => {
1102
+ applyStyle("crosshair.show", show);
1103
+ setSettings((s) => ({ ...s, showCrosshair: show }));
1104
+ },
1105
+ [applyStyle]
1106
+ );
1107
+ const setShowCandleTooltip = react.useCallback(
1108
+ (show) => {
1109
+ applyStyle("candle.tooltip.show", show);
1110
+ setSettings((s) => ({ ...s, showCandleTooltip: show }));
1111
+ },
1112
+ [applyStyle]
1113
+ );
1114
+ const setShowIndicatorTooltip = react.useCallback(
1115
+ (show) => {
1116
+ applyStyle("indicator.tooltip.show", show);
1117
+ setSettings((s) => ({ ...s, showIndicatorTooltip: show }));
1118
+ },
1119
+ [applyStyle]
1120
+ );
1121
+ const setTooltipShowRule = react.useCallback(
1122
+ (rule) => {
1123
+ state.chart?.setStyles({
1124
+ candle: { tooltip: { showRule: rule } },
1125
+ indicator: { tooltip: { showRule: rule } }
1126
+ });
1127
+ setSettings((s) => ({ ...s, tooltipShowRule: rule }));
1128
+ },
1129
+ [state.chart]
1130
+ );
1131
+ const resetToDefaults = react.useCallback(() => {
1132
+ setSettings(defaultSettings);
1133
+ state.chart?.setStyles(state.theme);
1134
+ state.chart?.setPaneOptions({
1135
+ id: "candle_pane",
1136
+ axis: { name: "normal", reverse: false, position: "right", inside: false }
1137
+ });
1138
+ }, [state.chart, state.theme]);
1139
+ return {
1140
+ ...settings,
1141
+ candleTypes,
1142
+ priceAxisTypes,
1143
+ yAxisPositions,
1144
+ compareRules,
1145
+ tooltipShowRules,
1146
+ setCandleType,
1147
+ setCandleUpColor,
1148
+ setCandleDownColor,
1149
+ setCompareRule,
1150
+ setShowLastPrice,
1151
+ setShowLastPriceLine,
1152
+ setShowHighPrice,
1153
+ setShowLowPrice,
1154
+ setShowIndicatorLastValue,
1155
+ setPriceAxisType,
1156
+ setYAxisPosition,
1157
+ setYAxisInside,
1158
+ setReverseCoordinate,
1159
+ setShowTimeAxis,
1160
+ setShowGrid,
1161
+ setShowCrosshair,
1162
+ setShowCandleTooltip,
1163
+ setShowIndicatorTooltip,
1164
+ setTooltipShowRule,
1165
+ resetToDefaults
1166
+ };
1167
+ }
1168
+ function useScreenshot() {
1169
+ const { state, dispatch } = useKlinechartsUI();
1170
+ const capture = react.useCallback(() => {
1171
+ if (!state.chart) return;
1172
+ const url = state.chart.getConvertPictureUrl(true, "jpeg", state.theme === "dark" ? "#151517" : "#ffffff");
1173
+ dispatch({ type: "SET_SCREENSHOT_URL", url });
1174
+ }, [state.chart, state.theme, dispatch]);
1175
+ const download = react.useCallback(
1176
+ (filename = "chart-screenshot.jpg") => {
1177
+ if (!state.screenshotUrl) return;
1178
+ const link = document.createElement("a");
1179
+ link.href = state.screenshotUrl;
1180
+ link.download = filename;
1181
+ document.body.appendChild(link);
1182
+ link.click();
1183
+ document.body.removeChild(link);
1184
+ },
1185
+ [state.screenshotUrl]
1186
+ );
1187
+ const clear = react.useCallback(() => {
1188
+ dispatch({ type: "SET_SCREENSHOT_URL", url: null });
1189
+ }, [dispatch]);
1190
+ return {
1191
+ screenshotUrl: state.screenshotUrl,
1192
+ capture,
1193
+ download,
1194
+ clear
1195
+ };
1196
+ }
1197
+ function useFullscreen() {
1198
+ const { fullscreenContainerRef } = useKlinechartsUIDispatch();
1199
+ const [isFullscreen, setIsFullscreen] = react.useState(false);
1200
+ const enter = react.useCallback(() => {
1201
+ const el = fullscreenContainerRef.current;
1202
+ if (!el) return;
1203
+ if (el.requestFullscreen) {
1204
+ el.requestFullscreen();
1205
+ } else if ("webkitRequestFullscreen" in el) {
1206
+ el.webkitRequestFullscreen();
1207
+ } else if ("msRequestFullscreen" in el) {
1208
+ el.msRequestFullscreen();
1209
+ }
1210
+ }, [fullscreenContainerRef]);
1211
+ const exit = react.useCallback(() => {
1212
+ if (document.exitFullscreen) {
1213
+ document.exitFullscreen();
1214
+ } else if ("webkitExitFullscreen" in document) {
1215
+ document.webkitExitFullscreen();
1216
+ } else if ("msExitFullscreen" in document) {
1217
+ document.msExitFullscreen();
1218
+ }
1219
+ }, []);
1220
+ const toggle = react.useCallback(() => {
1221
+ if (isFullscreen) {
1222
+ exit();
1223
+ } else {
1224
+ enter();
1225
+ }
1226
+ }, [isFullscreen, enter, exit]);
1227
+ react.useEffect(() => {
1228
+ const handler = () => {
1229
+ setIsFullscreen(!!document.fullscreenElement);
1230
+ };
1231
+ document.addEventListener("fullscreenchange", handler);
1232
+ document.addEventListener("webkitfullscreenchange", handler);
1233
+ return () => {
1234
+ document.removeEventListener("fullscreenchange", handler);
1235
+ document.removeEventListener("webkitfullscreenchange", handler);
1236
+ };
1237
+ }, []);
1238
+ return {
1239
+ isFullscreen,
1240
+ toggle,
1241
+ enter,
1242
+ exit,
1243
+ containerRef: fullscreenContainerRef
1244
+ };
1245
+ }
1246
+ function useOrderLines() {
1247
+ const { state } = useKlinechartsUI();
1248
+ const callbacksRef = react.useRef(/* @__PURE__ */ new Map());
1249
+ const createOrderLine = react.useCallback(
1250
+ (options) => {
1251
+ if (!state.chart) return null;
1252
+ const {
1253
+ id: optId,
1254
+ price,
1255
+ draggable = false,
1256
+ onPriceChange,
1257
+ ...extendData
1258
+ } = options;
1259
+ const id = optId ?? `order_line_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
1260
+ if (onPriceChange) {
1261
+ callbacksRef.current.set(id, onPriceChange);
1262
+ }
1263
+ const dataCount = state.chart.getDataList().length;
1264
+ const anchorIndex = dataCount > 0 ? dataCount - 1 : 0;
1265
+ state.chart.createOverlay({
1266
+ name: "orderLine",
1267
+ id,
1268
+ points: [{ dataIndex: anchorIndex, value: price }],
1269
+ extendData,
1270
+ lock: !draggable,
1271
+ mode: "normal",
1272
+ onPressedMoveEnd: (event) => {
1273
+ const newPrice = event.overlay.points[0]?.value;
1274
+ if (newPrice != null) {
1275
+ callbacksRef.current.get(id)?.(newPrice);
1276
+ }
1277
+ }
1278
+ });
1279
+ return id;
1280
+ },
1281
+ [state.chart]
1282
+ );
1283
+ const updateOrderLine = react.useCallback(
1284
+ (id, options) => {
1285
+ if (!state.chart) return;
1286
+ const { price, draggable, onPriceChange, ...extendData } = options;
1287
+ const existing = state.chart.getOverlays({ id })?.[0];
1288
+ if (!existing) return;
1289
+ if (onPriceChange !== void 0) {
1290
+ callbacksRef.current.set(id, onPriceChange);
1291
+ }
1292
+ const dataCount = state.chart.getDataList().length;
1293
+ const anchorIndex = dataCount > 0 ? dataCount - 1 : 0;
1294
+ state.chart.overrideOverlay({
1295
+ id,
1296
+ ...price != null ? { points: [{ dataIndex: anchorIndex, value: price }] } : {},
1297
+ ...draggable != null ? { lock: !draggable } : {},
1298
+ extendData: {
1299
+ ...existing.extendData,
1300
+ ...extendData
1301
+ }
1302
+ });
1303
+ },
1304
+ [state.chart]
1305
+ );
1306
+ const removeOrderLine = react.useCallback(
1307
+ (id) => {
1308
+ state.chart?.removeOverlay({ id });
1309
+ callbacksRef.current.delete(id);
1310
+ },
1311
+ [state.chart]
1312
+ );
1313
+ const removeAllOrderLines = react.useCallback(() => {
1314
+ state.chart?.removeOverlay({ name: "orderLine" });
1315
+ callbacksRef.current.clear();
1316
+ }, [state.chart]);
1317
+ return {
1318
+ createOrderLine,
1319
+ updateOrderLine,
1320
+ removeOrderLine,
1321
+ removeAllOrderLines
1322
+ };
1323
+ }
1324
+
1325
+ // src/utils/createDataLoader.ts
1326
+ function createDataLoader(datafeed, dispatch) {
1327
+ let oldestTimestamp = null;
1328
+ let currentGen = 0;
1329
+ return {
1330
+ getBars: async (params) => {
1331
+ try {
1332
+ dispatch({ type: "SET_LOADING", isLoading: true });
1333
+ if (params.type === "init") {
1334
+ oldestTimestamp = null;
1335
+ const gen = ++currentGen;
1336
+ const data = await datafeed.getHistoryKLineData(
1337
+ params.symbol,
1338
+ { ...params.period, label: "" },
1339
+ 0,
1340
+ Date.now()
1341
+ );
1342
+ if (gen !== currentGen) return;
1343
+ if (data.length > 0) {
1344
+ oldestTimestamp = data[0].timestamp;
1345
+ }
1346
+ params.callback(data, {
1347
+ forward: data.length > 0,
1348
+ backward: false
1349
+ });
1350
+ } else if (params.type === "forward" && oldestTimestamp !== null) {
1351
+ const gen = currentGen;
1352
+ const data = await datafeed.getHistoryKLineData(
1353
+ params.symbol,
1354
+ { ...params.period, label: "" },
1355
+ 0,
1356
+ oldestTimestamp - 1
1357
+ );
1358
+ if (gen !== currentGen) return;
1359
+ if (data.length > 0) {
1360
+ oldestTimestamp = data[0].timestamp;
1361
+ }
1362
+ params.callback(data, {
1363
+ forward: data.length > 0,
1364
+ backward: false
1365
+ });
1366
+ } else if (params.type === "backward") {
1367
+ params.callback([], { forward: false, backward: false });
1368
+ }
1369
+ } catch (error) {
1370
+ console.error("Failed to load chart data:", error);
1371
+ params.callback([], { forward: false, backward: false });
1372
+ } finally {
1373
+ dispatch({ type: "SET_LOADING", isLoading: false });
1374
+ }
1375
+ },
1376
+ subscribeBar: (params) => {
1377
+ datafeed.subscribe(
1378
+ params.symbol,
1379
+ { ...params.period, label: "" },
1380
+ (klineData) => params.callback(klineData)
1381
+ );
1382
+ },
1383
+ unsubscribeBar: (params) => {
1384
+ datafeed.unsubscribe(params.symbol, { ...params.period, label: "" });
1385
+ }
1386
+ };
1387
+ }
1388
+
1389
+ Object.defineProperty(exports, "abcd", {
1390
+ enumerable: true,
1391
+ get: function () { return chunkSLTXNLKN_cjs.abcd_default; }
1392
+ });
1393
+ Object.defineProperty(exports, "anyWaves", {
1394
+ enumerable: true,
1395
+ get: function () { return chunkSLTXNLKN_cjs.anyWaves_default; }
1396
+ });
1397
+ Object.defineProperty(exports, "arrow", {
1398
+ enumerable: true,
1399
+ get: function () { return chunkSLTXNLKN_cjs.arrow_default; }
1400
+ });
1401
+ Object.defineProperty(exports, "circle", {
1402
+ enumerable: true,
1403
+ get: function () { return chunkSLTXNLKN_cjs.circle_default; }
1404
+ });
1405
+ Object.defineProperty(exports, "eightWaves", {
1406
+ enumerable: true,
1407
+ get: function () { return chunkSLTXNLKN_cjs.eightWaves_default; }
1408
+ });
1409
+ Object.defineProperty(exports, "fibonacciCircle", {
1410
+ enumerable: true,
1411
+ get: function () { return chunkSLTXNLKN_cjs.fibonacciCircle_default; }
1412
+ });
1413
+ Object.defineProperty(exports, "fibonacciExtension", {
1414
+ enumerable: true,
1415
+ get: function () { return chunkSLTXNLKN_cjs.fibonacciExtension_default; }
1416
+ });
1417
+ Object.defineProperty(exports, "fibonacciSegment", {
1418
+ enumerable: true,
1419
+ get: function () { return chunkSLTXNLKN_cjs.fibonacciSegment_default; }
1420
+ });
1421
+ Object.defineProperty(exports, "fibonacciSpeedResistanceFan", {
1422
+ enumerable: true,
1423
+ get: function () { return chunkSLTXNLKN_cjs.fibonacciSpeedResistanceFan_default; }
1424
+ });
1425
+ Object.defineProperty(exports, "fibonacciSpiral", {
1426
+ enumerable: true,
1427
+ get: function () { return chunkSLTXNLKN_cjs.fibonacciSpiral_default; }
1428
+ });
1429
+ Object.defineProperty(exports, "fiveWaves", {
1430
+ enumerable: true,
1431
+ get: function () { return chunkSLTXNLKN_cjs.fiveWaves_default; }
1432
+ });
1433
+ Object.defineProperty(exports, "gannBox", {
1434
+ enumerable: true,
1435
+ get: function () { return chunkSLTXNLKN_cjs.gannBox_default; }
1436
+ });
1437
+ Object.defineProperty(exports, "orderLine", {
1438
+ enumerable: true,
1439
+ get: function () { return chunkSLTXNLKN_cjs.orderLine_default; }
1440
+ });
1441
+ Object.defineProperty(exports, "overlays", {
1442
+ enumerable: true,
1443
+ get: function () { return chunkSLTXNLKN_cjs.overlays; }
1444
+ });
1445
+ Object.defineProperty(exports, "parallelogram", {
1446
+ enumerable: true,
1447
+ get: function () { return chunkSLTXNLKN_cjs.parallelogram_default; }
1448
+ });
1449
+ Object.defineProperty(exports, "rect", {
1450
+ enumerable: true,
1451
+ get: function () { return chunkSLTXNLKN_cjs.rect_default; }
1452
+ });
1453
+ Object.defineProperty(exports, "registerExtensions", {
1454
+ enumerable: true,
1455
+ get: function () { return chunkSLTXNLKN_cjs.registerExtensions; }
1456
+ });
1457
+ Object.defineProperty(exports, "threeWaves", {
1458
+ enumerable: true,
1459
+ get: function () { return chunkSLTXNLKN_cjs.threeWaves_default; }
1460
+ });
1461
+ Object.defineProperty(exports, "triangle", {
1462
+ enumerable: true,
1463
+ get: function () { return chunkSLTXNLKN_cjs.triangle_default; }
1464
+ });
1465
+ Object.defineProperty(exports, "xabcd", {
1466
+ enumerable: true,
1467
+ get: function () { return chunkSLTXNLKN_cjs.xabcd_default; }
1468
+ });
1469
+ exports.CANDLE_TYPES = CANDLE_TYPES;
1470
+ exports.COMPARE_RULES = COMPARE_RULES;
1471
+ exports.DEFAULT_PERIODS = DEFAULT_PERIODS;
1472
+ exports.DRAWING_CATEGORIES = DRAWING_CATEGORIES;
1473
+ exports.INDICATOR_PARAMS = INDICATOR_PARAMS;
1474
+ exports.KlinechartsUIDispatchContext = KlinechartsUIDispatchContext;
1475
+ exports.KlinechartsUIProvider = KlinechartsUIProvider;
1476
+ exports.KlinechartsUIStateContext = KlinechartsUIStateContext;
1477
+ exports.MAIN_INDICATORS = MAIN_INDICATORS;
1478
+ exports.PRICE_AXIS_TYPES = PRICE_AXIS_TYPES;
1479
+ exports.SUB_INDICATORS = SUB_INDICATORS;
1480
+ exports.TIMEZONES = TIMEZONES;
1481
+ exports.TOOLTIP_SHOW_RULES = TOOLTIP_SHOW_RULES;
1482
+ exports.YAXIS_POSITIONS = YAXIS_POSITIONS;
1483
+ exports.createDataLoader = createDataLoader;
1484
+ exports.useDrawingTools = useDrawingTools;
1485
+ exports.useFullscreen = useFullscreen;
1486
+ exports.useIndicators = useIndicators;
1487
+ exports.useKlinechartsUI = useKlinechartsUI;
1488
+ exports.useKlinechartsUILoading = useKlinechartsUILoading;
1489
+ exports.useKlinechartsUISettings = useKlinechartsUISettings;
1490
+ exports.useKlinechartsUITheme = useKlinechartsUITheme;
1491
+ exports.useOrderLines = useOrderLines;
1492
+ exports.usePeriods = usePeriods;
1493
+ exports.useScreenshot = useScreenshot;
1494
+ exports.useSymbolSearch = useSymbolSearch;
1495
+ exports.useTimezone = useTimezone;
1496
+ //# sourceMappingURL=index.cjs.map
1497
+ //# sourceMappingURL=index.cjs.map