@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,82 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /**
3
- * FloatingPanel — a draggable, resizable floating panel shell.
4
- *
5
- * Renders `position: fixed` with a title bar (drag to move) and 8 resize
6
- * handles (edges + corners). Pass panel content as `children`.
7
- */
8
- import { useRef, useState } from 'react';
9
- export function FloatingPanel({ title, onClose, defaultWidth = 380, defaultHeight = 520, minWidth = 200, minHeight = 120, children, }) {
10
- const [pos, setPos] = useState(() => ({
11
- x: Math.max(0, window.innerWidth - defaultWidth - 24),
12
- y: 72,
13
- }));
14
- const [size, setSize] = useState({ w: defaultWidth, h: defaultHeight });
15
- // Refs capture drag-start values to avoid stale-closure accumulation
16
- const moveRef = useRef(null);
17
- const resizeRef = useRef(null);
18
- // ── Drag to move ──────────────────────────────────────────────────────────
19
- const startMove = (e) => {
20
- if (e.target.closest('.fp-close'))
21
- return;
22
- e.preventDefault();
23
- moveRef.current = { ox: e.clientX, oy: e.clientY, px: pos.x, py: pos.y };
24
- const onMove = (ev) => {
25
- if (!moveRef.current)
26
- return;
27
- setPos({
28
- x: moveRef.current.px + ev.clientX - moveRef.current.ox,
29
- y: moveRef.current.py + ev.clientY - moveRef.current.oy,
30
- });
31
- };
32
- const onUp = () => {
33
- moveRef.current = null;
34
- window.removeEventListener('mousemove', onMove);
35
- window.removeEventListener('mouseup', onUp);
36
- };
37
- window.addEventListener('mousemove', onMove);
38
- window.addEventListener('mouseup', onUp);
39
- };
40
- // ── Resize from any edge/corner ───────────────────────────────────────────
41
- const startResize = (e, edges) => {
42
- e.preventDefault();
43
- e.stopPropagation();
44
- resizeRef.current = {
45
- edges,
46
- ox: e.clientX, oy: e.clientY,
47
- pw: size.w, ph: size.h,
48
- px: pos.x, py: pos.y,
49
- };
50
- const onMove = (ev) => {
51
- if (!resizeRef.current)
52
- return;
53
- const { edges: ed, ox, oy, pw, ph, px, py } = resizeRef.current;
54
- const dx = ev.clientX - ox;
55
- const dy = ev.clientY - oy;
56
- let nx = px, ny = py, nw = pw, nh = ph;
57
- if (ed.includes('e'))
58
- nw = Math.max(minWidth, pw + dx);
59
- if (ed.includes('s'))
60
- nh = Math.max(minHeight, ph + dy);
61
- if (ed.includes('w')) {
62
- nw = Math.max(minWidth, pw - dx);
63
- nx = px + pw - nw;
64
- }
65
- if (ed.includes('n')) {
66
- nh = Math.max(minHeight, ph - dy);
67
- ny = py + ph - nh;
68
- }
69
- setSize({ w: nw, h: nh });
70
- setPos({ x: nx, y: ny });
71
- };
72
- const onUp = () => {
73
- resizeRef.current = null;
74
- window.removeEventListener('mousemove', onMove);
75
- window.removeEventListener('mouseup', onUp);
76
- };
77
- window.addEventListener('mousemove', onMove);
78
- window.addEventListener('mouseup', onUp);
79
- };
80
- return (_jsxs("div", { className: "fp-shell", style: { left: pos.x, top: pos.y, width: size.w, height: size.h }, children: [_jsxs("div", { className: "fp-titlebar", onMouseDown: startMove, children: [_jsx("span", { className: "fp-title", children: title }), _jsx("button", { className: "fp-close", onClick: onClose, title: "Close", children: _jsxs("svg", { viewBox: "0 0 14 14", width: "12", height: "12", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", children: [_jsx("line", { x1: "2", y1: "2", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "2", x2: "2", y2: "12" })] }) })] }), _jsx("div", { className: "fp-content", children: children }), _jsx("div", { className: "fp-resize fp-resize-n", onMouseDown: (e) => startResize(e, 'n') }), _jsx("div", { className: "fp-resize fp-resize-s", onMouseDown: (e) => startResize(e, 's') }), _jsx("div", { className: "fp-resize fp-resize-e", onMouseDown: (e) => startResize(e, 'e') }), _jsx("div", { className: "fp-resize fp-resize-w", onMouseDown: (e) => startResize(e, 'w') }), _jsx("div", { className: "fp-resize fp-resize-nw", onMouseDown: (e) => startResize(e, 'nw') }), _jsx("div", { className: "fp-resize fp-resize-ne", onMouseDown: (e) => startResize(e, 'ne') }), _jsx("div", { className: "fp-resize fp-resize-sw", onMouseDown: (e) => startResize(e, 'sw') }), _jsx("div", { className: "fp-resize fp-resize-se", onMouseDown: (e) => startResize(e, 'se') })] }));
81
- }
82
- //# sourceMappingURL=FloatingPanel.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FloatingPanel.js","sourceRoot":"","sources":["../../../src/react/workspace/FloatingPanel.tsx"],"names":[],"mappings":"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"}
@@ -1,121 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState, useEffect, useRef } from 'react';
3
- const CATEGORIES = ['All', 'Trend', 'Momentum', 'Volume', 'Volatility'];
4
- // Sorted alphabetically by label
5
- const CATALOGUE = [
6
- {
7
- type: 'atr',
8
- label: 'ATR',
9
- description: 'Average True Range — measures market volatility as the average of true ranges.',
10
- author: 'ForgeCharts',
11
- category: 'Volatility',
12
- defaultConfig: { type: 'atr', params: { period: 14 }, overlay: false },
13
- },
14
- {
15
- type: 'bbands',
16
- label: 'Bollinger Bands',
17
- description: 'Volatility bands placed above and below an SMA at ±N standard deviations.',
18
- author: 'ForgeCharts',
19
- category: 'Trend',
20
- defaultConfig: { type: 'bbands', params: { period: 20, multiplier: 2 }, overlay: true },
21
- },
22
- {
23
- type: 'ema',
24
- label: 'EMA',
25
- description: 'Exponential Moving Average — weights recent bars more heavily.',
26
- author: 'ForgeCharts',
27
- category: 'Trend',
28
- defaultConfig: { type: 'ema', params: { period: 20 }, overlay: true },
29
- },
30
- {
31
- type: 'macd',
32
- label: 'MACD',
33
- description: 'Moving Average Convergence/Divergence — trend-following momentum oscillator.',
34
- author: 'ForgeCharts',
35
- category: 'Momentum',
36
- defaultConfig: { type: 'macd', params: { fast: 12, slow: 26, signal: 9 }, overlay: false },
37
- },
38
- {
39
- type: 'obv',
40
- label: 'OBV',
41
- description: 'On-Balance Volume — running tally that adds/subtracts volume based on direction.',
42
- author: 'ForgeCharts',
43
- category: 'Volume',
44
- defaultConfig: { type: 'obv', overlay: false },
45
- },
46
- {
47
- type: 'rsi',
48
- label: 'RSI',
49
- description: 'Relative Strength Index — measures speed and magnitude of price changes (0–100).',
50
- author: 'ForgeCharts',
51
- category: 'Momentum',
52
- defaultConfig: { type: 'rsi', params: { period: 14 }, overlay: false },
53
- },
54
- {
55
- type: 'sma',
56
- label: 'SMA',
57
- description: 'Simple Moving Average — average closing price over N bars.',
58
- author: 'ForgeCharts',
59
- category: 'Trend',
60
- defaultConfig: { type: 'sma', params: { period: 20 }, overlay: true },
61
- },
62
- {
63
- type: 'stochastic',
64
- label: 'Stochastic',
65
- description: 'Stochastic Oscillator — compares closing price to high-low range over N bars.',
66
- author: 'ForgeCharts',
67
- category: 'Momentum',
68
- defaultConfig: { type: 'stochastic', params: { k: 14, d: 3 }, overlay: false },
69
- },
70
- {
71
- type: 'volume',
72
- label: 'Volume',
73
- description: 'Bar volume rendered as a histogram in a separate sub-pane.',
74
- author: 'ForgeCharts',
75
- category: 'Volume',
76
- defaultConfig: { type: 'volume', overlay: false },
77
- },
78
- {
79
- type: 'wma',
80
- label: 'WMA',
81
- description: 'Weighted Moving Average — linearly weighted toward recent bars.',
82
- author: 'ForgeCharts',
83
- category: 'Trend',
84
- defaultConfig: { type: 'wma', params: { period: 20 }, overlay: true },
85
- },
86
- ];
87
- // ── Component ─────────────────────────────────────────────────────────────────
88
- export function IndicatorsDialog({ onAdd, onClose }) {
89
- const [category, setCategory] = useState('All');
90
- const [query, setQuery] = useState('');
91
- const [added, setAdded] = useState(null);
92
- const dialogRef = useRef(null);
93
- const inputRef = useRef(null);
94
- useEffect(() => { inputRef.current?.focus(); }, []);
95
- useEffect(() => {
96
- const handler = (e) => { if (e.key === 'Escape')
97
- onClose(); };
98
- window.addEventListener('keydown', handler);
99
- return () => window.removeEventListener('keydown', handler);
100
- }, [onClose]);
101
- const handleBackdrop = (e) => {
102
- if (dialogRef.current && !dialogRef.current.contains(e.target))
103
- onClose();
104
- };
105
- const q = query.trim().toLowerCase();
106
- const visible = CATALOGUE.filter((entry) => {
107
- const matchesCat = category === 'All' || entry.category === category;
108
- const matchesQ = !q || entry.label.toLowerCase().includes(q) || entry.description.toLowerCase().includes(q);
109
- return matchesCat && matchesQ;
110
- });
111
- const handleAdd = (entry) => {
112
- onAdd(entry.defaultConfig);
113
- setAdded(entry.type);
114
- setTimeout(() => setAdded(null), 1400);
115
- };
116
- return (_jsx("div", { className: "ind-backdrop", onMouseDown: handleBackdrop, children: _jsxs("div", { className: "ind-dialog", ref: dialogRef, role: "dialog", "aria-modal": "true", "aria-label": "Indicators", children: [_jsxs("div", { className: "ind-header", children: [_jsx("span", { className: "ind-title", children: "Indicators" }), _jsx("button", { className: "ind-close", onClick: onClose, "aria-label": "Close", children: _jsxs("svg", { viewBox: "0 0 14 14", width: "12", height: "12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", fill: "none", children: [_jsx("line", { x1: "2", y1: "2", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "2", x2: "2", y2: "12" })] }) })] }), _jsxs("div", { className: "ind-search-row", children: [_jsxs("svg", { viewBox: "0 0 16 16", width: "13", height: "13", stroke: "currentColor", fill: "none", strokeWidth: "1.8", strokeLinecap: "round", style: { opacity: 0.5, flexShrink: 0 }, children: [_jsx("circle", { cx: "6.5", cy: "6.5", r: "4.5" }), _jsx("line", { x1: "10.5", y1: "10.5", x2: "14", y2: "14" })] }), _jsx("input", { ref: inputRef, className: "ind-search-input", type: "text", value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Search indicators\u2026", autoComplete: "off", spellCheck: false }), query && (_jsx("button", { className: "ind-search-clear", onClick: () => setQuery(''), "aria-label": "Clear", children: _jsxs("svg", { viewBox: "0 0 12 12", width: "10", height: "10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", fill: "none", children: [_jsx("line", { x1: "2", y1: "2", x2: "10", y2: "10" }), _jsx("line", { x1: "10", y1: "2", x2: "2", y2: "10" })] }) }))] }), _jsx("div", { className: "ind-tabs", children: CATEGORIES.map((cat) => (_jsx("button", { className: `ind-tab${cat === category ? ' active' : ''}`, onClick: () => setCategory(cat), children: cat }, cat))) }), _jsx("div", { className: "ind-list-wrap", children: visible.length === 0 ? (_jsxs("div", { className: "ind-empty", children: ["No indicators match \"", query, "\""] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "ind-section-hdr", children: [_jsx("span", { children: "Built-in" }), _jsx("span", { className: "ind-section-count", children: visible.length })] }), visible.map((entry) => {
117
- const isAdded = added === entry.type;
118
- return (_jsxs("button", { className: `ind-list-row${isAdded ? ' added' : ''}`, onClick: () => handleAdd(entry), children: [_jsxs("div", { className: "ind-list-info", children: [_jsx("span", { className: "ind-list-name", children: entry.label }), _jsxs("span", { className: "ind-list-meta", children: [entry.author, " \u00B7 ", entry.category] })] }), _jsx("span", { className: `ind-list-badge${entry.defaultConfig.overlay ? ' overlay' : ' pane'}`, children: entry.defaultConfig.overlay ? 'Overlay' : 'Pane' }), _jsx("span", { className: "ind-list-add", children: isAdded ? (_jsxs(_Fragment, { children: [_jsx("svg", { viewBox: "0 0 12 10", width: "11", height: "10", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", fill: "none", children: _jsx("polyline", { points: "1,5 4,8 11,1" }) }), "Added"] })) : (_jsxs(_Fragment, { children: [_jsxs("svg", { viewBox: "0 0 12 12", width: "11", height: "11", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", fill: "none", children: [_jsx("line", { x1: "6", y1: "1", x2: "6", y2: "11" }), _jsx("line", { x1: "1", y1: "6", x2: "11", y2: "6" })] }), "Add to Chart"] })) })] }, entry.type));
119
- })] })) })] }) }));
120
- }
121
- //# sourceMappingURL=IndicatorsDialog.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"IndicatorsDialog.js","sourceRoot":"","sources":["../../../src/react/workspace/IndicatorsDialog.tsx"],"names":[],"mappings":"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"}
@@ -1,113 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from 'react';
3
- export function LayoutMenu({ currentName, currentLayoutId, autoSave, onFetchLayouts, onSave, onLoad, onRename, onCopy, onToggleAutoSave, onDelete, onOpenInNewTab, }) {
4
- const [open, setOpen] = useState(false);
5
- const [view, setView] = useState('menu');
6
- const [inputVal, setInputVal] = useState('');
7
- const [busy, setBusy] = useState(false);
8
- const [error, setError] = useState(null);
9
- const [layouts, setLayouts] = useState([]);
10
- const [loadError, setLoadError] = useState(null);
11
- const [fetching, setFetching] = useState(false);
12
- const [confirmDelete, setConfirmDelete] = useState(null);
13
- const menuRef = useRef(null);
14
- // Close on outside click
15
- useEffect(() => {
16
- if (!open)
17
- return;
18
- const handler = (e) => {
19
- if (menuRef.current && !menuRef.current.contains(e.target)) {
20
- setOpen(false);
21
- setView('menu');
22
- }
23
- };
24
- document.addEventListener('mousedown', handler);
25
- return () => document.removeEventListener('mousedown', handler);
26
- }, [open]);
27
- // Fetch saved layouts when menu opens
28
- useEffect(() => {
29
- if (!open)
30
- return;
31
- setLoadError(null);
32
- setFetching(true);
33
- onFetchLayouts()
34
- .then(setLayouts)
35
- .catch((err) => setLoadError(err.message))
36
- .finally(() => setFetching(false));
37
- }, [open]);
38
- const isSaved = !!currentLayoutId;
39
- function openMenu() {
40
- setError(null);
41
- setView('menu');
42
- setOpen((o) => !o);
43
- }
44
- function startView(v, prefill) {
45
- setInputVal(prefill);
46
- setError(null);
47
- setView(v);
48
- }
49
- async function handleSubmit(action) {
50
- const name = inputVal.trim();
51
- if (!name)
52
- return;
53
- setBusy(true);
54
- setError(null);
55
- try {
56
- await action(name);
57
- setOpen(false);
58
- setView('menu');
59
- }
60
- catch (err) {
61
- setError(err instanceof Error ? err.message : 'Action failed');
62
- }
63
- finally {
64
- setBusy(false);
65
- }
66
- }
67
- async function handleLoad(id) {
68
- setOpen(false);
69
- try {
70
- await onLoad(id);
71
- }
72
- catch (err) {
73
- // Silently ignore — App.tsx surfaces errors via tab state
74
- console.error('Load layout error:', err);
75
- }
76
- }
77
- async function handleOpenInNewTabLocal(id) {
78
- setOpen(false);
79
- try {
80
- await onOpenInNewTab(id);
81
- }
82
- catch (err) {
83
- console.error('Open layout in new tab error:', err);
84
- }
85
- }
86
- async function handleConfirmDelete() {
87
- if (!confirmDelete)
88
- return;
89
- try {
90
- await onDelete(confirmDelete.id);
91
- setLayouts((prev) => prev.filter((l) => l.id !== confirmDelete.id));
92
- setConfirmDelete(null);
93
- }
94
- catch {
95
- setConfirmDelete(null);
96
- }
97
- }
98
- function fmtError(msg) {
99
- return msg.includes('401') || msg.includes('Missing authorization')
100
- ? 'Sign in to use layouts'
101
- : msg;
102
- }
103
- function renderForm(label, placeholder, action, note) {
104
- return (_jsxs("div", { className: "layout-save-form", children: [_jsx("div", { className: "layout-save-label", children: label }), note && _jsx("div", { className: "layout-dropdown-empty", style: { padding: '0 0 4px' }, children: note }), _jsx("input", { className: "layout-save-input", value: inputVal, onChange: (e) => setInputVal(e.target.value), onKeyDown: (e) => {
105
- if (e.key === 'Enter')
106
- handleSubmit(action);
107
- if (e.key === 'Escape')
108
- setView('menu');
109
- }, placeholder: placeholder, autoFocus: true }), error && (_jsx("div", { className: "layout-dropdown-error", style: { padding: 0, fontSize: 11 }, children: fmtError(error) })), _jsxs("div", { className: "layout-save-actions", children: [_jsx("button", { onClick: () => setView('menu'), children: "Cancel" }), _jsx("button", { className: inputVal.trim() && !busy ? 'active' : undefined, onClick: () => handleSubmit(action), disabled: busy || !inputVal.trim(), children: busy ? 'Saving…' : 'Save' })] })] }));
110
- }
111
- return (_jsxs("div", { className: "layout-menu-root", ref: menuRef, children: [_jsxs("button", { className: open ? 'active' : undefined, onClick: openMenu, title: "Manage chart layouts", style: { display: 'flex', alignItems: 'center', gap: 4 }, children: [_jsxs("svg", { viewBox: "0 0 14 14", width: "12", height: "12", fill: "currentColor", children: [_jsx("rect", { x: "1", y: "1", width: "5", height: "5", rx: "1" }), _jsx("rect", { x: "8", y: "1", width: "5", height: "5", rx: "1" }), _jsx("rect", { x: "1", y: "8", width: "5", height: "5", rx: "1" }), _jsx("rect", { x: "8", y: "8", width: "5", height: "5", rx: "1" })] }), currentName ?? 'Layout', " \u25BE", autoSave && isSaved && (_jsx("span", { className: "layout-autosave-dot", title: "Auto-save enabled" }))] }), open && (_jsxs("div", { className: "layout-dropdown", children: [view === 'menu' && (_jsxs(_Fragment, { children: [_jsxs("label", { className: "layout-dropdown-item layout-autosave-row", children: [_jsxs("svg", { className: "layout-menu-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("polyline", { points: "23 4 23 10 17 10" }), _jsx("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })] }), "Auto-save", _jsxs("span", { className: "layout-autosave-status", children: [autoSave && isSaved && _jsx("span", { style: { color: 'var(--up)' }, children: "ON" }), autoSave && !isSaved && _jsx("span", { style: { color: 'var(--text-muted)' }, children: "save first" })] }), _jsx("span", { className: `layout-toggle-switch${autoSave ? ' on' : ''}`, onClick: (e) => { e.preventDefault(); onToggleAutoSave(!autoSave); }, role: "switch", "aria-checked": autoSave, children: _jsx("span", { className: "layout-toggle-thumb" }) })] }), _jsx("div", { className: "layout-dropdown-divider" }), _jsxs("button", { className: "layout-dropdown-item", onClick: () => startView('save', currentName ?? ''), children: [_jsxs("svg", { className: "layout-menu-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" }), _jsx("polyline", { points: "17 21 17 13 7 13 7 21" }), _jsx("polyline", { points: "7 3 7 8 15 8" })] }), "Save layout\u2026"] }), isSaved && (_jsxs("button", { className: "layout-dropdown-item", onClick: () => startView('rename', currentName ?? ''), children: [_jsxs("svg", { className: "layout-menu-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M12 20h9" }), _jsx("path", { d: "M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z" })] }), "Rename\u2026"] })), _jsxs("button", { className: "layout-dropdown-item", onClick: () => startView('copy', `${currentName ?? 'Layout'} copy`), children: [_jsxs("svg", { className: "layout-menu-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), _jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] }), "Copy layout\u2026"] }), _jsx("div", { className: "layout-dropdown-divider" }), fetching && _jsx("div", { className: "layout-dropdown-empty", children: "Loading\u2026" }), !fetching && loadError && (_jsx("div", { className: "layout-dropdown-error", children: fmtError(loadError) })), !fetching && !loadError && layouts.length === 0 && (_jsx("div", { className: "layout-dropdown-empty", children: "No saved layouts yet" })), !fetching && !loadError && layouts.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "layout-dropdown-section", children: "Saved layouts" }), layouts.map((l) => (_jsxs("div", { style: { display: 'flex', alignItems: 'center' }, children: [_jsxs("button", { className: `layout-dropdown-item${l.id === currentLayoutId ? ' layout-dropdown-item--current' : ''}`, onClick: () => l.id === currentLayoutId ? handleLoad(l.id) : handleOpenInNewTabLocal(l.id), title: `${l.symbol} · ${l.timeframe} · ${new Date(l.updated_at).toLocaleDateString()}`, style: { flex: 1, textAlign: 'left' }, children: [l.id === currentLayoutId ? (_jsx("svg", { className: "layout-menu-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) })) : (_jsx("svg", { className: "layout-menu-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" }) })), _jsx("span", { style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', minWidth: 0 }, children: l.name })] }), _jsx("button", { onClick: (e) => { e.stopPropagation(); setConfirmDelete({ id: l.id, name: l.name }); }, title: "Delete layout", style: { padding: '4px 8px', opacity: 0.45, flexShrink: 0, lineHeight: 1, width: 'auto' }, className: "layout-dropdown-item", children: "\u2715" })] }, l.id)))] })), confirmDelete && (_jsxs("div", { style: { padding: '8px 12px', borderTop: '1px solid var(--border)' }, children: [_jsxs("div", { style: { fontSize: 12, marginBottom: 8 }, children: ["Delete ", _jsx("strong", { children: confirmDelete.name }), "? This cannot be undone."] }), _jsxs("div", { style: { display: 'flex', gap: 6, justifyContent: 'flex-end' }, children: [_jsx("button", { onClick: () => setConfirmDelete(null), children: "Cancel" }), _jsx("button", { onClick: handleConfirmDelete, style: { color: 'var(--down, #ef5350)' }, children: "Delete" })] })] }))] })), view === 'save' && renderForm('Layout name', 'My layout', onSave), view === 'rename' && renderForm('Rename layout', currentName ?? 'Layout', onRename), view === 'copy' && renderForm('Copy to new layout', `${currentName ?? 'Layout'} copy`, onCopy, 'Creates a copy of the current layout in a new tab.')] }))] }));
112
- }
113
- //# sourceMappingURL=LayoutMenu.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LayoutMenu.js","sourceRoot":"","sources":["../../../src/react/workspace/LayoutMenu.tsx"],"names":[],"mappings":"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"}
@@ -1,245 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect, useRef, useCallback } from 'react';
3
- const PAGE_SIZE = 100;
4
- const TABS = [
5
- { label: 'All', market: '' },
6
- { label: 'Stocks', market: 'stocks' },
7
- { label: 'Funds', market: 'etfs' },
8
- { label: 'Futures', market: 'futures' },
9
- { label: 'Forex', market: 'forex' },
10
- { label: 'Crypto', market: 'crypto' },
11
- { label: 'Indices', market: 'indices' },
12
- { label: 'Bonds', market: 'bonds' },
13
- { label: 'Economy', market: 'economy' },
14
- { label: 'Options', market: 'options' },
15
- ];
16
- function refSymbolsToEntries(symbols) {
17
- return symbols.map(s => ({
18
- symbol: s.symbol,
19
- name: s.displayName,
20
- symbolKey: s.symbolKey,
21
- exchange: s.exchange,
22
- assetType: s.assetType,
23
- market: s.market,
24
- ...(s.logoUrl ? { logoUrl: s.logoUrl } : {}),
25
- }));
26
- }
27
- function stringColor(str) {
28
- const palette = [
29
- '#f7931a', '#627eea', '#2775ca', '#26a17b', '#e84142',
30
- '#00adef', '#e91e63', '#9945ff', '#00d4aa', '#ff6b35',
31
- ];
32
- let h = 0;
33
- for (let i = 0; i < str.length; i++)
34
- h = (Math.imul(31, h) + str.charCodeAt(i)) | 0;
35
- return palette[Math.abs(h) % palette.length] ?? '#888888';
36
- }
37
- function badgeLabel(assetType, market) {
38
- const a = assetType?.toLowerCase() ?? '';
39
- const m = market?.toLowerCase() ?? '';
40
- if (a && m && a !== m)
41
- return `${a} ${m}`;
42
- return a || m || '';
43
- }
44
- function SymbolIcon({ logoUrl, letter, color }) {
45
- const [failed, setFailed] = useState(false);
46
- return (_jsx("span", { className: "sym-row-icon", style: { background: (logoUrl && !failed) ? 'transparent' : color }, children: logoUrl && !failed
47
- ? _jsx("img", { src: logoUrl, alt: "", className: "sym-logo-img", onError: () => setFailed(true) })
48
- : letter }));
49
- }
50
- export function SymbolSearchDialog({ current, onSelect, onClose, symbolResolver }) {
51
- const [query, setQuery] = useState('');
52
- const [activeTab, setActiveTab] = useState(0);
53
- const [tabSymbols, setTabSymbols] = useState([]);
54
- const [tabLoading, setTabLoading] = useState(false);
55
- const [tabLoadingMore, setTabLoadingMore] = useState(false);
56
- const [tabOffset, setTabOffset] = useState(0);
57
- const [tabHasMore, setTabHasMore] = useState(false);
58
- const [searchResults, setSearchResults] = useState(null);
59
- const [isSearching, setIsSearching] = useState(false);
60
- const [searchingMore, setSearchingMore] = useState(false);
61
- const [searchOffset, setSearchOffset] = useState(0);
62
- const [searchHasMore, setSearchHasMore] = useState(false);
63
- const inputRef = useRef(null);
64
- const dialogRef = useRef(null);
65
- const sentinelRef = useRef(null);
66
- const searchTimer = useRef(null);
67
- const queryRef = useRef(query);
68
- const activeTabRef = useRef(activeTab);
69
- queryRef.current = query;
70
- activeTabRef.current = activeTab;
71
- useEffect(() => { inputRef.current?.focus(); }, []);
72
- useEffect(() => {
73
- const h = (e) => { if (e.key === 'Escape')
74
- onClose(); };
75
- window.addEventListener('keydown', h);
76
- return () => window.removeEventListener('keydown', h);
77
- }, [onClose]);
78
- // Tab browse: use getSymbols() for all tabs — supports offset pagination.
79
- useEffect(() => {
80
- const market = TABS[activeTab]?.market ?? '';
81
- let cancelled = false;
82
- setTabLoading(true);
83
- setTabSymbols([]);
84
- setTabOffset(0);
85
- setTabHasMore(false);
86
- symbolResolver.getSymbols({ ...(market ? { market } : {}), limit: PAGE_SIZE, offset: 0 })
87
- .then((r) => {
88
- if (!cancelled) {
89
- setTabSymbols(refSymbolsToEntries(r.symbols));
90
- setTabHasMore(r.symbols.length === PAGE_SIZE);
91
- setTabOffset(PAGE_SIZE);
92
- }
93
- })
94
- .catch(() => { })
95
- .finally(() => { if (!cancelled)
96
- setTabLoading(false); });
97
- return () => { cancelled = true; };
98
- }, [activeTab]);
99
- const loadMoreTab = useCallback(async () => {
100
- if (tabLoadingMore || !tabHasMore)
101
- return;
102
- const market = TABS[activeTabRef.current]?.market ?? '';
103
- setTabLoadingMore(true);
104
- try {
105
- const r = await symbolResolver.getSymbols({ ...(market ? { market } : {}), limit: PAGE_SIZE, offset: tabOffset });
106
- setTabSymbols(prev => [...prev, ...refSymbolsToEntries(r.symbols)]);
107
- setTabHasMore(r.symbols.length === PAGE_SIZE);
108
- setTabOffset(prev => prev + PAGE_SIZE);
109
- }
110
- catch { /* ignore */ }
111
- finally {
112
- setTabLoadingMore(false);
113
- }
114
- }, [tabLoadingMore, tabHasMore, tabOffset]);
115
- const loadMoreSearch = useCallback(async () => {
116
- if (searchingMore || !searchHasMore)
117
- return;
118
- const q = queryRef.current.trim();
119
- if (!q)
120
- return;
121
- const market = TABS[activeTabRef.current]?.market;
122
- setSearchingMore(true);
123
- try {
124
- const res = await symbolResolver.searchSymbols(q, {
125
- limit: PAGE_SIZE, offset: searchOffset,
126
- ...(market ? { market } : {}),
127
- });
128
- setSearchResults(prev => prev ? [...prev, ...refSymbolsToEntries(res.symbols)] : refSymbolsToEntries(res.symbols));
129
- setSearchHasMore(res.symbols.length === PAGE_SIZE);
130
- setSearchOffset(prev => prev + PAGE_SIZE);
131
- }
132
- catch { /* ignore */ }
133
- finally {
134
- setSearchingMore(false);
135
- }
136
- }, [searchingMore, searchHasMore, searchOffset]);
137
- // Stable refs so the IntersectionObserver callback always calls the latest version
138
- const loadMoreTabRef = useRef(loadMoreTab);
139
- const loadMoreSearchRef = useRef(loadMoreSearch);
140
- loadMoreTabRef.current = loadMoreTab;
141
- loadMoreSearchRef.current = loadMoreSearch;
142
- // Sentinel IntersectionObserver — fires loadMore when the bottom of the list enters view
143
- useEffect(() => {
144
- const sentinel = sentinelRef.current;
145
- if (!sentinel)
146
- return;
147
- const observer = new IntersectionObserver(entries => {
148
- if (entries[0]?.isIntersecting) {
149
- if (queryRef.current.trim()) {
150
- void loadMoreSearchRef.current();
151
- }
152
- else {
153
- void loadMoreTabRef.current();
154
- }
155
- }
156
- }, { threshold: 0.1 });
157
- observer.observe(sentinel);
158
- return () => observer.disconnect();
159
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
160
- const doSearch = useCallback((q, tab) => {
161
- if (searchTimer.current)
162
- clearTimeout(searchTimer.current);
163
- if (!q.trim()) {
164
- setSearchResults(null);
165
- setSearchOffset(0);
166
- setSearchHasMore(false);
167
- return;
168
- }
169
- setIsSearching(true);
170
- searchTimer.current = setTimeout(async () => {
171
- try {
172
- const market = TABS[tab]?.market;
173
- const res = await symbolResolver.searchSymbols(q.trim(), {
174
- limit: PAGE_SIZE, offset: 0,
175
- ...(market ? { market } : {}),
176
- });
177
- setSearchResults(refSymbolsToEntries(res.symbols));
178
- setSearchHasMore(res.symbols.length === PAGE_SIZE);
179
- setSearchOffset(PAGE_SIZE);
180
- }
181
- catch {
182
- setSearchResults([]);
183
- setSearchHasMore(false);
184
- }
185
- finally {
186
- setIsSearching(false);
187
- }
188
- }, 180);
189
- }, []);
190
- const handleQueryChange = (value) => {
191
- setQuery(value);
192
- doSearch(value, activeTab);
193
- };
194
- const handleTabChange = (i) => {
195
- setActiveTab(i);
196
- if (queryRef.current.trim())
197
- doSearch(queryRef.current, i);
198
- };
199
- const handleBackdrop = (e) => {
200
- if (dialogRef.current && !dialogRef.current.contains(e.target))
201
- onClose();
202
- };
203
- const isSearch = query.trim().length > 0;
204
- const displayList = isSearch ? (searchResults ?? []) : tabSymbols;
205
- // Use exchange:symbol format (strip market prefix from symbolKey) so the
206
- // datafeed can pass it directly to the TV API, e.g. "BINANCE:BTCUSDT"
207
- const toFeedSymbol = (entry) => {
208
- if (!entry.symbolKey)
209
- return entry.symbol;
210
- const parts = entry.symbolKey.split(':');
211
- // symbolKey is MARKET:EXCHANGE:SYMBOL → we want EXCHANGE:SYMBOL
212
- return parts.length >= 3 ? parts.slice(1).join(':') : entry.symbolKey;
213
- };
214
- const pick = (entry) => { onSelect(toFeedSymbol(entry)); onClose(); };
215
- const renderRow = (entry) => {
216
- const iconColor = stringColor(entry.symbol);
217
- const exchColor = stringColor(entry.exchange);
218
- const letter = entry.symbol.charAt(0).toUpperCase();
219
- const exchAbbr = entry.exchange.slice(0, 2).toUpperCase();
220
- const badge = badgeLabel(entry.assetType, entry.market);
221
- return (_jsxs("button", { className: `sym-row${entry.symbol === current ? ' active' : ''}`, onClick: () => pick(entry), children: [_jsx(SymbolIcon, { letter: letter, color: iconColor, ...(entry.logoUrl ? { logoUrl: entry.logoUrl } : {}) }), _jsxs("span", { className: "sym-row-info", children: [_jsx("span", { className: "sym-row-ticker", children: entry.symbol }), _jsx("span", { className: "sym-row-name", children: entry.name })] }), badge && _jsx("span", { className: "sym-row-badge", children: badge }), _jsx("span", { className: "sym-row-exchange", children: entry.exchange }), _jsx("span", { className: "sym-row-exch-icon", style: { background: exchColor }, children: exchAbbr })] }, entry.symbolKey ?? `${entry.exchange}:${entry.symbol}`));
222
- };
223
- const renderDirectRow = () => {
224
- const q = query.trim();
225
- if (!q)
226
- return null;
227
- return (_jsxs("button", { className: "sym-row", onClick: () => { onSelect(q.toUpperCase()); onClose(); }, style: { borderTop: '1px solid var(--sym-border, rgba(255,255,255,.08))', marginTop: 4 }, children: [_jsx("span", { className: "sym-row-icon", style: { background: '#444', fontSize: 11, fontWeight: 700 }, children: "\u2192" }), _jsxs("span", { className: "sym-row-info", children: [_jsx("span", { className: "sym-row-ticker", children: q.toUpperCase() }), _jsx("span", { className: "sym-row-name", children: "Use this symbol directly" })] })] }));
228
- };
229
- const renderBody = () => {
230
- if (isSearch && isSearching)
231
- return _jsx("div", { className: "sym-list", children: renderDirectRow() });
232
- if (isSearch && searchResults !== null && searchResults.length === 0)
233
- return _jsx("div", { className: "sym-list", children: renderDirectRow() });
234
- if (!isSearch && tabLoading)
235
- return _jsx("div", { className: "sym-empty", children: "Loading..." });
236
- if (displayList.length === 0 && !isSearch && !tabLoading)
237
- return _jsx("div", { className: "sym-empty", children: "No data \u2014 run a Symbol Sync from the Studio" });
238
- const loadingMore = isSearch ? searchingMore : tabLoadingMore;
239
- if (isSearch)
240
- return (_jsxs("div", { className: "sym-list", children: [displayList.map(renderRow), renderDirectRow(), _jsx("div", { ref: sentinelRef, className: "sym-sentinel" }), loadingMore && _jsx("div", { className: "sym-loading-more", children: "Loading more\u2026" })] }));
241
- return (_jsxs("div", { className: "sym-list", children: [displayList.map(renderRow), _jsx("div", { ref: sentinelRef, className: "sym-sentinel" }), loadingMore && _jsx("div", { className: "sym-loading-more", children: "Loading more\u2026" })] }));
242
- };
243
- return (_jsx("div", { className: "sym-backdrop", onMouseDown: handleBackdrop, children: _jsxs("div", { className: "sym-dialog", ref: dialogRef, role: "dialog", "aria-modal": "true", "aria-label": "Symbol Search", children: [_jsxs("div", { className: "sym-header", children: [_jsx("span", { className: "sym-header-title", children: "Symbol Search" }), _jsx("button", { className: "sym-header-close", onClick: onClose, "aria-label": "Close", children: _jsxs("svg", { viewBox: "0 0 14 14", width: "13", height: "13", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", fill: "none", children: [_jsx("line", { x1: "2", y1: "2", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "2", x2: "2", y2: "12" })] }) })] }), _jsxs("div", { className: "sym-search-row", children: [_jsxs("svg", { className: "sym-search-icon", viewBox: "0 0 16 16", width: "15", height: "15", stroke: "currentColor", fill: "none", strokeWidth: "1.8", strokeLinecap: "round", children: [_jsx("circle", { cx: "6.5", cy: "6.5", r: "4.5" }), _jsx("line", { x1: "10.5", y1: "10.5", x2: "14", y2: "14" })] }), _jsx("input", { ref: inputRef, className: "sym-search-input", type: "text", value: query, onChange: (e) => handleQueryChange(e.target.value), placeholder: "Search symbols or names...", autoComplete: "off", spellCheck: false }), query && (_jsx("button", { className: "sym-search-clear", onClick: () => { setQuery(''); setSearchResults(null); }, "aria-label": "Clear", children: _jsxs("svg", { viewBox: "0 0 12 12", width: "11", height: "11", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", fill: "none", children: [_jsx("line", { x1: "2", y1: "2", x2: "10", y2: "10" }), _jsx("line", { x1: "10", y1: "2", x2: "2", y2: "10" })] }) }))] }), _jsx("div", { className: "sym-tabs", children: TABS.map((tab, i) => (_jsx("button", { className: `sym-tab${i === activeTab ? ' active' : ''}`, onClick: () => handleTabChange(i), children: tab.label }, tab.label))) }), _jsx("div", { className: "sym-list-wrap", children: renderBody() }), _jsx("div", { className: "sym-footer", children: "Search using ISIN and CUSIP codes" })] }) }));
244
- }
245
- //# sourceMappingURL=SymbolSearchDialog.js.map