react-klinecharts-ui 0.4.0 → 0.5.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.d.cts CHANGED
@@ -9,6 +9,63 @@ interface TerminalPeriod extends Period {
9
9
  }
10
10
  declare const DEFAULT_PERIODS: TerminalPeriod[];
11
11
 
12
+ /**
13
+ * Shared domain types for stateful feature hooks (`useAlerts`, `useMeasure`,
14
+ * `useReplay`).
15
+ *
16
+ * These live in a neutral module so they can be referenced both by the
17
+ * provider store (`KlinechartsUIState` / actions in `./types`) and by the
18
+ * hooks, without creating a circular import between the two. The hooks
19
+ * re-export them so the public API surface (consumed via the package root)
20
+ * stays unchanged.
21
+ */
22
+ type AlertCondition = "crossing_up" | "crossing_down" | "crossing";
23
+ interface Alert {
24
+ id: string;
25
+ price: number;
26
+ condition: AlertCondition;
27
+ message?: string;
28
+ triggered: boolean;
29
+ }
30
+ interface MeasurePoint {
31
+ price: number;
32
+ timestamp: number;
33
+ barIndex: number;
34
+ }
35
+ interface MeasureResult {
36
+ from: MeasurePoint;
37
+ to: MeasurePoint;
38
+ /** Absolute price difference */
39
+ priceDiff: number;
40
+ /** Percentage change from → to */
41
+ pricePercent: number;
42
+ /** Number of bars between the two points */
43
+ bars: number;
44
+ /** Time difference in milliseconds */
45
+ timeDiff: number;
46
+ }
47
+ interface MeasureState {
48
+ /** Whether measure mode is active (waiting for clicks) */
49
+ isActive: boolean;
50
+ /** First point (set after first click) */
51
+ fromPoint: MeasurePoint | null;
52
+ /** Current measurement result (null until both points are set) */
53
+ result: MeasureResult | null;
54
+ }
55
+ type ReplaySpeed = 1 | 2 | 5 | 10;
56
+ interface ReplayState {
57
+ /** Whether a replay session is active */
58
+ isReplaying: boolean;
59
+ /** Whether the replay is currently paused */
60
+ isPaused: boolean;
61
+ /** Current playback speed multiplier */
62
+ speed: ReplaySpeed;
63
+ /** Current bar index in the replay */
64
+ barIndex: number;
65
+ /** Total number of bars in the saved data */
66
+ totalBars: number;
67
+ }
68
+
12
69
  /**
13
70
  * Explicit partial symbol type — avoids `PickPartial<SymbolInfo, ...>` which
14
71
  * degenerates when SymbolInfo has an index signature `[key: string]: unknown`.
@@ -74,6 +131,37 @@ interface KlinechartsUIState {
74
131
  * undo/redo and layout presets.
75
132
  */
76
133
  indicatorAxes: Record<string, string>;
134
+ /**
135
+ * Visibility overrides for indicators, keyed by indicator id
136
+ * (`main_<name>` / `sub_<name>`), value is whether the indicator is shown.
137
+ * Mirrors the `visible` flag held inside klinecharts so `useIndicators` can
138
+ * expose a reactive getter (the chart instance has no React-friendly read
139
+ * path). Only populated for indicators whose visibility has been toggled
140
+ * away from the default; an absent key means visible (`true`). Updated by
141
+ * `setIndicatorVisible` and the collapse/expand helpers, and rebuilt when a
142
+ * layout preset is restored so the mirror never drifts from the chart.
143
+ */
144
+ indicatorVisibility: Record<string, boolean>;
145
+ /**
146
+ * Price alerts (`useAlerts`). Lives in the shared store rather than per-hook
147
+ * local state so every consumer (toolbar, list panel, status bar, sound
148
+ * trigger) observes one synchronized list. The crossing poller and the
149
+ * `onAlertTriggered` listener are owned by the provider, not the hook.
150
+ */
151
+ alerts: Alert[];
152
+ /**
153
+ * Measure-tool state (`useMeasure`). Shared so the toolbar toggle and the
154
+ * result readout panel stay in sync regardless of where each is mounted.
155
+ */
156
+ measure: MeasureState;
157
+ /**
158
+ * Historical-replay control state (`useReplay`). Shared so play/pause/step
159
+ * controls in different components drive one session. The playback interval
160
+ * and data buffers are owned by the provider (see the `replay*Ref` fields on
161
+ * the dispatch value), guaranteeing a single timer no matter how many hook
162
+ * instances are mounted.
163
+ */
164
+ replay: ReplayState;
77
165
  styles: DeepPartial<Styles> | undefined;
78
166
  screenshotUrl: string | null;
79
167
  }
@@ -104,6 +192,18 @@ type KlinechartsUIAction = {
104
192
  } | {
105
193
  type: "SET_INDICATOR_AXES";
106
194
  axes: Record<string, string>;
195
+ } | {
196
+ type: "SET_INDICATOR_VISIBILITY";
197
+ visibility: Record<string, boolean>;
198
+ } | {
199
+ type: "SET_ALERTS";
200
+ alerts: Alert[];
201
+ } | {
202
+ type: "SET_MEASURE";
203
+ measure: Partial<MeasureState>;
204
+ } | {
205
+ type: "SET_REPLAY";
206
+ replay: Partial<ReplayState>;
107
207
  } | {
108
208
  type: "SET_STYLES";
109
209
  styles: DeepPartial<Styles> | undefined;
@@ -127,6 +227,20 @@ interface KlinechartsUIDispatchValue {
127
227
  fullscreenContainerRef: RefObject<HTMLElement | null>;
128
228
  /** Ref populated by useUndoRedo; other hooks call it to record actions. */
129
229
  undoRedoListenerRef: RefObject<UndoRedoListener | null>;
230
+ /**
231
+ * Listener set by `useAlerts.onAlertTriggered`; invoked by the provider-owned
232
+ * crossing poller when an alert fires. Last writer wins (one active listener).
233
+ */
234
+ alertTriggeredListenerRef: RefObject<((alert: Alert) => void) | null>;
235
+ /**
236
+ * Provider-owned replay resources, shared across every `useReplay` instance
237
+ * so there is exactly one playback timer and one data buffer. The hook reads
238
+ * and writes these instead of its own refs; the provider clears the interval
239
+ * on unmount.
240
+ */
241
+ replayIntervalRef: RefObject<ReturnType<typeof setInterval> | null>;
242
+ replaySavedDataRef: RefObject<KLineData[]>;
243
+ replayIndexRef: RefObject<number>;
130
244
  }
131
245
  /** Combined context value returned by `useKlinechartsUI()`. */
132
246
  interface KlinechartsUIContextValue extends KlinechartsUIDispatchValue {
@@ -187,6 +301,13 @@ declare function useSymbolSearch(debounceMs?: number): UseSymbolSearchReturn;
187
301
  interface IndicatorInfo {
188
302
  name: string;
189
303
  isActive: boolean;
304
+ /**
305
+ * Whether the indicator is currently visible on the chart. Defaults to
306
+ * `true`; only `false` after the indicator has been hidden via
307
+ * `setIndicatorVisible` or `collapseSubIndicator`. Meaningful only when
308
+ * `isActive` is `true` (inactive indicators are always reported `true`).
309
+ */
310
+ visible: boolean;
190
311
  }
191
312
  /** Options accepted when adding an indicator. */
192
313
  interface AddIndicatorOptions {
@@ -214,6 +335,13 @@ interface UseIndicatorsReturn {
214
335
  moveToMain: (name: string) => void;
215
336
  moveToSub: (name: string) => void;
216
337
  setIndicatorVisible: (name: string, isMain: boolean, visible: boolean) => void;
338
+ /**
339
+ * Read whether an indicator is currently visible. Returns `true` for the
340
+ * default (un-toggled) state and for inactive indicators. This is the
341
+ * reactive read counterpart to `setIndicatorVisible` — UI no longer needs to
342
+ * track visibility locally or reach into the chart instance.
343
+ */
344
+ isIndicatorVisible: (name: string, isMain: boolean) => boolean;
217
345
  updateIndicatorParams: (name: string, paneId: string, params: number[]) => void;
218
346
  getIndicatorParams: (name: string) => {
219
347
  label: string;
@@ -236,6 +364,13 @@ interface UseIndicatorsReturn {
236
364
  indicatorAxes: Record<string, string>;
237
365
  /** Get the custom `yAxisId` an indicator is bound to, or `undefined` for the default axis. */
238
366
  getIndicatorAxis: (name: string, isMain: boolean) => string | undefined;
367
+ /**
368
+ * Visibility overrides keyed by indicator id (`main_<name>` / `sub_<name>`).
369
+ * Only contains indicators hidden away from the default; an absent key means
370
+ * visible. Mirror of the provider state, exposed for layout-preset
371
+ * persistence and direct rendering.
372
+ */
373
+ indicatorVisibility: Record<string, boolean>;
239
374
  /**
240
375
  * Rebind an existing indicator to a different Y-axis. Because klinecharts v10
241
376
  * `overrideIndicator` cannot change axis binding, this removes and recreates
@@ -561,14 +696,6 @@ interface UseCrosshairReturn {
561
696
  }
562
697
  declare function useCrosshair(): UseCrosshairReturn;
563
698
 
564
- type AlertCondition = "crossing_up" | "crossing_down" | "crossing";
565
- interface Alert {
566
- id: string;
567
- price: number;
568
- condition: AlertCondition;
569
- message?: string;
570
- triggered: boolean;
571
- }
572
699
  interface UseAlertsReturn {
573
700
  alerts: Alert[];
574
701
  addAlert: (price: number, condition: AlertCondition, message?: string) => string;
@@ -576,6 +703,15 @@ interface UseAlertsReturn {
576
703
  clearAlerts: () => void;
577
704
  onAlertTriggered: (callback: (alert: Alert) => void) => void;
578
705
  }
706
+ /**
707
+ * Headless hook for price-crossing alerts.
708
+ *
709
+ * The alert list lives in the shared provider store, and the 1s crossing
710
+ * poller + the `onAlertTriggered` listener are owned by the provider. This
711
+ * means several `useAlerts()` instances (toolbar, list panel, sound trigger)
712
+ * observe and mutate one synchronized list and share a single poller — they no
713
+ * longer drift apart or each spawn their own interval.
714
+ */
579
715
  declare function useAlerts(): UseAlertsReturn;
580
716
 
581
717
  type ExportFormat = "csv" | "json";
@@ -602,7 +738,6 @@ interface UseWatchlistReturn {
602
738
  }
603
739
  declare function useWatchlist(): UseWatchlistReturn;
604
740
 
605
- type ReplaySpeed = 1 | 2 | 5 | 10;
606
741
  interface UseReplayReturn {
607
742
  /** Whether a replay session is active */
608
743
  isReplaying: boolean;
@@ -633,8 +768,13 @@ interface UseReplayReturn {
633
768
  * Headless hook for historical data replay (bar-by-bar playback).
634
769
  *
635
770
  * Loads the current chart data, clears the chart, then progressively adds
636
- * bars back one at a time at the configured speed. Useful for backtesting
637
- * and reviewing price action.
771
+ * bars back one at a time at the configured speed.
772
+ *
773
+ * Replay control state lives in the shared provider store and the playback
774
+ * interval + data buffers are owned by the provider (accessed through stable
775
+ * refs). This guarantees a single playback session even when `useReplay()` is
776
+ * mounted in several components (e.g. toolbar + bottom controls + status bar):
777
+ * starting in one and stepping in another drives the same timer and buffer.
638
778
  */
639
779
  declare function useReplay(): UseReplayReturn;
640
780
 
@@ -666,23 +806,6 @@ interface UseCompareReturn {
666
806
  */
667
807
  declare function useCompare(): UseCompareReturn;
668
808
 
669
- interface MeasurePoint {
670
- price: number;
671
- timestamp: number;
672
- barIndex: number;
673
- }
674
- interface MeasureResult {
675
- from: MeasurePoint;
676
- to: MeasurePoint;
677
- /** Absolute price difference */
678
- priceDiff: number;
679
- /** Percentage change from → to */
680
- pricePercent: number;
681
- /** Number of bars between the two points */
682
- bars: number;
683
- /** Time difference in milliseconds */
684
- timeDiff: number;
685
- }
686
809
  interface UseMeasureReturn {
687
810
  /** Whether measure mode is active (waiting for clicks) */
688
811
  isActive: boolean;
@@ -701,7 +824,10 @@ interface UseMeasureReturn {
701
824
  * Headless hook for measuring distance/time/percentage between two points.
702
825
  *
703
826
  * Activates measure mode, captures two clicks on the chart via overlay
704
- * interaction, then computes price diff, %, bar count, and time diff.
827
+ * interaction, then computes price diff, %, bar count, and time diff. The
828
+ * measure state (active/from/result) lives in the shared provider store, so a
829
+ * toolbar toggle and a separate result-readout panel stay in sync no matter
830
+ * where each is mounted.
705
831
  */
706
832
  declare function useMeasure(): UseMeasureReturn;
707
833
 
package/dist/index.d.ts CHANGED
@@ -9,6 +9,63 @@ interface TerminalPeriod extends Period {
9
9
  }
10
10
  declare const DEFAULT_PERIODS: TerminalPeriod[];
11
11
 
12
+ /**
13
+ * Shared domain types for stateful feature hooks (`useAlerts`, `useMeasure`,
14
+ * `useReplay`).
15
+ *
16
+ * These live in a neutral module so they can be referenced both by the
17
+ * provider store (`KlinechartsUIState` / actions in `./types`) and by the
18
+ * hooks, without creating a circular import between the two. The hooks
19
+ * re-export them so the public API surface (consumed via the package root)
20
+ * stays unchanged.
21
+ */
22
+ type AlertCondition = "crossing_up" | "crossing_down" | "crossing";
23
+ interface Alert {
24
+ id: string;
25
+ price: number;
26
+ condition: AlertCondition;
27
+ message?: string;
28
+ triggered: boolean;
29
+ }
30
+ interface MeasurePoint {
31
+ price: number;
32
+ timestamp: number;
33
+ barIndex: number;
34
+ }
35
+ interface MeasureResult {
36
+ from: MeasurePoint;
37
+ to: MeasurePoint;
38
+ /** Absolute price difference */
39
+ priceDiff: number;
40
+ /** Percentage change from → to */
41
+ pricePercent: number;
42
+ /** Number of bars between the two points */
43
+ bars: number;
44
+ /** Time difference in milliseconds */
45
+ timeDiff: number;
46
+ }
47
+ interface MeasureState {
48
+ /** Whether measure mode is active (waiting for clicks) */
49
+ isActive: boolean;
50
+ /** First point (set after first click) */
51
+ fromPoint: MeasurePoint | null;
52
+ /** Current measurement result (null until both points are set) */
53
+ result: MeasureResult | null;
54
+ }
55
+ type ReplaySpeed = 1 | 2 | 5 | 10;
56
+ interface ReplayState {
57
+ /** Whether a replay session is active */
58
+ isReplaying: boolean;
59
+ /** Whether the replay is currently paused */
60
+ isPaused: boolean;
61
+ /** Current playback speed multiplier */
62
+ speed: ReplaySpeed;
63
+ /** Current bar index in the replay */
64
+ barIndex: number;
65
+ /** Total number of bars in the saved data */
66
+ totalBars: number;
67
+ }
68
+
12
69
  /**
13
70
  * Explicit partial symbol type — avoids `PickPartial<SymbolInfo, ...>` which
14
71
  * degenerates when SymbolInfo has an index signature `[key: string]: unknown`.
@@ -74,6 +131,37 @@ interface KlinechartsUIState {
74
131
  * undo/redo and layout presets.
75
132
  */
76
133
  indicatorAxes: Record<string, string>;
134
+ /**
135
+ * Visibility overrides for indicators, keyed by indicator id
136
+ * (`main_<name>` / `sub_<name>`), value is whether the indicator is shown.
137
+ * Mirrors the `visible` flag held inside klinecharts so `useIndicators` can
138
+ * expose a reactive getter (the chart instance has no React-friendly read
139
+ * path). Only populated for indicators whose visibility has been toggled
140
+ * away from the default; an absent key means visible (`true`). Updated by
141
+ * `setIndicatorVisible` and the collapse/expand helpers, and rebuilt when a
142
+ * layout preset is restored so the mirror never drifts from the chart.
143
+ */
144
+ indicatorVisibility: Record<string, boolean>;
145
+ /**
146
+ * Price alerts (`useAlerts`). Lives in the shared store rather than per-hook
147
+ * local state so every consumer (toolbar, list panel, status bar, sound
148
+ * trigger) observes one synchronized list. The crossing poller and the
149
+ * `onAlertTriggered` listener are owned by the provider, not the hook.
150
+ */
151
+ alerts: Alert[];
152
+ /**
153
+ * Measure-tool state (`useMeasure`). Shared so the toolbar toggle and the
154
+ * result readout panel stay in sync regardless of where each is mounted.
155
+ */
156
+ measure: MeasureState;
157
+ /**
158
+ * Historical-replay control state (`useReplay`). Shared so play/pause/step
159
+ * controls in different components drive one session. The playback interval
160
+ * and data buffers are owned by the provider (see the `replay*Ref` fields on
161
+ * the dispatch value), guaranteeing a single timer no matter how many hook
162
+ * instances are mounted.
163
+ */
164
+ replay: ReplayState;
77
165
  styles: DeepPartial<Styles> | undefined;
78
166
  screenshotUrl: string | null;
79
167
  }
@@ -104,6 +192,18 @@ type KlinechartsUIAction = {
104
192
  } | {
105
193
  type: "SET_INDICATOR_AXES";
106
194
  axes: Record<string, string>;
195
+ } | {
196
+ type: "SET_INDICATOR_VISIBILITY";
197
+ visibility: Record<string, boolean>;
198
+ } | {
199
+ type: "SET_ALERTS";
200
+ alerts: Alert[];
201
+ } | {
202
+ type: "SET_MEASURE";
203
+ measure: Partial<MeasureState>;
204
+ } | {
205
+ type: "SET_REPLAY";
206
+ replay: Partial<ReplayState>;
107
207
  } | {
108
208
  type: "SET_STYLES";
109
209
  styles: DeepPartial<Styles> | undefined;
@@ -127,6 +227,20 @@ interface KlinechartsUIDispatchValue {
127
227
  fullscreenContainerRef: RefObject<HTMLElement | null>;
128
228
  /** Ref populated by useUndoRedo; other hooks call it to record actions. */
129
229
  undoRedoListenerRef: RefObject<UndoRedoListener | null>;
230
+ /**
231
+ * Listener set by `useAlerts.onAlertTriggered`; invoked by the provider-owned
232
+ * crossing poller when an alert fires. Last writer wins (one active listener).
233
+ */
234
+ alertTriggeredListenerRef: RefObject<((alert: Alert) => void) | null>;
235
+ /**
236
+ * Provider-owned replay resources, shared across every `useReplay` instance
237
+ * so there is exactly one playback timer and one data buffer. The hook reads
238
+ * and writes these instead of its own refs; the provider clears the interval
239
+ * on unmount.
240
+ */
241
+ replayIntervalRef: RefObject<ReturnType<typeof setInterval> | null>;
242
+ replaySavedDataRef: RefObject<KLineData[]>;
243
+ replayIndexRef: RefObject<number>;
130
244
  }
131
245
  /** Combined context value returned by `useKlinechartsUI()`. */
132
246
  interface KlinechartsUIContextValue extends KlinechartsUIDispatchValue {
@@ -187,6 +301,13 @@ declare function useSymbolSearch(debounceMs?: number): UseSymbolSearchReturn;
187
301
  interface IndicatorInfo {
188
302
  name: string;
189
303
  isActive: boolean;
304
+ /**
305
+ * Whether the indicator is currently visible on the chart. Defaults to
306
+ * `true`; only `false` after the indicator has been hidden via
307
+ * `setIndicatorVisible` or `collapseSubIndicator`. Meaningful only when
308
+ * `isActive` is `true` (inactive indicators are always reported `true`).
309
+ */
310
+ visible: boolean;
190
311
  }
191
312
  /** Options accepted when adding an indicator. */
192
313
  interface AddIndicatorOptions {
@@ -214,6 +335,13 @@ interface UseIndicatorsReturn {
214
335
  moveToMain: (name: string) => void;
215
336
  moveToSub: (name: string) => void;
216
337
  setIndicatorVisible: (name: string, isMain: boolean, visible: boolean) => void;
338
+ /**
339
+ * Read whether an indicator is currently visible. Returns `true` for the
340
+ * default (un-toggled) state and for inactive indicators. This is the
341
+ * reactive read counterpart to `setIndicatorVisible` — UI no longer needs to
342
+ * track visibility locally or reach into the chart instance.
343
+ */
344
+ isIndicatorVisible: (name: string, isMain: boolean) => boolean;
217
345
  updateIndicatorParams: (name: string, paneId: string, params: number[]) => void;
218
346
  getIndicatorParams: (name: string) => {
219
347
  label: string;
@@ -236,6 +364,13 @@ interface UseIndicatorsReturn {
236
364
  indicatorAxes: Record<string, string>;
237
365
  /** Get the custom `yAxisId` an indicator is bound to, or `undefined` for the default axis. */
238
366
  getIndicatorAxis: (name: string, isMain: boolean) => string | undefined;
367
+ /**
368
+ * Visibility overrides keyed by indicator id (`main_<name>` / `sub_<name>`).
369
+ * Only contains indicators hidden away from the default; an absent key means
370
+ * visible. Mirror of the provider state, exposed for layout-preset
371
+ * persistence and direct rendering.
372
+ */
373
+ indicatorVisibility: Record<string, boolean>;
239
374
  /**
240
375
  * Rebind an existing indicator to a different Y-axis. Because klinecharts v10
241
376
  * `overrideIndicator` cannot change axis binding, this removes and recreates
@@ -561,14 +696,6 @@ interface UseCrosshairReturn {
561
696
  }
562
697
  declare function useCrosshair(): UseCrosshairReturn;
563
698
 
564
- type AlertCondition = "crossing_up" | "crossing_down" | "crossing";
565
- interface Alert {
566
- id: string;
567
- price: number;
568
- condition: AlertCondition;
569
- message?: string;
570
- triggered: boolean;
571
- }
572
699
  interface UseAlertsReturn {
573
700
  alerts: Alert[];
574
701
  addAlert: (price: number, condition: AlertCondition, message?: string) => string;
@@ -576,6 +703,15 @@ interface UseAlertsReturn {
576
703
  clearAlerts: () => void;
577
704
  onAlertTriggered: (callback: (alert: Alert) => void) => void;
578
705
  }
706
+ /**
707
+ * Headless hook for price-crossing alerts.
708
+ *
709
+ * The alert list lives in the shared provider store, and the 1s crossing
710
+ * poller + the `onAlertTriggered` listener are owned by the provider. This
711
+ * means several `useAlerts()` instances (toolbar, list panel, sound trigger)
712
+ * observe and mutate one synchronized list and share a single poller — they no
713
+ * longer drift apart or each spawn their own interval.
714
+ */
579
715
  declare function useAlerts(): UseAlertsReturn;
580
716
 
581
717
  type ExportFormat = "csv" | "json";
@@ -602,7 +738,6 @@ interface UseWatchlistReturn {
602
738
  }
603
739
  declare function useWatchlist(): UseWatchlistReturn;
604
740
 
605
- type ReplaySpeed = 1 | 2 | 5 | 10;
606
741
  interface UseReplayReturn {
607
742
  /** Whether a replay session is active */
608
743
  isReplaying: boolean;
@@ -633,8 +768,13 @@ interface UseReplayReturn {
633
768
  * Headless hook for historical data replay (bar-by-bar playback).
634
769
  *
635
770
  * Loads the current chart data, clears the chart, then progressively adds
636
- * bars back one at a time at the configured speed. Useful for backtesting
637
- * and reviewing price action.
771
+ * bars back one at a time at the configured speed.
772
+ *
773
+ * Replay control state lives in the shared provider store and the playback
774
+ * interval + data buffers are owned by the provider (accessed through stable
775
+ * refs). This guarantees a single playback session even when `useReplay()` is
776
+ * mounted in several components (e.g. toolbar + bottom controls + status bar):
777
+ * starting in one and stepping in another drives the same timer and buffer.
638
778
  */
639
779
  declare function useReplay(): UseReplayReturn;
640
780
 
@@ -666,23 +806,6 @@ interface UseCompareReturn {
666
806
  */
667
807
  declare function useCompare(): UseCompareReturn;
668
808
 
669
- interface MeasurePoint {
670
- price: number;
671
- timestamp: number;
672
- barIndex: number;
673
- }
674
- interface MeasureResult {
675
- from: MeasurePoint;
676
- to: MeasurePoint;
677
- /** Absolute price difference */
678
- priceDiff: number;
679
- /** Percentage change from → to */
680
- pricePercent: number;
681
- /** Number of bars between the two points */
682
- bars: number;
683
- /** Time difference in milliseconds */
684
- timeDiff: number;
685
- }
686
809
  interface UseMeasureReturn {
687
810
  /** Whether measure mode is active (waiting for clicks) */
688
811
  isActive: boolean;
@@ -701,7 +824,10 @@ interface UseMeasureReturn {
701
824
  * Headless hook for measuring distance/time/percentage between two points.
702
825
  *
703
826
  * Activates measure mode, captures two clicks on the chart via overlay
704
- * interaction, then computes price diff, %, bar count, and time diff.
827
+ * interaction, then computes price diff, %, bar count, and time diff. The
828
+ * measure state (active/from/result) lives in the shared provider store, so a
829
+ * toolbar toggle and a separate result-readout panel stay in sync no matter
830
+ * where each is mounted.
705
831
  */
706
832
  declare function useMeasure(): UseMeasureReturn;
707
833