@forgecharts/sdk 1.1.28 → 1.1.30

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.
Files changed (237) hide show
  1. package/dist/index.js +8100 -48
  2. package/dist/index.js.map +1 -1
  3. package/dist/internal.js +8851 -31
  4. package/dist/internal.js.map +1 -1
  5. package/dist/react/index.js +11558 -27
  6. package/dist/react/index.js.map +1 -1
  7. package/dist/react/internal.js +12147 -43
  8. package/dist/react/internal.js.map +1 -1
  9. package/package.json +1 -1
  10. package/dist/__tests__/backwardCompatibility.test.js +0 -159
  11. package/dist/__tests__/backwardCompatibility.test.js.map +0 -1
  12. package/dist/__tests__/candleInvariant.test.js +0 -415
  13. package/dist/__tests__/candleInvariant.test.js.map +0 -1
  14. package/dist/__tests__/public-api-surface.js +0 -38
  15. package/dist/__tests__/public-api-surface.js.map +0 -1
  16. package/dist/__tests__/timeframeBoundary.test.js +0 -452
  17. package/dist/__tests__/timeframeBoundary.test.js.map +0 -1
  18. package/dist/api/DrawingManager.js +0 -190
  19. package/dist/api/DrawingManager.js.map +0 -1
  20. package/dist/api/EventBus.js +0 -44
  21. package/dist/api/EventBus.js.map +0 -1
  22. package/dist/api/IndicatorDAG.js +0 -316
  23. package/dist/api/IndicatorDAG.js.map +0 -1
  24. package/dist/api/IndicatorRegistry.js +0 -39
  25. package/dist/api/IndicatorRegistry.js.map +0 -1
  26. package/dist/api/LayoutManager.js +0 -51
  27. package/dist/api/LayoutManager.js.map +0 -1
  28. package/dist/api/PaneManager.js +0 -119
  29. package/dist/api/PaneManager.js.map +0 -1
  30. package/dist/api/ReferenceAPI.js +0 -153
  31. package/dist/api/ReferenceAPI.js.map +0 -1
  32. package/dist/api/TChart.js +0 -765
  33. package/dist/api/TChart.js.map +0 -1
  34. package/dist/api/createChart.js +0 -42
  35. package/dist/api/createChart.js.map +0 -1
  36. package/dist/api/drawing tools/fib gann menu/fibRetracement.js +0 -22
  37. package/dist/api/drawing tools/fib gann menu/fibRetracement.js.map +0 -1
  38. package/dist/api/drawing tools/lines menu/crossLine.js +0 -16
  39. package/dist/api/drawing tools/lines menu/crossLine.js.map +0 -1
  40. package/dist/api/drawing tools/lines menu/disjointChannel.js +0 -59
  41. package/dist/api/drawing tools/lines menu/disjointChannel.js.map +0 -1
  42. package/dist/api/drawing tools/lines menu/extendedLine.js +0 -17
  43. package/dist/api/drawing tools/lines menu/extendedLine.js.map +0 -1
  44. package/dist/api/drawing tools/lines menu/flatTopBottom.js +0 -41
  45. package/dist/api/drawing tools/lines menu/flatTopBottom.js.map +0 -1
  46. package/dist/api/drawing tools/lines menu/horizontal.js +0 -19
  47. package/dist/api/drawing tools/lines menu/horizontal.js.map +0 -1
  48. package/dist/api/drawing tools/lines menu/horizontalRay.js +0 -20
  49. package/dist/api/drawing tools/lines menu/horizontalRay.js.map +0 -1
  50. package/dist/api/drawing tools/lines menu/infoLine.js +0 -107
  51. package/dist/api/drawing tools/lines menu/infoLine.js.map +0 -1
  52. package/dist/api/drawing tools/lines menu/insidePitchfork.js +0 -31
  53. package/dist/api/drawing tools/lines menu/insidePitchfork.js.map +0 -1
  54. package/dist/api/drawing tools/lines menu/modifiedSchiffPitchfork.js +0 -15
  55. package/dist/api/drawing tools/lines menu/modifiedSchiffPitchfork.js.map +0 -1
  56. package/dist/api/drawing tools/lines menu/parallelChannel.js +0 -43
  57. package/dist/api/drawing tools/lines menu/parallelChannel.js.map +0 -1
  58. package/dist/api/drawing tools/lines menu/pitchfork.js +0 -12
  59. package/dist/api/drawing tools/lines menu/pitchfork.js.map +0 -1
  60. package/dist/api/drawing tools/lines menu/ray.js +0 -23
  61. package/dist/api/drawing tools/lines menu/ray.js.map +0 -1
  62. package/dist/api/drawing tools/lines menu/regressionTrend.js +0 -127
  63. package/dist/api/drawing tools/lines menu/regressionTrend.js.map +0 -1
  64. package/dist/api/drawing tools/lines menu/schiffPitchfork.js +0 -15
  65. package/dist/api/drawing tools/lines menu/schiffPitchfork.js.map +0 -1
  66. package/dist/api/drawing tools/lines menu/trendAngle.js +0 -51
  67. package/dist/api/drawing tools/lines menu/trendAngle.js.map +0 -1
  68. package/dist/api/drawing tools/lines menu/trendline.js +0 -11
  69. package/dist/api/drawing tools/lines menu/trendline.js.map +0 -1
  70. package/dist/api/drawing tools/lines menu/vertical.js +0 -11
  71. package/dist/api/drawing tools/lines menu/vertical.js.map +0 -1
  72. package/dist/api/drawing tools/pointers menu/crosshair.js +0 -16
  73. package/dist/api/drawing tools/pointers menu/crosshair.js.map +0 -1
  74. package/dist/api/drawing tools/pointers menu/cursor.js +0 -15
  75. package/dist/api/drawing tools/pointers menu/cursor.js.map +0 -1
  76. package/dist/api/drawing tools/pointers menu/demonstration.js +0 -30
  77. package/dist/api/drawing tools/pointers menu/demonstration.js.map +0 -1
  78. package/dist/api/drawing tools/pointers menu/dot.js +0 -23
  79. package/dist/api/drawing tools/pointers menu/dot.js.map +0 -1
  80. package/dist/api/drawing tools/shapes menu/rectangle.js +0 -19
  81. package/dist/api/drawing tools/shapes menu/rectangle.js.map +0 -1
  82. package/dist/api/drawing tools/shapes menu/text.js +0 -25
  83. package/dist/api/drawing tools/shapes menu/text.js.map +0 -1
  84. package/dist/api/drawingUtils.js +0 -83
  85. package/dist/api/drawingUtils.js.map +0 -1
  86. package/dist/core/CanvasLayer.js +0 -56
  87. package/dist/core/CanvasLayer.js.map +0 -1
  88. package/dist/core/Chart.js +0 -839
  89. package/dist/core/Chart.js.map +0 -1
  90. package/dist/core/CoordTransform.js +0 -224
  91. package/dist/core/CoordTransform.js.map +0 -1
  92. package/dist/core/Crosshair.js +0 -186
  93. package/dist/core/Crosshair.js.map +0 -1
  94. package/dist/core/IndicatorEngine.js +0 -181
  95. package/dist/core/IndicatorEngine.js.map +0 -1
  96. package/dist/core/InteractionManager.js +0 -698
  97. package/dist/core/InteractionManager.js.map +0 -1
  98. package/dist/core/PriceScale.js +0 -113
  99. package/dist/core/PriceScale.js.map +0 -1
  100. package/dist/core/Series.js +0 -114
  101. package/dist/core/Series.js.map +0 -1
  102. package/dist/core/TimeScale.js +0 -150
  103. package/dist/core/TimeScale.js.map +0 -1
  104. package/dist/datafeed/DatafeedConnector.js +0 -268
  105. package/dist/datafeed/DatafeedConnector.js.map +0 -1
  106. package/dist/engine/CandleEngine.js +0 -318
  107. package/dist/engine/CandleEngine.js.map +0 -1
  108. package/dist/engine/__tests__/CandleEngine.test.js +0 -300
  109. package/dist/engine/__tests__/CandleEngine.test.js.map +0 -1
  110. package/dist/engine/candleInvariants.js +0 -134
  111. package/dist/engine/candleInvariants.js.map +0 -1
  112. package/dist/engine/mergeUtils.js +0 -64
  113. package/dist/engine/mergeUtils.js.map +0 -1
  114. package/dist/engine/timeframeUtils.js +0 -100
  115. package/dist/engine/timeframeUtils.js.map +0 -1
  116. package/dist/licensing/ChartRuntimeResolver.js +0 -310
  117. package/dist/licensing/ChartRuntimeResolver.js.map +0 -1
  118. package/dist/licensing/LicenseManager.js +0 -114
  119. package/dist/licensing/LicenseManager.js.map +0 -1
  120. package/dist/licensing/__tests__/ChartRuntimeResolver.test.js +0 -177
  121. package/dist/licensing/__tests__/ChartRuntimeResolver.test.js.map +0 -1
  122. package/dist/licensing/__tests__/LicenseManager.test.js +0 -153
  123. package/dist/licensing/__tests__/LicenseManager.test.js.map +0 -1
  124. package/dist/licensing/licenseTypes.js +0 -2
  125. package/dist/licensing/licenseTypes.js.map +0 -1
  126. package/dist/pine/PineCompiler.js +0 -44
  127. package/dist/pine/PineCompiler.js.map +0 -1
  128. package/dist/pine/diagnostics.js +0 -11
  129. package/dist/pine/diagnostics.js.map +0 -1
  130. package/dist/pine/index.js +0 -5
  131. package/dist/pine/index.js.map +0 -1
  132. package/dist/pine/pine-ast.js +0 -19
  133. package/dist/pine/pine-ast.js.map +0 -1
  134. package/dist/pine/pine-lexer.js +0 -249
  135. package/dist/pine/pine-lexer.js.map +0 -1
  136. package/dist/pine/pine-parser.js +0 -416
  137. package/dist/pine/pine-parser.js.map +0 -1
  138. package/dist/pine/pine-transpiler.js +0 -260
  139. package/dist/pine/pine-transpiler.js.map +0 -1
  140. package/dist/pixi/LayerName.js +0 -35
  141. package/dist/pixi/LayerName.js.map +0 -1
  142. package/dist/pixi/PixiCandlestickRenderer.js +0 -107
  143. package/dist/pixi/PixiCandlestickRenderer.js.map +0 -1
  144. package/dist/pixi/PixiChart.js +0 -367
  145. package/dist/pixi/PixiChart.js.map +0 -1
  146. package/dist/pixi/PixiCrosshairRenderer.js +0 -110
  147. package/dist/pixi/PixiCrosshairRenderer.js.map +0 -1
  148. package/dist/pixi/PixiDrawingRenderer.js +0 -111
  149. package/dist/pixi/PixiDrawingRenderer.js.map +0 -1
  150. package/dist/pixi/PixiGridRenderer.js +0 -114
  151. package/dist/pixi/PixiGridRenderer.js.map +0 -1
  152. package/dist/pixi/PixiLayerManager.js +0 -92
  153. package/dist/pixi/PixiLayerManager.js.map +0 -1
  154. package/dist/react/canvas/ChartCanvas.js +0 -604
  155. package/dist/react/canvas/ChartCanvas.js.map +0 -1
  156. package/dist/react/canvas/ChartContextMenu.js +0 -5
  157. package/dist/react/canvas/ChartContextMenu.js.map +0 -1
  158. package/dist/react/canvas/ChartSettingsDialog.js +0 -28
  159. package/dist/react/canvas/ChartSettingsDialog.js.map +0 -1
  160. package/dist/react/canvas/IndicatorLabel.js +0 -196
  161. package/dist/react/canvas/IndicatorLabel.js.map +0 -1
  162. package/dist/react/canvas/IndicatorPane.js +0 -395
  163. package/dist/react/canvas/IndicatorPane.js.map +0 -1
  164. package/dist/react/canvas/PointerOverlay.js +0 -61
  165. package/dist/react/canvas/PointerOverlay.js.map +0 -1
  166. package/dist/react/canvas/toolbars/LeftToolbar.js +0 -407
  167. package/dist/react/canvas/toolbars/LeftToolbar.js.map +0 -1
  168. package/dist/react/hooks/useChartCapabilities.js +0 -66
  169. package/dist/react/hooks/useChartCapabilities.js.map +0 -1
  170. package/dist/react/shell/ManagedAppShell.js +0 -440
  171. package/dist/react/shell/ManagedAppShell.js.map +0 -1
  172. package/dist/react/trading/TradingBridge.js +0 -73
  173. package/dist/react/trading/TradingBridge.js.map +0 -1
  174. package/dist/react/workspace/ChartWorkspace.js +0 -42
  175. package/dist/react/workspace/ChartWorkspace.js.map +0 -1
  176. package/dist/react/workspace/FloatingPanel.js +0 -82
  177. package/dist/react/workspace/FloatingPanel.js.map +0 -1
  178. package/dist/react/workspace/IndicatorsDialog.js +0 -121
  179. package/dist/react/workspace/IndicatorsDialog.js.map +0 -1
  180. package/dist/react/workspace/LayoutMenu.js +0 -113
  181. package/dist/react/workspace/LayoutMenu.js.map +0 -1
  182. package/dist/react/workspace/SymbolSearchDialog.js +0 -245
  183. package/dist/react/workspace/SymbolSearchDialog.js.map +0 -1
  184. package/dist/react/workspace/TabBar.js +0 -29
  185. package/dist/react/workspace/TabBar.js.map +0 -1
  186. package/dist/react/workspace/toolbars/BottomToolbar.js +0 -236
  187. package/dist/react/workspace/toolbars/BottomToolbar.js.map +0 -1
  188. package/dist/react/workspace/toolbars/RightToolbar.js +0 -18
  189. package/dist/react/workspace/toolbars/RightToolbar.js.map +0 -1
  190. package/dist/react/workspace/toolbars/TopToolbar.js +0 -82
  191. package/dist/react/workspace/toolbars/TopToolbar.js.map +0 -1
  192. package/dist/renderers/CandlestickRenderer.js +0 -98
  193. package/dist/renderers/CandlestickRenderer.js.map +0 -1
  194. package/dist/renderers/HistogramRenderer.js +0 -50
  195. package/dist/renderers/HistogramRenderer.js.map +0 -1
  196. package/dist/renderers/LineRenderer.js +0 -64
  197. package/dist/renderers/LineRenderer.js.map +0 -1
  198. package/dist/theme/colors.js +0 -19
  199. package/dist/theme/colors.js.map +0 -1
  200. package/dist/tools/barDivergenceCheck.js +0 -200
  201. package/dist/tools/barDivergenceCheck.js.map +0 -1
  202. package/dist/trading/TradingOverlayStore.js +0 -139
  203. package/dist/trading/TradingOverlayStore.js.map +0 -1
  204. package/dist/trading/UnmanagedIngestion.js +0 -114
  205. package/dist/trading/UnmanagedIngestion.js.map +0 -1
  206. package/dist/trading/__tests__/ManagedTradingController.test.js +0 -271
  207. package/dist/trading/__tests__/ManagedTradingController.test.js.map +0 -1
  208. package/dist/trading/__tests__/TradingOverlayStore.test.js +0 -267
  209. package/dist/trading/__tests__/TradingOverlayStore.test.js.map +0 -1
  210. package/dist/trading/__tests__/UnmanagedIngestion.test.js +0 -170
  211. package/dist/trading/__tests__/UnmanagedIngestion.test.js.map +0 -1
  212. package/dist/trading/managed/ManagedTradingController.js +0 -247
  213. package/dist/trading/managed/ManagedTradingController.js.map +0 -1
  214. package/dist/trading/managed/managedCapabilities.js +0 -79
  215. package/dist/trading/managed/managedCapabilities.js.map +0 -1
  216. package/dist/trading/managed/managedTypes.js +0 -13
  217. package/dist/trading/managed/managedTypes.js.map +0 -1
  218. package/dist/trading/tradingTypes.js +0 -8
  219. package/dist/trading/tradingTypes.js.map +0 -1
  220. package/dist/tscript/TScriptIndicator.js +0 -47
  221. package/dist/tscript/TScriptIndicator.js.map +0 -1
  222. package/dist/tscript/ast.js +0 -22
  223. package/dist/tscript/ast.js.map +0 -1
  224. package/dist/tscript/lexer.js +0 -187
  225. package/dist/tscript/lexer.js.map +0 -1
  226. package/dist/tscript/parser.js +0 -318
  227. package/dist/tscript/parser.js.map +0 -1
  228. package/dist/tscript/runtime.js +0 -475
  229. package/dist/tscript/runtime.js.map +0 -1
  230. package/dist/tscript/series.js +0 -79
  231. package/dist/tscript/series.js.map +0 -1
  232. package/dist/types/IChart.js +0 -2
  233. package/dist/types/IChart.js.map +0 -1
  234. package/dist/types/IRenderer.js +0 -2
  235. package/dist/types/IRenderer.js.map +0 -1
  236. package/dist/types/ISeries.js +0 -2
  237. package/dist/types/ISeries.js.map +0 -1
@@ -1,604 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- /**
3
- * ChartCanvas — stacks the main price chart above one or more indicator panes.
4
- *
5
- * Features:
6
- * - Creates a TChart instance and attaches any `initialIndicators`.
7
- * - Each non-overlay indicator gets its own sub-pane (managed by TChart's PaneManager).
8
- * - Draggable dividers let the user resize panes; the price-split fraction is
9
- * reported via onPriceFractionChange (no localStorage in this package).
10
- * - A requestAnimationFrame loop forwards viewport changes (pan/zoom) to the
11
- * indicator canvases so they stay in sync with the main chart’s time axis.
12
- *
13
- * Previously exported as MultiPaneChart — that name is kept as an alias.
14
- */
15
- import { useEffect, useRef, useState, useCallback, forwardRef, useImperativeHandle } from 'react';
16
- import { TChart, IndicatorDAG } from '../../';
17
- import { IndicatorPane } from './IndicatorPane';
18
- import { LeftToolbar } from './toolbars/LeftToolbar';
19
- import { IndicatorLabel, IndicatorConfigDialog } from './IndicatorLabel';
20
- import { ChartContextMenu } from './ChartContextMenu';
21
- import { ChartSettingsDialog } from './ChartSettingsDialog';
22
- import { PointerOverlay } from './PointerOverlay';
23
- // ─── Defaults ──────────────────────────────────────────────────────────────────
24
- const OVERLAY_COLORS = ['#2196f3', '#4caf50', '#ff9800', '#e040fb', '#00bcd4', '#f44336'];
25
- /** Candle duration in seconds per timeframe — mirrors Chart.ts _TF_SECONDS. */
26
- const _TF_SECONDS = {
27
- '1s': 1, '5s': 5, '10s': 10, '30s': 30,
28
- '1m': 60, '3m': 180, '5m': 300, '15m': 900, '30m': 1800,
29
- '1h': 3600, '2h': 7200, '4h': 14400, '6h': 21600, '12h': 43200,
30
- '1d': 86400, '3d': 259200, '1w': 604800, '1M': 2592000,
31
- };
32
- /**
33
- * Returns true if a hex background color is perceptually light (luminance > 0.5).
34
- * Used to derive a contrasting axis/text color automatically.
35
- */
36
- function _isLightBg(hex) {
37
- const c = hex.replace('#', '');
38
- if (c.length < 6)
39
- return false;
40
- const r = parseInt(c.slice(0, 2), 16) / 255;
41
- const g = parseInt(c.slice(2, 4), 16) / 255;
42
- const b = parseInt(c.slice(4, 6), 16) / 255;
43
- // sRGB luminance (WCAG formula)
44
- const toLinear = (v) => v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
45
- const L = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
46
- return L > 0.179;
47
- }
48
- function Divider({ onDrag }) {
49
- const lastY = useRef(0);
50
- const handleMouseDown = useCallback((e) => {
51
- e.preventDefault();
52
- lastY.current = e.clientY;
53
- const onMove = (me) => {
54
- onDrag(me.clientY - lastY.current);
55
- lastY.current = me.clientY;
56
- };
57
- const onUp = () => {
58
- window.removeEventListener('mousemove', onMove);
59
- window.removeEventListener('mouseup', onUp);
60
- };
61
- window.addEventListener('mousemove', onMove);
62
- window.addEventListener('mouseup', onUp);
63
- }, [onDrag]);
64
- return (_jsx("div", { onMouseDown: handleMouseDown, style: {
65
- height: 4,
66
- cursor: 'ns-resize',
67
- background: 'var(--border, #2a2e39)',
68
- flexShrink: 0,
69
- userSelect: 'none',
70
- } }));
71
- }
72
- // ─── Price helpers ───────────────────────────────────────────────────────────
73
- function _fmtPrice(v) {
74
- const abs = Math.abs(v);
75
- const dec = abs >= 100 ? 2 : abs >= 1 ? 2 : abs >= 0.0001 ? 4 : 6;
76
- return v.toLocaleString('en-US', { minimumFractionDigits: dec, maximumFractionDigits: dec });
77
- }
78
- function _fmtVol(v) {
79
- if (v >= 1_000_000)
80
- return `${(v / 1_000_000).toFixed(2)}M`;
81
- if (v >= 1_000)
82
- return `${(v / 1_000).toFixed(1)}K`;
83
- return v.toFixed(0);
84
- }
85
- // ─── PricePaneHeader ──────────────────────────────────────────────────────────
86
- function PricePaneHeader({ symbol, timeframe, bars, theme, indicators, overlayColors, onRemove, onConfigure, getExchangeLogoUrl, }) {
87
- const [collapsed, setCollapsed] = useState(false);
88
- const lastBar = bars[bars.length - 1];
89
- const prevBar = bars[bars.length - 2];
90
- const change = lastBar && prevBar ? lastBar.close - prevBar.close : 0;
91
- const pctChange = prevBar && prevBar.close !== 0 ? (change / prevBar.close) * 100 : 0;
92
- const isUp = change >= 0;
93
- const changeColor = isUp ? 'var(--up, #26a641)' : 'var(--down, #f85149)';
94
- const muted = theme === 'dark' ? 'rgba(255,255,255,0.42)' : 'rgba(0,0,0,0.38)';
95
- const textColor = theme === 'dark' ? 'rgba(255,255,255,0.82)' : 'rgba(0,0,0,0.82)';
96
- const overlayInds = indicators.filter((ind) => ind.config.overlay === true);
97
- return (_jsxs("div", { style: {
98
- position: 'absolute',
99
- top: 6,
100
- left: 6,
101
- zIndex: 3,
102
- pointerEvents: 'auto',
103
- maxWidth: 'calc(100% - 80px)',
104
- fontFamily: '-apple-system, BlinkMacSystemFont, sans-serif',
105
- userSelect: 'none',
106
- }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'baseline', flexWrap: 'wrap', gap: '0 5px', fontSize: 11.5, lineHeight: 1.7 }, children: [(() => {
107
- const exchange = symbol.includes(':') ? symbol.split(':')[0].toUpperCase() : '';
108
- if (!exchange)
109
- return null;
110
- const logoUrl = getExchangeLogoUrl?.(exchange);
111
- if (!logoUrl)
112
- return null;
113
- return (_jsx("img", { src: logoUrl, alt: exchange, width: 14, height: 14, style: { display: 'inline-block', verticalAlign: 'middle', marginBottom: 1, borderRadius: 2, flexShrink: 0 }, onError: (e) => { e.currentTarget.style.display = 'none'; } }));
114
- })(), _jsx("span", { style: { fontWeight: 700, color: textColor }, children: symbol }), _jsxs("span", { style: { color: muted }, children: ["\u00B7 ", timeframe] }), lastBar && (_jsxs(_Fragment, { children: [_jsxs("span", { children: [_jsx("span", { style: { color: muted }, children: "O" }), _jsx("span", { style: { color: muted }, children: " " }), _jsx("span", { style: { color: textColor }, children: _fmtPrice(lastBar.open) })] }), _jsxs("span", { children: [_jsx("span", { style: { color: '#26a641', fontWeight: 500 }, children: "H" }), _jsx("span", { style: { color: muted }, children: " " }), _jsx("span", { style: { color: textColor }, children: _fmtPrice(lastBar.high) })] }), _jsxs("span", { children: [_jsx("span", { style: { color: '#f85149', fontWeight: 500 }, children: "L" }), _jsx("span", { style: { color: muted }, children: " " }), _jsx("span", { style: { color: textColor }, children: _fmtPrice(lastBar.low) })] }), _jsxs("span", { children: [_jsx("span", { style: { color: muted }, children: "C" }), _jsx("span", { style: { color: muted }, children: " " }), _jsx("span", { style: { color: textColor }, children: _fmtPrice(lastBar.close) })] }), _jsxs("span", { style: { color: changeColor }, children: [isUp ? '+' : '', _fmtPrice(change), " (", isUp ? '+' : '', pctChange.toFixed(2), "%)"] })] }))] }), overlayInds.length > 0 && (_jsxs(_Fragment, { children: [!collapsed && (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 1, marginTop: 2 }, children: overlayInds.map((ind, i) => (_jsx(IndicatorLabel, { indicator: ind, color: ind.config.color ?? overlayColors[i % overlayColors.length] ?? '#2196f3', onRemove: () => onRemove(ind.id), onConfigure: () => onConfigure(ind) }, ind.id))) })), _jsx("button", { onClick: () => setCollapsed((c) => !c), title: collapsed ? 'Show indicators' : 'Hide indicators', style: {
115
- display: 'flex',
116
- alignItems: 'center',
117
- justifyContent: 'center',
118
- marginTop: 3,
119
- width: 20,
120
- height: 14,
121
- background: 'rgba(100,100,100,0.25)',
122
- border: 'none',
123
- borderRadius: 3,
124
- color: muted,
125
- fontSize: 9,
126
- cursor: 'pointer',
127
- padding: 0,
128
- lineHeight: 1,
129
- }, children: collapsed ? '▾' : '▴' })] }))] }));
130
- }
131
- export const ChartCanvas = forwardRef(function ChartCanvas({ symbol, timeframe, datafeed, theme = 'dark', timezone = 'UTC', initialIndicators = [], layoutToRestore, onIndicatorsChanged, priceFraction: priceFractionProp, onPriceFractionChange, getExchangeLogoUrl, tradingBridge, }, ref) {
132
- const outerRef = useRef(null);
133
- const priceRef = useRef(null);
134
- const overlayCanvasRef = useRef(null);
135
- /** Crosshair X pixel (relative to chart column) — updated via mousemove, no re-render needed. */
136
- const crosshairXRef = useRef(null);
137
- const chartRef = useRef(null);
138
- const transformRef = useRef(null);
139
- const [loading, setLoading] = useState(true);
140
- const [error, setError] = useState(null);
141
- const [bars, setBars] = useState([]);
142
- const [panes, setPanes] = useState([]);
143
- const [indicators, setIndicators] = useState([]);
144
- const [totalHeight, setTotalHeight] = useState(600);
145
- const [activeTool, setActiveTool] = useState('cursor');
146
- const [ctxMenu, setCtxMenu] = useState(null);
147
- const [chartCtxMenu, setChartCtxMenu] = useState(null);
148
- const [settingsOpen, setSettingsOpen] = useState(false);
149
- const [canvasSettings, setCanvasSettings] = useState({
150
- background: '#000000',
151
- gridColor: '#2a2a2a',
152
- gridVisible: true,
153
- });
154
- const [configTarget, setConfigTarget] = useState(null);
155
- // Flag to suppress chart context menu when a drawing context menu was triggered
156
- const drawingCtxJustFired = useRef(false);
157
- const dagRef = useRef(null);
158
- const [computedResults, setComputedResults] = useState(() => new Map());
159
- // Stable ref to the overlay draw function — rebuilt whenever data changes,
160
- // called directly from the RAF loop to stay in the same frame as candles.
161
- const drawOverlayRef = useRef(null);
162
- const [priceFraction, setPriceFraction] = useState(priceFractionProp ?? 0.6);
163
- // ── Imperative handle (tab snapshot save/load) ─────────────────────────────
164
- useImperativeHandle(ref, () => ({
165
- getLayoutSnapshot: () => chartRef.current?.saveLayout() ?? null,
166
- loadLayoutSnapshot: (layout) => {
167
- chartRef.current?.loadLayout(layout);
168
- },
169
- addIndicator: (config) => chartRef.current?.addIndicator(config) ?? null,
170
- getOverlayStore: () => chartRef.current?.getTradingOverlayStore() ?? null,
171
- captureScreenshot: async () => {
172
- const container = outerRef.current;
173
- if (!container)
174
- return null;
175
- const containerRect = container.getBoundingClientRect();
176
- const { width, height } = containerRect;
177
- if (width === 0 || height === 0)
178
- return null;
179
- const dpr = window.devicePixelRatio || 1;
180
- const composite = document.createElement('canvas');
181
- composite.width = Math.round(width * dpr);
182
- composite.height = Math.round(height * dpr);
183
- const ctx = composite.getContext('2d');
184
- if (!ctx)
185
- return null;
186
- // Fill background colour from CSS variable
187
- const bgColor = getComputedStyle(document.documentElement)
188
- .getPropertyValue('--bg').trim() || '#000000';
189
- ctx.fillStyle = bgColor;
190
- ctx.fillRect(0, 0, composite.width, composite.height);
191
- // Composite every canvas element inside the chart container
192
- const canvases = container.querySelectorAll('canvas');
193
- for (const canvas of canvases) {
194
- const rect = canvas.getBoundingClientRect();
195
- const x = Math.round((rect.left - containerRect.left) * dpr);
196
- const y = Math.round((rect.top - containerRect.top) * dpr);
197
- const w = Math.round(rect.width * dpr);
198
- const h = Math.round(rect.height * dpr);
199
- try {
200
- ctx.drawImage(canvas, x, y, w, h);
201
- }
202
- catch { /* tainted canvas — skip */ }
203
- }
204
- return composite.toDataURL('image/png');
205
- },
206
- }));
207
- // ── Mount: create TChart ────────────────────────────────────────────────────
208
- useEffect(() => {
209
- const container = priceRef.current;
210
- if (!container)
211
- return;
212
- const chart = new TChart({
213
- container,
214
- symbol,
215
- interval: timeframe,
216
- theme,
217
- ...(datafeed !== undefined ? { datafeed } : {}),
218
- });
219
- // Add initial indicators — non-overlay ones get sub-panes created automatically
220
- for (const config of initialIndicators) {
221
- chart.addIndicator(config);
222
- }
223
- transformRef.current = chart.getTransform();
224
- const syncChartState = () => {
225
- setBars(chart.getBars());
226
- setPanes(chart.getPanes());
227
- setIndicators(chart.getIndicators());
228
- };
229
- chart.on('dataLoading', () => {
230
- setLoading(true);
231
- setError(null);
232
- });
233
- chart.on('dataLoaded', ({ interval: loadedInterval }) => {
234
- setLoading(false);
235
- syncChartState();
236
- // Only restore a saved viewport when it is genuinely valid for the current
237
- // timeframe. Two guards prevent stale data from locking the view:
238
- // 1. interval must match — compares the *loaded* interval (from event payload,
239
- // not a stale closure) against the saved layout's interval. This correctly
240
- // handles the case where the user switches timeframes after mount.
241
- // 2. span must be ≥ 50 candles — avoids restoring zoomed-in states.
242
- // In all other cases fall back to fitDefaultView() so the user always sees
243
- // a sensible ~150-candle window on first load or after a timeframe switch.
244
- const tfSec = _TF_SECONDS[loadedInterval] ?? 3600;
245
- const savedSpan = layoutToRestore?.viewport
246
- ? (layoutToRestore.viewport.timeRange.to - layoutToRestore.viewport.timeRange.from)
247
- : 0;
248
- const hasValidViewport = !!layoutToRestore?.viewport &&
249
- layoutToRestore.interval === loadedInterval &&
250
- savedSpan >= tfSec * 50; // require at least 50 candles visible — avoids restoring zoomed-in states
251
- if (hasValidViewport) {
252
- chart.restoreViewport(layoutToRestore.viewport);
253
- chart.resetPriceScale();
254
- }
255
- else {
256
- chart.fitDefaultView();
257
- }
258
- });
259
- chart.on('dataError', ({ error: msg }) => {
260
- setLoading(false);
261
- setError(msg);
262
- });
263
- chart.on('barsUpdated', syncChartState);
264
- chart.on('indicatorAdded', () => { syncChartState(); onIndicatorsChanged?.(); });
265
- chart.on('indicatorRemoved', () => { syncChartState(); onIndicatorsChanged?.(); });
266
- // Auto-revert to cursor after each drawing placement.
267
- chart.on('drawingCreated', () => {
268
- setActiveTool('cursor');
269
- chart.setCrosshairEnabled(false); // back to arrow — no crosshair
270
- });
271
- // Show context menu when user right-clicks a drawing.
272
- chart.on('drawingContextMenu', ({ id, x, y }) => {
273
- const canvas = priceRef.current;
274
- if (!canvas)
275
- return;
276
- const rect = canvas.getBoundingClientRect();
277
- drawingCtxJustFired.current = true;
278
- setTimeout(() => { drawingCtxJustFired.current = false; }, 0);
279
- setCtxMenu({ drawingId: id, x: rect.left + x, y: rect.top + y });
280
- });
281
- // Restore layout from the explicit snapshot when provided.
282
- // Without a snapshot the chart starts empty (no localStorage fallback —
283
- // persistence is handled by DB auto-save in App.tsx).
284
- if (layoutToRestore) {
285
- try {
286
- chart.loadLayout(layoutToRestore);
287
- }
288
- catch { /* invalid snapshot — ignore */ }
289
- }
290
- chartRef.current = chart;
291
- syncChartState(); // read panes added synchronously for initialIndicators
292
- return () => {
293
- chart.destroy();
294
- chartRef.current = null;
295
- transformRef.current = null;
296
- };
297
- // eslint-disable-next-line react-hooks/exhaustive-deps
298
- }, []);
299
- // ── Symbol / timeframe propagation ──────────────────────────────────────────
300
- useEffect(() => { chartRef.current?.setSymbol(symbol); }, [symbol]);
301
- useEffect(() => { chartRef.current?.setInterval(timeframe); }, [timeframe]);
302
- useEffect(() => { chartRef.current?.setTimezone(timezone); }, [timezone]);
303
- useEffect(() => { chartRef.current?.setTheme(theme); }, [theme]);
304
- // ── DAG: recompute indicators when bars or indicator list changes ────────────
305
- useEffect(() => {
306
- if (!dagRef.current)
307
- dagRef.current = new IndicatorDAG();
308
- const dag = dagRef.current;
309
- dag.sync(indicators);
310
- let changed = false;
311
- try {
312
- changed = dag.execute(bars);
313
- }
314
- catch (e) {
315
- console.error('[ForgeCharts] Indicator computation error:', e);
316
- }
317
- if (changed)
318
- setComputedResults(new Map(dag.getAllResults()));
319
- }, [bars, indicators]);
320
- // ── Overlay indicators: draw script/ema/etc lines on the price pane canvas ──
321
- // The draw function is stored in a ref so the RAF loop can call it directly
322
- // every frame — bypassing the React state update cycle and keeping the
323
- // indicator overlay pixel-perfect in sync with the candle layer.
324
- useEffect(() => {
325
- drawOverlayRef.current = () => {
326
- const canvas = overlayCanvasRef.current;
327
- const transform = transformRef.current;
328
- if (!canvas || !transform)
329
- return;
330
- const curPriceH = panes.length > 0 ? totalHeight * priceFraction : totalHeight;
331
- const dpr = window.devicePixelRatio ?? 1;
332
- const cssW = canvas.offsetWidth || (canvas.parentElement?.clientWidth ?? 800);
333
- const physW = Math.round(cssW * dpr);
334
- const physH = Math.round(curPriceH * dpr);
335
- if (canvas.width !== physW || canvas.height !== physH) {
336
- canvas.width = physW;
337
- canvas.height = physH;
338
- }
339
- const ctx = canvas.getContext('2d');
340
- if (!ctx)
341
- return;
342
- ctx.clearRect(0, 0, physW, physH);
343
- const overlayInds = indicators.filter((ind) => ind.config.overlay === true);
344
- if (overlayInds.length === 0)
345
- return;
346
- ctx.save();
347
- ctx.scale(dpr, dpr);
348
- const plotW = transform.plotWidth;
349
- let colorIdx = 0;
350
- for (const ind of overlayInds) {
351
- const result = computedResults.get(ind.id);
352
- if (!result || result.kind !== 'series' || result.points.length === 0)
353
- continue;
354
- const color = ind.config.color ?? OVERLAY_COLORS[colorIdx++ % OVERLAY_COLORS.length];
355
- ctx.strokeStyle = color;
356
- ctx.lineWidth = 1.5;
357
- ctx.beginPath();
358
- let started = false;
359
- for (const p of result.points) {
360
- const x = transform.timeToX(p.time);
361
- if (x < -20 || x > plotW + 20) {
362
- started = false;
363
- continue;
364
- }
365
- const y = transform.priceToY(p.value);
366
- if (!started) {
367
- ctx.moveTo(x, y);
368
- started = true;
369
- }
370
- else {
371
- ctx.lineTo(x, y);
372
- }
373
- }
374
- ctx.stroke();
375
- }
376
- ctx.restore();
377
- };
378
- // Trigger an immediate repaint whenever the data (bars, indicator config,
379
- // canvas size) changes — viewport-only changes are handled by the RAF loop.
380
- drawOverlayRef.current();
381
- }, [computedResults, totalHeight, priceFraction, panes, indicators]);
382
- // ── ResizeObserver for total container height ──────────────────────────────
383
- useEffect(() => {
384
- const el = outerRef.current;
385
- if (!el)
386
- return;
387
- const ro = new ResizeObserver(([entry]) => {
388
- if (entry)
389
- setTotalHeight(entry.contentRect.height);
390
- });
391
- ro.observe(el);
392
- return () => ro.disconnect();
393
- }, []);
394
- // ── RAF loop: keep indicator overlay in sync with the candle layer ──────────
395
- // Calls the draw function directly every animation frame — no React state
396
- // update roundtrip — so indicators move in the exact same frame as candles.
397
- useEffect(() => {
398
- let rafId;
399
- const tick = () => {
400
- drawOverlayRef.current?.();
401
- rafId = requestAnimationFrame(tick);
402
- };
403
- rafId = requestAnimationFrame(tick);
404
- return () => cancelAnimationFrame(rafId);
405
- }, []);
406
- // ── Chart-level right-click (canvas background, not a drawing) ────────────
407
- const handleCanvasContextMenu = useCallback((e) => {
408
- e.preventDefault();
409
- if (drawingCtxJustFired.current)
410
- return;
411
- setChartCtxMenu({ x: e.clientX, y: e.clientY });
412
- }, []);
413
- const handleClearDrawings = useCallback(() => {
414
- chartRef.current?.clearDrawings();
415
- }, []);
416
- const [drawingsHidden, setDrawingsHidden] = useState(false);
417
- const [indicatorsHidden, setIndicatorsHidden] = useState(false);
418
- const handleVisibilityAction = useCallback((action) => {
419
- const chart = chartRef.current;
420
- if (!chart)
421
- return;
422
- if (action === 'hideDrawings') {
423
- const next = !drawingsHidden;
424
- setDrawingsHidden(next);
425
- chart.setAllDrawingsVisible(!next);
426
- }
427
- else if (action === 'hideIndicators') {
428
- const next = !indicatorsHidden;
429
- setIndicatorsHidden(next);
430
- chart.setIndicatorsVisible(!next);
431
- }
432
- else if (action === 'hideAll') {
433
- const nextD = !drawingsHidden;
434
- const nextI = !indicatorsHidden;
435
- setDrawingsHidden(nextD);
436
- setIndicatorsHidden(nextI);
437
- chart.setAllDrawingsVisible(!nextD);
438
- chart.setIndicatorsVisible(!nextI);
439
- }
440
- // hidePositions: positions system not yet implemented
441
- }, [drawingsHidden, indicatorsHidden]);
442
- const visibilityActiveAction = drawingsHidden && indicatorsHidden ? 'hideAll' :
443
- drawingsHidden ? 'hideDrawings' :
444
- indicatorsHidden ? 'hideIndicators' :
445
- null;
446
- const handleVisibilityDeactivate = useCallback(() => {
447
- const chart = chartRef.current;
448
- if (!chart)
449
- return;
450
- setDrawingsHidden(false);
451
- setIndicatorsHidden(false);
452
- chart.setAllDrawingsVisible(true);
453
- chart.setIndicatorsVisible(true);
454
- }, []);
455
- const handleClearIndicators = useCallback(() => {
456
- const chart = chartRef.current;
457
- if (!chart)
458
- return;
459
- for (const ind of chart.getIndicators()) {
460
- chart.removeIndicator(ind.id);
461
- }
462
- }, []);
463
- const handleResetView = useCallback(() => {
464
- chartRef.current?.scrollToEnd();
465
- }, []);
466
- const handleApplySettings = useCallback((settings) => {
467
- setCanvasSettings(settings);
468
- const light = _isLightBg(settings.background);
469
- chartRef.current?.applyOptions({
470
- colors: {
471
- background: settings.background,
472
- backgroundSecondary: light ? '#f5f5f5' : '#0a0a0a',
473
- text: light ? '#000000' : '#ffffff',
474
- textMuted: light ? '#666666' : '#888888',
475
- crosshair: light ? '#000000' : '#ffffff',
476
- border: light ? '#cccccc' : '#333333',
477
- ...(settings.gridVisible
478
- ? { grid: settings.gridColor }
479
- : { grid: 'transparent' }),
480
- },
481
- });
482
- }, []);
483
- // ── Indicator remove / configure ──────────────────────────────────────────
484
- const handleRemoveIndicator = useCallback((id) => {
485
- chartRef.current?.removeIndicator(id);
486
- }, []);
487
- const handleConfigureIndicator = useCallback((indicator) => {
488
- setConfigTarget(indicator);
489
- }, []);
490
- const handleSaveConfig = useCallback((newConfig) => {
491
- const chart = chartRef.current;
492
- if (!chart || !configTarget)
493
- return;
494
- chart.removeIndicator(configTarget.id);
495
- chart.addIndicator(newConfig);
496
- setConfigTarget(null);
497
- }, [configTarget]);
498
- // ── Drawing tool selection ─────────────────────────────────────────────────
499
- const POINTER_TOOLS = ['cursor', 'crosshair', 'dot', 'demonstration'];
500
- const handleToolSelect = useCallback((tool) => {
501
- setActiveTool(tool);
502
- const chart = chartRef.current;
503
- if (!chart)
504
- return;
505
- const isPointerTool = POINTER_TOOLS.includes(tool);
506
- if (isPointerTool) {
507
- chart.cancelDrawingTool();
508
- // Only the crosshair tool uses the SDK crosshair lines.
509
- // dot/demonstration use PointerOverlay for their own visuals.
510
- chart.setCrosshairEnabled(tool === 'crosshair');
511
- // Hide the native OS cursor for any tool that provides its own visual.
512
- chart.setNativeCursorHidden(tool !== 'cursor');
513
- }
514
- else {
515
- chart.setCrosshairEnabled(false); // drawing tool uses its own cursor
516
- chart.startDrawingTool(tool);
517
- }
518
- // eslint-disable-next-line react-hooks/exhaustive-deps
519
- }, []);
520
- // ── Divider drag: price | sub-pane area split ──────────────────────────────
521
- const handlePriceDividerDrag = useCallback((dy) => {
522
- if (totalHeight === 0)
523
- return;
524
- setPriceFraction((prev) => {
525
- const next = Math.min(0.85, Math.max(0.3, prev + dy / totalHeight));
526
- onPriceFractionChange?.(next);
527
- return next;
528
- });
529
- }, [totalHeight]);
530
- // ── Divider drag: between two sub-panes ──────────────────────────────────
531
- const handleSubPaneDividerDrag = useCallback((paneId, dy) => {
532
- const chart = chartRef.current;
533
- if (!chart || totalHeight === 0)
534
- return;
535
- const subH = totalHeight * (1 - priceFraction);
536
- if (subH === 0)
537
- return;
538
- const currentPanes = chart.getPanes();
539
- const pane = currentPanes.find((p) => p.id === paneId);
540
- if (!pane)
541
- return;
542
- const newFraction = Math.min(0.9, Math.max(0.05, pane.heightFraction + dy / subH));
543
- chart.resizePane(paneId, newFraction);
544
- setPanes([...chart.getPanes()]);
545
- }, [totalHeight, priceFraction]);
546
- // ── Derived layout dims ────────────────────────────────────────────────────
547
- const hasSubPanes = panes.length > 0;
548
- const priceH = hasSubPanes ? totalHeight * priceFraction : totalHeight;
549
- const subH = totalHeight * (1 - priceFraction);
550
- return (_jsxs("div", { ref: outerRef, style: {
551
- position: 'relative',
552
- width: '100%',
553
- height: '100%',
554
- display: 'flex',
555
- gap: 8,
556
- overflow: 'hidden',
557
- }, children: [_jsx(LeftToolbar, { activeTool: activeTool, onSelectTool: handleToolSelect, onVisibilityAction: handleVisibilityAction, visibilityActiveAction: visibilityActiveAction, onVisibilityDeactivate: handleVisibilityDeactivate, onDeleteClick: () => chartRef.current?.deleteSelectedDrawing() }), _jsxs("div", { className: activeTool === 'crosshair' ? 'chart-crosshair-mode' : undefined, style: {
558
- flex: 1,
559
- display: 'flex',
560
- flexDirection: 'column',
561
- overflow: 'hidden',
562
- position: 'relative',
563
- minWidth: 0,
564
- cursor: activeTool === 'crosshair' ? 'none' :
565
- activeTool === 'dot' || activeTool === 'demonstration' ? 'none' :
566
- activeTool === 'cursor' ? 'default' :
567
- 'crosshair', // drawing tools
568
- }, onMouseMove: (e) => {
569
- const rect = e.currentTarget.getBoundingClientRect();
570
- crosshairXRef.current = e.clientX - rect.left;
571
- }, onMouseLeave: () => { crosshairXRef.current = null; }, children: [_jsxs("div", { style: { position: 'relative', height: `${priceH}px`, flexShrink: 0 }, onContextMenu: handleCanvasContextMenu, children: [_jsx("div", { ref: priceRef, style: { width: '100%', height: '100%' } }), _jsx("canvas", { ref: overlayCanvasRef, style: {
572
- position: 'absolute', top: 0, left: 0,
573
- width: '100%', height: '100%',
574
- pointerEvents: 'none', zIndex: 2,
575
- } }), " ", (activeTool === 'dot' || activeTool === 'demonstration') && (_jsx(PointerOverlay, { mode: activeTool, width: priceRef.current?.clientWidth ?? 0, height: priceH })), " ", _jsx(PricePaneHeader, { symbol: symbol, timeframe: timeframe, bars: bars, theme: theme, indicators: indicators, overlayColors: OVERLAY_COLORS, onRemove: handleRemoveIndicator, onConfigure: handleConfigureIndicator, ...(getExchangeLogoUrl ? { getExchangeLogoUrl } : {}) })] }), loading && (_jsx("div", { style: {
576
- position: 'absolute',
577
- top: priceH / 2 - 12,
578
- left: '50%',
579
- transform: 'translateX(-50%)',
580
- color: 'var(--text-muted, #787b86)',
581
- fontSize: 13,
582
- pointerEvents: 'none',
583
- zIndex: 10,
584
- }, children: "Loading\u2026" })), error && (_jsx("div", { style: {
585
- position: 'absolute',
586
- top: priceH / 2 - 12,
587
- left: '50%',
588
- transform: 'translateX(-50%)',
589
- color: '#ef5350',
590
- fontSize: 13,
591
- pointerEvents: 'none',
592
- zIndex: 10,
593
- }, children: error })), hasSubPanes && (_jsxs(_Fragment, { children: [_jsx(Divider, { onDrag: handlePriceDividerDrag }), panes.map((pane, idx) => {
594
- const paneH = Math.max(60, Math.round(subH * pane.heightFraction));
595
- const paneIndicators = indicators.filter((ind) => pane.indicatorIds.includes(ind.id));
596
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column' }, children: [_jsx(IndicatorPane, { indicators: paneIndicators, bars: bars, transform: transformRef.current, height: paneH, theme: theme, computedResults: computedResults, crosshairXRef: crosshairXRef, onRemove: handleRemoveIndicator, onConfigure: handleConfigureIndicator }), idx < panes.length - 1 && (_jsx(Divider, { onDrag: (dy) => handleSubPaneDividerDrag(pane.id, dy) }))] }, pane.id));
597
- })] }))] }), configTarget && (_jsx(IndicatorConfigDialog, { indicator: configTarget, onSave: handleSaveConfig, onClose: () => setConfigTarget(null) })), ctxMenu && (_jsxs(_Fragment, { children: [_jsx("div", { className: "drawing-ctx-backdrop", onClick: () => setCtxMenu(null), onContextMenu: (e) => { e.preventDefault(); setCtxMenu(null); } }), _jsx("div", { className: "drawing-ctx-menu", style: { left: ctxMenu.x, top: ctxMenu.y }, children: _jsx("button", { className: "drawing-ctx-item", onClick: () => {
598
- chartRef.current?.removeDrawing(ctxMenu.drawingId);
599
- setCtxMenu(null);
600
- }, children: "Remove" }) })] })), chartCtxMenu && (_jsx(ChartContextMenu, { x: chartCtxMenu.x, y: chartCtxMenu.y, onClose: () => setChartCtxMenu(null), onSettings: () => setSettingsOpen(true), onClearDrawings: handleClearDrawings, onClearIndicators: handleClearIndicators, onResetView: handleResetView })), settingsOpen && (_jsx(ChartSettingsDialog, { initialSettings: canvasSettings, onApply: handleApplySettings, onClose: () => setSettingsOpen(false) }))] }));
601
- });
602
- /** @deprecated Use ChartCanvas */
603
- export const MultiPaneChart = ChartCanvas;
604
- //# sourceMappingURL=ChartCanvas.js.map