@tradecanvas/chart 1.4.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +910 -858
  3. package/dist/Chart.d.ts +606 -23
  4. package/dist/Chart.d.ts.map +1 -1
  5. package/dist/DataManager.d.ts +5 -0
  6. package/dist/DataManager.d.ts.map +1 -1
  7. package/dist/HistoryPager.d.ts +58 -0
  8. package/dist/HistoryPager.d.ts.map +1 -0
  9. package/dist/LayoutSession-CTZB90NX.cjs +2 -0
  10. package/dist/LayoutSession-CTZB90NX.cjs.map +1 -0
  11. package/dist/LayoutSession-CWn3sdbs.js +3967 -0
  12. package/dist/LayoutSession-CWn3sdbs.js.map +1 -0
  13. package/dist/ThemeManager.d.ts +5 -1
  14. package/dist/ThemeManager.d.ts.map +1 -1
  15. package/dist/chartA11y.d.ts +59 -0
  16. package/dist/chartA11y.d.ts.map +1 -0
  17. package/dist/charts/ChartTypeStrategy.d.ts +5 -4
  18. package/dist/charts/ChartTypeStrategy.d.ts.map +1 -1
  19. package/dist/grid/ChartGrid.d.ts +6 -1
  20. package/dist/grid/ChartGrid.d.ts.map +1 -1
  21. package/dist/i18n-CiQ8EDVs.js +1469 -0
  22. package/dist/i18n-CiQ8EDVs.js.map +1 -0
  23. package/dist/i18n-WsLA9SmD.cjs +2 -0
  24. package/dist/i18n-WsLA9SmD.cjs.map +1 -0
  25. package/dist/index.cjs +1 -1
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.ts +22 -3
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +31 -31
  30. package/dist/index.js.map +1 -1
  31. package/dist/indicatorLabel.d.ts +7 -0
  32. package/dist/indicatorLabel.d.ts.map +1 -0
  33. package/dist/layout/LayoutManager.d.ts +50 -0
  34. package/dist/layout/LayoutManager.d.ts.map +1 -1
  35. package/dist/layout/priceAxisWidth.d.ts +2 -0
  36. package/dist/layout/priceAxisWidth.d.ts.map +1 -1
  37. package/dist/regularHours.d.ts +10 -0
  38. package/dist/regularHours.d.ts.map +1 -0
  39. package/dist/state/LayoutSession.d.ts +101 -0
  40. package/dist/state/LayoutSession.d.ts.map +1 -0
  41. package/dist/state/layoutStorage.d.ts +46 -0
  42. package/dist/state/layoutStorage.d.ts.map +1 -0
  43. package/dist/trading/wireExecution.d.ts +7 -3
  44. package/dist/trading/wireExecution.d.ts.map +1 -1
  45. package/dist/widget/ChartWidget.d.ts +219 -10
  46. package/dist/widget/ChartWidget.d.ts.map +1 -1
  47. package/dist/widget/ChartWidgetGrid.d.ts +166 -0
  48. package/dist/widget/ChartWidgetGrid.d.ts.map +1 -0
  49. package/dist/widget/DrawingTemplateStore.d.ts +29 -8
  50. package/dist/widget/DrawingTemplateStore.d.ts.map +1 -1
  51. package/dist/widget/WatchlistStore.d.ts +65 -0
  52. package/dist/widget/WatchlistStore.d.ts.map +1 -0
  53. package/dist/widget/WidgetAccountPanel.d.ts +72 -0
  54. package/dist/widget/WidgetAccountPanel.d.ts.map +1 -0
  55. package/dist/widget/WidgetAlertsPanel.d.ts +50 -3
  56. package/dist/widget/WidgetAlertsPanel.d.ts.map +1 -1
  57. package/dist/widget/WidgetBracketBar.d.ts +3 -1
  58. package/dist/widget/WidgetBracketBar.d.ts.map +1 -1
  59. package/dist/widget/WidgetChartNav.d.ts +36 -0
  60. package/dist/widget/WidgetChartNav.d.ts.map +1 -0
  61. package/dist/widget/WidgetCommandPalette.d.ts +3 -1
  62. package/dist/widget/WidgetCommandPalette.d.ts.map +1 -1
  63. package/dist/widget/WidgetContextMenu.d.ts +40 -0
  64. package/dist/widget/WidgetContextMenu.d.ts.map +1 -0
  65. package/dist/widget/WidgetDataWindow.d.ts +3 -1
  66. package/dist/widget/WidgetDataWindow.d.ts.map +1 -1
  67. package/dist/widget/WidgetDepthLadder.d.ts +3 -1
  68. package/dist/widget/WidgetDepthLadder.d.ts.map +1 -1
  69. package/dist/widget/WidgetDrawingSettings.d.ts +108 -0
  70. package/dist/widget/WidgetDrawingSettings.d.ts.map +1 -0
  71. package/dist/widget/WidgetDrawingSidebar.d.ts +14 -1
  72. package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
  73. package/dist/widget/WidgetDrawingStyle.d.ts +3 -1
  74. package/dist/widget/WidgetDrawingStyle.d.ts.map +1 -1
  75. package/dist/widget/WidgetDropdown.d.ts.map +1 -1
  76. package/dist/widget/WidgetGoToDate.d.ts +5 -4
  77. package/dist/widget/WidgetGoToDate.d.ts.map +1 -1
  78. package/dist/widget/WidgetHistoryPill.d.ts +23 -0
  79. package/dist/widget/WidgetHistoryPill.d.ts.map +1 -0
  80. package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
  81. package/dist/widget/WidgetIndicatorLegend.d.ts +31 -1
  82. package/dist/widget/WidgetIndicatorLegend.d.ts.map +1 -1
  83. package/dist/widget/WidgetIndicatorSettings.d.ts +62 -7
  84. package/dist/widget/WidgetIndicatorSettings.d.ts.map +1 -1
  85. package/dist/widget/WidgetIntervalInput.d.ts +34 -0
  86. package/dist/widget/WidgetIntervalInput.d.ts.map +1 -0
  87. package/dist/widget/WidgetLayoutsDialog.d.ts +39 -0
  88. package/dist/widget/WidgetLayoutsDialog.d.ts.map +1 -0
  89. package/dist/widget/WidgetLayoutsUI.d.ts +37 -0
  90. package/dist/widget/WidgetLayoutsUI.d.ts.map +1 -0
  91. package/dist/widget/WidgetNamePrompt.d.ts +31 -0
  92. package/dist/widget/WidgetNamePrompt.d.ts.map +1 -0
  93. package/dist/widget/WidgetObjectTree.d.ts +21 -3
  94. package/dist/widget/WidgetObjectTree.d.ts.map +1 -1
  95. package/dist/widget/WidgetOrderTicket.d.ts +49 -0
  96. package/dist/widget/WidgetOrderTicket.d.ts.map +1 -0
  97. package/dist/widget/WidgetReplayBar.d.ts +15 -0
  98. package/dist/widget/WidgetReplayBar.d.ts.map +1 -1
  99. package/dist/widget/WidgetSettings.d.ts +13 -1
  100. package/dist/widget/WidgetSettings.d.ts.map +1 -1
  101. package/dist/widget/WidgetStatusBar.d.ts +3 -0
  102. package/dist/widget/WidgetStatusBar.d.ts.map +1 -1
  103. package/dist/widget/WidgetStyles.d.ts +3 -1
  104. package/dist/widget/WidgetStyles.d.ts.map +1 -1
  105. package/dist/widget/WidgetSymbolInfo.d.ts +64 -0
  106. package/dist/widget/WidgetSymbolInfo.d.ts.map +1 -0
  107. package/dist/widget/WidgetSymbolSearch.d.ts +26 -5
  108. package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -1
  109. package/dist/widget/WidgetToolbar.d.ts +30 -1
  110. package/dist/widget/WidgetToolbar.d.ts.map +1 -1
  111. package/dist/widget/WidgetWatchlist.d.ts +53 -13
  112. package/dist/widget/WidgetWatchlist.d.ts.map +1 -1
  113. package/dist/widget/chartMenu.d.ts +40 -0
  114. package/dist/widget/chartMenu.d.ts.map +1 -0
  115. package/dist/widget/drawingMenu.d.ts +21 -0
  116. package/dist/widget/drawingMenu.d.ts.map +1 -0
  117. package/dist/widget/focusTrap.d.ts +8 -0
  118. package/dist/widget/focusTrap.d.ts.map +1 -0
  119. package/dist/widget/i18n.d.ts +20 -89
  120. package/dist/widget/i18n.d.ts.map +1 -1
  121. package/dist/widget/iconSet.d.ts.map +1 -1
  122. package/dist/widget/index.cjs +4294 -3028
  123. package/dist/widget/index.cjs.map +1 -1
  124. package/dist/widget/index.d.ts +15 -1
  125. package/dist/widget/index.d.ts.map +1 -1
  126. package/dist/widget/index.js +6326 -1185
  127. package/dist/widget/index.js.map +1 -1
  128. package/dist/widget/indicatorTemplates.d.ts +24 -0
  129. package/dist/widget/indicatorTemplates.d.ts.map +1 -0
  130. package/dist/widget/keyTarget.d.ts +11 -0
  131. package/dist/widget/keyTarget.d.ts.map +1 -0
  132. package/dist/widget/legendValues.d.ts +11 -6
  133. package/dist/widget/legendValues.d.ts.map +1 -1
  134. package/dist/widget/locales/ar.d.ts +4 -0
  135. package/dist/widget/locales/ar.d.ts.map +1 -0
  136. package/dist/widget/locales/de.d.ts +4 -0
  137. package/dist/widget/locales/de.d.ts.map +1 -0
  138. package/dist/widget/locales/en.d.ts +722 -0
  139. package/dist/widget/locales/en.d.ts.map +1 -0
  140. package/dist/widget/locales/es.d.ts +4 -0
  141. package/dist/widget/locales/es.d.ts.map +1 -0
  142. package/dist/widget/locales/fr.d.ts +4 -0
  143. package/dist/widget/locales/fr.d.ts.map +1 -0
  144. package/dist/widget/locales/he.d.ts +4 -0
  145. package/dist/widget/locales/he.d.ts.map +1 -0
  146. package/dist/widget/locales/id.d.ts +4 -0
  147. package/dist/widget/locales/id.d.ts.map +1 -0
  148. package/dist/widget/locales/index.cjs +2 -0
  149. package/dist/widget/locales/index.cjs.map +1 -0
  150. package/dist/widget/locales/index.d.ts +33 -0
  151. package/dist/widget/locales/index.d.ts.map +1 -0
  152. package/dist/widget/locales/index.js +10089 -0
  153. package/dist/widget/locales/index.js.map +1 -0
  154. package/dist/widget/locales/ja.d.ts +4 -0
  155. package/dist/widget/locales/ja.d.ts.map +1 -0
  156. package/dist/widget/locales/ko.d.ts +4 -0
  157. package/dist/widget/locales/ko.d.ts.map +1 -0
  158. package/dist/widget/locales/pt.d.ts +4 -0
  159. package/dist/widget/locales/pt.d.ts.map +1 -0
  160. package/dist/widget/locales/ru.d.ts +4 -0
  161. package/dist/widget/locales/ru.d.ts.map +1 -0
  162. package/dist/widget/locales/th.d.ts +4 -0
  163. package/dist/widget/locales/th.d.ts.map +1 -0
  164. package/dist/widget/locales/tr.d.ts +4 -0
  165. package/dist/widget/locales/tr.d.ts.map +1 -0
  166. package/dist/widget/locales/vi.d.ts +4 -0
  167. package/dist/widget/locales/vi.d.ts.map +1 -0
  168. package/dist/widget/locales/zh.d.ts +4 -0
  169. package/dist/widget/locales/zh.d.ts.map +1 -0
  170. package/dist/widget/locales/zhHant.d.ts +4 -0
  171. package/dist/widget/locales/zhHant.d.ts.map +1 -0
  172. package/dist/widget/orderTicket.d.ts +27 -0
  173. package/dist/widget/orderTicket.d.ts.map +1 -0
  174. package/dist/widget/settingsControls.d.ts +24 -0
  175. package/dist/widget/settingsControls.d.ts.map +1 -0
  176. package/dist/widget/types.d.ts +182 -6
  177. package/dist/widget/types.d.ts.map +1 -1
  178. package/dist/widget/widgetConfig.d.ts.map +1 -1
  179. package/dist/widget/widgetLayout.d.ts +22 -0
  180. package/dist/widget/widgetLayout.d.ts.map +1 -0
  181. package/dist/widget/widgetLocales.d.ts +17 -0
  182. package/dist/widget/widgetLocales.d.ts.map +1 -0
  183. package/dist/widget/widgetTimeframes.d.ts +8 -0
  184. package/dist/widget/widgetTimeframes.d.ts.map +1 -1
  185. package/dist/widget/widgetTimezones.d.ts +32 -0
  186. package/dist/widget/widgetTimezones.d.ts.map +1 -0
  187. package/dist/widget/widgetUI.d.ts +126 -0
  188. package/dist/widget/widgetUI.d.ts.map +1 -0
  189. package/package.json +8 -3
  190. package/dist/DragDropImporter-C5kgfbET.cjs +0 -2
  191. package/dist/DragDropImporter-C5kgfbET.cjs.map +0 -1
  192. package/dist/DragDropImporter-Dd9Mud5J.js +0 -2099
  193. package/dist/DragDropImporter-Dd9Mud5J.js.map +0 -1
  194. package/dist/charts/IndicatorPriceRange.d.ts +0 -20
  195. package/dist/charts/IndicatorPriceRange.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/io/resampleOHLCV.ts","../../src/widget/widgetConfig.ts","../../src/widget/WidgetStyles.ts","../../src/widget/iconSet.ts","../../src/widget/icons.ts","../../src/widget/escapeHtml.ts","../../src/widget/WidgetDropdown.ts","../../src/widget/WidgetToolbar.ts","../../src/widget/WidgetDrawingSidebar.ts","../../src/widget/WidgetSettings.ts","../../src/widget/WidgetStatusBar.ts","../../src/widget/WidgetCommandPalette.ts","../../src/widget/WidgetSymbolSearch.ts","../../src/widget/WidgetHotkeySheet.ts","../../src/widget/WidgetReplayBar.ts","../../src/widget/WidgetWatchlist.ts","../../src/widget/WidgetAlertsPanel.ts","../../src/widget/WidgetObjectTree.ts","../../src/widget/WidgetIndicatorSettings.ts","../../src/widget/DrawingTemplateStore.ts","../../src/widget/WidgetDrawingStyle.ts","../../src/widget/DrawingFavoritesStore.ts","../../src/widget/widgetTimeframes.ts","../../src/widget/WidgetGoToDate.ts","../../src/widget/WidgetTooltip.ts","../../src/widget/WidgetIndicatorLegend.ts","../../src/widget/legendValues.ts","../../src/widget/WidgetBracketBar.ts","../../src/widget/AlertNotifier.ts","../../src/widget/ladderRows.ts","../../src/widget/WidgetDepthLadder.ts","../../src/widget/WidgetDataWindow.ts","../../src/widget/widgetShareState.ts","../../src/widget/i18n.ts","../../src/widget/WidgetLoadingOverlay.ts","../../src/widget/ChartWidget.ts"],"sourcesContent":["import type { DataSeries, OHLCBar, TimeFrame } from '@tradecanvas/commons';\nimport { timeframeToMs, timeframeBucketStart } from '@tradecanvas/commons';\n\nexport interface ResampleOptions {\n /** 0 = Sunday, 1 = Monday (default) — anchor for weekly buckets. */\n weekStartsOn?: 0 | 1;\n}\n\n/**\n * Aggregate a finer OHLCV series into a coarser timeframe.\n *\n * Bars are grouped by calendar-aware bucket (see `timeframeBucketStart`):\n * open = first bar's open, high/low = extremes, close = last bar's close,\n * volume = sum. Input bars are assumed sorted ascending by `time` and are\n * never mutated.\n *\n * Upsampling (target finer than source) cannot synthesize data — pass a target\n * coarser than the source. Use `inferTimeframeMs` to detect the source spacing.\n */\nexport function resampleOHLCV(\n bars: DataSeries,\n target: TimeFrame,\n opts: ResampleOptions = {},\n): DataSeries {\n if (bars.length === 0) return [];\n const weekStartsOn = opts.weekStartsOn ?? 1;\n\n const out: OHLCBar[] = [];\n let current: OHLCBar | null = null;\n let currentKey = Number.NaN;\n\n for (const bar of bars) {\n const key = timeframeBucketStart(bar.time, target, weekStartsOn);\n if (current === null || key !== currentKey) {\n if (current !== null) out.push(current);\n current = {\n time: key,\n open: bar.open,\n high: bar.high,\n low: bar.low,\n close: bar.close,\n volume: bar.volume,\n };\n currentKey = key;\n } else {\n current = {\n time: current.time,\n open: current.open,\n high: Math.max(current.high, bar.high),\n low: Math.min(current.low, bar.low),\n close: bar.close,\n volume: current.volume + bar.volume,\n };\n }\n }\n if (current !== null) out.push(current);\n return out;\n}\n\n/**\n * Estimate the source bar spacing in milliseconds from the median gap between\n * consecutive bars. Robust to occasional gaps (weekends, halts). Returns 0 for\n * series with fewer than two bars.\n */\nexport function inferTimeframeMs(bars: DataSeries): number {\n if (bars.length < 2) return 0;\n const gaps: number[] = [];\n for (let i = 1; i < bars.length; i++) {\n const gap = bars[i].time - bars[i - 1].time;\n if (gap > 0) gaps.push(gap);\n }\n if (gaps.length === 0) return 0;\n gaps.sort((a, b) => a - b);\n return gaps[Math.floor(gaps.length / 2)];\n}\n\n/**\n * Whether `target` is coarser than (or equal to) the source spacing, i.e. a\n * valid downsample. A non-positive `sourceMs` (unknown) is treated as valid.\n */\nexport function canResample(sourceMs: number, target: TimeFrame): boolean {\n if (sourceMs <= 0) return true;\n return timeframeToMs(target) >= sourceMs;\n}\n","import { DARK_THEME } from '@tradecanvas/commons';\nimport type { ChartType, DrawingToolType } from '@tradecanvas/commons';\nimport type { IndicatorDef, DrawingToolGroupDef, ChartSettingsState } from './types.js';\n\nexport const CHART_TYPES: { label: string; value: ChartType }[] = [\n { label: 'Candlestick', value: 'candlestick' },\n { label: 'Line', value: 'line' },\n { label: 'Area', value: 'area' },\n { label: 'Bar', value: 'bar' },\n { label: 'Heikin-Ashi', value: 'heikinAshi' },\n { label: 'Hollow Candle', value: 'hollowCandle' },\n { label: 'Baseline', value: 'baseline' },\n { label: 'Volume Candles', value: 'volumeCandles' },\n { label: 'Equivolume', value: 'equivolume' },\n { label: 'HLC Area', value: 'hlcArea' },\n { label: 'Step Line', value: 'stepLine' },\n { label: 'Line + Markers', value: 'lineWithMarkers' },\n];\n\nexport const DRAWING_TOOL_GROUPS: DrawingToolGroupDef[] = [\n {\n label: 'Lines',\n tools: [\n { label: 'Trend Line', value: 'trendLine' as DrawingToolType },\n { label: 'Ray', value: 'ray' as DrawingToolType },\n { label: 'Extended Line', value: 'extendedLine' as DrawingToolType },\n { label: 'Info Line', value: 'infoLine' as DrawingToolType },\n { label: 'Trend Angle', value: 'trendAngle' as DrawingToolType },\n ],\n },\n {\n label: 'Horizontal/Vertical',\n tools: [\n { label: 'Horizontal Line', value: 'horizontalLine' as DrawingToolType },\n { label: 'Horizontal Ray', value: 'horizontalRay' as DrawingToolType },\n { label: 'Vertical Line', value: 'verticalLine' as DrawingToolType },\n { label: 'Cross Line', value: 'crossLine' as DrawingToolType },\n ],\n },\n {\n label: 'Channels',\n tools: [\n { label: 'Parallel Channel', value: 'parallelChannel' as DrawingToolType },\n { label: 'Regression Channel', value: 'regressionChannel' as DrawingToolType },\n ],\n },\n {\n label: 'Fibonacci',\n tools: [\n { label: 'Fib Retracement', value: 'fibRetracement' as DrawingToolType },\n { label: 'Fib Extension', value: 'fibExtension' as DrawingToolType },\n { label: 'Fib Channel', value: 'fibChannel' as DrawingToolType },\n { label: 'Fib Time Zones', value: 'fibTimeZones' as DrawingToolType },\n { label: 'Fib Speed Resistance Fan', value: 'fibSpeedResistanceFan' as DrawingToolType },\n ],\n },\n {\n label: 'Shapes',\n tools: [\n { label: 'Rectangle', value: 'rectangle' as DrawingToolType },\n { label: 'Circle', value: 'circle' as DrawingToolType },\n { label: 'Ellipse', value: 'ellipse' as DrawingToolType },\n { label: 'Triangle', value: 'triangle' as DrawingToolType },\n ],\n },\n {\n label: 'Gann & Pitchforks',\n tools: [\n { label: 'Pitchfork', value: 'pitchfork' as DrawingToolType },\n { label: 'Schiff Pitchfork', value: 'schiffPitchfork' as DrawingToolType },\n { label: 'Modified Schiff Pitchfork', value: 'modifiedSchiffPitchfork' as DrawingToolType },\n { label: 'Gann Fan', value: 'gannFan' as DrawingToolType },\n { label: 'Gann Box', value: 'gannBox' as DrawingToolType },\n { label: 'Cyclic Lines', value: 'cyclicLines' as DrawingToolType },\n ],\n },\n {\n label: 'Patterns',\n tools: [\n { label: 'XABCD Pattern', value: 'xabcdPattern' as DrawingToolType },\n { label: 'ABCD Pattern', value: 'abcdPattern' as DrawingToolType },\n { label: 'Head and Shoulders', value: 'headAndShoulders' as DrawingToolType },\n { label: 'Elliott Wave', value: 'elliottWave' as DrawingToolType },\n ],\n },\n {\n label: 'Measure',\n tools: [\n { label: 'Price Range', value: 'priceRange' as DrawingToolType },\n { label: 'Date Range', value: 'dateRange' as DrawingToolType },\n { label: 'Date and Price Range', value: 'dateAndPriceRange' as DrawingToolType },\n { label: 'Measure', value: 'measure' as DrawingToolType },\n ],\n },\n {\n label: 'Annotation',\n tools: [\n { label: 'Text', value: 'text' as DrawingToolType },\n { label: 'Price Label', value: 'priceLabel' as DrawingToolType },\n { label: 'Arrow', value: 'arrow' as DrawingToolType },\n ],\n },\n {\n label: 'Forecasting',\n tools: [\n { label: 'Long/Short Position', value: 'riskReward' as DrawingToolType },\n { label: 'Anchored VWAP', value: 'anchoredVWAP' as DrawingToolType },\n { label: 'Fixed Range Volume Profile', value: 'volumeProfileRange' as DrawingToolType },\n ],\n },\n];\n\nexport const INDICATORS: IndicatorDef[] = [\n { id: 'sma', name: 'SMA', type: 'overlay' },\n { id: 'ema', name: 'EMA', type: 'overlay' },\n { id: 'tema', name: 'Triple EMA', type: 'overlay' },\n { id: 'vwma', name: 'VWMA', type: 'overlay' },\n { id: 'wma', name: 'Weighted MA', type: 'overlay' },\n { id: 'hma', name: 'Hull MA', type: 'overlay' },\n { id: 'mtfma', name: 'MTF Moving Average', type: 'overlay' },\n { id: 'bb', name: 'Bollinger Bands', type: 'overlay' },\n { id: 'envelope', name: 'Envelope', type: 'overlay' },\n { id: 'vwap', name: 'VWAP', type: 'overlay' },\n { id: 'avwap', name: 'Anchored VWAP', type: 'overlay' },\n { id: 'svwap', name: 'Session VWAP', type: 'overlay' },\n { id: 'ichimoku', name: 'Ichimoku Cloud', type: 'overlay' },\n { id: 'psar', name: 'Parabolic SAR', type: 'overlay' },\n { id: 'supertrend', name: 'Supertrend', type: 'overlay' },\n { id: 'keltner', name: 'Keltner Channel', type: 'overlay' },\n { id: 'donchian', name: 'Donchian Channel', type: 'overlay' },\n { id: 'pivots', name: 'Pivot Points', type: 'overlay' },\n { id: 'zigzag', name: 'ZigZag', type: 'overlay' },\n { id: 'lrc', name: 'Linear Regression Channel', type: 'overlay' },\n { id: 'chandelier', name: 'Chandelier Exit', type: 'overlay' },\n { id: 'alligator', name: 'Alligator', type: 'overlay' },\n { id: 'rsi', name: 'RSI', type: 'panel' },\n { id: 'macd', name: 'MACD', type: 'panel' },\n { id: 'stochastic', name: 'Stochastic', type: 'panel' },\n { id: 'atr', name: 'ATR', type: 'panel' },\n { id: 'adx', name: 'ADX', type: 'panel' },\n { id: 'obv', name: 'OBV', type: 'panel' },\n { id: 'williamsR', name: 'Williams %R', type: 'panel' },\n { id: 'cci', name: 'CCI', type: 'panel' },\n { id: 'mfi', name: 'MFI', type: 'panel' },\n { id: 'roc', name: 'ROC', type: 'panel' },\n { id: 'tsi', name: 'TSI', type: 'panel' },\n { id: 'cmf', name: 'CMF', type: 'panel' },\n { id: 'aroon', name: 'Aroon', type: 'panel' },\n { id: 'stddev', name: 'Std Deviation', type: 'panel' },\n { id: 'vroc', name: 'Volume ROC', type: 'panel' },\n { id: 'ad', name: 'Acc/Dist', type: 'panel' },\n { id: 'ao', name: 'Awesome Oscillator', type: 'panel' },\n { id: 'chaikinOsc', name: 'Chaikin Oscillator', type: 'panel' },\n { id: 'voldelta', name: 'Volume Delta', type: 'panel' },\n { id: 'vortex', name: 'Vortex Indicator', type: 'panel' },\n { id: 'chop', name: 'Choppiness Index', type: 'panel' },\n { id: 'uo', name: 'Ultimate Oscillator', type: 'panel' },\n { id: 'fi', name: 'Force Index', type: 'panel' },\n { id: 'crsi', name: 'Connors RSI', type: 'panel' },\n { id: 'coppock', name: 'Coppock Curve', type: 'panel' },\n { id: 'kst', name: 'Know Sure Thing', type: 'panel' },\n { id: 'elderray', name: 'Elder Ray', type: 'panel' },\n { id: 'stc', name: 'Schaff Trend Cycle', type: 'panel' },\n { id: 'kvo', name: 'Klinger Oscillator', type: 'panel' },\n { id: 'fisher', name: 'Fisher Transform', type: 'panel' },\n { id: 'dpo', name: 'Detrended Price Osc', type: 'panel' },\n { id: 'bop', name: 'Balance of Power', type: 'panel' },\n { id: 'massindex', name: 'Mass Index', type: 'panel' },\n { id: 'cmo', name: 'Chande Momentum', type: 'panel' },\n { id: 'trix', name: 'TRIX', type: 'panel' },\n { id: 'emv', name: 'Ease of Movement', type: 'panel' },\n { id: 'pvt', name: 'Price Volume Trend', type: 'panel' },\n { id: 'wad', name: 'Williams A/D', type: 'panel' },\n { id: 'chaikinvol', name: 'Chaikin Volatility', type: 'panel' },\n { id: 'rvi', name: 'Relative Vigor Index', type: 'panel' },\n { id: 'stochrsi', name: 'Stochastic RSI', type: 'panel' },\n { id: 'ppo', name: 'Percentage Price Oscillator', type: 'panel' },\n { id: 'ac', name: 'Accelerator Oscillator', type: 'panel' },\n { id: 'rmi', name: 'Relative Momentum Index', type: 'panel' },\n { id: 'disparity', name: 'Disparity Index', type: 'panel' },\n { id: 'qstick', name: 'Qstick', type: 'panel' },\n { id: 'pgo', name: 'Pretty Good Oscillator', type: 'panel' },\n { id: 'volumeProfile', name: 'Volume Profile', type: 'panel' },\n];\n\nexport const POPULAR_INDICATORS = [\n 'sma', 'ema', 'bb', 'rsi', 'macd', 'stochastic',\n 'vwap', 'atr', 'obv', 'ichimoku',\n];\n\nexport const DEFAULT_SYMBOLS = [\n 'BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT',\n];\n\nexport const DEFAULT_SETTINGS: ChartSettingsState = {\n candleUpColor: DARK_THEME.candleUp,\n candleDownColor: DARK_THEME.candleDown,\n candleUpWick: DARK_THEME.candleUpWick,\n candleDownWick: DARK_THEME.candleDownWick,\n backgroundColor: DARK_THEME.background,\n gridColor: DARK_THEME.grid,\n gridVisible: true,\n volumeVisible: true,\n volumeProfileVisible: false,\n marketProfileVisible: false,\n marketProfileSplit: false,\n marketProfileLetters: false,\n marketProfileBuckets: 48,\n marketProfileOpacity: 0.32,\n depthHeatmapVisible: false,\n depthHeatmapOpacity: 0.7,\n sessionShadingVisible: false,\n pivotMarkersVisible: false,\n pivotStrength: 5,\n pivotStructureLabels: false,\n periodLevelsVisible: false,\n periodLevelsPeriod: 'day',\n legendVisible: true,\n barCountdown: true,\n logScale: false,\n scaleMode: 'regular',\n autoScale: true,\n invertScale: false,\n crosshairMode: 'magnet',\n numberLocale: 'en-US',\n timezone: 'local',\n};\n","import widgetCss from './WidgetStyles.css?raw';\r\n\r\nlet refCount = 0;\r\nconst STYLE_ID = 'tcw-styles';\r\n\r\n/**\r\n * Inject the widget stylesheet into `document.head`. Reference-counted so\r\n * multiple `ChartWidget` instances share the same `<style>` tag and the last\r\n * to detach removes it. CSS lives in a sibling `.css` file and is inlined at\r\n * build time via Vite's `?raw` query — consumers see a plain string at runtime.\r\n */\r\nexport function injectWidgetStyles(): void {\r\n refCount++;\r\n if (refCount > 1) return;\r\n if (document.getElementById(STYLE_ID)) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = STYLE_ID;\r\n style.textContent = widgetCss;\r\n document.head.appendChild(style);\r\n}\r\n\r\nexport function removeWidgetStyles(): void {\r\n refCount--;\r\n if (refCount > 0) return;\r\n\r\n const style = document.getElementById(STYLE_ID);\r\n if (style) {\r\n style.remove();\r\n }\r\n}\r\n","/**\n * The TradeCanvas icon set, as in the \"TradeCanvas Icons\" Figma file: a 24 px\n * grid with 2 px padding, 1.75 px strokes with round caps and joins. Drawing\n * tools mark their anchor points (where you click to draw) with filled dots.\n */\nexport interface IconDef {\n /** Stroked path data. */\n d?: string;\n /** Dashed stroke, for guides. */\n dash?: string;\n /** Solid shapes, such as filled candle bodies. */\n fills?: readonly string[];\n /** An area filled at 22%. */\n soft?: string;\n /** Filled dots: [cx, cy, r = 1.75]. */\n dots?: readonly (readonly number[])[];\n}\n\n/** Toolbar, sidebar and panel glyphs. */\nexport const UI_ICONS: Readonly<Record<string, IconDef>> = {\n cursor: { d: 'M6 3.5L18.5 12.5L12.6 13.6L9.7 19.4z' }, // Cursor\n trendingUp: { d: 'M3 17L9 11L13 14.5L21 6.5M15 6.5H21V12.5' }, // Indicators / Long\n trendingDown: { d: 'M3 7L9 13L13 9.5L21 17.5M15 17.5H21V11.5' }, // Short\n minus: { d: 'M5 12H19' }, // Minus\n plus: { d: 'M12 5V19M5 12H19' }, // Plus\n penLine: { d: 'M14.5 5.5L18.5 9.5M4 20L5 15.5L15.8 4.7a2 2 0 0 1 2.83 0l.67.67a2 2 0 0 1 0 2.83L8.5 19z' }, // Draw\n zigzag: { d: 'M3 17L8 9L13 15L21 6' }, // Patterns\n hash: { d: 'M5 9H19M5 15H19M10 4L8.5 20M15.5 4L14 20' }, // Grid\n square: { d: 'M6.5 4.5h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-11a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2z' }, // Shape\n gitBranch: { d: 'M6 3V15M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 9a9 9 0 0 1-9 9' }, // Branch\n ruler: { d: 'M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9' }, // Measure\n type: { d: 'M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5' }, // Text\n magnet: { d: 'M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18M6 8h3.5M14.5 8H18' }, // Magnet\n undo: { d: 'M9 14L4 9L9 4M4 9H14.5a5.5 5.5 0 0 1 0 11H11' }, // Undo\n redo: { d: 'M15 14L20 9L15 4M20 9H9.5a5.5 5.5 0 0 0 0 11H13' }, // Redo\n trash: { d: 'M4 7H20M9.5 7V4.5h5V7M6.5 7l.8 12.2A1.5 1.5 0 0 0 8.8 20.6h6.4a1.5 1.5 0 0 0 1.5-1.4L17.5 7M10 11v6M14 11v6' }, // Delete\n camera: { d: 'M4.5 7.5h3L9 5h6l1.5 2.5h3A1.5 1.5 0 0 1 21 9v9.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 18.5V9a1.5 1.5 0 0 1 1.5-1.5zM15.5 13.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z' }, // Screenshot\n settings: { d: 'M4 7H14M18 7H20M4 17H8M12 17H20M18 7a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM12 17a2 2 0 1 1-4 0 2 2 0 0 1 4 0z' }, // Settings\n moon: { d: 'M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z' }, // Dark theme\n sun: { d: 'M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM12 2.5v2M12 19.5v2M4.6 4.6l1.4 1.4M18 18l1.4 1.4M2.5 12h2M19.5 12h2M4.6 19.4L6 18M18 6l1.4-1.4' }, // Light theme\n chevronDown: { d: 'M6 9L12 15L18 9' }, // Expand\n chevronUp: { d: 'M6 15L12 9L18 15' }, // Collapse\n barChart: { d: 'M5 20V13M12 20V5M19 20V10' }, // Chart type\n x: { d: 'M6 6L18 18M18 6L6 18' }, // Close\n play: { d: 'M7 4.5v15L19.5 12z' }, // Play\n pause: { d: 'M8 5V19M16 5V19' }, // Pause\n stop: { d: 'M7.5 6h9A1.5 1.5 0 0 1 18 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 16.5v-9A1.5 1.5 0 0 1 7.5 6z' }, // Stop\n receipt: { d: 'M6 3.5h12v17l-2-1.25-2 1.25-2-1.25-2 1.25-2-1.25-2 1.25zM9 8h6M9 12h6M9 16h3' }, // Orders\n bell: { d: 'M6 16.5V11a6 6 0 0 1 12 0v5.5l1.5 2H4.5zM10 20.5a2.2 2.2 0 0 0 4 0' }, // Alerts\n layers: { d: 'M12 3.5L21 8.5L12 13.5L3 8.5zM3 12.5L12 17.5L21 12.5M3 16.5L12 21.5L21 16.5' }, // Objects\n eye: { d: 'M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12zM15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z' }, // Show\n eyeOff: { d: 'M4 4L20 20M9.9 5.8A9.6 9.6 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a16 16 0 0 1-2.3 3.1M6.6 7.1C3.9 8.9 2.5 12 2.5 12S6 18.5 12 18.5a9.3 9.3 0 0 0 4.7-1.3M10 10.1a3 3 0 0 0 4 4' }, // Hide\n lock: { d: 'M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 8 0v3' }, // Lock\n unlock: { d: 'M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 7.7-1.5' }, // Unlock\n palette: { d: 'M12 3.5a8.5 8.5 0 0 0 0 17c1.1 0 1.6-.8 1.6-1.6 0-.5-.2-.9-.5-1.2a1.6 1.6 0 0 1 1.2-2.7h1.9a4.3 4.3 0 0 0 4.3-4.3C20.5 6.9 16.7 3.5 12 3.5z', dots: [[7.5, 11.5, 1.25], [9.5, 7.75, 1.25], [14, 7.25, 1.25]] }, // Style\n check: { d: 'M5 12.5L10 17.5L19 7' }, // Done\n maximize: { d: 'M8 4H5a1 1 0 0 0-1 1v3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3' }, // Fullscreen\n minimize: { d: 'M4 8h3a1 1 0 0 0 1-1V4M16 4v3a1 1 0 0 0 1 1h3M20 16h-3a1 1 0 0 0-1 1v3M8 20v-3a1 1 0 0 0-1-1H4' }, // Exit fullscreen\n repeat: { d: 'M17 3.5L20.5 7L17 10.5M3.5 11.5V10a3 3 0 0 1 3-3h14M7 20.5L3.5 17L7 13.5M20.5 12.5V14a3 3 0 0 1-3 3h-14' }, // Stay in drawing mode\n calendar: { d: 'M5.5 5h13a2 2 0 0 1 2 2v11.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2zM3.5 10H20.5M8 3V7M16 3V7' }, // Go to date\n star: { d: 'M12 3.5L14.6 9L20.5 9.6L16 13.6L17.3 19.5L12 16.5L6.7 19.5L8 13.6L3.5 9.6L9.4 9z' }, // Favourite\n ladder: { d: 'M4 6H11M13 6H17M6 10H11M13 10H20M8 14H11M13 14H15M5 18H11M13 18H19' }, // Depth ladder\n};\n\n/** One per drawing tool, keyed by tool type. */\nexport const DRAWING_TOOL_ICONS: Readonly<Record<string, IconDef>> = {\n trendLine: { d: 'M5 18L19 6', dots: [[5, 18], [19, 6]] }, // Trend Line\n ray: { d: 'M5 17L21 5M17.5 4.81L21 5L20.2 8.41', dots: [[5, 17], [11, 12.5]] }, // Ray\n extendedLine: { d: 'M3 18.5L21 5M17.5 4.81L21 5L20.2 8.41M6.5 18.69L3 18.5L3.8 15.09', dots: [[9, 14], [15, 9.5]] }, // Extended Line\n infoLine: { d: 'M5 20L19 10M4.5 3.5h9a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zM6.5 6.5h5', dots: [[5, 20], [19, 10]] }, // Info Line\n trendAngle: { d: 'M5 18L19 7M5 18H20M11 18A6 6 0 0 0 9.71 14.29', dots: [[5, 18], [19, 7]] }, // Trend Angle\n horizontalLine: { d: 'M3 12H21', dots: [[12, 12]] }, // Horizontal Line\n horizontalRay: { d: 'M7 12H21M18.5 9.5L21 12L18.5 14.5', dots: [[7, 12]] }, // Horizontal Ray\n verticalLine: { d: 'M12 3V21', dots: [[12, 12]] }, // Vertical Line\n crossLine: { d: 'M3 12H21M12 3V21', dots: [[12, 12]] }, // Cross Line\n parallelChannel: { d: 'M3 15L15 5M9 19L21 9', dots: [[3, 15], [15, 5], [9, 19]] }, // Parallel Channel\n regressionChannel: { d: 'M3 12L21 4M3 20L21 12', dash: 'M3 16L21 8', dots: [[3, 16], [21, 8]] }, // Regression Channel\n fibRetracement: { d: 'M3 4H21M3 9H21M3 13H21M3 20H21', dots: [[5, 20], [19, 4]] }, // Fib Retracement\n fibExtension: { d: 'M3 20L8 10L12 16M14 4H21M14 8H21M14 12H21', dots: [[3, 20], [8, 10], [12, 16]] }, // Fib Extension\n fibChannel: { d: 'M3 9L21 3M3 13L21 7M3 16L21 10M3 21L21 15', dots: [[3, 21], [21, 15], [3, 9]] }, // Fib Channel\n fibTimeZones: { d: 'M3 4V20M6 4V20M9.5 4V20M14 4V20M20.5 4V20', dots: [[3, 20], [6, 20]] }, // Fib Time Zones\n fibSpeedResistanceFan: { d: 'M4 20L20 4M4 20L20 11M4 20L20 16M4 20L11 4', dash: 'M4 4H20V20', dots: [[4, 20], [20, 4]] }, // Fib Speed Resistance Fan\n rectangle: { d: 'M5.5 6h13A1.5 1.5 0 0 1 20 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 16.5v-9A1.5 1.5 0 0 1 5.5 6z', dots: [[4, 6], [20, 18]] }, // Rectangle\n circle: { d: 'M19.5 12a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0z', dots: [[12, 12], [19.5, 12]] }, // Circle\n ellipse: { d: 'M20.5 12c0 3-3.8 5.5-8.5 5.5S3.5 15 3.5 12 7.3 6.5 12 6.5s8.5 2.5 8.5 5.5z', dots: [[3.5, 12], [20.5, 12]] }, // Ellipse\n triangle: { d: 'M12 4.5L20 19H4z', dots: [[12, 4.5], [20, 19], [4, 19]] }, // Triangle\n pitchfork: { d: 'M4 20L16.75 3M7 9L11.5 3M13 15L21 4.33M7 9L13 15', dots: [[4, 20], [7, 9], [13, 15]] }, // Pitchfork\n schiffPitchfork: { d: 'M4 14.5L21 7.42M7 9L21 3.17M13 15L21 11.67M7 9L13 15', dash: 'M4 20V14.5', dots: [[4, 14.5], [7, 9], [13, 15]] }, // Schiff Pitchfork\n modifiedSchiffPitchfork: { d: 'M5.5 14.5L21 5.89M7 9L17.8 3M13 15L21 10.56M7 9L13 15', dash: 'M4 20L5.5 14.5', dots: [[5.5, 14.5], [7, 9], [13, 15]] }, // Modified Schiff Pitchfork\n gannFan: { d: 'M4 20L20 4M4 20L20 12M4 20L12 4M4 20L20 16.5M4 20L7.5 4', dots: [[4, 20], [20, 4]] }, // Gann Fan\n gannBox: { d: 'M4 4H20V20H4zM4 20L20 4M4 4L20 20M12 4V20', dots: [[4, 20], [20, 4]] }, // Gann Box\n cyclicLines: { d: 'M4 4V20M9 4V20M14 4V20M19 4V20', dots: [[4, 20], [9, 20]] }, // Cyclic Lines\n xabcdPattern: { d: 'M3 18L7 6L11 13L15 8L21 19', dash: 'M3 18L11 13L21 19', dots: [[3, 18], [7, 6], [11, 13], [15, 8], [21, 19]] }, // XABCD Pattern\n abcdPattern: { d: 'M4 19L9 8L13 14L20 4', dots: [[4, 19], [9, 8], [13, 14], [20, 4]] }, // ABCD Pattern\n headAndShoulders: { d: 'M3 19L6 11L8.5 15L12 5L15.5 15L18 11L21 19', dash: 'M4.5 15H19.5', dots: [[6, 11], [12, 5], [18, 11]] }, // Head and Shoulders\n elliottWave: { d: 'M3 19L6 13L8.5 16L14 6L16 10L21 4', dots: [[3, 19], [21, 4]] }, // Elliott Wave\n priceRange: { d: 'M5 4H19M5 20H19M12 6.5V17.5M9 9.5L12 6.5L15 9.5M9 14.5L12 17.5L15 14.5' }, // Price Range\n dateRange: { d: 'M4 5V19M20 5V19M6.5 12H17.5M9.5 9L6.5 12L9.5 15M14.5 9L17.5 12L14.5 15' }, // Date Range\n dateAndPriceRange: { d: 'M6 18V4M3 7L6 4L9 7M6 18H20M17 15L20 18L17 21', dash: 'M6 4H20V18' }, // Date and Price Range\n measure: { d: 'M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9' }, // Measure\n text: { d: 'M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5' }, // Text\n priceLabel: { d: 'M9 5H19a1.5 1.5 0 0 1 1.5 1.5v11A1.5 1.5 0 0 1 19 19H9L3.5 12zM11 12H17' }, // Price Label\n arrow: { d: 'M5 19L19 5M10 5H19V14' }, // Arrow\n riskReward: { d: 'M5 12V4H19V12M3 12H21', dash: 'M5 12V18H19V12', dots: [[5, 12]] }, // Long/Short Position\n anchoredVWAP: { d: 'M4 18C9 17 12 10 20 7M4 20.5V18', dots: [[4, 18]] }, // Anchored VWAP\n volumeProfileRange: { d: 'M6 7H12M6 10.5H17M6 14H15M6 17.5H10', dash: 'M3.5 4V20M20.5 4V20', dots: [[3.5, 20], [20.5, 20]] }, // Fixed Range Volume Profile\n};\n\n/** One per chart type, keyed by chart type. */\nexport const CHART_TYPE_ICONS: Readonly<Record<string, IconDef>> = {\n candlestick: { d: 'M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19', fills: ['M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1z', 'M14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z'] }, // Candlestick\n hollowCandle: { d: 'M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zM14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z' }, // Hollow Candle\n heikinAshi: { d: 'M5.5 9.5V12M5.5 18V20M12 5.5V8M12 14V16M18.5 3V4.5M18.5 10.5V12.5', fills: ['M4 12h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5H4a.5.5 0 0 1-.5-.5v-5A.5.5 0 0 1 4 12z', 'M10.5 8h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-5a.5.5 0 0 1 .5-.5z', 'M17 4.5h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5z'] }, // Heikin-Ashi\n bar: { d: 'M8 4V20M5 8H8M8 16H11M16 6V18M13 15H16M16 9H19' }, // Bar (OHLC)\n volumeCandles: { d: 'M6.5 5V8M6.5 16V19M15.5 3.5V6M15.5 16V20', fills: ['M5.5 8h2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5z', 'M11.5 6h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5z'] }, // Volume Candles\n equivolume: { d: 'M4.5 10h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1zM10 6h5a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zM18.5 4h1a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z' }, // Equivolume\n line: { d: 'M3 17L8 11L12 14L21 5' }, // Line\n area: { d: 'M3 17L8 11L12 14L21 5', soft: 'M3 17L8 11L12 14L21 5V20H3z' }, // Area\n baseline: { d: 'M3 16L7 9L11 14L15 7L21 15', dash: 'M3 12H21' }, // Baseline\n hlcArea: { d: 'M3 9L8 6L13 9L21 4M3 15L8 13L13 16L21 11', dash: 'M3 12L8 9.5L13 12.5L21 7.5', soft: 'M3 9L8 6L13 9L21 4V11L13 16L8 13L3 15z' }, // HLC Area\n stepLine: { d: 'M3 18H8V12H12V15H16V7H21' }, // Step Line\n lineWithMarkers: { d: 'M4 17L9 10L14 14L20 6', dots: [[4, 17], [9, 10], [14, 14], [20, 6]] }, // Line with Markers\n};\n\nconst DOT_RADIUS = 1.75;\nconst SOFT_OPACITY = 0.22;\nconst markupCache = new WeakMap<IconDef, string>();\n\n/** The icon's SVG elements, drawn in `currentColor`. */\nfunction markup(icon: IconDef): string {\n const cached = markupCache.get(icon);\n if (cached) return cached;\n let s = '';\n if (icon.soft) s += `<path d=\"${icon.soft}\" fill=\"currentColor\" fill-opacity=\"${SOFT_OPACITY}\" stroke=\"none\"/>`;\n for (const f of icon.fills ?? []) s += `<path d=\"${f}\" fill=\"currentColor\" stroke=\"none\"/>`;\n if (icon.d) s += `<path d=\"${icon.d}\"/>`;\n if (icon.dash) s += `<path d=\"${icon.dash}\" stroke-dasharray=\"2 2.5\"/>`;\n for (const [cx, cy, r = DOT_RADIUS] of icon.dots ?? []) s += `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"currentColor\" stroke=\"none\"/>`;\n markupCache.set(icon, s);\n return s;\n}\n\n/** The icon as an inline SVG string at `size` px, coloured by `currentColor`. */\nexport function iconSvg(icon: IconDef, size: number): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\">${markup(icon)}</svg>`;\n}\n","import { CHART_TYPE_ICONS, DRAWING_TOOL_ICONS, UI_ICONS, iconSvg, type IconDef } from './iconSet.js';\n\nconst own = (map: Readonly<Record<string, IconDef>>, key: string): IconDef | undefined =>\n Object.prototype.hasOwnProperty.call(map, key) ? map[key] : undefined;\n\n/** An interface icon (toolbar, sidebar, panels) as inline SVG; '' for an unknown name. */\nexport function createIcon(name: string, size = 14): string {\n const icon = own(UI_ICONS, name);\n return icon ? iconSvg(icon, size) : '';\n}\n\n/** A drawing tool's own icon; a pen for a tool without one (e.g. from a plugin). */\nexport function createToolIcon(tool: string, size = 16): string {\n return iconSvg(own(DRAWING_TOOL_ICONS, tool) ?? UI_ICONS.penLine, size);\n}\n\n/** A chart type's icon; the generic chart glyph for a type without one. */\nexport function createChartTypeIcon(type: string, size = 14): string {\n return iconSvg(own(CHART_TYPE_ICONS, type) ?? UI_ICONS.barChart, size);\n}\n","/** Text made safe to put in HTML markup, attribute values included. */\nexport function escapeHtml(text: string): string {\n return text.replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c]!);\n}\n","export class WidgetDropdown {\n private trigger: HTMLElement;\n private panel: HTMLDivElement;\n private _isOpen = false;\n private onOutsideClick: (e: MouseEvent) => void;\n private onEscapeKey: (e: KeyboardEvent) => void;\n private onTriggerClick: () => void;\n\n constructor(trigger: HTMLElement, config: { width?: string; align?: 'left' | 'right' } = {}) {\n this.trigger = trigger;\n\n this.panel = document.createElement('div');\n this.panel.className = 'tcw-dropdown';\n this.panel.style.width = config.width ?? '200px';\n if (config.align === 'right') {\n this.panel.style.right = '0';\n } else {\n this.panel.style.left = '0';\n }\n this.panel.style.display = 'none';\n\n // Position relative to trigger\n trigger.style.position = 'relative';\n trigger.appendChild(this.panel);\n\n this.onTriggerClick = () => {\n if (this._isOpen) {\n this.close();\n } else {\n this.open();\n }\n };\n\n this.onOutsideClick = (e: MouseEvent) => {\n if (!this.trigger.contains(e.target as Node)) {\n this.close();\n }\n };\n\n this.onEscapeKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.close();\n }\n };\n\n trigger.addEventListener('click', this.onTriggerClick);\n }\n\n setContent(html: string): void {\n this.panel.innerHTML = html;\n }\n\n open(): void {\n if (this._isOpen) return;\n this._isOpen = true;\n this.panel.style.display = '';\n document.addEventListener('mousedown', this.onOutsideClick);\n document.addEventListener('keydown', this.onEscapeKey);\n }\n\n close(): void {\n if (!this._isOpen) return;\n this._isOpen = false;\n this.panel.style.display = 'none';\n document.removeEventListener('mousedown', this.onOutsideClick);\n document.removeEventListener('keydown', this.onEscapeKey);\n }\n\n isOpen(): boolean {\n return this._isOpen;\n }\n\n destroy(): void {\n this.trigger.removeEventListener('click', this.onTriggerClick);\n document.removeEventListener('mousedown', this.onOutsideClick);\n document.removeEventListener('keydown', this.onEscapeKey);\n this.panel.remove();\n }\n}\n","import type { ChartType, TimeFrame } from '@tradecanvas/commons';\nimport type { ToolbarConfig, ToolbarCallbacks, WidgetState } from './types.js';\nimport { createChartTypeIcon, createIcon } from './icons.js';\nimport { escapeHtml as esc } from './escapeHtml.js';\nimport { WidgetDropdown } from './WidgetDropdown.js';\nimport type { Translator } from './i18n.js';\n\nexport class WidgetToolbar {\n private config: ToolbarConfig;\n private callbacks: ToolbarCallbacks;\n private t: Translator;\n private el: HTMLDivElement;\n private chartTypeDropdown: WidgetDropdown | null = null;\n private indicatorDropdown: WidgetDropdown | null = null;\n private tfGroup: HTMLDivElement | null = null;\n private tfDropdown: WidgetDropdown | null = null;\n private tfFavorites: TimeFrame[] = [];\n private tfRendered = '';\n private themeBtn: HTMLButtonElement | null = null;\n private fullscreenBtn: HTMLButtonElement | null = null;\n\n constructor(host: HTMLElement, config: ToolbarConfig, callbacks: ToolbarCallbacks, t: Translator) {\n this.config = config;\n this.callbacks = callbacks;\n this.t = t;\n this.el = document.createElement('div');\n this.el.className = 'tcw-toolbar';\n this.build();\n host.appendChild(this.el);\n }\n\n private build(): void {\n const { config, callbacks, el } = this;\n\n // Symbol button\n const symbolBtn = document.createElement('button');\n symbolBtn.className = 'tcw-toolbar-symbol';\n symbolBtn.dataset.role = 'symbol';\n symbolBtn.addEventListener('click', callbacks.onSymbolClick);\n el.appendChild(symbolBtn);\n el.appendChild(this.sep());\n\n // Timeframes: the favourites as buttons (plus the current one if it isn't\n // pinned); the menu lists them all, with a star to pin or unpin.\n this.tfFavorites = [...(config.timeframeFavorites ?? config.timeframes.map((tf) => tf.value))];\n this.tfGroup = document.createElement('div');\n this.tfGroup.className = 'tcw-toolbar-group';\n el.appendChild(this.tfGroup);\n if (callbacks.onToggleTimeframeFavorite && config.timeframes.length > 0) {\n const tfWrap = document.createElement('div');\n tfWrap.style.position = 'relative';\n tfWrap.style.display = 'inline-flex';\n const tfTrigger = document.createElement('button');\n tfTrigger.className = 'tcw-btn tcw-tf-more';\n tfTrigger.dataset.role = 'timeframes';\n tfTrigger.title = this.t('toolbar.timeframes');\n tfTrigger.setAttribute('aria-label', this.t('toolbar.timeframes'));\n tfTrigger.innerHTML = createIcon('chevronDown', 12);\n tfWrap.appendChild(tfTrigger);\n el.appendChild(tfWrap);\n this.tfDropdown = new WidgetDropdown(tfWrap, { width: '150px' });\n this.buildTimeframeMenu();\n }\n el.appendChild(this.sep());\n\n // Chart type dropdown\n const ctWrap = document.createElement('div');\n ctWrap.style.position = 'relative';\n ctWrap.style.display = 'inline-flex';\n\n const ctTrigger = document.createElement('button');\n ctTrigger.className = 'tcw-dropdown-trigger';\n ctTrigger.dataset.role = 'charttype';\n ctWrap.appendChild(ctTrigger);\n el.appendChild(ctWrap);\n\n this.chartTypeDropdown = new WidgetDropdown(ctWrap, { width: '160px' });\n this.buildChartTypeMenu();\n\n el.appendChild(this.sep());\n\n // Indicators dropdown\n const indWrap = document.createElement('div');\n indWrap.style.position = 'relative';\n indWrap.style.display = 'inline-flex';\n\n const indTrigger = document.createElement('button');\n indTrigger.className = 'tcw-dropdown-trigger';\n indTrigger.dataset.role = 'indicators';\n indWrap.appendChild(indTrigger);\n el.appendChild(indWrap);\n\n this.indicatorDropdown = new WidgetDropdown(indWrap, { width: '280px' });\n this.buildIndicatorMenu();\n\n\n // Spacer\n el.appendChild(this.spacer());\n\n // Right side buttons\n if (callbacks.onToggleReplay) {\n const replayBtn = this.iconBtn('play', this.t('toolbar.replay'), callbacks.onToggleReplay);\n replayBtn.dataset.role = 'replay';\n el.appendChild(replayBtn);\n }\n\n if (callbacks.onBracket) {\n const onBracket = callbacks.onBracket;\n const longBtn = this.iconBtn('trendingUp', this.t('toolbar.longBracket'), () => onBracket('buy'));\n longBtn.dataset.role = 'long';\n longBtn.classList.add('tcw-btn-long');\n el.appendChild(longBtn);\n const shortBtn = this.iconBtn('trendingDown', this.t('toolbar.shortBracket'), () => onBracket('sell'));\n shortBtn.dataset.role = 'short';\n shortBtn.classList.add('tcw-btn-short');\n el.appendChild(shortBtn);\n }\n\n if (callbacks.onToggleLadder) {\n const ladderBtn = this.iconBtn('ladder', this.t('toolbar.depthLadder'), callbacks.onToggleLadder);\n ladderBtn.dataset.role = 'ladder';\n el.appendChild(ladderBtn);\n }\n\n if (callbacks.onToggleObjects) {\n const objectsBtn = this.iconBtn('layers', this.t('toolbar.objects'), callbacks.onToggleObjects);\n objectsBtn.dataset.role = 'objects';\n el.appendChild(objectsBtn);\n }\n\n if (callbacks.onToggleAlerts) {\n const alertsBtn = this.iconBtn('bell', this.t('toolbar.priceAlerts'), callbacks.onToggleAlerts);\n alertsBtn.dataset.role = 'alerts';\n el.appendChild(alertsBtn);\n }\n\n const screenshotBtn = this.iconBtn('camera', this.t('toolbar.screenshot'), callbacks.onScreenshot);\n el.appendChild(screenshotBtn);\n\n const settingsBtn = this.iconBtn('settings', this.t('toolbar.settings'), callbacks.onSettings);\n el.appendChild(settingsBtn);\n\n this.themeBtn = this.iconBtn('moon', this.t('toolbar.toggleTheme'), callbacks.onToggleTheme);\n this.themeBtn.dataset.role = 'theme';\n el.appendChild(this.themeBtn);\n\n if (callbacks.onToggleFullscreen) {\n this.fullscreenBtn = this.iconBtn('maximize', this.t('toolbar.fullscreen'), callbacks.onToggleFullscreen);\n this.fullscreenBtn.dataset.role = 'fullscreen';\n this.fullscreenBtn.setAttribute('aria-pressed', 'false');\n el.appendChild(this.fullscreenBtn);\n }\n }\n\n /** Swap the fullscreen button between enter and exit. */\n setFullscreen(on: boolean): void {\n if (!this.fullscreenBtn) return;\n const label = this.t(on ? 'toolbar.exitFullscreen' : 'toolbar.fullscreen');\n this.fullscreenBtn.innerHTML = createIcon(on ? 'minimize' : 'maximize', 14);\n this.fullscreenBtn.title = label;\n this.fullscreenBtn.setAttribute('aria-pressed', String(on));\n }\n\n private chartTypeLabel(ct: { value: ChartType; label: string }): string {\n const key = `chartType.${ct.value}` as const;\n const translated = this.t(key as Parameters<Translator>[0]);\n return translated === key ? ct.label : translated;\n }\n\n private buildChartTypeMenu(): void {\n if (!this.chartTypeDropdown) return;\n const items = this.config.chartTypes.map(ct =>\n `<button class=\"tcw-dropdown-item tcw-dropdown-item--icon\" data-ct=\"${esc(ct.value)}\">${createChartTypeIcon(ct.value, 16)}<span>${esc(this.chartTypeLabel(ct))}</span></button>`\n ).join('');\n this.chartTypeDropdown.setContent(items);\n\n // Attach events to items after content set\n const panel = this.chartTypeDropdown['panel'] as HTMLDivElement;\n panel.querySelectorAll('.tcw-dropdown-item').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const value = (e.currentTarget as HTMLElement).dataset.ct as ChartType;\n this.callbacks.onChartType(value);\n this.chartTypeDropdown?.close();\n });\n });\n }\n\n /** Re-pin after the user starred or unstarred a timeframe. */\n setTimeframeFavorites(favorites: TimeFrame[]): void {\n this.tfFavorites = [...favorites];\n this.tfRendered = '';\n this.buildTimeframeMenu();\n }\n\n private buildTimeframeMenu(): void {\n if (!this.tfDropdown) return;\n const pin = esc(this.t('toolbar.timeframes.pin'));\n let html = `<div class=\"tcw-dropdown-label\">${esc(this.t('toolbar.timeframes'))}</div>`;\n for (const tf of this.config.timeframes) {\n const pinned = this.tfFavorites.includes(tf.value);\n const [value, label] = [esc(tf.value), esc(tf.label)];\n html += `<div class=\"tcw-tf-row\">`\n + `<button class=\"tcw-dropdown-item\" data-tf-pick=\"${value}\">${label}</button>`\n + `<button class=\"tcw-tf-star${pinned ? ' tcw-active' : ''}\" data-tf-star=\"${value}\" aria-pressed=\"${pinned}\"`\n + ` title=\"${pin}\" aria-label=\"${pin}: ${label}\">${createIcon('star', 12)}</button>`\n + `</div>`;\n }\n this.tfDropdown.setContent(html);\n\n const panel = this.tfDropdown['panel'] as HTMLDivElement;\n panel.querySelectorAll<HTMLButtonElement>('[data-tf-pick]').forEach((btn) => {\n btn.addEventListener('click', () => this.callbacks.onTimeframe(btn.dataset.tfPick as TimeFrame));\n });\n panel.querySelectorAll<HTMLButtonElement>('[data-tf-star]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation(); // pinning keeps the menu open\n this.callbacks.onToggleTimeframeFavorite?.(btn.dataset.tfStar as TimeFrame);\n });\n });\n }\n\n private renderTimeframes(current: TimeFrame): void {\n if (!this.tfGroup) return;\n const shown = this.config.timeframes.filter((tf) => this.tfFavorites.includes(tf.value) || tf.value === current);\n const key = `${shown.map((tf) => tf.value).join(',')}|${current}`;\n if (key === this.tfRendered) return;\n this.tfRendered = key;\n\n this.tfGroup.replaceChildren(...shown.map((tf) => {\n const btn = document.createElement('button');\n btn.className = 'tcw-btn';\n btn.textContent = tf.label;\n btn.dataset.tf = tf.value;\n btn.classList.toggle('tcw-active', tf.value === current);\n btn.addEventListener('click', () => this.callbacks.onTimeframe(tf.value));\n return btn;\n }));\n const panel = this.tfDropdown?.['panel'] as HTMLDivElement | undefined;\n panel?.querySelectorAll<HTMLButtonElement>('[data-tf-pick]').forEach((btn) => {\n btn.classList.toggle('tcw-active', btn.dataset.tfPick === current);\n });\n }\n\n private buildIndicatorMenu(): void {\n if (!this.indicatorDropdown) return;\n const { indicators, popularIndicatorIds } = this.config;\n\n const popular = indicators.filter(d => popularIndicatorIds.includes(d.id));\n const other = indicators.filter(d => !popularIndicatorIds.includes(d.id));\n\n const typeLabel = (type: string) => this.t(`indicatorType.${type}` as Parameters<Translator>[0]);\n\n const row = (ind: (typeof indicators)[number]) =>\n `<button class=\"tcw-dropdown-item\" data-ind=\"${esc(ind.id)}\"><span>${esc(ind.name)}</span><span class=\"tcw-tag\">${esc(typeLabel(ind.type))}</span></button>`;\n let html = `<div class=\"tcw-dropdown-label\">${esc(this.t('toolbar.indicators.popular'))}</div>`;\n for (const ind of popular) html += row(ind);\n html += '<div class=\"tcw-dropdown-divider\"></div>';\n html += `<div class=\"tcw-dropdown-label\">${esc(this.t('toolbar.indicators.all'))}</div>`;\n for (const ind of other) html += row(ind);\n\n this.indicatorDropdown.setContent(html);\n\n const panel = this.indicatorDropdown['panel'] as HTMLDivElement;\n panel.querySelectorAll('.tcw-dropdown-item[data-ind]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n const id = (e.currentTarget as HTMLElement).dataset.ind!;\n this.callbacks.onAddIndicator(id);\n });\n });\n }\n\n update(state: WidgetState): void {\n // Symbol\n const symbolBtn = this.el.querySelector('[data-role=\"symbol\"]') as HTMLButtonElement | null;\n if (symbolBtn) symbolBtn.textContent = state.symbol;\n\n // Timeframe buttons\n this.renderTimeframes(state.timeframe);\n\n // Chart type trigger label\n const ctTrigger = this.el.querySelector('[data-role=\"charttype\"]') as HTMLElement | null;\n if (ctTrigger) {\n const ct = this.config.chartTypes.find(ct => ct.value === state.chartType);\n const label = ct ? this.chartTypeLabel(ct) : state.chartType;\n ctTrigger.innerHTML = `${createChartTypeIcon(state.chartType, 14)} ${esc(label)} ${createIcon('chevronDown', 12)}`;\n }\n\n // Indicator trigger + badge\n const indTrigger = this.el.querySelector('[data-role=\"indicators\"]') as HTMLElement | null;\n if (indTrigger) {\n const count = state.activeIndicators.size;\n let inner = `${createIcon('trendingUp', 14)} ${this.t('toolbar.indicators')}`;\n if (count > 0) {\n inner += ` <span class=\"tcw-badge-count\">${count}</span>`;\n }\n indTrigger.innerHTML = inner;\n }\n\n // Theme toggle icon\n if (this.themeBtn) {\n this.themeBtn.innerHTML = state.isDark ? createIcon('moon', 14) : createIcon('sun', 14);\n }\n }\n\n private sep(): HTMLSpanElement {\n const s = document.createElement('span');\n s.className = 'tcw-toolbar-sep';\n return s;\n }\n\n private spacer(): HTMLSpanElement {\n const s = document.createElement('span');\n s.className = 'tcw-toolbar-spacer';\n return s;\n }\n\n private iconBtn(icon: string, title: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button');\n btn.className = 'tcw-btn-icon';\n btn.title = title;\n btn.innerHTML = createIcon(icon, 14);\n btn.addEventListener('click', onClick);\n return btn;\n }\n\n destroy(): void {\n this.chartTypeDropdown?.destroy();\n this.indicatorDropdown?.destroy();\n this.el.remove();\n }\n}\n","import type { DrawingToolType } from '@tradecanvas/commons';\nimport type { SidebarConfig, SidebarCallbacks, WidgetState } from './types.js';\nimport { createIcon, createToolIcon } from './icons.js';\n\n/** Drawing tool icons carry more detail than interface glyphs: a size up. */\nconst TOOL_ICON_PX = 16;\n\n/** How long a tool menu stays after the pointer leaves it. */\nconst FLYOUT_CLOSE_DELAY_MS = 150;\n\n/** Human label for a tool id, sourced from the configured groups. */\nfunction toolLabel(groups: SidebarConfig['drawingToolGroups'], tool: string): string {\n for (const g of groups) {\n const t = g.tools.find((x) => x.value === tool);\n if (t) return t.label;\n }\n return tool;\n}\n\nexport class WidgetDrawingSidebar {\n private config: SidebarConfig;\n private callbacks: SidebarCallbacks;\n private el: HTMLDivElement;\n private groupWraps: HTMLDivElement[] = [];\n private groupButtons: HTMLButtonElement[] = [];\n /** Per group, the icon holder in its button and the tool it stands for (the last one used). */\n private groupIcons: HTMLSpanElement[] = [];\n private groupTools: DrawingToolType[] = [];\n private cursorBtn: HTMLButtonElement | null = null;\n private magnetBtn: HTMLButtonElement | null = null;\n private stayBtn: HTMLButtonElement | null = null;\n private flyoutEl: HTMLDivElement | null = null;\n private flyoutIdx = -1;\n private flyoutHideTimer: ReturnType<typeof setTimeout> | null = null;\n private favoritesEl: HTMLDivElement | null = null;\n private favoritesDivider: HTMLDivElement | null = null;\n private favorites: string[] = [];\n\n constructor(host: HTMLElement, config: SidebarConfig, callbacks: SidebarCallbacks) {\n this.config = config;\n this.callbacks = callbacks;\n this.el = document.createElement('div');\n this.el.className = 'tcw-sidebar';\n this.build();\n host.appendChild(this.el);\n }\n\n private build(): void {\n const { config, callbacks, el } = this;\n\n // Cursor button\n this.cursorBtn = document.createElement('button');\n this.cursorBtn.className = 'tcw-sidebar-btn';\n this.cursorBtn.title = 'Cursor';\n this.cursorBtn.innerHTML = createIcon('cursor', 14);\n this.cursorBtn.addEventListener('click', callbacks.onCancelDrawing);\n el.appendChild(this.cursorBtn);\n\n el.appendChild(this.divider());\n\n // Favorites strip (pinned tools) — only when favorites are enabled.\n if (callbacks.onToggleFavorite) {\n this.favorites = [...(config.favorites ?? [])];\n this.favoritesEl = document.createElement('div');\n this.favoritesEl.className = 'tcw-sidebar-favorites';\n el.appendChild(this.favoritesEl);\n this.favoritesDivider = this.divider();\n el.appendChild(this.favoritesDivider);\n this.renderFavorites();\n }\n\n // Tool groups\n config.drawingToolGroups.forEach((group, idx) => {\n const wrap = document.createElement('div');\n wrap.className = 'tcw-tool-group-wrap';\n\n const btn = document.createElement('button');\n btn.className = 'tcw-sidebar-btn';\n // The group shows, and picks, its last used tool — the first until then.\n const tool = group.tools[0]?.value;\n if (!tool) return;\n // A group with a menu names itself in the menu's header: no tooltip on top of it.\n if (group.tools.length > 1) btn.setAttribute('aria-label', `${group.label}: ${group.tools[0].label}`);\n else btn.title = group.label;\n const icon = document.createElement('span');\n icon.className = 'tcw-sidebar-icon';\n icon.innerHTML = createToolIcon(tool, TOOL_ICON_PX);\n btn.appendChild(icon);\n this.groupIcons.push(icon);\n this.groupTools.push(tool);\n\n if (group.tools.length > 1) {\n const dot = document.createElement('span');\n dot.className = 'tcw-multi-dot';\n btn.appendChild(dot);\n }\n\n btn.addEventListener('click', () => callbacks.onDrawingTool(this.groupTools[idx]));\n wrap.appendChild(btn);\n\n // Flyout events via JS (not CSS hover); keyboard focus opens it too.\n wrap.addEventListener('mouseenter', () => this.showFlyout(idx));\n wrap.addEventListener('mouseleave', () => this.scheduleHideFlyout());\n btn.addEventListener('focus', () => { if (btn.matches(':focus-visible')) this.showFlyout(idx); });\n wrap.addEventListener('focusout', (e) => {\n if (!wrap.contains(e.relatedTarget as Node | null)) this.scheduleHideFlyout();\n });\n\n el.appendChild(wrap);\n this.groupWraps.push(wrap);\n this.groupButtons.push(btn);\n });\n\n // Spacer\n const spacer = document.createElement('div');\n spacer.className = 'tcw-sidebar-spacer';\n el.appendChild(spacer);\n\n el.appendChild(this.divider());\n\n // Bottom tools\n if (callbacks.onToggleStyle) {\n const styleBtn = document.createElement('button');\n styleBtn.className = 'tcw-sidebar-btn';\n styleBtn.title = 'Drawing style & templates';\n styleBtn.dataset.role = 'style';\n styleBtn.innerHTML = createIcon('palette', 14);\n styleBtn.addEventListener('click', callbacks.onToggleStyle);\n el.appendChild(styleBtn);\n }\n\n if (callbacks.onToggleMagnet) {\n this.magnetBtn = document.createElement('button');\n this.magnetBtn.className = 'tcw-sidebar-btn';\n this.magnetBtn.title = 'Magnet';\n this.magnetBtn.innerHTML = createIcon('magnet', 14);\n this.magnetBtn.addEventListener('click', callbacks.onToggleMagnet);\n el.appendChild(this.magnetBtn);\n }\n\n if (callbacks.onToggleStayInDrawing) {\n this.stayBtn = document.createElement('button');\n this.stayBtn.className = 'tcw-sidebar-btn';\n this.stayBtn.dataset.role = 'stay';\n this.stayBtn.title = 'Stay in drawing mode';\n this.stayBtn.setAttribute('aria-pressed', 'false');\n this.stayBtn.innerHTML = createIcon('repeat', 14);\n this.stayBtn.addEventListener('click', callbacks.onToggleStayInDrawing);\n el.appendChild(this.stayBtn);\n }\n\n const undoBtn = document.createElement('button');\n undoBtn.className = 'tcw-sidebar-btn';\n undoBtn.title = 'Undo';\n undoBtn.innerHTML = createIcon('undo', 14);\n undoBtn.addEventListener('click', callbacks.onUndo);\n el.appendChild(undoBtn);\n\n const redoBtn = document.createElement('button');\n redoBtn.className = 'tcw-sidebar-btn';\n redoBtn.title = 'Redo';\n redoBtn.innerHTML = createIcon('redo', 14);\n redoBtn.addEventListener('click', callbacks.onRedo);\n el.appendChild(redoBtn);\n\n const clearBtn = document.createElement('button');\n clearBtn.className = 'tcw-sidebar-btn tcw-danger';\n clearBtn.title = 'Clear all';\n clearBtn.innerHTML = createIcon('trash', 14);\n clearBtn.addEventListener('click', callbacks.onClearDrawings);\n el.appendChild(clearBtn);\n }\n\n /** Update the pinned-tools strip. */\n setFavorites(favorites: string[]): void {\n this.favorites = [...favorites];\n this.renderFavorites();\n }\n\n private renderFavorites(): void {\n if (!this.favoritesEl) return;\n this.favoritesEl.replaceChildren();\n const visible = this.favorites.length > 0;\n this.favoritesEl.style.display = visible ? '' : 'none';\n if (this.favoritesDivider) this.favoritesDivider.style.display = visible ? '' : 'none';\n\n for (const tool of this.favorites) {\n const btn = document.createElement('button');\n btn.className = 'tcw-sidebar-btn';\n btn.title = `${toolLabel(this.config.drawingToolGroups, tool)} (right-click to unpin)`;\n btn.dataset.toolValue = tool;\n btn.innerHTML = createToolIcon(tool, TOOL_ICON_PX);\n btn.addEventListener('click', () => this.callbacks.onDrawingTool(tool as never));\n btn.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n this.callbacks.onToggleFavorite?.(tool as never);\n });\n this.favoritesEl.appendChild(btn);\n }\n }\n\n private showFlyout(idx: number): void {\n this.cancelHideFlyout();\n if (this.flyoutEl && this.flyoutIdx === idx) return; // back before it closed: keep it\n const group = this.config.drawingToolGroups[idx];\n if (!group || group.tools.length <= 1) {\n this.hideFlyout();\n return;\n }\n\n this.hideFlyout();\n\n const flyout = document.createElement('div');\n flyout.className = 'tcw-flyout';\n\n const header = document.createElement('div');\n header.className = 'tcw-flyout-header';\n header.textContent = group.label;\n flyout.appendChild(header);\n\n for (const tool of group.tools) {\n const item = document.createElement('button');\n item.className = 'tcw-flyout-item';\n item.innerHTML = createToolIcon(tool.value, TOOL_ICON_PX);\n const name = document.createElement('span');\n name.textContent = tool.label;\n item.appendChild(name);\n item.dataset.toolValue = tool.value;\n item.addEventListener('click', () => {\n this.callbacks.onDrawingTool(tool.value);\n this.hideFlyout();\n });\n if (this.callbacks.onToggleFavorite) {\n if (this.favorites.includes(tool.value)) item.classList.add('tcw-flyout-faved');\n item.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n this.callbacks.onToggleFavorite?.(tool.value);\n });\n }\n flyout.appendChild(item);\n }\n if (this.callbacks.onToggleFavorite) {\n // Said once for the menu rather than as a tooltip on every row.\n const hint = document.createElement('div');\n hint.className = 'tcw-flyout-hint';\n hint.textContent = 'Right-click a tool to pin it';\n flyout.appendChild(hint);\n }\n\n this.flyoutEl = flyout;\n this.flyoutIdx = idx;\n this.groupWraps[idx].appendChild(flyout);\n }\n\n /**\n * Close a moment after the pointer leaves, so one that slips off the menu\n * on its way to an item (a diagonal move) doesn't lose it.\n */\n private scheduleHideFlyout(): void {\n this.cancelHideFlyout();\n this.flyoutHideTimer = setTimeout(() => {\n this.flyoutHideTimer = null;\n this.hideFlyout();\n }, FLYOUT_CLOSE_DELAY_MS);\n }\n\n private cancelHideFlyout(): void {\n if (this.flyoutHideTimer === null) return;\n clearTimeout(this.flyoutHideTimer);\n this.flyoutHideTimer = null;\n }\n\n private hideFlyout(): void {\n this.cancelHideFlyout();\n if (this.flyoutEl) {\n this.flyoutEl.remove();\n this.flyoutEl = null;\n }\n this.flyoutIdx = -1;\n }\n\n update(state: WidgetState): void {\n // Cursor active\n if (this.cursorBtn) {\n this.cursorBtn.classList.toggle('tcw-active', state.activeTool === null);\n }\n\n // Group buttons: the active group lights up and takes on the picked tool's icon.\n const { drawingToolGroups } = this.config;\n for (let i = 0; i < drawingToolGroups.length; i++) {\n const isActive = drawingToolGroups[i].tools.some(t => t.value === state.activeTool);\n this.groupButtons[i].classList.toggle('tcw-active', isActive);\n if (isActive && state.activeTool && state.activeTool !== this.groupTools[i]) {\n this.groupTools[i] = state.activeTool;\n this.groupIcons[i].innerHTML = createToolIcon(state.activeTool, TOOL_ICON_PX);\n if (drawingToolGroups[i].tools.length > 1) {\n this.groupButtons[i].setAttribute('aria-label', `${drawingToolGroups[i].label}: ${toolLabel(drawingToolGroups, state.activeTool)}`);\n }\n }\n }\n\n // Flyout items\n if (this.flyoutEl) {\n this.flyoutEl.querySelectorAll('.tcw-flyout-item').forEach((item) => {\n const el = item as HTMLElement;\n el.classList.toggle('tcw-active', el.dataset.toolValue === state.activeTool);\n });\n }\n\n // Magnet\n if (this.magnetBtn) {\n this.magnetBtn.classList.toggle('tcw-active', state.magnetEnabled);\n this.magnetBtn.title = state.magnetEnabled ? 'Magnet ON' : 'Magnet OFF';\n }\n\n if (this.stayBtn) {\n this.stayBtn.classList.toggle('tcw-active', state.stayInDrawing);\n this.stayBtn.setAttribute('aria-pressed', String(state.stayInDrawing));\n }\n }\n\n private divider(): HTMLDivElement {\n const d = document.createElement('div');\n d.className = 'tcw-sidebar-divider';\n return d;\n }\n\n destroy(): void {\n this.hideFlyout();\n this.el.remove();\n }\n}\n","import type { ChartSettingsState, SettingsCallbacks } from './types.js';\nimport { createIcon } from './icons.js';\nimport type { Translator } from './i18n.js';\n\ntype Tab = 'style' | 'display' | 'scale';\nconst TABS: Tab[] = ['style', 'display', 'scale'];\n\nexport class WidgetSettings {\n private callbacks: SettingsCallbacks;\n private t: Translator;\n private backdrop: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private currentTab: Tab = 'style';\n private currentSettings: ChartSettingsState | null = null;\n private bodyEl: HTMLDivElement | null = null;\n private tabButtons: HTMLButtonElement[] = [];\n\n /**\n * `barCountdown` / `logScale` false leave out the controls for features the\n * chart has switched off.\n */\n constructor(\n callbacks: SettingsCallbacks,\n t: Translator,\n private readonly available: { barCountdown?: boolean; logScale?: boolean } = {},\n /** Where the panel mounts (the widget's portal: themed, and inside it when fullscreen). */\n private readonly host: () => HTMLElement = () => document.body,\n ) {\n this.callbacks = callbacks;\n this.t = t;\n }\n\n open(currentSettings: ChartSettingsState): void {\n this.currentSettings = { ...currentSettings };\n this.currentTab = 'style';\n this.buildModal();\n }\n\n close(): void {\n this.backdrop?.remove();\n this.modal?.remove();\n this.backdrop = null;\n this.modal = null;\n this.bodyEl = null;\n this.tabButtons = [];\n }\n\n private buildModal(): void {\n // Backdrop\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.addEventListener('click', () => {\n this.callbacks.onClose();\n this.close();\n });\n this.host().appendChild(this.backdrop);\n\n // Modal\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-modal';\n\n // Header\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n const h3 = document.createElement('h3');\n h3.textContent = this.t('settings.title');\n header.appendChild(h3);\n const closeBtn = document.createElement('button');\n closeBtn.className = 'tcw-modal-close';\n closeBtn.innerHTML = createIcon('x', 16);\n closeBtn.addEventListener('click', () => {\n this.callbacks.onClose();\n this.close();\n });\n header.appendChild(closeBtn);\n this.modal.appendChild(header);\n\n // Tabs\n const tabsEl = document.createElement('div');\n tabsEl.className = 'tcw-modal-tabs';\n this.tabButtons = [];\n for (const tab of TABS) {\n const btn = document.createElement('button');\n btn.className = 'tcw-modal-tab';\n btn.textContent = this.t(`settings.tab.${tab}` as Parameters<Translator>[0]);\n btn.dataset.tab = tab;\n if (tab === this.currentTab) btn.classList.add('tcw-active');\n btn.addEventListener('click', () => {\n this.currentTab = tab;\n this.tabButtons.forEach(b => b.classList.toggle('tcw-active', b.dataset.tab === tab));\n this.renderTabContent();\n });\n tabsEl.appendChild(btn);\n this.tabButtons.push(btn);\n }\n this.modal.appendChild(tabsEl);\n\n // Body\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'tcw-modal-body';\n this.modal.appendChild(this.bodyEl);\n this.renderTabContent();\n\n // Footer\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n const resetBtn = document.createElement('button');\n resetBtn.className = 'tcw-reset-link';\n resetBtn.textContent = this.t('settings.resetToDefaults');\n resetBtn.addEventListener('click', () => this.callbacks.onReset());\n footer.appendChild(resetBtn);\n const doneBtn = document.createElement('button');\n doneBtn.className = 'tcw-done-btn';\n doneBtn.textContent = this.t('settings.done');\n doneBtn.addEventListener('click', () => {\n this.callbacks.onClose();\n this.close();\n });\n footer.appendChild(doneBtn);\n this.modal.appendChild(footer);\n\n this.host().appendChild(this.modal);\n\n // Escape key\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n document.removeEventListener('keydown', onKeyDown);\n this.callbacks.onClose();\n this.close();\n }\n };\n document.addEventListener('keydown', onKeyDown);\n }\n\n private renderTabContent(): void {\n if (!this.bodyEl || !this.currentSettings) return;\n this.bodyEl.innerHTML = '';\n\n switch (this.currentTab) {\n case 'style':\n this.renderStyleTab();\n break;\n case 'display':\n this.renderDisplayTab();\n break;\n case 'scale':\n this.renderScaleTab();\n break;\n }\n }\n\n private renderStyleTab(): void {\n if (!this.bodyEl || !this.currentSettings) return;\n const s = this.currentSettings;\n\n // Candle Colors\n const candleSection = this.section(this.t('settings.section.candleColors'));\n candleSection.appendChild(this.colorRow('Up Body', s.candleUpColor, (v) => this.patch({ candleUpColor: v })));\n candleSection.appendChild(this.colorRow('Down Body', s.candleDownColor, (v) => this.patch({ candleDownColor: v })));\n candleSection.appendChild(this.colorRow('Up Wick', s.candleUpWick, (v) => this.patch({ candleUpWick: v })));\n candleSection.appendChild(this.colorRow('Down Wick', s.candleDownWick, (v) => this.patch({ candleDownWick: v })));\n this.bodyEl.appendChild(candleSection);\n\n // Background\n const bgSection = this.section(this.t('settings.section.background'));\n bgSection.appendChild(this.colorRow('Background', s.backgroundColor, (v) => this.patch({ backgroundColor: v })));\n bgSection.appendChild(this.colorRow('Grid', s.gridColor, (v) => this.patch({ gridColor: v })));\n this.bodyEl.appendChild(bgSection);\n }\n\n private renderDisplayTab(): void {\n if (!this.bodyEl || !this.currentSettings) return;\n const s = this.currentSettings;\n\n const section = this.section();\n section.appendChild(this.toggleRow('Grid Lines', s.gridVisible, (v) => this.patch({ gridVisible: v })));\n section.appendChild(this.toggleRow('Volume', s.volumeVisible, (v) => this.patch({ volumeVisible: v })));\n section.appendChild(this.toggleRow('Volume Profile', s.volumeProfileVisible, (v) => this.patch({ volumeProfileVisible: v })));\n section.appendChild(this.toggleRow('Market Profile (TPO)', s.marketProfileVisible, (v) => this.patch({ marketProfileVisible: v })));\n section.appendChild(this.toggleRow('MP split by session', s.marketProfileSplit, (v) => this.patch({ marketProfileSplit: v })));\n section.appendChild(this.toggleRow('MP letters (TPO)', s.marketProfileLetters, (v) => this.patch({ marketProfileLetters: v })));\n section.appendChild(this.rangeRow('MP buckets', s.marketProfileBuckets, 8, 200, 1, (v) => this.patch({ marketProfileBuckets: v })));\n section.appendChild(this.rangeRow('MP opacity', s.marketProfileOpacity, 0.05, 1, 0.05, (v) => this.patch({ marketProfileOpacity: v }), (v) => `${Math.round(v * 100)}%`));\n section.appendChild(this.toggleRow('Liquidity heatmap', s.depthHeatmapVisible, (v) => this.patch({ depthHeatmapVisible: v })));\n section.appendChild(this.rangeRow('Heatmap opacity', s.depthHeatmapOpacity, 0.1, 1, 0.05, (v) => this.patch({ depthHeatmapOpacity: v }), (v) => `${Math.round(v * 100)}%`));\n section.appendChild(this.toggleRow('Swing markers', s.pivotMarkersVisible, (v) => this.patch({ pivotMarkersVisible: v })));\n section.appendChild(this.rangeRow('Swing strength', s.pivotStrength, 2, 20, 1, (v) => this.patch({ pivotStrength: v })));\n section.appendChild(this.toggleRow('Swing structure (HH/HL)', s.pivotStructureLabels, (v) => this.patch({ pivotStructureLabels: v })));\n section.appendChild(this.toggleRow('Session shading (RTH)', s.sessionShadingVisible, (v) => this.patch({ sessionShadingVisible: v })));\n section.appendChild(this.toggleRow('Prior-period levels', s.periodLevelsVisible, (v) => this.patch({ periodLevelsVisible: v })));\n section.appendChild(this.selectRow('Period levels basis', s.periodLevelsPeriod, [\n { value: 'day', label: 'Prior Day (PDH/PDL)' },\n { value: 'week', label: 'Prior Week (PWH/PWL)' },\n ], (v) => this.patch({ periodLevelsPeriod: v as ChartSettingsState['periodLevelsPeriod'] })));\n section.appendChild(this.toggleRow('OHLC Legend', s.legendVisible, (v) => this.patch({ legendVisible: v })));\n if (this.available.barCountdown !== false) {\n section.appendChild(this.toggleRow('Bar Countdown', s.barCountdown, (v) => this.patch({ barCountdown: v })));\n }\n\n // Crosshair mode\n section.appendChild(this.selectRow('Crosshair Mode', s.crosshairMode, [\n { label: 'Magnet', value: 'magnet' },\n { label: 'Normal', value: 'normal' },\n { label: 'Hidden', value: 'hidden' },\n ], (v) => this.patch({ crosshairMode: v as ChartSettingsState['crosshairMode'] })));\n\n // Number locale\n section.appendChild(this.selectRow('Timezone', s.timezone, [\n { value: 'local', label: 'Local' },\n { value: '0', label: 'UTC / London' },\n { value: '-300', label: 'New York (UTC-5)' },\n { value: '-360', label: 'Chicago (UTC-6)' },\n { value: '60', label: 'Frankfurt (UTC+1)' },\n { value: '480', label: 'Singapore/HK (UTC+8)' },\n { value: '540', label: 'Tokyo (UTC+9)' },\n { value: '330', label: 'Mumbai (UTC+5:30)' },\n ], (v) => this.patch({ timezone: v })));\n section.appendChild(this.selectRow('Number Locale', s.numberLocale, [\n { label: 'en-US (65,234.00)', value: 'en-US' },\n { label: 'de-DE (65.234,00)', value: 'de-DE' },\n { label: 'fr-FR (65 234,00)', value: 'fr-FR' },\n { label: 'vi-VN (65.234,00)', value: 'vi-VN' },\n { label: 'en-IN (65,234.00)', value: 'en-IN' },\n { label: 'ja-JP (65,234.00)', value: 'ja-JP' },\n ], (v) => this.patch({ numberLocale: v })));\n\n this.bodyEl.appendChild(section);\n }\n\n private renderScaleTab(): void {\n if (!this.bodyEl || !this.currentSettings) return;\n const s = this.currentSettings;\n\n const section = this.section();\n section.appendChild(this.toggleRow('Auto Scale', s.autoScale, (v) => this.patch({ autoScale: v })));\n section.appendChild(this.toggleRow('Invert Scale (Alt+I)', s.invertScale, (v) => this.patch({ invertScale: v })));\n const scales = [\n { value: 'regular', label: 'Regular' },\n { value: 'logarithmic', label: 'Logarithmic' },\n { value: 'percentage', label: 'Percentage' },\n { value: 'indexedTo100', label: 'Indexed to 100' },\n ].filter((o) => o.value !== 'logarithmic' || this.available.logScale !== false);\n section.appendChild(this.selectRow('Price Scale', s.scaleMode, scales,\n (v) => this.patch({ scaleMode: v as ChartSettingsState['scaleMode'] })));\n this.bodyEl.appendChild(section);\n }\n\n private patch(partial: Partial<ChartSettingsState>): void {\n if (this.currentSettings) {\n Object.assign(this.currentSettings, partial);\n }\n this.callbacks.onChange(partial);\n }\n\n private section(title?: string): HTMLDivElement {\n const div = document.createElement('div');\n div.className = 'tcw-settings-section';\n if (title) {\n const t = document.createElement('div');\n t.className = 'tcw-settings-section-title';\n t.textContent = title;\n div.appendChild(t);\n }\n return div;\n }\n\n private colorRow(label: string, value: string, onChange: (v: string) => void): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n\n const lbl = document.createElement('span');\n lbl.className = 'tcw-settings-label';\n lbl.textContent = label;\n row.appendChild(lbl);\n\n const wrap = document.createElement('div');\n wrap.className = 'tcw-color-picker-wrap';\n\n const input = document.createElement('input');\n input.type = 'color';\n input.value = value;\n\n const hex = document.createElement('span');\n hex.className = 'tcw-color-hex';\n hex.textContent = value;\n\n input.addEventListener('input', () => {\n hex.textContent = input.value;\n onChange(input.value);\n });\n\n wrap.appendChild(input);\n wrap.appendChild(hex);\n row.appendChild(wrap);\n return row;\n }\n\n private toggleRow(label: string, value: boolean, onChange: (v: boolean) => void): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n\n const lbl = document.createElement('span');\n lbl.className = 'tcw-settings-label';\n lbl.textContent = label;\n row.appendChild(lbl);\n\n const toggle = document.createElement('button');\n toggle.className = `tcw-toggle${value ? ' tcw-on' : ''}`;\n toggle.addEventListener('click', () => {\n const newVal = !toggle.classList.contains('tcw-on');\n toggle.classList.toggle('tcw-on', newVal);\n onChange(newVal);\n });\n row.appendChild(toggle);\n return row;\n }\n\n private selectRow(\n label: string,\n value: string,\n options: { label: string; value: string }[],\n onChange: (v: string) => void,\n ): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n\n const lbl = document.createElement('span');\n lbl.className = 'tcw-settings-label';\n lbl.textContent = label;\n row.appendChild(lbl);\n\n const select = document.createElement('select');\n select.className = 'tcw-settings-select';\n for (const opt of options) {\n const o = document.createElement('option');\n o.value = opt.value;\n o.textContent = opt.label;\n if (opt.value === value) o.selected = true;\n select.appendChild(o);\n }\n select.addEventListener('change', () => onChange(select.value));\n row.appendChild(select);\n return row;\n }\n\n private rangeRow(\n label: string,\n value: number,\n min: number,\n max: number,\n step: number,\n onChange: (v: number) => void,\n format: (v: number) => string = (v) => String(v),\n ): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n\n const lbl = document.createElement('span');\n lbl.className = 'tcw-settings-label';\n lbl.textContent = label;\n row.appendChild(lbl);\n\n const wrap = document.createElement('div');\n wrap.className = 'tcw-settings-range';\n\n const input = document.createElement('input');\n input.type = 'range';\n input.min = String(min);\n input.max = String(max);\n input.step = String(step);\n input.value = String(value);\n\n const out = document.createElement('span');\n out.className = 'tcw-settings-range-val';\n out.textContent = format(value);\n\n input.addEventListener('input', () => {\n const v = Number(input.value);\n out.textContent = format(v);\n onChange(v);\n });\n\n wrap.appendChild(input);\n wrap.appendChild(out);\n row.appendChild(wrap);\n return row;\n }\n\n destroy(): void {\n this.close();\n }\n}\n","import type { RangePreset } from '@tradecanvas/core';\nimport { createIcon } from './icons.js';\n\nexport interface StatusBarRange {\n presets: readonly RangePreset[];\n /** Button text per preset; the preset itself when missing. */\n presetLabels?: Partial<Record<RangePreset, string>>;\n groupLabel: string;\n goToLabel: string;\n onPreset: (preset: RangePreset) => void;\n onGoTo: () => void;\n}\n\n/**\n * Bottom bar: range presets and \"go to date\" on the left (when `range` is\n * given), connection state and symbol on the right.\n */\nexport class WidgetStatusBar {\n private el: HTMLDivElement;\n private dotEl: HTMLSpanElement;\n private messageEl: HTMLSpanElement;\n private infoEl: HTMLSpanElement;\n\n constructor(host: HTMLElement, range?: StatusBarRange) {\n this.el = document.createElement('div');\n this.el.className = 'tcw-statusbar';\n\n if (range) this.el.appendChild(this.buildRange(range));\n\n const right = document.createElement('div');\n right.className = 'tcw-status-right';\n\n const indicator = document.createElement('div');\n indicator.className = 'tcw-status-indicator';\n\n this.dotEl = document.createElement('span');\n this.dotEl.className = 'tcw-status-dot';\n indicator.appendChild(this.dotEl);\n\n this.messageEl = document.createElement('span');\n indicator.appendChild(this.messageEl);\n\n right.appendChild(indicator);\n\n this.infoEl = document.createElement('span');\n this.infoEl.className = 'tcw-status-info';\n right.appendChild(this.infoEl);\n\n this.el.appendChild(right);\n host.appendChild(this.el);\n }\n\n update(state: { connectionState: string; message: string; symbol: string; timeframe: string }): void {\n this.dotEl.className = 'tcw-status-dot';\n if (state.connectionState === 'connected') {\n this.dotEl.classList.add('tcw-connected');\n } else if (state.connectionState === 'error') {\n this.dotEl.classList.add('tcw-error');\n }\n\n this.messageEl.textContent = state.message;\n this.infoEl.textContent = `${state.symbol} ${state.timeframe}`;\n }\n\n destroy(): void {\n this.el.remove();\n }\n\n private buildRange(range: StatusBarRange): HTMLDivElement {\n const group = document.createElement('div');\n group.className = 'tcw-range-bar';\n group.setAttribute('role', 'group');\n group.setAttribute('aria-label', range.groupLabel);\n\n for (const preset of range.presets) {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tcw-range-btn';\n btn.dataset.range = preset;\n btn.textContent = range.presetLabels?.[preset] ?? preset;\n btn.addEventListener('click', () => range.onPreset(preset));\n group.appendChild(btn);\n }\n\n const goTo = document.createElement('button');\n goTo.type = 'button';\n goTo.className = 'tcw-range-btn tcw-range-goto';\n goTo.dataset.role = 'goto';\n goTo.title = `${range.goToLabel} (Alt+G)`;\n goTo.setAttribute('aria-label', range.goToLabel);\n goTo.innerHTML = createIcon('calendar', 13);\n goTo.addEventListener('click', range.onGoTo);\n group.appendChild(goTo);\n return group;\n }\n}\n","import type { ChartType, DrawingToolType, TimeFrame } from '@tradecanvas/commons';\n\nexport interface CommandItem {\n id: string;\n label: string;\n category: 'indicator' | 'chartType' | 'drawing' | 'timeframe' | 'action';\n shortcut?: string;\n active?: boolean;\n}\n\nexport interface CommandPaletteCallbacks {\n onIndicator: (id: string) => void;\n onChartType: (type: ChartType) => void;\n onDrawingTool: (tool: DrawingToolType) => void;\n onTimeframe: (tf: TimeFrame) => void;\n onAction: (id: string) => void;\n onClose: () => void;\n}\n\nexport class WidgetCommandPalette {\n private backdrop: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private list: HTMLDivElement | null = null;\n private items: CommandItem[] = [];\n private filtered: CommandItem[] = [];\n private selectedIndex = 0;\n private callbacks: CommandPaletteCallbacks;\n private boundKeydown: (e: KeyboardEvent) => void;\n\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\n constructor(\n callbacks: CommandPaletteCallbacks,\n private readonly host: () => HTMLElement = () => document.body,\n ) {\n this.callbacks = callbacks;\n this.boundKeydown = this.handleKeydown.bind(this);\n }\n\n open(items: CommandItem[]): void {\n if (this.backdrop) return;\n this.items = items;\n this.filtered = items;\n this.selectedIndex = 0;\n\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.addEventListener('click', () => this.close());\n\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-cmd-palette';\n\n const header = document.createElement('div');\n header.className = 'tcw-cmd-header';\n\n const searchIcon = document.createElement('span');\n searchIcon.className = 'tcw-cmd-icon';\n searchIcon.textContent = '⌕';\n header.appendChild(searchIcon);\n\n this.input = document.createElement('input');\n this.input.className = 'tcw-cmd-input';\n this.input.type = 'text';\n this.input.placeholder = 'Search indicators, chart types, tools...';\n this.input.addEventListener('input', () => this.filter());\n header.appendChild(this.input);\n\n const hint = document.createElement('span');\n hint.className = 'tcw-cmd-hint';\n hint.textContent = 'ESC';\n header.appendChild(hint);\n\n this.modal.appendChild(header);\n\n this.list = document.createElement('div');\n this.list.className = 'tcw-cmd-list';\n this.modal.appendChild(this.list);\n\n const footer = document.createElement('div');\n footer.className = 'tcw-cmd-footer';\n footer.innerHTML = '<span>↑↓ Navigate</span><span>⏎ Select</span><span>Esc Close</span>';\n this.modal.appendChild(footer);\n\n this.host().append(this.backdrop, this.modal);\n\n this.renderList();\n this.input.focus();\n document.addEventListener('keydown', this.boundKeydown);\n }\n\n close(): void {\n document.removeEventListener('keydown', this.boundKeydown);\n this.backdrop?.remove();\n this.modal?.remove();\n this.backdrop = null;\n this.modal = null;\n this.input = null;\n this.list = null;\n this.callbacks.onClose();\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n private filter(): void {\n const query = this.input?.value.toLowerCase().trim() ?? '';\n if (!query) {\n this.filtered = this.items;\n } else {\n this.filtered = this.items.filter(item =>\n item.label.toLowerCase().includes(query) ||\n item.category.toLowerCase().includes(query) ||\n item.id.toLowerCase().includes(query),\n );\n }\n this.selectedIndex = 0;\n this.renderList();\n }\n\n private renderList(): void {\n if (!this.list) return;\n this.list.innerHTML = '';\n\n if (this.filtered.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'tcw-cmd-empty';\n empty.textContent = 'No results found';\n this.list.appendChild(empty);\n return;\n }\n\n let currentCategory = '';\n for (let i = 0; i < this.filtered.length; i++) {\n const item = this.filtered[i];\n\n if (item.category !== currentCategory) {\n currentCategory = item.category;\n const label = document.createElement('div');\n label.className = 'tcw-cmd-category';\n label.textContent = this.categoryLabel(currentCategory);\n this.list.appendChild(label);\n }\n\n const row = document.createElement('button');\n row.className = 'tcw-cmd-item';\n if (i === this.selectedIndex) row.classList.add('tcw-selected');\n if (item.active) row.classList.add('tcw-active');\n row.dataset.index = String(i);\n\n const nameSpan = document.createElement('span');\n nameSpan.className = 'tcw-cmd-item-label';\n nameSpan.textContent = item.label;\n row.appendChild(nameSpan);\n\n if (item.active) {\n const check = document.createElement('span');\n check.className = 'tcw-cmd-check';\n check.textContent = '✓';\n row.appendChild(check);\n }\n\n if (item.shortcut) {\n const kbd = document.createElement('kbd');\n kbd.className = 'tcw-cmd-kbd';\n kbd.textContent = item.shortcut;\n row.appendChild(kbd);\n }\n\n row.addEventListener('click', () => this.select(i));\n row.addEventListener('mouseenter', () => {\n this.selectedIndex = i;\n this.updateSelection();\n });\n\n this.list.appendChild(row);\n }\n }\n\n private updateSelection(): void {\n if (!this.list) return;\n const items = this.list.querySelectorAll('.tcw-cmd-item');\n items.forEach((el, i) => {\n el.classList.toggle('tcw-selected', i === this.selectedIndex);\n });\n items[this.selectedIndex]?.scrollIntoView({ block: 'nearest' });\n }\n\n private select(index: number): void {\n const item = this.filtered[index];\n if (!item) return;\n\n switch (item.category) {\n case 'indicator':\n this.callbacks.onIndicator(item.id);\n break;\n case 'chartType':\n this.callbacks.onChartType(item.id as ChartType);\n break;\n case 'drawing':\n this.callbacks.onDrawingTool(item.id as DrawingToolType);\n break;\n case 'timeframe':\n this.callbacks.onTimeframe(item.id as TimeFrame);\n break;\n case 'action':\n this.callbacks.onAction(item.id);\n break;\n }\n this.close();\n }\n\n private handleKeydown(e: KeyboardEvent): void {\n switch (e.key) {\n case 'Escape':\n e.preventDefault();\n this.close();\n break;\n case 'ArrowDown':\n e.preventDefault();\n if (this.filtered.length > 0) {\n this.selectedIndex = (this.selectedIndex + 1) % this.filtered.length;\n this.updateSelection();\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (this.filtered.length > 0) {\n this.selectedIndex = (this.selectedIndex - 1 + this.filtered.length) % this.filtered.length;\n this.updateSelection();\n }\n break;\n case 'Enter':\n e.preventDefault();\n this.select(this.selectedIndex);\n break;\n }\n }\n\n private categoryLabel(cat: string): string {\n switch (cat) {\n case 'indicator': return 'Indicators';\n case 'chartType': return 'Chart Types';\n case 'drawing': return 'Drawing Tools';\n case 'timeframe': return 'Timeframes';\n case 'action': return 'Actions';\n default: return cat;\n }\n }\n\n destroy(): void {\n this.close();\n }\n}\n","import { escapeHtml } from './escapeHtml.js';\n/**\n * Lightweight fuzzy symbol picker. Reuses the command-palette CSS for visual\n * consistency. Scoring is a cheap subsequence match — good enough for symbol\n * lists in the low thousands without pulling in a fuzzy-search dependency.\n */\nexport interface SymbolSearchCallbacks {\n onPick: (symbol: string) => void;\n onClose: () => void;\n}\n\ninterface ScoredSymbol {\n symbol: string;\n score: number;\n}\n\nexport class WidgetSymbolSearch {\n private backdrop: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private list: HTMLDivElement | null = null;\n private symbols: string[] = [];\n private current: string = '';\n private filtered: ScoredSymbol[] = [];\n private selectedIndex = 0;\n private callbacks: SymbolSearchCallbacks;\n private boundKeydown: (e: KeyboardEvent) => void;\n /** One-shot pick override — when set, this open() routes picks here instead. */\n private pickOverride: ((symbol: string) => void) | null = null;\n\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\n constructor(\n callbacks: SymbolSearchCallbacks,\n private readonly host: () => HTMLElement = () => document.body,\n ) {\n this.callbacks = callbacks;\n this.boundKeydown = this.handleKeydown.bind(this);\n }\n\n open(symbols: string[], current: string, onPick?: (symbol: string) => void): void {\n if (this.backdrop) return;\n this.pickOverride = onPick ?? null;\n this.symbols = symbols;\n this.current = current;\n this.filtered = symbols.map(s => ({ symbol: s, score: 0 }));\n this.selectedIndex = Math.max(0, symbols.indexOf(current));\n\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.addEventListener('click', () => this.close());\n\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-cmd-palette';\n\n const header = document.createElement('div');\n header.className = 'tcw-cmd-header';\n\n const icon = document.createElement('span');\n icon.className = 'tcw-cmd-icon';\n icon.innerHTML = svgSearch();\n header.appendChild(icon);\n\n this.input = document.createElement('input');\n this.input.className = 'tcw-cmd-input';\n this.input.type = 'text';\n this.input.placeholder = 'Search symbol… (e.g. BTC, ETH, AAPL)';\n this.input.autocomplete = 'off';\n this.input.spellcheck = false;\n this.input.addEventListener('input', () => this.filter());\n header.appendChild(this.input);\n\n const hint = document.createElement('span');\n hint.className = 'tcw-cmd-hint';\n hint.textContent = 'ESC';\n header.appendChild(hint);\n\n this.modal.appendChild(header);\n\n this.list = document.createElement('div');\n this.list.className = 'tcw-cmd-list';\n this.modal.appendChild(this.list);\n\n const footer = document.createElement('div');\n footer.className = 'tcw-cmd-footer';\n footer.innerHTML = '<span>↑↓ Navigate</span><span>⏎ Open</span><span>Esc Close</span>';\n this.modal.appendChild(footer);\n\n this.host().append(this.backdrop, this.modal);\n\n this.renderList();\n this.input.focus();\n document.addEventListener('keydown', this.boundKeydown);\n }\n\n close(): void {\n document.removeEventListener('keydown', this.boundKeydown);\n this.backdrop?.remove();\n this.modal?.remove();\n this.backdrop = null;\n this.modal = null;\n this.input = null;\n this.list = null;\n this.pickOverride = null;\n this.callbacks.onClose();\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n destroy(): void {\n this.close();\n }\n\n private filter(): void {\n const q = (this.input?.value ?? '').toUpperCase().trim();\n if (!q) {\n this.filtered = this.symbols.map(s => ({ symbol: s, score: 0 }));\n } else {\n this.filtered = this.symbols\n .map(s => ({ symbol: s, score: scoreMatch(s.toUpperCase(), q) }))\n .filter(r => r.score > 0)\n .sort((a, b) => b.score - a.score);\n }\n this.selectedIndex = 0;\n this.renderList();\n }\n\n private renderList(): void {\n if (!this.list) return;\n this.list.innerHTML = '';\n\n if (this.filtered.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'tcw-cmd-empty';\n empty.textContent = 'No symbols match';\n this.list.appendChild(empty);\n return;\n }\n\n const query = (this.input?.value ?? '').toUpperCase().trim();\n for (let i = 0; i < this.filtered.length; i++) {\n const { symbol } = this.filtered[i];\n const row = document.createElement('button');\n row.className = 'tcw-cmd-item';\n if (i === this.selectedIndex) row.classList.add('tcw-selected');\n if (symbol === this.current) row.classList.add('tcw-active');\n\n const label = document.createElement('span');\n label.className = 'tcw-cmd-item-label';\n label.innerHTML = highlight(symbol, query);\n row.appendChild(label);\n\n if (symbol === this.current) {\n const check = document.createElement('span');\n check.className = 'tcw-cmd-check';\n check.textContent = '✓';\n row.appendChild(check);\n }\n\n row.addEventListener('click', () => this.pick(i));\n row.addEventListener('mouseenter', () => {\n this.selectedIndex = i;\n this.updateSelection();\n });\n\n this.list.appendChild(row);\n }\n }\n\n private updateSelection(): void {\n if (!this.list) return;\n const items = this.list.querySelectorAll('.tcw-cmd-item');\n items.forEach((el, i) => el.classList.toggle('tcw-selected', i === this.selectedIndex));\n items[this.selectedIndex]?.scrollIntoView({ block: 'nearest' });\n }\n\n private pick(index: number): void {\n const entry = this.filtered[index];\n if (!entry) return;\n const override = this.pickOverride;\n if (override) override(entry.symbol);\n else this.callbacks.onPick(entry.symbol);\n this.close();\n }\n\n private handleKeydown(e: KeyboardEvent): void {\n switch (e.key) {\n case 'Escape':\n e.preventDefault();\n this.close();\n break;\n case 'ArrowDown':\n e.preventDefault();\n if (this.filtered.length > 0) {\n this.selectedIndex = (this.selectedIndex + 1) % this.filtered.length;\n this.updateSelection();\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (this.filtered.length > 0) {\n this.selectedIndex = (this.selectedIndex - 1 + this.filtered.length) % this.filtered.length;\n this.updateSelection();\n }\n break;\n case 'Enter':\n e.preventDefault();\n this.pick(this.selectedIndex);\n break;\n }\n }\n}\n\n/**\n * Cheap fuzzy score:\n * exact match → 1000\n * starts-with → 500 + tighter-prefix bonus\n * subsequence match → 100 − gap penalty\n * no match → 0\n */\nfunction scoreMatch(symbol: string, query: string): number {\n if (symbol === query) return 1000;\n if (symbol.startsWith(query)) return 500 + (50 - Math.min(50, symbol.length - query.length));\n if (symbol.includes(query)) return 200 + (50 - Math.min(50, symbol.length - query.length));\n\n let qi = 0;\n let lastIdx = -1;\n let gapPenalty = 0;\n for (let i = 0; i < symbol.length && qi < query.length; i++) {\n if (symbol[i] === query[qi]) {\n if (lastIdx >= 0) gapPenalty += i - lastIdx - 1;\n lastIdx = i;\n qi++;\n }\n }\n if (qi < query.length) return 0;\n return 100 - Math.min(99, gapPenalty);\n}\n\nfunction highlight(symbol: string, query: string): string {\n if (!query) return escapeHtml(symbol);\n const upper = symbol.toUpperCase();\n let out = '';\n let qi = 0;\n for (let i = 0; i < symbol.length; i++) {\n if (qi < query.length && upper[i] === query[qi]) {\n out += `<mark style=\"background:transparent;color:var(--tcw-accent);font-weight:700\">${escapeHtml(symbol[i])}</mark>`;\n qi++;\n } else {\n out += escapeHtml(symbol[i]);\n }\n }\n return out;\n}\n\n\nfunction svgSearch(): string {\n return '<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m21 21-4.3-4.3\"/></svg>';\n}\n","import type { MessageKey, Translator } from './i18n.js';\n\n/**\n * Keyboard-shortcut reference sheet. Bound to `?` (and `Shift+/`). Surfaces\n * shortcuts so users discover the widget's hidden interaction model — a\n * premium-feel detail polished desktop tools all ship.\n */\nexport interface HotkeySheetCallbacks {\n onClose: () => void;\n}\n\n// Group titles translate via this lookup; individual shortcut labels (and\n// the `keys` badges) stay English for now — see README \"Widget i18n\".\nconst GROUP_TITLE_KEYS: Record<string, MessageKey> = {\n 'Search & navigation': 'hotkeys.group.searchNavigation',\n 'Chart manipulation': 'hotkeys.group.chartManipulation',\n 'Touch (mobile / tablet)': 'hotkeys.group.touch',\n 'Keyboard': 'hotkeys.group.keyboard',\n 'Drawing': 'hotkeys.group.drawing',\n};\n\ninterface HotkeyEntry {\n keys: string[];\n label: string;\n}\n\ninterface HotkeyGroup {\n title: string;\n entries: HotkeyEntry[];\n}\n\nconst isMac =\n typeof navigator !== 'undefined' && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);\nconst mod = isMac ? '⌘' : 'Ctrl';\n\nconst GROUPS: HotkeyGroup[] = [\n {\n title: 'Search & navigation',\n entries: [\n { keys: [mod, 'K'], label: 'Command palette' },\n { keys: [mod, 'P'], label: 'Symbol search' },\n { keys: ['Alt', 'G'], label: 'Go to date' },\n { keys: ['Alt', 'I'], label: 'Invert price scale' },\n { keys: ['?'], label: 'Show this sheet' },\n ],\n },\n {\n title: 'Chart manipulation',\n entries: [\n { keys: ['Drag'], label: 'Pan — past the last bar into empty future space' },\n { keys: [mod, 'Drag'], label: 'Select drawings in a box' },\n { keys: [mod, 'Click'], label: 'Add / remove a drawing from the selection' },\n { keys: ['Shift', 'Drag'], label: 'Measure tool (bars × price Δ)' },\n { keys: ['Drag', 'Price axis'], label: 'Compress / expand vertical scale' },\n { keys: ['Drag', 'Time axis'], label: 'Zoom time axis' },\n { keys: ['Double-click', 'Price axis'], label: 'Re-enable auto-scale' },\n { keys: ['Double-click', 'Time axis'], label: 'Fit content' },\n { keys: ['Scroll'], label: 'Zoom around cursor' },\n ],\n },\n {\n title: 'Touch (mobile / tablet)',\n entries: [\n { keys: ['1 finger', 'Drag'], label: 'Pan / move crosshair' },\n { keys: ['2 fingers', 'Pinch'], label: 'Zoom around midpoint' },\n { keys: ['Long-press'], label: 'Pin OHLC tooltip at bar' },\n { keys: ['Drag', 'Axis strip'], label: 'Scale price / time axis' },\n ],\n },\n {\n title: 'Keyboard',\n entries: [\n { keys: ['←', '→'], label: 'Pan one bar' },\n { keys: ['+', '−'], label: 'Zoom in / out' },\n { keys: ['Home'], label: 'Scroll to start' },\n { keys: ['End'], label: 'Scroll to end (live edge)' },\n { keys: ['F'], label: 'Fit content' },\n ],\n },\n {\n title: 'Drawing',\n entries: [\n { keys: [mod, 'Z'], label: 'Undo' },\n { keys: [mod, 'Shift', 'Z'], label: 'Redo' },\n { keys: ['Esc'], label: 'Cancel active drawing' },\n { keys: [mod, 'C'], label: 'Copy selected drawings' },\n { keys: [mod, 'V'], label: 'Paste drawings (into any chart on the page)' },\n ],\n },\n];\n\nexport class WidgetHotkeySheet {\n private backdrop: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private callbacks: HotkeySheetCallbacks;\n private t: Translator;\n private boundKeydown: (e: KeyboardEvent) => void;\n\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\n constructor(\n callbacks: HotkeySheetCallbacks,\n t: Translator,\n private readonly host: () => HTMLElement = () => document.body,\n ) {\n this.callbacks = callbacks;\n this.t = t;\n this.boundKeydown = (e) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n this.close();\n }\n };\n }\n\n open(): void {\n if (this.backdrop) return;\n\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.addEventListener('click', () => this.close());\n\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-modal tcw-hotkey-sheet';\n this.modal.style.width = '640px';\n\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n header.innerHTML = `<h3>${this.t('hotkeys.title')}</h3>`;\n const closeBtn = document.createElement('button');\n closeBtn.className = 'tcw-modal-close';\n closeBtn.setAttribute('aria-label', this.t('hotkeys.close'));\n closeBtn.innerHTML = '×';\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(closeBtn);\n this.modal.appendChild(header);\n\n const body = document.createElement('div');\n body.className = 'tcw-modal-body';\n\n const grid = document.createElement('div');\n grid.className = 'tcw-hotkey-grid';\n\n for (const group of GROUPS) {\n const section = document.createElement('section');\n section.className = 'tcw-hotkey-section';\n const title = document.createElement('div');\n title.className = 'tcw-settings-section-title';\n const titleKey = GROUP_TITLE_KEYS[group.title];\n title.textContent = titleKey ? this.t(titleKey) : group.title;\n section.appendChild(title);\n\n for (const entry of group.entries) {\n const row = document.createElement('div');\n row.className = 'tcw-hotkey-row';\n\n const keys = document.createElement('div');\n keys.className = 'tcw-hotkey-keys';\n for (let i = 0; i < entry.keys.length; i++) {\n if (i > 0) {\n const plus = document.createElement('span');\n plus.className = 'tcw-hotkey-sep';\n plus.textContent = '+';\n keys.appendChild(plus);\n }\n const kbd = document.createElement('kbd');\n kbd.className = 'tcw-cmd-kbd';\n kbd.textContent = entry.keys[i];\n keys.appendChild(kbd);\n }\n row.appendChild(keys);\n\n const label = document.createElement('span');\n label.className = 'tcw-hotkey-label';\n label.textContent = entry.label;\n row.appendChild(label);\n\n section.appendChild(row);\n }\n\n grid.appendChild(section);\n }\n\n body.appendChild(grid);\n this.modal.appendChild(body);\n\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n footer.innerHTML = '<span style=\"font-size:11px;color:var(--tcw-text-muted)\">Press ? anytime to show this sheet</span>';\n const ok = document.createElement('button');\n ok.className = 'tcw-done-btn';\n ok.textContent = this.t('hotkeys.gotIt');\n ok.addEventListener('click', () => this.close());\n footer.appendChild(ok);\n this.modal.appendChild(footer);\n\n this.host().append(this.backdrop, this.modal);\n\n document.addEventListener('keydown', this.boundKeydown);\n }\n\n close(): void {\n document.removeEventListener('keydown', this.boundKeydown);\n this.backdrop?.remove();\n this.modal?.remove();\n this.backdrop = null;\n this.modal = null;\n this.callbacks.onClose();\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n destroy(): void {\n this.close();\n }\n}\n","import { escapeHtml } from './escapeHtml.js';\n/**\n * Replay control bar. Surfaces the chart's replay engine as a floating\n * bottom-of-chart control and reports user intent through callbacks (no\n * chart coupling — the host calls chart.replayStart() / replayPause() / …).\n *\n * Two modes: `select` (pick the start bar: a hint, \"random bar\", play from a\n * default start) and `replay` (step, play/pause, scrub, speed). \"Back to\n * realtime\" is always there and is highlighted once the replay reaches the\n * last bar.\n */\nexport interface ReplayBarCallbacks {\n onPlay: () => void;\n onPause: () => void;\n onStepBack: () => void;\n onStepForward: () => void;\n onSeek: (index: number) => void;\n /** Bars revealed per second. */\n onSpeedChange: (barsPerSecond: number) => void;\n onRandomStart: () => void;\n onClose: () => void;\n}\n\nexport interface ReplayBarLabels {\n selectHint: string;\n random: string;\n realtime: string;\n barsPerSecond: string;\n play: string;\n pause: string;\n stepBack: string;\n stepForward: string;\n}\n\nexport const DEFAULT_REPLAY_LABELS: ReplayBarLabels = {\n selectHint: 'Click a bar to start the replay',\n random: 'Random bar',\n realtime: 'Back to realtime',\n barsPerSecond: 'bars/s',\n play: 'Play',\n pause: 'Pause',\n stepBack: 'Step back (Shift+←)',\n stepForward: 'Step forward (Shift+→)',\n};\n\nexport type ReplayBarState = 'playing' | 'paused' | 'stopped';\nexport type ReplayBarMode = 'select' | 'replay';\n\n/** Replay speeds, in bars revealed per second. */\nexport const REPLAY_SPEEDS = [1, 2, 3, 5, 10, 25, 50] as const;\nexport const DEFAULT_REPLAY_SPEED = 5;\n\nexport class WidgetReplayBar {\n private root: HTMLDivElement | null = null;\n private scrubber: HTMLInputElement | null = null;\n private progressLabel: HTMLSpanElement | null = null;\n private playBtn: HTMLButtonElement | null = null;\n private realtimeBtn: HTMLButtonElement | null = null;\n private state: ReplayBarState = 'stopped';\n private mode: ReplayBarMode = 'select';\n private ended = false;\n private total = 0;\n private speed = DEFAULT_REPLAY_SPEED;\n private readonly labels: ReplayBarLabels;\n\n constructor(private readonly callbacks: ReplayBarCallbacks, labels: Partial<ReplayBarLabels> = {}) {\n this.labels = { ...DEFAULT_REPLAY_LABELS, ...labels };\n }\n\n mount(host: HTMLElement, opts: { total: number; speed?: number; mode?: ReplayBarMode }): void {\n if (this.root) return;\n this.total = Math.max(0, opts.total);\n this.speed = opts.speed ?? DEFAULT_REPLAY_SPEED;\n this.state = 'paused';\n this.mode = opts.mode ?? 'select';\n\n this.root = document.createElement('div');\n this.root.className = 'tcw-replay-bar';\n this.root.setAttribute('role', 'toolbar');\n this.root.setAttribute('aria-label', 'Replay');\n this.root.innerHTML = this.markup();\n\n host.appendChild(this.root);\n this.wireEvents();\n this.syncUi();\n }\n\n unmount(): void {\n this.root?.remove();\n this.root = null;\n this.scrubber = null;\n this.progressLabel = null;\n this.playBtn = null;\n this.realtimeBtn = null;\n this.state = 'stopped';\n this.ended = false;\n }\n\n isMounted(): boolean {\n return this.root !== null;\n }\n\n getMode(): ReplayBarMode {\n return this.mode;\n }\n\n setMode(mode: ReplayBarMode): void {\n // The button that started the replay (Random, Play) is about to hide:\n // keep keyboard focus inside the bar, on Play.\n const hadFocus = !!this.root?.contains(document.activeElement);\n this.mode = mode;\n this.syncUi();\n if (hadFocus && mode === 'replay') this.playBtn?.focus();\n }\n\n setState(state: ReplayBarState): void {\n this.state = state;\n this.syncUi();\n }\n\n /** The replay sits on its last bar: nothing left to play. */\n setEnded(ended: boolean): void {\n if (this.ended === ended) return;\n this.ended = ended;\n this.syncUi();\n }\n\n /** `current`: index of the bar on screen. */\n setProgress(current: number, total: number): void {\n this.total = total;\n if (this.scrubber) {\n this.scrubber.max = String(Math.max(0, total - 1));\n this.scrubber.value = String(current);\n }\n if (this.progressLabel) {\n this.progressLabel.textContent = `${Math.min(current + 1, total)} / ${total}`;\n }\n }\n\n destroy(): void {\n this.unmount();\n }\n\n private markup(): string {\n const l = this.labels;\n const speeds = REPLAY_SPEEDS.map(\n (s) => `<option value=\"${s}\"${s === this.speed ? ' selected' : ''}>${s} ${escapeHtml(l.barsPerSecond)}</option>`,\n ).join('');\n return `\n <span class=\"tcw-replay-group\" data-mode=\"select\">\n <span class=\"tcw-replay-hint\" role=\"status\">${svgCursor()}${escapeHtml(l.selectHint)}</span>\n <button class=\"tcw-replay-text-btn\" data-act=\"random\">${escapeHtml(l.random)}</button>\n </span>\n <span class=\"tcw-replay-group\" data-mode=\"replay\">\n <button class=\"tcw-replay-btn\" data-act=\"stepBack\" title=\"${escapeHtml(l.stepBack)}\" aria-label=\"${escapeHtml(l.stepBack)}\">${svgStepBack()}</button>\n <button class=\"tcw-replay-btn tcw-replay-play\" data-act=\"play\" title=\"${escapeHtml(l.play)}\" aria-label=\"${escapeHtml(l.play)}\">${svgPlay()}</button>\n <button class=\"tcw-replay-btn\" data-act=\"stepForward\" title=\"${escapeHtml(l.stepForward)}\" aria-label=\"${escapeHtml(l.stepForward)}\">${svgStepForward()}</button>\n <input type=\"range\" class=\"tcw-replay-scrubber\" data-act=\"seek\" min=\"0\" max=\"${Math.max(0, this.total - 1)}\" value=\"0\" step=\"1\" aria-label=\"Replay position\" />\n <span class=\"tcw-replay-progress\" data-tcw=\"progress\">1 / ${this.total}</span>\n <select class=\"tcw-replay-speed\" data-act=\"speed\" aria-label=\"Speed\">${speeds}</select>\n </span>\n <button class=\"tcw-replay-text-btn tcw-replay-realtime\" data-act=\"realtime\">${escapeHtml(l.realtime)}</button>\n `;\n }\n\n private wireEvents(): void {\n const root = this.root;\n if (!root) return;\n this.scrubber = root.querySelector('input[data-act=\"seek\"]');\n this.progressLabel = root.querySelector('[data-tcw=\"progress\"]');\n this.playBtn = root.querySelector('button[data-act=\"play\"]');\n this.realtimeBtn = root.querySelector('button[data-act=\"realtime\"]');\n\n this.realtimeBtn?.addEventListener('click', () => this.callbacks.onClose());\n root.querySelector('[data-act=\"random\"]')?.addEventListener('click', () => this.callbacks.onRandomStart());\n root.querySelector('[data-act=\"stepBack\"]')?.addEventListener('click', () => this.callbacks.onStepBack());\n root.querySelector('[data-act=\"stepForward\"]')?.addEventListener('click', () => this.callbacks.onStepForward());\n this.playBtn?.addEventListener('click', () => {\n if (this.state === 'playing') this.callbacks.onPause();\n else this.callbacks.onPlay();\n });\n this.scrubber?.addEventListener('input', () => this.callbacks.onSeek(Number(this.scrubber!.value)));\n (root.querySelector('[data-act=\"speed\"]') as HTMLSelectElement | null)?.addEventListener('change', (e) => {\n const v = Number((e.target as HTMLSelectElement).value);\n this.speed = v;\n this.callbacks.onSpeedChange(v);\n });\n }\n\n private syncUi(): void {\n const root = this.root;\n if (!root) return;\n for (const group of root.querySelectorAll<HTMLElement>('.tcw-replay-group')) {\n group.hidden = group.dataset.mode !== this.mode;\n }\n root.classList.toggle('tcw-replay-bar--ended', this.ended);\n if (this.playBtn) {\n const playing = this.state === 'playing';\n this.playBtn.innerHTML = playing ? svgPause() : svgPlay();\n this.playBtn.title = playing ? this.labels.pause : this.labels.play;\n this.playBtn.setAttribute('aria-label', this.playBtn.title);\n const disable = this.ended && !playing;\n if (disable && document.activeElement === this.playBtn) this.realtimeBtn?.focus();\n this.playBtn.disabled = disable;\n }\n }\n}\n\n\nfunction svgPlay(): string {\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M8 5v14l11-7L8 5z\"/></svg>';\n}\nfunction svgPause(): string {\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/></svg>';\n}\nfunction svgStepBack(): string {\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M6 6h2v12H6zM20 6L9 12l11 6V6z\"/></svg>';\n}\nfunction svgStepForward(): string {\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M4 6l11 6L4 18V6zM16 6h2v12h-2z\"/></svg>';\n}\nfunction svgCursor(): string {\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M12 3v18M8 7l4-4 4 4M8 17l4 4 4-4\"/></svg>';\n}\n","/**\r\n * Watchlist sidebar — vertical list of symbols, each with last price, %\r\n * change, and a mini sparkline. Clicking switches the chart's symbol.\r\n *\r\n * The widget tracks the *active* symbol's price/spark automatically from the\r\n * live stream. For non-active symbols, the host can push data via\r\n * `setEntry(symbol, …)` so the row reflects whatever the app already has.\r\n */\r\nexport interface WatchlistEntry {\r\n symbol: string;\r\n lastPrice?: number;\r\n /** Reference price for % calc (usually session open or 24h-ago close). */\r\n refPrice?: number;\r\n /** Recent close samples for the sparkline — last point is the live price. */\r\n sparkline?: number[];\r\n}\r\n\r\nexport interface WatchlistCallbacks {\r\n onSelect: (symbol: string) => void;\r\n}\r\n\r\nexport class WidgetWatchlist {\r\n private el: HTMLDivElement;\r\n private listEl: HTMLDivElement;\r\n private rowMap = new Map<string, {\r\n row: HTMLDivElement;\r\n priceEl: HTMLSpanElement;\r\n changeEl: HTMLSpanElement;\r\n sparkCanvas: HTMLCanvasElement;\r\n }>();\r\n private entries = new Map<string, WatchlistEntry>();\r\n private active: string | null = null;\r\n private callbacks: WatchlistCallbacks;\r\n private locale: string | undefined;\r\n\r\n constructor(host: HTMLElement, symbols: string[], callbacks: WatchlistCallbacks, title = 'Watchlist') {\r\n this.callbacks = callbacks;\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-watchlist';\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-watchlist-header';\r\n header.textContent = title;\r\n this.el.appendChild(header);\r\n\r\n this.listEl = document.createElement('div');\r\n this.listEl.className = 'tcw-watchlist-list';\r\n this.el.appendChild(this.listEl);\r\n\r\n for (const symbol of symbols) {\r\n this.entries.set(symbol, { symbol });\r\n this.appendRow(symbol);\r\n }\r\n\r\n host.appendChild(this.el);\r\n }\r\n\r\n /** Set the BCP 47 locale used for price/percent formatting. */\r\n setLocale(locale: string | undefined): void {\r\n this.locale = locale;\r\n for (const symbol of this.entries.keys()) this.renderRow(symbol);\r\n }\r\n\r\n /** Replace the symbol set. Rows are diff'd so DOM churn is minimal. */\r\n setSymbols(symbols: string[]): void {\r\n const next = new Set(symbols);\r\n for (const sym of this.rowMap.keys()) {\r\n if (!next.has(sym)) this.removeRow(sym);\r\n }\r\n for (const sym of symbols) {\r\n if (!this.rowMap.has(sym)) {\r\n this.entries.set(sym, this.entries.get(sym) ?? { symbol: sym });\r\n this.appendRow(sym);\r\n }\r\n }\r\n }\r\n\r\n setActive(symbol: string): void {\r\n if (this.active === symbol) return;\r\n if (this.active && this.rowMap.has(this.active)) {\r\n this.rowMap.get(this.active)!.row.classList.remove('tcw-watchlist-active');\r\n }\r\n this.active = symbol;\r\n const cur = this.rowMap.get(symbol);\r\n if (cur) cur.row.classList.add('tcw-watchlist-active');\r\n }\r\n\r\n /** Push a price tick into a row. The widget calls this automatically for\r\n * the active symbol. Apps can call it for the rest. */\r\n setEntry(symbol: string, patch: Partial<WatchlistEntry>): void {\r\n const prev = this.entries.get(symbol) ?? { symbol };\r\n const next = { ...prev, ...patch };\r\n this.entries.set(symbol, next);\r\n this.renderRow(symbol);\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n this.rowMap.clear();\r\n this.entries.clear();\r\n }\r\n\r\n private appendRow(symbol: string): void {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-watchlist-row';\r\n row.tabIndex = 0;\r\n\r\n const label = document.createElement('div');\r\n label.className = 'tcw-watchlist-symbol';\r\n label.textContent = formatSymbol(symbol);\r\n\r\n const spark = document.createElement('canvas');\r\n spark.className = 'tcw-watchlist-spark';\r\n spark.width = 64;\r\n spark.height = 22;\r\n\r\n const right = document.createElement('div');\r\n right.className = 'tcw-watchlist-stats';\r\n const priceEl = document.createElement('span');\r\n priceEl.className = 'tcw-watchlist-price';\r\n priceEl.textContent = '—';\r\n const changeEl = document.createElement('span');\r\n changeEl.className = 'tcw-watchlist-change';\r\n changeEl.textContent = '';\r\n right.appendChild(priceEl);\r\n right.appendChild(changeEl);\r\n\r\n row.appendChild(label);\r\n row.appendChild(spark);\r\n row.appendChild(right);\r\n\r\n row.addEventListener('click', () => this.callbacks.onSelect(symbol));\r\n row.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter' || e.key === ' ') {\r\n e.preventDefault();\r\n this.callbacks.onSelect(symbol);\r\n }\r\n });\r\n\r\n this.listEl.appendChild(row);\r\n this.rowMap.set(symbol, { row, priceEl, changeEl, sparkCanvas: spark });\r\n if (symbol === this.active) row.classList.add('tcw-watchlist-active');\r\n }\r\n\r\n private removeRow(symbol: string): void {\r\n const ref = this.rowMap.get(symbol);\r\n if (!ref) return;\r\n ref.row.remove();\r\n this.rowMap.delete(symbol);\r\n }\r\n\r\n private renderRow(symbol: string): void {\r\n const ref = this.rowMap.get(symbol);\r\n const entry = this.entries.get(symbol);\r\n if (!ref || !entry) return;\r\n\r\n if (entry.lastPrice !== undefined) {\r\n ref.priceEl.textContent = formatPrice(entry.lastPrice, this.locale);\r\n }\r\n\r\n if (entry.lastPrice !== undefined && entry.refPrice !== undefined && entry.refPrice !== 0) {\r\n const diff = entry.lastPrice - entry.refPrice;\r\n const pct = (diff / entry.refPrice) * 100;\r\n const sign = diff >= 0 ? '+' : '-';\r\n const pctText = Math.abs(pct).toLocaleString(this.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\r\n ref.changeEl.textContent = `${sign}${pctText}%`;\r\n ref.changeEl.className = `tcw-watchlist-change ${diff >= 0 ? 'tcw-up' : 'tcw-down'}`;\r\n } else {\r\n ref.changeEl.textContent = '';\r\n }\r\n\r\n if (entry.sparkline && entry.sparkline.length >= 2) {\r\n drawSparkline(ref.sparkCanvas, entry.sparkline, entry.refPrice ?? entry.sparkline[0]);\r\n }\r\n }\r\n}\r\n\r\nfunction formatSymbol(symbol: string): string {\r\n // Add a / separator for typical crypto pair suffixes; leaves stock tickers\r\n // (AAPL, NVDA) alone.\r\n for (const quote of ['USDT', 'USD', 'BTC', 'ETH', 'EUR']) {\r\n if (symbol.length > quote.length && symbol.endsWith(quote)) {\r\n return symbol.slice(0, -quote.length) + '/' + quote;\r\n }\r\n }\r\n return symbol;\r\n}\r\n\r\nfunction formatPrice(v: number, locale: string | undefined): string {\r\n if (v === 0) return '0';\r\n const abs = Math.abs(v);\r\n if (abs >= 1000) return v.toLocaleString(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\r\n if (abs >= 1) return v.toLocaleString(locale, { minimumFractionDigits: 4, maximumFractionDigits: 4 });\r\n // toPrecision(4) has no locale-aware equivalent via toLocaleString (it\r\n // targets significant digits, not decimal places) — reformat its raw\r\n // fixed-notation output through Number.toLocaleString for the separator.\r\n const precise = Number(v.toPrecision(4));\r\n return precise.toLocaleString(locale, { maximumFractionDigits: 10 });\r\n}\r\n\r\nfunction drawSparkline(canvas: HTMLCanvasElement, samples: number[], ref: number): void {\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n const dpr = window.devicePixelRatio || 1;\r\n if (canvas.width !== canvas.clientWidth * dpr) {\r\n canvas.width = (canvas.clientWidth || 64) * dpr;\r\n canvas.height = (canvas.clientHeight || 22) * dpr;\r\n }\r\n const w = canvas.width;\r\n const h = canvas.height;\r\n\r\n let lo = Infinity, hi = -Infinity;\r\n for (const v of samples) {\r\n if (v < lo) lo = v;\r\n if (v > hi) hi = v;\r\n }\r\n const span = Math.max(hi - lo, 1e-9);\r\n const last = samples[samples.length - 1];\r\n const up = last >= ref;\r\n const color = up ? '#1fa874' : '#e8505b';\r\n\r\n ctx.clearRect(0, 0, w, h);\r\n ctx.lineWidth = 1.4 * dpr;\r\n ctx.strokeStyle = color;\r\n ctx.beginPath();\r\n const step = w / (samples.length - 1);\r\n for (let i = 0; i < samples.length; i++) {\r\n const x = i * step;\r\n const y = h - ((samples[i] - lo) / span) * (h - 4) - 2;\r\n if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n}\r\n","import type { AlertCondition } from '@tradecanvas/core';\nimport { createIcon } from './icons.js';\n\nexport interface AlertListItem {\n id: string;\n price: number;\n condition: string;\n message?: string;\n triggered: boolean;\n channel?: string;\n label?: string;\n}\n\nexport interface AlertSource {\n /** `'price'` or `<instanceId>:<key>`. */\n channel: string;\n label: string;\n}\n\nexport interface AlertsPanelCallbacks {\n onAdd: (price: number, condition: AlertCondition, message: string | undefined, channel: string, label: string) => void;\n onRemove: (id: string) => void;\n onClear: () => void;\n /** Latest value for a source channel, used to prefill the add form. */\n getChannelValue: (channel: string) => number | null;\n formatPrice: (price: number) => string;\n}\n\nconst CONDITION_OPTIONS: { value: AlertCondition; label: string }[] = [\n { value: 'crossing', label: 'Crossing' },\n { value: 'crossingUp', label: 'Crossing up' },\n { value: 'crossingDown', label: 'Crossing down' },\n { value: 'greaterThan', label: 'Greater than' },\n { value: 'lessThan', label: 'Less than' },\n];\n\nconst CONDITION_LABEL = new Map(CONDITION_OPTIONS.map((o) => [o.value, o.label]));\n\nfunction roundForInput(v: number): number {\n return Math.round(v * 1e6) / 1e6;\n}\n\nfunction formatPlain(v: number): string {\n const abs = Math.abs(v);\n return abs >= 1000 ? v.toFixed(2) : abs >= 1 ? v.toFixed(2) : v.toPrecision(4);\n}\n\n/**\n * Floating price-alerts panel. Lists current alerts (with condition, price,\n * message, and a delete control) and an inline form to add a new one prefilled\n * with the current price. Toggled from the toolbar bell button; the host wires\n * add/remove back to the chart's `AlertManager`.\n */\nexport class WidgetAlertsPanel {\n private el: HTMLDivElement;\n private listEl: HTMLDivElement;\n private priceInput: HTMLInputElement;\n private conditionSelect: HTMLSelectElement;\n private sourceSelect: HTMLSelectElement;\n private messageInput: HTMLInputElement;\n private emptyEl: HTMLDivElement;\n private callbacks: AlertsPanelCallbacks;\n private open = false;\n private alerts: AlertListItem[] = [];\n private sources: AlertSource[] = [{ channel: 'price', label: 'Price' }];\n\n constructor(host: HTMLElement, callbacks: AlertsPanelCallbacks) {\n this.callbacks = callbacks;\n\n this.el = document.createElement('div');\n this.el.className = 'tcw-alerts-panel';\n this.el.hidden = true;\n\n // Header\n const header = document.createElement('div');\n header.className = 'tcw-alerts-header';\n const title = document.createElement('span');\n title.textContent = 'Price Alerts';\n const closeBtn = document.createElement('button');\n closeBtn.className = 'tcw-alerts-close';\n closeBtn.type = 'button';\n closeBtn.setAttribute('aria-label', 'Close alerts');\n closeBtn.innerHTML = createIcon('x', 14);\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(title);\n header.appendChild(closeBtn);\n this.el.appendChild(header);\n\n // Add form\n const form = document.createElement('form');\n form.className = 'tcw-alerts-form';\n\n this.sourceSelect = document.createElement('select');\n this.sourceSelect.className = 'tcw-alerts-source';\n this.sourceSelect.addEventListener('change', () => this.prefillPrice());\n\n this.priceInput = document.createElement('input');\n this.priceInput.type = 'number';\n this.priceInput.step = 'any';\n this.priceInput.placeholder = 'Value';\n this.priceInput.className = 'tcw-alerts-price';\n this.priceInput.required = true;\n\n this.conditionSelect = document.createElement('select');\n this.conditionSelect.className = 'tcw-alerts-condition';\n for (const opt of CONDITION_OPTIONS) {\n const o = document.createElement('option');\n o.value = opt.value;\n o.textContent = opt.label;\n this.conditionSelect.appendChild(o);\n }\n\n this.messageInput = document.createElement('input');\n this.messageInput.type = 'text';\n this.messageInput.placeholder = 'Note (optional)';\n this.messageInput.className = 'tcw-alerts-message';\n\n const addBtn = document.createElement('button');\n addBtn.type = 'submit';\n addBtn.className = 'tcw-alerts-add';\n addBtn.innerHTML = `${createIcon('plus', 14)}<span>Add alert</span>`;\n\n form.appendChild(this.sourceSelect);\n form.appendChild(this.priceInput);\n form.appendChild(this.conditionSelect);\n form.appendChild(this.messageInput);\n form.appendChild(addBtn);\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n this.submitForm();\n });\n this.el.appendChild(form);\n\n // List\n this.listEl = document.createElement('div');\n this.listEl.className = 'tcw-alerts-list';\n this.el.appendChild(this.listEl);\n\n this.emptyEl = document.createElement('div');\n this.emptyEl.className = 'tcw-alerts-empty';\n this.emptyEl.textContent = 'No alerts yet. Add one above, or right-click the chart.';\n this.listEl.appendChild(this.emptyEl);\n\n this.renderSources();\n host.appendChild(this.el);\n }\n\n /** Replace the alert-source options (price + indicator lines). */\n setSources(sources: AlertSource[]): void {\n this.sources = sources.length > 0 ? sources : [{ channel: 'price', label: 'Price' }];\n this.renderSources();\n }\n\n private renderSources(): void {\n const current = this.sourceSelect.value || 'price';\n this.sourceSelect.replaceChildren();\n for (const src of this.sources) {\n const o = document.createElement('option');\n o.value = src.channel;\n o.textContent = src.label;\n this.sourceSelect.appendChild(o);\n }\n // Keep the prior selection if it still exists, else default to price.\n this.sourceSelect.value = this.sources.some((s) => s.channel === current) ? current : 'price';\n }\n\n isOpen(): boolean {\n return this.open;\n }\n\n toggle(): void {\n this.open ? this.close() : this.openPanel();\n }\n\n openPanel(): void {\n this.open = true;\n this.el.hidden = false;\n if (this.priceInput.value === '') this.prefillPrice();\n }\n\n /** Fill the value input with the selected source's current value. */\n private prefillPrice(): void {\n const v = this.callbacks.getChannelValue(this.sourceSelect.value || 'price');\n this.priceInput.value = v !== null ? String(roundForInput(v)) : '';\n }\n\n close(): void {\n this.open = false;\n this.el.hidden = true;\n }\n\n /** Replace the displayed alert list. */\n setAlerts(alerts: AlertListItem[]): void {\n this.alerts = alerts;\n this.renderList();\n }\n\n destroy(): void {\n this.el.remove();\n }\n\n private submitForm(): void {\n const price = Number(this.priceInput.value);\n if (!Number.isFinite(price)) return;\n const condition = this.conditionSelect.value as AlertCondition;\n const message = this.messageInput.value.trim() || undefined;\n const channel = this.sourceSelect.value || 'price';\n const label = this.sources.find((s) => s.channel === channel)?.label ?? 'Price';\n this.callbacks.onAdd(price, condition, message, channel, label);\n this.messageInput.value = '';\n this.prefillPrice();\n }\n\n private renderList(): void {\n // Clear rows but keep the empty placeholder reference.\n this.listEl.replaceChildren();\n\n if (this.alerts.length === 0) {\n this.listEl.appendChild(this.emptyEl);\n return;\n }\n\n // Show most recent first.\n for (const alert of [...this.alerts].reverse()) {\n const row = document.createElement('div');\n row.className = 'tcw-alerts-row' + (alert.triggered ? ' tcw-alerts-triggered' : '');\n\n const info = document.createElement('div');\n info.className = 'tcw-alerts-info';\n const main = document.createElement('div');\n main.className = 'tcw-alerts-row-main';\n const label = CONDITION_LABEL.get(alert.condition as AlertCondition) ?? alert.condition;\n const isIndicator = alert.channel && alert.channel !== 'price';\n const valueStr = isIndicator ? formatPlain(alert.price) : this.callbacks.formatPrice(alert.price);\n const prefix = isIndicator && alert.label ? `${alert.label} ` : '';\n main.textContent = `${prefix}${label} ${valueStr}`;\n info.appendChild(main);\n if (alert.message) {\n const note = document.createElement('div');\n note.className = 'tcw-alerts-row-note';\n note.textContent = alert.message;\n info.appendChild(note);\n }\n if (alert.triggered) {\n const badge = document.createElement('span');\n badge.className = 'tcw-alerts-badge';\n badge.textContent = 'triggered';\n main.appendChild(badge);\n }\n\n const del = document.createElement('button');\n del.type = 'button';\n del.className = 'tcw-alerts-del';\n del.setAttribute('aria-label', 'Delete alert');\n del.innerHTML = createIcon('trash', 14);\n del.addEventListener('click', () => this.callbacks.onRemove(alert.id));\n\n row.appendChild(info);\n row.appendChild(del);\n this.listEl.appendChild(row);\n }\n }\n}\n","import { createIcon } from './icons.js';\r\n\r\nexport interface ObjectTreeIndicator {\r\n instanceId: string;\r\n name: string;\r\n visible: boolean;\r\n}\r\n\r\nexport interface ObjectTreeDrawing {\r\n id: string;\r\n label: string;\r\n visible: boolean;\r\n locked: boolean;\r\n}\r\n\r\nexport interface ObjectTreeCompare {\r\n id: string;\r\n label: string;\r\n color: string;\r\n}\r\n\r\nexport interface ObjectTreeCallbacks {\r\n onRemoveIndicator: (instanceId: string) => void;\r\n onConfigureIndicator?: (instanceId: string) => void;\r\n onToggleIndicatorVisible?: (instanceId: string, visible: boolean) => void;\r\n onRemoveDrawing: (id: string) => void;\r\n onToggleDrawingVisible: (id: string, visible: boolean) => void;\r\n onToggleDrawingLocked: (id: string, locked: boolean) => void;\r\n /** When provided, a Compare section with an \"add\" button is shown. */\r\n onAddCompare?: () => void;\r\n onRemoveCompare?: (id: string) => void;\r\n}\r\n\r\n/**\r\n * Object-tree panel — a layers manager. Lists every active\r\n * indicator and drawing on the chart with per-item controls: indicators can be\r\n * removed; drawings can be shown/hidden, locked/unlocked, and removed. Toggled\r\n * from the toolbar layers button; the host wires actions back to the chart.\r\n */\r\nexport class WidgetObjectTree {\r\n private el: HTMLDivElement;\r\n private indicatorsEl: HTMLDivElement;\r\n private drawingsEl: HTMLDivElement;\r\n private compareEl: HTMLDivElement | null = null;\r\n private callbacks: ObjectTreeCallbacks;\r\n private open = false;\r\n\r\n constructor(host: HTMLElement, callbacks: ObjectTreeCallbacks) {\r\n this.callbacks = callbacks;\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-tree-panel';\r\n this.el.hidden = true;\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-tree-header';\r\n const title = document.createElement('span');\r\n title.textContent = 'Objects';\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-tree-close';\r\n closeBtn.setAttribute('aria-label', 'Close objects');\r\n closeBtn.innerHTML = createIcon('x', 14);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.appendChild(title);\r\n header.appendChild(closeBtn);\r\n this.el.appendChild(header);\r\n\r\n this.indicatorsEl = this.makeSection('Indicators');\r\n this.drawingsEl = this.makeSection('Drawings');\r\n if (this.callbacks.onAddCompare) {\r\n this.compareEl = this.makeSection('Compare', () => this.callbacks.onAddCompare?.());\r\n }\r\n\r\n host.appendChild(this.el);\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.open;\r\n }\r\n\r\n toggle(): void {\r\n this.open ? this.close() : this.openPanel();\r\n }\r\n\r\n openPanel(): void {\r\n this.open = true;\r\n this.el.hidden = false;\r\n }\r\n\r\n close(): void {\r\n this.open = false;\r\n this.el.hidden = true;\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n /** Replace all lists. Cheap full re-render — counts are small. */\r\n setObjects(\r\n indicators: ObjectTreeIndicator[],\r\n drawings: ObjectTreeDrawing[],\r\n compares: ObjectTreeCompare[] = [],\r\n ): void {\r\n this.renderIndicators(indicators);\r\n this.renderDrawings(drawings);\r\n this.renderCompares(compares);\r\n }\r\n\r\n private makeSection(title: string, onAdd?: () => void): HTMLDivElement {\r\n const wrap = document.createElement('div');\r\n wrap.className = 'tcw-tree-section';\r\n const head = document.createElement('div');\r\n head.className = 'tcw-tree-section-head';\r\n const label = document.createElement('span');\r\n label.textContent = title;\r\n head.appendChild(label);\r\n if (onAdd) {\r\n const addBtn = document.createElement('button');\r\n addBtn.type = 'button';\r\n addBtn.className = 'tcw-tree-add';\r\n addBtn.setAttribute('aria-label', `Add ${title.toLowerCase()}`);\r\n addBtn.title = `Add ${title.toLowerCase()}`;\r\n addBtn.innerHTML = createIcon('plus', 13);\r\n addBtn.addEventListener('click', onAdd);\r\n head.appendChild(addBtn);\r\n }\r\n const list = document.createElement('div');\r\n list.className = 'tcw-tree-list';\r\n wrap.appendChild(head);\r\n wrap.appendChild(list);\r\n this.el.appendChild(wrap);\r\n return list;\r\n }\r\n\r\n private renderIndicators(indicators: ObjectTreeIndicator[]): void {\r\n this.indicatorsEl.replaceChildren();\r\n if (indicators.length === 0) {\r\n this.indicatorsEl.appendChild(this.emptyRow('No indicators'));\r\n return;\r\n }\r\n for (const ind of indicators) {\r\n const row = this.row(ind.name);\r\n if (!ind.visible) row.classList.add('tcw-tree-hidden');\r\n const actions = document.createElement('div');\r\n actions.className = 'tcw-tree-actions';\r\n if (this.callbacks.onToggleIndicatorVisible) {\r\n actions.appendChild(this.iconButton(\r\n ind.visible ? 'eye' : 'eyeOff',\r\n ind.visible ? 'Hide' : 'Show',\r\n '',\r\n () => this.callbacks.onToggleIndicatorVisible?.(ind.instanceId, !ind.visible),\r\n ));\r\n }\r\n if (this.callbacks.onConfigureIndicator) {\r\n actions.appendChild(this.iconButton('settings', 'Indicator settings', '', () =>\r\n this.callbacks.onConfigureIndicator?.(ind.instanceId),\r\n ));\r\n }\r\n actions.appendChild(this.iconButton('trash', 'Remove indicator', 'tcw-tree-del', () =>\r\n this.callbacks.onRemoveIndicator(ind.instanceId),\r\n ));\r\n row.appendChild(actions);\r\n this.indicatorsEl.appendChild(row);\r\n }\r\n }\r\n\r\n private renderDrawings(drawings: ObjectTreeDrawing[]): void {\r\n this.drawingsEl.replaceChildren();\r\n if (drawings.length === 0) {\r\n this.drawingsEl.appendChild(this.emptyRow('No drawings'));\r\n return;\r\n }\r\n for (const d of drawings) {\r\n const row = this.row(d.label);\r\n if (!d.visible) row.classList.add('tcw-tree-hidden');\r\n\r\n const actions = document.createElement('div');\r\n actions.className = 'tcw-tree-actions';\r\n actions.appendChild(this.iconButton(\r\n d.visible ? 'eye' : 'eyeOff',\r\n d.visible ? 'Hide' : 'Show',\r\n '',\r\n () => this.callbacks.onToggleDrawingVisible(d.id, !d.visible),\r\n ));\r\n actions.appendChild(this.iconButton(\r\n d.locked ? 'lock' : 'unlock',\r\n d.locked ? 'Unlock' : 'Lock',\r\n d.locked ? 'tcw-tree-on' : '',\r\n () => this.callbacks.onToggleDrawingLocked(d.id, !d.locked),\r\n ));\r\n actions.appendChild(this.iconButton('trash', 'Remove drawing', 'tcw-tree-del', () =>\r\n this.callbacks.onRemoveDrawing(d.id),\r\n ));\r\n row.appendChild(actions);\r\n this.drawingsEl.appendChild(row);\r\n }\r\n }\r\n\r\n private renderCompares(compares: ObjectTreeCompare[]): void {\r\n if (!this.compareEl) return;\r\n this.compareEl.replaceChildren();\r\n if (compares.length === 0) {\r\n this.compareEl.appendChild(this.emptyRow('No comparisons'));\r\n return;\r\n }\r\n for (const c of compares) {\r\n const row = this.row(c.label);\r\n const dot = document.createElement('span');\r\n dot.className = 'tcw-tree-dot';\r\n dot.style.background = c.color;\r\n row.insertBefore(dot, row.firstChild);\r\n if (this.callbacks.onRemoveCompare) {\r\n row.appendChild(this.iconButton('trash', 'Remove comparison', 'tcw-tree-del', () =>\r\n this.callbacks.onRemoveCompare?.(c.id),\r\n ));\r\n }\r\n this.compareEl.appendChild(row);\r\n }\r\n }\r\n\r\n private row(label: string): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-tree-row';\r\n const name = document.createElement('span');\r\n name.className = 'tcw-tree-name';\r\n name.textContent = label;\r\n name.title = label;\r\n row.appendChild(name);\r\n return row;\r\n }\r\n\r\n private emptyRow(text: string): HTMLDivElement {\r\n const el = document.createElement('div');\r\n el.className = 'tcw-tree-empty';\r\n el.textContent = text;\r\n return el;\r\n }\r\n\r\n private iconButton(icon: string, label: string, extraClass: string, onClick: () => void): HTMLButtonElement {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = `tcw-tree-btn ${extraClass}`.trim();\r\n btn.setAttribute('aria-label', label);\r\n btn.title = label;\r\n btn.innerHTML = createIcon(icon, 14);\r\n btn.addEventListener('click', onClick);\r\n return btn;\r\n }\r\n}\r\n\r\nconst DRAWING_TYPE_LABELS: Record<string, string> = {\r\n trendLine: 'Trend Line',\r\n ray: 'Ray',\r\n extendedLine: 'Extended Line',\r\n horizontalLine: 'Horizontal Line',\r\n horizontalRay: 'Horizontal Ray',\r\n crossLine: 'Cross Line',\r\n infoLine: 'Info Line',\r\n trendAngle: 'Trend Angle',\r\n circle: 'Circle',\r\n fibChannel: 'Fib Channel',\r\n fibSpeedResistanceFan: 'Fib Speed Resistance Fan',\r\n schiffPitchfork: 'Schiff Pitchfork',\r\n modifiedSchiffPitchfork: 'Modified Schiff Pitchfork',\r\n xabcdPattern: 'XABCD Pattern',\r\n abcdPattern: 'ABCD Pattern',\r\n headAndShoulders: 'Head and Shoulders',\r\n dateAndPriceRange: 'Date and Price Range',\r\n cyclicLines: 'Cyclic Lines',\r\n priceLabel: 'Price Label',\r\n verticalLine: 'Vertical Line',\r\n rectangle: 'Rectangle',\r\n ellipse: 'Ellipse',\r\n triangle: 'Triangle',\r\n arrow: 'Arrow',\r\n parallelChannel: 'Parallel Channel',\r\n regressionChannel: 'Regression Channel',\r\n pitchfork: 'Pitchfork',\r\n fibRetracement: 'Fib Retracement',\r\n fibExtension: 'Fib Extension',\r\n fibTimeZones: 'Fib Time Zones',\r\n gannBox: 'Gann Box',\r\n gannFan: 'Gann Fan',\r\n elliottWave: 'Elliott Wave',\r\n priceRange: 'Price Range',\r\n dateRange: 'Date Range',\r\n measure: 'Measure',\r\n text: 'Text',\r\n textAnnotation: 'Text',\r\n anchoredVWAP: 'Anchored VWAP',\r\n volumeProfileRange: 'Volume Profile',\r\n riskReward: 'Long/Short Position',\r\n};\r\n\r\n/** Human-readable label for a drawing type, falling back to the raw key. */\r\nexport function drawingTypeLabel(type: string): string {\r\n return DRAWING_TYPE_LABELS[type] ?? type;\r\n}\r\n","import { createIcon } from './icons.js';\n\nexport type IndicatorParamValue = number | string | boolean;\n\nexport interface IndicatorSettingsTarget {\n instanceId: string;\n name: string;\n /** Default config — defines the editable keys and their types. */\n defaults: Record<string, unknown>;\n /** Current values, overlaid on defaults. */\n params: Record<string, unknown>;\n}\n\nexport interface IndicatorSettingsCallbacks {\n onApply: (instanceId: string, params: Record<string, IndicatorParamValue>) => void;\n onClose: () => void;\n}\n\nconst HEX_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;\n\nfunction titleCase(key: string): string {\n // camelCase / snake_case → \"Title Case\"\n return key\n .replace(/_/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/^./, (c) => c.toUpperCase());\n}\n\n/**\n * Per-indicator parameter editor. Introspects the indicator's default config to\n * decide each control (number → stepper, boolean → toggle, hex string → color,\n * other string → text) and applies edits live via `onApply`.\n */\nexport class WidgetIndicatorSettings {\n private backdrop: HTMLDivElement;\n private modal: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private titleEl: HTMLHeadingElement;\n private callbacks: IndicatorSettingsCallbacks;\n private target: IndicatorSettingsTarget | null = null;\n private draft: Record<string, IndicatorParamValue> = {};\n\n constructor(host: HTMLElement, callbacks: IndicatorSettingsCallbacks) {\n this.callbacks = callbacks;\n\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.hidden = true;\n this.backdrop.addEventListener('click', (e) => {\n if (e.target === this.backdrop) this.close();\n });\n\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-modal tcw-modal-narrow';\n\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n this.titleEl = document.createElement('h3');\n this.titleEl.textContent = 'Indicator';\n const closeBtn = document.createElement('button');\n closeBtn.className = 'tcw-modal-close';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.innerHTML = createIcon('x', 16);\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(this.titleEl);\n header.appendChild(closeBtn);\n\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'tcw-modal-body';\n\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n const resetBtn = document.createElement('button');\n resetBtn.className = 'tcw-reset-link';\n resetBtn.textContent = 'Reset to defaults';\n resetBtn.addEventListener('click', () => this.resetDefaults());\n const doneBtn = document.createElement('button');\n doneBtn.className = 'tcw-done-btn';\n doneBtn.textContent = 'Done';\n doneBtn.addEventListener('click', () => this.close());\n footer.appendChild(resetBtn);\n footer.appendChild(doneBtn);\n\n this.modal.appendChild(header);\n this.modal.appendChild(this.bodyEl);\n this.modal.appendChild(footer);\n this.backdrop.appendChild(this.modal);\n host.appendChild(this.backdrop);\n }\n\n open(target: IndicatorSettingsTarget): void {\n this.target = target;\n this.titleEl.textContent = `${target.name} settings`;\n this.draft = {};\n this.renderFields();\n this.backdrop.hidden = false;\n }\n\n close(): void {\n this.backdrop.hidden = true;\n this.target = null;\n this.callbacks.onClose();\n }\n\n isOpen(): boolean {\n return !this.backdrop.hidden;\n }\n\n destroy(): void {\n this.backdrop.remove();\n }\n\n private currentValue(key: string): IndicatorParamValue {\n if (key in this.draft) return this.draft[key];\n const cur = this.target?.params[key];\n const def = this.target?.defaults[key];\n const val = cur ?? def;\n return val as IndicatorParamValue;\n }\n\n private setValue(key: string, value: IndicatorParamValue): void {\n if (!this.target) return;\n this.draft[key] = value;\n this.callbacks.onApply(this.target.instanceId, { ...this.draft });\n }\n\n private resetDefaults(): void {\n if (!this.target) return;\n const reset: Record<string, IndicatorParamValue> = {};\n for (const [key, def] of Object.entries(this.target.defaults)) {\n reset[key] = def as IndicatorParamValue;\n }\n this.draft = reset;\n this.callbacks.onApply(this.target.instanceId, { ...reset });\n this.renderFields();\n }\n\n private renderFields(): void {\n this.bodyEl.replaceChildren();\n if (!this.target) return;\n\n const section = document.createElement('div');\n section.className = 'tcw-settings-section';\n\n const keys = Object.keys(this.target.defaults);\n if (keys.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'tcw-settings-label';\n empty.textContent = 'This indicator has no adjustable parameters.';\n section.appendChild(empty);\n }\n\n for (const key of keys) {\n section.appendChild(this.fieldRow(key));\n }\n this.bodyEl.appendChild(section);\n }\n\n private fieldRow(key: string): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n const label = document.createElement('span');\n label.className = 'tcw-settings-label';\n label.textContent = titleCase(key);\n row.appendChild(label);\n\n const value = this.currentValue(key);\n const defType = typeof (this.target?.defaults[key] ?? value);\n\n if (defType === 'boolean') {\n row.appendChild(this.toggleControl(key, Boolean(value)));\n } else if (defType === 'number') {\n row.appendChild(this.numberControl(key, Number(value)));\n } else if (typeof value === 'string' && HEX_RE.test(value)) {\n row.appendChild(this.colorControl(key, value));\n } else {\n row.appendChild(this.textControl(key, String(value ?? '')));\n }\n return row;\n }\n\n private toggleControl(key: string, value: boolean): HTMLButtonElement {\n const toggle = document.createElement('button');\n toggle.className = `tcw-toggle${value ? ' tcw-on' : ''}`;\n toggle.type = 'button';\n toggle.addEventListener('click', () => {\n const next = !toggle.classList.contains('tcw-on');\n toggle.classList.toggle('tcw-on', next);\n this.setValue(key, next);\n });\n return toggle;\n }\n\n private numberControl(key: string, value: number): HTMLInputElement {\n const input = document.createElement('input');\n input.type = 'number';\n input.className = 'tcw-indi-input';\n input.value = String(value);\n // Integer-looking defaults step by 1; fractional defaults step by 0.1.\n input.step = Number.isInteger(value) ? '1' : '0.1';\n input.addEventListener('change', () => {\n const n = Number(input.value);\n if (Number.isFinite(n)) this.setValue(key, n);\n });\n return input;\n }\n\n private colorControl(key: string, value: string): HTMLInputElement {\n const input = document.createElement('input');\n input.type = 'color';\n input.className = 'tcw-indi-color';\n input.value = value.length === 4 ? expandHex(value) : value;\n input.addEventListener('input', () => this.setValue(key, input.value));\n return input;\n }\n\n private textControl(key: string, value: string): HTMLInputElement {\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'tcw-indi-input';\n input.value = value;\n input.addEventListener('change', () => this.setValue(key, input.value));\n return input;\n }\n}\n\nfunction expandHex(short: string): string {\n // #abc → #aabbcc\n const r = short[1], g = short[2], b = short[3];\n return `#${r}${r}${g}${g}${b}${b}`;\n}\n","import type { DrawingStyle } from '@tradecanvas/commons';\n\nexport interface DrawingStyleTemplate {\n name: string;\n style: Partial<DrawingStyle>;\n}\n\n/** Minimal storage surface — satisfied by `localStorage` and easy to mock. */\nexport interface KeyValueStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nfunction defaultStorage(): KeyValueStorage | null {\n try {\n return typeof localStorage !== 'undefined' ? localStorage : null;\n } catch {\n return null;\n }\n}\n\nconst STYLE_KEYS: (keyof DrawingStyle)[] = [\n 'color', 'lineWidth', 'lineStyle', 'fillColor', 'fillOpacity', 'fontSize',\n];\n\n/** Keep only known style keys — guards against junk persisted by older builds. */\nfunction sanitizeStyle(raw: unknown): Partial<DrawingStyle> {\n if (!raw || typeof raw !== 'object') return {};\n const out: Partial<DrawingStyle> = {};\n const obj = raw as Record<string, unknown>;\n for (const key of STYLE_KEYS) {\n if (obj[key] !== undefined) (out as Record<string, unknown>)[key] = obj[key];\n }\n return out;\n}\n\n/**\n * Named drawing-style presets, persisted to a key-value store. Templates are\n * upserted by name (case-sensitive) and ordered most-recently-saved last.\n */\nexport class DrawingTemplateStore {\n private templates: DrawingStyleTemplate[] = [];\n\n constructor(\n private storageKey = 'tcw:draw-templates',\n private storage: KeyValueStorage | null = defaultStorage(),\n ) {\n this.load();\n }\n\n list(): DrawingStyleTemplate[] {\n return this.templates.map((t) => ({ name: t.name, style: { ...t.style } }));\n }\n\n get(name: string): DrawingStyleTemplate | null {\n const t = this.templates.find((x) => x.name === name);\n return t ? { name: t.name, style: { ...t.style } } : null;\n }\n\n /** Insert or replace a template by name. */\n save(name: string, style: Partial<DrawingStyle>): void {\n const trimmed = name.trim();\n if (!trimmed) return;\n const clean = sanitizeStyle(style);\n this.templates = this.templates.filter((t) => t.name !== trimmed);\n this.templates.push({ name: trimmed, style: clean });\n this.persist();\n }\n\n remove(name: string): void {\n const next = this.templates.filter((t) => t.name !== name);\n if (next.length === this.templates.length) return;\n this.templates = next;\n this.persist();\n }\n\n clear(): void {\n this.templates = [];\n this.persist();\n }\n\n private load(): void {\n if (!this.storage) return;\n try {\n const raw = this.storage.getItem(this.storageKey);\n if (!raw) return;\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return;\n this.templates = parsed\n .filter((t) => t && typeof t.name === 'string')\n .map((t) => ({ name: t.name, style: sanitizeStyle(t.style) }));\n } catch {\n // Corrupt or unavailable storage — start empty.\n }\n }\n\n private persist(): void {\n if (!this.storage) return;\n try {\n this.storage.setItem(this.storageKey, JSON.stringify(this.templates));\n } catch {\n // Storage full or blocked — keep the in-memory copy.\n }\n }\n}\n","import type { DrawingStyle } from '@tradecanvas/commons';\r\nimport { createIcon } from './icons.js';\r\nimport { DrawingTemplateStore } from './DrawingTemplateStore.js';\r\n\r\nexport interface DrawingStyleCallbacks {\r\n /** Apply a style change to the active (next) drawing and the selected one. */\r\n onStyleChange: (style: Partial<DrawingStyle>) => void;\r\n /** Current active drawing style, for seeding controls and saving templates. */\r\n getStyle: () => DrawingStyle;\r\n}\r\n\r\nconst SWATCHES = ['#4c8dff', '#1fa874', '#e8505b', '#f2a93b', '#a57cff', '#1398a8', '#ffffff', '#7d8696'];\r\nconst WIDTHS = [1, 2, 3, 4];\r\nconst LINE_STYLES: DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\r\n\r\n/**\r\n * Drawing style popover — pick colour, line width, and line style for the next\r\n * drawing (and the selected one), plus save/apply named style templates\r\n * persisted via `DrawingTemplateStore`.\r\n */\r\nexport class WidgetDrawingStyle {\r\n private el: HTMLDivElement;\r\n private templatesEl: HTMLDivElement;\r\n private nameInput: HTMLInputElement;\r\n private callbacks: DrawingStyleCallbacks;\r\n private store: DrawingTemplateStore;\r\n private open = false;\r\n\r\n constructor(host: HTMLElement, callbacks: DrawingStyleCallbacks, store: DrawingTemplateStore) {\r\n this.callbacks = callbacks;\r\n this.store = store;\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-style-panel';\r\n this.el.hidden = true;\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-style-header';\r\n const title = document.createElement('span');\r\n title.textContent = 'Drawing Style';\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-style-close';\r\n closeBtn.setAttribute('aria-label', 'Close');\r\n closeBtn.innerHTML = createIcon('x', 14);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.appendChild(title);\r\n header.appendChild(closeBtn);\r\n this.el.appendChild(header);\r\n\r\n this.el.appendChild(this.colorRow());\r\n this.el.appendChild(this.widthRow());\r\n this.el.appendChild(this.lineStyleRow());\r\n\r\n // Templates\r\n const tmplHead = document.createElement('div');\r\n tmplHead.className = 'tcw-style-subhead';\r\n tmplHead.textContent = 'Templates';\r\n this.el.appendChild(tmplHead);\r\n\r\n const saveRow = document.createElement('div');\r\n saveRow.className = 'tcw-style-save';\r\n this.nameInput = document.createElement('input');\r\n this.nameInput.type = 'text';\r\n this.nameInput.placeholder = 'Template name';\r\n this.nameInput.className = 'tcw-style-name';\r\n const saveBtn = document.createElement('button');\r\n saveBtn.type = 'button';\r\n saveBtn.className = 'tcw-style-savebtn';\r\n saveBtn.innerHTML = `${createIcon('plus', 13)}<span>Save</span>`;\r\n saveBtn.addEventListener('click', () => this.saveTemplate());\r\n saveRow.appendChild(this.nameInput);\r\n saveRow.appendChild(saveBtn);\r\n this.el.appendChild(saveRow);\r\n\r\n this.templatesEl = document.createElement('div');\r\n this.templatesEl.className = 'tcw-style-templates';\r\n this.el.appendChild(this.templatesEl);\r\n\r\n host.appendChild(this.el);\r\n this.renderTemplates();\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.open;\r\n }\r\n\r\n toggle(): void {\r\n this.open ? this.close() : this.openPanel();\r\n }\r\n\r\n openPanel(): void {\r\n this.open = true;\r\n this.el.hidden = false;\r\n this.syncActiveControls();\r\n this.renderTemplates();\r\n }\r\n\r\n close(): void {\r\n this.open = false;\r\n this.el.hidden = true;\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n private colorRow(): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-row tcw-style-colors';\r\n for (const c of SWATCHES) {\r\n const sw = document.createElement('button');\r\n sw.type = 'button';\r\n sw.className = 'tcw-style-swatch';\r\n sw.style.background = c;\r\n sw.dataset.color = c;\r\n sw.setAttribute('aria-label', c);\r\n sw.addEventListener('click', () => this.applyStyle({ color: c }));\r\n row.appendChild(sw);\r\n }\r\n const picker = document.createElement('input');\r\n picker.type = 'color';\r\n picker.className = 'tcw-style-picker';\r\n picker.addEventListener('input', () => this.applyStyle({ color: picker.value }));\r\n row.appendChild(picker);\r\n return row;\r\n }\r\n\r\n private widthRow(): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-row tcw-style-widths';\r\n for (const w of WIDTHS) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-style-width';\r\n btn.dataset.width = String(w);\r\n const bar = document.createElement('span');\r\n bar.style.height = `${w}px`;\r\n btn.appendChild(bar);\r\n btn.addEventListener('click', () => this.applyStyle({ lineWidth: w }));\r\n row.appendChild(btn);\r\n }\r\n return row;\r\n }\r\n\r\n private lineStyleRow(): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-row tcw-style-dashes';\r\n for (const ls of LINE_STYLES) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-style-dash';\r\n btn.dataset.linestyle = ls;\r\n btn.textContent = ls === 'solid' ? '──' : ls === 'dashed' ? '╌╌' : '┄┄';\r\n btn.title = ls;\r\n btn.addEventListener('click', () => this.applyStyle({ lineStyle: ls }));\r\n row.appendChild(btn);\r\n }\r\n return row;\r\n }\r\n\r\n private applyStyle(patch: Partial<DrawingStyle>): void {\r\n this.callbacks.onStyleChange(patch);\r\n this.syncActiveControls();\r\n }\r\n\r\n /** Mark the controls matching the current active style. */\r\n private syncActiveControls(): void {\r\n const style = this.callbacks.getStyle();\r\n this.el.querySelectorAll<HTMLElement>('.tcw-style-swatch').forEach((sw) => {\r\n sw.classList.toggle('tcw-on', sw.dataset.color?.toLowerCase() === style.color?.toLowerCase());\r\n });\r\n this.el.querySelectorAll<HTMLElement>('.tcw-style-width').forEach((b) => {\r\n b.classList.toggle('tcw-on', Number(b.dataset.width) === style.lineWidth);\r\n });\r\n this.el.querySelectorAll<HTMLElement>('.tcw-style-dash').forEach((b) => {\r\n b.classList.toggle('tcw-on', b.dataset.linestyle === style.lineStyle);\r\n });\r\n }\r\n\r\n private saveTemplate(): void {\r\n const name = this.nameInput.value.trim();\r\n if (!name) return;\r\n this.store.save(name, this.callbacks.getStyle());\r\n this.nameInput.value = '';\r\n this.renderTemplates();\r\n }\r\n\r\n private renderTemplates(): void {\r\n this.templatesEl.replaceChildren();\r\n const templates = this.store.list();\r\n if (templates.length === 0) {\r\n const empty = document.createElement('div');\r\n empty.className = 'tcw-style-empty';\r\n empty.textContent = 'No saved templates';\r\n this.templatesEl.appendChild(empty);\r\n return;\r\n }\r\n for (const t of templates) {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-template';\r\n\r\n const apply = document.createElement('button');\r\n apply.type = 'button';\r\n apply.className = 'tcw-style-apply';\r\n const dot = document.createElement('span');\r\n dot.className = 'tcw-style-tdot';\r\n dot.style.background = (t.style.color as string) ?? 'var(--tcw-text-muted)';\r\n const label = document.createElement('span');\r\n label.textContent = t.name;\r\n apply.appendChild(dot);\r\n apply.appendChild(label);\r\n apply.addEventListener('click', () => {\r\n this.callbacks.onStyleChange({ ...t.style });\r\n this.syncActiveControls();\r\n });\r\n\r\n const del = document.createElement('button');\r\n del.type = 'button';\r\n del.className = 'tcw-style-tdel';\r\n del.setAttribute('aria-label', 'Delete template');\r\n del.innerHTML = createIcon('trash', 13);\r\n del.addEventListener('click', () => {\r\n this.store.remove(t.name);\r\n this.renderTemplates();\r\n });\r\n\r\n row.appendChild(apply);\r\n row.appendChild(del);\r\n this.templatesEl.appendChild(row);\r\n }\r\n }\r\n}\r\n","import type { KeyValueStorage } from './DrawingTemplateStore.js';\n\nfunction defaultStorage(): KeyValueStorage | null {\n try {\n return typeof localStorage !== 'undefined' ? localStorage : null;\n } catch {\n return null;\n }\n}\n\n/**\n * An ordered, de-duplicated set of pinned drawing-tool ids, persisted to a\n * key-value store. Order is insertion order (most-recently-pinned last).\n */\nexport class DrawingFavoritesStore {\n private favorites: string[] = [];\n\n constructor(\n private storageKey = 'tcw:draw-favorites',\n private storage: KeyValueStorage | null = defaultStorage(),\n ) {\n this.load();\n }\n\n list(): string[] {\n return [...this.favorites];\n }\n\n has(tool: string): boolean {\n return this.favorites.includes(tool);\n }\n\n add(tool: string): void {\n if (!tool || this.favorites.includes(tool)) return;\n this.favorites = [...this.favorites, tool];\n this.persist();\n }\n\n remove(tool: string): void {\n if (!this.favorites.includes(tool)) return;\n this.favorites = this.favorites.filter((t) => t !== tool);\n this.persist();\n }\n\n /** Toggle a tool's pinned state. Returns the new state (true = pinned). */\n toggle(tool: string): boolean {\n if (this.has(tool)) {\n this.remove(tool);\n return false;\n }\n this.add(tool);\n return true;\n }\n\n /** Seed the favorites only when none are stored yet (first run). */\n seedDefaults(tools: string[]): void {\n if (this.favorites.length > 0) return;\n this.favorites = [...new Set(tools.filter(Boolean))];\n this.persist();\n }\n\n private load(): void {\n if (!this.storage) return;\n try {\n const raw = this.storage.getItem(this.storageKey);\n if (!raw) return;\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed)) {\n this.favorites = [...new Set(parsed.filter((t) => typeof t === 'string'))];\n }\n } catch {\n // Corrupt or unavailable — start empty.\n }\n }\n\n private persist(): void {\n if (!this.storage) return;\n try {\n this.storage.setItem(this.storageKey, JSON.stringify(this.favorites));\n } catch {\n // Storage full or blocked — keep the in-memory copy.\n }\n }\n}\n","import type { TimeFrame } from '@tradecanvas/commons';\nimport { timeframeToMs } from '@tradecanvas/commons';\n\n/** The timeframe menu when the host offers no list of its own. */\nexport const WIDGET_TIMEFRAMES: TimeFrame[] = ['1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '1d', '1w', '1M'];\n\n/** On the toolbar until the user pins others. */\nexport const WIDGET_TIMEFRAME_FAVORITES: TimeFrame[] = ['1m', '5m', '15m', '1h', '4h', '1d'];\n\nconst MAX_FALLBACK_FAVORITES = 6;\n\n/** \"1m\", \"1H\", \"1D\", \"1W\"; minutes and months keep their case (\"1m\" vs \"1M\"). */\nexport function timeframeLabel(tf: TimeFrame): string {\n const unit = tf.slice(-1);\n return unit === 'h' || unit === 'd' || unit === 'w' ? tf.slice(0, -1) + unit.toUpperCase() : tf;\n}\n\nconst isKnown = (tf: TimeFrame): boolean => Number.isFinite(timeframeToMs(tf));\n\n/**\n * The timeframes to offer, shortest first: the widget's own list (or the\n * default menu), less any that the chart's `features.timeframes` whitelist\n * leaves out.\n */\nexport function availableTimeframes(widgetList?: TimeFrame[], whitelist?: TimeFrame[]): TimeFrame[] {\n const allowed = whitelist?.length ? whitelist : null;\n const base = widgetList?.length ? widgetList : (allowed ?? WIDGET_TIMEFRAMES);\n return [...new Set(base)]\n .filter((tf) => isKnown(tf) && (!allowed || allowed.includes(tf)))\n .sort((a, b) => timeframeToMs(a) - timeframeToMs(b));\n}\n\n/**\n * The toolbar's first favourites: the host's defaults; else, when the host\n * chose the list, all of it (so a short custom list shows as before); else\n * the standard set; else the first few offered.\n */\nexport function initialTimeframeFavorites(\n available: TimeFrame[],\n hostDefaults?: TimeFrame[],\n hostChoseList = false,\n): TimeFrame[] {\n if (hostDefaults?.length) return available.filter((tf) => hostDefaults.includes(tf));\n if (hostChoseList) return [...available];\n const standard = available.filter((tf) => WIDGET_TIMEFRAME_FAVORITES.includes(tf));\n return standard.length > 0 ? standard : available.slice(0, MAX_FALLBACK_FAVORITES);\n}\n","const MINUTE_MS = 60_000;\nconst DATE_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\nconst TIME_RE = /^(\\d{2}):(\\d{2})$/;\n\n/**\n * A wall-clock date (\"2026-03-01\") and time (\"14:30\", empty = midnight) in the\n * display timezone (`tzOffsetMinutes` east of UTC; null = the browser's) as a\n * UTC timestamp. Null when the date or time is not valid.\n */\nexport function wallTimeToUtc(date: string, time: string, tzOffsetMinutes: number | null): number | null {\n const d = DATE_RE.exec(date);\n const t = time ? TIME_RE.exec(time) : ['', '00', '00'];\n if (!d || !t) return null;\n const [year, month, day, hours, minutes] = [+d[1], +d[2], +d[3], +t[1], +t[2]];\n if (month < 1 || month > 12 || day < 1 || day > 31 || hours > 23 || minutes > 59) return null;\n if (tzOffsetMinutes === null) {\n const local = new Date(year, month - 1, day, hours, minutes);\n return local.getDate() === day ? local.getTime() : null; // 31 February rolls over: reject\n }\n const utc = Date.UTC(year, month - 1, day, hours, minutes);\n if (new Date(utc).getUTCDate() !== day) return null;\n return utc - tzOffsetMinutes * MINUTE_MS;\n}\n\n/** The date and time fields' values for `ts` in the display timezone. */\nexport function utcToWallTime(ts: number, tzOffsetMinutes: number | null): { date: string; time: string } {\n const pad = (n: number) => String(n).padStart(2, '0');\n if (tzOffsetMinutes === null) {\n const d = new Date(ts);\n return {\n date: `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`,\n time: `${pad(d.getHours())}:${pad(d.getMinutes())}`,\n };\n }\n const d = new Date(ts + tzOffsetMinutes * MINUTE_MS);\n return {\n date: `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`,\n time: `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}`,\n };\n}\n\nexport interface GoToDateLabels {\n title: string;\n date: string;\n time: string;\n submit: string;\n cancel: string;\n}\n\n/**\n * \"Go to date\" popover: a date and an optional time. Enter submits, Escape or\n * a click outside closes it, and focus returns to whatever opened it.\n */\nexport class WidgetGoToDate {\n private form: HTMLFormElement | null = null;\n private returnFocus: HTMLElement | null = null;\n /** The button that opened it: pressing it again toggles, so it's not \"outside\". */\n private opener: Element | null = null;\n private readonly onOutside = (e: MouseEvent) => {\n const target = e.target as Node;\n if (this.form && !this.form.contains(target) && !this.opener?.contains(target)) this.close();\n };\n\n constructor(\n private readonly host: HTMLElement,\n private readonly labels: GoToDateLabels,\n private readonly onSubmit: (value: { date: string; time: string }) => void,\n ) {}\n\n isOpen(): boolean {\n return this.form !== null;\n }\n\n open(initial: { date: string; time: string }, opener: Element | null = null): void {\n this.close();\n this.opener = opener;\n this.returnFocus = document.activeElement as HTMLElement | null;\n\n const form = document.createElement('form');\n form.className = 'tcw-goto';\n form.setAttribute('role', 'dialog');\n form.setAttribute('aria-label', this.labels.title);\n\n const title = document.createElement('div');\n title.className = 'tcw-goto-title';\n title.textContent = this.labels.title;\n\n const date = this.field(form, this.labels.date, 'date', initial.date);\n date.required = true;\n const time = this.field(form, this.labels.time, 'time', initial.time);\n\n const actions = document.createElement('div');\n actions.className = 'tcw-goto-actions';\n const cancel = document.createElement('button');\n cancel.type = 'button';\n cancel.className = 'tcw-btn';\n cancel.textContent = this.labels.cancel;\n cancel.addEventListener('click', () => this.close());\n const submit = document.createElement('button');\n submit.type = 'submit';\n submit.className = 'tcw-btn tcw-goto-submit';\n submit.textContent = this.labels.submit;\n actions.append(cancel, submit);\n\n form.prepend(title);\n form.append(actions);\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n if (!date.value) return;\n const value = { date: date.value, time: time.value };\n this.close();\n this.onSubmit(value);\n });\n form.addEventListener('keydown', (e) => {\n e.stopPropagation(); // typing here must not drive chart shortcuts\n if (e.key === 'Escape') this.close();\n });\n\n this.host.appendChild(form);\n this.form = form;\n document.addEventListener('mousedown', this.onOutside);\n date.focus();\n }\n\n close(): void {\n if (!this.form) return;\n document.removeEventListener('mousedown', this.onOutside);\n this.form.remove();\n this.form = null;\n const back = this.returnFocus;\n this.returnFocus = null;\n if (back?.isConnected) back.focus();\n }\n\n destroy(): void {\n this.close();\n }\n\n private field(form: HTMLFormElement, label: string, type: 'date' | 'time', value: string): HTMLInputElement {\n const wrap = document.createElement('label');\n wrap.className = 'tcw-goto-field';\n const text = document.createElement('span');\n text.textContent = label;\n const input = document.createElement('input');\n input.type = type;\n input.value = value;\n input.className = 'tcw-goto-input';\n wrap.append(text, input);\n form.appendChild(wrap);\n return input;\n }\n}\n","/** Pause before the first tooltip shows. */\nexport const TOOLTIP_DELAY_MS = 300;\n/** After one hides, the next shows at once within this window (moving along a toolbar). */\nexport const TOOLTIP_WARM_MS = 500;\nconst GAP_PX = 8;\nconst EDGE_PX = 4;\nconst SLIDE_PX = 3;\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\nconst TIPPED = '[title]:not([title=\"\"]), [data-tip]:not([data-tip=\"\"])';\n\n/**\n * Quick, styled tooltips for the widget's controls, in place of the\n * browser's `title` tooltip (a fixed ~1 s wait, unstyled). Any element in\n * the widget with a `title` gets one. While the pointer is on it, its title\n * is lifted into `data-tip` so the browser's own tooltip can't appear, and\n * put back when the pointer leaves — so the title keeps doing its other jobs\n * (accessible description, selectors). Keyboard focus shows the tooltip too,\n * leaving the title in place. `data-tip-side` picks a side.\n */\nexport class WidgetTooltip {\n private readonly el: HTMLDivElement;\n private target: HTMLElement | null = null;\n private source: 'pointer' | 'focus' | null = null;\n /** The control just pressed (or keyed): no tooltip on it until the pointer leaves. */\n private pressed: HTMLElement | null = null;\n private showTimer: ReturnType<typeof setTimeout> | null = null;\n private watchFrame = 0;\n private warmUntil = 0;\n private readonly observer: MutationObserver;\n\n constructor(private readonly root: HTMLElement) {\n this.el = document.createElement('div');\n this.el.className = 'tcw-tooltip';\n this.el.setAttribute('aria-hidden', 'true'); // the control's title still describes it\n root.appendChild(this.el);\n\n root.addEventListener('pointerover', this.onOver);\n root.addEventListener('pointerout', this.onOut);\n root.addEventListener('pointerdown', this.onPress, true);\n root.addEventListener('keydown', this.onPress, true);\n root.addEventListener('focusin', this.onFocus);\n root.addEventListener('focusout', this.onBlur);\n root.addEventListener('wheel', this.hide, { passive: true });\n\n // Code that sets the title while the pointer is on the control (e.g.\n // \"Magnet ON\" ↔ \"Magnet OFF\" on click) mustn't bring the browser's back.\n this.observer = new MutationObserver(() => {\n // The control just clicked often renames itself (Hide → Show).\n if (this.pressed?.hasAttribute('title')) lift(this.pressed);\n const t = this.target;\n if (!t || this.source !== 'pointer' || !t.hasAttribute('title')) return;\n lift(t);\n if (this.isVisible()) this.show(t);\n });\n this.observer.observe(root, { subtree: true, attributes: true, attributeFilter: ['title'] });\n }\n\n destroy(): void {\n this.hide();\n if (this.pressed) restore(this.pressed);\n this.observer.disconnect();\n this.root.removeEventListener('pointerover', this.onOver);\n this.root.removeEventListener('pointerout', this.onOut);\n this.root.removeEventListener('pointerdown', this.onPress, true);\n this.root.removeEventListener('keydown', this.onPress, true);\n this.root.removeEventListener('focusin', this.onFocus);\n this.root.removeEventListener('focusout', this.onBlur);\n this.root.removeEventListener('wheel', this.hide);\n this.el.remove();\n }\n\n private readonly onOver = (e: PointerEvent): void => {\n if (e.pointerType === 'touch') return;\n const target = this.tipTarget(e.target);\n if (!target || target === this.pressed) return;\n if (target === this.target && this.source === 'pointer') return;\n lift(target);\n this.schedule(target, 'pointer', Date.now() < this.warmUntil || this.isVisible());\n };\n\n private readonly onOut = (e: PointerEvent): void => {\n const next = e.relatedTarget as Node | null;\n const within = (el: HTMLElement | null) => !!el && !!next && el.contains(next); // still on that control\n if (this.pressed && !within(this.pressed)) {\n restore(this.pressed);\n this.pressed = null;\n }\n if (this.source === 'pointer' && !within(this.target)) this.hide();\n };\n\n private readonly onPress = (): void => {\n const was = this.target;\n const lifted = this.source === 'pointer';\n this.warmUntil = 0;\n this.clearTimer();\n cancelAnimationFrame(this.watchFrame);\n this.el.classList.remove('tcw-tooltip--visible');\n this.target = null;\n this.source = null;\n // The title stays lifted while the pointer stays, or the browser's tooltip would take over.\n if (this.pressed && this.pressed !== was) restore(this.pressed);\n this.pressed = lifted ? was : null;\n };\n\n private readonly onFocus = (e: FocusEvent): void => {\n const target = this.tipTarget(e.target);\n // Keyboard focus only: a click focuses the control too, and that is no time for a tooltip.\n if (!target || !isFocusVisible(target) || target === this.pressed) return;\n this.schedule(target, 'focus', true);\n };\n\n private readonly onBlur = (e: FocusEvent): void => {\n if (this.source !== 'focus') return;\n const next = e.relatedTarget as Node | null;\n if (this.target && next && this.target.contains(next)) return;\n this.hide();\n };\n\n private readonly hide = (): void => {\n this.clearTimer();\n cancelAnimationFrame(this.watchFrame);\n if (this.isVisible()) this.warmUntil = Date.now() + TOOLTIP_WARM_MS;\n this.el.classList.remove('tcw-tooltip--visible');\n if (this.target && this.source === 'pointer') restore(this.target);\n this.target = null;\n this.source = null;\n };\n\n private tipTarget(node: EventTarget | null): HTMLElement | null {\n if (!(node instanceof Element)) return null;\n const el = node.closest<HTMLElement>(TIPPED);\n return el && el !== this.el && this.root.contains(el) ? el : null;\n }\n\n private schedule(target: HTMLElement, source: 'pointer' | 'focus', now: boolean): void {\n const previous = this.target;\n this.clearTimer();\n cancelAnimationFrame(this.watchFrame);\n if (previous && previous !== target && this.source === 'pointer') restore(previous);\n this.target = target;\n this.source = source;\n if (now) {\n this.show(target);\n return;\n }\n this.el.classList.remove('tcw-tooltip--visible');\n this.showTimer = setTimeout(() => {\n this.showTimer = null;\n if (this.target === target) this.show(target);\n }, TOOLTIP_DELAY_MS);\n }\n\n private show(target: HTMLElement): void {\n if (!isShown(target)) {\n this.hide();\n return;\n }\n this.el.textContent = tipText(target);\n this.place(target);\n this.el.classList.add('tcw-tooltip--visible');\n this.watch(target);\n }\n\n /** While shown, follow the control: gone, hidden or disabled takes the tooltip with it. */\n private watch(target: HTMLElement): void {\n cancelAnimationFrame(this.watchFrame);\n this.watchFrame = requestAnimationFrame(() => {\n if (this.target !== target) return;\n if (!isShown(target)) this.hide();\n else this.watch(target);\n });\n }\n\n /** Beside the control on its preferred side, flipped and clamped to stay inside the widget. */\n private place(target: HTMLElement): void {\n const box = this.root.getBoundingClientRect();\n const t = target.getBoundingClientRect();\n const w = this.el.offsetWidth;\n const h = this.el.offsetHeight;\n const left = t.left - box.left;\n const top = t.top - box.top;\n let side = preferredSide(target);\n if (side === 'bottom' && top + t.height + GAP_PX + h > box.height) side = 'top';\n else if (side === 'top' && top - GAP_PX - h < 0) side = 'bottom';\n else if (side === 'right' && left + t.width + GAP_PX + w > box.width) side = 'left';\n\n let x: number;\n let y: number;\n if (side === 'top' || side === 'bottom') {\n x = left + t.width / 2 - w / 2;\n y = side === 'bottom' ? top + t.height + GAP_PX : top - GAP_PX - h;\n } else {\n x = side === 'right' ? left + t.width + GAP_PX : left - GAP_PX - w;\n y = top + t.height / 2 - h / 2;\n }\n x = Math.max(EDGE_PX, Math.min(box.width - w - EDGE_PX, x));\n y = Math.max(EDGE_PX, Math.min(box.height - h - EDGE_PX, y));\n this.el.style.left = `${Math.round(x)}px`;\n this.el.style.top = `${Math.round(y)}px`;\n // It slides in from the control's side.\n const slide = { top: [0, SLIDE_PX], bottom: [0, -SLIDE_PX], left: [SLIDE_PX, 0], right: [-SLIDE_PX, 0] }[side];\n this.el.style.setProperty('--tcw-tip-dx', `${slide[0]}px`);\n this.el.style.setProperty('--tcw-tip-dy', `${slide[1]}px`);\n this.el.dataset.side = side;\n }\n\n private isVisible(): boolean {\n return this.el.classList.contains('tcw-tooltip--visible');\n }\n\n private clearTimer(): void {\n if (this.showTimer === null) return;\n clearTimeout(this.showTimer);\n this.showTimer = null;\n }\n}\n\n/** Take the title off while the pointer is on the control, keeping its text in `data-tip`. */\nfunction lift(el: HTMLElement): void {\n const title = el.getAttribute('title');\n if (title === null) return;\n el.dataset.tip = title;\n el.removeAttribute('title');\n}\n\n/** Put a lifted title back. */\nfunction restore(el: HTMLElement): void {\n if (el.dataset.tip !== undefined && !el.hasAttribute('title')) {\n el.setAttribute('title', el.dataset.tip);\n delete el.dataset.tip;\n }\n}\n\nfunction tipText(el: HTMLElement): string {\n return el.dataset.tip ?? el.getAttribute('title') ?? '';\n}\n\n/** Still on screen and usable: attached, laid out, not disabled. */\nfunction isShown(el: HTMLElement): boolean {\n return el.isConnected && el.getClientRects().length > 0 && !(el as HTMLButtonElement).disabled;\n}\n\nfunction isFocusVisible(el: HTMLElement): boolean {\n try {\n return el.matches(':focus-visible');\n } catch {\n return false; // engines without :focus-visible\n }\n}\n\nfunction preferredSide(el: HTMLElement): Side {\n const side = el.dataset.tipSide as Side | undefined;\n if (side) return side;\n if (el.closest('.tcw-sidebar')) return 'right';\n if (el.closest('.tcw-statusbar, .tcw-replay-bar')) return 'top';\n return 'bottom';\n}\n","import { createIcon } from './icons.js';\n\nexport interface IndicatorLegendRow {\n instanceId: string;\n /** \"EMA 50\", \"MACD 12 26 9\". */\n label: string;\n visible: boolean;\n /** The values at the bar in view; `color` null = the neutral text colour. */\n values: readonly { text: string; color: string | null }[];\n /**\n * Where the row sits inside its own pane (container px, `width` = the room\n * it may take); null = stacked under the OHLCV legend.\n */\n pane: { x: number; y: number; width: number } | null;\n}\n\nexport interface IndicatorLegendCallbacks {\n onToggleVisible: (instanceId: string, visible: boolean) => void;\n onSettings: (instanceId: string) => void;\n onRemove: (instanceId: string) => void;\n}\n\nexport interface IndicatorLegendLabels {\n show: string;\n hide: string;\n settings: string;\n remove: string;\n collapse: string;\n expand: string;\n}\n\n/** Collapsing is offered once this many indicators share the price pane. */\nconst COLLAPSE_FROM = 2;\n\ninterface RowEls {\n el: HTMLDivElement;\n name: HTMLButtonElement;\n values: HTMLSpanElement;\n eye: HTMLButtonElement;\n settings: HTMLButtonElement;\n remove: HTMLButtonElement;\n visible: boolean;\n valuesKey: string;\n state: string;\n placeKey: string;\n}\n\n/**\n * The indicators on the chart itself, instead of chips in the toolbar: price\n * pane indicators stack under the OHLCV legend, pane indicators sit at the\n * top of their pane. Each row reads \"EMA 50 123.45\" and, on hover or focus,\n * offers show/hide, settings and remove. A long stack can be collapsed.\n *\n * `update()` is cheap to call every frame: rows are kept by instance id and\n * only changed text and positions are written.\n */\nexport class WidgetIndicatorLegend {\n private readonly stack: HTMLDivElement;\n private readonly toggle: HTMLButtonElement;\n private readonly rows = new Map<string, RowEls>();\n private collapsed = false;\n private toggleKey = '';\n private stackKey = '';\n\n constructor(\n private readonly host: HTMLElement,\n private readonly callbacks: IndicatorLegendCallbacks,\n private readonly labels: IndicatorLegendLabels,\n ) {\n this.stack = document.createElement('div');\n this.stack.className = 'tcw-ind-legend';\n this.toggle = document.createElement('button');\n this.toggle.type = 'button';\n this.toggle.className = 'tcw-ind-legend-toggle';\n this.toggle.addEventListener('click', () => {\n this.setCollapsed(!this.collapsed);\n this.renderToggle(this.overlayCount());\n });\n this.stack.appendChild(this.toggle);\n host.appendChild(this.stack);\n }\n\n update(rows: readonly IndicatorLegendRow[], overlay: { left: number; top: number }): void {\n const stackKey = `${Math.round(overlay.left)},${Math.round(overlay.top)}`;\n if (stackKey !== this.stackKey) {\n this.stackKey = stackKey;\n this.stack.style.left = `${Math.round(overlay.left)}px`;\n this.stack.style.top = `${Math.round(overlay.top)}px`;\n }\n\n const seen = new Set<string>();\n let joinedStack = false;\n for (const row of rows) {\n seen.add(row.instanceId);\n const els = this.rows.get(row.instanceId) ?? this.createRow(row.instanceId);\n this.fill(els, row);\n if (row.pane) {\n if (els.el.parentElement !== this.host) this.host.appendChild(els.el);\n } else if (els.el.parentElement !== this.stack) {\n // New rows join the end (the chart's order), before the toggle.\n this.stack.insertBefore(els.el, this.toggle);\n joinedStack = true;\n }\n this.place(els, row.pane);\n }\n for (const [id, els] of this.rows) {\n if (seen.has(id)) continue;\n els.el.remove();\n this.rows.delete(id);\n }\n // A collapsed stack would hide the indicator just added: open it.\n if (joinedStack && this.collapsed) this.setCollapsed(false);\n this.renderToggle(rows.filter((r) => !r.pane).length);\n }\n\n destroy(): void {\n for (const els of this.rows.values()) els.el.remove();\n this.rows.clear();\n this.stack.remove();\n }\n\n private createRow(instanceId: string): RowEls {\n const el = document.createElement('div');\n el.className = 'tcw-ind-legend-row';\n el.dataset.instance = instanceId;\n\n const name = document.createElement('button');\n name.type = 'button';\n name.className = 'tcw-ind-legend-name';\n name.addEventListener('click', () => this.callbacks.onSettings(instanceId));\n\n const values = document.createElement('span');\n values.className = 'tcw-ind-legend-values';\n\n const actions = document.createElement('span');\n actions.className = 'tcw-ind-legend-actions';\n // Named in fill(), once the row's label is known.\n const action = (act: string, icon: string, run: () => void) => {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'tcw-ind-legend-act';\n b.dataset.act = act;\n b.innerHTML = createIcon(icon, 13);\n b.addEventListener('click', run);\n actions.appendChild(b);\n return b;\n };\n const eye = action('visible', 'eye', () => {\n this.callbacks.onToggleVisible(instanceId, !els.visible);\n });\n const settings = action('settings', 'settings', () => this.callbacks.onSettings(instanceId));\n const remove = action('remove', 'x', () => this.callbacks.onRemove(instanceId));\n\n el.append(name, values, actions);\n const els: RowEls = {\n el, name, values, eye, settings, remove, visible: true, valuesKey: '', state: '', placeKey: '',\n };\n this.rows.set(instanceId, els);\n return els;\n }\n\n private fill(els: RowEls, row: IndicatorLegendRow): void {\n const state = `${row.label}|${row.visible}`;\n if (state !== els.state) {\n els.state = state;\n els.visible = row.visible;\n els.name.textContent = row.label;\n els.name.title = this.labels.settings;\n els.el.classList.toggle('tcw-ind-legend-row--hidden', !row.visible);\n els.eye.innerHTML = createIcon(row.visible ? 'eye' : 'eyeOff', 13);\n setLabel(els.eye, row.visible ? this.labels.hide : this.labels.show, row.label);\n setLabel(els.settings, this.labels.settings, row.label);\n setLabel(els.remove, this.labels.remove, row.label);\n }\n const valuesKey = row.values.map((v) => `${v.text}${v.color ?? ''}`).join('\\u0001');\n if (valuesKey === els.valuesKey) return;\n els.valuesKey = valuesKey;\n els.values.replaceChildren(...row.values.map((v) => {\n const span = document.createElement('span');\n span.textContent = v.text;\n if (v.color) span.style.color = v.color;\n return span;\n }));\n }\n\n /** Pane rows are placed in their pane; stacked rows flow in the stack. */\n private place(els: RowEls, pane: IndicatorLegendRow['pane']): void {\n const key = pane ? `${Math.round(pane.x)},${Math.round(pane.y)},${Math.round(pane.width)}` : '';\n if (key === els.placeKey) return;\n els.placeKey = key;\n els.el.classList.toggle('tcw-ind-legend-row--pane', pane !== null);\n els.el.style.left = pane ? `${Math.round(pane.x)}px` : '';\n els.el.style.top = pane ? `${Math.round(pane.y)}px` : '';\n els.el.style.maxWidth = pane ? `${Math.max(0, Math.round(pane.width))}px` : '';\n }\n\n private setCollapsed(collapsed: boolean): void {\n this.collapsed = collapsed;\n this.stack.classList.toggle('tcw-ind-legend--collapsed', collapsed);\n }\n\n private overlayCount(): number {\n return this.stack.querySelectorAll(':scope > .tcw-ind-legend-row').length;\n }\n\n /** Written only when something changed: `update()` runs every frame. */\n private renderToggle(count: number): void {\n const shown = count >= COLLAPSE_FROM;\n if (!shown && this.collapsed) this.setCollapsed(false);\n const key = `${shown}|${this.collapsed}|${count}`;\n if (key === this.toggleKey) return;\n this.toggleKey = key;\n this.toggle.hidden = !shown;\n if (!shown) return;\n const label = this.collapsed ? this.labels.expand : this.labels.collapse;\n setLabel(this.toggle, label, this.collapsed ? `(${count})` : undefined);\n this.toggle.setAttribute('aria-expanded', String(!this.collapsed));\n const icon = createIcon(this.collapsed ? 'chevronDown' : 'chevronUp', 12);\n this.toggle.innerHTML = this.collapsed ? `${icon}<span>${count}</span>` : icon;\n }\n}\n\n/**\n * An icon button's name: `title` for the tooltip (\"Remove\"), and an\n * `aria-label` that says what it acts on (\"Remove EMA 50\") for assistive tech,\n * which would otherwise hear a column of identical \"Remove\" buttons. (The\n * tooltip also lifts `title` off the element while it is hovered.)\n */\nfunction setLabel(button: HTMLButtonElement, label: string, subject?: string): void {\n button.title = label;\n button.setAttribute('aria-label', subject ? `${label} ${subject}` : label);\n}\n","import type { IndicatorValue } from '@tradecanvas/commons';\nimport { formatPrice } from '@tradecanvas/commons';\n\n/**\n * Output fields that are not drawn — flags (trend direction, session key, bar\n * colour) and intermediate or running values — so the legend leaves them out.\n * Keep in step with the indicators' `render` in core.\n */\nconst SKIP_KEYS: Readonly<Record<string, readonly string[]>> = {\n psar: ['trend'],\n supertrend: ['trend'],\n svwap: ['session'],\n ao: ['up'],\n voldelta: ['up'],\n chaikinOsc: ['adl'],\n adx: ['dx'],\n lrc: ['slope'],\n ichimoku: ['chikou'],\n};\n\n/**\n * One-line indicators drawn in an up colour (`colors[0]`) or a down colour\n * (`colors[1]`) bar by bar: whether a point is drawn in the up colour.\n */\nconst TWO_TONE: Readonly<Record<string, (point: IndicatorValue) => boolean>> = {\n psar: (p) => p.trend === 1,\n supertrend: (p) => p.trend === 1,\n ao: (p) => p.up === 1,\n voldelta: (p) => p.up === 1,\n chaikinOsc: (p) => (p.value ?? 0) >= 0,\n cmf: (p) => (p.value ?? 0) >= 0,\n dpo: (p) => (p.value ?? 0) >= 0,\n};\n\n/** Indicators that draw in fixed colours of their own, not their style's. */\nconst OWN_COLOURS: ReadonlySet<string> = new Set(['ac']);\n\n/** The finite line values of one indicator output point, in output order. */\nexport function legendNumbers(id: string, point: IndicatorValue | null | undefined): number[] {\n if (!point) return [];\n const skip = SKIP_KEYS[id];\n const numbers: number[] = [];\n for (const key in point) {\n const v = point[key];\n if (typeof v === 'number' && Number.isFinite(v) && !skip?.includes(key)) numbers.push(v);\n }\n return numbers;\n}\n\n/**\n * The colour a one-line indicator is drawn in at `point`, so its value reads\n * as part of the line; null = the neutral text colour.\n */\nexport function legendLineColor(\n id: string,\n colors: readonly string[],\n point: IndicatorValue | null | undefined,\n): string | null {\n if (OWN_COLOURS.has(id)) return null;\n const isUp = TWO_TONE[id];\n if (!isUp) return colors[0] ?? null;\n if (!point) return null;\n return (isUp(point) ? colors[0] : colors[1]) ?? null;\n}\n\n/** Compact formats (\"1.23M\") by locale; the legend formats every frame. */\nconst compactFormats = new Map<string, Intl.NumberFormat>();\n\nfunction compactFormat(locale: string): Intl.NumberFormat {\n let format = compactFormats.get(locale);\n if (!format) {\n format = new Intl.NumberFormat(locale, { notation: 'compact', maximumFractionDigits: 2 });\n compactFormats.set(locale, format);\n }\n return format;\n}\n\n/**\n * A pane indicator's value (RSI 54.32, MACD 0.0012, OBV 1.23M): the decimals\n * follow its size, and big ones are shortened.\n */\nexport function formatIndicatorValue(value: number, locale = 'en-US'): string {\n const size = Math.abs(value);\n if (size >= 1e6) return compactFormat(locale).format(value);\n const digits = size >= 1000 ? 1 : size >= 1 ? 2 : size >= 0.01 ? 4 : 6;\n return formatPrice(value, digits, locale);\n}\n","import { createIcon } from './icons.js';\n\nexport interface BracketBarCallbacks {\n onConfirm: () => void;\n onCancel: () => void;\n}\n\n/**\n * Floating confirm/cancel bar shown while a bracket order is being placed.\n * The live entry / SL / TP numbers are drawn on the chart canvas; this bar\n * just carries the commit and discard actions (also bound to Enter / Esc).\n */\nexport class WidgetBracketBar {\n private el: HTMLDivElement;\n private labelEl: HTMLSpanElement;\n private callbacks: BracketBarCallbacks;\n private visible = false;\n\n constructor(host: HTMLElement, callbacks: BracketBarCallbacks) {\n this.callbacks = callbacks;\n\n this.el = document.createElement('div');\n this.el.className = 'tcw-bracket-bar';\n this.el.hidden = true;\n\n this.labelEl = document.createElement('span');\n this.labelEl.className = 'tcw-bracket-label';\n this.el.appendChild(this.labelEl);\n\n const hint = document.createElement('span');\n hint.className = 'tcw-bracket-hint';\n hint.textContent = 'drag lines to adjust';\n this.el.appendChild(hint);\n\n const cancel = document.createElement('button');\n cancel.type = 'button';\n cancel.className = 'tcw-bracket-cancel';\n cancel.innerHTML = `${createIcon('x', 14)}<span>Cancel</span>`;\n cancel.addEventListener('click', () => this.callbacks.onCancel());\n\n const confirm = document.createElement('button');\n confirm.type = 'button';\n confirm.className = 'tcw-bracket-confirm';\n confirm.innerHTML = `${createIcon('check', 14)}<span>Place</span>`;\n confirm.addEventListener('click', () => this.callbacks.onConfirm());\n\n this.el.appendChild(cancel);\n this.el.appendChild(confirm);\n host.appendChild(this.el);\n }\n\n show(side: 'buy' | 'sell'): void {\n this.visible = true;\n this.labelEl.textContent = side === 'buy' ? 'Long bracket' : 'Short bracket';\n this.labelEl.dataset.side = side;\n this.el.hidden = false;\n }\n\n hide(): void {\n this.visible = false;\n this.el.hidden = true;\n }\n\n isVisible(): boolean {\n return this.visible;\n }\n\n destroy(): void {\n this.el.remove();\n }\n}\n","export interface AlertNotifyOptions {\n /** Play a sound on trigger. `true` = built-in beep, string = audio URL. Default `false`. */\n sound?: boolean | string;\n /** Show a desktop notification (requests permission on first use). Default `false`. */\n desktop?: boolean;\n /** Title for desktop notifications. Default `'Price alert'`. */\n title?: string;\n}\n\n/** True when the Notification API is present and not denied. */\nexport function canRequestNotifications(): boolean {\n return typeof Notification !== 'undefined' && Notification.permission !== 'denied';\n}\n\n/**\n * Plays a sound and/or raises a desktop notification when a price alert fires.\n * Browser-API heavy by nature — every entry point is guarded so it degrades to\n * a no-op in SSR, unsupported browsers, or when permission is denied.\n */\nexport class AlertNotifier {\n private options: AlertNotifyOptions;\n private audioCtx: AudioContext | null = null;\n private audioEl: HTMLAudioElement | null = null;\n private permissionAsked = false;\n\n constructor(options: AlertNotifyOptions = {}) {\n this.options = options;\n if (typeof options.sound === 'string') {\n try {\n this.audioEl = new Audio(options.sound);\n this.audioEl.preload = 'auto';\n } catch {\n this.audioEl = null;\n }\n }\n // Request notification permission up front so the first alert isn't silent.\n if (options.desktop) this.ensurePermission();\n }\n\n setOptions(options: AlertNotifyOptions): void {\n this.options = { ...this.options, ...options };\n }\n\n /** Fire the configured notifications for a triggered alert. */\n notify(message: string): void {\n if (this.options.sound) this.playSound();\n if (this.options.desktop) this.showDesktop(message);\n }\n\n private playSound(): void {\n if (this.audioEl) {\n this.audioEl.currentTime = 0;\n void this.audioEl.play().catch(() => {});\n return;\n }\n this.beep();\n }\n\n /** A short two-tone beep via Web Audio — no asset required. */\n private beep(): void {\n try {\n const Ctx = window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctx) return;\n if (!this.audioCtx) this.audioCtx = new Ctx();\n const ctx = this.audioCtx;\n const now = ctx.currentTime;\n const gain = ctx.createGain();\n gain.gain.setValueAtTime(0.0001, now);\n gain.gain.exponentialRampToValueAtTime(0.2, now + 0.01);\n gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.35);\n gain.connect(ctx.destination);\n const osc = ctx.createOscillator();\n osc.type = 'sine';\n osc.frequency.setValueAtTime(880, now);\n osc.frequency.setValueAtTime(1320, now + 0.16);\n osc.connect(gain);\n osc.start(now);\n osc.stop(now + 0.36);\n } catch {\n // Audio unavailable or blocked by autoplay policy — silent.\n }\n }\n\n private ensurePermission(): void {\n if (this.permissionAsked) return;\n this.permissionAsked = true;\n if (typeof Notification === 'undefined') return;\n if (Notification.permission === 'default') {\n void Notification.requestPermission().catch(() => {});\n }\n }\n\n private showDesktop(message: string): void {\n if (typeof Notification === 'undefined') return;\n if (Notification.permission !== 'granted') {\n this.ensurePermission();\n return;\n }\n try {\n new Notification(this.options.title ?? 'Price alert', { body: message });\n } catch {\n // Some browsers throw if not invoked from a user gesture — ignore.\n }\n }\n\n destroy(): void {\n try {\n void this.audioCtx?.close();\n } catch {\n // ignore\n }\n this.audioCtx = null;\n this.audioEl = null;\n }\n}\n","import type { DepthData } from '@tradecanvas/commons';\n\nexport interface LadderRow {\n price: number;\n bidVolume: number;\n askVolume: number;\n}\n\nexport interface LadderModel {\n /** Rows ordered high → low price (asks on top, bids below). */\n rows: LadderRow[];\n /** Largest single-side volume across the shown rows (for bar scaling). */\n maxVolume: number;\n /** Midpoint between best bid and best ask, or null if a side is empty. */\n mid: number | null;\n}\n\n/**\n * Build a depth-of-market ladder from an order book: the best `maxLevels` asks\n * (lowest prices) and best `maxLevels` bids (highest prices), merged into rows\n * ordered high→low. A price present on both sides is merged into one row.\n */\nexport function buildLadderRows(data: DepthData, maxLevels = 12): LadderModel {\n const asks = [...data.asks].sort((a, b) => a.price - b.price).slice(0, maxLevels);\n const bids = [...data.bids].sort((a, b) => b.price - a.price).slice(0, maxLevels);\n\n const bestAsk = asks.length > 0 ? asks[0].price : null;\n const bestBid = bids.length > 0 ? bids[0].price : null;\n const mid = bestAsk !== null && bestBid !== null ? (bestAsk + bestBid) / 2 : null;\n\n const byPrice = new Map<number, LadderRow>();\n const rowAt = (price: number): LadderRow => {\n let row = byPrice.get(price);\n if (!row) {\n row = { price, bidVolume: 0, askVolume: 0 };\n byPrice.set(price, row);\n }\n return row;\n };\n for (const a of asks) rowAt(a.price).askVolume += a.volume;\n for (const b of bids) rowAt(b.price).bidVolume += b.volume;\n\n const rows = [...byPrice.values()].sort((a, b) => b.price - a.price);\n let maxVolume = 0;\n for (const r of rows) maxVolume = Math.max(maxVolume, r.bidVolume, r.askVolume);\n\n return { rows, maxVolume, mid };\n}\n","import type { DepthData } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { buildLadderRows, type LadderModel } from './ladderRows.js';\n\nexport interface DepthLadderCallbacks {\n /** Buy at `price` (clicked an ask cell) or sell at `price` (clicked a bid cell). */\n onTrade: (side: 'buy' | 'sell', price: number) => void;\n formatPrice: (price: number) => string;\n}\n\n/**\n * Depth-of-market ladder (DOM). Renders the order book as price rows with bid\n * and ask size columns; clicking an ask cell buys at that price, a bid cell\n * sells. Fed by `setData(depth)`; the bar widths scale to the largest visible\n * size.\n */\nexport class WidgetDepthLadder {\n private el: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private callbacks: DepthLadderCallbacks;\n private open = false;\n private levels: number;\n\n constructor(host: HTMLElement, callbacks: DepthLadderCallbacks, levels = 12) {\n this.callbacks = callbacks;\n this.levels = levels;\n\n this.el = document.createElement('div');\n this.el.className = 'tcw-ladder';\n this.el.hidden = true;\n\n const header = document.createElement('div');\n header.className = 'tcw-ladder-header';\n const title = document.createElement('span');\n title.textContent = 'Depth Ladder';\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.className = 'tcw-ladder-close';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.innerHTML = createIcon('x', 14);\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(title);\n header.appendChild(closeBtn);\n this.el.appendChild(header);\n\n const cols = document.createElement('div');\n cols.className = 'tcw-ladder-cols';\n cols.innerHTML = '<span>Bid</span><span>Price</span><span>Ask</span>';\n this.el.appendChild(cols);\n\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'tcw-ladder-body';\n this.el.appendChild(this.bodyEl);\n\n host.appendChild(this.el);\n }\n\n isOpen(): boolean {\n return this.open;\n }\n\n toggle(): void {\n this.open ? this.close() : this.openPanel();\n }\n\n openPanel(): void {\n this.open = true;\n this.el.hidden = false;\n }\n\n close(): void {\n this.open = false;\n this.el.hidden = true;\n }\n\n setData(depth: DepthData | null): void {\n if (!depth) {\n this.renderEmpty();\n return;\n }\n this.render(buildLadderRows(depth, this.levels));\n }\n\n destroy(): void {\n this.el.remove();\n }\n\n private renderEmpty(): void {\n this.bodyEl.replaceChildren();\n const empty = document.createElement('div');\n empty.className = 'tcw-ladder-empty';\n empty.textContent = 'No order-book data';\n this.bodyEl.appendChild(empty);\n }\n\n private render(model: LadderModel): void {\n this.bodyEl.replaceChildren();\n if (model.rows.length === 0) {\n this.renderEmpty();\n return;\n }\n const inv = model.maxVolume > 0 ? 1 / model.maxVolume : 0;\n\n for (const row of model.rows) {\n const isAsk = row.askVolume > 0;\n const tr = document.createElement('div');\n tr.className = 'tcw-ladder-row';\n\n // Bid cell (click → sell at price)\n const bid = document.createElement('button');\n bid.type = 'button';\n bid.className = 'tcw-ladder-cell tcw-ladder-bid';\n if (row.bidVolume > 0) {\n bid.textContent = formatSize(row.bidVolume);\n bid.style.setProperty('--w', `${(row.bidVolume * inv * 100).toFixed(1)}%`);\n bid.title = `Sell @ ${this.callbacks.formatPrice(row.price)}`;\n bid.addEventListener('click', () => this.callbacks.onTrade('sell', row.price));\n } else {\n bid.disabled = true;\n }\n\n const price = document.createElement('div');\n price.className = `tcw-ladder-price ${isAsk ? 'tcw-ask' : 'tcw-bid'}`;\n price.textContent = this.callbacks.formatPrice(row.price);\n\n // Ask cell (click → buy at price)\n const ask = document.createElement('button');\n ask.type = 'button';\n ask.className = 'tcw-ladder-cell tcw-ladder-ask';\n if (row.askVolume > 0) {\n ask.textContent = formatSize(row.askVolume);\n ask.style.setProperty('--w', `${(row.askVolume * inv * 100).toFixed(1)}%`);\n ask.title = `Buy @ ${this.callbacks.formatPrice(row.price)}`;\n ask.addEventListener('click', () => this.callbacks.onTrade('buy', row.price));\n } else {\n ask.disabled = true;\n }\n\n tr.appendChild(bid);\n tr.appendChild(price);\n tr.appendChild(ask);\n this.bodyEl.appendChild(tr);\n }\n }\n}\n\nfunction formatSize(v: number): string {\n if (v >= 1000) return (v / 1000).toFixed(1) + 'k';\n if (v >= 1) return v.toFixed(2).replace(/\\.00$/, '');\n return v.toPrecision(2);\n}\n","import { createIcon } from './icons.js';\n\nexport interface DataWindowIndicator {\n name: string;\n values: { key: string; value: number }[];\n}\n\nexport interface DataWindowModel {\n ohlc: { open: number; high: number; low: number; close: number; volume: number } | null;\n change: number;\n changePct: number;\n indicators: DataWindowIndicator[];\n}\n\nexport interface DataWindowCallbacks {\n formatPrice: (price: number) => string;\n}\n\n/**\n * Data Window — a floating readout of the exact O/H/L/C/V, change, and every\n * active indicator value at the hovered bar. Updated from `crosshairMove`.\n */\nexport class WidgetDataWindow {\n private el: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private callbacks: DataWindowCallbacks;\n private open = false;\n\n constructor(host: HTMLElement, callbacks: DataWindowCallbacks) {\n this.callbacks = callbacks;\n\n this.el = document.createElement('div');\n this.el.className = 'tcw-datawin';\n this.el.hidden = true;\n\n const header = document.createElement('div');\n header.className = 'tcw-datawin-header';\n const title = document.createElement('span');\n title.textContent = 'Data Window';\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.className = 'tcw-datawin-close';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.innerHTML = createIcon('x', 14);\n closeBtn.addEventListener('click', () => this.close());\n header.appendChild(title);\n header.appendChild(closeBtn);\n this.el.appendChild(header);\n\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'tcw-datawin-body';\n this.el.appendChild(this.bodyEl);\n\n host.appendChild(this.el);\n }\n\n isOpen(): boolean {\n return this.open;\n }\n\n toggle(): void {\n this.open ? this.close() : this.openPanel();\n }\n\n openPanel(): void {\n this.open = true;\n this.el.hidden = false;\n }\n\n close(): void {\n this.open = false;\n this.el.hidden = true;\n }\n\n destroy(): void {\n this.el.remove();\n }\n\n render(model: DataWindowModel): void {\n if (!this.open) return;\n this.bodyEl.replaceChildren();\n\n if (!model.ohlc) {\n const empty = document.createElement('div');\n empty.className = 'tcw-datawin-empty';\n empty.textContent = 'Hover the chart';\n this.bodyEl.appendChild(empty);\n return;\n }\n\n const fp = this.callbacks.formatPrice;\n const o = model.ohlc;\n this.bodyEl.appendChild(this.row('Open', fp(o.open)));\n this.bodyEl.appendChild(this.row('High', fp(o.high)));\n this.bodyEl.appendChild(this.row('Low', fp(o.low)));\n this.bodyEl.appendChild(this.row('Close', fp(o.close)));\n const tone = model.change > 0 ? 'up' : model.change < 0 ? 'down' : '';\n const sign = model.change > 0 ? '+' : '';\n this.bodyEl.appendChild(this.row('Change', `${sign}${fp(model.change)} (${sign}${model.changePct.toFixed(2)}%)`, tone));\n this.bodyEl.appendChild(this.row('Volume', formatVolume(o.volume)));\n\n for (const ind of model.indicators) {\n const head = document.createElement('div');\n head.className = 'tcw-datawin-sub';\n head.textContent = ind.name;\n this.bodyEl.appendChild(head);\n for (const v of ind.values) {\n this.bodyEl.appendChild(this.row(v.key, formatNumber(v.value)));\n }\n }\n }\n\n private row(label: string, value: string, tone = ''): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-datawin-row';\n const l = document.createElement('span');\n l.className = 'tcw-datawin-label';\n l.textContent = label;\n const v = document.createElement('span');\n v.className = `tcw-datawin-value${tone ? ` tcw-${tone}` : ''}`;\n v.textContent = value;\n row.appendChild(l);\n row.appendChild(v);\n return row;\n }\n}\n\nfunction formatNumber(v: number): string {\n if (!Number.isFinite(v)) return '—';\n const abs = Math.abs(v);\n if (abs >= 1000) return v.toFixed(2);\n if (abs >= 1) return v.toFixed(4);\n return v.toPrecision(4);\n}\n\nfunction formatVolume(v: number): string {\n if (v >= 1_000_000_000) return (v / 1_000_000_000).toFixed(2) + 'B';\n if (v >= 1_000_000) return (v / 1_000_000).toFixed(2) + 'M';\n if (v >= 1_000) return (v / 1_000).toFixed(2) + 'K';\n return v.toFixed(0);\n}\n","import type { ChartType, TimeFrame, DrawingState, PriceScaleMode } from '@tradecanvas/commons';\n\nexport interface ShareableIndicator {\n id: string;\n params: Record<string, number | string | boolean>;\n}\n\nexport interface ShareableWidgetState {\n v: 1;\n symbol: string;\n timeframe: TimeFrame;\n chartType: ChartType;\n scaleMode: PriceScaleMode;\n indicators: ShareableIndicator[];\n drawings: DrawingState[];\n}\n\ninterface NodeBufferCtor {\n from(input: string, encoding: string): { toString(encoding: string): string };\n}\nconst nodeBuffer = (globalThis as { Buffer?: NodeBufferCtor }).Buffer;\n\nfunction utf8ToBase64(str: string): string {\n if (nodeBuffer) return nodeBuffer.from(str, 'utf8').toString('base64');\n const bytes = new TextEncoder().encode(str);\n let bin = '';\n for (const b of bytes) bin += String.fromCharCode(b);\n return btoa(bin);\n}\n\nfunction base64ToUtf8(b64: string): string {\n if (nodeBuffer) return nodeBuffer.from(b64, 'base64').toString('utf8');\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n}\n\nfunction toBase64Url(b64: string): string {\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction fromBase64Url(s: string): string {\n const b64 = s.replace(/-/g, '+').replace(/_/g, '/');\n const pad = b64.length % 4 === 0 ? '' : '='.repeat(4 - (b64.length % 4));\n return b64 + pad;\n}\n\n/** Encode a shareable widget state to a compact, URL-safe string. */\nexport function encodeWidgetState(state: ShareableWidgetState): string {\n return toBase64Url(utf8ToBase64(JSON.stringify(state)));\n}\n\n/**\n * Decode a shareable-state string. Returns null for anything malformed or of an\n * unknown version — callers should treat null as \"ignore and keep current view\".\n */\nexport function decodeWidgetState(encoded: string): ShareableWidgetState | null {\n if (!encoded) return null;\n try {\n const json = base64ToUtf8(fromBase64Url(encoded));\n const obj = JSON.parse(json);\n if (!obj || obj.v !== 1 || typeof obj.symbol !== 'string') return null;\n return {\n v: 1,\n symbol: obj.symbol,\n timeframe: obj.timeframe,\n chartType: obj.chartType,\n scaleMode: obj.scaleMode ?? 'regular',\n indicators: Array.isArray(obj.indicators) ? obj.indicators : [],\n drawings: Array.isArray(obj.drawings) ? obj.drawings : [],\n };\n } catch {\n return null;\n }\n}\n\nconst HASH_KEY = 'tcw';\n\n/** Read a `#tcw=<encoded>` fragment from a URL hash, or null. */\nexport function readShareHash(hash: string): string | null {\n const clean = hash.startsWith('#') ? hash.slice(1) : hash;\n for (const part of clean.split('&')) {\n const eq = part.indexOf('=');\n if (eq > 0 && part.slice(0, eq) === HASH_KEY) return decodeURIComponent(part.slice(eq + 1));\n }\n return null;\n}\n\n/** Build a shareable URL by replacing the `tcw` hash param on `base`. */\nexport function buildShareUrl(base: string, encoded: string): string {\n const [withoutHash] = base.split('#');\n return `${withoutHash}#${HASH_KEY}=${encoded}`;\n}\n","/**\n * i18n for ChartWidget's own chrome (toolbar, watchlist, indicator picker,\n * status bar, settings panel, hotkey sheet). This does NOT translate\n * data-driven labels sourced from `widgetConfig.ts` (the 69 indicator\n * display names, drawing-tool names, timezone/locale option labels) — those\n * stay in English for now; see README \"Widget i18n\" for the current\n * coverage and how to extend it via `messages`.\n */\n\nexport type MessageKey = typeof EN_MESSAGES extends Record<infer K, string> ? K : never;\n\nexport const EN_MESSAGES = {\n // Toolbar\n 'toolbar.indicators': 'Indicators',\n 'toolbar.indicators.popular': 'Popular',\n 'toolbar.indicators.all': 'All',\n 'indicatorType.overlay': 'overlay',\n 'indicatorType.panel': 'panel',\n 'toolbar.replay': 'Bar replay',\n 'replay.selectHint': 'Click a bar to start the replay',\n 'replay.random': 'Random bar',\n 'replay.realtime': 'Back to realtime',\n 'replay.barsPerSecond': 'bars/s',\n 'replay.play': 'Play',\n 'replay.pause': 'Pause',\n 'replay.stepBack': 'Step back (Shift+←)',\n 'replay.stepForward': 'Step forward (Shift+→)',\n 'toolbar.longBracket': 'Long bracket',\n 'toolbar.shortBracket': 'Short bracket',\n 'toolbar.depthLadder': 'Depth ladder',\n 'toolbar.objects': 'Objects',\n 'toolbar.priceAlerts': 'Price alerts',\n 'toolbar.screenshot': 'Screenshot',\n 'toolbar.settings': 'Chart Settings',\n 'toolbar.toggleTheme': 'Toggle theme',\n 'toolbar.timeframes': 'Timeframes',\n 'toolbar.timeframes.pin': 'Pin to toolbar',\n 'toolbar.fullscreen': 'Fullscreen',\n 'legend.show': 'Show',\n 'legend.hide': 'Hide',\n 'legend.settings': 'Settings',\n 'legend.remove': 'Remove',\n 'legend.collapse': 'Collapse indicators',\n 'legend.expand': 'Show indicators',\n 'toolbar.exitFullscreen': 'Exit fullscreen',\n 'range.presets': 'Visible range',\n 'range.all': 'All',\n 'range.goTo': 'Go to date',\n 'range.goToSubmit': 'Go to',\n 'range.date': 'Date',\n 'range.time': 'Time',\n 'range.cancel': 'Cancel',\n 'range.beforeData': 'Showing the earliest loaded bar',\n\n // Chart types\n 'chartType.candlestick': 'Candlestick',\n 'chartType.line': 'Line',\n 'chartType.area': 'Area',\n 'chartType.bar': 'Bar',\n 'chartType.heikinAshi': 'Heikin-Ashi',\n 'chartType.hollowCandle': 'Hollow Candle',\n 'chartType.baseline': 'Baseline',\n 'chartType.volumeCandles': 'Volume Candles',\n 'chartType.equivolume': 'Equivolume',\n 'chartType.hlcArea': 'HLC Area',\n 'chartType.stepLine': 'Step Line',\n 'chartType.lineWithMarkers': 'Line + Markers',\n\n // Watchlist\n 'watchlist.title': 'Watchlist',\n\n // Status bar / connection\n 'status.connecting': 'Connecting...',\n 'status.live': 'Live',\n 'status.connectionFailed': 'Connection failed',\n 'status.loading': 'Loading chart...',\n\n // Settings panel\n 'settings.title': 'Chart Settings',\n 'settings.tab.style': 'style',\n 'settings.tab.display': 'display',\n 'settings.tab.scale': 'scale',\n 'settings.resetToDefaults': 'Reset to defaults',\n 'settings.done': 'Done',\n 'settings.section.candleColors': 'Candle Colors',\n 'settings.section.background': 'Background',\n\n // Hotkey sheet\n 'hotkeys.title': 'Keyboard shortcuts',\n 'hotkeys.close': 'Close',\n 'hotkeys.gotIt': 'Got it',\n 'hotkeys.group.searchNavigation': 'Search & navigation',\n 'hotkeys.group.chartManipulation': 'Chart manipulation',\n 'hotkeys.group.touch': 'Touch (mobile / tablet)',\n 'hotkeys.group.keyboard': 'Keyboard',\n 'hotkeys.group.drawing': 'Drawing',\n} as const;\n\nexport const VI_MESSAGES: Partial<Record<MessageKey, string>> = {\n 'toolbar.indicators': 'Chỉ báo',\n 'toolbar.indicators.popular': 'Phổ biến',\n 'toolbar.indicators.all': 'Tất cả',\n 'indicatorType.overlay': 'phủ lên',\n 'indicatorType.panel': 'bảng riêng',\n 'toolbar.replay': 'Phát lại',\n 'replay.selectHint': 'Bấm vào một nến để bắt đầu phát lại',\n 'replay.random': 'Nến ngẫu nhiên',\n 'replay.realtime': 'Về thời gian thực',\n 'replay.barsPerSecond': 'nến/giây',\n 'replay.play': 'Phát',\n 'replay.pause': 'Tạm dừng',\n 'replay.stepBack': 'Lùi một nến (Shift+←)',\n 'replay.stepForward': 'Tiến một nến (Shift+→)',\n 'toolbar.longBracket': 'Lệnh Long',\n 'toolbar.shortBracket': 'Lệnh Short',\n 'toolbar.depthLadder': 'Sổ lệnh',\n 'toolbar.objects': 'Đối tượng',\n 'toolbar.priceAlerts': 'Cảnh báo giá',\n 'toolbar.screenshot': 'Chụp màn hình',\n 'toolbar.settings': 'Cài đặt biểu đồ',\n 'toolbar.toggleTheme': 'Đổi giao diện',\n 'toolbar.timeframes': 'Khung thời gian',\n 'toolbar.timeframes.pin': 'Ghim lên thanh công cụ',\n 'toolbar.fullscreen': 'Toàn màn hình',\n 'legend.show': 'Hiện',\n 'legend.hide': 'Ẩn',\n 'legend.settings': 'Cài đặt',\n 'legend.remove': 'Xoá',\n 'legend.collapse': 'Thu gọn chỉ báo',\n 'legend.expand': 'Hiện chỉ báo',\n 'toolbar.exitFullscreen': 'Thoát toàn màn hình',\n 'range.presets': 'Khoảng hiển thị',\n 'range.all': 'Tất cả',\n 'range.goTo': 'Đi tới ngày',\n 'range.goToSubmit': 'Đi tới',\n 'range.date': 'Ngày',\n 'range.time': 'Giờ',\n 'range.cancel': 'Huỷ',\n 'range.beforeData': 'Đang hiện nến sớm nhất đã tải',\n\n 'chartType.candlestick': 'Nến',\n 'chartType.line': 'Đường',\n 'chartType.area': 'Vùng',\n 'chartType.bar': 'Thanh',\n 'chartType.heikinAshi': 'Heikin-Ashi',\n 'chartType.hollowCandle': 'Nến rỗng',\n 'chartType.baseline': 'Đường cơ sở',\n 'chartType.volumeCandles': 'Nến khối lượng',\n 'chartType.equivolume': 'Equivolume',\n 'chartType.hlcArea': 'Vùng HLC',\n 'chartType.stepLine': 'Đường bậc thang',\n 'chartType.lineWithMarkers': 'Đường + điểm đánh dấu',\n\n 'watchlist.title': 'Danh mục theo dõi',\n\n 'status.connecting': 'Đang kết nối...',\n 'status.live': 'Trực tiếp',\n 'status.connectionFailed': 'Kết nối thất bại',\n 'status.loading': 'Đang tải biểu đồ...',\n\n 'settings.title': 'Cài đặt biểu đồ',\n 'settings.tab.style': 'Giao diện',\n 'settings.tab.display': 'Hiển thị',\n 'settings.tab.scale': 'Thang giá',\n 'settings.resetToDefaults': 'Khôi phục mặc định',\n 'settings.done': 'Xong',\n 'settings.section.candleColors': 'Màu nến',\n 'settings.section.background': 'Nền',\n\n 'hotkeys.title': 'Phím tắt',\n 'hotkeys.close': 'Đóng',\n 'hotkeys.gotIt': 'Đã hiểu',\n 'hotkeys.group.searchNavigation': 'Tìm kiếm & điều hướng',\n 'hotkeys.group.chartManipulation': 'Thao tác biểu đồ',\n 'hotkeys.group.touch': 'Cảm ứng (di động / máy tính bảng)',\n 'hotkeys.group.keyboard': 'Bàn phím',\n 'hotkeys.group.drawing': 'Vẽ',\n};\n\nexport const BUILTIN_LOCALES: Record<string, Partial<Record<MessageKey, string>>> = {\n en: EN_MESSAGES,\n vi: VI_MESSAGES,\n};\n\n/**\n * Resolve the widget's message table: built-in English as the base, the\n * requested built-in locale layered on top (falling back key-by-key to\n * English for anything that locale hasn't translated yet), then host\n * `messages` overrides layered last so they always win.\n */\nexport function resolveMessages(\n locale: string | undefined,\n overrides: Partial<Record<MessageKey, string>> | undefined,\n): Record<MessageKey, string> {\n const base = { ...EN_MESSAGES } as Record<MessageKey, string>;\n const localeTable = locale ? BUILTIN_LOCALES[locale] : undefined;\n if (localeTable) Object.assign(base, localeTable);\n if (overrides) Object.assign(base, overrides);\n return base;\n}\n\nexport type Translator = (key: MessageKey) => string;\n\nexport function createTranslator(messages: Record<MessageKey, string>): Translator {\n return (key: MessageKey) => messages[key] ?? EN_MESSAGES[key] ?? key;\n}\n","/**\n * How long a symbol/timeframe switch may run before the loading veil\n * appears. Faster loads just swap the chart in place — flashing a loader for\n * a 150 ms request reads as flicker, not feedback.\n */\nexport const LOADING_SHOW_DELAY_MS = 200;\n\n/**\n * Silhouette of the loading mark: a short rising run of candles as\n * [body top, body height, wick top, wick height, rising] in a 64 px box\n * (y grows downward).\n */\nconst SKELETON_CANDLES: readonly (readonly [number, number, number, number, boolean])[] = [\n [34, 16, 28, 26, false],\n [30, 14, 24, 26, true],\n [26, 18, 20, 30, true],\n [30, 10, 24, 22, false],\n [20, 16, 14, 28, true],\n [14, 18, 8, 30, true],\n [18, 10, 12, 20, false],\n [8, 18, 2, 30, true],\n];\n\n/**\n * Loading state for the chart area: a run of candles lit one after another\n * over a sweeping accent line. The status text is for screen readers only;\n * an error message is shown.\n *\n * - First load (nothing to show yet): opaque skeleton, shown immediately.\n * - Switch (a chart is already on screen): the old chart stays visible and is\n * veiled only if the load outlasts `LOADING_SHOW_DELAY_MS`.\n * - Failure: the label becomes the error message until the next load or a\n * successful retry ends it.\n */\nexport class WidgetLoadingOverlay {\n private readonly el: HTMLDivElement;\n private readonly label: HTMLDivElement;\n private showTimer: ReturnType<typeof setTimeout> | null = null;\n // Starts loading: the widget mounts before its first bars arrive.\n private phase: 'idle' | 'loading' | 'failed' = 'loading';\n\n constructor(parent: HTMLElement, private readonly loadingText: string) {\n this.el = document.createElement('div');\n this.el.className = 'tcw-loading-overlay';\n this.el.setAttribute('role', 'status');\n this.el.setAttribute('aria-live', 'polite');\n\n // Candles + label share a card: transparent on the opaque first-load\n // screen, a raised panel when veiling a chart so it reads over the candles.\n const card = document.createElement('div');\n card.className = 'tcw-loading-card';\n\n const candles = document.createElement('div');\n candles.className = 'tcw-loading-candles';\n candles.setAttribute('aria-hidden', 'true');\n SKELETON_CANDLES.forEach(([bodyTop, bodyHeight, wickTop, wickHeight, rising], i) => {\n const candle = document.createElement('span');\n candle.className = rising ? 'tcw-loading-candle tcw-loading-candle--up' : 'tcw-loading-candle';\n candle.style.setProperty('--tcw-body-top', `${bodyTop}px`);\n candle.style.setProperty('--tcw-body-h', `${bodyHeight}px`);\n candle.style.setProperty('--tcw-wick-top', `${wickTop}px`);\n candle.style.setProperty('--tcw-wick-h', `${wickHeight}px`);\n // A custom property, so a page-wide `animation-delay: 0 !important` reset can't flatten the wave.\n candle.style.setProperty('--tcw-delay', `${i * 110}ms`);\n candles.appendChild(candle);\n });\n card.appendChild(candles);\n\n const track = document.createElement('div');\n track.className = 'tcw-loading-track';\n track.setAttribute('aria-hidden', 'true');\n track.appendChild(document.createElement('span'));\n card.appendChild(track);\n\n this.label = document.createElement('div');\n this.label.className = 'tcw-loading-label';\n this.label.textContent = loadingText;\n card.appendChild(this.label);\n this.el.appendChild(card);\n\n parent.appendChild(this.el);\n }\n\n /**\n * Start a load. `hasContent`: a chart is already on screen to keep showing.\n * `immediate`: skip the show delay — the caller knows the load is slow.\n */\n begin(hasContent: boolean, immediate = false): void {\n this.phase = 'loading';\n this.clearTimer();\n this.label.textContent = this.loadingText;\n this.el.classList.remove('tcw-loading-overlay--error');\n this.el.classList.toggle('tcw-loading-overlay--veil', hasContent);\n if (!hasContent || immediate || this.isShown()) {\n this.el.classList.remove('tcw-loading-overlay--hidden');\n return;\n }\n this.showTimer = setTimeout(() => {\n this.showTimer = null;\n this.el.classList.remove('tcw-loading-overlay--hidden');\n }, LOADING_SHOW_DELAY_MS);\n }\n\n /** The load finished: fade out, or never appear if still within the delay. */\n end(): void {\n this.phase = 'idle';\n this.clearTimer();\n this.el.classList.add('tcw-loading-overlay--hidden');\n }\n\n /** The current load failed (a retry may still be running): show why. */\n fail(message: string): void {\n if (this.phase === 'idle') return;\n this.phase = 'failed';\n this.clearTimer();\n this.label.textContent = message;\n this.el.classList.add('tcw-loading-overlay--error');\n this.el.classList.remove('tcw-loading-overlay--hidden');\n }\n\n /** Whether a load is in progress (begun, not yet ended) — failed included. */\n isActive(): boolean {\n return this.phase !== 'idle';\n }\n\n /** Whether the current load failed and is waiting on a retry. */\n hasFailed(): boolean {\n return this.phase === 'failed';\n }\n\n /** Whether the overlay is on screen (or fading in). */\n isShown(): boolean {\n return !this.el.classList.contains('tcw-loading-overlay--hidden');\n }\n\n destroy(): void {\n this.clearTimer();\n this.el.remove();\n }\n\n private clearTimer(): void {\n if (this.showTimer !== null) {\n clearTimeout(this.showTimer);\n this.showTimer = null;\n }\n }\n}\n","import type { ChartType, DrawingToolType, FeaturesConfig, Theme, TimeFrame } from '@tradecanvas/commons';\nimport { Chart } from '../Chart.js';\nimport { DARK_THEME, LIGHT_THEME } from '@tradecanvas/commons';\nimport type { ActiveIndicatorInfo, ChartWidgetOptions, WidgetState, ChartSettingsState } from './types.js';\nimport { CHART_TYPES, INDICATORS, POPULAR_INDICATORS, DRAWING_TOOL_GROUPS, DEFAULT_SYMBOLS, DEFAULT_SETTINGS } from './widgetConfig.js';\nimport { injectWidgetStyles, removeWidgetStyles } from './WidgetStyles.js';\nimport { WidgetToolbar } from './WidgetToolbar.js';\nimport { WidgetDrawingSidebar } from './WidgetDrawingSidebar.js';\nimport { WidgetSettings } from './WidgetSettings.js';\nimport { WidgetStatusBar } from './WidgetStatusBar.js';\nimport { WidgetCommandPalette } from './WidgetCommandPalette.js';\nimport { WidgetSymbolSearch } from './WidgetSymbolSearch.js';\nimport { WidgetHotkeySheet } from './WidgetHotkeySheet.js';\nimport { WidgetReplayBar, DEFAULT_REPLAY_SPEED } from './WidgetReplayBar.js';\nimport { WidgetWatchlist, type WatchlistEntry } from './WidgetWatchlist.js';\nimport { WidgetAlertsPanel } from './WidgetAlertsPanel.js';\nimport { WidgetObjectTree, drawingTypeLabel } from './WidgetObjectTree.js';\nimport { WidgetIndicatorSettings } from './WidgetIndicatorSettings.js';\nimport { WidgetDrawingStyle } from './WidgetDrawingStyle.js';\nimport { DrawingTemplateStore } from './DrawingTemplateStore.js';\nimport { DrawingFavoritesStore } from './DrawingFavoritesStore.js';\nimport { availableTimeframes, initialTimeframeFavorites, timeframeLabel } from './widgetTimeframes.js';\nimport { WidgetGoToDate, utcToWallTime, wallTimeToUtc } from './WidgetGoToDate.js';\nimport { WidgetTooltip } from './WidgetTooltip.js';\nimport { WidgetIndicatorLegend, type IndicatorLegendRow } from './WidgetIndicatorLegend.js';\nimport { formatIndicatorValue, legendLineColor, legendNumbers } from './legendValues.js';\nimport { RANGE_PRESETS } from '@tradecanvas/core';\nimport { WidgetBracketBar } from './WidgetBracketBar.js';\nimport { AlertNotifier } from './AlertNotifier.js';\nimport { WidgetDepthLadder } from './WidgetDepthLadder.js';\nimport { WidgetDataWindow, type DataWindowModel } from './WidgetDataWindow.js';\nimport type { DepthData } from '@tradecanvas/commons';\nimport { encodeWidgetState, decodeWidgetState, readShareHash, buildShareUrl } from './widgetShareState.js';\nimport { DragDropImporter, resampleOHLCV, inferTimeframeMs } from '../io/index.js';\nimport type { DataSeries } from '@tradecanvas/commons';\nimport { timeframeToMs } from '@tradecanvas/commons';\nimport type { CommandItem } from './WidgetCommandPalette.js';\nimport { resolveMessages, createTranslator, type Translator } from './i18n.js';\nimport { WidgetLoadingOverlay } from './WidgetLoadingOverlay.js';\n\n/**\n * A local timeframe switch (resampling static data) that took at least this\n * long last time is announced with the loading veil before it runs, since the\n * main thread is about to be busy for several frames.\n */\nconst SLOW_LOCAL_SWITCH_MS = 48;\n/** Base series this long are assumed slow to resample before any timing exists. */\nconst LARGE_SERIES_BARS = 50_000;\n\n/** Upper bound on waiting for a paint — rAF never fires in a frame that isn't rendering. */\nconst PAINT_WAIT_MAX_MS = 100;\n\n/** Resolve once the browser has painted the current DOM state (or gave up waiting). */\nfunction afterPaint(): Promise<void> {\n return new Promise((resolve) => {\n if (typeof requestAnimationFrame !== 'function' || document.hidden) {\n setTimeout(resolve, 0);\n return;\n }\n const fallback = setTimeout(resolve, PAINT_WAIT_MAX_MS);\n requestAnimationFrame(() => setTimeout(() => {\n clearTimeout(fallback);\n resolve();\n }, 0));\n });\n}\n\n/** Distinct line colors for comparison overlays, cycled by add order. */\nconst COMPARE_COLORS = ['#4c8dff', '#a57cff', '#1398a8', '#e25592', '#8a93a3', '#62c895'];\n\n/** Gap between the on-chart indicator rows and the plot or pane edge, px. */\nconst LEGEND_INSET = 4;\n\n/** The widget pressed last: with several on a page, Alt+ shortcuts act on that one. */\nlet lastPressedWidget: ChartWidget | null = null;\n\n/** 1 when bar times are milliseconds, 1000 when they are seconds. */\nconst barTimeUnit = (data: ReadonlyArray<{ time: number }>): number =>\n (data[data.length - 1]?.time ?? 0) > 1e12 ? 1 : 1000;\n\nconst isTyping = (): boolean => {\n const active = document.activeElement as HTMLElement | null;\n return !!active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.tagName === 'SELECT' || active.isContentEditable);\n};\n\nexport class ChartWidget {\n private chart: Chart;\n private state: WidgetState;\n private toolbar: WidgetToolbar | null = null;\n private sidebar: WidgetDrawingSidebar | null = null;\n private settings: WidgetSettings | null = null;\n private statusBar: WidgetStatusBar | null = null;\n private goToDate: WidgetGoToDate | null = null;\n private readonly tooltip: WidgetTooltip;\n private indicatorLegend: WidgetIndicatorLegend | null = null;\n private legendFrame = 0;\n /**\n * Modals (settings, search, command palette, hotkeys) mount here: it carries\n * the theme tokens to `document.body`, and moves inside the widget while\n * the widget is fullscreen, where nothing outside it is shown.\n */\n private readonly portal = document.createElement('div');\n private readonly overlayHost = (): HTMLElement => {\n const host = document.fullscreenElement === this.root ? this.root : document.body;\n if (this.portal.parentElement !== host) host.appendChild(this.portal);\n return this.portal;\n };\n private readonly onRootPointerDown = () => { lastPressedWidget = this; };\n private readonly onFullscreenChange = () => {\n this.toolbar?.setFullscreen(document.fullscreenElement === this.root);\n if (this.portal.isConnected) this.overlayHost(); // an open modal follows\n };\n private commandPalette: WidgetCommandPalette | null = null;\n private symbolSearch: WidgetSymbolSearch | null = null;\n private hotkeySheet: WidgetHotkeySheet | null = null;\n private replayBar: WidgetReplayBar | null = null;\n private dragDrop: DragDropImporter | null = null;\n private alertsPanel: WidgetAlertsPanel | null = null;\n private objectTree: WidgetObjectTree | null = null;\n private indicatorSettings: WidgetIndicatorSettings | null = null;\n private drawingStyle: WidgetDrawingStyle | null = null;\n private bracketBar: WidgetBracketBar | null = null;\n private alertNotifier: AlertNotifier | null = null;\n private depthLadder: WidgetDepthLadder | null = null;\n private dataWindow: WidgetDataWindow | null = null;\n private lastHoverIndex: number | null = null;\n /** The bar the on-chart indicator values are read at; null = the latest. */\n private legendHoverIndex: number | null = null;\n private favoritesStore = new DrawingFavoritesStore();\n /** Timeframes pinned to the toolbar (same store shape as drawing favourites). */\n private timeframeFavorites = new DrawingFavoritesStore('tcw:tf-favorites');\n /** Timeframes on offer, shortest first. */\n private timeframes: TimeFrame[] = [];\n private watchlist: WidgetWatchlist | null = null;\n private watchlistSparkBuffer = new Map<string, number[]>();\n private sessionRefPrice: number | null = null;\n /** Per-symbol refPrice explicitly pushed by the host via `setWatchlistEntry` — takes precedence over `sessionRefPrice`. */\n private hostWatchlistRefPrice = new Map<string, number>();\n private watchlistInterval: ReturnType<typeof setInterval> | null = null;\n private replayPollInterval: ReturnType<typeof setInterval> | null = null;\n /** Bars revealed per second. */\n private replaySpeed = DEFAULT_REPLAY_SPEED;\n /** While picking the start bar: shades the bars right of the pointer. */\n private replayShade: HTMLDivElement | null = null;\n private layoutKeyPrefix: string | null = null;\n private layoutDebounceMs = 1500;\n private activeLayoutKey: string | null = null;\n private root: HTMLDivElement;\n private chartContainer: HTMLDivElement;\n private loading: WidgetLoadingOverlay;\n /** Bumped per stream connect; a connect that is no longer the latest leaves the UI to the newer one. */\n private connectSeq = 0;\n /** Bumped per local resample and widget.setData; a deferred local switch that is no longer the latest is skipped. */\n private localSeq = 0;\n /** Duration of the last local resample + setData, for SLOW_LOCAL_SWITCH_MS. */\n private lastLocalSwitchMs = 0;\n private destroyed = false;\n private options: ChartWidgetOptions;\n private symbols: string[];\n private settingsState: ChartSettingsState;\n private t: Translator;\n private adapter: import('@tradecanvas/commons').DataAdapter | null = null;\n private boundGlobalKeydown: ((e: KeyboardEvent) => void) | null = null;\n // Finest-resolution series the widget has seen. When no live adapter is\n // attached, switching to a coarser timeframe resamples from this base\n // instead of refetching. See `setData` / `applyTimeframeData`.\n private baseSeries: DataSeries | null = null;\n private baseTimeframeMs = 0;\n private compares: { id: string; symbol: string; color: string }[] = [];\n\n constructor(container: HTMLElement, options: ChartWidgetOptions = {}) {\n this.options = options;\n this.symbols = options.symbols ?? DEFAULT_SYMBOLS;\n // `numberLocale` lives in two places: the headless Chart gets it via\n // `chartOptions` (spread straight into `new Chart()` below) — but the\n // widget's own chrome (watchlist, alerts, hotkey sheet, settings panel)\n // reads `settingsState.numberLocale`, which otherwise stays on\n // DEFAULT_SETTINGS' 'en-US' until the host touches the Settings UI.\n // Seed it from the same option so both layers start in sync.\n this.settingsState = {\n ...DEFAULT_SETTINGS,\n ...(options.chartOptions?.numberLocale ? { numberLocale: options.chartOptions.numberLocale } : {}),\n };\n this.t = createTranslator(resolveMessages(options.locale, options.messages));\n\n // Resolve layout persistence config. Treated as opt-in — defaults to\n // `false` so existing apps don't suddenly start writing to localStorage.\n if (options.persistLayouts) {\n const cfg = options.persistLayouts === true ? {} : options.persistLayouts;\n this.layoutKeyPrefix = cfg.keyPrefix ?? 'tcw:layout:';\n this.layoutDebounceMs = cfg.debounceMs ?? 1500;\n }\n\n // Resolve theme\n const isDark = this.resolveIsDark(options.theme);\n const resolvedTheme = this.resolveTheme(options.theme);\n\n // The chart's feature flags; controls for switched-off features are left out.\n // Host overrides win per key (see the Chart below).\n const features: FeaturesConfig = {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: options.trading !== false,\n tradingContextMenu: false,\n volume: true,\n legend: true,\n crosshair: true,\n // Pro trading charts have no cursor-following OHLCV popup — just the\n // legend, which ChartWidget already renders. Off by default here\n // (the headless Chart's own default stays `true`); opt back in via\n // `chartOptions: { features: { crosshairTooltip: true } }`.\n crosshairTooltip: false,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...options.chartOptions?.features,\n };\n\n this.timeframes = availableTimeframes(options.timeframes, features.timeframes);\n // First run, or none of the saved pins is on offer here: start from the defaults.\n if (!this.timeframes.some((tf) => this.timeframeFavorites.has(tf))) {\n const initial = initialTimeframeFavorites(this.timeframes, features.defaultTimeframeFavorites, !!options.timeframes?.length);\n for (const tf of initial) this.timeframeFavorites.add(tf);\n }\n const requestedTimeframe = options.timeframe ?? '5m';\n const startTimeframe = !features.timeframes?.length || features.timeframes.includes(requestedTimeframe)\n ? requestedTimeframe\n : this.timeframes[0] ?? requestedTimeframe;\n\n // Initialize state\n this.state = {\n symbol: options.symbol ?? this.symbols[0] ?? 'BTCUSDT',\n timeframe: startTimeframe,\n chartType: options.chartOptions?.chartType ?? 'candlestick',\n isDark,\n activeIndicators: new Map(),\n activeTool: null,\n magnetEnabled: features.drawingMagnet !== false,\n stayInDrawing: false,\n // Static data (no adapter) has no connection to report.\n connectionState: options.adapter ? 'connecting' : 'disconnected',\n connectionMessage: options.adapter ? this.t('status.connecting') : '',\n };\n\n\n // 1. Inject styles\n injectWidgetStyles();\n\n // 2. Create DOM skeleton\n this.root = document.createElement('div');\n this.root.className = 'tcw-root';\n this.root.dataset.tcwTheme = isDark ? 'dark' : 'light';\n container.appendChild(this.root);\n this.tooltip = new WidgetTooltip(this.root);\n this.portal.className = 'tcw-root tcw-portal';\n this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme;\n\n // 3. Create toolbar\n if (options.toolbar !== false) {\n this.toolbar = new WidgetToolbar(\n this.root,\n {\n symbols: this.symbols,\n timeframes: this.timeframes.map((value) => ({ value, label: timeframeLabel(value) })),\n timeframeFavorites: this.pinnedTimeframes(),\n chartTypes: options.chartTypes\n ? CHART_TYPES.filter(ct => (options.chartTypes as ChartType[]).includes(ct.value))\n : CHART_TYPES,\n indicators: INDICATORS,\n popularIndicatorIds: POPULAR_INDICATORS,\n },\n {\n onSymbolClick: () => this.handleSymbolClick(),\n onTimeframe: (tf) => this.handleTimeframe(tf),\n onToggleTimeframeFavorite: (tf) => this.handleToggleTimeframeFavorite(tf),\n onChartType: (type) => this.handleChartType(type),\n onAddIndicator: (id) => this.handleAddIndicator(id),\n onScreenshot: () => this.chart.screenshot(),\n onSettings: () => this.openSettings(),\n onToggleTheme: () => this.handleToggleTheme(),\n onToggleReplay: () => this.toggleReplay(),\n onToggleAlerts: options.alerts !== false ? () => this.toggleAlerts() : undefined,\n onToggleObjects: options.objectTree !== false ? () => this.toggleObjects() : undefined,\n onBracket: options.trading !== false ? (side) => this.startBracket(side) : undefined,\n onToggleLadder: options.trading !== false && options.depthLadder ? () => this.depthLadder?.toggle() : undefined,\n onToggleFullscreen: options.fullscreen !== false && typeof document !== 'undefined' && document.fullscreenEnabled\n ? () => this.toggleFullscreen()\n : undefined,\n },\n this.t,\n );\n }\n\n // 4. Create body\n const body = document.createElement('div');\n body.className = 'tcw-body';\n\n if (options.drawingTools !== false) {\n if (options.drawingFavorites) this.favoritesStore.seedDefaults(options.drawingFavorites);\n this.sidebar = new WidgetDrawingSidebar(\n body,\n { drawingToolGroups: DRAWING_TOOL_GROUPS, favorites: this.favoritesStore.list() as DrawingToolType[] },\n {\n onDrawingTool: (tool) => this.handleDrawingTool(tool),\n onCancelDrawing: () => this.handleCancelDrawing(),\n onToggleMagnet: features.drawingMagnet !== false ? () => this.handleToggleMagnet() : undefined,\n onToggleFavorite: (tool) => this.handleToggleFavorite(tool),\n onUndo: () => this.chart.undo(),\n onRedo: () => this.chart.redo(),\n onClearDrawings: () => {\n this.chart.clearDrawings();\n this.state = { ...this.state, activeTool: null };\n this.updateUI();\n },\n onToggleStyle: () => this.drawingStyle?.toggle(),\n onToggleStayInDrawing: () => this.handleToggleStayInDrawing(),\n },\n );\n }\n\n this.chartContainer = document.createElement('div');\n this.chartContainer.className = 'tcw-chart-container';\n body.appendChild(this.chartContainer);\n\n // Loading state: covers the empty chart until the first\n // bars land, then veils the previous chart during slow switches.\n this.loading = new WidgetLoadingOverlay(this.chartContainer, this.t('status.loading'));\n\n // Watchlist sidebar (right side). Appended AFTER the chart container so\n // it sits to the right of the canvas in the flexbox row.\n if (options.watchlist) {\n this.watchlist = new WidgetWatchlist(body, this.symbols, {\n onSelect: (sym) => { void this.setSymbol(sym); },\n }, this.t('watchlist.title'));\n this.watchlist.setActive(this.state.symbol);\n this.watchlist.setLocale(this.settingsState.numberLocale || undefined);\n }\n\n this.root.appendChild(body);\n\n // 5. Create chart\n this.chart = new Chart(this.chartContainer, {\n chartType: this.state.chartType,\n theme: resolvedTheme,\n autoScale: true,\n crosshair: { mode: 'magnet' },\n ...options.chartOptions,\n // `features` is merged explicitly (host overrides win per-key) rather\n // than inherited wholesale from the `...options.chartOptions` spread\n // above — otherwise passing e.g. `chartOptions: { features: { x } }`\n // would silently drop every other default.\n features,\n });\n\n // New bars end the loading state, whoever supplied them (stream snapshot,\n // widget.setData, or the host calling getChart().setData directly); stream\n // errors surface in the status bar and, mid-load, on the loading veil.\n this.chart.on('dataUpdate', (e) => this.handleDataUpdate(e.payload));\n\n // Drag-and-drop CSV / JSON onto the chart container — instant data load.\n // Opt-out via `dragDropImport: false`. The adapter (live stream) keeps\n // running but the next bar update will append to whatever we just\n // loaded — that's the expected behavior when overlaying historical data.\n if (options.dragDropImport !== false) {\n this.dragDrop = new DragDropImporter(this.chartContainer, {\n onData: (data, result, file) => {\n this.setData(data);\n this.toast(`Loaded ${result.data.length} bars from ${file.name}` + (result.skipped > 0 ? ` (${result.skipped} skipped)` : ''));\n },\n onError: (err, file) => {\n this.toast(`${file.name}: ${err.message}`, 'error');\n },\n });\n this.dragDrop.attach();\n }\n\n // 6. Create status bar\n if (options.statusBar !== false) {\n const range = options.rangeBar !== false;\n this.statusBar = new WidgetStatusBar(this.root, range ? {\n presets: RANGE_PRESETS,\n presetLabels: { All: this.t('range.all') },\n groupLabel: this.t('range.presets'),\n goToLabel: this.t('range.goTo'),\n onPreset: (preset) => this.chart.setVisibleRangePreset(preset),\n onGoTo: () => this.toggleGoToDate(),\n } : undefined);\n if (range) {\n this.goToDate = new WidgetGoToDate(this.root, {\n title: this.t('range.goTo'),\n date: this.t('range.date'),\n time: this.t('range.time'),\n submit: this.t('range.goToSubmit'),\n cancel: this.t('range.cancel'),\n }, ({ date, time }) => this.goToWallTime(date, time));\n }\n }\n\n // 7. Create settings (lazy, not appended until opened)\n if (options.settings !== false) {\n this.settings = new WidgetSettings({\n onChange: (patch) => this.applySettings(patch),\n onReset: () => this.resetSettings(),\n onClose: () => {},\n }, this.t, { barCountdown: features.barCountdown, logScale: features.logScale }, this.overlayHost);\n }\n\n // 8a. Symbol search\n this.symbolSearch = new WidgetSymbolSearch({\n onPick: (sym) => { void this.setSymbol(sym); },\n onClose: () => {},\n }, this.overlayHost);\n this.hotkeySheet = new WidgetHotkeySheet({ onClose: () => {} }, this.t, this.overlayHost);\n\n // The sidebar follows the chart's drawing tool: finished, cancelled with\n // Esc, or kept for the next drawing in stay-in-drawing mode.\n this.chart.on('drawingToolChange', (e) => {\n const tool = (e.payload as { tool: DrawingToolType | null }).tool;\n if (tool === this.state.activeTool) return;\n this.state = { ...this.state, activeTool: tool };\n this.updateUI();\n });\n\n // The indicator list mirrors the chart's indicators, whoever adds or removes them.\n this.chart.on('indicatorAdd', () => this.syncIndicatorsFromChart());\n this.chart.on('indicatorRemove', () => this.syncIndicatorsFromChart());\n\n // The indicators on the chart itself, instead of toolbar chips that overflow.\n if (options.indicatorLegend !== false) {\n this.chart.setPaneTitlesVisible(false);\n this.indicatorLegend = new WidgetIndicatorLegend(this.chartContainer, {\n onToggleVisible: (iid, visible) => {\n this.chart.setIndicatorVisible(iid, visible);\n this.scheduleLegend();\n if (this.objectTree?.isOpen()) this.refreshObjects();\n },\n onSettings: (iid) => this.openIndicatorSettings(iid),\n onRemove: (iid) => this.handleRemoveIndicator(iid),\n }, {\n show: this.t('legend.show'),\n hide: this.t('legend.hide'),\n settings: this.t('legend.settings'),\n remove: this.t('legend.remove'),\n collapse: this.t('legend.collapse'),\n expand: this.t('legend.expand'),\n });\n this.chart.on('crosshairMove', (e) => {\n const p = e.payload as { barIndex?: number };\n this.legendHoverIndex = typeof p.barIndex === 'number' ? p.barIndex : null;\n this.scheduleLegend();\n });\n // Off the chart, the values go back to the latest bar.\n this.chart.on('crosshairLeave', () => {\n this.legendHoverIndex = null;\n this.scheduleLegend();\n });\n for (const event of ['indicatorUpdate', 'dataUpdate', 'resize', 'paneResize', 'themeChange'] as const) {\n this.chart.on(event, () => this.scheduleLegend());\n }\n }\n\n // Replay: while picking, a click starts the replay at that bar; during a\n // replay it jumps the cursor there.\n this.chart.on('barClick', (e) => {\n if (!this.replayBar?.isMounted()) return;\n const idx = (e.payload as { barIndex?: number }).barIndex;\n if (typeof idx !== 'number') return;\n if (this.replayBar.getMode() === 'select') {\n this.startReplayAt(idx);\n return;\n }\n if (this.chart.getReplayState() === 'playing') this.chart.replayPause();\n this.chart.replaySeek(idx);\n this.replayBar.setState('paused');\n });\n // While picking the start bar, shade the bars that would be hidden.\n this.chart.on('crosshairMove', (e) => {\n if (this.replayBar?.getMode() !== 'select' || !this.replayBar.isMounted()) return;\n const point = (e.payload as { point?: { x: number } | null }).point;\n this.positionReplayShade(point?.x ?? null);\n });\n\n // Data Window — precise OHLCV + indicator values at the hovered bar.\n this.dataWindow = new WidgetDataWindow(this.root, { formatPrice: (p) => this.formatAlertPrice(p) });\n this.chart.on('crosshairMove', (e) => {\n const p = e.payload as { barIndex?: number };\n this.lastHoverIndex = typeof p.barIndex === 'number' ? p.barIndex : null;\n if (this.dataWindow?.isOpen()) this.dataWindow.render(this.buildDataWindowModel());\n });\n\n // Drawing style + templates popover (paired with the sidebar palette button)\n if (options.drawingTools !== false) {\n this.drawingStyle = new WidgetDrawingStyle(\n this.root,\n {\n onStyleChange: (style) => {\n this.chart.setDrawingStyle(style);\n this.chart.setSelectedDrawingStyle(style);\n },\n getStyle: () => this.chart.getDrawingStyle(),\n },\n new DrawingTemplateStore(),\n );\n }\n\n // Bracket-order placement: floating confirm/cancel bar + event wiring.\n if (options.trading !== false) {\n this.bracketBar = new WidgetBracketBar(this.root, {\n onConfirm: () => this.chart.confirmBracket(),\n onCancel: () => {\n this.chart.cancelBracket();\n this.bracketBar?.hide();\n },\n });\n this.chart.on('bracketPlace', (e) => {\n const b = e.payload;\n this.bracketBar?.hide();\n this.toast(`${b.side === 'buy' ? 'Long' : 'Short'} bracket placed · ${b.riskReward.toFixed(2)}R`);\n });\n\n // Depth-of-market ladder (opt-in; fed via widget.setDepth)\n if (options.depthLadder) {\n this.depthLadder = new WidgetDepthLadder(this.root, {\n onTrade: (side, price) => {\n this.chart.placeOrderIntent({ side, type: 'limit', price });\n this.toast(`${side === 'buy' ? 'Buy' : 'Sell'} limit @ ${this.formatAlertPrice(price)}`);\n },\n formatPrice: (p) => this.formatAlertPrice(p),\n });\n }\n // Esc-cancel originates in the chart; reflect it in the bar.\n this.chart.on('dataUpdate', (e) => {\n const p = e.payload as { bracket?: string };\n if (p && p.bracket === 'cancelled') this.bracketBar?.hide();\n });\n }\n\n // 8a-bis. Price alerts panel (floating popover, toggled from the bell button)\n if (options.alerts !== false) {\n this.alertsPanel = new WidgetAlertsPanel(this.root, {\n onAdd: (price, condition, message, channel, label) => {\n this.chart.addAlert(price, condition, message, channel, label);\n },\n onRemove: (id) => this.chart.removeAlert(id),\n onClear: () => this.chart.clearAlerts(),\n getChannelValue: (channel) => this.getAlertChannelValue(channel),\n formatPrice: (p) => this.formatAlertPrice(p),\n });\n\n // Keep the panel list and toasts in sync with the chart's AlertManager.\n this.chart.on('alertAdd', () => this.refreshAlerts());\n this.chart.on('alertRemove', () => this.refreshAlerts());\n this.chart.on('alertUpdate', () => this.refreshAlerts());\n if (options.alertNotifications) {\n this.alertNotifier = new AlertNotifier(options.alertNotifications);\n }\n this.chart.on('alertTriggered', (e) => {\n const p = e.payload;\n const text = `Price ${this.formatAlertPrice(p.price)}${p.message ? ` — ${p.message}` : ''}`;\n this.toast(`🔔 Alert: ${text}`, 'info');\n this.alertNotifier?.notify(text);\n this.refreshAlerts();\n });\n }\n\n // 8a-ter. Object tree (indicators + drawings manager)\n if (options.objectTree !== false) {\n this.indicatorSettings = new WidgetIndicatorSettings(this.root, {\n onApply: (instanceId, params) => {\n this.chart.updateIndicator(instanceId, params);\n this.syncIndicatorsFromChart(); // the chip shows the parameters\n },\n onClose: () => {},\n });\n this.objectTree = new WidgetObjectTree(this.root, {\n onRemoveIndicator: (iid) => this.handleRemoveIndicator(iid),\n onConfigureIndicator: (iid) => this.openIndicatorSettings(iid),\n onToggleIndicatorVisible: (iid, visible) => {\n this.chart.setIndicatorVisible(iid, visible);\n this.refreshObjects();\n this.scheduleLegend();\n },\n onRemoveDrawing: (id) => {\n this.chart.removeDrawing(id);\n this.refreshObjects();\n },\n onToggleDrawingVisible: (id, visible) => {\n this.chart.setDrawingVisible(id, visible);\n this.refreshObjects();\n },\n onToggleDrawingLocked: (id, locked) => {\n this.chart.setDrawingLocked(id, locked);\n this.refreshObjects();\n },\n onAddCompare: features.compareSymbols !== false ? () => this.handleAddCompare() : undefined,\n onRemoveCompare: (id) => this.handleRemoveCompare(id),\n });\n const refresh = () => { if (this.objectTree?.isOpen()) this.refreshObjects(); };\n this.chart.on('drawingCreate', refresh);\n this.chart.on('drawingRemove', refresh);\n this.chart.on('indicatorAdd', refresh);\n this.chart.on('indicatorRemove', refresh);\n }\n\n // 8b. Command palette\n this.commandPalette = new WidgetCommandPalette({\n onIndicator: (id) => this.handleAddIndicator(id),\n onChartType: (type) => this.handleChartType(type),\n onDrawingTool: (tool) => this.handleDrawingTool(tool),\n onTimeframe: (tf) => this.handleTimeframe(tf),\n onAction: (id) => this.handleAction(id),\n onClose: () => {},\n }, this.overlayHost);\n\n this.boundGlobalKeydown = (e: KeyboardEvent) => {\n if (this.replayBar?.isMounted() && this.handleReplayKey(e)) return;\n if ((e.ctrlKey || e.metaKey) && e.key === 'k') {\n e.preventDefault();\n this.toggleCommandPalette();\n } else if ((e.ctrlKey || e.metaKey) && (e.key === 'p' || e.key === 'P')) {\n // Ctrl/Cmd+P → symbol search (matches Bloomberg / many trading UIs)\n e.preventDefault();\n this.symbolSearch?.open(this.symbols, this.state.symbol);\n } else if (e.altKey && !e.ctrlKey && !e.metaKey && (e.code === 'KeyI' || e.code === 'KeyG')) {\n // By key position: on macOS Alt+G types \"©\".\n if (isTyping() || (lastPressedWidget !== null && lastPressedWidget !== this)) return;\n if (e.code === 'KeyI') {\n // Alt+I → invert the price scale.\n e.preventDefault();\n this.applySettings({ invertScale: !this.settingsState.invertScale });\n } else if (this.goToDate) {\n // Alt+G → go to date.\n e.preventDefault();\n this.toggleGoToDate();\n }\n } else if (e.key === '?' && !e.ctrlKey && !e.metaKey && !e.altKey) {\n // Only fire when the user isn't typing into an input.\n const active = document.activeElement as HTMLElement | null;\n if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable)) return;\n e.preventDefault();\n this.hotkeySheet?.open();\n }\n };\n document.addEventListener('keydown', this.boundGlobalKeydown);\n document.addEventListener('fullscreenchange', this.onFullscreenChange);\n this.root.addEventListener('pointerdown', this.onRootPointerDown, true);\n\n // 9. Connect stream\n if (options.adapter) {\n this.adapter = options.adapter;\n this.connectStream();\n }\n\n // Watchlist live-update loop. 1s cadence keeps DOM churn low while still\n // feeling responsive; for sub-second visual response, apps can call\n // `setWatchlistEntry` directly from their own WebSocket.\n if (this.watchlist) {\n this.watchlistInterval = setInterval(() => this.tickWatchlist(), 1000);\n }\n\n // Initial UI update\n this.updateUI();\n\n // 9. Fire onReady\n options.onReady?.(this.chart);\n\n // Deep-link restore: apply a `#tcw=` view from the URL when enabled.\n if (options.shareUrl && typeof location !== 'undefined') {\n const encoded = readShareHash(location.hash);\n if (encoded) void this.importState(encoded);\n }\n }\n\n // --- Public API ---\n\n /** Replace the searchable symbol catalog. Does not change the active symbol. */\n setSymbols(symbols: string[]): void {\n this.symbols = symbols;\n this.watchlist?.setSymbols(symbols);\n }\n\n async setSymbol(symbol: string): Promise<void> {\n // Flush the outgoing symbol's layout BEFORE switching state, so the\n // saved snapshot reflects what the user actually saw under that ticker.\n this.flushActiveLayout();\n this.state = { ...this.state, symbol };\n this.sessionRefPrice = null;\n this.options.onSymbolChange?.(symbol);\n this.updateUI();\n this.watchlist?.setActive(symbol);\n if (this.adapter) {\n await this.connectStream();\n }\n }\n\n /**\n * Push an entry into the watchlist (e.g., from your own WebSocket).\n * Call with the symbols you care about; the active symbol is updated\n * automatically from the chart's live data.\n *\n * A host-supplied `refPrice` takes precedence over the widget's own\n * session-open guess for that symbol — including the active one, so the\n * auto-tick loop stops clobbering it (see `tickWatchlist`).\n */\n setWatchlistEntry(symbol: string, entry: Partial<WatchlistEntry>): void {\n if (entry.refPrice !== undefined) {\n this.hostWatchlistRefPrice.set(symbol, entry.refPrice);\n }\n this.watchlist?.setEntry(symbol, entry);\n }\n\n private tickWatchlist(): void {\n if (!this.watchlist) return;\n const data = this.chart.getData();\n if (data.length === 0) return;\n const last = data[data.length - 1];\n const hostRef = this.hostWatchlistRefPrice.get(this.state.symbol);\n // Reference price: first bar of the loaded slice — that's the closest\n // approximation of \"session open\" without timezone bookkeeping. Only\n // used as a fallback; a refPrice the host already pushed via\n // `setWatchlistEntry` (even for the active symbol) always wins.\n if (hostRef === undefined && this.sessionRefPrice === null) {\n this.sessionRefPrice = data[0].open;\n }\n\n const buf = this.watchlistSparkBuffer.get(this.state.symbol) ?? [];\n buf.push(last.close);\n if (buf.length > 40) buf.shift();\n this.watchlistSparkBuffer.set(this.state.symbol, buf);\n\n this.watchlist.setEntry(this.state.symbol, {\n lastPrice: last.close,\n refPrice: hostRef ?? this.sessionRefPrice ?? data[0].open,\n sparkline: buf.slice(),\n });\n }\n\n /** Ignored when the chart's `features.timeframes` whitelist leaves `tf` out. */\n async setTimeframe(tf: TimeFrame): Promise<void> {\n if (!this.chart.isTimeframeAllowed(tf)) return;\n this.state = { ...this.state, timeframe: tf };\n this.options.onTimeframeChange?.(tf);\n this.updateUI();\n if (this.adapter) {\n // Live adapter owns the data — refetch at the native resolution.\n await this.connectStream();\n return;\n }\n if (this.options.resampleTimeframes === false) return;\n // Static data: aggregate the base series locally. Lazily adopt whatever is\n // currently on the chart as the base if the host fed it via getChart().\n if (!this.baseSeries) {\n const current = this.chart.getData();\n if (current.length > 0) {\n this.baseSeries = current;\n this.baseTimeframeMs = inferTimeframeMs(current);\n }\n }\n await this.switchLocalTimeframe();\n }\n\n setTheme(theme: import('@tradecanvas/commons').ThemeName | Theme): void {\n const isDark = this.resolveIsDark(theme);\n const resolved = this.resolveTheme(theme);\n this.state = { ...this.state, isDark };\n this.root.dataset.tcwTheme = isDark ? 'dark' : 'light';\n this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme;\n this.chart.setTheme(resolved);\n this.updateUI();\n }\n\n getChart(): Chart {\n return this.chart;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n if (this.boundGlobalKeydown) {\n document.removeEventListener('keydown', this.boundGlobalKeydown);\n }\n document.removeEventListener('fullscreenchange', this.onFullscreenChange);\n this.root.removeEventListener('pointerdown', this.onRootPointerDown, true);\n this.tooltip.destroy();\n if (this.legendFrame) cancelAnimationFrame(this.legendFrame);\n this.indicatorLegend?.destroy();\n if (lastPressedWidget === this) lastPressedWidget = null;\n this.portal.remove();\n if (document.fullscreenElement === this.root) void document.exitFullscreen().catch(() => {});\n this.flushActiveLayout();\n this.commandPalette?.destroy();\n this.symbolSearch?.destroy();\n this.hotkeySheet?.destroy();\n if (this.replayPollInterval) clearInterval(this.replayPollInterval);\n this.replayShade?.remove();\n this.replayBar?.destroy();\n this.dragDrop?.detach();\n this.alertsPanel?.destroy();\n this.objectTree?.destroy();\n this.indicatorSettings?.destroy();\n this.drawingStyle?.destroy();\n this.bracketBar?.destroy();\n this.alertNotifier?.destroy();\n this.depthLadder?.destroy();\n this.dataWindow?.destroy();\n if (this.watchlistInterval) clearInterval(this.watchlistInterval);\n this.watchlist?.destroy();\n this.toolbar?.destroy();\n this.sidebar?.destroy();\n this.settings?.destroy();\n this.statusBar?.destroy();\n this.goToDate?.destroy();\n this.loading.destroy();\n this.chart.destroy();\n this.root.remove();\n removeWidgetStyles();\n }\n\n // --- Internal handlers ---\n\n private handleSymbolClick(): void {\n // Opens the fuzzy search modal. The cycle-through behaviour the toolbar\n // used to do is gone — a real search scales past 3-4 symbols and matches\n // what users expect from professional trading terminals.\n this.symbolSearch?.open(this.symbols, this.state.symbol);\n }\n\n private handleTimeframe(tf: TimeFrame): void {\n void this.setTimeframe(tf);\n }\n\n /** Fill the screen with the widget, or leave fullscreen. */\n toggleFullscreen(): void {\n if (document.fullscreenElement === this.root) {\n void document.exitFullscreen().catch(() => {});\n return;\n }\n this.root.requestFullscreen().catch((err: unknown) => {\n this.toast(err instanceof Error ? err.message : 'Fullscreen is not available', 'error');\n });\n }\n\n /** The display timezone from the settings: minutes east of UTC, null = local. */\n private displayTzOffset(): number | null {\n const tz = this.settingsState.timezone;\n return tz === 'local' || !Number.isFinite(Number(tz)) ? null : Number(tz);\n }\n\n private toggleGoToDate(): void {\n if (!this.goToDate) return;\n if (this.goToDate.isOpen()) {\n this.goToDate.close();\n return;\n }\n const data = this.chart.getData();\n if (data.length === 0) return;\n this.goToDate.open(\n utcToWallTime(data[data.length - 1].time * barTimeUnit(data), this.displayTzOffset()),\n this.root.querySelector('[data-role=\"goto\"]'),\n );\n }\n\n private goToWallTime(date: string, time: string): void {\n const ms = wallTimeToUtc(date, time, this.displayTzOffset());\n const data = this.chart.getData();\n if (ms === null || data.length === 0) return;\n const ts = ms / barTimeUnit(data); // the bars' own unit\n this.chart.goToTime(ts);\n if (ts < data[0].time) this.toast(this.t('range.beforeData'));\n }\n\n /** Pinned timeframes that are still on offer, shortest first. */\n private pinnedTimeframes(): TimeFrame[] {\n const pinned = this.timeframeFavorites.list();\n return this.timeframes.filter((tf) => pinned.includes(tf));\n }\n\n private handleToggleTimeframeFavorite(tf: TimeFrame): void {\n this.timeframeFavorites.toggle(tf);\n this.toolbar?.setTimeframeFavorites(this.pinnedTimeframes());\n this.updateUI();\n }\n\n /**\n * Load the widget's base series. Prefer this over `getChart().setData()` so\n * client-side timeframe resampling has a finest-resolution source to\n * aggregate from. The data is rendered at the current timeframe (resampled\n * when that timeframe is coarser than the data's native spacing).\n */\n setData(data: DataSeries): void {\n this.localSeq++; // supersedes a local switch still waiting to run\n this.baseSeries = data;\n this.baseTimeframeMs = inferTimeframeMs(data);\n this.applyTimeframeData();\n // Static data is loaded the moment it's set, even an empty series. With a\n // live adapter the stream's own load decides (connectStream).\n if (!this.adapter) this.loading.end();\n }\n\n /**\n * Local timeframe switch. When it is expected to block the main thread for\n * several frames, veil the chart first and let that paint — otherwise the\n * click would look ignored until the new chart pops in.\n */\n private async switchLocalTimeframe(): Promise<void> {\n if (!this.baseSeries) return;\n const seq = ++this.localSeq;\n const expectSlow = this.lastLocalSwitchMs >= SLOW_LOCAL_SWITCH_MS\n || this.baseSeries.length >= LARGE_SERIES_BARS;\n try {\n if (expectSlow) {\n this.loading.begin(this.chart.getData().length > 0, true);\n await afterPaint();\n // Superseded: the newer switch or setData() ends the loading state.\n if (seq !== this.localSeq || this.destroyed) return;\n }\n this.applyTimeframeData();\n } finally {\n // Also on a throw (bad data, a failing custom indicator) — never leave\n // the veil up.\n if (seq === this.localSeq) this.loading.end();\n }\n }\n\n /** Render the base series at the active timeframe, resampling when coarser. */\n private applyTimeframeData(): void {\n if (!this.baseSeries) return;\n const started = performance.now();\n const targetMs = timeframeToMs(this.state.timeframe);\n if (this.baseTimeframeMs > 0 && targetMs > this.baseTimeframeMs) {\n const weekStartsOn = this.options.weekStartsOn ?? 1;\n this.chart.setData(resampleOHLCV(this.baseSeries, this.state.timeframe, { weekStartsOn }));\n } else {\n this.chart.setData(this.baseSeries);\n }\n this.lastLocalSwitchMs = performance.now() - started;\n }\n\n private handleDataUpdate(payload: unknown): void {\n if (!payload || typeof payload !== 'object') return;\n const p = payload as { length?: number; error?: string; connection?: { state?: string } };\n if (typeof p.length === 'number') {\n if (p.length > 0 && this.loading.isActive()) {\n this.loading.end();\n // A retry after a failed load just delivered history.\n if (this.state.connectionState === 'error') this.setConnectionState('connected', this.t('status.live'));\n }\n return;\n }\n if (p.error !== undefined) {\n // Only a failed *load* is reported from the error itself. Errors outside\n // one can be transient (a single failed poll on a healthy connection);\n // the status bar follows the stream's connection state below instead.\n if (this.loading.isActive()) {\n this.loading.fail(this.t('status.connectionFailed'));\n this.setConnectionState('error', p.error || this.t('status.connectionFailed'));\n }\n return;\n }\n switch (p.connection?.state) {\n case 'connected':\n // A retry that brought back an empty history ends a failed load too.\n if (this.loading.hasFailed()) this.loading.end();\n if (!this.loading.isActive() && this.state.connectionState !== 'connected') {\n this.setConnectionState('connected', this.t('status.live'));\n }\n break;\n case 'reconnecting':\n if (!this.loading.isActive()) this.setConnectionState('connecting', this.t('status.connecting'));\n break;\n case 'error':\n if (!this.loading.isActive()) this.setConnectionState('error', this.t('status.connectionFailed'));\n break;\n }\n }\n\n private setConnectionState(connectionState: WidgetState['connectionState'], connectionMessage: string): void {\n this.state = { ...this.state, connectionState, connectionMessage };\n this.updateUI();\n }\n\n private toggleAlerts(): void {\n if (!this.alertsPanel) return;\n this.alertsPanel.toggle();\n if (this.alertsPanel.isOpen()) this.refreshAlerts();\n }\n\n private handleToggleFavorite(tool: DrawingToolType): void {\n const pinned = this.favoritesStore.toggle(tool);\n this.sidebar?.setFavorites(this.favoritesStore.list());\n this.toast(pinned ? 'Pinned to favorites' : 'Unpinned');\n }\n\n /** Encode the current view (symbol, timeframe, chart type, scale, indicators, drawings). */\n exportState(): string {\n const indicators = this.chart.getActiveIndicators().map((i) => ({\n id: i.id,\n params: i.params as Record<string, number | string | boolean>,\n }));\n return encodeWidgetState({\n v: 1,\n symbol: this.state.symbol,\n timeframe: this.state.timeframe,\n chartType: this.state.chartType,\n scaleMode: this.chart.getScaleMode(),\n indicators,\n drawings: this.chart.getDrawings(),\n });\n }\n\n /** Restore a view from an `exportState()` string. Returns false if malformed. */\n async importState(encoded: string): Promise<boolean> {\n const s = decodeWidgetState(encoded);\n if (!s) return false;\n\n // Symbol/timeframe first so any stream/layout restore happens before we\n // overlay the shared view on top.\n if (s.symbol && s.symbol !== this.state.symbol) await this.setSymbol(s.symbol);\n if (s.timeframe && s.timeframe !== this.state.timeframe) await this.setTimeframe(s.timeframe);\n\n if (s.chartType) this.handleChartType(s.chartType);\n this.chart.setScaleMode(s.scaleMode);\n\n for (const instanceId of [...this.state.activeIndicators.keys()]) this.chart.removeIndicator(instanceId);\n for (const ind of s.indicators) this.chart.addIndicator(ind.id, ind.params);\n this.chart.setDrawings(s.drawings);\n this.updateUI();\n return true;\n }\n\n /** Copy the chart image to the clipboard, with a toast on success/failure. */\n async copyChartImage(): Promise<void> {\n const ok = await this.chart.copyScreenshot();\n this.toast(ok ? 'Chart image copied' : 'Copy failed — image clipboard unavailable', ok ? 'info' : 'error');\n }\n\n /** Copy a shareable deep-link (current view encoded in the URL hash) to the clipboard. */\n async copyShareLink(): Promise<void> {\n const base = typeof location !== 'undefined' ? location.href : '';\n const url = buildShareUrl(base, this.exportState());\n try {\n await navigator.clipboard.writeText(url);\n this.toast('Share link copied');\n } catch {\n this.toast('Copy failed — clipboard unavailable', 'error');\n }\n }\n\n /** Feed order-book depth to the chart overlay, depth ladder, and heatmap. */\n setDepth(depth: DepthData | null): void {\n this.chart.setDepthData(depth);\n this.depthLadder?.setData(depth);\n if (depth) this.chart.pushDepthSnapshot(depth);\n }\n\n /** Begin a draggable bracket order at the latest price and show the action bar. */\n startBracket(side: 'buy' | 'sell'): void {\n if (this.chart.startBracket(side)) {\n this.bracketBar?.show(side);\n }\n }\n\n private buildDataWindowModel(): DataWindowModel {\n const data = this.chart.getData();\n const idx = this.lastHoverIndex;\n if (idx === null || idx < 0 || idx >= data.length) {\n return { ohlc: null, change: 0, changePct: 0, indicators: [] };\n }\n const bar = data[idx];\n const prevClose = idx > 0 ? data[idx - 1].close : bar.open;\n const change = bar.close - prevClose;\n const changePct = prevClose !== 0 ? (change / prevClose) * 100 : 0;\n\n const indicators = this.chart.getActiveIndicators().map((ind) => {\n const series = this.chart.getIndicatorOutput(ind.instanceId)?.series;\n const point = series?.[idx] ?? null;\n const values = point\n ? Object.entries(point)\n .filter(([, v]) => typeof v === 'number' && Number.isFinite(v))\n .map(([key, v]) => ({ key, value: v as number }))\n : [];\n return { name: ind.descriptor.name, values };\n }).filter((i) => i.values.length > 0);\n\n return {\n ohlc: { open: bar.open, high: bar.high, low: bar.low, close: bar.close, volume: bar.volume },\n change,\n changePct,\n indicators,\n };\n }\n\n private toggleDataWindow(): void {\n if (!this.dataWindow) return;\n this.dataWindow.toggle();\n if (this.dataWindow.isOpen()) this.dataWindow.render(this.buildDataWindowModel());\n }\n\n private toggleObjects(): void {\n if (!this.objectTree) return;\n this.objectTree.toggle();\n if (this.objectTree.isOpen()) this.refreshObjects();\n }\n\n private openIndicatorSettings(instanceId: string): void {\n if (!this.indicatorSettings) return;\n const ind = this.chart.getActiveIndicators().find((i) => i.instanceId === instanceId);\n if (!ind) return;\n this.indicatorSettings.open({\n instanceId,\n name: ind.descriptor.name,\n defaults: ind.descriptor.defaultConfig,\n params: ind.params,\n });\n }\n\n private refreshObjects(): void {\n if (!this.objectTree) return;\n const indicators = this.chart.getActiveIndicators().map((i) => ({\n instanceId: i.instanceId,\n name: i.descriptor.name,\n visible: i.visible,\n }));\n const drawings = this.chart.getDrawings().map((d) => ({\n id: d.id,\n label: drawingTypeLabel(d.type),\n visible: d.visible,\n locked: d.locked,\n }));\n const compares = this.compares.map((c) => ({ id: c.id, label: c.symbol, color: c.color }));\n this.objectTree.setObjects(indicators, drawings, compares);\n }\n\n private async handleAddCompare(): Promise<void> {\n if (!this.adapter) {\n this.toast('Comparison needs a live data adapter', 'error');\n return;\n }\n const taken = new Set([this.state.symbol, ...this.compares.map((c) => c.symbol)]);\n const options = this.symbols.filter((s) => !taken.has(s));\n this.symbolSearch?.open(options.length ? options : this.symbols, this.state.symbol, (symbol) => {\n void this.addCompareSymbol(symbol);\n });\n }\n\n /** Overlay another symbol's normalized series. Fetches history via the adapter. */\n async addCompareSymbol(symbol: string): Promise<void> {\n if (!this.adapter || this.compares.some((c) => c.symbol === symbol)) return;\n const color = COMPARE_COLORS[this.compares.length % COMPARE_COLORS.length];\n const id = `cmp_${symbol}`;\n try {\n const bars = await this.adapter.fetchHistory(symbol, this.state.timeframe, this.options.historyLimit ?? 500);\n // Percent mode normalizes mixed-price symbols (e.g. BTC vs a $2 alt) onto\n // a shared % axis — the right default for comparison.\n if (this.compares.length === 0) this.chart.setCompareMode('percent');\n this.chart.addCompareSymbol(id, symbol, bars, color);\n this.compares = [...this.compares, { id, symbol, color }];\n this.refreshObjects();\n this.toast(`Comparing ${symbol}`);\n } catch (err: unknown) {\n this.toast(`${symbol}: ${err instanceof Error ? err.message : 'failed to load'}`, 'error');\n }\n }\n\n private handleRemoveCompare(id: string): void {\n this.chart.removeCompareSymbol(id);\n this.compares = this.compares.filter((c) => c.id !== id);\n this.refreshObjects();\n }\n\n /** Refetch every comparison overlay at the current symbol/timeframe. */\n private async refetchCompares(): Promise<void> {\n if (!this.adapter || this.compares.length === 0) return;\n // A comparison against the now-active symbol is redundant — drop it.\n const stale = this.compares.filter((c) => c.symbol === this.state.symbol);\n for (const c of stale) this.handleRemoveCompare(c.id);\n\n for (const c of this.compares) {\n try {\n const bars = await this.adapter.fetchHistory(c.symbol, this.state.timeframe, this.options.historyLimit ?? 500);\n this.chart.updateCompareData(c.id, bars);\n } catch { /* leave the stale overlay in place if the refetch fails */ }\n }\n }\n\n private refreshAlerts(): void {\n if (!this.alertsPanel) return;\n this.alertsPanel.setSources(this.buildAlertSources());\n this.alertsPanel.setAlerts(\n this.chart.getAlerts().map((a) => ({\n id: a.id,\n price: a.price,\n condition: a.condition,\n message: a.message,\n triggered: a.triggered,\n channel: a.channel,\n label: a.label,\n })),\n );\n }\n\n /** Price + every active indicator line, as selectable alert sources. */\n private buildAlertSources(): { channel: string; label: string }[] {\n const sources = [{ channel: 'price', label: 'Price' }];\n for (const ind of this.chart.getActiveIndicators()) {\n // Use the latest point — multi-output indicators (MACD, Stochastic) only\n // have all their lines populated once warmed up; the first point may not.\n const series = this.chart.getIndicatorOutput(ind.instanceId)?.series;\n const point = series && series.length > 0 ? series[series.length - 1] : null;\n const keys = point ? Object.keys(point).filter((k) => typeof point[k] === 'number') : [];\n for (const key of keys) {\n const label = keys.length > 1 ? `${ind.descriptor.name} ${key}` : ind.descriptor.name;\n sources.push({ channel: `${ind.instanceId}:${key}`, label });\n }\n }\n return sources;\n }\n\n /** Latest value for an alert source channel (price or indicator line). */\n private getAlertChannelValue(channel: string): number | null {\n const data = this.chart.getData();\n if (channel === 'price') return data.length > 0 ? data[data.length - 1].close : null;\n const sep = channel.indexOf(':');\n if (sep < 0 || data.length === 0) return null;\n const instanceId = channel.slice(0, sep);\n const key = channel.slice(sep + 1);\n const v = this.chart.getIndicatorOutput(instanceId)?.series?.[data.length - 1]?.[key];\n return typeof v === 'number' && Number.isFinite(v) ? v : null;\n }\n\n private formatAlertPrice(price: number): string {\n // No fixed precision config on the widget — pick digits from magnitude so\n // BTC (64,200.5) and a sub-dollar alt (0.04821) both read sensibly.\n const abs = Math.abs(price);\n const digits = abs >= 1000 ? 2 : abs >= 1 ? 4 : 6;\n const locale = this.settingsState.numberLocale || undefined;\n return price.toLocaleString(locale, { minimumFractionDigits: 2, maximumFractionDigits: digits });\n }\n\n private handleChartType(type: ChartType): void {\n this.state = { ...this.state, chartType: type };\n this.chart.setChartType(type);\n this.updateUI();\n }\n\n /**\n * Add another instance — picking EMA twice gives two EMAs (e.g. 20 and 50\n * once their settings are changed). Remove one from its chip.\n */\n private handleAddIndicator(indId: string): void {\n this.chart.addIndicator(indId); // the chip strip follows the indicatorAdd event\n }\n\n private handleRemoveIndicator(instanceId: string): void {\n this.chart.removeIndicator(instanceId);\n }\n\n private toggleCommandPalette(): void {\n if (this.commandPalette?.isOpen()) {\n this.commandPalette.close();\n return;\n }\n this.commandPalette?.open(this.buildCommandItems());\n }\n\n private buildCommandItems(): CommandItem[] {\n const items: CommandItem[] = [];\n\n for (const ind of INDICATORS) {\n items.push({\n id: ind.id,\n label: ind.name,\n category: 'indicator',\n active: [...this.state.activeIndicators.values()].some((a) => a.id === ind.id),\n });\n }\n\n for (const ct of CHART_TYPES) {\n items.push({\n id: ct.value,\n label: ct.label,\n category: 'chartType',\n active: this.state.chartType === ct.value,\n });\n }\n\n for (const group of DRAWING_TOOL_GROUPS) {\n for (const tool of group.tools) {\n items.push({\n id: tool.value,\n label: tool.label,\n category: 'drawing',\n active: this.state.activeTool === tool.value,\n });\n }\n }\n\n for (const tf of this.timeframes) {\n items.push({\n id: tf,\n label: timeframeLabel(tf),\n category: 'timeframe',\n active: this.state.timeframe === tf,\n });\n }\n\n items.push(\n { id: 'screenshot', label: 'Screenshot', category: 'action', shortcut: '' },\n { id: 'copyImage', label: 'Copy Chart Image', category: 'action' },\n { id: 'toggleTheme', label: 'Toggle Theme', category: 'action' },\n { id: 'settings', label: 'Settings', category: 'action' },\n { id: 'shareView', label: 'Share View (copy link)', category: 'action' },\n { id: 'autoFib', label: 'Auto Fibonacci (visible swing)', category: 'action' },\n { id: 'dataWindow', label: 'Toggle Data Window', category: 'action' },\n { id: 'clearDrawings', label: 'Clear All Drawings', category: 'action' },\n );\n\n return items;\n }\n\n private handleAction(id: string): void {\n switch (id) {\n case 'screenshot':\n this.chart.screenshot();\n break;\n case 'toggleTheme':\n this.handleToggleTheme();\n break;\n case 'settings':\n this.openSettings();\n break;\n case 'copyImage':\n void this.copyChartImage();\n break;\n case 'shareView':\n void this.copyShareLink();\n break;\n case 'autoFib': {\n const id = this.chart.autoFib();\n this.toast(id ? 'Auto Fibonacci added' : 'No clear swing in view');\n break;\n }\n case 'dataWindow':\n this.toggleDataWindow();\n break;\n case 'clearDrawings':\n this.chart.clearDrawings();\n this.state = { ...this.state, activeTool: null };\n this.updateUI();\n break;\n }\n }\n\n private handleDrawingTool(tool: DrawingToolType): void {\n this.state = { ...this.state, activeTool: tool };\n this.chart.setDrawingTool(tool);\n this.updateUI();\n }\n\n private handleCancelDrawing(): void {\n this.state = { ...this.state, activeTool: null };\n this.chart.setDrawingTool(null);\n this.updateUI();\n }\n\n private handleToggleStayInDrawing(): void {\n const stayInDrawing = !this.state.stayInDrawing;\n this.state = { ...this.state, stayInDrawing };\n this.chart.setStayInDrawingMode(stayInDrawing);\n this.updateUI();\n }\n\n private handleToggleMagnet(): void {\n const magnetEnabled = !this.state.magnetEnabled;\n this.state = { ...this.state, magnetEnabled };\n this.chart.setDrawingMagnet(magnetEnabled);\n this.updateUI();\n }\n\n private handleToggleTheme(): void {\n const isDark = !this.state.isDark;\n this.state = { ...this.state, isDark };\n this.root.dataset.tcwTheme = isDark ? 'dark' : 'light';\n this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme;\n this.chart.setTheme(isDark ? DARK_THEME : LIGHT_THEME);\n this.chart.setWatermark(this.state.symbol.replace('USDT', ' / USDT'), {\n fontSize: 48,\n color: isDark ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.03)',\n });\n this.updateUI();\n }\n\n private openSettings(): void {\n this.settings?.open(this.settingsState);\n }\n\n // --- Toast ---\n\n /**\n * Show a transient toast inside the widget. Auto-dismisses after 3.5s.\n * Used by the drag-drop importer for success / failure feedback, but\n * exposed so apps can post their own (e.g. \"alert triggered at 64,200\").\n */\n toast(message: string, kind: 'info' | 'error' = 'info'): void {\n const el = document.createElement('div');\n el.className = `tcw-toast ${kind === 'error' ? 'tcw-toast-error' : ''}`;\n el.textContent = message;\n this.root.appendChild(el);\n // Trigger CSS transition on next frame\n requestAnimationFrame(() => el.classList.add('tcw-toast-in'));\n setTimeout(() => {\n el.classList.remove('tcw-toast-in');\n el.addEventListener('transitionend', () => el.remove(), { once: true });\n // Hard timeout in case transitionend doesn't fire (display:none, etc.)\n setTimeout(() => el.remove(), 400);\n }, 3500);\n }\n\n // --- Layout persistence ---\n\n /**\n * Wipe the layout saved for `symbol` (or the active symbol if omitted).\n * Useful as an \"Reset layout\" command in user-facing menus.\n */\n clearSavedLayout(symbol?: string): void {\n if (!this.layoutKeyPrefix) return;\n const target = symbol ?? this.state.symbol;\n try {\n localStorage.removeItem(this.layoutKeyPrefix + target);\n } catch { /* localStorage may be unavailable (private mode, SSR, etc.) */ }\n }\n\n private applySymbolLayout(symbol: string): void {\n if (!this.layoutKeyPrefix) return;\n const key = this.layoutKeyPrefix + symbol;\n this.activeLayoutKey = key;\n\n try {\n // Best-effort load. If parsing or any restore step throws, we silently\n // fall back to a fresh layout — a corrupted layout shouldn't break the\n // chart.\n const ok = this.chart.loadStateFromStorage(key);\n if (ok) this.syncIndicatorsFromChart();\n } catch { /* swallow — layout will be rebuilt from user actions */ }\n\n // Wire chart-level auto-save so any further drawing/indicator change\n // flushes itself into this symbol's slot.\n this.chart.setAutoSave(key, this.layoutDebounceMs);\n }\n\n private flushActiveLayout(): void {\n if (!this.activeLayoutKey) return;\n try { this.chart.saveState(this.activeLayoutKey); } catch { /* same */ }\n this.chart.disableAutoSave();\n this.activeLayoutKey = null;\n }\n\n /** Rebuild the chip strip from the chart's indicator instances. */\n private syncIndicatorsFromChart(): void {\n const next = new Map<string, ActiveIndicatorInfo>();\n for (const a of this.chart.getActiveIndicators()) {\n next.set(a.instanceId, { id: a.id, label: indicatorChipLabel(a.id, a.params, a.descriptor.defaultConfig) });\n }\n this.state = { ...this.state, activeIndicators: next };\n this.updateUI();\n }\n\n // --- Replay ---\n\n /** Open (or close) bar replay with its scrubber — what the toolbar's Replay button does. */\n toggleReplay(): void {\n if (this.replayBar?.isMounted()) {\n this.exitReplay();\n } else {\n this.enterReplay();\n }\n }\n\n /**\n * Open replay in \"pick a start bar\" mode: the bars right of the pointer\n * are shaded, and a click cuts the chart there and waits paused. Play\n * starts from a default point; \"random bar\" picks one.\n */\n private enterReplay(): void {\n if (this.replayTotal() < 2) return;\n\n const t = this.t;\n this.replayBar = new WidgetReplayBar(\n {\n onPlay: () => {\n if (this.replayBar?.getMode() === 'select') {\n this.startReplayAt(Math.max(1, this.replayTotal() - 100), true);\n return;\n }\n if (this.chart.getReplayState() === 'paused') this.chart.replayResume();\n this.replayBar?.setState('playing');\n },\n onPause: () => {\n this.chart.replayPause();\n this.replayBar?.setState('paused');\n },\n onStepBack: () => this.stepReplay(-1),\n onStepForward: () => this.stepReplay(1),\n onSeek: (idx) => {\n if (this.chart.getReplayState() === 'playing') this.chart.replayPause();\n this.chart.replaySeek(idx);\n this.replayBar?.setState('paused');\n },\n onSpeedChange: (barsPerSecond) => {\n this.replaySpeed = barsPerSecond;\n this.chart.setReplaySpeed(barsPerSecond);\n },\n onRandomStart: () => {\n const n = this.replayTotal();\n // Somewhere in the middle 80%, so there is history before and bars after.\n const lo = Math.max(1, Math.floor(n * 0.1));\n const hi = Math.max(lo, Math.floor(n * 0.9));\n this.startReplayAt(lo + Math.floor(Math.random() * (hi - lo + 1)));\n },\n onClose: () => this.exitReplay(),\n },\n {\n selectHint: t('replay.selectHint'),\n random: t('replay.random'),\n realtime: t('replay.realtime'),\n barsPerSecond: t('replay.barsPerSecond'),\n play: t('replay.play'),\n pause: t('replay.pause'),\n stepBack: t('replay.stepBack'),\n stepForward: t('replay.stepForward'),\n },\n );\n this.replayBar.mount(this.chartContainer, { total: this.replayTotal(), speed: this.replaySpeed, mode: 'select' });\n\n this.replayShade = document.createElement('div');\n this.replayShade.className = 'tcw-replay-shade';\n this.replayShade.hidden = true;\n this.chartContainer.appendChild(this.replayShade);\n this.chartContainer.addEventListener('mouseleave', this.hideReplayShade);\n }\n\n private readonly hideReplayShade = (): void => this.positionReplayShade(null);\n\n /**\n * Open replay (if it isn't open) and start it at bar `index` — paused, or\n * playing when `play` is set — skipping the pick-a-bar step.\n */\n replayFrom(index: number, play = false): void {\n if (!this.replayBar?.isMounted()) this.enterReplay();\n this.startReplayAt(index, play);\n }\n\n /** Cut the chart at `index` and wait paused (or play at once). */\n private startReplayAt(index: number, play = false): void {\n const bar = this.replayBar;\n if (!bar) return;\n const n = this.replayTotal();\n const start = Math.max(0, Math.min(Number.isFinite(index) ? Math.floor(index) : 0, n - 1));\n this.replayShade?.remove();\n this.replayShade = null;\n this.chartContainer.removeEventListener('mouseleave', this.hideReplayShade);\n bar.setMode('replay');\n this.chart.replayStart({ speed: this.replaySpeed, interval: 1000, startIndex: start, paused: true });\n if (play) this.chart.replayResume();\n bar.setState(play ? 'playing' : 'paused');\n this.syncReplayBar();\n\n if (this.replayPollInterval) clearInterval(this.replayPollInterval);\n this.replayPollInterval = setInterval(() => this.syncReplayBar(), 150);\n }\n\n /** Bars available to replay: the whole series, not the slice on screen. */\n private replayTotal(): number {\n return this.chart.isReplayActive() ? this.chart.getReplayProgress().total : this.chart.getData().length;\n }\n\n /** Mirror the replay engine in the bar; close it if the session ended elsewhere. */\n private syncReplayBar(): void {\n const bar = this.replayBar;\n if (!bar?.isMounted() || bar.getMode() !== 'replay') return;\n if (!this.chart.isReplayActive()) {\n // e.g. a symbol or timeframe switch replaced the series.\n this.teardownReplayUi();\n return;\n }\n const p = this.chart.getReplayProgress();\n const state = this.chart.getReplayState();\n bar.setProgress(p.current, p.total);\n bar.setState(state === 'stopped' ? 'paused' : state);\n bar.setEnded(state !== 'playing' && p.total > 0 && p.current >= p.total - 1);\n }\n\n private stepReplay(delta: number): void {\n if (this.replayBar?.getMode() !== 'replay') return;\n const p = this.chart.getReplayProgress();\n if (this.chart.getReplayState() === 'playing') this.chart.replayPause();\n this.chart.replaySeek(Math.max(0, Math.min(p.total - 1, p.current + delta)));\n this.replayBar.setState('paused');\n this.syncReplayBar();\n }\n\n /** Replay shortcuts: Shift+←/→ step one bar; Escape cancels picking a start bar. */\n private handleReplayKey(e: KeyboardEvent): boolean {\n if (e.defaultPrevented) return false;\n const active = document.activeElement as HTMLElement | null;\n if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.tagName === 'SELECT' || active.isContentEditable)) {\n return false;\n }\n if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowLeft') && this.replayBar?.getMode() === 'replay') {\n e.preventDefault();\n // The chart's own Shift+Arrow scrolls ten bars; this one steps the replay.\n e.stopPropagation();\n this.stepReplay(e.key === 'ArrowRight' ? 1 : -1);\n return true;\n }\n if (e.key === 'Escape' && this.replayBar?.getMode() === 'select') {\n this.exitReplay();\n return true;\n }\n return false;\n }\n\n private positionReplayShade(x: number | null): void {\n const shade = this.replayShade;\n if (!shade) return;\n const plot = this.chart.getPlotRect();\n if (x === null || x < plot.x || x > plot.x + plot.width) {\n shade.hidden = true;\n return;\n }\n shade.hidden = false;\n shade.style.left = `${x}px`;\n shade.style.top = `${plot.y}px`;\n shade.style.width = `${plot.x + plot.width - x}px`;\n shade.style.height = `${plot.height}px`;\n }\n\n /** Leave replay and return to the live series (with updates that arrived meanwhile). */\n private exitReplay(): void {\n this.teardownReplayUi();\n this.chart.replayStop();\n }\n\n private teardownReplayUi(): void {\n if (this.replayPollInterval) {\n clearInterval(this.replayPollInterval);\n this.replayPollInterval = null;\n }\n this.replayShade?.remove();\n this.replayShade = null;\n this.chartContainer.removeEventListener('mouseleave', this.hideReplayShade);\n this.replayBar?.unmount();\n this.replayBar = null;\n }\n\n private applySettings(patch: Partial<ChartSettingsState>): void {\n this.settingsState = { ...this.settingsState, ...patch };\n this.scheduleLegend(); // the OHLCV legend's rows and the locale move or reword it\n\n if (patch.gridVisible !== undefined) this.chart.setGridVisible(patch.gridVisible);\n if (patch.volumeVisible !== undefined) this.chart.setVolumeVisible(patch.volumeVisible);\n if (patch.volumeProfileVisible !== undefined) this.chart.setVolumeProfileVisible(patch.volumeProfileVisible);\n if (patch.marketProfileVisible !== undefined) this.chart.setMarketProfileVisible(patch.marketProfileVisible);\n if (patch.marketProfileSplit !== undefined) this.chart.setMarketProfileConfig({ splitBySession: patch.marketProfileSplit });\n if (patch.marketProfileLetters !== undefined) this.chart.setMarketProfileConfig({ letters: patch.marketProfileLetters });\n if (patch.marketProfileBuckets !== undefined) this.chart.setMarketProfileConfig({ buckets: patch.marketProfileBuckets });\n if (patch.marketProfileOpacity !== undefined) this.chart.setMarketProfileConfig({ opacity: patch.marketProfileOpacity });\n if (patch.depthHeatmapVisible !== undefined) this.chart.setDepthHeatmapVisible(patch.depthHeatmapVisible);\n if (patch.depthHeatmapOpacity !== undefined) this.chart.setDepthHeatmapConfig({ opacity: patch.depthHeatmapOpacity });\n if (patch.sessionShadingVisible !== undefined) this.chart.setSessionShadingVisible(patch.sessionShadingVisible);\n if (patch.pivotMarkersVisible !== undefined) this.chart.setPivotMarkersVisible(patch.pivotMarkersVisible);\n if (patch.pivotStrength !== undefined) this.chart.setPivotMarkersConfig({ left: patch.pivotStrength, right: patch.pivotStrength });\n if (patch.pivotStructureLabels !== undefined) this.chart.setPivotMarkersConfig({ structureLabels: patch.pivotStructureLabels });\n if (patch.periodLevelsVisible !== undefined) this.chart.setPeriodLevelsVisible(patch.periodLevelsVisible);\n if (patch.periodLevelsPeriod !== undefined) this.chart.setPeriodLevelsPeriod(patch.periodLevelsPeriod);\n if (patch.crosshairMode !== undefined) this.chart.setCrosshairMode(patch.crosshairMode);\n if (patch.autoScale !== undefined) this.chart.setAutoScale(patch.autoScale);\n if (patch.invertScale !== undefined) this.chart.setInvertScale(patch.invertScale);\n if (patch.scaleMode !== undefined) {\n this.chart.setScaleMode(patch.scaleMode);\n // Keep the legacy logScale flag mirrored so persisted layouts stay valid.\n this.settingsState = { ...this.settingsState, logScale: patch.scaleMode === 'logarithmic' };\n } else if (patch.logScale !== undefined) {\n this.chart.setLogScale(patch.logScale);\n this.settingsState = { ...this.settingsState, scaleMode: patch.logScale ? 'logarithmic' : 'regular' };\n }\n if (patch.numberLocale !== undefined) {\n this.chart.setNumberLocale(patch.numberLocale);\n this.watchlist?.setLocale(patch.numberLocale || undefined);\n }\n if (patch.timezone !== undefined) {\n this.chart.setTimezoneOffset(patch.timezone === 'local' ? null : Number(patch.timezone));\n }\n\n // Apply theme colors\n const currentTheme = this.chart.getTheme();\n const themeUpdate = { ...currentTheme } as Record<string, unknown>;\n let themeChanged = false;\n\n if (patch.candleUpColor !== undefined) { themeUpdate.candleUp = patch.candleUpColor; themeChanged = true; }\n if (patch.candleDownColor !== undefined) { themeUpdate.candleDown = patch.candleDownColor; themeChanged = true; }\n if (patch.candleUpWick !== undefined) { themeUpdate.candleUpWick = patch.candleUpWick; themeChanged = true; }\n if (patch.candleDownWick !== undefined) { themeUpdate.candleDownWick = patch.candleDownWick; themeChanged = true; }\n if (patch.backgroundColor !== undefined) { themeUpdate.background = patch.backgroundColor; themeChanged = true; }\n if (patch.gridColor !== undefined) { themeUpdate.grid = patch.gridColor; themeChanged = true; }\n\n if (themeChanged) {\n this.chart.setTheme(themeUpdate as unknown as Theme);\n }\n }\n\n private resetSettings(): void {\n this.settingsState = { ...DEFAULT_SETTINGS };\n this.applySettings(this.settingsState);\n }\n\n private async connectStream(): Promise<void> {\n if (!this.adapter) return;\n const seq = ++this.connectSeq;\n\n this.state = {\n ...this.state,\n connectionState: 'connecting',\n connectionMessage: this.t('status.connecting'),\n };\n this.updateUI();\n // Keep the previous chart up while the next one loads; it only gets the\n // veil if the request is slow (see WidgetLoadingOverlay).\n this.loading.begin(this.chart.getData().length > 0);\n\n try {\n this.chart.disconnectStream();\n await this.chart.connect({\n adapter: this.adapter,\n symbol: this.state.symbol,\n timeframe: this.state.timeframe,\n historyLimit: this.options.historyLimit ?? 500,\n });\n // A newer switch started while this one was loading — it owns the UI now.\n if (seq !== this.connectSeq || this.destroyed) return;\n\n this.chart.setWatermark(this.state.symbol.replace('USDT', ' / USDT'), {\n fontSize: 48,\n color: this.state.isDark ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.03)',\n });\n\n // Re-apply per-symbol layout (indicators, drawings, chart type) after\n // the new history is in. Doing this *after* connect ensures indicators\n // recalculate against the loaded data, not the previous symbol's data.\n this.applySymbolLayout(this.state.symbol);\n\n if (this.loading.hasFailed()) {\n // History failed to load; the stream keeps retrying and the next\n // snapshot ends the loading state (handleDataUpdate).\n this.state = { ...this.state, connectionState: 'error' };\n } else {\n this.loading.end();\n this.state = {\n ...this.state,\n connectionState: 'connected',\n connectionMessage: this.t('status.live'),\n };\n }\n\n // Re-pull comparison overlays at the (possibly new) timeframe so they\n // stay aligned with the main series. Drop the active symbol if it ended\n // up in the compare set after a symbol switch.\n void this.refetchCompares();\n } catch (err: unknown) {\n if (seq !== this.connectSeq || this.destroyed) return;\n this.loading.fail(this.t('status.connectionFailed'));\n this.state = {\n ...this.state,\n connectionState: 'error',\n connectionMessage: err instanceof Error ? err.message : this.t('status.connectionFailed'),\n };\n }\n\n this.updateUI();\n }\n\n /** Redraw the on-chart indicator list on the next frame (coalesced). */\n private scheduleLegend(): void {\n if (!this.indicatorLegend || this.legendFrame) return;\n this.legendFrame = requestAnimationFrame(() => {\n this.legendFrame = 0;\n this.renderLegend();\n });\n }\n\n private renderLegend(): void {\n if (!this.indicatorLegend || this.destroyed) return;\n const last = this.chart.getData().length - 1;\n // Renko, Kagi and the like redraw the series: the hovered bar is not a\n // data bar, so their values stay on the latest one.\n const hover = this.chart.isTimeAligned() ? this.legendHoverIndex : null;\n const idx = hover === null ? last : Math.min(Math.max(hover, 0), last);\n const panes = new Map(this.chart.getIndicatorPanes().map((p) => [p.instanceId, p.rect]));\n const locale = this.settingsState.numberLocale || 'en-US';\n const rows: IndicatorLegendRow[] = this.chart.getActiveIndicators().map((ind) => {\n const pane = panes.get(ind.instanceId) ?? null;\n const series = this.chart.getIndicatorOutput(ind.instanceId)?.series;\n const point = idx >= 0 ? series?.[idx] : null;\n const numbers = legendNumbers(ind.id, point);\n // One line (judged at the latest bar, past any warm-up): the line's\n // colour there. Several: which value is which line isn't known here,\n // so they share the neutral colour rather than guess.\n const lines = idx === last ? numbers.length : legendNumbers(ind.id, last >= 0 ? series?.[last] : null).length;\n const color = lines === 1 ? legendLineColor(ind.id, this.chart.getIndicatorStyle(ind.instanceId)?.colors ?? [], point) : null;\n return {\n instanceId: ind.instanceId,\n label: indicatorChipLabel(ind.id, ind.params, ind.descriptor.defaultConfig),\n visible: ind.visible,\n values: numbers.map((v) => ({ text: pane ? formatIndicatorValue(v, locale) : this.chart.formatPrice(v), color })),\n pane: pane ? { x: pane.x + LEGEND_INSET, y: pane.y + 1, width: pane.width - 2 * LEGEND_INSET } : null,\n };\n });\n const plot = this.chart.getPlotRect();\n this.indicatorLegend.update(rows, { left: plot.x + LEGEND_INSET, top: this.chart.getLegendBottom() + 1 });\n }\n\n private updateUI(): void {\n this.scheduleLegend();\n this.toolbar?.update(this.state);\n this.sidebar?.update(this.state);\n this.statusBar?.update({\n connectionState: this.state.connectionState,\n message: this.state.connectionMessage,\n symbol: this.state.symbol,\n timeframe: this.state.timeframe,\n });\n }\n\n private resolveIsDark(theme?: import('@tradecanvas/commons').ThemeName | Theme): boolean {\n if (theme === undefined || theme === 'dark') return true;\n if (theme === 'light') return false;\n // If it's a Theme object, check background color\n if (typeof theme === 'object' && theme.background) {\n return this.isColorDark(theme.background);\n }\n return true;\n }\n\n private resolveTheme(theme?: import('@tradecanvas/commons').ThemeName | Theme): Theme {\n if (theme === undefined || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n if (typeof theme === 'object') return theme as Theme;\n return DARK_THEME;\n }\n\n private isColorDark(color: string): boolean {\n // Simple heuristic: if it starts with # and R+G+B < 384 (half of 768)\n if (color.startsWith('#') && color.length >= 7) {\n const r = parseInt(color.slice(1, 3), 16);\n const g = parseInt(color.slice(3, 5), 16);\n const b = parseInt(color.slice(5, 7), 16);\n return (r + g + b) < 384;\n }\n return true;\n }\n}\n\n/**\n * \"EMA 20\", \"BB 20 2\", \"MACD 12 26 9\": the short name plus up to three\n * numeric parameters, in the indicator's own order, so two instances of the\n * same indicator can be told apart.\n */\nexport function indicatorChipLabel(\n id: string,\n params: Record<string, unknown>,\n defaults?: Record<string, unknown>,\n): string {\n const order = defaults ? Object.keys(defaults) : Object.keys(params);\n const numbers = order\n .map((k) => params[k])\n .filter((v): v is number => typeof v === 'number' && Number.isFinite(v))\n .slice(0, 3)\n .map((v) => String(Number(v.toFixed(4))));\n return [id.toUpperCase(), ...numbers].join(' ');\n}\n"],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/io/resampleOHLCV.ts","../../src/widget/widgetTimezones.ts","../../src/widget/widgetConfig.ts","../../src/widget/WidgetStyles.ts","../../src/widget/iconSet.ts","../../src/widget/icons.ts","../../src/widget/escapeHtml.ts","../../src/widget/WidgetDropdown.ts","../../src/widget/widgetLocales.ts","../../src/widget/WidgetToolbar.ts","../../src/widget/WidgetDrawingSidebar.ts","../../src/widget/WidgetSettings.ts","../../src/widget/WidgetStatusBar.ts","../../src/widget/WidgetCommandPalette.ts","../../src/widget/WidgetSymbolSearch.ts","../../src/widget/WidgetHotkeySheet.ts","../../src/widget/WidgetReplayBar.ts","../../src/widget/WidgetWatchlist.ts","../../src/widget/WatchlistStore.ts","../../src/widget/WidgetSymbolInfo.ts","../../src/widget/WidgetChartNav.ts","../../src/widget/WidgetAlertsPanel.ts","../../src/widget/widgetUI.ts","../../src/widget/WidgetObjectTree.ts","../../src/widget/focusTrap.ts","../../src/widget/WidgetIndicatorSettings.ts","../../src/widget/DrawingTemplateStore.ts","../../src/widget/WidgetDrawingStyle.ts","../../src/widget/settingsControls.ts","../../src/widget/WidgetDrawingSettings.ts","../../src/widget/WidgetContextMenu.ts","../../src/widget/drawingMenu.ts","../../src/widget/chartMenu.ts","../../src/widget/WidgetAccountPanel.ts","../../src/widget/orderTicket.ts","../../src/widget/WidgetOrderTicket.ts","../../src/widget/WidgetNamePrompt.ts","../../src/widget/WidgetLayoutsDialog.ts","../../src/widget/WidgetLayoutsUI.ts","../../src/widget/widgetTimeframes.ts","../../src/widget/WidgetIntervalInput.ts","../../src/widget/indicatorTemplates.ts","../../src/widget/keyTarget.ts","../../src/widget/widgetLayout.ts","../../src/widget/DrawingFavoritesStore.ts","../../src/widget/WidgetGoToDate.ts","../../src/widget/WidgetTooltip.ts","../../src/widget/WidgetIndicatorLegend.ts","../../src/widget/legendValues.ts","../../src/widget/WidgetBracketBar.ts","../../src/widget/AlertNotifier.ts","../../src/widget/ladderRows.ts","../../src/widget/WidgetDepthLadder.ts","../../src/widget/WidgetDataWindow.ts","../../src/widget/widgetShareState.ts","../../src/widget/WidgetLoadingOverlay.ts","../../src/widget/WidgetHistoryPill.ts","../../src/widget/ChartWidget.ts","../../src/widget/ChartWidgetGrid.ts"],"sourcesContent":["import type { DataSeries, OHLCBar, TimeFrame } from '@tradecanvas/commons';\r\nimport { timeframeToMs, timeframeBucketStart } from '@tradecanvas/commons';\r\n\r\nexport interface ResampleOptions {\r\n /** 0 = Sunday, 1 = Monday (default) — anchor for weekly buckets. */\r\n weekStartsOn?: 0 | 1;\r\n}\r\n\r\n/**\r\n * Aggregate a finer OHLCV series into a coarser timeframe.\r\n *\r\n * Bars are grouped by calendar-aware bucket (see `timeframeBucketStart`):\r\n * open = first bar's open, high/low = extremes, close = last bar's close,\r\n * volume = sum. Input bars are assumed sorted ascending by `time` and are\r\n * never mutated.\r\n *\r\n * Upsampling (target finer than source) cannot synthesize data — pass a target\r\n * coarser than the source. Use `inferTimeframeMs` to detect the source spacing.\r\n */\r\nexport function resampleOHLCV(\r\n bars: DataSeries,\r\n target: TimeFrame,\r\n opts: ResampleOptions = {},\r\n): DataSeries {\r\n if (bars.length === 0) return [];\r\n const weekStartsOn = opts.weekStartsOn ?? 1;\r\n\r\n const out: OHLCBar[] = [];\r\n let current: OHLCBar | null = null;\r\n let currentKey = Number.NaN;\r\n\r\n for (const bar of bars) {\r\n const key = timeframeBucketStart(bar.time, target, weekStartsOn);\r\n if (current === null || key !== currentKey) {\r\n if (current !== null) out.push(current);\r\n current = {\r\n time: key,\r\n open: bar.open,\r\n high: bar.high,\r\n low: bar.low,\r\n close: bar.close,\r\n volume: bar.volume,\r\n };\r\n currentKey = key;\r\n } else {\r\n current = {\r\n time: current.time,\r\n open: current.open,\r\n high: Math.max(current.high, bar.high),\r\n low: Math.min(current.low, bar.low),\r\n close: bar.close,\r\n volume: current.volume + bar.volume,\r\n };\r\n }\r\n }\r\n if (current !== null) out.push(current);\r\n return out;\r\n}\r\n\r\n/**\r\n * Estimate the source bar spacing in milliseconds from the median gap between\r\n * consecutive bars. Robust to occasional gaps (weekends, halts). Returns 0 for\r\n * series with fewer than two bars.\r\n */\r\nexport function inferTimeframeMs(bars: DataSeries): number {\r\n if (bars.length < 2) return 0;\r\n const gaps: number[] = [];\r\n for (let i = 1; i < bars.length; i++) {\r\n const gap = bars[i].time - bars[i - 1].time;\r\n if (gap > 0) gaps.push(gap);\r\n }\r\n if (gaps.length === 0) return 0;\r\n gaps.sort((a, b) => a - b);\r\n return gaps[Math.floor(gaps.length / 2)];\r\n}\r\n\r\n/**\r\n * Whether `target` is coarser than (or equal to) the source spacing, i.e. a\r\n * valid downsample. A non-positive `sourceMs` (unknown) is treated as valid.\r\n */\r\nexport function canResample(sourceMs: number, target: TimeFrame): boolean {\r\n if (sourceMs <= 0) return true;\r\n return timeframeToMs(target) >= sourceMs;\r\n}\r\n","import type { TimeZoneSetting } from '@tradecanvas/commons';\r\nimport { isValidTimeZone, offsetAt, tzLabel } from '@tradecanvas/commons';\r\n\r\n/** The zones the settings offer besides the browser's own, by city. */\r\nexport const WIDGET_TIMEZONES: readonly { zone: string; city: string }[] = [\r\n { zone: 'Pacific/Honolulu', city: 'Honolulu' },\r\n { zone: 'America/Los_Angeles', city: 'Los Angeles' },\r\n { zone: 'America/Denver', city: 'Denver' },\r\n { zone: 'America/Chicago', city: 'Chicago' },\r\n { zone: 'America/New_York', city: 'New York' },\r\n { zone: 'America/Toronto', city: 'Toronto' },\r\n { zone: 'America/Sao_Paulo', city: 'São Paulo' },\r\n { zone: 'UTC', city: 'UTC' },\r\n { zone: 'Europe/London', city: 'London' },\r\n { zone: 'Europe/Berlin', city: 'Frankfurt' },\r\n { zone: 'Europe/Paris', city: 'Paris' },\r\n { zone: 'Europe/Zurich', city: 'Zurich' },\r\n { zone: 'Africa/Johannesburg', city: 'Johannesburg' },\r\n { zone: 'Europe/Istanbul', city: 'Istanbul' },\r\n { zone: 'Europe/Moscow', city: 'Moscow' },\r\n { zone: 'Asia/Dubai', city: 'Dubai' },\r\n { zone: 'Asia/Kolkata', city: 'Mumbai' },\r\n { zone: 'Asia/Bangkok', city: 'Bangkok' },\r\n { zone: 'Asia/Ho_Chi_Minh', city: 'Ho Chi Minh City' },\r\n { zone: 'Asia/Jakarta', city: 'Jakarta' },\r\n { zone: 'Asia/Singapore', city: 'Singapore' },\r\n { zone: 'Asia/Hong_Kong', city: 'Hong Kong' },\r\n { zone: 'Asia/Shanghai', city: 'Shanghai' },\r\n { zone: 'Asia/Taipei', city: 'Taipei' },\r\n { zone: 'Asia/Seoul', city: 'Seoul' },\r\n { zone: 'Asia/Tokyo', city: 'Tokyo' },\r\n { zone: 'Australia/Sydney', city: 'Sydney' },\r\n { zone: 'Pacific/Auckland', city: 'Auckland' },\r\n];\r\n\r\n/**\r\n * The settings' timezone value as a display timezone: `'local'` is the\r\n * browser's, a number of minutes a fixed offset (older saved settings), and\r\n * anything else an IANA zone — the browser's own when it doesn't know it.\r\n */\r\nexport function settingToTimezone(value: string): TimeZoneSetting {\r\n if (!value || value === 'local') return null;\r\n if (value === 'exchange') return 'exchange';\r\n if (/^-?\\d+$/.test(value)) return Number(value);\r\n return isValidTimeZone(value) ? value : null;\r\n}\r\n\r\n/** A display timezone as the settings' value: the inverse of `settingToTimezone`. */\r\nexport function timezoneToSetting(tz: TimeZoneSetting): string {\r\n if (tz === null) return 'local';\r\n return String(tz);\r\n}\r\n\r\nexport interface TimezoneOption {\r\n value: string;\r\n label: string;\r\n /** Minutes east of UTC at the time the list was made. */\r\n offset: number;\r\n}\r\n\r\n/**\r\n * The timezone menu at `atMs`: the browser's zone first, then the zones by\r\n * the offset in force then (\"(UTC-4) New York\"). An older fixed-offset\r\n * setting that isn't one of them stays on the list.\r\n */\r\nexport function timezoneOptions(\r\n current: string,\r\n atMs: number,\r\n localLabel: string,\r\n /** Offer the symbol's exchange zone ('exchange'); `zone` is null while unknown (UTC). */\r\n exchange?: { label: string; zone: string | null },\r\n): TimezoneOption[] {\r\n const local = offsetAt(null, atMs);\r\n const zones = WIDGET_TIMEZONES\r\n .filter(({ zone }) => isValidTimeZone(zone))\r\n .map(({ zone, city }) => {\r\n const offset = offsetAt(zone, atMs);\r\n return { value: zone, label: zone === 'UTC' ? 'UTC' : `(${tzLabel(offset)}) ${city}`, offset };\r\n });\r\n const fixed = settingToTimezone(current);\r\n if (typeof fixed === 'number') zones.push({ value: current, label: tzLabel(fixed), offset: fixed });\r\n zones.sort((a, b) => a.offset - b.offset);\r\n const first: TimezoneOption[] = [{ value: 'local', label: `${localLabel} (${tzLabel(local)})`, offset: local }];\r\n if (exchange) {\r\n const zone = exchange.zone && isValidTimeZone(exchange.zone) ? exchange.zone : 'UTC';\r\n const offset = offsetAt(zone, atMs);\r\n first.push({ value: 'exchange', label: `${exchange.label} (${tzLabel(offset)})`, offset });\r\n }\r\n return [...first, ...zones];\r\n}\r\n","import { DARK_THEME } from '@tradecanvas/commons';\r\nimport type { ChartType, DrawingToolType } from '@tradecanvas/commons';\r\nimport type { IndicatorDef, DrawingToolGroupDef, ChartSettingsState } from './types.js';\r\n\r\nexport const CHART_TYPES: { label: string; value: ChartType }[] = [\r\n { label: 'Candlestick', value: 'candlestick' },\r\n { label: 'Line', value: 'line' },\r\n { label: 'Area', value: 'area' },\r\n { label: 'Bar', value: 'bar' },\r\n { label: 'Heikin-Ashi', value: 'heikinAshi' },\r\n { label: 'Hollow Candle', value: 'hollowCandle' },\r\n { label: 'Baseline', value: 'baseline' },\r\n { label: 'Volume Candles', value: 'volumeCandles' },\r\n { label: 'Equivolume', value: 'equivolume' },\r\n { label: 'HLC Area', value: 'hlcArea' },\r\n { label: 'Step Line', value: 'stepLine' },\r\n { label: 'Line + Markers', value: 'lineWithMarkers' },\r\n { label: 'High-Low', value: 'hiLo' },\r\n { label: 'Renko', value: 'renko' },\r\n { label: 'Line Break', value: 'lineBreak' },\r\n { label: 'Kagi', value: 'kagi' },\r\n { label: 'Point & Figure', value: 'pointAndFigure' },\r\n { label: 'Range Bars', value: 'rangeBars' },\r\n];\r\n\r\nexport const DRAWING_TOOL_GROUPS: DrawingToolGroupDef[] = [\r\n {\r\n label: 'Lines',\r\n tools: [\r\n { label: 'Trend Line', value: 'trendLine' as DrawingToolType },\r\n { label: 'Ray', value: 'ray' as DrawingToolType },\r\n { label: 'Extended Line', value: 'extendedLine' as DrawingToolType },\r\n { label: 'Info Line', value: 'infoLine' as DrawingToolType },\r\n { label: 'Trend Angle', value: 'trendAngle' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Horizontal/Vertical',\r\n tools: [\r\n { label: 'Horizontal Line', value: 'horizontalLine' as DrawingToolType },\r\n { label: 'Horizontal Ray', value: 'horizontalRay' as DrawingToolType },\r\n { label: 'Vertical Line', value: 'verticalLine' as DrawingToolType },\r\n { label: 'Cross Line', value: 'crossLine' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Channels',\r\n tools: [\r\n { label: 'Parallel Channel', value: 'parallelChannel' as DrawingToolType },\r\n { label: 'Regression Channel', value: 'regressionChannel' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Fibonacci',\r\n tools: [\r\n { label: 'Fib Retracement', value: 'fibRetracement' as DrawingToolType },\r\n { label: 'Fib Extension', value: 'fibExtension' as DrawingToolType },\r\n { label: 'Fib Channel', value: 'fibChannel' as DrawingToolType },\r\n { label: 'Fib Time Zones', value: 'fibTimeZones' as DrawingToolType },\r\n { label: 'Fib Speed Resistance Fan', value: 'fibSpeedResistanceFan' as DrawingToolType },\r\n { label: 'Fib Speed Resistance Arcs', value: 'fibArcs' as DrawingToolType },\r\n { label: 'Fib Circles', value: 'fibCircles' as DrawingToolType },\r\n { label: 'Fib Spiral', value: 'fibSpiral' as DrawingToolType },\r\n { label: 'Fib Wedge', value: 'fibWedge' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Shapes',\r\n tools: [\r\n { label: 'Rectangle', value: 'rectangle' as DrawingToolType },\r\n { label: 'Circle', value: 'circle' as DrawingToolType },\r\n { label: 'Ellipse', value: 'ellipse' as DrawingToolType },\r\n { label: 'Triangle', value: 'triangle' as DrawingToolType },\r\n { label: 'Polyline', value: 'polyline' as DrawingToolType },\r\n { label: 'Curve', value: 'curve' as DrawingToolType },\r\n { label: 'Arc', value: 'arc' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Brushes',\r\n tools: [\r\n { label: 'Brush', value: 'brush' as DrawingToolType },\r\n { label: 'Highlighter', value: 'highlighter' as DrawingToolType },\r\n { label: 'Path', value: 'path' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Gann & Pitchforks',\r\n tools: [\r\n { label: 'Pitchfork', value: 'pitchfork' as DrawingToolType },\r\n { label: 'Schiff Pitchfork', value: 'schiffPitchfork' as DrawingToolType },\r\n { label: 'Modified Schiff Pitchfork', value: 'modifiedSchiffPitchfork' as DrawingToolType },\r\n { label: 'Gann Fan', value: 'gannFan' as DrawingToolType },\r\n { label: 'Gann Box', value: 'gannBox' as DrawingToolType },\r\n { label: 'Gann Square', value: 'gannSquare' as DrawingToolType },\r\n { label: 'Pitchfan', value: 'pitchfan' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Cycles',\r\n tools: [\r\n { label: 'Cyclic Lines', value: 'cyclicLines' as DrawingToolType },\r\n { label: 'Time Cycles', value: 'timeCycles' as DrawingToolType },\r\n { label: 'Sine Line', value: 'sineLine' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Patterns',\r\n tools: [\r\n { label: 'XABCD Pattern', value: 'xabcdPattern' as DrawingToolType },\r\n { label: 'ABCD Pattern', value: 'abcdPattern' as DrawingToolType },\r\n { label: 'Head and Shoulders', value: 'headAndShoulders' as DrawingToolType },\r\n { label: 'Cypher Pattern', value: 'cypherPattern' as DrawingToolType },\r\n { label: 'Three Drives Pattern', value: 'threeDrives' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Elliott Waves',\r\n tools: [\r\n { label: 'Elliott Wave', value: 'elliottWave' as DrawingToolType },\r\n { label: 'Elliott Impulse Wave', value: 'elliottImpulse' as DrawingToolType },\r\n { label: 'Elliott Correction Wave', value: 'elliottCorrection' as DrawingToolType },\r\n { label: 'Elliott Triangle Wave', value: 'elliottTriangle' as DrawingToolType },\r\n { label: 'Elliott Double Combo Wave', value: 'elliottDoubleCombo' as DrawingToolType },\r\n { label: 'Elliott Triple Combo Wave', value: 'elliottTripleCombo' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Measure',\r\n tools: [\r\n { label: 'Price Range', value: 'priceRange' as DrawingToolType },\r\n { label: 'Date Range', value: 'dateRange' as DrawingToolType },\r\n { label: 'Date and Price Range', value: 'dateAndPriceRange' as DrawingToolType },\r\n { label: 'Measure', value: 'measure' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Annotation',\r\n tools: [\r\n { label: 'Text', value: 'text' as DrawingToolType },\r\n { label: 'Price Label', value: 'priceLabel' as DrawingToolType },\r\n { label: 'Arrow', value: 'arrow' as DrawingToolType },\r\n { label: 'Note', value: 'note' as DrawingToolType },\r\n { label: 'Callout', value: 'callout' as DrawingToolType },\r\n { label: 'Flag Mark', value: 'flag' as DrawingToolType },\r\n { label: 'Arrow Mark', value: 'arrowMark' as DrawingToolType },\r\n { label: 'Icon', value: 'icon' as DrawingToolType },\r\n ],\r\n },\r\n {\r\n label: 'Forecasting',\r\n tools: [\r\n { label: 'Long/Short Position', value: 'riskReward' as DrawingToolType },\r\n { label: 'Anchored VWAP', value: 'anchoredVWAP' as DrawingToolType },\r\n { label: 'Fixed Range Volume Profile', value: 'volumeProfileRange' as DrawingToolType },\r\n { label: 'Forecast', value: 'forecast' as DrawingToolType },\r\n { label: 'Projection', value: 'projection' as DrawingToolType },\r\n { label: 'Bars Pattern', value: 'barsPattern' as DrawingToolType },\r\n ],\r\n },\r\n];\r\n\r\nexport const INDICATORS: IndicatorDef[] = [\r\n { id: 'sma', name: 'SMA', type: 'overlay' },\r\n { id: 'ema', name: 'EMA', type: 'overlay' },\r\n { id: 'tema', name: 'Triple EMA', type: 'overlay' },\r\n { id: 'vwma', name: 'VWMA', type: 'overlay' },\r\n { id: 'wma', name: 'Weighted MA', type: 'overlay' },\r\n { id: 'hma', name: 'Hull MA', type: 'overlay' },\r\n { id: 'mtfma', name: 'MTF Moving Average', type: 'overlay' },\r\n { id: 'bb', name: 'Bollinger Bands', type: 'overlay' },\r\n { id: 'envelope', name: 'Envelope', type: 'overlay' },\r\n { id: 'vwap', name: 'VWAP', type: 'overlay' },\r\n { id: 'avwap', name: 'Anchored VWAP', type: 'overlay' },\r\n { id: 'svwap', name: 'Session VWAP', type: 'overlay' },\r\n { id: 'ichimoku', name: 'Ichimoku Cloud', type: 'overlay' },\r\n { id: 'psar', name: 'Parabolic SAR', type: 'overlay' },\r\n { id: 'supertrend', name: 'Supertrend', type: 'overlay' },\r\n { id: 'keltner', name: 'Keltner Channel', type: 'overlay' },\r\n { id: 'donchian', name: 'Donchian Channel', type: 'overlay' },\r\n { id: 'pivots', name: 'Pivot Points', type: 'overlay' },\r\n { id: 'zigzag', name: 'ZigZag', type: 'overlay' },\r\n { id: 'lrc', name: 'Linear Regression Channel', type: 'overlay' },\r\n { id: 'chandelier', name: 'Chandelier Exit', type: 'overlay' },\r\n { id: 'alligator', name: 'Alligator', type: 'overlay' },\r\n { id: 'rsi', name: 'RSI', type: 'panel' },\r\n { id: 'macd', name: 'MACD', type: 'panel' },\r\n { id: 'stochastic', name: 'Stochastic', type: 'panel' },\r\n { id: 'atr', name: 'ATR', type: 'panel' },\r\n { id: 'adx', name: 'ADX', type: 'panel' },\r\n { id: 'obv', name: 'OBV', type: 'panel' },\r\n { id: 'williamsR', name: 'Williams %R', type: 'panel' },\r\n { id: 'cci', name: 'CCI', type: 'panel' },\r\n { id: 'mfi', name: 'MFI', type: 'panel' },\r\n { id: 'roc', name: 'ROC', type: 'panel' },\r\n { id: 'tsi', name: 'TSI', type: 'panel' },\r\n { id: 'cmf', name: 'CMF', type: 'panel' },\r\n { id: 'aroon', name: 'Aroon', type: 'panel' },\r\n { id: 'stddev', name: 'Std Deviation', type: 'panel' },\r\n { id: 'vroc', name: 'Volume ROC', type: 'panel' },\r\n { id: 'ad', name: 'Acc/Dist', type: 'panel' },\r\n { id: 'ao', name: 'Awesome Oscillator', type: 'panel' },\r\n { id: 'chaikinOsc', name: 'Chaikin Oscillator', type: 'panel' },\r\n { id: 'voldelta', name: 'Volume Delta', type: 'panel' },\r\n { id: 'vortex', name: 'Vortex Indicator', type: 'panel' },\r\n { id: 'chop', name: 'Choppiness Index', type: 'panel' },\r\n { id: 'uo', name: 'Ultimate Oscillator', type: 'panel' },\r\n { id: 'fi', name: 'Force Index', type: 'panel' },\r\n { id: 'crsi', name: 'Connors RSI', type: 'panel' },\r\n { id: 'coppock', name: 'Coppock Curve', type: 'panel' },\r\n { id: 'kst', name: 'Know Sure Thing', type: 'panel' },\r\n { id: 'elderray', name: 'Elder Ray', type: 'panel' },\r\n { id: 'stc', name: 'Schaff Trend Cycle', type: 'panel' },\r\n { id: 'kvo', name: 'Klinger Oscillator', type: 'panel' },\r\n { id: 'fisher', name: 'Fisher Transform', type: 'panel' },\r\n { id: 'dpo', name: 'Detrended Price Osc', type: 'panel' },\r\n { id: 'bop', name: 'Balance of Power', type: 'panel' },\r\n { id: 'massindex', name: 'Mass Index', type: 'panel' },\r\n { id: 'cmo', name: 'Chande Momentum', type: 'panel' },\r\n { id: 'trix', name: 'TRIX', type: 'panel' },\r\n { id: 'emv', name: 'Ease of Movement', type: 'panel' },\r\n { id: 'pvt', name: 'Price Volume Trend', type: 'panel' },\r\n { id: 'wad', name: 'Williams A/D', type: 'panel' },\r\n { id: 'chaikinvol', name: 'Chaikin Volatility', type: 'panel' },\r\n { id: 'rvi', name: 'Relative Vigor Index', type: 'panel' },\r\n { id: 'stochrsi', name: 'Stochastic RSI', type: 'panel' },\r\n { id: 'ppo', name: 'Percentage Price Oscillator', type: 'panel' },\r\n { id: 'ac', name: 'Accelerator Oscillator', type: 'panel' },\r\n { id: 'rmi', name: 'Relative Momentum Index', type: 'panel' },\r\n { id: 'disparity', name: 'Disparity Index', type: 'panel' },\r\n { id: 'qstick', name: 'Qstick', type: 'panel' },\r\n { id: 'pgo', name: 'Pretty Good Oscillator', type: 'panel' },\r\n { id: 'volumeProfile', name: 'Volume Profile', type: 'overlay' },\r\n { id: 'dema', name: 'Double EMA', type: 'overlay' },\r\n { id: 'smma', name: 'Smoothed MA', type: 'overlay' },\r\n { id: 'alma', name: 'Arnaud Legoux MA', type: 'overlay' },\r\n { id: 'kama', name: 'Kaufman Adaptive MA', type: 'overlay' },\r\n { id: 'lsma', name: 'Least Squares MA', type: 'overlay' },\r\n { id: 'mcginley', name: 'McGinley Dynamic', type: 'overlay' },\r\n { id: 'macross', name: 'MA Cross', type: 'overlay' },\r\n { id: 'fractals', name: 'Williams Fractals', type: 'overlay' },\r\n { id: 'cks', name: 'Chande Kroll Stop', type: 'overlay' },\r\n { id: 'bbpb', name: 'Bollinger %B', type: 'panel' },\r\n { id: 'bbw', name: 'Bollinger BandWidth', type: 'panel' },\r\n { id: 'mom', name: 'Momentum', type: 'panel' },\r\n { id: 'hv', name: 'Historical Volatility', type: 'panel' },\r\n { id: 'vo', name: 'Volume Oscillator', type: 'panel' },\r\n { id: 'ulcer', name: 'Ulcer Index', type: 'panel' },\r\n { id: 'seb', name: 'Standard Error Bands', type: 'overlay' },\r\n { id: 'gmma', name: 'Guppy Multiple MA', type: 'overlay' },\r\n { id: 'maribbon', name: 'Moving Average Ribbon', type: 'overlay' },\r\n { id: 'smi', name: 'Stochastic Momentum Index', type: 'panel' },\r\n { id: 'rvix', name: 'Relative Volatility Index', type: 'panel' },\r\n { id: 'trendstrength', name: 'Trend Strength Index', type: 'panel' },\r\n { id: 'lrslope', name: 'Linear Regression Slope', type: 'panel' },\r\n { id: 'stderror', name: 'Standard Error', type: 'panel' },\r\n { id: 'adr', name: 'Average Day Range', type: 'panel' },\r\n { id: 'netvolume', name: 'Net Volume', type: 'panel' },\r\n];\r\n\r\nexport const POPULAR_INDICATORS = [\r\n 'sma', 'ema', 'bb', 'rsi', 'macd', 'stochastic',\r\n 'vwap', 'atr', 'obv', 'ichimoku',\r\n];\r\n\r\nexport const DEFAULT_SYMBOLS = [\r\n 'BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT',\r\n];\r\n\r\nexport const DEFAULT_SETTINGS: ChartSettingsState = {\r\n candleUpColor: DARK_THEME.candleUp,\r\n candleDownColor: DARK_THEME.candleDown,\r\n candleUpWick: DARK_THEME.candleUpWick,\r\n candleDownWick: DARK_THEME.candleDownWick,\r\n backgroundColor: DARK_THEME.background,\r\n gridColor: DARK_THEME.grid,\r\n gridVisible: true,\r\n volumeVisible: true,\r\n volumeProfileVisible: false,\r\n marketProfileVisible: false,\r\n marketProfileSplit: false,\r\n marketProfileLetters: false,\r\n marketProfileBuckets: 48,\r\n marketProfileOpacity: 0.32,\r\n depthHeatmapVisible: false,\r\n depthHeatmapOpacity: 0.7,\r\n sessionShadingVisible: false,\r\n pivotMarkersVisible: false,\r\n pivotStrength: 5,\r\n pivotStructureLabels: false,\r\n periodLevelsVisible: false,\r\n periodLevelsPeriod: 'day',\r\n legendVisible: true,\r\n barCountdown: true,\r\n indicatorValueLabels: true,\r\n logScale: false,\r\n scaleMode: 'regular',\r\n autoScale: true,\r\n invertScale: false,\r\n leftPriceScale: false,\r\n crosshairMode: 'magnet',\r\n numberLocale: 'en-US',\r\n timezone: 'local',\r\n highLowLines: false,\r\n mainSeriesVisible: true,\r\n extendedHours: true,\r\n chartTypeOptions: {},\r\n};\r\n","import widgetCss from './WidgetStyles.css?raw';\r\n\r\nlet refCount = 0;\r\nconst STYLE_ID = 'tcw-styles';\r\n\r\n/**\r\n * Inject the widget stylesheet at the top of `document.head`, so the page's\r\n * own CSS wins a tie of specificity (a `.tcw-root { --tcw-radius: 0 }` of\r\n * yours sets the token). Reference-counted so\r\n * multiple `ChartWidget` instances share the same `<style>` tag and the last\r\n * to detach removes it. CSS lives in a sibling `.css` file and is inlined at\r\n * build time via Vite's `?raw` query — consumers see a plain string at runtime.\r\n */\r\nexport function injectWidgetStyles(): void {\r\n refCount++;\r\n if (refCount > 1) return;\r\n if (document.getElementById(STYLE_ID)) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = STYLE_ID;\r\n style.textContent = widgetCss;\r\n document.head.insertBefore(style, document.head.firstChild);\r\n}\r\n\r\nexport function removeWidgetStyles(): void {\r\n refCount--;\r\n if (refCount > 0) return;\r\n\r\n const style = document.getElementById(STYLE_ID);\r\n if (style) {\r\n style.remove();\r\n }\r\n}\r\n","/**\r\n * The TradeCanvas icon set, as in the \"TradeCanvas Icons\" Figma file: a 24 px\r\n * grid with 2 px padding, 1.75 px strokes with round caps and joins. Drawing\r\n * tools mark their anchor points (where you click to draw) with filled dots.\r\n */\r\nexport interface IconDef {\r\n /** Stroked path data. */\r\n d?: string;\r\n /** Dashed stroke, for guides. */\r\n dash?: string;\r\n /** Solid shapes, such as filled candle bodies. */\r\n fills?: readonly string[];\r\n /** An area filled at 22%. */\r\n soft?: string;\r\n /** Filled dots: [cx, cy, r = 1.75]. */\r\n dots?: readonly (readonly number[])[];\r\n}\r\n\r\n/** Toolbar, sidebar and panel glyphs. */\r\nexport const UI_ICONS: Readonly<Record<string, IconDef>> = {\r\n cursor: { d: 'M6 3.5L18.5 12.5L12.6 13.6L9.7 19.4z' }, // Cursor\r\n trendingUp: { d: 'M3 17L9 11L13 14.5L21 6.5M15 6.5H21V12.5' }, // Indicators / Long\r\n trendingDown: { d: 'M3 7L9 13L13 9.5L21 17.5M15 17.5H21V11.5' }, // Short\r\n minus: { d: 'M5 12H19' }, // Minus\r\n plus: { d: 'M12 5V19M5 12H19' }, // Plus\r\n penLine: { d: 'M14.5 5.5L18.5 9.5M4 20L5 15.5L15.8 4.7a2 2 0 0 1 2.83 0l.67.67a2 2 0 0 1 0 2.83L8.5 19z' }, // Draw\r\n zigzag: { d: 'M3 17L8 9L13 15L21 6' }, // Patterns\r\n hash: { d: 'M5 9H19M5 15H19M10 4L8.5 20M15.5 4L14 20' }, // Grid\r\n square: { d: 'M6.5 4.5h11a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2h-11a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2z' }, // Shape\r\n gitBranch: { d: 'M6 3V15M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM18 9a9 9 0 0 1-9 9' }, // Branch\r\n ruler: { d: 'M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9' }, // Measure\r\n type: { d: 'M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5' }, // Text\r\n magnet: { d: 'M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18M6 8h3.5M14.5 8H18' }, // Magnet\r\n magnetStrong: { d: 'M6 4V11a6 6 0 0 0 12 0V4M6 4h3.5v7a2.5 2.5 0 0 0 5 0V4H18', fills: ['M6 4h3.5v4H6z', 'M14.5 4H18v4h-3.5z'] }, // Strong magnet\r\n eraser: { d: 'M8.5 19.5L3.9 14.9a1.5 1.5 0 0 1 0-2.1l8.5-8.5a1.5 1.5 0 0 1 2.1 0l5.2 5.2a1.5 1.5 0 0 1 0 2.1L12 19.5zM8 9l7 7M12 19.5H20' }, // Eraser\r\n zoomIn: { d: 'M16.5 10.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0zM15 15L20.5 20.5M10.5 7.5V13.5M7.5 10.5H13.5' }, // Zoom area\r\n undo: { d: 'M9 14L4 9L9 4M4 9H14.5a5.5 5.5 0 0 1 0 11H11' }, // Undo\r\n redo: { d: 'M15 14L20 9L15 4M20 9H9.5a5.5 5.5 0 0 0 0 11H13' }, // Redo\r\n trash: { d: 'M4 7H20M9.5 7V4.5h5V7M6.5 7l.8 12.2A1.5 1.5 0 0 0 8.8 20.6h6.4a1.5 1.5 0 0 0 1.5-1.4L17.5 7M10 11v6M14 11v6' }, // Delete\r\n camera: { d: 'M4.5 7.5h3L9 5h6l1.5 2.5h3A1.5 1.5 0 0 1 21 9v9.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 18.5V9a1.5 1.5 0 0 1 1.5-1.5zM15.5 13.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z' }, // Screenshot\r\n settings: { d: 'M4 7H14M18 7H20M4 17H8M12 17H20M18 7a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM12 17a2 2 0 1 1-4 0 2 2 0 0 1 4 0z' }, // Settings\r\n moon: { d: 'M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z' }, // Dark theme\r\n sun: { d: 'M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM12 2.5v2M12 19.5v2M4.6 4.6l1.4 1.4M18 18l1.4 1.4M2.5 12h2M19.5 12h2M4.6 19.4L6 18M18 6l1.4-1.4' }, // Light theme\r\n chevronDown: { d: 'M6 9L12 15L18 9' }, // Expand\r\n chevronUp: { d: 'M6 15L12 9L18 15' }, // Collapse\r\n barChart: { d: 'M5 20V13M12 20V5M19 20V10' }, // Chart type\r\n x: { d: 'M6 6L18 18M18 6L6 18' }, // Close\r\n play: { d: 'M7 4.5v15L19.5 12z' }, // Play\r\n pause: { d: 'M8 5V19M16 5V19' }, // Pause\r\n stop: { d: 'M7.5 6h9A1.5 1.5 0 0 1 18 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 6 16.5v-9A1.5 1.5 0 0 1 7.5 6z' }, // Stop\r\n receipt: { d: 'M6 3.5h12v17l-2-1.25-2 1.25-2-1.25-2 1.25-2-1.25-2 1.25zM9 8h6M9 12h6M9 16h3' }, // Orders\r\n bell: { d: 'M6 16.5V11a6 6 0 0 1 12 0v5.5l1.5 2H4.5zM10 20.5a2.2 2.2 0 0 0 4 0' }, // Alerts\r\n layers: { d: 'M12 3.5L21 8.5L12 13.5L3 8.5zM3 12.5L12 17.5L21 12.5M3 16.5L12 21.5L21 16.5' }, // Objects\r\n eye: { d: 'M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12zM15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z' }, // Show\r\n eyeOff: { d: 'M4 4L20 20M9.9 5.8A9.6 9.6 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a16 16 0 0 1-2.3 3.1M6.6 7.1C3.9 8.9 2.5 12 2.5 12S6 18.5 12 18.5a9.3 9.3 0 0 0 4.7-1.3M10 10.1a3 3 0 0 0 4 4' }, // Hide\r\n lock: { d: 'M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 8 0v3' }, // Lock\r\n unlock: { d: 'M7 10.5h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2zM8 10.5V7.5a4 4 0 0 1 7.7-1.5' }, // Unlock\r\n palette: { d: 'M12 3.5a8.5 8.5 0 0 0 0 17c1.1 0 1.6-.8 1.6-1.6 0-.5-.2-.9-.5-1.2a1.6 1.6 0 0 1 1.2-2.7h1.9a4.3 4.3 0 0 0 4.3-4.3C20.5 6.9 16.7 3.5 12 3.5z', dots: [[7.5, 11.5, 1.25], [9.5, 7.75, 1.25], [14, 7.25, 1.25]] }, // Style\r\n check: { d: 'M5 12.5L10 17.5L19 7' }, // Done\r\n maximize: { d: 'M8 4H5a1 1 0 0 0-1 1v3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3' }, // Fullscreen\r\n minimize: { d: 'M4 8h3a1 1 0 0 0 1-1V4M16 4v3a1 1 0 0 0 1 1h3M20 16h-3a1 1 0 0 0-1 1v3M8 20v-3a1 1 0 0 0-1-1H4' }, // Exit fullscreen\r\n repeat: { d: 'M17 3.5L20.5 7L17 10.5M3.5 11.5V10a3 3 0 0 1 3-3h14M7 20.5L3.5 17L7 13.5M20.5 12.5V14a3 3 0 0 1-3 3h-14' }, // Stay in drawing mode\r\n info: { d: 'M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0zM12 11V16.5', dots: [[12, 7.75, 1.25]] }, // Symbol info\r\n chevronLeft: { d: 'M15 5L8 12L15 19' }, // Scroll left\r\n chevronRight: { d: 'M9 5L16 12L9 19' }, // Scroll right\r\n reset: { d: 'M4.5 12a7.5 7.5 0 1 0 2.2-5.3M4.5 4v4.5H9' }, // Reset the view\r\n calendar: { d: 'M5.5 5h13a2 2 0 0 1 2 2v11.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2zM3.5 10H20.5M8 3V7M16 3V7' }, // Go to date\r\n star: { d: 'M12 3.5L14.6 9L20.5 9.6L16 13.6L17.3 19.5L12 16.5L6.7 19.5L8 13.6L3.5 9.6L9.4 9z' }, // Favourite\r\n ladder: { d: 'M4 6H11M13 6H17M6 10H11M13 10H20M8 14H11M13 14H15M5 18H11M13 18H19' }, // Depth ladder\r\n save: { d: 'M5.5 3.5h10.5l4.5 4.5v10.5a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2v-13a2 2 0 0 1 2-2zM8 3.5v5h7v-5M7.5 20.5v-6h9v6' }, // Save layout\r\n folder: { d: 'M3.5 7a2 2 0 0 1 2-2h4l2 2.5h7a2 2 0 0 1 2 2V17a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z' }, // Open layout\r\n link: { d: 'M10 14a4 4 0 0 0 5.66 0l3-3a4 4 0 0 0-5.66-5.66l-1.2 1.2M14 10a4 4 0 0 0-5.66 0l-3 3a4 4 0 0 0 5.66 5.66l1.2-1.2' }, // Sync\r\n arrowUp: { d: 'M12 19V5M6 11L12 5L18 11' }, // Move pane up\r\n arrowDown: { d: 'M12 5V19M6 13L12 19L18 13' }, // Move pane down\r\n more: { dots: [[6, 12, 1.6], [12, 12, 1.6], [18, 12, 1.6]] }, // More\r\n layoutGrid: { d: 'M5 4.5h4.5a.5.5 0 0 1 .5.5v4.5a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5zM14.5 4.5H19a.5.5 0 0 1 .5.5v4.5a.5.5 0 0 1-.5.5h-4.5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5zM5 14h4.5a.5.5 0 0 1 .5.5V19a.5.5 0 0 1-.5.5H5a.5.5 0 0 1-.5-.5v-4.5A.5.5 0 0 1 5 14zM14.5 14H19a.5.5 0 0 1 .5.5V19a.5.5 0 0 1-.5.5h-4.5a.5.5 0 0 1-.5-.5v-4.5a.5.5 0 0 1 .5-.5z' }, // Chart layout\r\n};\r\n\r\n/** One per drawing tool, keyed by tool type. */\r\nexport const DRAWING_TOOL_ICONS: Readonly<Record<string, IconDef>> = {\r\n trendLine: { d: 'M5 18L19 6', dots: [[5, 18], [19, 6]] }, // Trend Line\r\n ray: { d: 'M5 17L21 5M17.5 4.81L21 5L20.2 8.41', dots: [[5, 17], [11, 12.5]] }, // Ray\r\n extendedLine: { d: 'M3 18.5L21 5M17.5 4.81L21 5L20.2 8.41M6.5 18.69L3 18.5L3.8 15.09', dots: [[9, 14], [15, 9.5]] }, // Extended Line\r\n infoLine: { d: 'M5 20L19 10M4.5 3.5h9a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1zM6.5 6.5h5', dots: [[5, 20], [19, 10]] }, // Info Line\r\n trendAngle: { d: 'M5 18L19 7M5 18H20M11 18A6 6 0 0 0 9.71 14.29', dots: [[5, 18], [19, 7]] }, // Trend Angle\r\n horizontalLine: { d: 'M3 12H21', dots: [[12, 12]] }, // Horizontal Line\r\n horizontalRay: { d: 'M7 12H21M18.5 9.5L21 12L18.5 14.5', dots: [[7, 12]] }, // Horizontal Ray\r\n verticalLine: { d: 'M12 3V21', dots: [[12, 12]] }, // Vertical Line\r\n crossLine: { d: 'M3 12H21M12 3V21', dots: [[12, 12]] }, // Cross Line\r\n parallelChannel: { d: 'M3 15L15 5M9 19L21 9', dots: [[3, 15], [15, 5], [9, 19]] }, // Parallel Channel\r\n regressionChannel: { d: 'M3 12L21 4M3 20L21 12', dash: 'M3 16L21 8', dots: [[3, 16], [21, 8]] }, // Regression Channel\r\n fibRetracement: { d: 'M3 4H21M3 9H21M3 13H21M3 20H21', dots: [[5, 20], [19, 4]] }, // Fib Retracement\r\n fibExtension: { d: 'M3 20L8 10L12 16M14 4H21M14 8H21M14 12H21', dots: [[3, 20], [8, 10], [12, 16]] }, // Fib Extension\r\n fibChannel: { d: 'M3 9L21 3M3 13L21 7M3 16L21 10M3 21L21 15', dots: [[3, 21], [21, 15], [3, 9]] }, // Fib Channel\r\n fibTimeZones: { d: 'M3 4V20M6 4V20M9.5 4V20M14 4V20M20.5 4V20', dots: [[3, 20], [6, 20]] }, // Fib Time Zones\r\n fibSpeedResistanceFan: { d: 'M4 20L20 4M4 20L20 11M4 20L20 16M4 20L11 4', dash: 'M4 4H20V20', dots: [[4, 20], [20, 4]] }, // Fib Speed Resistance Fan\r\n rectangle: { d: 'M5.5 6h13A1.5 1.5 0 0 1 20 7.5v9a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 16.5v-9A1.5 1.5 0 0 1 5.5 6z', dots: [[4, 6], [20, 18]] }, // Rectangle\r\n circle: { d: 'M19.5 12a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0z', dots: [[12, 12], [19.5, 12]] }, // Circle\r\n ellipse: { d: 'M20.5 12c0 3-3.8 5.5-8.5 5.5S3.5 15 3.5 12 7.3 6.5 12 6.5s8.5 2.5 8.5 5.5z', dots: [[3.5, 12], [20.5, 12]] }, // Ellipse\r\n triangle: { d: 'M12 4.5L20 19H4z', dots: [[12, 4.5], [20, 19], [4, 19]] }, // Triangle\r\n pitchfork: { d: 'M4 20L16.75 3M7 9L11.5 3M13 15L21 4.33M7 9L13 15', dots: [[4, 20], [7, 9], [13, 15]] }, // Pitchfork\r\n schiffPitchfork: { d: 'M4 14.5L21 7.42M7 9L21 3.17M13 15L21 11.67M7 9L13 15', dash: 'M4 20V14.5', dots: [[4, 14.5], [7, 9], [13, 15]] }, // Schiff Pitchfork\r\n modifiedSchiffPitchfork: { d: 'M5.5 14.5L21 5.89M7 9L17.8 3M13 15L21 10.56M7 9L13 15', dash: 'M4 20L5.5 14.5', dots: [[5.5, 14.5], [7, 9], [13, 15]] }, // Modified Schiff Pitchfork\r\n gannFan: { d: 'M4 20L20 4M4 20L20 12M4 20L12 4M4 20L20 16.5M4 20L7.5 4', dots: [[4, 20], [20, 4]] }, // Gann Fan\r\n gannBox: { d: 'M4 4H20V20H4zM4 20L20 4M4 4L20 20M12 4V20', dots: [[4, 20], [20, 4]] }, // Gann Box\r\n cyclicLines: { d: 'M4 4V20M9 4V20M14 4V20M19 4V20', dots: [[4, 20], [9, 20]] }, // Cyclic Lines\r\n xabcdPattern: { d: 'M3 18L7 6L11 13L15 8L21 19', dash: 'M3 18L11 13L21 19', dots: [[3, 18], [7, 6], [11, 13], [15, 8], [21, 19]] }, // XABCD Pattern\r\n abcdPattern: { d: 'M4 19L9 8L13 14L20 4', dots: [[4, 19], [9, 8], [13, 14], [20, 4]] }, // ABCD Pattern\r\n headAndShoulders: { d: 'M3 19L6 11L8.5 15L12 5L15.5 15L18 11L21 19', dash: 'M4.5 15H19.5', dots: [[6, 11], [12, 5], [18, 11]] }, // Head and Shoulders\r\n elliottWave: { d: 'M3 19L6 13L8.5 16L14 6L16 10L21 4', dots: [[3, 19], [21, 4]] }, // Elliott Wave\r\n priceRange: { d: 'M5 4H19M5 20H19M12 6.5V17.5M9 9.5L12 6.5L15 9.5M9 14.5L12 17.5L15 14.5' }, // Price Range\r\n dateRange: { d: 'M4 5V19M20 5V19M6.5 12H17.5M9.5 9L6.5 12L9.5 15M14.5 9L17.5 12L14.5 15' }, // Date Range\r\n dateAndPriceRange: { d: 'M6 18V4M3 7L6 4L9 7M6 18H20M17 15L20 18L17 21', dash: 'M6 4H20V18' }, // Date and Price Range\r\n measure: { d: 'M3.5 16.5L16.5 3.5L20.5 7.5L7.5 20.5zM6.5 13.5L8 15M9.5 10.5L11.5 12.5M12.5 7.5L14 9' }, // Measure\r\n text: { d: 'M6 6V4.5H18V6M12 4.5V19.5M9.5 19.5H14.5' }, // Text\r\n priceLabel: { d: 'M9 5H19a1.5 1.5 0 0 1 1.5 1.5v11A1.5 1.5 0 0 1 19 19H9L3.5 12zM11 12H17' }, // Price Label\r\n arrow: { d: 'M5 19L19 5M10 5H19V14' }, // Arrow\r\n riskReward: { d: 'M5 12V4H19V12M3 12H21', dash: 'M5 12V18H19V12', dots: [[5, 12]] }, // Long/Short Position\r\n anchoredVWAP: { d: 'M4 18C9 17 12 10 20 7M4 20.5V18', dots: [[4, 18]] }, // Anchored VWAP\r\n volumeProfileRange: { d: 'M6 7H12M6 10.5H17M6 14H15M6 17.5H10', dash: 'M3.5 4V20M20.5 4V20', dots: [[3.5, 20], [20.5, 20]] }, // Fixed Range Volume Profile\r\n note: { d: 'M5.5 4.5h13v9l-5 5h-8zM13.5 18.5v-5h5M8.5 8.5h7M8.5 11.5h4' }, // Note\r\n callout: { d: 'M10.5 4h9a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1zM12 12L5 19M12.5 8h5', dots: [[5, 19]] }, // Callout\r\n flag: { d: 'M6 21V4M6 4.5h11l-2.5 3.75L17 12H6', soft: 'M6 4.5h11l-2.5 3.75L17 12H6z', dots: [[6, 21]] }, // Flag Mark\r\n arrowMark: { d: 'M12 4L18 11H14.5V20H9.5V11H6z' }, // Arrow Mark\r\n icon: { d: 'M12 3.5l2.6 5.3 5.9.85-4.25 4.15 1 5.85L12 16.9l-5.25 2.75 1-5.85L3.5 9.65l5.9-.85z' }, // Icon\r\n brush: { d: 'M3.5 17c2.5 0 3-5 6-5s2.5 5 5.5 5 3.5-6 5.5-9' }, // Brush\r\n highlighter: { d: 'M14.5 4.5l5 5L11 18H6v-5zM12 7l5 5M4 21h8' }, // Highlighter\r\n path: { d: 'M4 18L9 10L14 14L20 6M16.2 6.6L20 6L19.6 9.8', dots: [[4, 18], [9, 10], [14, 14]] }, // Path\r\n polyline: { d: 'M5 17L8 6L16 4L20 14L12 20z', soft: 'M5 17L8 6L16 4L20 14L12 20z', dots: [[5, 17], [8, 6], [16, 4], [20, 14], [12, 20]] }, // Polyline\r\n curve: { d: 'M4 18C8 4 16 4 20 18', dots: [[4, 18], [20, 18], [12, 7.5]] }, // Curve\r\n arc: { d: 'M4 17a8 8 0 0 1 16 0', dots: [[4, 17], [20, 17], [12, 9]] }, // Arc\r\n fibCircles: { d: 'M14 12a2 2 0 1 1-4 0 2 2 0 0 1 4 0zM16.5 12a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0zM20 12a8 8 0 1 1-16 0 8 8 0 0 1 16 0z', dots: [[12, 12], [20, 12]] }, // Fib Circles\r\n fibSpiral: { d: 'M12 12a1.5 1.5 0 0 1 1.5 1.5 3 3 0 0 1-3 3A4.5 4.5 0 0 1 6 12a6 6 0 0 1 6-6 8 8 0 0 1 8 8', dots: [[12, 12]] }, // Fib Spiral\r\n fibArcs: { d: 'M10 20a6 6 0 0 0-6-6M14 20a10 10 0 0 0-10-10M18 20a14 14 0 0 0-14-14', dash: 'M4 20L18 6', dots: [[4, 20], [18, 6]] }, // Fib Speed Resistance Arcs\r\n fibWedge: { d: 'M4 19L20 7M4 19L20 16M10.4 14.2A8 8 0 0 1 11.86 17.53M14.4 11.2A13 13 0 0 1 16.78 16.6', dots: [[4, 19], [20, 7], [20, 16]] }, // Fib Wedge\r\n pitchfan: { d: 'M4 20L14 4M4 20L20 14M4 20L17 9', dash: 'M14 4L20 14', dots: [[4, 20], [14, 4], [20, 14]] }, // Pitchfan\r\n gannSquare: { d: 'M4 4H20V20H4zM4 20L20 4M4 12H20M12 4V20M4 12a8 8 0 0 1 8 8', dots: [[4, 20], [20, 4]] }, // Gann Square\r\n elliottImpulse: { d: 'M3 19L7 12L10 15L15 5L17.5 9L21 3', dots: [[3, 19], [21, 3]] }, // Elliott Impulse Wave\r\n elliottCorrection: { d: 'M4 5L10 17L14 11L20 20', dots: [[4, 5], [20, 20]] }, // Elliott Correction Wave\r\n elliottTriangle: { d: 'M3 6L7 17L11 9L15 15L18 11L21 13', dots: [[3, 6], [21, 13]] }, // Elliott Triangle Wave\r\n elliottDoubleCombo: { d: 'M4 5L9 14L13 9L20 19', dots: [[4, 5], [9, 14], [13, 9], [20, 19]] }, // Elliott Double Combo Wave\r\n elliottTripleCombo: { d: 'M3 5L7 13L10 9L14 16L17 12L21 20', dots: [[3, 5], [21, 20]] }, // Elliott Triple Combo Wave\r\n threeDrives: { d: 'M3 20L7 12L9.5 15L14 7L16.5 10L21 3', dash: 'M7 12L14 7L21 3', dots: [[7, 12], [14, 7], [21, 3]] }, // Three Drives Pattern\r\n cypherPattern: { d: 'M3 19L7 9L10 14L15 5L20 16', dash: 'M3 19L10 14L20 16', dots: [[3, 19], [7, 9], [10, 14], [15, 5], [20, 16]] }, // Cypher Pattern\r\n timeCycles: { d: 'M3 18a4.5 4.5 0 0 1 9 0a4.5 4.5 0 0 1 9 0', dots: [[3, 18], [12, 18]] }, // Time Cycles\r\n sineLine: { d: 'M3 12C5 5 7.5 5 9 12S13 19 15 12 19.5 5 21 12', dots: [[6, 6.75], [12, 17.25]] }, // Sine Line\r\n forecast: { d: 'M4 18L15.2 7.8M19.5 6a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z', dots: [[4, 18]] }, // Forecast\r\n projection: { d: 'M12 19L18 11M15.2 11.3L18 11L17.8 13.8', dash: 'M3 17L9 9', dots: [[3, 17], [9, 9], [12, 19]] }, // Projection\r\n barsPattern: { d: 'M5 6V14M9 9V18M15 4V12M19 7V16', fills: ['M4 8h2v4H4z', 'M8 11h2v5H8z', 'M14 6h2v4h-2z', 'M18 9h2v5h-2z'], dash: 'M12 3V21' }, // Bars Pattern\r\n};\r\n\r\n/** One per chart type, keyed by chart type. */\r\nexport const CHART_TYPE_ICONS: Readonly<Record<string, IconDef>> = {\r\n candlestick: { d: 'M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19', fills: ['M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1z', 'M14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z'] }, // Candlestick\r\n hollowCandle: { d: 'M8 3.5V7M8 16V20.5M16 5V8.5M16 15.5V19M6.5 7h3a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zM14.5 8.5h3a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z' }, // Hollow Candle\r\n heikinAshi: { d: 'M5.5 9.5V12M5.5 18V20M12 5.5V8M12 14V16M18.5 3V4.5M18.5 10.5V12.5', fills: ['M4 12h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5H4a.5.5 0 0 1-.5-.5v-5A.5.5 0 0 1 4 12z', 'M10.5 8h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-5a.5.5 0 0 1 .5-.5z', 'M17 4.5h3a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5V5a.5.5 0 0 1 .5-.5z'] }, // Heikin-Ashi\r\n bar: { d: 'M8 4V20M5 8H8M8 16H11M16 6V18M13 15H16M16 9H19' }, // Bar (OHLC)\r\n volumeCandles: { d: 'M6.5 5V8M6.5 16V19M15.5 3.5V6M15.5 16V20', fills: ['M5.5 8h2a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5z', 'M11.5 6h8a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-9a.5.5 0 0 1 .5-.5z'] }, // Volume Candles\r\n equivolume: { d: 'M4.5 10h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1zM10 6h5a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zM18.5 4h1a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z' }, // Equivolume\r\n line: { d: 'M3 17L8 11L12 14L21 5' }, // Line\r\n area: { d: 'M3 17L8 11L12 14L21 5', soft: 'M3 17L8 11L12 14L21 5V20H3z' }, // Area\r\n baseline: { d: 'M3 16L7 9L11 14L15 7L21 15', dash: 'M3 12H21' }, // Baseline\r\n hlcArea: { d: 'M3 9L8 6L13 9L21 4M3 15L8 13L13 16L21 11', dash: 'M3 12L8 9.5L13 12.5L21 7.5', soft: 'M3 9L8 6L13 9L21 4V11L13 16L8 13L3 15z' }, // HLC Area\r\n stepLine: { d: 'M3 18H8V12H12V15H16V7H21' }, // Step Line\r\n lineWithMarkers: { d: 'M4 17L9 10L14 14L20 6', dots: [[4, 17], [9, 10], [14, 14], [20, 6]] }, // Line with Markers\r\n hiLo: { d: 'M6 7V17M12 4V14M18 9V20', fills: ['M5 7h2v10H5z', 'M11 4h2v10h-2z', 'M17 9h2v11h-2z'] }, // High-Low\r\n renko: { d: 'M3.5 15.5h4v4h-4zM7.5 11.5h4v4h-4zM11.5 7.5h4v4h-4zM15.5 11.5h4v4h-4z' }, // Renko\r\n lineBreak: { d: 'M4 14h4v5H4zM8 10h4v4H8zM16 9h4v8h-4z', fills: ['M12 5h4v5h-4z'] }, // Line Break\r\n kagi: { d: 'M4 19V11H9V16H14V5H20V13' }, // Kagi\r\n pointAndFigure: { d: 'M5.5 5.5l3 3M8.5 5.5l-3 3M5.5 10.5l3 3M8.5 10.5l-3 3M5.5 15.5l3 3M8.5 15.5l-3 3M14.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0M14.5 14a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0' }, // Point & Figure\r\n rangeBars: { d: 'M6.5 11V12M6.5 18V19M12 7V8M12 14V15M17.5 3.5V4.5M17.5 10.5V11.5', fills: ['M5 12h3v6H5z', 'M10.5 8h3v6h-3z', 'M16 4.5h3v6h-3z'] }, // Range Bars\r\n};\r\n\r\nconst DOT_RADIUS = 1.75;\r\nconst SOFT_OPACITY = 0.22;\r\nconst markupCache = new WeakMap<IconDef, string>();\r\n\r\n/** The icon's SVG elements, drawn in `currentColor`. */\r\nfunction markup(icon: IconDef): string {\r\n const cached = markupCache.get(icon);\r\n if (cached) return cached;\r\n let s = '';\r\n if (icon.soft) s += `<path d=\"${icon.soft}\" fill=\"currentColor\" fill-opacity=\"${SOFT_OPACITY}\" stroke=\"none\"/>`;\r\n for (const f of icon.fills ?? []) s += `<path d=\"${f}\" fill=\"currentColor\" stroke=\"none\"/>`;\r\n if (icon.d) s += `<path d=\"${icon.d}\"/>`;\r\n if (icon.dash) s += `<path d=\"${icon.dash}\" stroke-dasharray=\"2 2.5\"/>`;\r\n for (const [cx, cy, r = DOT_RADIUS] of icon.dots ?? []) s += `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"currentColor\" stroke=\"none\"/>`;\r\n markupCache.set(icon, s);\r\n return s;\r\n}\r\n\r\n/** The icon as an inline SVG string at `size` px, coloured by `currentColor`. */\r\nexport function iconSvg(icon: IconDef, size: number): string {\r\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\">${markup(icon)}</svg>`;\r\n}\r\n","import { CHART_TYPE_ICONS, DRAWING_TOOL_ICONS, UI_ICONS, iconSvg, type IconDef } from './iconSet.js';\r\n\r\nconst own = (map: Readonly<Record<string, IconDef>>, key: string): IconDef | undefined =>\r\n Object.prototype.hasOwnProperty.call(map, key) ? map[key] : undefined;\r\n\r\n/** An interface icon (toolbar, sidebar, panels) as inline SVG; '' for an unknown name. */\r\nexport function createIcon(name: string, size = 14): string {\r\n const icon = own(UI_ICONS, name);\r\n return icon ? iconSvg(icon, size) : '';\r\n}\r\n\r\n/** A drawing tool's own icon; a pen for a tool without one (e.g. from a plugin). */\r\nexport function createToolIcon(tool: string, size = 16): string {\r\n return iconSvg(own(DRAWING_TOOL_ICONS, tool) ?? UI_ICONS.penLine, size);\r\n}\r\n\r\n/** A chart type's icon; the generic chart glyph for a type without one. */\r\nexport function createChartTypeIcon(type: string, size = 14): string {\r\n return iconSvg(own(CHART_TYPE_ICONS, type) ?? UI_ICONS.barChart, size);\r\n}\r\n","/** Text made safe to put in HTML markup, attribute values included. */\r\nexport function escapeHtml(text: string): string {\r\n return text.replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c]!);\r\n}\r\n","export class WidgetDropdown {\r\n private trigger: HTMLElement;\r\n private panel: HTMLDivElement;\r\n private _isOpen = false;\r\n private onOutsideClick: (e: MouseEvent) => void;\r\n private onEscapeKey: (e: KeyboardEvent) => void;\r\n private onTriggerClick: () => void;\r\n\r\n constructor(trigger: HTMLElement, config: { width?: string; align?: 'left' | 'right' } = {}) {\r\n this.trigger = trigger;\r\n\r\n this.panel = document.createElement('div');\r\n this.panel.className = 'tcw-dropdown';\r\n // At least this wide; wider when a label in the look's font or a longer language needs it.\r\n this.panel.style.minWidth = config.width ?? '200px';\r\n // From the trigger's start edge (its left, or its right in a right-to-left widget).\r\n if (config.align === 'right') {\r\n this.panel.style.insetInlineEnd = '0px';\r\n } else {\r\n this.panel.style.insetInlineStart = '0px';\r\n }\r\n this.panel.style.display = 'none';\r\n\r\n // Position relative to trigger\r\n trigger.style.position = 'relative';\r\n trigger.appendChild(this.panel);\r\n\r\n this.onTriggerClick = () => {\r\n if (this._isOpen) {\r\n this.close();\r\n } else {\r\n this.open();\r\n }\r\n };\r\n\r\n this.onOutsideClick = (e: MouseEvent) => {\r\n if (!this.trigger.contains(e.target as Node)) {\r\n this.close();\r\n }\r\n };\r\n\r\n this.onEscapeKey = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') {\r\n this.close();\r\n }\r\n };\r\n\r\n trigger.addEventListener('click', this.onTriggerClick);\r\n }\r\n\r\n setContent(html: string): void {\r\n this.panel.innerHTML = html;\r\n }\r\n\r\n open(): void {\r\n if (this._isOpen) return;\r\n this._isOpen = true;\r\n this.panel.style.display = '';\r\n document.addEventListener('mousedown', this.onOutsideClick);\r\n document.addEventListener('keydown', this.onEscapeKey);\r\n }\r\n\r\n close(): void {\r\n if (!this._isOpen) return;\r\n this._isOpen = false;\r\n this.panel.style.display = 'none';\r\n document.removeEventListener('mousedown', this.onOutsideClick);\r\n document.removeEventListener('keydown', this.onEscapeKey);\r\n }\r\n\r\n isOpen(): boolean {\r\n return this._isOpen;\r\n }\r\n\r\n destroy(): void {\r\n this.trigger.removeEventListener('click', this.onTriggerClick);\r\n document.removeEventListener('mousedown', this.onOutsideClick);\r\n document.removeEventListener('keydown', this.onEscapeKey);\r\n this.panel.remove();\r\n }\r\n}\r\n","import type { DrawingToolGroupDef } from './types.js';\r\nimport type { MessageKey, Translator } from './i18n.js';\r\n\r\n/** Number formats the settings offer, by locale tag. */\r\nexport const NUMBER_LOCALES: readonly string[] = [\r\n 'en-US', 'en-GB', 'en-IN', 'de-DE', 'fr-FR', 'es-ES', 'it-IT', 'pt-BR', 'ru-RU', 'tr-TR',\r\n 'vi-VN', 'id-ID', 'th-TH', 'zh-CN', 'zh-TW', 'ja-JP', 'ko-KR',\r\n];\r\n\r\nconst SAMPLE = 65234;\r\n\r\n/** \"de-DE (65.234,00)\": each format with a sample number; the current one stays listed. */\r\nexport function numberLocaleOptions(current: string): { value: string; label: string }[] {\r\n const codes = current && !NUMBER_LOCALES.includes(current) ? [current, ...NUMBER_LOCALES] : NUMBER_LOCALES;\r\n return codes.map((code) => {\r\n let sample: string;\r\n try {\r\n sample = new Intl.NumberFormat(code, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(SAMPLE);\r\n } catch {\r\n sample = '';\r\n }\r\n return { value: code, label: sample ? `${code} (${sample})` : code };\r\n });\r\n}\r\n\r\n/** Message key of each built-in drawing-tool group, by its English name. */\r\nconst TOOL_GROUP_KEYS: Readonly<Record<string, MessageKey>> = {\r\n Lines: 'toolGroup.lines',\r\n 'Horizontal/Vertical': 'toolGroup.horizontalVertical',\r\n Channels: 'toolGroup.channels',\r\n Fibonacci: 'toolGroup.fibonacci',\r\n Shapes: 'toolGroup.shapes',\r\n 'Gann & Pitchforks': 'toolGroup.gannPitchforks',\r\n Patterns: 'toolGroup.patterns',\r\n Measure: 'toolGroup.measure',\r\n Annotation: 'toolGroup.annotation',\r\n Forecasting: 'toolGroup.forecasting',\r\n Brushes: 'toolGroup.brushes',\r\n Cycles: 'toolGroup.cycles',\r\n 'Elliott Waves': 'toolGroup.elliott',\r\n};\r\n\r\n/** A chart type's name in the widget's language (an unknown type keeps its own). */\r\nexport function chartTypeLabel(ct: { value: string; label: string }, t: Translator): string {\r\n const key = `chartType.${ct.value}` as MessageKey;\r\n const translated = t(key);\r\n return translated === key ? ct.label : translated;\r\n}\r\n\r\n/** The drawing-tool groups with names in the widget's language (unknown tools keep theirs). */\r\nexport function localizeToolGroups(groups: readonly DrawingToolGroupDef[], t: Translator): DrawingToolGroupDef[] {\r\n return groups.map((group) => ({\r\n label: TOOL_GROUP_KEYS[group.label] ? t(TOOL_GROUP_KEYS[group.label]) : group.label,\r\n tools: group.tools.map((tool) => {\r\n const key = `tool.${tool.value}` as MessageKey;\r\n const label = t(key);\r\n return { ...tool, label: label === key ? tool.label : label };\r\n }),\r\n }));\r\n}\r\n","import type { ChartType, TimeFrame } from '@tradecanvas/commons';\r\nimport type { ToolbarButtonSpec, ToolbarConfig, ToolbarCallbacks, WidgetState } from './types.js';\r\nimport { createChartTypeIcon, createIcon } from './icons.js';\r\nimport { escapeHtml as esc } from './escapeHtml.js';\r\nimport { WidgetDropdown } from './WidgetDropdown.js';\r\nimport { fill, type Translator } from './i18n.js';\r\nimport { chartTypeLabel } from './widgetLocales.js';\r\n\r\nlet toolbarCount = 0;\r\n\r\n/** A host button's name: its label, with the text it shows when that says more (\"News: 3\"). */\r\nexport function setHostButtonName(btn: HTMLButtonElement, label: string): void {\r\n const text = btn.querySelector('.tcw-host-btn-text')?.textContent ?? '';\r\n if (text === label) btn.removeAttribute('aria-label');\r\n else btn.setAttribute('aria-label', text ? `${label}: ${text}` : label);\r\n}\r\n\r\nexport class WidgetToolbar {\r\n private config: ToolbarConfig;\r\n private callbacks: ToolbarCallbacks;\r\n private t: Translator;\r\n private el: HTMLDivElement;\r\n private chartTypeDropdown: WidgetDropdown | null = null;\r\n private indicatorDropdown: WidgetDropdown | null = null;\r\n private tfGroup: HTMLDivElement | null = null;\r\n private tfDropdown: WidgetDropdown | null = null;\r\n private tfFavorites: TimeFrame[] = [];\r\n /** Tells this toolbar's element ids apart from another widget's on the page. */\r\n private readonly uid = (toolbarCount++).toString(36);\r\n private tfRendered = '';\r\n private themeBtn: HTMLButtonElement | null = null;\r\n /** Indicator templates' names, listed atop the indicators menu. */\r\n private indicatorTemplates: string[] = [];\r\n private fullscreenBtn: HTMLButtonElement | null = null;\r\n /** Where hosts' own buttons go: after the chart controls, and before the panel buttons. */\r\n private hostLeft: HTMLDivElement | null = null;\r\n private hostRight: HTMLDivElement | null = null;\r\n\r\n constructor(host: HTMLElement, config: ToolbarConfig, callbacks: ToolbarCallbacks, t: Translator) {\r\n this.config = config;\r\n this.callbacks = callbacks;\r\n this.t = t;\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-toolbar';\r\n this.build();\r\n host.appendChild(this.el);\r\n }\r\n\r\n private build(): void {\r\n const { config, callbacks, el } = this;\r\n\r\n // Symbol button\r\n const symbolBtn = document.createElement('button');\r\n symbolBtn.className = 'tcw-toolbar-symbol';\r\n symbolBtn.dataset.role = 'symbol';\r\n symbolBtn.addEventListener('click', callbacks.onSymbolClick);\r\n el.appendChild(symbolBtn);\r\n if (callbacks.onSymbolInfo) {\r\n const infoBtn = this.iconBtn('info', this.t('symbolInfo.title'), callbacks.onSymbolInfo);\r\n infoBtn.dataset.role = 'symbolInfo';\r\n el.appendChild(infoBtn);\r\n }\r\n el.appendChild(this.sep());\r\n\r\n // Timeframes: the favourites as buttons (plus the current one if it isn't\r\n // pinned); the menu lists them all, with a star to pin or unpin.\r\n this.tfFavorites = [...(config.timeframeFavorites ?? config.timeframes.map((tf) => tf.value))];\r\n this.tfGroup = document.createElement('div');\r\n this.tfGroup.className = 'tcw-toolbar-group tcw-tf-group';\r\n el.appendChild(this.tfGroup);\r\n if (callbacks.onToggleTimeframeFavorite && config.timeframes.length > 0) {\r\n const tfWrap = document.createElement('div');\r\n tfWrap.style.position = 'relative';\r\n tfWrap.style.display = 'inline-flex';\r\n const tfTrigger = document.createElement('button');\r\n tfTrigger.className = 'tcw-btn tcw-tf-more';\r\n tfTrigger.dataset.role = 'timeframes';\r\n tfTrigger.title = this.t('toolbar.timeframes');\r\n tfTrigger.setAttribute('aria-label', this.t('toolbar.timeframes'));\r\n tfTrigger.innerHTML = createIcon('chevronDown', 12);\r\n tfWrap.appendChild(tfTrigger);\r\n el.appendChild(tfWrap);\r\n this.tfDropdown = new WidgetDropdown(tfWrap, { width: '150px' });\r\n this.buildTimeframeMenu();\r\n }\r\n el.appendChild(this.sep());\r\n\r\n // Chart type dropdown\r\n const ctWrap = document.createElement('div');\r\n ctWrap.style.position = 'relative';\r\n ctWrap.style.display = 'inline-flex';\r\n\r\n const ctTrigger = document.createElement('button');\r\n ctTrigger.className = 'tcw-dropdown-trigger';\r\n ctTrigger.dataset.role = 'charttype';\r\n ctWrap.appendChild(ctTrigger);\r\n el.appendChild(ctWrap);\r\n\r\n this.chartTypeDropdown = new WidgetDropdown(ctWrap, { width: '160px' });\r\n this.buildChartTypeMenu();\r\n\r\n el.appendChild(this.sep());\r\n\r\n // Indicators dropdown\r\n const indWrap = document.createElement('div');\r\n indWrap.style.position = 'relative';\r\n indWrap.style.display = 'inline-flex';\r\n\r\n const indTrigger = document.createElement('button');\r\n indTrigger.className = 'tcw-dropdown-trigger';\r\n indTrigger.dataset.role = 'indicators';\r\n indWrap.appendChild(indTrigger);\r\n el.appendChild(indWrap);\r\n\r\n this.indicatorDropdown = new WidgetDropdown(indWrap, { width: '280px' });\r\n this.buildIndicatorMenu();\r\n\r\n this.hostLeft = this.hostGroup();\r\n el.appendChild(this.hostLeft);\r\n\r\n // Spacer\r\n el.appendChild(this.spacer());\r\n\r\n // Right side buttons\r\n if (callbacks.onLayouts) {\r\n const onLayouts = callbacks.onLayouts;\r\n const layoutsBtn = document.createElement('button');\r\n layoutsBtn.type = 'button';\r\n layoutsBtn.className = 'tcw-dropdown-trigger tcw-layouts-btn';\r\n layoutsBtn.dataset.role = 'layouts';\r\n layoutsBtn.setAttribute('aria-haspopup', 'menu');\r\n layoutsBtn.addEventListener('click', () => onLayouts(layoutsBtn));\r\n el.appendChild(layoutsBtn);\r\n this.setLayout(null, false);\r\n }\r\n\r\n this.hostRight = this.hostGroup();\r\n el.appendChild(this.hostRight);\r\n\r\n if (callbacks.onToggleReplay) {\r\n const replayBtn = this.iconBtn('play', this.t('toolbar.replay'), callbacks.onToggleReplay);\r\n replayBtn.dataset.role = 'replay';\r\n el.appendChild(replayBtn);\r\n }\r\n\r\n if (callbacks.onBracket) {\r\n const onBracket = callbacks.onBracket;\r\n const longBtn = this.iconBtn('trendingUp', this.t('toolbar.longBracket'), () => onBracket('buy'));\r\n longBtn.dataset.role = 'long';\r\n longBtn.classList.add('tcw-btn-long');\r\n el.appendChild(longBtn);\r\n const shortBtn = this.iconBtn('trendingDown', this.t('toolbar.shortBracket'), () => onBracket('sell'));\r\n shortBtn.dataset.role = 'short';\r\n shortBtn.classList.add('tcw-btn-short');\r\n el.appendChild(shortBtn);\r\n }\r\n\r\n if (callbacks.onToggleLadder) {\r\n const ladderBtn = this.iconBtn('ladder', this.t('toolbar.depthLadder'), callbacks.onToggleLadder);\r\n ladderBtn.dataset.role = 'ladder';\r\n el.appendChild(ladderBtn);\r\n }\r\n\r\n if (callbacks.onToggleAccount) {\r\n const accountBtn = this.iconBtn('receipt', this.t('toolbar.account'), callbacks.onToggleAccount);\r\n accountBtn.dataset.role = 'account';\r\n accountBtn.setAttribute('aria-pressed', 'false');\r\n el.appendChild(accountBtn);\r\n }\r\n\r\n if (callbacks.onToggleObjects) {\r\n const objectsBtn = this.iconBtn('layers', this.t('toolbar.objects'), callbacks.onToggleObjects);\r\n objectsBtn.dataset.role = 'objects';\r\n el.appendChild(objectsBtn);\r\n }\r\n\r\n if (callbacks.onToggleAlerts) {\r\n const alertsBtn = this.iconBtn('bell', this.t('toolbar.priceAlerts'), callbacks.onToggleAlerts);\r\n alertsBtn.dataset.role = 'alerts';\r\n el.appendChild(alertsBtn);\r\n }\r\n\r\n const screenshotBtn = this.iconBtn('camera', this.t('toolbar.screenshot'), callbacks.onScreenshot);\r\n el.appendChild(screenshotBtn);\r\n\r\n const settingsBtn = this.iconBtn('settings', this.t('toolbar.settings'), callbacks.onSettings);\r\n el.appendChild(settingsBtn);\r\n\r\n this.themeBtn = this.iconBtn('moon', this.t('toolbar.toggleTheme'), callbacks.onToggleTheme);\r\n this.themeBtn.dataset.role = 'theme';\r\n el.appendChild(this.themeBtn);\r\n\r\n if (callbacks.onToggleFullscreen) {\r\n this.fullscreenBtn = this.iconBtn('maximize', this.t('toolbar.fullscreen'), callbacks.onToggleFullscreen);\r\n this.fullscreenBtn.dataset.role = 'fullscreen';\r\n this.fullscreenBtn.setAttribute('aria-pressed', 'false');\r\n el.appendChild(this.fullscreenBtn);\r\n }\r\n }\r\n\r\n /** A host's own button, on the left or the right of the toolbar. */\r\n addHostButton(spec: ToolbarButtonSpec): HTMLButtonElement {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = spec.text || !spec.icon ? 'tcw-btn tcw-host-btn' : 'tcw-btn-icon tcw-host-btn';\r\n btn.dataset.hostButton = spec.id;\r\n btn.title = spec.label;\r\n if (spec.toggle) btn.setAttribute('aria-pressed', 'false');\r\n if (typeof spec.icon === 'string') btn.innerHTML = createIcon(spec.icon, 14);\r\n else if (spec.icon) btn.appendChild(spec.icon);\r\n const text = spec.text ?? (spec.icon ? '' : spec.label);\r\n if (text) {\r\n const span = document.createElement('span');\r\n span.className = 'tcw-host-btn-text';\r\n span.textContent = text;\r\n btn.appendChild(span);\r\n }\r\n setHostButtonName(btn, spec.label);\r\n btn.addEventListener('click', () => spec.onClick(btn));\r\n (spec.side === 'left' ? this.hostLeft : this.hostRight)?.appendChild(btn);\r\n return btn;\r\n }\r\n\r\n private hostGroup(): HTMLDivElement {\r\n const group = document.createElement('div');\r\n group.className = 'tcw-toolbar-host';\r\n return group;\r\n }\r\n\r\n /** Show a panel button (by its role: 'account', 'objects'…) as on or off. */\r\n setActive(role: string, on: boolean): void {\r\n const btn = this.el.querySelector<HTMLButtonElement>(`[data-role=\"${role}\"]`);\r\n if (!btn) return;\r\n btn.classList.toggle('tcw-active', on);\r\n btn.setAttribute('aria-pressed', String(on));\r\n }\r\n\r\n /** The layout open now on its button (`null`: none saved yet), with a dot while it has unsaved changes. */\r\n setLayout(name: string | null, dirty: boolean): void {\r\n const btn = this.el.querySelector<HTMLButtonElement>('[data-role=\"layouts\"]');\r\n if (!btn) return;\r\n const shown = name ?? this.t('layouts.unnamed');\r\n const label = `${this.t('toolbar.layouts')}: ${shown}${dirty ? ` (${this.t('layouts.unsavedChanges')})` : ''}`;\r\n btn.innerHTML = `${createIcon('save', 14)}<span class=\"tcw-layouts-label\">${esc(shown)}</span>`\r\n + (dirty ? '<span class=\"tcw-layouts-dirty\" aria-hidden=\"true\"></span>' : '')\r\n + createIcon('chevronDown', 12);\r\n btn.title = label;\r\n btn.setAttribute('aria-label', label);\r\n }\r\n\r\n /** Swap the fullscreen button between enter and exit. */\r\n setFullscreen(on: boolean): void {\r\n if (!this.fullscreenBtn) return;\r\n const label = this.t(on ? 'toolbar.exitFullscreen' : 'toolbar.fullscreen');\r\n this.fullscreenBtn.innerHTML = createIcon(on ? 'minimize' : 'maximize', 14);\r\n this.fullscreenBtn.title = label;\r\n this.fullscreenBtn.setAttribute('aria-pressed', String(on));\r\n }\r\n\r\n private chartTypeLabel(ct: { value: ChartType; label: string }): string {\r\n return chartTypeLabel(ct, this.t);\r\n }\r\n\r\n private buildChartTypeMenu(): void {\r\n if (!this.chartTypeDropdown) return;\r\n const items = this.config.chartTypes.map(ct =>\r\n `<button class=\"tcw-dropdown-item tcw-dropdown-item--icon\" data-ct=\"${esc(ct.value)}\">${createChartTypeIcon(ct.value, 16)}<span>${esc(this.chartTypeLabel(ct))}</span></button>`\r\n ).join('');\r\n this.chartTypeDropdown.setContent(items);\r\n\r\n // Attach events to items after content set\r\n const panel = this.chartTypeDropdown['panel'] as HTMLDivElement;\r\n panel.querySelectorAll('.tcw-dropdown-item').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n const value = (e.currentTarget as HTMLElement).dataset.ct as ChartType;\r\n this.callbacks.onChartType(value);\r\n this.chartTypeDropdown?.close();\r\n });\r\n });\r\n }\r\n\r\n /** The symbol's name on its button, as a tooltip (\"Apple Inc. · NASDAQ\"). */\r\n setSymbolDescription(text: string | null): void {\r\n const btn = this.el.querySelector<HTMLButtonElement>('[data-role=\"symbol\"]');\r\n if (!btn) return;\r\n if (text) btn.title = text;\r\n else btn.removeAttribute('title');\r\n }\r\n\r\n /** A new list of timeframes (a custom one added or removed), with its pins. */\r\n setTimeframes(timeframes: ToolbarConfig['timeframes'], favorites: TimeFrame[]): void {\r\n this.config = { ...this.config, timeframes };\r\n this.setTimeframeFavorites(favorites);\r\n }\r\n\r\n /** Re-pin after the user starred or unstarred a timeframe. */\r\n setTimeframeFavorites(favorites: TimeFrame[]): void {\r\n this.tfFavorites = [...favorites];\r\n this.tfRendered = '';\r\n this.buildTimeframeMenu();\r\n }\r\n\r\n private buildTimeframeMenu(): void {\r\n if (!this.tfDropdown) return;\r\n const pin = esc(this.t('toolbar.timeframes.pin'));\r\n const remove = esc(this.t('toolbar.timeframes.remove'));\r\n let html = `<div class=\"tcw-dropdown-label\">${esc(this.t('toolbar.timeframes'))}</div>`;\r\n for (const tf of this.config.timeframes) {\r\n const pinned = this.tfFavorites.includes(tf.value);\r\n const [value, label] = [esc(tf.value), esc(tf.label)];\r\n html += `<div class=\"tcw-tf-row\">`\r\n + `<button class=\"tcw-dropdown-item\" data-tf-pick=\"${value}\">${label}</button>`\r\n + (tf.custom && this.callbacks.onRemoveTimeframe\r\n ? `<button class=\"tcw-tf-remove\" data-tf-remove=\"${value}\" title=\"${remove}\" aria-label=\"${remove}: ${label}\">${createIcon('x', 12)}</button>`\r\n : '')\r\n + `<button class=\"tcw-tf-star${pinned ? ' tcw-active' : ''}\" data-tf-star=\"${value}\" aria-pressed=\"${pinned}\"`\r\n + ` title=\"${pin}\" aria-label=\"${pin}: ${label}\">${createIcon('star', 12)}</button>`\r\n + `</div>`;\r\n }\r\n if (this.callbacks.onAddTimeframe) {\r\n const custom = esc(this.t('toolbar.timeframes.custom'));\r\n const add = esc(this.t('toolbar.timeframes.add'));\r\n html += `<form class=\"tcw-tf-custom\" novalidate>`\r\n + `<input class=\"tcw-tf-custom-input\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\" maxlength=\"6\"`\r\n + ` placeholder=\"7m, 90m, 2h…\" aria-label=\"${custom}\" aria-describedby=\"tcw-tf-hint-${this.uid}\">`\r\n + `<button type=\"submit\" class=\"tcw-tf-custom-add\" title=\"${add}\" aria-label=\"${add}\">${createIcon('plus', 12)}</button>`\r\n + `<div class=\"tcw-tf-custom-hint\" id=\"tcw-tf-hint-${this.uid}\" role=\"status\"></div>`\r\n + `</form>`;\r\n }\r\n this.tfDropdown.setContent(html);\r\n\r\n const panel = this.tfDropdown['panel'] as HTMLDivElement;\r\n panel.querySelectorAll<HTMLButtonElement>('[data-tf-pick]').forEach((btn) => {\r\n btn.addEventListener('click', () => this.callbacks.onTimeframe(btn.dataset.tfPick as TimeFrame));\r\n });\r\n panel.querySelectorAll<HTMLButtonElement>('[data-tf-star]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation(); // pinning keeps the menu open\r\n this.callbacks.onToggleTimeframeFavorite?.(btn.dataset.tfStar as TimeFrame);\r\n });\r\n });\r\n panel.querySelectorAll<HTMLButtonElement>('[data-tf-remove]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.callbacks.onRemoveTimeframe?.(btn.dataset.tfRemove as TimeFrame);\r\n });\r\n });\r\n const form = panel.querySelector<HTMLFormElement>('.tcw-tf-custom');\r\n if (form) this.wireCustomTimeframe(form);\r\n }\r\n\r\n /** The custom-interval field: Enter or + adds it; text that isn't an interval is marked and kept. */\r\n private wireCustomTimeframe(form: HTMLFormElement): void {\r\n const input = form.querySelector<HTMLInputElement>('.tcw-tf-custom-input')!;\r\n const hint = form.querySelector<HTMLDivElement>('.tcw-tf-custom-hint')!;\r\n // Typing and clicking here must not toggle the menu shut.\r\n form.addEventListener('click', (e) => e.stopPropagation());\r\n input.addEventListener('input', () => {\r\n input.removeAttribute('aria-invalid');\r\n hint.textContent = '';\r\n });\r\n form.addEventListener('submit', (e) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n if (this.callbacks.onAddTimeframe?.(input.value)) {\r\n input.value = '';\r\n hint.textContent = '';\r\n this.tfDropdown?.close();\r\n // The field just went away: put focus back where the menu opened.\r\n this.el.querySelector<HTMLButtonElement>('[data-role=\"timeframes\"]')?.focus();\r\n } else {\r\n input.setAttribute('aria-invalid', 'true');\r\n hint.textContent = this.t('toolbar.timeframes.invalid');\r\n }\r\n });\r\n }\r\n\r\n private renderTimeframes(current: TimeFrame): void {\r\n if (!this.tfGroup) return;\r\n const shown = this.config.timeframes.filter((tf) => this.tfFavorites.includes(tf.value) || tf.value === current);\r\n const key = `${shown.map((tf) => tf.value).join(',')}|${current}`;\r\n if (key === this.tfRendered) return;\r\n this.tfRendered = key;\r\n\r\n this.tfGroup.replaceChildren(...shown.map((tf) => {\r\n const btn = document.createElement('button');\r\n btn.className = 'tcw-btn';\r\n btn.textContent = tf.label;\r\n btn.dataset.tf = tf.value;\r\n btn.classList.toggle('tcw-active', tf.value === current);\r\n btn.addEventListener('click', () => this.callbacks.onTimeframe(tf.value));\r\n return btn;\r\n }));\r\n const panel = this.tfDropdown?.['panel'] as HTMLDivElement | undefined;\r\n panel?.querySelectorAll<HTMLButtonElement>('[data-tf-pick]').forEach((btn) => {\r\n btn.classList.toggle('tcw-active', btn.dataset.tfPick === current);\r\n });\r\n }\r\n\r\n /**\r\n * The indicator templates to list (names), after one is saved or deleted.\r\n * `keepFocus`: focus was in the menu (a delete), so it goes to \"Save…\".\r\n */\r\n setIndicatorTemplates(names: readonly string[], keepFocus = false): void {\r\n this.indicatorTemplates = [...names];\r\n this.buildIndicatorMenu();\r\n if (keepFocus) (this.indicatorDropdown?.['panel'] as HTMLDivElement | undefined)?.querySelector<HTMLButtonElement>('[data-tpl-save]')?.focus();\r\n }\r\n\r\n /** Templates atop the indicators menu: apply one, delete one, save the chart's. */\r\n private templatesMenuHtml(): string {\r\n if (!this.callbacks.onSaveIndicatorTemplate) return '';\r\n const remove = this.t('templates.delete');\r\n let html = `<div class=\"tcw-dropdown-label\">${esc(this.t('toolbar.indicators.templates'))}</div>`;\r\n for (const name of this.indicatorTemplates) {\r\n const n = esc(name);\r\n html += `<div class=\"tcw-tf-row\">`\r\n + `<button class=\"tcw-dropdown-item\" data-tpl-apply=\"${n}\">${createIcon('layers', 14)}<span>${n}</span></button>`\r\n + `<button class=\"tcw-tf-remove\" data-tpl-delete=\"${n}\" title=\"${esc(fill(remove, { name }))}\" aria-label=\"${esc(fill(remove, { name }))}\">${createIcon('x', 12)}</button>`\r\n + `</div>`;\r\n }\r\n html += `<button class=\"tcw-dropdown-item\" data-tpl-save>${createIcon('save', 14)}<span>${esc(this.t('templates.save'))}</span></button>`;\r\n return html + '<div class=\"tcw-dropdown-divider\"></div>';\r\n }\r\n\r\n private buildIndicatorMenu(): void {\r\n if (!this.indicatorDropdown) return;\r\n const { indicators, popularIndicatorIds } = this.config;\r\n\r\n const popular = indicators.filter(d => popularIndicatorIds.includes(d.id));\r\n const other = indicators.filter(d => !popularIndicatorIds.includes(d.id));\r\n\r\n const typeLabel = (type: string) => this.t(`indicatorType.${type}` as Parameters<Translator>[0]);\r\n\r\n const row = (ind: (typeof indicators)[number]) =>\r\n `<button class=\"tcw-dropdown-item\" data-ind=\"${esc(ind.id)}\"><span>${esc(ind.name)}</span><span class=\"tcw-tag\">${esc(typeLabel(ind.type))}</span></button>`;\r\n let html = this.templatesMenuHtml();\r\n html += `<div class=\"tcw-dropdown-label\">${esc(this.t('toolbar.indicators.popular'))}</div>`;\r\n for (const ind of popular) html += row(ind);\r\n html += '<div class=\"tcw-dropdown-divider\"></div>';\r\n html += `<div class=\"tcw-dropdown-label\">${esc(this.t('toolbar.indicators.all'))}</div>`;\r\n for (const ind of other) html += row(ind);\r\n\r\n this.indicatorDropdown.setContent(html);\r\n\r\n const panel = this.indicatorDropdown['panel'] as HTMLDivElement;\r\n panel.querySelectorAll('.tcw-dropdown-item[data-ind]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n const id = (e.currentTarget as HTMLElement).dataset.ind!;\r\n this.callbacks.onAddIndicator(id);\r\n });\r\n });\r\n panel.querySelectorAll<HTMLButtonElement>('[data-tpl-apply]').forEach((btn) => {\r\n btn.addEventListener('click', () => {\r\n this.indicatorDropdown?.close();\r\n this.callbacks.onApplyIndicatorTemplate?.(btn.dataset.tplApply!);\r\n });\r\n });\r\n panel.querySelectorAll<HTMLButtonElement>('[data-tpl-delete]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation(); // deleting keeps the menu open\r\n this.callbacks.onDeleteIndicatorTemplate?.(btn.dataset.tplDelete!);\r\n });\r\n });\r\n panel.querySelector<HTMLButtonElement>('[data-tpl-save]')?.addEventListener('click', () => {\r\n this.indicatorDropdown?.close();\r\n this.callbacks.onSaveIndicatorTemplate?.();\r\n });\r\n }\r\n\r\n update(state: WidgetState): void {\r\n // Symbol\r\n const symbolBtn = this.el.querySelector('[data-role=\"symbol\"]') as HTMLButtonElement | null;\r\n if (symbolBtn) symbolBtn.textContent = state.symbol;\r\n\r\n // Timeframe buttons\r\n this.renderTimeframes(state.timeframe);\r\n\r\n // Chart type trigger label\r\n const ctTrigger = this.el.querySelector('[data-role=\"charttype\"]') as HTMLElement | null;\r\n if (ctTrigger) {\r\n const ct = this.config.chartTypes.find(ct => ct.value === state.chartType);\r\n const label = ct ? this.chartTypeLabel(ct) : state.chartType;\r\n ctTrigger.innerHTML = `${createChartTypeIcon(state.chartType, 14)} ${esc(label)} ${createIcon('chevronDown', 12)}`;\r\n }\r\n\r\n // Indicator trigger + badge\r\n const indTrigger = this.el.querySelector('[data-role=\"indicators\"]') as HTMLElement | null;\r\n if (indTrigger) {\r\n const count = state.activeIndicators.size;\r\n let inner = `${createIcon('trendingUp', 14)} ${this.t('toolbar.indicators')}`;\r\n if (count > 0) {\r\n inner += ` <span class=\"tcw-badge-count\">${count}</span>`;\r\n }\r\n indTrigger.innerHTML = inner;\r\n }\r\n\r\n // Theme toggle icon\r\n if (this.themeBtn) {\r\n this.themeBtn.innerHTML = state.isDark ? createIcon('moon', 14) : createIcon('sun', 14);\r\n }\r\n }\r\n\r\n private sep(): HTMLSpanElement {\r\n const s = document.createElement('span');\r\n s.className = 'tcw-toolbar-sep';\r\n return s;\r\n }\r\n\r\n private spacer(): HTMLSpanElement {\r\n const s = document.createElement('span');\r\n s.className = 'tcw-toolbar-spacer';\r\n return s;\r\n }\r\n\r\n private iconBtn(icon: string, title: string, onClick: () => void): HTMLButtonElement {\r\n const btn = document.createElement('button');\r\n btn.className = 'tcw-btn-icon';\r\n btn.title = title;\r\n btn.innerHTML = createIcon(icon, 14);\r\n btn.addEventListener('click', onClick);\r\n return btn;\r\n }\r\n\r\n destroy(): void {\r\n this.chartTypeDropdown?.destroy();\r\n this.indicatorDropdown?.destroy();\r\n this.el.remove();\r\n }\r\n}\r\n","import type { DrawingToolType } from '@tradecanvas/commons';\r\nimport type { SidebarConfig, SidebarCallbacks, WidgetState } from './types.js';\r\nimport { createIcon, createToolIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, fill, type Translator } from './i18n.js';\r\n\r\n/** Drawing tool icons carry more detail than interface glyphs: a size up. */\r\nconst TOOL_ICON_PX = 16;\r\n\r\n/** How long a tool menu stays after the pointer leaves it. */\r\nconst FLYOUT_CLOSE_DELAY_MS = 150;\r\n/** Room kept between a tool menu and the bottom of the chart (px). */\r\nconst FLYOUT_MARGIN = 4;\r\n\r\n/** Human label for a tool id, sourced from the configured groups. */\r\nfunction toolLabel(groups: SidebarConfig['drawingToolGroups'], tool: string): string {\r\n for (const g of groups) {\r\n const t = g.tools.find((x) => x.value === tool);\r\n if (t) return t.label;\r\n }\r\n return tool;\r\n}\r\n\r\nexport class WidgetDrawingSidebar {\r\n private config: SidebarConfig;\r\n private callbacks: SidebarCallbacks;\r\n private el: HTMLDivElement;\r\n private groupWraps: HTMLDivElement[] = [];\r\n private groupButtons: HTMLButtonElement[] = [];\r\n /** Per group, the icon holder in its button and the tool it stands for (the last one used). */\r\n private groupIcons: HTMLSpanElement[] = [];\r\n private groupTools: DrawingToolType[] = [];\r\n private cursorBtn: HTMLButtonElement | null = null;\r\n private magnetBtn: HTMLButtonElement | null = null;\r\n private eraserBtn: HTMLButtonElement | null = null;\r\n private zoomBtn: HTMLButtonElement | null = null;\r\n private stayBtn: HTMLButtonElement | null = null;\r\n private flyoutEl: HTMLDivElement | null = null;\r\n private flyoutIdx = -1;\r\n private flyoutHideTimer: ReturnType<typeof setTimeout> | null = null;\r\n private favoritesEl: HTMLDivElement | null = null;\r\n private favoritesDivider: HTMLDivElement | null = null;\r\n private favorites: string[] = [];\r\n\r\n constructor(\r\n private readonly host: HTMLElement,\r\n config: SidebarConfig,\r\n callbacks: SidebarCallbacks,\r\n private readonly t: Translator = EN_TRANSLATOR,\r\n ) {\r\n this.config = config;\r\n this.callbacks = callbacks;\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-sidebar';\r\n this.build();\r\n // On a short screen the sidebar scrolls; a menu left open would point at the wrong button.\r\n this.el.addEventListener('scroll', () => this.hideFlyout(), { passive: true });\r\n host.appendChild(this.el);\r\n }\r\n\r\n private build(): void {\r\n const { config, callbacks, el } = this;\r\n\r\n // Cursor button\r\n this.cursorBtn = document.createElement('button');\r\n this.cursorBtn.className = 'tcw-sidebar-btn';\r\n this.cursorBtn.title = this.t('drawing.cursor');\r\n this.cursorBtn.innerHTML = createIcon('cursor', 14);\r\n this.cursorBtn.addEventListener('click', callbacks.onCancelDrawing);\r\n el.appendChild(this.cursorBtn);\r\n\r\n el.appendChild(this.divider());\r\n\r\n // Favorites strip (pinned tools) — only when favorites are enabled.\r\n if (callbacks.onToggleFavorite) {\r\n this.favorites = [...(config.favorites ?? [])];\r\n this.favoritesEl = document.createElement('div');\r\n this.favoritesEl.className = 'tcw-sidebar-favorites';\r\n el.appendChild(this.favoritesEl);\r\n this.favoritesDivider = this.divider();\r\n el.appendChild(this.favoritesDivider);\r\n this.renderFavorites();\r\n }\r\n\r\n // Tool groups\r\n config.drawingToolGroups.forEach((group, idx) => {\r\n const wrap = document.createElement('div');\r\n wrap.className = 'tcw-tool-group-wrap';\r\n\r\n const btn = document.createElement('button');\r\n btn.className = 'tcw-sidebar-btn';\r\n // The group shows, and picks, its last used tool — the first until then.\r\n const tool = group.tools[0]?.value;\r\n if (!tool) return;\r\n // A group with a menu names itself in the menu's header: no tooltip on top of it.\r\n if (group.tools.length > 1) btn.setAttribute('aria-label', `${group.label}: ${group.tools[0].label}`);\r\n else btn.title = group.label;\r\n const icon = document.createElement('span');\r\n icon.className = 'tcw-sidebar-icon';\r\n icon.innerHTML = createToolIcon(tool, TOOL_ICON_PX);\r\n btn.appendChild(icon);\r\n this.groupIcons.push(icon);\r\n this.groupTools.push(tool);\r\n\r\n if (group.tools.length > 1) {\r\n const dot = document.createElement('span');\r\n dot.className = 'tcw-multi-dot';\r\n btn.appendChild(dot);\r\n }\r\n\r\n btn.addEventListener('click', () => callbacks.onDrawingTool(this.groupTools[idx]));\r\n wrap.appendChild(btn);\r\n\r\n // Flyout events via JS (not CSS hover). From the keyboard, the arrow\r\n // keys open a group's menu and go into it.\r\n wrap.addEventListener('mouseenter', () => this.showFlyout(idx));\r\n wrap.addEventListener('mouseleave', () => this.scheduleHideFlyout());\r\n if (group.tools.length > 1) {\r\n btn.setAttribute('aria-haspopup', 'menu');\r\n btn.setAttribute('aria-expanded', 'false');\r\n btn.addEventListener('keydown', (e) => {\r\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\r\n e.preventDefault();\r\n this.showFlyout(idx);\r\n this.focusFlyoutItem(0);\r\n } else if (e.key === 'Escape' && this.flyoutEl) {\r\n e.stopPropagation();\r\n this.hideFlyout();\r\n }\r\n });\r\n }\r\n wrap.addEventListener('focusout', (e) => {\r\n const to = e.relatedTarget as Node | null;\r\n if (!wrap.contains(to) && !this.flyoutEl?.contains(to)) this.scheduleHideFlyout();\r\n });\r\n\r\n el.appendChild(wrap);\r\n this.groupWraps.push(wrap);\r\n this.groupButtons.push(btn);\r\n });\r\n\r\n // Spacer\r\n const spacer = document.createElement('div');\r\n spacer.className = 'tcw-sidebar-spacer';\r\n el.appendChild(spacer);\r\n\r\n el.appendChild(this.divider());\r\n\r\n // Bottom tools\r\n if (callbacks.onToggleStyle) {\r\n const styleBtn = document.createElement('button');\r\n styleBtn.className = 'tcw-sidebar-btn';\r\n styleBtn.title = this.t('drawing.style');\r\n styleBtn.dataset.role = 'style';\r\n styleBtn.innerHTML = createIcon('palette', 14);\r\n styleBtn.addEventListener('click', callbacks.onToggleStyle);\r\n el.appendChild(styleBtn);\r\n }\r\n\r\n if (callbacks.onToggleMagnet) {\r\n this.magnetBtn = document.createElement('button');\r\n this.magnetBtn.className = 'tcw-sidebar-btn';\r\n this.magnetBtn.title = this.t('drawing.magnet');\r\n this.magnetBtn.innerHTML = createIcon('magnet', 14);\r\n this.magnetBtn.addEventListener('click', callbacks.onToggleMagnet);\r\n el.appendChild(this.magnetBtn);\r\n }\r\n\r\n if (callbacks.onToggleEraser) {\r\n this.eraserBtn = this.toggleButton('eraser', this.t('drawing.eraser'), callbacks.onToggleEraser);\r\n el.appendChild(this.eraserBtn);\r\n }\r\n\r\n if (callbacks.onToggleZoomArea) {\r\n this.zoomBtn = this.toggleButton('zoomIn', this.t('drawing.zoomArea'), callbacks.onToggleZoomArea);\r\n el.appendChild(this.zoomBtn);\r\n }\r\n\r\n if (callbacks.onToggleStayInDrawing) {\r\n this.stayBtn = document.createElement('button');\r\n this.stayBtn.className = 'tcw-sidebar-btn';\r\n this.stayBtn.dataset.role = 'stay';\r\n this.stayBtn.title = this.t('drawing.stay');\r\n this.stayBtn.setAttribute('aria-pressed', 'false');\r\n this.stayBtn.innerHTML = createIcon('repeat', 14);\r\n this.stayBtn.addEventListener('click', callbacks.onToggleStayInDrawing);\r\n el.appendChild(this.stayBtn);\r\n }\r\n\r\n const undoBtn = document.createElement('button');\r\n undoBtn.className = 'tcw-sidebar-btn';\r\n undoBtn.title = this.t('drawing.undo');\r\n undoBtn.innerHTML = createIcon('undo', 14);\r\n undoBtn.addEventListener('click', callbacks.onUndo);\r\n el.appendChild(undoBtn);\r\n\r\n const redoBtn = document.createElement('button');\r\n redoBtn.className = 'tcw-sidebar-btn';\r\n redoBtn.title = this.t('drawing.redo');\r\n redoBtn.innerHTML = createIcon('redo', 14);\r\n redoBtn.addEventListener('click', callbacks.onRedo);\r\n el.appendChild(redoBtn);\r\n\r\n const clearBtn = document.createElement('button');\r\n clearBtn.className = 'tcw-sidebar-btn tcw-danger';\r\n clearBtn.title = this.t('drawing.clearAll');\r\n clearBtn.innerHTML = createIcon('trash', 14);\r\n clearBtn.addEventListener('click', callbacks.onClearDrawings);\r\n el.appendChild(clearBtn);\r\n }\r\n\r\n /** Update the pinned-tools strip. */\r\n setFavorites(favorites: string[]): void {\r\n this.favorites = [...favorites];\r\n this.renderFavorites();\r\n }\r\n\r\n private renderFavorites(): void {\r\n if (!this.favoritesEl) return;\r\n this.favoritesEl.replaceChildren();\r\n const visible = this.favorites.length > 0;\r\n this.favoritesEl.style.display = visible ? '' : 'none';\r\n if (this.favoritesDivider) this.favoritesDivider.style.display = visible ? '' : 'none';\r\n\r\n for (const tool of this.favorites) {\r\n const btn = document.createElement('button');\r\n btn.className = 'tcw-sidebar-btn';\r\n btn.title = fill(this.t('sidebar.unpinHint'), { tool: toolLabel(this.config.drawingToolGroups, tool) });\r\n btn.dataset.toolValue = tool;\r\n btn.innerHTML = createToolIcon(tool, TOOL_ICON_PX);\r\n btn.addEventListener('click', () => this.callbacks.onDrawingTool(tool as never));\r\n btn.addEventListener('contextmenu', (e) => {\r\n e.preventDefault();\r\n this.callbacks.onToggleFavorite?.(tool as never);\r\n });\r\n this.favoritesEl.appendChild(btn);\r\n }\r\n }\r\n\r\n private showFlyout(idx: number): void {\r\n this.cancelHideFlyout();\r\n if (this.flyoutEl && this.flyoutIdx === idx) return; // back before it closed: keep it\r\n const group = this.config.drawingToolGroups[idx];\r\n if (!group || group.tools.length <= 1) {\r\n this.hideFlyout();\r\n return;\r\n }\r\n\r\n this.hideFlyout();\r\n\r\n const flyout = document.createElement('div');\r\n flyout.className = 'tcw-flyout';\r\n flyout.setAttribute('role', 'menu');\r\n flyout.setAttribute('aria-label', group.label);\r\n flyout.addEventListener('keydown', (e) => this.onFlyoutKey(e, idx));\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-flyout-header';\r\n header.textContent = group.label;\r\n flyout.appendChild(header);\r\n\r\n for (const tool of group.tools) {\r\n const item = document.createElement('button');\r\n item.className = 'tcw-flyout-item';\r\n item.setAttribute('role', 'menuitem');\r\n item.tabIndex = -1;\r\n item.innerHTML = createToolIcon(tool.value, TOOL_ICON_PX);\r\n const name = document.createElement('span');\r\n name.textContent = tool.label;\r\n item.appendChild(name);\r\n item.dataset.toolValue = tool.value;\r\n item.addEventListener('click', () => {\r\n this.callbacks.onDrawingTool(tool.value);\r\n this.hideFlyout();\r\n });\r\n if (this.callbacks.onToggleFavorite) {\r\n if (this.favorites.includes(tool.value)) item.classList.add('tcw-flyout-faved');\r\n item.addEventListener('contextmenu', (e) => {\r\n e.preventDefault();\r\n this.callbacks.onToggleFavorite?.(tool.value);\r\n });\r\n }\r\n flyout.appendChild(item);\r\n }\r\n if (this.callbacks.onToggleFavorite) {\r\n // Said once for the menu rather than as a tooltip on every row.\r\n const hint = document.createElement('div');\r\n hint.className = 'tcw-flyout-hint';\r\n hint.textContent = this.t('drawing.pinHint');\r\n flyout.appendChild(hint);\r\n }\r\n\r\n // The menu sits beside the sidebar, not in it, so the sidebar can scroll\r\n // without cutting it off.\r\n flyout.addEventListener('mouseenter', () => this.cancelHideFlyout());\r\n flyout.addEventListener('mouseleave', () => this.scheduleHideFlyout());\r\n flyout.addEventListener('focusout', (e) => {\r\n const to = e.relatedTarget as Node | null;\r\n if (!flyout.contains(to) && !this.groupWraps[idx].contains(to)) this.scheduleHideFlyout();\r\n });\r\n this.flyoutEl = flyout;\r\n this.flyoutIdx = idx;\r\n this.host.appendChild(flyout);\r\n this.placeFlyout(flyout, this.groupButtons[idx]);\r\n this.groupButtons[idx].setAttribute('aria-expanded', 'true');\r\n }\r\n\r\n private flyoutItems(): HTMLButtonElement[] {\r\n return this.flyoutEl ? [...this.flyoutEl.querySelectorAll<HTMLButtonElement>('.tcw-flyout-item')] : [];\r\n }\r\n\r\n private focusFlyoutItem(index: number): void {\r\n const items = this.flyoutItems();\r\n if (items.length === 0) return;\r\n items[(index + items.length) % items.length].focus();\r\n }\r\n\r\n /** Arrows, Home and End move through the menu; Escape or Left go back to its button; Tab leaves it. */\r\n private onFlyoutKey(e: KeyboardEvent, idx: number): void {\r\n const items = this.flyoutItems();\r\n const at = items.indexOf(document.activeElement as HTMLButtonElement);\r\n switch (e.key) {\r\n case 'ArrowDown': this.focusFlyoutItem(at + 1); break;\r\n case 'ArrowUp': this.focusFlyoutItem(at - 1); break;\r\n case 'Home': this.focusFlyoutItem(0); break;\r\n case 'End': this.focusFlyoutItem(items.length - 1); break;\r\n case 'Escape':\r\n case 'ArrowLeft':\r\n e.stopPropagation();\r\n this.hideFlyout();\r\n this.groupButtons[idx]?.focus();\r\n break;\r\n case 'Tab':\r\n this.hideFlyout();\r\n this.groupButtons[idx]?.focus();\r\n return; // the Tab itself moves on from the button\r\n default:\r\n return;\r\n }\r\n e.preventDefault();\r\n }\r\n\r\n /** Beside `button`, kept inside the host when it is taller than the room below. */\r\n private placeFlyout(flyout: HTMLElement, button: HTMLElement): void {\r\n const host = this.host.getBoundingClientRect();\r\n const at = button.getBoundingClientRect();\r\n // Taller than the chart, the menu scrolls.\r\n flyout.style.maxHeight = `${Math.max(0, this.host.clientHeight - FLYOUT_MARGIN * 2)}px`;\r\n const room = this.host.clientHeight - flyout.offsetHeight - FLYOUT_MARGIN;\r\n // Beside the button, toward the chart: its right, or its left in a right-to-left widget.\r\n if (this.host.closest('[dir]')?.getAttribute('dir') === 'rtl') {\r\n flyout.style.left = '';\r\n flyout.style.right = `${host.right - at.left}px`;\r\n } else {\r\n flyout.style.right = '';\r\n flyout.style.left = `${at.right - host.left}px`;\r\n }\r\n flyout.style.top = `${Math.max(0, Math.min(at.top - host.top, room))}px`;\r\n }\r\n\r\n /**\r\n * Close a moment after the pointer leaves, so one that slips off the menu\r\n * on its way to an item (a diagonal move) doesn't lose it.\r\n */\r\n private scheduleHideFlyout(): void {\r\n this.cancelHideFlyout();\r\n this.flyoutHideTimer = setTimeout(() => {\r\n this.flyoutHideTimer = null;\r\n this.hideFlyout();\r\n }, FLYOUT_CLOSE_DELAY_MS);\r\n }\r\n\r\n private cancelHideFlyout(): void {\r\n if (this.flyoutHideTimer === null) return;\r\n clearTimeout(this.flyoutHideTimer);\r\n this.flyoutHideTimer = null;\r\n }\r\n\r\n private hideFlyout(): void {\r\n this.cancelHideFlyout();\r\n if (this.flyoutEl) {\r\n this.flyoutEl.remove();\r\n this.flyoutEl = null;\r\n }\r\n this.groupButtons[this.flyoutIdx]?.setAttribute('aria-expanded', 'false');\r\n this.flyoutIdx = -1;\r\n }\r\n\r\n update(state: WidgetState): void {\r\n // Cursor active\r\n if (this.cursorBtn) {\r\n this.cursorBtn.classList.toggle('tcw-active', state.activeTool === null);\r\n }\r\n\r\n // Group buttons: the active group lights up and takes on the picked tool's icon.\r\n const { drawingToolGroups } = this.config;\r\n for (let i = 0; i < drawingToolGroups.length; i++) {\r\n const isActive = drawingToolGroups[i].tools.some(t => t.value === state.activeTool);\r\n this.groupButtons[i].classList.toggle('tcw-active', isActive);\r\n if (isActive && state.activeTool && state.activeTool !== this.groupTools[i]) {\r\n this.groupTools[i] = state.activeTool;\r\n this.groupIcons[i].innerHTML = createToolIcon(state.activeTool, TOOL_ICON_PX);\r\n if (drawingToolGroups[i].tools.length > 1) {\r\n this.groupButtons[i].setAttribute('aria-label', `${drawingToolGroups[i].label}: ${toolLabel(drawingToolGroups, state.activeTool)}`);\r\n }\r\n }\r\n }\r\n\r\n // Flyout items\r\n if (this.flyoutEl) {\r\n this.flyoutEl.querySelectorAll('.tcw-flyout-item').forEach((item) => {\r\n const el = item as HTMLElement;\r\n el.classList.toggle('tcw-active', el.dataset.toolValue === state.activeTool);\r\n });\r\n }\r\n\r\n // Magnet: off, weak or strong.\r\n if (this.magnetBtn) {\r\n const strong = state.magnetEnabled && state.magnetStrong;\r\n this.magnetBtn.classList.toggle('tcw-active', state.magnetEnabled);\r\n this.magnetBtn.innerHTML = createIcon(strong ? 'magnetStrong' : 'magnet', 14);\r\n this.magnetBtn.title = strong ? this.t('drawing.magnetStrong') : state.magnetEnabled ? this.t('drawing.magnetOn') : this.t('drawing.magnetOff');\r\n this.magnetBtn.setAttribute('aria-label', this.magnetBtn.title);\r\n }\r\n\r\n for (const [btn, on] of [[this.eraserBtn, state.eraser], [this.zoomBtn, state.zoomArea]] as const) {\r\n if (!btn) continue;\r\n btn.classList.toggle('tcw-active', on);\r\n btn.setAttribute('aria-pressed', String(on));\r\n }\r\n\r\n if (this.stayBtn) {\r\n this.stayBtn.classList.toggle('tcw-active', state.stayInDrawing);\r\n this.stayBtn.setAttribute('aria-pressed', String(state.stayInDrawing));\r\n }\r\n }\r\n\r\n /** A sidebar button that is on or off (aria-pressed). */\r\n private toggleButton(icon: string, label: string, onClick: () => void): HTMLButtonElement {\r\n const btn = document.createElement('button');\r\n btn.className = 'tcw-sidebar-btn';\r\n btn.title = label;\r\n btn.setAttribute('aria-label', label);\r\n btn.setAttribute('aria-pressed', 'false');\r\n btn.innerHTML = createIcon(icon, 14);\r\n btn.addEventListener('click', onClick);\r\n return btn;\r\n }\r\n\r\n private divider(): HTMLDivElement {\r\n const d = document.createElement('div');\r\n d.className = 'tcw-sidebar-divider';\r\n return d;\r\n }\r\n\r\n destroy(): void {\r\n this.hideFlyout();\r\n this.el.remove();\r\n }\r\n}\r\n","import type { ChartType, ChartTypeOptions } from '@tradecanvas/commons';\r\nimport type { ChartSettingsState, SettingsCallbacks } from './types.js';\r\nimport { CHART_TYPES } from './widgetConfig.js';\r\nimport { chartTypeLabel } from './widgetLocales.js';\r\nimport { createIcon } from './icons.js';\r\nimport { timezoneOptions } from './widgetTimezones.js';\r\nimport { numberLocaleOptions } from './widgetLocales.js';\r\nimport type { Translator } from './i18n.js';\r\n\r\ntype Tab = 'style' | 'display' | 'scale';\r\nconst TABS: Tab[] = ['style', 'display', 'scale'];\r\n\r\nexport class WidgetSettings {\r\n private callbacks: SettingsCallbacks;\r\n private t: Translator;\r\n private backdrop: HTMLDivElement | null = null;\r\n private modal: HTMLDivElement | null = null;\r\n private currentTab: Tab = 'style';\r\n private currentSettings: ChartSettingsState | null = null;\r\n private bodyEl: HTMLDivElement | null = null;\r\n private tabButtons: HTMLButtonElement[] = [];\r\n /** The chart's type, whose settings the Style tab offers. */\r\n private chartType: ChartType | null = null;\r\n\r\n /**\r\n * `barCountdown` / `logScale` false leave out the controls for features the\r\n * chart has switched off.\r\n */\r\n constructor(\r\n callbacks: SettingsCallbacks,\r\n t: Translator,\r\n private readonly available: {\r\n barCountdown?: boolean;\r\n logScale?: boolean;\r\n /** Offer the exchange's time zone; returns it (null while unknown). */\r\n exchangeZone?: () => string | null;\r\n } = {},\r\n /** Where the panel mounts (the widget's portal: themed, and inside it when fullscreen). */\r\n private readonly host: () => HTMLElement = () => document.body,\r\n ) {\r\n this.callbacks = callbacks;\r\n this.t = t;\r\n }\r\n\r\n open(currentSettings: ChartSettingsState, chartType: ChartType | null = null): void {\r\n this.currentSettings = { ...currentSettings };\r\n this.chartType = chartType;\r\n this.currentTab = 'style';\r\n this.buildModal();\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.modal !== null;\r\n }\r\n\r\n /** The settings as they are now (after an undo), on the tab that's open. */\r\n refresh(settings: ChartSettingsState): void {\r\n if (!this.modal) return;\r\n this.currentSettings = { ...settings };\r\n this.renderTabContent();\r\n }\r\n\r\n close(): void {\r\n this.backdrop?.remove();\r\n this.modal?.remove();\r\n this.backdrop = null;\r\n this.modal = null;\r\n this.bodyEl = null;\r\n this.tabButtons = [];\r\n }\r\n\r\n private buildModal(): void {\r\n // Backdrop\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.addEventListener('click', () => {\r\n this.callbacks.onClose();\r\n this.close();\r\n });\r\n this.host().appendChild(this.backdrop);\r\n\r\n // Modal\r\n this.modal = document.createElement('div');\r\n this.modal.className = 'tcw-modal';\r\n\r\n // Header\r\n const header = document.createElement('div');\r\n header.className = 'tcw-modal-header';\r\n const h3 = document.createElement('h3');\r\n h3.textContent = this.t('settings.title');\r\n header.appendChild(h3);\r\n const closeBtn = document.createElement('button');\r\n closeBtn.className = 'tcw-modal-close';\r\n closeBtn.innerHTML = createIcon('x', 16);\r\n closeBtn.addEventListener('click', () => {\r\n this.callbacks.onClose();\r\n this.close();\r\n });\r\n header.appendChild(closeBtn);\r\n this.modal.appendChild(header);\r\n\r\n // Tabs\r\n const tabsEl = document.createElement('div');\r\n tabsEl.className = 'tcw-modal-tabs';\r\n this.tabButtons = [];\r\n for (const tab of TABS) {\r\n const btn = document.createElement('button');\r\n btn.className = 'tcw-modal-tab';\r\n btn.textContent = this.t(`settings.tab.${tab}` as Parameters<Translator>[0]);\r\n btn.dataset.tab = tab;\r\n if (tab === this.currentTab) btn.classList.add('tcw-active');\r\n btn.addEventListener('click', () => {\r\n this.currentTab = tab;\r\n this.tabButtons.forEach(b => b.classList.toggle('tcw-active', b.dataset.tab === tab));\r\n this.renderTabContent();\r\n });\r\n tabsEl.appendChild(btn);\r\n this.tabButtons.push(btn);\r\n }\r\n this.modal.appendChild(tabsEl);\r\n\r\n // Body\r\n this.bodyEl = document.createElement('div');\r\n this.bodyEl.className = 'tcw-modal-body';\r\n this.modal.appendChild(this.bodyEl);\r\n this.renderTabContent();\r\n\r\n // Footer\r\n const footer = document.createElement('div');\r\n footer.className = 'tcw-modal-footer';\r\n const resetBtn = document.createElement('button');\r\n resetBtn.className = 'tcw-reset-link';\r\n resetBtn.textContent = this.t('settings.resetToDefaults');\r\n resetBtn.addEventListener('click', () => this.callbacks.onReset());\r\n footer.appendChild(resetBtn);\r\n const doneBtn = document.createElement('button');\r\n doneBtn.className = 'tcw-done-btn';\r\n doneBtn.textContent = this.t('settings.done');\r\n doneBtn.addEventListener('click', () => {\r\n this.callbacks.onClose();\r\n this.close();\r\n });\r\n footer.appendChild(doneBtn);\r\n this.modal.appendChild(footer);\r\n\r\n this.host().appendChild(this.modal);\r\n\r\n // Escape key\r\n const onKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') {\r\n document.removeEventListener('keydown', onKeyDown);\r\n this.callbacks.onClose();\r\n this.close();\r\n }\r\n };\r\n document.addEventListener('keydown', onKeyDown);\r\n }\r\n\r\n private renderTabContent(): void {\r\n if (!this.bodyEl || !this.currentSettings) return;\r\n this.bodyEl.innerHTML = '';\r\n\r\n switch (this.currentTab) {\r\n case 'style':\r\n this.renderStyleTab();\r\n break;\r\n case 'display':\r\n this.renderDisplayTab();\r\n break;\r\n case 'scale':\r\n this.renderScaleTab();\r\n break;\r\n }\r\n }\r\n\r\n private renderStyleTab(): void {\r\n if (!this.bodyEl || !this.currentSettings) return;\r\n const s = this.currentSettings;\r\n\r\n this.renderChartTypeSection();\r\n\r\n // Candle Colors\r\n const candleSection = this.section(this.t('settings.section.candleColors'));\r\n candleSection.appendChild(this.colorRow(this.t('settings.upBody'), s.candleUpColor, (v) => this.patch({ candleUpColor: v })));\r\n candleSection.appendChild(this.colorRow(this.t('settings.downBody'), s.candleDownColor, (v) => this.patch({ candleDownColor: v })));\r\n candleSection.appendChild(this.colorRow(this.t('settings.upWick'), s.candleUpWick, (v) => this.patch({ candleUpWick: v })));\r\n candleSection.appendChild(this.colorRow(this.t('settings.downWick'), s.candleDownWick, (v) => this.patch({ candleDownWick: v })));\r\n this.bodyEl.appendChild(candleSection);\r\n\r\n // Background\r\n const bgSection = this.section(this.t('settings.section.background'));\r\n bgSection.appendChild(this.colorRow(this.t('settings.background'), s.backgroundColor, (v) => this.patch({ backgroundColor: v })));\r\n bgSection.appendChild(this.colorRow(this.t('settings.grid'), s.gridColor, (v) => this.patch({ gridColor: v })));\r\n this.bodyEl.appendChild(bgSection);\r\n }\r\n\r\n private renderDisplayTab(): void {\r\n if (!this.bodyEl || !this.currentSettings) return;\r\n const s = this.currentSettings;\r\n\r\n const section = this.section();\r\n section.appendChild(this.toggleRow(this.t('settings.mainSeries'), s.mainSeriesVisible, (v) => this.patch({ mainSeriesVisible: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.highLowLines'), s.highLowLines, (v) => this.patch({ highLowLines: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.extendedHours'), s.extendedHours, (v) => this.patch({ extendedHours: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.gridLines'), s.gridVisible, (v) => this.patch({ gridVisible: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.volume'), s.volumeVisible, (v) => this.patch({ volumeVisible: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.volumeProfile'), s.volumeProfileVisible, (v) => this.patch({ volumeProfileVisible: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.marketProfile'), s.marketProfileVisible, (v) => this.patch({ marketProfileVisible: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.marketProfileSplit'), s.marketProfileSplit, (v) => this.patch({ marketProfileSplit: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.marketProfileLetters'), s.marketProfileLetters, (v) => this.patch({ marketProfileLetters: v })));\r\n section.appendChild(this.rangeRow(this.t('settings.marketProfileBuckets'), s.marketProfileBuckets, 8, 200, 1, (v) => this.patch({ marketProfileBuckets: v })));\r\n section.appendChild(this.rangeRow(this.t('settings.marketProfileOpacity'), s.marketProfileOpacity, 0.05, 1, 0.05, (v) => this.patch({ marketProfileOpacity: v }), (v) => `${Math.round(v * 100)}%`));\r\n section.appendChild(this.toggleRow(this.t('settings.depthHeatmap'), s.depthHeatmapVisible, (v) => this.patch({ depthHeatmapVisible: v })));\r\n section.appendChild(this.rangeRow(this.t('settings.depthHeatmapOpacity'), s.depthHeatmapOpacity, 0.1, 1, 0.05, (v) => this.patch({ depthHeatmapOpacity: v }), (v) => `${Math.round(v * 100)}%`));\r\n section.appendChild(this.toggleRow(this.t('settings.swingMarkers'), s.pivotMarkersVisible, (v) => this.patch({ pivotMarkersVisible: v })));\r\n section.appendChild(this.rangeRow(this.t('settings.swingStrength'), s.pivotStrength, 2, 20, 1, (v) => this.patch({ pivotStrength: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.swingStructure'), s.pivotStructureLabels, (v) => this.patch({ pivotStructureLabels: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.sessionShading'), s.sessionShadingVisible, (v) => this.patch({ sessionShadingVisible: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.periodLevels'), s.periodLevelsVisible, (v) => this.patch({ periodLevelsVisible: v })));\r\n section.appendChild(this.selectRow(this.t('settings.periodLevelsBasis'), s.periodLevelsPeriod, [\r\n { value: 'day', label: this.t('settings.priorDay') },\r\n { value: 'week', label: this.t('settings.priorWeek') },\r\n ], (v) => this.patch({ periodLevelsPeriod: v as ChartSettingsState['periodLevelsPeriod'] })));\r\n section.appendChild(this.toggleRow(this.t('settings.ohlcLegend'), s.legendVisible, (v) => this.patch({ legendVisible: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.indicatorValues'), s.indicatorValueLabels, (v) => this.patch({ indicatorValueLabels: v })));\r\n if (this.available.barCountdown !== false) {\r\n section.appendChild(this.toggleRow(this.t('settings.barCountdown'), s.barCountdown, (v) => this.patch({ barCountdown: v })));\r\n }\r\n\r\n // Crosshair mode\r\n section.appendChild(this.selectRow(this.t('settings.crosshairMode'), s.crosshairMode, [\r\n { label: this.t('settings.crosshair.magnet'), value: 'magnet' },\r\n { label: this.t('settings.crosshair.normal'), value: 'normal' },\r\n { label: this.t('settings.crosshair.hidden'), value: 'hidden' },\r\n ], (v) => this.patch({ crosshairMode: v as ChartSettingsState['crosshairMode'] })));\r\n\r\n section.appendChild(this.selectRow(this.t('settings.timezone'), s.timezone,\r\n timezoneOptions(s.timezone, Date.now(), this.t('settings.timezone.local'),\r\n this.available.exchangeZone\r\n ? { label: this.t('settings.timezone.exchange'), zone: this.available.exchangeZone() }\r\n : undefined),\r\n (v) => this.patch({ timezone: v })));\r\n section.appendChild(this.selectRow(this.t('settings.numberLocale'), s.numberLocale,\r\n numberLocaleOptions(s.numberLocale),\r\n (v) => this.patch({ numberLocale: v })));\r\n\r\n this.bodyEl.appendChild(section);\r\n }\r\n\r\n private renderScaleTab(): void {\r\n if (!this.bodyEl || !this.currentSettings) return;\r\n const s = this.currentSettings;\r\n\r\n const section = this.section();\r\n section.appendChild(this.toggleRow(this.t('settings.autoScale'), s.autoScale, (v) => this.patch({ autoScale: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.invertScale'), s.invertScale, (v) => this.patch({ invertScale: v })));\r\n section.appendChild(this.toggleRow(this.t('settings.leftScale'), s.leftPriceScale, (v) => this.patch({ leftPriceScale: v })));\r\n const scales = [\r\n { value: 'regular', label: this.t('settings.scale.regular') },\r\n { value: 'logarithmic', label: this.t('settings.scale.logarithmic') },\r\n { value: 'percentage', label: this.t('settings.scale.percentage') },\r\n { value: 'indexedTo100', label: this.t('settings.scale.indexedTo100') },\r\n ].filter((o) => o.value !== 'logarithmic' || this.available.logScale !== false);\r\n section.appendChild(this.selectRow(this.t('settings.priceScale'), s.scaleMode, scales,\r\n (v) => this.patch({ scaleMode: v as ChartSettingsState['scaleMode'] })));\r\n this.bodyEl.appendChild(section);\r\n }\r\n\r\n /** The settings of the chart's type, when it has any (Renko's box, Kagi's reversal…). */\r\n private renderChartTypeSection(): void {\r\n if (!this.bodyEl || !this.currentSettings || !this.chartType) return;\r\n const type = this.chartType;\r\n const all = this.currentSettings.chartTypeOptions ?? {};\r\n const def = CHART_TYPES.find((c) => c.value === type);\r\n const section = this.section(def ? chartTypeLabel(def, this.t) : type);\r\n /** Change one type's settings: the rest of its own stay. */\r\n const set = <K extends keyof ChartTypeOptions>(key: K, value: NonNullable<ChartTypeOptions[K]>) =>\r\n this.patch({ chartTypeOptions: { ...(this.currentSettings?.chartTypeOptions ?? {}), [key]: value } });\r\n switch (type) {\r\n case 'renko': {\r\n const o = all.renko ?? {};\r\n section.appendChild(this.numberRow(this.t('settings.boxSize'), typeof o.boxSize === 'number' ? o.boxSize : null, 'any', Infinity,\r\n (v) => set('renko', { ...(this.currentSettings?.chartTypeOptions?.renko ?? {}), boxSize: v ?? 'atr' })));\r\n section.appendChild(this.numberRow(this.t('settings.atrPeriod'), o.atrPeriod ?? null, '1', 500,\r\n (v) => set('renko', withValue(this.currentSettings?.chartTypeOptions?.renko, 'atrPeriod', v))));\r\n break;\r\n }\r\n case 'lineBreak':\r\n section.appendChild(this.numberRow(this.t('settings.lineBreakLines'), all.lineBreak?.lines ?? null, '1', 10,\r\n (v) => set('lineBreak', withValue(this.currentSettings?.chartTypeOptions?.lineBreak, 'lines', v))));\r\n break;\r\n case 'kagi':\r\n section.appendChild(this.numberRow(this.t('settings.reversal'), all.kagi?.reversal ?? null, 'any', Infinity,\r\n (v) => set('kagi', withValue(this.currentSettings?.chartTypeOptions?.kagi, 'reversal', v))));\r\n section.appendChild(this.selectRow(this.t('settings.reversalType'), all.kagi?.reversalType ?? 'percent', [\r\n { value: 'percent', label: this.t('settings.reversalType.percent') },\r\n { value: 'price', label: this.t('settings.reversalType.price') },\r\n ], (v) => set('kagi', { ...(this.currentSettings?.chartTypeOptions?.kagi ?? {}), reversalType: v === 'price' ? 'price' : 'percent' })));\r\n break;\r\n case 'pointAndFigure':\r\n section.appendChild(this.numberRow(this.t('settings.boxSize'), typeof all.pointAndFigure?.boxSize === 'number' ? all.pointAndFigure.boxSize : null, 'any', Infinity,\r\n (v) => set('pointAndFigure', { ...(this.currentSettings?.chartTypeOptions?.pointAndFigure ?? {}), boxSize: v ?? 'auto' })));\r\n section.appendChild(this.numberRow(this.t('settings.reversalBoxes'), all.pointAndFigure?.reversal ?? null, '1', 10,\r\n (v) => set('pointAndFigure', withValue(this.currentSettings?.chartTypeOptions?.pointAndFigure, 'reversal', v))));\r\n break;\r\n case 'rangeBars':\r\n section.appendChild(this.numberRow(this.t('settings.barRange'), typeof all.rangeBars?.range === 'number' ? all.rangeBars.range : null, 'any', Infinity,\r\n (v) => set('rangeBars', { range: v ?? 'auto' })));\r\n break;\r\n default:\r\n return;\r\n }\r\n this.bodyEl.appendChild(section);\r\n }\r\n\r\n /** A number field; empty means \"worked out from the data\" (shown as Auto). Only numbers above 0 are taken. */\r\n private numberRow(label: string, value: number | null, step: string, max: number, onChange: (v: number | null) => void): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-settings-row';\r\n const lbl = document.createElement('label');\r\n lbl.className = 'tcw-settings-label';\r\n lbl.textContent = label;\r\n row.appendChild(lbl);\r\n const input = document.createElement('input');\r\n input.type = 'number';\r\n input.className = 'tcw-settings-number';\r\n input.min = '0';\r\n input.step = step;\r\n if (Number.isFinite(max)) input.max = String(max);\r\n input.placeholder = this.t('settings.auto');\r\n input.value = value === null ? '' : String(value);\r\n input.setAttribute('aria-label', label);\r\n input.addEventListener('change', () => {\r\n if (input.value.trim() === '') {\r\n input.removeAttribute('aria-invalid');\r\n onChange(null);\r\n return;\r\n }\r\n const v = Number(input.value);\r\n const ok = Number.isFinite(v) && v > 0 && v <= max && (step !== '1' || Number.isInteger(v));\r\n input.toggleAttribute('aria-invalid', !ok);\r\n if (ok) onChange(v);\r\n });\r\n row.appendChild(input);\r\n return row;\r\n }\r\n\r\n private patch(partial: Partial<ChartSettingsState>): void {\r\n if (this.currentSettings) {\r\n Object.assign(this.currentSettings, partial);\r\n }\r\n this.callbacks.onChange(partial);\r\n }\r\n\r\n private section(title?: string): HTMLDivElement {\r\n const div = document.createElement('div');\r\n div.className = 'tcw-settings-section';\r\n if (title) {\r\n const t = document.createElement('div');\r\n t.className = 'tcw-settings-section-title';\r\n t.textContent = title;\r\n div.appendChild(t);\r\n }\r\n return div;\r\n }\r\n\r\n private colorRow(label: string, value: string, onChange: (v: string) => void): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-settings-row';\r\n\r\n const lbl = document.createElement('span');\r\n lbl.className = 'tcw-settings-label';\r\n lbl.textContent = label;\r\n row.appendChild(lbl);\r\n\r\n const wrap = document.createElement('div');\r\n wrap.className = 'tcw-color-picker-wrap';\r\n\r\n const input = document.createElement('input');\r\n input.type = 'color';\r\n input.value = value;\r\n\r\n const hex = document.createElement('span');\r\n hex.className = 'tcw-color-hex';\r\n hex.textContent = value;\r\n\r\n input.addEventListener('input', () => {\r\n hex.textContent = input.value;\r\n onChange(input.value);\r\n });\r\n\r\n wrap.appendChild(input);\r\n wrap.appendChild(hex);\r\n row.appendChild(wrap);\r\n return row;\r\n }\r\n\r\n private toggleRow(label: string, value: boolean, onChange: (v: boolean) => void): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-settings-row';\r\n\r\n const lbl = document.createElement('span');\r\n lbl.className = 'tcw-settings-label';\r\n lbl.textContent = label;\r\n row.appendChild(lbl);\r\n\r\n const toggle = document.createElement('button');\r\n toggle.className = `tcw-toggle${value ? ' tcw-on' : ''}`;\r\n toggle.addEventListener('click', () => {\r\n const newVal = !toggle.classList.contains('tcw-on');\r\n toggle.classList.toggle('tcw-on', newVal);\r\n onChange(newVal);\r\n });\r\n row.appendChild(toggle);\r\n return row;\r\n }\r\n\r\n private selectRow(\r\n label: string,\r\n value: string,\r\n options: { label: string; value: string }[],\r\n onChange: (v: string) => void,\r\n ): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-settings-row';\r\n\r\n const lbl = document.createElement('span');\r\n lbl.className = 'tcw-settings-label';\r\n lbl.textContent = label;\r\n row.appendChild(lbl);\r\n\r\n const select = document.createElement('select');\r\n select.className = 'tcw-settings-select';\r\n for (const opt of options) {\r\n const o = document.createElement('option');\r\n o.value = opt.value;\r\n o.textContent = opt.label;\r\n if (opt.value === value) o.selected = true;\r\n select.appendChild(o);\r\n }\r\n select.addEventListener('change', () => onChange(select.value));\r\n row.appendChild(select);\r\n return row;\r\n }\r\n\r\n private rangeRow(\r\n label: string,\r\n value: number,\r\n min: number,\r\n max: number,\r\n step: number,\r\n onChange: (v: number) => void,\r\n format: (v: number) => string = (v) => String(v),\r\n ): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-settings-row';\r\n\r\n const lbl = document.createElement('span');\r\n lbl.className = 'tcw-settings-label';\r\n lbl.textContent = label;\r\n row.appendChild(lbl);\r\n\r\n const wrap = document.createElement('div');\r\n wrap.className = 'tcw-settings-range';\r\n\r\n const input = document.createElement('input');\r\n input.type = 'range';\r\n input.min = String(min);\r\n input.max = String(max);\r\n input.step = String(step);\r\n input.value = String(value);\r\n\r\n const out = document.createElement('span');\r\n out.className = 'tcw-settings-range-val';\r\n out.textContent = format(value);\r\n\r\n input.addEventListener('input', () => {\r\n const v = Number(input.value);\r\n out.textContent = format(v);\r\n onChange(v);\r\n });\r\n\r\n wrap.appendChild(input);\r\n wrap.appendChild(out);\r\n row.appendChild(wrap);\r\n return row;\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n }\r\n}\r\n\r\n/** `settings` with `key` set to `value`, or without it (back to its default) for null. */\r\nfunction withValue<T extends object, K extends string>(settings: T | undefined, key: K, value: number | null): T {\r\n const next = { ...(settings ?? {}) } as Record<string, unknown>;\r\n if (value === null) delete next[key];\r\n else next[key] = value;\r\n return next as T;\r\n}\r\n","import type { RangePreset } from '@tradecanvas/core';\r\nimport { createIcon } from './icons.js';\r\n\r\nexport interface StatusBarRange {\r\n presets: readonly RangePreset[];\r\n /** Button text per preset; the preset itself when missing. */\r\n presetLabels?: Partial<Record<RangePreset, string>>;\r\n groupLabel: string;\r\n goToLabel: string;\r\n onPreset: (preset: RangePreset) => void;\r\n onGoTo: () => void;\r\n}\r\n\r\n/**\r\n * Bottom bar: range presets and \"go to date\" on the left (when `range` is\r\n * given), connection state and symbol on the right.\r\n */\r\nexport class WidgetStatusBar {\r\n private el: HTMLDivElement;\r\n private dotEl: HTMLSpanElement;\r\n private messageEl: HTMLSpanElement;\r\n private infoEl: HTMLSpanElement;\r\n private marketEl: HTMLSpanElement;\r\n\r\n constructor(host: HTMLElement, range?: StatusBarRange) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-statusbar';\r\n\r\n if (range) this.el.appendChild(this.buildRange(range));\r\n\r\n const right = document.createElement('div');\r\n right.className = 'tcw-status-right';\r\n\r\n const indicator = document.createElement('div');\r\n indicator.className = 'tcw-status-indicator';\r\n\r\n this.dotEl = document.createElement('span');\r\n this.dotEl.className = 'tcw-status-dot';\r\n indicator.appendChild(this.dotEl);\r\n\r\n this.messageEl = document.createElement('span');\r\n indicator.appendChild(this.messageEl);\r\n\r\n this.marketEl = document.createElement('span');\r\n this.marketEl.className = 'tcw-status-market';\r\n this.marketEl.hidden = true;\r\n right.appendChild(this.marketEl);\r\n\r\n right.appendChild(indicator);\r\n\r\n this.infoEl = document.createElement('span');\r\n this.infoEl.className = 'tcw-status-info';\r\n right.appendChild(this.infoEl);\r\n\r\n this.el.appendChild(right);\r\n host.appendChild(this.el);\r\n }\r\n\r\n update(state: { connectionState: string; message: string; symbol: string; timeframe: string }): void {\r\n this.dotEl.className = 'tcw-status-dot';\r\n if (state.connectionState === 'connected') {\r\n this.dotEl.classList.add('tcw-connected');\r\n } else if (state.connectionState === 'error') {\r\n this.dotEl.classList.add('tcw-error');\r\n }\r\n\r\n this.messageEl.textContent = state.message;\r\n this.infoEl.textContent = `${state.symbol} ${state.timeframe}`;\r\n }\r\n\r\n /** The market's status (open or closed); hidden for a market around the clock. */\r\n setMarket(state: 'open' | 'closed' | 'always', text: string): void {\r\n this.marketEl.hidden = state === 'always';\r\n this.marketEl.dataset.state = state;\r\n this.marketEl.textContent = state === 'always' ? '' : text;\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n private buildRange(range: StatusBarRange): HTMLDivElement {\r\n const group = document.createElement('div');\r\n group.className = 'tcw-range-bar';\r\n group.setAttribute('role', 'group');\r\n group.setAttribute('aria-label', range.groupLabel);\r\n\r\n for (const preset of range.presets) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-range-btn';\r\n btn.dataset.range = preset;\r\n btn.textContent = range.presetLabels?.[preset] ?? preset;\r\n btn.addEventListener('click', () => range.onPreset(preset));\r\n group.appendChild(btn);\r\n }\r\n\r\n const goTo = document.createElement('button');\r\n goTo.type = 'button';\r\n goTo.className = 'tcw-range-btn tcw-range-goto';\r\n goTo.dataset.role = 'goto';\r\n goTo.title = `${range.goToLabel} (Alt+G)`;\r\n goTo.setAttribute('aria-label', range.goToLabel);\r\n goTo.innerHTML = createIcon('calendar', 13);\r\n goTo.addEventListener('click', range.onGoTo);\r\n group.appendChild(goTo);\r\n return group;\r\n }\r\n}\r\n","import type { ChartType, DrawingToolType, TimeFrame } from '@tradecanvas/commons';\r\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\r\nimport { escapeHtml } from './escapeHtml.js';\r\n\r\nexport interface CommandItem {\r\n id: string;\r\n label: string;\r\n category: 'indicator' | 'chartType' | 'drawing' | 'timeframe' | 'action';\r\n shortcut?: string;\r\n active?: boolean;\r\n}\r\n\r\nexport interface CommandPaletteCallbacks {\r\n onIndicator: (id: string) => void;\r\n onChartType: (type: ChartType) => void;\r\n onDrawingTool: (tool: DrawingToolType) => void;\r\n onTimeframe: (tf: TimeFrame) => void;\r\n onAction: (id: string) => void;\r\n onClose: () => void;\r\n}\r\n\r\nexport class WidgetCommandPalette {\r\n private backdrop: HTMLDivElement | null = null;\r\n private modal: HTMLDivElement | null = null;\r\n private input: HTMLInputElement | null = null;\r\n private list: HTMLDivElement | null = null;\r\n private items: CommandItem[] = [];\r\n private filtered: CommandItem[] = [];\r\n private selectedIndex = 0;\r\n private callbacks: CommandPaletteCallbacks;\r\n private boundKeydown: (e: KeyboardEvent) => void;\r\n\r\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\r\n constructor(\r\n callbacks: CommandPaletteCallbacks,\r\n private readonly host: () => HTMLElement = () => document.body,\r\n private readonly t: Translator = EN_TRANSLATOR,\r\n ) {\r\n this.callbacks = callbacks;\r\n this.boundKeydown = this.handleKeydown.bind(this);\r\n }\r\n\r\n open(items: CommandItem[]): void {\r\n if (this.backdrop) return;\r\n this.items = items;\r\n this.filtered = items;\r\n this.selectedIndex = 0;\r\n\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.addEventListener('click', () => this.close());\r\n\r\n this.modal = document.createElement('div');\r\n this.modal.className = 'tcw-cmd-palette';\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-cmd-header';\r\n\r\n const searchIcon = document.createElement('span');\r\n searchIcon.className = 'tcw-cmd-icon';\r\n searchIcon.textContent = '⌕';\r\n header.appendChild(searchIcon);\r\n\r\n this.input = document.createElement('input');\r\n this.input.className = 'tcw-cmd-input';\r\n this.input.type = 'text';\r\n this.input.placeholder = this.t('palette.placeholder');\r\n this.input.addEventListener('input', () => this.filter());\r\n header.appendChild(this.input);\r\n\r\n const hint = document.createElement('span');\r\n hint.className = 'tcw-cmd-hint';\r\n hint.textContent = 'ESC';\r\n header.appendChild(hint);\r\n\r\n this.modal.appendChild(header);\r\n\r\n this.list = document.createElement('div');\r\n this.list.className = 'tcw-cmd-list';\r\n this.modal.appendChild(this.list);\r\n\r\n const footer = document.createElement('div');\r\n footer.className = 'tcw-cmd-footer';\r\n footer.innerHTML = `<span>↑↓ ${escapeHtml(this.t('common.navigate'))}</span>`\r\n + `<span>⏎ ${escapeHtml(this.t('common.select'))}</span>`\r\n + `<span>Esc ${escapeHtml(this.t('common.close'))}</span>`;\r\n this.modal.appendChild(footer);\r\n\r\n this.host().append(this.backdrop, this.modal);\r\n\r\n this.renderList();\r\n this.input.focus();\r\n document.addEventListener('keydown', this.boundKeydown);\r\n }\r\n\r\n close(): void {\r\n document.removeEventListener('keydown', this.boundKeydown);\r\n this.backdrop?.remove();\r\n this.modal?.remove();\r\n this.backdrop = null;\r\n this.modal = null;\r\n this.input = null;\r\n this.list = null;\r\n this.callbacks.onClose();\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.backdrop !== null;\r\n }\r\n\r\n private filter(): void {\r\n const query = this.input?.value.toLowerCase().trim() ?? '';\r\n if (!query) {\r\n this.filtered = this.items;\r\n } else {\r\n this.filtered = this.items.filter(item =>\r\n item.label.toLowerCase().includes(query) ||\r\n item.category.toLowerCase().includes(query) ||\r\n item.id.toLowerCase().includes(query),\r\n );\r\n }\r\n this.selectedIndex = 0;\r\n this.renderList();\r\n }\r\n\r\n private renderList(): void {\r\n if (!this.list) return;\r\n this.list.innerHTML = '';\r\n\r\n if (this.filtered.length === 0) {\r\n const empty = document.createElement('div');\r\n empty.className = 'tcw-cmd-empty';\r\n empty.textContent = this.t('palette.empty');\r\n this.list.appendChild(empty);\r\n return;\r\n }\r\n\r\n let currentCategory = '';\r\n for (let i = 0; i < this.filtered.length; i++) {\r\n const item = this.filtered[i];\r\n\r\n if (item.category !== currentCategory) {\r\n currentCategory = item.category;\r\n const label = document.createElement('div');\r\n label.className = 'tcw-cmd-category';\r\n label.textContent = this.categoryLabel(currentCategory);\r\n this.list.appendChild(label);\r\n }\r\n\r\n const row = document.createElement('button');\r\n row.className = 'tcw-cmd-item';\r\n if (i === this.selectedIndex) row.classList.add('tcw-selected');\r\n if (item.active) row.classList.add('tcw-active');\r\n row.dataset.index = String(i);\r\n\r\n const nameSpan = document.createElement('span');\r\n nameSpan.className = 'tcw-cmd-item-label';\r\n nameSpan.textContent = item.label;\r\n row.appendChild(nameSpan);\r\n\r\n if (item.active) {\r\n const check = document.createElement('span');\r\n check.className = 'tcw-cmd-check';\r\n check.textContent = '✓';\r\n row.appendChild(check);\r\n }\r\n\r\n if (item.shortcut) {\r\n const kbd = document.createElement('kbd');\r\n kbd.className = 'tcw-cmd-kbd';\r\n kbd.textContent = item.shortcut;\r\n row.appendChild(kbd);\r\n }\r\n\r\n row.addEventListener('click', () => this.select(i));\r\n row.addEventListener('mouseenter', () => {\r\n this.selectedIndex = i;\r\n this.updateSelection();\r\n });\r\n\r\n this.list.appendChild(row);\r\n }\r\n }\r\n\r\n private updateSelection(): void {\r\n if (!this.list) return;\r\n const items = this.list.querySelectorAll('.tcw-cmd-item');\r\n items.forEach((el, i) => {\r\n el.classList.toggle('tcw-selected', i === this.selectedIndex);\r\n });\r\n items[this.selectedIndex]?.scrollIntoView({ block: 'nearest' });\r\n }\r\n\r\n private select(index: number): void {\r\n const item = this.filtered[index];\r\n if (!item) return;\r\n\r\n switch (item.category) {\r\n case 'indicator':\r\n this.callbacks.onIndicator(item.id);\r\n break;\r\n case 'chartType':\r\n this.callbacks.onChartType(item.id as ChartType);\r\n break;\r\n case 'drawing':\r\n this.callbacks.onDrawingTool(item.id as DrawingToolType);\r\n break;\r\n case 'timeframe':\r\n this.callbacks.onTimeframe(item.id as TimeFrame);\r\n break;\r\n case 'action':\r\n this.callbacks.onAction(item.id);\r\n break;\r\n }\r\n this.close();\r\n }\r\n\r\n private handleKeydown(e: KeyboardEvent): void {\r\n switch (e.key) {\r\n case 'Escape':\r\n e.preventDefault();\r\n this.close();\r\n break;\r\n case 'ArrowDown':\r\n e.preventDefault();\r\n if (this.filtered.length > 0) {\r\n this.selectedIndex = (this.selectedIndex + 1) % this.filtered.length;\r\n this.updateSelection();\r\n }\r\n break;\r\n case 'ArrowUp':\r\n e.preventDefault();\r\n if (this.filtered.length > 0) {\r\n this.selectedIndex = (this.selectedIndex - 1 + this.filtered.length) % this.filtered.length;\r\n this.updateSelection();\r\n }\r\n break;\r\n case 'Enter':\r\n e.preventDefault();\r\n this.select(this.selectedIndex);\r\n break;\r\n }\r\n }\r\n\r\n private categoryLabel(cat: string): string {\r\n switch (cat) {\r\n case 'indicator': return this.t('palette.group.indicator');\r\n case 'chartType': return this.t('palette.group.chartType');\r\n case 'drawing': return this.t('palette.group.drawing');\r\n case 'timeframe': return this.t('palette.group.timeframe');\r\n case 'action': return this.t('palette.group.action');\r\n default: return cat;\r\n }\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n }\r\n}\r\n","import type { SymbolInfo } from '@tradecanvas/commons';\r\nimport { escapeHtml } from './escapeHtml.js';\r\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\r\n/**\r\n * Symbol picker. Reuses the command-palette CSS for visual consistency.\r\n *\r\n * - Without a search function it filters the symbols it was given with a\r\n * cheap subsequence match, good enough for lists in the low thousands.\r\n * - With one (a feed's `searchSymbols`) it asks once typing pauses, cancels a\r\n * query a newer one replaced, and lists names and exchanges.\r\n */\r\nexport interface SymbolSearchCallbacks {\r\n onPick: (symbol: string) => void;\r\n onClose: () => void;\r\n}\r\n\r\n/** Symbols matching a query, best first; aborted when a newer query replaces it. */\r\nexport type SymbolSearchFn = (query: string, signal: AbortSignal) => Promise<SymbolInfo[]>;\r\n\r\n/** How long typing must pause before a search function is asked. */\r\nexport const SYMBOL_SEARCH_DEBOUNCE_MS = 150;\r\n\r\ninterface ScoredSymbol {\r\n symbol: string;\r\n score: number;\r\n description?: string;\r\n /** Exchange and type: \"Binance · crypto\". */\r\n meta?: string;\r\n}\r\n\r\nexport class WidgetSymbolSearch {\r\n private backdrop: HTMLDivElement | null = null;\r\n private modal: HTMLDivElement | null = null;\r\n private input: HTMLInputElement | null = null;\r\n private list: HTMLDivElement | null = null;\r\n private symbols: string[] = [];\r\n private current: string = '';\r\n private filtered: ScoredSymbol[] = [];\r\n private selectedIndex = 0;\r\n private callbacks: SymbolSearchCallbacks;\r\n private boundKeydown: (e: KeyboardEvent) => void;\r\n /** One-shot pick override — when set, this open() routes picks here instead. */\r\n private pickOverride: ((symbol: string) => void) | null = null;\r\n private searchFn: SymbolSearchFn | null = null;\r\n private searchTimer: ReturnType<typeof setTimeout> | null = null;\r\n private searchAbort: AbortController | null = null;\r\n private status: 'idle' | 'searching' | 'failed' = 'idle';\r\n /** Enter came before the results for what was typed: take the top one when they land. */\r\n private pickOnResults = false;\r\n\r\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\r\n constructor(\r\n callbacks: SymbolSearchCallbacks,\r\n private readonly host: () => HTMLElement = () => document.body,\r\n private readonly t: Translator = EN_TRANSLATOR,\r\n ) {\r\n this.callbacks = callbacks;\r\n this.boundKeydown = this.handleKeydown.bind(this);\r\n }\r\n\r\n open(symbols: string[], current: string, onPick?: (symbol: string) => void, search?: SymbolSearchFn): void {\r\n if (this.backdrop) return;\r\n this.pickOverride = onPick ?? null;\r\n this.searchFn = search ?? null;\r\n this.status = 'idle';\r\n this.symbols = symbols;\r\n this.current = current;\r\n this.filtered = symbols.map(s => ({ symbol: s, score: 0 }));\r\n this.selectedIndex = Math.max(0, symbols.indexOf(current));\r\n\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.addEventListener('click', () => this.close());\r\n\r\n this.modal = document.createElement('div');\r\n this.modal.className = 'tcw-cmd-palette';\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-cmd-header';\r\n\r\n const icon = document.createElement('span');\r\n icon.className = 'tcw-cmd-icon';\r\n icon.innerHTML = svgSearch();\r\n header.appendChild(icon);\r\n\r\n this.input = document.createElement('input');\r\n this.input.className = 'tcw-cmd-input';\r\n this.input.type = 'text';\r\n this.input.placeholder = this.t('symbolSearch.placeholder');\r\n this.input.autocomplete = 'off';\r\n this.input.spellcheck = false;\r\n this.input.addEventListener('input', () => this.filter());\r\n header.appendChild(this.input);\r\n\r\n const hint = document.createElement('span');\r\n hint.className = 'tcw-cmd-hint';\r\n hint.textContent = 'ESC';\r\n header.appendChild(hint);\r\n\r\n this.modal.appendChild(header);\r\n\r\n this.list = document.createElement('div');\r\n this.list.className = 'tcw-cmd-list';\r\n this.modal.appendChild(this.list);\r\n\r\n const footer = document.createElement('div');\r\n footer.className = 'tcw-cmd-footer';\r\n footer.innerHTML = `<span>↑↓ ${escapeHtml(this.t('common.navigate'))}</span>`\r\n + `<span>⏎ ${escapeHtml(this.t('common.open'))}</span>`\r\n + `<span>Esc ${escapeHtml(this.t('common.close'))}</span>`;\r\n this.modal.appendChild(footer);\r\n\r\n this.host().append(this.backdrop, this.modal);\r\n\r\n this.renderList();\r\n this.input.focus();\r\n document.addEventListener('keydown', this.boundKeydown);\r\n }\r\n\r\n close(): void {\r\n document.removeEventListener('keydown', this.boundKeydown);\r\n this.cancelSearch();\r\n this.pickOnResults = false;\r\n this.searchFn = null;\r\n this.backdrop?.remove();\r\n this.modal?.remove();\r\n this.backdrop = null;\r\n this.modal = null;\r\n this.input = null;\r\n this.list = null;\r\n this.pickOverride = null;\r\n this.callbacks.onClose();\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.backdrop !== null;\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n }\r\n\r\n private filter(): void {\r\n this.pickOnResults = false;\r\n const q = (this.input?.value ?? '').toUpperCase().trim();\r\n if (this.searchFn && q) {\r\n this.scheduleSearch(this.input?.value.trim() ?? '');\r\n return;\r\n }\r\n this.cancelSearch();\r\n this.status = 'idle';\r\n if (!q) {\r\n this.filtered = this.symbols.map(s => ({ symbol: s, score: 0 }));\r\n } else {\r\n this.filtered = this.symbols\r\n .map(s => ({ symbol: s, score: scoreMatch(s.toUpperCase(), q) }))\r\n .filter(r => r.score > 0)\r\n .sort((a, b) => b.score - a.score);\r\n }\r\n this.selectedIndex = 0;\r\n this.renderList();\r\n }\r\n\r\n private scheduleSearch(query: string): void {\r\n if (this.searchTimer !== null) clearTimeout(this.searchTimer);\r\n this.searchTimer = setTimeout(() => {\r\n this.searchTimer = null;\r\n void this.runSearch(query);\r\n }, SYMBOL_SEARCH_DEBOUNCE_MS);\r\n }\r\n\r\n /** Run the search the pause would have started, now. */\r\n private searchNow(): void {\r\n if (this.searchTimer !== null) clearTimeout(this.searchTimer);\r\n this.searchTimer = null;\r\n void this.runSearch(this.input?.value.trim() ?? '');\r\n }\r\n\r\n private async runSearch(query: string): Promise<void> {\r\n const search = this.searchFn;\r\n if (!search) return;\r\n this.searchAbort?.abort();\r\n const controller = new AbortController();\r\n this.searchAbort = controller;\r\n this.status = 'searching';\r\n this.filtered = [];\r\n this.renderList();\r\n try {\r\n const results = await search(query, controller.signal);\r\n if (controller.signal.aborted) return;\r\n this.filtered = results.map((info) => ({\r\n symbol: info.symbol,\r\n score: 0,\r\n description: info.description,\r\n meta: [info.exchange, info.type].filter(Boolean).join(' · ') || undefined,\r\n }));\r\n this.status = 'idle';\r\n } catch {\r\n if (controller.signal.aborted) return;\r\n this.filtered = [];\r\n this.status = 'failed';\r\n }\r\n this.selectedIndex = 0;\r\n this.renderList();\r\n if (this.pickOnResults) {\r\n this.pickOnResults = false;\r\n this.pick(0);\r\n }\r\n }\r\n\r\n private cancelSearch(): void {\r\n if (this.searchTimer !== null) clearTimeout(this.searchTimer);\r\n this.searchTimer = null;\r\n this.searchAbort?.abort();\r\n this.searchAbort = null;\r\n }\r\n\r\n private renderList(): void {\r\n if (!this.list) return;\r\n this.list.innerHTML = '';\r\n\r\n if (this.filtered.length === 0) {\r\n const empty = document.createElement('div');\r\n empty.className = 'tcw-cmd-empty';\r\n empty.setAttribute('role', 'status');\r\n empty.textContent = this.status === 'searching'\r\n ? this.t('symbolSearch.searching')\r\n : this.status === 'failed' ? this.t('symbolSearch.failed') : this.t('symbolSearch.empty');\r\n this.list.appendChild(empty);\r\n return;\r\n }\r\n\r\n const query = (this.input?.value ?? '').toUpperCase().trim();\r\n for (let i = 0; i < this.filtered.length; i++) {\r\n const { symbol, description, meta } = this.filtered[i];\r\n const row = document.createElement('button');\r\n row.className = 'tcw-cmd-item';\r\n if (i === this.selectedIndex) row.classList.add('tcw-selected');\r\n if (symbol === this.current) row.classList.add('tcw-active');\r\n\r\n const label = document.createElement('span');\r\n label.className = 'tcw-cmd-item-label';\r\n label.innerHTML = highlight(symbol, query);\r\n row.appendChild(label);\r\n\r\n if (description && description !== symbol) {\r\n const desc = document.createElement('span');\r\n desc.className = 'tcw-cmd-item-desc';\r\n desc.textContent = description;\r\n row.appendChild(desc);\r\n }\r\n if (meta) {\r\n const tag = document.createElement('span');\r\n tag.className = 'tcw-cmd-item-meta';\r\n tag.textContent = meta;\r\n row.appendChild(tag);\r\n }\r\n\r\n if (symbol === this.current) {\r\n const check = document.createElement('span');\r\n check.className = 'tcw-cmd-check';\r\n check.textContent = '✓';\r\n row.appendChild(check);\r\n }\r\n\r\n row.addEventListener('click', () => this.pick(i));\r\n row.addEventListener('mouseenter', () => {\r\n this.selectedIndex = i;\r\n this.updateSelection();\r\n });\r\n\r\n this.list.appendChild(row);\r\n }\r\n }\r\n\r\n private updateSelection(): void {\r\n if (!this.list) return;\r\n const items = this.list.querySelectorAll('.tcw-cmd-item');\r\n items.forEach((el, i) => el.classList.toggle('tcw-selected', i === this.selectedIndex));\r\n items[this.selectedIndex]?.scrollIntoView?.({ block: 'nearest' });\r\n }\r\n\r\n private pick(index: number): void {\r\n const entry = this.filtered[index];\r\n if (!entry) return;\r\n const override = this.pickOverride;\r\n if (override) override(entry.symbol);\r\n else this.callbacks.onPick(entry.symbol);\r\n this.close();\r\n }\r\n\r\n private handleKeydown(e: KeyboardEvent): void {\r\n switch (e.key) {\r\n case 'Escape':\r\n e.preventDefault();\r\n this.close();\r\n break;\r\n case 'ArrowDown':\r\n e.preventDefault();\r\n if (this.filtered.length > 0) {\r\n this.selectedIndex = (this.selectedIndex + 1) % this.filtered.length;\r\n this.updateSelection();\r\n }\r\n break;\r\n case 'ArrowUp':\r\n e.preventDefault();\r\n if (this.filtered.length > 0) {\r\n this.selectedIndex = (this.selectedIndex - 1 + this.filtered.length) % this.filtered.length;\r\n this.updateSelection();\r\n }\r\n break;\r\n case 'Enter':\r\n e.preventDefault();\r\n if (this.searchTimer !== null || this.status === 'searching') {\r\n // The list on screen is for an older query.\r\n this.pickOnResults = true;\r\n if (this.searchTimer !== null) this.searchNow();\r\n break;\r\n }\r\n this.pick(this.selectedIndex);\r\n break;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Cheap fuzzy score:\r\n * exact match → 1000\r\n * starts-with → 500 + tighter-prefix bonus\r\n * subsequence match → 100 − gap penalty\r\n * no match → 0\r\n */\r\nfunction scoreMatch(symbol: string, query: string): number {\r\n if (symbol === query) return 1000;\r\n if (symbol.startsWith(query)) return 500 + (50 - Math.min(50, symbol.length - query.length));\r\n if (symbol.includes(query)) return 200 + (50 - Math.min(50, symbol.length - query.length));\r\n\r\n let qi = 0;\r\n let lastIdx = -1;\r\n let gapPenalty = 0;\r\n for (let i = 0; i < symbol.length && qi < query.length; i++) {\r\n if (symbol[i] === query[qi]) {\r\n if (lastIdx >= 0) gapPenalty += i - lastIdx - 1;\r\n lastIdx = i;\r\n qi++;\r\n }\r\n }\r\n if (qi < query.length) return 0;\r\n return 100 - Math.min(99, gapPenalty);\r\n}\r\n\r\nfunction highlight(symbol: string, query: string): string {\r\n if (!query) return escapeHtml(symbol);\r\n const upper = symbol.toUpperCase();\r\n let out = '';\r\n let qi = 0;\r\n for (let i = 0; i < symbol.length; i++) {\r\n if (qi < query.length && upper[i] === query[qi]) {\r\n out += `<mark style=\"background:transparent;color:var(--tcw-accent);font-weight:700\">${escapeHtml(symbol[i])}</mark>`;\r\n qi++;\r\n } else {\r\n out += escapeHtml(symbol[i]);\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n\r\nfunction svgSearch(): string {\r\n return '<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m21 21-4.3-4.3\"/></svg>';\r\n}\r\n","import type { MessageKey, Translator } from './i18n.js';\r\n\r\n/**\r\n * Keyboard-shortcut reference sheet. Bound to `?` (and `Shift+/`). Surfaces\r\n * shortcuts so users discover the widget's hidden interaction model — a\r\n * premium-feel detail polished desktop tools all ship.\r\n */\r\nexport interface HotkeySheetCallbacks {\r\n onClose: () => void;\r\n}\r\n\r\n// Group titles translate via this lookup; individual shortcut labels (and\r\n// the `keys` badges) stay English for now — see README \"Widget i18n\".\r\nconst GROUP_TITLE_KEYS: Record<string, MessageKey> = {\r\n 'Search & navigation': 'hotkeys.group.searchNavigation',\r\n 'Chart manipulation': 'hotkeys.group.chartManipulation',\r\n 'Touch (mobile / tablet)': 'hotkeys.group.touch',\r\n 'Keyboard': 'hotkeys.group.keyboard',\r\n 'Drawing': 'hotkeys.group.drawing',\r\n};\r\n\r\ninterface HotkeyEntry {\r\n keys: string[];\r\n label: string;\r\n}\r\n\r\ninterface HotkeyGroup {\r\n title: string;\r\n entries: HotkeyEntry[];\r\n}\r\n\r\nconst isMac =\r\n typeof navigator !== 'undefined' && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);\r\nconst mod = isMac ? '⌘' : 'Ctrl';\r\n\r\nconst GROUPS: HotkeyGroup[] = [\r\n {\r\n title: 'Search & navigation',\r\n entries: [\r\n { keys: [mod, 'K'], label: 'hotkeys.commandPalette' },\r\n { keys: [mod, 'P'], label: 'hotkeys.symbolSearch' },\r\n { keys: ['Alt', 'G'], label: 'hotkeys.goToDate' },\r\n { keys: ['Alt', 'I'], label: 'hotkeys.invertScale' },\r\n { keys: [mod, 'S'], label: 'hotkeys.saveLayout' },\r\n { keys: ['0–9'], label: 'hotkeys.typeInterval' },\r\n { keys: ['?'], label: 'hotkeys.showSheet' },\r\n ],\r\n },\r\n {\r\n title: 'Chart manipulation',\r\n entries: [\r\n { keys: ['key.drag'], label: 'hotkeys.pan' },\r\n { keys: [mod, 'key.drag'], label: 'hotkeys.boxSelect' },\r\n { keys: [mod, 'key.click'], label: 'hotkeys.toggleSelect' },\r\n { keys: ['Shift', 'key.drag'], label: 'hotkeys.measure' },\r\n { keys: ['key.drag', 'key.priceAxis'], label: 'hotkeys.scalePrice' },\r\n { keys: ['key.drag', 'key.timeAxis'], label: 'hotkeys.zoomTime' },\r\n { keys: ['key.doubleClick', 'key.priceAxis'], label: 'hotkeys.autoScale' },\r\n { keys: ['key.doubleClick', 'key.timeAxis'], label: 'hotkeys.fit' },\r\n { keys: ['key.scroll'], label: 'hotkeys.zoomCursor' },\r\n ],\r\n },\r\n {\r\n title: 'Touch (mobile / tablet)',\r\n entries: [\r\n { keys: ['key.oneFinger', 'key.drag'], label: 'hotkeys.touchPan' },\r\n { keys: ['key.twoFingers', 'key.pinch'], label: 'hotkeys.pinch' },\r\n { keys: ['key.longPress'], label: 'hotkeys.longPress' },\r\n { keys: ['key.drag', 'key.axisStrip'], label: 'hotkeys.touchAxis' },\r\n ],\r\n },\r\n {\r\n title: 'Keyboard',\r\n entries: [\r\n { keys: ['←', '→'], label: 'hotkeys.panBar' },\r\n { keys: ['+', '−'], label: 'hotkeys.zoomInOut' },\r\n { keys: ['Home'], label: 'hotkeys.toStart' },\r\n { keys: ['End'], label: 'hotkeys.toEnd' },\r\n { keys: ['F'], label: 'hotkeys.fit' },\r\n ],\r\n },\r\n {\r\n title: 'Drawing',\r\n entries: [\r\n { keys: [mod, 'Z'], label: 'hotkeys.undo' },\r\n { keys: [mod, 'Shift', 'Z'], label: 'hotkeys.redo' },\r\n { keys: ['Esc'], label: 'hotkeys.cancelDrawing' },\r\n { keys: [mod, 'C'], label: 'hotkeys.copy' },\r\n { keys: [mod, 'V'], label: 'hotkeys.paste' },\r\n { keys: ['key.rightClick'], label: 'hotkeys.drawingMenu' },\r\n { keys: ['key.doubleClick'], label: 'hotkeys.drawingSettings' },\r\n { keys: [mod, 'G'], label: 'hotkeys.group' },\r\n { keys: [mod, 'Shift', 'G'], label: 'hotkeys.ungroup' },\r\n { keys: [mod, ']', '['], label: 'hotkeys.orderStep' },\r\n { keys: [mod, 'Shift', ']', '['], label: 'hotkeys.orderEnd' },\r\n { keys: ['Enter'], label: 'hotkeys.finishPath' },\r\n { keys: ['Alt', 'T'], label: 'tool.trendLine' },\r\n { keys: ['Alt', 'H'], label: 'tool.horizontalLine' },\r\n { keys: ['Alt', 'J'], label: 'tool.horizontalRay' },\r\n { keys: ['Alt', 'V'], label: 'tool.verticalLine' },\r\n { keys: ['Alt', 'C'], label: 'tool.crossLine' },\r\n { keys: ['Alt', 'F'], label: 'tool.fibRetracement' },\r\n ],\r\n },\r\n];\r\n\r\nexport class WidgetHotkeySheet {\r\n private backdrop: HTMLDivElement | null = null;\r\n private modal: HTMLDivElement | null = null;\r\n private callbacks: HotkeySheetCallbacks;\r\n private t: Translator;\r\n private boundKeydown: (e: KeyboardEvent) => void;\r\n\r\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\r\n constructor(\r\n callbacks: HotkeySheetCallbacks,\r\n t: Translator,\r\n private readonly host: () => HTMLElement = () => document.body,\r\n ) {\r\n this.callbacks = callbacks;\r\n this.t = t;\r\n this.boundKeydown = (e) => {\r\n if (e.key === 'Escape') {\r\n e.preventDefault();\r\n this.close();\r\n }\r\n };\r\n }\r\n\r\n open(): void {\r\n if (this.backdrop) return;\r\n\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.addEventListener('click', () => this.close());\r\n\r\n this.modal = document.createElement('div');\r\n this.modal.className = 'tcw-modal tcw-hotkey-sheet';\r\n this.modal.style.width = '640px';\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-modal-header';\r\n const title = document.createElement('h3');\r\n title.textContent = this.t('hotkeys.title');\r\n header.appendChild(title);\r\n const closeBtn = document.createElement('button');\r\n closeBtn.className = 'tcw-modal-close';\r\n closeBtn.setAttribute('aria-label', this.t('hotkeys.close'));\r\n closeBtn.innerHTML = '×';\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.appendChild(closeBtn);\r\n this.modal.appendChild(header);\r\n\r\n const body = document.createElement('div');\r\n body.className = 'tcw-modal-body';\r\n\r\n const grid = document.createElement('div');\r\n grid.className = 'tcw-hotkey-grid';\r\n\r\n for (const group of GROUPS) {\r\n const section = document.createElement('section');\r\n section.className = 'tcw-hotkey-section';\r\n const title = document.createElement('div');\r\n title.className = 'tcw-settings-section-title';\r\n const titleKey = GROUP_TITLE_KEYS[group.title];\r\n title.textContent = titleKey ? this.t(titleKey) : group.title;\r\n section.appendChild(title);\r\n\r\n for (const entry of group.entries) {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-hotkey-row';\r\n\r\n const keys = document.createElement('div');\r\n keys.className = 'tcw-hotkey-keys';\r\n for (let i = 0; i < entry.keys.length; i++) {\r\n if (i > 0) {\r\n const plus = document.createElement('span');\r\n plus.className = 'tcw-hotkey-sep';\r\n plus.textContent = '+';\r\n keys.appendChild(plus);\r\n }\r\n const kbd = document.createElement('kbd');\r\n kbd.className = 'tcw-cmd-kbd';\r\n const key = entry.keys[i];\r\n kbd.textContent = key.startsWith('key.') ? this.t(key as MessageKey) : key;\r\n keys.appendChild(kbd);\r\n }\r\n row.appendChild(keys);\r\n\r\n const label = document.createElement('span');\r\n label.className = 'tcw-hotkey-label';\r\n label.textContent = this.t(entry.label as MessageKey);\r\n row.appendChild(label);\r\n\r\n section.appendChild(row);\r\n }\r\n\r\n grid.appendChild(section);\r\n }\r\n\r\n body.appendChild(grid);\r\n this.modal.appendChild(body);\r\n\r\n const footer = document.createElement('div');\r\n footer.className = 'tcw-modal-footer';\r\n const hint = document.createElement('span');\r\n hint.style.cssText = 'font-size:11px;color:var(--tcw-text-muted)';\r\n hint.textContent = this.t('hotkeys.footer');\r\n footer.appendChild(hint);\r\n const ok = document.createElement('button');\r\n ok.className = 'tcw-done-btn';\r\n ok.textContent = this.t('hotkeys.gotIt');\r\n ok.addEventListener('click', () => this.close());\r\n footer.appendChild(ok);\r\n this.modal.appendChild(footer);\r\n\r\n this.host().append(this.backdrop, this.modal);\r\n\r\n document.addEventListener('keydown', this.boundKeydown);\r\n }\r\n\r\n close(): void {\r\n document.removeEventListener('keydown', this.boundKeydown);\r\n this.backdrop?.remove();\r\n this.modal?.remove();\r\n this.backdrop = null;\r\n this.modal = null;\r\n this.callbacks.onClose();\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.backdrop !== null;\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n }\r\n}\r\n","import { escapeHtml } from './escapeHtml.js';\r\n/**\r\n * Replay control bar. Surfaces the chart's replay engine as a floating\r\n * bottom-of-chart control and reports user intent through callbacks (no\r\n * chart coupling — the host calls chart.replayStart() / replayPause() / …).\r\n *\r\n * Two modes: `select` (pick the start bar: a hint, \"random bar\", play from a\r\n * default start) and `replay` (step, play/pause, scrub, speed). \"Back to\r\n * realtime\" is always there and is highlighted once the replay reaches the\r\n * last bar.\r\n */\r\nexport interface ReplayBarCallbacks {\r\n onPlay: () => void;\r\n onPause: () => void;\r\n onStepBack: () => void;\r\n onStepForward: () => void;\r\n onSeek: (index: number) => void;\r\n /** Bars revealed per second. */\r\n onSpeedChange: (barsPerSecond: number) => void;\r\n onRandomStart: () => void;\r\n onClose: () => void;\r\n /** The step picked: `'bar'`, or a finer interval to replay through. */\r\n onStepChange?: (step: string) => void;\r\n}\r\n\r\n/** A replay step on offer: `'bar'` or a finer interval. */\r\nexport interface ReplayStepOption {\r\n value: string;\r\n label: string;\r\n}\r\n\r\nexport interface ReplayBarLabels {\r\n selectHint: string;\r\n random: string;\r\n realtime: string;\r\n barsPerSecond: string;\r\n play: string;\r\n pause: string;\r\n stepBack: string;\r\n stepForward: string;\r\n replay: string;\r\n position: string;\r\n speed: string;\r\n step: string;\r\n}\r\n\r\nexport const DEFAULT_REPLAY_LABELS: ReplayBarLabels = {\r\n selectHint: 'Click a bar to start the replay',\r\n random: 'Random bar',\r\n realtime: 'Back to realtime',\r\n barsPerSecond: 'bars/s',\r\n play: 'Play',\r\n pause: 'Pause',\r\n stepBack: 'Step back (Shift+←)',\r\n stepForward: 'Step forward (Shift+→)',\r\n replay: 'Replay',\r\n position: 'Replay position',\r\n speed: 'Speed',\r\n step: 'Step',\r\n};\r\n\r\nexport type ReplayBarState = 'playing' | 'paused' | 'stopped';\r\nexport type ReplayBarMode = 'select' | 'replay';\r\n\r\n/** Replay speeds, in bars revealed per second. */\r\nexport const REPLAY_SPEEDS = [1, 2, 3, 5, 10, 25, 50] as const;\r\nexport const DEFAULT_REPLAY_SPEED = 5;\r\n\r\nexport class WidgetReplayBar {\r\n private root: HTMLDivElement | null = null;\r\n private scrubber: HTMLInputElement | null = null;\r\n private progressLabel: HTMLSpanElement | null = null;\r\n private playBtn: HTMLButtonElement | null = null;\r\n private realtimeBtn: HTMLButtonElement | null = null;\r\n private state: ReplayBarState = 'stopped';\r\n private mode: ReplayBarMode = 'select';\r\n private ended = false;\r\n private total = 0;\r\n private speed = DEFAULT_REPLAY_SPEED;\r\n private steps: readonly ReplayStepOption[] = [];\r\n private step = 'bar';\r\n private readonly labels: ReplayBarLabels;\r\n\r\n constructor(private readonly callbacks: ReplayBarCallbacks, labels: Partial<ReplayBarLabels> = {}) {\r\n this.labels = { ...DEFAULT_REPLAY_LABELS, ...labels };\r\n }\r\n\r\n mount(\r\n host: HTMLElement,\r\n opts: { total: number; speed?: number; mode?: ReplayBarMode; steps?: readonly ReplayStepOption[]; step?: string },\r\n ): void {\r\n if (this.root) return;\r\n this.total = Math.max(0, opts.total);\r\n this.speed = opts.speed ?? DEFAULT_REPLAY_SPEED;\r\n this.steps = opts.steps ?? [];\r\n this.step = opts.step ?? 'bar';\r\n this.state = 'paused';\r\n this.mode = opts.mode ?? 'select';\r\n\r\n this.root = document.createElement('div');\r\n this.root.className = 'tcw-replay-bar';\r\n this.root.setAttribute('role', 'toolbar');\r\n this.root.setAttribute('aria-label', this.labels.replay);\r\n this.root.innerHTML = this.markup();\r\n\r\n host.appendChild(this.root);\r\n this.wireEvents();\r\n this.syncUi();\r\n }\r\n\r\n unmount(): void {\r\n this.root?.remove();\r\n this.root = null;\r\n this.scrubber = null;\r\n this.progressLabel = null;\r\n this.playBtn = null;\r\n this.realtimeBtn = null;\r\n this.state = 'stopped';\r\n this.ended = false;\r\n }\r\n\r\n isMounted(): boolean {\r\n return this.root !== null;\r\n }\r\n\r\n getMode(): ReplayBarMode {\r\n return this.mode;\r\n }\r\n\r\n setMode(mode: ReplayBarMode): void {\r\n // The button that started the replay (Random, Play) is about to hide:\r\n // keep keyboard focus inside the bar, on Play.\r\n const hadFocus = !!this.root?.contains(document.activeElement);\r\n this.mode = mode;\r\n this.syncUi();\r\n if (hadFocus && mode === 'replay') this.playBtn?.focus();\r\n }\r\n\r\n setState(state: ReplayBarState): void {\r\n this.state = state;\r\n this.syncUi();\r\n }\r\n\r\n /** The replay sits on its last bar: nothing left to play. */\r\n setEnded(ended: boolean): void {\r\n if (this.ended === ended) return;\r\n this.ended = ended;\r\n this.syncUi();\r\n }\r\n\r\n /** `current`: index of the bar on screen. */\r\n setProgress(current: number, total: number): void {\r\n this.total = total;\r\n if (this.scrubber) {\r\n this.scrubber.max = String(Math.max(0, total - 1));\r\n this.scrubber.value = String(current);\r\n }\r\n if (this.progressLabel) {\r\n this.progressLabel.textContent = `${Math.min(current + 1, total)} / ${total}`;\r\n }\r\n }\r\n\r\n destroy(): void {\r\n this.unmount();\r\n }\r\n\r\n private markup(): string {\r\n const l = this.labels;\r\n const speeds = REPLAY_SPEEDS.map(\r\n (s) => `<option value=\"${s}\"${s === this.speed ? ' selected' : ''}>${s} ${escapeHtml(l.barsPerSecond)}</option>`,\r\n ).join('');\r\n return `\r\n <span class=\"tcw-replay-group\" data-mode=\"select\">\r\n <span class=\"tcw-replay-hint\" role=\"status\">${svgCursor()}${escapeHtml(l.selectHint)}</span>\r\n <button class=\"tcw-replay-text-btn\" data-act=\"random\">${escapeHtml(l.random)}</button>\r\n </span>\r\n <span class=\"tcw-replay-group\" data-mode=\"replay\">\r\n <button class=\"tcw-replay-btn\" data-act=\"stepBack\" title=\"${escapeHtml(l.stepBack)}\" aria-label=\"${escapeHtml(l.stepBack)}\">${svgStepBack()}</button>\r\n <button class=\"tcw-replay-btn tcw-replay-play\" data-act=\"play\" title=\"${escapeHtml(l.play)}\" aria-label=\"${escapeHtml(l.play)}\">${svgPlay()}</button>\r\n <button class=\"tcw-replay-btn\" data-act=\"stepForward\" title=\"${escapeHtml(l.stepForward)}\" aria-label=\"${escapeHtml(l.stepForward)}\">${svgStepForward()}</button>\r\n <input type=\"range\" class=\"tcw-replay-scrubber\" data-act=\"seek\" min=\"0\" max=\"${Math.max(0, this.total - 1)}\" value=\"0\" step=\"1\" aria-label=\"${escapeHtml(this.labels.position)}\" />\r\n <span class=\"tcw-replay-progress\" data-tcw=\"progress\">1 / ${this.total}</span>\r\n <select class=\"tcw-replay-speed\" data-act=\"speed\" aria-label=\"${escapeHtml(this.labels.speed)}\">${speeds}</select>\r\n </span>\r\n ${this.steps.length > 1 ? `<select class=\"tcw-replay-speed tcw-replay-step\" data-act=\"step\" aria-label=\"${escapeHtml(l.step)}\" title=\"${escapeHtml(l.step)}\">${\r\n this.steps.map((s) => `<option value=\"${escapeHtml(s.value)}\"${s.value === this.step ? ' selected' : ''}>${escapeHtml(s.label)}</option>`).join('')\r\n }</select>` : ''}\r\n <button class=\"tcw-replay-text-btn tcw-replay-realtime\" data-act=\"realtime\">${escapeHtml(l.realtime)}</button>\r\n `;\r\n }\r\n\r\n private wireEvents(): void {\r\n const root = this.root;\r\n if (!root) return;\r\n this.scrubber = root.querySelector('input[data-act=\"seek\"]');\r\n this.progressLabel = root.querySelector('[data-tcw=\"progress\"]');\r\n this.playBtn = root.querySelector('button[data-act=\"play\"]');\r\n this.realtimeBtn = root.querySelector('button[data-act=\"realtime\"]');\r\n\r\n this.realtimeBtn?.addEventListener('click', () => this.callbacks.onClose());\r\n root.querySelector('[data-act=\"random\"]')?.addEventListener('click', () => this.callbacks.onRandomStart());\r\n root.querySelector('[data-act=\"stepBack\"]')?.addEventListener('click', () => this.callbacks.onStepBack());\r\n root.querySelector('[data-act=\"stepForward\"]')?.addEventListener('click', () => this.callbacks.onStepForward());\r\n this.playBtn?.addEventListener('click', () => {\r\n if (this.state === 'playing') this.callbacks.onPause();\r\n else this.callbacks.onPlay();\r\n });\r\n this.scrubber?.addEventListener('input', () => this.callbacks.onSeek(Number(this.scrubber!.value)));\r\n (root.querySelector('[data-act=\"speed\"]') as HTMLSelectElement | null)?.addEventListener('change', (e) => {\r\n const v = Number((e.target as HTMLSelectElement).value);\r\n this.speed = v;\r\n this.callbacks.onSpeedChange(v);\r\n });\r\n (root.querySelector('[data-act=\"step\"]') as HTMLSelectElement | null)?.addEventListener('change', (e) => {\r\n this.step = (e.target as HTMLSelectElement).value;\r\n this.callbacks.onStepChange?.(this.step);\r\n });\r\n }\r\n\r\n private syncUi(): void {\r\n const root = this.root;\r\n if (!root) return;\r\n for (const group of root.querySelectorAll<HTMLElement>('.tcw-replay-group')) {\r\n group.hidden = group.dataset.mode !== this.mode;\r\n }\r\n root.classList.toggle('tcw-replay-bar--ended', this.ended);\r\n if (this.playBtn) {\r\n const playing = this.state === 'playing';\r\n this.playBtn.innerHTML = playing ? svgPause() : svgPlay();\r\n this.playBtn.title = playing ? this.labels.pause : this.labels.play;\r\n this.playBtn.setAttribute('aria-label', this.playBtn.title);\r\n const disable = this.ended && !playing;\r\n if (disable && document.activeElement === this.playBtn) this.realtimeBtn?.focus();\r\n this.playBtn.disabled = disable;\r\n }\r\n }\r\n}\r\n\r\n\r\nfunction svgPlay(): string {\r\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M8 5v14l11-7L8 5z\"/></svg>';\r\n}\r\nfunction svgPause(): string {\r\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/></svg>';\r\n}\r\nfunction svgStepBack(): string {\r\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M6 6h2v12H6zM20 6L9 12l11 6V6z\"/></svg>';\r\n}\r\nfunction svgStepForward(): string {\r\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M4 6l11 6L4 18V6zM16 6h2v12h-2z\"/></svg>';\r\n}\r\nfunction svgCursor(): string {\r\n return '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M12 3v18M8 7l4-4 4 4M8 17l4 4 4-4\"/></svg>';\r\n}\r\n","import type { WatchlistList } from './WatchlistStore.js';\r\nimport { fill } from './i18n.js';\r\n\r\n/**\r\n * Watchlist sidebar: the shown list's symbols, each with last price, % change\r\n * and a mini sparkline. A menu switches, creates, renames and deletes lists;\r\n * rows are added, removed and reordered (drag, or Alt+↑/↓). It only renders\r\n * and reports: the widget keeps the lists (see WatchlistStore).\r\n *\r\n * The widget tracks the chart's symbol from the live stream, and fills the\r\n * other rows from a quote source or what the host pushes (`setEntry`).\r\n */\r\nexport interface WatchlistEntry {\r\n symbol: string;\r\n lastPrice?: number;\r\n /** Reference price for % calc (usually session open or 24h-ago close). */\r\n refPrice?: number;\r\n /** Recent close samples for the sparkline — last point is the live price. */\r\n sparkline?: number[];\r\n}\r\n\r\nexport interface WatchlistCallbacks {\r\n onSelect: (symbol: string) => void;\r\n /** \"+\": add a symbol to the shown list (the widget opens its symbol search). */\r\n onAdd?: () => void;\r\n onRemove?: (symbol: string) => void;\r\n /** Move a symbol to `index` in the shown list. */\r\n onMove?: (symbol: string, index: number) => void;\r\n onPickList?: (id: string) => void;\r\n onCreateList?: (name: string) => void;\r\n onRenameList?: (id: string, name: string) => void;\r\n onDeleteList?: (id: string) => void;\r\n}\r\n\r\nexport interface WatchlistLabels {\r\n title: string;\r\n lists: string;\r\n newList: string;\r\n rename: string;\r\n deleteList: string;\r\n /** `{name}`: the list's name. */\r\n confirmDelete: string;\r\n add: string;\r\n /** `{symbol}`. */\r\n remove: string;\r\n empty: string;\r\n listName: string;\r\n}\r\n\r\ninterface RowRef {\r\n row: HTMLDivElement;\r\n priceEl: HTMLSpanElement;\r\n changeEl: HTMLSpanElement;\r\n sparkCanvas: HTMLCanvasElement;\r\n}\r\n\r\nexport class WidgetWatchlist {\r\n private el: HTMLDivElement;\r\n private headerEl: HTMLDivElement;\r\n private nameBtn: HTMLButtonElement;\r\n private menuEl: HTMLDivElement;\r\n private listEl: HTMLDivElement;\r\n private rowMap = new Map<string, RowRef>();\r\n private entries = new Map<string, WatchlistEntry>();\r\n private lists: WatchlistList[] = [];\r\n private activeList = '';\r\n private active: string | null = null;\r\n private locale: string | undefined;\r\n private dragging: string | null = null;\r\n private readonly onOutside = (e: MouseEvent) => {\r\n if (!this.headerEl.contains(e.target as Node)) this.closeMenu();\r\n };\r\n\r\n constructor(\r\n host: HTMLElement,\r\n private readonly callbacks: WatchlistCallbacks,\r\n private readonly labels: WatchlistLabels,\r\n ) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-watchlist';\r\n this.el.setAttribute('aria-label', labels.title);\r\n\r\n this.headerEl = document.createElement('div');\r\n this.headerEl.className = 'tcw-watchlist-header';\r\n\r\n this.nameBtn = document.createElement('button');\r\n this.nameBtn.type = 'button';\r\n this.nameBtn.className = 'tcw-watchlist-name';\r\n this.nameBtn.setAttribute('aria-haspopup', 'menu');\r\n this.nameBtn.setAttribute('aria-expanded', 'false');\r\n this.nameBtn.title = labels.lists;\r\n this.nameBtn.addEventListener('click', () => (this.menuEl.hidden ? this.openMenu() : this.closeMenu()));\r\n\r\n const addBtn = document.createElement('button');\r\n addBtn.type = 'button';\r\n addBtn.className = 'tcw-watchlist-add';\r\n addBtn.textContent = '+';\r\n addBtn.title = labels.add;\r\n addBtn.setAttribute('aria-label', labels.add);\r\n addBtn.hidden = !callbacks.onAdd;\r\n addBtn.addEventListener('click', () => callbacks.onAdd?.());\r\n\r\n this.menuEl = document.createElement('div');\r\n this.menuEl.className = 'tcw-dropdown tcw-watchlist-menu';\r\n this.menuEl.setAttribute('role', 'menu');\r\n this.menuEl.hidden = true;\r\n\r\n this.headerEl.append(this.nameBtn, addBtn, this.menuEl);\r\n this.el.appendChild(this.headerEl);\r\n\r\n this.listEl = document.createElement('div');\r\n this.listEl.className = 'tcw-watchlist-list';\r\n this.listEl.setAttribute('role', 'list');\r\n this.el.appendChild(this.listEl);\r\n\r\n host.appendChild(this.el);\r\n }\r\n\r\n /** The lists, and which one shows. Rows are diffed so prices stay. */\r\n setLists(lists: WatchlistList[], activeId: string): void {\r\n this.lists = lists.map((l) => ({ ...l, symbols: [...l.symbols] }));\r\n this.activeList = lists.some((l) => l.id === activeId) ? activeId : lists[0]?.id ?? '';\r\n const shown = this.shownList();\r\n this.nameBtn.textContent = shown?.name ?? this.labels.title;\r\n this.renderRows(shown?.symbols ?? []);\r\n if (!this.menuEl.hidden) this.renderMenu();\r\n }\r\n\r\n /** Set the BCP 47 locale used for price/percent formatting. */\r\n setLocale(locale: string | undefined): void {\r\n this.locale = locale;\r\n for (const symbol of this.rowMap.keys()) this.renderRow(symbol);\r\n }\r\n\r\n /** The chart's symbol, marked in the list. */\r\n setActive(symbol: string): void {\r\n this.active = symbol;\r\n for (const [sym, ref] of this.rowMap) {\r\n const on = sym === symbol;\r\n ref.row.classList.toggle('tcw-watchlist-active', on);\r\n if (on) ref.row.setAttribute('aria-current', 'true');\r\n else ref.row.removeAttribute('aria-current');\r\n }\r\n }\r\n\r\n /** A row's price, move and sparkline. Kept for symbols not shown yet. */\r\n setEntry(symbol: string, patch: Partial<WatchlistEntry>): void {\r\n const prev = this.entries.get(symbol) ?? { symbol };\r\n this.entries.set(symbol, { ...prev, ...patch, symbol });\r\n this.renderRow(symbol);\r\n }\r\n\r\n destroy(): void {\r\n this.closeMenu();\r\n this.el.remove();\r\n this.rowMap.clear();\r\n this.entries.clear();\r\n }\r\n\r\n private shownList(): WatchlistList | undefined {\r\n return this.lists.find((l) => l.id === this.activeList);\r\n }\r\n\r\n // --- Rows ---\r\n\r\n private renderRows(symbols: string[]): void {\r\n for (const sym of [...this.rowMap.keys()]) {\r\n if (!symbols.includes(sym)) {\r\n this.rowMap.get(sym)!.row.remove();\r\n this.rowMap.delete(sym);\r\n }\r\n }\r\n for (const sym of symbols) if (!this.rowMap.has(sym)) this.makeRow(sym);\r\n // In list order; nodes already in place stay.\r\n this.listEl.replaceChildren(...symbols.map((sym) => this.rowMap.get(sym)!.row));\r\n if (symbols.length === 0) {\r\n const empty = document.createElement('div');\r\n empty.className = 'tcw-watchlist-empty';\r\n empty.textContent = this.labels.empty;\r\n this.listEl.appendChild(empty);\r\n }\r\n if (this.active) this.setActive(this.active);\r\n }\r\n\r\n private makeRow(symbol: string): void {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-watchlist-row';\r\n row.setAttribute('role', 'listitem');\r\n row.dataset.symbol = symbol;\r\n row.tabIndex = 0;\r\n row.draggable = !!this.callbacks.onMove;\r\n\r\n const label = document.createElement('div');\r\n label.className = 'tcw-watchlist-symbol';\r\n label.textContent = formatSymbol(symbol);\r\n\r\n const spark = document.createElement('canvas');\r\n spark.className = 'tcw-watchlist-spark';\r\n spark.width = 64;\r\n spark.height = 22;\r\n\r\n const right = document.createElement('div');\r\n right.className = 'tcw-watchlist-stats';\r\n const priceEl = document.createElement('span');\r\n priceEl.className = 'tcw-watchlist-price';\r\n priceEl.textContent = '—';\r\n const changeEl = document.createElement('span');\r\n changeEl.className = 'tcw-watchlist-change';\r\n right.append(priceEl, changeEl);\r\n row.append(label, spark, right);\r\n\r\n if (this.callbacks.onRemove) {\r\n const remove = document.createElement('button');\r\n remove.type = 'button';\r\n remove.className = 'tcw-watchlist-remove';\r\n remove.textContent = '×';\r\n remove.tabIndex = -1;\r\n const text = fill(this.labels.remove, { symbol });\r\n remove.title = text;\r\n remove.setAttribute('aria-label', text);\r\n remove.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.callbacks.onRemove?.(symbol);\r\n });\r\n row.appendChild(remove);\r\n }\r\n\r\n row.addEventListener('click', () => this.callbacks.onSelect(symbol));\r\n row.addEventListener('keydown', (e) => this.onRowKey(e, symbol));\r\n row.addEventListener('dragstart', (e) => {\r\n this.dragging = symbol;\r\n e.dataTransfer?.setData('text/plain', symbol);\r\n if (e.dataTransfer) e.dataTransfer.effectAllowed = 'move';\r\n row.classList.add('tcw-watchlist-dragging');\r\n });\r\n row.addEventListener('dragend', () => {\r\n this.dragging = null;\r\n row.classList.remove('tcw-watchlist-dragging');\r\n });\r\n row.addEventListener('dragover', (e) => {\r\n if (this.dragging && this.dragging !== symbol) e.preventDefault();\r\n });\r\n row.addEventListener('drop', (e) => {\r\n e.preventDefault();\r\n const from = this.dragging;\r\n this.dragging = null;\r\n if (!from || from === symbol) return;\r\n const order = this.shownList()?.symbols ?? [];\r\n this.callbacks.onMove?.(from, order.indexOf(symbol));\r\n });\r\n\r\n this.rowMap.set(symbol, { row, priceEl, changeEl, sparkCanvas: spark });\r\n this.renderRow(symbol);\r\n }\r\n\r\n private onRowKey(e: KeyboardEvent, symbol: string): void {\r\n const order = this.shownList()?.symbols ?? [];\r\n const index = order.indexOf(symbol);\r\n // Keys handled here stay here (Delete would also remove a selected drawing).\r\n if (['Enter', ' ', 'Delete', 'Backspace', 'ArrowDown', 'ArrowUp'].includes(e.key)) e.stopPropagation();\r\n if (e.key === 'Enter' || e.key === ' ') {\r\n e.preventDefault();\r\n this.callbacks.onSelect(symbol);\r\n } else if ((e.key === 'Delete' || e.key === 'Backspace') && this.callbacks.onRemove) {\r\n e.preventDefault();\r\n const next = order[index + 1] ?? order[index - 1];\r\n this.callbacks.onRemove(symbol);\r\n if (next) this.rowMap.get(next)?.row.focus();\r\n } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\r\n e.preventDefault();\r\n const to = index + (e.key === 'ArrowDown' ? 1 : -1);\r\n if (to < 0 || to >= order.length) return;\r\n if (e.altKey) {\r\n this.callbacks.onMove?.(symbol, to);\r\n this.rowMap.get(symbol)?.row.focus();\r\n } else {\r\n this.rowMap.get(order[to])?.row.focus();\r\n }\r\n }\r\n }\r\n\r\n private renderRow(symbol: string): void {\r\n const ref = this.rowMap.get(symbol);\r\n const entry = this.entries.get(symbol);\r\n if (!ref || !entry) return;\r\n\r\n if (entry.lastPrice !== undefined) {\r\n ref.priceEl.textContent = formatPrice(entry.lastPrice, this.locale);\r\n }\r\n\r\n if (entry.lastPrice !== undefined && entry.refPrice !== undefined && entry.refPrice !== 0) {\r\n const diff = entry.lastPrice - entry.refPrice;\r\n const pct = (diff / entry.refPrice) * 100;\r\n const sign = diff >= 0 ? '+' : '-';\r\n const pctText = Math.abs(pct).toLocaleString(this.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\r\n ref.changeEl.textContent = `${sign}${pctText}%`;\r\n ref.changeEl.className = `tcw-watchlist-change ${diff >= 0 ? 'tcw-up' : 'tcw-down'}`;\r\n } else {\r\n ref.changeEl.textContent = '';\r\n }\r\n\r\n if (entry.sparkline && entry.sparkline.length >= 2) {\r\n drawSparkline(ref.sparkCanvas, entry.sparkline, entry.refPrice ?? entry.sparkline[0]);\r\n }\r\n }\r\n\r\n // --- The lists menu ---\r\n\r\n private openMenu(): void {\r\n this.renderMenu();\r\n this.menuEl.hidden = false;\r\n this.nameBtn.setAttribute('aria-expanded', 'true');\r\n document.addEventListener('mousedown', this.onOutside);\r\n }\r\n\r\n private closeMenu(): void {\r\n this.menuEl.hidden = true;\r\n this.nameBtn.setAttribute('aria-expanded', 'false');\r\n document.removeEventListener('mousedown', this.onOutside);\r\n }\r\n\r\n private renderMenu(): void {\r\n const item = (text: string, onClick: () => void): HTMLButtonElement => {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-dropdown-item';\r\n btn.setAttribute('role', 'menuitem');\r\n btn.textContent = text;\r\n btn.addEventListener('click', onClick);\r\n return btn;\r\n };\r\n const items: HTMLElement[] = this.lists.map((list) => {\r\n const btn = item('', () => {\r\n this.closeMenu();\r\n this.callbacks.onPickList?.(list.id);\r\n });\r\n btn.dataset.list = list.id;\r\n btn.classList.toggle('tcw-active', list.id === this.activeList);\r\n const name = document.createElement('span');\r\n name.textContent = list.name;\r\n const count = document.createElement('span');\r\n count.className = 'tcw-watchlist-count';\r\n count.textContent = String(list.symbols.length);\r\n btn.append(name, count);\r\n return btn;\r\n });\r\n const sep = document.createElement('div');\r\n sep.className = 'tcw-dropdown-divider';\r\n items.push(sep);\r\n if (this.callbacks.onCreateList) {\r\n const create = item(this.labels.newList, () => this.editName('', (name) => this.callbacks.onCreateList?.(name)));\r\n create.dataset.action = 'new';\r\n items.push(create);\r\n }\r\n const shown = this.shownList();\r\n if (shown && this.callbacks.onRenameList) {\r\n const rename = item(this.labels.rename, () => this.editName(shown.name, (name) => this.callbacks.onRenameList?.(shown.id, name)));\r\n rename.dataset.action = 'rename';\r\n items.push(rename);\r\n }\r\n if (shown && this.callbacks.onDeleteList && this.lists.length > 1) {\r\n let armed = false;\r\n const del = item(this.labels.deleteList, () => {\r\n if (!armed) {\r\n armed = true;\r\n del.textContent = fill(this.labels.confirmDelete, { name: shown.name });\r\n del.classList.add('tcw-danger');\r\n return;\r\n }\r\n this.closeMenu();\r\n this.callbacks.onDeleteList?.(shown.id);\r\n });\r\n del.dataset.action = 'delete';\r\n items.push(del);\r\n }\r\n this.menuEl.replaceChildren(...items);\r\n }\r\n\r\n /** A name typed in place of the list's: Enter keeps it, Escape or leaving drops it. */\r\n private editName(initial: string, done: (name: string) => void): void {\r\n this.closeMenu();\r\n const input = document.createElement('input');\r\n input.className = 'tcw-watchlist-input';\r\n input.type = 'text';\r\n input.maxLength = 60;\r\n input.value = initial;\r\n input.placeholder = this.labels.listName;\r\n input.setAttribute('aria-label', this.labels.listName);\r\n this.nameBtn.hidden = true;\r\n this.headerEl.insertBefore(input, this.nameBtn);\r\n let finished = false;\r\n const finish = (keep: boolean) => {\r\n if (finished) return;\r\n finished = true;\r\n const name = input.value.trim();\r\n input.remove();\r\n this.nameBtn.hidden = false;\r\n if (keep && name && name !== initial) done(name);\r\n this.nameBtn.focus();\r\n };\r\n input.addEventListener('keydown', (e) => {\r\n e.stopPropagation();\r\n if (e.key === 'Enter') {\r\n e.preventDefault();\r\n finish(true);\r\n } else if (e.key === 'Escape') {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n finish(false);\r\n }\r\n });\r\n input.addEventListener('blur', () => finish(false));\r\n input.focus();\r\n }\r\n}\r\n\r\nfunction formatSymbol(symbol: string): string {\r\n // Add a / separator for typical crypto pair suffixes; leaves stock tickers\r\n // (AAPL, NVDA) alone.\r\n for (const quote of ['USDT', 'USD', 'BTC', 'ETH', 'EUR']) {\r\n if (symbol.length > quote.length && symbol.endsWith(quote)) {\r\n return symbol.slice(0, -quote.length) + '/' + quote;\r\n }\r\n }\r\n return symbol;\r\n}\r\n\r\nfunction formatPrice(v: number, locale: string | undefined): string {\r\n if (v === 0) return '0';\r\n const abs = Math.abs(v);\r\n if (abs >= 1000) return v.toLocaleString(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\r\n if (abs >= 1) return v.toLocaleString(locale, { minimumFractionDigits: 4, maximumFractionDigits: 4 });\r\n // toPrecision(4) has no locale-aware equivalent via toLocaleString (it\r\n // targets significant digits, not decimal places) — reformat its raw\r\n // fixed-notation output through Number.toLocaleString for the separator.\r\n const precise = Number(v.toPrecision(4));\r\n return precise.toLocaleString(locale, { maximumFractionDigits: 10 });\r\n}\r\n\r\nfunction drawSparkline(canvas: HTMLCanvasElement, samples: number[], ref: number): void {\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n const dpr = window.devicePixelRatio || 1;\r\n if (canvas.width !== canvas.clientWidth * dpr) {\r\n canvas.width = (canvas.clientWidth || 64) * dpr;\r\n canvas.height = (canvas.clientHeight || 22) * dpr;\r\n }\r\n const w = canvas.width;\r\n const h = canvas.height;\r\n\r\n let lo = Infinity, hi = -Infinity;\r\n for (const v of samples) {\r\n if (v < lo) lo = v;\r\n if (v > hi) hi = v;\r\n }\r\n const span = Math.max(hi - lo, 1e-9);\r\n const last = samples[samples.length - 1];\r\n const up = last >= ref;\r\n const color = up ? '#1fa874' : '#e8505b';\r\n\r\n ctx.clearRect(0, 0, w, h);\r\n ctx.lineWidth = 1.4 * dpr;\r\n ctx.strokeStyle = color;\r\n ctx.beginPath();\r\n const step = w / (samples.length - 1);\r\n for (let i = 0; i < samples.length; i++) {\r\n const x = i * step;\r\n const y = h - ((samples[i] - lo) / span) * (h - 4) - 2;\r\n if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);\r\n }\r\n ctx.stroke();\r\n}\r\n","import type { KeyValueStorage } from './DrawingTemplateStore.js';\r\n\r\n/** One watchlist: a name and its symbols, in order. */\r\nexport interface WatchlistList {\r\n id: string;\r\n name: string;\r\n symbols: string[];\r\n}\r\n\r\nexport interface WatchlistStoreOptions {\r\n /** Lists to start with; when none, one list of `symbols`. */\r\n lists?: WatchlistList[];\r\n /** The list shown first, by id. */\r\n activeList?: string;\r\n symbols?: string[];\r\n /** The first list's name when the store makes it. */\r\n defaultName?: string;\r\n /** Where the lists are kept between visits; none keeps them in memory only. */\r\n storage?: KeyValueStorage | null;\r\n storageKey?: string;\r\n}\r\n\r\nconst MAX_LISTS = 50;\r\nconst MAX_SYMBOLS = 500;\r\nconst MAX_NAME = 60;\r\nconst MAX_SYMBOL = 64;\r\n\r\nconst cleanName = (v: unknown): string | null => {\r\n if (typeof v !== 'string') return null;\r\n const name = v.trim().slice(0, MAX_NAME);\r\n return name || null;\r\n};\r\n\r\nconst cleanSymbol = (v: unknown): string | null => {\r\n if (typeof v !== 'string') return null;\r\n const symbol = v.trim();\r\n return symbol && symbol.length <= MAX_SYMBOL ? symbol : null;\r\n};\r\n\r\nfunction cleanSymbols(raw: readonly unknown[]): string[] {\r\n const out: string[] = [];\r\n for (const v of raw) {\r\n const symbol = cleanSymbol(v);\r\n if (symbol && !out.includes(symbol)) out.push(symbol);\r\n if (out.length === MAX_SYMBOLS) break;\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Watchlists from untrusted input (storage, a host): lists need an id and a\r\n * name; repeated ids, symbols that aren't strings and repeats are dropped;\r\n * at most 50 lists of 500 symbols. The active id falls back to the first\r\n * list. Null when no list is left.\r\n */\r\nexport function readWatchlists(raw: unknown): { lists: WatchlistList[]; active: string } | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const r = raw as { lists?: unknown; active?: unknown };\r\n if (!Array.isArray(r.lists)) return null;\r\n const lists: WatchlistList[] = [];\r\n for (const item of r.lists) {\r\n if (lists.length === MAX_LISTS) break;\r\n if (!item || typeof item !== 'object') continue;\r\n const l = item as Record<string, unknown>;\r\n const id = typeof l.id === 'string' && l.id && l.id.length <= MAX_SYMBOL ? l.id : null;\r\n const name = cleanName(l.name);\r\n if (!id || !name || lists.some((x) => x.id === id)) continue;\r\n lists.push({ id, name, symbols: Array.isArray(l.symbols) ? cleanSymbols(l.symbols) : [] });\r\n }\r\n if (lists.length === 0) return null;\r\n const active = typeof r.active === 'string' && lists.some((l) => l.id === r.active) ? r.active : lists[0].id;\r\n return { lists, active };\r\n}\r\n\r\nconst copy = (list: WatchlistList): WatchlistList => ({ ...list, symbols: [...list.symbols] });\r\n\r\n/**\r\n * The widget's watchlists: which one is shown, and their symbols. Every\r\n * change is kept in storage (when it has one) and told to its listeners;\r\n * readers get copies.\r\n */\r\nexport class WatchlistStore {\r\n private lists: WatchlistList[];\r\n private active: string;\r\n private readonly listeners = new Set<() => void>();\r\n private readonly storage: KeyValueStorage | null;\r\n private readonly storageKey: string;\r\n\r\n constructor(options: WatchlistStoreOptions) {\r\n this.storage = options.storage ?? null;\r\n this.storageKey = options.storageKey ?? 'tcw:watchlists';\r\n const saved = this.load();\r\n const given = options.lists ? readWatchlists({ lists: options.lists, active: options.activeList }) : null;\r\n const start = saved ?? given ?? {\r\n lists: [{ id: 'default', name: cleanName(options.defaultName) ?? 'Watchlist', symbols: cleanSymbols(options.symbols ?? []) }],\r\n active: 'default',\r\n };\r\n this.lists = start.lists;\r\n this.active = start.active;\r\n }\r\n\r\n getLists(): WatchlistList[] {\r\n return this.lists.map(copy);\r\n }\r\n\r\n getActive(): WatchlistList {\r\n return copy(this.activeList());\r\n }\r\n\r\n setActive(id: string): void {\r\n if (id === this.active || !this.lists.some((l) => l.id === id)) return;\r\n this.active = id;\r\n this.changed();\r\n }\r\n\r\n /** Replace every list (untrusted input is read as `readWatchlists` does). */\r\n replace(lists: WatchlistList[], active?: string): void {\r\n const read = readWatchlists({ lists, active: active ?? this.active });\r\n if (!read) return;\r\n this.lists = read.lists;\r\n this.active = read.active;\r\n this.changed();\r\n }\r\n\r\n /** A new list, shown at once; null for a name it can't use or one list too many. */\r\n create(name: string): WatchlistList | null {\r\n const clean = cleanName(name);\r\n if (!clean || this.lists.length >= MAX_LISTS) return null;\r\n let n = this.lists.length + 1;\r\n while (this.lists.some((l) => l.id === `list-${n}`)) n++;\r\n const list = { id: `list-${n}`, name: clean, symbols: [] };\r\n this.lists = [...this.lists, list];\r\n this.active = list.id;\r\n this.changed();\r\n return copy(list);\r\n }\r\n\r\n rename(id: string, name: string): void {\r\n const clean = cleanName(name);\r\n if (!clean) return;\r\n this.update(id, (list) => ({ ...list, name: clean }));\r\n }\r\n\r\n /** Delete a list; the last one stays. */\r\n remove(id: string): void {\r\n if (this.lists.length <= 1 || !this.lists.some((l) => l.id === id)) return;\r\n this.lists = this.lists.filter((l) => l.id !== id);\r\n if (this.active === id) this.active = this.lists[0].id;\r\n this.changed();\r\n }\r\n\r\n /** Add a symbol to the end of a list (the shown one by default); false when it's there or unusable. */\r\n add(symbol: string, id = this.active): boolean {\r\n const clean = cleanSymbol(symbol);\r\n const list = this.lists.find((l) => l.id === id);\r\n if (!clean || !list || list.symbols.includes(clean) || list.symbols.length >= MAX_SYMBOLS) return false;\r\n this.update(id, (l) => ({ ...l, symbols: [...l.symbols, clean] }));\r\n return true;\r\n }\r\n\r\n removeSymbol(symbol: string, id = this.active): void {\r\n const list = this.lists.find((l) => l.id === id);\r\n if (!list?.symbols.includes(symbol)) return;\r\n this.update(id, (l) => ({ ...l, symbols: l.symbols.filter((s) => s !== symbol) }));\r\n }\r\n\r\n /** Move a symbol to `index` in its list. */\r\n move(symbol: string, index: number, id = this.active): void {\r\n const list = this.lists.find((l) => l.id === id);\r\n if (!list) return;\r\n const from = list.symbols.indexOf(symbol);\r\n if (from < 0) return;\r\n const rest = list.symbols.filter((s) => s !== symbol);\r\n const to = Math.max(0, Math.min(Math.round(index), rest.length));\r\n if (to === from) return;\r\n this.update(id, (l) => ({ ...l, symbols: [...rest.slice(0, to), symbol, ...rest.slice(to)] }));\r\n }\r\n\r\n /** Called after every change; returns a function that stops it. */\r\n subscribe(listener: () => void): () => void {\r\n this.listeners.add(listener);\r\n return () => this.listeners.delete(listener);\r\n }\r\n\r\n private activeList(): WatchlistList {\r\n return this.lists.find((l) => l.id === this.active) ?? this.lists[0];\r\n }\r\n\r\n private update(id: string, change: (list: WatchlistList) => WatchlistList): void {\r\n this.lists = this.lists.map((l) => (l.id === id ? change(l) : l));\r\n this.changed();\r\n }\r\n\r\n private changed(): void {\r\n this.save();\r\n for (const listener of this.listeners) listener();\r\n }\r\n\r\n private load(): { lists: WatchlistList[]; active: string } | null {\r\n if (!this.storage) return null;\r\n try {\r\n const raw = this.storage.getItem(this.storageKey);\r\n return raw ? readWatchlists(JSON.parse(raw)) : null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n private save(): void {\r\n if (!this.storage) return;\r\n try {\r\n this.storage.setItem(this.storageKey, JSON.stringify({ lists: this.lists, active: this.active }));\r\n } catch { /* storage full or unavailable: the lists stay in memory */ }\r\n }\r\n}\r\n","import { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\r\n\r\n/** What the symbol info panel shows, formatted by the widget. */\r\nexport interface SymbolInfoView {\r\n symbol: string;\r\n description?: string;\r\n /** Exchange, type, currency, joined. */\r\n meta?: string;\r\n price?: string;\r\n change?: { text: string; up: boolean };\r\n status: { state: 'open' | 'closed' | 'always'; text: string };\r\n stats: { label: string; value: string }[];\r\n}\r\n\r\nexport interface SymbolInfoNewsItem {\r\n title: string;\r\n url?: string;\r\n /** Source and age, joined. */\r\n meta: string;\r\n}\r\n\r\n/** The news part: no source, loading, failed, or the headlines (maybe none). */\r\nexport type SymbolInfoNews =\r\n | { kind: 'none' }\r\n | { kind: 'loading' }\r\n | { kind: 'failed' }\r\n | { kind: 'items'; items: SymbolInfoNewsItem[] };\r\n\r\nexport interface SymbolInfoCallbacks {\r\n /** After it opens or closes. */\r\n onToggle?: (open: boolean) => void;\r\n}\r\n\r\n/**\r\n * Symbol info — a floating panel with the symbol's names, price and move,\r\n * market status, the day's numbers, its hours, and news. It only renders:\r\n * the widget builds what it shows.\r\n */\r\nexport class WidgetSymbolInfo {\r\n private el: HTMLDivElement;\r\n private bodyEl: HTMLDivElement;\r\n private newsEl: HTMLDivElement;\r\n private shown = false;\r\n\r\n constructor(\r\n host: HTMLElement,\r\n private readonly t: Translator = EN_TRANSLATOR,\r\n private readonly callbacks: SymbolInfoCallbacks = {},\r\n ) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-syminfo';\r\n this.el.setAttribute('role', 'dialog');\r\n this.el.setAttribute('aria-label', t('symbolInfo.title'));\r\n this.el.hidden = true;\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-syminfo-header';\r\n const title = document.createElement('span');\r\n title.textContent = t('symbolInfo.title');\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-syminfo-close';\r\n closeBtn.setAttribute('aria-label', t('common.close'));\r\n closeBtn.innerHTML = createIcon('x', 14);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.append(title, closeBtn);\r\n\r\n this.bodyEl = document.createElement('div');\r\n this.bodyEl.className = 'tcw-syminfo-body';\r\n\r\n this.newsEl = document.createElement('div');\r\n this.newsEl.className = 'tcw-syminfo-news';\r\n this.newsEl.hidden = true;\r\n\r\n this.el.append(header, this.bodyEl, this.newsEl);\r\n host.appendChild(this.el);\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.shown;\r\n }\r\n\r\n toggle(): void {\r\n if (this.shown) this.close();\r\n else this.open();\r\n }\r\n\r\n open(): void {\r\n if (this.shown) return;\r\n this.shown = true;\r\n this.el.hidden = false;\r\n this.callbacks.onToggle?.(true);\r\n }\r\n\r\n close(): void {\r\n if (!this.shown) return;\r\n this.shown = false;\r\n this.el.hidden = true;\r\n this.callbacks.onToggle?.(false);\r\n }\r\n\r\n render(view: SymbolInfoView): void {\r\n const head = document.createElement('div');\r\n head.className = 'tcw-syminfo-head';\r\n head.append(text('div', 'tcw-syminfo-symbol', view.symbol));\r\n if (view.description) head.append(text('div', 'tcw-syminfo-desc', view.description));\r\n if (view.meta) head.append(text('div', 'tcw-syminfo-meta', view.meta));\r\n\r\n const quote = document.createElement('div');\r\n quote.className = 'tcw-syminfo-quote';\r\n if (view.price) quote.append(text('span', 'tcw-syminfo-price', view.price));\r\n if (view.change) {\r\n const change = text('span', 'tcw-syminfo-change', view.change.text);\r\n change.classList.add(view.change.up ? 'tcw-up' : 'tcw-down');\r\n quote.append(change);\r\n }\r\n\r\n const status = text('div', 'tcw-syminfo-status', view.status.text);\r\n status.dataset.state = view.status.state;\r\n\r\n const stats = document.createElement('dl');\r\n stats.className = 'tcw-syminfo-stats';\r\n for (const stat of view.stats) {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-syminfo-stat';\r\n row.append(text('dt', '', stat.label), text('dd', '', stat.value));\r\n stats.append(row);\r\n }\r\n\r\n this.bodyEl.replaceChildren(head, quote, status, stats);\r\n }\r\n\r\n renderNews(news: SymbolInfoNews): void {\r\n this.newsEl.hidden = news.kind === 'none';\r\n if (news.kind === 'none') {\r\n this.newsEl.replaceChildren();\r\n return;\r\n }\r\n const title = text('div', 'tcw-syminfo-news-title', this.t('symbolInfo.news'));\r\n if (news.kind === 'loading' || news.kind === 'failed' || news.items.length === 0) {\r\n const note = news.kind === 'loading' ? 'symbolInfo.loading' : news.kind === 'failed' ? 'symbolInfo.newsFailed' : 'symbolInfo.noNews';\r\n // The heading stays out of a lone note's text, for screen readers' sake too.\r\n this.newsEl.replaceChildren(text('div', 'tcw-syminfo-news-note', this.t(note)));\r\n return;\r\n }\r\n const list = document.createElement('ul');\r\n list.className = 'tcw-syminfo-news-list';\r\n for (const item of news.items) {\r\n const li = document.createElement('li');\r\n li.className = 'tcw-syminfo-news-item';\r\n if (item.url) {\r\n const link = document.createElement('a');\r\n link.href = item.url;\r\n link.target = '_blank';\r\n link.rel = 'noopener noreferrer';\r\n link.textContent = item.title;\r\n li.append(link);\r\n } else {\r\n li.append(text('span', '', item.title));\r\n }\r\n if (item.meta) li.append(text('div', 'tcw-syminfo-news-meta', item.meta));\r\n list.append(li);\r\n }\r\n this.newsEl.replaceChildren(title, list);\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n}\r\n\r\nfunction text<K extends keyof HTMLElementTagNameMap>(tag: K, className: string, content: string): HTMLElementTagNameMap[K] {\r\n const el = document.createElement(tag);\r\n if (className) el.className = className;\r\n el.textContent = content;\r\n return el;\r\n}\r\n","import { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\r\n\r\nexport interface ChartNavActions {\r\n zoomIn: () => void;\r\n zoomOut: () => void;\r\n /** Scroll a step toward later (1) or earlier (-1) bars. */\r\n scroll: (direction: 1 | -1) => void;\r\n /** Back to the whole chart, scaled to fit. */\r\n reset: () => void;\r\n /** The plot area in the host, where the buttons sit (centred on its bottom). */\r\n plotRect: () => { x: number; y: number; width: number; height: number };\r\n}\r\n\r\n/** A held scroll button repeats after this, every REPEAT_MS. */\r\nconst HOLD_MS = 300;\r\nconst REPEAT_MS = 80;\r\n\r\n/**\r\n * Navigation over the chart: zoom out and in, scroll earlier and later\r\n * (held, it keeps going), reset. It shows while a mouse or pen is over the\r\n * chart; touch has its own gestures.\r\n */\r\nexport class WidgetChartNav {\r\n private el: HTMLDivElement;\r\n private holdTimer: ReturnType<typeof setTimeout> | null = null;\r\n private repeatTimer: ReturnType<typeof setInterval> | null = null;\r\n private readonly onMove = (e: PointerEvent) => {\r\n if (e.pointerType === 'touch') return;\r\n if (!this.el.classList.contains('tcw-nav-shown')) this.place();\r\n this.el.classList.add('tcw-nav-shown');\r\n };\r\n private readonly onLeave = () => {\r\n this.el.classList.remove('tcw-nav-shown');\r\n this.stopHold();\r\n };\r\n\r\n constructor(\r\n private readonly host: HTMLElement,\r\n private readonly actions: ChartNavActions,\r\n t: Translator = EN_TRANSLATOR,\r\n ) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-nav';\r\n this.el.setAttribute('role', 'toolbar');\r\n this.el.setAttribute('aria-label', t('nav.label'));\r\n\r\n const buttons: [string, string, string][] = [\r\n ['zoomOut', 'minus', t('nav.zoomOut')],\r\n ['zoomIn', 'plus', t('nav.zoomIn')],\r\n ['scrollLeft', 'chevronLeft', t('nav.scrollLeft')],\r\n ['scrollRight', 'chevronRight', t('nav.scrollRight')],\r\n ['reset', 'reset', t('nav.reset')],\r\n ];\r\n for (const [action, icon, label] of buttons) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-nav-btn';\r\n btn.dataset.nav = action;\r\n btn.title = label;\r\n btn.setAttribute('aria-label', label);\r\n btn.innerHTML = createIcon(icon, 16);\r\n if (action === 'scrollLeft' || action === 'scrollRight') {\r\n const direction = action === 'scrollRight' ? 1 : -1;\r\n btn.addEventListener('pointerdown', (e) => {\r\n if (e.button !== 0) return;\r\n e.preventDefault();\r\n // A release elsewhere (or a lost window) still ends the hold.\r\n try { btn.setPointerCapture(e.pointerId); } catch { /* an unknown pointer */ }\r\n this.startHold(direction);\r\n });\r\n for (const end of ['pointerup', 'pointercancel', 'pointerleave'] as const) btn.addEventListener(end, () => this.stopHold());\r\n // A keyboard press scrolls one step.\r\n btn.addEventListener('click', (e) => {\r\n if (e.detail === 0) actions.scroll(direction);\r\n });\r\n } else {\r\n btn.addEventListener('click', () => {\r\n if (action === 'zoomIn') actions.zoomIn();\r\n else if (action === 'zoomOut') actions.zoomOut();\r\n else actions.reset();\r\n });\r\n }\r\n this.el.appendChild(btn);\r\n }\r\n\r\n // A double-click or a right-click on the buttons isn't the chart's (a drawing under them).\r\n for (const type of ['dblclick', 'contextmenu', 'pointerdown', 'mousedown'] as const) {\r\n this.el.addEventListener(type, (e) => e.stopPropagation());\r\n }\r\n\r\n // Shown with the keyboard too, while a button has focus.\r\n this.el.addEventListener('focusin', () => {\r\n this.place();\r\n this.el.classList.add('tcw-nav-shown');\r\n });\r\n this.el.addEventListener('focusout', (e) => {\r\n if (!this.el.contains(e.relatedTarget as Node | null)) this.el.classList.remove('tcw-nav-shown');\r\n });\r\n\r\n host.appendChild(this.el);\r\n host.addEventListener('pointermove', this.onMove);\r\n host.addEventListener('pointerleave', this.onLeave);\r\n }\r\n\r\n destroy(): void {\r\n this.stopHold();\r\n this.host.removeEventListener('pointermove', this.onMove);\r\n this.host.removeEventListener('pointerleave', this.onLeave);\r\n this.el.remove();\r\n }\r\n\r\n private place(): void {\r\n const r = this.actions.plotRect();\r\n this.el.style.left = `${Math.round(r.x + r.width / 2)}px`;\r\n this.el.style.top = `${Math.round(r.y + r.height)}px`;\r\n }\r\n\r\n private startHold(direction: 1 | -1): void {\r\n this.stopHold();\r\n this.actions.scroll(direction);\r\n this.holdTimer = setTimeout(() => {\r\n this.repeatTimer = setInterval(() => this.actions.scroll(direction), REPEAT_MS);\r\n }, HOLD_MS);\r\n }\r\n\r\n private stopHold(): void {\r\n if (this.holdTimer) clearTimeout(this.holdTimer);\r\n if (this.repeatTimer) clearInterval(this.repeatTimer);\r\n this.holdTimer = null;\r\n this.repeatTimer = null;\r\n }\r\n}\r\n","import { MAX_ALERT_BARS, MIN_ALERT_BARS, type AlertCondition, type AlertOptions } from '@tradecanvas/core';\r\nimport { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, fill, type MessageKey, type Translator } from './i18n.js';\r\nimport { escapeHtml } from './escapeHtml.js';\r\n\r\nexport interface AlertListItem {\r\n id: string;\r\n price: number;\r\n condition: string;\r\n message?: string;\r\n triggered: boolean;\r\n channel?: string;\r\n label?: string;\r\n /** Set for an alert on a drawing: its price follows the drawing's line. */\r\n drawingId?: string;\r\n /** Another line it compares with, and its name. */\r\n target?: string;\r\n targetLabel?: string;\r\n percent?: number;\r\n bars?: number;\r\n onBarClose?: boolean;\r\n expiresAt?: number;\r\n expired?: boolean;\r\n}\r\n\r\n/** What the form asks for. */\r\nexport interface AlertSpec {\r\n /** The level (NaN when comparing with a line or measuring a move). */\r\n price: number;\r\n condition: AlertCondition;\r\n message: string | undefined;\r\n channel: string;\r\n label: string;\r\n options: AlertOptions;\r\n}\r\n\r\nexport interface AlertSource {\r\n /** `'price'` or `<instanceId>:<key>`. */\r\n channel: string;\r\n label: string;\r\n}\r\n\r\nexport interface AlertsPanelCallbacks {\r\n /** Add the alert; false when the chart turned it down (the form stays as it is). */\r\n onAdd: (spec: AlertSpec) => boolean | void;\r\n onRemove: (id: string) => void;\r\n onClear: () => void;\r\n /** Latest value for a source channel, used to prefill the add form. */\r\n getChannelValue: (channel: string) => number | null;\r\n formatPrice: (price: number) => string;\r\n /** A time, for \"until …\". */\r\n formatTime?: (ms: number) => string;\r\n /** Now, in ms (an expiry is counted from it). */\r\n now?: () => number;\r\n}\r\n\r\n/**\r\n * What an alert watches, in words: \"RSI crossing 70\", \"Price crossing EMA 20\",\r\n * \"Price up 5% within 10 bars\". `named` names the price too (\"Price crossing\r\n * 105\"), for words read away from the list (a toast, a notification).\r\n */\r\nexport function describeAlert(alert: AlertListItem, t: Translator, formatPrice: (price: number) => string, named = false): string {\r\n const source = alert.label ?? t('alerts.source.price');\r\n const conditionKey = CONDITION_KEY.get(alert.condition as AlertCondition);\r\n const condition = conditionKey ? t(conditionKey) : alert.condition;\r\n if (MOVES.includes(alert.condition)) {\r\n return `${source} ${condition} ${fill(t('alerts.moveSummary'), { percent: alert.percent ?? 0, bars: alert.bars ?? 0 })}`;\r\n }\r\n if (alert.target) return `${source} ${condition} ${alert.targetLabel ?? alert.target}`;\r\n const isIndicator = alert.channel && alert.channel !== 'price';\r\n const valueStr = !Number.isFinite(alert.price) ? '—'\r\n : isIndicator ? formatPlain(alert.price) : formatPrice(alert.price);\r\n const prefix = (isIndicator || alert.drawingId) && alert.label ? `${alert.label} ` : named ? `${source} ` : '';\r\n return `${prefix}${condition} ${valueStr}`;\r\n}\r\n\r\nconst CONDITION_OPTIONS: { value: AlertCondition; key: MessageKey }[] = [\r\n { value: 'crossing', key: 'alerts.condition.crossing' },\r\n { value: 'crossingUp', key: 'alerts.condition.crossingUp' },\r\n { value: 'crossingDown', key: 'alerts.condition.crossingDown' },\r\n { value: 'greaterThan', key: 'alerts.condition.greaterThan' },\r\n { value: 'lessThan', key: 'alerts.condition.lessThan' },\r\n { value: 'movesUp', key: 'alerts.condition.movesUp' },\r\n { value: 'movesDown', key: 'alerts.condition.movesDown' },\r\n];\r\n\r\nconst MOVES: readonly string[] = ['movesUp', 'movesDown'];\r\n\r\n/** How long an alert lasts, from the form's choice. */\r\nconst EXPIRY_MS: Readonly<Record<string, number>> = {\r\n hour: 3_600_000,\r\n day: 86_400_000,\r\n week: 7 * 86_400_000,\r\n month: 30 * 86_400_000,\r\n};\r\n\r\n/** The value the \"compared with\" choice has when it is a level, not a line. */\r\nconst VALUE = '';\r\n\r\nconst CONDITION_KEY = new Map(CONDITION_OPTIONS.map((o) => [o.value, o.key]));\r\n\r\nfunction roundForInput(v: number): number {\r\n return Math.round(v * 1e6) / 1e6;\r\n}\r\n\r\nfunction formatPlain(v: number): string {\r\n const abs = Math.abs(v);\r\n return abs >= 1000 ? v.toFixed(2) : abs >= 1 ? v.toFixed(2) : v.toPrecision(4);\r\n}\r\n\r\n/**\r\n * Floating price-alerts panel. Lists current alerts (with condition, price,\r\n * message, and a delete control) and an inline form to add a new one prefilled\r\n * with the current price. Toggled from the toolbar bell button; the host wires\r\n * add/remove back to the chart's `AlertManager`.\r\n */\r\nexport class WidgetAlertsPanel {\r\n private el: HTMLDivElement;\r\n private listEl: HTMLDivElement;\r\n private priceInput: HTMLInputElement;\r\n private conditionSelect: HTMLSelectElement;\r\n private sourceSelect: HTMLSelectElement;\r\n private targetSelect: HTMLSelectElement;\r\n private percentInput: HTMLInputElement;\r\n private barsInput: HTMLInputElement;\r\n private levelRow: HTMLDivElement;\r\n private moveRow: HTMLDivElement;\r\n private closeCheck: HTMLInputElement;\r\n private expirySelect: HTMLSelectElement;\r\n private messageInput: HTMLInputElement;\r\n private emptyEl: HTMLDivElement;\r\n private callbacks: AlertsPanelCallbacks;\r\n private open = false;\r\n private alerts: AlertListItem[] = [];\r\n private sources: AlertSource[];\r\n\r\n constructor(host: HTMLElement, callbacks: AlertsPanelCallbacks, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.callbacks = callbacks;\r\n this.sources = [{ channel: 'price', label: this.t('alerts.source.price') }];\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-alerts-panel';\r\n this.el.hidden = true;\r\n\r\n // Header\r\n const header = document.createElement('div');\r\n header.className = 'tcw-alerts-header';\r\n const title = document.createElement('span');\r\n title.textContent = this.t('alerts.title');\r\n const closeBtn = document.createElement('button');\r\n closeBtn.className = 'tcw-alerts-close';\r\n closeBtn.type = 'button';\r\n closeBtn.setAttribute('aria-label', this.t('alerts.close'));\r\n closeBtn.innerHTML = createIcon('x', 14);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.appendChild(title);\r\n header.appendChild(closeBtn);\r\n this.el.appendChild(header);\r\n\r\n // Add form\r\n const form = document.createElement('form');\r\n form.className = 'tcw-alerts-form';\r\n // The panel checks the fields itself (and marks the one that's wrong).\r\n form.noValidate = true;\r\n\r\n this.sourceSelect = document.createElement('select');\r\n this.sourceSelect.className = 'tcw-alerts-source';\r\n this.sourceSelect.setAttribute('aria-label', this.t('alerts.source'));\r\n this.sourceSelect.addEventListener('change', () => {\r\n this.renderTargets();\r\n this.prefillPrice();\r\n });\r\n\r\n this.conditionSelect = document.createElement('select');\r\n this.conditionSelect.className = 'tcw-alerts-condition';\r\n this.conditionSelect.setAttribute('aria-label', this.t('alerts.conditionLabel'));\r\n for (const opt of CONDITION_OPTIONS) {\r\n const o = document.createElement('option');\r\n o.value = opt.value;\r\n o.textContent = this.t(opt.key);\r\n this.conditionSelect.appendChild(o);\r\n }\r\n this.conditionSelect.addEventListener('change', () => this.showFields());\r\n\r\n // A level, or another line to compare with.\r\n this.levelRow = document.createElement('div');\r\n this.levelRow.className = 'tcw-alerts-row-fields';\r\n this.targetSelect = document.createElement('select');\r\n this.targetSelect.className = 'tcw-alerts-target';\r\n this.targetSelect.setAttribute('aria-label', this.t('alerts.compareWith'));\r\n this.targetSelect.addEventListener('change', () => this.showFields());\r\n this.priceInput = document.createElement('input');\r\n this.priceInput.type = 'number';\r\n this.priceInput.step = 'any';\r\n this.priceInput.placeholder = this.t('alerts.value');\r\n this.priceInput.setAttribute('aria-label', this.t('alerts.value'));\r\n this.priceInput.className = 'tcw-alerts-price';\r\n this.levelRow.append(this.targetSelect, this.priceInput);\r\n\r\n // A move: percent within bars.\r\n this.moveRow = document.createElement('div');\r\n this.moveRow.className = 'tcw-alerts-row-fields';\r\n this.percentInput = this.numberField('tcw-alerts-percent', this.t('alerts.percent'), '1', '0.01');\r\n this.barsInput = this.numberField('tcw-alerts-bars', this.t('alerts.bars'), '10', '1');\r\n this.barsInput.min = String(MIN_ALERT_BARS);\r\n this.barsInput.max = String(MAX_ALERT_BARS);\r\n this.moveRow.append(this.percentInput, this.barsInput);\r\n\r\n // On bar close; an end.\r\n const optionsRow = document.createElement('div');\r\n optionsRow.className = 'tcw-alerts-row-fields tcw-alerts-options';\r\n const closeLabel = document.createElement('label');\r\n closeLabel.className = 'tcw-alerts-check';\r\n this.closeCheck = document.createElement('input');\r\n this.closeCheck.type = 'checkbox';\r\n closeLabel.append(this.closeCheck, document.createTextNode(this.t('alerts.onBarClose')));\r\n this.expirySelect = document.createElement('select');\r\n this.expirySelect.className = 'tcw-alerts-expiry';\r\n this.expirySelect.setAttribute('aria-label', this.t('alerts.expires'));\r\n for (const value of ['never', 'hour', 'day', 'week', 'month']) {\r\n const o = document.createElement('option');\r\n o.value = value;\r\n o.textContent = this.t(`alerts.expires.${value}` as MessageKey);\r\n this.expirySelect.appendChild(o);\r\n }\r\n optionsRow.append(closeLabel, this.expirySelect);\r\n\r\n this.messageInput = document.createElement('input');\r\n this.messageInput.type = 'text';\r\n this.messageInput.placeholder = this.t('alerts.note');\r\n this.messageInput.setAttribute('aria-label', this.t('alerts.note'));\r\n this.messageInput.className = 'tcw-alerts-message';\r\n\r\n const addBtn = document.createElement('button');\r\n addBtn.type = 'submit';\r\n addBtn.className = 'tcw-alerts-add';\r\n addBtn.innerHTML = `${createIcon('plus', 14)}<span>${escapeHtml(this.t('alerts.add'))}</span>`;\r\n\r\n form.append(this.sourceSelect, this.conditionSelect, this.levelRow, this.moveRow, optionsRow, this.messageInput, addBtn);\r\n form.addEventListener('submit', (e) => {\r\n e.preventDefault();\r\n this.submitForm();\r\n });\r\n this.el.appendChild(form);\r\n\r\n // List\r\n this.listEl = document.createElement('div');\r\n this.listEl.className = 'tcw-alerts-list';\r\n this.el.appendChild(this.listEl);\r\n\r\n this.emptyEl = document.createElement('div');\r\n this.emptyEl.className = 'tcw-alerts-empty';\r\n this.emptyEl.textContent = this.t('alerts.empty');\r\n this.listEl.appendChild(this.emptyEl);\r\n\r\n this.renderSources();\r\n this.showFields();\r\n host.appendChild(this.el);\r\n }\r\n\r\n private numberField(className: string, label: string, value: string, step: string): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.type = 'number';\r\n input.step = step;\r\n input.min = '0';\r\n input.value = value;\r\n input.className = className;\r\n input.placeholder = label;\r\n input.setAttribute('aria-label', label);\r\n return input;\r\n }\r\n\r\n /** A move asks for percent and bars; a level for a value or another line. */\r\n private showFields(): void {\r\n const move = MOVES.includes(this.conditionSelect.value);\r\n this.moveRow.hidden = !move;\r\n this.levelRow.hidden = move;\r\n this.priceInput.hidden = this.targetSelect.value !== VALUE;\r\n }\r\n\r\n /** \"Compared with\": a value, or any line but the one watched. */\r\n private renderTargets(): void {\r\n const current = this.targetSelect.value;\r\n const watched = this.sourceSelect.value || 'price';\r\n this.targetSelect.replaceChildren();\r\n const value = document.createElement('option');\r\n value.value = VALUE;\r\n value.textContent = this.t('alerts.compare.value');\r\n this.targetSelect.appendChild(value);\r\n for (const src of this.sources) {\r\n if (src.channel === watched) continue;\r\n const o = document.createElement('option');\r\n o.value = src.channel;\r\n o.textContent = src.label;\r\n this.targetSelect.appendChild(o);\r\n }\r\n this.targetSelect.value = [...this.targetSelect.options].some((o) => o.value === current) ? current : VALUE;\r\n this.showFields();\r\n }\r\n\r\n /** Replace the alert-source options (price + indicator lines). */\r\n setSources(sources: AlertSource[]): void {\r\n this.sources = sources.length > 0 ? sources : [{ channel: 'price', label: this.t('alerts.source.price') }];\r\n this.renderSources();\r\n }\r\n\r\n private renderSources(): void {\r\n const current = this.sourceSelect.value || 'price';\r\n this.sourceSelect.replaceChildren();\r\n for (const src of this.sources) {\r\n const o = document.createElement('option');\r\n o.value = src.channel;\r\n o.textContent = src.label;\r\n this.sourceSelect.appendChild(o);\r\n }\r\n // Keep the prior selection if it still exists, else default to price.\r\n this.sourceSelect.value = this.sources.some((s) => s.channel === current) ? current : 'price';\r\n this.renderTargets();\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.open;\r\n }\r\n\r\n toggle(): void {\r\n this.open ? this.close() : this.openPanel();\r\n }\r\n\r\n openPanel(): void {\r\n this.open = true;\r\n this.el.hidden = false;\r\n if (this.priceInput.value === '') this.prefillPrice();\r\n }\r\n\r\n /** Fill the value input with the selected source's current value. */\r\n private prefillPrice(): void {\r\n const v = this.callbacks.getChannelValue(this.sourceSelect.value || 'price');\r\n this.priceInput.value = v !== null ? String(roundForInput(v)) : '';\r\n }\r\n\r\n close(): void {\r\n this.open = false;\r\n this.el.hidden = true;\r\n }\r\n\r\n /** Replace the displayed alert list. */\r\n setAlerts(alerts: AlertListItem[]): void {\r\n this.alerts = alerts;\r\n this.renderList();\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n private submitForm(): void {\r\n const condition = this.conditionSelect.value as AlertCondition;\r\n const message = this.messageInput.value.trim() || undefined;\r\n const channel = this.sourceSelect.value || 'price';\r\n const label = this.sources.find((s) => s.channel === channel)?.label ?? this.t('alerts.source.price');\r\n const options: AlertOptions = {};\r\n let price = Number.NaN;\r\n if (MOVES.includes(condition)) {\r\n options.percent = Number(this.percentInput.value);\r\n options.bars = Number(this.barsInput.value);\r\n const barsOk = Number.isInteger(options.bars) && options.bars >= MIN_ALERT_BARS && options.bars <= MAX_ALERT_BARS;\r\n if (!(options.percent > 0) || !barsOk) {\r\n this.markInvalid(!(options.percent > 0) ? this.percentInput : this.barsInput);\r\n return;\r\n }\r\n } else if (this.targetSelect.value !== VALUE) {\r\n options.target = this.targetSelect.value;\r\n } else {\r\n price = Number(this.priceInput.value);\r\n if (this.priceInput.value.trim() === '' || !Number.isFinite(price)) {\r\n this.markInvalid(this.priceInput);\r\n return;\r\n }\r\n }\r\n if (this.closeCheck.checked) options.onBarClose = true;\r\n const span = EXPIRY_MS[this.expirySelect.value];\r\n if (span) options.expiresAt = (this.callbacks.now ?? Date.now)() + span;\r\n if (this.callbacks.onAdd({ price, condition, message, channel, label, options }) === false) return;\r\n this.messageInput.value = '';\r\n this.prefillPrice();\r\n }\r\n\r\n private markInvalid(input: HTMLInputElement): void {\r\n input.setAttribute('aria-invalid', 'true');\r\n input.focus();\r\n input.addEventListener('input', () => input.removeAttribute('aria-invalid'), { once: true });\r\n }\r\n\r\n private describe(alert: AlertListItem): string {\r\n return describeAlert(alert, this.t, this.callbacks.formatPrice);\r\n }\r\n\r\n private renderList(): void {\r\n // Clear rows but keep the empty placeholder reference.\r\n this.listEl.replaceChildren();\r\n\r\n if (this.alerts.length === 0) {\r\n this.listEl.appendChild(this.emptyEl);\r\n return;\r\n }\r\n\r\n // Show most recent first.\r\n for (const alert of [...this.alerts].reverse()) {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-alerts-row' + (alert.triggered ? ' tcw-alerts-triggered' : '') + (alert.expired ? ' tcw-alerts-expired' : '');\r\n\r\n const info = document.createElement('div');\r\n info.className = 'tcw-alerts-info';\r\n const main = document.createElement('div');\r\n main.className = 'tcw-alerts-row-main';\r\n main.textContent = this.describe(alert);\r\n info.appendChild(main);\r\n // On bar close, until when.\r\n const notes: string[] = [];\r\n if (alert.onBarClose) notes.push(this.t('alerts.onClose'));\r\n if (alert.expiresAt !== undefined && !alert.expired) {\r\n const when = this.callbacks.formatTime?.(alert.expiresAt) ?? new Date(alert.expiresAt).toISOString();\r\n notes.push(fill(this.t('alerts.until'), { time: when }));\r\n }\r\n if (notes.length > 0) {\r\n const meta = document.createElement('div');\r\n meta.className = 'tcw-alerts-row-meta';\r\n meta.textContent = notes.join(' · ');\r\n info.appendChild(meta);\r\n }\r\n if (alert.message) {\r\n const note = document.createElement('div');\r\n note.className = 'tcw-alerts-row-note';\r\n note.textContent = alert.message;\r\n info.appendChild(note);\r\n }\r\n if (alert.triggered || alert.expired) {\r\n const badge = document.createElement('span');\r\n badge.className = 'tcw-alerts-badge';\r\n badge.textContent = this.t(alert.expired ? 'alerts.expired' : 'alerts.triggered');\r\n main.appendChild(badge);\r\n }\r\n\r\n const del = document.createElement('button');\r\n del.type = 'button';\r\n del.className = 'tcw-alerts-del';\r\n del.setAttribute('aria-label', this.t('alerts.delete'));\r\n del.innerHTML = createIcon('trash', 14);\r\n del.addEventListener('click', () => this.callbacks.onRemove(alert.id));\r\n\r\n row.appendChild(info);\r\n row.appendChild(del);\r\n this.listEl.appendChild(row);\r\n }\r\n }\r\n}\r\n","/**\r\n * The widget's look: corners, sizes, type, lines, shadows and the shape of\r\n * its bars, as tokens. A preset gives all of them; a theme of yours changes\r\n * what it names. Colours stay with the widget's dark / light theme.\r\n */\r\n\r\nexport type WidgetUIPreset = 'studio' | 'terminal' | 'capsule';\r\n\r\n/** Corners, in px (999 makes a pill). */\r\nexport interface WidgetUIRadius {\r\n xs: number;\r\n sm: number;\r\n md: number;\r\n lg: number;\r\n xl: number;\r\n}\r\n\r\n/** Each part's corners, in px; unset parts follow the scale. */\r\nexport interface WidgetUIComponentRadius {\r\n /** Buttons and toggles in bars. */\r\n control: number;\r\n /** Text fields and selects. */\r\n input: number;\r\n /** Menus and dropdowns. */\r\n menu: number;\r\n /** Dialogs. */\r\n dialog: number;\r\n /** Floating panels (alerts, data window, order ticket). */\r\n panel: number;\r\n tooltip: number;\r\n /** Price tags and chips. */\r\n tag: number;\r\n toast: number;\r\n /** The toolbar's own box (a floating toolbar is an island). */\r\n toolbar: number;\r\n /** The drawing tools' own box. */\r\n sidebar: number;\r\n}\r\n\r\n/** Sizes, in px. */\r\nexport interface WidgetUISizes {\r\n toolbar: number;\r\n control: number;\r\n controlSmall: number;\r\n icon: number;\r\n sidebar: number;\r\n menuItem: number;\r\n}\r\n\r\nexport interface WidgetUIFont {\r\n /** A CSS font-family list. The widget loads no fonts: load the ones you name. */\r\n family: string;\r\n /** For prices and numbers. */\r\n mono: string;\r\n /** Body size, px; the small sizes follow it. */\r\n size: number;\r\n weight: number;\r\n strongWeight: number;\r\n /** Small labels (section titles, field names): as written or in capitals. */\r\n labelCase: 'none' | 'uppercase';\r\n /** Their letter spacing, in em. */\r\n labelTracking: number;\r\n}\r\n\r\nexport interface WidgetUIShadows {\r\n menu: string;\r\n dialog: string;\r\n tooltip: string;\r\n}\r\n\r\n/** The whole look, every token set. */\r\nexport interface ResolvedWidgetUI {\r\n preset: WidgetUIPreset;\r\n radius: WidgetUIRadius;\r\n components: WidgetUIComponentRadius;\r\n sizes: WidgetUISizes;\r\n font: WidgetUIFont;\r\n borders: { width: number; separators: boolean };\r\n shadows: WidgetUIShadows;\r\n /** Frosted floating surfaces: blur behind them, px (0: solid). */\r\n blur: number;\r\n /** How a chosen button shows: a tinted fill, a solid pill, or an underline. */\r\n active: 'tint' | 'solid' | 'underline';\r\n /** The toolbar along the top edge, or floating as an island. */\r\n toolbar: 'docked' | 'floating';\r\n /** The drawing tools along the left edge, or floating. */\r\n sidebar: 'docked' | 'floating';\r\n /** The interval buttons as they are, or in a segmented track. */\r\n intervals: 'plain' | 'segmented';\r\n /** Corners of the price tags and pills the chart draws (999: pills). */\r\n tagRadius: number;\r\n}\r\n\r\n/** Your look: a preset to start from (Studio by default) and what to change. */\r\nexport interface WidgetUITheme {\r\n preset?: WidgetUIPreset;\r\n radius?: Partial<WidgetUIRadius>;\r\n components?: Partial<WidgetUIComponentRadius>;\r\n /** Control sizes at once: compact, comfortable (the preset's) or spacious; `sizes` win over it. */\r\n density?: 'compact' | 'comfortable' | 'spacious';\r\n sizes?: Partial<WidgetUISizes>;\r\n font?: Partial<WidgetUIFont>;\r\n borders?: Partial<ResolvedWidgetUI['borders']>;\r\n shadows?: Partial<WidgetUIShadows>;\r\n blur?: number;\r\n active?: ResolvedWidgetUI['active'];\r\n toolbar?: ResolvedWidgetUI['toolbar'];\r\n sidebar?: ResolvedWidgetUI['sidebar'];\r\n intervals?: ResolvedWidgetUI['intervals'];\r\n tagRadius?: number;\r\n}\r\n\r\nconst SYSTEM_SANS = \"system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif\";\r\nconst MONO = \"'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', ui-monospace, monospace\";\r\n\r\ntype PresetBase = Omit<ResolvedWidgetUI, 'components' | 'preset'> & { components: Partial<WidgetUIComponentRadius> };\r\n\r\nconst PRESETS: Record<WidgetUIPreset, PresetBase> = {\r\n studio: {\r\n radius: { xs: 3, sm: 5, md: 7, lg: 11, xl: 16 },\r\n components: { toolbar: 0, sidebar: 0 },\r\n sizes: { toolbar: 46, control: 30, controlSmall: 24, icon: 18, sidebar: 48, menuItem: 30 },\r\n font: { family: `'Manrope', 'Inter', ${SYSTEM_SANS}`, mono: MONO, size: 13, weight: 500, strongWeight: 600, labelCase: 'none', labelTracking: 0 },\r\n borders: { width: 1, separators: false },\r\n // Shadows from the theme's tokens, so they suit dark and light alike.\r\n shadows: { menu: 'var(--tcw-shadow-lg)', dialog: 'var(--tcw-shadow-xl)', tooltip: 'var(--tcw-shadow-md)' },\r\n blur: 0,\r\n active: 'tint',\r\n toolbar: 'docked',\r\n sidebar: 'docked',\r\n intervals: 'segmented',\r\n tagRadius: 4,\r\n },\r\n terminal: {\r\n radius: { xs: 1, sm: 2, md: 2, lg: 2, xl: 3 },\r\n components: { tag: 0, toolbar: 0, sidebar: 0 },\r\n sizes: { toolbar: 36, control: 26, controlSmall: 20, icon: 16, sidebar: 40, menuItem: 26 },\r\n font: {\r\n family: `'IBM Plex Sans Condensed', 'Roboto Condensed', 'Arial Narrow', ${SYSTEM_SANS}`,\r\n mono: \"'IBM Plex Mono', ui-monospace, monospace\",\r\n size: 12, weight: 500, strongWeight: 600, labelCase: 'uppercase', labelTracking: 0.08,\r\n },\r\n borders: { width: 1, separators: true },\r\n shadows: {\r\n menu: '0 0 0 1px var(--tcw-border-strong)',\r\n dialog: '0 0 0 1px var(--tcw-border-strong), var(--tcw-shadow-lg)',\r\n tooltip: 'none',\r\n },\r\n blur: 0,\r\n active: 'underline',\r\n toolbar: 'docked',\r\n sidebar: 'docked',\r\n intervals: 'plain',\r\n tagRadius: 0,\r\n },\r\n capsule: {\r\n radius: { xs: 6, sm: 10, md: 999, lg: 18, xl: 24 },\r\n components: { tooltip: 10, toolbar: 999, sidebar: 999, toast: 999, tag: 999 },\r\n sizes: { toolbar: 44, control: 32, controlSmall: 26, icon: 18, sidebar: 48, menuItem: 34 },\r\n font: { family: `'Sora', 'Manrope', ${SYSTEM_SANS}`, mono: MONO, size: 13, weight: 500, strongWeight: 600, labelCase: 'none', labelTracking: 0 },\r\n borders: { width: 1, separators: false },\r\n shadows: {\r\n menu: '0 0 0 1px var(--tcw-divider), var(--tcw-shadow-xl)',\r\n dialog: '0 0 0 1px var(--tcw-divider), var(--tcw-shadow-xl)',\r\n tooltip: 'var(--tcw-shadow-lg)',\r\n },\r\n blur: 16,\r\n active: 'solid',\r\n toolbar: 'floating',\r\n sidebar: 'floating',\r\n intervals: 'segmented',\r\n tagRadius: 999,\r\n },\r\n};\r\n\r\nconst DENSITY: Record<'compact' | 'spacious', WidgetUISizes> = {\r\n compact: { toolbar: 38, control: 26, controlSmall: 20, icon: 16, sidebar: 40, menuItem: 26 },\r\n spacious: { toolbar: 52, control: 34, controlSmall: 28, icon: 20, sidebar: 54, menuItem: 34 },\r\n};\r\n\r\n/** Each part's corners from the scale (where the preset sets none of its own). */\r\nfunction componentsFrom(radius: WidgetUIRadius, own: Partial<WidgetUIComponentRadius>): WidgetUIComponentRadius {\r\n return {\r\n control: radius.md,\r\n input: radius.md,\r\n menu: radius.lg,\r\n dialog: radius.xl,\r\n panel: radius.lg,\r\n tooltip: radius.sm,\r\n tag: radius.sm,\r\n toast: radius.lg,\r\n toolbar: 0,\r\n sidebar: 0,\r\n ...own,\r\n };\r\n}\r\n\r\n/** The presets, every token set. */\r\nexport const WIDGET_UI_PRESETS: Readonly<Record<WidgetUIPreset, Readonly<ResolvedWidgetUI>>> = Object.freeze(\r\n Object.fromEntries((Object.keys(PRESETS) as WidgetUIPreset[]).map((name) => [name, deepFreeze(resolvePreset(name))])) as Record<WidgetUIPreset, ResolvedWidgetUI>,\r\n);\r\n\r\nfunction resolvePreset(name: WidgetUIPreset): ResolvedWidgetUI {\r\n const base = PRESETS[name];\r\n return {\r\n ...base,\r\n preset: name,\r\n radius: { ...base.radius },\r\n components: componentsFrom(base.radius, base.components),\r\n sizes: { ...base.sizes },\r\n font: { ...base.font },\r\n borders: { ...base.borders },\r\n shadows: { ...base.shadows },\r\n };\r\n}\r\n\r\nfunction deepFreeze<T extends object>(value: T): T {\r\n for (const v of Object.values(value)) if (v && typeof v === 'object') deepFreeze(v as object);\r\n return Object.freeze(value);\r\n}\r\n\r\nconst isPreset = (v: unknown): v is WidgetUIPreset => v === 'studio' || v === 'terminal' || v === 'capsule';\r\nconst px = (v: unknown, lo: number, hi: number): v is number => typeof v === 'number' && Number.isFinite(v) && v >= lo && v <= hi;\r\n/**\r\n * CSS text that stays a value: no way out of the declaration, no URLs, and\r\n * nothing the browser would drop (an open quote or bracket, a comment).\r\n */\r\nconst cssValue = (v: unknown): v is string =>\r\n typeof v === 'string' && v.trim().length > 0 && v.length <= 300 && !/[;{}<>\\\\]|url\\s*\\(|expression\\s*\\(|\\/\\*/i.test(v) && balanced(v);\r\n\r\n/** Quotes closed and brackets matched. */\r\nfunction balanced(v: string): boolean {\r\n let depth = 0;\r\n let quote = '';\r\n for (const ch of v) {\r\n if (quote) {\r\n if (ch === quote) quote = '';\r\n } else if (ch === '\"' || ch === \"'\") quote = ch;\r\n else if (ch === '(') depth++;\r\n else if (ch === ')' && --depth < 0) return false;\r\n }\r\n return depth === 0 && !quote;\r\n}\r\nconst oneOf = <T extends string>(v: unknown, options: readonly T[]): v is T => typeof v === 'string' && (options as readonly string[]).includes(v);\r\n\r\nfunction pick<T extends object>(base: T, over: Partial<Record<keyof T, unknown>> | undefined, ok: (key: keyof T, v: unknown) => boolean): T {\r\n const out = { ...base };\r\n if (!over || typeof over !== 'object') return out;\r\n for (const key of Object.keys(base) as (keyof T)[]) {\r\n const v = over[key];\r\n if (v !== undefined && ok(key, v)) (out as Record<keyof T, unknown>)[key] = v;\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Every token of a look: a preset by name, or your theme over its preset\r\n * (Studio when none). What isn't a usable value is left at the preset's.\r\n */\r\nexport function resolveWidgetUI(theme?: WidgetUIPreset | WidgetUITheme): ResolvedWidgetUI {\r\n const t: WidgetUITheme = typeof theme === 'string' ? { preset: theme } : theme ?? {};\r\n const name: WidgetUIPreset = isPreset(t.preset) ? t.preset : 'studio';\r\n const base = PRESETS[name];\r\n\r\n const radius = pick(base.radius, t.radius, (_, v) => px(v, 0, 999));\r\n const density = t.density === 'compact' || t.density === 'spacious' ? DENSITY[t.density] : base.sizes;\r\n const sizes = pick(density, t.sizes, (key, v) => (key === 'icon' ? px(v, 10, 32) : px(v, 16, 80)));\r\n const font = pick(base.font, t.font, (key, v) => {\r\n if (key === 'family' || key === 'mono') return cssValue(v);\r\n if (key === 'size') return px(v, 11, 20);\r\n if (key === 'weight' || key === 'strongWeight') return px(v, 100, 900);\r\n if (key === 'labelCase') return v === 'none' || v === 'uppercase';\r\n return px(v, 0, 0.5);\r\n });\r\n // Corners the theme sets on the scale reach the parts that follow it.\r\n const components = pick(componentsFrom(radius, base.components), t.components, (_, v) => px(v, 0, 999));\r\n return {\r\n preset: name,\r\n radius,\r\n components,\r\n sizes,\r\n font,\r\n borders: pick(base.borders, t.borders, (key, v) => (key === 'width' ? px(v, 0, 4) : typeof v === 'boolean')),\r\n shadows: pick(base.shadows, t.shadows, (_, v) => cssValue(v)),\r\n blur: px(t.blur, 0, 40) ? t.blur : base.blur,\r\n active: oneOf(t.active, ['tint', 'solid', 'underline'] as const) ? t.active : base.active,\r\n toolbar: oneOf(t.toolbar, ['docked', 'floating'] as const) ? t.toolbar : base.toolbar,\r\n sidebar: oneOf(t.sidebar, ['docked', 'floating'] as const) ? t.sidebar : base.sidebar,\r\n intervals: oneOf(t.intervals, ['plain', 'segmented'] as const) ? t.intervals : base.intervals,\r\n tagRadius: px(t.tagRadius, 0, 999) ? t.tagRadius : base.tagRadius,\r\n };\r\n}\r\n\r\n/** The look as the widget's CSS variables. */\r\nexport function widgetUIVariables(ui: ResolvedWidgetUI): Record<string, string> {\r\n const p = (n: number) => `${n}px`;\r\n const r = ui.radius;\r\n const c = ui.components;\r\n const s = ui.sizes;\r\n const f = ui.font;\r\n return {\r\n '--tcw-radius-xs': p(r.xs),\r\n '--tcw-radius-sm': p(r.sm),\r\n '--tcw-radius': p(r.md),\r\n '--tcw-radius-lg': p(r.lg),\r\n '--tcw-radius-xl': p(r.xl),\r\n '--tcw-control-radius': p(c.control),\r\n '--tcw-input-radius': p(c.input),\r\n '--tcw-menu-radius': p(c.menu),\r\n '--tcw-dialog-radius': p(c.dialog),\r\n '--tcw-panel-radius': p(c.panel),\r\n '--tcw-tooltip-radius': p(c.tooltip),\r\n '--tcw-tag-radius': p(c.tag),\r\n '--tcw-toast-radius': p(c.toast),\r\n '--tcw-toolbar-radius': p(c.toolbar),\r\n '--tcw-sidebar-radius': p(c.sidebar),\r\n '--tcw-toolbar-h': p(s.toolbar),\r\n '--tcw-control-h': p(s.control),\r\n '--tcw-control-h-sm': p(s.controlSmall),\r\n '--tcw-icon': p(s.icon),\r\n '--tcw-sidebar-w': p(s.sidebar),\r\n '--tcw-menu-item-h': p(s.menuItem),\r\n '--tcw-font': f.family,\r\n '--tcw-font-mono': f.mono,\r\n '--tcw-font-size': p(f.size),\r\n '--tcw-font-size-sm': p(f.size - 1),\r\n '--tcw-font-size-xs': p(f.size - 2),\r\n '--tcw-font-size-lg': p(f.size + 2),\r\n '--tcw-weight': String(f.weight),\r\n '--tcw-weight-strong': String(f.strongWeight),\r\n '--tcw-label-case': f.labelCase,\r\n '--tcw-label-tracking': `${f.labelTracking}em`,\r\n '--tcw-border-w': p(ui.borders.width),\r\n '--tcw-sep-w': ui.borders.separators ? p(Math.max(1, ui.borders.width)) : '0px',\r\n '--tcw-menu-shadow': ui.shadows.menu,\r\n '--tcw-dialog-shadow': ui.shadows.dialog,\r\n '--tcw-tooltip-shadow': ui.shadows.tooltip,\r\n '--tcw-blur': p(ui.blur),\r\n // A frosted surface lets some of the chart through.\r\n '--tcw-surface-opacity': ui.blur > 0 ? '82%' : '100%',\r\n };\r\n}\r\n\r\n/**\r\n * Put the look on an element of the widget (its root, its modal portal):\r\n * its tokens inline and its layout switches as data attributes. With\r\n * `variables: false` only the switches; the tokens are left to the\r\n * stylesheet (whose defaults are Studio's), and any set inline before are\r\n * cleared.\r\n */\r\nexport function applyWidgetUI(el: HTMLElement, ui: ResolvedWidgetUI, options: { variables?: boolean } = {}): void {\r\n const inline = options.variables !== false;\r\n for (const [name, value] of Object.entries(widgetUIVariables(ui))) {\r\n if (inline) el.style.setProperty(name, value);\r\n else el.style.removeProperty(name);\r\n }\r\n el.dataset.tcwUi = ui.preset;\r\n el.dataset.tcwActive = ui.active;\r\n el.dataset.tcwToolbar = ui.toolbar;\r\n el.dataset.tcwSidebar = ui.sidebar;\r\n el.dataset.tcwIntervals = ui.intervals;\r\n el.dataset.tcwSeparators = ui.borders.separators ? 'on' : 'off';\r\n}\r\n","import { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, type MessageKey, type Translator } from './i18n.js';\r\n\r\nexport interface ObjectTreeIndicator {\r\n instanceId: string;\r\n name: string;\r\n visible: boolean;\r\n}\r\n\r\nexport interface ObjectTreeDrawing {\r\n id: string;\r\n label: string;\r\n visible: boolean;\r\n locked: boolean;\r\n /** The group it belongs to; a group's drawings are listed under one row. */\r\n group?: { id: string; name: string };\r\n}\r\n\r\nexport interface ObjectTreeCompare {\r\n id: string;\r\n label: string;\r\n color: string;\r\n}\r\n\r\nexport interface ObjectTreeCallbacks {\r\n onRemoveIndicator: (instanceId: string) => void;\r\n onConfigureIndicator?: (instanceId: string) => void;\r\n onToggleIndicatorVisible?: (instanceId: string, visible: boolean) => void;\r\n onRemoveDrawing: (id: string) => void;\r\n onToggleDrawingVisible: (id: string, visible: boolean) => void;\r\n onToggleDrawingLocked: (id: string, locked: boolean) => void;\r\n /** When provided, each drawing row gets a settings button. */\r\n onConfigureDrawing?: (id: string) => void;\r\n /** Group rows: hide, lock, rename (or double-click its name) and ungroup the group. */\r\n onToggleGroupVisible?: (groupId: string, visible: boolean) => void;\r\n onToggleGroupLocked?: (groupId: string, locked: boolean) => void;\r\n onUngroup?: (groupId: string) => void;\r\n onRenameGroup?: (groupId: string, name: string) => void;\r\n /** When provided, a Compare section with an \"add\" button is shown. */\r\n onAddCompare?: () => void;\r\n onRemoveCompare?: (id: string) => void;\r\n}\r\n\r\n/**\r\n * Object-tree panel — a layers manager. Lists every active\r\n * indicator and drawing on the chart with per-item controls: indicators can be\r\n * removed; drawings can be shown/hidden, locked/unlocked, and removed. Toggled\r\n * from the toolbar layers button; the host wires actions back to the chart.\r\n */\r\nexport class WidgetObjectTree {\r\n private el: HTMLDivElement;\r\n private indicatorsEl: HTMLDivElement;\r\n private drawingsEl: HTMLDivElement;\r\n private compareEl: HTMLDivElement | null = null;\r\n private callbacks: ObjectTreeCallbacks;\r\n private open = false;\r\n\r\n constructor(host: HTMLElement, callbacks: ObjectTreeCallbacks, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.callbacks = callbacks;\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-tree-panel';\r\n this.el.hidden = true;\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-tree-header';\r\n const title = document.createElement('span');\r\n title.textContent = this.t('objects.title');\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-tree-close';\r\n closeBtn.setAttribute('aria-label', this.t('objects.close'));\r\n closeBtn.innerHTML = createIcon('x', 14);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.appendChild(title);\r\n header.appendChild(closeBtn);\r\n this.el.appendChild(header);\r\n\r\n this.indicatorsEl = this.makeSection(this.t('objects.indicators'));\r\n this.drawingsEl = this.makeSection(this.t('objects.drawings'));\r\n if (this.callbacks.onAddCompare) {\r\n this.compareEl = this.makeSection(this.t('objects.compare'), {\r\n label: this.t('objects.addCompare'),\r\n run: () => this.callbacks.onAddCompare?.(),\r\n });\r\n }\r\n\r\n host.appendChild(this.el);\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.open;\r\n }\r\n\r\n toggle(): void {\r\n this.open ? this.close() : this.openPanel();\r\n }\r\n\r\n openPanel(): void {\r\n this.open = true;\r\n this.el.hidden = false;\r\n }\r\n\r\n close(): void {\r\n this.open = false;\r\n this.el.hidden = true;\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n /** Replace all lists. Cheap full re-render — counts are small. */\r\n setObjects(\r\n indicators: ObjectTreeIndicator[],\r\n drawings: ObjectTreeDrawing[],\r\n compares: ObjectTreeCompare[] = [],\r\n ): void {\r\n this.renderIndicators(indicators);\r\n this.renderDrawings(drawings);\r\n this.renderCompares(compares);\r\n }\r\n\r\n private makeSection(title: string, add?: { label: string; run: () => void }): HTMLDivElement {\r\n const wrap = document.createElement('div');\r\n wrap.className = 'tcw-tree-section';\r\n const head = document.createElement('div');\r\n head.className = 'tcw-tree-section-head';\r\n const label = document.createElement('span');\r\n label.textContent = title;\r\n head.appendChild(label);\r\n if (add) {\r\n const addBtn = document.createElement('button');\r\n addBtn.type = 'button';\r\n addBtn.className = 'tcw-tree-add';\r\n addBtn.setAttribute('aria-label', add.label);\r\n addBtn.title = add.label;\r\n addBtn.innerHTML = createIcon('plus', 13);\r\n addBtn.addEventListener('click', add.run);\r\n head.appendChild(addBtn);\r\n }\r\n const list = document.createElement('div');\r\n list.className = 'tcw-tree-list';\r\n wrap.appendChild(head);\r\n wrap.appendChild(list);\r\n this.el.appendChild(wrap);\r\n return list;\r\n }\r\n\r\n private renderIndicators(indicators: ObjectTreeIndicator[]): void {\r\n this.indicatorsEl.replaceChildren();\r\n if (indicators.length === 0) {\r\n this.indicatorsEl.appendChild(this.emptyRow(this.t('objects.noIndicators')));\r\n return;\r\n }\r\n for (const ind of indicators) {\r\n const row = this.row(ind.name);\r\n if (!ind.visible) row.classList.add('tcw-tree-hidden');\r\n const actions = document.createElement('div');\r\n actions.className = 'tcw-tree-actions';\r\n if (this.callbacks.onToggleIndicatorVisible) {\r\n actions.appendChild(this.iconButton(\r\n ind.visible ? 'eye' : 'eyeOff',\r\n ind.visible ? this.t('common.hide') : this.t('common.show'),\r\n '',\r\n () => this.callbacks.onToggleIndicatorVisible?.(ind.instanceId, !ind.visible),\r\n ));\r\n }\r\n if (this.callbacks.onConfigureIndicator) {\r\n actions.appendChild(this.iconButton('settings', this.t('objects.indicatorSettings'), '', () =>\r\n this.callbacks.onConfigureIndicator?.(ind.instanceId),\r\n ));\r\n }\r\n actions.appendChild(this.iconButton('trash', this.t('objects.removeIndicator'), 'tcw-tree-del', () =>\r\n this.callbacks.onRemoveIndicator(ind.instanceId),\r\n ));\r\n row.appendChild(actions);\r\n this.indicatorsEl.appendChild(row);\r\n }\r\n }\r\n\r\n private renderDrawings(drawings: ObjectTreeDrawing[]): void {\r\n this.drawingsEl.replaceChildren();\r\n if (drawings.length === 0) {\r\n this.drawingsEl.appendChild(this.emptyRow(this.t('objects.noDrawings')));\r\n return;\r\n }\r\n const listed = new Set<string>();\r\n for (const d of drawings) {\r\n if (!d.group) {\r\n this.drawingsEl.appendChild(this.drawingRow(d));\r\n continue;\r\n }\r\n if (listed.has(d.group.id)) continue;\r\n // A group is listed where its first drawing is, its drawings under it.\r\n listed.add(d.group.id);\r\n const groupId = d.group.id;\r\n const members = drawings.filter((m) => m.group?.id === groupId);\r\n this.drawingsEl.appendChild(this.groupRow(groupId, d.group.name, members));\r\n for (const m of members) {\r\n const row = this.drawingRow(m);\r\n row.classList.add('tcw-tree-member');\r\n this.drawingsEl.appendChild(row);\r\n }\r\n }\r\n }\r\n\r\n private groupRow(groupId: string, name: string, members: readonly ObjectTreeDrawing[]): HTMLDivElement {\r\n const row = this.row(name);\r\n row.classList.add('tcw-tree-group');\r\n const visible = members.some((m) => m.visible);\r\n const locked = members.every((m) => m.locked);\r\n if (!visible) row.classList.add('tcw-tree-hidden');\r\n const nameEl = row.querySelector<HTMLSpanElement>('.tcw-tree-name')!;\r\n nameEl.innerHTML = createIcon('layers', 13);\r\n nameEl.append(` ${name}`);\r\n const actions = document.createElement('div');\r\n actions.className = 'tcw-tree-actions';\r\n if (this.callbacks.onRenameGroup) {\r\n nameEl.addEventListener('dblclick', () => this.renameGroup(nameEl, groupId, name));\r\n actions.appendChild(this.iconButton('penLine', this.t('objects.renameGroup'), '', () => this.renameGroup(nameEl, groupId, name)));\r\n }\r\n if (this.callbacks.onToggleGroupVisible) {\r\n actions.appendChild(this.iconButton(\r\n visible ? 'eye' : 'eyeOff',\r\n visible ? this.t('common.hide') : this.t('common.show'),\r\n '',\r\n () => this.callbacks.onToggleGroupVisible?.(groupId, !visible),\r\n ));\r\n }\r\n if (this.callbacks.onToggleGroupLocked) {\r\n actions.appendChild(this.iconButton(\r\n locked ? 'lock' : 'unlock',\r\n locked ? this.t('common.unlock') : this.t('common.lock'),\r\n locked ? 'tcw-tree-on' : '',\r\n () => this.callbacks.onToggleGroupLocked?.(groupId, !locked),\r\n ));\r\n }\r\n if (this.callbacks.onUngroup) {\r\n actions.appendChild(this.iconButton('x', this.t('drawingMenu.ungroup'), '', () => this.callbacks.onUngroup?.(groupId)));\r\n }\r\n row.appendChild(actions);\r\n return row;\r\n }\r\n\r\n /** Swap a group's name for a text box: Enter or leaving it renames, Escape keeps the name. */\r\n private renameGroup(nameEl: HTMLElement, groupId: string, name: string): void {\r\n if (!nameEl.isConnected) return; // already being renamed\r\n const input = document.createElement('input');\r\n input.type = 'text';\r\n input.className = 'tcw-tree-rename';\r\n input.value = name;\r\n input.maxLength = 80;\r\n input.setAttribute('aria-label', this.t('objects.renameGroup'));\r\n let done = false;\r\n const finish = (save: boolean) => {\r\n if (done) return;\r\n done = true;\r\n const next = input.value.trim();\r\n if (input.isConnected) input.replaceWith(nameEl);\r\n if (save && next && next !== name) this.callbacks.onRenameGroup?.(groupId, next);\r\n };\r\n input.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') finish(true);\r\n else if (e.key === 'Escape') {\r\n e.stopPropagation();\r\n finish(false);\r\n }\r\n });\r\n input.addEventListener('blur', () => finish(true));\r\n nameEl.replaceWith(input);\r\n input.focus();\r\n input.select();\r\n }\r\n\r\n private drawingRow(d: ObjectTreeDrawing): HTMLDivElement {\r\n const row = this.row(d.label);\r\n if (!d.visible) row.classList.add('tcw-tree-hidden');\r\n\r\n const actions = document.createElement('div');\r\n actions.className = 'tcw-tree-actions';\r\n actions.appendChild(this.iconButton(\r\n d.visible ? 'eye' : 'eyeOff',\r\n d.visible ? this.t('common.hide') : this.t('common.show'),\r\n '',\r\n () => this.callbacks.onToggleDrawingVisible(d.id, !d.visible),\r\n ));\r\n actions.appendChild(this.iconButton(\r\n d.locked ? 'lock' : 'unlock',\r\n d.locked ? this.t('common.unlock') : this.t('common.lock'),\r\n d.locked ? 'tcw-tree-on' : '',\r\n () => this.callbacks.onToggleDrawingLocked(d.id, !d.locked),\r\n ));\r\n if (this.callbacks.onConfigureDrawing) {\r\n actions.appendChild(this.iconButton('settings', this.t('objects.drawingSettings'), '', () =>\r\n this.callbacks.onConfigureDrawing?.(d.id),\r\n ));\r\n }\r\n actions.appendChild(this.iconButton('trash', this.t('objects.removeDrawing'), 'tcw-tree-del', () =>\r\n this.callbacks.onRemoveDrawing(d.id),\r\n ));\r\n row.appendChild(actions);\r\n return row;\r\n }\r\n\r\n private renderCompares(compares: ObjectTreeCompare[]): void {\r\n if (!this.compareEl) return;\r\n this.compareEl.replaceChildren();\r\n if (compares.length === 0) {\r\n this.compareEl.appendChild(this.emptyRow(this.t('objects.noComparisons')));\r\n return;\r\n }\r\n for (const c of compares) {\r\n const row = this.row(c.label);\r\n const dot = document.createElement('span');\r\n dot.className = 'tcw-tree-dot';\r\n dot.style.background = c.color;\r\n row.insertBefore(dot, row.firstChild);\r\n if (this.callbacks.onRemoveCompare) {\r\n row.appendChild(this.iconButton('trash', this.t('objects.removeComparison'), 'tcw-tree-del', () =>\r\n this.callbacks.onRemoveCompare?.(c.id),\r\n ));\r\n }\r\n this.compareEl.appendChild(row);\r\n }\r\n }\r\n\r\n private row(label: string): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-tree-row';\r\n const name = document.createElement('span');\r\n name.className = 'tcw-tree-name';\r\n name.textContent = label;\r\n name.title = label;\r\n row.appendChild(name);\r\n return row;\r\n }\r\n\r\n private emptyRow(text: string): HTMLDivElement {\r\n const el = document.createElement('div');\r\n el.className = 'tcw-tree-empty';\r\n el.textContent = text;\r\n return el;\r\n }\r\n\r\n private iconButton(icon: string, label: string, extraClass: string, onClick: () => void): HTMLButtonElement {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = `tcw-tree-btn ${extraClass}`.trim();\r\n btn.setAttribute('aria-label', label);\r\n btn.title = label;\r\n btn.innerHTML = createIcon(icon, 14);\r\n btn.addEventListener('click', onClick);\r\n return btn;\r\n }\r\n}\r\n\r\nconst DRAWING_TYPE_LABELS: Record<string, string> = {\r\n trendLine: 'Trend Line',\r\n ray: 'Ray',\r\n extendedLine: 'Extended Line',\r\n horizontalLine: 'Horizontal Line',\r\n horizontalRay: 'Horizontal Ray',\r\n crossLine: 'Cross Line',\r\n infoLine: 'Info Line',\r\n trendAngle: 'Trend Angle',\r\n circle: 'Circle',\r\n fibChannel: 'Fib Channel',\r\n fibSpeedResistanceFan: 'Fib Speed Resistance Fan',\r\n schiffPitchfork: 'Schiff Pitchfork',\r\n modifiedSchiffPitchfork: 'Modified Schiff Pitchfork',\r\n xabcdPattern: 'XABCD Pattern',\r\n abcdPattern: 'ABCD Pattern',\r\n headAndShoulders: 'Head and Shoulders',\r\n dateAndPriceRange: 'Date and Price Range',\r\n cyclicLines: 'Cyclic Lines',\r\n priceLabel: 'Price Label',\r\n verticalLine: 'Vertical Line',\r\n rectangle: 'Rectangle',\r\n ellipse: 'Ellipse',\r\n triangle: 'Triangle',\r\n arrow: 'Arrow',\r\n parallelChannel: 'Parallel Channel',\r\n regressionChannel: 'Regression Channel',\r\n pitchfork: 'Pitchfork',\r\n fibRetracement: 'Fib Retracement',\r\n fibExtension: 'Fib Extension',\r\n fibTimeZones: 'Fib Time Zones',\r\n gannBox: 'Gann Box',\r\n gannFan: 'Gann Fan',\r\n elliottWave: 'Elliott Wave',\r\n priceRange: 'Price Range',\r\n dateRange: 'Date Range',\r\n measure: 'Measure',\r\n text: 'Text',\r\n textAnnotation: 'Text',\r\n anchoredVWAP: 'Anchored VWAP',\r\n volumeProfileRange: 'Volume Profile',\r\n riskReward: 'Long/Short Position',\r\n};\r\n\r\n/** Label for a drawing type in the widget's language, falling back to English, then the raw key. */\r\nexport function drawingTypeLabel(type: string, t?: Translator): string {\r\n const key = `tool.${type}` as MessageKey;\r\n const translated = t?.(key);\r\n return translated && translated !== key ? translated : DRAWING_TYPE_LABELS[type] ?? type;\r\n}\r\n","/** What Tab can land on inside a dialog. */\r\nexport const FOCUSABLE = 'button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\r\n\r\n/**\r\n * Keep Tab inside `container` (a modal dialog): from its last control Tab\r\n * goes to its first, and Shift+Tab the other way. Call from its keydown.\r\n */\r\nexport function keepTabInside(e: KeyboardEvent, container: HTMLElement): void {\r\n if (e.key !== 'Tab') return;\r\n const items = [...container.querySelectorAll<HTMLElement>(FOCUSABLE)]\r\n .filter((el) => el.getClientRects().length > 0 || el === document.activeElement);\r\n if (items.length === 0) return;\r\n const first = items[0];\r\n const last = items[items.length - 1];\r\n const active = document.activeElement;\r\n if (e.shiftKey && (active === first || !container.contains(active))) {\r\n e.preventDefault();\r\n last.focus();\r\n } else if (!e.shiftKey && (active === last || !container.contains(active))) {\r\n e.preventDefault();\r\n first.focus();\r\n }\r\n}\r\n","import type { IndicatorInputSpec, IndicatorPlot } from '@tradecanvas/commons';\r\nimport { FOCUSABLE, keepTabInside } from './focusTrap.js';\r\nimport { PRICE_SOURCES } from '@tradecanvas/commons';\r\nimport { createIcon } from './icons.js';\r\nimport { EN_MESSAGES, type Translator } from './i18n.js';\r\n\r\nexport type IndicatorParamValue = number | string | boolean;\r\n\r\nexport interface IndicatorSettingsTarget {\r\n instanceId: string;\r\n name: string;\r\n /** Default config — defines the editable keys and their types. */\r\n defaults: Record<string, unknown>;\r\n /** Current values, overlaid on defaults. */\r\n params: Record<string, unknown>;\r\n /** How parameters are edited (the descriptor's `inputs`). */\r\n inputs?: Readonly<Record<string, IndicatorInputSpec>>;\r\n /** Other indicators' lines a source can be: value `ind:<instanceId>:<key>`. */\r\n lineSources?: readonly { value: string; label: string }[];\r\n /** What it draws; with `colors`, the Style tab. */\r\n plots?: readonly IndicatorPlot[];\r\n colors?: readonly string[];\r\n lineWidth?: number;\r\n /** Its levels and its indicator's defaults; with them, the Levels tab. */\r\n levels?: readonly number[];\r\n defaultLevels?: readonly number[];\r\n /** The price scale an overlay is on; set only for price-pane overlays. */\r\n scale?: 'right' | 'left';\r\n}\r\n\r\nexport interface IndicatorSettingsCallbacks {\r\n onApply: (instanceId: string, params: Record<string, IndicatorParamValue>) => void;\r\n onStyle?: (instanceId: string, style: { colors?: string[]; lineWidths?: number[] }) => void;\r\n /** `null` restores the indicator's default levels. */\r\n onLevels?: (instanceId: string, levels: number[] | null) => void;\r\n /** Move an overlay to the left price scale or back to the price scale. */\r\n onScale?: (instanceId: string, scale: 'right' | 'left') => void;\r\n onClose: () => void;\r\n}\r\n\r\ntype Tab = 'inputs' | 'style' | 'levels';\r\n\r\n/** Ids for the dialog's labelling (several widgets may share a page). */\r\nlet nextDialogId = 1;\r\n\r\n\r\nconst HEX_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;\r\nconst LINE_WIDTHS = [1, 1.5, 2, 3, 4];\r\n\r\nfunction titleCase(key: string): string {\r\n // camelCase / snake_case → \"Title Case\"\r\n return key\r\n .replace(/_/g, ' ')\r\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\r\n .replace(/^./, (c) => c.toUpperCase());\r\n}\r\n\r\n/**\r\n * Per-indicator settings: its inputs (a stepper, toggle, colour, choice or\r\n * source for each parameter), its style (a colour per line, the line width)\r\n * and its levels. Every edit applies at once.\r\n */\r\nexport class WidgetIndicatorSettings {\r\n private backdrop: HTMLDivElement;\r\n private modal: HTMLDivElement;\r\n private bodyEl: HTMLDivElement;\r\n private titleEl: HTMLHeadingElement;\r\n private tabsEl: HTMLDivElement;\r\n private resetBtn: HTMLButtonElement;\r\n private callbacks: IndicatorSettingsCallbacks;\r\n private target: IndicatorSettingsTarget | null = null;\r\n private draft: Record<string, IndicatorParamValue> = {};\r\n private colors: string[] = [];\r\n private levels: number[] = [];\r\n private tab: Tab = 'inputs';\r\n private tabButtons: HTMLButtonElement[] = [];\r\n private returnFocus: HTMLElement | null = null;\r\n private readonly uid = nextDialogId++;\r\n private readonly t: Translator;\r\n\r\n constructor(host: HTMLElement, callbacks: IndicatorSettingsCallbacks, t?: Translator) {\r\n this.callbacks = callbacks;\r\n this.t = t ?? ((key) => EN_MESSAGES[key]);\r\n\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.hidden = true;\r\n this.backdrop.addEventListener('click', (e) => {\r\n if (e.target === this.backdrop) this.close();\r\n });\r\n\r\n this.modal = document.createElement('div');\r\n this.modal.className = 'tcw-modal tcw-modal-narrow';\r\n this.modal.setAttribute('role', 'dialog');\r\n this.modal.setAttribute('aria-modal', 'true');\r\n this.modal.setAttribute('aria-labelledby', `tcw-indi-title-${this.uid}`);\r\n // Focusable, so keys still reach it after a click on its blank parts.\r\n this.modal.tabIndex = -1;\r\n this.modal.addEventListener('keydown', (e) => this.onKeyDown(e));\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-modal-header';\r\n this.titleEl = document.createElement('h3');\r\n this.titleEl.id = `tcw-indi-title-${this.uid}`;\r\n this.titleEl.textContent = 'Indicator';\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-modal-close';\r\n closeBtn.setAttribute('aria-label', this.t('indicatorSettings.close'));\r\n closeBtn.innerHTML = createIcon('x', 16);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.append(this.titleEl, closeBtn);\r\n\r\n this.tabsEl = document.createElement('div');\r\n this.tabsEl.className = 'tcw-modal-tabs';\r\n this.tabsEl.setAttribute('role', 'tablist');\r\n this.tabsEl.addEventListener('keydown', (e) => this.onTabKey(e));\r\n\r\n this.bodyEl = document.createElement('div');\r\n this.bodyEl.className = 'tcw-modal-body';\r\n this.bodyEl.id = `tcw-indi-panel-${this.uid}`;\r\n this.bodyEl.setAttribute('role', 'tabpanel');\r\n\r\n const footer = document.createElement('div');\r\n footer.className = 'tcw-modal-footer';\r\n this.resetBtn = document.createElement('button');\r\n this.resetBtn.type = 'button';\r\n this.resetBtn.className = 'tcw-reset-link';\r\n this.resetBtn.textContent = this.t('settings.resetToDefaults');\r\n this.resetBtn.addEventListener('click', () => this.resetTab());\r\n const doneBtn = document.createElement('button');\r\n doneBtn.type = 'button';\r\n doneBtn.className = 'tcw-done-btn';\r\n doneBtn.textContent = this.t('settings.done');\r\n doneBtn.addEventListener('click', () => this.close());\r\n footer.append(this.resetBtn, doneBtn);\r\n\r\n this.modal.append(header, this.tabsEl, this.bodyEl, footer);\r\n this.backdrop.appendChild(this.modal);\r\n host.appendChild(this.backdrop);\r\n }\r\n\r\n open(target: IndicatorSettingsTarget): void {\r\n if (this.backdrop.hidden) this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\r\n this.target = target;\r\n this.titleEl.textContent = this.t('indicatorSettings.title').replace('{name}', target.name);\r\n this.draft = {};\r\n this.colors = [...(target.colors ?? [])];\r\n this.levels = [...(target.levels ?? [])];\r\n this.tab = 'inputs';\r\n this.renderTabs();\r\n this.renderBody();\r\n this.backdrop.hidden = false;\r\n // Start on the first input, else the tabs, else the dialog itself.\r\n const firstTab = this.tabsEl.hidden ? null : this.tabButtons[0] ?? null;\r\n (this.bodyEl.querySelector<HTMLElement>(FOCUSABLE) ?? firstTab ?? this.modal).focus();\r\n }\r\n\r\n close(): void {\r\n // A value typed but not yet committed (Escape pressed in the field) still applies.\r\n const active = document.activeElement;\r\n if ((active instanceof HTMLInputElement || active instanceof HTMLSelectElement) && this.modal.contains(active)) {\r\n active.dispatchEvent(new Event('change'));\r\n }\r\n this.backdrop.hidden = true;\r\n this.target = null;\r\n this.callbacks.onClose();\r\n // Back to where the dialog was opened from (a legend row, the object tree).\r\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\r\n this.returnFocus = null;\r\n }\r\n\r\n isOpen(): boolean {\r\n return !this.backdrop.hidden;\r\n }\r\n\r\n destroy(): void {\r\n this.backdrop.remove();\r\n }\r\n\r\n private tabs(): Tab[] {\r\n const target = this.target;\r\n if (!target) return [];\r\n const out: Tab[] = ['inputs'];\r\n if (target.plots?.length && target.colors && this.callbacks.onStyle) out.push('style');\r\n if (target.levels && this.callbacks.onLevels) out.push('levels');\r\n return out;\r\n }\r\n\r\n /** The tab buttons for this indicator; built on open, then only marked (focus stays put). */\r\n private renderTabs(): void {\r\n const tabs = this.tabs();\r\n this.tabsEl.hidden = tabs.length < 2;\r\n this.tabButtons = tabs.map((tab) => {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-modal-tab';\r\n btn.id = `tcw-indi-tab-${this.uid}-${tab}`;\r\n btn.setAttribute('role', 'tab');\r\n btn.setAttribute('aria-controls', this.bodyEl.id);\r\n btn.dataset.tab = tab;\r\n btn.textContent = this.t(`indicatorSettings.tab.${tab}`);\r\n btn.addEventListener('click', () => this.selectTab(tab));\r\n return btn;\r\n });\r\n this.tabsEl.replaceChildren(...this.tabButtons);\r\n this.markTabs();\r\n }\r\n\r\n private markTabs(): void {\r\n for (const btn of this.tabButtons) {\r\n const selected = btn.dataset.tab === this.tab;\r\n btn.classList.toggle('tcw-active', selected);\r\n btn.setAttribute('aria-selected', String(selected));\r\n btn.tabIndex = selected ? 0 : -1;\r\n if (selected) this.bodyEl.setAttribute('aria-labelledby', btn.id);\r\n }\r\n }\r\n\r\n private selectTab(tab: Tab, focus = false): void {\r\n this.tab = tab;\r\n this.markTabs();\r\n this.renderBody();\r\n if (focus) this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\r\n }\r\n\r\n /** Arrow keys, Home and End move between tabs. */\r\n private onTabKey(e: KeyboardEvent): void {\r\n const tabs = this.tabButtons.map((b) => b.dataset.tab as Tab);\r\n const at = tabs.indexOf(this.tab);\r\n const next = e.key === 'ArrowRight' ? (at + 1) % tabs.length\r\n : e.key === 'ArrowLeft' ? (at - 1 + tabs.length) % tabs.length\r\n : e.key === 'Home' ? 0\r\n : e.key === 'End' ? tabs.length - 1\r\n : -1;\r\n if (next < 0 || tabs.length === 0) return;\r\n e.preventDefault();\r\n this.selectTab(tabs[next], true);\r\n }\r\n\r\n /** Escape closes; Tab stays inside the dialog. */\r\n private onKeyDown(e: KeyboardEvent): void {\r\n if (e.key === 'Escape') {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.close();\r\n return;\r\n }\r\n keepTabInside(e, this.modal);\r\n }\r\n\r\n private renderBody(): void {\r\n this.bodyEl.replaceChildren();\r\n if (!this.target) return;\r\n const section = document.createElement('div');\r\n section.className = 'tcw-settings-section';\r\n if (this.tab === 'style') this.renderStyle(section);\r\n else if (this.tab === 'levels') this.renderLevels(section);\r\n else this.renderInputs(section);\r\n this.resetBtn.hidden = this.tab === 'style';\r\n this.bodyEl.appendChild(section);\r\n }\r\n\r\n // --- Inputs ---\r\n\r\n private currentValue(key: string): IndicatorParamValue {\r\n if (key in this.draft) return this.draft[key];\r\n const cur = this.target?.params[key];\r\n const def = this.target?.defaults[key];\r\n return (cur ?? def) as IndicatorParamValue;\r\n }\r\n\r\n private setValue(key: string, value: IndicatorParamValue): void {\r\n if (!this.target) return;\r\n this.draft[key] = value;\r\n this.callbacks.onApply(this.target.instanceId, { ...this.draft });\r\n }\r\n\r\n private renderInputs(section: HTMLElement): void {\r\n const keys = Object.keys(this.target!.defaults);\r\n if (keys.length === 0) {\r\n section.appendChild(this.note(this.t('indicatorSettings.noInputs')));\r\n return;\r\n }\r\n for (const key of keys) section.appendChild(this.fieldRow(key));\r\n }\r\n\r\n private fieldRow(key: string): HTMLLabelElement {\r\n const spec = this.target?.inputs?.[key];\r\n const value = this.currentValue(key);\r\n const defType = typeof (this.target?.defaults[key] ?? value);\r\n let control: HTMLElement;\r\n if (spec?.source) control = this.sourceControl(key, String(value ?? 'close'));\r\n else if (spec?.options) control = this.choiceControl(key, spec.options, value);\r\n else if (defType === 'boolean') control = this.toggleControl(key, Boolean(value));\r\n else if (defType === 'number') control = this.numberControl(key, Number(value), spec);\r\n else if (typeof value === 'string' && HEX_RE.test(value)) control = this.colorInput(value, (v) => this.setValue(key, v));\r\n else control = this.textControl(key, String(value ?? ''));\r\n return this.row(spec?.label ?? titleCase(key), control);\r\n }\r\n\r\n private sourceControl(key: string, value: string): HTMLSelectElement {\r\n const select = document.createElement('select');\r\n select.className = 'tcw-indi-input tcw-indi-select';\r\n const prices = document.createElement('optgroup');\r\n prices.label = this.t('indicatorSettings.source.prices');\r\n for (const source of PRICE_SOURCES) prices.appendChild(this.option(source, source));\r\n select.appendChild(prices);\r\n const lines = this.target?.lineSources ?? [];\r\n if (lines.length) {\r\n const group = document.createElement('optgroup');\r\n group.label = this.t('indicatorSettings.source.indicators');\r\n for (const line of lines) group.appendChild(this.option(line.value, line.label));\r\n select.appendChild(group);\r\n }\r\n select.value = value;\r\n if (select.value !== value) select.value = 'close'; // a line that is gone\r\n select.addEventListener('change', () => this.setValue(key, select.value));\r\n return select;\r\n }\r\n\r\n private choiceControl(key: string, options: readonly (string | number)[], value: IndicatorParamValue): HTMLSelectElement {\r\n const select = document.createElement('select');\r\n select.className = 'tcw-indi-input tcw-indi-select';\r\n for (const opt of options) select.appendChild(this.option(String(opt), String(opt)));\r\n select.value = String(value);\r\n select.addEventListener('change', () => {\r\n const picked = options.find((o) => String(o) === select.value);\r\n if (picked !== undefined) this.setValue(key, picked);\r\n });\r\n return select;\r\n }\r\n\r\n private toggleControl(key: string, value: boolean): HTMLButtonElement {\r\n const toggle = document.createElement('button');\r\n toggle.type = 'button';\r\n toggle.className = `tcw-toggle${value ? ' tcw-on' : ''}`;\r\n toggle.setAttribute('role', 'switch');\r\n toggle.setAttribute('aria-checked', String(value));\r\n toggle.addEventListener('click', () => {\r\n const next = !toggle.classList.contains('tcw-on');\r\n toggle.classList.toggle('tcw-on', next);\r\n toggle.setAttribute('aria-checked', String(next));\r\n this.setValue(key, next);\r\n });\r\n return toggle;\r\n }\r\n\r\n private numberControl(key: string, value: number, spec?: IndicatorInputSpec): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.type = 'number';\r\n input.className = 'tcw-indi-input';\r\n input.value = String(value);\r\n // Integer-looking defaults step by 1; fractional defaults step by 0.1.\r\n input.step = String(spec?.step ?? (Number.isInteger(value) ? 1 : 0.1));\r\n if (spec?.min !== undefined) input.min = String(spec.min);\r\n if (spec?.max !== undefined) input.max = String(spec.max);\r\n input.addEventListener('change', () => {\r\n let n = Number(input.value);\r\n if (!Number.isFinite(n)) return;\r\n if (spec?.min !== undefined) n = Math.max(spec.min, n);\r\n if (spec?.max !== undefined) n = Math.min(spec.max, n);\r\n input.value = String(n);\r\n this.setValue(key, n);\r\n });\r\n return input;\r\n }\r\n\r\n private textControl(key: string, value: string): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.type = 'text';\r\n input.className = 'tcw-indi-input';\r\n input.value = value;\r\n input.addEventListener('change', () => this.setValue(key, input.value));\r\n return input;\r\n }\r\n\r\n // --- Style ---\r\n\r\n /** One row per colour the indicator uses: the lines drawn in it, and \"up\" / \"down\" for two-tone ones. */\r\n private renderStyle(section: HTMLElement): void {\r\n const target = this.target!;\r\n const names = new Map<number, string[]>();\r\n const add = (index: number, name: string) => {\r\n const list = names.get(index) ?? [];\r\n if (!list.includes(name)) list.push(name);\r\n names.set(index, list);\r\n };\r\n for (const plot of target.plots ?? []) {\r\n const twoTone = plot.tone !== undefined && plot.downColor !== undefined;\r\n add(plot.color, twoTone ? `${plot.title} ${this.t('indicatorSettings.up')}` : plot.title);\r\n if (twoTone) add(plot.downColor!, `${plot.title} ${this.t('indicatorSettings.down')}`);\r\n }\r\n for (const [index, labels] of [...names].sort((a, b) => a[0] - b[0])) {\r\n const color = this.colors[index] ?? this.colors[0] ?? '#4c8dff';\r\n section.appendChild(this.row(labels.join(' · '), this.colorInput(color, (v) => {\r\n const next = [...this.colors];\r\n while (next.length <= index) next.push(next[0] ?? v);\r\n next[index] = v;\r\n this.colors = next;\r\n this.callbacks.onStyle?.(target.instanceId, { colors: [...next] });\r\n })));\r\n }\r\n const width = document.createElement('select');\r\n width.className = 'tcw-indi-input tcw-indi-select';\r\n for (const w of LINE_WIDTHS) width.appendChild(this.option(String(w), `${w} px`));\r\n width.value = String(target.lineWidth ?? 1.5);\r\n width.addEventListener('change', () => this.callbacks.onStyle?.(target.instanceId, { lineWidths: [Number(width.value)] }));\r\n section.appendChild(this.row(this.t('indicatorSettings.lineWidth'), width));\r\n\r\n if (target.scale && this.callbacks.onScale) {\r\n const scale = document.createElement('select');\r\n scale.className = 'tcw-indi-input tcw-indi-select';\r\n scale.appendChild(this.option('right', this.t('indicatorSettings.scale.right')));\r\n scale.appendChild(this.option('left', this.t('indicatorSettings.scale.left')));\r\n scale.value = target.scale;\r\n scale.addEventListener('change', () => {\r\n const next = scale.value === 'left' ? 'left' : 'right';\r\n this.target = { ...target, scale: next };\r\n this.callbacks.onScale?.(target.instanceId, next);\r\n });\r\n section.appendChild(this.row(this.t('indicatorSettings.scale'), scale));\r\n }\r\n }\r\n\r\n // --- Levels ---\r\n\r\n private renderLevels(section: HTMLElement): void {\r\n if (this.levels.length === 0) section.appendChild(this.note(this.t('indicatorSettings.noLevels')));\r\n this.levels.forEach((level, i) => {\r\n const input = document.createElement('input');\r\n input.type = 'number';\r\n input.className = 'tcw-indi-input';\r\n input.id = `tcw-indi-level-${this.uid}-${i}`;\r\n input.value = String(level);\r\n input.step = 'any';\r\n input.addEventListener('change', () => {\r\n const n = Number(input.value);\r\n if (!Number.isFinite(n) || input.value.trim() === '') return;\r\n this.levels = this.levels.map((v, j) => (j === i ? n : v));\r\n this.applyLevels();\r\n });\r\n const remove = document.createElement('button');\r\n remove.type = 'button';\r\n remove.className = 'tcw-indi-remove';\r\n remove.innerHTML = createIcon('x', 12);\r\n const label = this.t('indicatorSettings.removeLevel');\r\n remove.title = label;\r\n remove.setAttribute('aria-label', `${label} ${i + 1}`);\r\n remove.addEventListener('click', () => {\r\n this.levels = this.levels.filter((_, j) => j !== i);\r\n this.applyLevels();\r\n this.renderBody();\r\n // Keep the keyboard nearby: the next level's remove, else Add.\r\n (this.bodyEl.querySelectorAll<HTMLElement>('.tcw-indi-remove')[i]\r\n ?? this.bodyEl.querySelector<HTMLElement>('.tcw-indi-add'))?.focus();\r\n });\r\n const controls = document.createElement('span');\r\n controls.className = 'tcw-indi-level';\r\n controls.append(input, remove);\r\n const row = document.createElement('div');\r\n row.className = 'tcw-settings-row';\r\n const text = document.createElement('label');\r\n text.className = 'tcw-settings-label';\r\n text.htmlFor = input.id;\r\n text.textContent = `${this.t('indicatorSettings.level')} ${i + 1}`;\r\n row.append(text, controls);\r\n section.appendChild(row);\r\n });\r\n const addBtn = document.createElement('button');\r\n addBtn.type = 'button';\r\n addBtn.className = 'tcw-reset-link tcw-indi-add';\r\n addBtn.textContent = `+ ${this.t('indicatorSettings.addLevel')}`;\r\n addBtn.addEventListener('click', () => {\r\n const last = this.levels[this.levels.length - 1];\r\n this.levels = [...this.levels, last === undefined ? 0 : last + 10];\r\n this.applyLevels();\r\n this.renderBody();\r\n const inputs = this.bodyEl.querySelectorAll<HTMLInputElement>('.tcw-indi-level input');\r\n inputs[inputs.length - 1]?.focus();\r\n });\r\n section.appendChild(addBtn);\r\n }\r\n\r\n private applyLevels(): void {\r\n if (this.target) this.callbacks.onLevels?.(this.target.instanceId, [...this.levels]);\r\n }\r\n\r\n // --- Reset ---\r\n\r\n private resetTab(): void {\r\n const target = this.target;\r\n if (!target) return;\r\n if (this.tab === 'levels') {\r\n this.levels = [...(target.defaultLevels ?? [])];\r\n this.callbacks.onLevels?.(target.instanceId, null);\r\n } else {\r\n const reset: Record<string, IndicatorParamValue> = {};\r\n for (const [key, def] of Object.entries(target.defaults)) reset[key] = def as IndicatorParamValue;\r\n this.draft = reset;\r\n this.callbacks.onApply(target.instanceId, { ...reset });\r\n }\r\n this.renderBody();\r\n }\r\n\r\n // --- Pieces ---\r\n\r\n /** A labelled control: clicking the label reaches the control. */\r\n private row(label: string, control: HTMLElement): HTMLLabelElement {\r\n const row = document.createElement('label');\r\n row.className = 'tcw-settings-row';\r\n const text = document.createElement('span');\r\n text.className = 'tcw-settings-label';\r\n text.textContent = label;\r\n row.append(text, control);\r\n return row;\r\n }\r\n\r\n private note(text: string): HTMLDivElement {\r\n const el = document.createElement('div');\r\n el.className = 'tcw-settings-label';\r\n el.textContent = text;\r\n return el;\r\n }\r\n\r\n private option(value: string, label: string): HTMLOptionElement {\r\n const opt = document.createElement('option');\r\n opt.value = value;\r\n opt.textContent = label;\r\n return opt;\r\n }\r\n\r\n private colorInput(value: string, onInput: (v: string) => void): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.type = 'color';\r\n input.className = 'tcw-indi-color';\r\n input.value = toHex(value);\r\n input.addEventListener('input', () => onInput(input.value));\r\n return input;\r\n }\r\n}\r\n\r\n/** A colour as `#rrggbb` (what a colour input takes); black if unreadable. */\r\nfunction toHex(color: string): string {\r\n const c = color.trim();\r\n if (/^#[0-9a-f]{6}$/i.test(c)) return c.toLowerCase();\r\n if (/^#[0-9a-f]{3}$/i.test(c)) return `#${c[1]}${c[1]}${c[2]}${c[2]}${c[3]}${c[3]}`.toLowerCase();\r\n const m = /^rgba?\\(\\s*(\\d+)[\\s,]+(\\d+)[\\s,]+(\\d+)/i.exec(c);\r\n if (!m) return '#000000';\r\n return `#${[m[1], m[2], m[3]].map((v) => Math.min(255, Number(v)).toString(16).padStart(2, '0')).join('')}`;\r\n}\r\n","import type { DrawingOptions, DrawingStyle, DrawingToolType } from '@tradecanvas/commons';\r\nimport { sanitizeDrawingStyle } from '@tradecanvas/commons';\r\n\r\nexport interface DrawingStyleTemplate {\r\n name: string;\r\n style: Partial<DrawingStyle>;\r\n /** The tool it was saved from, with that tool's options; absent for a style-only template. */\r\n type?: DrawingToolType;\r\n options?: DrawingOptions;\r\n}\r\n\r\n/** Minimal storage surface — satisfied by `localStorage` and easy to mock. */\r\nexport interface KeyValueStorage {\r\n getItem(key: string): string | null;\r\n setItem(key: string, value: string): void;\r\n}\r\n\r\nfunction defaultStorage(): KeyValueStorage | null {\r\n try {\r\n return typeof localStorage !== 'undefined' ? localStorage : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/** Longest template name kept. */\r\nconst MAX_TEMPLATE_NAME = 80;\r\n\r\n/** A template's style: the valid fields of `raw`, without text (a template styles, it doesn't write). */\r\nfunction sanitizeStyle(raw: unknown): Partial<DrawingStyle> {\r\n const { text: _text, ...style } = sanitizeDrawingStyle(raw);\r\n return style;\r\n}\r\n\r\nfunction copyTemplate(t: DrawingStyleTemplate): DrawingStyleTemplate {\r\n const out: DrawingStyleTemplate = { name: t.name, style: { ...t.style } };\r\n if (t.type) out.type = t.type;\r\n if (t.options) out.options = structuredClone(t.options);\r\n return out;\r\n}\r\n\r\n/**\r\n * Named drawing presets, persisted to a key-value store: a style, and for a\r\n * template saved from a tool, that tool's options. Templates are upserted by\r\n * name and tool (case-sensitive) and ordered most-recently-saved last.\r\n */\r\nexport class DrawingTemplateStore {\r\n private templates: DrawingStyleTemplate[] = [];\r\n\r\n constructor(\r\n private storageKey = 'tcw:draw-templates',\r\n private storage: KeyValueStorage | null = defaultStorage(),\r\n ) {\r\n this.load();\r\n }\r\n\r\n /** Style-only templates, plus with `type` the ones saved from that tool. */\r\n list(type?: DrawingToolType): DrawingStyleTemplate[] {\r\n return this.templates.filter((t) => !t.type || t.type === type).map(copyTemplate);\r\n }\r\n\r\n get(name: string, type?: DrawingToolType): DrawingStyleTemplate | null {\r\n const t = this.templates.find((x) => x.name === name && x.type === type);\r\n return t ? copyTemplate(t) : null;\r\n }\r\n\r\n /** Insert or replace a template by name (and tool, when it is saved with one). */\r\n save(name: string, style: Partial<DrawingStyle>, tool?: { type: DrawingToolType; options: DrawingOptions }): void {\r\n const trimmed = name.trim().slice(0, MAX_TEMPLATE_NAME);\r\n if (!trimmed) return;\r\n const template: DrawingStyleTemplate = { name: trimmed, style: sanitizeStyle(style) };\r\n if (tool) {\r\n template.type = tool.type;\r\n template.options = structuredClone(tool.options);\r\n }\r\n this.templates = this.templates.filter((t) => !(t.name === trimmed && t.type === template.type));\r\n this.templates.push(template);\r\n this.persist();\r\n }\r\n\r\n remove(name: string, type?: DrawingToolType): void {\r\n this.templates = this.templates.filter((t) => !(t.name === name && t.type === type));\r\n this.persist();\r\n }\r\n\r\n clear(): void {\r\n this.templates = [];\r\n this.persist();\r\n }\r\n\r\n private load(): void {\r\n if (!this.storage) return;\r\n try {\r\n const raw = this.storage.getItem(this.storageKey);\r\n if (!raw) return;\r\n const parsed = JSON.parse(raw);\r\n if (!Array.isArray(parsed)) return;\r\n this.templates = parsed\r\n .filter((t) => t && typeof t.name === 'string' && t.name.trim() !== '')\r\n .map((t) => {\r\n const template: DrawingStyleTemplate = { name: t.name.trim().slice(0, MAX_TEMPLATE_NAME), style: sanitizeStyle(t.style) };\r\n // Options are checked against the tool when they are applied.\r\n if (typeof t.type === 'string') template.type = t.type as DrawingToolType;\r\n if (t.options && typeof t.options === 'object' && !Array.isArray(t.options)) template.options = t.options;\r\n return template;\r\n });\r\n } catch {\r\n // Corrupt or unavailable storage — start empty.\r\n }\r\n }\r\n\r\n private persist(): void {\r\n if (!this.storage) return;\r\n try {\r\n this.storage.setItem(this.storageKey, JSON.stringify(this.templates));\r\n } catch {\r\n // Storage full or blocked — keep the in-memory copy.\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * The options each drawing tool starts with (\"save as default\"), persisted to\r\n * a key-value store. Values are checked by the chart when they are applied.\r\n */\r\nexport class DrawingDefaultsStore {\r\n private defaults: Partial<Record<DrawingToolType, DrawingOptions>> = {};\r\n\r\n constructor(\r\n private storageKey = 'tcw:drawing-defaults',\r\n private storage: KeyValueStorage | null = defaultStorage(),\r\n ) {\r\n try {\r\n const raw = this.storage?.getItem(this.storageKey);\r\n const parsed: unknown = raw ? JSON.parse(raw) : null;\r\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\r\n for (const [type, options] of Object.entries(parsed)) {\r\n if (options && typeof options === 'object' && !Array.isArray(options)) {\r\n this.defaults[type as DrawingToolType] = options as DrawingOptions;\r\n }\r\n }\r\n }\r\n } catch {\r\n // Corrupt or unavailable storage — no defaults.\r\n }\r\n }\r\n\r\n all(): Partial<Record<DrawingToolType, DrawingOptions>> {\r\n return structuredClone(this.defaults);\r\n }\r\n\r\n /** Remember a tool's default options; null forgets them. */\r\n set(type: DrawingToolType, options: DrawingOptions | null): void {\r\n if (options && Object.keys(options).length > 0) this.defaults[type] = structuredClone(options);\r\n else delete this.defaults[type];\r\n try {\r\n this.storage?.setItem(this.storageKey, JSON.stringify(this.defaults));\r\n } catch {\r\n // Storage full or blocked — keep the in-memory copy.\r\n }\r\n }\r\n}\r\n","import type { DrawingStyle } from '@tradecanvas/commons';\r\nimport { createIcon } from './icons.js';\r\nimport { DrawingTemplateStore } from './DrawingTemplateStore.js';\r\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\r\nimport { escapeHtml } from './escapeHtml.js';\r\n\r\nexport interface DrawingStyleCallbacks {\r\n /** Apply a style change to the active (next) drawing and the selected one. */\r\n onStyleChange: (style: Partial<DrawingStyle>) => void;\r\n /** Current active drawing style, for seeding controls and saving templates. */\r\n getStyle: () => DrawingStyle;\r\n}\r\n\r\nconst SWATCHES = ['#4c8dff', '#1fa874', '#e8505b', '#f2a93b', '#a57cff', '#1398a8', '#ffffff', '#7d8696'];\r\nconst WIDTHS = [1, 2, 3, 4];\r\nconst LINE_STYLES: DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\r\n\r\n/**\r\n * Drawing style popover — pick colour, line width, and line style for the next\r\n * drawing (and the selected one), plus save/apply named style templates\r\n * persisted via `DrawingTemplateStore`.\r\n */\r\nexport class WidgetDrawingStyle {\r\n private el: HTMLDivElement;\r\n private templatesEl: HTMLDivElement;\r\n private nameInput: HTMLInputElement;\r\n private callbacks: DrawingStyleCallbacks;\r\n private store: DrawingTemplateStore;\r\n private open = false;\r\n\r\n constructor(\r\n host: HTMLElement,\r\n callbacks: DrawingStyleCallbacks,\r\n store: DrawingTemplateStore,\r\n private readonly t: Translator = EN_TRANSLATOR,\r\n ) {\r\n this.callbacks = callbacks;\r\n this.store = store;\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-style-panel';\r\n this.el.hidden = true;\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-style-header';\r\n const title = document.createElement('span');\r\n title.textContent = this.t('drawingStyle.title');\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-style-close';\r\n closeBtn.setAttribute('aria-label', this.t('common.close'));\r\n closeBtn.innerHTML = createIcon('x', 14);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.appendChild(title);\r\n header.appendChild(closeBtn);\r\n this.el.appendChild(header);\r\n\r\n this.el.appendChild(this.colorRow());\r\n this.el.appendChild(this.widthRow());\r\n this.el.appendChild(this.lineStyleRow());\r\n\r\n // Templates\r\n const tmplHead = document.createElement('div');\r\n tmplHead.className = 'tcw-style-subhead';\r\n tmplHead.textContent = this.t('drawingStyle.templates');\r\n this.el.appendChild(tmplHead);\r\n\r\n const saveRow = document.createElement('div');\r\n saveRow.className = 'tcw-style-save';\r\n this.nameInput = document.createElement('input');\r\n this.nameInput.type = 'text';\r\n this.nameInput.placeholder = this.t('drawingStyle.templateName');\r\n this.nameInput.className = 'tcw-style-name';\r\n const saveBtn = document.createElement('button');\r\n saveBtn.type = 'button';\r\n saveBtn.className = 'tcw-style-savebtn';\r\n saveBtn.innerHTML = `${createIcon('plus', 13)}<span>${escapeHtml(this.t('common.save'))}</span>`;\r\n saveBtn.addEventListener('click', () => this.saveTemplate());\r\n saveRow.appendChild(this.nameInput);\r\n saveRow.appendChild(saveBtn);\r\n this.el.appendChild(saveRow);\r\n\r\n this.templatesEl = document.createElement('div');\r\n this.templatesEl.className = 'tcw-style-templates';\r\n this.el.appendChild(this.templatesEl);\r\n\r\n host.appendChild(this.el);\r\n this.renderTemplates();\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.open;\r\n }\r\n\r\n toggle(): void {\r\n this.open ? this.close() : this.openPanel();\r\n }\r\n\r\n openPanel(): void {\r\n this.open = true;\r\n this.el.hidden = false;\r\n this.syncActiveControls();\r\n this.renderTemplates();\r\n }\r\n\r\n close(): void {\r\n this.open = false;\r\n this.el.hidden = true;\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n private colorRow(): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-row tcw-style-colors';\r\n for (const c of SWATCHES) {\r\n const sw = document.createElement('button');\r\n sw.type = 'button';\r\n sw.className = 'tcw-style-swatch';\r\n sw.style.background = c;\r\n sw.dataset.color = c;\r\n sw.setAttribute('aria-label', c);\r\n sw.addEventListener('click', () => this.applyStyle({ color: c }));\r\n row.appendChild(sw);\r\n }\r\n const picker = document.createElement('input');\r\n picker.type = 'color';\r\n picker.className = 'tcw-style-picker';\r\n picker.addEventListener('input', () => this.applyStyle({ color: picker.value }));\r\n row.appendChild(picker);\r\n return row;\r\n }\r\n\r\n private widthRow(): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-row tcw-style-widths';\r\n for (const w of WIDTHS) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-style-width';\r\n btn.dataset.width = String(w);\r\n const bar = document.createElement('span');\r\n bar.style.height = `${w}px`;\r\n btn.appendChild(bar);\r\n btn.addEventListener('click', () => this.applyStyle({ lineWidth: w }));\r\n row.appendChild(btn);\r\n }\r\n return row;\r\n }\r\n\r\n private lineStyleRow(): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-row tcw-style-dashes';\r\n for (const ls of LINE_STYLES) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-style-dash';\r\n btn.dataset.linestyle = ls;\r\n btn.textContent = ls === 'solid' ? '──' : ls === 'dashed' ? '╌╌' : '┄┄';\r\n btn.title = ls;\r\n btn.addEventListener('click', () => this.applyStyle({ lineStyle: ls }));\r\n row.appendChild(btn);\r\n }\r\n return row;\r\n }\r\n\r\n private applyStyle(patch: Partial<DrawingStyle>): void {\r\n this.callbacks.onStyleChange(patch);\r\n this.syncActiveControls();\r\n }\r\n\r\n /** Mark the controls matching the current active style. */\r\n private syncActiveControls(): void {\r\n const style = this.callbacks.getStyle();\r\n this.el.querySelectorAll<HTMLElement>('.tcw-style-swatch').forEach((sw) => {\r\n sw.classList.toggle('tcw-on', sw.dataset.color?.toLowerCase() === style.color?.toLowerCase());\r\n });\r\n this.el.querySelectorAll<HTMLElement>('.tcw-style-width').forEach((b) => {\r\n b.classList.toggle('tcw-on', Number(b.dataset.width) === style.lineWidth);\r\n });\r\n this.el.querySelectorAll<HTMLElement>('.tcw-style-dash').forEach((b) => {\r\n b.classList.toggle('tcw-on', b.dataset.linestyle === style.lineStyle);\r\n });\r\n }\r\n\r\n private saveTemplate(): void {\r\n const name = this.nameInput.value.trim();\r\n if (!name) return;\r\n this.store.save(name, this.callbacks.getStyle());\r\n this.nameInput.value = '';\r\n this.renderTemplates();\r\n }\r\n\r\n private renderTemplates(): void {\r\n this.templatesEl.replaceChildren();\r\n const templates = this.store.list();\r\n if (templates.length === 0) {\r\n const empty = document.createElement('div');\r\n empty.className = 'tcw-style-empty';\r\n empty.textContent = this.t('drawingStyle.noTemplates');\r\n this.templatesEl.appendChild(empty);\r\n return;\r\n }\r\n for (const t of templates) {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-template';\r\n\r\n const apply = document.createElement('button');\r\n apply.type = 'button';\r\n apply.className = 'tcw-style-apply';\r\n const dot = document.createElement('span');\r\n dot.className = 'tcw-style-tdot';\r\n dot.style.background = (t.style.color as string) ?? 'var(--tcw-text-muted)';\r\n const label = document.createElement('span');\r\n label.textContent = t.name;\r\n apply.appendChild(dot);\r\n apply.appendChild(label);\r\n apply.addEventListener('click', () => {\r\n this.callbacks.onStyleChange({ ...t.style });\r\n this.syncActiveControls();\r\n });\r\n\r\n const del = document.createElement('button');\r\n del.type = 'button';\r\n del.className = 'tcw-style-tdel';\r\n del.setAttribute('aria-label', this.t('drawingStyle.deleteTemplate'));\r\n del.innerHTML = createIcon('trash', 13);\r\n del.addEventListener('click', () => {\r\n this.store.remove(t.name);\r\n this.renderTemplates();\r\n });\r\n\r\n row.appendChild(apply);\r\n row.appendChild(del);\r\n this.templatesEl.appendChild(row);\r\n }\r\n }\r\n}\r\n","/**\r\n * Form controls shared by the settings dialogs: a labelled row, a switch, a\r\n * number field, a colour picker and a select. Each calls back on change.\r\n */\r\n\r\n/** A labelled control: clicking the label reaches the control. */\r\nexport function settingsRow(label: string, control: HTMLElement): HTMLLabelElement {\r\n const row = document.createElement('label');\r\n row.className = 'tcw-settings-row';\r\n const text = document.createElement('span');\r\n text.className = 'tcw-settings-label';\r\n text.textContent = label;\r\n row.append(text, control);\r\n return row;\r\n}\r\n\r\nexport function toggleSwitch(value: boolean, onChange: (value: boolean) => void): HTMLButtonElement {\r\n const toggle = document.createElement('button');\r\n toggle.type = 'button';\r\n toggle.className = `tcw-toggle${value ? ' tcw-on' : ''}`;\r\n toggle.setAttribute('role', 'switch');\r\n toggle.setAttribute('aria-checked', String(value));\r\n toggle.addEventListener('click', () => {\r\n const next = !toggle.classList.contains('tcw-on');\r\n toggle.classList.toggle('tcw-on', next);\r\n toggle.setAttribute('aria-checked', String(next));\r\n onChange(next);\r\n });\r\n return toggle;\r\n}\r\n\r\nexport function numberInput(\r\n value: number,\r\n range: { min?: number; max?: number; step?: number | 'any' },\r\n onChange: (value: number) => void,\r\n): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.type = 'number';\r\n input.className = 'tcw-indi-input';\r\n input.value = String(value);\r\n input.step = String(range.step ?? (Number.isInteger(value) ? 1 : 0.001));\r\n if (range.min !== undefined) input.min = String(range.min);\r\n if (range.max !== undefined) input.max = String(range.max);\r\n input.addEventListener('change', () => {\r\n if (input.value.trim() === '') return;\r\n let n = Number(input.value);\r\n if (!Number.isFinite(n)) return;\r\n if (range.min !== undefined) n = Math.max(range.min, n);\r\n if (range.max !== undefined) n = Math.min(range.max, n);\r\n input.value = String(n);\r\n onChange(n);\r\n });\r\n return input;\r\n}\r\n\r\nexport function colorInput(value: string, onInput: (value: string) => void): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.type = 'color';\r\n input.className = 'tcw-indi-color';\r\n input.value = toHex(value);\r\n input.addEventListener('input', () => onInput(input.value));\r\n return input;\r\n}\r\n\r\nexport function selectInput(\r\n choices: readonly { value: string; label: string }[],\r\n value: string,\r\n onChange: (value: string) => void,\r\n): HTMLSelectElement {\r\n const select = document.createElement('select');\r\n select.className = 'tcw-indi-input tcw-indi-select';\r\n for (const choice of choices) {\r\n const opt = document.createElement('option');\r\n opt.value = choice.value;\r\n opt.textContent = choice.label;\r\n select.appendChild(opt);\r\n }\r\n select.value = value;\r\n select.addEventListener('change', () => onChange(select.value));\r\n return select;\r\n}\r\n\r\n/** A colour as `#rrggbb` (what a colour input takes); black if unreadable. */\r\nexport function toHex(color: unknown): string {\r\n if (typeof color !== 'string') return '#000000';\r\n const c = color.trim();\r\n if (/^#[0-9a-f]{6}$/i.test(c)) return c.toLowerCase();\r\n if (/^#[0-9a-f]{3}$/i.test(c)) return `#${c[1]}${c[1]}${c[2]}${c[2]}${c[3]}${c[3]}`.toLowerCase();\r\n const m = /^rgba?\\(\\s*(\\d+)[\\s,]+(\\d+)[\\s,]+(\\d+)/i.exec(c);\r\n if (!m) return '#000000';\r\n return `#${[m[1], m[2], m[3]].map((v) => Math.min(255, Number(v)).toString(16).padStart(2, '0')).join('')}`;\r\n}\r\n\r\n/** The alpha of a colour (1 for `#rgb` / `#rrggbb`). */\r\nexport function colorAlpha(color: unknown): number {\r\n if (typeof color !== 'string') return 1;\r\n const m = /^rgba\\([^)]*,\\s*([\\d.]+)\\s*\\)$/i.exec(color.trim());\r\n return m ? Math.max(0, Math.min(1, Number(m[1]))) : 1;\r\n}\r\n\r\n/** `#rrggbb` with an alpha, as `rgba(…)`. */\r\nexport function withAlpha(hex: string, alpha: number): string {\r\n const h = toHex(hex);\r\n const [r, g, b] = [1, 3, 5].map((i) => parseInt(h.slice(i, i + 2), 16));\r\n return `rgba(${r}, ${g}, ${b}, ${Math.round(alpha * 100) / 100})`;\r\n}\r\n","import type {\r\n AnchorPoint,\r\n DrawingLevel,\r\n DrawingOptionDef,\r\n DrawingOptionDefs,\r\n DrawingOptions,\r\n DrawingStyle,\r\n DrawingToolType,\r\n} from '@tradecanvas/commons';\r\nimport { sanitizeDrawingOptions } from '@tradecanvas/commons';\r\nimport { createIcon } from './icons.js';\r\nimport { keepTabInside } from './focusTrap.js';\r\nimport { EN_TRANSLATOR, fill, type MessageKey, type Translator } from './i18n.js';\r\nimport { colorAlpha, colorInput, numberInput, selectInput, settingsRow, toHex, toggleSwitch, withAlpha } from './settingsControls.js';\r\nimport type { DrawingStyleTemplate } from './DrawingTemplateStore.js';\r\n\r\n/** The drawing a settings dialog edits. */\r\nexport interface DrawingSettingsTarget {\r\n id: string;\r\n type: DrawingToolType;\r\n /** The tool's name in the widget's language. */\r\n name: string;\r\n style: DrawingStyle;\r\n /** Every option, defaults filled in. */\r\n options: DrawingOptions;\r\n defs: DrawingOptionDefs;\r\n anchors: AnchorPoint[];\r\n /** Whether the tool fills an area and draws text (which style fields to offer). */\r\n fill: boolean;\r\n text: boolean;\r\n /** Whether an alert can watch it (it has lines the price can cross). */\r\n alertable?: boolean;\r\n}\r\n\r\nexport interface DrawingSettingsPatch {\r\n anchors?: AnchorPoint[];\r\n style?: Partial<DrawingStyle>;\r\n options?: DrawingOptions;\r\n}\r\n\r\nexport interface DrawingSettingsCallbacks {\r\n /** The dialog opened on a drawing: edits until `onEnd` are one undo step. */\r\n onBegin: (id: string) => void;\r\n /** An edit, shown on the chart at once. */\r\n onChange: (id: string, patch: DrawingSettingsPatch) => void;\r\n /** OK keeps the edits; Cancel, Escape or the close button put the drawing back. */\r\n onEnd: (id: string, cancel: boolean) => void;\r\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\r\n toWallTime: (time: number) => { date: string; time: string };\r\n fromWallTime: (date: string, time: string) => number | null;\r\n /** Alert when the price crosses the drawing. */\r\n onAddAlert?: (id: string) => void;\r\n /** Make these the options new drawings of the tool start with. */\r\n onSaveDefault?: (type: DrawingToolType, options: DrawingOptions) => void;\r\n /** Saved templates: a style, and the tool's options for those saved from it. */\r\n templates?: {\r\n list: (type: DrawingToolType) => DrawingStyleTemplate[];\r\n save: (name: string, style: Partial<DrawingStyle>, tool: { type: DrawingToolType; options: DrawingOptions }) => void;\r\n remove: (name: string, type?: DrawingToolType) => void;\r\n };\r\n}\r\n\r\ntype Tab = 'style' | 'options' | 'coordinates';\r\n\r\n/** Most points the Coordinates tab lists. */\r\nconst MAX_COORDINATE_ROWS = 12;\r\n\r\nconst LINE_WIDTHS = [1, 2, 3, 4];\r\nconst LINE_STYLES: DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\r\nconst FONT_SIZES = [10, 11, 12, 14, 16, 18, 20, 24, 28, 32];\r\n/** Most levels the editor offers to add, like the chart keeps. */\r\nconst MAX_LEVELS = 48;\r\n\r\nlet nextDialogId = 1;\r\n\r\n/**\r\n * A drawing's settings: its style (colour, width, line, fill and text where\r\n * the tool has them, saved templates), the tool's own options (levels,\r\n * extend left/right…), and its anchors as dates and prices. Edits show on the\r\n * chart at once; OK keeps them as one undo step, Cancel puts it back.\r\n */\r\nexport class WidgetDrawingSettings {\r\n private backdrop: HTMLDivElement;\r\n private modal: HTMLDivElement;\r\n private titleEl: HTMLHeadingElement;\r\n private tabsEl: HTMLDivElement;\r\n private bodyEl: HTMLDivElement;\r\n private footerLeft: HTMLDivElement;\r\n private tabButtons: HTMLButtonElement[] = [];\r\n private target: DrawingSettingsTarget | null = null;\r\n private style!: DrawingStyle;\r\n private options: DrawingOptions = {};\r\n private anchors: AnchorPoint[] = [];\r\n private tab: Tab = 'style';\r\n private returnFocus: HTMLElement | null = null;\r\n private readonly uid = nextDialogId++;\r\n\r\n constructor(\r\n host: HTMLElement,\r\n private readonly callbacks: DrawingSettingsCallbacks,\r\n private readonly t: Translator = EN_TRANSLATOR,\r\n ) {\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.hidden = true;\r\n // A press that starts in the dialog (selecting text, say) and ends on the\r\n // backdrop doesn't close it.\r\n let pressedBackdrop = false;\r\n this.backdrop.addEventListener('pointerdown', (e) => {\r\n pressedBackdrop = e.target === this.backdrop;\r\n });\r\n this.backdrop.addEventListener('click', (e) => {\r\n if (e.target === this.backdrop && pressedBackdrop) this.close(true);\r\n pressedBackdrop = false;\r\n });\r\n\r\n this.modal = document.createElement('div');\r\n this.modal.className = 'tcw-modal tcw-modal-narrow tcw-drawing-settings';\r\n this.modal.setAttribute('role', 'dialog');\r\n this.modal.setAttribute('aria-modal', 'true');\r\n this.modal.setAttribute('aria-labelledby', `tcw-draw-title-${this.uid}`);\r\n this.modal.tabIndex = -1;\r\n this.modal.addEventListener('keydown', (e) => this.onKeyDown(e));\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-modal-header';\r\n this.titleEl = document.createElement('h3');\r\n this.titleEl.id = `tcw-draw-title-${this.uid}`;\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-modal-close';\r\n closeBtn.setAttribute('aria-label', this.t('common.close'));\r\n closeBtn.innerHTML = createIcon('x', 16);\r\n closeBtn.addEventListener('click', () => this.close(true));\r\n header.append(this.titleEl, closeBtn);\r\n\r\n this.tabsEl = document.createElement('div');\r\n this.tabsEl.className = 'tcw-modal-tabs';\r\n this.tabsEl.setAttribute('role', 'tablist');\r\n this.tabsEl.addEventListener('keydown', (e) => this.onTabKey(e));\r\n\r\n this.bodyEl = document.createElement('div');\r\n this.bodyEl.className = 'tcw-modal-body';\r\n this.bodyEl.id = `tcw-draw-panel-${this.uid}`;\r\n this.bodyEl.setAttribute('role', 'tabpanel');\r\n\r\n const footer = document.createElement('div');\r\n footer.className = 'tcw-modal-footer';\r\n this.footerLeft = document.createElement('div');\r\n this.footerLeft.className = 'tcw-drawing-settings-tools';\r\n const cancel = document.createElement('button');\r\n cancel.type = 'button';\r\n cancel.className = 'tcw-reset-link';\r\n cancel.textContent = this.t('common.cancel');\r\n cancel.addEventListener('click', () => this.close(true));\r\n const ok = document.createElement('button');\r\n ok.type = 'button';\r\n ok.className = 'tcw-done-btn';\r\n ok.textContent = this.t('drawingSettings.ok');\r\n ok.addEventListener('click', () => this.close(false));\r\n footer.append(this.footerLeft, cancel, ok);\r\n\r\n this.modal.append(header, this.tabsEl, this.bodyEl, footer);\r\n this.backdrop.appendChild(this.modal);\r\n host.appendChild(this.backdrop);\r\n }\r\n\r\n open(target: DrawingSettingsTarget): void {\r\n if (this.target) this.close(false);\r\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\r\n this.target = target;\r\n this.style = { ...target.style };\r\n this.options = structuredClone(target.options);\r\n this.anchors = target.anchors.map((a) => ({ ...a }));\r\n this.titleEl.textContent = target.name;\r\n this.tab = 'style';\r\n this.callbacks.onBegin(target.id);\r\n try {\r\n this.renderTabs();\r\n this.renderBody();\r\n } catch (err) {\r\n // A drawing the dialog can't show: end the edit it began.\r\n this.target = null;\r\n this.callbacks.onEnd(target.id, true);\r\n throw err;\r\n }\r\n this.backdrop.hidden = false;\r\n (this.tabButtons[0] ?? this.modal).focus();\r\n }\r\n\r\n /** Close the dialog, keeping the edits or (with `cancel`) putting the drawing back. */\r\n close(cancel: boolean): void {\r\n const target = this.target;\r\n if (!target) return;\r\n // A value typed but not yet committed still applies on OK.\r\n const active = document.activeElement;\r\n if (!cancel && (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) && this.modal.contains(active)) {\r\n active.dispatchEvent(new Event('change'));\r\n }\r\n this.target = null;\r\n this.backdrop.hidden = true;\r\n this.callbacks.onEnd(target.id, cancel);\r\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\r\n this.returnFocus = null;\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.target !== null;\r\n }\r\n\r\n /** The drawing being edited, if any. */\r\n editing(): string | null {\r\n return this.target?.id ?? null;\r\n }\r\n\r\n destroy(): void {\r\n this.close(true);\r\n this.backdrop.remove();\r\n }\r\n\r\n // --- Tabs ---\r\n\r\n private tabs(): Tab[] {\r\n const out: Tab[] = ['style'];\r\n if (this.target && Object.keys(this.target.defs).length > 0) out.push('options');\r\n // A freehand stroke has hundreds of points: no table of them.\r\n if (this.target && this.target.anchors.length <= MAX_COORDINATE_ROWS) out.push('coordinates');\r\n return out;\r\n }\r\n\r\n private renderTabs(): void {\r\n this.tabButtons = this.tabs().map((tab) => {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-modal-tab';\r\n btn.id = `tcw-draw-tab-${this.uid}-${tab}`;\r\n btn.setAttribute('role', 'tab');\r\n btn.setAttribute('aria-controls', this.bodyEl.id);\r\n btn.dataset.tab = tab;\r\n btn.textContent = this.t(`drawingSettings.tab.${tab}`);\r\n btn.addEventListener('click', () => this.selectTab(tab));\r\n return btn;\r\n });\r\n this.tabsEl.replaceChildren(...this.tabButtons);\r\n this.markTabs();\r\n }\r\n\r\n private markTabs(): void {\r\n for (const btn of this.tabButtons) {\r\n const selected = btn.dataset.tab === this.tab;\r\n btn.classList.toggle('tcw-active', selected);\r\n btn.setAttribute('aria-selected', String(selected));\r\n btn.tabIndex = selected ? 0 : -1;\r\n if (selected) this.bodyEl.setAttribute('aria-labelledby', btn.id);\r\n }\r\n }\r\n\r\n private selectTab(tab: Tab, focus = false): void {\r\n this.tab = tab;\r\n this.markTabs();\r\n this.renderBody();\r\n if (focus) this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\r\n }\r\n\r\n private onTabKey(e: KeyboardEvent): void {\r\n const tabs = this.tabButtons.map((b) => b.dataset.tab as Tab);\r\n const at = tabs.indexOf(this.tab);\r\n const next = e.key === 'ArrowRight' ? (at + 1) % tabs.length\r\n : e.key === 'ArrowLeft' ? (at - 1 + tabs.length) % tabs.length\r\n : e.key === 'Home' ? 0\r\n : e.key === 'End' ? tabs.length - 1\r\n : -1;\r\n if (next < 0) return;\r\n e.preventDefault();\r\n this.selectTab(tabs[next], true);\r\n }\r\n\r\n /** Escape cancels; Tab stays inside the dialog. */\r\n private onKeyDown(e: KeyboardEvent): void {\r\n if (e.key === 'Escape') {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.close(true);\r\n return;\r\n }\r\n keepTabInside(e, this.modal);\r\n }\r\n\r\n private renderBody(): void {\r\n this.bodyEl.replaceChildren();\r\n this.footerLeft.replaceChildren();\r\n if (!this.target) return;\r\n if (this.target.alertable && this.callbacks.onAddAlert) {\r\n const alert = document.createElement('button');\r\n alert.type = 'button';\r\n alert.className = 'tcw-reset-link tcw-drawing-alert';\r\n alert.innerHTML = `${createIcon('bell', 13)}<span></span>`;\r\n alert.querySelector('span')!.textContent = this.t('drawingSettings.addAlert');\r\n alert.addEventListener('click', () => this.callbacks.onAddAlert?.(this.target!.id));\r\n this.footerLeft.appendChild(alert);\r\n }\r\n const section = document.createElement('div');\r\n section.className = 'tcw-settings-section';\r\n if (this.tab === 'options') this.renderOptions(section);\r\n else if (this.tab === 'coordinates') this.renderCoordinates(section);\r\n else this.renderStyle(section);\r\n this.bodyEl.appendChild(section);\r\n }\r\n\r\n private change(patch: DrawingSettingsPatch): void {\r\n if (this.target) this.callbacks.onChange(this.target.id, patch);\r\n }\r\n\r\n private setStyle(style: Partial<DrawingStyle>): void {\r\n this.style = { ...this.style, ...style };\r\n this.change({ style });\r\n }\r\n\r\n private setOptions(options: DrawingOptions): void {\r\n this.options = { ...this.options, ...structuredClone(options) };\r\n this.change({ options });\r\n }\r\n\r\n // --- Style ---\r\n\r\n private renderStyle(section: HTMLElement): void {\r\n const target = this.target!;\r\n section.appendChild(settingsRow(this.t('drawingSettings.color'), colorInput(this.style.color, (color) => this.setStyle({ color }))));\r\n section.appendChild(settingsRow(this.t('drawingSettings.lineWidth'), selectInput(\r\n LINE_WIDTHS.map((w) => ({ value: String(w), label: `${w} px` })),\r\n String(this.style.lineWidth),\r\n (v) => this.setStyle({ lineWidth: Number(v) }),\r\n )));\r\n section.appendChild(settingsRow(this.t('drawingSettings.lineStyle'), selectInput(\r\n LINE_STYLES.map((s) => ({ value: s, label: this.t(`drawingSettings.lineStyle.${s}`) })),\r\n this.style.lineStyle,\r\n (v) => this.setStyle({ lineStyle: v as DrawingStyle['lineStyle'] }),\r\n )));\r\n if (target.fill) this.renderFill(section);\r\n if (target.text) this.renderText(section);\r\n if (this.callbacks.templates) this.renderTemplates(section);\r\n }\r\n\r\n private renderFill(section: HTMLElement): void {\r\n const current = this.style.fillColor ?? withAlpha(this.style.color, 0.1);\r\n let hex = toHex(current);\r\n let alpha = colorAlpha(current);\r\n const apply = () => this.setStyle({ fillColor: withAlpha(hex, alpha), fillOpacity: alpha });\r\n section.appendChild(settingsRow(this.t('drawingSettings.fill'), colorInput(hex, (v) => {\r\n hex = v;\r\n apply();\r\n })));\r\n section.appendChild(settingsRow(this.t('drawingSettings.opacity'), numberInput(Math.round(alpha * 100), { min: 0, max: 100, step: 5 }, (v) => {\r\n alpha = v / 100;\r\n apply();\r\n })));\r\n }\r\n\r\n private renderText(section: HTMLElement): void {\r\n const text = document.createElement('textarea');\r\n text.className = 'tcw-indi-input tcw-drawing-text';\r\n text.rows = 3;\r\n text.value = this.style.text ?? '';\r\n text.addEventListener('input', () => this.setStyle({ text: text.value }));\r\n section.appendChild(settingsRow(this.t('drawingSettings.text'), text));\r\n section.appendChild(settingsRow(this.t('drawingSettings.fontSize'), selectInput(\r\n FONT_SIZES.map((s) => ({ value: String(s), label: `${s} px` })),\r\n String(this.style.fontSize ?? 12),\r\n (v) => this.setStyle({ fontSize: Number(v) }),\r\n )));\r\n }\r\n\r\n private renderTemplates(section: HTMLElement): void {\r\n const store = this.callbacks.templates!;\r\n const target = this.target!;\r\n const head = document.createElement('div');\r\n head.className = 'tcw-style-subhead';\r\n head.textContent = this.t('drawingStyle.templates');\r\n section.appendChild(head);\r\n\r\n const list = document.createElement('div');\r\n list.className = 'tcw-drawing-templates';\r\n const templates = store.list(target.type);\r\n if (templates.length === 0) {\r\n const empty = document.createElement('div');\r\n empty.className = 'tcw-settings-label';\r\n empty.textContent = this.t('drawingStyle.noTemplates');\r\n list.appendChild(empty);\r\n }\r\n for (const template of templates) {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-style-tmpl';\r\n const apply = document.createElement('button');\r\n apply.type = 'button';\r\n apply.className = 'tcw-style-tmpl-apply';\r\n apply.textContent = template.name;\r\n apply.addEventListener('click', () => {\r\n this.setStyle(template.style);\r\n // Templates come from storage: only options the tool takes apply.\r\n if (template.options) this.setOptions(sanitizeDrawingOptions(target.defs, template.options));\r\n this.renderBody();\r\n });\r\n const remove = document.createElement('button');\r\n remove.type = 'button';\r\n remove.className = 'tcw-style-tmpl-del';\r\n remove.setAttribute('aria-label', this.t('drawingStyle.deleteTemplate'));\r\n remove.innerHTML = createIcon('x', 12);\r\n remove.addEventListener('click', () => {\r\n store.remove(template.name, template.type);\r\n this.renderBody();\r\n });\r\n row.append(apply, remove);\r\n list.appendChild(row);\r\n }\r\n section.appendChild(list);\r\n\r\n const saveRow = document.createElement('div');\r\n saveRow.className = 'tcw-style-save';\r\n const name = document.createElement('input');\r\n name.type = 'text';\r\n name.className = 'tcw-style-name';\r\n name.placeholder = this.t('drawingStyle.templateName');\r\n name.setAttribute('aria-label', this.t('drawingStyle.templateName'));\r\n const save = document.createElement('button');\r\n save.type = 'button';\r\n save.className = 'tcw-style-savebtn';\r\n save.textContent = this.t('common.save');\r\n save.addEventListener('click', () => {\r\n if (!name.value.trim()) return;\r\n store.save(name.value, this.style, { type: target.type, options: this.options });\r\n this.renderBody();\r\n });\r\n saveRow.append(name, save);\r\n section.appendChild(saveRow);\r\n }\r\n\r\n // --- Tool options ---\r\n\r\n /** A label from the widget's strings (`drawingOption.<key>`), else the tool's own. */\r\n private label(key: string, fallback: string): string {\r\n const messageKey = `drawingOption.${key}` as MessageKey;\r\n const text = this.t(messageKey);\r\n return text === messageKey ? fallback : text;\r\n }\r\n\r\n private renderOptions(section: HTMLElement): void {\r\n const target = this.target!;\r\n for (const [key, def] of Object.entries(target.defs)) {\r\n if (def.kind === 'levels') section.appendChild(this.levelsEditor(key, def));\r\n else section.appendChild(settingsRow(this.label(key, def.label), this.optionControl(key, def)));\r\n }\r\n\r\n const reset = document.createElement('button');\r\n reset.type = 'button';\r\n reset.className = 'tcw-reset-link';\r\n reset.textContent = this.t('settings.resetToDefaults');\r\n reset.addEventListener('click', () => {\r\n const defaults: DrawingOptions = {};\r\n for (const [key, def] of Object.entries(target.defs)) defaults[key] = structuredClone(def.default) as DrawingOptions[string];\r\n this.setOptions(defaults);\r\n this.renderBody();\r\n });\r\n this.footerLeft.appendChild(reset);\r\n if (this.callbacks.onSaveDefault) {\r\n const saveDefault = document.createElement('button');\r\n saveDefault.type = 'button';\r\n saveDefault.className = 'tcw-reset-link';\r\n saveDefault.textContent = this.t('drawingSettings.saveDefault');\r\n saveDefault.addEventListener('click', () => this.callbacks.onSaveDefault?.(target.type, structuredClone(this.options)));\r\n this.footerLeft.appendChild(saveDefault);\r\n }\r\n }\r\n\r\n private optionControl(key: string, def: Exclude<DrawingOptionDef, { kind: 'levels' }>): HTMLElement {\r\n const value = this.options[key];\r\n switch (def.kind) {\r\n case 'boolean':\r\n return toggleSwitch(Boolean(value), (v) => this.setOptions({ [key]: v }));\r\n case 'number':\r\n return numberInput(Number(value), { min: def.min, max: def.max, step: def.step }, (v) => this.setOptions({ [key]: v }));\r\n case 'choice':\r\n return selectInput(\r\n def.choices.map((c) => ({ value: c.value, label: this.label(`${key}.${c.value}`, c.label) })),\r\n String(value),\r\n (v) => this.setOptions({ [key]: v }),\r\n );\r\n case 'text': {\r\n const input = document.createElement('input');\r\n input.type = 'text';\r\n input.className = 'tcw-indi-input';\r\n input.value = String(value ?? '');\r\n input.addEventListener('change', () => this.setOptions({ [key]: input.value }));\r\n return input;\r\n }\r\n }\r\n }\r\n\r\n /** One row per level: shown or not, its ratio, its colour, remove; and a button to add one. */\r\n private levelsEditor(key: string, def: Extract<DrawingOptionDef, { kind: 'levels' }>): HTMLElement {\r\n const wrap = document.createElement('div');\r\n wrap.className = 'tcw-levels-editor';\r\n const head = document.createElement('div');\r\n head.className = 'tcw-style-subhead';\r\n head.textContent = this.label(key, def.label);\r\n wrap.appendChild(head);\r\n\r\n const levels = (): DrawingLevel[] => {\r\n const value = this.options[key];\r\n return Array.isArray(value) ? (value as DrawingLevel[]) : [];\r\n };\r\n const commit = (next: DrawingLevel[]) => this.setOptions({ [key]: next });\r\n const grid = document.createElement('div');\r\n grid.className = 'tcw-levels-grid';\r\n levels().forEach((level, index) => {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-level-row';\r\n const visible = document.createElement('input');\r\n visible.type = 'checkbox';\r\n visible.checked = level.visible;\r\n const nth = ` ${index + 1}`; // rows share labels; the number tells them apart\r\n visible.setAttribute('aria-label', this.t('drawingSettings.levelVisible') + nth);\r\n visible.addEventListener('change', () => commit(levels().map((l, i) => (i === index ? { ...l, visible: visible.checked } : l))));\r\n const value = numberInput(level.value, { step: 0.001 }, (v) => commit(levels().map((l, i) => (i === index ? { ...l, value: v } : l))));\r\n value.setAttribute('aria-label', this.t('drawingSettings.levelValue') + nth);\r\n const color = colorInput(level.color ?? this.style.color, (v) => commit(levels().map((l, i) => (i === index ? { ...l, color: v } : l))));\r\n color.setAttribute('aria-label', this.t('drawingSettings.levelColor') + nth);\r\n const remove = document.createElement('button');\r\n remove.type = 'button';\r\n remove.className = 'tcw-level-remove';\r\n remove.setAttribute('aria-label', this.t('drawingSettings.removeLevel') + nth);\r\n remove.innerHTML = createIcon('x', 12);\r\n remove.addEventListener('click', () => {\r\n commit(levels().filter((_, i) => i !== index));\r\n this.renderBody();\r\n });\r\n row.append(visible, value, color, remove);\r\n grid.appendChild(row);\r\n });\r\n wrap.appendChild(grid);\r\n\r\n const add = document.createElement('button');\r\n add.type = 'button';\r\n add.className = 'tcw-reset-link tcw-level-add';\r\n add.textContent = this.t('drawingSettings.addLevel');\r\n add.disabled = levels().length >= MAX_LEVELS;\r\n add.addEventListener('click', () => {\r\n const last = levels().at(-1)?.value ?? 0;\r\n commit([...levels(), { value: Math.round((last + 0.5) * 1000) / 1000, visible: true }]);\r\n this.renderBody();\r\n });\r\n wrap.appendChild(add);\r\n return wrap;\r\n }\r\n\r\n // --- Coordinates ---\r\n\r\n private renderCoordinates(section: HTMLElement): void {\r\n this.anchors.forEach((anchor, index) => {\r\n const head = document.createElement('div');\r\n head.className = 'tcw-style-subhead';\r\n head.textContent = fill(this.t('drawingSettings.point'), { n: index + 1 });\r\n section.appendChild(head);\r\n\r\n const wall = this.callbacks.toWallTime(anchor.time);\r\n const date = document.createElement('input');\r\n date.type = 'date';\r\n date.className = 'tcw-indi-input';\r\n date.value = wall.date;\r\n const time = document.createElement('input');\r\n time.type = 'time';\r\n time.className = 'tcw-indi-input';\r\n time.value = wall.time;\r\n const onTime = () => {\r\n const t = this.callbacks.fromWallTime(date.value, time.value);\r\n if (t === null) return;\r\n this.setAnchor(index, { time: t });\r\n };\r\n date.addEventListener('change', onTime);\r\n time.addEventListener('change', onTime);\r\n section.appendChild(settingsRow(this.t('drawingSettings.date'), date));\r\n section.appendChild(settingsRow(this.t('drawingSettings.time'), time));\r\n section.appendChild(settingsRow(this.t('drawingSettings.price'), numberInput(anchor.price, { step: 'any' }, (price) => this.setAnchor(index, { price }))));\r\n });\r\n }\r\n\r\n private setAnchor(index: number, patch: Partial<AnchorPoint>): void {\r\n this.anchors = this.anchors.map((a, i) => (i === index ? { ...a, ...patch } : a));\r\n this.change({ anchors: this.anchors.map((a) => ({ ...a })) });\r\n }\r\n}\r\n","import { createIcon } from './icons.js';\r\n\r\nexport type ContextMenuEntry =\r\n /** `checked` makes it a switch (ticked when on). */\r\n | { id: string; label: string; icon?: string; danger?: boolean; checked?: boolean }\r\n | 'separator';\r\n\r\n/** Room kept between the menu and the edge it would touch. */\r\nconst MENU_MARGIN = 4;\r\n\r\n/** Where a menu `size` long starts along one axis: after `at`, or before it when it would pass `end`. */\r\nfunction place(at: number, size: number, end: number): number {\r\n const start = at + size > end ? at - size : at;\r\n return Math.max(0, Math.min(start, end - size));\r\n}\r\n\r\n/**\r\n * A small menu opened at a point (a right-click on a drawing, say): arrow\r\n * keys, Home and End move through it, Enter picks, Escape, Tab or a click\r\n * outside close it. Focus returns to where it was.\r\n */\r\nexport class WidgetContextMenu {\r\n private el: HTMLDivElement;\r\n private onPick: ((id: string) => void) | null = null;\r\n private returnFocus: HTMLElement | null = null;\r\n /** The button that opened it: pressing it again is its click's to handle (a toggle). */\r\n private anchor: HTMLElement | null = null;\r\n private readonly onDocPointer = (e: Event) => {\r\n const target = e.target as Node;\r\n if (this.el.contains(target) || this.anchor?.contains(target)) return;\r\n this.close();\r\n };\r\n /** Scrolling, resizing or leaving the window moves the chart from under the menu. */\r\n private readonly onAway = () => this.close();\r\n\r\n constructor(private readonly host: HTMLElement, label: string) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-context-menu';\r\n this.el.setAttribute('role', 'menu');\r\n this.el.setAttribute('aria-label', label);\r\n this.el.hidden = true;\r\n this.el.addEventListener('keydown', (e) => this.onKeyDown(e));\r\n host.appendChild(this.el);\r\n }\r\n\r\n /**\r\n * Open at (`x`, `y`) in the host's coordinates. It opens up or to the left\r\n * of the point when there is no room below or to the right, and stays\r\n * inside both the host and the window.\r\n */\r\n open(entries: readonly ContextMenuEntry[], x: number, y: number, onPick: (id: string) => void, anchor?: HTMLElement): void {\r\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\r\n this.onPick = onPick;\r\n this.anchor = anchor ?? null;\r\n this.el.replaceChildren(...entries.map((entry) => this.entry(entry)));\r\n this.el.hidden = false;\r\n const hostRect = this.host.getBoundingClientRect();\r\n const right = Math.min(this.host.clientWidth, window.innerWidth - hostRect.left) - MENU_MARGIN;\r\n const bottom = Math.min(this.host.clientHeight, window.innerHeight - hostRect.top) - MENU_MARGIN;\r\n this.el.style.left = `${place(x, this.el.offsetWidth, right)}px`;\r\n this.el.style.top = `${place(y, this.el.offsetHeight, bottom)}px`;\r\n document.addEventListener('pointerdown', this.onDocPointer, true);\r\n document.addEventListener('wheel', this.onAway, { capture: true, passive: true });\r\n window.addEventListener('resize', this.onAway);\r\n window.addEventListener('blur', this.onAway);\r\n this.items()[0]?.focus({ preventScroll: true });\r\n }\r\n\r\n close(): void {\r\n if (this.el.hidden) return;\r\n this.el.hidden = true;\r\n this.onPick = null;\r\n this.anchor = null;\r\n document.removeEventListener('pointerdown', this.onDocPointer, true);\r\n document.removeEventListener('wheel', this.onAway, { capture: true });\r\n window.removeEventListener('resize', this.onAway);\r\n window.removeEventListener('blur', this.onAway);\r\n if (this.returnFocus?.isConnected) this.returnFocus.focus({ preventScroll: true });\r\n this.returnFocus = null;\r\n }\r\n\r\n isOpen(): boolean {\r\n return !this.el.hidden;\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n this.el.remove();\r\n }\r\n\r\n private entry(entry: ContextMenuEntry): HTMLElement {\r\n if (entry === 'separator') {\r\n const sep = document.createElement('div');\r\n sep.className = 'tcw-context-sep';\r\n sep.setAttribute('role', 'separator');\r\n return sep;\r\n }\r\n const item = document.createElement('button');\r\n item.type = 'button';\r\n item.className = `tcw-context-item${entry.danger ? ' tcw-context-danger' : ''}`;\r\n item.setAttribute('role', entry.checked === undefined ? 'menuitem' : 'menuitemcheckbox');\r\n if (entry.checked !== undefined) item.setAttribute('aria-checked', String(entry.checked));\r\n item.tabIndex = -1;\r\n item.dataset.id = entry.id;\r\n // A switch shows a tick when on, and room for one when off.\r\n const icon = entry.checked !== undefined ? (entry.checked ? 'check' : '') : entry.icon ?? '';\r\n item.innerHTML = icon ? createIcon(icon, 14) : '<span class=\"tcw-context-icon\"></span>';\r\n const text = document.createElement('span');\r\n text.textContent = entry.label;\r\n item.appendChild(text);\r\n item.addEventListener('click', () => this.pick(entry.id));\r\n return item;\r\n }\r\n\r\n private pick(id: string): void {\r\n const onPick = this.onPick;\r\n this.close();\r\n onPick?.(id);\r\n }\r\n\r\n private items(): HTMLButtonElement[] {\r\n return [...this.el.querySelectorAll<HTMLButtonElement>('[role=menuitem], [role=menuitemcheckbox]')];\r\n }\r\n\r\n private onKeyDown(e: KeyboardEvent): void {\r\n const items = this.items();\r\n const at = items.indexOf(document.activeElement as HTMLButtonElement);\r\n let next = -1;\r\n if (e.key === 'ArrowDown') next = (at + 1) % items.length;\r\n else if (e.key === 'ArrowUp') next = (at - 1 + items.length) % items.length;\r\n else if (e.key === 'Home') next = 0;\r\n else if (e.key === 'End') next = items.length - 1;\r\n else if (e.key === 'Escape' || e.key === 'Tab') {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.close();\r\n return;\r\n } else return;\r\n e.preventDefault();\r\n items[next]?.focus({ preventScroll: true });\r\n }\r\n}\r\n","import type { ContextMenuEntry } from './WidgetContextMenu.js';\r\nimport type { Translator } from './i18n.js';\r\n\r\n/** What a right-clicked drawing's menu can do. */\r\nexport type DrawingMenuAction =\r\n | 'settings' | 'alert'\r\n | 'front' | 'forward' | 'backward' | 'back'\r\n | 'group' | 'ungroup'\r\n | 'lock' | 'unlock' | 'hide' | 'duplicate' | 'delete';\r\n\r\n/** The right-clicked drawing and the selection it is part of. */\r\nexport interface DrawingMenuTarget {\r\n /** Selected drawings: the right-clicked one, its group, or a selection it was part of. */\r\n selected: readonly { id: string; locked: boolean; groupId: string | null }[];\r\n canConfigure: boolean;\r\n canAlert: boolean;\r\n}\r\n\r\n/**\r\n * The menu's entries: settings and alert for one drawing, order, grouping,\r\n * then lock, hide, duplicate and delete for the whole selection.\r\n */\r\nexport function drawingMenuEntries(target: DrawingMenuTarget, t: Translator): ContextMenuEntry[] {\r\n const { selected } = target;\r\n const single = selected.length === 1;\r\n const groups = new Set(selected.map((d) => d.groupId));\r\n const oneGroup = groups.size === 1 && !groups.has(null);\r\n const entries: ContextMenuEntry[] = [];\r\n if (target.canConfigure && single) entries.push({ id: 'settings', label: t('drawingMenu.settings'), icon: 'settings' });\r\n if (target.canAlert && single) entries.push({ id: 'alert', label: t('drawingSettings.addAlert'), icon: 'bell' });\r\n if (entries.length > 0) entries.push('separator');\r\n if (single) {\r\n entries.push(\r\n { id: 'front', label: t('drawingMenu.front') },\r\n { id: 'forward', label: t('drawingMenu.forward') },\r\n { id: 'backward', label: t('drawingMenu.backward') },\r\n { id: 'back', label: t('drawingMenu.back') },\r\n 'separator',\r\n );\r\n }\r\n if (selected.length > 1 && !oneGroup) entries.push({ id: 'group', label: t('drawingMenu.group'), icon: 'layers' });\r\n if (selected.some((d) => d.groupId)) entries.push({ id: 'ungroup', label: t('drawingMenu.ungroup'), icon: 'layers' });\r\n const locked = selected.every((d) => d.locked);\r\n entries.push(\r\n locked\r\n ? { id: 'unlock', label: t('common.unlock'), icon: 'unlock' }\r\n : { id: 'lock', label: t('common.lock'), icon: 'lock' },\r\n { id: 'hide', label: t('common.hide'), icon: 'eyeOff' },\r\n );\r\n if (single) entries.push({ id: 'duplicate', label: t('drawingMenu.duplicate'), icon: 'plus' });\r\n if (!locked) entries.push('separator', { id: 'delete', label: t('drawingMenu.delete'), icon: 'trash', danger: true });\r\n return entries;\r\n}\r\n","import type { ChartContextArea, PriceScaleMode } from '@tradecanvas/commons';\r\nimport type { ContextMenuEntry } from './WidgetContextMenu.js';\r\nimport { fill, type Translator } from './i18n.js';\r\n\r\n/** What a menu on the chart (a right-click, or the \"+\" by the price axis) can do. */\r\nexport type ChartMenuAction =\r\n | 'alert' | 'buyLimit' | 'buyStop' | 'sellLimit' | 'sellStop' | 'orderTicket' | 'horizontalLine'\r\n | 'resetView' | 'hideDrawings' | 'showDrawings' | 'removeDrawings' | 'settings' | 'exportData'\r\n | 'autoScale' | 'logScale' | 'percentScale' | 'invertScale'\r\n | 'goToDate'\r\n | 'paneLog'\r\n | 'paneInvert'\r\n | 'panePercent';\r\n\r\n/** What the widget can do here, and how the chart is set now. */\r\nexport interface ChartMenuContext {\r\n /** The price at the click (the price pane, the price axis, the \"+\"). */\r\n price?: number;\r\n /** The latest price, to tell a limit from a stop. */\r\n lastPrice: number | null;\r\n formatPrice: (price: number) => string;\r\n canAlert: boolean;\r\n canTrade: boolean;\r\n /** An order ticket to open (the account panel is on). */\r\n canOrderTicket?: boolean;\r\n canDraw: boolean;\r\n hasDrawings: boolean;\r\n drawingsHidden: boolean;\r\n canGoToDate: boolean;\r\n /** A download of the bars and indicator lines (`features.dataExport`). */\r\n canExport?: boolean;\r\n autoScale: boolean;\r\n scaleMode: PriceScaleMode;\r\n inverted: boolean;\r\n /** For a pane's menu: its scale switches. */\r\n pane?: { log: boolean; invert: boolean; percent: boolean };\r\n}\r\n\r\n/**\r\n * What to do at a price: an alert, a buy and a sell (a limit on the side of\r\n * the market it would wait on, else a stop), a horizontal line.\r\n */\r\nexport function priceEntries(ctx: ChartMenuContext, t: Translator): ContextMenuEntry[] {\r\n if (ctx.price === undefined || !Number.isFinite(ctx.price)) return [];\r\n const price = ctx.formatPrice(ctx.price);\r\n const entries: ContextMenuEntry[] = [];\r\n if (ctx.canAlert) entries.push({ id: 'alert', label: fill(t('chartMenu.addAlert'), { price }), icon: 'bell' });\r\n if (ctx.canTrade) {\r\n // Below the market a buy waits as a limit and a sell as a stop; above, the other way round.\r\n const below = ctx.lastPrice === null || ctx.price <= ctx.lastPrice;\r\n entries.push(\r\n below\r\n ? { id: 'buyLimit', label: fill(t('chartMenu.buyLimit'), { price }), icon: 'trendingUp' }\r\n : { id: 'buyStop', label: fill(t('chartMenu.buyStop'), { price }), icon: 'trendingUp' },\r\n below\r\n ? { id: 'sellStop', label: fill(t('chartMenu.sellStop'), { price }), icon: 'trendingDown' }\r\n : { id: 'sellLimit', label: fill(t('chartMenu.sellLimit'), { price }), icon: 'trendingDown' },\r\n );\r\n if (ctx.canOrderTicket) entries.push({ id: 'orderTicket', label: t('chartMenu.orderTicket'), icon: 'receipt' });\r\n }\r\n if (ctx.canDraw) entries.push({ id: 'horizontalLine', label: fill(t('chartMenu.horizontalLine'), { price }), icon: 'minus' });\r\n return entries;\r\n}\r\n\r\n/** The right-click menu for where it landed. */\r\nexport function chartMenuEntries(area: ChartContextArea, ctx: ChartMenuContext, t: Translator): ContextMenuEntry[] {\r\n const withPrice = (rest: ContextMenuEntry[]): ContextMenuEntry[] => {\r\n const atPrice = priceEntries(ctx, t);\r\n return atPrice.length > 0 ? [...atPrice, 'separator', ...rest] : rest;\r\n };\r\n const settings: ContextMenuEntry = { id: 'settings', label: t('chartMenu.settings'), icon: 'settings' };\r\n switch (area) {\r\n case 'priceAxis': {\r\n // On the axis, only an alert is offered at the price.\r\n const alert = priceEntries({ ...ctx, canTrade: false, canDraw: false }, t);\r\n return [\r\n { id: 'autoScale', label: t('settings.autoScale'), checked: ctx.autoScale },\r\n { id: 'logScale', label: t('settings.scale.logarithmic'), checked: ctx.scaleMode === 'logarithmic' },\r\n { id: 'percentScale', label: t('settings.scale.percentage'), checked: ctx.scaleMode === 'percentage' },\r\n { id: 'invertScale', label: t('chartMenu.invertScale'), checked: ctx.inverted },\r\n ...(alert.length > 0 ? ['separator' as const, ...alert] : []),\r\n ];\r\n }\r\n case 'timeAxis':\r\n return [\r\n { id: 'resetView', label: t('chartMenu.resetTimeScale') },\r\n ...(ctx.canGoToDate ? [{ id: 'goToDate', label: t('chartMenu.goToDate'), icon: 'calendar' }] : []),\r\n ];\r\n case 'pane':\r\n return [\r\n { id: 'resetView', label: t('chartMenu.resetView') },\r\n ...(ctx.pane\r\n ? ['separator' as const,\r\n { id: 'paneLog', label: t('chartMenu.paneLog'), checked: ctx.pane.log },\r\n { id: 'paneInvert', label: t('chartMenu.paneInvert'), checked: ctx.pane.invert },\r\n { id: 'panePercent', label: t('chartMenu.panePercent'), checked: ctx.pane.percent }]\r\n : []),\r\n 'separator',\r\n settings,\r\n ];\r\n default: {\r\n const drawings: ContextMenuEntry[] = ctx.hasDrawings\r\n ? [\r\n ctx.drawingsHidden\r\n ? { id: 'showDrawings', label: t('chartMenu.showDrawings'), icon: 'eye' }\r\n : { id: 'hideDrawings', label: t('chartMenu.hideDrawings'), icon: 'eyeOff' },\r\n { id: 'removeDrawings', label: t('chartMenu.removeDrawings'), icon: 'trash', danger: true },\r\n ]\r\n : [];\r\n const exportData: ContextMenuEntry[] = ctx.canExport ? [{ id: 'exportData', label: t('chartMenu.exportData'), icon: 'save' }] : [];\r\n return withPrice([{ id: 'resetView', label: t('chartMenu.resetView') }, ...drawings, ...exportData, 'separator', settings]);\r\n }\r\n }\r\n}\r\n","import type { FillEvent, TradingOrder, TradingPosition } from '@tradecanvas/commons';\r\nimport { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, fill, type MessageKey, type Translator } from './i18n.js';\r\n\r\nexport interface AccountPanelCallbacks {\r\n onClosePosition: (id: string) => void;\r\n onReversePosition: (id: string) => void;\r\n onCancelOrder: (id: string) => void;\r\n onNewOrder: () => void;\r\n formatPrice: (price: number) => string;\r\n formatTime: (ms: number) => string;\r\n /** Called when the panel opens or closes (the chart above resizes). */\r\n onToggle?: (open: boolean) => void;\r\n}\r\n\r\nexport interface AccountSnapshot {\r\n positions: readonly TradingPosition[];\r\n orders: readonly TradingOrder[];\r\n fills: readonly FillEvent[];\r\n /** The latest price, for the positions' profit and loss. */\r\n price: number | null;\r\n /** The P&L realised by every fill (the list may keep only the latest); else the listed fills' sum. */\r\n realisedPnl?: number;\r\n}\r\n\r\ntype Tab = 'positions' | 'orders' | 'history';\r\nconst TABS: readonly Tab[] = ['positions', 'orders', 'history'];\r\nconst REASONS = ['order', 'close', 'reverse', 'stopLoss', 'takeProfit'] as const;\r\nconst ORDER_TYPES = ['market', 'limit', 'stop'] as const;\r\nconst TIME_IN_FORCE = ['gtc', 'day'] as const;\r\n\r\n/** `value` when it is one of `known`, else `fallback` (a host may send what the panel has no words for). */\r\nfunction known<T extends string>(known: readonly T[], value: string | undefined, fallback: T): T {\r\n return (known as readonly string[]).includes(value ?? '') ? (value as T) : fallback;\r\n}\r\n\r\n/** Same rows: the same objects in the same order (a tick changes only the price). */\r\nfunction sameRows(a: readonly object[], b: readonly object[]): boolean {\r\n return a.length === b.length && a.every((row, i) => row === b[i]);\r\n}\r\n\r\n/** The cells a tick changes on an open position's row. */\r\ninterface LiveCells {\r\n position: TradingPosition;\r\n price: HTMLTableCellElement;\r\n pnl: HTMLSpanElement;\r\n}\r\n\r\n/** A position's open profit or loss at `price`, and as a percent of what went in. */\r\nexport function positionPnl(position: TradingPosition, price: number | null): { pnl: number; pct: number } | null {\r\n if (price === null) return null;\r\n const open = position.quantity - (position.closedQuantity ?? 0);\r\n const direction = position.side === 'buy' ? 1 : -1;\r\n const pnl = (price - position.entryPrice) * open * direction;\r\n const pct = position.entryPrice !== 0 ? ((price - position.entryPrice) / position.entryPrice) * 100 * direction : 0;\r\n return { pnl, pct };\r\n}\r\n\r\nfunction signed(value: number, decimals = 2): string {\r\n return `${value > 0 ? '+' : ''}${value.toFixed(decimals)}`;\r\n}\r\n\r\n/**\r\n * The account at the bottom of the widget: open positions with their profit\r\n * and loss, working orders, and the fills so far, each with its actions\r\n * (close, reverse, cancel), and a button for a new order.\r\n */\r\nexport class WidgetAccountPanel {\r\n private el: HTMLElement;\r\n private tabButtons = new Map<Tab, HTMLButtonElement>();\r\n private content: HTMLDivElement;\r\n private tab: Tab = 'positions';\r\n private snapshot: AccountSnapshot = { positions: [], orders: [], fills: [], price: null };\r\n private open = false;\r\n private live: LiveCells[] = [];\r\n\r\n constructor(host: HTMLElement, private readonly callbacks: AccountPanelCallbacks, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.el = document.createElement('section');\r\n this.el.className = 'tcw-account';\r\n this.el.hidden = true;\r\n this.el.setAttribute('aria-label', this.t('account.title'));\r\n\r\n const head = document.createElement('div');\r\n head.className = 'tcw-account-head';\r\n const tabs = document.createElement('div');\r\n tabs.className = 'tcw-account-tabs';\r\n tabs.setAttribute('role', 'tablist');\r\n tabs.addEventListener('keydown', (e) => this.onTabKey(e));\r\n for (const tab of TABS) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-account-tab';\r\n btn.setAttribute('role', 'tab');\r\n btn.id = `tcw-account-tab-${tab}`;\r\n btn.addEventListener('click', () => this.selectTab(tab));\r\n this.tabButtons.set(tab, btn);\r\n tabs.appendChild(btn);\r\n }\r\n const newOrder = document.createElement('button');\r\n newOrder.type = 'button';\r\n newOrder.className = 'tcw-account-new';\r\n newOrder.innerHTML = createIcon('plus', 13);\r\n newOrder.append(this.t('account.newOrder'));\r\n newOrder.addEventListener('click', () => this.callbacks.onNewOrder());\r\n const close = document.createElement('button');\r\n close.type = 'button';\r\n close.className = 'tcw-tree-close';\r\n close.setAttribute('aria-label', this.t('account.close'));\r\n close.innerHTML = createIcon('x', 14);\r\n close.addEventListener('click', () => this.closePanel());\r\n head.append(tabs, newOrder, close);\r\n\r\n this.content = document.createElement('div');\r\n this.content.className = 'tcw-account-body';\r\n this.content.setAttribute('role', 'tabpanel');\r\n this.el.append(head, this.content);\r\n host.appendChild(this.el);\r\n this.renderTabs();\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.open;\r\n }\r\n\r\n toggle(): void {\r\n if (this.open) this.closePanel();\r\n else this.openPanel();\r\n }\r\n\r\n openPanel(): void {\r\n this.open = true;\r\n this.el.hidden = false;\r\n this.render();\r\n this.callbacks.onToggle?.(true);\r\n }\r\n\r\n closePanel(): void {\r\n if (!this.open) return;\r\n this.open = false;\r\n this.el.hidden = true;\r\n this.callbacks.onToggle?.(false);\r\n }\r\n\r\n /**\r\n * New positions, orders, fills or price; the tabs' counts follow, the open\r\n * tab redraws. A new price alone only rewrites the price and P&L cells, so\r\n * a tick never takes a button from under the pointer or the focus.\r\n */\r\n update(snapshot: AccountSnapshot): void {\r\n const before = this.snapshot;\r\n this.snapshot = snapshot;\r\n const rowsSame = sameRows(before.positions, snapshot.positions)\r\n && sameRows(before.orders, snapshot.orders)\r\n && sameRows(before.fills, snapshot.fills)\r\n && before.realisedPnl === snapshot.realisedPnl;\r\n if (rowsSame) {\r\n if (this.open && this.tab === 'positions' && before.price !== snapshot.price) this.patchPrices();\r\n return;\r\n }\r\n this.renderTabs();\r\n if (this.open) this.render();\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n private selectTab(tab: Tab): void {\r\n this.tab = tab;\r\n this.renderTabs();\r\n this.render();\r\n }\r\n\r\n /** Left and Right move between the tabs. */\r\n private onTabKey(e: KeyboardEvent): void {\r\n const at = TABS.indexOf(this.tab);\r\n const next = e.key === 'ArrowRight' ? at + 1 : e.key === 'ArrowLeft' ? at - 1 : -2;\r\n if (next === -2) return;\r\n e.preventDefault();\r\n const tab = TABS[(next + TABS.length) % TABS.length];\r\n this.selectTab(tab);\r\n this.tabButtons.get(tab)?.focus();\r\n }\r\n\r\n private renderTabs(): void {\r\n const counts: Record<Tab, number> = {\r\n positions: this.snapshot.positions.length,\r\n orders: this.snapshot.orders.length,\r\n history: this.snapshot.fills.length,\r\n };\r\n for (const [tab, btn] of this.tabButtons) {\r\n const selected = tab === this.tab;\r\n btn.textContent = `${this.t(`account.${tab}` as MessageKey)} (${counts[tab]})`;\r\n btn.setAttribute('aria-selected', String(selected));\r\n btn.tabIndex = selected ? 0 : -1;\r\n if (selected) this.content.setAttribute('aria-labelledby', btn.id);\r\n }\r\n }\r\n\r\n private render(): void {\r\n // The button in use keeps focus through the rebuild (the same action on the same row).\r\n const active = document.activeElement;\r\n const focused = active instanceof HTMLElement && this.content.contains(active) ? active.dataset.focusKey : undefined;\r\n this.live = [];\r\n if (this.tab === 'positions') this.renderPositions();\r\n else if (this.tab === 'orders') this.renderOrders();\r\n else this.renderHistory();\r\n if (focused) [...this.content.querySelectorAll<HTMLElement>('[data-focus-key]')].find((el) => el.dataset.focusKey === focused)?.focus();\r\n }\r\n\r\n /** The price and P&L cells, rewritten in place. */\r\n private patchPrices(): void {\r\n const { price } = this.snapshot;\r\n for (const cells of this.live) {\r\n cells.price.textContent = price === null ? '—' : this.callbacks.formatPrice(price);\r\n this.writePnl(cells.pnl, positionPnl(cells.position, price));\r\n }\r\n }\r\n\r\n private writePnl(span: HTMLSpanElement, result: { pnl: number; pct: number } | null): void {\r\n span.className = result === null ? '' : result.pnl >= 0 ? 'tcw-account-up' : 'tcw-account-down';\r\n span.textContent = result === null ? '—' : `${signed(result.pnl)} (${signed(result.pct)}%)`;\r\n }\r\n\r\n private table(columns: readonly MessageKey[], rows: HTMLTableRowElement[], empty: MessageKey): void {\r\n if (rows.length === 0) {\r\n const p = document.createElement('p');\r\n p.className = 'tcw-account-empty';\r\n p.textContent = this.t(empty);\r\n this.content.replaceChildren(p);\r\n return;\r\n }\r\n const table = document.createElement('table');\r\n table.className = 'tcw-account-table';\r\n const head = table.createTHead().insertRow();\r\n for (const key of columns) {\r\n const th = document.createElement('th');\r\n th.scope = 'col';\r\n th.textContent = key ? this.t(key) : '';\r\n head.appendChild(th);\r\n }\r\n table.createTBody().append(...rows);\r\n this.content.replaceChildren(table);\r\n }\r\n\r\n private row(cells: readonly (string | HTMLElement)[], className = ''): HTMLTableRowElement {\r\n const tr = document.createElement('tr');\r\n if (className) tr.className = className;\r\n for (const cell of cells) {\r\n const td = tr.insertCell();\r\n if (typeof cell === 'string') td.textContent = cell;\r\n else td.appendChild(cell);\r\n }\r\n return tr;\r\n }\r\n\r\n /** Long or Short for a position; Buy or Sell for an order or a fill (closing a long is a sell). */\r\n private sideCell(side: 'buy' | 'sell', kind: 'position' | 'trade' = 'position'): HTMLElement {\r\n const span = document.createElement('span');\r\n span.className = `tcw-account-side tcw-account-${side}`;\r\n span.textContent = this.sideText(side, kind);\r\n return span;\r\n }\r\n\r\n private sideText(side: 'buy' | 'sell', kind: 'position' | 'trade'): string {\r\n if (kind === 'trade') return this.t(side === 'buy' ? 'ticket.buy' : 'ticket.sell');\r\n return this.t(side === 'buy' ? 'account.long' : 'account.short');\r\n }\r\n\r\n private actions(...buttons: { icon: string; label: string; key: string; run: () => void; danger?: boolean }[]): HTMLElement {\r\n const wrap = document.createElement('div');\r\n wrap.className = 'tcw-account-actions';\r\n for (const b of buttons) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = `tcw-tree-btn${b.danger ? ' tcw-tree-del' : ''}`;\r\n btn.setAttribute('aria-label', b.label);\r\n btn.title = b.label;\r\n btn.dataset.focusKey = b.key;\r\n btn.innerHTML = createIcon(b.icon, 14);\r\n btn.addEventListener('click', b.run);\r\n wrap.appendChild(btn);\r\n }\r\n return wrap;\r\n }\r\n\r\n private renderPositions(): void {\r\n const { formatPrice } = this.callbacks;\r\n const { price } = this.snapshot;\r\n const rows = this.snapshot.positions.map((p) => {\r\n const open = p.quantity - (p.closedQuantity ?? 0);\r\n const pnl = document.createElement('span');\r\n this.writePnl(pnl, positionPnl(p, price));\r\n // \"Close position: Long 2 @ 100.00\", so each row's buttons say which.\r\n const which = `${this.sideText(p.side, 'position')} ${open} @ ${formatPrice(p.entryPrice)}`;\r\n const tr = this.row([\r\n this.sideCell(p.side),\r\n String(open),\r\n formatPrice(p.entryPrice),\r\n price === null ? '—' : formatPrice(price),\r\n pnl,\r\n p.stopLoss === undefined ? '—' : formatPrice(p.stopLoss),\r\n p.takeProfit === undefined ? '—' : formatPrice(p.takeProfit),\r\n this.actions(\r\n { icon: 'repeat', label: `${this.t('account.reverse')}: ${which}`, key: `reverse:${p.id}`, run: () => this.callbacks.onReversePosition(p.id) },\r\n { icon: 'x', label: `${this.t('account.closePosition')}: ${which}`, key: `close:${p.id}`, run: () => this.callbacks.onClosePosition(p.id), danger: true },\r\n ),\r\n ]);\r\n this.live.push({ position: p, price: tr.cells[3], pnl });\r\n return tr;\r\n });\r\n this.table(\r\n ['account.side', 'account.quantity', 'account.entry', 'account.price', 'account.pnl', 'account.stopLoss', 'account.takeProfit', 'account.actions'],\r\n rows,\r\n 'account.noPositions',\r\n );\r\n }\r\n\r\n private renderOrders(): void {\r\n const { formatPrice } = this.callbacks;\r\n const rows = this.snapshot.orders.map((o) => {\r\n const type = known(ORDER_TYPES, o.type === 'stopLimit' ? 'stop' : o.type, 'limit');\r\n const which = `${this.sideText(o.side, 'trade')} ${o.quantity} @ ${formatPrice(o.price)}`;\r\n return this.row([\r\n this.sideCell(o.side, 'trade'),\r\n this.t(`ticket.type.${type}` as MessageKey),\r\n String(o.quantity),\r\n formatPrice(o.price),\r\n o.stopLoss === undefined ? '—' : formatPrice(o.stopLoss),\r\n o.takeProfit === undefined ? '—' : formatPrice(o.takeProfit),\r\n o.timeInForce ? this.t(`ticket.tif.${known(TIME_IN_FORCE, o.timeInForce, 'gtc')}` as MessageKey) : '—',\r\n this.actions({ icon: 'x', label: `${this.t('account.cancelOrder')}: ${which}`, key: `cancel:${o.id}`, run: () => this.callbacks.onCancelOrder(o.id), danger: true }),\r\n ]);\r\n });\r\n this.table(\r\n ['account.side', 'ticket.type', 'account.quantity', 'account.price', 'account.stopLoss', 'account.takeProfit', 'ticket.timeInForce', 'account.actions'],\r\n rows,\r\n 'account.noOrders',\r\n );\r\n }\r\n\r\n private renderHistory(): void {\r\n const { formatPrice, formatTime } = this.callbacks;\r\n // The newest first.\r\n const rows = [...this.snapshot.fills].reverse().map((f) => {\r\n const pnl = document.createElement('span');\r\n if (f.pnl !== undefined) {\r\n pnl.className = f.pnl >= 0 ? 'tcw-account-up' : 'tcw-account-down';\r\n pnl.textContent = signed(f.pnl);\r\n } else {\r\n pnl.textContent = '—';\r\n }\r\n return this.row([\r\n formatTime(f.time),\r\n this.sideCell(f.side, 'trade'),\r\n String(f.quantity),\r\n formatPrice(f.price),\r\n this.t(`account.reason.${known(REASONS, f.reason, 'order')}` as MessageKey),\r\n pnl,\r\n ]);\r\n });\r\n this.table(['account.time', 'account.side', 'account.quantity', 'account.price', 'account.reason', 'account.pnl'], rows, 'account.noFills');\r\n const total = this.snapshot.realisedPnl ?? this.snapshot.fills.reduce((sum, f) => sum + (f.pnl ?? 0), 0);\r\n if (rows.length > 0) {\r\n const summary = document.createElement('p');\r\n summary.className = 'tcw-account-summary';\r\n summary.textContent = fill(this.t('account.realised'), { pnl: signed(total) });\r\n this.content.appendChild(summary);\r\n }\r\n }\r\n}\r\n","import type { OrderPlaceIntent, OrderSide, TimeInForce } from '@tradecanvas/commons';\r\n\r\n/** What the order ticket holds while it is filled in. */\r\nexport interface OrderTicketDraft {\r\n side: OrderSide;\r\n type: 'market' | 'limit' | 'stop';\r\n quantity: number;\r\n /** The limit or stop price (a market order fills at the market). */\r\n price: number;\r\n stopLoss: number | null;\r\n takeProfit: number | null;\r\n timeInForce: TimeInForce;\r\n}\r\n\r\n/** What is wrong with a draft, as message keys. */\r\nexport type OrderTicketProblem =\r\n | 'quantity'\r\n | 'price'\r\n /** A market order with no market price to fill at (no bars yet). */\r\n | 'market'\r\n | 'stopLoss'\r\n | 'takeProfit'\r\n | 'stopLossSide'\r\n | 'takeProfitSide'\r\n | 'limitSide'\r\n | 'stopSide';\r\n\r\n/**\r\n * Where the position would start: the limit or stop price, or the market for\r\n * a market order.\r\n */\r\nfunction entryOf(draft: OrderTicketDraft, lastPrice: number | null): number | null {\r\n return draft.type === 'market' ? lastPrice : draft.price;\r\n}\r\n\r\n/**\r\n * The problems with a draft: a quantity or price that isn't positive, a stop-loss\r\n * or take-profit on the wrong side of the entry, a limit or stop on the wrong side\r\n * of the market (it would fill at once).\r\n */\r\nexport function orderTicketProblems(draft: OrderTicketDraft, lastPrice: number | null): OrderTicketProblem[] {\r\n const problems: OrderTicketProblem[] = [];\r\n if (!(draft.quantity > 0) || !Number.isFinite(draft.quantity)) problems.push('quantity');\r\n if (draft.type !== 'market' && (!(draft.price > 0) || !Number.isFinite(draft.price))) problems.push('price');\r\n if (draft.type === 'market' && !((lastPrice ?? draft.price) > 0)) problems.push('market');\r\n const buy = draft.side === 'buy';\r\n if (lastPrice !== null && draft.type !== 'market' && draft.price > 0) {\r\n // A buy limit waits below the market, a buy stop above it; a sell the other way.\r\n const below = draft.price < lastPrice;\r\n if (draft.type === 'limit' && below !== buy && draft.price !== lastPrice) problems.push('limitSide');\r\n if (draft.type === 'stop' && below === buy && draft.price !== lastPrice) problems.push('stopSide');\r\n }\r\n const valid = (price: number | null) => price === null || (Number.isFinite(price) && price > 0);\r\n if (!valid(draft.stopLoss)) problems.push('stopLoss');\r\n if (!valid(draft.takeProfit)) problems.push('takeProfit');\r\n const entry = entryOf(draft, lastPrice);\r\n if (entry !== null && entry > 0) {\r\n if (draft.stopLoss !== null && valid(draft.stopLoss) && (buy ? draft.stopLoss >= entry : draft.stopLoss <= entry)) problems.push('stopLossSide');\r\n if (draft.takeProfit !== null && valid(draft.takeProfit) && (buy ? draft.takeProfit <= entry : draft.takeProfit >= entry)) problems.push('takeProfitSide');\r\n }\r\n return problems;\r\n}\r\n\r\n/** The order a draft asks for. */\r\nexport function orderTicketIntent(draft: OrderTicketDraft, lastPrice: number | null): OrderPlaceIntent {\r\n const intent: OrderPlaceIntent = {\r\n side: draft.side,\r\n type: draft.type,\r\n price: draft.type === 'market' ? lastPrice ?? draft.price : draft.price,\r\n quantity: draft.quantity,\r\n };\r\n if (draft.type === 'stop') intent.stopPrice = draft.price;\r\n if (draft.type !== 'market') intent.timeInForce = draft.timeInForce;\r\n if (draft.stopLoss !== null) intent.stopLoss = draft.stopLoss;\r\n if (draft.takeProfit !== null) intent.takeProfit = draft.takeProfit;\r\n return intent;\r\n}\r\n\r\n/** Reward over risk for a draft with both a stop-loss and a take-profit, or null. */\r\nexport function orderTicketRiskReward(draft: OrderTicketDraft, lastPrice: number | null): number | null {\r\n const entry = entryOf(draft, lastPrice);\r\n if (entry === null || draft.stopLoss === null || draft.takeProfit === null) return null;\r\n const risk = Math.abs(entry - draft.stopLoss);\r\n return risk > 0 ? Math.abs(draft.takeProfit - entry) / risk : null;\r\n}\r\n","import type { OrderPlaceIntent, OrderSide, TimeInForce } from '@tradecanvas/commons';\r\nimport { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, fill, type MessageKey, type Translator } from './i18n.js';\r\nimport { selectInput, settingsRow, toggleSwitch } from './settingsControls.js';\r\nimport { keepTabInside } from './focusTrap.js';\r\nimport {\r\n orderTicketIntent,\r\n orderTicketProblems,\r\n orderTicketRiskReward,\r\n type OrderTicketDraft,\r\n} from './orderTicket.js';\r\n\r\nexport interface OrderTicketCallbacks {\r\n onSubmit: (intent: OrderPlaceIntent) => void;\r\n formatPrice: (price: number) => string;\r\n}\r\n\r\n/** Where a ticket starts: a side and a price (a click on the chart), and the market. */\r\nexport interface OrderTicketStart {\r\n side?: OrderSide;\r\n price?: number;\r\n lastPrice: number | null;\r\n}\r\n\r\nlet ticketSeq = 0;\r\n\r\n/**\r\n * An order ticket: side, type, quantity, price, stop-loss, take-profit and\r\n * time in force, checked as it is filled in; Place sends an `orderPlace`\r\n * intent. Escape, Cancel or a click outside close it.\r\n */\r\nexport class WidgetOrderTicket {\r\n private backdrop: HTMLDivElement;\r\n private modal: HTMLDivElement;\r\n private body: HTMLDivElement;\r\n private problemsEl: HTMLDivElement;\r\n private submit: HTMLButtonElement;\r\n private draft: OrderTicketDraft | null = null;\r\n private lastPrice: number | null = null;\r\n private returnFocus: HTMLElement | null = null;\r\n private readonly uid = ++ticketSeq;\r\n\r\n constructor(host: HTMLElement, private readonly callbacks: OrderTicketCallbacks, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.hidden = true;\r\n let pressedBackdrop = false;\r\n this.backdrop.addEventListener('pointerdown', (e) => { pressedBackdrop = e.target === this.backdrop; });\r\n this.backdrop.addEventListener('click', (e) => {\r\n if (e.target === this.backdrop && pressedBackdrop) this.close();\r\n pressedBackdrop = false;\r\n });\r\n\r\n this.modal = document.createElement('div');\r\n this.modal.className = 'tcw-modal tcw-modal-narrow tcw-order-ticket';\r\n this.modal.setAttribute('role', 'dialog');\r\n this.modal.setAttribute('aria-modal', 'true');\r\n this.modal.setAttribute('aria-labelledby', `tcw-ticket-title-${this.uid}`);\r\n this.modal.addEventListener('keydown', (e) => {\r\n if (e.key === 'Escape') {\r\n e.stopPropagation();\r\n this.close();\r\n return;\r\n }\r\n keepTabInside(e, this.modal);\r\n });\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-modal-header';\r\n const title = document.createElement('h3');\r\n title.id = `tcw-ticket-title-${this.uid}`;\r\n title.textContent = this.t('ticket.title');\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-modal-close';\r\n closeBtn.setAttribute('aria-label', this.t('common.close'));\r\n closeBtn.innerHTML = createIcon('x', 16);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.append(title, closeBtn);\r\n\r\n this.body = document.createElement('div');\r\n this.body.className = 'tcw-modal-body';\r\n this.problemsEl = document.createElement('div');\r\n this.problemsEl.className = 'tcw-ticket-problems';\r\n this.problemsEl.setAttribute('aria-live', 'polite');\r\n\r\n const footer = document.createElement('div');\r\n footer.className = 'tcw-modal-footer';\r\n const cancel = document.createElement('button');\r\n cancel.type = 'button';\r\n cancel.className = 'tcw-reset-link';\r\n cancel.textContent = this.t('common.cancel');\r\n cancel.addEventListener('click', () => this.close());\r\n this.submit = document.createElement('button');\r\n this.submit.type = 'button';\r\n this.submit.className = 'tcw-done-btn';\r\n this.submit.addEventListener('click', () => this.place());\r\n footer.append(cancel, this.submit);\r\n\r\n this.modal.append(header, this.body, this.problemsEl, footer);\r\n this.backdrop.appendChild(this.modal);\r\n host.appendChild(this.backdrop);\r\n }\r\n\r\n open(start: OrderTicketStart): void {\r\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\r\n this.lastPrice = start.lastPrice;\r\n const price = start.price ?? start.lastPrice ?? 0;\r\n const side = start.side ?? 'buy';\r\n // A price away from the market starts as the order that waits there.\r\n let type: OrderTicketDraft['type'] = 'market';\r\n if (start.price !== undefined && start.lastPrice !== null && start.price !== start.lastPrice) {\r\n type = (start.price < start.lastPrice) === (side === 'buy') ? 'limit' : 'stop';\r\n }\r\n this.draft = { side, type, quantity: 1, price, stopLoss: null, takeProfit: null, timeInForce: 'gtc' };\r\n this.render();\r\n this.backdrop.hidden = false;\r\n this.body.querySelector<HTMLElement>('button, input, select')?.focus();\r\n }\r\n\r\n close(): void {\r\n if (this.backdrop.hidden) return;\r\n this.backdrop.hidden = true;\r\n this.draft = null;\r\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\r\n this.returnFocus = null;\r\n }\r\n\r\n isOpen(): boolean {\r\n return !this.backdrop.hidden;\r\n }\r\n\r\n /** The latest price, while the ticket is open (a market order's price, the checks). */\r\n setLastPrice(price: number | null): void {\r\n if (!this.draft || price === this.lastPrice) return;\r\n this.lastPrice = price;\r\n this.check();\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n this.backdrop.remove();\r\n }\r\n\r\n private place(): void {\r\n const draft = this.draft;\r\n if (!draft || orderTicketProblems(draft, this.lastPrice).length > 0) return;\r\n this.callbacks.onSubmit(orderTicketIntent(draft, this.lastPrice));\r\n this.close();\r\n }\r\n\r\n private set(patch: Partial<OrderTicketDraft>, rerender = false): void {\r\n if (!this.draft) return;\r\n this.draft = { ...this.draft, ...patch };\r\n if (rerender) this.render();\r\n else this.check();\r\n }\r\n\r\n private render(): void {\r\n const draft = this.draft;\r\n if (!draft) return;\r\n // The control in use keeps focus through the rebuild.\r\n const active = document.activeElement;\r\n const focused = active instanceof HTMLElement && this.body.contains(active) ? active.dataset.ticketField : undefined;\r\n this.body.replaceChildren(\r\n this.sideToggle(draft.side),\r\n settingsRow(this.t('ticket.type'), field('type', selectInput(\r\n (['market', 'limit', 'stop'] as const).map((value) => ({ value, label: this.t(`ticket.type.${value}` as MessageKey) })),\r\n draft.type,\r\n (value) => this.set({ type: value as OrderTicketDraft['type'] }, true),\r\n ))),\r\n settingsRow(this.t('ticket.quantity'), field('quantity', this.number(draft.quantity, (quantity) => this.set({ quantity })))),\r\n );\r\n if (draft.type !== 'market') {\r\n this.body.append(\r\n settingsRow(this.t('ticket.price'), field('price', this.number(draft.price, (price) => this.set({ price })))),\r\n settingsRow(this.t('ticket.timeInForce'), field('timeInForce', selectInput(\r\n (['gtc', 'day'] as const).map((value) => ({ value, label: this.t(`ticket.tif.${value}` as MessageKey) })),\r\n draft.timeInForce,\r\n (value) => this.set({ timeInForce: value as TimeInForce }),\r\n ))),\r\n );\r\n }\r\n // Switched on, a stop starts 1% the losing way and a target 2% the winning way.\r\n const entry = draft.type === 'market' ? this.lastPrice ?? draft.price : draft.price;\r\n const away = (pct: number) => roundLike(entry * (1 + (draft.side === 'buy' ? pct : -pct) / 100), entry);\r\n this.body.append(\r\n this.optionalPrice('ticket.stopLoss', draft.stopLoss, away(-1), (stopLoss) => this.set({ stopLoss }, stopLoss === null || draft.stopLoss === null)),\r\n this.optionalPrice('ticket.takeProfit', draft.takeProfit, away(2), (takeProfit) => this.set({ takeProfit }, takeProfit === null || draft.takeProfit === null)),\r\n );\r\n if (focused) this.body.querySelector<HTMLElement>(`[data-ticket-field=\"${focused}\"]`)?.focus();\r\n this.check();\r\n }\r\n\r\n /** Buy or Sell, as two pressed buttons. */\r\n private sideToggle(side: OrderSide): HTMLElement {\r\n const group = document.createElement('div');\r\n group.className = 'tcw-ticket-side';\r\n group.setAttribute('role', 'group');\r\n for (const value of ['buy', 'sell'] as const) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = `tcw-ticket-side-btn tcw-ticket-${value}`;\r\n btn.textContent = this.t(`ticket.${value}`);\r\n btn.setAttribute('aria-pressed', String(side === value));\r\n btn.dataset.ticketField = `side-${value}`;\r\n btn.addEventListener('click', () => this.set({ side: value }, true));\r\n group.appendChild(btn);\r\n }\r\n return group;\r\n }\r\n\r\n /** A number checked as it is typed (not only when it is left). */\r\n private number(value: number, onInput: (value: number) => void): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.type = 'number';\r\n input.className = 'tcw-indi-input';\r\n input.step = 'any';\r\n input.min = '0';\r\n input.value = String(value);\r\n input.addEventListener('input', () => onInput(input.value.trim() === '' ? NaN : Number(input.value)));\r\n return input;\r\n }\r\n\r\n /** A price that is off unless switched on (a stop-loss, a take-profit). */\r\n private optionalPrice(key: MessageKey, value: number | null, start: number, onChange: (value: number | null) => void): HTMLElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-settings-row tcw-ticket-optional';\r\n const label = document.createElement('span');\r\n label.textContent = this.t(key);\r\n const toggle = toggleSwitch(value !== null, (on) => onChange(on ? start : null));\r\n toggle.setAttribute('aria-label', this.t(key));\r\n toggle.dataset.ticketField = `${key}-switch`;\r\n row.append(label, toggle);\r\n if (value !== null) {\r\n const input = this.number(value, (n) => onChange(Number.isFinite(n) ? n : NaN));\r\n input.setAttribute('aria-label', this.t(key));\r\n input.dataset.ticketField = key;\r\n row.appendChild(input);\r\n }\r\n return row;\r\n }\r\n\r\n /** Show what is wrong and the reward:risk, and enable Place only for a sound order. */\r\n private check(): void {\r\n const draft = this.draft;\r\n if (!draft) return;\r\n const problems = orderTicketProblems(draft, this.lastPrice);\r\n const lines = problems.map((p) => this.t(`ticket.problem.${p}` as MessageKey));\r\n const rr = orderTicketRiskReward(draft, this.lastPrice);\r\n if (problems.length === 0 && rr !== null) lines.push(fill(this.t('ticket.riskReward'), { rr: rr.toFixed(2) }));\r\n this.problemsEl.replaceChildren(...lines.map((text) => {\r\n const p = document.createElement('p');\r\n p.textContent = text;\r\n return p;\r\n }));\r\n this.problemsEl.classList.toggle('tcw-ticket-bad', problems.length > 0);\r\n this.submit.disabled = problems.length > 0;\r\n this.submit.classList.toggle('tcw-ticket-sell', draft.side === 'sell');\r\n this.submit.textContent = this.t(draft.side === 'buy' ? 'ticket.placeBuy' : 'ticket.placeSell');\r\n }\r\n}\r\n\r\n/** Name a control, so focus can find it again after a rebuild. */\r\nfunction field<T extends HTMLElement>(name: string, el: T): T {\r\n el.dataset.ticketField = name;\r\n return el;\r\n}\r\n\r\n/** `value` with as many decimals as a price like `ref` needs (2, or more below 10). */\r\nfunction roundLike(value: number, ref: number): number {\r\n const abs = Math.abs(ref);\r\n const decimals = abs >= 10 || abs === 0 ? 2 : abs >= 1 ? 4 : Math.min(10, Math.ceil(-Math.log10(abs)) + 3);\r\n return Number(value.toFixed(decimals));\r\n}\r\n","import { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\r\nimport { MAX_LAYOUT_NAME, cleanLayoutName } from '../state/LayoutSession.js';\r\nimport { keepTabInside } from './focusTrap.js';\r\n\r\nexport interface NamePromptRequest {\r\n title: string;\r\n /** The name to start from (a rename), selected. */\r\n value?: string;\r\n submitLabel: string;\r\n /** Example text in the empty field (default: a layout's). */\r\n placeholder?: string;\r\n /** Resolves when done; a rejection keeps the prompt open. */\r\n onSubmit: (name: string) => void | Promise<void>;\r\n}\r\n\r\nlet promptSeq = 0;\r\n\r\n/** A small dialog asking for a name (save a layout as, rename one). */\r\nexport class WidgetNamePrompt {\r\n private backdrop: HTMLDivElement;\r\n private titleEl: HTMLHeadingElement;\r\n private input: HTMLInputElement;\r\n private submit: HTMLButtonElement;\r\n private request: NamePromptRequest | null = null;\r\n private returnFocus: HTMLElement | null = null;\r\n private busy = false;\r\n private readonly uid = ++promptSeq;\r\n\r\n constructor(host: HTMLElement, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.hidden = true;\r\n let pressedBackdrop = false;\r\n this.backdrop.addEventListener('pointerdown', (e) => { pressedBackdrop = e.target === this.backdrop; });\r\n this.backdrop.addEventListener('click', (e) => {\r\n if (e.target === this.backdrop && pressedBackdrop) this.close();\r\n pressedBackdrop = false;\r\n });\r\n\r\n const modal = document.createElement('form');\r\n modal.className = 'tcw-modal tcw-modal-narrow tcw-name-prompt';\r\n modal.noValidate = true;\r\n modal.setAttribute('role', 'dialog');\r\n modal.setAttribute('aria-modal', 'true');\r\n modal.setAttribute('aria-labelledby', `tcw-name-title-${this.uid}`);\r\n modal.addEventListener('keydown', (e) => {\r\n if (e.key === 'Escape') {\r\n e.stopPropagation();\r\n this.close();\r\n return;\r\n }\r\n keepTabInside(e, modal);\r\n });\r\n modal.addEventListener('submit', (e) => {\r\n e.preventDefault();\r\n void this.done();\r\n });\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-modal-header';\r\n this.titleEl = document.createElement('h3');\r\n this.titleEl.id = `tcw-name-title-${this.uid}`;\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-modal-close';\r\n closeBtn.setAttribute('aria-label', this.t('common.close'));\r\n closeBtn.innerHTML = createIcon('x', 16);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.append(this.titleEl, closeBtn);\r\n\r\n const body = document.createElement('div');\r\n body.className = 'tcw-modal-body';\r\n const label = document.createElement('label');\r\n label.className = 'tcw-name-field';\r\n const caption = document.createElement('span');\r\n caption.textContent = this.t('layouts.name');\r\n this.input = document.createElement('input');\r\n this.input.type = 'text';\r\n this.input.className = 'tcw-indi-input';\r\n this.input.maxLength = MAX_LAYOUT_NAME;\r\n this.input.autocomplete = 'off';\r\n this.input.spellcheck = false;\r\n this.input.placeholder = this.t('layouts.namePlaceholder');\r\n this.input.addEventListener('input', () => this.check());\r\n label.append(caption, this.input);\r\n body.appendChild(label);\r\n\r\n const footer = document.createElement('div');\r\n footer.className = 'tcw-modal-footer';\r\n const cancel = document.createElement('button');\r\n cancel.type = 'button';\r\n cancel.className = 'tcw-reset-link';\r\n cancel.textContent = this.t('common.cancel');\r\n cancel.addEventListener('click', () => this.close());\r\n this.submit = document.createElement('button');\r\n this.submit.type = 'submit';\r\n this.submit.className = 'tcw-done-btn';\r\n footer.append(cancel, this.submit);\r\n\r\n modal.append(header, body, footer);\r\n this.backdrop.appendChild(modal);\r\n host.appendChild(this.backdrop);\r\n }\r\n\r\n open(request: NamePromptRequest): void {\r\n if (!this.isOpen()) this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\r\n this.request = request;\r\n this.busy = false;\r\n this.titleEl.textContent = request.title;\r\n this.submit.textContent = request.submitLabel;\r\n this.input.value = request.value ?? '';\r\n this.input.placeholder = request.placeholder ?? this.t('layouts.namePlaceholder');\r\n this.check();\r\n this.backdrop.hidden = false;\r\n this.input.focus();\r\n this.input.select();\r\n }\r\n\r\n close(): void {\r\n if (this.backdrop.hidden) return;\r\n this.backdrop.hidden = true;\r\n this.request = null;\r\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\r\n this.returnFocus = null;\r\n }\r\n\r\n isOpen(): boolean {\r\n return !this.backdrop.hidden;\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n this.backdrop.remove();\r\n }\r\n\r\n private check(): void {\r\n this.submit.disabled = this.busy || cleanLayoutName(this.input.value) === null;\r\n }\r\n\r\n private async done(): Promise<void> {\r\n const request = this.request;\r\n const name = cleanLayoutName(this.input.value);\r\n if (!request || name === null || this.busy) return;\r\n this.busy = true;\r\n this.check();\r\n try {\r\n await request.onSubmit(name);\r\n if (this.request === request) this.close();\r\n } catch {\r\n // The caller said what went wrong; the name stays to try again.\r\n } finally {\r\n this.busy = false;\r\n this.check();\r\n }\r\n }\r\n}\r\n","import { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, fill, type Translator } from './i18n.js';\r\nimport type { SavedLayoutSummary } from '../state/layoutStorage.js';\r\nimport { keepTabInside } from './focusTrap.js';\r\n\r\nexport interface LayoutsDialogCallbacks {\r\n list: () => Promise<SavedLayoutSummary[]>;\r\n /** The id of the layout showing now. */\r\n currentId: () => string | null;\r\n onOpen: (id: string) => void;\r\n onRename: (layout: SavedLayoutSummary) => void;\r\n onDelete: (id: string) => Promise<void>;\r\n formatTime: (ms: number) => string;\r\n}\r\n\r\nlet dialogSeq = 0;\r\n\r\n/** Every saved layout, searchable: open one, rename it or delete it (asked twice). */\r\nexport class WidgetLayoutsDialog {\r\n private backdrop: HTMLDivElement;\r\n private search: HTMLInputElement;\r\n private listEl: HTMLDivElement;\r\n private layouts: SavedLayoutSummary[] = [];\r\n private confirming: string | null = null;\r\n private returnFocus: HTMLElement | null = null;\r\n private loadSeq = 0;\r\n private readonly uid = ++dialogSeq;\r\n\r\n constructor(host: HTMLElement, private readonly callbacks: LayoutsDialogCallbacks, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.backdrop = document.createElement('div');\r\n this.backdrop.className = 'tcw-modal-backdrop';\r\n this.backdrop.hidden = true;\r\n let pressedBackdrop = false;\r\n this.backdrop.addEventListener('pointerdown', (e) => { pressedBackdrop = e.target === this.backdrop; });\r\n this.backdrop.addEventListener('click', (e) => {\r\n if (e.target === this.backdrop && pressedBackdrop) this.close();\r\n pressedBackdrop = false;\r\n });\r\n\r\n const modal = document.createElement('div');\r\n modal.className = 'tcw-modal tcw-modal-narrow tcw-layouts-dialog';\r\n modal.setAttribute('role', 'dialog');\r\n modal.setAttribute('aria-modal', 'true');\r\n modal.setAttribute('aria-labelledby', `tcw-layouts-title-${this.uid}`);\r\n modal.addEventListener('keydown', (e) => {\r\n if (e.key !== 'Escape') {\r\n keepTabInside(e, modal);\r\n return;\r\n }\r\n e.stopPropagation();\r\n if (this.confirming) this.setConfirming(null);\r\n else this.close();\r\n });\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-modal-header';\r\n const title = document.createElement('h3');\r\n title.id = `tcw-layouts-title-${this.uid}`;\r\n title.textContent = this.t('layouts.dialogTitle');\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-modal-close';\r\n closeBtn.setAttribute('aria-label', this.t('common.close'));\r\n closeBtn.innerHTML = createIcon('x', 16);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.append(title, closeBtn);\r\n\r\n this.search = document.createElement('input');\r\n this.search.type = 'search';\r\n this.search.className = 'tcw-indi-input tcw-layouts-search';\r\n this.search.placeholder = this.t('layouts.search');\r\n this.search.setAttribute('aria-label', this.t('layouts.search'));\r\n this.search.addEventListener('input', () => this.render());\r\n\r\n this.listEl = document.createElement('div');\r\n this.listEl.className = 'tcw-layouts-list';\r\n this.listEl.setAttribute('role', 'list');\r\n\r\n const body = document.createElement('div');\r\n body.className = 'tcw-modal-body tcw-layouts-body';\r\n body.append(this.search, this.listEl);\r\n modal.append(header, body);\r\n this.backdrop.appendChild(modal);\r\n host.appendChild(this.backdrop);\r\n }\r\n\r\n async open(): Promise<void> {\r\n if (!this.isOpen()) this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\r\n this.search.value = '';\r\n this.confirming = null;\r\n this.backdrop.hidden = false;\r\n this.search.focus();\r\n await this.refresh();\r\n }\r\n\r\n /** Read the list again (after a rename, say). */\r\n async refresh(): Promise<void> {\r\n const seq = ++this.loadSeq;\r\n let layouts: SavedLayoutSummary[];\r\n try {\r\n layouts = await this.callbacks.list();\r\n } catch {\r\n layouts = [];\r\n }\r\n if (seq !== this.loadSeq) return;\r\n this.layouts = layouts;\r\n this.render();\r\n }\r\n\r\n close(): void {\r\n if (this.backdrop.hidden) return;\r\n this.backdrop.hidden = true;\r\n this.confirming = null;\r\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\r\n this.returnFocus = null;\r\n }\r\n\r\n isOpen(): boolean {\r\n return !this.backdrop.hidden;\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n this.backdrop.remove();\r\n }\r\n\r\n private shown(): SavedLayoutSummary[] {\r\n const query = this.search.value.trim().toLowerCase();\r\n if (!query) return this.layouts;\r\n return this.layouts.filter((l) => l.name.toLowerCase().includes(query) || (l.symbol ?? '').toLowerCase().includes(query));\r\n }\r\n\r\n private render(): void {\r\n const shown = this.shown();\r\n if (shown.length === 0) {\r\n const empty = document.createElement('p');\r\n empty.className = 'tcw-account-empty';\r\n empty.textContent = this.t(this.layouts.length === 0 ? 'layouts.empty' : 'layouts.noMatch');\r\n this.listEl.replaceChildren(empty);\r\n return;\r\n }\r\n const currentId = this.callbacks.currentId();\r\n this.listEl.replaceChildren(...shown.map((layout) => this.row(layout, layout.id === currentId)));\r\n }\r\n\r\n private row(layout: SavedLayoutSummary, current: boolean): HTMLElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-layouts-row';\r\n row.setAttribute('role', 'listitem');\r\n row.dataset.id = layout.id;\r\n\r\n const open = document.createElement('button');\r\n open.type = 'button';\r\n open.className = 'tcw-layouts-open';\r\n if (current) open.setAttribute('aria-current', 'true');\r\n const name = document.createElement('span');\r\n name.className = 'tcw-layouts-name';\r\n name.textContent = layout.name;\r\n const meta = document.createElement('span');\r\n meta.className = 'tcw-layouts-meta';\r\n meta.textContent = [\r\n [layout.symbol, layout.timeframe].filter(Boolean).join(' · '),\r\n fill(this.t('layouts.updated'), { time: this.callbacks.formatTime(layout.updatedAt) }),\r\n ].filter(Boolean).join(' — ');\r\n open.append(name, meta);\r\n if (current) {\r\n const badge = document.createElement('span');\r\n badge.className = 'tcw-tag';\r\n badge.textContent = this.t('layouts.current');\r\n name.appendChild(badge);\r\n }\r\n open.addEventListener('click', () => {\r\n this.callbacks.onOpen(layout.id);\r\n this.close();\r\n });\r\n\r\n const actions = document.createElement('div');\r\n actions.className = 'tcw-account-actions';\r\n if (this.confirming === layout.id) {\r\n const confirm = document.createElement('button');\r\n confirm.type = 'button';\r\n confirm.className = 'tcw-layouts-confirm';\r\n confirm.textContent = this.t('layouts.deleteConfirm');\r\n confirm.setAttribute('aria-label', fill(this.t('layouts.deleteNamed'), { name: layout.name }));\r\n confirm.addEventListener('click', () => void this.remove(layout.id));\r\n const keep = this.iconButton('x', this.t('common.cancel'), () => this.setConfirming(null));\r\n actions.append(confirm, keep);\r\n } else {\r\n actions.append(\r\n this.iconButton('penLine', fill(this.t('layouts.renameNamed'), { name: layout.name }), () => this.callbacks.onRename(layout)),\r\n this.iconButton('trash', fill(this.t('layouts.deleteNamed'), { name: layout.name }), () => this.setConfirming(layout.id), true),\r\n );\r\n }\r\n row.append(open, actions);\r\n return row;\r\n }\r\n\r\n private iconButton(icon: string, label: string, run: () => void, danger = false): HTMLButtonElement {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = `tcw-tree-btn${danger ? ' tcw-tree-del' : ''}`;\r\n btn.setAttribute('aria-label', label);\r\n btn.title = label;\r\n btn.innerHTML = createIcon(icon, 14);\r\n btn.addEventListener('click', run);\r\n return btn;\r\n }\r\n\r\n /** Ask before deleting; focus follows to the button that asks (or back). */\r\n private setConfirming(id: string | null): void {\r\n const was = this.confirming;\r\n this.confirming = id;\r\n this.render();\r\n const target = id ?? was;\r\n if (!target) return;\r\n const row = [...this.listEl.querySelectorAll<HTMLElement>('.tcw-layouts-row')].find((r) => r.dataset.id === target);\r\n row?.querySelector<HTMLButtonElement>(id ? '.tcw-layouts-confirm' : '.tcw-tree-del')?.focus();\r\n }\r\n\r\n private async remove(id: string): Promise<void> {\r\n try {\r\n await this.callbacks.onDelete(id);\r\n } finally {\r\n this.confirming = null;\r\n await this.refresh();\r\n if (this.isOpen()) this.search.focus();\r\n }\r\n }\r\n}\r\n","import { WidgetContextMenu, type ContextMenuEntry } from './WidgetContextMenu.js';\r\nimport { WidgetNamePrompt } from './WidgetNamePrompt.js';\r\nimport { WidgetLayoutsDialog } from './WidgetLayoutsDialog.js';\r\nimport { fill, type Translator } from './i18n.js';\r\nimport type { LayoutSession } from '../state/LayoutSession.js';\r\nimport type { SavedLayoutSummary } from '../state/layoutStorage.js';\r\n\r\n/** Saved layouts listed in the layouts menu; the rest are in its \"Open layout…\" dialog. */\r\nconst RECENT_LAYOUTS = 5;\r\n\r\nexport interface LayoutsUIHost {\r\n /** Where the menu, the name prompt and the dialog live. */\r\n root: HTMLElement;\r\n t: Translator;\r\n toast: (message: string, kind?: 'info' | 'error') => void;\r\n formatTime: (ms: number) => string;\r\n}\r\n\r\n/**\r\n * The named-layouts controls over a {@link LayoutSession}: the menu under the\r\n * layouts button (save, save as, rename, auto-save, the latest layouts, open\r\n * another), the name prompt and the list of every layout. Failures are told\r\n * in a toast.\r\n */\r\nexport class WidgetLayoutsUI {\r\n private readonly menu: WidgetContextMenu;\r\n private readonly prompt: WidgetNamePrompt;\r\n private readonly dialog: WidgetLayoutsDialog;\r\n private destroyed = false;\r\n\r\n constructor(private readonly session: LayoutSession, private readonly host: LayoutsUIHost) {\r\n const { root, t } = host;\r\n this.menu = new WidgetContextMenu(root, t('toolbar.layouts'));\r\n this.prompt = new WidgetNamePrompt(root, t);\r\n this.dialog = new WidgetLayoutsDialog(root, {\r\n list: () => session.list(),\r\n currentId: () => session.current()?.id ?? null,\r\n onOpen: (id) => void this.open(id),\r\n onRename: (layout) => this.promptRename(layout),\r\n onDelete: async (id) => {\r\n try {\r\n await session.remove(id);\r\n } catch {\r\n this.host.toast(t('layouts.deleteFailed'), 'error');\r\n }\r\n },\r\n formatTime: host.formatTime,\r\n }, t);\r\n }\r\n\r\n /** Save into the open layout, or ask for a name when there is none. */\r\n async save(): Promise<void> {\r\n // Already asking for a name: that save is under way.\r\n if (this.prompt.isOpen()) return;\r\n if (!this.session.current()) {\r\n this.promptSaveAs();\r\n return;\r\n }\r\n const { t, toast } = this.host;\r\n try {\r\n const saved = await this.session.save();\r\n if (saved) toast(fill(t('layouts.saved'), { name: saved.name }));\r\n } catch {\r\n toast(t('layouts.saveFailed'), 'error');\r\n }\r\n }\r\n\r\n /** Open a saved layout by id; `false` (and a toast) when it could not be. */\r\n async open(id: string): Promise<boolean> {\r\n try {\r\n if (await this.session.open(id)) return true;\r\n } catch {\r\n // Told below.\r\n }\r\n if (!this.destroyed) this.host.toast(this.host.t('layouts.openFailed'), 'error');\r\n return false;\r\n }\r\n\r\n promptSaveAs(): void {\r\n const { t, toast } = this.host;\r\n const current = this.session.current();\r\n this.prompt.open({\r\n title: t('layouts.saveAsTitle'),\r\n value: current ? fill(t('layouts.copyName'), { name: current.name }) : '',\r\n submitLabel: t('common.save'),\r\n onSubmit: async (name) => {\r\n try {\r\n const saved = await this.session.saveAs(name);\r\n toast(fill(t('layouts.saved'), { name: saved.name }));\r\n } catch (err) {\r\n toast(t('layouts.saveFailed'), 'error');\r\n throw err;\r\n }\r\n },\r\n });\r\n }\r\n\r\n promptRename(layout: SavedLayoutSummary | null = this.session.current()): void {\r\n if (!layout) return;\r\n const { t, toast } = this.host;\r\n this.prompt.open({\r\n title: t('layouts.renameTitle'),\r\n value: layout.name,\r\n submitLabel: t('layouts.renameSubmit'),\r\n onSubmit: async (name) => {\r\n try {\r\n await this.session.rename(layout.id, name);\r\n } catch (err) {\r\n toast(t('layouts.saveFailed'), 'error');\r\n throw err;\r\n }\r\n if (this.dialog.isOpen()) void this.dialog.refresh();\r\n },\r\n });\r\n }\r\n\r\n /** Every layout, to open, rename or delete. */\r\n openDialog(): Promise<void> {\r\n return this.dialog.open();\r\n }\r\n\r\n /** The layouts menu under `anchor` (a second press closes it). */\r\n async openMenu(anchor: HTMLElement): Promise<void> {\r\n if (this.menu.isOpen()) {\r\n this.menu.close();\r\n return;\r\n }\r\n const { session } = this;\r\n const { t, root } = this.host;\r\n let recent: SavedLayoutSummary[] = [];\r\n try {\r\n recent = (await session.list()).slice(0, RECENT_LAYOUTS);\r\n } catch {\r\n // The menu still saves; the list shows what it can.\r\n }\r\n if (this.destroyed) return;\r\n const current = session.current();\r\n const entries: ContextMenuEntry[] = [\r\n { id: 'save', label: t('layouts.save'), icon: 'save' },\r\n { id: 'saveAs', label: t('layouts.saveAs'), icon: 'plus' },\r\n ];\r\n if (current) entries.push({ id: 'rename', label: t('layouts.rename'), icon: 'penLine' });\r\n entries.push({ id: 'autoSave', label: t('layouts.autoSave'), checked: session.isAutoSave() });\r\n if (recent.length > 0) {\r\n entries.push('separator', ...recent.map((l): ContextMenuEntry => ({ id: `open:${l.id}`, label: l.name, checked: l.id === current?.id })));\r\n }\r\n entries.push('separator', { id: 'manage', label: t('layouts.open'), icon: 'folder' });\r\n\r\n const at = anchor.getBoundingClientRect();\r\n const box = root.getBoundingClientRect();\r\n this.menu.open(entries, at.left - box.left, at.bottom - box.top + 2, (id) => {\r\n if (id === 'save') void this.save();\r\n else if (id === 'saveAs') this.promptSaveAs();\r\n else if (id === 'rename') this.promptRename();\r\n else if (id === 'autoSave') session.setAutoSave(!session.isAutoSave());\r\n else if (id === 'manage') void this.openDialog();\r\n else if (id.startsWith('open:')) void this.open(id.slice('open:'.length));\r\n }, anchor);\r\n }\r\n\r\n destroy(): void {\r\n this.destroyed = true;\r\n this.menu.destroy();\r\n this.prompt.destroy();\r\n this.dialog.destroy();\r\n }\r\n}\r\n","import type { TimeFrame } from '@tradecanvas/commons';\r\nimport { isTimeFrame, tickBarCount, timeframeToMs } from '@tradecanvas/commons';\r\n\r\n/** The timeframe menu when the host offers no list of its own. */\r\nexport const WIDGET_TIMEFRAMES: TimeFrame[] = ['1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '1d', '1w', '1M'];\r\n\r\n/** On the toolbar until the user pins others. */\r\nexport const WIDGET_TIMEFRAME_FAVORITES: TimeFrame[] = ['1m', '5m', '15m', '1h', '4h', '1d'];\r\n\r\nconst MAX_FALLBACK_FAVORITES = 6;\r\n\r\n/** \"1m\", \"1H\", \"1D\", \"1W\"; minutes and months keep their case (\"1m\" vs \"1M\"). */\r\nexport function timeframeLabel(tf: TimeFrame): string {\r\n const unit = tf.slice(-1);\r\n return unit === 'h' || unit === 'd' || unit === 'w' ? tf.slice(0, -1) + unit.toUpperCase() : tf;\r\n}\r\n\r\nconst isKnown = (tf: TimeFrame): boolean => Number.isFinite(timeframeToMs(tf)) || tickBarCount(tf) !== null;\r\n\r\n/** Shortest first: tick timeframes (fewest trades first), then by length. */\r\nconst byLength = (a: TimeFrame, b: TimeFrame): number => {\r\n const ta = tickBarCount(a);\r\n const tb = tickBarCount(b);\r\n if (ta !== null || tb !== null) return ta === null ? 1 : tb === null ? -1 : ta - tb;\r\n return timeframeToMs(a) - timeframeToMs(b);\r\n};\r\n\r\n/**\r\n * The timeframes to offer, shortest first: the widget's own list (or the\r\n * default menu), less any that the chart's `features.timeframes` whitelist\r\n * leaves out.\r\n */\r\nexport function availableTimeframes(widgetList?: TimeFrame[], whitelist?: TimeFrame[]): TimeFrame[] {\r\n const allowed = whitelist?.length ? whitelist : null;\r\n const base = widgetList?.length ? widgetList : (allowed ?? WIDGET_TIMEFRAMES);\r\n return [...new Set(base)]\r\n .filter((tf) => isKnown(tf) && (!allowed || allowed.includes(tf)))\r\n .sort(byLength);\r\n}\r\n\r\n/**\r\n * The toolbar's first favourites: the host's defaults; else, when the host\r\n * chose the list, all of it (so a short custom list shows as before); else\r\n * the standard set; else the first few offered.\r\n */\r\nexport function initialTimeframeFavorites(\r\n available: TimeFrame[],\r\n hostDefaults?: TimeFrame[],\r\n hostChoseList = false,\r\n): TimeFrame[] {\r\n if (hostDefaults?.length) return available.filter((tf) => hostDefaults.includes(tf));\r\n if (hostChoseList) return [...available];\r\n const standard = available.filter((tf) => WIDGET_TIMEFRAME_FAVORITES.includes(tf));\r\n return standard.length > 0 ? standard : available.slice(0, MAX_FALLBACK_FAVORITES);\r\n}\r\n\r\n/** Largest count a typed interval may have. */\r\nconst MAX_TYPED_COUNT = 9999;\r\n\r\n/** Units a typed interval may use; lower-case `m` is minutes, upper-case `M` months. */\r\nconst TYPED_UNITS: Record<string, 's' | 'm' | 'h' | 'd' | 'w' | 'M'> = {\r\n '': 'm', s: 's', S: 's', m: 'm', h: 'h', H: 'h', d: 'd', D: 'd', w: 'w', W: 'w', M: 'M',\r\n};\r\n\r\n/** Larger unit each one rolls up into, and how many make one. */\r\nconst ROLL_UP: Partial<Record<'s' | 'm' | 'h', ['m' | 'h' | 'd', number]>> = { s: ['m', 60], m: ['h', 60], h: ['d', 24] };\r\n\r\n/**\r\n * A typed interval as a timeframe, or null: a whole count and an optional\r\n * unit (`7`, `7m`, `2H`, `3d`, `1W`, `2M`; minutes when the unit is left\r\n * out). Written in its largest whole unit, so `60` and `1h` are the same.\r\n */\r\nexport function parseTimeframeInput(text: string): TimeFrame | null {\r\n const match = /^(\\d+)([a-zA-Z]?)$/.exec(text.trim());\r\n if (!match) return null;\r\n // Ticks: bars of that many trades (`100T`), from a feed with trades.\r\n if (match[2] === 'T' || match[2] === 't') {\r\n const tf = `${Number(match[1])}T` as TimeFrame;\r\n return Number(match[1]) <= MAX_TYPED_COUNT && tickBarCount(tf) !== null ? tf : null;\r\n }\r\n let count = Number(match[1]);\r\n let unit = TYPED_UNITS[match[2]];\r\n if (!unit || !Number.isSafeInteger(count) || count < 1) return null;\r\n for (let up = ROLL_UP[unit as 's' | 'm' | 'h']; up && count % up[1] === 0; up = ROLL_UP[unit as 's' | 'm' | 'h']) {\r\n count /= up[1];\r\n unit = up[0];\r\n }\r\n if (count > MAX_TYPED_COUNT) return null;\r\n const tf = `${count}${unit}`;\r\n return isTimeFrame(tf) ? tf : null;\r\n}\r\n\r\n/** `list` plus `extra`, without repeats, leaving out what the whitelist excludes, shortest first. */\r\nexport function withExtraTimeframes(list: TimeFrame[], extra: TimeFrame[], whitelist?: TimeFrame[]): TimeFrame[] {\r\n const allowed = whitelist?.length ? whitelist : null;\r\n const added = extra.filter((tf) => isKnown(tf) && (!allowed || allowed.includes(tf)));\r\n return [...new Set([...list, ...added])].sort(byLength);\r\n}\r\n","import type { TimeFrame } from '@tradecanvas/commons';\r\nimport { parseTimeframeInput } from './widgetTimeframes.js';\r\n\r\nexport interface IntervalInputLabels {\r\n /** The field's name: \"Change interval\". */\r\n title: string;\r\n /** Under it: \"5, 15m, 1h, 1D — Enter to apply\". */\r\n hint: string;\r\n /** When the text isn't an interval the chart can show. */\r\n invalid: string;\r\n}\r\n\r\nlet inputSeq = 0;\r\n\r\n/**\r\n * Typing a number on the chart opens this: the interval typed so far, in a\r\n * small field over the chart. Enter switches to it, Escape or leaving it\r\n * closes it.\r\n */\r\nexport class WidgetIntervalInput {\r\n private el: HTMLDivElement;\r\n private input: HTMLInputElement;\r\n private hint: HTMLDivElement;\r\n private returnFocus: HTMLElement | null = null;\r\n\r\n constructor(\r\n host: HTMLElement,\r\n private readonly labels: IntervalInputLabels,\r\n /** Switch to `tf`; false when the chart can't show it. */\r\n private readonly onApply: (tf: TimeFrame) => boolean,\r\n ) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-interval-input';\r\n this.el.hidden = true;\r\n // A dialog: the chart's own keys (Enter confirms a bracket order) leave it alone.\r\n this.el.setAttribute('role', 'dialog');\r\n this.el.setAttribute('aria-label', labels.title);\r\n this.input = document.createElement('input');\r\n this.input.type = 'text';\r\n this.input.className = 'tcw-interval-field';\r\n this.input.autocomplete = 'off';\r\n this.input.spellcheck = false;\r\n this.input.maxLength = 6;\r\n this.input.setAttribute('aria-label', labels.title);\r\n this.hint = document.createElement('div');\r\n this.hint.className = 'tcw-interval-hint';\r\n this.hint.setAttribute('role', 'status');\r\n this.hint.id = `tcw-interval-hint-${++inputSeq}`;\r\n this.input.setAttribute('aria-describedby', this.hint.id);\r\n this.el.append(this.input, this.hint);\r\n host.appendChild(this.el);\r\n\r\n this.input.addEventListener('input', () => this.check());\r\n this.input.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.apply();\r\n } else if (e.key === 'Escape') {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.close();\r\n }\r\n });\r\n this.input.addEventListener('blur', () => this.close(false));\r\n }\r\n\r\n /** Open with what was typed so far (the first digit). */\r\n open(text: string): void {\r\n if (!this.isOpen()) this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\r\n this.el.hidden = false;\r\n this.input.value = text;\r\n this.check();\r\n this.input.focus();\r\n this.input.setSelectionRange(text.length, text.length);\r\n }\r\n\r\n close(restoreFocus = true): void {\r\n if (this.el.hidden) return;\r\n this.el.hidden = true;\r\n const target = this.returnFocus;\r\n this.returnFocus = null;\r\n if (restoreFocus && target?.isConnected) target.focus({ preventScroll: true });\r\n }\r\n\r\n isOpen(): boolean {\r\n return !this.el.hidden;\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n private check(): void {\r\n const valid = parseTimeframeInput(this.input.value) !== null;\r\n if (!valid && this.input.value.trim() !== '') this.input.setAttribute('aria-invalid', 'true');\r\n else this.input.removeAttribute('aria-invalid');\r\n this.hint.textContent = valid || this.input.value.trim() === '' ? this.labels.hint : this.labels.invalid;\r\n }\r\n\r\n private apply(): void {\r\n const tf = parseTimeframeInput(this.input.value);\r\n if (tf && this.onApply(tf)) {\r\n this.close();\r\n return;\r\n }\r\n this.input.setAttribute('aria-invalid', 'true');\r\n this.hint.textContent = this.labels.invalid;\r\n }\r\n}\r\n","import { ChartStateManager, type SnapshotIndicator } from '@tradecanvas/core';\r\n\r\n/** A named set of indicators: their inputs, style, levels and panes. */\r\nexport interface IndicatorTemplate {\r\n name: string;\r\n indicators: SnapshotIndicator[];\r\n}\r\n\r\n/** The longest a template's name may be. */\r\nexport const MAX_TEMPLATE_NAME = 60;\r\n\r\n/**\r\n * Indicator templates kept in this browser's `localStorage`. What is read\r\n * back is checked as a saved layout's indicators are; entries it cannot read\r\n * are left out.\r\n */\r\nexport class IndicatorTemplateStore {\r\n constructor(private readonly key = 'tcw:indicator-templates') {}\r\n\r\n /** Every template, by name. */\r\n list(): IndicatorTemplate[] {\r\n let raw: unknown;\r\n try {\r\n raw = JSON.parse(localStorage.getItem(this.key) ?? '[]');\r\n } catch {\r\n return [];\r\n }\r\n if (!Array.isArray(raw)) return [];\r\n const out: IndicatorTemplate[] = [];\r\n for (const entry of raw) {\r\n if (typeof entry !== 'object' || entry === null) continue;\r\n const { name, indicators } = entry as Record<string, unknown>;\r\n if (typeof name !== 'string' || !name.trim() || !Array.isArray(indicators)) continue;\r\n // The same checks as a saved layout's indicators.\r\n const checked = ChartStateManager.deserialize(JSON.stringify({ version: 2, indicators })).indicators;\r\n if (checked.length > 0) out.push({ name: name.slice(0, MAX_TEMPLATE_NAME), indicators: checked });\r\n }\r\n return out.sort((a, b) => a.name.localeCompare(b.name));\r\n }\r\n\r\n get(name: string): IndicatorTemplate | null {\r\n return this.list().find((t) => t.name === name) ?? null;\r\n }\r\n\r\n /** Save under `name`, replacing a template of that name. Throws when storage refuses. */\r\n save(name: string, indicators: readonly SnapshotIndicator[]): void {\r\n const clean = name.replace(/\\s+/g, ' ').trim().slice(0, MAX_TEMPLATE_NAME);\r\n if (!clean) throw new Error('A template needs a name');\r\n const next = [...this.list().filter((t) => t.name !== clean), { name: clean, indicators: [...indicators] }];\r\n localStorage.setItem(this.key, JSON.stringify(next));\r\n }\r\n\r\n remove(name: string): void {\r\n try {\r\n localStorage.setItem(this.key, JSON.stringify(this.list().filter((t) => t.name !== name)));\r\n } catch {\r\n // Storage unavailable: nothing was kept to remove.\r\n }\r\n }\r\n}\r\n","/**\r\n * Which widget the page's keyboard shortcuts go to when several (or a grid of\r\n * them) share a page: the one pressed last, else the one holding focus, else\r\n * the first on the page. Roots nest (a grid holds widgets): a press inside a\r\n * widget counts for it and for the grid around it.\r\n */\r\nconst roots: HTMLElement[] = [];\r\nlet pressed: HTMLElement | null = null;\r\n\r\n/** Follow presses in `root`; returns the function that stops it. */\r\nexport function registerKeyRoot(root: HTMLElement): () => void {\r\n // Capture order runs outer roots first, so the innermost press is kept.\r\n const onPress = () => { pressed = root; };\r\n root.addEventListener('pointerdown', onPress, true);\r\n roots.push(root);\r\n return () => {\r\n root.removeEventListener('pointerdown', onPress, true);\r\n const at = roots.indexOf(root);\r\n if (at >= 0) roots.splice(at, 1);\r\n if (pressed === root) pressed = null;\r\n };\r\n}\r\n\r\n/**\r\n * Whether the page's shortcuts go to `root`. `strict` leaves out the\r\n * first-on-the-page fallback: for a key the page itself may want (Ctrl+S),\r\n * the widget must have been pressed or hold focus.\r\n */\r\nexport function isKeyTarget(root: HTMLElement, strict = false): boolean {\r\n let target: HTMLElement | null = pressed?.isConnected ? pressed : null;\r\n if (!target) {\r\n const active = document.activeElement;\r\n target = active ? roots.find((r) => r.contains(active)) ?? null : null;\r\n }\r\n if (!target && !strict) target = roots.find((r) => r.isConnected) ?? null;\r\n return target !== null && root.contains(target);\r\n}\r\n\r\n/** Focus is in a text field (keys there are typing, not shortcuts). */\r\nexport function isTyping(): boolean {\r\n const active = document.activeElement as HTMLElement | null;\r\n return !!active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.tagName === 'SELECT' || active.isContentEditable);\r\n}\r\n","import type { PriceScaleMode, TimeFrame } from '@tradecanvas/commons';\r\nimport { isTimeFrame, tickBarCount } from '@tradecanvas/commons';\r\n\r\n/** What a widget's named layout holds. */\r\nexport interface WidgetLayoutContent {\r\n v: 1;\r\n symbol: string;\r\n timeframe: TimeFrame;\r\n scaleMode: PriceScaleMode;\r\n invertScale: boolean;\r\n /** The chart's own state, as `Chart.saveState()` writes it: chart type, indicators, drawings, alerts. */\r\n chart: Record<string, unknown> | null;\r\n}\r\n\r\nconst SCALE_MODES: readonly PriceScaleMode[] = ['regular', 'logarithmic', 'percentage', 'indexedTo100'];\r\n\r\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null && !Array.isArray(value);\r\n\r\n/** The chart's state without what a layout leaves to the viewer (the theme) or never compares (when it was taken). */\r\nexport function layoutChartState(state: Record<string, unknown>): Record<string, unknown> {\r\n const { theme: _theme, timestamp: _timestamp, ...rest } = state;\r\n return rest;\r\n}\r\n\r\n/**\r\n * A widget layout read back from storage (or a host's server), or `null` when\r\n * it is not one. Whatever comes in is checked: an interval it can't read\r\n * refuses the layout, and a theme in the chart's state is dropped.\r\n */\r\nexport function readWidgetLayout(value: unknown): WidgetLayoutContent | null {\r\n if (!isRecord(value) || value.v !== 1) return null;\r\n if (typeof value.symbol !== 'string' || !value.symbol || typeof value.timeframe !== 'string' || !(isTimeFrame(value.timeframe) || tickBarCount(value.timeframe) !== null)) return null;\r\n return {\r\n v: 1,\r\n symbol: value.symbol,\r\n timeframe: value.timeframe as TimeFrame,\r\n scaleMode: SCALE_MODES.find((m) => m === value.scaleMode) ?? 'regular',\r\n invertScale: value.invertScale === true,\r\n chart: isRecord(value.chart) ? layoutChartState(value.chart) : null,\r\n };\r\n}\r\n\r\n/** Parse a layout's JSON; `null` for anything that does not parse. */\r\nexport function parseLayoutJson(json: string): unknown {\r\n try {\r\n return JSON.parse(json);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","import type { KeyValueStorage } from './DrawingTemplateStore.js';\r\n\r\nfunction defaultStorage(): KeyValueStorage | null {\r\n try {\r\n return typeof localStorage !== 'undefined' ? localStorage : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * An ordered, de-duplicated set of pinned drawing-tool ids, persisted to a\r\n * key-value store. Order is insertion order (most-recently-pinned last).\r\n */\r\nexport class DrawingFavoritesStore {\r\n private favorites: string[] = [];\r\n\r\n constructor(\r\n private storageKey = 'tcw:draw-favorites',\r\n private storage: KeyValueStorage | null = defaultStorage(),\r\n ) {\r\n this.load();\r\n }\r\n\r\n list(): string[] {\r\n return [...this.favorites];\r\n }\r\n\r\n has(tool: string): boolean {\r\n return this.favorites.includes(tool);\r\n }\r\n\r\n add(tool: string): void {\r\n if (!tool || this.favorites.includes(tool)) return;\r\n this.favorites = [...this.favorites, tool];\r\n this.persist();\r\n }\r\n\r\n remove(tool: string): void {\r\n if (!this.favorites.includes(tool)) return;\r\n this.favorites = this.favorites.filter((t) => t !== tool);\r\n this.persist();\r\n }\r\n\r\n /** Toggle a tool's pinned state. Returns the new state (true = pinned). */\r\n toggle(tool: string): boolean {\r\n if (this.has(tool)) {\r\n this.remove(tool);\r\n return false;\r\n }\r\n this.add(tool);\r\n return true;\r\n }\r\n\r\n /** Seed the favorites only when none are stored yet (first run). */\r\n seedDefaults(tools: string[]): void {\r\n if (this.favorites.length > 0) return;\r\n this.favorites = [...new Set(tools.filter(Boolean))];\r\n this.persist();\r\n }\r\n\r\n private load(): void {\r\n if (!this.storage) return;\r\n try {\r\n const raw = this.storage.getItem(this.storageKey);\r\n if (!raw) return;\r\n const parsed = JSON.parse(raw);\r\n if (Array.isArray(parsed)) {\r\n this.favorites = [...new Set(parsed.filter((t) => typeof t === 'string'))];\r\n }\r\n } catch {\r\n // Corrupt or unavailable — start empty.\r\n }\r\n }\r\n\r\n private persist(): void {\r\n if (!this.storage) return;\r\n try {\r\n this.storage.setItem(this.storageKey, JSON.stringify(this.favorites));\r\n } catch {\r\n // Storage full or blocked — keep the in-memory copy.\r\n }\r\n }\r\n}\r\n","import { timeParts, wallToUtc, type TimeZoneSetting } from '@tradecanvas/commons';\r\n\r\nconst DATE_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\r\nconst TIME_RE = /^(\\d{2}):(\\d{2})$/;\r\n\r\n/**\r\n * A wall-clock date (\"2026-03-01\") and time (\"14:30\", empty = midnight) in the\r\n * display timezone (an IANA zone, minutes east of UTC, or null for the\r\n * browser's) as a UTC timestamp. Null when the date or time is not valid.\r\n */\r\nexport function wallTimeToUtc(date: string, time: string, tz: TimeZoneSetting): number | null {\r\n const d = DATE_RE.exec(date);\r\n const t = time ? TIME_RE.exec(time) : ['', '00', '00'];\r\n if (!d || !t) return null;\r\n const [year, month, day, hours, minutes] = [+d[1], +d[2], +d[3], +t[1], +t[2]];\r\n if (month < 1 || month > 12 || day < 1 || day > 31 || hours > 23 || minutes > 59) return null;\r\n const wall = Date.UTC(year, month - 1, day, hours, minutes);\r\n if (new Date(wall).getUTCDate() !== day) return null; // 31 February rolls over: reject\r\n return wallToUtc(wall, tz);\r\n}\r\n\r\n/** The date and time fields' values for `ts` in the display timezone. */\r\nexport function utcToWallTime(ts: number, tz: TimeZoneSetting): { date: string; time: string } {\r\n const pad = (n: number) => String(n).padStart(2, '0');\r\n const p = timeParts(ts, tz);\r\n return {\r\n date: `${p.year}-${pad(p.month)}-${pad(p.day)}`,\r\n time: `${pad(p.hours)}:${pad(p.minutes)}`,\r\n };\r\n}\r\n\r\nexport interface GoToDateLabels {\r\n title: string;\r\n date: string;\r\n time: string;\r\n submit: string;\r\n cancel: string;\r\n}\r\n\r\n/**\r\n * \"Go to date\" popover: a date and an optional time. Enter submits, Escape or\r\n * a click outside closes it, and focus returns to whatever opened it.\r\n */\r\nexport class WidgetGoToDate {\r\n private form: HTMLFormElement | null = null;\r\n private returnFocus: HTMLElement | null = null;\r\n /** The button that opened it: pressing it again toggles, so it's not \"outside\". */\r\n private opener: Element | null = null;\r\n private readonly onOutside = (e: MouseEvent) => {\r\n const target = e.target as Node;\r\n if (this.form && !this.form.contains(target) && !this.opener?.contains(target)) this.close();\r\n };\r\n\r\n constructor(\r\n private readonly host: HTMLElement,\r\n private readonly labels: GoToDateLabels,\r\n private readonly onSubmit: (value: { date: string; time: string }) => void,\r\n ) {}\r\n\r\n isOpen(): boolean {\r\n return this.form !== null;\r\n }\r\n\r\n open(initial: { date: string; time: string }, opener: Element | null = null): void {\r\n this.close();\r\n this.opener = opener;\r\n this.returnFocus = document.activeElement as HTMLElement | null;\r\n\r\n const form = document.createElement('form');\r\n form.className = 'tcw-goto';\r\n form.setAttribute('role', 'dialog');\r\n form.setAttribute('aria-label', this.labels.title);\r\n\r\n const title = document.createElement('div');\r\n title.className = 'tcw-goto-title';\r\n title.textContent = this.labels.title;\r\n\r\n const date = this.field(form, this.labels.date, 'date', initial.date);\r\n date.required = true;\r\n const time = this.field(form, this.labels.time, 'time', initial.time);\r\n\r\n const actions = document.createElement('div');\r\n actions.className = 'tcw-goto-actions';\r\n const cancel = document.createElement('button');\r\n cancel.type = 'button';\r\n cancel.className = 'tcw-btn';\r\n cancel.textContent = this.labels.cancel;\r\n cancel.addEventListener('click', () => this.close());\r\n const submit = document.createElement('button');\r\n submit.type = 'submit';\r\n submit.className = 'tcw-btn tcw-goto-submit';\r\n submit.textContent = this.labels.submit;\r\n actions.append(cancel, submit);\r\n\r\n form.prepend(title);\r\n form.append(actions);\r\n form.addEventListener('submit', (e) => {\r\n e.preventDefault();\r\n if (!date.value) return;\r\n const value = { date: date.value, time: time.value };\r\n this.close();\r\n this.onSubmit(value);\r\n });\r\n form.addEventListener('keydown', (e) => {\r\n e.stopPropagation(); // typing here must not drive chart shortcuts\r\n if (e.key === 'Escape') this.close();\r\n });\r\n\r\n this.host.appendChild(form);\r\n this.form = form;\r\n document.addEventListener('mousedown', this.onOutside);\r\n date.focus();\r\n }\r\n\r\n close(): void {\r\n if (!this.form) return;\r\n document.removeEventListener('mousedown', this.onOutside);\r\n this.form.remove();\r\n this.form = null;\r\n const back = this.returnFocus;\r\n this.returnFocus = null;\r\n if (back?.isConnected) back.focus();\r\n }\r\n\r\n destroy(): void {\r\n this.close();\r\n }\r\n\r\n private field(form: HTMLFormElement, label: string, type: 'date' | 'time', value: string): HTMLInputElement {\r\n const wrap = document.createElement('label');\r\n wrap.className = 'tcw-goto-field';\r\n const text = document.createElement('span');\r\n text.textContent = label;\r\n const input = document.createElement('input');\r\n input.type = type;\r\n input.value = value;\r\n input.className = 'tcw-goto-input';\r\n wrap.append(text, input);\r\n form.appendChild(wrap);\r\n return input;\r\n }\r\n}\r\n","/** Pause before the first tooltip shows. */\r\nexport const TOOLTIP_DELAY_MS = 300;\r\n/** After one hides, the next shows at once within this window (moving along a toolbar). */\r\nexport const TOOLTIP_WARM_MS = 500;\r\nconst GAP_PX = 8;\r\nconst EDGE_PX = 4;\r\nconst SLIDE_PX = 3;\r\n\r\ntype Side = 'top' | 'bottom' | 'left' | 'right';\r\nconst TIPPED = '[title]:not([title=\"\"]), [data-tip]:not([data-tip=\"\"])';\r\n\r\n/**\r\n * Quick, styled tooltips for the widget's controls, in place of the\r\n * browser's `title` tooltip (a fixed ~1 s wait, unstyled). Any element in\r\n * the widget with a `title` gets one. While the pointer is on it, its title\r\n * is lifted into `data-tip` so the browser's own tooltip can't appear, and\r\n * put back when the pointer leaves — so the title keeps doing its other jobs\r\n * (accessible description, selectors). Keyboard focus shows the tooltip too,\r\n * leaving the title in place. `data-tip-side` picks a side.\r\n */\r\nexport class WidgetTooltip {\r\n private readonly el: HTMLDivElement;\r\n private target: HTMLElement | null = null;\r\n private source: 'pointer' | 'focus' | null = null;\r\n /** The control just pressed (or keyed): no tooltip on it until the pointer leaves. */\r\n private pressed: HTMLElement | null = null;\r\n private showTimer: ReturnType<typeof setTimeout> | null = null;\r\n private watchFrame = 0;\r\n private warmUntil = 0;\r\n private readonly observer: MutationObserver;\r\n\r\n constructor(private readonly root: HTMLElement) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-tooltip';\r\n this.el.setAttribute('aria-hidden', 'true'); // the control's title still describes it\r\n root.appendChild(this.el);\r\n\r\n root.addEventListener('pointerover', this.onOver);\r\n root.addEventListener('pointerout', this.onOut);\r\n root.addEventListener('pointerdown', this.onPress, true);\r\n root.addEventListener('keydown', this.onPress, true);\r\n root.addEventListener('focusin', this.onFocus);\r\n root.addEventListener('focusout', this.onBlur);\r\n root.addEventListener('wheel', this.hide, { passive: true });\r\n\r\n // Code that sets the title while the pointer is on the control (e.g.\r\n // \"Magnet ON\" ↔ \"Magnet OFF\" on click) mustn't bring the browser's back.\r\n this.observer = new MutationObserver(() => {\r\n // The control just clicked often renames itself (Hide → Show).\r\n if (this.pressed?.hasAttribute('title')) lift(this.pressed);\r\n const t = this.target;\r\n if (!t || this.source !== 'pointer' || !t.hasAttribute('title')) return;\r\n lift(t);\r\n if (this.isVisible()) this.show(t);\r\n });\r\n this.observer.observe(root, { subtree: true, attributes: true, attributeFilter: ['title'] });\r\n }\r\n\r\n destroy(): void {\r\n this.hide();\r\n if (this.pressed) restore(this.pressed);\r\n this.observer.disconnect();\r\n this.root.removeEventListener('pointerover', this.onOver);\r\n this.root.removeEventListener('pointerout', this.onOut);\r\n this.root.removeEventListener('pointerdown', this.onPress, true);\r\n this.root.removeEventListener('keydown', this.onPress, true);\r\n this.root.removeEventListener('focusin', this.onFocus);\r\n this.root.removeEventListener('focusout', this.onBlur);\r\n this.root.removeEventListener('wheel', this.hide);\r\n this.el.remove();\r\n }\r\n\r\n private readonly onOver = (e: PointerEvent): void => {\r\n if (e.pointerType === 'touch') return;\r\n const target = this.tipTarget(e.target);\r\n if (!target || target === this.pressed) return;\r\n if (target === this.target && this.source === 'pointer') return;\r\n lift(target);\r\n this.schedule(target, 'pointer', Date.now() < this.warmUntil || this.isVisible());\r\n };\r\n\r\n private readonly onOut = (e: PointerEvent): void => {\r\n const next = e.relatedTarget as Node | null;\r\n const within = (el: HTMLElement | null) => !!el && !!next && el.contains(next); // still on that control\r\n if (this.pressed && !within(this.pressed)) {\r\n restore(this.pressed);\r\n this.pressed = null;\r\n }\r\n if (this.source === 'pointer' && !within(this.target)) this.hide();\r\n };\r\n\r\n private readonly onPress = (): void => {\r\n const was = this.target;\r\n const lifted = this.source === 'pointer';\r\n this.warmUntil = 0;\r\n this.clearTimer();\r\n cancelAnimationFrame(this.watchFrame);\r\n this.el.classList.remove('tcw-tooltip--visible');\r\n this.target = null;\r\n this.source = null;\r\n // The title stays lifted while the pointer stays, or the browser's tooltip would take over.\r\n if (this.pressed && this.pressed !== was) restore(this.pressed);\r\n this.pressed = lifted ? was : null;\r\n };\r\n\r\n private readonly onFocus = (e: FocusEvent): void => {\r\n const target = this.tipTarget(e.target);\r\n // Keyboard focus only: a click focuses the control too, and that is no time for a tooltip.\r\n if (!target || !isFocusVisible(target) || target === this.pressed) return;\r\n this.schedule(target, 'focus', true);\r\n };\r\n\r\n private readonly onBlur = (e: FocusEvent): void => {\r\n if (this.source !== 'focus') return;\r\n const next = e.relatedTarget as Node | null;\r\n if (this.target && next && this.target.contains(next)) return;\r\n this.hide();\r\n };\r\n\r\n private readonly hide = (): void => {\r\n this.clearTimer();\r\n cancelAnimationFrame(this.watchFrame);\r\n if (this.isVisible()) this.warmUntil = Date.now() + TOOLTIP_WARM_MS;\r\n this.el.classList.remove('tcw-tooltip--visible');\r\n if (this.target && this.source === 'pointer') restore(this.target);\r\n this.target = null;\r\n this.source = null;\r\n };\r\n\r\n private tipTarget(node: EventTarget | null): HTMLElement | null {\r\n if (!(node instanceof Element)) return null;\r\n const el = node.closest<HTMLElement>(TIPPED);\r\n return el && el !== this.el && this.root.contains(el) ? el : null;\r\n }\r\n\r\n private schedule(target: HTMLElement, source: 'pointer' | 'focus', now: boolean): void {\r\n const previous = this.target;\r\n this.clearTimer();\r\n cancelAnimationFrame(this.watchFrame);\r\n if (previous && previous !== target && this.source === 'pointer') restore(previous);\r\n this.target = target;\r\n this.source = source;\r\n if (now) {\r\n this.show(target);\r\n return;\r\n }\r\n this.el.classList.remove('tcw-tooltip--visible');\r\n this.showTimer = setTimeout(() => {\r\n this.showTimer = null;\r\n if (this.target === target) this.show(target);\r\n }, TOOLTIP_DELAY_MS);\r\n }\r\n\r\n private show(target: HTMLElement): void {\r\n if (!isShown(target)) {\r\n this.hide();\r\n return;\r\n }\r\n this.el.textContent = tipText(target);\r\n this.place(target);\r\n this.el.classList.add('tcw-tooltip--visible');\r\n this.watch(target);\r\n }\r\n\r\n /** While shown, follow the control: gone, hidden or disabled takes the tooltip with it. */\r\n private watch(target: HTMLElement): void {\r\n cancelAnimationFrame(this.watchFrame);\r\n this.watchFrame = requestAnimationFrame(() => {\r\n if (this.target !== target) return;\r\n if (!isShown(target)) this.hide();\r\n else this.watch(target);\r\n });\r\n }\r\n\r\n /** Beside the control on its preferred side, flipped and clamped to stay inside the widget. */\r\n private place(target: HTMLElement): void {\r\n const box = this.root.getBoundingClientRect();\r\n const t = target.getBoundingClientRect();\r\n const w = this.el.offsetWidth;\r\n const h = this.el.offsetHeight;\r\n const left = t.left - box.left;\r\n const top = t.top - box.top;\r\n let side = preferredSide(target);\r\n if (side === 'bottom' && top + t.height + GAP_PX + h > box.height) side = 'top';\r\n else if (side === 'top' && top - GAP_PX - h < 0) side = 'bottom';\r\n else if (side === 'right' && left + t.width + GAP_PX + w > box.width) side = 'left';\r\n\r\n let x: number;\r\n let y: number;\r\n if (side === 'top' || side === 'bottom') {\r\n x = left + t.width / 2 - w / 2;\r\n y = side === 'bottom' ? top + t.height + GAP_PX : top - GAP_PX - h;\r\n } else {\r\n x = side === 'right' ? left + t.width + GAP_PX : left - GAP_PX - w;\r\n y = top + t.height / 2 - h / 2;\r\n }\r\n x = Math.max(EDGE_PX, Math.min(box.width - w - EDGE_PX, x));\r\n y = Math.max(EDGE_PX, Math.min(box.height - h - EDGE_PX, y));\r\n this.el.style.left = `${Math.round(x)}px`;\r\n this.el.style.top = `${Math.round(y)}px`;\r\n // It slides in from the control's side.\r\n const slide = { top: [0, SLIDE_PX], bottom: [0, -SLIDE_PX], left: [SLIDE_PX, 0], right: [-SLIDE_PX, 0] }[side];\r\n this.el.style.setProperty('--tcw-tip-dx', `${slide[0]}px`);\r\n this.el.style.setProperty('--tcw-tip-dy', `${slide[1]}px`);\r\n this.el.dataset.side = side;\r\n }\r\n\r\n private isVisible(): boolean {\r\n return this.el.classList.contains('tcw-tooltip--visible');\r\n }\r\n\r\n private clearTimer(): void {\r\n if (this.showTimer === null) return;\r\n clearTimeout(this.showTimer);\r\n this.showTimer = null;\r\n }\r\n}\r\n\r\n/** Take the title off while the pointer is on the control, keeping its text in `data-tip`. */\r\nfunction lift(el: HTMLElement): void {\r\n const title = el.getAttribute('title');\r\n if (title === null) return;\r\n el.dataset.tip = title;\r\n el.removeAttribute('title');\r\n}\r\n\r\n/** Put a lifted title back. */\r\nfunction restore(el: HTMLElement): void {\r\n if (el.dataset.tip !== undefined && !el.hasAttribute('title')) {\r\n el.setAttribute('title', el.dataset.tip);\r\n delete el.dataset.tip;\r\n }\r\n}\r\n\r\nfunction tipText(el: HTMLElement): string {\r\n return el.dataset.tip ?? el.getAttribute('title') ?? '';\r\n}\r\n\r\n/** Still on screen and usable: attached, laid out, not disabled. */\r\nfunction isShown(el: HTMLElement): boolean {\r\n return el.isConnected && el.getClientRects().length > 0 && !(el as HTMLButtonElement).disabled;\r\n}\r\n\r\nfunction isFocusVisible(el: HTMLElement): boolean {\r\n try {\r\n return el.matches(':focus-visible');\r\n } catch {\r\n return false; // engines without :focus-visible\r\n }\r\n}\r\n\r\nfunction preferredSide(el: HTMLElement): Side {\r\n const side = el.dataset.tipSide as Side | undefined;\r\n if (side) return side;\r\n if (el.closest('.tcw-sidebar')) return 'right';\r\n if (el.closest('.tcw-statusbar, .tcw-replay-bar')) return 'top';\r\n return 'bottom';\r\n}\r\n","import { createIcon } from './icons.js';\r\n\r\nexport interface IndicatorLegendRow {\r\n instanceId: string;\r\n /** \"EMA 50\", \"MACD 12 26 9\". */\r\n label: string;\r\n visible: boolean;\r\n /** The values at the bar in view; `color` null = the neutral text colour. */\r\n values: readonly { text: string; color: string | null }[];\r\n /**\r\n * Where the row sits inside its own pane (container px, `width` = the room\r\n * it may take); null = stacked under the OHLCV legend.\r\n */\r\n pane: { x: number; y: number; width: number } | null;\r\n}\r\n\r\n/** An indicator pane, for the buttons at its top right. */\r\nexport interface IndicatorLegendPane {\r\n /** The indicator whose pane it is. */\r\n instanceId: string;\r\n /** The pane's top right corner, inside the price axis (container px). */\r\n x: number;\r\n y: number;\r\n /** For the buttons' names: \"Collapse pane RSI 14\". */\r\n label: string;\r\n collapsed: boolean;\r\n maximized: boolean;\r\n canMoveUp: boolean;\r\n canMoveDown: boolean;\r\n}\r\n\r\nexport type PaneAction = 'up' | 'down' | 'collapse' | 'expand' | 'maximize' | 'restore';\r\n\r\nexport interface IndicatorLegendCallbacks {\r\n onToggleVisible: (instanceId: string, visible: boolean) => void;\r\n onSettings: (instanceId: string) => void;\r\n onRemove: (instanceId: string) => void;\r\n /** The row's \"more\" button: a menu under `anchor` (move to another pane…). */\r\n onMore?: (instanceId: string, anchor: HTMLElement) => void;\r\n /** A pane's button: move it, fold it, maximise it. */\r\n onPaneAction?: (instanceId: string, action: PaneAction) => void;\r\n}\r\n\r\nexport interface IndicatorLegendLabels {\r\n show: string;\r\n hide: string;\r\n settings: string;\r\n remove: string;\r\n collapse: string;\r\n expand: string;\r\n more?: string;\r\n paneUp?: string;\r\n paneDown?: string;\r\n paneCollapse?: string;\r\n paneExpand?: string;\r\n paneMaximize?: string;\r\n paneRestore?: string;\r\n}\r\n\r\ninterface PaneEls {\r\n el: HTMLDivElement;\r\n buttons: Map<string, HTMLButtonElement>;\r\n key: string;\r\n}\r\n\r\n/** Collapsing is offered once this many indicators share the price pane. */\r\nconst COLLAPSE_FROM = 2;\r\n\r\ninterface RowEls {\r\n el: HTMLDivElement;\r\n name: HTMLButtonElement;\r\n values: HTMLSpanElement;\r\n eye: HTMLButtonElement;\r\n settings: HTMLButtonElement;\r\n more: HTMLButtonElement | null;\r\n remove: HTMLButtonElement;\r\n visible: boolean;\r\n valuesKey: string;\r\n state: string;\r\n placeKey: string;\r\n}\r\n\r\n/**\r\n * The indicators on the chart itself, instead of chips in the toolbar: price\r\n * pane indicators stack under the OHLCV legend, pane indicators sit at the\r\n * top of their pane. Each row reads \"EMA 50 123.45\" and, on hover or focus,\r\n * offers show/hide, settings and remove. A long stack can be collapsed.\r\n *\r\n * `update()` is cheap to call every frame: rows are kept by instance id and\r\n * only changed text and positions are written.\r\n */\r\nexport class WidgetIndicatorLegend {\r\n private readonly stack: HTMLDivElement;\r\n private readonly toggle: HTMLButtonElement;\r\n private readonly rows = new Map<string, RowEls>();\r\n private readonly panes = new Map<string, PaneEls>();\r\n private collapsed = false;\r\n private toggleKey = '';\r\n private stackKey = '';\r\n\r\n constructor(\r\n private readonly host: HTMLElement,\r\n private readonly callbacks: IndicatorLegendCallbacks,\r\n private readonly labels: IndicatorLegendLabels,\r\n ) {\r\n this.stack = document.createElement('div');\r\n this.stack.className = 'tcw-ind-legend';\r\n this.toggle = document.createElement('button');\r\n this.toggle.type = 'button';\r\n this.toggle.className = 'tcw-ind-legend-toggle';\r\n this.toggle.addEventListener('click', () => {\r\n this.setCollapsed(!this.collapsed);\r\n this.renderToggle(this.overlayCount());\r\n });\r\n this.stack.appendChild(this.toggle);\r\n host.appendChild(this.stack);\r\n }\r\n\r\n update(rows: readonly IndicatorLegendRow[], overlay: { left: number; top: number }, panes: readonly IndicatorLegendPane[] = []): void {\r\n this.updatePanes(panes);\r\n const stackKey = `${Math.round(overlay.left)},${Math.round(overlay.top)}`;\r\n if (stackKey !== this.stackKey) {\r\n this.stackKey = stackKey;\r\n this.stack.style.left = `${Math.round(overlay.left)}px`;\r\n this.stack.style.top = `${Math.round(overlay.top)}px`;\r\n }\r\n\r\n const seen = new Set<string>();\r\n let joinedStack = false;\r\n for (const row of rows) {\r\n seen.add(row.instanceId);\r\n const els = this.rows.get(row.instanceId) ?? this.createRow(row.instanceId);\r\n this.fill(els, row);\r\n if (row.pane) {\r\n if (els.el.parentElement !== this.host) this.host.appendChild(els.el);\r\n } else if (els.el.parentElement !== this.stack) {\r\n // New rows join the end (the chart's order), before the toggle.\r\n this.stack.insertBefore(els.el, this.toggle);\r\n joinedStack = true;\r\n }\r\n this.place(els, row.pane);\r\n }\r\n for (const [id, els] of this.rows) {\r\n if (seen.has(id)) continue;\r\n els.el.remove();\r\n this.rows.delete(id);\r\n }\r\n // A collapsed stack would hide the indicator just added: open it.\r\n if (joinedStack && this.collapsed) this.setCollapsed(false);\r\n this.renderToggle(rows.filter((r) => !r.pane).length);\r\n }\r\n\r\n destroy(): void {\r\n for (const els of this.rows.values()) els.el.remove();\r\n this.rows.clear();\r\n for (const els of this.panes.values()) els.el.remove();\r\n this.panes.clear();\r\n this.stack.remove();\r\n }\r\n\r\n /** Each pane's buttons at its top right: move up, move down, fold, maximise. */\r\n private updatePanes(panes: readonly IndicatorLegendPane[]): void {\r\n if (!this.callbacks.onPaneAction) return;\r\n const seen = new Set<string>();\r\n for (const pane of panes) {\r\n seen.add(pane.instanceId);\r\n const els = this.panes.get(pane.instanceId) ?? this.createPane(pane.instanceId);\r\n const key = `${Math.round(pane.x)},${Math.round(pane.y)}|${pane.label}|${pane.collapsed}|${pane.maximized}|${pane.canMoveUp}|${pane.canMoveDown}`;\r\n if (key === els.key) continue;\r\n els.key = key;\r\n els.el.style.left = `${Math.round(pane.x)}px`;\r\n els.el.style.top = `${Math.round(pane.y)}px`;\r\n const l = this.labels;\r\n const show = (act: string, visible: boolean, icon: string, label: string | undefined) => {\r\n const b = els.buttons.get(act)!;\r\n if (!visible && document.activeElement === b) els.buttons.get('max')!.focus();\r\n b.hidden = !visible;\r\n b.innerHTML = createIcon(icon, 12);\r\n setLabel(b, label ?? act, pane.label);\r\n };\r\n show('up', pane.canMoveUp && !pane.maximized, 'arrowUp', l.paneUp);\r\n show('down', pane.canMoveDown && !pane.maximized, 'arrowDown', l.paneDown);\r\n show('fold', !pane.maximized, pane.collapsed ? 'chevronDown' : 'chevronUp', pane.collapsed ? l.paneExpand : l.paneCollapse);\r\n show('max', true, pane.maximized ? 'minimize' : 'maximize', pane.maximized ? l.paneRestore : l.paneMaximize);\r\n els.el.dataset.collapsed = String(pane.collapsed);\r\n els.el.dataset.maximized = String(pane.maximized);\r\n }\r\n for (const [id, els] of this.panes) {\r\n if (seen.has(id)) continue;\r\n els.el.remove();\r\n this.panes.delete(id);\r\n }\r\n }\r\n\r\n private createPane(instanceId: string): PaneEls {\r\n const el = document.createElement('div');\r\n el.className = 'tcw-pane-controls';\r\n el.dataset.instance = instanceId;\r\n const buttons = new Map<string, HTMLButtonElement>();\r\n const run = (act: string): PaneAction => {\r\n if (act === 'up' || act === 'down') return act;\r\n if (act === 'fold') return el.dataset.collapsed === 'true' ? 'expand' : 'collapse';\r\n return el.dataset.maximized === 'true' ? 'restore' : 'maximize';\r\n };\r\n for (const act of ['up', 'down', 'fold', 'max']) {\r\n const b = document.createElement('button');\r\n b.type = 'button';\r\n b.className = 'tcw-pane-btn';\r\n b.dataset.act = act;\r\n b.addEventListener('click', () => this.callbacks.onPaneAction?.(instanceId, run(act)));\r\n buttons.set(act, b);\r\n el.appendChild(b);\r\n }\r\n this.host.appendChild(el);\r\n const els: PaneEls = { el, buttons, key: '' };\r\n this.panes.set(instanceId, els);\r\n return els;\r\n }\r\n\r\n private createRow(instanceId: string): RowEls {\r\n const el = document.createElement('div');\r\n el.className = 'tcw-ind-legend-row';\r\n el.dataset.instance = instanceId;\r\n\r\n const name = document.createElement('button');\r\n name.type = 'button';\r\n name.className = 'tcw-ind-legend-name';\r\n name.addEventListener('click', () => this.callbacks.onSettings(instanceId));\r\n\r\n const values = document.createElement('span');\r\n values.className = 'tcw-ind-legend-values';\r\n\r\n const actions = document.createElement('span');\r\n actions.className = 'tcw-ind-legend-actions';\r\n // Named in fill(), once the row's label is known.\r\n const action = (act: string, icon: string, run: () => void) => {\r\n const b = document.createElement('button');\r\n b.type = 'button';\r\n b.className = 'tcw-ind-legend-act';\r\n b.dataset.act = act;\r\n b.innerHTML = createIcon(icon, 13);\r\n b.addEventListener('click', run);\r\n actions.appendChild(b);\r\n return b;\r\n };\r\n const eye = action('visible', 'eye', () => {\r\n this.callbacks.onToggleVisible(instanceId, !els.visible);\r\n });\r\n const settings = action('settings', 'settings', () => this.callbacks.onSettings(instanceId));\r\n const more = this.callbacks.onMore\r\n ? action('more', 'more', () => this.callbacks.onMore?.(instanceId, more!))\r\n : null;\r\n const remove = action('remove', 'x', () => this.callbacks.onRemove(instanceId));\r\n\r\n el.append(name, values, actions);\r\n const els: RowEls = {\r\n el, name, values, eye, settings, more, remove, visible: true, valuesKey: '', state: '', placeKey: '',\r\n };\r\n this.rows.set(instanceId, els);\r\n return els;\r\n }\r\n\r\n private fill(els: RowEls, row: IndicatorLegendRow): void {\r\n const state = `${row.label}|${row.visible}`;\r\n if (state !== els.state) {\r\n els.state = state;\r\n els.visible = row.visible;\r\n els.name.textContent = row.label;\r\n els.name.title = this.labels.settings;\r\n els.el.classList.toggle('tcw-ind-legend-row--hidden', !row.visible);\r\n els.eye.innerHTML = createIcon(row.visible ? 'eye' : 'eyeOff', 13);\r\n setLabel(els.eye, row.visible ? this.labels.hide : this.labels.show, row.label);\r\n setLabel(els.settings, this.labels.settings, row.label);\r\n if (els.more) {\r\n setLabel(els.more, this.labels.more ?? 'More', row.label);\r\n els.more.setAttribute('aria-haspopup', 'menu');\r\n }\r\n setLabel(els.remove, this.labels.remove, row.label);\r\n }\r\n const valuesKey = row.values.map((v) => `${v.text}${v.color ?? ''}`).join('\\u0001');\r\n if (valuesKey === els.valuesKey) return;\r\n els.valuesKey = valuesKey;\r\n els.values.replaceChildren(...row.values.map((v) => {\r\n const span = document.createElement('span');\r\n span.textContent = v.text;\r\n if (v.color) span.style.color = v.color;\r\n return span;\r\n }));\r\n }\r\n\r\n /** Pane rows are placed in their pane; stacked rows flow in the stack. */\r\n private place(els: RowEls, pane: IndicatorLegendRow['pane']): void {\r\n const key = pane ? `${Math.round(pane.x)},${Math.round(pane.y)},${Math.round(pane.width)}` : '';\r\n if (key === els.placeKey) return;\r\n els.placeKey = key;\r\n els.el.classList.toggle('tcw-ind-legend-row--pane', pane !== null);\r\n els.el.style.left = pane ? `${Math.round(pane.x)}px` : '';\r\n els.el.style.top = pane ? `${Math.round(pane.y)}px` : '';\r\n els.el.style.maxWidth = pane ? `${Math.max(0, Math.round(pane.width))}px` : '';\r\n }\r\n\r\n private setCollapsed(collapsed: boolean): void {\r\n this.collapsed = collapsed;\r\n this.stack.classList.toggle('tcw-ind-legend--collapsed', collapsed);\r\n }\r\n\r\n private overlayCount(): number {\r\n return this.stack.querySelectorAll(':scope > .tcw-ind-legend-row').length;\r\n }\r\n\r\n /** Written only when something changed: `update()` runs every frame. */\r\n private renderToggle(count: number): void {\r\n const shown = count >= COLLAPSE_FROM;\r\n if (!shown && this.collapsed) this.setCollapsed(false);\r\n const key = `${shown}|${this.collapsed}|${count}`;\r\n if (key === this.toggleKey) return;\r\n this.toggleKey = key;\r\n this.toggle.hidden = !shown;\r\n if (!shown) return;\r\n const label = this.collapsed ? this.labels.expand : this.labels.collapse;\r\n setLabel(this.toggle, label, this.collapsed ? `(${count})` : undefined);\r\n this.toggle.setAttribute('aria-expanded', String(!this.collapsed));\r\n const icon = createIcon(this.collapsed ? 'chevronDown' : 'chevronUp', 12);\r\n this.toggle.innerHTML = this.collapsed ? `${icon}<span>${count}</span>` : icon;\r\n }\r\n}\r\n\r\n/**\r\n * An icon button's name: `title` for the tooltip (\"Remove\"), and an\r\n * `aria-label` that says what it acts on (\"Remove EMA 50\") for assistive tech,\r\n * which would otherwise hear a column of identical \"Remove\" buttons. (The\r\n * tooltip also lifts `title` off the element while it is hovered.)\r\n */\r\nfunction setLabel(button: HTMLButtonElement, label: string, subject?: string): void {\r\n button.title = label;\r\n button.setAttribute('aria-label', subject ? `${label} ${subject}` : label);\r\n}\r\n","import type { IndicatorDescriptor, IndicatorValue } from '@tradecanvas/commons';\r\nimport { formatPrice } from '@tradecanvas/commons';\r\nimport { plotColor, indicatorValuePrecision } from '@tradecanvas/core';\r\n\r\n/** One value in an indicator's legend row; `color` null = the neutral text colour. */\r\nexport interface LegendValue {\r\n value: number;\r\n color: string | null;\r\n}\r\n\r\n/**\r\n * An indicator's values at one bar, as its legend shows them: one per plot it\r\n * draws, in drawing order, each in the colour its line has at that bar (the\r\n * up or down colour of a two-tone plot). An indicator that declares no plots\r\n * shows every finite field, in its colour only when there is just one.\r\n */\r\nexport function legendValues(\r\n descriptor: Pick<IndicatorDescriptor, 'plots'>,\r\n point: IndicatorValue | null | undefined,\r\n colors: readonly string[],\r\n): LegendValue[] {\r\n if (!point) return [];\r\n const plots = descriptor.plots;\r\n if (!plots) {\r\n const numbers: number[] = [];\r\n for (const key in point) {\r\n const v = point[key];\r\n if (typeof v === 'number' && Number.isFinite(v)) numbers.push(v);\r\n }\r\n const color = numbers.length === 1 ? colors[0] ?? null : null;\r\n return numbers.map((value) => ({ value, color }));\r\n }\r\n const style = { colors: [...colors], lineWidths: [], opacity: 1 };\r\n const out: LegendValue[] = [];\r\n for (const plot of plots) {\r\n const v = point[plot.key];\r\n if (typeof v !== 'number' || !Number.isFinite(v)) continue;\r\n out.push({ value: v, color: colors.length ? plotColor(plot, style, point) : null });\r\n }\r\n return out;\r\n}\r\n\r\n/** Compact formats (\"1.23M\") by locale; the legend formats every frame. */\r\nconst compactFormats = new Map<string, Intl.NumberFormat>();\r\n\r\nfunction compactFormat(locale: string): Intl.NumberFormat {\r\n let format = compactFormats.get(locale);\r\n if (!format) {\r\n format = new Intl.NumberFormat(locale, { notation: 'compact', maximumFractionDigits: 2 });\r\n compactFormats.set(locale, format);\r\n }\r\n return format;\r\n}\r\n\r\n/**\r\n * A pane indicator's value (RSI 54.32, MACD 0.0012, OBV 1.23M): the decimals\r\n * follow its size, and big ones are shortened.\r\n */\r\nexport function formatIndicatorValue(value: number, locale = 'en-US'): string {\r\n if (Math.abs(value) >= 1e6) return compactFormat(locale).format(value);\r\n return formatPrice(value, indicatorValuePrecision(value), locale);\r\n}\r\n","import { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\r\nimport { escapeHtml } from './escapeHtml.js';\r\n\r\nexport interface BracketBarCallbacks {\r\n onConfirm: () => void;\r\n onCancel: () => void;\r\n}\r\n\r\n/**\r\n * Floating confirm/cancel bar shown while a bracket order is being placed.\r\n * The live entry / SL / TP numbers are drawn on the chart canvas; this bar\r\n * just carries the commit and discard actions (also bound to Enter / Esc).\r\n */\r\nexport class WidgetBracketBar {\r\n private el: HTMLDivElement;\r\n private labelEl: HTMLSpanElement;\r\n private callbacks: BracketBarCallbacks;\r\n private visible = false;\r\n\r\n constructor(host: HTMLElement, callbacks: BracketBarCallbacks, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.callbacks = callbacks;\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-bracket-bar';\r\n this.el.hidden = true;\r\n\r\n this.labelEl = document.createElement('span');\r\n this.labelEl.className = 'tcw-bracket-label';\r\n this.el.appendChild(this.labelEl);\r\n\r\n const hint = document.createElement('span');\r\n hint.className = 'tcw-bracket-hint';\r\n hint.textContent = this.t('bracket.hint');\r\n this.el.appendChild(hint);\r\n\r\n const cancel = document.createElement('button');\r\n cancel.type = 'button';\r\n cancel.className = 'tcw-bracket-cancel';\r\n cancel.innerHTML = `${createIcon('x', 14)}<span>${escapeHtml(this.t('common.cancel'))}</span>`;\r\n cancel.addEventListener('click', () => this.callbacks.onCancel());\r\n\r\n const confirm = document.createElement('button');\r\n confirm.type = 'button';\r\n confirm.className = 'tcw-bracket-confirm';\r\n confirm.innerHTML = `${createIcon('check', 14)}<span>${escapeHtml(this.t('bracket.place'))}</span>`;\r\n confirm.addEventListener('click', () => this.callbacks.onConfirm());\r\n\r\n this.el.appendChild(cancel);\r\n this.el.appendChild(confirm);\r\n host.appendChild(this.el);\r\n }\r\n\r\n show(side: 'buy' | 'sell'): void {\r\n this.visible = true;\r\n this.labelEl.textContent = side === 'buy' ? this.t('toolbar.longBracket') : this.t('toolbar.shortBracket');\r\n this.labelEl.dataset.side = side;\r\n this.el.hidden = false;\r\n }\r\n\r\n hide(): void {\r\n this.visible = false;\r\n this.el.hidden = true;\r\n }\r\n\r\n isVisible(): boolean {\r\n return this.visible;\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n}\r\n","export interface AlertNotifyOptions {\r\n /** Play a sound on trigger. `true` = built-in beep, string = audio URL. Default `false`. */\r\n sound?: boolean | string;\r\n /** Show a desktop notification (requests permission on first use). Default `false`. */\r\n desktop?: boolean;\r\n /** Title for desktop notifications. Default `'Price alert'`. */\r\n title?: string;\r\n}\r\n\r\n/** True when the Notification API is present and not denied. */\r\nexport function canRequestNotifications(): boolean {\r\n return typeof Notification !== 'undefined' && Notification.permission !== 'denied';\r\n}\r\n\r\n/**\r\n * Plays a sound and/or raises a desktop notification when a price alert fires.\r\n * Browser-API heavy by nature — every entry point is guarded so it degrades to\r\n * a no-op in SSR, unsupported browsers, or when permission is denied.\r\n */\r\nexport class AlertNotifier {\r\n private options: AlertNotifyOptions;\r\n private audioCtx: AudioContext | null = null;\r\n private audioEl: HTMLAudioElement | null = null;\r\n private permissionAsked = false;\r\n\r\n constructor(options: AlertNotifyOptions = {}) {\r\n this.options = options;\r\n if (typeof options.sound === 'string') {\r\n try {\r\n this.audioEl = new Audio(options.sound);\r\n this.audioEl.preload = 'auto';\r\n } catch {\r\n this.audioEl = null;\r\n }\r\n }\r\n // Request notification permission up front so the first alert isn't silent.\r\n if (options.desktop) this.ensurePermission();\r\n }\r\n\r\n setOptions(options: AlertNotifyOptions): void {\r\n this.options = { ...this.options, ...options };\r\n }\r\n\r\n /** Fire the configured notifications for a triggered alert. */\r\n notify(message: string): void {\r\n if (this.options.sound) this.playSound();\r\n if (this.options.desktop) this.showDesktop(message);\r\n }\r\n\r\n private playSound(): void {\r\n if (this.audioEl) {\r\n this.audioEl.currentTime = 0;\r\n void this.audioEl.play().catch(() => {});\r\n return;\r\n }\r\n this.beep();\r\n }\r\n\r\n /** A short two-tone beep via Web Audio — no asset required. */\r\n private beep(): void {\r\n try {\r\n const Ctx = window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\r\n if (!Ctx) return;\r\n if (!this.audioCtx) this.audioCtx = new Ctx();\r\n const ctx = this.audioCtx;\r\n const now = ctx.currentTime;\r\n const gain = ctx.createGain();\r\n gain.gain.setValueAtTime(0.0001, now);\r\n gain.gain.exponentialRampToValueAtTime(0.2, now + 0.01);\r\n gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.35);\r\n gain.connect(ctx.destination);\r\n const osc = ctx.createOscillator();\r\n osc.type = 'sine';\r\n osc.frequency.setValueAtTime(880, now);\r\n osc.frequency.setValueAtTime(1320, now + 0.16);\r\n osc.connect(gain);\r\n osc.start(now);\r\n osc.stop(now + 0.36);\r\n } catch {\r\n // Audio unavailable or blocked by autoplay policy — silent.\r\n }\r\n }\r\n\r\n private ensurePermission(): void {\r\n if (this.permissionAsked) return;\r\n this.permissionAsked = true;\r\n if (typeof Notification === 'undefined') return;\r\n if (Notification.permission === 'default') {\r\n void Notification.requestPermission().catch(() => {});\r\n }\r\n }\r\n\r\n private showDesktop(message: string): void {\r\n if (typeof Notification === 'undefined') return;\r\n if (Notification.permission !== 'granted') {\r\n this.ensurePermission();\r\n return;\r\n }\r\n try {\r\n new Notification(this.options.title ?? 'Price alert', { body: message });\r\n } catch {\r\n // Some browsers throw if not invoked from a user gesture — ignore.\r\n }\r\n }\r\n\r\n destroy(): void {\r\n try {\r\n void this.audioCtx?.close();\r\n } catch {\r\n // ignore\r\n }\r\n this.audioCtx = null;\r\n this.audioEl = null;\r\n }\r\n}\r\n","import type { DepthData } from '@tradecanvas/commons';\r\n\r\nexport interface LadderRow {\r\n price: number;\r\n bidVolume: number;\r\n askVolume: number;\r\n}\r\n\r\nexport interface LadderModel {\r\n /** Rows ordered high → low price (asks on top, bids below). */\r\n rows: LadderRow[];\r\n /** Largest single-side volume across the shown rows (for bar scaling). */\r\n maxVolume: number;\r\n /** Midpoint between best bid and best ask, or null if a side is empty. */\r\n mid: number | null;\r\n}\r\n\r\n/**\r\n * Build a depth-of-market ladder from an order book: the best `maxLevels` asks\r\n * (lowest prices) and best `maxLevels` bids (highest prices), merged into rows\r\n * ordered high→low. A price present on both sides is merged into one row.\r\n */\r\nexport function buildLadderRows(data: DepthData, maxLevels = 12): LadderModel {\r\n const asks = [...data.asks].sort((a, b) => a.price - b.price).slice(0, maxLevels);\r\n const bids = [...data.bids].sort((a, b) => b.price - a.price).slice(0, maxLevels);\r\n\r\n const bestAsk = asks.length > 0 ? asks[0].price : null;\r\n const bestBid = bids.length > 0 ? bids[0].price : null;\r\n const mid = bestAsk !== null && bestBid !== null ? (bestAsk + bestBid) / 2 : null;\r\n\r\n const byPrice = new Map<number, LadderRow>();\r\n const rowAt = (price: number): LadderRow => {\r\n let row = byPrice.get(price);\r\n if (!row) {\r\n row = { price, bidVolume: 0, askVolume: 0 };\r\n byPrice.set(price, row);\r\n }\r\n return row;\r\n };\r\n for (const a of asks) rowAt(a.price).askVolume += a.volume;\r\n for (const b of bids) rowAt(b.price).bidVolume += b.volume;\r\n\r\n const rows = [...byPrice.values()].sort((a, b) => b.price - a.price);\r\n let maxVolume = 0;\r\n for (const r of rows) maxVolume = Math.max(maxVolume, r.bidVolume, r.askVolume);\r\n\r\n return { rows, maxVolume, mid };\r\n}\r\n","import type { DepthData } from '@tradecanvas/commons';\r\nimport { createIcon } from './icons.js';\r\nimport { buildLadderRows, type LadderModel } from './ladderRows.js';\r\nimport { EN_TRANSLATOR, fill, type Translator } from './i18n.js';\r\nimport { escapeHtml } from './escapeHtml.js';\r\n\r\nexport interface DepthLadderCallbacks {\r\n /** Buy at `price` (clicked an ask cell) or sell at `price` (clicked a bid cell). */\r\n onTrade: (side: 'buy' | 'sell', price: number) => void;\r\n formatPrice: (price: number) => string;\r\n}\r\n\r\n/**\r\n * Depth-of-market ladder (DOM). Renders the order book as price rows with bid\r\n * and ask size columns; clicking an ask cell buys at that price, a bid cell\r\n * sells. Fed by `setData(depth)`; the bar widths scale to the largest visible\r\n * size.\r\n */\r\nexport class WidgetDepthLadder {\r\n private el: HTMLDivElement;\r\n private bodyEl: HTMLDivElement;\r\n private callbacks: DepthLadderCallbacks;\r\n private open = false;\r\n private levels: number;\r\n\r\n constructor(host: HTMLElement, callbacks: DepthLadderCallbacks, levels = 12, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.callbacks = callbacks;\r\n this.levels = levels;\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-ladder';\r\n this.el.hidden = true;\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-ladder-header';\r\n const title = document.createElement('span');\r\n title.textContent = this.t('ladder.title');\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-ladder-close';\r\n closeBtn.setAttribute('aria-label', this.t('common.close'));\r\n closeBtn.innerHTML = createIcon('x', 14);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.appendChild(title);\r\n header.appendChild(closeBtn);\r\n this.el.appendChild(header);\r\n\r\n const cols = document.createElement('div');\r\n cols.className = 'tcw-ladder-cols';\r\n cols.innerHTML = [this.t('ladder.bid'), this.t('ladder.price'), this.t('ladder.ask')]\r\n .map((label) => `<span>${escapeHtml(label)}</span>`).join('');\r\n this.el.appendChild(cols);\r\n\r\n this.bodyEl = document.createElement('div');\r\n this.bodyEl.className = 'tcw-ladder-body';\r\n this.el.appendChild(this.bodyEl);\r\n\r\n host.appendChild(this.el);\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.open;\r\n }\r\n\r\n toggle(): void {\r\n this.open ? this.close() : this.openPanel();\r\n }\r\n\r\n openPanel(): void {\r\n this.open = true;\r\n this.el.hidden = false;\r\n }\r\n\r\n close(): void {\r\n this.open = false;\r\n this.el.hidden = true;\r\n }\r\n\r\n setData(depth: DepthData | null): void {\r\n if (!depth) {\r\n this.renderEmpty();\r\n return;\r\n }\r\n this.render(buildLadderRows(depth, this.levels));\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n private renderEmpty(): void {\r\n this.bodyEl.replaceChildren();\r\n const empty = document.createElement('div');\r\n empty.className = 'tcw-ladder-empty';\r\n empty.textContent = this.t('ladder.empty');\r\n this.bodyEl.appendChild(empty);\r\n }\r\n\r\n private render(model: LadderModel): void {\r\n this.bodyEl.replaceChildren();\r\n if (model.rows.length === 0) {\r\n this.renderEmpty();\r\n return;\r\n }\r\n const inv = model.maxVolume > 0 ? 1 / model.maxVolume : 0;\r\n\r\n for (const row of model.rows) {\r\n const isAsk = row.askVolume > 0;\r\n const tr = document.createElement('div');\r\n tr.className = 'tcw-ladder-row';\r\n\r\n // Bid cell (click → sell at price)\r\n const bid = document.createElement('button');\r\n bid.type = 'button';\r\n bid.className = 'tcw-ladder-cell tcw-ladder-bid';\r\n if (row.bidVolume > 0) {\r\n bid.textContent = formatSize(row.bidVolume);\r\n bid.style.setProperty('--w', `${(row.bidVolume * inv * 100).toFixed(1)}%`);\r\n bid.title = fill(this.t('ladder.sellAt'), { price: this.callbacks.formatPrice(row.price) });\r\n bid.addEventListener('click', () => this.callbacks.onTrade('sell', row.price));\r\n } else {\r\n bid.disabled = true;\r\n }\r\n\r\n const price = document.createElement('div');\r\n price.className = `tcw-ladder-price ${isAsk ? 'tcw-ask' : 'tcw-bid'}`;\r\n price.textContent = this.callbacks.formatPrice(row.price);\r\n\r\n // Ask cell (click → buy at price)\r\n const ask = document.createElement('button');\r\n ask.type = 'button';\r\n ask.className = 'tcw-ladder-cell tcw-ladder-ask';\r\n if (row.askVolume > 0) {\r\n ask.textContent = formatSize(row.askVolume);\r\n ask.style.setProperty('--w', `${(row.askVolume * inv * 100).toFixed(1)}%`);\r\n ask.title = fill(this.t('ladder.buyAt'), { price: this.callbacks.formatPrice(row.price) });\r\n ask.addEventListener('click', () => this.callbacks.onTrade('buy', row.price));\r\n } else {\r\n ask.disabled = true;\r\n }\r\n\r\n tr.appendChild(bid);\r\n tr.appendChild(price);\r\n tr.appendChild(ask);\r\n this.bodyEl.appendChild(tr);\r\n }\r\n }\r\n}\r\n\r\nfunction formatSize(v: number): string {\r\n if (v >= 1000) return (v / 1000).toFixed(1) + 'k';\r\n if (v >= 1) return v.toFixed(2).replace(/\\.00$/, '');\r\n return v.toPrecision(2);\r\n}\r\n","import { createIcon } from './icons.js';\r\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\r\n\r\nexport interface DataWindowIndicator {\r\n name: string;\r\n values: { key: string; value: number }[];\r\n}\r\n\r\nexport interface DataWindowModel {\r\n ohlc: { open: number; high: number; low: number; close: number; volume: number } | null;\r\n change: number;\r\n changePct: number;\r\n indicators: DataWindowIndicator[];\r\n}\r\n\r\nexport interface DataWindowCallbacks {\r\n formatPrice: (price: number) => string;\r\n}\r\n\r\n/**\r\n * Data Window — a floating readout of the exact O/H/L/C/V, change, and every\r\n * active indicator value at the hovered bar. Updated from `crosshairMove`.\r\n */\r\nexport class WidgetDataWindow {\r\n private el: HTMLDivElement;\r\n private bodyEl: HTMLDivElement;\r\n private callbacks: DataWindowCallbacks;\r\n private open = false;\r\n\r\n constructor(host: HTMLElement, callbacks: DataWindowCallbacks, private readonly t: Translator = EN_TRANSLATOR) {\r\n this.callbacks = callbacks;\r\n\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-datawin';\r\n this.el.hidden = true;\r\n\r\n const header = document.createElement('div');\r\n header.className = 'tcw-datawin-header';\r\n const title = document.createElement('span');\r\n title.textContent = this.t('dataWindow.title');\r\n const closeBtn = document.createElement('button');\r\n closeBtn.type = 'button';\r\n closeBtn.className = 'tcw-datawin-close';\r\n closeBtn.setAttribute('aria-label', this.t('common.close'));\r\n closeBtn.innerHTML = createIcon('x', 14);\r\n closeBtn.addEventListener('click', () => this.close());\r\n header.appendChild(title);\r\n header.appendChild(closeBtn);\r\n this.el.appendChild(header);\r\n\r\n this.bodyEl = document.createElement('div');\r\n this.bodyEl.className = 'tcw-datawin-body';\r\n this.el.appendChild(this.bodyEl);\r\n\r\n host.appendChild(this.el);\r\n }\r\n\r\n isOpen(): boolean {\r\n return this.open;\r\n }\r\n\r\n toggle(): void {\r\n this.open ? this.close() : this.openPanel();\r\n }\r\n\r\n openPanel(): void {\r\n this.open = true;\r\n this.el.hidden = false;\r\n }\r\n\r\n close(): void {\r\n this.open = false;\r\n this.el.hidden = true;\r\n }\r\n\r\n destroy(): void {\r\n this.el.remove();\r\n }\r\n\r\n render(model: DataWindowModel): void {\r\n if (!this.open) return;\r\n this.bodyEl.replaceChildren();\r\n\r\n if (!model.ohlc) {\r\n const empty = document.createElement('div');\r\n empty.className = 'tcw-datawin-empty';\r\n empty.textContent = this.t('dataWindow.hover');\r\n this.bodyEl.appendChild(empty);\r\n return;\r\n }\r\n\r\n const fp = this.callbacks.formatPrice;\r\n const o = model.ohlc;\r\n this.bodyEl.appendChild(this.row(this.t('dataWindow.open'), fp(o.open)));\r\n this.bodyEl.appendChild(this.row(this.t('dataWindow.high'), fp(o.high)));\r\n this.bodyEl.appendChild(this.row(this.t('dataWindow.low'), fp(o.low)));\r\n this.bodyEl.appendChild(this.row(this.t('dataWindow.close'), fp(o.close)));\r\n const tone = model.change > 0 ? 'up' : model.change < 0 ? 'down' : '';\r\n const sign = model.change > 0 ? '+' : '';\r\n this.bodyEl.appendChild(this.row(this.t('dataWindow.change'), `${sign}${fp(model.change)} (${sign}${model.changePct.toFixed(2)}%)`, tone));\r\n this.bodyEl.appendChild(this.row(this.t('dataWindow.volume'), formatVolume(o.volume)));\r\n\r\n for (const ind of model.indicators) {\r\n const head = document.createElement('div');\r\n head.className = 'tcw-datawin-sub';\r\n head.textContent = ind.name;\r\n this.bodyEl.appendChild(head);\r\n for (const v of ind.values) {\r\n this.bodyEl.appendChild(this.row(v.key, formatNumber(v.value)));\r\n }\r\n }\r\n }\r\n\r\n private row(label: string, value: string, tone = ''): HTMLDivElement {\r\n const row = document.createElement('div');\r\n row.className = 'tcw-datawin-row';\r\n const l = document.createElement('span');\r\n l.className = 'tcw-datawin-label';\r\n l.textContent = label;\r\n const v = document.createElement('span');\r\n v.className = `tcw-datawin-value${tone ? ` tcw-${tone}` : ''}`;\r\n v.textContent = value;\r\n row.appendChild(l);\r\n row.appendChild(v);\r\n return row;\r\n }\r\n}\r\n\r\nfunction formatNumber(v: number): string {\r\n if (!Number.isFinite(v)) return '—';\r\n const abs = Math.abs(v);\r\n if (abs >= 1000) return v.toFixed(2);\r\n if (abs >= 1) return v.toFixed(4);\r\n return v.toPrecision(4);\r\n}\r\n\r\nfunction formatVolume(v: number): string {\r\n if (v >= 1_000_000_000) return (v / 1_000_000_000).toFixed(2) + 'B';\r\n if (v >= 1_000_000) return (v / 1_000_000).toFixed(2) + 'M';\r\n if (v >= 1_000) return (v / 1_000).toFixed(2) + 'K';\r\n return v.toFixed(0);\r\n}\r\n","import type { ChartType, TimeFrame, DrawingState, PriceScaleMode } from '@tradecanvas/commons';\r\n\r\nexport interface ShareableIndicator {\r\n id: string;\r\n params: Record<string, number | string | boolean>;\r\n}\r\n\r\nexport interface ShareableWidgetState {\r\n v: 1;\r\n symbol: string;\r\n timeframe: TimeFrame;\r\n chartType: ChartType;\r\n scaleMode: PriceScaleMode;\r\n indicators: ShareableIndicator[];\r\n drawings: DrawingState[];\r\n}\r\n\r\ninterface NodeBufferCtor {\r\n from(input: string, encoding: string): { toString(encoding: string): string };\r\n}\r\nconst nodeBuffer = (globalThis as { Buffer?: NodeBufferCtor }).Buffer;\r\n\r\nfunction utf8ToBase64(str: string): string {\r\n if (nodeBuffer) return nodeBuffer.from(str, 'utf8').toString('base64');\r\n const bytes = new TextEncoder().encode(str);\r\n let bin = '';\r\n for (const b of bytes) bin += String.fromCharCode(b);\r\n return btoa(bin);\r\n}\r\n\r\nfunction base64ToUtf8(b64: string): string {\r\n if (nodeBuffer) return nodeBuffer.from(b64, 'base64').toString('utf8');\r\n const bin = atob(b64);\r\n const bytes = new Uint8Array(bin.length);\r\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\r\n return new TextDecoder().decode(bytes);\r\n}\r\n\r\nfunction toBase64Url(b64: string): string {\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\r\n}\r\n\r\nfunction fromBase64Url(s: string): string {\r\n const b64 = s.replace(/-/g, '+').replace(/_/g, '/');\r\n const pad = b64.length % 4 === 0 ? '' : '='.repeat(4 - (b64.length % 4));\r\n return b64 + pad;\r\n}\r\n\r\n/** Encode a shareable widget state to a compact, URL-safe string. */\r\nexport function encodeWidgetState(state: ShareableWidgetState): string {\r\n return toBase64Url(utf8ToBase64(JSON.stringify(state)));\r\n}\r\n\r\n/**\r\n * Decode a shareable-state string. Returns null for anything malformed or of an\r\n * unknown version — callers should treat null as \"ignore and keep current view\".\r\n */\r\nexport function decodeWidgetState(encoded: string): ShareableWidgetState | null {\r\n if (!encoded) return null;\r\n try {\r\n const json = base64ToUtf8(fromBase64Url(encoded));\r\n const obj = JSON.parse(json);\r\n if (!obj || obj.v !== 1 || typeof obj.symbol !== 'string') return null;\r\n return {\r\n v: 1,\r\n symbol: obj.symbol,\r\n timeframe: obj.timeframe,\r\n chartType: obj.chartType,\r\n scaleMode: obj.scaleMode ?? 'regular',\r\n indicators: Array.isArray(obj.indicators) ? obj.indicators : [],\r\n drawings: Array.isArray(obj.drawings) ? obj.drawings : [],\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nconst HASH_KEY = 'tcw';\r\n\r\n/** Read a `#tcw=<encoded>` fragment from a URL hash, or null. */\r\nexport function readShareHash(hash: string): string | null {\r\n const clean = hash.startsWith('#') ? hash.slice(1) : hash;\r\n for (const part of clean.split('&')) {\r\n const eq = part.indexOf('=');\r\n if (eq > 0 && part.slice(0, eq) === HASH_KEY) return decodeURIComponent(part.slice(eq + 1));\r\n }\r\n return null;\r\n}\r\n\r\n/** Build a shareable URL by replacing the `tcw` hash param on `base`. */\r\nexport function buildShareUrl(base: string, encoded: string): string {\r\n const [withoutHash] = base.split('#');\r\n return `${withoutHash}#${HASH_KEY}=${encoded}`;\r\n}\r\n","/**\r\n * How long a symbol/timeframe switch may run before the loading veil\r\n * appears. Faster loads just swap the chart in place — flashing a loader for\r\n * a 150 ms request reads as flicker, not feedback.\r\n */\r\nexport const LOADING_SHOW_DELAY_MS = 200;\r\n\r\n/**\r\n * Silhouette of the loading mark: a short rising run of candles as\r\n * [body top, body height, wick top, wick height, rising] in a 64 px box\r\n * (y grows downward).\r\n */\r\nconst SKELETON_CANDLES: readonly (readonly [number, number, number, number, boolean])[] = [\r\n [34, 16, 28, 26, false],\r\n [30, 14, 24, 26, true],\r\n [26, 18, 20, 30, true],\r\n [30, 10, 24, 22, false],\r\n [20, 16, 14, 28, true],\r\n [14, 18, 8, 30, true],\r\n [18, 10, 12, 20, false],\r\n [8, 18, 2, 30, true],\r\n];\r\n\r\n/**\r\n * Loading state for the chart area: a run of candles lit one after another\r\n * over a sweeping accent line. The status text is for screen readers only;\r\n * an error message is shown.\r\n *\r\n * - First load (nothing to show yet): opaque skeleton, shown immediately.\r\n * - Switch (a chart is already on screen): the old chart stays visible and is\r\n * veiled only if the load outlasts `LOADING_SHOW_DELAY_MS`.\r\n * - Failure: the label becomes the error message until the next load or a\r\n * successful retry ends it.\r\n */\r\nexport class WidgetLoadingOverlay {\r\n private readonly el: HTMLDivElement;\r\n private readonly label: HTMLDivElement;\r\n private showTimer: ReturnType<typeof setTimeout> | null = null;\r\n // Starts loading: the widget mounts before its first bars arrive.\r\n private phase: 'idle' | 'loading' | 'failed' = 'loading';\r\n\r\n constructor(parent: HTMLElement, private readonly loadingText: string) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-loading-overlay';\r\n this.el.setAttribute('role', 'status');\r\n this.el.setAttribute('aria-live', 'polite');\r\n\r\n // Candles + label share a card: transparent on the opaque first-load\r\n // screen, a raised panel when veiling a chart so it reads over the candles.\r\n const card = document.createElement('div');\r\n card.className = 'tcw-loading-card';\r\n\r\n const candles = document.createElement('div');\r\n candles.className = 'tcw-loading-candles';\r\n candles.setAttribute('aria-hidden', 'true');\r\n SKELETON_CANDLES.forEach(([bodyTop, bodyHeight, wickTop, wickHeight, rising], i) => {\r\n const candle = document.createElement('span');\r\n candle.className = rising ? 'tcw-loading-candle tcw-loading-candle--up' : 'tcw-loading-candle';\r\n candle.style.setProperty('--tcw-body-top', `${bodyTop}px`);\r\n candle.style.setProperty('--tcw-body-h', `${bodyHeight}px`);\r\n candle.style.setProperty('--tcw-wick-top', `${wickTop}px`);\r\n candle.style.setProperty('--tcw-wick-h', `${wickHeight}px`);\r\n // A custom property, so a page-wide `animation-delay: 0 !important` reset can't flatten the wave.\r\n candle.style.setProperty('--tcw-delay', `${i * 110}ms`);\r\n candles.appendChild(candle);\r\n });\r\n card.appendChild(candles);\r\n\r\n const track = document.createElement('div');\r\n track.className = 'tcw-loading-track';\r\n track.setAttribute('aria-hidden', 'true');\r\n track.appendChild(document.createElement('span'));\r\n card.appendChild(track);\r\n\r\n this.label = document.createElement('div');\r\n this.label.className = 'tcw-loading-label';\r\n this.label.textContent = loadingText;\r\n card.appendChild(this.label);\r\n this.el.appendChild(card);\r\n\r\n parent.appendChild(this.el);\r\n }\r\n\r\n /**\r\n * Start a load. `hasContent`: a chart is already on screen to keep showing.\r\n * `immediate`: skip the show delay — the caller knows the load is slow.\r\n */\r\n begin(hasContent: boolean, immediate = false): void {\r\n this.phase = 'loading';\r\n this.clearTimer();\r\n this.label.textContent = this.loadingText;\r\n this.el.classList.remove('tcw-loading-overlay--error');\r\n this.el.classList.toggle('tcw-loading-overlay--veil', hasContent);\r\n if (!hasContent || immediate || this.isShown()) {\r\n this.el.classList.remove('tcw-loading-overlay--hidden');\r\n return;\r\n }\r\n this.showTimer = setTimeout(() => {\r\n this.showTimer = null;\r\n this.el.classList.remove('tcw-loading-overlay--hidden');\r\n }, LOADING_SHOW_DELAY_MS);\r\n }\r\n\r\n /** The load finished: fade out, or never appear if still within the delay. */\r\n end(): void {\r\n this.phase = 'idle';\r\n this.clearTimer();\r\n this.el.classList.add('tcw-loading-overlay--hidden');\r\n }\r\n\r\n /** The current load failed (a retry may still be running): show why. */\r\n fail(message: string): void {\r\n if (this.phase === 'idle') return;\r\n this.phase = 'failed';\r\n this.clearTimer();\r\n this.label.textContent = message;\r\n this.el.classList.add('tcw-loading-overlay--error');\r\n this.el.classList.remove('tcw-loading-overlay--hidden');\r\n }\r\n\r\n /** Whether a load is in progress (begun, not yet ended) — failed included. */\r\n isActive(): boolean {\r\n return this.phase !== 'idle';\r\n }\r\n\r\n /** Whether the current load failed and is waiting on a retry. */\r\n hasFailed(): boolean {\r\n return this.phase === 'failed';\r\n }\r\n\r\n /** Whether the overlay is on screen (or fading in). */\r\n isShown(): boolean {\r\n return !this.el.classList.contains('tcw-loading-overlay--hidden');\r\n }\r\n\r\n destroy(): void {\r\n this.clearTimer();\r\n this.el.remove();\r\n }\r\n\r\n private clearTimer(): void {\r\n if (this.showTimer !== null) {\r\n clearTimeout(this.showTimer);\r\n this.showTimer = null;\r\n }\r\n }\r\n}\r\n","import type { HistoryLoadPayload } from '@tradecanvas/commons';\r\n\r\n/** How long a failed history page stays reported. */\r\nexport const HISTORY_ERROR_MS = 4000;\r\n\r\n/**\r\n * A small status pill at the left edge of the chart while older bars load\r\n * (scrolling back in time), and briefly when a page fails.\r\n */\r\nexport class WidgetHistoryPill {\r\n private readonly el: HTMLDivElement;\r\n private readonly text: HTMLSpanElement;\r\n private hideTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n constructor(parent: HTMLElement, private readonly texts: { loading: string; failed: string }) {\r\n this.el = document.createElement('div');\r\n this.el.className = 'tcw-history-pill tcw-history-pill--hidden';\r\n this.el.setAttribute('aria-hidden', 'true');\r\n this.el.setAttribute('role', 'status');\r\n this.el.setAttribute('aria-live', 'polite');\r\n const spinner = document.createElement('span');\r\n spinner.className = 'tcw-history-spinner';\r\n spinner.setAttribute('aria-hidden', 'true');\r\n this.text = document.createElement('span');\r\n this.el.append(spinner, this.text);\r\n parent.appendChild(this.el);\r\n }\r\n\r\n update(payload: HistoryLoadPayload): void {\r\n this.clearTimer();\r\n if (payload.state === 'loading') {\r\n this.show(this.texts.loading, false);\r\n } else if (payload.state === 'error') {\r\n this.show(this.texts.failed, true);\r\n this.hideTimer = setTimeout(() => this.hide(), HISTORY_ERROR_MS);\r\n } else {\r\n this.hide();\r\n }\r\n }\r\n\r\n destroy(): void {\r\n this.clearTimer();\r\n this.el.remove();\r\n }\r\n\r\n private show(text: string, failed: boolean): void {\r\n this.text.textContent = text;\r\n this.el.classList.toggle('tcw-history-pill--error', failed);\r\n this.el.classList.remove('tcw-history-pill--hidden');\r\n this.el.removeAttribute('aria-hidden');\r\n }\r\n\r\n private hide(): void {\r\n this.hideTimer = null;\r\n this.el.classList.add('tcw-history-pill--hidden');\r\n this.el.setAttribute('aria-hidden', 'true');\r\n this.text.textContent = '';\r\n }\r\n\r\n private clearTimer(): void {\r\n if (this.hideTimer !== null) clearTimeout(this.hideTimer);\r\n this.hideTimer = null;\r\n }\r\n}\r\n","import type { ChartType, DrawingToolType, FeaturesConfig, HistoryLoadPayload, Quote, QuoteSource, SymbolInfo, Theme, TimeFrame, TimeZoneSetting } from '@tradecanvas/commons';\r\nimport { marketStatus, readNews, readQuote, isValidTimeZone, tickBarCount, zoneOffsetMinutes, type NewsItem } from '@tradecanvas/commons';\r\nimport { settingToTimezone, timezoneToSetting } from './widgetTimezones.js';\r\nimport { Chart } from '../Chart.js';\r\nimport { DARK_THEME, LIGHT_THEME, indicatorSource, parseIndicatorSource } from '@tradecanvas/commons';\r\nimport type { ActiveIndicatorInfo, ChartWidgetOptions, WidgetState, ChartSettingsState } from './types.js';\r\nimport { CHART_TYPES, INDICATORS, POPULAR_INDICATORS, DRAWING_TOOL_GROUPS, DEFAULT_SYMBOLS, DEFAULT_SETTINGS } from './widgetConfig.js';\r\nimport { injectWidgetStyles, removeWidgetStyles } from './WidgetStyles.js';\r\nimport { WidgetToolbar, setHostButtonName } from './WidgetToolbar.js';\r\nimport { WidgetDrawingSidebar } from './WidgetDrawingSidebar.js';\r\nimport { WidgetSettings } from './WidgetSettings.js';\r\nimport { WidgetStatusBar } from './WidgetStatusBar.js';\r\nimport { WidgetCommandPalette } from './WidgetCommandPalette.js';\r\nimport { WidgetSymbolSearch, type SymbolSearchFn } from './WidgetSymbolSearch.js';\r\nimport { WidgetHotkeySheet } from './WidgetHotkeySheet.js';\r\nimport { WidgetReplayBar, DEFAULT_REPLAY_SPEED } from './WidgetReplayBar.js';\r\nimport { WidgetWatchlist, type WatchlistEntry } from './WidgetWatchlist.js';\r\nimport { WatchlistStore, type WatchlistList } from './WatchlistStore.js';\r\nimport { WidgetSymbolInfo, type SymbolInfoView } from './WidgetSymbolInfo.js';\r\nimport { WidgetChartNav } from './WidgetChartNav.js';\r\nimport { WidgetAlertsPanel, describeAlert, type AlertListItem, type AlertSource } from './WidgetAlertsPanel.js';\r\nimport { indicatorChipLabel } from '../indicatorLabel.js';\r\nimport { readChartTypeOptions } from '@tradecanvas/commons';\r\nimport { applyWidgetUI, resolveWidgetUI, type ResolvedWidgetUI, type WidgetUIPreset, type WidgetUITheme } from './widgetUI.js';\r\nimport { WidgetObjectTree, drawingTypeLabel } from './WidgetObjectTree.js';\r\nimport { WidgetIndicatorSettings } from './WidgetIndicatorSettings.js';\r\nimport { WidgetDrawingStyle } from './WidgetDrawingStyle.js';\r\nimport { DrawingDefaultsStore, DrawingTemplateStore } from './DrawingTemplateStore.js';\r\nimport { WidgetDrawingSettings } from './WidgetDrawingSettings.js';\r\nimport { WidgetContextMenu, type ContextMenuEntry } from './WidgetContextMenu.js';\r\nimport { drawingMenuEntries, type DrawingMenuAction } from './drawingMenu.js';\r\nimport { chartMenuEntries, priceEntries, type ChartMenuAction, type ChartMenuContext } from './chartMenu.js';\r\nimport { WidgetAccountPanel } from './WidgetAccountPanel.js';\r\nimport { WidgetOrderTicket } from './WidgetOrderTicket.js';\r\nimport { WidgetLayoutsUI } from './WidgetLayoutsUI.js';\r\nimport { WidgetNamePrompt } from './WidgetNamePrompt.js';\r\nimport { WidgetIntervalInput } from './WidgetIntervalInput.js';\r\nimport { IndicatorTemplateStore } from './indicatorTemplates.js';\r\nimport { isKeyTarget, isTyping, registerKeyRoot } from './keyTarget.js';\r\nimport { layoutChartState, readWidgetLayout, parseLayoutJson, type WidgetLayoutContent } from './widgetLayout.js';\r\nimport { LayoutSession } from '../state/LayoutSession.js';\r\nimport { localStorageLayouts, type SavedLayout } from '../state/layoutStorage.js';\r\nimport { DrawingFavoritesStore } from './DrawingFavoritesStore.js';\r\nimport {\r\n availableTimeframes,\r\n initialTimeframeFavorites,\r\n parseTimeframeInput,\r\n timeframeLabel,\r\n withExtraTimeframes,\r\n} from './widgetTimeframes.js';\r\nimport { WidgetGoToDate, utcToWallTime, wallTimeToUtc } from './WidgetGoToDate.js';\r\nimport { WidgetTooltip } from './WidgetTooltip.js';\r\nimport { WidgetIndicatorLegend, type IndicatorLegendPane, type IndicatorLegendRow, type PaneAction } from './WidgetIndicatorLegend.js';\r\nimport { formatIndicatorValue, legendValues } from './legendValues.js';\r\nimport { RANGE_PRESETS, servesTimeframe, sourceParam, withResampling } from '@tradecanvas/core';\r\nimport { WidgetBracketBar } from './WidgetBracketBar.js';\r\nimport { AlertNotifier } from './AlertNotifier.js';\r\nimport { WidgetDepthLadder } from './WidgetDepthLadder.js';\r\nimport { WidgetDataWindow, type DataWindowModel } from './WidgetDataWindow.js';\r\nimport type { DepthData } from '@tradecanvas/commons';\r\nimport { encodeWidgetState, decodeWidgetState, readShareHash, buildShareUrl } from './widgetShareState.js';\r\nimport { DragDropImporter, resampleOHLCV, inferTimeframeMs } from '../io/index.js';\r\nimport type { DataSeries } from '@tradecanvas/commons';\r\nimport { timeframeToMs } from '@tradecanvas/commons';\r\nimport type { CommandItem } from './WidgetCommandPalette.js';\r\nimport { resolveMessages, createTranslator, fill, type MessageKey, type Translator } from './i18n.js';\r\nimport { chartTypeLabel, localizeToolGroups } from './widgetLocales.js';\r\nimport { WidgetLoadingOverlay } from './WidgetLoadingOverlay.js';\r\nimport { WidgetHistoryPill } from './WidgetHistoryPill.js';\r\n\r\n/**\r\n * A local timeframe switch (resampling static data) that took at least this\r\n * long last time is announced with the loading veil before it runs, since the\r\n * main thread is about to be busy for several frames.\r\n */\r\nconst SLOW_LOCAL_SWITCH_MS = 48;\r\n/** Base series this long are assumed slow to resample before any timing exists. */\r\nconst LARGE_SERIES_BARS = 50_000;\r\n\r\n/** Upper bound on waiting for a paint — rAF never fires in a frame that isn't rendering. */\r\nconst PAINT_WAIT_MAX_MS = 100;\r\n\r\n/** Resolve once the browser has painted the current DOM state (or gave up waiting). */\r\nfunction afterPaint(): Promise<void> {\r\n return new Promise((resolve) => {\r\n if (typeof requestAnimationFrame !== 'function' || document.hidden) {\r\n setTimeout(resolve, 0);\r\n return;\r\n }\r\n const fallback = setTimeout(resolve, PAINT_WAIT_MAX_MS);\r\n requestAnimationFrame(() => setTimeout(() => {\r\n clearTimeout(fallback);\r\n resolve();\r\n }, 0));\r\n });\r\n}\r\n\r\n/** Distinct line colors for comparison overlays, cycled by add order. */\r\nconst COMPARE_COLORS = ['#4c8dff', '#a57cff', '#1398a8', '#e25592', '#8a93a3', '#62c895'];\r\n\r\n/** Gap between the on-chart indicator rows and the plot or pane edge, px. */\r\nconst LEGEND_INSET = 4;\r\n/** A pane's row starts below the divider's grab zone (±6 px), so it never blocks a resize. */\r\nconst PANE_ROW_TOP = 7;\r\n/** Rows of the indicators sharing a pane, one under the other (px). */\r\nconst PANE_ROW_STEP = 17;\r\n/** Where a pane's buttons (move, fold, maximise) sit below its top edge. */\r\nconst PANE_CONTROLS_TOP = 3;\r\n/** Finer intervals a replay may step through (those dividing the chart's interval are offered). */\r\nconst REPLAY_STEP_CANDIDATES: readonly TimeFrame[] = ['1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '1d'];\r\n/** The most finer bars fetched for one replay. */\r\nconst MAX_REPLAY_STEPS = 5000;\r\n/** Focus is in a dialog or a menu (the widget's or the page's): its keys are its own. */\r\nconst inOverlay = (): boolean => {\r\n const active = document.activeElement;\r\n return active instanceof Element && active.closest('[role=\"dialog\"], [aria-modal=\"true\"], [role=\"menu\"]') !== null;\r\n};\r\n/** Alt + a letter picks a drawing tool (by key position, so it works on any layout). */\r\nconst TOOL_HOTKEYS: Readonly<Record<string, DrawingToolType>> = {\r\n KeyT: 'trendLine',\r\n KeyH: 'horizontalLine',\r\n KeyJ: 'horizontalRay',\r\n KeyV: 'verticalLine',\r\n KeyC: 'crossLine',\r\n KeyF: 'fibRetracement',\r\n};\r\n\r\n/** The widget pressed last: with several on a page, Alt+ shortcuts act on that one. */\r\n\r\n/** 1 when bar times are milliseconds, 1000 when they are seconds. */\r\nconst barTimeUnit = (data: ReadonlyArray<{ time: number }>): number =>\r\n (data[data.length - 1]?.time ?? 0) > 1e12 ? 1 : 1000;\r\n\r\n\r\nexport class ChartWidget {\r\n private chart: Chart;\r\n private state: WidgetState;\r\n private toolbar: WidgetToolbar | null = null;\r\n private sidebar: WidgetDrawingSidebar | null = null;\r\n private settings: WidgetSettings | null = null;\r\n private statusBar: WidgetStatusBar | null = null;\r\n private goToDate: WidgetGoToDate | null = null;\r\n private readonly tooltip: WidgetTooltip;\r\n private indicatorLegend: WidgetIndicatorLegend | null = null;\r\n private legendFrame = 0;\r\n /**\r\n * Modals (settings, search, command palette, hotkeys) mount here: it carries\r\n * the theme tokens to `document.body`, and moves inside the widget while\r\n * the widget is fullscreen, where nothing outside it is shown.\r\n */\r\n private readonly portal = document.createElement('div');\r\n private readonly overlayHost = (): HTMLElement => {\r\n const host = document.fullscreenElement === this.root ? this.root : document.body;\r\n if (this.portal.parentElement !== host) host.appendChild(this.portal);\r\n return this.portal;\r\n };\r\n /** Stops following presses for the page's shortcuts (see keyTarget). */\r\n private unregisterKeys: () => void = () => {};\r\n private readonly onFullscreenChange = () => {\r\n this.toolbar?.setFullscreen(document.fullscreenElement === this.root);\r\n if (this.portal.isConnected) this.overlayHost(); // an open modal follows\r\n };\r\n private commandPalette: WidgetCommandPalette | null = null;\r\n private symbolSearch: WidgetSymbolSearch | null = null;\r\n private hotkeySheet: WidgetHotkeySheet | null = null;\r\n private replayBar: WidgetReplayBar | null = null;\r\n private dragDrop: DragDropImporter | null = null;\r\n private alertsPanel: WidgetAlertsPanel | null = null;\r\n private objectTree: WidgetObjectTree | null = null;\r\n private indicatorSettings: WidgetIndicatorSettings | null = null;\r\n private drawingStyle: WidgetDrawingStyle | null = null;\r\n private drawingSettings: WidgetDrawingSettings | null = null;\r\n private drawingMenu: WidgetContextMenu | null = null;\r\n private chartMenu: WidgetContextMenu | null = null;\r\n /** The pane a chart menu was opened on (its scale switches act on it). */\r\n private menuPane: string | null = null;\r\n /** Whether the chart menu offers a download of the data. */\r\n private canExport = true;\r\n /** The latest fetch of each symbol the chart's indicators read. */\r\n private symbolLoads = new Map<string, number>();\r\n /** The widget's look. */\r\n private ui!: ResolvedWidgetUI;\r\n /** The legend row's \"more\" menu: move the indicator to another pane. */\r\n private legendMenu: WidgetContextMenu | null = null;\r\n private templates = new IndicatorTemplateStore();\r\n private templatePrompt: WidgetNamePrompt | null = null;\r\n private intervalInput: WidgetIntervalInput | null = null;\r\n /** The note shown over a signal marker under the pointer. */\r\n private markerTip: HTMLDivElement | null = null;\r\n private accountPanel: WidgetAccountPanel | null = null;\r\n private orderTicket: WidgetOrderTicket | null = null;\r\n private accountFrame = 0;\r\n private layoutSession: LayoutSession | null = null;\r\n private layoutsUI: WidgetLayoutsUI | null = null;\r\n private bracketBar: WidgetBracketBar | null = null;\r\n private alertNotifier: AlertNotifier | null = null;\r\n private depthLadder: WidgetDepthLadder | null = null;\r\n private dataWindow: WidgetDataWindow | null = null;\r\n private lastHoverIndex: number | null = null;\r\n /** The bar the on-chart indicator values are read at; null = the latest. */\r\n private legendHoverIndex: number | null = null;\r\n private favoritesStore = new DrawingFavoritesStore();\r\n /** Timeframes pinned to the toolbar (same store shape as drawing favourites). */\r\n private timeframeFavorites = new DrawingFavoritesStore('tcw:tf-favorites');\r\n /** Intervals the user typed in the timeframe menu. */\r\n private customTimeframes = new DrawingFavoritesStore('tcw:tf-custom');\r\n /** Timeframes on offer, shortest first. */\r\n private timeframes: TimeFrame[] = [];\r\n private watchlist: WidgetWatchlist | null = null;\r\n private watchlistSparkBuffer = new Map<string, number[]>();\r\n private sessionRefPrice: number | null = null;\r\n /** Per-symbol refPrice explicitly pushed by the host via `setWatchlistEntry` — takes precedence over `sessionRefPrice`. */\r\n private hostWatchlistRefPrice = new Map<string, number>();\r\n private watchlistInterval: ReturnType<typeof setInterval> | null = null;\r\n private watchlistStore: WatchlistStore | null = null;\r\n /** The list follows `setSymbols` (no lists given, none kept). */\r\n private watchlistFromSymbols = false;\r\n private quoteSource: QuoteSource | null = null;\r\n private stopQuotes: (() => void) | null = null;\r\n /** The symbols quotes are coming for, joined. */\r\n private quotedKey = '';\r\n /** The latest quote of each symbol. */\r\n private quotes = new Map<string, Quote>();\r\n private symbolInfoPanel: WidgetSymbolInfo | null = null;\r\n /** Bumped by each news request: a late answer for an earlier symbol is dropped. */\r\n private newsRequest = 0;\r\n /** Headlines per symbol, kept a few minutes. */\r\n private newsCache = new Map<string, { at: number; items: NewsItem[] }>();\r\n private marketTimer: ReturnType<typeof setInterval> | null = null;\r\n private chartNav: WidgetChartNav | null = null;\r\n /** Bars on screen, for the navigation's scroll step. */\r\n private visibleBarCount = 50;\r\n private replayPollInterval: ReturnType<typeof setInterval> | null = null;\r\n /** Bars revealed per second. */\r\n private replaySpeed = DEFAULT_REPLAY_SPEED;\r\n /** `'bar'`, or the finer interval a replay steps through. */\r\n private replayStep = 'bar';\r\n private replayStartSeq = 0;\r\n /** Finer bars fetched or built for the last replay in steps. */\r\n private replayStepsCache: { key: string; steps: DataSeries } | null = null;\r\n /** While picking the start bar: shades the bars right of the pointer. */\r\n private replayShade: HTMLDivElement | null = null;\r\n private layoutKeyPrefix: string | null = null;\r\n private layoutDebounceMs = 1500;\r\n private activeLayoutKey: string | null = null;\r\n private root: HTMLDivElement;\r\n private chartContainer: HTMLDivElement;\r\n private loading: WidgetLoadingOverlay;\r\n private historyPill: WidgetHistoryPill;\r\n /** Bumped per stream connect; a connect that is no longer the latest leaves the UI to the newer one. */\r\n private connectSeq = 0;\r\n /** Bumped per local resample and widget.setData; a deferred local switch that is no longer the latest is skipped. */\r\n private localSeq = 0;\r\n /** Duration of the last local resample + setData, for SLOW_LOCAL_SWITCH_MS. */\r\n private lastLocalSwitchMs = 0;\r\n private destroyed = false;\r\n private options: ChartWidgetOptions;\r\n private symbols: string[];\r\n private settingsState: ChartSettingsState;\r\n /** What Reset in the settings panel goes back to: the defaults, as the host's features set them. */\r\n private settingsDefaults: ChartSettingsState;\r\n private t: Translator;\r\n private adapter: import('@tradecanvas/commons').DataAdapter | null = null;\r\n private boundGlobalKeydown: ((e: KeyboardEvent) => void) | null = null;\r\n // Finest-resolution series the widget has seen. When no live adapter is\r\n // attached, switching to a coarser timeframe resamples from this base\r\n // instead of refetching. See `setData` / `applyTimeframeData`.\r\n private baseSeries: DataSeries | null = null;\r\n private baseTimeframeMs = 0;\r\n private compares: { id: string; symbol: string; color: string }[] = [];\r\n\r\n constructor(container: HTMLElement, options: ChartWidgetOptions = {}) {\r\n this.options = options;\r\n this.symbols = options.symbols ?? DEFAULT_SYMBOLS;\r\n // `numberLocale`, `timeZone` and `leftPriceScale` live in two places:\r\n // the headless Chart gets them via `chartOptions` (spread straight into\r\n // `new Chart()` below) — but the widget's own chrome (watchlist, alerts,\r\n // go-to-date, settings panel, Reset) reads `settingsState`, which\r\n // otherwise stays on DEFAULT_SETTINGS until the host touches the Settings\r\n // UI. Seed it from the same options so both layers start in sync.\r\n const chartOptions = options.chartOptions;\r\n this.settingsState = {\r\n ...DEFAULT_SETTINGS,\r\n ...(chartOptions?.numberLocale ? { numberLocale: chartOptions.numberLocale } : {}),\r\n ...(chartOptions?.timeZone != null ? { timezone: timezoneToSetting(chartOptions.timeZone) } : {}),\r\n ...(chartOptions?.leftPriceScale !== undefined ? { leftPriceScale: chartOptions.leftPriceScale } : {}),\r\n ...(chartOptions?.highLowLines !== undefined ? { highLowLines: chartOptions.highLowLines } : {}),\r\n ...(chartOptions?.extendedHours !== undefined ? { extendedHours: chartOptions.extendedHours } : {}),\r\n ...(chartOptions?.chartTypeOptions ? { chartTypeOptions: readChartTypeOptions(chartOptions.chartTypeOptions) } : {}),\r\n };\r\n this.t = createTranslator(resolveMessages(options.locale, options.messages));\r\n\r\n // Resolve layout persistence config. Treated as opt-in — defaults to\r\n // `false` so existing apps don't suddenly start writing to localStorage.\r\n if (options.persistLayouts) {\r\n const cfg = options.persistLayouts === true ? {} : options.persistLayouts;\r\n this.layoutKeyPrefix = cfg.keyPrefix ?? 'tcw:layout:';\r\n this.layoutDebounceMs = cfg.debounceMs ?? 1500;\r\n }\r\n\r\n // Resolve theme\r\n const isDark = this.resolveIsDark(options.theme);\r\n const resolvedTheme = this.resolveTheme(options.theme);\r\n\r\n // The chart's feature flags; controls for switched-off features are left out.\r\n // Host overrides win per key (see the Chart below).\r\n const features: FeaturesConfig = {\r\n drawings: true,\r\n drawingMagnet: true,\r\n drawingUndoRedo: true,\r\n indicators: true,\r\n trading: options.trading !== false,\r\n tradingContextMenu: false,\r\n // The \"+\" by the price axis offers an alert, an order or a line at a price.\r\n priceAxisAddButton: options.alerts !== false || options.trading !== false || options.drawingTools !== false,\r\n volume: true,\r\n legend: true,\r\n crosshair: true,\r\n // Pro trading charts have no cursor-following OHLCV popup — just the\r\n // legend, which ChartWidget already renders. Off by default here\r\n // (the headless Chart's own default stays `true`); opt back in via\r\n // `chartOptions: { features: { crosshairTooltip: true } }`.\r\n crosshairTooltip: false,\r\n keyboard: true,\r\n screenshot: true,\r\n alerts: true,\r\n barCountdown: true,\r\n logScale: true,\r\n watermark: true,\r\n ...options.chartOptions?.features,\r\n };\r\n\r\n this.canExport = features.dataExport !== false;\r\n // The display toggles start where the host's features put them, and Reset goes back there.\r\n this.settingsDefaults = {\r\n ...this.settingsState,\r\n legendVisible: features.legend !== false,\r\n barCountdown: features.barCountdown !== false,\r\n indicatorValueLabels: features.indicatorValueLabels !== false,\r\n };\r\n this.settingsState = { ...this.settingsDefaults };\r\n\r\n this.timeframes = withExtraTimeframes(\r\n availableTimeframes(options.timeframes, features.timeframes),\r\n this.customTimeframes.list() as TimeFrame[],\r\n features.timeframes,\r\n );\r\n // First run, or none of the saved pins is on offer here: start from the defaults.\r\n if (!this.timeframes.some((tf) => this.timeframeFavorites.has(tf))) {\r\n const initial = initialTimeframeFavorites(this.timeframes, features.defaultTimeframeFavorites, !!options.timeframes?.length);\r\n for (const tf of initial) this.timeframeFavorites.add(tf);\r\n }\r\n const requestedTimeframe = options.timeframe ?? '5m';\r\n const startTimeframe = !features.timeframes?.length || features.timeframes.includes(requestedTimeframe)\r\n ? requestedTimeframe\r\n : this.timeframes[0] ?? requestedTimeframe;\r\n\r\n // Initialize state\r\n this.state = {\r\n symbol: options.symbol ?? this.symbols[0] ?? 'BTCUSDT',\r\n timeframe: startTimeframe,\r\n chartType: options.chartOptions?.chartType ?? 'candlestick',\r\n isDark,\r\n activeIndicators: new Map(),\r\n activeTool: null,\r\n magnetEnabled: features.drawingMagnet !== false,\r\n magnetStrong: false,\r\n eraser: false,\r\n zoomArea: false,\r\n stayInDrawing: false,\r\n // Static data (no adapter) has no connection to report.\r\n connectionState: options.adapter ? 'connecting' : 'disconnected',\r\n connectionMessage: options.adapter ? this.t('status.connecting') : '',\r\n };\r\n\r\n\r\n // 1. Inject styles\r\n injectWidgetStyles();\r\n\r\n // 2. Create DOM skeleton\r\n this.root = document.createElement('div');\r\n this.root.className = 'tcw-root';\r\n this.root.dataset.tcwTheme = isDark ? 'dark' : 'light';\r\n // Right to left for Arabic, Hebrew and the like (or as asked); the chart itself runs left to right.\r\n const dir = options.dir === 'ltr' || options.dir === 'rtl' ? options.dir : isRtlLocale(options.locale) ? 'rtl' : 'ltr';\r\n this.root.dir = dir;\r\n this.portal.dir = dir;\r\n container.appendChild(this.root);\r\n this.tooltip = new WidgetTooltip(this.root);\r\n this.portal.className = 'tcw-root tcw-portal';\r\n this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme;\r\n // The look: tokens and layout switches on the root and the modal portal\r\n // alike. Without `ui` the tokens stay the stylesheet's (Studio's), so a\r\n // host's CSS can still set them.\r\n this.ui = resolveWidgetUI(options.ui);\r\n const variables = options.ui !== undefined;\r\n applyWidgetUI(this.root, this.ui, { variables });\r\n applyWidgetUI(this.portal, this.ui, { variables });\r\n\r\n // 3. Create toolbar\r\n if (options.toolbar !== false) {\r\n this.toolbar = new WidgetToolbar(\r\n this.root,\r\n {\r\n symbols: this.symbols,\r\n timeframes: this.timeframeMenu(),\r\n timeframeFavorites: this.pinnedTimeframes(),\r\n chartTypes: options.chartTypes\r\n ? CHART_TYPES.filter(ct => (options.chartTypes as ChartType[]).includes(ct.value))\r\n : CHART_TYPES,\r\n indicators: INDICATORS,\r\n popularIndicatorIds: POPULAR_INDICATORS,\r\n },\r\n {\r\n onSymbolClick: () => this.handleSymbolClick(),\r\n onSymbolInfo: options.symbolInfo !== false ? () => this.toggleSymbolInfo() : undefined,\r\n onTimeframe: (tf) => this.handleTimeframe(tf),\r\n onToggleTimeframeFavorite: (tf) => this.handleToggleTimeframeFavorite(tf),\r\n onAddTimeframe: options.customTimeframes === false ? undefined : (text) => this.handleAddTimeframe(text),\r\n onRemoveTimeframe: (tf) => this.handleRemoveTimeframe(tf),\r\n onChartType: (type) => this.handleChartType(type),\r\n onAddIndicator: (id) => this.handleAddIndicator(id),\r\n onScreenshot: () => this.chart.screenshot(),\r\n onSettings: () => this.openSettings(),\r\n onToggleTheme: () => this.handleToggleTheme(),\r\n onToggleReplay: () => this.toggleReplay(),\r\n onToggleAlerts: options.alerts !== false ? () => this.toggleAlerts() : undefined,\r\n onToggleObjects: options.objectTree !== false ? () => this.toggleObjects() : undefined,\r\n onToggleAccount: options.trading !== false && options.accountPanel !== false ? () => this.accountPanel?.toggle() : undefined,\r\n onLayouts: options.layouts !== false ? (anchor) => void this.layoutsUI?.openMenu(anchor) : undefined,\r\n ...(options.indicatorTemplates !== false\r\n ? {\r\n onApplyIndicatorTemplate: (name: string) => this.applyIndicatorTemplate(name),\r\n onSaveIndicatorTemplate: () => this.promptSaveIndicatorTemplate(),\r\n onDeleteIndicatorTemplate: (name: string) => {\r\n this.templates.remove(name);\r\n this.toolbar?.setIndicatorTemplates(this.templates.list().map((t) => t.name), true);\r\n },\r\n }\r\n : {}),\r\n onBracket: options.trading !== false ? (side) => this.startBracket(side) : undefined,\r\n onToggleLadder: options.trading !== false && options.depthLadder ? () => this.depthLadder?.toggle() : undefined,\r\n onToggleFullscreen: options.fullscreen !== false && typeof document !== 'undefined' && document.fullscreenEnabled\r\n ? () => this.toggleFullscreen()\r\n : undefined,\r\n },\r\n this.t,\r\n );\r\n }\r\n\r\n // 4. Create body\r\n const body = document.createElement('div');\r\n body.className = 'tcw-body';\r\n\r\n if (options.drawingTools !== false) {\r\n if (options.drawingFavorites) this.favoritesStore.seedDefaults(options.drawingFavorites);\r\n this.sidebar = new WidgetDrawingSidebar(\r\n body,\r\n { drawingToolGroups: localizeToolGroups(DRAWING_TOOL_GROUPS, this.t), favorites: this.favoritesStore.list() as DrawingToolType[] },\r\n {\r\n onDrawingTool: (tool) => this.handleDrawingTool(tool),\r\n onCancelDrawing: () => this.handleCancelDrawing(),\r\n onToggleMagnet: features.drawingMagnet !== false ? () => this.handleToggleMagnet() : undefined,\r\n onToggleEraser: () => this.chart.setEraserMode(!this.chart.isEraserMode()),\r\n onToggleZoomArea: () => this.chart.setZoomAreaMode(!this.chart.isZoomAreaMode()),\r\n onToggleFavorite: (tool) => this.handleToggleFavorite(tool),\r\n onUndo: () => this.chart.undo(),\r\n onRedo: () => this.chart.redo(),\r\n onClearDrawings: () => {\r\n this.chart.clearDrawings();\r\n this.state = { ...this.state, activeTool: null };\r\n this.updateUI();\r\n },\r\n onToggleStyle: () => this.drawingStyle?.toggle(),\r\n onToggleStayInDrawing: () => this.handleToggleStayInDrawing(),\r\n },\r\n this.t,\r\n );\r\n }\r\n\r\n this.chartContainer = document.createElement('div');\r\n this.chartContainer.className = 'tcw-chart-container';\r\n this.chartContainer.dir = 'ltr';\r\n body.appendChild(this.chartContainer);\r\n\r\n // Loading state: covers the empty chart until the first\r\n // bars land, then veils the previous chart during slow switches.\r\n this.loading = new WidgetLoadingOverlay(this.chartContainer, this.t('status.loading'));\r\n this.historyPill = new WidgetHistoryPill(this.chartContainer, {\r\n loading: this.t('history.loading'),\r\n failed: this.t('history.failed'),\r\n });\r\n\r\n // Watchlist sidebar (right side). Appended AFTER the chart container so\r\n // it sits to the right of the canvas in the flexbox row.\r\n if (options.watchlist) this.createWatchlist(body, options.watchlist === true ? {} : options.watchlist);\r\n\r\n this.root.appendChild(body);\r\n // The account panel docks under the chart, above the status bar.\r\n const accountHost = document.createElement('div');\r\n accountHost.className = 'tcw-account-dock';\r\n this.root.appendChild(accountHost);\r\n\r\n // 5. Create chart\r\n this.chart = new Chart(this.chartContainer, {\r\n chartType: this.state.chartType,\r\n theme: resolvedTheme,\r\n autoScale: true,\r\n crosshair: { mode: 'magnet' },\r\n // Screen readers hear the chart in the widget's language.\r\n a11y: {\r\n labels: {\r\n role: this.t('a11y.role'),\r\n summary: this.t('a11y.summary'),\r\n empty: this.t('a11y.empty'),\r\n view: this.t('a11y.view'),\r\n bar: this.t('a11y.bar'),\r\n keys: this.t('a11y.keys'),\r\n typeName: (type) => {\r\n const key = `chartType.${type}` as MessageKey;\r\n const name = this.t(key);\r\n return name === key ? type : name;\r\n },\r\n },\r\n },\r\n ...options.chartOptions,\r\n // `features` is merged explicitly (host overrides win per-key) rather\r\n // than inherited wholesale from the `...options.chartOptions` spread\r\n // above — otherwise passing e.g. `chartOptions: { features: { x } }`\r\n // would silently drop every other default.\r\n features,\r\n });\r\n // A shape the chart's options give stays until a look is set.\r\n if (!options.chartOptions?.shapes) this.applyChartShapes();\r\n\r\n // Navigation over the chart; a scroll step is a tenth of the bars on screen.\r\n this.chart.on('visibleRangeChange', (e) => {\r\n const { from, to } = e.payload as { from: number; to: number };\r\n if (Number.isFinite(from) && Number.isFinite(to)) this.visibleBarCount = Math.max(1, to - from);\r\n });\r\n if (options.navigation !== false) {\r\n this.chartNav = new WidgetChartNav(this.chartContainer, {\r\n zoomIn: () => this.chart.zoomIn(),\r\n zoomOut: () => this.chart.zoomOut(),\r\n scroll: (direction) => this.chart.scrollBars(direction * Math.max(1, Math.round(this.visibleBarCount / 10))),\r\n reset: () => {\r\n this.chart.fitContent();\r\n this.changeSettings({ autoScale: true });\r\n },\r\n plotRect: () => this.chart.getPlotRect(),\r\n }, this.t);\r\n }\r\n\r\n // New bars end the loading state, whoever supplied them (stream snapshot,\r\n // widget.setData, or the host calling getChart().setData directly); stream\r\n // errors surface in the status bar and, mid-load, on the loading veil.\r\n this.chart.on('dataUpdate', (e) => this.handleDataUpdate(e.payload));\r\n this.chart.on('historyLoad', (e) => this.historyPill.update(e.payload as HistoryLoadPayload));\r\n this.chart.on('symbolInfoChange', (e) => {\r\n const info = (e.payload as { info: SymbolInfo | null }).info;\r\n const text = info ? [info.description, info.exchange].filter(Boolean).join(' · ') : '';\r\n this.toolbar?.setSymbolDescription(text || null);\r\n this.refreshMarket();\r\n });\r\n\r\n // Symbol info: the panel, and the market's status in the status bar,\r\n // kept current as the clock runs toward the next open or close.\r\n if (options.symbolInfo !== false) {\r\n this.symbolInfoPanel = new WidgetSymbolInfo(this.root, this.t, {\r\n onToggle: (open) => {\r\n this.toolbar?.setActive('symbolInfo', open);\r\n if (open) {\r\n this.refreshSymbolInfo();\r\n this.loadNews();\r\n }\r\n },\r\n });\r\n }\r\n this.marketTimer = setInterval(() => this.refreshMarket(), 30_000);\r\n\r\n // Drag-and-drop CSV / JSON onto the chart container — instant data load.\r\n // Opt-out via `dragDropImport: false`. The adapter (live stream) keeps\r\n // running but the next bar update will append to whatever we just\r\n // loaded — that's the expected behavior when overlaying historical data.\r\n if (options.dragDropImport !== false) {\r\n this.dragDrop = new DragDropImporter(this.chartContainer, {\r\n onData: (data, result, file) => {\r\n this.setData(data);\r\n const loaded = fill(this.t('toast.fileLoaded'), { count: result.data.length, file: file.name });\r\n this.toast(result.skipped > 0 ? `${loaded} (${fill(this.t('toast.fileSkipped'), { count: result.skipped })})` : loaded);\r\n },\r\n onError: (err, file) => {\r\n this.toast(`${file.name}: ${err.message}`, 'error');\r\n },\r\n });\r\n this.dragDrop.attach();\r\n }\r\n\r\n // 6. Create status bar\r\n if (options.statusBar !== false) {\r\n const range = options.rangeBar !== false;\r\n this.statusBar = new WidgetStatusBar(this.root, range ? {\r\n presets: RANGE_PRESETS,\r\n presetLabels: { All: this.t('range.all') },\r\n groupLabel: this.t('range.presets'),\r\n goToLabel: this.t('range.goTo'),\r\n onPreset: (preset) => this.chart.setVisibleRangePreset(preset),\r\n onGoTo: () => this.toggleGoToDate(),\r\n } : undefined);\r\n if (range) {\r\n this.goToDate = new WidgetGoToDate(this.root, {\r\n title: this.t('range.goTo'),\r\n date: this.t('range.date'),\r\n time: this.t('range.time'),\r\n submit: this.t('range.goToSubmit'),\r\n cancel: this.t('range.cancel'),\r\n }, ({ date, time }) => this.goToWallTime(date, time));\r\n }\r\n }\r\n\r\n // 7. Create settings (lazy, not appended until opened)\r\n if (options.settings !== false) {\r\n this.settings = new WidgetSettings({\r\n onChange: (patch) => this.changeSettings(patch),\r\n onReset: () => this.resetSettings(),\r\n onClose: () => {},\r\n }, this.t, {\r\n barCountdown: features.barCountdown,\r\n logScale: features.logScale,\r\n exchangeZone: this.adapter?.resolveSymbol ? () => this.chart.getSymbolInfo()?.timezone ?? null : undefined,\r\n }, this.overlayHost);\r\n }\r\n\r\n // 8a. Symbol search\r\n this.symbolSearch = new WidgetSymbolSearch({\r\n onPick: (sym) => { void this.setSymbol(sym); },\r\n onClose: () => {},\r\n }, this.overlayHost, this.t);\r\n this.hotkeySheet = new WidgetHotkeySheet({ onClose: () => {} }, this.t, this.overlayHost);\r\n\r\n // The sidebar follows the chart's drawing tool: finished, cancelled with\r\n // Esc, or kept for the next drawing in stay-in-drawing mode.\r\n this.chart.on('drawingToolChange', (e) => {\r\n const tool = (e.payload as { tool: DrawingToolType | null }).tool;\r\n if (tool === this.state.activeTool) return;\r\n this.state = { ...this.state, activeTool: tool };\r\n this.updateUI();\r\n });\r\n // The eraser and the zoom tool turn themselves off (Escape, a tool picked, a zoom done).\r\n this.chart.on('toolModeChange', (e) => {\r\n const { eraser, zoomArea } = e.payload as { eraser?: boolean; zoomArea?: boolean };\r\n this.state = {\r\n ...this.state,\r\n eraser: eraser ?? this.state.eraser,\r\n zoomArea: zoomArea ?? this.state.zoomArea,\r\n };\r\n this.updateUI();\r\n });\r\n\r\n // The indicator list mirrors the chart's indicators, whoever adds or removes them.\r\n this.chart.on('indicatorAdd', () => this.syncIndicatorsFromChart());\r\n this.chart.on('indicatorRemove', () => this.syncIndicatorsFromChart());\r\n\r\n // The indicators on the chart itself, instead of toolbar chips that overflow.\r\n if (options.indicatorLegend !== false) {\r\n this.chart.setPaneTitlesVisible(false);\r\n this.indicatorLegend = new WidgetIndicatorLegend(this.chartContainer, {\r\n onToggleVisible: (iid, visible) => {\r\n this.chart.setIndicatorVisible(iid, visible);\r\n this.scheduleLegend();\r\n if (this.objectTree?.isOpen()) this.refreshObjects();\r\n },\r\n onSettings: (iid) => this.openIndicatorSettings(iid),\r\n onRemove: (iid) => this.handleRemoveIndicator(iid),\r\n onMore: (iid, anchor) => this.openLegendMenu(iid, anchor),\r\n onPaneAction: (iid, action) => this.runPaneAction(iid, action),\r\n }, {\r\n show: this.t('legend.show'),\r\n hide: this.t('legend.hide'),\r\n settings: this.t('legend.settings'),\r\n remove: this.t('legend.remove'),\r\n collapse: this.t('legend.collapse'),\r\n expand: this.t('legend.expand'),\r\n more: this.t('legend.more'),\r\n paneUp: this.t('pane.moveUp'),\r\n paneDown: this.t('pane.moveDown'),\r\n paneCollapse: this.t('pane.collapse'),\r\n paneExpand: this.t('pane.expand'),\r\n paneMaximize: this.t('pane.maximize'),\r\n paneRestore: this.t('pane.restore'),\r\n });\r\n this.legendMenu = new WidgetContextMenu(this.root, this.t('legend.more'));\r\n this.chart.on('crosshairMove', (e) => {\r\n const p = e.payload as { barIndex?: number };\r\n this.legendHoverIndex = typeof p.barIndex === 'number' ? p.barIndex : null;\r\n this.scheduleLegend();\r\n });\r\n // Off the chart, the values go back to the latest bar.\r\n this.chart.on('crosshairLeave', () => {\r\n this.legendHoverIndex = null;\r\n this.scheduleLegend();\r\n });\r\n for (const event of ['indicatorUpdate', 'indicatorChange', 'dataUpdate', 'resize', 'paneResize', 'paneChange', 'themeChange'] as const) {\r\n this.chart.on(event, () => this.scheduleLegend());\r\n }\r\n }\r\n\r\n // Replay: while picking, a click starts the replay at that bar; during a\r\n // replay it jumps the cursor there.\r\n this.chart.on('barClick', (e) => {\r\n if (!this.replayBar?.isMounted()) return;\r\n const idx = (e.payload as { barIndex?: number }).barIndex;\r\n if (typeof idx !== 'number') return;\r\n if (this.replayBar.getMode() === 'select') {\r\n this.startReplayAt(idx);\r\n return;\r\n }\r\n if (this.chart.getReplayState() === 'playing') this.chart.replayPause();\r\n // To the end of the bar clicked (in finer steps, its last step).\r\n this.chart.replaySeekToBar(idx);\r\n this.replayBar.setState('paused');\r\n });\r\n // While picking the start bar, shade the bars that would be hidden.\r\n this.chart.on('crosshairMove', (e) => {\r\n if (this.replayBar?.getMode() !== 'select' || !this.replayBar.isMounted()) return;\r\n const point = (e.payload as { point?: { x: number } | null }).point;\r\n this.positionReplayShade(point?.x ?? null);\r\n });\r\n\r\n // Data Window — precise OHLCV + indicator values at the hovered bar.\r\n this.dataWindow = new WidgetDataWindow(this.root, { formatPrice: (p) => this.formatAlertPrice(p) }, this.t);\r\n this.chart.on('crosshairMove', (e) => {\r\n const p = e.payload as { barIndex?: number };\r\n this.lastHoverIndex = typeof p.barIndex === 'number' ? p.barIndex : null;\r\n if (this.dataWindow?.isOpen()) this.dataWindow.render(this.buildDataWindowModel());\r\n });\r\n\r\n // Drawing style + templates popover (paired with the sidebar palette button)\r\n if (options.drawingTools !== false) {\r\n const templates = new DrawingTemplateStore();\r\n // Each tool's saved defaults (\"Save as default\" in a drawing's settings).\r\n const defaults = new DrawingDefaultsStore();\r\n for (const [type, toolOptions] of Object.entries(defaults.all())) {\r\n this.chart.setDrawingToolDefaults(type as DrawingToolType, toolOptions ?? null);\r\n }\r\n this.drawingSettings = new WidgetDrawingSettings(this.root, {\r\n onBegin: (id) => this.chart.beginDrawingEdit(id),\r\n onChange: (id, patch) => this.chart.updateDrawing(id, patch),\r\n onEnd: (id, cancel) => {\r\n this.chart.endDrawingEdit(id, { cancel });\r\n this.refreshObjects();\r\n },\r\n toWallTime: (time) => utcToWallTime(time * barTimeUnit(this.chart.getData()), this.displayTimezone()),\r\n fromWallTime: (date, time) => {\r\n const ms = wallTimeToUtc(date, time, this.displayTimezone());\r\n return ms === null ? null : ms / barTimeUnit(this.chart.getData());\r\n },\r\n onAddAlert: (id) => this.addDrawingAlert(id),\r\n onSaveDefault: (type, toolOptions) => {\r\n this.chart.setDrawingToolDefaults(type, toolOptions);\r\n defaults.set(type, this.chart.getDrawingToolDefaults(type));\r\n this.toast(fill(this.t('drawingSettings.defaultSaved'), { name: this.drawingToolName(type) }));\r\n },\r\n templates,\r\n }, this.t);\r\n this.chart.on('drawingDoubleClick', (e) => this.openDrawingSettings((e.payload as { id: string }).id));\r\n this.drawingStyle = new WidgetDrawingStyle(\r\n this.root,\r\n {\r\n onStyleChange: (style) => {\r\n this.chart.setDrawingStyle(style);\r\n this.chart.setSelectedDrawingStyle(style);\r\n },\r\n getStyle: () => this.chart.getDrawingStyle(),\r\n },\r\n templates,\r\n this.t,\r\n );\r\n }\r\n\r\n // Right-click on a drawing: settings, alert, order, group, lock, hide, delete.\r\n this.drawingMenu = new WidgetContextMenu(this.root, this.t('drawingMenu.label'));\r\n this.chart.on('drawingContextMenu', (e) => {\r\n const { id, x, y } = e.payload as { id: string; x: number; y: number };\r\n this.openDrawingMenu(id, x, y);\r\n });\r\n\r\n // Right-click elsewhere: what the plot, an axis or a pane offers. The \"+\"\r\n // by the price axis: what to do at its price.\r\n this.chartMenu = new WidgetContextMenu(this.root, this.t('chartMenu.label'));\r\n // Indicators that read another symbol (a compare on its own scale, a spread) ask for its bars.\r\n this.chart.on('symbolSeriesRequest', (e) => void this.loadSymbolSeries(e.payload.symbol));\r\n // Prices from the pointer go on the market's grid (its smallest step).\r\n this.chart.on('chartContextMenu', (e) => {\r\n const { area, x, y, price: raw, time, pane } = e.payload as import('@tradecanvas/commons').ChartContextMenuPayload;\r\n const price = raw === undefined ? undefined : this.chart.roundPrice(raw);\r\n const context = { ...this.chartMenuContext(price), ...(pane ? { pane: this.chart.getPaneScale(pane) } : {}) };\r\n this.menuPane = pane ?? null;\r\n this.openChartMenu(chartMenuEntries(area, context, this.t), x, y, { area, price, time });\r\n });\r\n this.chart.on('priceAxisAdd', (e) => {\r\n const { price: raw, x, y } = e.payload as import('@tradecanvas/commons').PriceAxisAddPayload;\r\n const price = this.chart.roundPrice(raw);\r\n this.openChartMenu(priceEntries(this.chartMenuContext(price), this.t), x, y, { area: 'priceAxisAdd', price });\r\n });\r\n\r\n // A signal marker under the pointer says what it is.\r\n this.chart.on('signalMarkerHover', (e) => this.showMarkerTip(e.payload));\r\n\r\n // Typing a number on the chart changes the interval.\r\n if (options.intervalTyping !== false) {\r\n this.intervalInput = new WidgetIntervalInput(this.chartContainer, {\r\n title: this.t('interval.title'),\r\n hint: this.t('interval.hint'),\r\n invalid: this.t('interval.invalid'),\r\n }, (tf) => this.selectTypedTimeframe(tf));\r\n }\r\n if (options.indicatorTemplates !== false) this.toolbar?.setIndicatorTemplates(this.templates.list().map((t) => t.name));\r\n\r\n // Named layouts: save, open, rename, delete, auto-save.\r\n if (options.layouts !== false) this.setupLayouts(options.layouts === true || options.layouts === undefined ? {} : options.layouts);\r\n\r\n // Account panel and order ticket.\r\n if (options.trading !== false && options.accountPanel !== false) {\r\n this.orderTicket = new WidgetOrderTicket(this.root, {\r\n onSubmit: (intent) => {\r\n this.chart.placeOrderIntent(intent);\r\n this.toast(fill(this.t('ticket.sent'), {\r\n side: this.t(intent.side === 'buy' ? 'ticket.buy' : 'ticket.sell'),\r\n quantity: intent.quantity ?? 1,\r\n price: this.formatAlertPrice(intent.price),\r\n }));\r\n },\r\n formatPrice: (p) => this.formatAlertPrice(p),\r\n }, this.t);\r\n this.accountPanel = new WidgetAccountPanel(accountHost, {\r\n onClosePosition: (id) => this.chart.closePositionIntent(id),\r\n onReversePosition: (id) => this.chart.reversePositionIntent(id),\r\n onCancelOrder: (id) => this.chart.cancelOrderIntent(id),\r\n onNewOrder: () => this.openOrderTicket(),\r\n formatPrice: (p) => this.formatAlertPrice(p),\r\n formatTime: (ms) => {\r\n const { date, time } = utcToWallTime(ms, this.displayTimezone());\r\n return `${date} ${time}`;\r\n },\r\n onToggle: (open) => {\r\n this.toolbar?.setActive('account', open);\r\n this.refreshAccount();\r\n },\r\n }, this.t);\r\n // indicatorUpdate comes once per tick, so open P&L follows the price.\r\n for (const event of ['ordersChange', 'positionsChange', 'executionFill', 'dataUpdate', 'indicatorUpdate'] as const) {\r\n this.chart.on(event, () => this.refreshAccountSoon());\r\n }\r\n }\r\n\r\n // Bracket-order placement: floating confirm/cancel bar + event wiring.\r\n if (options.trading !== false) {\r\n this.bracketBar = new WidgetBracketBar(this.root, {\r\n onConfirm: () => this.chart.confirmBracket(),\r\n onCancel: () => {\r\n this.chart.cancelBracket();\r\n this.bracketBar?.hide();\r\n },\r\n }, this.t);\r\n this.chart.on('bracketPlace', (e) => {\r\n const b = e.payload;\r\n this.bracketBar?.hide();\r\n this.toast(fill(this.t(b.side === 'buy' ? 'bracket.longPlaced' : 'bracket.shortPlaced'), { rr: b.riskReward.toFixed(2) }));\r\n });\r\n\r\n // Depth-of-market ladder (opt-in; fed via widget.setDepth)\r\n if (options.depthLadder) {\r\n this.depthLadder = new WidgetDepthLadder(this.root, {\r\n onTrade: (side, price) => {\r\n this.chart.placeOrderIntent({ side, type: 'limit', price });\r\n this.toast(fill(this.t(side === 'buy' ? 'order.buyLimit' : 'order.sellLimit'), { price: this.formatAlertPrice(price) }));\r\n },\r\n formatPrice: (p) => this.formatAlertPrice(p),\r\n }, undefined, this.t);\r\n }\r\n // Esc-cancel originates in the chart; reflect it in the bar.\r\n this.chart.on('dataUpdate', (e) => {\r\n const p = e.payload as { bracket?: string };\r\n if (p && p.bracket === 'cancelled') this.bracketBar?.hide();\r\n });\r\n }\r\n\r\n // 8a-bis. Price alerts panel (floating popover, toggled from the bell button)\r\n if (options.alerts !== false) {\r\n this.alertsPanel = new WidgetAlertsPanel(this.root, {\r\n onAdd: ({ price, condition, message, channel, label, options }) => {\r\n try {\r\n this.chart.addAlert(price, condition, message, channel, label, options);\r\n return true;\r\n } catch {\r\n this.toast(this.t('alerts.invalid'), 'error');\r\n return false;\r\n }\r\n },\r\n formatTime: (ms) => {\r\n const { date, time } = utcToWallTime(ms, this.displayTimezone());\r\n return `${date} ${time}`;\r\n },\r\n onRemove: (id) => this.chart.removeAlert(id),\r\n onClear: () => this.chart.clearAlerts(),\r\n getChannelValue: (channel) => this.getAlertChannelValue(channel),\r\n formatPrice: (p) => this.formatAlertPrice(p),\r\n }, this.t);\r\n\r\n // Keep the panel list and toasts in sync with the chart's AlertManager.\r\n this.chart.on('alertAdd', () => this.refreshAlerts());\r\n this.chart.on('alertRemove', () => this.refreshAlerts());\r\n this.chart.on('alertUpdate', () => this.refreshAlerts());\r\n this.chart.on('alertExpired', (e) => {\r\n const p = e.payload;\r\n this.toast(fill(this.t('alerts.expiredToast'), { text: p.message ?? this.alertText(p) }));\r\n this.refreshAlerts();\r\n });\r\n if (options.alertNotifications) {\r\n this.alertNotifier = new AlertNotifier(options.alertNotifications);\r\n }\r\n this.chart.on('alertTriggered', (e) => {\r\n const p = e.payload;\r\n const text = `${this.alertText(p)}${p.message ? ` — ${p.message}` : ''}`;\r\n this.toast(`🔔 ${fill(this.t('alerts.fired'), { text })}`, 'info');\r\n this.alertNotifier?.notify(text);\r\n this.refreshAlerts();\r\n });\r\n }\r\n\r\n // 8a-ter. Object tree (indicators + drawings manager)\r\n if (options.objectTree !== false) {\r\n this.indicatorSettings = new WidgetIndicatorSettings(this.root, {\r\n onApply: (instanceId, params) => {\r\n this.chart.updateIndicator(instanceId, params);\r\n this.syncIndicatorsFromChart(); // the legend shows the parameters\r\n },\r\n onStyle: (instanceId, style) => this.chart.updateIndicatorStyle(instanceId, style),\r\n onLevels: (instanceId, levels) => this.chart.setIndicatorLevels(instanceId, levels),\r\n onScale: (instanceId, scale) => this.chart.setIndicatorScale(instanceId, scale),\r\n onClose: () => {},\r\n }, this.t);\r\n this.objectTree = new WidgetObjectTree(this.root, {\r\n onRemoveIndicator: (iid) => this.handleRemoveIndicator(iid),\r\n onConfigureIndicator: (iid) => this.openIndicatorSettings(iid),\r\n onToggleIndicatorVisible: (iid, visible) => {\r\n this.chart.setIndicatorVisible(iid, visible);\r\n this.refreshObjects();\r\n this.scheduleLegend();\r\n },\r\n onRemoveDrawing: (id) => {\r\n if (this.drawingSettings?.editing() === id) this.drawingSettings.close(true);\r\n this.chart.removeDrawing(id);\r\n this.refreshObjects();\r\n },\r\n onConfigureDrawing: this.drawingSettings ? (id) => this.openDrawingSettings(id) : undefined,\r\n onToggleDrawingVisible: (id, visible) => {\r\n this.chart.setDrawingVisible(id, visible);\r\n this.refreshObjects();\r\n },\r\n onToggleDrawingLocked: (id, locked) => {\r\n this.chart.setDrawingLocked(id, locked);\r\n this.refreshObjects();\r\n },\r\n onToggleGroupVisible: (group, visible) => {\r\n this.chart.setDrawingGroupVisible(group, visible);\r\n this.refreshObjects();\r\n },\r\n onToggleGroupLocked: (group, locked) => {\r\n this.chart.setDrawingGroupLocked(group, locked);\r\n this.refreshObjects();\r\n },\r\n onUngroup: (group) => {\r\n this.chart.ungroupDrawings(group);\r\n this.refreshObjects();\r\n },\r\n onRenameGroup: (group, name) => {\r\n this.chart.renameDrawingGroup(group, name);\r\n this.refreshObjects();\r\n },\r\n onAddCompare: features.compareSymbols !== false ? () => this.handleAddCompare() : undefined,\r\n onRemoveCompare: (id) => this.handleRemoveCompare(id),\r\n }, this.t);\r\n const refresh = () => { if (this.objectTree?.isOpen()) this.refreshObjects(); };\r\n // A drawing changes many times a second while its settings are edited\r\n // (a colour being picked): rebuild the list once a frame at most.\r\n let refreshFrame = 0;\r\n const refreshSoon = () => {\r\n if (refreshFrame || !this.objectTree?.isOpen()) return;\r\n refreshFrame = requestAnimationFrame(() => {\r\n refreshFrame = 0;\r\n if (!this.destroyed) refresh();\r\n });\r\n };\r\n this.chart.on('drawingCreate', refresh);\r\n this.chart.on('drawingRemove', refresh);\r\n this.chart.on('drawingUpdate', refreshSoon);\r\n this.chart.on('indicatorAdd', refresh);\r\n this.chart.on('indicatorRemove', refresh);\r\n this.chart.on('indicatorChange', refresh);\r\n }\r\n\r\n // 8b. Command palette\r\n this.commandPalette = new WidgetCommandPalette({\r\n onIndicator: (id) => this.handleAddIndicator(id),\r\n onChartType: (type) => this.handleChartType(type),\r\n onDrawingTool: (tool) => this.handleDrawingTool(tool),\r\n onTimeframe: (tf) => this.handleTimeframe(tf),\r\n onAction: (id) => this.handleAction(id),\r\n onClose: () => {},\r\n }, this.overlayHost, this.t);\r\n\r\n this.boundGlobalKeydown = (e: KeyboardEvent) => {\r\n if (this.replayBar?.isMounted() && this.handleReplayKey(e)) return;\r\n // With several widgets on the page, the shortcuts go to the one used last.\r\n const mine = isKeyTarget(this.root);\r\n if ((e.ctrlKey || e.metaKey) && e.key === 'k') {\r\n if (!mine) return;\r\n e.preventDefault();\r\n this.toggleCommandPalette();\r\n } else if ((e.ctrlKey || e.metaKey) && (e.key === 'p' || e.key === 'P')) {\r\n // Ctrl/Cmd+P → symbol search (matches Bloomberg / many trading UIs)\r\n if (!mine) return;\r\n e.preventDefault();\r\n this.symbolSearch?.open(this.symbols, this.state.symbol, undefined, this.symbolSearchFn());\r\n } else if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && (e.key === 's' || e.key === 'S')) {\r\n // Ctrl/Cmd+S → save the layout (rather than the page), once this widget was used.\r\n if (!this.layoutSession || isTyping() || !isKeyTarget(this.root, true)) return;\r\n e.preventDefault();\r\n void this.saveLayout();\r\n } else if (e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey && TOOL_HOTKEYS[e.code]) {\r\n // Alt+T trend line, Alt+H horizontal line… (the drawing tools' keys).\r\n if (e.defaultPrevented || isTyping() || !mine || inOverlay() || this.options.drawingTools === false) return;\r\n e.preventDefault();\r\n this.handleDrawingTool(TOOL_HOTKEYS[e.code]);\r\n } else if (/^[0-9]$/.test(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey) {\r\n // A number typed on the chart starts an interval (5, 15m, 1h…).\r\n if (e.defaultPrevented || !this.intervalInput || isTyping() || inOverlay() || !isKeyTarget(this.root, true)) return;\r\n const active = document.activeElement;\r\n // Focus in another part of the page: the keys are its.\r\n if (active && active !== document.body && !this.root.contains(active)) return;\r\n e.preventDefault();\r\n this.intervalInput.open(e.key);\r\n } else if (e.altKey && !e.ctrlKey && !e.metaKey && (e.code === 'KeyI' || e.code === 'KeyG')) {\r\n // By key position: on macOS Alt+G types \"©\".\r\n if (isTyping() || !mine) return;\r\n if (e.code === 'KeyI') {\r\n // Alt+I → invert the price scale.\r\n e.preventDefault();\r\n this.changeSettings({ invertScale: !this.settingsState.invertScale });\r\n } else if (this.goToDate) {\r\n // Alt+G → go to date.\r\n e.preventDefault();\r\n this.toggleGoToDate();\r\n }\r\n } else if (e.key === '?' && !e.ctrlKey && !e.metaKey && !e.altKey) {\r\n // Only fire when the user isn't typing into an input.\r\n if (isTyping() || !mine) return;\r\n e.preventDefault();\r\n this.hotkeySheet?.open();\r\n }\r\n };\r\n document.addEventListener('keydown', this.boundGlobalKeydown);\r\n document.addEventListener('fullscreenchange', this.onFullscreenChange);\r\n this.unregisterKeys = registerKeyRoot(this.root);\r\n\r\n // 9. Connect stream\r\n if (options.adapter) {\r\n this.adapter = options.adapter;\r\n this.connectStream();\r\n }\r\n\r\n // Watchlist live-update loop. 1s cadence keeps DOM churn low while still\r\n // feeling responsive; for sub-second visual response, apps can call\r\n // `setWatchlistEntry` directly from their own WebSocket.\r\n if (this.watchlist) {\r\n this.watchlistInterval = setInterval(() => this.tickWatchlist(), 1000);\r\n }\r\n\r\n // Initial UI update\r\n this.refreshMarket();\r\n this.updateUI();\r\n\r\n // 9. Fire onReady\r\n options.onReady?.(this.chart);\r\n\r\n // Deep-link restore: apply a `#tcw=` view from the URL when enabled.\r\n if (options.shareUrl && typeof location !== 'undefined') {\r\n const encoded = readShareHash(location.hash);\r\n if (encoded) void this.importState(encoded);\r\n }\r\n }\r\n\r\n // --- Public API ---\r\n\r\n /** Replace the searchable symbol catalog. Does not change the active symbol. */\r\n setSymbols(symbols: string[]): void {\r\n this.symbols = symbols;\r\n // A list made from the symbols follows them; lists given or kept stay.\r\n const store = this.watchlistStore;\r\n if (store && this.watchlistFromSymbols) {\r\n store.replace(store.getLists().map((l) => (l.id === 'default' ? { ...l, symbols } : l)));\r\n }\r\n }\r\n\r\n // --- Watchlists ---\r\n\r\n /** Every watchlist, in order. */\r\n getWatchlists(): WatchlistList[] {\r\n return this.watchlistStore?.getLists() ?? [];\r\n }\r\n\r\n /** The shown watchlist's id, or null without a watchlist. */\r\n getActiveWatchlist(): string | null {\r\n return this.watchlistStore?.getActive().id ?? null;\r\n }\r\n\r\n /** Replace every watchlist (and which one shows). */\r\n setWatchlists(lists: WatchlistList[], activeList?: string): void {\r\n this.watchlistFromSymbols = false;\r\n this.watchlistStore?.replace(lists, activeList);\r\n }\r\n\r\n setActiveWatchlist(id: string): void {\r\n this.watchlistStore?.setActive(id);\r\n }\r\n\r\n /** Add a symbol to a watchlist (the shown one by default). */\r\n addToWatchlist(symbol: string, listId?: string): void {\r\n this.watchlistStore?.add(symbol, listId);\r\n }\r\n\r\n removeFromWatchlist(symbol: string, listId?: string): void {\r\n this.watchlistStore?.removeSymbol(symbol, listId);\r\n }\r\n\r\n /**\r\n * Quotes for the watchlist's rows (and `getQuote`), from your own feed.\r\n * What isn't a quote (no symbol, no finite last price) is left out.\r\n */\r\n setQuotes(quotes: readonly Quote[]): void {\r\n const read = quotes.map(readQuote).filter((q): q is Quote => q !== null);\r\n if (read.length > 0) this.takeQuotes(read);\r\n }\r\n\r\n /** The latest quote of a symbol, from the quote source or `setQuotes`. */\r\n getQuote(symbol: string): Quote | null {\r\n const quote = this.quotes.get(symbol);\r\n return quote ? { ...quote } : null;\r\n }\r\n\r\n /** Open or close the symbol info panel (toggle when `open` is left out). */\r\n toggleSymbolInfo(open?: boolean): void {\r\n const panel = this.symbolInfoPanel;\r\n if (!panel) return;\r\n if (open === undefined) panel.toggle();\r\n else if (open) panel.open();\r\n else panel.close();\r\n }\r\n\r\n /** The market's status in the status bar, and the panel when it's open. */\r\n private refreshMarket(): void {\r\n const status = marketStatus(this.chart.getSymbolInfo(), Date.now());\r\n this.statusBar?.setMarket(status.state, this.t(status.state === 'open' ? 'symbolInfo.open' : 'symbolInfo.closed'));\r\n this.refreshSymbolInfo();\r\n }\r\n\r\n private refreshSymbolInfo(): void {\r\n const panel = this.symbolInfoPanel;\r\n if (!panel?.isOpen() || this.destroyed) return;\r\n panel.render(this.symbolInfoView());\r\n }\r\n\r\n private symbolInfoView(): SymbolInfoView {\r\n const info = this.chart.getSymbolInfo();\r\n const symbol = this.state.symbol;\r\n const quote = this.quotes.get(symbol);\r\n const day = sessionDay(this.chart.getData(), info?.timezone);\r\n const fp = (p: number) => this.formatAlertPrice(p);\r\n const locale = this.textLocale();\r\n\r\n const last = quote?.last ?? day?.close;\r\n const prevClose = quote?.prevClose ?? day?.prevClose;\r\n const change = quote?.change ?? (last !== undefined && prevClose !== undefined ? last - prevClose : undefined);\r\n const base = last !== undefined && change !== undefined ? last - change : undefined;\r\n const percent = quote?.changePercent ?? (change !== undefined && base ? (change / base) * 100 : undefined);\r\n\r\n const status = marketStatus(info, Date.now());\r\n let statusText = this.t(status.state === 'open' ? 'symbolInfo.open' : status.state === 'closed' ? 'symbolInfo.closed' : 'symbolInfo.always');\r\n if (status.state !== 'always' && status.next !== null) {\r\n const when = relativeTime(status.next - Date.now(), locale);\r\n statusText += ` · ${fill(this.t(status.state === 'open' ? 'symbolInfo.closesIn' : 'symbolInfo.opensIn'), { when })}`;\r\n }\r\n\r\n const stats: { label: string; value: string }[] = [];\r\n const add = (label: string, value: string | undefined) => {\r\n if (value) stats.push({ label, value });\r\n };\r\n const price = (v: number | undefined) => (v !== undefined ? fp(v) : undefined);\r\n add(this.t('dataWindow.open'), price(quote?.open ?? day?.open));\r\n add(this.t('dataWindow.high'), price(quote?.high ?? day?.high));\r\n add(this.t('dataWindow.low'), price(quote?.low ?? day?.low));\r\n add(this.t('symbolInfo.prevClose'), price(prevClose));\r\n const volume = quote?.volume ?? day?.volume;\r\n add(this.t('dataWindow.volume'), volume !== undefined ? compactNumber(volume, this.intlLocale()) : undefined);\r\n add(this.t('symbolInfo.bid'), price(quote?.bid));\r\n add(this.t('symbolInfo.ask'), price(quote?.ask));\r\n add(this.t('symbolInfo.tick'), info?.minTick !== undefined ? String(info.minTick) : undefined);\r\n add(this.t('symbolInfo.currency'), info?.currency);\r\n add(this.t('symbolInfo.timezone'), info?.timezone);\r\n add(this.t('symbolInfo.hours'), sessionsText(info, locale));\r\n\r\n const sign = (change ?? 0) >= 0 ? '+' : '-';\r\n return {\r\n symbol,\r\n description: info?.description,\r\n meta: [info?.exchange, info?.type].filter(Boolean).join(' · ') || undefined,\r\n price: last !== undefined ? fp(last) : undefined,\r\n change: change !== undefined\r\n ? { text: `${sign}${fp(Math.abs(change))}${percent !== undefined ? ` (${sign}${Math.abs(percent).toFixed(2)}%)` : ''}`, up: change >= 0 }\r\n : undefined,\r\n status: { state: status.state, text: statusText },\r\n stats,\r\n };\r\n }\r\n\r\n /** Headlines for the chart's symbol into the open panel; cached a few minutes. */\r\n private loadNews(): void {\r\n const panel = this.symbolInfoPanel;\r\n if (!panel?.isOpen()) return;\r\n const adapter = this.options.adapter;\r\n const source = this.options.news ?? (adapter?.fetchNews ? adapter.fetchNews.bind(adapter) : null);\r\n if (!source) {\r\n panel.renderNews({ kind: 'none' });\r\n return;\r\n }\r\n const symbol = this.state.symbol;\r\n const request = ++this.newsRequest;\r\n const show = (items: NewsItem[]) => {\r\n const locale = this.textLocale();\r\n panel.renderNews({\r\n kind: 'items',\r\n items: items.map((item) => ({\r\n title: item.title,\r\n url: item.url,\r\n meta: [item.source, relativeTime(item.time - Date.now(), locale)].filter(Boolean).join(' · '),\r\n })),\r\n });\r\n };\r\n const cached = this.newsCache.get(symbol);\r\n if (cached && Date.now() - cached.at < NEWS_TTL_MS) {\r\n show(cached.items);\r\n return;\r\n }\r\n panel.renderNews({ kind: 'loading' });\r\n Promise.resolve()\r\n .then(() => source(symbol, NEWS_LIMIT))\r\n .then((raw) => {\r\n if (request !== this.newsRequest || this.destroyed) return;\r\n const items = readNews(raw, NEWS_LIMIT);\r\n this.newsCache.set(symbol, { at: Date.now(), items });\r\n show(items);\r\n })\r\n .catch(() => {\r\n if (request === this.newsRequest && !this.destroyed) panel.renderNews({ kind: 'failed' });\r\n });\r\n }\r\n\r\n /** The BCP 47 tag numbers in the panels are written in. */\r\n private intlLocale(): string {\r\n return this.settingsState.numberLocale || this.options.locale || 'en';\r\n }\r\n\r\n /** The language words in the panels are written in (\"in 3 hours\", weekday names): the widget's. */\r\n private textLocale(): string {\r\n return this.options.locale || 'en';\r\n }\r\n\r\n private createWatchlist(body: HTMLElement, opts: import('./types.js').WatchlistOptions): void {\r\n const storage = opts.persist ? browserStorage() : null;\r\n const store = new WatchlistStore({\r\n lists: opts.lists,\r\n activeList: opts.activeList,\r\n symbols: this.symbols,\r\n defaultName: this.t('watchlist.title'),\r\n storage,\r\n storageKey: opts.storageKey,\r\n });\r\n this.watchlistStore = store;\r\n this.watchlistFromSymbols = !opts.lists && !opts.persist;\r\n this.quoteSource = opts.quotes === false ? null : opts.quotes ?? (this.options.adapter?.subscribeQuotes ? this.options.adapter as QuoteSource : null);\r\n\r\n const t = (key: Parameters<typeof this.t>[0]) => this.t(key);\r\n this.watchlist = new WidgetWatchlist(body, {\r\n onSelect: (sym) => { void this.setSymbol(sym); },\r\n onAdd: () => this.symbolSearch?.open(this.symbols, this.state.symbol, (sym) => store.add(sym), this.symbolSearchFn()),\r\n onRemove: (sym) => store.removeSymbol(sym),\r\n onMove: (sym, index) => store.move(sym, index),\r\n onPickList: (id) => store.setActive(id),\r\n onCreateList: (name) => store.create(name),\r\n onRenameList: (id, name) => store.rename(id, name),\r\n onDeleteList: (id) => store.remove(id),\r\n }, {\r\n title: t('watchlist.title'),\r\n lists: t('watchlist.lists'),\r\n newList: t('watchlist.newList'),\r\n rename: t('watchlist.rename'),\r\n deleteList: t('watchlist.deleteList'),\r\n confirmDelete: t('watchlist.confirmDelete'),\r\n add: t('watchlist.add'),\r\n remove: t('watchlist.remove'),\r\n empty: t('watchlist.empty'),\r\n listName: t('watchlist.listName'),\r\n });\r\n this.watchlist.setActive(this.state.symbol);\r\n this.watchlist.setLocale(this.settingsState.numberLocale || undefined);\r\n const show = () => {\r\n this.watchlist?.setLists(store.getLists(), store.getActive().id);\r\n this.followQuotes();\r\n };\r\n store.subscribe(() => {\r\n show();\r\n opts.onChange?.(store.getLists(), store.getActive().id);\r\n });\r\n show();\r\n }\r\n\r\n /** Quotes for the shown list's symbols: a new subscription when they change. */\r\n private followQuotes(): void {\r\n if (!this.quoteSource || !this.watchlistStore || this.destroyed) return;\r\n const symbols = this.watchlistStore.getActive().symbols;\r\n // The same symbols in another order (a row moved) keep their subscription.\r\n const key = [...symbols].sort().join('\\u0000');\r\n if (key === this.quotedKey) return;\r\n this.quotedKey = key;\r\n this.stopQuotes?.();\r\n this.stopQuotes = null;\r\n if (symbols.length === 0) return;\r\n try {\r\n this.stopQuotes = this.quoteSource.subscribeQuotes(symbols, (quotes) => {\r\n if (this.destroyed || !Array.isArray(quotes)) return;\r\n // A source of the host's is untrusted: what isn't a quote is left out.\r\n const read = quotes.map(readQuote).filter((q): q is Quote => q !== null);\r\n if (read.length > 0) this.takeQuotes(read);\r\n });\r\n } catch {\r\n this.stopQuotes = null;\r\n }\r\n }\r\n\r\n private takeQuotes(quotes: readonly Quote[]): void {\r\n for (const update of quotes) {\r\n // A stream frame carries less than a snapshot: what it leaves out stays.\r\n const quote = { ...this.quotes.get(update.symbol), ...update };\r\n this.quotes.set(quote.symbol, quote);\r\n const buf = this.watchlistSparkBuffer.get(quote.symbol) ?? [];\r\n buf.push(quote.last);\r\n if (buf.length > 40) buf.shift();\r\n this.watchlistSparkBuffer.set(quote.symbol, buf);\r\n const hostRef = this.hostWatchlistRefPrice.get(quote.symbol);\r\n this.watchlist?.setEntry(quote.symbol, {\r\n lastPrice: quote.last,\r\n refPrice: hostRef ?? (quote.change !== undefined ? quote.last - quote.change : undefined),\r\n sparkline: buf.slice(),\r\n });\r\n }\r\n if (quotes.some((q) => q.symbol === this.state.symbol)) this.refreshSymbolInfo();\r\n }\r\n\r\n async setSymbol(symbol: string): Promise<void> {\r\n // Flush the outgoing symbol's layout BEFORE switching state, so the\r\n // saved snapshot reflects what the user actually saw under that ticker.\r\n this.flushActiveLayout();\r\n // Fill marks sit on this symbol's bars; the next symbol starts with none.\r\n if (symbol !== this.state.symbol) this.chart.clearFills();\r\n this.state = { ...this.state, symbol };\r\n this.sessionRefPrice = null;\r\n this.options.onSymbolChange?.(symbol);\r\n this.updateUI();\r\n this.watchlist?.setActive(symbol);\r\n this.refreshMarket();\r\n this.loadNews();\r\n this.layoutSession?.changed();\r\n if (this.adapter) {\r\n await this.connectStream();\r\n }\r\n }\r\n\r\n /**\r\n * Push an entry into the watchlist (e.g., from your own WebSocket).\r\n * Call with the symbols you care about; the active symbol is updated\r\n * automatically from the chart's live data.\r\n *\r\n * A host-supplied `refPrice` takes precedence over the widget's own\r\n * session-open guess for that symbol — including the active one, so the\r\n * auto-tick loop stops clobbering it (see `tickWatchlist`).\r\n */\r\n setWatchlistEntry(symbol: string, entry: Partial<WatchlistEntry>): void {\r\n if (entry.refPrice !== undefined) {\r\n this.hostWatchlistRefPrice.set(symbol, entry.refPrice);\r\n }\r\n this.watchlist?.setEntry(symbol, entry);\r\n }\r\n\r\n private tickWatchlist(): void {\r\n // A symbol with quotes shows them (the day's move), not the loaded bars'.\r\n if (!this.watchlist || this.quotes.has(this.state.symbol)) return;\r\n const data = this.chart.getData();\r\n if (data.length === 0) return;\r\n const last = data[data.length - 1];\r\n const hostRef = this.hostWatchlistRefPrice.get(this.state.symbol);\r\n // Reference price: first bar of the loaded slice — that's the closest\r\n // approximation of \"session open\" without timezone bookkeeping. Only\r\n // used as a fallback; a refPrice the host already pushed via\r\n // `setWatchlistEntry` (even for the active symbol) always wins.\r\n if (hostRef === undefined && this.sessionRefPrice === null) {\r\n this.sessionRefPrice = data[0].open;\r\n }\r\n\r\n const buf = this.watchlistSparkBuffer.get(this.state.symbol) ?? [];\r\n buf.push(last.close);\r\n if (buf.length > 40) buf.shift();\r\n this.watchlistSparkBuffer.set(this.state.symbol, buf);\r\n\r\n this.watchlist.setEntry(this.state.symbol, {\r\n lastPrice: last.close,\r\n refPrice: hostRef ?? this.sessionRefPrice ?? data[0].open,\r\n sparkline: buf.slice(),\r\n });\r\n }\r\n\r\n /** Ignored when the chart's `features.timeframes` whitelist leaves `tf` out. */\r\n async setTimeframe(tf: TimeFrame): Promise<void> {\r\n if (!this.chart.isTimeframeAllowed(tf)) return;\r\n this.state = { ...this.state, timeframe: tf };\r\n this.options.onTimeframeChange?.(tf);\r\n this.updateUI();\r\n this.layoutSession?.changed();\r\n if (this.adapter) {\r\n // Live adapter owns the data — refetch at the native resolution.\r\n await this.connectStream();\r\n return;\r\n }\r\n if (this.options.resampleTimeframes === false) return;\r\n // Static data: aggregate the base series locally. Lazily adopt whatever is\r\n // currently on the chart as the base if the host fed it via getChart().\r\n if (!this.baseSeries) {\r\n const current = this.chart.getData();\r\n if (current.length > 0) {\r\n this.baseSeries = current;\r\n this.baseTimeframeMs = inferTimeframeMs(current);\r\n }\r\n }\r\n await this.switchLocalTimeframe();\r\n }\r\n\r\n setTheme(theme: import('@tradecanvas/commons').ThemeName | Theme): void {\r\n const isDark = this.resolveIsDark(theme);\r\n const resolved = this.resolveTheme(theme);\r\n this.state = { ...this.state, isDark };\r\n this.root.dataset.tcwTheme = isDark ? 'dark' : 'light';\r\n this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme;\r\n this.chart.setTheme(resolved);\r\n this.updateUI();\r\n }\r\n\r\n getChart(): Chart {\r\n return this.chart;\r\n }\r\n\r\n /**\r\n * Change the widget's look: a preset (`'studio'`, `'terminal'`,\r\n * `'capsule'`) or your theme over one. Colours stay with `setTheme`.\r\n */\r\n setUI(theme: WidgetUIPreset | WidgetUITheme): void {\r\n this.ui = resolveWidgetUI(theme);\r\n applyWidgetUI(this.root, this.ui);\r\n applyWidgetUI(this.portal, this.ui);\r\n this.applyChartShapes();\r\n }\r\n\r\n /** The widget's look, every token set. */\r\n getUI(): ResolvedWidgetUI {\r\n return resolveWidgetUI({ ...this.ui });\r\n }\r\n\r\n /** The chart's own tags and pills take the look's corners. */\r\n private applyChartShapes(): void {\r\n this.chart.setShapes({ tagRadius: this.ui.tagRadius });\r\n }\r\n\r\n destroy(): void {\r\n if (this.destroyed) return;\r\n this.destroyed = true;\r\n\r\n if (this.boundGlobalKeydown) {\r\n document.removeEventListener('keydown', this.boundGlobalKeydown);\r\n }\r\n document.removeEventListener('fullscreenchange', this.onFullscreenChange);\r\n this.unregisterKeys();\r\n this.tooltip.destroy();\r\n if (this.legendFrame) cancelAnimationFrame(this.legendFrame);\r\n this.indicatorLegend?.destroy();\r\n this.portal.remove();\r\n if (document.fullscreenElement === this.root) void document.exitFullscreen().catch(() => {});\r\n this.flushActiveLayout();\r\n this.commandPalette?.destroy();\r\n this.symbolSearch?.destroy();\r\n this.hotkeySheet?.destroy();\r\n if (this.replayPollInterval) clearInterval(this.replayPollInterval);\r\n this.replayShade?.remove();\r\n this.replayBar?.destroy();\r\n this.dragDrop?.detach();\r\n this.alertsPanel?.destroy();\r\n this.objectTree?.destroy();\r\n this.indicatorSettings?.destroy();\r\n this.drawingStyle?.destroy();\r\n this.drawingSettings?.destroy();\r\n this.drawingMenu?.destroy();\r\n this.chartMenu?.destroy();\r\n this.legendMenu?.destroy();\r\n this.templatePrompt?.destroy();\r\n this.intervalInput?.destroy();\r\n this.markerTip?.remove();\r\n this.layoutSession?.destroy();\r\n this.layoutsUI?.destroy();\r\n this.accountPanel?.destroy();\r\n this.orderTicket?.destroy();\r\n if (this.accountFrame) cancelAnimationFrame(this.accountFrame);\r\n this.bracketBar?.destroy();\r\n this.alertNotifier?.destroy();\r\n this.depthLadder?.destroy();\r\n this.dataWindow?.destroy();\r\n if (this.watchlistInterval) clearInterval(this.watchlistInterval);\r\n if (this.marketTimer) clearInterval(this.marketTimer);\r\n this.chartNav?.destroy();\r\n this.symbolInfoPanel?.destroy();\r\n this.stopQuotes?.();\r\n this.stopQuotes = null;\r\n this.watchlist?.destroy();\r\n this.toolbar?.destroy();\r\n this.sidebar?.destroy();\r\n this.settings?.destroy();\r\n this.statusBar?.destroy();\r\n this.goToDate?.destroy();\r\n this.loading.destroy();\r\n this.historyPill.destroy();\r\n this.chart.destroy();\r\n this.root.remove();\r\n removeWidgetStyles();\r\n }\r\n\r\n // --- Internal handlers ---\r\n\r\n private handleSymbolClick(): void {\r\n // Opens the fuzzy search modal. The cycle-through behaviour the toolbar\r\n // used to do is gone — a real search scales past 3-4 symbols and matches\r\n // what users expect from professional trading terminals.\r\n this.symbolSearch?.open(this.symbols, this.state.symbol, undefined, this.symbolSearchFn());\r\n }\r\n\r\n /** The host's symbol search, else the adapter's; none filters `symbols`. */\r\n private symbolSearchFn(): SymbolSearchFn | undefined {\r\n if (this.options.searchSymbols) return this.options.searchSymbols;\r\n const adapter = this.adapter;\r\n if (!adapter?.searchSymbols) return undefined;\r\n return (query, signal) => adapter.searchSymbols!(query, { signal, limit: 50 });\r\n }\r\n\r\n private handleTimeframe(tf: TimeFrame): void {\r\n void this.setTimeframe(tf);\r\n }\r\n\r\n /** Fill the screen with the widget, or leave fullscreen. */\r\n toggleFullscreen(): void {\r\n if (document.fullscreenElement === this.root) {\r\n void document.exitFullscreen().catch(() => {});\r\n return;\r\n }\r\n this.root.requestFullscreen().catch((err: unknown) => {\r\n this.toast(err instanceof Error ? err.message : this.t('toast.fullscreenUnavailable'), 'error');\r\n });\r\n }\r\n\r\n /** A drawing tool's name in the widget's language. */\r\n private drawingToolName(type: DrawingToolType): string {\r\n const key = `tool.${type}` as MessageKey;\r\n const name = this.t(key);\r\n return name === key ? this.chart.getDrawingToolDescriptor(type)?.name ?? type : name;\r\n }\r\n\r\n /** Open a drawing's settings (double-click on it, or the object tree's settings button). */\r\n private openDrawingSettings(id: string): void {\r\n const drawing = this.chart.getDrawings().find((d) => d.id === id);\r\n const descriptor = drawing ? this.chart.getDrawingToolDescriptor(drawing.type) : null;\r\n if (!drawing || !descriptor || !this.drawingSettings) return;\r\n this.drawingSettings.open({\r\n id,\r\n type: drawing.type,\r\n name: this.drawingToolName(drawing.type),\r\n style: { ...drawing.style },\r\n options: this.chart.getDrawingOptions(id),\r\n defs: descriptor.options ?? {},\r\n anchors: drawing.anchors.map((a) => ({ ...a })),\r\n fill: descriptor.fill === true,\r\n text: descriptor.text === true,\r\n alertable: this.chart.canAddDrawingAlert(id),\r\n });\r\n }\r\n\r\n /** Add a \"price crosses this drawing\" alert and say so. */\r\n private addDrawingAlert(id: string): void {\r\n const drawing = this.chart.getDrawings().find((d) => d.id === id);\r\n const name = drawing ? this.drawingToolName(drawing.type) : '';\r\n if (this.chart.addDrawingAlert(id, { label: name })) {\r\n this.toast(fill(this.t('drawingSettings.alertAdded'), { name }));\r\n }\r\n }\r\n\r\n /** The menu of a right-clicked drawing; the chart has selected it (and its group) by now. */\r\n private openDrawingMenu(id: string, x: number, y: number): void {\r\n if (!this.drawingMenu) return;\r\n const drawings = new Map(this.chart.getDrawings().map((d) => [d.id, d]));\r\n const selected = this.chart.getSelectedDrawingIds().flatMap((sid) => {\r\n const d = drawings.get(sid);\r\n return d ? [{ id: d.id, locked: d.locked, groupId: d.group?.id ?? null }] : [];\r\n });\r\n if (selected.length === 0) return;\r\n const entries = drawingMenuEntries({\r\n selected,\r\n canConfigure: this.drawingSettings !== null,\r\n canAlert: this.chart.canAddDrawingAlert(id),\r\n }, this.t);\r\n const chartRect = this.chartContainer.getBoundingClientRect();\r\n const rootRect = this.root.getBoundingClientRect();\r\n const ids = selected.map((d) => d.id);\r\n this.drawingMenu.open(entries, chartRect.left - rootRect.left + x, chartRect.top - rootRect.top + y,\r\n (action) => this.runDrawingMenuAction(id, ids, action as DrawingMenuAction));\r\n }\r\n\r\n private runDrawingMenuAction(id: string, ids: readonly string[], action: DrawingMenuAction): void {\r\n switch (action) {\r\n case 'settings':\r\n this.openDrawingSettings(id);\r\n return;\r\n case 'alert':\r\n this.addDrawingAlert(id);\r\n return;\r\n case 'front':\r\n case 'forward':\r\n case 'backward':\r\n case 'back':\r\n this.chart.moveDrawing(id, action);\r\n break;\r\n case 'group':\r\n this.chart.groupDrawings(ids);\r\n break;\r\n case 'ungroup': {\r\n const groups = new Set(this.chart.getDrawings().filter((d) => ids.includes(d.id)).map((d) => d.group?.id));\r\n for (const group of groups) if (group) this.chart.ungroupDrawings(group);\r\n break;\r\n }\r\n case 'lock':\r\n case 'unlock':\r\n this.chart.setDrawingsLocked(ids, action === 'lock');\r\n break;\r\n case 'hide':\r\n this.chart.setDrawingsVisible(ids, false);\r\n break;\r\n case 'duplicate':\r\n this.chart.duplicateDrawing(id);\r\n break;\r\n case 'delete': {\r\n const editing = this.drawingSettings?.editing();\r\n if (editing && ids.includes(editing)) this.drawingSettings?.close(true);\r\n this.chart.removeDrawings(ids);\r\n break;\r\n }\r\n }\r\n if (this.objectTree?.isOpen()) this.refreshObjects();\r\n }\r\n\r\n /** What the chart's menus can offer here, and how the chart is set now. */\r\n private chartMenuContext(price: number | undefined): ChartMenuContext {\r\n const drawings = this.chart.getDrawings();\r\n const data = this.chart.getData();\r\n return {\r\n price,\r\n lastPrice: data.length > 0 ? data[data.length - 1].close : null,\r\n formatPrice: (p) => this.formatAlertPrice(p),\r\n canAlert: this.alertsPanel !== null,\r\n canTrade: this.options.trading !== false,\r\n canOrderTicket: this.orderTicket !== null,\r\n canDraw: this.options.drawingTools !== false,\r\n hasDrawings: drawings.length > 0,\r\n drawingsHidden: drawings.length > 0 && drawings.every((d) => !d.visible),\r\n canGoToDate: this.goToDate !== null,\r\n canExport: this.canExport,\r\n autoScale: this.chart.isAutoScale(),\r\n scaleMode: this.settingsState.scaleMode,\r\n inverted: this.chart.isInvertScale(),\r\n };\r\n }\r\n\r\n /**\r\n * Open a chart menu at (x, y) in the chart's pixels, the host's own entries\r\n * last; nothing when it has no entries.\r\n */\r\n private openChartMenu(\r\n entries: import('./WidgetContextMenu.js').ContextMenuEntry[],\r\n x: number,\r\n y: number,\r\n context: import('./types.js').ChartMenuItemsContext,\r\n ): void {\r\n if (!this.chartMenu) return;\r\n const extra = this.options.chartMenuItems?.(context) ?? [];\r\n const all: import('./WidgetContextMenu.js').ContextMenuEntry[] = [\r\n ...entries,\r\n ...(entries.length > 0 && extra.length > 0 ? ['separator' as const] : []),\r\n ...extra.map((item, i) => ({ id: `host:${i}`, label: item.label, icon: item.icon, danger: item.danger, checked: item.checked })),\r\n ];\r\n if (all.length === 0) return;\r\n const chartRect = this.chartContainer.getBoundingClientRect();\r\n const rootRect = this.root.getBoundingClientRect();\r\n this.chartMenu.open(all, chartRect.left - rootRect.left + x, chartRect.top - rootRect.top + y, (action) => {\r\n if (action.startsWith('host:')) extra[Number(action.slice('host:'.length))]?.onSelect();\r\n else this.runChartMenuAction(action as ChartMenuAction, context.price);\r\n });\r\n }\r\n\r\n /**\r\n * A button of your own on the toolbar: an icon (built-in or yours), text,\r\n * a switch. `null` without a toolbar.\r\n */\r\n addToolbarButton(spec: import('./types.js').ToolbarButtonSpec): import('./types.js').ToolbarButtonHandle | null {\r\n if (!this.toolbar) return null;\r\n const element = this.toolbar.addHostButton(spec);\r\n const textSpan = (): HTMLSpanElement => {\r\n const found = element.querySelector<HTMLSpanElement>('.tcw-host-btn-text');\r\n if (found) return found;\r\n const added = document.createElement('span');\r\n added.className = 'tcw-host-btn-text';\r\n element.appendChild(added);\r\n return added;\r\n };\r\n return {\r\n element,\r\n setActive: (on) => {\r\n element.classList.toggle('tcw-active', on);\r\n if (spec.toggle) element.setAttribute('aria-pressed', String(on));\r\n },\r\n setText: (text) => {\r\n textSpan().textContent = text;\r\n setHostButtonName(element, spec.label);\r\n },\r\n remove: () => element.remove(),\r\n };\r\n }\r\n\r\n private runChartMenuAction(action: ChartMenuAction, price: number | undefined): void {\r\n const at = price ?? NaN;\r\n switch (action) {\r\n case 'alert':\r\n this.chart.addAlert(at, 'crossing');\r\n this.toast(fill(this.t('chartMenu.alertAdded'), { price: this.formatAlertPrice(at) }));\r\n break;\r\n case 'buyLimit':\r\n case 'sellLimit':\r\n case 'buyStop':\r\n case 'sellStop':\r\n this.placeOrderAt(action, at);\r\n break;\r\n case 'orderTicket':\r\n this.openOrderTicket(price);\r\n break;\r\n case 'exportData':\r\n // Every bar loaded, with the indicator lines, named after the symbol and interval.\r\n this.chart.exportAllData('csv', `${this.state.symbol}-${this.state.timeframe}.csv`.replace(/[^\\w.-]+/g, '_'));\r\n break;\r\n case 'paneLog':\r\n case 'paneInvert':\r\n case 'panePercent': {\r\n const pane = this.menuPane;\r\n if (!pane) break;\r\n const scale = this.chart.getPaneScale(pane);\r\n this.chart.setPaneScale(pane, action === 'paneLog' ? { log: !scale.log }\r\n : action === 'paneInvert' ? { invert: !scale.invert } : { percent: !scale.percent });\r\n break;\r\n }\r\n case 'horizontalLine': {\r\n const data = this.chart.getData();\r\n if (data.length > 0) this.chart.addDrawing({ type: 'horizontalLine', anchors: [{ time: data[data.length - 1].time, price: at }] });\r\n break;\r\n }\r\n case 'resetView':\r\n this.chart.fitContent();\r\n this.changeSettings({ autoScale: true });\r\n break;\r\n case 'hideDrawings':\r\n this.chart.setDrawingsVisible(this.chart.getDrawings().map((d) => d.id), false);\r\n break;\r\n case 'showDrawings':\r\n this.chart.setDrawingsVisible(this.chart.getDrawings().map((d) => d.id), true);\r\n break;\r\n case 'removeDrawings':\r\n // One undo step; locked drawings stay.\r\n this.chart.removeDrawings(this.chart.getDrawings().map((d) => d.id));\r\n break;\r\n case 'settings':\r\n this.openSettings();\r\n break;\r\n case 'autoScale':\r\n this.changeSettings({ autoScale: !this.chart.isAutoScale() });\r\n break;\r\n case 'logScale':\r\n this.changeSettings({ scaleMode: this.settingsState.scaleMode === 'logarithmic' ? 'regular' : 'logarithmic' });\r\n break;\r\n case 'percentScale':\r\n this.changeSettings({ scaleMode: this.settingsState.scaleMode === 'percentage' ? 'regular' : 'percentage' });\r\n break;\r\n case 'invertScale':\r\n this.changeSettings({ invertScale: !this.chart.isInvertScale() });\r\n break;\r\n case 'goToDate':\r\n this.toggleGoToDate();\r\n break;\r\n }\r\n if (this.objectTree?.isOpen()) this.refreshObjects();\r\n }\r\n\r\n /** Open or close the account panel (no argument: the other way from now). */\r\n toggleAccountPanel(open?: boolean): void {\r\n const panel = this.accountPanel;\r\n if (!panel || open === panel.isOpen()) return;\r\n panel.toggle();\r\n }\r\n\r\n /** The order ticket, at a price from the chart (or the market). */\r\n private openOrderTicket(price?: number): void {\r\n const data = this.chart.getData();\r\n this.orderTicket?.open({ price, lastPrice: data.length > 0 ? data[data.length - 1].close : null });\r\n }\r\n\r\n /** Redraw the account panel once a frame at most (ticks, fills and order changes come in bursts). */\r\n private refreshAccountSoon(): void {\r\n if (this.accountFrame || !this.accountPanel) return;\r\n this.accountFrame = requestAnimationFrame(() => {\r\n this.accountFrame = 0;\r\n if (!this.destroyed) this.refreshAccount();\r\n });\r\n }\r\n\r\n private refreshAccount(): void {\r\n if (!this.accountPanel) return;\r\n const data = this.chart.getData();\r\n const price = data.length > 0 ? data[data.length - 1].close : null;\r\n this.accountPanel.update({\r\n positions: this.chart.getPositions(),\r\n orders: this.chart.getOrders(),\r\n fills: this.chart.getFills(),\r\n price,\r\n realisedPnl: this.chart.getRealisedPnl(),\r\n });\r\n this.orderTicket?.setLastPrice(price);\r\n }\r\n\r\n /** Ask for a limit or stop order at `price` (one unit), and say so. */\r\n private placeOrderAt(kind: 'buyLimit' | 'sellLimit' | 'buyStop' | 'sellStop', price: number): void {\r\n const side = kind.startsWith('buy') ? 'buy' : 'sell';\r\n const stop = kind.endsWith('Stop');\r\n this.chart.placeOrderIntent(stop ? { side, type: 'stop', price, stopPrice: price, quantity: 1 } : { side, type: 'limit', price, quantity: 1 });\r\n this.toast(fill(this.t(`order.${kind}` as MessageKey), { price: this.formatAlertPrice(price) }));\r\n }\r\n\r\n /** The display timezone from the settings; 'exchange' is the zone the chart resolved it to. */\r\n private displayTimezone(): TimeZoneSetting {\r\n const tz = settingToTimezone(this.settingsState.timezone);\r\n return tz === 'exchange' ? this.chart.getEffectiveTimezone() : tz;\r\n }\r\n\r\n private toggleGoToDate(): void {\r\n if (!this.goToDate) return;\r\n if (this.goToDate.isOpen()) {\r\n this.goToDate.close();\r\n return;\r\n }\r\n const data = this.chart.getData();\r\n if (data.length === 0) return;\r\n this.goToDate.open(\r\n utcToWallTime(data[data.length - 1].time * barTimeUnit(data), this.displayTimezone()),\r\n this.root.querySelector('[data-role=\"goto\"]'),\r\n );\r\n }\r\n\r\n private goToWallTime(date: string, time: string): void {\r\n const ms = wallTimeToUtc(date, time, this.displayTimezone());\r\n const data = this.chart.getData();\r\n if (ms === null || data.length === 0) return;\r\n const ts = ms / barTimeUnit(data); // the bars' own unit\r\n this.chart.goToTime(ts);\r\n if (ts < data[0].time) this.toast(this.t('range.beforeData'));\r\n }\r\n\r\n /** Pinned timeframes that are still on offer, shortest first. */\r\n private pinnedTimeframes(): TimeFrame[] {\r\n const pinned = this.timeframeFavorites.list();\r\n return this.timeframes.filter((tf) => pinned.includes(tf));\r\n }\r\n\r\n /** The timeframe menu's rows, typed intervals marked so they can be removed. */\r\n private timeframeMenu(): { value: TimeFrame; label: string; custom: boolean }[] {\r\n return this.timeframes.map((value) => ({ value, label: timeframeLabel(value), custom: this.customTimeframes.has(value) }));\r\n }\r\n\r\n /** A typed interval: switch to it, adding and pinning it when it is new. False when it isn't one. */\r\n private handleAddTimeframe(text: string): boolean {\r\n const tf = parseTimeframeInput(text);\r\n if (!tf || !this.chart.isTimeframeAllowed(tf)) return false;\r\n if (this.adapter && !servesTimeframe(this.adapter, tf)) return false;\r\n // Tick bars come from a feed's trades; bars on the chart can't make them.\r\n if (!this.adapter && tickBarCount(tf) !== null) return false;\r\n if (!this.timeframes.includes(tf)) {\r\n this.customTimeframes.add(tf);\r\n this.timeframeFavorites.add(tf);\r\n this.timeframes = withExtraTimeframes(this.timeframes, [tf]);\r\n this.toolbar?.setTimeframes(this.timeframeMenu(), this.pinnedTimeframes());\r\n }\r\n this.handleTimeframe(tf);\r\n return true;\r\n }\r\n\r\n /** A note by a signal marker: its source or label, side, confidence, price and time; null hides it. */\r\n private showMarkerTip(hover: { marker: import('@tradecanvas/commons').SignalMarker | null; x: number; y: number }): void {\r\n const { marker } = hover;\r\n if (!marker) {\r\n if (this.markerTip) this.markerTip.hidden = true;\r\n return;\r\n }\r\n if (!this.markerTip) {\r\n this.markerTip = document.createElement('div');\r\n this.markerTip.className = 'tcw-marker-tip';\r\n this.markerTip.setAttribute('role', 'tooltip');\r\n this.chartContainer.appendChild(this.markerTip);\r\n }\r\n const side = marker.direction === 'long' ? this.t('account.long') : marker.direction === 'short' ? this.t('account.short') : this.t('markers.neutral');\r\n const title = document.createElement('strong');\r\n title.textContent = marker.label ? `${marker.label} · ${marker.source}` : marker.source;\r\n const line = document.createElement('div');\r\n line.textContent = `${side} · ${this.formatAlertPrice(marker.price)} · ${fill(this.t('markers.confidence'), { pct: Math.round(marker.confidence * 100) })}`;\r\n const when = document.createElement('div');\r\n const { date, time } = utcToWallTime(marker.time, this.displayTimezone());\r\n when.textContent = `${date} ${time}`;\r\n this.markerTip.replaceChildren(title, line, when);\r\n this.markerTip.hidden = false;\r\n // Beside the pointer, kept inside the chart.\r\n const box = this.chartContainer.getBoundingClientRect();\r\n const left = Math.min(hover.x + 12, Math.max(0, box.width - this.markerTip.offsetWidth - 4));\r\n const top = Math.max(0, hover.y - this.markerTip.offsetHeight - 10);\r\n this.markerTip.style.left = `${left}px`;\r\n this.markerTip.style.top = `${top}px`;\r\n }\r\n\r\n /** A typed interval: one on offer is picked; another joins the menu (not the toolbar's pins). */\r\n private selectTypedTimeframe(tf: TimeFrame): boolean {\r\n if (!this.chart.isTimeframeAllowed(tf)) return false;\r\n if (this.adapter && !servesTimeframe(this.adapter, tf)) return false;\r\n if (!this.timeframes.includes(tf)) {\r\n this.customTimeframes.add(tf);\r\n this.timeframes = withExtraTimeframes(this.timeframes, [tf]);\r\n this.toolbar?.setTimeframes(this.timeframeMenu(), this.pinnedTimeframes());\r\n }\r\n this.handleTimeframe(tf);\r\n return true;\r\n }\r\n\r\n /** Put a template's indicators in place of the chart's (one undo step). */\r\n private applyIndicatorTemplate(name: string): void {\r\n const template = this.templates.get(name);\r\n if (!template) return;\r\n this.chart.applyIndicatorSetup(template.indicators);\r\n this.syncIndicatorsFromChart();\r\n this.updateUI();\r\n this.toast(fill(this.t('templates.applied'), { name: template.name }));\r\n }\r\n\r\n /** Save the chart's indicators as a template, asking for its name. */\r\n private promptSaveIndicatorTemplate(): void {\r\n if (this.chart.getActiveIndicators().length === 0) {\r\n this.toast(this.t('templates.nothing'), 'error');\r\n return;\r\n }\r\n this.templatePrompt ??= new WidgetNamePrompt(this.root, this.t);\r\n this.templatePrompt.open({\r\n title: this.t('templates.saveTitle'),\r\n submitLabel: this.t('common.save'),\r\n placeholder: this.t('templates.namePlaceholder'),\r\n onSubmit: (name) => {\r\n try {\r\n this.templates.save(name, this.chart.getIndicatorSetup());\r\n } catch (err) {\r\n this.toast(this.t('templates.saveFailed'), 'error');\r\n throw err;\r\n }\r\n this.toolbar?.setIndicatorTemplates(this.templates.list().map((t) => t.name));\r\n this.toast(fill(this.t('templates.saved'), { name }));\r\n },\r\n });\r\n }\r\n\r\n private handleRemoveTimeframe(tf: TimeFrame): void {\r\n if (!this.customTimeframes.has(tf)) return;\r\n this.customTimeframes.remove(tf);\r\n this.timeframeFavorites.remove(tf);\r\n this.timeframes = this.timeframes.filter((t) => t !== tf);\r\n this.toolbar?.setTimeframes(this.timeframeMenu(), this.pinnedTimeframes());\r\n this.updateUI();\r\n }\r\n\r\n private handleToggleTimeframeFavorite(tf: TimeFrame): void {\r\n this.timeframeFavorites.toggle(tf);\r\n this.toolbar?.setTimeframeFavorites(this.pinnedTimeframes());\r\n this.updateUI();\r\n }\r\n\r\n /**\r\n * Load the widget's base series. Prefer this over `getChart().setData()` so\r\n * client-side timeframe resampling has a finest-resolution source to\r\n * aggregate from. The data is rendered at the current timeframe (resampled\r\n * when that timeframe is coarser than the data's native spacing).\r\n */\r\n setData(data: DataSeries): void {\r\n this.localSeq++; // supersedes a local switch still waiting to run\r\n this.baseSeries = data;\r\n this.baseTimeframeMs = inferTimeframeMs(data);\r\n this.applyTimeframeData();\r\n // Static data is loaded the moment it's set, even an empty series. With a\r\n // live adapter the stream's own load decides (connectStream).\r\n if (!this.adapter) this.loading.end();\r\n }\r\n\r\n /**\r\n * Local timeframe switch. When it is expected to block the main thread for\r\n * several frames, veil the chart first and let that paint — otherwise the\r\n * click would look ignored until the new chart pops in.\r\n */\r\n private async switchLocalTimeframe(): Promise<void> {\r\n if (!this.baseSeries) return;\r\n const seq = ++this.localSeq;\r\n const expectSlow = this.lastLocalSwitchMs >= SLOW_LOCAL_SWITCH_MS\r\n || this.baseSeries.length >= LARGE_SERIES_BARS;\r\n try {\r\n if (expectSlow) {\r\n this.loading.begin(this.chart.getData().length > 0, true);\r\n await afterPaint();\r\n // Superseded: the newer switch or setData() ends the loading state.\r\n if (seq !== this.localSeq || this.destroyed) return;\r\n }\r\n this.applyTimeframeData();\r\n } finally {\r\n // Also on a throw (bad data, a failing custom indicator) — never leave\r\n // the veil up.\r\n if (seq === this.localSeq) this.loading.end();\r\n }\r\n }\r\n\r\n /** Render the base series at the active timeframe, resampling when coarser. */\r\n private applyTimeframeData(): void {\r\n if (!this.baseSeries) return;\r\n const started = performance.now();\r\n const targetMs = timeframeToMs(this.state.timeframe);\r\n if (this.baseTimeframeMs > 0 && targetMs > this.baseTimeframeMs) {\r\n const weekStartsOn = this.options.weekStartsOn ?? 1;\r\n this.chart.setData(resampleOHLCV(this.baseSeries, this.state.timeframe, { weekStartsOn }));\r\n } else {\r\n this.chart.setData(this.baseSeries);\r\n }\r\n this.lastLocalSwitchMs = performance.now() - started;\r\n }\r\n\r\n private handleDataUpdate(payload: unknown): void {\r\n if (!payload || typeof payload !== 'object') return;\r\n const p = payload as { length?: number; error?: string; connection?: { state?: string } };\r\n if (typeof p.length === 'number') {\r\n if (p.length > 0 && this.loading.isActive()) {\r\n this.loading.end();\r\n // A retry after a failed load just delivered history.\r\n if (this.state.connectionState === 'error') this.setConnectionState('connected', this.t('status.live'));\r\n }\r\n return;\r\n }\r\n if (p.error !== undefined) {\r\n // Only a failed *load* is reported from the error itself. Errors outside\r\n // one can be transient (a single failed poll on a healthy connection);\r\n // the status bar follows the stream's connection state below instead.\r\n if (this.loading.isActive()) {\r\n this.loading.fail(this.t('status.connectionFailed'));\r\n this.setConnectionState('error', p.error || this.t('status.connectionFailed'));\r\n }\r\n return;\r\n }\r\n switch (p.connection?.state) {\r\n case 'connected':\r\n // A retry that brought back an empty history ends a failed load too.\r\n if (this.loading.hasFailed()) this.loading.end();\r\n if (!this.loading.isActive() && this.state.connectionState !== 'connected') {\r\n this.setConnectionState('connected', this.t('status.live'));\r\n }\r\n break;\r\n case 'reconnecting':\r\n if (!this.loading.isActive()) this.setConnectionState('connecting', this.t('status.connecting'));\r\n break;\r\n case 'error':\r\n if (!this.loading.isActive()) this.setConnectionState('error', this.t('status.connectionFailed'));\r\n break;\r\n }\r\n }\r\n\r\n private setConnectionState(connectionState: WidgetState['connectionState'], connectionMessage: string): void {\r\n this.state = { ...this.state, connectionState, connectionMessage };\r\n this.updateUI();\r\n }\r\n\r\n private toggleAlerts(): void {\r\n if (!this.alertsPanel) return;\r\n this.alertsPanel.toggle();\r\n if (this.alertsPanel.isOpen()) this.refreshAlerts();\r\n }\r\n\r\n private handleToggleFavorite(tool: DrawingToolType): void {\r\n const pinned = this.favoritesStore.toggle(tool);\r\n this.sidebar?.setFavorites(this.favoritesStore.list());\r\n this.toast(pinned ? this.t('toast.pinned') : this.t('toast.unpinned'));\r\n }\r\n\r\n /** Encode the current view (symbol, timeframe, chart type, scale, indicators, drawings). */\r\n exportState(): string {\r\n const indicators = this.chart.getActiveIndicators().map((i) => ({\r\n id: i.id,\r\n params: i.params as Record<string, number | string | boolean>,\r\n }));\r\n return encodeWidgetState({\r\n v: 1,\r\n symbol: this.state.symbol,\r\n timeframe: this.state.timeframe,\r\n chartType: this.state.chartType,\r\n scaleMode: this.chart.getScaleMode(),\r\n indicators,\r\n drawings: this.chart.getDrawings(),\r\n });\r\n }\r\n\r\n /** Restore a view from an `exportState()` string. Returns false if malformed. */\r\n async importState(encoded: string): Promise<boolean> {\r\n const s = decodeWidgetState(encoded);\r\n if (!s) return false;\r\n\r\n // Symbol/timeframe first so any stream/layout restore happens before we\r\n // overlay the shared view on top.\r\n if (s.symbol && s.symbol !== this.state.symbol) await this.setSymbol(s.symbol);\r\n if (s.timeframe && s.timeframe !== this.state.timeframe) await this.setTimeframe(s.timeframe);\r\n\r\n if (s.chartType) this.applyChartType(s.chartType);\r\n this.chart.setScaleMode(s.scaleMode);\r\n\r\n // The shared indicators in place of the chart's, as one undo step.\r\n this.chart.applyIndicatorSetup(s.indicators.map((ind, i) => ({ id: ind.id, instanceId: `shared_${i}`, params: ind.params })));\r\n this.chart.setDrawings(s.drawings);\r\n this.updateUI();\r\n return true;\r\n }\r\n\r\n /** Copy the chart image to the clipboard, with a toast on success/failure. */\r\n async copyChartImage(): Promise<void> {\r\n const ok = await this.chart.copyScreenshot();\r\n this.toast(ok ? this.t('toast.imageCopied') : this.t('toast.imageCopyFailed'), ok ? 'info' : 'error');\r\n }\r\n\r\n /** Copy a shareable deep-link (current view encoded in the URL hash) to the clipboard. */\r\n async copyShareLink(): Promise<void> {\r\n const base = typeof location !== 'undefined' ? location.href : '';\r\n const url = buildShareUrl(base, this.exportState());\r\n try {\r\n await navigator.clipboard.writeText(url);\r\n this.toast(this.t('toast.linkCopied'));\r\n } catch {\r\n this.toast(this.t('toast.copyFailed'), 'error');\r\n }\r\n }\r\n\r\n /** Feed order-book depth to the chart overlay, depth ladder, and heatmap. */\r\n setDepth(depth: DepthData | null): void {\r\n this.chart.setDepthData(depth);\r\n this.depthLadder?.setData(depth);\r\n if (depth) this.chart.pushDepthSnapshot(depth);\r\n }\r\n\r\n /** Begin a draggable bracket order at the latest price and show the action bar. */\r\n startBracket(side: 'buy' | 'sell'): void {\r\n if (this.chart.startBracket(side)) {\r\n this.bracketBar?.show(side);\r\n }\r\n }\r\n\r\n private buildDataWindowModel(): DataWindowModel {\r\n const data = this.chart.getData();\r\n const idx = this.lastHoverIndex;\r\n if (idx === null || idx < 0 || idx >= data.length) {\r\n return { ohlc: null, change: 0, changePct: 0, indicators: [] };\r\n }\r\n const bar = data[idx];\r\n const prevClose = idx > 0 ? data[idx - 1].close : bar.open;\r\n const change = bar.close - prevClose;\r\n const changePct = prevClose !== 0 ? (change / prevClose) * 100 : 0;\r\n\r\n const indicators = this.chart.getActiveIndicators().map((ind) => {\r\n const series = this.chart.getIndicatorOutput(ind.instanceId)?.series;\r\n const point = series?.[idx] ?? null;\r\n // The drawn lines by their titles (\"Signal\"), else every field by its key.\r\n const fields = ind.descriptor.plots?.map((p) => [p.key, p.title] as const)\r\n ?? Object.keys(point ?? {}).map((k) => [k, k] as const);\r\n const values = point\r\n ? fields\r\n .filter(([key]) => typeof point[key] === 'number' && Number.isFinite(point[key]))\r\n .map(([key, title]) => ({ key: title, value: point[key] as number }))\r\n : [];\r\n return { name: ind.descriptor.name, values };\r\n }).filter((i) => i.values.length > 0);\r\n\r\n return {\r\n ohlc: { open: bar.open, high: bar.high, low: bar.low, close: bar.close, volume: bar.volume },\r\n change,\r\n changePct,\r\n indicators,\r\n };\r\n }\r\n\r\n private toggleDataWindow(): void {\r\n if (!this.dataWindow) return;\r\n this.dataWindow.toggle();\r\n if (this.dataWindow.isOpen()) this.dataWindow.render(this.buildDataWindowModel());\r\n }\r\n\r\n private toggleObjects(): void {\r\n if (!this.objectTree) return;\r\n this.objectTree.toggle();\r\n if (this.objectTree.isOpen()) this.refreshObjects();\r\n }\r\n\r\n private openIndicatorSettings(instanceId: string): void {\r\n if (!this.indicatorSettings) return;\r\n const active = this.chart.getActiveIndicators();\r\n const ind = active.find((i) => i.instanceId === instanceId);\r\n if (!ind) return;\r\n const style = this.chart.getIndicatorStyle(instanceId);\r\n const pane = ind.descriptor.placement === 'panel' || !!ind.pane;\r\n this.indicatorSettings.open({\r\n instanceId,\r\n name: ind.descriptor.name,\r\n defaults: ind.descriptor.defaultConfig,\r\n params: ind.params,\r\n inputs: ind.descriptor.inputs,\r\n lineSources: lineSourcesFor(instanceId, active),\r\n plots: ind.descriptor.plots,\r\n colors: style?.colors,\r\n lineWidth: style?.lineWidths[0],\r\n // Levels belong to pane indicators.\r\n levels: pane ? this.chart.getIndicatorLevels(instanceId) : undefined,\r\n defaultLevels: ind.descriptor.levels,\r\n scale: pane ? undefined : this.chart.getIndicatorScale(instanceId),\r\n });\r\n }\r\n\r\n private refreshObjects(): void {\r\n if (!this.objectTree) return;\r\n const indicators = this.chart.getActiveIndicators().map((i) => ({\r\n instanceId: i.instanceId,\r\n name: i.descriptor.name,\r\n visible: i.visible,\r\n }));\r\n const drawings = this.chart.getDrawings().map((d) => ({\r\n id: d.id,\r\n label: drawingTypeLabel(d.type, this.t),\r\n visible: d.visible,\r\n locked: d.locked,\r\n group: d.group,\r\n }));\r\n const compares = this.compares.map((c) => ({ id: c.id, label: c.symbol, color: c.color }));\r\n this.objectTree.setObjects(indicators, drawings, compares);\r\n }\r\n\r\n private async handleAddCompare(): Promise<void> {\r\n if (!this.adapter) {\r\n this.toast(this.t('toast.compareNeedsAdapter'), 'error');\r\n return;\r\n }\r\n const taken = new Set([this.state.symbol, ...this.compares.map((c) => c.symbol)]);\r\n const options = this.symbols.filter((s) => !taken.has(s));\r\n this.symbolSearch?.open(options.length ? options : this.symbols, this.state.symbol, (symbol) => {\r\n this.pickCompareWay(symbol);\r\n }, this.symbolSearchFn());\r\n }\r\n\r\n /** How to compare with `symbol`: a menu by the chart's top left. */\r\n private pickCompareWay(symbol: string): void {\r\n const main = this.state.symbol;\r\n const entries = [\r\n { id: 'percent', label: this.t('compare.percent') },\r\n { id: 'scale', label: this.t('compare.ownScale') },\r\n { id: 'pane', label: this.t('compare.ownPane') },\r\n { id: 'spread', label: fill(this.t('compare.spread'), { main, other: symbol }) },\r\n { id: 'ratio', label: fill(this.t('compare.ratio'), { main, other: symbol }) },\r\n ];\r\n const rect = this.chart.getPlotRect();\r\n this.chartMenu?.open(entries, rect.x + 24, rect.y + 24, (way) => void this.addCompareSymbol(symbol, way as CompareWay));\r\n }\r\n\r\n /**\r\n * Compare with another symbol: its percent change on the price scale\r\n * (`'percent'`, the default), its price on a scale of its own (`'scale'`)\r\n * or in a pane of its own (`'pane'`), or the spread or ratio of this\r\n * symbol to it (`'spread'`, `'ratio'`). Its bars come through the adapter.\r\n */\r\n async addCompareSymbol(symbol: string, way: CompareWay = 'percent'): Promise<void> {\r\n if (!this.adapter) {\r\n this.toast(this.t('toast.compareNeedsAdapter'), 'error');\r\n return;\r\n }\r\n if (way !== 'percent') {\r\n const id = way === 'scale' ? this.chart.addIndicator('compareSymbol', { symbol }, 'bottom', { scale: 'left' })\r\n : way === 'pane' ? this.chart.addIndicator('compareSymbol', { symbol })\r\n : this.chart.addIndicator('spread', { symbol, mode: way });\r\n if (id && way === 'pane') this.chart.moveIndicatorToPane(id, 'new');\r\n return;\r\n }\r\n if (this.compares.some((c) => c.symbol === symbol)) return;\r\n const color = COMPARE_COLORS[this.compares.length % COMPARE_COLORS.length];\r\n const id = `cmp_${symbol}`;\r\n try {\r\n const bars = await withResampling(this.adapter).fetchHistory(symbol, this.state.timeframe, this.options.historyLimit ?? 500);\r\n // Percent mode normalizes mixed-price symbols (e.g. BTC vs a $2 alt) onto\r\n // a shared % axis — the right default for comparison.\r\n if (this.compares.length === 0) this.chart.setCompareMode('percent');\r\n this.chart.addCompareSymbol(id, symbol, bars, color);\r\n this.compares = [...this.compares, { id, symbol, color }];\r\n this.refreshObjects();\r\n this.toast(fill(this.t('toast.comparing'), { symbol }));\r\n } catch (err: unknown) {\r\n this.toast(`${symbol}: ${err instanceof Error ? err.message : this.t('toast.loadFailed')}`, 'error');\r\n }\r\n }\r\n\r\n private handleRemoveCompare(id: string): void {\r\n this.chart.removeCompareSymbol(id);\r\n this.compares = this.compares.filter((c) => c.id !== id);\r\n this.refreshObjects();\r\n }\r\n\r\n /**\r\n * Bars of a symbol the chart's indicators read (a compare on its own\r\n * scale, a spread), at the chart's interval. A later interval wins.\r\n */\r\n private async loadSymbolSeries(symbol: string): Promise<void> {\r\n if (!this.adapter) {\r\n this.toast(this.t('toast.compareNeedsAdapter'), 'error');\r\n return;\r\n }\r\n const timeframe = this.state.timeframe;\r\n const seq = (this.symbolLoads.get(symbol) ?? 0) + 1;\r\n this.symbolLoads.set(symbol, seq);\r\n // Only the latest fetch of a symbol, at the interval on screen, answers.\r\n const stale = () => this.destroyed || timeframe !== this.state.timeframe || this.symbolLoads.get(symbol) !== seq;\r\n try {\r\n const limit = Math.max(this.chart.getData().length, this.options.historyLimit ?? 500);\r\n const bars = await withResampling(this.adapter).fetchHistory(symbol, timeframe, limit);\r\n if (stale()) return;\r\n this.chart.setSymbolSeries(symbol, bars);\r\n } catch (err: unknown) {\r\n if (stale()) return;\r\n // Keep what the chart had; an indicator on the symbol may ask again.\r\n this.chart.setSymbolSeries(symbol, this.chart.getSymbolSeries(symbol));\r\n this.toast(`${symbol}: ${err instanceof Error ? err.message : this.t('toast.loadFailed')}`, 'error');\r\n }\r\n }\r\n\r\n /** Refetch every comparison overlay at the current symbol/timeframe. */\r\n private async refetchCompares(): Promise<void> {\r\n // The symbols indicators read, at the new interval.\r\n for (const symbol of this.chart.getRequiredSymbols?.() ?? []) void this.loadSymbolSeries(symbol);\r\n if (!this.adapter || this.compares.length === 0) return;\r\n // A comparison against the now-active symbol is redundant — drop it.\r\n const stale = this.compares.filter((c) => c.symbol === this.state.symbol);\r\n for (const c of stale) this.handleRemoveCompare(c.id);\r\n\r\n for (const c of this.compares) {\r\n try {\r\n const bars = await withResampling(this.adapter).fetchHistory(c.symbol, this.state.timeframe, this.options.historyLimit ?? 500);\r\n this.chart.updateCompareData(c.id, bars);\r\n } catch { /* leave the stale overlay in place if the refetch fails */ }\r\n }\r\n }\r\n\r\n private refreshAlerts(): void {\r\n if (!this.alertsPanel) return;\r\n const sources = this.buildAlertSources();\r\n this.alertsPanel.setSources(sources);\r\n this.alertsPanel.setAlerts(this.chart.getAlerts().map((a) => this.alertListItem(a, sources)));\r\n }\r\n\r\n private alertListItem(a: AlertListItem, sources: readonly AlertSource[]): AlertListItem {\r\n return {\r\n id: a.id,\r\n price: a.price,\r\n condition: a.condition,\r\n message: a.message,\r\n triggered: a.triggered,\r\n channel: a.channel,\r\n label: a.label,\r\n drawingId: a.drawingId,\r\n target: a.target,\r\n targetLabel: a.target ? sources.find((s) => s.channel === a.target)?.label : undefined,\r\n percent: a.percent,\r\n bars: a.bars,\r\n onBarClose: a.onBarClose,\r\n expiresAt: a.expiresAt,\r\n expired: a.expired,\r\n };\r\n }\r\n\r\n /** An alert in words, for a toast or a notification: \"Price crossing EMA 20\", \"RSI greater than 70\". */\r\n private alertText(p: AlertListItem): string {\r\n return describeAlert(this.alertListItem(p, this.buildAlertSources()), this.t, (price) => this.formatAlertPrice(price), true);\r\n }\r\n\r\n /** Price + every active indicator line, as selectable alert sources. */\r\n private buildAlertSources(): { channel: string; label: string }[] {\r\n const sources = [{ channel: 'price', label: this.t('alerts.source.price') }];\r\n for (const ind of this.chart.getActiveIndicators()) {\r\n // Use the latest point — multi-output indicators (MACD, Stochastic) only\r\n // have all their lines populated once warmed up; the first point may not.\r\n const series = this.chart.getIndicatorOutput(ind.instanceId)?.series;\r\n const point = series && series.length > 0 ? series[series.length - 1] : null;\r\n const keys = point ? Object.keys(point).filter((k) => typeof point[k] === 'number') : [];\r\n for (const key of keys) {\r\n const label = keys.length > 1 ? `${ind.descriptor.name} ${key}` : ind.descriptor.name;\r\n sources.push({ channel: `${ind.instanceId}:${key}`, label });\r\n }\r\n }\r\n return sources;\r\n }\r\n\r\n /** Latest value for an alert source channel (price or indicator line). */\r\n private getAlertChannelValue(channel: string): number | null {\r\n const data = this.chart.getData();\r\n if (channel === 'price') return data.length > 0 ? data[data.length - 1].close : null;\r\n const sep = channel.indexOf(':');\r\n if (sep < 0 || data.length === 0) return null;\r\n const instanceId = channel.slice(0, sep);\r\n const key = channel.slice(sep + 1);\r\n const v = this.chart.getIndicatorOutput(instanceId)?.series?.[data.length - 1]?.[key];\r\n return typeof v === 'number' && Number.isFinite(v) ? v : null;\r\n }\r\n\r\n private formatAlertPrice(price: number): string {\r\n // The chart's own price format (fractions, a host's function) wins.\r\n const custom = this.chart.getPriceFormatter?.();\r\n if (custom) return custom(price);\r\n // No fixed precision config on the widget — pick digits from magnitude so\r\n // BTC (64,200.5) and a sub-dollar alt (0.04821) both read sensibly.\r\n const abs = Math.abs(price);\r\n const digits = abs >= 1000 ? 2 : abs >= 1 ? 4 : 6;\r\n const locale = this.settingsState.numberLocale || undefined;\r\n return price.toLocaleString(locale, { minimumFractionDigits: 2, maximumFractionDigits: digits });\r\n }\r\n\r\n /** The user picked a chart type: applied, and undoable. */\r\n private handleChartType(type: ChartType): void {\r\n const before = this.state.chartType;\r\n if (type === before) return;\r\n this.applyChartType(type);\r\n this.chart.recordUndo({ subject: 'chartType', undo: () => this.applyChartType(before), redo: () => this.applyChartType(type) });\r\n }\r\n\r\n private applyChartType(type: ChartType): void {\r\n this.state = { ...this.state, chartType: type };\r\n this.chart.setChartType(type);\r\n this.updateUI();\r\n }\r\n\r\n /**\r\n * Add another instance — picking EMA twice gives two EMAs (e.g. 20 and 50\r\n * once their settings are changed). Remove one from its chip.\r\n */\r\n private handleAddIndicator(indId: string): void {\r\n this.chart.addIndicator(indId); // the chip strip follows the indicatorAdd event\r\n }\r\n\r\n private handleRemoveIndicator(instanceId: string): void {\r\n this.chart.removeIndicator(instanceId);\r\n }\r\n\r\n private toggleCommandPalette(): void {\r\n if (this.commandPalette?.isOpen()) {\r\n this.commandPalette.close();\r\n return;\r\n }\r\n this.commandPalette?.open(this.buildCommandItems());\r\n }\r\n\r\n private buildCommandItems(): CommandItem[] {\r\n const items: CommandItem[] = [];\r\n\r\n for (const ind of INDICATORS) {\r\n items.push({\r\n id: ind.id,\r\n label: ind.name,\r\n category: 'indicator',\r\n active: [...this.state.activeIndicators.values()].some((a) => a.id === ind.id),\r\n });\r\n }\r\n\r\n for (const ct of CHART_TYPES) {\r\n items.push({\r\n id: ct.value,\r\n label: chartTypeLabel(ct, this.t),\r\n category: 'chartType',\r\n active: this.state.chartType === ct.value,\r\n });\r\n }\r\n\r\n for (const group of localizeToolGroups(DRAWING_TOOL_GROUPS, this.t)) {\r\n for (const tool of group.tools) {\r\n items.push({\r\n id: tool.value,\r\n label: tool.label,\r\n category: 'drawing',\r\n active: this.state.activeTool === tool.value,\r\n });\r\n }\r\n }\r\n\r\n for (const tf of this.timeframes) {\r\n items.push({\r\n id: tf,\r\n label: timeframeLabel(tf),\r\n category: 'timeframe',\r\n active: this.state.timeframe === tf,\r\n });\r\n }\r\n\r\n items.push(\r\n { id: 'screenshot', label: this.t('action.screenshot'), category: 'action', shortcut: '' },\r\n { id: 'copyImage', label: this.t('action.copyImage'), category: 'action' },\r\n { id: 'toggleTheme', label: this.t('action.toggleTheme'), category: 'action' },\r\n { id: 'settings', label: this.t('action.settings'), category: 'action' },\r\n { id: 'shareView', label: this.t('action.shareView'), category: 'action' },\r\n { id: 'autoFib', label: this.t('action.autoFib'), category: 'action' },\r\n { id: 'dataWindow', label: this.t('action.dataWindow'), category: 'action' },\r\n ...(this.symbolInfoPanel ? [{ id: 'symbolInfo', label: this.t('action.symbolInfo'), category: 'action' as const }] : []),\r\n { id: 'clearDrawings', label: this.t('action.clearDrawings'), category: 'action' },\r\n );\r\n\r\n return items;\r\n }\r\n\r\n private handleAction(id: string): void {\r\n switch (id) {\r\n case 'screenshot':\r\n this.chart.screenshot();\r\n break;\r\n case 'toggleTheme':\r\n this.handleToggleTheme();\r\n break;\r\n case 'settings':\r\n this.openSettings();\r\n break;\r\n case 'copyImage':\r\n void this.copyChartImage();\r\n break;\r\n case 'shareView':\r\n void this.copyShareLink();\r\n break;\r\n case 'autoFib': {\r\n const id = this.chart.autoFib();\r\n this.toast(id ? this.t('toast.autoFibAdded') : this.t('toast.noSwing'));\r\n break;\r\n }\r\n case 'dataWindow':\r\n this.toggleDataWindow();\r\n break;\r\n case 'symbolInfo':\r\n this.toggleSymbolInfo();\r\n break;\r\n case 'clearDrawings':\r\n this.chart.clearDrawings();\r\n this.state = { ...this.state, activeTool: null };\r\n this.updateUI();\r\n break;\r\n }\r\n }\r\n\r\n private handleDrawingTool(tool: DrawingToolType): void {\r\n this.state = { ...this.state, activeTool: tool };\r\n this.chart.setDrawingTool(tool);\r\n this.updateUI();\r\n }\r\n\r\n /** The cursor button: no tool, no eraser, no zoom box. */\r\n private handleCancelDrawing(): void {\r\n this.state = { ...this.state, activeTool: null };\r\n this.chart.setDrawingTool(null);\r\n this.chart.setEraserMode(false);\r\n this.chart.setZoomAreaMode(false);\r\n this.updateUI();\r\n }\r\n\r\n private handleToggleStayInDrawing(): void {\r\n const stayInDrawing = !this.state.stayInDrawing;\r\n this.state = { ...this.state, stayInDrawing };\r\n this.chart.setStayInDrawingMode(stayInDrawing);\r\n this.updateUI();\r\n }\r\n\r\n /** The magnet button goes off → weak → strong → off. */\r\n private handleToggleMagnet(): void {\r\n const mode = !this.state.magnetEnabled ? 'weak' : this.state.magnetStrong ? 'off' : 'strong';\r\n this.state = { ...this.state, magnetEnabled: mode !== 'off', magnetStrong: mode === 'strong' };\r\n this.chart.setDrawingMagnetMode(mode);\r\n this.updateUI();\r\n }\r\n\r\n private handleToggleTheme(): void {\r\n const isDark = !this.state.isDark;\r\n this.state = { ...this.state, isDark };\r\n this.root.dataset.tcwTheme = isDark ? 'dark' : 'light';\r\n this.portal.dataset.tcwTheme = this.root.dataset.tcwTheme;\r\n this.chart.setTheme(isDark ? DARK_THEME : LIGHT_THEME);\r\n this.chart.setWatermark(this.state.symbol.replace('USDT', ' / USDT'), {\r\n fontSize: 48,\r\n color: isDark ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.03)',\r\n });\r\n this.updateUI();\r\n }\r\n\r\n private openSettings(): void {\r\n // The chart's own settings of its type (a layout may have brought them).\r\n this.settingsState = { ...this.settingsState, chartTypeOptions: this.chart.getChartTypeOptions?.() ?? {} };\r\n this.settings?.open(this.settingsState, this.state.chartType);\r\n }\r\n\r\n // --- Toast ---\r\n\r\n /**\r\n * Show a transient toast inside the widget. Auto-dismisses after 3.5s.\r\n * Used by the drag-drop importer for success / failure feedback, but\r\n * exposed so apps can post their own (e.g. \"alert triggered at 64,200\").\r\n */\r\n toast(message: string, kind: 'info' | 'error' = 'info'): void {\r\n const el = document.createElement('div');\r\n el.className = `tcw-toast ${kind === 'error' ? 'tcw-toast-error' : ''}`;\r\n el.textContent = message;\r\n this.root.appendChild(el);\r\n // Trigger CSS transition on next frame\r\n requestAnimationFrame(() => el.classList.add('tcw-toast-in'));\r\n setTimeout(() => {\r\n el.classList.remove('tcw-toast-in');\r\n el.addEventListener('transitionend', () => el.remove(), { once: true });\r\n // Hard timeout in case transitionend doesn't fire (display:none, etc.)\r\n setTimeout(() => el.remove(), 400);\r\n }, 3500);\r\n }\r\n\r\n // --- Named layouts ---\r\n\r\n /** Named layouts: save, open, rename, delete, auto-save. `null` with `layouts: false`. */\r\n getLayoutSession(): LayoutSession | null {\r\n return this.layoutSession;\r\n }\r\n\r\n /** The symbol showing. */\r\n getSymbol(): string {\r\n return this.state.symbol;\r\n }\r\n\r\n /** The interval showing. */\r\n getTimeframe(): TimeFrame {\r\n return this.state.timeframe;\r\n }\r\n\r\n /** This chart as a layout: symbol, interval, scale and the chart's state (no theme). A copy, free to keep. */\r\n captureLayout(): WidgetLayoutContent {\r\n const json = this.chart.saveState();\r\n const state = json ? parseLayoutJson(json) : null;\r\n // The theme stays the viewer's; the time of the capture would make every capture differ.\r\n const chart = state && typeof state === 'object' ? layoutChartState(state as Record<string, unknown>) : null;\r\n return {\r\n v: 1,\r\n symbol: this.state.symbol,\r\n timeframe: this.state.timeframe,\r\n scaleMode: this.settingsState.scaleMode,\r\n invertScale: this.settingsState.invertScale,\r\n chart,\r\n };\r\n }\r\n\r\n /** Show a layout from `captureLayout()`. */\r\n async restoreLayout(content: WidgetLayoutContent): Promise<void> {\r\n if (content.symbol !== this.state.symbol) await this.setSymbol(content.symbol);\r\n if (content.timeframe !== this.state.timeframe) await this.setTimeframe(content.timeframe);\r\n if (this.destroyed) return;\r\n if (content.chart) {\r\n this.chart.loadState(JSON.stringify(layoutChartState(content.chart)));\r\n const type = content.chart.chartType;\r\n if (typeof type === 'string') this.state = { ...this.state, chartType: type as ChartType };\r\n }\r\n this.applySettings({ scaleMode: content.scaleMode, invertScale: content.invertScale });\r\n this.syncIndicatorsFromChart();\r\n this.updateUI();\r\n }\r\n\r\n /** `captureLayout()` as JSON. */\r\n getLayoutContent(): string {\r\n return JSON.stringify(this.captureLayout());\r\n }\r\n\r\n /** Show a layout from `getLayoutContent()`; `false` when it is not one. */\r\n async applyLayoutContent(content: string): Promise<boolean> {\r\n const layout = readWidgetLayout(parseLayoutJson(content));\r\n if (!layout) return false;\r\n await this.restoreLayout(layout);\r\n return true;\r\n }\r\n\r\n private setupLayouts(cfg: import('./types.js').WidgetLayoutsOptions): void {\r\n const session = new LayoutSession(cfg.storage ?? localStorageLayouts(), {\r\n capture: () => ({ content: this.getLayoutContent(), symbol: this.state.symbol, timeframe: this.state.timeframe }),\r\n apply: async (layout: SavedLayout) => {\r\n if (!(await this.applyLayoutContent(layout.content))) throw new Error('Not a widget layout');\r\n },\r\n }, {\r\n autoSave: cfg.autoSave,\r\n debounceMs: cfg.debounceMs,\r\n onChange: () => this.toolbar?.setLayout(session.current()?.name ?? null, session.isDirty()),\r\n onError: () => this.toast(this.t('layouts.saveFailed'), 'error'),\r\n });\r\n this.layoutSession = session;\r\n this.layoutsUI = new WidgetLayoutsUI(session, {\r\n root: this.root,\r\n t: this.t,\r\n toast: (message, kind) => this.toast(message, kind),\r\n formatTime: (ms) => {\r\n const { date, time } = utcToWallTime(ms, this.displayTimezone());\r\n return `${date} ${time}`;\r\n },\r\n });\r\n this.chart.on('stateChange', () => session.changed());\r\n if (cfg.openLast) {\r\n void session.list().then(([last]) => (last && !this.destroyed ? this.openLayout(last.id) : undefined), () => undefined);\r\n }\r\n }\r\n\r\n /** Save into the open layout, or ask for a name when there is none. */\r\n async saveLayout(): Promise<void> {\r\n await this.layoutsUI?.save();\r\n }\r\n\r\n /** Open a saved layout by id; `false` when it could not be. */\r\n async openLayout(id: string): Promise<boolean> {\r\n return (await this.layoutsUI?.open(id)) ?? false;\r\n }\r\n\r\n // --- Layout persistence ---\r\n\r\n /**\r\n * Wipe the layout saved for `symbol` (or the active symbol if omitted).\r\n * Useful as an \"Reset layout\" command in user-facing menus.\r\n */\r\n clearSavedLayout(symbol?: string): void {\r\n if (!this.layoutKeyPrefix) return;\r\n const target = symbol ?? this.state.symbol;\r\n try {\r\n localStorage.removeItem(this.layoutKeyPrefix + target);\r\n } catch { /* localStorage may be unavailable (private mode, SSR, etc.) */ }\r\n }\r\n\r\n private applySymbolLayout(symbol: string): void {\r\n if (!this.layoutKeyPrefix) return;\r\n const key = this.layoutKeyPrefix + symbol;\r\n this.activeLayoutKey = key;\r\n\r\n try {\r\n // Best-effort load. If parsing or any restore step throws, we silently\r\n // fall back to a fresh layout — a corrupted layout shouldn't break the\r\n // chart.\r\n const ok = this.chart.loadStateFromStorage(key);\r\n if (ok) this.syncIndicatorsFromChart();\r\n } catch { /* swallow — layout will be rebuilt from user actions */ }\r\n\r\n // Wire chart-level auto-save so any further drawing/indicator change\r\n // flushes itself into this symbol's slot.\r\n this.chart.setAutoSave(key, this.layoutDebounceMs);\r\n }\r\n\r\n private flushActiveLayout(): void {\r\n if (!this.activeLayoutKey) return;\r\n try { this.chart.saveState(this.activeLayoutKey); } catch { /* same */ }\r\n this.chart.disableAutoSave();\r\n this.activeLayoutKey = null;\r\n }\r\n\r\n /** Rebuild the chip strip from the chart's indicator instances. */\r\n private syncIndicatorsFromChart(): void {\r\n const next = new Map<string, ActiveIndicatorInfo>();\r\n for (const a of this.chart.getActiveIndicators()) {\r\n next.set(a.instanceId, { id: a.id, label: indicatorChipLabel(a.id, a.params, a.descriptor.defaultConfig, a.descriptor.shortName) });\r\n }\r\n this.state = { ...this.state, activeIndicators: next };\r\n this.updateUI();\r\n }\r\n\r\n // --- Replay ---\r\n\r\n /** Open (or close) bar replay with its scrubber — what the toolbar's Replay button does. */\r\n toggleReplay(): void {\r\n if (this.replayBar?.isMounted()) {\r\n this.exitReplay();\r\n } else {\r\n this.enterReplay();\r\n }\r\n }\r\n\r\n /**\r\n * Open replay in \"pick a start bar\" mode: the bars right of the pointer\r\n * are shaded, and a click cuts the chart there and waits paused. Play\r\n * starts from a default point; \"random bar\" picks one.\r\n */\r\n private enterReplay(): void {\r\n if (this.replayTotal() < 2) return;\r\n\r\n const t = this.t;\r\n this.replayBar = new WidgetReplayBar(\r\n {\r\n onPlay: () => {\r\n if (this.replayBar?.getMode() === 'select') {\r\n this.startReplayAt(Math.max(1, this.replayTotal() - 100), true);\r\n return;\r\n }\r\n if (this.chart.getReplayState() === 'paused') this.chart.replayResume();\r\n this.replayBar?.setState('playing');\r\n },\r\n onPause: () => {\r\n this.chart.replayPause();\r\n this.replayBar?.setState('paused');\r\n },\r\n onStepBack: () => this.stepReplay(-1),\r\n onStepForward: () => this.stepReplay(1),\r\n onSeek: (idx) => {\r\n if (this.chart.getReplayState() === 'playing') this.chart.replayPause();\r\n this.chart.replaySeek(idx);\r\n this.replayBar?.setState('paused');\r\n },\r\n onSpeedChange: (barsPerSecond) => {\r\n this.replaySpeed = barsPerSecond;\r\n this.chart.setReplaySpeed(barsPerSecond);\r\n },\r\n onRandomStart: () => {\r\n const n = this.replayTotal();\r\n // Somewhere in the middle 80%, so there is history before and bars after.\r\n const lo = Math.max(1, Math.floor(n * 0.1));\r\n const hi = Math.max(lo, Math.floor(n * 0.9));\r\n this.startReplayAt(lo + Math.floor(Math.random() * (hi - lo + 1)));\r\n },\r\n onClose: () => this.exitReplay(),\r\n onStepChange: (step) => {\r\n this.replayStep = step;\r\n if (this.replayBar?.getMode() !== 'replay') return;\r\n // Mid-replay: start again in the new steps from the bar before the\r\n // forming one (so the rest of it isn't given away), playing if it was.\r\n const playing = this.chart.getReplayState() === 'playing';\r\n this.startReplayAt(Math.max(0, this.chart.getReplayBarIndex() - 1), playing);\r\n },\r\n },\r\n {\r\n selectHint: t('replay.selectHint'),\r\n random: t('replay.random'),\r\n realtime: t('replay.realtime'),\r\n barsPerSecond: t('replay.barsPerSecond'),\r\n play: t('replay.play'),\r\n pause: t('replay.pause'),\r\n stepBack: t('replay.stepBack'),\r\n stepForward: t('replay.stepForward'),\r\n replay: t('replay.label'),\r\n position: t('replay.position'),\r\n speed: t('replay.speed'),\r\n step: t('replay.step'),\r\n },\r\n );\r\n const steps = [\r\n { value: 'bar', label: t('replay.step.bar') },\r\n ...this.replayStepOptions().map((tf) => ({ value: tf, label: tf })),\r\n ];\r\n if (!steps.some((s) => s.value === this.replayStep)) this.replayStep = 'bar';\r\n this.replayBar.mount(this.chartContainer, { total: this.replayTotal(), speed: this.replaySpeed, mode: 'select', steps, step: this.replayStep });\r\n\r\n this.replayShade = document.createElement('div');\r\n this.replayShade.className = 'tcw-replay-shade';\r\n this.replayShade.hidden = true;\r\n this.chartContainer.appendChild(this.replayShade);\r\n this.chartContainer.addEventListener('mouseleave', this.hideReplayShade);\r\n }\r\n\r\n private readonly hideReplayShade = (): void => this.positionReplayShade(null);\r\n\r\n /**\r\n * Open replay (if it isn't open) and start it at bar `index` — paused, or\r\n * playing when `play` is set — skipping the pick-a-bar step.\r\n */\r\n replayFrom(index: number, play = false): void {\r\n if (!this.replayBar?.isMounted()) this.enterReplay();\r\n this.startReplayAt(index, play);\r\n }\r\n\r\n /** Cut the chart at `index` and wait paused (or play at once). */\r\n private startReplayAt(index: number, play = false): void {\r\n const bar = this.replayBar;\r\n if (!bar) return;\r\n const n = this.replayTotal();\r\n const start = Math.max(0, Math.min(Number.isFinite(index) ? Math.floor(index) : 0, n - 1));\r\n this.replayShade?.remove();\r\n this.replayShade = null;\r\n this.chartContainer.removeEventListener('mouseleave', this.hideReplayShade);\r\n bar.setMode('replay');\r\n // A newer start (a quicker step choice) wins over one still fetching its steps.\r\n const seq = ++this.replayStartSeq;\r\n const go = (steps: DataSeries | null) => {\r\n if (this.destroyed || this.replayBar !== bar || !bar.isMounted() || seq !== this.replayStartSeq) return;\r\n this.chart.replayStart({ speed: this.replaySpeed, interval: 1000, startIndex: start, paused: true, ...(steps ? { steps } : {}) });\r\n if (play) this.chart.replayResume();\r\n bar.setState(play ? 'playing' : 'paused');\r\n this.syncReplayBar();\r\n if (this.replayPollInterval) clearInterval(this.replayPollInterval);\r\n this.replayPollInterval = setInterval(() => this.syncReplayBar(), 150);\r\n };\r\n if (this.replayStep === 'bar') {\r\n go(null);\r\n return;\r\n }\r\n void this.replayStepsFor(this.replayStep as TimeFrame).then((steps) => {\r\n if (seq !== this.replayStartSeq) return; // a newer start took over\r\n if (!steps) this.toast(this.t('replay.stepsFailed'), 'error');\r\n go(steps);\r\n });\r\n }\r\n\r\n /** Finer intervals a replay can step through: they divide the chart's, and the feed (or the bars loaded) has them. */\r\n private replayStepOptions(): TimeFrame[] {\r\n const current = timeframeToMs(this.state.timeframe);\r\n return REPLAY_STEP_CANDIDATES.filter((tf) => {\r\n const ms = timeframeToMs(tf);\r\n if (!(ms < current) || current % ms !== 0) return false;\r\n if (this.adapter) return servesTimeframe(this.adapter, tf);\r\n return this.baseSeries !== null && this.baseTimeframeMs > 0 && ms >= this.baseTimeframeMs && ms % this.baseTimeframeMs === 0;\r\n });\r\n }\r\n\r\n /** The finer bars for a replay in `tf` steps: from the feed, or built from the bars loaded. Null when there are none. */\r\n private async replayStepsFor(tf: TimeFrame): Promise<DataSeries | null> {\r\n const key = `${this.state.symbol}|${this.state.timeframe}|${tf}`;\r\n if (this.replayStepsCache?.key === key) return this.replayStepsCache.steps;\r\n let steps: DataSeries | null = null;\r\n if (this.adapter) {\r\n const ratio = Math.max(1, Math.round(timeframeToMs(this.state.timeframe) / timeframeToMs(tf)));\r\n const limit = Math.min(MAX_REPLAY_STEPS, Math.max(this.chart.getData().length, 100) * ratio);\r\n try {\r\n steps = await withResampling(this.adapter).fetchHistory(this.state.symbol, tf, limit);\r\n } catch {\r\n steps = null;\r\n }\r\n } else if (this.baseSeries) {\r\n steps = timeframeToMs(tf) === this.baseTimeframeMs ? this.baseSeries : resampleOHLCV(this.baseSeries, tf);\r\n }\r\n if (!steps || steps.length === 0) return null;\r\n this.replayStepsCache = { key, steps };\r\n return steps;\r\n }\r\n\r\n /** Bars available to replay: the whole series, not the slice on screen. */\r\n private replayTotal(): number {\r\n return this.chart.isReplayActive() ? this.chart.getReplayProgress().total : this.chart.getData().length;\r\n }\r\n\r\n /** Mirror the replay engine in the bar; close it if the session ended elsewhere. */\r\n private syncReplayBar(): void {\r\n const bar = this.replayBar;\r\n if (!bar?.isMounted() || bar.getMode() !== 'replay') return;\r\n if (!this.chart.isReplayActive()) {\r\n // e.g. a symbol or timeframe switch replaced the series.\r\n this.teardownReplayUi();\r\n return;\r\n }\r\n const p = this.chart.getReplayProgress();\r\n const state = this.chart.getReplayState();\r\n bar.setProgress(p.current, p.total);\r\n bar.setState(state === 'stopped' ? 'paused' : state);\r\n bar.setEnded(state !== 'playing' && p.total > 0 && p.current >= p.total - 1);\r\n }\r\n\r\n private stepReplay(delta: number): void {\r\n if (this.replayBar?.getMode() !== 'replay') return;\r\n const p = this.chart.getReplayProgress();\r\n if (this.chart.getReplayState() === 'playing') this.chart.replayPause();\r\n this.chart.replaySeek(Math.max(0, Math.min(p.total - 1, p.current + delta)));\r\n this.replayBar.setState('paused');\r\n this.syncReplayBar();\r\n }\r\n\r\n /** Replay shortcuts: Shift+←/→ step one bar; Escape cancels picking a start bar. */\r\n private handleReplayKey(e: KeyboardEvent): boolean {\r\n if (e.defaultPrevented) return false;\r\n const active = document.activeElement as HTMLElement | null;\r\n if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.tagName === 'SELECT' || active.isContentEditable)) {\r\n return false;\r\n }\r\n if (e.shiftKey && (e.key === 'ArrowRight' || e.key === 'ArrowLeft') && this.replayBar?.getMode() === 'replay') {\r\n e.preventDefault();\r\n // The chart's own Shift+Arrow scrolls ten bars; this one steps the replay.\r\n e.stopPropagation();\r\n this.stepReplay(e.key === 'ArrowRight' ? 1 : -1);\r\n return true;\r\n }\r\n if (e.key === 'Escape' && this.replayBar?.getMode() === 'select') {\r\n this.exitReplay();\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n private positionReplayShade(x: number | null): void {\r\n const shade = this.replayShade;\r\n if (!shade) return;\r\n const plot = this.chart.getPlotRect();\r\n if (x === null || x < plot.x || x > plot.x + plot.width) {\r\n shade.hidden = true;\r\n return;\r\n }\r\n shade.hidden = false;\r\n shade.style.left = `${x}px`;\r\n shade.style.top = `${plot.y}px`;\r\n shade.style.width = `${plot.x + plot.width - x}px`;\r\n shade.style.height = `${plot.height}px`;\r\n }\r\n\r\n /** Leave replay and return to the live series (with updates that arrived meanwhile). */\r\n private exitReplay(): void {\r\n this.teardownReplayUi();\r\n this.chart.replayStop();\r\n }\r\n\r\n private teardownReplayUi(): void {\r\n if (this.replayPollInterval) {\r\n clearInterval(this.replayPollInterval);\r\n this.replayPollInterval = null;\r\n }\r\n this.replayShade?.remove();\r\n this.replayShade = null;\r\n this.chartContainer.removeEventListener('mouseleave', this.hideReplayShade);\r\n this.replayBar?.unmount();\r\n this.replayBar = null;\r\n }\r\n\r\n private applySettings(patch: Partial<ChartSettingsState>): void {\r\n this.settingsState = { ...this.settingsState, ...patch };\r\n if (patch.scaleMode !== undefined || patch.logScale !== undefined || patch.invertScale !== undefined) this.layoutSession?.changed();\r\n this.scheduleLegend(); // the OHLCV legend's rows and the locale move or reword it\r\n\r\n if (patch.gridVisible !== undefined) this.chart.setGridVisible(patch.gridVisible);\r\n if (patch.volumeVisible !== undefined) this.chart.setVolumeVisible(patch.volumeVisible);\r\n if (patch.volumeProfileVisible !== undefined) this.chart.setVolumeProfileVisible(patch.volumeProfileVisible);\r\n if (patch.marketProfileVisible !== undefined) this.chart.setMarketProfileVisible(patch.marketProfileVisible);\r\n if (patch.marketProfileSplit !== undefined) this.chart.setMarketProfileConfig({ splitBySession: patch.marketProfileSplit });\r\n if (patch.marketProfileLetters !== undefined) this.chart.setMarketProfileConfig({ letters: patch.marketProfileLetters });\r\n if (patch.marketProfileBuckets !== undefined) this.chart.setMarketProfileConfig({ buckets: patch.marketProfileBuckets });\r\n if (patch.marketProfileOpacity !== undefined) this.chart.setMarketProfileConfig({ opacity: patch.marketProfileOpacity });\r\n if (patch.depthHeatmapVisible !== undefined) this.chart.setDepthHeatmapVisible(patch.depthHeatmapVisible);\r\n if (patch.depthHeatmapOpacity !== undefined) this.chart.setDepthHeatmapConfig({ opacity: patch.depthHeatmapOpacity });\r\n if (patch.sessionShadingVisible !== undefined) this.chart.setSessionShadingVisible(patch.sessionShadingVisible);\r\n if (patch.pivotMarkersVisible !== undefined) this.chart.setPivotMarkersVisible(patch.pivotMarkersVisible);\r\n if (patch.pivotStrength !== undefined) this.chart.setPivotMarkersConfig({ left: patch.pivotStrength, right: patch.pivotStrength });\r\n if (patch.pivotStructureLabels !== undefined) this.chart.setPivotMarkersConfig({ structureLabels: patch.pivotStructureLabels });\r\n if (patch.periodLevelsVisible !== undefined) this.chart.setPeriodLevelsVisible(patch.periodLevelsVisible);\r\n if (patch.periodLevelsPeriod !== undefined) this.chart.setPeriodLevelsPeriod(patch.periodLevelsPeriod);\r\n if (patch.legendVisible !== undefined) this.chart.setLegend({ visible: patch.legendVisible });\r\n if (patch.barCountdown !== undefined) this.chart.setBarCountdownVisible(patch.barCountdown);\r\n if (patch.indicatorValueLabels !== undefined) this.chart.setIndicatorValueLabelsVisible(patch.indicatorValueLabels);\r\n if (patch.crosshairMode !== undefined) this.chart.setCrosshairMode(patch.crosshairMode);\r\n if (patch.autoScale !== undefined) this.chart.setAutoScale(patch.autoScale);\r\n if (patch.invertScale !== undefined) this.chart.setInvertScale(patch.invertScale);\r\n if (patch.leftPriceScale !== undefined) this.chart.setLeftPriceScaleVisible(patch.leftPriceScale);\r\n if (patch.scaleMode !== undefined) {\r\n this.chart.setScaleMode(patch.scaleMode);\r\n // Keep the legacy logScale flag mirrored so persisted layouts stay valid.\r\n this.settingsState = { ...this.settingsState, logScale: patch.scaleMode === 'logarithmic' };\r\n } else if (patch.logScale !== undefined) {\r\n this.chart.setLogScale(patch.logScale);\r\n this.settingsState = { ...this.settingsState, scaleMode: patch.logScale ? 'logarithmic' : 'regular' };\r\n }\r\n if (patch.numberLocale !== undefined) {\r\n this.chart.setNumberLocale(patch.numberLocale);\r\n this.watchlist?.setLocale(patch.numberLocale || undefined);\r\n }\r\n if (patch.timezone !== undefined) {\r\n this.chart.setTimezone(settingToTimezone(patch.timezone));\r\n }\r\n if (patch.highLowLines !== undefined) this.chart.setHighLowLines(patch.highLowLines);\r\n if (patch.extendedHours !== undefined) this.chart.setExtendedHours(patch.extendedHours);\r\n if (patch.mainSeriesVisible !== undefined) this.chart.setMainSeriesVisible(patch.mainSeriesVisible);\r\n if (patch.chartTypeOptions !== undefined) {\r\n // Every type: one left out goes back to its defaults (a reset).\r\n this.chart.setChartTypeOptions({ renko: {}, lineBreak: {}, kagi: {}, pointAndFigure: {}, rangeBars: {}, ...patch.chartTypeOptions });\r\n }\r\n\r\n // Apply theme colors\r\n const currentTheme = this.chart.getTheme();\r\n const themeUpdate = { ...currentTheme } as Record<string, unknown>;\r\n let themeChanged = false;\r\n\r\n if (patch.candleUpColor !== undefined) { themeUpdate.candleUp = patch.candleUpColor; themeChanged = true; }\r\n if (patch.candleDownColor !== undefined) { themeUpdate.candleDown = patch.candleDownColor; themeChanged = true; }\r\n if (patch.candleUpWick !== undefined) { themeUpdate.candleUpWick = patch.candleUpWick; themeChanged = true; }\r\n if (patch.candleDownWick !== undefined) { themeUpdate.candleDownWick = patch.candleDownWick; themeChanged = true; }\r\n if (patch.backgroundColor !== undefined) { themeUpdate.background = patch.backgroundColor; themeChanged = true; }\r\n if (patch.gridColor !== undefined) { themeUpdate.grid = patch.gridColor; themeChanged = true; }\r\n\r\n if (themeChanged) {\r\n this.chart.setTheme(themeUpdate as unknown as Theme);\r\n }\r\n }\r\n\r\n private resetSettings(): void {\r\n const before = { ...this.settingsState };\r\n this.settingsState = { ...this.settingsDefaults };\r\n this.applySettings(this.settingsState);\r\n const after = { ...this.settingsState };\r\n if (JSON.stringify(before) === JSON.stringify(after)) return;\r\n this.chart.recordUndo({ undo: () => this.restoreSettings(before), redo: () => this.restoreSettings(after) });\r\n }\r\n\r\n /**\r\n * A settings change the user made: applied, and put in the chart's undo\r\n * history with its drawings and indicators. A burst on the same settings\r\n * (a colour dragged across the picker) is one step.\r\n */\r\n private changeSettings(patch: Partial<ChartSettingsState>): void {\r\n const keys = Object.keys(patch) as (keyof ChartSettingsState)[];\r\n // The scale mode and the legacy log flag move together.\r\n if (keys.includes('scaleMode') || keys.includes('logScale')) {\r\n for (const k of ['scaleMode', 'logScale'] as const) if (!keys.includes(k)) keys.push(k);\r\n }\r\n const pick = (): Partial<ChartSettingsState> => Object.fromEntries(keys.map((k) => [k, this.settingsState[k]]));\r\n const before = pick();\r\n this.applySettings(patch);\r\n const after = pick();\r\n if (JSON.stringify(before) === JSON.stringify(after)) return;\r\n this.chart.recordUndo({\r\n subject: `settings:${Object.keys(patch).sort().join(',')}`,\r\n undo: () => this.restoreSettings(before),\r\n redo: () => this.restoreSettings(after),\r\n });\r\n }\r\n\r\n /** Settings back as they were (an undo or redo), shown in the settings if they're open. */\r\n private restoreSettings(values: Partial<ChartSettingsState>): void {\r\n this.applySettings(values);\r\n this.settings?.refresh(this.settingsState);\r\n }\r\n\r\n private async connectStream(): Promise<void> {\r\n if (!this.adapter) return;\r\n const seq = ++this.connectSeq;\r\n\r\n this.state = {\r\n ...this.state,\r\n connectionState: 'connecting',\r\n connectionMessage: this.t('status.connecting'),\r\n };\r\n this.updateUI();\r\n // Keep the previous chart up while the next one loads; it only gets the\r\n // veil if the request is slow (see WidgetLoadingOverlay).\r\n this.loading.begin(this.chart.getData().length > 0);\r\n\r\n try {\r\n this.chart.disconnectStream();\r\n await this.chart.connect({\r\n adapter: this.adapter,\r\n symbol: this.state.symbol,\r\n timeframe: this.state.timeframe,\r\n historyLimit: this.options.historyLimit ?? 500,\r\n historyPageSize: this.options.historyPageSize,\r\n });\r\n // A newer switch started while this one was loading — it owns the UI now.\r\n if (seq !== this.connectSeq || this.destroyed) return;\r\n\r\n this.chart.setWatermark(this.state.symbol.replace('USDT', ' / USDT'), {\r\n fontSize: 48,\r\n color: this.state.isDark ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.03)',\r\n });\r\n\r\n // Re-apply per-symbol layout (indicators, drawings, chart type) after\r\n // the new history is in. Doing this *after* connect ensures indicators\r\n // recalculate against the loaded data, not the previous symbol's data.\r\n this.applySymbolLayout(this.state.symbol);\r\n\r\n if (this.loading.hasFailed()) {\r\n // History failed to load; the stream keeps retrying and the next\r\n // snapshot ends the loading state (handleDataUpdate).\r\n this.state = { ...this.state, connectionState: 'error' };\r\n } else {\r\n this.loading.end();\r\n this.state = {\r\n ...this.state,\r\n connectionState: 'connected',\r\n connectionMessage: this.t('status.live'),\r\n };\r\n }\r\n\r\n // Re-pull comparison overlays at the (possibly new) timeframe so they\r\n // stay aligned with the main series. Drop the active symbol if it ended\r\n // up in the compare set after a symbol switch.\r\n void this.refetchCompares();\r\n } catch (err: unknown) {\r\n if (seq !== this.connectSeq || this.destroyed) return;\r\n this.loading.fail(this.t('status.connectionFailed'));\r\n this.state = {\r\n ...this.state,\r\n connectionState: 'error',\r\n connectionMessage: err instanceof Error ? err.message : this.t('status.connectionFailed'),\r\n };\r\n }\r\n\r\n this.updateUI();\r\n }\r\n\r\n /** Redraw the on-chart indicator list on the next frame (coalesced). */\r\n private scheduleLegend(): void {\r\n if (!this.indicatorLegend || this.legendFrame) return;\r\n this.legendFrame = requestAnimationFrame(() => {\r\n this.legendFrame = 0;\r\n this.renderLegend();\r\n });\r\n }\r\n\r\n private renderLegend(): void {\r\n if (!this.indicatorLegend || this.destroyed) return;\r\n const last = this.chart.getData().length - 1;\r\n // Renko, Kagi and the like redraw the series: the hovered bar is not a\r\n // data bar, so their values stay on the latest one.\r\n const hover = this.chart.isTimeAligned() ? this.legendHoverIndex : null;\r\n const idx = hover === null ? last : Math.min(Math.max(hover, 0), last);\r\n // Each pane's indicators, its own first, stacked down from its top.\r\n const panes = new Map<string, { x: number; y: number; width: number; height: number; row: number }>();\r\n for (const pane of this.chart.getIndicatorPanes()) {\r\n (pane.instanceIds ?? [pane.instanceId]).forEach((id, row) => panes.set(id, { ...pane.rect, row }));\r\n }\r\n const locale = this.settingsState.numberLocale || 'en-US';\r\n const rows: IndicatorLegendRow[] = this.chart.getActiveIndicators().map((ind) => {\r\n const pane = panes.get(ind.instanceId) ?? null;\r\n const point = idx >= 0 ? this.chart.getIndicatorOutput(ind.instanceId)?.series?.[idx] : null;\r\n const colors = this.chart.getIndicatorStyle(ind.instanceId)?.colors ?? [];\r\n const values = legendValues(ind.descriptor, point, colors);\r\n return {\r\n instanceId: ind.instanceId,\r\n label: indicatorChipLabel(ind.id, ind.params, ind.descriptor.defaultConfig, ind.descriptor.shortName),\r\n visible: ind.visible,\r\n values: values.map((v) => ({\r\n text: pane ? formatIndicatorValue(v.value, locale) : this.chart.formatPrice(v.value),\r\n color: v.color,\r\n })),\r\n pane: pane\r\n ? {\r\n x: pane.x + LEGEND_INSET,\r\n // A short pane with many indicators: the last rows overlap rather than spill out.\r\n y: pane.y + Math.min(PANE_ROW_TOP + pane.row * PANE_ROW_STEP, Math.max(PANE_ROW_TOP, pane.height - PANE_ROW_STEP)),\r\n width: pane.width - 2 * LEGEND_INSET,\r\n }\r\n : null,\r\n };\r\n });\r\n const plot = this.chart.getPlotRect();\r\n const maximized = this.chart.getMaximizedPane();\r\n const labelOf = (id: string) => rows.find((r) => r.instanceId === id)?.label ?? '';\r\n // As the panes show: one maximised folds the others.\r\n const paneControls: IndicatorLegendPane[] = this.chart.getIndicatorPanes().map((pane) => ({\r\n instanceId: pane.instanceId,\r\n x: pane.rect.x + pane.rect.width - LEGEND_INSET,\r\n y: pane.rect.y + PANE_CONTROLS_TOP,\r\n label: labelOf(pane.instanceId),\r\n collapsed: this.chart.isPaneCollapsed(pane.instanceId),\r\n maximized: maximized === pane.instanceId,\r\n canMoveUp: this.chart.canMovePane(pane.instanceId, -1),\r\n canMoveDown: this.chart.canMovePane(pane.instanceId, 1),\r\n }));\r\n this.indicatorLegend.update(rows, { left: plot.x + LEGEND_INSET, top: this.chart.getLegendBottom() + 1 }, paneControls);\r\n }\r\n\r\n /** A pane's button on the chart. */\r\n private runPaneAction(instanceId: string, action: PaneAction): void {\r\n if (action === 'up' || action === 'down') this.chart.movePane(instanceId, action === 'up' ? -1 : 1);\r\n else if (action === 'collapse' || action === 'expand') this.chart.setPaneCollapsed(instanceId, action === 'collapse');\r\n else this.chart.setMaximizedPane(action === 'maximize' ? instanceId : null);\r\n this.scheduleLegend();\r\n }\r\n\r\n /**\r\n * An indicator's \"more\" menu: into the pane above or below it (the price\r\n * pane at the top), a pane of its own, back to the price pane; then its\r\n * settings and remove.\r\n */\r\n private openLegendMenu(instanceId: string, anchor: HTMLElement): void {\r\n const menu = this.legendMenu;\r\n if (!menu) return;\r\n if (menu.isOpen()) {\r\n menu.close();\r\n return;\r\n }\r\n // The price pane, then each indicator pane top to bottom.\r\n const places = ['price', ...this.chart.getIndicatorPanes().map((p) => p.instanceId)];\r\n const at = 1 + this.chart.getIndicatorPanes().findIndex((p) => p.instanceIds.includes(instanceId));\r\n const above = places[at - 1];\r\n const below = places[at + 1];\r\n const can = (target: string | undefined) => target !== undefined && this.chart.canMoveIndicatorToPane(instanceId, target);\r\n const entries: ContextMenuEntry[] = [];\r\n if (can(above)) entries.push({ id: `move:${above}`, label: this.t(above === 'price' ? 'legend.movePrice' : 'legend.moveUp'), icon: 'arrowUp' });\r\n if (can(below)) entries.push({ id: `move:${below}`, label: this.t('legend.moveDown'), icon: 'arrowDown' });\r\n if (can('new')) entries.push({ id: 'move:new', label: this.t('legend.moveNew'), icon: 'plus' });\r\n if (above !== 'price' && can('price')) entries.push({ id: 'move:price', label: this.t('legend.movePrice'), icon: 'trendingUp' });\r\n if (entries.length > 0) entries.push('separator');\r\n entries.push(\r\n { id: 'settings', label: this.t('legend.settings'), icon: 'settings' },\r\n { id: 'remove', label: this.t('legend.remove'), icon: 'trash', danger: true },\r\n );\r\n const box = anchor.getBoundingClientRect();\r\n const root = this.root.getBoundingClientRect();\r\n menu.open(entries, box.left - root.left, box.bottom - root.top + 2, (id) => {\r\n if (id === 'settings') this.openIndicatorSettings(instanceId);\r\n else if (id === 'remove') this.handleRemoveIndicator(instanceId);\r\n else if (id.startsWith('move:')) this.chart.moveIndicatorToPane(instanceId, id.slice('move:'.length));\r\n this.scheduleLegend();\r\n }, anchor);\r\n }\r\n\r\n private updateUI(): void {\r\n this.scheduleLegend();\r\n this.toolbar?.update(this.state);\r\n this.sidebar?.update(this.state);\r\n this.statusBar?.update({\r\n connectionState: this.state.connectionState,\r\n message: this.state.connectionMessage,\r\n symbol: this.state.symbol,\r\n timeframe: this.state.timeframe,\r\n });\r\n }\r\n\r\n private resolveIsDark(theme?: import('@tradecanvas/commons').ThemeName | Theme): boolean {\r\n if (theme === undefined || theme === 'dark') return true;\r\n if (theme === 'light') return false;\r\n // If it's a Theme object, check background color\r\n if (typeof theme === 'object' && theme.background) {\r\n return this.isColorDark(theme.background);\r\n }\r\n return true;\r\n }\r\n\r\n private resolveTheme(theme?: import('@tradecanvas/commons').ThemeName | Theme): Theme {\r\n if (theme === undefined || theme === 'dark') return DARK_THEME;\r\n if (theme === 'light') return LIGHT_THEME;\r\n if (typeof theme === 'object') return theme as Theme;\r\n return DARK_THEME;\r\n }\r\n\r\n private isColorDark(color: string): boolean {\r\n // Simple heuristic: if it starts with # and R+G+B < 384 (half of 768)\r\n if (color.startsWith('#') && color.length >= 7) {\r\n const r = parseInt(color.slice(1, 3), 16);\r\n const g = parseInt(color.slice(3, 5), 16);\r\n const b = parseInt(color.slice(5, 7), 16);\r\n return (r + g + b) < 384;\r\n }\r\n return true;\r\n }\r\n}\r\n\r\nexport { indicatorChipLabel };\r\n\r\ntype ActiveIndicator = ReturnType<Chart['getActiveIndicators']>[number];\r\n\r\n/** How `addCompareSymbol` compares: percent change on the price scale, its own scale or pane, spread, ratio. */\r\nexport type CompareWay = 'percent' | 'scale' | 'pane' | 'spread' | 'ratio';\r\n\r\n/**\r\n * The lines `instanceId` can be computed from: every drawn line of the other\r\n * indicators, except those that already read from it (that would be a loop).\r\n */\r\nexport function lineSourcesFor(instanceId: string, active: readonly ActiveIndicator[]): { value: string; label: string }[] {\r\n const readsFrom = (ind: ActiveIndicator): string | null => {\r\n const name = sourceParam(ind.descriptor);\r\n return (name && parseIndicatorSource(ind.params[name])?.instanceId) || null;\r\n };\r\n // Everything downstream of `instanceId`.\r\n const downstream = new Set([instanceId]);\r\n for (let grew = true; grew;) {\r\n grew = false;\r\n for (const ind of active) {\r\n const from = readsFrom(ind);\r\n if (from && downstream.has(from) && !downstream.has(ind.instanceId)) {\r\n downstream.add(ind.instanceId);\r\n grew = true;\r\n }\r\n }\r\n }\r\n const out: { value: string; label: string }[] = [];\r\n for (const ind of active) {\r\n if (downstream.has(ind.instanceId)) continue;\r\n const name = indicatorChipLabel(ind.id, ind.params, ind.descriptor.defaultConfig, ind.descriptor.shortName);\r\n for (const plot of ind.descriptor.plots ?? []) {\r\n out.push({ value: indicatorSource(ind.instanceId, plot.key), label: `${name}: ${plot.title}` });\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/** The page's localStorage, or null where it can't be used (private mode, SSR). */\r\nfunction browserStorage(): Storage | null {\r\n try {\r\n return typeof localStorage !== 'undefined' ? localStorage : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nconst NEWS_LIMIT = 10;\r\nconst NEWS_TTL_MS = 5 * 60_000;\r\nconst DAY_MS = 86_400_000;\r\n\r\n/**\r\n * The latest day in the bars, in the exchange's zone (UTC when it has none):\r\n * its open, range, volume and last close, and the close before it.\r\n */\r\nfunction sessionDay(\r\n bars: readonly { time: number; open: number; high: number; low: number; close: number; volume?: number }[],\r\n zone: string | undefined,\r\n): { open: number; high: number; low: number; close: number; volume: number; prevClose?: number } | null {\r\n if (bars.length === 0) return null;\r\n const tz = zone && isValidTimeZone(zone) ? zone : null;\r\n const dayOf = (t: number) => {\r\n const ms = t < 1e11 ? t * 1000 : t; // bars timed in seconds\r\n return Math.floor((ms + (tz ? zoneOffsetMinutes(tz, ms) * 60_000 : 0)) / DAY_MS);\r\n };\r\n const last = bars[bars.length - 1];\r\n const today = dayOf(last.time);\r\n let first = bars.length - 1;\r\n while (first > 0 && dayOf(bars[first - 1].time) === today) first--;\r\n let high = -Infinity;\r\n let low = Infinity;\r\n let volume = 0;\r\n for (let i = first; i < bars.length; i++) {\r\n high = Math.max(high, bars[i].high);\r\n low = Math.min(low, bars[i].low);\r\n volume += bars[i].volume ?? 0;\r\n }\r\n return { open: bars[first].open, high, low, close: last.close, volume, prevClose: first > 0 ? bars[first - 1].close : undefined };\r\n}\r\n\r\n/** \"in 3 hours\", \"5 minutes ago\": the nearest whole minutes, hours or days. */\r\nfunction relativeTime(deltaMs: number, locale: string): string {\r\n const minutes = deltaMs / 60_000;\r\n const [value, unit]: [number, Intl.RelativeTimeFormatUnit] = Math.abs(minutes) < 60\r\n ? [Math.round(minutes) || Math.sign(minutes) || 1, 'minute']\r\n : Math.abs(minutes) < 24 * 60\r\n ? [Math.round(minutes / 60), 'hour']\r\n : [Math.round(minutes / 1440), 'day'];\r\n try {\r\n return new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(value, unit);\r\n } catch {\r\n return new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(value, unit);\r\n }\r\n}\r\n\r\nfunction compactNumber(value: number, locale: string): string {\r\n try {\r\n return new Intl.NumberFormat(locale, { notation: 'compact', maximumFractionDigits: 2 }).format(value);\r\n } catch {\r\n return String(value);\r\n }\r\n}\r\n\r\n/** \"09:30–16:00 Mon–Fri\", from a symbol's sessions; undefined without any. */\r\nfunction sessionsText(info: SymbolInfo | null, locale: string): string | undefined {\r\n const sessions = info?.sessions ?? [];\r\n if (sessions.length === 0) return undefined;\r\n let names: string[];\r\n try {\r\n const format = new Intl.DateTimeFormat(locale, { weekday: 'short', timeZone: 'UTC' });\r\n names = Array.from({ length: 7 }, (_, d) => format.format(Date.UTC(1970, 0, 4 + d))); // 4 Jan 1970 was a Sunday\r\n } catch {\r\n names = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\r\n }\r\n const daysText = (days: number[] | undefined): string => {\r\n const list = [...new Set((days ?? []).filter((d) => Number.isInteger(d) && d >= 0 && d <= 6))].sort((a, b) => a - b);\r\n if (list.length === 0 || list.length === 7) return '';\r\n const contiguous = list.every((d, i) => i === 0 || d === list[i - 1] + 1);\r\n return contiguous && list.length > 2 ? `${names[list[0]]}–${names[list[list.length - 1]]}` : list.map((d) => names[d]).join(', ');\r\n };\r\n // The times read left to right in any language (isolated, so a right-to-left line keeps 09:30–16:00).\r\n return sessions.map((s) => [`⁦${s.start}–${s.end}⁩`, daysText(s.days)].filter(Boolean).join(' ')).join(', ');\r\n}\r\n\r\n/** Languages written right to left. */\r\nfunction isRtlLocale(locale: string | undefined): boolean {\r\n return !!locale && /^(ar|he|iw|fa|ur|ps|yi|dv|ckb|sd|ug)(-|$)/i.test(locale);\r\n}\r\n","import type { DataAdapter, DrawingState, Theme, ThemeName, VisibleRangeChangePayload } from '@tradecanvas/commons';\r\nimport { ChartWidget } from './ChartWidget.js';\r\nimport type { ChartWidgetOptions, WidgetLayoutsOptions } from './types.js';\r\nimport type { GridLayout } from '../grid/ChartGrid.js';\r\nimport { injectWidgetStyles, removeWidgetStyles } from './WidgetStyles.js';\r\nimport { createTranslator, fill, resolveMessages, type MessageKey, type Translator } from './i18n.js';\r\nimport { createIcon } from './icons.js';\r\nimport { escapeHtml as esc } from './escapeHtml.js';\r\nimport { WidgetLayoutsUI } from './WidgetLayoutsUI.js';\r\nimport { LayoutSession } from '../state/LayoutSession.js';\r\nimport { localStorageLayouts, type SavedLayout } from '../state/layoutStorage.js';\r\nimport { parseLayoutJson, readWidgetLayout, type WidgetLayoutContent } from './widgetLayout.js';\r\nimport { utcToWallTime } from './WidgetGoToDate.js';\r\nimport { isKeyTarget, isTyping, registerKeyRoot } from './keyTarget.js';\r\nimport { applyWidgetUI, resolveWidgetUI, type ResolvedWidgetUI, type WidgetUIPreset, type WidgetUITheme } from './widgetUI.js';\r\n\r\n/** What the charts of a grid follow from each other. */\r\nexport interface WidgetGridSync {\r\n /** A new symbol on one chart goes to all. */\r\n symbol: boolean;\r\n /** A new interval on one chart goes to all. */\r\n interval: boolean;\r\n /** The crosshair's time shows on every chart. */\r\n crosshair: boolean;\r\n /** Scrolling and zooming one chart moves the others to the same times. */\r\n time: boolean;\r\n /** Drawings are copied to the charts showing the same symbol. */\r\n drawings: boolean;\r\n /** A replay on one chart replays the others to the same time. */\r\n replay: boolean;\r\n}\r\n\r\nexport const DEFAULT_GRID_SYNC: Readonly<WidgetGridSync> = { symbol: false, interval: false, crosshair: true, time: false, drawings: false, replay: false };\r\n\r\nconst SYNC_KEYS: readonly (keyof WidgetGridSync)[] = ['symbol', 'interval', 'crosshair', 'time', 'drawings', 'replay'];\r\n\r\n/** Columns and rows of each arrangement. */\r\nexport const GRID_SHAPES: Readonly<Record<GridLayout, { cols: number; rows: number }>> = {\r\n '1x1': { cols: 1, rows: 1 },\r\n '1x2': { cols: 2, rows: 1 },\r\n '2x1': { cols: 1, rows: 2 },\r\n '2x2': { cols: 2, rows: 2 },\r\n '1x3': { cols: 3, rows: 1 },\r\n '3x1': { cols: 1, rows: 3 },\r\n '2x3': { cols: 3, rows: 2 },\r\n '3x2': { cols: 2, rows: 3 },\r\n};\r\n\r\nexport interface ChartWidgetGridOptions {\r\n /** How the charts are arranged. Default `'1x2'` (two side by side). */\r\n layout?: GridLayout;\r\n /** The arrangements the bar offers. Default all of them. */\r\n layoutChoices?: readonly GridLayout[];\r\n /**\r\n * Options for every chart. Leave `adapter` out of these when there is more\r\n * than one chart: an adapter keeps one stream, so each chart needs its own\r\n * (see `adapter`).\r\n */\r\n widget?: ChartWidgetOptions;\r\n /** Makes each chart's data adapter, `new BinanceAdapter()` say; called once per chart. */\r\n adapter?: (index: number) => DataAdapter;\r\n /** Each chart's own options, by position (its symbol and interval, say), over `widget`. */\r\n cells?: readonly ChartWidgetOptions[];\r\n /** What the charts follow from each other; see {@link DEFAULT_GRID_SYNC}. */\r\n sync?: Partial<WidgetGridSync>;\r\n /** Named layouts of the whole grid (arrangement, sync and every chart). Default `true`. */\r\n layouts?: boolean | WidgetLayoutsOptions;\r\n /** The bar above the charts: arrangement, sync, layouts. Default `true`. */\r\n bar?: boolean;\r\n /** The chart in use changed (pressed, or the grid shrank). */\r\n onActiveChange?: (index: number, widget: ChartWidget) => void;\r\n /** A chart was made: at the start, and when the grid grows. Feed it data, add indicators… */\r\n onChartAdd?: (widget: ChartWidget, index: number) => void;\r\n}\r\n\r\n/** What a grid's named layout holds. */\r\nexport interface WidgetGridLayoutContent {\r\n v: 1;\r\n kind: 'grid';\r\n layout: GridLayout;\r\n sync: WidgetGridSync;\r\n active: number;\r\n cells: WidgetLayoutContent[];\r\n}\r\n\r\ninterface Cell {\r\n el: HTMLDivElement;\r\n widget: ChartWidget;\r\n}\r\n\r\n/** An arrangement the grid knows (own keys only: a stored `\"constructor\"` is not one). */\r\nexport function isGridLayout(value: unknown): value is GridLayout {\r\n return typeof value === 'string' && Object.prototype.hasOwnProperty.call(GRID_SHAPES, value);\r\n}\r\n\r\n/** A detached copy of plain data (drawings): charts must not share objects they change in place. */\r\nfunction copyOf<T>(value: T): T {\r\n return JSON.parse(JSON.stringify(value)) as T;\r\n}\r\n\r\n/** A small picture of an arrangement: `cols` × `rows` boxes. */\r\nfunction shapeIcon(cols: number, rows: number, size = 16): string {\r\n const gap = 2;\r\n const w = (20 - gap * (cols - 1)) / cols;\r\n const h = (20 - gap * (rows - 1)) / rows;\r\n let rects = '';\r\n for (let r = 0; r < rows; r++) {\r\n for (let c = 0; c < cols; c++) {\r\n rects += `<rect x=\"${2 + c * (w + gap)}\" y=\"${2 + r * (h + gap)}\" width=\"${w}\" height=\"${h}\" rx=\"1\"/>`;\r\n }\r\n }\r\n return `<svg width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" aria-hidden=\"true\">${rects}</svg>`;\r\n}\r\n\r\n/** A grid's layout read back from storage, or `null` when it is not one. */\r\nexport function readGridLayout(value: unknown): WidgetGridLayoutContent | null {\r\n if (typeof value !== 'object' || value === null) return null;\r\n const v = value as Record<string, unknown>;\r\n if (v.v !== 1 || v.kind !== 'grid' || !isGridLayout(v.layout) || !Array.isArray(v.cells)) return null;\r\n const cells = v.cells.map(readWidgetLayout);\r\n if (cells.some((c) => c === null)) return null;\r\n const rawSync = (typeof v.sync === 'object' && v.sync !== null ? v.sync : {}) as Record<string, unknown>;\r\n const sync = { ...DEFAULT_GRID_SYNC };\r\n for (const key of SYNC_KEYS) if (typeof rawSync[key] === 'boolean') sync[key] = rawSync[key] as boolean;\r\n const active = typeof v.active === 'number' && Number.isInteger(v.active) ? v.active : 0;\r\n return { v: 1, kind: 'grid', layout: v.layout, sync, active, cells: cells as WidgetLayoutContent[] };\r\n}\r\n\r\n/**\r\n * Several chart widgets side by side, each with its own symbol, interval,\r\n * indicators and drawings. A bar above them picks the arrangement, links them\r\n * (symbol, interval, crosshair, time, drawings) and saves the whole grid as a\r\n * named layout. The chart pressed last is the active one.\r\n */\r\nexport class ChartWidgetGrid {\r\n private root: HTMLDivElement;\r\n private cellsEl: HTMLDivElement;\r\n private cells: Cell[] = [];\r\n private layout: GridLayout;\r\n private sync: WidgetGridSync;\r\n private active = 0;\r\n /** The chart under the pointer: scrolling there moves the others. */\r\n private hovered: Cell | null = null;\r\n /** Above 0 while the grid itself changes charts (a relay, a restore), so they don't pass it back. */\r\n private relayDepth = 0;\r\n /** The look given to setUI, for charts added later. */\r\n private uiTheme: WidgetUIPreset | WidgetUITheme | null = null;\r\n /** Charts the grid shrank away from, by position: growing again brings them back as they were. */\r\n private parked = new Map<number, WidgetLayoutContent>();\r\n private drawingFrame = 0;\r\n private drawingSource: Cell | null = null;\r\n private layoutButtons = new Map<GridLayout, HTMLButtonElement>();\r\n private syncButtons = new Map<keyof WidgetGridSync, HTMLButtonElement>();\r\n private layoutsButton: HTMLButtonElement | null = null;\r\n private session: LayoutSession | null = null;\r\n private layoutsUI: WidgetLayoutsUI | null = null;\r\n private readonly t: Translator;\r\n private destroyed = false;\r\n private unregisterKeys: () => void = () => {};\r\n private readonly onKeyDown = (e: KeyboardEvent) => {\r\n if (!(e.ctrlKey || e.metaKey) || e.altKey || e.shiftKey || (e.key !== 's' && e.key !== 'S')) return;\r\n // Ctrl/Cmd+S saves the grid once it was used (else the page keeps its own Ctrl+S).\r\n if (!this.layoutsUI || isTyping() || !isKeyTarget(this.root, true)) return;\r\n e.preventDefault();\r\n void this.layoutsUI.save();\r\n };\r\n\r\n constructor(container: HTMLElement, private readonly options: ChartWidgetGridOptions = {}) {\r\n this.layout = isGridLayout(options.layout) ? options.layout : '1x2';\r\n this.sync = { ...DEFAULT_GRID_SYNC, ...options.sync };\r\n this.t = createTranslator(resolveMessages(options.widget?.locale, options.widget?.messages));\r\n injectWidgetStyles();\r\n\r\n this.root = document.createElement('div');\r\n this.root.className = 'tcw-root tcw-grid';\r\n this.root.dataset.tcwTheme = options.widget?.theme === 'light' ? 'light' : 'dark';\r\n applyWidgetUI(this.root, resolveWidgetUI(options.widget?.ui), { variables: options.widget?.ui !== undefined });\r\n if (options.bar !== false) this.root.appendChild(this.buildBar());\r\n this.cellsEl = document.createElement('div');\r\n this.cellsEl.className = 'tcw-grid-cells';\r\n this.root.appendChild(this.cellsEl);\r\n container.appendChild(this.root);\r\n\r\n this.applyShape();\r\n for (let i = 0; i < this.shapeCount(); i++) this.cells.push(this.createCell(i));\r\n this.markActive();\r\n // The bar takes the charts' theme (a Theme object can be dark or light).\r\n const theme = this.cells[0]?.el.querySelector<HTMLElement>('.tcw-root')?.dataset.tcwTheme;\r\n if (theme) this.root.dataset.tcwTheme = theme;\r\n\r\n if (options.layouts !== false) this.setupLayouts(options.layouts === true || options.layouts === undefined ? {} : options.layouts);\r\n // After the charts: the first of them takes the shortcuts until one is pressed.\r\n this.unregisterKeys = registerKeyRoot(this.root);\r\n document.addEventListener('keydown', this.onKeyDown);\r\n }\r\n\r\n private get relaying(): boolean {\r\n return this.relayDepth > 0;\r\n }\r\n\r\n /** Run `change` as the grid's own (the charts it changes don't pass it on). */\r\n private quietly<T>(change: () => T): T {\r\n this.relayDepth++;\r\n try {\r\n return change();\r\n } finally {\r\n this.relayDepth--;\r\n }\r\n }\r\n\r\n // --- Public API ---\r\n\r\n getWidget(index: number): ChartWidget | null {\r\n return this.cells[index]?.widget ?? null;\r\n }\r\n\r\n getWidgets(): ChartWidget[] {\r\n return this.cells.map((c) => c.widget);\r\n }\r\n\r\n getActiveIndex(): number {\r\n return this.active;\r\n }\r\n\r\n getActiveWidget(): ChartWidget {\r\n return this.cells[this.active].widget;\r\n }\r\n\r\n setActive(index: number): void {\r\n if (index < 0 || index >= this.cells.length || index === this.active) return;\r\n this.active = index;\r\n this.markActive();\r\n this.options.onActiveChange?.(index, this.cells[index].widget);\r\n this.session?.changed();\r\n }\r\n\r\n getLayout(): GridLayout {\r\n return this.layout;\r\n }\r\n\r\n /**\r\n * Arrange the charts. Charts that no longer fit are put away (kept in the\r\n * saved layout too) and come back as they were when the grid grows again;\r\n * brand-new ones open on the active chart's symbol and interval when those\r\n * are synced.\r\n */\r\n setLayout(layout: GridLayout): void {\r\n if (layout === this.layout || !isGridLayout(layout)) return;\r\n this.layout = layout;\r\n const count = this.shapeCount();\r\n while (this.cells.length > count) {\r\n const index = this.cells.length - 1;\r\n const cell = this.cells.pop()!;\r\n this.parked.set(index, cell.widget.captureLayout());\r\n this.destroyCell(cell);\r\n }\r\n this.applyShape();\r\n for (let i = this.cells.length; i < count; i++) {\r\n const cell = this.createCell(i);\r\n this.cells.push(cell);\r\n this.unpark(i, cell);\r\n }\r\n if (this.active >= count) {\r\n this.active = 0;\r\n this.options.onActiveChange?.(0, this.cells[0].widget);\r\n }\r\n this.markActive();\r\n this.renderBar();\r\n this.session?.changed();\r\n }\r\n\r\n getSync(): WidgetGridSync {\r\n return { ...this.sync };\r\n }\r\n\r\n /** Every chart's look, and the bar's (see `ChartWidget.setUI`). */\r\n setUI(theme: WidgetUIPreset | WidgetUITheme): void {\r\n const ui = resolveWidgetUI(theme);\r\n applyWidgetUI(this.root, ui);\r\n for (const cell of this.cells) cell.widget.setUI(ui);\r\n this.uiTheme = ui;\r\n }\r\n\r\n /** The grid's look, every token set. */\r\n getUI(): ResolvedWidgetUI {\r\n return resolveWidgetUI(this.uiTheme ?? this.options.widget?.ui);\r\n }\r\n\r\n setSync(patch: Partial<WidgetGridSync>): void {\r\n const before = this.sync;\r\n this.sync = { ...this.sync, ...patch };\r\n if (before.crosshair && !this.sync.crosshair) for (const c of this.cells) c.widget.getChart().setCrosshairTime(null);\r\n // Switched on: line the others up with the active chart now.\r\n const source = this.cells[this.active];\r\n if (source && !this.relaying) {\r\n const symbol = source.widget.getSymbol();\r\n const timeframe = source.widget.getTimeframe();\r\n if (!before.symbol && this.sync.symbol) this.relay(source, (w) => void w.setSymbol(symbol));\r\n if (!before.interval && this.sync.interval) this.relay(source, (w) => void w.setTimeframe(timeframe));\r\n if (!before.drawings && this.sync.drawings) this.mergeDrawings();\r\n }\r\n this.renderBar();\r\n this.session?.changed();\r\n }\r\n\r\n /** Every chart's theme. */\r\n setTheme(theme: ThemeName | Theme): void {\r\n for (const c of this.cells) c.widget.setTheme(theme);\r\n this.followTheme();\r\n }\r\n\r\n /** Named layouts of the grid. `null` with `layouts: false`. */\r\n getLayoutSession(): LayoutSession | null {\r\n return this.session;\r\n }\r\n\r\n /** The grid as a layout: arrangement, sync and every chart, those put away included. */\r\n captureLayout(): WidgetGridLayoutContent {\r\n const parked = [...this.parked.entries()].sort(([a], [b]) => a - b).map(([, content]) => content);\r\n return {\r\n v: 1,\r\n kind: 'grid',\r\n layout: this.layout,\r\n sync: { ...this.sync },\r\n active: this.active,\r\n cells: [...this.cells.map((c) => c.widget.captureLayout()), ...parked],\r\n };\r\n }\r\n\r\n /**\r\n * Show a layout from `captureLayout()`. Rejects when a chart could not take\r\n * its part (the others still finish). For a saved layout, open it through\r\n * `getLayoutSession()`, so an auto-save can't catch it half shown.\r\n */\r\n async restoreLayout(content: WidgetGridLayoutContent): Promise<void> {\r\n this.relayDepth++;\r\n let results: PromiseSettledResult<void>[];\r\n try {\r\n this.parked.clear();\r\n this.setLayout(content.layout);\r\n this.sync = { ...content.sync };\r\n this.renderBar();\r\n const count = this.cells.length;\r\n content.cells.slice(count).forEach((cell, i) => this.parked.set(count + i, cell));\r\n results = await Promise.allSettled(this.cells.map((c, i) => (content.cells[i] ? c.widget.restoreLayout(content.cells[i]) : Promise.resolve())));\r\n } finally {\r\n this.relayDepth--;\r\n }\r\n if (this.destroyed) return;\r\n this.setActive(Math.min(Math.max(0, content.active), this.cells.length - 1));\r\n const failed = results.find((r): r is PromiseRejectedResult => r.status === 'rejected');\r\n if (failed) throw failed.reason;\r\n }\r\n\r\n getLayoutContent(): string {\r\n return JSON.stringify(this.captureLayout());\r\n }\r\n\r\n /** Show a layout from `getLayoutContent()`; `false` when it is not one. */\r\n async applyLayoutContent(content: string): Promise<boolean> {\r\n const layout = readGridLayout(parseLayoutJson(content));\r\n if (!layout) return false;\r\n await this.restoreLayout(layout);\r\n return true;\r\n }\r\n\r\n destroy(): void {\r\n if (this.destroyed) return;\r\n this.destroyed = true;\r\n document.removeEventListener('keydown', this.onKeyDown);\r\n this.unregisterKeys();\r\n if (this.drawingFrame) cancelAnimationFrame(this.drawingFrame);\r\n this.session?.destroy();\r\n this.layoutsUI?.destroy();\r\n for (const c of this.cells) this.destroyCell(c);\r\n this.cells = [];\r\n this.root.remove();\r\n removeWidgetStyles();\r\n }\r\n\r\n // --- Cells ---\r\n\r\n private shapeCount(): number {\r\n const { cols, rows } = GRID_SHAPES[this.layout];\r\n return cols * rows;\r\n }\r\n\r\n private applyShape(): void {\r\n const { cols, rows } = GRID_SHAPES[this.layout];\r\n this.cellsEl.style.gridTemplateColumns = `repeat(${cols}, minmax(0, 1fr))`;\r\n this.cellsEl.style.gridTemplateRows = `repeat(${rows}, minmax(0, 1fr))`;\r\n }\r\n\r\n private createCell(index: number): Cell {\r\n const el = document.createElement('div');\r\n el.className = 'tcw-grid-cell';\r\n el.setAttribute('role', 'region');\r\n el.setAttribute('aria-label', fill(this.t('grid.chart'), { n: index + 1 }));\r\n this.cellsEl.appendChild(el);\r\n\r\n const shared = this.options.widget ?? {};\r\n const own = this.options.cells?.[index] ?? {};\r\n // A new chart joins the synced symbol and interval.\r\n const lead = this.cells[this.active]?.widget;\r\n const cell = {} as Cell;\r\n const widget = new ChartWidget(el, {\r\n ...shared,\r\n ...own,\r\n ...(lead && this.sync.symbol ? { symbol: lead.getSymbol() } : {}),\r\n ...(lead && this.sync.interval ? { timeframe: lead.getTimeframe() } : {}),\r\n ...(this.options.adapter && !own.adapter ? { adapter: this.options.adapter(index) } : {}),\r\n // A look set on the grid since (setUI) for a chart it adds too.\r\n ...(this.uiTheme ? { ui: this.uiTheme } : {}),\r\n // The grid keeps the layouts, of all its charts at once.\r\n layouts: false,\r\n onSymbolChange: (symbol) => {\r\n own.onSymbolChange?.(symbol);\r\n shared.onSymbolChange?.(symbol);\r\n if (this.sync.symbol) this.relay(cell, (w) => void w.setSymbol(symbol));\r\n this.session?.changed();\r\n },\r\n onTimeframeChange: (tf) => {\r\n own.onTimeframeChange?.(tf);\r\n shared.onTimeframeChange?.(tf);\r\n if (this.sync.interval) this.relay(cell, (w) => void w.setTimeframe(tf));\r\n this.session?.changed();\r\n },\r\n });\r\n cell.el = el;\r\n cell.widget = widget;\r\n this.wireCell(cell);\r\n el.addEventListener('pointerdown', () => this.setActive(this.cells.indexOf(cell)), true);\r\n el.addEventListener('pointerenter', () => { this.hovered = cell; });\r\n el.addEventListener('pointerleave', () => { if (this.hovered === cell) this.hovered = null; });\r\n this.options.onChartAdd?.(widget, index);\r\n return cell;\r\n }\r\n\r\n /** The chart's links to the others (its listeners go with it when the widget is destroyed). */\r\n private wireCell(cell: Cell): void {\r\n const chart = cell.widget.getChart();\r\n const others = () => this.cells.filter((c) => c !== cell);\r\n chart.on('crosshairMove', (e) => {\r\n const time = (e.payload as { bar?: { time: number } }).bar?.time;\r\n if (!this.sync.crosshair || time === undefined) return;\r\n for (const other of others()) other.widget.getChart().setCrosshairTime(time);\r\n });\r\n chart.on('crosshairLeave', () => {\r\n if (!this.sync.crosshair) return;\r\n for (const other of others()) other.widget.getChart().setCrosshairTime(null);\r\n });\r\n chart.on('visibleRangeChange', (e) => {\r\n // Only the chart being scrolled leads, so new bars on the others don't pull it back.\r\n if (!this.sync.time || this.relaying || (this.hovered ?? this.cells[this.active]) !== cell) return;\r\n const { from, to } = e.payload as VisibleRangeChangePayload;\r\n const data = chart.getData();\r\n const fromTime = data[from]?.time;\r\n const toTime = data[to]?.time;\r\n if (fromTime === undefined || toTime === undefined) return;\r\n this.relay(cell, (w) => w.getChart().setVisibleRange(fromTime, toTime));\r\n });\r\n for (const event of ['drawingCreate', 'drawingUpdate', 'drawingRemove'] as const) {\r\n chart.on(event, () => {\r\n if (this.sync.drawings && !this.relaying) this.copyDrawingsSoon(cell);\r\n });\r\n }\r\n // A replay leads the others: they start at its time, follow its steps and end with it.\r\n chart.on('replayStep', (e) => {\r\n if (!this.sync.replay || this.relaying) return;\r\n const { until } = e.payload;\r\n this.relay(cell, (w) => {\r\n const other = w.getChart();\r\n if (other.isReplayActive()) {\r\n other.replaySeekToTime(until);\r\n return;\r\n }\r\n const start = lastBarBefore(other.getData(), until);\r\n if (start >= 0) other.replayStart({ startIndex: start, paused: true });\r\n });\r\n });\r\n chart.on('replayState', (e) => {\r\n if (!this.sync.replay || this.relaying || e.payload.state !== 'stopped') return;\r\n this.relay(cell, (w) => {\r\n if (w.getChart().isReplayActive()) w.getChart().replayStop();\r\n });\r\n });\r\n chart.on('stateChange', () => this.session?.changed());\r\n chart.on('themeChange', () => {\r\n if (!this.relaying) this.followTheme(cell);\r\n });\r\n }\r\n\r\n private destroyCell(cell: Cell): void {\r\n if (this.hovered === cell) this.hovered = null;\r\n if (this.drawingSource === cell) this.drawingSource = null;\r\n // What it says on its way out (its replay ending) is not for the others.\r\n this.quietly(() => cell.widget.destroy());\r\n cell.el.remove();\r\n }\r\n\r\n /** Pass a change from `source` on to the other charts, without it coming back. */\r\n private relay(source: Cell, apply: (widget: ChartWidget) => void): void {\r\n if (this.relaying) return;\r\n this.quietly(() => {\r\n for (const c of this.cells) if (c !== source) apply(c.widget);\r\n });\r\n }\r\n\r\n /** A chart that was put away comes back at `index`, as it was (on the synced symbol and interval). */\r\n private unpark(index: number, cell: Cell): void {\r\n const content = this.parked.get(index);\r\n if (!content) return;\r\n this.parked.delete(index);\r\n const lead = this.cells[this.active]?.widget;\r\n const restored: WidgetLayoutContent = {\r\n ...content,\r\n ...(lead && this.sync.symbol ? { symbol: lead.getSymbol() } : {}),\r\n ...(lead && this.sync.interval ? { timeframe: lead.getTimeframe() } : {}),\r\n };\r\n this.relayDepth++;\r\n cell.widget.restoreLayout(restored)\r\n .catch(() => cell.widget.toast(this.t('layouts.openFailed'), 'error'))\r\n .finally(() => { this.relayDepth--; });\r\n }\r\n\r\n /** Drawings move in bursts (a drag): copy them once a frame. */\r\n private copyDrawingsSoon(source: Cell): void {\r\n this.drawingSource = source;\r\n if (this.drawingFrame) return;\r\n this.drawingFrame = requestAnimationFrame(() => {\r\n this.drawingFrame = 0;\r\n const from = this.drawingSource;\r\n this.drawingSource = null;\r\n // A restore under way sets every chart's drawings itself.\r\n if (from && !this.destroyed && !this.relaying) this.copyDrawings(from);\r\n });\r\n }\r\n\r\n /** `source`'s drawings onto the charts showing its symbol (copies: charts change drawings in place). */\r\n private copyDrawings(source: Cell): void {\r\n const symbol = source.widget.getSymbol();\r\n const drawings = source.widget.getChart().getDrawings();\r\n this.quietly(() => {\r\n for (const c of this.cells) {\r\n if (c !== source && c.widget.getSymbol() === symbol) c.widget.getChart().setDrawings(copyOf(drawings));\r\n }\r\n });\r\n }\r\n\r\n /** Drawings sync switched on: each symbol's charts get all their drawings put together (none lost). */\r\n private mergeDrawings(): void {\r\n const bySymbol = new Map<string, Cell[]>();\r\n for (const c of this.cells) bySymbol.set(c.widget.getSymbol(), [...(bySymbol.get(c.widget.getSymbol()) ?? []), c]);\r\n this.quietly(() => {\r\n for (const cells of bySymbol.values()) {\r\n if (cells.length < 2) continue;\r\n const merged = new Map<string, DrawingState>();\r\n for (const c of cells) for (const d of c.widget.getChart().getDrawings()) if (!merged.has(d.id)) merged.set(d.id, d);\r\n const all = [...merged.values()];\r\n for (const c of cells) c.widget.getChart().setDrawings(copyOf(all));\r\n }\r\n });\r\n }\r\n\r\n /** Dark or light, as `source` (or the active chart) now is, for the bar and every chart. */\r\n private followTheme(source: Cell = this.cells[this.active]): void {\r\n const theme = source?.el.querySelector<HTMLElement>('.tcw-root')?.dataset.tcwTheme;\r\n if (!theme) return;\r\n this.root.dataset.tcwTheme = theme;\r\n this.quietly(() => {\r\n for (const c of this.cells) {\r\n if (c !== source && c.el.querySelector<HTMLElement>('.tcw-root')?.dataset.tcwTheme !== theme) c.widget.setTheme(theme as ThemeName);\r\n }\r\n });\r\n }\r\n\r\n private markActive(): void {\r\n this.cells.forEach((c, i) => c.el.classList.toggle('tcw-grid-cell-active', i === this.active && this.cells.length > 1));\r\n }\r\n\r\n // --- Bar ---\r\n\r\n private buildBar(): HTMLElement {\r\n const bar = document.createElement('div');\r\n bar.className = 'tcw-grid-bar';\r\n bar.setAttribute('role', 'toolbar');\r\n bar.setAttribute('aria-label', this.t('grid.bar'));\r\n\r\n const shapes = document.createElement('div');\r\n shapes.className = 'tcw-grid-group';\r\n shapes.setAttribute('role', 'group');\r\n shapes.setAttribute('aria-label', this.t('grid.layout'));\r\n const choices = this.options.layoutChoices?.filter(isGridLayout) ?? (Object.keys(GRID_SHAPES) as GridLayout[]);\r\n for (const layout of choices) {\r\n const { cols, rows } = GRID_SHAPES[layout];\r\n const label = cols * rows === 1\r\n ? this.t('grid.single')\r\n : fill(this.t('grid.layoutOption'), { count: cols * rows, cols, rows });\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-btn-icon';\r\n btn.title = label;\r\n btn.setAttribute('aria-label', label);\r\n btn.innerHTML = shapeIcon(cols, rows);\r\n btn.addEventListener('click', () => this.setLayout(layout));\r\n this.layoutButtons.set(layout, btn);\r\n shapes.appendChild(btn);\r\n }\r\n\r\n const sync = document.createElement('div');\r\n sync.className = 'tcw-grid-group';\r\n sync.setAttribute('role', 'group');\r\n sync.setAttribute('aria-label', this.t('grid.sync'));\r\n const syncLabel = document.createElement('span');\r\n syncLabel.className = 'tcw-grid-label';\r\n syncLabel.innerHTML = `${createIcon('link', 13)}<span>${esc(this.t('grid.sync'))}</span>`;\r\n sync.appendChild(syncLabel);\r\n for (const key of SYNC_KEYS) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className = 'tcw-btn tcw-grid-sync';\r\n btn.textContent = this.t(`grid.sync.${key}` as MessageKey);\r\n btn.title = this.t(`grid.sync.${key}.hint` as MessageKey);\r\n btn.addEventListener('click', () => this.setSync({ [key]: !this.sync[key] }));\r\n this.syncButtons.set(key, btn);\r\n sync.appendChild(btn);\r\n }\r\n\r\n const spacer = document.createElement('span');\r\n spacer.className = 'tcw-toolbar-spacer';\r\n bar.append(shapes, this.sep(), sync, spacer);\r\n\r\n if (this.options.layouts !== false) {\r\n this.layoutsButton = document.createElement('button');\r\n this.layoutsButton.type = 'button';\r\n this.layoutsButton.className = 'tcw-dropdown-trigger tcw-layouts-btn';\r\n this.layoutsButton.setAttribute('aria-haspopup', 'menu');\r\n this.layoutsButton.addEventListener('click', () => {\r\n if (this.layoutsButton) void this.layoutsUI?.openMenu(this.layoutsButton);\r\n });\r\n bar.appendChild(this.layoutsButton);\r\n }\r\n this.renderBar();\r\n return bar;\r\n }\r\n\r\n private sep(): HTMLSpanElement {\r\n const s = document.createElement('span');\r\n s.className = 'tcw-toolbar-sep';\r\n return s;\r\n }\r\n\r\n private renderBar(): void {\r\n for (const [layout, btn] of this.layoutButtons) {\r\n const on = layout === this.layout;\r\n btn.classList.toggle('tcw-active', on);\r\n btn.setAttribute('aria-pressed', String(on));\r\n }\r\n for (const [key, btn] of this.syncButtons) {\r\n btn.classList.toggle('tcw-active', this.sync[key]);\r\n btn.setAttribute('aria-pressed', String(this.sync[key]));\r\n }\r\n this.renderLayoutsButton();\r\n }\r\n\r\n private renderLayoutsButton(): void {\r\n const btn = this.layoutsButton;\r\n if (!btn) return;\r\n const name = this.session?.current()?.name ?? this.t('layouts.unnamed');\r\n const dirty = this.session?.isDirty() ?? false;\r\n const label = `${this.t('toolbar.layouts')}: ${name}${dirty ? ` (${this.t('layouts.unsavedChanges')})` : ''}`;\r\n btn.innerHTML = `${createIcon('save', 14)}<span class=\"tcw-layouts-label\">${esc(name)}</span>`\r\n + (dirty ? '<span class=\"tcw-layouts-dirty\" aria-hidden=\"true\"></span>' : '')\r\n + createIcon('chevronDown', 12);\r\n btn.title = label;\r\n btn.setAttribute('aria-label', label);\r\n }\r\n\r\n // --- Layouts ---\r\n\r\n private setupLayouts(cfg: WidgetLayoutsOptions): void {\r\n const session = new LayoutSession(cfg.storage ?? localStorageLayouts('tcw:grid-layouts:'), {\r\n capture: () => {\r\n const lead = this.cells[this.active].widget;\r\n return { content: this.getLayoutContent(), symbol: lead.getSymbol(), timeframe: lead.getTimeframe() };\r\n },\r\n apply: async (layout: SavedLayout) => {\r\n if (!(await this.applyLayoutContent(layout.content))) throw new Error('Not a grid layout');\r\n },\r\n }, {\r\n autoSave: cfg.autoSave,\r\n debounceMs: cfg.debounceMs,\r\n kind: 'grid',\r\n onChange: () => this.renderLayoutsButton(),\r\n onError: () => this.toast(this.t('layouts.saveFailed'), 'error'),\r\n });\r\n this.session = session;\r\n this.layoutsUI = new WidgetLayoutsUI(session, {\r\n root: this.root,\r\n t: this.t,\r\n toast: (message, kind) => this.toast(message, kind),\r\n formatTime: (ms) => {\r\n const { date, time } = utcToWallTime(ms, null);\r\n return `${date} ${time}`;\r\n },\r\n });\r\n this.renderLayoutsButton();\r\n if (cfg.openLast) {\r\n void session.list().then(([last]) => (last && !this.destroyed ? this.layoutsUI?.open(last.id) : undefined), () => undefined);\r\n }\r\n }\r\n\r\n private toast(message: string, kind: 'info' | 'error' = 'info'): void {\r\n this.cells[this.active]?.widget.toast(message, kind);\r\n }\r\n}\r\n\r\n/** The last bar of `data` that opened before `time`; -1 for none. */\r\nfunction lastBarBefore(data: readonly { time: number }[], time: number): number {\r\n let at = -1;\r\n for (let i = 0; i < data.length && data[i].time < time; i++) at = i;\r\n return at;\r\n}\r\n"],"mappings":"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BAAmB,GACnB,cAAe,GACf,iBAAkB,EAAE,CACrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}