@tradecanvas/chart 0.9.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Chart.d.ts +148 -5
- package/dist/Chart.d.ts.map +1 -1
- package/dist/{DragDropImporter-6QOjnfSj.js → DragDropImporter-C4x09P7e.js} +446 -112
- package/dist/DragDropImporter-C4x09P7e.js.map +1 -0
- package/dist/DragDropImporter-DeXlngof.cjs +2 -0
- package/dist/DragDropImporter-DeXlngof.cjs.map +1 -0
- package/dist/charts/ChartTypeStrategy.d.ts +13 -0
- package/dist/charts/ChartTypeStrategy.d.ts.map +1 -1
- package/dist/finance/PerformanceDashboard.d.ts +43 -0
- package/dist/finance/PerformanceDashboard.d.ts.map +1 -0
- package/dist/finance/index.d.ts +4 -0
- package/dist/finance/index.d.ts.map +1 -1
- package/dist/finance/performanceData.d.ts +39 -0
- package/dist/finance/performanceData.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +293 -36
- package/dist/index.js.map +1 -1
- package/dist/io/index.d.ts +2 -0
- package/dist/io/index.d.ts.map +1 -1
- package/dist/io/resampleOHLCV.d.ts +29 -0
- package/dist/io/resampleOHLCV.d.ts.map +1 -0
- package/dist/plugins/PluginManager.d.ts +27 -1
- package/dist/plugins/PluginManager.d.ts.map +1 -1
- package/dist/plugins/contracts.d.ts +54 -0
- package/dist/plugins/contracts.d.ts.map +1 -0
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/registry.d.ts +10 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/trading/wireExecution.d.ts +26 -0
- package/dist/trading/wireExecution.d.ts.map +1 -0
- package/dist/widget/AlertNotifier.d.ts +32 -0
- package/dist/widget/AlertNotifier.d.ts.map +1 -0
- package/dist/widget/ChartWidget.d.ts +54 -1
- package/dist/widget/ChartWidget.d.ts.map +1 -1
- package/dist/widget/DrawingFavoritesStore.d.ts +22 -0
- package/dist/widget/DrawingFavoritesStore.d.ts.map +1 -0
- package/dist/widget/DrawingTemplateStore.d.ts +29 -0
- package/dist/widget/DrawingTemplateStore.d.ts.map +1 -0
- package/dist/widget/WidgetAlertsPanel.d.ts +58 -0
- package/dist/widget/WidgetAlertsPanel.d.ts.map +1 -0
- package/dist/widget/WidgetBracketBar.d.ts +21 -0
- package/dist/widget/WidgetBracketBar.d.ts.map +1 -0
- package/dist/widget/WidgetDataWindow.d.ts +41 -0
- package/dist/widget/WidgetDataWindow.d.ts.map +1 -0
- package/dist/widget/WidgetDepthLadder.d.ts +29 -0
- package/dist/widget/WidgetDepthLadder.d.ts.map +1 -0
- package/dist/widget/WidgetDrawingSidebar.d.ts +6 -0
- package/dist/widget/WidgetDrawingSidebar.d.ts.map +1 -1
- package/dist/widget/WidgetDrawingStyle.d.ts +36 -0
- package/dist/widget/WidgetDrawingStyle.d.ts.map +1 -0
- package/dist/widget/WidgetHotkeySheet.d.ts.map +1 -1
- package/dist/widget/WidgetIndicatorSettings.d.ts +42 -0
- package/dist/widget/WidgetIndicatorSettings.d.ts.map +1 -0
- package/dist/widget/WidgetObjectTree.d.ts +59 -0
- package/dist/widget/WidgetObjectTree.d.ts.map +1 -0
- package/dist/widget/WidgetReplayBar.d.ts +1 -1
- package/dist/widget/WidgetSettings.d.ts +1 -0
- package/dist/widget/WidgetSettings.d.ts.map +1 -1
- package/dist/widget/WidgetSymbolSearch.d.ts +3 -1
- package/dist/widget/WidgetSymbolSearch.d.ts.map +1 -1
- package/dist/widget/WidgetToolbar.d.ts.map +1 -1
- package/dist/widget/icons.d.ts.map +1 -1
- package/dist/widget/index.cjs +947 -15
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +1826 -159
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/ladderRows.d.ts +21 -0
- package/dist/widget/ladderRows.d.ts.map +1 -0
- package/dist/widget/types.d.ts +72 -1
- package/dist/widget/types.d.ts.map +1 -1
- package/dist/widget/widgetConfig.d.ts.map +1 -1
- package/dist/widget/widgetShareState.d.ts +26 -0
- package/dist/widget/widgetShareState.d.ts.map +1 -0
- package/package.json +3 -3
- package/dist/DragDropImporter-6QOjnfSj.js.map +0 -1
- package/dist/DragDropImporter-CQ3EarQn.cjs +0 -2
- package/dist/DragDropImporter-CQ3EarQn.cjs.map +0 -1
package/dist/widget/index.cjs
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../DragDropImporter-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../DragDropImporter-DeXlngof.cjs`);let t=require(`@tradecanvas/commons`);function n(e,n,r={}){if(e.length===0)return[];let i=r.weekStartsOn??1,a=[],o=null,s=NaN;for(let r of e){let e=(0,t.timeframeBucketStart)(r.time,n,i);o===null||e!==s?(o!==null&&a.push(o),o={time:e,open:r.open,high:r.high,low:r.low,close:r.close,volume:r.volume},s=e):o={time:o.time,open:o.open,high:Math.max(o.high,r.high),low:Math.min(o.low,r.low),close:r.close,volume:o.volume+r.volume}}return o!==null&&a.push(o),a}function r(e){if(e.length<2)return 0;let t=[];for(let n=1;n<e.length;n++){let r=e[n].time-e[n-1].time;r>0&&t.push(r)}return t.length===0?0:(t.sort((e,t)=>e-t),t[Math.floor(t.length/2)])}var i=[{label:`1m`,value:`1m`},{label:`5m`,value:`5m`},{label:`15m`,value:`15m`},{label:`1H`,value:`1h`},{label:`4H`,value:`4h`},{label:`1D`,value:`1d`}],a=[{label:`Candlestick`,value:`candlestick`},{label:`Line`,value:`line`},{label:`Area`,value:`area`},{label:`Bar`,value:`bar`},{label:`Heikin-Ashi`,value:`heikinAshi`},{label:`Hollow Candle`,value:`hollowCandle`},{label:`Baseline`,value:`baseline`},{label:`Volume Candles`,value:`volumeCandles`},{label:`Equivolume`,value:`equivolume`},{label:`HLC Area`,value:`hlcArea`},{label:`Step Line`,value:`stepLine`},{label:`Line + Markers`,value:`lineWithMarkers`}],o=[{label:`Lines`,tools:[{label:`Trend Line`,value:`trendLine`},{label:`Ray`,value:`ray`},{label:`Extended Line`,value:`extendedLine`}]},{label:`Horizontal/Vertical`,tools:[{label:`Horizontal Line`,value:`horizontalLine`},{label:`Vertical Line`,value:`verticalLine`}]},{label:`Channels`,tools:[{label:`Parallel Channel`,value:`parallelChannel`},{label:`Regression Channel`,value:`regressionChannel`}]},{label:`Fibonacci`,tools:[{label:`Fib Retracement`,value:`fibRetracement`},{label:`Fib Extension`,value:`fibExtension`}]},{label:`Shapes`,tools:[{label:`Rectangle`,value:`rectangle`},{label:`Ellipse`,value:`ellipse`},{label:`Triangle`,value:`triangle`}]},{label:`Gann & Advanced`,tools:[{label:`Pitchfork`,value:`pitchfork`},{label:`Gann Fan`,value:`gannFan`},{label:`Gann Box`,value:`gannBox`},{label:`Elliott Wave`,value:`elliottWave`}]},{label:`Measure`,tools:[{label:`Price Range`,value:`priceRange`},{label:`Date Range`,value:`dateRange`},{label:`Measure`,value:`measure`}]},{label:`Annotation`,tools:[{label:`Text`,value:`text`},{label:`Arrow`,value:`arrow`}]}],s=[{id:`sma`,name:`SMA`,type:`overlay`},{id:`ema`,name:`EMA`,type:`overlay`},{id:`hma`,name:`Hull MA`,type:`overlay`},{id:`mtfma`,name:`MTF Moving Average`,type:`overlay`},{id:`bb`,name:`Bollinger Bands`,type:`overlay`},{id:`vwap`,name:`VWAP`,type:`overlay`},{id:`avwap`,name:`Anchored VWAP`,type:`overlay`},{id:`svwap`,name:`Session VWAP`,type:`overlay`},{id:`ichimoku`,name:`Ichimoku Cloud`,type:`overlay`},{id:`psar`,name:`Parabolic SAR`,type:`overlay`},{id:`supertrend`,name:`Supertrend`,type:`overlay`},{id:`keltner`,name:`Keltner Channel`,type:`overlay`},{id:`donchian`,name:`Donchian Channel`,type:`overlay`},{id:`pivots`,name:`Pivot Points`,type:`overlay`},{id:`zigzag`,name:`ZigZag`,type:`overlay`},{id:`lrc`,name:`Linear Regression Channel`,type:`overlay`},{id:`chandelier`,name:`Chandelier Exit`,type:`overlay`},{id:`alligator`,name:`Alligator`,type:`overlay`},{id:`rsi`,name:`RSI`,type:`panel`},{id:`macd`,name:`MACD`,type:`panel`},{id:`stochastic`,name:`Stochastic`,type:`panel`},{id:`atr`,name:`ATR`,type:`panel`},{id:`adx`,name:`ADX`,type:`panel`},{id:`obv`,name:`OBV`,type:`panel`},{id:`williamsR`,name:`Williams %R`,type:`panel`},{id:`cci`,name:`CCI`,type:`panel`},{id:`mfi`,name:`MFI`,type:`panel`},{id:`roc`,name:`ROC`,type:`panel`},{id:`tsi`,name:`TSI`,type:`panel`},{id:`cmf`,name:`CMF`,type:`panel`},{id:`aroon`,name:`Aroon`,type:`panel`},{id:`stddev`,name:`Std Deviation`,type:`panel`},{id:`vroc`,name:`Volume ROC`,type:`panel`},{id:`ad`,name:`Acc/Dist`,type:`panel`},{id:`ao`,name:`Awesome Oscillator`,type:`panel`},{id:`chaikinOsc`,name:`Chaikin Oscillator`,type:`panel`},{id:`voldelta`,name:`Volume Delta`,type:`panel`},{id:`vortex`,name:`Vortex Indicator`,type:`panel`},{id:`chop`,name:`Choppiness Index`,type:`panel`},{id:`uo`,name:`Ultimate Oscillator`,type:`panel`},{id:`fi`,name:`Force Index`,type:`panel`},{id:`crsi`,name:`Connors RSI`,type:`panel`},{id:`coppock`,name:`Coppock Curve`,type:`panel`},{id:`kst`,name:`Know Sure Thing`,type:`panel`},{id:`elderray`,name:`Elder Ray`,type:`panel`},{id:`stc`,name:`Schaff Trend Cycle`,type:`panel`},{id:`kvo`,name:`Klinger Oscillator`,type:`panel`},{id:`fisher`,name:`Fisher Transform`,type:`panel`},{id:`dpo`,name:`Detrended Price Osc`,type:`panel`},{id:`bop`,name:`Balance of Power`,type:`panel`},{id:`massindex`,name:`Mass Index`,type:`panel`},{id:`cmo`,name:`Chande Momentum`,type:`panel`},{id:`trix`,name:`TRIX`,type:`panel`},{id:`emv`,name:`Ease of Movement`,type:`panel`},{id:`pvt`,name:`Price Volume Trend`,type:`panel`},{id:`wad`,name:`Williams A/D`,type:`panel`},{id:`chaikinvol`,name:`Chaikin Volatility`,type:`panel`},{id:`rvi`,name:`Relative Vigor Index`,type:`panel`},{id:`stochrsi`,name:`Stochastic RSI`,type:`panel`},{id:`ppo`,name:`Percentage Price Oscillator`,type:`panel`},{id:`ac`,name:`Accelerator Oscillator`,type:`panel`},{id:`rmi`,name:`Relative Momentum Index`,type:`panel`},{id:`disparity`,name:`Disparity Index`,type:`panel`},{id:`qstick`,name:`Qstick`,type:`panel`},{id:`pgo`,name:`Pretty Good Oscillator`,type:`panel`},{id:`volumeProfile`,name:`Volume Profile`,type:`panel`}],c=[`sma`,`ema`,`bb`,`rsi`,`macd`,`stochastic`,`vwap`,`atr`,`obv`,`ichimoku`],l=[`BTCUSDT`,`ETHUSDT`,`SOLUSDT`,`BNBUSDT`],u={candleUpColor:`#26A69A`,candleDownColor:`#EF5350`,candleUpWick:`#26A69A`,candleDownWick:`#EF5350`,backgroundColor:`#131722`,gridColor:`#1E222D`,gridVisible:!0,volumeVisible:!0,volumeProfileVisible:!1,marketProfileVisible:!1,marketProfileSplit:!1,marketProfileLetters:!1,marketProfileBuckets:48,marketProfileOpacity:.32,depthHeatmapVisible:!1,depthHeatmapOpacity:.7,sessionShadingVisible:!1,pivotMarkersVisible:!1,pivotStrength:5,pivotStructureLabels:!1,periodLevelsVisible:!1,periodLevelsPeriod:`day`,legendVisible:!0,barCountdown:!0,logScale:!1,scaleMode:`regular`,autoScale:!0,crosshairMode:`magnet`,numberLocale:`en-US`,timezone:`local`},d=`/* === TradeCanvas Widget — Premium Styles === */
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* The HTML \`hidden\` attribute only sets \`display: none\` via the UA stylesheet,
|
|
5
|
+
* which any author \`display\` rule (e.g. \`.tcw-alerts-panel { display: flex }\`)
|
|
6
|
+
* silently overrides — leaving panels stuck open when JS sets \`el.hidden = true\`.
|
|
7
|
+
* Force \`hidden\` to win for every namespaced widget element. Scoped to \`tcw-\`
|
|
8
|
+
* so it never touches the host page.
|
|
9
|
+
*/
|
|
10
|
+
[class^="tcw-"][hidden],
|
|
11
|
+
[class*=" tcw-"][hidden] {
|
|
12
|
+
display: none !important;
|
|
13
|
+
}
|
|
2
14
|
|
|
3
15
|
.tcw-root {
|
|
4
16
|
display: flex;
|
|
@@ -535,6 +547,36 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
535
547
|
font-weight: 600;
|
|
536
548
|
}
|
|
537
549
|
|
|
550
|
+
/* Pinned (favorited) flyout item — a star marker on the right. */
|
|
551
|
+
.tcw-flyout-item.tcw-flyout-faved::after {
|
|
552
|
+
content: '★';
|
|
553
|
+
float: right;
|
|
554
|
+
color: var(--tcw-accent);
|
|
555
|
+
font-size: 11px;
|
|
556
|
+
line-height: 1.4;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* Favorites strip — pinned drawing tools above the tool groups. */
|
|
560
|
+
.tcw-sidebar-favorites {
|
|
561
|
+
display: flex;
|
|
562
|
+
flex-direction: column;
|
|
563
|
+
gap: 2px;
|
|
564
|
+
}
|
|
565
|
+
.tcw-sidebar-favorites .tcw-sidebar-btn {
|
|
566
|
+
position: relative;
|
|
567
|
+
}
|
|
568
|
+
.tcw-sidebar-favorites .tcw-sidebar-btn::before {
|
|
569
|
+
content: '';
|
|
570
|
+
position: absolute;
|
|
571
|
+
top: 3px;
|
|
572
|
+
right: 3px;
|
|
573
|
+
width: 4px;
|
|
574
|
+
height: 4px;
|
|
575
|
+
border-radius: 50%;
|
|
576
|
+
background: var(--tcw-accent);
|
|
577
|
+
opacity: 0.7;
|
|
578
|
+
}
|
|
579
|
+
|
|
538
580
|
/* === Modal === */
|
|
539
581
|
|
|
540
582
|
.tcw-modal-backdrop {
|
|
@@ -1407,8 +1449,8 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
1407
1449
|
|
|
1408
1450
|
@media (max-width: 768px) {
|
|
1409
1451
|
.tcw-toolbar {
|
|
1410
|
-
padding: 0
|
|
1411
|
-
height:
|
|
1452
|
+
padding: 0 4px;
|
|
1453
|
+
height: 44px; /* Apple HIG minimum touch target */
|
|
1412
1454
|
}
|
|
1413
1455
|
.tcw-toolbar-sep {
|
|
1414
1456
|
display: none;
|
|
@@ -1416,20 +1458,910 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
1416
1458
|
.tcw-indicator-chips {
|
|
1417
1459
|
display: none;
|
|
1418
1460
|
}
|
|
1461
|
+
.tcw-btn,
|
|
1462
|
+
.tcw-dropdown-trigger {
|
|
1463
|
+
padding: 10px 12px; /* fatter tap target */
|
|
1464
|
+
font-size: 13px;
|
|
1465
|
+
}
|
|
1466
|
+
.tcw-btn-icon {
|
|
1467
|
+
width: 40px;
|
|
1468
|
+
height: 40px;
|
|
1469
|
+
}
|
|
1419
1470
|
.tcw-sidebar {
|
|
1420
|
-
width:
|
|
1471
|
+
width: 44px;
|
|
1421
1472
|
}
|
|
1422
1473
|
.tcw-sidebar-btn {
|
|
1423
|
-
width:
|
|
1424
|
-
height:
|
|
1474
|
+
width: 40px;
|
|
1475
|
+
height: 40px;
|
|
1425
1476
|
}
|
|
1426
|
-
.tcw-modal
|
|
1477
|
+
.tcw-modal,
|
|
1478
|
+
.tcw-cmd-palette {
|
|
1427
1479
|
width: 94vw;
|
|
1428
1480
|
border-radius: var(--tcw-radius-lg);
|
|
1429
1481
|
}
|
|
1482
|
+
|
|
1483
|
+
/* Hide the right-side watchlist on tablets too — already declared but
|
|
1484
|
+
* grouped here for clarity. */
|
|
1485
|
+
.tcw-watchlist {
|
|
1486
|
+
display: none;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
/* Replay scrubber compact mode */
|
|
1490
|
+
.tcw-replay-scrubber {
|
|
1491
|
+
width: 120px;
|
|
1492
|
+
}
|
|
1493
|
+
.tcw-replay-progress {
|
|
1494
|
+
display: none;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
/* === Mobile bottom-sheet pattern ===
|
|
1499
|
+
* On phones, swap floating-centered modals for full-width sheets that slide
|
|
1500
|
+
* up from the bottom. Bigger hit targets, no awkward off-screen clipping,
|
|
1501
|
+
* matches how every modern iOS/Android app handles overflow UI.
|
|
1502
|
+
*/
|
|
1503
|
+
@media (max-width: 640px) {
|
|
1504
|
+
.tcw-modal,
|
|
1430
1505
|
.tcw-cmd-palette {
|
|
1431
|
-
|
|
1432
|
-
|
|
1506
|
+
top: auto;
|
|
1507
|
+
bottom: 0;
|
|
1508
|
+
left: 0;
|
|
1509
|
+
right: 0;
|
|
1510
|
+
transform: none;
|
|
1511
|
+
width: 100vw;
|
|
1512
|
+
max-width: 100vw;
|
|
1513
|
+
max-height: 92vh;
|
|
1514
|
+
border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;
|
|
1515
|
+
border-bottom: none;
|
|
1516
|
+
/* Grab handle */
|
|
1517
|
+
padding-top: 8px;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
/* Visual "grab handle" affordance — a short pill at the top of every sheet */
|
|
1521
|
+
.tcw-modal::before,
|
|
1522
|
+
.tcw-cmd-palette::before {
|
|
1523
|
+
content: '';
|
|
1524
|
+
display: block;
|
|
1525
|
+
width: 36px;
|
|
1526
|
+
height: 4px;
|
|
1527
|
+
border-radius: 2px;
|
|
1528
|
+
background: var(--tcw-border-strong);
|
|
1529
|
+
margin: 0 auto 8px;
|
|
1530
|
+
opacity: 0.7;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
/* Reuse the existing modal-in animation but slide from below instead of
|
|
1534
|
+
* popping from center, so the entrance reads as a sheet, not a dialog. */
|
|
1535
|
+
@keyframes tcw-modal-in {
|
|
1536
|
+
from { opacity: 0; transform: translateY(20px); }
|
|
1537
|
+
to { opacity: 1; transform: translateY(0); }
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
.tcw-modal,
|
|
1541
|
+
.tcw-cmd-palette {
|
|
1542
|
+
animation: tcw-modal-in var(--tcw-dur-slow) var(--tcw-ease-out);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
/* Safe-area-aware footer padding for iPhone notch / home indicator */
|
|
1546
|
+
.tcw-modal-footer,
|
|
1547
|
+
.tcw-cmd-footer {
|
|
1548
|
+
padding-bottom: max(14px, env(safe-area-inset-bottom));
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
/* Larger tap targets inside sheets */
|
|
1552
|
+
.tcw-modal-tab {
|
|
1553
|
+
padding: 14px 16px;
|
|
1554
|
+
}
|
|
1555
|
+
.tcw-cmd-item {
|
|
1556
|
+
padding: 12px 14px;
|
|
1557
|
+
font-size: 14px;
|
|
1558
|
+
}
|
|
1559
|
+
.tcw-dropdown-item {
|
|
1560
|
+
padding: 12px 12px;
|
|
1561
|
+
font-size: 14px;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/* Hotkey sheet — single column on phones */
|
|
1565
|
+
.tcw-hotkey-grid {
|
|
1566
|
+
grid-template-columns: 1fr;
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
/* === Price alerts panel === */
|
|
1571
|
+
|
|
1572
|
+
.tcw-alerts-panel {
|
|
1573
|
+
position: absolute;
|
|
1574
|
+
top: 50px;
|
|
1575
|
+
right: 12px;
|
|
1576
|
+
z-index: 40;
|
|
1577
|
+
width: 300px;
|
|
1578
|
+
max-width: calc(100vw - 24px);
|
|
1579
|
+
display: flex;
|
|
1580
|
+
flex-direction: column;
|
|
1581
|
+
background: var(--tcw-bg-elevated);
|
|
1582
|
+
border: 1px solid var(--tcw-border-strong);
|
|
1583
|
+
border-radius: var(--tcw-radius-lg);
|
|
1584
|
+
box-shadow: var(--tcw-shadow-lg);
|
|
1585
|
+
overflow: hidden;
|
|
1586
|
+
animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
@keyframes tcw-alerts-in {
|
|
1590
|
+
from { opacity: 0; transform: translateY(-6px) scale(0.98); }
|
|
1591
|
+
to { opacity: 1; transform: none; }
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
.tcw-alerts-header {
|
|
1595
|
+
display: flex;
|
|
1596
|
+
align-items: center;
|
|
1597
|
+
justify-content: space-between;
|
|
1598
|
+
padding: 10px 12px;
|
|
1599
|
+
font-weight: 600;
|
|
1600
|
+
font-size: 13px;
|
|
1601
|
+
color: var(--tcw-text);
|
|
1602
|
+
border-bottom: 1px solid var(--tcw-border);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
.tcw-alerts-close {
|
|
1606
|
+
display: inline-flex;
|
|
1607
|
+
align-items: center;
|
|
1608
|
+
justify-content: center;
|
|
1609
|
+
width: 26px;
|
|
1610
|
+
height: 26px;
|
|
1611
|
+
border: none;
|
|
1612
|
+
background: transparent;
|
|
1613
|
+
color: var(--tcw-text-muted);
|
|
1614
|
+
border-radius: var(--tcw-radius-sm);
|
|
1615
|
+
cursor: pointer;
|
|
1616
|
+
}
|
|
1617
|
+
.tcw-alerts-close:hover {
|
|
1618
|
+
background: var(--tcw-bg-surface);
|
|
1619
|
+
color: var(--tcw-text);
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
.tcw-alerts-form {
|
|
1623
|
+
display: grid;
|
|
1624
|
+
grid-template-columns: 1fr 1fr;
|
|
1625
|
+
gap: 8px;
|
|
1626
|
+
padding: 12px;
|
|
1627
|
+
border-bottom: 1px solid var(--tcw-border);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
.tcw-alerts-form input,
|
|
1631
|
+
.tcw-alerts-form select {
|
|
1632
|
+
width: 100%;
|
|
1633
|
+
min-width: 0;
|
|
1634
|
+
box-sizing: border-box;
|
|
1635
|
+
height: 32px;
|
|
1636
|
+
padding: 0 8px;
|
|
1637
|
+
font-size: 12px;
|
|
1638
|
+
color: var(--tcw-text);
|
|
1639
|
+
background: var(--tcw-bg-surface);
|
|
1640
|
+
border: 1px solid var(--tcw-border);
|
|
1641
|
+
border-radius: var(--tcw-radius-sm);
|
|
1642
|
+
outline: none;
|
|
1643
|
+
}
|
|
1644
|
+
.tcw-alerts-form input:focus,
|
|
1645
|
+
.tcw-alerts-form select:focus {
|
|
1646
|
+
border-color: var(--tcw-accent);
|
|
1647
|
+
box-shadow: 0 0 0 2px var(--tcw-accent-soft);
|
|
1648
|
+
}
|
|
1649
|
+
.tcw-alerts-message,
|
|
1650
|
+
.tcw-alerts-source {
|
|
1651
|
+
grid-column: 1 / -1;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
.tcw-alerts-add {
|
|
1655
|
+
grid-column: 1 / -1;
|
|
1656
|
+
display: inline-flex;
|
|
1657
|
+
align-items: center;
|
|
1658
|
+
justify-content: center;
|
|
1659
|
+
gap: 6px;
|
|
1660
|
+
height: 34px;
|
|
1661
|
+
font-size: 12px;
|
|
1662
|
+
font-weight: 600;
|
|
1663
|
+
color: #fff;
|
|
1664
|
+
background: var(--tcw-accent);
|
|
1665
|
+
border: none;
|
|
1666
|
+
border-radius: var(--tcw-radius-sm);
|
|
1667
|
+
cursor: pointer;
|
|
1668
|
+
}
|
|
1669
|
+
.tcw-alerts-add:hover {
|
|
1670
|
+
background: var(--tcw-accent-hover);
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
.tcw-alerts-list {
|
|
1674
|
+
max-height: 260px;
|
|
1675
|
+
overflow-y: auto;
|
|
1676
|
+
padding: 6px;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
.tcw-alerts-empty {
|
|
1680
|
+
padding: 18px 12px;
|
|
1681
|
+
text-align: center;
|
|
1682
|
+
font-size: 12px;
|
|
1683
|
+
color: var(--tcw-text-muted);
|
|
1684
|
+
line-height: 1.5;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
.tcw-alerts-row {
|
|
1688
|
+
display: flex;
|
|
1689
|
+
align-items: center;
|
|
1690
|
+
justify-content: space-between;
|
|
1691
|
+
gap: 8px;
|
|
1692
|
+
padding: 8px 8px;
|
|
1693
|
+
border-radius: var(--tcw-radius-sm);
|
|
1694
|
+
}
|
|
1695
|
+
.tcw-alerts-row:hover {
|
|
1696
|
+
background: var(--tcw-bg-surface);
|
|
1697
|
+
}
|
|
1698
|
+
.tcw-alerts-triggered {
|
|
1699
|
+
background: var(--tcw-accent-soft);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
.tcw-alerts-info {
|
|
1703
|
+
min-width: 0;
|
|
1704
|
+
}
|
|
1705
|
+
.tcw-alerts-row-main {
|
|
1706
|
+
display: flex;
|
|
1707
|
+
align-items: center;
|
|
1708
|
+
gap: 8px;
|
|
1709
|
+
font-size: 12px;
|
|
1710
|
+
font-weight: 600;
|
|
1711
|
+
color: var(--tcw-text);
|
|
1712
|
+
font-variant-numeric: tabular-nums;
|
|
1713
|
+
}
|
|
1714
|
+
.tcw-alerts-row-note {
|
|
1715
|
+
margin-top: 2px;
|
|
1716
|
+
font-size: 11px;
|
|
1717
|
+
color: var(--tcw-text-muted);
|
|
1718
|
+
overflow: hidden;
|
|
1719
|
+
text-overflow: ellipsis;
|
|
1720
|
+
white-space: nowrap;
|
|
1721
|
+
}
|
|
1722
|
+
.tcw-alerts-badge {
|
|
1723
|
+
font-size: 9px;
|
|
1724
|
+
font-weight: 700;
|
|
1725
|
+
text-transform: uppercase;
|
|
1726
|
+
letter-spacing: 0.04em;
|
|
1727
|
+
padding: 2px 5px;
|
|
1728
|
+
border-radius: 999px;
|
|
1729
|
+
color: var(--tcw-accent);
|
|
1730
|
+
background: var(--tcw-accent-soft);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
.tcw-alerts-del {
|
|
1734
|
+
flex-shrink: 0;
|
|
1735
|
+
display: inline-flex;
|
|
1736
|
+
align-items: center;
|
|
1737
|
+
justify-content: center;
|
|
1738
|
+
width: 28px;
|
|
1739
|
+
height: 28px;
|
|
1740
|
+
border: none;
|
|
1741
|
+
background: transparent;
|
|
1742
|
+
color: var(--tcw-text-muted);
|
|
1743
|
+
border-radius: var(--tcw-radius-sm);
|
|
1744
|
+
cursor: pointer;
|
|
1745
|
+
}
|
|
1746
|
+
.tcw-alerts-del:hover {
|
|
1747
|
+
background: var(--tcw-red-soft);
|
|
1748
|
+
color: var(--tcw-red);
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
@media (max-width: 640px) {
|
|
1752
|
+
.tcw-alerts-panel {
|
|
1753
|
+
top: auto;
|
|
1754
|
+
bottom: 0;
|
|
1755
|
+
left: 0;
|
|
1756
|
+
right: 0;
|
|
1757
|
+
width: 100vw;
|
|
1758
|
+
max-width: 100vw;
|
|
1759
|
+
border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;
|
|
1760
|
+
}
|
|
1761
|
+
.tcw-alerts-list {
|
|
1762
|
+
max-height: 40vh;
|
|
1763
|
+
padding-bottom: max(8px, env(safe-area-inset-bottom));
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/* === Data Window === */
|
|
1768
|
+
|
|
1769
|
+
.tcw-datawin {
|
|
1770
|
+
position: absolute;
|
|
1771
|
+
top: 50px;
|
|
1772
|
+
right: 12px;
|
|
1773
|
+
z-index: 38;
|
|
1774
|
+
width: 200px;
|
|
1775
|
+
display: flex;
|
|
1776
|
+
flex-direction: column;
|
|
1777
|
+
background: var(--tcw-bg-elevated);
|
|
1778
|
+
border: 1px solid var(--tcw-border-strong);
|
|
1779
|
+
border-radius: var(--tcw-radius-lg);
|
|
1780
|
+
box-shadow: var(--tcw-shadow-lg);
|
|
1781
|
+
overflow: hidden;
|
|
1782
|
+
animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;
|
|
1783
|
+
}
|
|
1784
|
+
.tcw-datawin-header {
|
|
1785
|
+
display: flex;
|
|
1786
|
+
align-items: center;
|
|
1787
|
+
justify-content: space-between;
|
|
1788
|
+
padding: 9px 12px;
|
|
1789
|
+
font-size: 12px;
|
|
1790
|
+
font-weight: 600;
|
|
1791
|
+
color: var(--tcw-text);
|
|
1792
|
+
border-bottom: 1px solid var(--tcw-border);
|
|
1793
|
+
}
|
|
1794
|
+
.tcw-datawin-close {
|
|
1795
|
+
display: inline-flex;
|
|
1796
|
+
align-items: center;
|
|
1797
|
+
justify-content: center;
|
|
1798
|
+
width: 24px;
|
|
1799
|
+
height: 24px;
|
|
1800
|
+
border: none;
|
|
1801
|
+
background: transparent;
|
|
1802
|
+
color: var(--tcw-text-muted);
|
|
1803
|
+
border-radius: var(--tcw-radius-sm);
|
|
1804
|
+
cursor: pointer;
|
|
1805
|
+
}
|
|
1806
|
+
.tcw-datawin-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }
|
|
1807
|
+
.tcw-datawin-body { padding: 6px 4px; max-height: 360px; overflow-y: auto; }
|
|
1808
|
+
.tcw-datawin-empty { padding: 14px; text-align: center; font-size: 12px; color: var(--tcw-text-muted); }
|
|
1809
|
+
.tcw-datawin-row {
|
|
1810
|
+
display: flex;
|
|
1811
|
+
align-items: center;
|
|
1812
|
+
justify-content: space-between;
|
|
1813
|
+
gap: 10px;
|
|
1814
|
+
padding: 3px 8px;
|
|
1815
|
+
font-size: 12px;
|
|
1816
|
+
}
|
|
1817
|
+
.tcw-datawin-label { color: var(--tcw-text-muted); }
|
|
1818
|
+
.tcw-datawin-value { color: var(--tcw-text); font-variant-numeric: tabular-nums; font-weight: 600; }
|
|
1819
|
+
.tcw-datawin-value.tcw-up { color: var(--tcw-green); }
|
|
1820
|
+
.tcw-datawin-value.tcw-down { color: var(--tcw-red); }
|
|
1821
|
+
.tcw-datawin-sub {
|
|
1822
|
+
margin: 6px 8px 2px;
|
|
1823
|
+
font-size: 10px;
|
|
1824
|
+
font-weight: 700;
|
|
1825
|
+
text-transform: uppercase;
|
|
1826
|
+
letter-spacing: 0.04em;
|
|
1827
|
+
color: var(--tcw-text-muted);
|
|
1828
|
+
border-top: 1px solid var(--tcw-border);
|
|
1829
|
+
padding-top: 6px;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
@media (max-width: 640px) {
|
|
1833
|
+
.tcw-datawin { top: auto; bottom: 0; left: 0; right: 0; width: 100vw; border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0; }
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
/* === Depth-of-market ladder === */
|
|
1837
|
+
|
|
1838
|
+
.tcw-ladder {
|
|
1839
|
+
position: absolute;
|
|
1840
|
+
top: 50px;
|
|
1841
|
+
right: 12px;
|
|
1842
|
+
z-index: 41;
|
|
1843
|
+
width: 240px;
|
|
1844
|
+
display: flex;
|
|
1845
|
+
flex-direction: column;
|
|
1846
|
+
background: var(--tcw-bg-elevated);
|
|
1847
|
+
border: 1px solid var(--tcw-border-strong);
|
|
1848
|
+
border-radius: var(--tcw-radius-lg);
|
|
1849
|
+
box-shadow: var(--tcw-shadow-lg);
|
|
1850
|
+
overflow: hidden;
|
|
1851
|
+
animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;
|
|
1852
|
+
}
|
|
1853
|
+
.tcw-ladder-header {
|
|
1854
|
+
display: flex;
|
|
1855
|
+
align-items: center;
|
|
1856
|
+
justify-content: space-between;
|
|
1857
|
+
padding: 10px 12px;
|
|
1858
|
+
font-size: 13px;
|
|
1859
|
+
font-weight: 600;
|
|
1860
|
+
color: var(--tcw-text);
|
|
1861
|
+
border-bottom: 1px solid var(--tcw-border);
|
|
1862
|
+
}
|
|
1863
|
+
.tcw-ladder-close {
|
|
1864
|
+
display: inline-flex;
|
|
1865
|
+
align-items: center;
|
|
1866
|
+
justify-content: center;
|
|
1867
|
+
width: 26px;
|
|
1868
|
+
height: 26px;
|
|
1869
|
+
border: none;
|
|
1870
|
+
background: transparent;
|
|
1871
|
+
color: var(--tcw-text-muted);
|
|
1872
|
+
border-radius: var(--tcw-radius-sm);
|
|
1873
|
+
cursor: pointer;
|
|
1874
|
+
}
|
|
1875
|
+
.tcw-ladder-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }
|
|
1876
|
+
.tcw-ladder-cols {
|
|
1877
|
+
display: grid;
|
|
1878
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
1879
|
+
padding: 4px 0;
|
|
1880
|
+
font-size: 10px;
|
|
1881
|
+
font-weight: 700;
|
|
1882
|
+
text-transform: uppercase;
|
|
1883
|
+
letter-spacing: 0.04em;
|
|
1884
|
+
color: var(--tcw-text-muted);
|
|
1885
|
+
border-bottom: 1px solid var(--tcw-border);
|
|
1886
|
+
}
|
|
1887
|
+
.tcw-ladder-cols span { text-align: center; }
|
|
1888
|
+
.tcw-ladder-body { max-height: 360px; overflow-y: auto; }
|
|
1889
|
+
.tcw-ladder-empty { padding: 18px; text-align: center; font-size: 12px; color: var(--tcw-text-muted); }
|
|
1890
|
+
|
|
1891
|
+
.tcw-ladder-row {
|
|
1892
|
+
display: grid;
|
|
1893
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
1894
|
+
height: 22px;
|
|
1895
|
+
font-variant-numeric: tabular-nums;
|
|
1896
|
+
}
|
|
1897
|
+
.tcw-ladder-cell {
|
|
1898
|
+
position: relative;
|
|
1899
|
+
display: flex;
|
|
1900
|
+
align-items: center;
|
|
1901
|
+
border: none;
|
|
1902
|
+
background: transparent;
|
|
1903
|
+
font-size: 11px;
|
|
1904
|
+
cursor: pointer;
|
|
1905
|
+
font-variant-numeric: tabular-nums;
|
|
1906
|
+
overflow: hidden;
|
|
1907
|
+
}
|
|
1908
|
+
.tcw-ladder-cell:disabled { cursor: default; }
|
|
1909
|
+
/* Depth bar grows from the centre column outward. */
|
|
1910
|
+
.tcw-ladder-cell::before {
|
|
1911
|
+
content: '';
|
|
1912
|
+
position: absolute;
|
|
1913
|
+
top: 1px; bottom: 1px;
|
|
1914
|
+
width: var(--w, 0%);
|
|
1915
|
+
}
|
|
1916
|
+
.tcw-ladder-bid { justify-content: flex-end; padding-right: 8px; color: var(--tcw-green); }
|
|
1917
|
+
.tcw-ladder-bid::before { right: 0; background: var(--tcw-green-soft); }
|
|
1918
|
+
.tcw-ladder-bid span, .tcw-ladder-bid { position: relative; }
|
|
1919
|
+
.tcw-ladder-ask { justify-content: flex-start; padding-left: 8px; color: var(--tcw-red); }
|
|
1920
|
+
.tcw-ladder-ask::before { left: 0; background: var(--tcw-red-soft); }
|
|
1921
|
+
.tcw-ladder-cell:not(:disabled):hover::before { opacity: 0.7; filter: brightness(1.4); }
|
|
1922
|
+
.tcw-ladder-cell > * { position: relative; }
|
|
1923
|
+
.tcw-ladder-price {
|
|
1924
|
+
display: flex;
|
|
1925
|
+
align-items: center;
|
|
1926
|
+
justify-content: center;
|
|
1927
|
+
font-size: 11px;
|
|
1928
|
+
font-weight: 600;
|
|
1929
|
+
color: var(--tcw-text-dim);
|
|
1930
|
+
border-left: 1px solid var(--tcw-border);
|
|
1931
|
+
border-right: 1px solid var(--tcw-border);
|
|
1932
|
+
}
|
|
1933
|
+
.tcw-ladder-price.tcw-ask { color: var(--tcw-red); }
|
|
1934
|
+
.tcw-ladder-price.tcw-bid { color: var(--tcw-green); }
|
|
1935
|
+
|
|
1936
|
+
@media (max-width: 640px) {
|
|
1937
|
+
.tcw-ladder { top: auto; bottom: 0; left: 0; right: 0; width: 100vw; border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0; }
|
|
1938
|
+
.tcw-ladder-body { max-height: 45vh; padding-bottom: max(0px, env(safe-area-inset-bottom)); }
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
/* === Bracket order placement === */
|
|
1942
|
+
|
|
1943
|
+
.tcw-btn-long:hover { color: var(--tcw-green) !important; }
|
|
1944
|
+
.tcw-btn-short:hover { color: var(--tcw-red) !important; }
|
|
1945
|
+
|
|
1946
|
+
.tcw-bracket-bar {
|
|
1947
|
+
position: absolute;
|
|
1948
|
+
top: 52px;
|
|
1949
|
+
left: 50%;
|
|
1950
|
+
transform: translateX(-50%);
|
|
1951
|
+
z-index: 45;
|
|
1952
|
+
display: flex;
|
|
1953
|
+
align-items: center;
|
|
1954
|
+
gap: 10px;
|
|
1955
|
+
padding: 7px 8px 7px 14px;
|
|
1956
|
+
background: var(--tcw-bg-elevated);
|
|
1957
|
+
border: 1px solid var(--tcw-border-strong);
|
|
1958
|
+
border-radius: 999px;
|
|
1959
|
+
box-shadow: var(--tcw-shadow-lg);
|
|
1960
|
+
animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;
|
|
1961
|
+
}
|
|
1962
|
+
.tcw-bracket-label {
|
|
1963
|
+
font-size: 12px;
|
|
1964
|
+
font-weight: 700;
|
|
1965
|
+
}
|
|
1966
|
+
.tcw-bracket-label[data-side='buy'] { color: var(--tcw-green); }
|
|
1967
|
+
.tcw-bracket-label[data-side='sell'] { color: var(--tcw-red); }
|
|
1968
|
+
.tcw-bracket-hint {
|
|
1969
|
+
font-size: 11px;
|
|
1970
|
+
color: var(--tcw-text-muted);
|
|
1971
|
+
}
|
|
1972
|
+
.tcw-bracket-cancel, .tcw-bracket-confirm {
|
|
1973
|
+
display: inline-flex;
|
|
1974
|
+
align-items: center;
|
|
1975
|
+
gap: 5px;
|
|
1976
|
+
height: 30px;
|
|
1977
|
+
padding: 0 12px;
|
|
1978
|
+
font-size: 12px;
|
|
1979
|
+
font-weight: 600;
|
|
1980
|
+
border: none;
|
|
1981
|
+
border-radius: 999px;
|
|
1982
|
+
cursor: pointer;
|
|
1983
|
+
}
|
|
1984
|
+
.tcw-bracket-cancel {
|
|
1985
|
+
color: var(--tcw-text-dim);
|
|
1986
|
+
background: var(--tcw-bg-surface);
|
|
1987
|
+
}
|
|
1988
|
+
.tcw-bracket-cancel:hover { color: var(--tcw-text); }
|
|
1989
|
+
.tcw-bracket-confirm {
|
|
1990
|
+
color: #fff;
|
|
1991
|
+
background: var(--tcw-accent);
|
|
1992
|
+
}
|
|
1993
|
+
.tcw-bracket-confirm:hover { background: var(--tcw-accent-hover); }
|
|
1994
|
+
|
|
1995
|
+
@media (max-width: 640px) {
|
|
1996
|
+
.tcw-bracket-bar { width: calc(100vw - 24px); justify-content: space-between; }
|
|
1997
|
+
.tcw-bracket-hint { display: none; }
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
/* === Drawing style + templates popover === */
|
|
2001
|
+
|
|
2002
|
+
.tcw-style-panel {
|
|
2003
|
+
position: absolute;
|
|
2004
|
+
bottom: 12px;
|
|
2005
|
+
left: 52px;
|
|
2006
|
+
z-index: 40;
|
|
2007
|
+
width: 220px;
|
|
2008
|
+
display: flex;
|
|
2009
|
+
flex-direction: column;
|
|
2010
|
+
gap: 8px;
|
|
2011
|
+
padding: 12px;
|
|
2012
|
+
background: var(--tcw-bg-elevated);
|
|
2013
|
+
border: 1px solid var(--tcw-border-strong);
|
|
2014
|
+
border-radius: var(--tcw-radius-lg);
|
|
2015
|
+
box-shadow: var(--tcw-shadow-lg);
|
|
2016
|
+
animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;
|
|
2017
|
+
}
|
|
2018
|
+
.tcw-style-header {
|
|
2019
|
+
display: flex;
|
|
2020
|
+
align-items: center;
|
|
2021
|
+
justify-content: space-between;
|
|
2022
|
+
font-size: 12px;
|
|
2023
|
+
font-weight: 600;
|
|
2024
|
+
color: var(--tcw-text);
|
|
2025
|
+
}
|
|
2026
|
+
.tcw-style-close {
|
|
2027
|
+
display: inline-flex;
|
|
2028
|
+
align-items: center;
|
|
2029
|
+
justify-content: center;
|
|
2030
|
+
width: 24px;
|
|
2031
|
+
height: 24px;
|
|
2032
|
+
border: none;
|
|
2033
|
+
background: transparent;
|
|
2034
|
+
color: var(--tcw-text-muted);
|
|
2035
|
+
border-radius: var(--tcw-radius-sm);
|
|
2036
|
+
cursor: pointer;
|
|
2037
|
+
}
|
|
2038
|
+
.tcw-style-close:hover { background: var(--tcw-bg-surface); color: var(--tcw-text); }
|
|
2039
|
+
|
|
2040
|
+
.tcw-style-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
|
2041
|
+
.tcw-style-swatch {
|
|
2042
|
+
width: 18px;
|
|
2043
|
+
height: 18px;
|
|
2044
|
+
border-radius: 50%;
|
|
2045
|
+
border: 1px solid var(--tcw-border-strong);
|
|
2046
|
+
cursor: pointer;
|
|
2047
|
+
padding: 0;
|
|
2048
|
+
}
|
|
2049
|
+
.tcw-style-swatch.tcw-on { outline: 2px solid var(--tcw-accent); outline-offset: 1px; }
|
|
2050
|
+
.tcw-style-picker {
|
|
2051
|
+
width: 22px;
|
|
2052
|
+
height: 22px;
|
|
2053
|
+
padding: 0;
|
|
2054
|
+
border: 1px solid var(--tcw-border);
|
|
2055
|
+
border-radius: var(--tcw-radius-sm);
|
|
2056
|
+
background: transparent;
|
|
2057
|
+
cursor: pointer;
|
|
2058
|
+
}
|
|
2059
|
+
.tcw-style-width, .tcw-style-dash {
|
|
2060
|
+
flex: 1;
|
|
2061
|
+
min-width: 0;
|
|
2062
|
+
height: 26px;
|
|
2063
|
+
display: flex;
|
|
2064
|
+
align-items: center;
|
|
2065
|
+
justify-content: center;
|
|
2066
|
+
background: var(--tcw-bg-surface);
|
|
2067
|
+
border: 1px solid var(--tcw-border);
|
|
2068
|
+
border-radius: var(--tcw-radius-sm);
|
|
2069
|
+
color: var(--tcw-text-dim);
|
|
2070
|
+
cursor: pointer;
|
|
2071
|
+
font-size: 11px;
|
|
2072
|
+
}
|
|
2073
|
+
.tcw-style-width span { width: 16px; background: currentColor; border-radius: 2px; }
|
|
2074
|
+
.tcw-style-width.tcw-on, .tcw-style-dash.tcw-on {
|
|
2075
|
+
border-color: var(--tcw-accent);
|
|
2076
|
+
color: var(--tcw-accent);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
.tcw-style-subhead {
|
|
2080
|
+
font-size: 10px;
|
|
2081
|
+
font-weight: 700;
|
|
2082
|
+
text-transform: uppercase;
|
|
2083
|
+
letter-spacing: 0.05em;
|
|
2084
|
+
color: var(--tcw-text-muted);
|
|
2085
|
+
margin-top: 2px;
|
|
2086
|
+
}
|
|
2087
|
+
.tcw-style-save { display: flex; gap: 6px; }
|
|
2088
|
+
.tcw-style-name {
|
|
2089
|
+
flex: 1;
|
|
2090
|
+
min-width: 0;
|
|
2091
|
+
height: 28px;
|
|
2092
|
+
padding: 0 8px;
|
|
2093
|
+
font-size: 12px;
|
|
2094
|
+
color: var(--tcw-text);
|
|
2095
|
+
background: var(--tcw-bg-surface);
|
|
2096
|
+
border: 1px solid var(--tcw-border);
|
|
2097
|
+
border-radius: var(--tcw-radius-sm);
|
|
2098
|
+
outline: none;
|
|
2099
|
+
}
|
|
2100
|
+
.tcw-style-name:focus { border-color: var(--tcw-accent); }
|
|
2101
|
+
.tcw-style-savebtn {
|
|
2102
|
+
display: inline-flex;
|
|
2103
|
+
align-items: center;
|
|
2104
|
+
gap: 4px;
|
|
2105
|
+
padding: 0 10px;
|
|
2106
|
+
height: 28px;
|
|
2107
|
+
font-size: 12px;
|
|
2108
|
+
font-weight: 600;
|
|
2109
|
+
color: #fff;
|
|
2110
|
+
background: var(--tcw-accent);
|
|
2111
|
+
border: none;
|
|
2112
|
+
border-radius: var(--tcw-radius-sm);
|
|
2113
|
+
cursor: pointer;
|
|
2114
|
+
}
|
|
2115
|
+
.tcw-style-savebtn:hover { background: var(--tcw-accent-hover); }
|
|
2116
|
+
|
|
2117
|
+
.tcw-style-templates { display: flex; flex-direction: column; gap: 2px; max-height: 140px; overflow-y: auto; }
|
|
2118
|
+
.tcw-style-empty { font-size: 11px; color: var(--tcw-text-muted); padding: 4px 0; }
|
|
2119
|
+
.tcw-style-template { display: flex; align-items: center; gap: 4px; }
|
|
2120
|
+
.tcw-style-apply {
|
|
2121
|
+
flex: 1;
|
|
2122
|
+
min-width: 0;
|
|
2123
|
+
display: flex;
|
|
2124
|
+
align-items: center;
|
|
2125
|
+
gap: 7px;
|
|
2126
|
+
padding: 5px 7px;
|
|
2127
|
+
font-size: 12px;
|
|
2128
|
+
color: var(--tcw-text);
|
|
2129
|
+
background: transparent;
|
|
2130
|
+
border: none;
|
|
2131
|
+
border-radius: var(--tcw-radius-sm);
|
|
2132
|
+
cursor: pointer;
|
|
2133
|
+
text-align: left;
|
|
2134
|
+
}
|
|
2135
|
+
.tcw-style-apply:hover { background: var(--tcw-bg-surface); }
|
|
2136
|
+
.tcw-style-tdot { flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%; }
|
|
2137
|
+
.tcw-style-tdel {
|
|
2138
|
+
display: inline-flex;
|
|
2139
|
+
align-items: center;
|
|
2140
|
+
justify-content: center;
|
|
2141
|
+
width: 26px;
|
|
2142
|
+
height: 26px;
|
|
2143
|
+
border: none;
|
|
2144
|
+
background: transparent;
|
|
2145
|
+
color: var(--tcw-text-muted);
|
|
2146
|
+
border-radius: var(--tcw-radius-sm);
|
|
2147
|
+
cursor: pointer;
|
|
2148
|
+
}
|
|
2149
|
+
.tcw-style-tdel:hover { background: var(--tcw-red-soft); color: var(--tcw-red); }
|
|
2150
|
+
|
|
2151
|
+
/* === Settings range slider === */
|
|
2152
|
+
|
|
2153
|
+
.tcw-settings-range {
|
|
2154
|
+
display: flex;
|
|
2155
|
+
align-items: center;
|
|
2156
|
+
gap: 8px;
|
|
2157
|
+
}
|
|
2158
|
+
.tcw-settings-range input[type='range'] {
|
|
2159
|
+
width: 110px;
|
|
2160
|
+
accent-color: var(--tcw-accent);
|
|
2161
|
+
cursor: pointer;
|
|
2162
|
+
}
|
|
2163
|
+
.tcw-settings-range-val {
|
|
2164
|
+
min-width: 38px;
|
|
2165
|
+
text-align: right;
|
|
2166
|
+
font-size: 12px;
|
|
2167
|
+
font-variant-numeric: tabular-nums;
|
|
2168
|
+
color: var(--tcw-text-dim);
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
/* === Indicator settings dialog === */
|
|
2172
|
+
|
|
2173
|
+
.tcw-modal-narrow {
|
|
2174
|
+
max-width: 360px;
|
|
2175
|
+
}
|
|
2176
|
+
.tcw-indi-input {
|
|
2177
|
+
width: 110px;
|
|
2178
|
+
height: 30px;
|
|
2179
|
+
padding: 0 8px;
|
|
2180
|
+
font-size: 12px;
|
|
2181
|
+
color: var(--tcw-text);
|
|
2182
|
+
background: var(--tcw-bg-surface);
|
|
2183
|
+
border: 1px solid var(--tcw-border);
|
|
2184
|
+
border-radius: var(--tcw-radius-sm);
|
|
2185
|
+
outline: none;
|
|
2186
|
+
font-variant-numeric: tabular-nums;
|
|
2187
|
+
}
|
|
2188
|
+
.tcw-indi-input:focus {
|
|
2189
|
+
border-color: var(--tcw-accent);
|
|
2190
|
+
box-shadow: 0 0 0 2px var(--tcw-accent-soft);
|
|
2191
|
+
}
|
|
2192
|
+
.tcw-indi-color {
|
|
2193
|
+
width: 36px;
|
|
2194
|
+
height: 28px;
|
|
2195
|
+
padding: 2px;
|
|
2196
|
+
background: var(--tcw-bg-surface);
|
|
2197
|
+
border: 1px solid var(--tcw-border);
|
|
2198
|
+
border-radius: var(--tcw-radius-sm);
|
|
2199
|
+
cursor: pointer;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
/* === Object tree panel === */
|
|
2203
|
+
|
|
2204
|
+
.tcw-tree-panel {
|
|
2205
|
+
position: absolute;
|
|
2206
|
+
top: 50px;
|
|
2207
|
+
right: 12px;
|
|
2208
|
+
z-index: 39;
|
|
2209
|
+
width: 280px;
|
|
2210
|
+
max-width: calc(100vw - 24px);
|
|
2211
|
+
display: flex;
|
|
2212
|
+
flex-direction: column;
|
|
2213
|
+
background: var(--tcw-bg-elevated);
|
|
2214
|
+
border: 1px solid var(--tcw-border-strong);
|
|
2215
|
+
border-radius: var(--tcw-radius-lg);
|
|
2216
|
+
box-shadow: var(--tcw-shadow-lg);
|
|
2217
|
+
overflow: hidden;
|
|
2218
|
+
animation: tcw-alerts-in var(--tcw-dur, 160ms) var(--tcw-ease, ease) both;
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
.tcw-tree-header {
|
|
2222
|
+
display: flex;
|
|
2223
|
+
align-items: center;
|
|
2224
|
+
justify-content: space-between;
|
|
2225
|
+
padding: 10px 12px;
|
|
2226
|
+
font-weight: 600;
|
|
2227
|
+
font-size: 13px;
|
|
2228
|
+
color: var(--tcw-text);
|
|
2229
|
+
border-bottom: 1px solid var(--tcw-border);
|
|
2230
|
+
}
|
|
2231
|
+
.tcw-tree-close {
|
|
2232
|
+
display: inline-flex;
|
|
2233
|
+
align-items: center;
|
|
2234
|
+
justify-content: center;
|
|
2235
|
+
width: 26px;
|
|
2236
|
+
height: 26px;
|
|
2237
|
+
border: none;
|
|
2238
|
+
background: transparent;
|
|
2239
|
+
color: var(--tcw-text-muted);
|
|
2240
|
+
border-radius: var(--tcw-radius-sm);
|
|
2241
|
+
cursor: pointer;
|
|
2242
|
+
}
|
|
2243
|
+
.tcw-tree-close:hover {
|
|
2244
|
+
background: var(--tcw-bg-surface);
|
|
2245
|
+
color: var(--tcw-text);
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
.tcw-tree-section {
|
|
2249
|
+
padding: 6px;
|
|
2250
|
+
border-bottom: 1px solid var(--tcw-border);
|
|
2251
|
+
}
|
|
2252
|
+
.tcw-tree-section:last-child {
|
|
2253
|
+
border-bottom: none;
|
|
2254
|
+
}
|
|
2255
|
+
.tcw-tree-section-head {
|
|
2256
|
+
display: flex;
|
|
2257
|
+
align-items: center;
|
|
2258
|
+
justify-content: space-between;
|
|
2259
|
+
padding: 6px 8px 4px;
|
|
2260
|
+
font-size: 10px;
|
|
2261
|
+
font-weight: 700;
|
|
2262
|
+
text-transform: uppercase;
|
|
2263
|
+
letter-spacing: 0.05em;
|
|
2264
|
+
color: var(--tcw-text-muted);
|
|
2265
|
+
}
|
|
2266
|
+
.tcw-tree-add {
|
|
2267
|
+
display: inline-flex;
|
|
2268
|
+
align-items: center;
|
|
2269
|
+
justify-content: center;
|
|
2270
|
+
width: 22px;
|
|
2271
|
+
height: 22px;
|
|
2272
|
+
border: none;
|
|
2273
|
+
background: transparent;
|
|
2274
|
+
color: var(--tcw-text-muted);
|
|
2275
|
+
border-radius: var(--tcw-radius-sm);
|
|
2276
|
+
cursor: pointer;
|
|
2277
|
+
}
|
|
2278
|
+
.tcw-tree-add:hover {
|
|
2279
|
+
background: var(--tcw-accent-soft);
|
|
2280
|
+
color: var(--tcw-accent);
|
|
2281
|
+
}
|
|
2282
|
+
.tcw-tree-dot {
|
|
2283
|
+
flex-shrink: 0;
|
|
2284
|
+
width: 8px;
|
|
2285
|
+
height: 8px;
|
|
2286
|
+
border-radius: 50%;
|
|
2287
|
+
}
|
|
2288
|
+
.tcw-tree-list {
|
|
2289
|
+
max-height: 200px;
|
|
2290
|
+
overflow-y: auto;
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
.tcw-tree-row {
|
|
2294
|
+
display: flex;
|
|
2295
|
+
align-items: center;
|
|
2296
|
+
justify-content: space-between;
|
|
2297
|
+
gap: 8px;
|
|
2298
|
+
padding: 6px 8px;
|
|
2299
|
+
border-radius: var(--tcw-radius-sm);
|
|
2300
|
+
}
|
|
2301
|
+
.tcw-tree-row:hover {
|
|
2302
|
+
background: var(--tcw-bg-surface);
|
|
2303
|
+
}
|
|
2304
|
+
.tcw-tree-hidden .tcw-tree-name {
|
|
2305
|
+
opacity: 0.5;
|
|
2306
|
+
}
|
|
2307
|
+
.tcw-tree-name {
|
|
2308
|
+
min-width: 0;
|
|
2309
|
+
font-size: 12px;
|
|
2310
|
+
color: var(--tcw-text);
|
|
2311
|
+
overflow: hidden;
|
|
2312
|
+
text-overflow: ellipsis;
|
|
2313
|
+
white-space: nowrap;
|
|
2314
|
+
}
|
|
2315
|
+
.tcw-tree-actions {
|
|
2316
|
+
display: flex;
|
|
2317
|
+
align-items: center;
|
|
2318
|
+
gap: 2px;
|
|
2319
|
+
flex-shrink: 0;
|
|
2320
|
+
}
|
|
2321
|
+
.tcw-tree-btn {
|
|
2322
|
+
display: inline-flex;
|
|
2323
|
+
align-items: center;
|
|
2324
|
+
justify-content: center;
|
|
2325
|
+
width: 26px;
|
|
2326
|
+
height: 26px;
|
|
2327
|
+
border: none;
|
|
2328
|
+
background: transparent;
|
|
2329
|
+
color: var(--tcw-text-muted);
|
|
2330
|
+
border-radius: var(--tcw-radius-sm);
|
|
2331
|
+
cursor: pointer;
|
|
2332
|
+
}
|
|
2333
|
+
.tcw-tree-btn:hover {
|
|
2334
|
+
background: var(--tcw-bg-elevated);
|
|
2335
|
+
color: var(--tcw-text);
|
|
2336
|
+
}
|
|
2337
|
+
.tcw-tree-btn.tcw-tree-on {
|
|
2338
|
+
color: var(--tcw-accent);
|
|
2339
|
+
}
|
|
2340
|
+
.tcw-tree-btn.tcw-tree-del:hover {
|
|
2341
|
+
background: var(--tcw-red-soft);
|
|
2342
|
+
color: var(--tcw-red);
|
|
2343
|
+
}
|
|
2344
|
+
.tcw-tree-empty {
|
|
2345
|
+
padding: 8px;
|
|
2346
|
+
font-size: 12px;
|
|
2347
|
+
color: var(--tcw-text-muted);
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
@media (max-width: 640px) {
|
|
2351
|
+
.tcw-tree-panel {
|
|
2352
|
+
top: auto;
|
|
2353
|
+
bottom: 0;
|
|
2354
|
+
left: 0;
|
|
2355
|
+
right: 0;
|
|
2356
|
+
width: 100vw;
|
|
2357
|
+
max-width: 100vw;
|
|
2358
|
+
border-radius: var(--tcw-radius-xl) var(--tcw-radius-xl) 0 0;
|
|
2359
|
+
}
|
|
2360
|
+
.tcw-tree-list {
|
|
2361
|
+
max-height: 30vh;
|
|
2362
|
+
}
|
|
2363
|
+
.tcw-tree-section:last-child {
|
|
2364
|
+
padding-bottom: max(6px, env(safe-area-inset-bottom));
|
|
1433
2365
|
}
|
|
1434
2366
|
}
|
|
1435
2367
|
|
|
@@ -1444,13 +2376,13 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
|
|
|
1444
2376
|
transition-duration: 0.01ms !important;
|
|
1445
2377
|
}
|
|
1446
2378
|
}
|
|
1447
|
-
`,u=0,d=`tcw-styles`;function f(){if(u++,u>1||document.getElementById(d))return;let e=document.createElement(`style`);e.id=d,e.textContent=l,document.head.appendChild(e)}function p(){if(u--,u>0)return;let e=document.getElementById(d);e&&e.remove()}var m={cursor:`<path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"/><path d="M13 13l6 6"/>`,trendingUp:`<polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/>`,minus:`<path d="M5 12h14"/>`,penLine:`<path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/>`,hash:`<line x1="4" y1="9" x2="20" y2="9"/><line x1="4" y1="15" x2="20" y2="15"/><line x1="10" y1="3" x2="8" y2="21"/><line x1="16" y1="3" x2="14" y2="21"/>`,square:`<rect width="18" height="18" x="3" y="3" rx="2"/>`,gitBranch:`<line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>`,ruler:`<path d="M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z"/><path d="m14.5 12.5 2-2"/><path d="m11.5 9.5 2-2"/><path d="m8.5 6.5 2-2"/><path d="m17.5 15.5 2-2"/>`,type:`<polyline points="4 7 4 4 20 4 20 7"/><line x1="9" y1="20" x2="15" y2="20"/><line x1="12" y1="4" x2="12" y2="20"/>`,magnet:`<path d="m6 15-4-4 6.75-6.77a7.79 7.79 0 0 1 11 11L13 22l-4-4 6.39-6.36a2.14 2.14 0 0 0-3-3L6 15"/><path d="m5 8 4 4"/><path d="m12 15 4 4"/>`,undo:`<path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13"/>`,redo:`<path d="M21 7v6h-6"/><path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13"/>`,trash:`<path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/>`,camera:`<path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/>`,settings:`<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/>`,moon:`<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>`,sun:`<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>`,chevronDown:`<path d="m6 9 6 6 6-6"/>`,chevronUp:`<path d="m18 15-6-6-6 6"/>`,barChart:`<line x1="12" y1="20" x2="12" y2="10"/><line x1="18" y1="20" x2="18" y2="4"/><line x1="6" y1="20" x2="6" y2="16"/>`,x:`<path d="M18 6 6 18"/><path d="m6 6 12 12"/>`,play:`<polygon points="6 3 20 12 6 21 6 3"/>`,pause:`<rect width="4" height="16" x="6" y="4"/><rect width="4" height="16" x="14" y="4"/>`,stop:`<rect width="14" height="14" x="5" y="5" rx="1"/>`,receipt:`<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z"/><path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8"/><path d="M12 17.5v-11"/>`};function h(e,t=14){let n=m[e];return n?`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${n}</svg>`:``}var g=class{trigger;panel;_isOpen=!1;onOutsideClick;onEscapeKey;onTriggerClick;constructor(e,t={}){this.trigger=e,this.panel=document.createElement(`div`),this.panel.className=`tcw-dropdown`,this.panel.style.width=t.width??`200px`,t.align===`right`?this.panel.style.right=`0`:this.panel.style.left=`0`,this.panel.style.display=`none`,e.style.position=`relative`,e.appendChild(this.panel),this.onTriggerClick=()=>{this._isOpen?this.close():this.open()},this.onOutsideClick=e=>{this.trigger.contains(e.target)||this.close()},this.onEscapeKey=e=>{e.key===`Escape`&&this.close()},e.addEventListener(`click`,this.onTriggerClick)}setContent(e){this.panel.innerHTML=e}open(){this._isOpen||(this._isOpen=!0,this.panel.style.display=``,document.addEventListener(`mousedown`,this.onOutsideClick),document.addEventListener(`keydown`,this.onEscapeKey))}close(){this._isOpen&&(this._isOpen=!1,this.panel.style.display=`none`,document.removeEventListener(`mousedown`,this.onOutsideClick),document.removeEventListener(`keydown`,this.onEscapeKey))}isOpen(){return this._isOpen}destroy(){this.trigger.removeEventListener(`click`,this.onTriggerClick),document.removeEventListener(`mousedown`,this.onOutsideClick),document.removeEventListener(`keydown`,this.onEscapeKey),this.panel.remove()}},_=class{config;callbacks;el;chartTypeDropdown=null;indicatorDropdown=null;tfButtons=[];chipsContainer=null;themeBtn=null;constructor(e,t,n){this.config=t,this.callbacks=n,this.el=document.createElement(`div`),this.el.className=`tcw-toolbar`,this.build(),e.appendChild(this.el)}build(){let{config:e,callbacks:t,el:n}=this,r=document.createElement(`button`);r.className=`tcw-toolbar-symbol`,r.dataset.role=`symbol`,r.addEventListener(`click`,t.onSymbolClick),n.appendChild(r),n.appendChild(this.sep());let i=document.createElement(`div`);i.className=`tcw-toolbar-group`;for(let n of e.timeframes){let e=document.createElement(`button`);e.className=`tcw-btn`,e.textContent=n.label,e.dataset.tf=n.value,e.addEventListener(`click`,()=>t.onTimeframe(n.value)),i.appendChild(e),this.tfButtons.push(e)}n.appendChild(i),n.appendChild(this.sep());let a=document.createElement(`div`);a.style.position=`relative`,a.style.display=`inline-flex`;let o=document.createElement(`button`);o.className=`tcw-dropdown-trigger`,o.dataset.role=`charttype`,a.appendChild(o),n.appendChild(a),this.chartTypeDropdown=new g(a,{width:`160px`}),this.buildChartTypeMenu(),n.appendChild(this.sep());let s=document.createElement(`div`);s.style.position=`relative`,s.style.display=`inline-flex`;let c=document.createElement(`button`);if(c.className=`tcw-dropdown-trigger`,c.dataset.role=`indicators`,s.appendChild(c),n.appendChild(s),this.indicatorDropdown=new g(s,{width:`280px`}),this.buildIndicatorMenu(),this.chipsContainer=document.createElement(`div`),this.chipsContainer.className=`tcw-indicator-chips`,n.appendChild(this.chipsContainer),n.appendChild(this.spacer()),t.onToggleReplay){let e=this.iconBtn(`play`,`Bar replay`,t.onToggleReplay);e.dataset.role=`replay`,n.appendChild(e)}let l=this.iconBtn(`camera`,`Screenshot`,t.onScreenshot);n.appendChild(l);let u=this.iconBtn(`settings`,`Chart Settings`,t.onSettings);n.appendChild(u),this.themeBtn=this.iconBtn(`moon`,`Toggle theme`,t.onToggleTheme),this.themeBtn.dataset.role=`theme`,n.appendChild(this.themeBtn)}buildChartTypeMenu(){if(!this.chartTypeDropdown)return;let e=this.config.chartTypes.map(e=>`<button class="tcw-dropdown-item" data-ct="${e.value}">${e.label}</button>`).join(``);this.chartTypeDropdown.setContent(e),this.chartTypeDropdown.panel.querySelectorAll(`.tcw-dropdown-item`).forEach(e=>{e.addEventListener(`click`,e=>{let t=e.currentTarget.dataset.ct;this.callbacks.onChartType(t),this.chartTypeDropdown?.close()})})}buildIndicatorMenu(){if(!this.indicatorDropdown)return;let{indicators:e,popularIndicatorIds:t}=this.config,n=e.filter(e=>t.includes(e.id)),r=e.filter(e=>!t.includes(e.id)),i=`<div class="tcw-dropdown-label">Popular</div>`;for(let e of n)i+=`<button class="tcw-dropdown-item" data-ind="${e.id}"><span>${e.name}</span><span class="tcw-tag">${e.type}</span></button>`;i+=`<div class="tcw-dropdown-divider"></div>`,i+=`<div class="tcw-dropdown-label">All</div>`;for(let e of r)i+=`<button class="tcw-dropdown-item" data-ind="${e.id}"><span>${e.name}</span><span class="tcw-tag">${e.type}</span></button>`;this.indicatorDropdown.setContent(i),this.indicatorDropdown.panel.querySelectorAll(`.tcw-dropdown-item[data-ind]`).forEach(e=>{e.addEventListener(`click`,e=>{let t=e.currentTarget.dataset.ind;this.callbacks.onAddIndicator(t)})})}update(e){let t=this.el.querySelector(`[data-role="symbol"]`);t&&(t.textContent=e.symbol);for(let t of this.tfButtons)t.classList.toggle(`tcw-active`,t.dataset.tf===e.timeframe);let n=this.el.querySelector(`[data-role="charttype"]`);if(n){let t=this.config.chartTypes.find(t=>t.value===e.chartType)?.label??`Candles`;n.innerHTML=`${h(`barChart`,14)} ${t} ${h(`chevronDown`,12)}`}let r=this.el.querySelector(`[data-role="indicators"]`);if(r){let t=e.activeIndicators.size,n=`${h(`trendingUp`,14)} Indicators`;t>0&&(n+=` <span class="tcw-badge-count">${t}</span>`),r.innerHTML=n}if(this.chipsContainer){let t=this.getActiveIndicatorList(e);this.chipsContainer.innerHTML=``;for(let e of t){let t=document.createElement(`div`);t.className=`tcw-indicator-chip`;let n=document.createElement(`span`);n.textContent=e.label,t.appendChild(n);let r=document.createElement(`button`);r.className=`tcw-chip-remove`,r.innerHTML=h(`x`,10),r.addEventListener(`click`,()=>this.callbacks.onRemoveIndicator(e.instanceId)),t.appendChild(r),this.chipsContainer.appendChild(t)}}this.themeBtn&&(this.themeBtn.innerHTML=e.isDark?h(`moon`,14):h(`sun`,14))}getActiveIndicatorList(e){let t=[];for(let[n,r]of e.activeIndicators.entries())t.push({instanceId:r,id:n,label:n.toUpperCase()});return t}sep(){let e=document.createElement(`span`);return e.className=`tcw-toolbar-sep`,e}spacer(){let e=document.createElement(`span`);return e.className=`tcw-toolbar-spacer`,e}iconBtn(e,t,n){let r=document.createElement(`button`);return r.className=`tcw-btn-icon`,r.title=t,r.innerHTML=h(e,14),r.addEventListener(`click`,n),r}destroy(){this.chartTypeDropdown?.destroy(),this.indicatorDropdown?.destroy(),this.el.remove()}},v=[`trendingUp`,`minus`,`penLine`,`hash`,`square`,`gitBranch`,`ruler`,`type`],y=class{config;callbacks;el;groupWraps=[];groupButtons=[];cursorBtn=null;magnetBtn=null;flyoutEl=null;constructor(e,t,n){this.config=t,this.callbacks=n,this.el=document.createElement(`div`),this.el.className=`tcw-sidebar`,this.build(),e.appendChild(this.el)}build(){let{config:e,callbacks:t,el:n}=this;this.cursorBtn=document.createElement(`button`),this.cursorBtn.className=`tcw-sidebar-btn`,this.cursorBtn.title=`Cursor`,this.cursorBtn.innerHTML=h(`cursor`,14),this.cursorBtn.addEventListener(`click`,t.onCancelDrawing),n.appendChild(this.cursorBtn),n.appendChild(this.divider()),e.drawingToolGroups.forEach((e,r)=>{let i=document.createElement(`div`);i.className=`tcw-tool-group-wrap`;let a=document.createElement(`button`);if(a.className=`tcw-sidebar-btn`,a.title=e.label,a.innerHTML=h(v[r]??`square`,14),e.tools.length>1){let e=document.createElement(`span`);e.className=`tcw-multi-dot`,a.appendChild(e)}a.addEventListener(`click`,()=>t.onDrawingTool(e.tools[0].value)),i.appendChild(a),i.addEventListener(`mouseenter`,()=>this.showFlyout(r)),i.addEventListener(`mouseleave`,()=>this.hideFlyout()),n.appendChild(i),this.groupWraps.push(i),this.groupButtons.push(a)});let r=document.createElement(`div`);r.className=`tcw-sidebar-spacer`,n.appendChild(r),n.appendChild(this.divider()),this.magnetBtn=document.createElement(`button`),this.magnetBtn.className=`tcw-sidebar-btn`,this.magnetBtn.title=`Magnet`,this.magnetBtn.innerHTML=h(`magnet`,14),this.magnetBtn.addEventListener(`click`,t.onToggleMagnet),n.appendChild(this.magnetBtn);let i=document.createElement(`button`);i.className=`tcw-sidebar-btn`,i.title=`Undo`,i.innerHTML=h(`undo`,14),i.addEventListener(`click`,t.onUndo),n.appendChild(i);let a=document.createElement(`button`);a.className=`tcw-sidebar-btn`,a.title=`Redo`,a.innerHTML=h(`redo`,14),a.addEventListener(`click`,t.onRedo),n.appendChild(a);let o=document.createElement(`button`);o.className=`tcw-sidebar-btn tcw-danger`,o.title=`Clear all`,o.innerHTML=h(`trash`,14),o.addEventListener(`click`,t.onClearDrawings),n.appendChild(o)}showFlyout(e){let t=this.config.drawingToolGroups[e];if(!t||t.tools.length<=1)return;this.hideFlyout();let n=document.createElement(`div`);n.className=`tcw-flyout`;let r=document.createElement(`div`);r.className=`tcw-flyout-header`,r.textContent=t.label,n.appendChild(r);for(let e of t.tools){let t=document.createElement(`button`);t.className=`tcw-flyout-item`,t.textContent=e.label,t.dataset.toolValue=e.value,t.addEventListener(`click`,()=>{this.callbacks.onDrawingTool(e.value),this.hideFlyout()}),n.appendChild(t)}this.flyoutEl=n,this.groupWraps[e].appendChild(n)}hideFlyout(){this.flyoutEl&&=(this.flyoutEl.remove(),null)}update(e){this.cursorBtn&&this.cursorBtn.classList.toggle(`tcw-active`,e.activeTool===null);let{drawingToolGroups:t}=this.config;for(let n=0;n<t.length;n++){let r=t[n].tools.some(t=>t.value===e.activeTool);this.groupButtons[n].classList.toggle(`tcw-active`,r)}this.flyoutEl&&this.flyoutEl.querySelectorAll(`.tcw-flyout-item`).forEach(t=>{let n=t;n.classList.toggle(`tcw-active`,n.dataset.toolValue===e.activeTool)}),this.magnetBtn&&(this.magnetBtn.classList.toggle(`tcw-active`,e.magnetEnabled),this.magnetBtn.title=e.magnetEnabled?`Magnet ON`:`Magnet OFF`)}divider(){let e=document.createElement(`div`);return e.className=`tcw-sidebar-divider`,e}destroy(){this.hideFlyout(),this.el.remove()}},b=[`style`,`display`,`scale`],x=class{callbacks;backdrop=null;modal=null;currentTab=`style`;currentSettings=null;bodyEl=null;tabButtons=[];constructor(e){this.callbacks=e}open(e){this.currentSettings={...e},this.currentTab=`style`,this.buildModal()}close(){this.backdrop?.remove(),this.modal?.remove(),this.backdrop=null,this.modal=null,this.bodyEl=null,this.tabButtons=[]}buildModal(){this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.addEventListener(`click`,()=>{this.callbacks.onClose(),this.close()}),document.body.appendChild(this.backdrop),this.modal=document.createElement(`div`),this.modal.className=`tcw-modal`;let e=document.createElement(`div`);e.className=`tcw-modal-header`;let t=document.createElement(`h3`);t.textContent=`Chart Settings`,e.appendChild(t);let n=document.createElement(`button`);n.className=`tcw-modal-close`,n.innerHTML=h(`x`,16),n.addEventListener(`click`,()=>{this.callbacks.onClose(),this.close()}),e.appendChild(n),this.modal.appendChild(e);let r=document.createElement(`div`);r.className=`tcw-modal-tabs`,this.tabButtons=[];for(let e of b){let t=document.createElement(`button`);t.className=`tcw-modal-tab`,t.textContent=e,t.dataset.tab=e,e===this.currentTab&&t.classList.add(`tcw-active`),t.addEventListener(`click`,()=>{this.currentTab=e,this.tabButtons.forEach(t=>t.classList.toggle(`tcw-active`,t.dataset.tab===e)),this.renderTabContent()}),r.appendChild(t),this.tabButtons.push(t)}this.modal.appendChild(r),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`tcw-modal-body`,this.modal.appendChild(this.bodyEl),this.renderTabContent();let i=document.createElement(`div`);i.className=`tcw-modal-footer`;let a=document.createElement(`button`);a.className=`tcw-reset-link`,a.textContent=`Reset to defaults`,a.addEventListener(`click`,()=>this.callbacks.onReset()),i.appendChild(a);let o=document.createElement(`button`);o.className=`tcw-done-btn`,o.textContent=`Done`,o.addEventListener(`click`,()=>{this.callbacks.onClose(),this.close()}),i.appendChild(o),this.modal.appendChild(i),document.body.appendChild(this.modal);let s=e=>{e.key===`Escape`&&(document.removeEventListener(`keydown`,s),this.callbacks.onClose(),this.close())};document.addEventListener(`keydown`,s)}renderTabContent(){if(!(!this.bodyEl||!this.currentSettings))switch(this.bodyEl.innerHTML=``,this.currentTab){case`style`:this.renderStyleTab();break;case`display`:this.renderDisplayTab();break;case`scale`:this.renderScaleTab();break}}renderStyleTab(){if(!this.bodyEl||!this.currentSettings)return;let e=this.currentSettings,t=this.section(`Candle Colors`);t.appendChild(this.colorRow(`Up Body`,e.candleUpColor,e=>this.patch({candleUpColor:e}))),t.appendChild(this.colorRow(`Down Body`,e.candleDownColor,e=>this.patch({candleDownColor:e}))),t.appendChild(this.colorRow(`Up Wick`,e.candleUpWick,e=>this.patch({candleUpWick:e}))),t.appendChild(this.colorRow(`Down Wick`,e.candleDownWick,e=>this.patch({candleDownWick:e}))),this.bodyEl.appendChild(t);let n=this.section(`Background`);n.appendChild(this.colorRow(`Background`,e.backgroundColor,e=>this.patch({backgroundColor:e}))),n.appendChild(this.colorRow(`Grid`,e.gridColor,e=>this.patch({gridColor:e}))),this.bodyEl.appendChild(n)}renderDisplayTab(){if(!this.bodyEl||!this.currentSettings)return;let e=this.currentSettings,t=this.section();t.appendChild(this.toggleRow(`Grid Lines`,e.gridVisible,e=>this.patch({gridVisible:e}))),t.appendChild(this.toggleRow(`Volume`,e.volumeVisible,e=>this.patch({volumeVisible:e}))),t.appendChild(this.toggleRow(`Volume Profile`,e.volumeProfileVisible,e=>this.patch({volumeProfileVisible:e}))),t.appendChild(this.toggleRow(`OHLC Legend`,e.legendVisible,e=>this.patch({legendVisible:e}))),t.appendChild(this.toggleRow(`Bar Countdown`,e.barCountdown,e=>this.patch({barCountdown:e}))),t.appendChild(this.selectRow(`Crosshair Mode`,e.crosshairMode,[{label:`Magnet`,value:`magnet`},{label:`Normal`,value:`normal`},{label:`Hidden`,value:`hidden`}],e=>this.patch({crosshairMode:e}))),t.appendChild(this.selectRow(`Number Locale`,e.numberLocale,[{label:`en-US (65,234.00)`,value:`en-US`},{label:`de-DE (65.234,00)`,value:`de-DE`},{label:`fr-FR (65 234,00)`,value:`fr-FR`},{label:`vi-VN (65.234,00)`,value:`vi-VN`},{label:`en-IN (65,234.00)`,value:`en-IN`},{label:`ja-JP (65,234.00)`,value:`ja-JP`}],e=>this.patch({numberLocale:e}))),this.bodyEl.appendChild(t)}renderScaleTab(){if(!this.bodyEl||!this.currentSettings)return;let e=this.currentSettings,t=this.section();t.appendChild(this.toggleRow(`Auto Scale`,e.autoScale,e=>this.patch({autoScale:e}))),t.appendChild(this.toggleRow(`Log Scale`,e.logScale,e=>this.patch({logScale:e}))),this.bodyEl.appendChild(t)}patch(e){this.currentSettings&&Object.assign(this.currentSettings,e),this.callbacks.onChange(e)}section(e){let t=document.createElement(`div`);if(t.className=`tcw-settings-section`,e){let n=document.createElement(`div`);n.className=`tcw-settings-section-title`,n.textContent=e,t.appendChild(n)}return t}colorRow(e,t,n){let r=document.createElement(`div`);r.className=`tcw-settings-row`;let i=document.createElement(`span`);i.className=`tcw-settings-label`,i.textContent=e,r.appendChild(i);let a=document.createElement(`div`);a.className=`tcw-color-picker-wrap`;let o=document.createElement(`input`);o.type=`color`,o.value=t;let s=document.createElement(`span`);return s.className=`tcw-color-hex`,s.textContent=t,o.addEventListener(`input`,()=>{s.textContent=o.value,n(o.value)}),a.appendChild(o),a.appendChild(s),r.appendChild(a),r}toggleRow(e,t,n){let r=document.createElement(`div`);r.className=`tcw-settings-row`;let i=document.createElement(`span`);i.className=`tcw-settings-label`,i.textContent=e,r.appendChild(i);let a=document.createElement(`button`);return a.className=`tcw-toggle${t?` tcw-on`:``}`,a.addEventListener(`click`,()=>{let e=!a.classList.contains(`tcw-on`);a.classList.toggle(`tcw-on`,e),n(e)}),r.appendChild(a),r}selectRow(e,t,n,r){let i=document.createElement(`div`);i.className=`tcw-settings-row`;let a=document.createElement(`span`);a.className=`tcw-settings-label`,a.textContent=e,i.appendChild(a);let o=document.createElement(`select`);o.className=`tcw-settings-select`;for(let e of n){let n=document.createElement(`option`);n.value=e.value,n.textContent=e.label,e.value===t&&(n.selected=!0),o.appendChild(n)}return o.addEventListener(`change`,()=>r(o.value)),i.appendChild(o),i}destroy(){this.close()}},S=class{el;dotEl;messageEl;infoEl;constructor(e){this.el=document.createElement(`div`),this.el.className=`tcw-statusbar`;let t=document.createElement(`div`);t.className=`tcw-status-indicator`,this.dotEl=document.createElement(`span`),this.dotEl.className=`tcw-status-dot`,t.appendChild(this.dotEl),this.messageEl=document.createElement(`span`),t.appendChild(this.messageEl),this.el.appendChild(t),this.infoEl=document.createElement(`span`),this.el.appendChild(this.infoEl),e.appendChild(this.el)}update(e){this.dotEl.className=`tcw-status-dot`,e.connectionState===`connected`?this.dotEl.classList.add(`tcw-connected`):e.connectionState===`error`&&this.dotEl.classList.add(`tcw-error`),this.messageEl.textContent=e.message,this.infoEl.textContent=`${e.symbol} ${e.timeframe}`}destroy(){this.el.remove()}},C=class{backdrop=null;modal=null;input=null;list=null;items=[];filtered=[];selectedIndex=0;callbacks;boundKeydown;constructor(e){this.callbacks=e,this.boundKeydown=this.handleKeydown.bind(this)}open(e){if(this.backdrop)return;this.items=e,this.filtered=e,this.selectedIndex=0,this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.addEventListener(`click`,()=>this.close()),this.modal=document.createElement(`div`),this.modal.className=`tcw-cmd-palette`;let t=document.createElement(`div`);t.className=`tcw-cmd-header`;let n=document.createElement(`span`);n.className=`tcw-cmd-icon`,n.textContent=`⌕`,t.appendChild(n),this.input=document.createElement(`input`),this.input.className=`tcw-cmd-input`,this.input.type=`text`,this.input.placeholder=`Search indicators, chart types, tools...`,this.input.addEventListener(`input`,()=>this.filter()),t.appendChild(this.input);let r=document.createElement(`span`);r.className=`tcw-cmd-hint`,r.textContent=`ESC`,t.appendChild(r),this.modal.appendChild(t),this.list=document.createElement(`div`),this.list.className=`tcw-cmd-list`,this.modal.appendChild(this.list);let i=document.createElement(`div`);i.className=`tcw-cmd-footer`,i.innerHTML=`<span>↑↓ Navigate</span><span>⏎ Select</span><span>Esc Close</span>`,this.modal.appendChild(i),document.body.appendChild(this.backdrop),document.body.appendChild(this.modal),this.renderList(),this.input.focus(),document.addEventListener(`keydown`,this.boundKeydown)}close(){document.removeEventListener(`keydown`,this.boundKeydown),this.backdrop?.remove(),this.modal?.remove(),this.backdrop=null,this.modal=null,this.input=null,this.list=null,this.callbacks.onClose()}isOpen(){return this.backdrop!==null}filter(){let e=this.input?.value.toLowerCase().trim()??``;e?this.filtered=this.items.filter(t=>t.label.toLowerCase().includes(e)||t.category.toLowerCase().includes(e)||t.id.toLowerCase().includes(e)):this.filtered=this.items,this.selectedIndex=0,this.renderList()}renderList(){if(!this.list)return;if(this.list.innerHTML=``,this.filtered.length===0){let e=document.createElement(`div`);e.className=`tcw-cmd-empty`,e.textContent=`No results found`,this.list.appendChild(e);return}let e=``;for(let t=0;t<this.filtered.length;t++){let n=this.filtered[t];if(n.category!==e){e=n.category;let t=document.createElement(`div`);t.className=`tcw-cmd-category`,t.textContent=this.categoryLabel(e),this.list.appendChild(t)}let r=document.createElement(`button`);r.className=`tcw-cmd-item`,t===this.selectedIndex&&r.classList.add(`tcw-selected`),n.active&&r.classList.add(`tcw-active`),r.dataset.index=String(t);let i=document.createElement(`span`);if(i.className=`tcw-cmd-item-label`,i.textContent=n.label,r.appendChild(i),n.active){let e=document.createElement(`span`);e.className=`tcw-cmd-check`,e.textContent=`✓`,r.appendChild(e)}if(n.shortcut){let e=document.createElement(`kbd`);e.className=`tcw-cmd-kbd`,e.textContent=n.shortcut,r.appendChild(e)}r.addEventListener(`click`,()=>this.select(t)),r.addEventListener(`mouseenter`,()=>{this.selectedIndex=t,this.updateSelection()}),this.list.appendChild(r)}}updateSelection(){if(!this.list)return;let e=this.list.querySelectorAll(`.tcw-cmd-item`);e.forEach((e,t)=>{e.classList.toggle(`tcw-selected`,t===this.selectedIndex)}),e[this.selectedIndex]?.scrollIntoView({block:`nearest`})}select(e){let t=this.filtered[e];if(t){switch(t.category){case`indicator`:this.callbacks.onIndicator(t.id);break;case`chartType`:this.callbacks.onChartType(t.id);break;case`drawing`:this.callbacks.onDrawingTool(t.id);break;case`timeframe`:this.callbacks.onTimeframe(t.id);break;case`action`:this.callbacks.onAction(t.id);break}this.close()}}handleKeydown(e){switch(e.key){case`Escape`:e.preventDefault(),this.close();break;case`ArrowDown`:e.preventDefault(),this.filtered.length>0&&(this.selectedIndex=(this.selectedIndex+1)%this.filtered.length,this.updateSelection());break;case`ArrowUp`:e.preventDefault(),this.filtered.length>0&&(this.selectedIndex=(this.selectedIndex-1+this.filtered.length)%this.filtered.length,this.updateSelection());break;case`Enter`:e.preventDefault(),this.select(this.selectedIndex);break}}categoryLabel(e){switch(e){case`indicator`:return`Indicators`;case`chartType`:return`Chart Types`;case`drawing`:return`Drawing Tools`;case`timeframe`:return`Timeframes`;case`action`:return`Actions`;default:return e}}destroy(){this.close()}},w=class{backdrop=null;modal=null;input=null;list=null;symbols=[];current=``;filtered=[];selectedIndex=0;callbacks;boundKeydown;constructor(e){this.callbacks=e,this.boundKeydown=this.handleKeydown.bind(this)}open(e,t){if(this.backdrop)return;this.symbols=e,this.current=t,this.filtered=e.map(e=>({symbol:e,score:0})),this.selectedIndex=Math.max(0,e.indexOf(t)),this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.addEventListener(`click`,()=>this.close()),this.modal=document.createElement(`div`),this.modal.className=`tcw-cmd-palette`;let n=document.createElement(`div`);n.className=`tcw-cmd-header`;let r=document.createElement(`span`);r.className=`tcw-cmd-icon`,r.innerHTML=O(),n.appendChild(r),this.input=document.createElement(`input`),this.input.className=`tcw-cmd-input`,this.input.type=`text`,this.input.placeholder=`Search symbol… (e.g. BTC, ETH, AAPL)`,this.input.autocomplete=`off`,this.input.spellcheck=!1,this.input.addEventListener(`input`,()=>this.filter()),n.appendChild(this.input);let i=document.createElement(`span`);i.className=`tcw-cmd-hint`,i.textContent=`ESC`,n.appendChild(i),this.modal.appendChild(n),this.list=document.createElement(`div`),this.list.className=`tcw-cmd-list`,this.modal.appendChild(this.list);let a=document.createElement(`div`);a.className=`tcw-cmd-footer`,a.innerHTML=`<span>↑↓ Navigate</span><span>⏎ Open</span><span>Esc Close</span>`,this.modal.appendChild(a),document.body.appendChild(this.backdrop),document.body.appendChild(this.modal),this.renderList(),this.input.focus(),document.addEventListener(`keydown`,this.boundKeydown)}close(){document.removeEventListener(`keydown`,this.boundKeydown),this.backdrop?.remove(),this.modal?.remove(),this.backdrop=null,this.modal=null,this.input=null,this.list=null,this.callbacks.onClose()}isOpen(){return this.backdrop!==null}destroy(){this.close()}filter(){let e=(this.input?.value??``).toUpperCase().trim();e?this.filtered=this.symbols.map(t=>({symbol:t,score:T(t.toUpperCase(),e)})).filter(e=>e.score>0).sort((e,t)=>t.score-e.score):this.filtered=this.symbols.map(e=>({symbol:e,score:0})),this.selectedIndex=0,this.renderList()}renderList(){if(!this.list)return;if(this.list.innerHTML=``,this.filtered.length===0){let e=document.createElement(`div`);e.className=`tcw-cmd-empty`,e.textContent=`No symbols match`,this.list.appendChild(e);return}let e=(this.input?.value??``).toUpperCase().trim();for(let t=0;t<this.filtered.length;t++){let{symbol:n}=this.filtered[t],r=document.createElement(`button`);r.className=`tcw-cmd-item`,t===this.selectedIndex&&r.classList.add(`tcw-selected`),n===this.current&&r.classList.add(`tcw-active`);let i=document.createElement(`span`);if(i.className=`tcw-cmd-item-label`,i.innerHTML=E(n,e),r.appendChild(i),n===this.current){let e=document.createElement(`span`);e.className=`tcw-cmd-check`,e.textContent=`✓`,r.appendChild(e)}r.addEventListener(`click`,()=>this.pick(t)),r.addEventListener(`mouseenter`,()=>{this.selectedIndex=t,this.updateSelection()}),this.list.appendChild(r)}}updateSelection(){if(!this.list)return;let e=this.list.querySelectorAll(`.tcw-cmd-item`);e.forEach((e,t)=>e.classList.toggle(`tcw-selected`,t===this.selectedIndex)),e[this.selectedIndex]?.scrollIntoView({block:`nearest`})}pick(e){let t=this.filtered[e];t&&(this.callbacks.onPick(t.symbol),this.close())}handleKeydown(e){switch(e.key){case`Escape`:e.preventDefault(),this.close();break;case`ArrowDown`:e.preventDefault(),this.filtered.length>0&&(this.selectedIndex=(this.selectedIndex+1)%this.filtered.length,this.updateSelection());break;case`ArrowUp`:e.preventDefault(),this.filtered.length>0&&(this.selectedIndex=(this.selectedIndex-1+this.filtered.length)%this.filtered.length,this.updateSelection());break;case`Enter`:e.preventDefault(),this.pick(this.selectedIndex);break}}};function T(e,t){if(e===t)return 1e3;if(e.startsWith(t))return 500+(50-Math.min(50,e.length-t.length));if(e.includes(t))return 200+(50-Math.min(50,e.length-t.length));let n=0,r=-1,i=0;for(let a=0;a<e.length&&n<t.length;a++)e[a]===t[n]&&(r>=0&&(i+=a-r-1),r=a,n++);return n<t.length?0:100-Math.min(99,i)}function E(e,t){if(!t)return D(e);let n=e.toUpperCase(),r=``,i=0;for(let a=0;a<e.length;a++)i<t.length&&n[a]===t[i]?(r+=`<mark style="background:transparent;color:var(--tcw-accent);font-weight:700">${D(e[a])}</mark>`,i++):r+=D(e[a]);return r}function D(e){return e.replace(/[&<>"']/g,e=>({"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`})[e])}function O(){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>`}var k=typeof navigator<`u`&&/mac|iphone|ipad|ipod/i.test(navigator.platform||navigator.userAgent)?`⌘`:`Ctrl`,A=[{title:`Search & navigation`,entries:[{keys:[k,`K`],label:`Command palette`},{keys:[k,`P`],label:`Symbol search`},{keys:[`?`],label:`Show this sheet`}]},{title:`Chart manipulation`,entries:[{keys:[`Shift`,`Drag`],label:`Measure tool (bars × price Δ)`},{keys:[`Drag`,`Price axis`],label:`Compress / expand vertical scale`},{keys:[`Drag`,`Time axis`],label:`Zoom time axis`},{keys:[`Double-click`,`Price axis`],label:`Re-enable auto-scale`},{keys:[`Double-click`,`Time axis`],label:`Fit content`},{keys:[`Scroll`],label:`Zoom around cursor`}]},{title:`Keyboard`,entries:[{keys:[`←`,`→`],label:`Pan one bar`},{keys:[`+`,`−`],label:`Zoom in / out`},{keys:[`Home`],label:`Scroll to start`},{keys:[`End`],label:`Scroll to end (live edge)`},{keys:[`F`],label:`Fit content`}]},{title:`Drawing`,entries:[{keys:[k,`Z`],label:`Undo`},{keys:[k,`Shift`,`Z`],label:`Redo`},{keys:[`Esc`],label:`Cancel active drawing`}]}],j=class{backdrop=null;modal=null;callbacks;boundKeydown;constructor(e){this.callbacks=e,this.boundKeydown=e=>{e.key===`Escape`&&(e.preventDefault(),this.close())}}open(){if(this.backdrop)return;this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.addEventListener(`click`,()=>this.close()),this.modal=document.createElement(`div`),this.modal.className=`tcw-modal tcw-hotkey-sheet`,this.modal.style.width=`640px`;let e=document.createElement(`div`);e.className=`tcw-modal-header`,e.innerHTML=`<h3>Keyboard shortcuts</h3>`;let t=document.createElement(`button`);t.className=`tcw-modal-close`,t.setAttribute(`aria-label`,`Close`),t.innerHTML=`×`,t.addEventListener(`click`,()=>this.close()),e.appendChild(t),this.modal.appendChild(e);let n=document.createElement(`div`);n.className=`tcw-modal-body`;let r=document.createElement(`div`);r.className=`tcw-hotkey-grid`;for(let e of A){let t=document.createElement(`section`);t.className=`tcw-hotkey-section`;let n=document.createElement(`div`);n.className=`tcw-settings-section-title`,n.textContent=e.title,t.appendChild(n);for(let n of e.entries){let e=document.createElement(`div`);e.className=`tcw-hotkey-row`;let r=document.createElement(`div`);r.className=`tcw-hotkey-keys`;for(let e=0;e<n.keys.length;e++){if(e>0){let e=document.createElement(`span`);e.className=`tcw-hotkey-sep`,e.textContent=`+`,r.appendChild(e)}let t=document.createElement(`kbd`);t.className=`tcw-cmd-kbd`,t.textContent=n.keys[e],r.appendChild(t)}e.appendChild(r);let i=document.createElement(`span`);i.className=`tcw-hotkey-label`,i.textContent=n.label,e.appendChild(i),t.appendChild(e)}r.appendChild(t)}n.appendChild(r),this.modal.appendChild(n);let i=document.createElement(`div`);i.className=`tcw-modal-footer`,i.innerHTML=`<span style="font-size:11px;color:var(--tcw-text-muted)">Press ? anytime to show this sheet</span>`;let a=document.createElement(`button`);a.className=`tcw-done-btn`,a.textContent=`Got it`,a.addEventListener(`click`,()=>this.close()),i.appendChild(a),this.modal.appendChild(i),document.body.appendChild(this.backdrop),document.body.appendChild(this.modal),document.addEventListener(`keydown`,this.boundKeydown)}close(){document.removeEventListener(`keydown`,this.boundKeydown),this.backdrop?.remove(),this.modal?.remove(),this.backdrop=null,this.modal=null,this.callbacks.onClose()}isOpen(){return this.backdrop!==null}destroy(){this.close()}},M=[.5,1,2,5,10,20,50,100],N=class{root=null;scrubber=null;progressLabel=null;playBtn=null;state=`stopped`;total=0;speed=5;callbacks;constructor(e){this.callbacks=e}mount(e,t){this.root||(this.total=Math.max(0,t.total),this.speed=t.speed??5,this.state=`paused`,this.root=document.createElement(`div`),this.root.className=`tcw-replay-bar`,this.root.innerHTML=this.markup(),e.appendChild(this.root),this.wireEvents(),this.syncUi())}unmount(){this.root?.remove(),this.root=null,this.scrubber=null,this.progressLabel=null,this.playBtn=null,this.state=`stopped`}isMounted(){return this.root!==null}setState(e){this.state=e,this.syncUi()}setProgress(e,t){this.total=t,this.scrubber&&(this.scrubber.max=String(Math.max(0,t-1)),this.scrubber.value=String(e)),this.progressLabel&&(this.progressLabel.textContent=`${e+1} / ${t}`)}destroy(){this.unmount()}markup(){let e=M.map(e=>`<option value="${e}"${e===this.speed?` selected`:``}>${e}× bars/s</option>`).join(``);return`
|
|
1448
|
-
<button class="tcw-replay-btn" data-act="close" title="Exit replay" aria-label="Exit replay">${
|
|
1449
|
-
<button class="tcw-replay-btn" data-act="stepBack" title="Step back" aria-label="Step back">${
|
|
1450
|
-
<button class="tcw-replay-btn tcw-replay-play" data-act="play" title="Play / pause" aria-label="Play / pause">${
|
|
1451
|
-
<button class="tcw-replay-btn" data-act="stepForward" title="Step forward" aria-label="Step forward">${
|
|
2379
|
+
`,f=0,p=`tcw-styles`;function m(){if(f++,f>1||document.getElementById(p))return;let e=document.createElement(`style`);e.id=p,e.textContent=d,document.head.appendChild(e)}function h(){if(f--,f>0)return;let e=document.getElementById(p);e&&e.remove()}var g={cursor:`<path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"/><path d="M13 13l6 6"/>`,trendingUp:`<polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/>`,minus:`<path d="M5 12h14"/>`,penLine:`<path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/>`,hash:`<line x1="4" y1="9" x2="20" y2="9"/><line x1="4" y1="15" x2="20" y2="15"/><line x1="10" y1="3" x2="8" y2="21"/><line x1="16" y1="3" x2="14" y2="21"/>`,square:`<rect width="18" height="18" x="3" y="3" rx="2"/>`,gitBranch:`<line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>`,ruler:`<path d="M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z"/><path d="m14.5 12.5 2-2"/><path d="m11.5 9.5 2-2"/><path d="m8.5 6.5 2-2"/><path d="m17.5 15.5 2-2"/>`,type:`<polyline points="4 7 4 4 20 4 20 7"/><line x1="9" y1="20" x2="15" y2="20"/><line x1="12" y1="4" x2="12" y2="20"/>`,magnet:`<path d="m6 15-4-4 6.75-6.77a7.79 7.79 0 0 1 11 11L13 22l-4-4 6.39-6.36a2.14 2.14 0 0 0-3-3L6 15"/><path d="m5 8 4 4"/><path d="m12 15 4 4"/>`,undo:`<path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13"/>`,redo:`<path d="M21 7v6h-6"/><path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13"/>`,trash:`<path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/>`,camera:`<path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/>`,settings:`<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/>`,moon:`<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>`,sun:`<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>`,chevronDown:`<path d="m6 9 6 6 6-6"/>`,chevronUp:`<path d="m18 15-6-6-6 6"/>`,barChart:`<line x1="12" y1="20" x2="12" y2="10"/><line x1="18" y1="20" x2="18" y2="4"/><line x1="6" y1="20" x2="6" y2="16"/>`,x:`<path d="M18 6 6 18"/><path d="m6 6 12 12"/>`,play:`<polygon points="6 3 20 12 6 21 6 3"/>`,pause:`<rect width="4" height="16" x="6" y="4"/><rect width="4" height="16" x="14" y="4"/>`,stop:`<rect width="14" height="14" x="5" y="5" rx="1"/>`,receipt:`<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z"/><path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8"/><path d="M12 17.5v-11"/>`,bell:`<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/>`,plus:`<path d="M5 12h14"/><path d="M12 5v14"/>`,layers:`<path d="m12 2 9 5-9 5-9-5 9-5Z"/><path d="m3 12 9 5 9-5"/><path d="m3 17 9 5 9-5"/>`,eye:`<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>`,eyeOff:`<path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c6.5 0 10 7 10 7a13.2 13.2 0 0 1-1.67 2.68"/><path d="M6.6 6.6A13.06 13.06 0 0 0 2 11s3.5 7 10 7a9.1 9.1 0 0 0 5.4-1.6"/><path d="m2 2 20 20"/>`,lock:`<rect width="18" height="11" x="3" y="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>`,unlock:`<rect width="18" height="11" x="3" y="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/>`,palette:`<circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2Z"/>`,trendingDown:`<polyline points="22 17 13.5 8.5 8.5 13.5 2 7"/><polyline points="16 17 22 17 22 11"/>`,check:`<polyline points="20 6 9 17 4 12"/>`,ladder:`<rect x="3" y="3" width="18" height="18" rx="2"/><line x1="12" y1="3" x2="12" y2="21"/><line x1="3" y1="8" x2="21" y2="8"/><line x1="3" y1="13" x2="21" y2="13"/><line x1="3" y1="18" x2="21" y2="18"/>`};function _(e,t=14){let n=g[e];return n?`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${n}</svg>`:``}var v=class{trigger;panel;_isOpen=!1;onOutsideClick;onEscapeKey;onTriggerClick;constructor(e,t={}){this.trigger=e,this.panel=document.createElement(`div`),this.panel.className=`tcw-dropdown`,this.panel.style.width=t.width??`200px`,t.align===`right`?this.panel.style.right=`0`:this.panel.style.left=`0`,this.panel.style.display=`none`,e.style.position=`relative`,e.appendChild(this.panel),this.onTriggerClick=()=>{this._isOpen?this.close():this.open()},this.onOutsideClick=e=>{this.trigger.contains(e.target)||this.close()},this.onEscapeKey=e=>{e.key===`Escape`&&this.close()},e.addEventListener(`click`,this.onTriggerClick)}setContent(e){this.panel.innerHTML=e}open(){this._isOpen||(this._isOpen=!0,this.panel.style.display=``,document.addEventListener(`mousedown`,this.onOutsideClick),document.addEventListener(`keydown`,this.onEscapeKey))}close(){this._isOpen&&(this._isOpen=!1,this.panel.style.display=`none`,document.removeEventListener(`mousedown`,this.onOutsideClick),document.removeEventListener(`keydown`,this.onEscapeKey))}isOpen(){return this._isOpen}destroy(){this.trigger.removeEventListener(`click`,this.onTriggerClick),document.removeEventListener(`mousedown`,this.onOutsideClick),document.removeEventListener(`keydown`,this.onEscapeKey),this.panel.remove()}},y=class{config;callbacks;el;chartTypeDropdown=null;indicatorDropdown=null;tfButtons=[];chipsContainer=null;themeBtn=null;constructor(e,t,n){this.config=t,this.callbacks=n,this.el=document.createElement(`div`),this.el.className=`tcw-toolbar`,this.build(),e.appendChild(this.el)}build(){let{config:e,callbacks:t,el:n}=this,r=document.createElement(`button`);r.className=`tcw-toolbar-symbol`,r.dataset.role=`symbol`,r.addEventListener(`click`,t.onSymbolClick),n.appendChild(r),n.appendChild(this.sep());let i=document.createElement(`div`);i.className=`tcw-toolbar-group`;for(let n of e.timeframes){let e=document.createElement(`button`);e.className=`tcw-btn`,e.textContent=n.label,e.dataset.tf=n.value,e.addEventListener(`click`,()=>t.onTimeframe(n.value)),i.appendChild(e),this.tfButtons.push(e)}n.appendChild(i),n.appendChild(this.sep());let a=document.createElement(`div`);a.style.position=`relative`,a.style.display=`inline-flex`;let o=document.createElement(`button`);o.className=`tcw-dropdown-trigger`,o.dataset.role=`charttype`,a.appendChild(o),n.appendChild(a),this.chartTypeDropdown=new v(a,{width:`160px`}),this.buildChartTypeMenu(),n.appendChild(this.sep());let s=document.createElement(`div`);s.style.position=`relative`,s.style.display=`inline-flex`;let c=document.createElement(`button`);if(c.className=`tcw-dropdown-trigger`,c.dataset.role=`indicators`,s.appendChild(c),n.appendChild(s),this.indicatorDropdown=new v(s,{width:`280px`}),this.buildIndicatorMenu(),this.chipsContainer=document.createElement(`div`),this.chipsContainer.className=`tcw-indicator-chips`,n.appendChild(this.chipsContainer),n.appendChild(this.spacer()),t.onToggleReplay){let e=this.iconBtn(`play`,`Bar replay`,t.onToggleReplay);e.dataset.role=`replay`,n.appendChild(e)}if(t.onBracket){let e=t.onBracket,r=this.iconBtn(`trendingUp`,`Long bracket`,()=>e(`buy`));r.dataset.role=`long`,r.classList.add(`tcw-btn-long`),n.appendChild(r);let i=this.iconBtn(`trendingDown`,`Short bracket`,()=>e(`sell`));i.dataset.role=`short`,i.classList.add(`tcw-btn-short`),n.appendChild(i)}if(t.onToggleLadder){let e=this.iconBtn(`ladder`,`Depth ladder`,t.onToggleLadder);e.dataset.role=`ladder`,n.appendChild(e)}if(t.onToggleObjects){let e=this.iconBtn(`layers`,`Objects`,t.onToggleObjects);e.dataset.role=`objects`,n.appendChild(e)}if(t.onToggleAlerts){let e=this.iconBtn(`bell`,`Price alerts`,t.onToggleAlerts);e.dataset.role=`alerts`,n.appendChild(e)}let l=this.iconBtn(`camera`,`Screenshot`,t.onScreenshot);n.appendChild(l);let u=this.iconBtn(`settings`,`Chart Settings`,t.onSettings);n.appendChild(u),this.themeBtn=this.iconBtn(`moon`,`Toggle theme`,t.onToggleTheme),this.themeBtn.dataset.role=`theme`,n.appendChild(this.themeBtn)}buildChartTypeMenu(){if(!this.chartTypeDropdown)return;let e=this.config.chartTypes.map(e=>`<button class="tcw-dropdown-item" data-ct="${e.value}">${e.label}</button>`).join(``);this.chartTypeDropdown.setContent(e),this.chartTypeDropdown.panel.querySelectorAll(`.tcw-dropdown-item`).forEach(e=>{e.addEventListener(`click`,e=>{let t=e.currentTarget.dataset.ct;this.callbacks.onChartType(t),this.chartTypeDropdown?.close()})})}buildIndicatorMenu(){if(!this.indicatorDropdown)return;let{indicators:e,popularIndicatorIds:t}=this.config,n=e.filter(e=>t.includes(e.id)),r=e.filter(e=>!t.includes(e.id)),i=`<div class="tcw-dropdown-label">Popular</div>`;for(let e of n)i+=`<button class="tcw-dropdown-item" data-ind="${e.id}"><span>${e.name}</span><span class="tcw-tag">${e.type}</span></button>`;i+=`<div class="tcw-dropdown-divider"></div>`,i+=`<div class="tcw-dropdown-label">All</div>`;for(let e of r)i+=`<button class="tcw-dropdown-item" data-ind="${e.id}"><span>${e.name}</span><span class="tcw-tag">${e.type}</span></button>`;this.indicatorDropdown.setContent(i),this.indicatorDropdown.panel.querySelectorAll(`.tcw-dropdown-item[data-ind]`).forEach(e=>{e.addEventListener(`click`,e=>{let t=e.currentTarget.dataset.ind;this.callbacks.onAddIndicator(t)})})}update(e){let t=this.el.querySelector(`[data-role="symbol"]`);t&&(t.textContent=e.symbol);for(let t of this.tfButtons)t.classList.toggle(`tcw-active`,t.dataset.tf===e.timeframe);let n=this.el.querySelector(`[data-role="charttype"]`);if(n){let t=this.config.chartTypes.find(t=>t.value===e.chartType)?.label??`Candles`;n.innerHTML=`${_(`barChart`,14)} ${t} ${_(`chevronDown`,12)}`}let r=this.el.querySelector(`[data-role="indicators"]`);if(r){let t=e.activeIndicators.size,n=`${_(`trendingUp`,14)} Indicators`;t>0&&(n+=` <span class="tcw-badge-count">${t}</span>`),r.innerHTML=n}if(this.chipsContainer){let t=this.getActiveIndicatorList(e);this.chipsContainer.innerHTML=``;for(let e of t){let t=document.createElement(`div`);t.className=`tcw-indicator-chip`;let n=document.createElement(`span`);n.textContent=e.label,t.appendChild(n);let r=document.createElement(`button`);r.className=`tcw-chip-remove`,r.innerHTML=_(`x`,10),r.addEventListener(`click`,()=>this.callbacks.onRemoveIndicator(e.instanceId)),t.appendChild(r),this.chipsContainer.appendChild(t)}}this.themeBtn&&(this.themeBtn.innerHTML=e.isDark?_(`moon`,14):_(`sun`,14))}getActiveIndicatorList(e){let t=[];for(let[n,r]of e.activeIndicators.entries())t.push({instanceId:r,id:n,label:n.toUpperCase()});return t}sep(){let e=document.createElement(`span`);return e.className=`tcw-toolbar-sep`,e}spacer(){let e=document.createElement(`span`);return e.className=`tcw-toolbar-spacer`,e}iconBtn(e,t,n){let r=document.createElement(`button`);return r.className=`tcw-btn-icon`,r.title=t,r.innerHTML=_(e,14),r.addEventListener(`click`,n),r}destroy(){this.chartTypeDropdown?.destroy(),this.indicatorDropdown?.destroy(),this.el.remove()}},ee=[`trendingUp`,`minus`,`penLine`,`hash`,`square`,`gitBranch`,`ruler`,`type`],te={trendLine:`trendingUp`,ray:`trendingUp`,extendedLine:`trendingUp`,horizontalLine:`minus`,verticalLine:`penLine`,rectangle:`square`,ellipse:`square`,triangle:`square`,arrow:`trendingUp`,parallelChannel:`gitBranch`,regressionChannel:`gitBranch`,pitchfork:`gitBranch`,fibRetracement:`hash`,fibExtension:`hash`,fibTimeZones:`hash`,gannBox:`hash`,gannFan:`gitBranch`,elliottWave:`trendingUp`,priceRange:`ruler`,dateRange:`ruler`,measure:`ruler`,textAnnotation:`type`,anchoredVWAP:`trendingUp`,volumeProfileRange:`barChart`};function ne(e){return te[e]??`penLine`}function re(e,t){for(let n of e){let e=n.tools.find(e=>e.value===t);if(e)return e.label}return t}var ie=class{config;callbacks;el;groupWraps=[];groupButtons=[];cursorBtn=null;magnetBtn=null;flyoutEl=null;favoritesEl=null;favoritesDivider=null;favorites=[];constructor(e,t,n){this.config=t,this.callbacks=n,this.el=document.createElement(`div`),this.el.className=`tcw-sidebar`,this.build(),e.appendChild(this.el)}build(){let{config:e,callbacks:t,el:n}=this;this.cursorBtn=document.createElement(`button`),this.cursorBtn.className=`tcw-sidebar-btn`,this.cursorBtn.title=`Cursor`,this.cursorBtn.innerHTML=_(`cursor`,14),this.cursorBtn.addEventListener(`click`,t.onCancelDrawing),n.appendChild(this.cursorBtn),n.appendChild(this.divider()),t.onToggleFavorite&&(this.favorites=[...e.favorites??[]],this.favoritesEl=document.createElement(`div`),this.favoritesEl.className=`tcw-sidebar-favorites`,n.appendChild(this.favoritesEl),this.favoritesDivider=this.divider(),n.appendChild(this.favoritesDivider),this.renderFavorites()),e.drawingToolGroups.forEach((e,r)=>{let i=document.createElement(`div`);i.className=`tcw-tool-group-wrap`;let a=document.createElement(`button`);if(a.className=`tcw-sidebar-btn`,a.title=e.label,a.innerHTML=_(ee[r]??`square`,14),e.tools.length>1){let e=document.createElement(`span`);e.className=`tcw-multi-dot`,a.appendChild(e)}a.addEventListener(`click`,()=>t.onDrawingTool(e.tools[0].value)),i.appendChild(a),i.addEventListener(`mouseenter`,()=>this.showFlyout(r)),i.addEventListener(`mouseleave`,()=>this.hideFlyout()),n.appendChild(i),this.groupWraps.push(i),this.groupButtons.push(a)});let r=document.createElement(`div`);if(r.className=`tcw-sidebar-spacer`,n.appendChild(r),n.appendChild(this.divider()),t.onToggleStyle){let e=document.createElement(`button`);e.className=`tcw-sidebar-btn`,e.title=`Drawing style & templates`,e.dataset.role=`style`,e.innerHTML=_(`palette`,14),e.addEventListener(`click`,t.onToggleStyle),n.appendChild(e)}this.magnetBtn=document.createElement(`button`),this.magnetBtn.className=`tcw-sidebar-btn`,this.magnetBtn.title=`Magnet`,this.magnetBtn.innerHTML=_(`magnet`,14),this.magnetBtn.addEventListener(`click`,t.onToggleMagnet),n.appendChild(this.magnetBtn);let i=document.createElement(`button`);i.className=`tcw-sidebar-btn`,i.title=`Undo`,i.innerHTML=_(`undo`,14),i.addEventListener(`click`,t.onUndo),n.appendChild(i);let a=document.createElement(`button`);a.className=`tcw-sidebar-btn`,a.title=`Redo`,a.innerHTML=_(`redo`,14),a.addEventListener(`click`,t.onRedo),n.appendChild(a);let o=document.createElement(`button`);o.className=`tcw-sidebar-btn tcw-danger`,o.title=`Clear all`,o.innerHTML=_(`trash`,14),o.addEventListener(`click`,t.onClearDrawings),n.appendChild(o)}setFavorites(e){this.favorites=[...e],this.renderFavorites()}renderFavorites(){if(!this.favoritesEl)return;this.favoritesEl.replaceChildren();let e=this.favorites.length>0;this.favoritesEl.style.display=e?``:`none`,this.favoritesDivider&&(this.favoritesDivider.style.display=e?``:`none`);for(let e of this.favorites){let t=document.createElement(`button`);t.className=`tcw-sidebar-btn`,t.title=`${re(this.config.drawingToolGroups,e)} (right-click to unpin)`,t.dataset.toolValue=e,t.innerHTML=_(ne(e),14),t.addEventListener(`click`,()=>this.callbacks.onDrawingTool(e)),t.addEventListener(`contextmenu`,t=>{t.preventDefault(),this.callbacks.onToggleFavorite?.(e)}),this.favoritesEl.appendChild(t)}}showFlyout(e){let t=this.config.drawingToolGroups[e];if(!t||t.tools.length<=1)return;this.hideFlyout();let n=document.createElement(`div`);n.className=`tcw-flyout`;let r=document.createElement(`div`);r.className=`tcw-flyout-header`,r.textContent=t.label,n.appendChild(r);for(let e of t.tools){let t=document.createElement(`button`);t.className=`tcw-flyout-item`,t.textContent=e.label,t.dataset.toolValue=e.value,t.addEventListener(`click`,()=>{this.callbacks.onDrawingTool(e.value),this.hideFlyout()}),this.callbacks.onToggleFavorite&&(this.favorites.includes(e.value)&&t.classList.add(`tcw-flyout-faved`),t.title=`Right-click to pin/unpin`,t.addEventListener(`contextmenu`,t=>{t.preventDefault(),this.callbacks.onToggleFavorite?.(e.value)})),n.appendChild(t)}this.flyoutEl=n,this.groupWraps[e].appendChild(n)}hideFlyout(){this.flyoutEl&&=(this.flyoutEl.remove(),null)}update(e){this.cursorBtn&&this.cursorBtn.classList.toggle(`tcw-active`,e.activeTool===null);let{drawingToolGroups:t}=this.config;for(let n=0;n<t.length;n++){let r=t[n].tools.some(t=>t.value===e.activeTool);this.groupButtons[n].classList.toggle(`tcw-active`,r)}this.flyoutEl&&this.flyoutEl.querySelectorAll(`.tcw-flyout-item`).forEach(t=>{let n=t;n.classList.toggle(`tcw-active`,n.dataset.toolValue===e.activeTool)}),this.magnetBtn&&(this.magnetBtn.classList.toggle(`tcw-active`,e.magnetEnabled),this.magnetBtn.title=e.magnetEnabled?`Magnet ON`:`Magnet OFF`)}divider(){let e=document.createElement(`div`);return e.className=`tcw-sidebar-divider`,e}destroy(){this.hideFlyout(),this.el.remove()}},ae=[`style`,`display`,`scale`],oe=class{callbacks;backdrop=null;modal=null;currentTab=`style`;currentSettings=null;bodyEl=null;tabButtons=[];constructor(e){this.callbacks=e}open(e){this.currentSettings={...e},this.currentTab=`style`,this.buildModal()}close(){this.backdrop?.remove(),this.modal?.remove(),this.backdrop=null,this.modal=null,this.bodyEl=null,this.tabButtons=[]}buildModal(){this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.addEventListener(`click`,()=>{this.callbacks.onClose(),this.close()}),document.body.appendChild(this.backdrop),this.modal=document.createElement(`div`),this.modal.className=`tcw-modal`;let e=document.createElement(`div`);e.className=`tcw-modal-header`;let t=document.createElement(`h3`);t.textContent=`Chart Settings`,e.appendChild(t);let n=document.createElement(`button`);n.className=`tcw-modal-close`,n.innerHTML=_(`x`,16),n.addEventListener(`click`,()=>{this.callbacks.onClose(),this.close()}),e.appendChild(n),this.modal.appendChild(e);let r=document.createElement(`div`);r.className=`tcw-modal-tabs`,this.tabButtons=[];for(let e of ae){let t=document.createElement(`button`);t.className=`tcw-modal-tab`,t.textContent=e,t.dataset.tab=e,e===this.currentTab&&t.classList.add(`tcw-active`),t.addEventListener(`click`,()=>{this.currentTab=e,this.tabButtons.forEach(t=>t.classList.toggle(`tcw-active`,t.dataset.tab===e)),this.renderTabContent()}),r.appendChild(t),this.tabButtons.push(t)}this.modal.appendChild(r),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`tcw-modal-body`,this.modal.appendChild(this.bodyEl),this.renderTabContent();let i=document.createElement(`div`);i.className=`tcw-modal-footer`;let a=document.createElement(`button`);a.className=`tcw-reset-link`,a.textContent=`Reset to defaults`,a.addEventListener(`click`,()=>this.callbacks.onReset()),i.appendChild(a);let o=document.createElement(`button`);o.className=`tcw-done-btn`,o.textContent=`Done`,o.addEventListener(`click`,()=>{this.callbacks.onClose(),this.close()}),i.appendChild(o),this.modal.appendChild(i),document.body.appendChild(this.modal);let s=e=>{e.key===`Escape`&&(document.removeEventListener(`keydown`,s),this.callbacks.onClose(),this.close())};document.addEventListener(`keydown`,s)}renderTabContent(){if(!(!this.bodyEl||!this.currentSettings))switch(this.bodyEl.innerHTML=``,this.currentTab){case`style`:this.renderStyleTab();break;case`display`:this.renderDisplayTab();break;case`scale`:this.renderScaleTab();break}}renderStyleTab(){if(!this.bodyEl||!this.currentSettings)return;let e=this.currentSettings,t=this.section(`Candle Colors`);t.appendChild(this.colorRow(`Up Body`,e.candleUpColor,e=>this.patch({candleUpColor:e}))),t.appendChild(this.colorRow(`Down Body`,e.candleDownColor,e=>this.patch({candleDownColor:e}))),t.appendChild(this.colorRow(`Up Wick`,e.candleUpWick,e=>this.patch({candleUpWick:e}))),t.appendChild(this.colorRow(`Down Wick`,e.candleDownWick,e=>this.patch({candleDownWick:e}))),this.bodyEl.appendChild(t);let n=this.section(`Background`);n.appendChild(this.colorRow(`Background`,e.backgroundColor,e=>this.patch({backgroundColor:e}))),n.appendChild(this.colorRow(`Grid`,e.gridColor,e=>this.patch({gridColor:e}))),this.bodyEl.appendChild(n)}renderDisplayTab(){if(!this.bodyEl||!this.currentSettings)return;let e=this.currentSettings,t=this.section();t.appendChild(this.toggleRow(`Grid Lines`,e.gridVisible,e=>this.patch({gridVisible:e}))),t.appendChild(this.toggleRow(`Volume`,e.volumeVisible,e=>this.patch({volumeVisible:e}))),t.appendChild(this.toggleRow(`Volume Profile`,e.volumeProfileVisible,e=>this.patch({volumeProfileVisible:e}))),t.appendChild(this.toggleRow(`Market Profile (TPO)`,e.marketProfileVisible,e=>this.patch({marketProfileVisible:e}))),t.appendChild(this.toggleRow(`MP split by session`,e.marketProfileSplit,e=>this.patch({marketProfileSplit:e}))),t.appendChild(this.toggleRow(`MP letters (TPO)`,e.marketProfileLetters,e=>this.patch({marketProfileLetters:e}))),t.appendChild(this.rangeRow(`MP buckets`,e.marketProfileBuckets,8,200,1,e=>this.patch({marketProfileBuckets:e}))),t.appendChild(this.rangeRow(`MP opacity`,e.marketProfileOpacity,.05,1,.05,e=>this.patch({marketProfileOpacity:e}),e=>`${Math.round(e*100)}%`)),t.appendChild(this.toggleRow(`Liquidity heatmap`,e.depthHeatmapVisible,e=>this.patch({depthHeatmapVisible:e}))),t.appendChild(this.rangeRow(`Heatmap opacity`,e.depthHeatmapOpacity,.1,1,.05,e=>this.patch({depthHeatmapOpacity:e}),e=>`${Math.round(e*100)}%`)),t.appendChild(this.toggleRow(`Swing markers`,e.pivotMarkersVisible,e=>this.patch({pivotMarkersVisible:e}))),t.appendChild(this.rangeRow(`Swing strength`,e.pivotStrength,2,20,1,e=>this.patch({pivotStrength:e}))),t.appendChild(this.toggleRow(`Swing structure (HH/HL)`,e.pivotStructureLabels,e=>this.patch({pivotStructureLabels:e}))),t.appendChild(this.toggleRow(`Session shading (RTH)`,e.sessionShadingVisible,e=>this.patch({sessionShadingVisible:e}))),t.appendChild(this.toggleRow(`Prior-period levels`,e.periodLevelsVisible,e=>this.patch({periodLevelsVisible:e}))),t.appendChild(this.selectRow(`Period levels basis`,e.periodLevelsPeriod,[{value:`day`,label:`Prior Day (PDH/PDL)`},{value:`week`,label:`Prior Week (PWH/PWL)`}],e=>this.patch({periodLevelsPeriod:e}))),t.appendChild(this.toggleRow(`OHLC Legend`,e.legendVisible,e=>this.patch({legendVisible:e}))),t.appendChild(this.toggleRow(`Bar Countdown`,e.barCountdown,e=>this.patch({barCountdown:e}))),t.appendChild(this.selectRow(`Crosshair Mode`,e.crosshairMode,[{label:`Magnet`,value:`magnet`},{label:`Normal`,value:`normal`},{label:`Hidden`,value:`hidden`}],e=>this.patch({crosshairMode:e}))),t.appendChild(this.selectRow(`Timezone`,e.timezone,[{value:`local`,label:`Local`},{value:`0`,label:`UTC / London`},{value:`-300`,label:`New York (UTC-5)`},{value:`-360`,label:`Chicago (UTC-6)`},{value:`60`,label:`Frankfurt (UTC+1)`},{value:`480`,label:`Singapore/HK (UTC+8)`},{value:`540`,label:`Tokyo (UTC+9)`},{value:`330`,label:`Mumbai (UTC+5:30)`}],e=>this.patch({timezone:e}))),t.appendChild(this.selectRow(`Number Locale`,e.numberLocale,[{label:`en-US (65,234.00)`,value:`en-US`},{label:`de-DE (65.234,00)`,value:`de-DE`},{label:`fr-FR (65 234,00)`,value:`fr-FR`},{label:`vi-VN (65.234,00)`,value:`vi-VN`},{label:`en-IN (65,234.00)`,value:`en-IN`},{label:`ja-JP (65,234.00)`,value:`ja-JP`}],e=>this.patch({numberLocale:e}))),this.bodyEl.appendChild(t)}renderScaleTab(){if(!this.bodyEl||!this.currentSettings)return;let e=this.currentSettings,t=this.section();t.appendChild(this.toggleRow(`Auto Scale`,e.autoScale,e=>this.patch({autoScale:e}))),t.appendChild(this.selectRow(`Price Scale`,e.scaleMode,[{value:`regular`,label:`Regular`},{value:`logarithmic`,label:`Logarithmic`},{value:`percentage`,label:`Percentage`},{value:`indexedTo100`,label:`Indexed to 100`}],e=>this.patch({scaleMode:e}))),this.bodyEl.appendChild(t)}patch(e){this.currentSettings&&Object.assign(this.currentSettings,e),this.callbacks.onChange(e)}section(e){let t=document.createElement(`div`);if(t.className=`tcw-settings-section`,e){let n=document.createElement(`div`);n.className=`tcw-settings-section-title`,n.textContent=e,t.appendChild(n)}return t}colorRow(e,t,n){let r=document.createElement(`div`);r.className=`tcw-settings-row`;let i=document.createElement(`span`);i.className=`tcw-settings-label`,i.textContent=e,r.appendChild(i);let a=document.createElement(`div`);a.className=`tcw-color-picker-wrap`;let o=document.createElement(`input`);o.type=`color`,o.value=t;let s=document.createElement(`span`);return s.className=`tcw-color-hex`,s.textContent=t,o.addEventListener(`input`,()=>{s.textContent=o.value,n(o.value)}),a.appendChild(o),a.appendChild(s),r.appendChild(a),r}toggleRow(e,t,n){let r=document.createElement(`div`);r.className=`tcw-settings-row`;let i=document.createElement(`span`);i.className=`tcw-settings-label`,i.textContent=e,r.appendChild(i);let a=document.createElement(`button`);return a.className=`tcw-toggle${t?` tcw-on`:``}`,a.addEventListener(`click`,()=>{let e=!a.classList.contains(`tcw-on`);a.classList.toggle(`tcw-on`,e),n(e)}),r.appendChild(a),r}selectRow(e,t,n,r){let i=document.createElement(`div`);i.className=`tcw-settings-row`;let a=document.createElement(`span`);a.className=`tcw-settings-label`,a.textContent=e,i.appendChild(a);let o=document.createElement(`select`);o.className=`tcw-settings-select`;for(let e of n){let n=document.createElement(`option`);n.value=e.value,n.textContent=e.label,e.value===t&&(n.selected=!0),o.appendChild(n)}return o.addEventListener(`change`,()=>r(o.value)),i.appendChild(o),i}rangeRow(e,t,n,r,i,a,o=e=>String(e)){let s=document.createElement(`div`);s.className=`tcw-settings-row`;let c=document.createElement(`span`);c.className=`tcw-settings-label`,c.textContent=e,s.appendChild(c);let l=document.createElement(`div`);l.className=`tcw-settings-range`;let u=document.createElement(`input`);u.type=`range`,u.min=String(n),u.max=String(r),u.step=String(i),u.value=String(t);let d=document.createElement(`span`);return d.className=`tcw-settings-range-val`,d.textContent=o(t),u.addEventListener(`input`,()=>{let e=Number(u.value);d.textContent=o(e),a(e)}),l.appendChild(u),l.appendChild(d),s.appendChild(l),s}destroy(){this.close()}},b=class{el;dotEl;messageEl;infoEl;constructor(e){this.el=document.createElement(`div`),this.el.className=`tcw-statusbar`;let t=document.createElement(`div`);t.className=`tcw-status-indicator`,this.dotEl=document.createElement(`span`),this.dotEl.className=`tcw-status-dot`,t.appendChild(this.dotEl),this.messageEl=document.createElement(`span`),t.appendChild(this.messageEl),this.el.appendChild(t),this.infoEl=document.createElement(`span`),this.el.appendChild(this.infoEl),e.appendChild(this.el)}update(e){this.dotEl.className=`tcw-status-dot`,e.connectionState===`connected`?this.dotEl.classList.add(`tcw-connected`):e.connectionState===`error`&&this.dotEl.classList.add(`tcw-error`),this.messageEl.textContent=e.message,this.infoEl.textContent=`${e.symbol} ${e.timeframe}`}destroy(){this.el.remove()}},x=class{backdrop=null;modal=null;input=null;list=null;items=[];filtered=[];selectedIndex=0;callbacks;boundKeydown;constructor(e){this.callbacks=e,this.boundKeydown=this.handleKeydown.bind(this)}open(e){if(this.backdrop)return;this.items=e,this.filtered=e,this.selectedIndex=0,this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.addEventListener(`click`,()=>this.close()),this.modal=document.createElement(`div`),this.modal.className=`tcw-cmd-palette`;let t=document.createElement(`div`);t.className=`tcw-cmd-header`;let n=document.createElement(`span`);n.className=`tcw-cmd-icon`,n.textContent=`⌕`,t.appendChild(n),this.input=document.createElement(`input`),this.input.className=`tcw-cmd-input`,this.input.type=`text`,this.input.placeholder=`Search indicators, chart types, tools...`,this.input.addEventListener(`input`,()=>this.filter()),t.appendChild(this.input);let r=document.createElement(`span`);r.className=`tcw-cmd-hint`,r.textContent=`ESC`,t.appendChild(r),this.modal.appendChild(t),this.list=document.createElement(`div`),this.list.className=`tcw-cmd-list`,this.modal.appendChild(this.list);let i=document.createElement(`div`);i.className=`tcw-cmd-footer`,i.innerHTML=`<span>↑↓ Navigate</span><span>⏎ Select</span><span>Esc Close</span>`,this.modal.appendChild(i),document.body.appendChild(this.backdrop),document.body.appendChild(this.modal),this.renderList(),this.input.focus(),document.addEventListener(`keydown`,this.boundKeydown)}close(){document.removeEventListener(`keydown`,this.boundKeydown),this.backdrop?.remove(),this.modal?.remove(),this.backdrop=null,this.modal=null,this.input=null,this.list=null,this.callbacks.onClose()}isOpen(){return this.backdrop!==null}filter(){let e=this.input?.value.toLowerCase().trim()??``;e?this.filtered=this.items.filter(t=>t.label.toLowerCase().includes(e)||t.category.toLowerCase().includes(e)||t.id.toLowerCase().includes(e)):this.filtered=this.items,this.selectedIndex=0,this.renderList()}renderList(){if(!this.list)return;if(this.list.innerHTML=``,this.filtered.length===0){let e=document.createElement(`div`);e.className=`tcw-cmd-empty`,e.textContent=`No results found`,this.list.appendChild(e);return}let e=``;for(let t=0;t<this.filtered.length;t++){let n=this.filtered[t];if(n.category!==e){e=n.category;let t=document.createElement(`div`);t.className=`tcw-cmd-category`,t.textContent=this.categoryLabel(e),this.list.appendChild(t)}let r=document.createElement(`button`);r.className=`tcw-cmd-item`,t===this.selectedIndex&&r.classList.add(`tcw-selected`),n.active&&r.classList.add(`tcw-active`),r.dataset.index=String(t);let i=document.createElement(`span`);if(i.className=`tcw-cmd-item-label`,i.textContent=n.label,r.appendChild(i),n.active){let e=document.createElement(`span`);e.className=`tcw-cmd-check`,e.textContent=`✓`,r.appendChild(e)}if(n.shortcut){let e=document.createElement(`kbd`);e.className=`tcw-cmd-kbd`,e.textContent=n.shortcut,r.appendChild(e)}r.addEventListener(`click`,()=>this.select(t)),r.addEventListener(`mouseenter`,()=>{this.selectedIndex=t,this.updateSelection()}),this.list.appendChild(r)}}updateSelection(){if(!this.list)return;let e=this.list.querySelectorAll(`.tcw-cmd-item`);e.forEach((e,t)=>{e.classList.toggle(`tcw-selected`,t===this.selectedIndex)}),e[this.selectedIndex]?.scrollIntoView({block:`nearest`})}select(e){let t=this.filtered[e];if(t){switch(t.category){case`indicator`:this.callbacks.onIndicator(t.id);break;case`chartType`:this.callbacks.onChartType(t.id);break;case`drawing`:this.callbacks.onDrawingTool(t.id);break;case`timeframe`:this.callbacks.onTimeframe(t.id);break;case`action`:this.callbacks.onAction(t.id);break}this.close()}}handleKeydown(e){switch(e.key){case`Escape`:e.preventDefault(),this.close();break;case`ArrowDown`:e.preventDefault(),this.filtered.length>0&&(this.selectedIndex=(this.selectedIndex+1)%this.filtered.length,this.updateSelection());break;case`ArrowUp`:e.preventDefault(),this.filtered.length>0&&(this.selectedIndex=(this.selectedIndex-1+this.filtered.length)%this.filtered.length,this.updateSelection());break;case`Enter`:e.preventDefault(),this.select(this.selectedIndex);break}}categoryLabel(e){switch(e){case`indicator`:return`Indicators`;case`chartType`:return`Chart Types`;case`drawing`:return`Drawing Tools`;case`timeframe`:return`Timeframes`;case`action`:return`Actions`;default:return e}}destroy(){this.close()}},S=class{backdrop=null;modal=null;input=null;list=null;symbols=[];current=``;filtered=[];selectedIndex=0;callbacks;boundKeydown;pickOverride=null;constructor(e){this.callbacks=e,this.boundKeydown=this.handleKeydown.bind(this)}open(e,t,n){if(this.backdrop)return;this.pickOverride=n??null,this.symbols=e,this.current=t,this.filtered=e.map(e=>({symbol:e,score:0})),this.selectedIndex=Math.max(0,e.indexOf(t)),this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.addEventListener(`click`,()=>this.close()),this.modal=document.createElement(`div`),this.modal.className=`tcw-cmd-palette`;let r=document.createElement(`div`);r.className=`tcw-cmd-header`;let i=document.createElement(`span`);i.className=`tcw-cmd-icon`,i.innerHTML=E(),r.appendChild(i),this.input=document.createElement(`input`),this.input.className=`tcw-cmd-input`,this.input.type=`text`,this.input.placeholder=`Search symbol… (e.g. BTC, ETH, AAPL)`,this.input.autocomplete=`off`,this.input.spellcheck=!1,this.input.addEventListener(`input`,()=>this.filter()),r.appendChild(this.input);let a=document.createElement(`span`);a.className=`tcw-cmd-hint`,a.textContent=`ESC`,r.appendChild(a),this.modal.appendChild(r),this.list=document.createElement(`div`),this.list.className=`tcw-cmd-list`,this.modal.appendChild(this.list);let o=document.createElement(`div`);o.className=`tcw-cmd-footer`,o.innerHTML=`<span>↑↓ Navigate</span><span>⏎ Open</span><span>Esc Close</span>`,this.modal.appendChild(o),document.body.appendChild(this.backdrop),document.body.appendChild(this.modal),this.renderList(),this.input.focus(),document.addEventListener(`keydown`,this.boundKeydown)}close(){document.removeEventListener(`keydown`,this.boundKeydown),this.backdrop?.remove(),this.modal?.remove(),this.backdrop=null,this.modal=null,this.input=null,this.list=null,this.pickOverride=null,this.callbacks.onClose()}isOpen(){return this.backdrop!==null}destroy(){this.close()}filter(){let e=(this.input?.value??``).toUpperCase().trim();e?this.filtered=this.symbols.map(t=>({symbol:t,score:C(t.toUpperCase(),e)})).filter(e=>e.score>0).sort((e,t)=>t.score-e.score):this.filtered=this.symbols.map(e=>({symbol:e,score:0})),this.selectedIndex=0,this.renderList()}renderList(){if(!this.list)return;if(this.list.innerHTML=``,this.filtered.length===0){let e=document.createElement(`div`);e.className=`tcw-cmd-empty`,e.textContent=`No symbols match`,this.list.appendChild(e);return}let e=(this.input?.value??``).toUpperCase().trim();for(let t=0;t<this.filtered.length;t++){let{symbol:n}=this.filtered[t],r=document.createElement(`button`);r.className=`tcw-cmd-item`,t===this.selectedIndex&&r.classList.add(`tcw-selected`),n===this.current&&r.classList.add(`tcw-active`);let i=document.createElement(`span`);if(i.className=`tcw-cmd-item-label`,i.innerHTML=w(n,e),r.appendChild(i),n===this.current){let e=document.createElement(`span`);e.className=`tcw-cmd-check`,e.textContent=`✓`,r.appendChild(e)}r.addEventListener(`click`,()=>this.pick(t)),r.addEventListener(`mouseenter`,()=>{this.selectedIndex=t,this.updateSelection()}),this.list.appendChild(r)}}updateSelection(){if(!this.list)return;let e=this.list.querySelectorAll(`.tcw-cmd-item`);e.forEach((e,t)=>e.classList.toggle(`tcw-selected`,t===this.selectedIndex)),e[this.selectedIndex]?.scrollIntoView({block:`nearest`})}pick(e){let t=this.filtered[e];if(!t)return;let n=this.pickOverride;n?n(t.symbol):this.callbacks.onPick(t.symbol),this.close()}handleKeydown(e){switch(e.key){case`Escape`:e.preventDefault(),this.close();break;case`ArrowDown`:e.preventDefault(),this.filtered.length>0&&(this.selectedIndex=(this.selectedIndex+1)%this.filtered.length,this.updateSelection());break;case`ArrowUp`:e.preventDefault(),this.filtered.length>0&&(this.selectedIndex=(this.selectedIndex-1+this.filtered.length)%this.filtered.length,this.updateSelection());break;case`Enter`:e.preventDefault(),this.pick(this.selectedIndex);break}}};function C(e,t){if(e===t)return 1e3;if(e.startsWith(t))return 500+(50-Math.min(50,e.length-t.length));if(e.includes(t))return 200+(50-Math.min(50,e.length-t.length));let n=0,r=-1,i=0;for(let a=0;a<e.length&&n<t.length;a++)e[a]===t[n]&&(r>=0&&(i+=a-r-1),r=a,n++);return n<t.length?0:100-Math.min(99,i)}function w(e,t){if(!t)return T(e);let n=e.toUpperCase(),r=``,i=0;for(let a=0;a<e.length;a++)i<t.length&&n[a]===t[i]?(r+=`<mark style="background:transparent;color:var(--tcw-accent);font-weight:700">${T(e[a])}</mark>`,i++):r+=T(e[a]);return r}function T(e){return e.replace(/[&<>"']/g,e=>({"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`})[e])}function E(){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>`}var D=typeof navigator<`u`&&/mac|iphone|ipad|ipod/i.test(navigator.platform||navigator.userAgent)?`⌘`:`Ctrl`,O=[{title:`Search & navigation`,entries:[{keys:[D,`K`],label:`Command palette`},{keys:[D,`P`],label:`Symbol search`},{keys:[`?`],label:`Show this sheet`}]},{title:`Chart manipulation`,entries:[{keys:[`Shift`,`Drag`],label:`Measure tool (bars × price Δ)`},{keys:[`Drag`,`Price axis`],label:`Compress / expand vertical scale`},{keys:[`Drag`,`Time axis`],label:`Zoom time axis`},{keys:[`Double-click`,`Price axis`],label:`Re-enable auto-scale`},{keys:[`Double-click`,`Time axis`],label:`Fit content`},{keys:[`Scroll`],label:`Zoom around cursor`}]},{title:`Touch (mobile / tablet)`,entries:[{keys:[`1 finger`,`Drag`],label:`Pan / move crosshair`},{keys:[`2 fingers`,`Pinch`],label:`Zoom around midpoint`},{keys:[`Long-press`],label:`Pin OHLC tooltip at bar`},{keys:[`Drag`,`Axis strip`],label:`Scale price / time axis`}]},{title:`Keyboard`,entries:[{keys:[`←`,`→`],label:`Pan one bar`},{keys:[`+`,`−`],label:`Zoom in / out`},{keys:[`Home`],label:`Scroll to start`},{keys:[`End`],label:`Scroll to end (live edge)`},{keys:[`F`],label:`Fit content`}]},{title:`Drawing`,entries:[{keys:[D,`Z`],label:`Undo`},{keys:[D,`Shift`,`Z`],label:`Redo`},{keys:[`Esc`],label:`Cancel active drawing`}]}],k=class{backdrop=null;modal=null;callbacks;boundKeydown;constructor(e){this.callbacks=e,this.boundKeydown=e=>{e.key===`Escape`&&(e.preventDefault(),this.close())}}open(){if(this.backdrop)return;this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.addEventListener(`click`,()=>this.close()),this.modal=document.createElement(`div`),this.modal.className=`tcw-modal tcw-hotkey-sheet`,this.modal.style.width=`640px`;let e=document.createElement(`div`);e.className=`tcw-modal-header`,e.innerHTML=`<h3>Keyboard shortcuts</h3>`;let t=document.createElement(`button`);t.className=`tcw-modal-close`,t.setAttribute(`aria-label`,`Close`),t.innerHTML=`×`,t.addEventListener(`click`,()=>this.close()),e.appendChild(t),this.modal.appendChild(e);let n=document.createElement(`div`);n.className=`tcw-modal-body`;let r=document.createElement(`div`);r.className=`tcw-hotkey-grid`;for(let e of O){let t=document.createElement(`section`);t.className=`tcw-hotkey-section`;let n=document.createElement(`div`);n.className=`tcw-settings-section-title`,n.textContent=e.title,t.appendChild(n);for(let n of e.entries){let e=document.createElement(`div`);e.className=`tcw-hotkey-row`;let r=document.createElement(`div`);r.className=`tcw-hotkey-keys`;for(let e=0;e<n.keys.length;e++){if(e>0){let e=document.createElement(`span`);e.className=`tcw-hotkey-sep`,e.textContent=`+`,r.appendChild(e)}let t=document.createElement(`kbd`);t.className=`tcw-cmd-kbd`,t.textContent=n.keys[e],r.appendChild(t)}e.appendChild(r);let i=document.createElement(`span`);i.className=`tcw-hotkey-label`,i.textContent=n.label,e.appendChild(i),t.appendChild(e)}r.appendChild(t)}n.appendChild(r),this.modal.appendChild(n);let i=document.createElement(`div`);i.className=`tcw-modal-footer`,i.innerHTML=`<span style="font-size:11px;color:var(--tcw-text-muted)">Press ? anytime to show this sheet</span>`;let a=document.createElement(`button`);a.className=`tcw-done-btn`,a.textContent=`Got it`,a.addEventListener(`click`,()=>this.close()),i.appendChild(a),this.modal.appendChild(i),document.body.appendChild(this.backdrop),document.body.appendChild(this.modal),document.addEventListener(`keydown`,this.boundKeydown)}close(){document.removeEventListener(`keydown`,this.boundKeydown),this.backdrop?.remove(),this.modal?.remove(),this.backdrop=null,this.modal=null,this.callbacks.onClose()}isOpen(){return this.backdrop!==null}destroy(){this.close()}},A=[.5,1,2,5,10,20,50,100],j=class{root=null;scrubber=null;progressLabel=null;playBtn=null;state=`stopped`;total=0;speed=5;callbacks;constructor(e){this.callbacks=e}mount(e,t){this.root||(this.total=Math.max(0,t.total),this.speed=t.speed??5,this.state=`paused`,this.root=document.createElement(`div`),this.root.className=`tcw-replay-bar`,this.root.innerHTML=this.markup(),e.appendChild(this.root),this.wireEvents(),this.syncUi())}unmount(){this.root?.remove(),this.root=null,this.scrubber=null,this.progressLabel=null,this.playBtn=null,this.state=`stopped`}isMounted(){return this.root!==null}setState(e){this.state=e,this.syncUi()}setProgress(e,t){this.total=t,this.scrubber&&(this.scrubber.max=String(Math.max(0,t-1)),this.scrubber.value=String(e)),this.progressLabel&&(this.progressLabel.textContent=`${e+1} / ${t}`)}destroy(){this.unmount()}markup(){let e=A.map(e=>`<option value="${e}"${e===this.speed?` selected`:``}>${e}× bars/s</option>`).join(``);return`
|
|
2380
|
+
<button class="tcw-replay-btn" data-act="close" title="Exit replay" aria-label="Exit replay">${I()}</button>
|
|
2381
|
+
<button class="tcw-replay-btn" data-act="stepBack" title="Step back" aria-label="Step back">${P()}</button>
|
|
2382
|
+
<button class="tcw-replay-btn tcw-replay-play" data-act="play" title="Play / pause" aria-label="Play / pause">${M()}</button>
|
|
2383
|
+
<button class="tcw-replay-btn" data-act="stepForward" title="Step forward" aria-label="Step forward">${F()}</button>
|
|
1452
2384
|
<input type="range" class="tcw-replay-scrubber" data-act="seek" min="0" max="${Math.max(0,this.total-1)}" value="0" step="1" />
|
|
1453
2385
|
<span class="tcw-replay-progress" data-tcw="progress">1 / ${this.total}</span>
|
|
1454
2386
|
<select class="tcw-replay-speed" data-act="speed">${e}</select>
|
|
1455
|
-
`}wireEvents(){this.root&&(this.scrubber=this.root.querySelector(`input[data-act="seek"]`),this.progressLabel=this.root.querySelector(`[data-tcw="progress"]`),this.playBtn=this.root.querySelector(`button[data-act="play"]`),this.root.querySelector(`[data-act="close"]`)?.addEventListener(`click`,()=>this.callbacks.onClose()),this.root.querySelector(`[data-act="stepBack"]`)?.addEventListener(`click`,()=>this.callbacks.onStepBack()),this.root.querySelector(`[data-act="stepForward"]`)?.addEventListener(`click`,()=>this.callbacks.onStepForward()),this.playBtn?.addEventListener(`click`,()=>{this.state===`playing`?this.callbacks.onPause():this.callbacks.onPlay()}),this.scrubber?.addEventListener(`input`,()=>{let e=Number(this.scrubber.value);this.callbacks.onSeek(e)}),this.root.querySelector(`[data-act="speed"]`)?.addEventListener(`change`,e=>{let t=Number(e.target.value);this.speed=t,this.callbacks.onSpeedChange(t)}))}syncUi(){this.playBtn&&(this.playBtn.innerHTML=this.state===`playing`?F():P(),this.playBtn.title=this.state===`playing`?`Pause`:`Play`)}};function P(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7L8 5z"/></svg>`}function F(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M6 5h4v14H6zM14 5h4v14h-4z"/></svg>`}function I(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M6 6h2v12H6zM20 6L9 12l11 6V6z"/></svg>`}function L(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6l11 6L4 18V6zM16 6h2v12h-2z"/></svg>`}function R(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6L6 18M6 6l12 12"/></svg>`}var z=class{el;listEl;rowMap=new Map;entries=new Map;active=null;callbacks;constructor(e,t,n){this.callbacks=n,this.el=document.createElement(`div`),this.el.className=`tcw-watchlist`;let r=document.createElement(`div`);r.className=`tcw-watchlist-header`,r.textContent=`Watchlist`,this.el.appendChild(r),this.listEl=document.createElement(`div`),this.listEl.className=`tcw-watchlist-list`,this.el.appendChild(this.listEl);for(let e of t)this.entries.set(e,{symbol:e}),this.appendRow(e);e.appendChild(this.el)}setSymbols(e){let t=new Set(e);for(let e of this.rowMap.keys())t.has(e)||this.removeRow(e);for(let t of e)this.rowMap.has(t)||(this.entries.set(t,this.entries.get(t)??{symbol:t}),this.appendRow(t))}setActive(e){if(this.active===e)return;this.active&&this.rowMap.has(this.active)&&this.rowMap.get(this.active).row.classList.remove(`tcw-watchlist-active`),this.active=e;let t=this.rowMap.get(e);t&&t.row.classList.add(`tcw-watchlist-active`)}setEntry(e,t){let n={...this.entries.get(e)??{symbol:e},...t};this.entries.set(e,n),this.renderRow(e)}destroy(){this.el.remove(),this.rowMap.clear(),this.entries.clear()}appendRow(e){let t=document.createElement(`div`);t.className=`tcw-watchlist-row`,t.tabIndex=0;let n=document.createElement(`div`);n.className=`tcw-watchlist-symbol`,n.textContent=B(e);let r=document.createElement(`canvas`);r.className=`tcw-watchlist-spark`,r.width=64,r.height=22;let i=document.createElement(`div`);i.className=`tcw-watchlist-stats`;let a=document.createElement(`span`);a.className=`tcw-watchlist-price`,a.textContent=`—`;let o=document.createElement(`span`);o.className=`tcw-watchlist-change`,o.textContent=``,i.appendChild(a),i.appendChild(o),t.appendChild(n),t.appendChild(r),t.appendChild(i),t.addEventListener(`click`,()=>this.callbacks.onSelect(e)),t.addEventListener(`keydown`,t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),this.callbacks.onSelect(e))}),this.listEl.appendChild(t),this.rowMap.set(e,{row:t,priceEl:a,changeEl:o,sparkCanvas:r}),e===this.active&&t.classList.add(`tcw-watchlist-active`)}removeRow(e){let t=this.rowMap.get(e);t&&(t.row.remove(),this.rowMap.delete(e))}renderRow(e){let t=this.rowMap.get(e),n=this.entries.get(e);if(!(!t||!n)){if(n.lastPrice!==void 0&&(t.priceEl.textContent=V(n.lastPrice)),n.lastPrice!==void 0&&n.refPrice!==void 0&&n.refPrice!==0){let e=n.lastPrice-n.refPrice,r=e/n.refPrice*100,i=e>=0?`+`:``;t.changeEl.textContent=`${i}${r.toFixed(2)}%`,t.changeEl.className=`tcw-watchlist-change ${e>=0?`tcw-up`:`tcw-down`}`}else t.changeEl.textContent=``;n.sparkline&&n.sparkline.length>=2&&H(t.sparkCanvas,n.sparkline,n.refPrice??n.sparkline[0])}}};function B(e){for(let t of[`USDT`,`USD`,`BTC`,`ETH`,`EUR`])if(e.length>t.length&&e.endsWith(t))return e.slice(0,-t.length)+`/`+t;return e}function V(e){if(e===0)return`0`;let t=Math.abs(e);return t>=1e3?e.toFixed(2):t>=1?e.toFixed(4):e.toPrecision(4)}function H(e,t,n){let r=e.getContext(`2d`);if(!r)return;let i=window.devicePixelRatio||1;e.width!==e.clientWidth*i&&(e.width=(e.clientWidth||64)*i,e.height=(e.clientHeight||22)*i);let a=e.width,o=e.height,s=1/0,c=-1/0;for(let e of t)e<s&&(s=e),e>c&&(c=e);let l=Math.max(c-s,1e-9),u=t[t.length-1]>=n?`#26a17b`:`#f23645`;r.clearRect(0,0,a,o),r.lineWidth=1.4*i,r.strokeStyle=u,r.beginPath();let d=a/(t.length-1);for(let e=0;e<t.length;e++){let n=e*d,i=o-(t[e]-s)/l*(o-4)-2;e===0?r.moveTo(n,i):r.lineTo(n,i)}r.stroke()}var U=class{chart;state;toolbar=null;sidebar=null;settings=null;statusBar=null;commandPalette=null;symbolSearch=null;hotkeySheet=null;replayBar=null;dragDrop=null;watchlist=null;watchlistSparkBuffer=new Map;sessionRefPrice=null;watchlistInterval=null;replayOriginalData=null;replayPollInterval=null;replaySpeed=5;layoutKeyPrefix=null;layoutDebounceMs=1500;activeLayoutKey=null;root;chartContainer;destroyed=!1;options;symbols;settingsState;adapter=null;boundGlobalKeydown=null;constructor(t,l={}){if(this.options=l,this.symbols=l.symbols??s,this.settingsState={...c},l.persistLayouts){let e=l.persistLayouts===!0?{}:l.persistLayouts;this.layoutKeyPrefix=e.keyPrefix??`tcw:layout:`,this.layoutDebounceMs=e.debounceMs??1500}let u=this.resolveIsDark(l.theme),d=this.resolveTheme(l.theme);this.state={symbol:l.symbol??this.symbols[0]??`BTCUSDT`,timeframe:l.timeframe??`5m`,chartType:l.chartOptions?.chartType??`candlestick`,isDark:u,activeIndicators:new Map,activeTool:null,magnetEnabled:!0,connectionState:`connecting`,connectionMessage:`Connecting...`},f(),this.root=document.createElement(`div`),this.root.className=`tcw-root`,this.root.dataset.tcwTheme=u?`dark`:`light`,t.appendChild(this.root),l.toolbar!==!1&&(this.toolbar=new _(this.root,{symbols:this.symbols,timeframes:l.timeframes?n.filter(e=>l.timeframes.includes(e.value)):n,chartTypes:l.chartTypes?r.filter(e=>l.chartTypes.includes(e.value)):r,indicators:a,popularIndicatorIds:o},{onSymbolClick:()=>this.handleSymbolClick(),onTimeframe:e=>this.handleTimeframe(e),onChartType:e=>this.handleChartType(e),onAddIndicator:e=>this.handleAddIndicator(e),onRemoveIndicator:e=>this.handleRemoveIndicator(e),onScreenshot:()=>this.chart.screenshot(),onSettings:()=>this.openSettings(),onToggleTheme:()=>this.handleToggleTheme(),onToggleReplay:()=>this.toggleReplay()}));let p=document.createElement(`div`);p.className=`tcw-body`,l.drawingTools!==!1&&(this.sidebar=new y(p,{drawingToolGroups:i},{onDrawingTool:e=>this.handleDrawingTool(e),onCancelDrawing:()=>this.handleCancelDrawing(),onToggleMagnet:()=>this.handleToggleMagnet(),onUndo:()=>this.chart.undo(),onRedo:()=>this.chart.redo(),onClearDrawings:()=>{this.chart.clearDrawings(),this.state={...this.state,activeTool:null},this.updateUI()}})),this.chartContainer=document.createElement(`div`),this.chartContainer.className=`tcw-chart-container`,p.appendChild(this.chartContainer),l.watchlist&&(this.watchlist=new z(p,this.symbols,{onSelect:e=>{this.setSymbol(e)}}),this.watchlist.setActive(this.state.symbol)),this.root.appendChild(p),this.chart=new e.r(this.chartContainer,{chartType:this.state.chartType,theme:d,autoScale:!0,crosshair:{mode:`magnet`},features:{drawings:!0,drawingMagnet:!0,drawingUndoRedo:!0,indicators:!0,trading:l.trading!==!1,tradingContextMenu:l.trading!==!1,volume:!0,legend:!0,crosshair:!0,keyboard:!0,screenshot:!0,alerts:!0,barCountdown:!0,logScale:!0,watermark:!0},...l.chartOptions}),l.dragDropImport!==!1&&(this.dragDrop=new e.t(this.chartContainer,{onData:(e,t,n)=>{this.chart.setData(e),this.toast(`Loaded ${t.data.length} bars from ${n.name}`+(t.skipped>0?` (${t.skipped} skipped)`:``))},onError:(e,t)=>{this.toast(`${t.name}: ${e.message}`,`error`)}}),this.dragDrop.attach()),l.statusBar!==!1&&(this.statusBar=new S(this.root)),l.settings!==!1&&(this.settings=new x({onChange:e=>this.applySettings(e),onReset:()=>this.resetSettings(),onClose:()=>{}})),this.symbolSearch=new w({onPick:e=>{this.setSymbol(e)},onClose:()=>{}}),this.hotkeySheet=new j({onClose:()=>{}}),this.commandPalette=new C({onIndicator:e=>this.handleAddIndicator(e),onChartType:e=>this.handleChartType(e),onDrawingTool:e=>this.handleDrawingTool(e),onTimeframe:e=>this.handleTimeframe(e),onAction:e=>this.handleAction(e),onClose:()=>{}}),this.boundGlobalKeydown=e=>{if((e.ctrlKey||e.metaKey)&&e.key===`k`)e.preventDefault(),this.toggleCommandPalette();else if((e.ctrlKey||e.metaKey)&&(e.key===`p`||e.key===`P`))e.preventDefault(),this.symbolSearch?.open(this.symbols,this.state.symbol);else if(e.key===`?`&&!e.ctrlKey&&!e.metaKey&&!e.altKey){let t=document.activeElement;if(t&&(t.tagName===`INPUT`||t.tagName===`TEXTAREA`||t.isContentEditable))return;e.preventDefault(),this.hotkeySheet?.open()}},document.addEventListener(`keydown`,this.boundGlobalKeydown),l.adapter&&(this.adapter=l.adapter,this.connectStream()),this.watchlist&&(this.watchlistInterval=setInterval(()=>this.tickWatchlist(),1e3)),this.updateUI(),l.onReady?.(this.chart)}setSymbols(e){this.symbols=e,this.watchlist?.setSymbols(e)}async setSymbol(e){this.flushActiveLayout(),this.state={...this.state,symbol:e},this.sessionRefPrice=null,this.options.onSymbolChange?.(e),this.updateUI(),this.watchlist?.setActive(e),this.adapter&&await this.connectStream()}setWatchlistEntry(e,t){this.watchlist?.setEntry(e,t)}tickWatchlist(){if(!this.watchlist)return;let e=this.chart.getData();if(e.length===0)return;let t=e[e.length-1];this.sessionRefPrice===null&&(this.sessionRefPrice=e[0].open);let n=this.watchlistSparkBuffer.get(this.state.symbol)??[];n.push(t.close),n.length>40&&n.shift(),this.watchlistSparkBuffer.set(this.state.symbol,n),this.watchlist.setEntry(this.state.symbol,{lastPrice:t.close,refPrice:this.sessionRefPrice,sparkline:n.slice()})}async setTimeframe(e){this.state={...this.state,timeframe:e},this.options.onTimeframeChange?.(e),this.updateUI(),this.adapter&&await this.connectStream()}setTheme(e){let t=this.resolveIsDark(e),n=this.resolveTheme(e);this.state={...this.state,isDark:t},this.root.dataset.tcwTheme=t?`dark`:`light`,this.chart.setTheme(n),this.updateUI()}getChart(){return this.chart}destroy(){this.destroyed||(this.destroyed=!0,this.boundGlobalKeydown&&document.removeEventListener(`keydown`,this.boundGlobalKeydown),this.flushActiveLayout(),this.commandPalette?.destroy(),this.symbolSearch?.destroy(),this.hotkeySheet?.destroy(),this.replayPollInterval&&clearInterval(this.replayPollInterval),this.replayBar?.destroy(),this.dragDrop?.detach(),this.watchlistInterval&&clearInterval(this.watchlistInterval),this.watchlist?.destroy(),this.toolbar?.destroy(),this.sidebar?.destroy(),this.settings?.destroy(),this.statusBar?.destroy(),this.chart.destroy(),this.root.remove(),p())}handleSymbolClick(){this.symbolSearch?.open(this.symbols,this.state.symbol)}handleTimeframe(e){this.state={...this.state,timeframe:e},this.options.onTimeframeChange?.(e),this.updateUI(),this.adapter&&this.connectStream()}handleChartType(e){this.state={...this.state,chartType:e},this.chart.setChartType(e),this.updateUI()}handleAddIndicator(e){if(this.state.activeIndicators.has(e)){let t=this.state.activeIndicators.get(e);this.chart.removeIndicator(t);let n=new Map(this.state.activeIndicators);n.delete(e),this.state={...this.state,activeIndicators:n}}else{let t=this.chart.addIndicator(e);if(t){let n=new Map(this.state.activeIndicators);n.set(e,t),this.state={...this.state,activeIndicators:n}}}this.updateUI()}handleRemoveIndicator(e){this.chart.removeIndicator(e);let t=new Map(this.state.activeIndicators);for(let[n,r]of t.entries())if(r===e){t.delete(n);break}this.state={...this.state,activeIndicators:t},this.updateUI()}toggleCommandPalette(){if(this.commandPalette?.isOpen()){this.commandPalette.close();return}this.commandPalette?.open(this.buildCommandItems())}buildCommandItems(){let e=[];for(let t of a)e.push({id:t.id,label:t.name,category:`indicator`,active:this.state.activeIndicators.has(t.id)});for(let t of r)e.push({id:t.value,label:t.label,category:`chartType`,active:this.state.chartType===t.value});for(let t of i)for(let n of t.tools)e.push({id:n.value,label:n.label,category:`drawing`,active:this.state.activeTool===n.value});for(let t of n)e.push({id:t.value,label:t.label,category:`timeframe`,active:this.state.timeframe===t.value});return e.push({id:`screenshot`,label:`Screenshot`,category:`action`,shortcut:``},{id:`toggleTheme`,label:`Toggle Theme`,category:`action`},{id:`settings`,label:`Settings`,category:`action`},{id:`clearDrawings`,label:`Clear All Drawings`,category:`action`}),e}handleAction(e){switch(e){case`screenshot`:this.chart.screenshot();break;case`toggleTheme`:this.handleToggleTheme();break;case`settings`:this.openSettings();break;case`clearDrawings`:this.chart.clearDrawings(),this.state={...this.state,activeTool:null},this.updateUI();break}}handleDrawingTool(e){this.state={...this.state,activeTool:e},this.chart.setDrawingTool(e),this.updateUI()}handleCancelDrawing(){this.state={...this.state,activeTool:null},this.chart.setDrawingTool(null),this.updateUI()}handleToggleMagnet(){let e=!this.state.magnetEnabled;this.state={...this.state,magnetEnabled:e},this.chart.setDrawingMagnet(e),this.updateUI()}handleToggleTheme(){let e=!this.state.isDark;this.state={...this.state,isDark:e},this.root.dataset.tcwTheme=e?`dark`:`light`,this.chart.setTheme(e?t.DARK_THEME:t.LIGHT_THEME),this.chart.setWatermark(this.state.symbol.replace(`USDT`,` / USDT`),{fontSize:48,color:e?`rgba(255,255,255,0.03)`:`rgba(0,0,0,0.03)`}),this.updateUI()}openSettings(){this.settings?.open(this.settingsState)}toast(e,t=`info`){let n=document.createElement(`div`);n.className=`tcw-toast ${t===`error`?`tcw-toast-error`:``}`,n.textContent=e,this.root.appendChild(n),requestAnimationFrame(()=>n.classList.add(`tcw-toast-in`)),setTimeout(()=>{n.classList.remove(`tcw-toast-in`),n.addEventListener(`transitionend`,()=>n.remove(),{once:!0}),setTimeout(()=>n.remove(),400)},3500)}clearSavedLayout(e){if(!this.layoutKeyPrefix)return;let t=e??this.state.symbol;try{localStorage.removeItem(this.layoutKeyPrefix+t)}catch{}}applySymbolLayout(e){if(!this.layoutKeyPrefix)return;let t=this.layoutKeyPrefix+e;this.activeLayoutKey=t;try{this.chart.loadStateFromStorage(t)&&this.rebuildActiveIndicatorsMapFromChart()}catch{}this.chart.setAutoSave(t,this.layoutDebounceMs)}flushActiveLayout(){if(this.activeLayoutKey){try{this.chart.saveState(this.activeLayoutKey)}catch{}this.chart.disableAutoSave(),this.activeLayoutKey=null}}rebuildActiveIndicatorsMapFromChart(){let e=new Map;for(let t of this.chart.getActiveIndicators())e.set(t.id,t.instanceId);this.state={...this.state,activeIndicators:e},this.updateUI()}toggleReplay(){this.replayBar?.isMounted()?this.exitReplay():this.enterReplay()}enterReplay(){let e=this.chart.getData();e.length<2||(this.replayOriginalData=e.slice(),this.replayBar=new N({onPlay:()=>{this.chart.getReplayState()===`paused`?this.chart.replayResume():this.chart.replay({speed:this.replaySpeed,interval:200}),this.replayBar?.setState(`playing`)},onPause:()=>{this.chart.replayPause(),this.replayBar?.setState(`paused`)},onStop:()=>{this.chart.replayStop(),this.replayBar?.setState(`paused`)},onStepBack:()=>{let e=this.chart.getReplayProgress();this.chart.getReplayState()===`playing`&&this.chart.replayPause(),this.chart.replaySeek(Math.max(0,e.current-1)),this.replayBar?.setState(`paused`)},onStepForward:()=>{let e=this.chart.getReplayProgress();this.chart.getReplayState()===`playing`&&this.chart.replayPause(),this.chart.replaySeek(Math.min(e.total-1,e.current+1)),this.replayBar?.setState(`paused`)},onSeek:e=>{this.chart.getReplayState()===`playing`&&this.chart.replayPause(),this.chart.replaySeek(e),this.replayBar?.setState(`paused`)},onSpeedChange:e=>{this.replaySpeed=e,this.chart.setReplaySpeed(e)},onClose:()=>this.exitReplay()}),this.replayBar.mount(this.chartContainer,{total:e.length,speed:this.replaySpeed}),this.chart.replay({speed:this.replaySpeed,interval:200,startIndex:1}),this.chart.replayPause(),this.replayBar.setState(`paused`),this.replayPollInterval=setInterval(()=>{if(!this.replayBar?.isMounted())return;let e=this.chart.getReplayProgress();this.replayBar.setProgress(e.current,e.total);let t=this.chart.getReplayState();t===`stopped`?this.replayBar.setState(`paused`):this.replayBar.setState(t)},150))}exitReplay(){this.replayPollInterval&&=(clearInterval(this.replayPollInterval),null),this.chart.replayStop(),this.replayBar?.unmount(),this.replayBar=null,this.replayOriginalData&&=(this.chart.setData(this.replayOriginalData),null)}applySettings(e){this.settingsState={...this.settingsState,...e},e.gridVisible!==void 0&&this.chart.setGridVisible(e.gridVisible),e.volumeVisible!==void 0&&this.chart.setVolumeVisible(e.volumeVisible),e.volumeProfileVisible!==void 0&&this.chart.setVolumeProfileVisible(e.volumeProfileVisible),e.crosshairMode!==void 0&&this.chart.setCrosshairMode(e.crosshairMode),e.autoScale!==void 0&&this.chart.setAutoScale(e.autoScale),e.logScale!==void 0&&this.chart.setLogScale(e.logScale),e.numberLocale!==void 0&&this.chart.setNumberLocale(e.numberLocale);let t={...this.chart.getTheme()},n=!1;e.candleUpColor!==void 0&&(t.candleUp=e.candleUpColor,n=!0),e.candleDownColor!==void 0&&(t.candleDown=e.candleDownColor,n=!0),e.candleUpWick!==void 0&&(t.candleUpWick=e.candleUpWick,n=!0),e.candleDownWick!==void 0&&(t.candleDownWick=e.candleDownWick,n=!0),e.backgroundColor!==void 0&&(t.background=e.backgroundColor,n=!0),e.gridColor!==void 0&&(t.grid=e.gridColor,n=!0),n&&this.chart.setTheme(t)}resetSettings(){this.settingsState={...c},this.applySettings(this.settingsState)}async connectStream(){if(this.adapter){this.state={...this.state,connectionState:`connecting`,connectionMessage:`Connecting...`},this.updateUI();try{this.chart.disconnectStream(),await this.chart.connect({adapter:this.adapter,symbol:this.state.symbol,timeframe:this.state.timeframe,historyLimit:this.options.historyLimit??500}),this.chart.setWatermark(this.state.symbol.replace(`USDT`,` / USDT`),{fontSize:48,color:this.state.isDark?`rgba(255,255,255,0.03)`:`rgba(0,0,0,0.03)`}),this.applySymbolLayout(this.state.symbol),this.state={...this.state,connectionState:`connected`,connectionMessage:`Live`}}catch(e){this.state={...this.state,connectionState:`error`,connectionMessage:e instanceof Error?e.message:`Connection failed`}}this.updateUI()}}updateUI(){this.toolbar?.update(this.state),this.sidebar?.update(this.state),this.statusBar?.update({connectionState:this.state.connectionState,message:this.state.connectionMessage,symbol:this.state.symbol,timeframe:this.state.timeframe})}resolveIsDark(e){return e===void 0||e===`dark`?!0:e===`light`?!1:typeof e==`object`&&e.background?this.isColorDark(e.background):!0}resolveTheme(e){return e===void 0||e===`dark`?t.DARK_THEME:e===`light`?t.LIGHT_THEME:typeof e==`object`?e:t.DARK_THEME}isColorDark(e){if(e.startsWith(`#`)&&e.length>=7){let t=parseInt(e.slice(1,3),16),n=parseInt(e.slice(3,5),16),r=parseInt(e.slice(5,7),16);return t+n+r<384}return!0}};exports.ChartWidget=U;
|
|
2387
|
+
`}wireEvents(){this.root&&(this.scrubber=this.root.querySelector(`input[data-act="seek"]`),this.progressLabel=this.root.querySelector(`[data-tcw="progress"]`),this.playBtn=this.root.querySelector(`button[data-act="play"]`),this.root.querySelector(`[data-act="close"]`)?.addEventListener(`click`,()=>this.callbacks.onClose()),this.root.querySelector(`[data-act="stepBack"]`)?.addEventListener(`click`,()=>this.callbacks.onStepBack()),this.root.querySelector(`[data-act="stepForward"]`)?.addEventListener(`click`,()=>this.callbacks.onStepForward()),this.playBtn?.addEventListener(`click`,()=>{this.state===`playing`?this.callbacks.onPause():this.callbacks.onPlay()}),this.scrubber?.addEventListener(`input`,()=>{let e=Number(this.scrubber.value);this.callbacks.onSeek(e)}),this.root.querySelector(`[data-act="speed"]`)?.addEventListener(`change`,e=>{let t=Number(e.target.value);this.speed=t,this.callbacks.onSpeedChange(t)}))}syncUi(){this.playBtn&&(this.playBtn.innerHTML=this.state===`playing`?N():M(),this.playBtn.title=this.state===`playing`?`Pause`:`Play`)}};function M(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7L8 5z"/></svg>`}function N(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M6 5h4v14H6zM14 5h4v14h-4z"/></svg>`}function P(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M6 6h2v12H6zM20 6L9 12l11 6V6z"/></svg>`}function F(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6l11 6L4 18V6zM16 6h2v12h-2z"/></svg>`}function I(){return`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6L6 18M6 6l12 12"/></svg>`}var L=class{el;listEl;rowMap=new Map;entries=new Map;active=null;callbacks;constructor(e,t,n){this.callbacks=n,this.el=document.createElement(`div`),this.el.className=`tcw-watchlist`;let r=document.createElement(`div`);r.className=`tcw-watchlist-header`,r.textContent=`Watchlist`,this.el.appendChild(r),this.listEl=document.createElement(`div`),this.listEl.className=`tcw-watchlist-list`,this.el.appendChild(this.listEl);for(let e of t)this.entries.set(e,{symbol:e}),this.appendRow(e);e.appendChild(this.el)}setSymbols(e){let t=new Set(e);for(let e of this.rowMap.keys())t.has(e)||this.removeRow(e);for(let t of e)this.rowMap.has(t)||(this.entries.set(t,this.entries.get(t)??{symbol:t}),this.appendRow(t))}setActive(e){if(this.active===e)return;this.active&&this.rowMap.has(this.active)&&this.rowMap.get(this.active).row.classList.remove(`tcw-watchlist-active`),this.active=e;let t=this.rowMap.get(e);t&&t.row.classList.add(`tcw-watchlist-active`)}setEntry(e,t){let n={...this.entries.get(e)??{symbol:e},...t};this.entries.set(e,n),this.renderRow(e)}destroy(){this.el.remove(),this.rowMap.clear(),this.entries.clear()}appendRow(e){let t=document.createElement(`div`);t.className=`tcw-watchlist-row`,t.tabIndex=0;let n=document.createElement(`div`);n.className=`tcw-watchlist-symbol`,n.textContent=R(e);let r=document.createElement(`canvas`);r.className=`tcw-watchlist-spark`,r.width=64,r.height=22;let i=document.createElement(`div`);i.className=`tcw-watchlist-stats`;let a=document.createElement(`span`);a.className=`tcw-watchlist-price`,a.textContent=`—`;let o=document.createElement(`span`);o.className=`tcw-watchlist-change`,o.textContent=``,i.appendChild(a),i.appendChild(o),t.appendChild(n),t.appendChild(r),t.appendChild(i),t.addEventListener(`click`,()=>this.callbacks.onSelect(e)),t.addEventListener(`keydown`,t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),this.callbacks.onSelect(e))}),this.listEl.appendChild(t),this.rowMap.set(e,{row:t,priceEl:a,changeEl:o,sparkCanvas:r}),e===this.active&&t.classList.add(`tcw-watchlist-active`)}removeRow(e){let t=this.rowMap.get(e);t&&(t.row.remove(),this.rowMap.delete(e))}renderRow(e){let t=this.rowMap.get(e),n=this.entries.get(e);if(!(!t||!n)){if(n.lastPrice!==void 0&&(t.priceEl.textContent=z(n.lastPrice)),n.lastPrice!==void 0&&n.refPrice!==void 0&&n.refPrice!==0){let e=n.lastPrice-n.refPrice,r=e/n.refPrice*100,i=e>=0?`+`:``;t.changeEl.textContent=`${i}${r.toFixed(2)}%`,t.changeEl.className=`tcw-watchlist-change ${e>=0?`tcw-up`:`tcw-down`}`}else t.changeEl.textContent=``;n.sparkline&&n.sparkline.length>=2&&B(t.sparkCanvas,n.sparkline,n.refPrice??n.sparkline[0])}}};function R(e){for(let t of[`USDT`,`USD`,`BTC`,`ETH`,`EUR`])if(e.length>t.length&&e.endsWith(t))return e.slice(0,-t.length)+`/`+t;return e}function z(e){if(e===0)return`0`;let t=Math.abs(e);return t>=1e3?e.toFixed(2):t>=1?e.toFixed(4):e.toPrecision(4)}function B(e,t,n){let r=e.getContext(`2d`);if(!r)return;let i=window.devicePixelRatio||1;e.width!==e.clientWidth*i&&(e.width=(e.clientWidth||64)*i,e.height=(e.clientHeight||22)*i);let a=e.width,o=e.height,s=1/0,c=-1/0;for(let e of t)e<s&&(s=e),e>c&&(c=e);let l=Math.max(c-s,1e-9),u=t[t.length-1]>=n?`#26a17b`:`#f23645`;r.clearRect(0,0,a,o),r.lineWidth=1.4*i,r.strokeStyle=u,r.beginPath();let d=a/(t.length-1);for(let e=0;e<t.length;e++){let n=e*d,i=o-(t[e]-s)/l*(o-4)-2;e===0?r.moveTo(n,i):r.lineTo(n,i)}r.stroke()}var V=[{value:`crossing`,label:`Crossing`},{value:`crossingUp`,label:`Crossing up`},{value:`crossingDown`,label:`Crossing down`},{value:`greaterThan`,label:`Greater than`},{value:`lessThan`,label:`Less than`}],H=new Map(V.map(e=>[e.value,e.label]));function U(e){return Math.round(e*1e6)/1e6}function W(e){let t=Math.abs(e);return t>=1e3||t>=1?e.toFixed(2):e.toPrecision(4)}var G=class{el;listEl;priceInput;conditionSelect;sourceSelect;messageInput;emptyEl;callbacks;open=!1;alerts=[];sources=[{channel:`price`,label:`Price`}];constructor(e,t){this.callbacks=t,this.el=document.createElement(`div`),this.el.className=`tcw-alerts-panel`,this.el.hidden=!0;let n=document.createElement(`div`);n.className=`tcw-alerts-header`;let r=document.createElement(`span`);r.textContent=`Price Alerts`;let i=document.createElement(`button`);i.className=`tcw-alerts-close`,i.type=`button`,i.setAttribute(`aria-label`,`Close alerts`),i.innerHTML=_(`x`,14),i.addEventListener(`click`,()=>this.close()),n.appendChild(r),n.appendChild(i),this.el.appendChild(n);let a=document.createElement(`form`);a.className=`tcw-alerts-form`,this.sourceSelect=document.createElement(`select`),this.sourceSelect.className=`tcw-alerts-source`,this.sourceSelect.addEventListener(`change`,()=>this.prefillPrice()),this.priceInput=document.createElement(`input`),this.priceInput.type=`number`,this.priceInput.step=`any`,this.priceInput.placeholder=`Value`,this.priceInput.className=`tcw-alerts-price`,this.priceInput.required=!0,this.conditionSelect=document.createElement(`select`),this.conditionSelect.className=`tcw-alerts-condition`;for(let e of V){let t=document.createElement(`option`);t.value=e.value,t.textContent=e.label,this.conditionSelect.appendChild(t)}this.messageInput=document.createElement(`input`),this.messageInput.type=`text`,this.messageInput.placeholder=`Note (optional)`,this.messageInput.className=`tcw-alerts-message`;let o=document.createElement(`button`);o.type=`submit`,o.className=`tcw-alerts-add`,o.innerHTML=`${_(`plus`,14)}<span>Add alert</span>`,a.appendChild(this.sourceSelect),a.appendChild(this.priceInput),a.appendChild(this.conditionSelect),a.appendChild(this.messageInput),a.appendChild(o),a.addEventListener(`submit`,e=>{e.preventDefault(),this.submitForm()}),this.el.appendChild(a),this.listEl=document.createElement(`div`),this.listEl.className=`tcw-alerts-list`,this.el.appendChild(this.listEl),this.emptyEl=document.createElement(`div`),this.emptyEl.className=`tcw-alerts-empty`,this.emptyEl.textContent=`No alerts yet. Add one above, or right-click the chart.`,this.listEl.appendChild(this.emptyEl),this.renderSources(),e.appendChild(this.el)}setSources(e){this.sources=e.length>0?e:[{channel:`price`,label:`Price`}],this.renderSources()}renderSources(){let e=this.sourceSelect.value||`price`;this.sourceSelect.replaceChildren();for(let e of this.sources){let t=document.createElement(`option`);t.value=e.channel,t.textContent=e.label,this.sourceSelect.appendChild(t)}this.sourceSelect.value=this.sources.some(t=>t.channel===e)?e:`price`}isOpen(){return this.open}toggle(){this.open?this.close():this.openPanel()}openPanel(){this.open=!0,this.el.hidden=!1,this.priceInput.value===``&&this.prefillPrice()}prefillPrice(){let e=this.callbacks.getChannelValue(this.sourceSelect.value||`price`);this.priceInput.value=e===null?``:String(U(e))}close(){this.open=!1,this.el.hidden=!0}setAlerts(e){this.alerts=e,this.renderList()}destroy(){this.el.remove()}submitForm(){let e=Number(this.priceInput.value);if(!Number.isFinite(e))return;let t=this.conditionSelect.value,n=this.messageInput.value.trim()||void 0,r=this.sourceSelect.value||`price`,i=this.sources.find(e=>e.channel===r)?.label??`Price`;this.callbacks.onAdd(e,t,n,r,i),this.messageInput.value=``,this.prefillPrice()}renderList(){if(this.listEl.replaceChildren(),this.alerts.length===0){this.listEl.appendChild(this.emptyEl);return}for(let e of[...this.alerts].reverse()){let t=document.createElement(`div`);t.className=`tcw-alerts-row`+(e.triggered?` tcw-alerts-triggered`:``);let n=document.createElement(`div`);n.className=`tcw-alerts-info`;let r=document.createElement(`div`);r.className=`tcw-alerts-row-main`;let i=H.get(e.condition)??e.condition,a=e.channel&&e.channel!==`price`,o=a?W(e.price):this.callbacks.formatPrice(e.price);if(r.textContent=`${a&&e.label?`${e.label} `:``}${i} ${o}`,n.appendChild(r),e.message){let t=document.createElement(`div`);t.className=`tcw-alerts-row-note`,t.textContent=e.message,n.appendChild(t)}if(e.triggered){let e=document.createElement(`span`);e.className=`tcw-alerts-badge`,e.textContent=`triggered`,r.appendChild(e)}let s=document.createElement(`button`);s.type=`button`,s.className=`tcw-alerts-del`,s.setAttribute(`aria-label`,`Delete alert`),s.innerHTML=_(`trash`,14),s.addEventListener(`click`,()=>this.callbacks.onRemove(e.id)),t.appendChild(n),t.appendChild(s),this.listEl.appendChild(t)}}},K=class{el;indicatorsEl;drawingsEl;compareEl=null;callbacks;open=!1;constructor(e,t){this.callbacks=t,this.el=document.createElement(`div`),this.el.className=`tcw-tree-panel`,this.el.hidden=!0;let n=document.createElement(`div`);n.className=`tcw-tree-header`;let r=document.createElement(`span`);r.textContent=`Objects`;let i=document.createElement(`button`);i.type=`button`,i.className=`tcw-tree-close`,i.setAttribute(`aria-label`,`Close objects`),i.innerHTML=_(`x`,14),i.addEventListener(`click`,()=>this.close()),n.appendChild(r),n.appendChild(i),this.el.appendChild(n),this.indicatorsEl=this.makeSection(`Indicators`),this.drawingsEl=this.makeSection(`Drawings`),this.callbacks.onAddCompare&&(this.compareEl=this.makeSection(`Compare`,()=>this.callbacks.onAddCompare?.())),e.appendChild(this.el)}isOpen(){return this.open}toggle(){this.open?this.close():this.openPanel()}openPanel(){this.open=!0,this.el.hidden=!1}close(){this.open=!1,this.el.hidden=!0}destroy(){this.el.remove()}setObjects(e,t,n=[]){this.renderIndicators(e),this.renderDrawings(t),this.renderCompares(n)}makeSection(e,t){let n=document.createElement(`div`);n.className=`tcw-tree-section`;let r=document.createElement(`div`);r.className=`tcw-tree-section-head`;let i=document.createElement(`span`);if(i.textContent=e,r.appendChild(i),t){let n=document.createElement(`button`);n.type=`button`,n.className=`tcw-tree-add`,n.setAttribute(`aria-label`,`Add ${e.toLowerCase()}`),n.title=`Add ${e.toLowerCase()}`,n.innerHTML=_(`plus`,13),n.addEventListener(`click`,t),r.appendChild(n)}let a=document.createElement(`div`);return a.className=`tcw-tree-list`,n.appendChild(r),n.appendChild(a),this.el.appendChild(n),a}renderIndicators(e){if(this.indicatorsEl.replaceChildren(),e.length===0){this.indicatorsEl.appendChild(this.emptyRow(`No indicators`));return}for(let t of e){let e=this.row(t.name);t.visible||e.classList.add(`tcw-tree-hidden`);let n=document.createElement(`div`);n.className=`tcw-tree-actions`,this.callbacks.onToggleIndicatorVisible&&n.appendChild(this.iconButton(t.visible?`eye`:`eyeOff`,t.visible?`Hide`:`Show`,``,()=>this.callbacks.onToggleIndicatorVisible?.(t.instanceId,!t.visible))),this.callbacks.onConfigureIndicator&&n.appendChild(this.iconButton(`settings`,`Indicator settings`,``,()=>this.callbacks.onConfigureIndicator?.(t.instanceId))),n.appendChild(this.iconButton(`trash`,`Remove indicator`,`tcw-tree-del`,()=>this.callbacks.onRemoveIndicator(t.instanceId))),e.appendChild(n),this.indicatorsEl.appendChild(e)}}renderDrawings(e){if(this.drawingsEl.replaceChildren(),e.length===0){this.drawingsEl.appendChild(this.emptyRow(`No drawings`));return}for(let t of e){let e=this.row(t.label);t.visible||e.classList.add(`tcw-tree-hidden`);let n=document.createElement(`div`);n.className=`tcw-tree-actions`,n.appendChild(this.iconButton(t.visible?`eye`:`eyeOff`,t.visible?`Hide`:`Show`,``,()=>this.callbacks.onToggleDrawingVisible(t.id,!t.visible))),n.appendChild(this.iconButton(t.locked?`lock`:`unlock`,t.locked?`Unlock`:`Lock`,t.locked?`tcw-tree-on`:``,()=>this.callbacks.onToggleDrawingLocked(t.id,!t.locked))),n.appendChild(this.iconButton(`trash`,`Remove drawing`,`tcw-tree-del`,()=>this.callbacks.onRemoveDrawing(t.id))),e.appendChild(n),this.drawingsEl.appendChild(e)}}renderCompares(e){if(this.compareEl){if(this.compareEl.replaceChildren(),e.length===0){this.compareEl.appendChild(this.emptyRow(`No comparisons`));return}for(let t of e){let e=this.row(t.label),n=document.createElement(`span`);n.className=`tcw-tree-dot`,n.style.background=t.color,e.insertBefore(n,e.firstChild),this.callbacks.onRemoveCompare&&e.appendChild(this.iconButton(`trash`,`Remove comparison`,`tcw-tree-del`,()=>this.callbacks.onRemoveCompare?.(t.id))),this.compareEl.appendChild(e)}}}row(e){let t=document.createElement(`div`);t.className=`tcw-tree-row`;let n=document.createElement(`span`);return n.className=`tcw-tree-name`,n.textContent=e,n.title=e,t.appendChild(n),t}emptyRow(e){let t=document.createElement(`div`);return t.className=`tcw-tree-empty`,t.textContent=e,t}iconButton(e,t,n,r){let i=document.createElement(`button`);return i.type=`button`,i.className=`tcw-tree-btn ${n}`.trim(),i.setAttribute(`aria-label`,t),i.title=t,i.innerHTML=_(e,14),i.addEventListener(`click`,r),i}},q={trendLine:`Trend Line`,ray:`Ray`,extendedLine:`Extended Line`,horizontalLine:`Horizontal Line`,verticalLine:`Vertical Line`,rectangle:`Rectangle`,ellipse:`Ellipse`,triangle:`Triangle`,arrow:`Arrow`,parallelChannel:`Parallel Channel`,regressionChannel:`Regression Channel`,pitchfork:`Pitchfork`,fibRetracement:`Fib Retracement`,fibExtension:`Fib Extension`,fibTimeZones:`Fib Time Zones`,gannBox:`Gann Box`,gannFan:`Gann Fan`,elliottWave:`Elliott Wave`,priceRange:`Price Range`,dateRange:`Date Range`,measure:`Measure`,textAnnotation:`Text`,anchoredVWAP:`Anchored VWAP`,volumeProfileRange:`Volume Profile`};function se(e){return q[e]??e}var ce=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;function le(e){return e.replace(/_/g,` `).replace(/([a-z0-9])([A-Z])/g,`$1 $2`).replace(/^./,e=>e.toUpperCase())}var ue=class{backdrop;modal;bodyEl;titleEl;callbacks;target=null;draft={};constructor(e,t){this.callbacks=t,this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.hidden=!0,this.backdrop.addEventListener(`click`,e=>{e.target===this.backdrop&&this.close()}),this.modal=document.createElement(`div`),this.modal.className=`tcw-modal tcw-modal-narrow`;let n=document.createElement(`div`);n.className=`tcw-modal-header`,this.titleEl=document.createElement(`h3`),this.titleEl.textContent=`Indicator`;let r=document.createElement(`button`);r.className=`tcw-modal-close`,r.setAttribute(`aria-label`,`Close`),r.innerHTML=_(`x`,16),r.addEventListener(`click`,()=>this.close()),n.appendChild(this.titleEl),n.appendChild(r),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`tcw-modal-body`;let i=document.createElement(`div`);i.className=`tcw-modal-footer`;let a=document.createElement(`button`);a.className=`tcw-reset-link`,a.textContent=`Reset to defaults`,a.addEventListener(`click`,()=>this.resetDefaults());let o=document.createElement(`button`);o.className=`tcw-done-btn`,o.textContent=`Done`,o.addEventListener(`click`,()=>this.close()),i.appendChild(a),i.appendChild(o),this.modal.appendChild(n),this.modal.appendChild(this.bodyEl),this.modal.appendChild(i),this.backdrop.appendChild(this.modal),e.appendChild(this.backdrop)}open(e){this.target=e,this.titleEl.textContent=`${e.name} settings`,this.draft={},this.renderFields(),this.backdrop.hidden=!1}close(){this.backdrop.hidden=!0,this.target=null,this.callbacks.onClose()}isOpen(){return!this.backdrop.hidden}destroy(){this.backdrop.remove()}currentValue(e){if(e in this.draft)return this.draft[e];let t=this.target?.params[e],n=this.target?.defaults[e];return t??n}setValue(e,t){this.target&&(this.draft[e]=t,this.callbacks.onApply(this.target.instanceId,{...this.draft}))}resetDefaults(){if(!this.target)return;let e={};for(let[t,n]of Object.entries(this.target.defaults))e[t]=n;this.draft=e,this.callbacks.onApply(this.target.instanceId,{...e}),this.renderFields()}renderFields(){if(this.bodyEl.replaceChildren(),!this.target)return;let e=document.createElement(`div`);e.className=`tcw-settings-section`;let t=Object.keys(this.target.defaults);if(t.length===0){let t=document.createElement(`div`);t.className=`tcw-settings-label`,t.textContent=`This indicator has no adjustable parameters.`,e.appendChild(t)}for(let n of t)e.appendChild(this.fieldRow(n));this.bodyEl.appendChild(e)}fieldRow(e){let t=document.createElement(`div`);t.className=`tcw-settings-row`;let n=document.createElement(`span`);n.className=`tcw-settings-label`,n.textContent=le(e),t.appendChild(n);let r=this.currentValue(e),i=typeof(this.target?.defaults[e]??r);return i===`boolean`?t.appendChild(this.toggleControl(e,!!r)):i===`number`?t.appendChild(this.numberControl(e,Number(r))):typeof r==`string`&&ce.test(r)?t.appendChild(this.colorControl(e,r)):t.appendChild(this.textControl(e,String(r??``))),t}toggleControl(e,t){let n=document.createElement(`button`);return n.className=`tcw-toggle${t?` tcw-on`:``}`,n.type=`button`,n.addEventListener(`click`,()=>{let t=!n.classList.contains(`tcw-on`);n.classList.toggle(`tcw-on`,t),this.setValue(e,t)}),n}numberControl(e,t){let n=document.createElement(`input`);return n.type=`number`,n.className=`tcw-indi-input`,n.value=String(t),n.step=Number.isInteger(t)?`1`:`0.1`,n.addEventListener(`change`,()=>{let t=Number(n.value);Number.isFinite(t)&&this.setValue(e,t)}),n}colorControl(e,t){let n=document.createElement(`input`);return n.type=`color`,n.className=`tcw-indi-color`,n.value=t.length===4?de(t):t,n.addEventListener(`input`,()=>this.setValue(e,n.value)),n}textControl(e,t){let n=document.createElement(`input`);return n.type=`text`,n.className=`tcw-indi-input`,n.value=t,n.addEventListener(`change`,()=>this.setValue(e,n.value)),n}};function de(e){let t=e[1],n=e[2],r=e[3];return`#${t}${t}${n}${n}${r}${r}`}function fe(){try{return typeof localStorage<`u`?localStorage:null}catch{return null}}var pe=[`color`,`lineWidth`,`lineStyle`,`fillColor`,`fillOpacity`,`fontSize`];function J(e){if(!e||typeof e!=`object`)return{};let t={},n=e;for(let e of pe)n[e]!==void 0&&(t[e]=n[e]);return t}var me=class{templates=[];constructor(e=`tcw:draw-templates`,t=fe()){this.storageKey=e,this.storage=t,this.load()}list(){return this.templates.map(e=>({name:e.name,style:{...e.style}}))}get(e){let t=this.templates.find(t=>t.name===e);return t?{name:t.name,style:{...t.style}}:null}save(e,t){let n=e.trim();if(!n)return;let r=J(t);this.templates=this.templates.filter(e=>e.name!==n),this.templates.push({name:n,style:r}),this.persist()}remove(e){let t=this.templates.filter(t=>t.name!==e);t.length!==this.templates.length&&(this.templates=t,this.persist())}clear(){this.templates=[],this.persist()}load(){if(this.storage)try{let e=this.storage.getItem(this.storageKey);if(!e)return;let t=JSON.parse(e);if(!Array.isArray(t))return;this.templates=t.filter(e=>e&&typeof e.name==`string`).map(e=>({name:e.name,style:J(e.style)}))}catch{}}persist(){if(this.storage)try{this.storage.setItem(this.storageKey,JSON.stringify(this.templates))}catch{}}},he=[`#2962ff`,`#089981`,`#f23645`,`#ff9800`,`#ab47bc`,`#26c6da`,`#ffffff`,`#787b86`],ge=[1,2,3,4],_e=[`solid`,`dashed`,`dotted`],ve=class{el;templatesEl;nameInput;callbacks;store;open=!1;constructor(e,t,n){this.callbacks=t,this.store=n,this.el=document.createElement(`div`),this.el.className=`tcw-style-panel`,this.el.hidden=!0;let r=document.createElement(`div`);r.className=`tcw-style-header`;let i=document.createElement(`span`);i.textContent=`Drawing Style`;let a=document.createElement(`button`);a.type=`button`,a.className=`tcw-style-close`,a.setAttribute(`aria-label`,`Close`),a.innerHTML=_(`x`,14),a.addEventListener(`click`,()=>this.close()),r.appendChild(i),r.appendChild(a),this.el.appendChild(r),this.el.appendChild(this.colorRow()),this.el.appendChild(this.widthRow()),this.el.appendChild(this.lineStyleRow());let o=document.createElement(`div`);o.className=`tcw-style-subhead`,o.textContent=`Templates`,this.el.appendChild(o);let s=document.createElement(`div`);s.className=`tcw-style-save`,this.nameInput=document.createElement(`input`),this.nameInput.type=`text`,this.nameInput.placeholder=`Template name`,this.nameInput.className=`tcw-style-name`;let c=document.createElement(`button`);c.type=`button`,c.className=`tcw-style-savebtn`,c.innerHTML=`${_(`plus`,13)}<span>Save</span>`,c.addEventListener(`click`,()=>this.saveTemplate()),s.appendChild(this.nameInput),s.appendChild(c),this.el.appendChild(s),this.templatesEl=document.createElement(`div`),this.templatesEl.className=`tcw-style-templates`,this.el.appendChild(this.templatesEl),e.appendChild(this.el),this.renderTemplates()}isOpen(){return this.open}toggle(){this.open?this.close():this.openPanel()}openPanel(){this.open=!0,this.el.hidden=!1,this.syncActiveControls(),this.renderTemplates()}close(){this.open=!1,this.el.hidden=!0}destroy(){this.el.remove()}colorRow(){let e=document.createElement(`div`);e.className=`tcw-style-row tcw-style-colors`;for(let t of he){let n=document.createElement(`button`);n.type=`button`,n.className=`tcw-style-swatch`,n.style.background=t,n.dataset.color=t,n.setAttribute(`aria-label`,t),n.addEventListener(`click`,()=>this.applyStyle({color:t})),e.appendChild(n)}let t=document.createElement(`input`);return t.type=`color`,t.className=`tcw-style-picker`,t.addEventListener(`input`,()=>this.applyStyle({color:t.value})),e.appendChild(t),e}widthRow(){let e=document.createElement(`div`);e.className=`tcw-style-row tcw-style-widths`;for(let t of ge){let n=document.createElement(`button`);n.type=`button`,n.className=`tcw-style-width`,n.dataset.width=String(t);let r=document.createElement(`span`);r.style.height=`${t}px`,n.appendChild(r),n.addEventListener(`click`,()=>this.applyStyle({lineWidth:t})),e.appendChild(n)}return e}lineStyleRow(){let e=document.createElement(`div`);e.className=`tcw-style-row tcw-style-dashes`;for(let t of _e){let n=document.createElement(`button`);n.type=`button`,n.className=`tcw-style-dash`,n.dataset.linestyle=t,n.textContent=t===`solid`?`──`:t===`dashed`?`╌╌`:`┄┄`,n.title=t,n.addEventListener(`click`,()=>this.applyStyle({lineStyle:t})),e.appendChild(n)}return e}applyStyle(e){this.callbacks.onStyleChange(e),this.syncActiveControls()}syncActiveControls(){let e=this.callbacks.getStyle();this.el.querySelectorAll(`.tcw-style-swatch`).forEach(t=>{t.classList.toggle(`tcw-on`,t.dataset.color?.toLowerCase()===e.color?.toLowerCase())}),this.el.querySelectorAll(`.tcw-style-width`).forEach(t=>{t.classList.toggle(`tcw-on`,Number(t.dataset.width)===e.lineWidth)}),this.el.querySelectorAll(`.tcw-style-dash`).forEach(t=>{t.classList.toggle(`tcw-on`,t.dataset.linestyle===e.lineStyle)})}saveTemplate(){let e=this.nameInput.value.trim();e&&(this.store.save(e,this.callbacks.getStyle()),this.nameInput.value=``,this.renderTemplates())}renderTemplates(){this.templatesEl.replaceChildren();let e=this.store.list();if(e.length===0){let e=document.createElement(`div`);e.className=`tcw-style-empty`,e.textContent=`No saved templates`,this.templatesEl.appendChild(e);return}for(let t of e){let e=document.createElement(`div`);e.className=`tcw-style-template`;let n=document.createElement(`button`);n.type=`button`,n.className=`tcw-style-apply`;let r=document.createElement(`span`);r.className=`tcw-style-tdot`,r.style.background=t.style.color??`var(--tcw-text-muted)`;let i=document.createElement(`span`);i.textContent=t.name,n.appendChild(r),n.appendChild(i),n.addEventListener(`click`,()=>{this.callbacks.onStyleChange({...t.style}),this.syncActiveControls()});let a=document.createElement(`button`);a.type=`button`,a.className=`tcw-style-tdel`,a.setAttribute(`aria-label`,`Delete template`),a.innerHTML=_(`trash`,13),a.addEventListener(`click`,()=>{this.store.remove(t.name),this.renderTemplates()}),e.appendChild(n),e.appendChild(a),this.templatesEl.appendChild(e)}}};function ye(){try{return typeof localStorage<`u`?localStorage:null}catch{return null}}var be=class{favorites=[];constructor(e=`tcw:draw-favorites`,t=ye()){this.storageKey=e,this.storage=t,this.load()}list(){return[...this.favorites]}has(e){return this.favorites.includes(e)}add(e){!e||this.favorites.includes(e)||(this.favorites=[...this.favorites,e],this.persist())}remove(e){this.favorites.includes(e)&&(this.favorites=this.favorites.filter(t=>t!==e),this.persist())}toggle(e){return this.has(e)?(this.remove(e),!1):(this.add(e),!0)}seedDefaults(e){this.favorites.length>0||(this.favorites=[...new Set(e.filter(Boolean))],this.persist())}load(){if(this.storage)try{let e=this.storage.getItem(this.storageKey);if(!e)return;let t=JSON.parse(e);Array.isArray(t)&&(this.favorites=[...new Set(t.filter(e=>typeof e==`string`))])}catch{}}persist(){if(this.storage)try{this.storage.setItem(this.storageKey,JSON.stringify(this.favorites))}catch{}}},xe=class{el;labelEl;callbacks;visible=!1;constructor(e,t){this.callbacks=t,this.el=document.createElement(`div`),this.el.className=`tcw-bracket-bar`,this.el.hidden=!0,this.labelEl=document.createElement(`span`),this.labelEl.className=`tcw-bracket-label`,this.el.appendChild(this.labelEl);let n=document.createElement(`span`);n.className=`tcw-bracket-hint`,n.textContent=`drag lines to adjust`,this.el.appendChild(n);let r=document.createElement(`button`);r.type=`button`,r.className=`tcw-bracket-cancel`,r.innerHTML=`${_(`x`,14)}<span>Cancel</span>`,r.addEventListener(`click`,()=>this.callbacks.onCancel());let i=document.createElement(`button`);i.type=`button`,i.className=`tcw-bracket-confirm`,i.innerHTML=`${_(`check`,14)}<span>Place</span>`,i.addEventListener(`click`,()=>this.callbacks.onConfirm()),this.el.appendChild(r),this.el.appendChild(i),e.appendChild(this.el)}show(e){this.visible=!0,this.labelEl.textContent=e===`buy`?`Long bracket`:`Short bracket`,this.labelEl.dataset.side=e,this.el.hidden=!1}hide(){this.visible=!1,this.el.hidden=!0}isVisible(){return this.visible}destroy(){this.el.remove()}},Se=class{options;audioCtx=null;audioEl=null;permissionAsked=!1;constructor(e={}){if(this.options=e,typeof e.sound==`string`)try{this.audioEl=new Audio(e.sound),this.audioEl.preload=`auto`}catch{this.audioEl=null}e.desktop&&this.ensurePermission()}setOptions(e){this.options={...this.options,...e}}notify(e){this.options.sound&&this.playSound(),this.options.desktop&&this.showDesktop(e)}playSound(){if(this.audioEl){this.audioEl.currentTime=0,this.audioEl.play().catch(()=>{});return}this.beep()}beep(){try{let e=window.AudioContext??window.webkitAudioContext;if(!e)return;this.audioCtx||=new e;let t=this.audioCtx,n=t.currentTime,r=t.createGain();r.gain.setValueAtTime(1e-4,n),r.gain.exponentialRampToValueAtTime(.2,n+.01),r.gain.exponentialRampToValueAtTime(1e-4,n+.35),r.connect(t.destination);let i=t.createOscillator();i.type=`sine`,i.frequency.setValueAtTime(880,n),i.frequency.setValueAtTime(1320,n+.16),i.connect(r),i.start(n),i.stop(n+.36)}catch{}}ensurePermission(){this.permissionAsked||(this.permissionAsked=!0,!(typeof Notification>`u`)&&Notification.permission===`default`&&Notification.requestPermission().catch(()=>{}))}showDesktop(e){if(!(typeof Notification>`u`)){if(Notification.permission!==`granted`){this.ensurePermission();return}try{new Notification(this.options.title??`Price alert`,{body:e})}catch{}}}destroy(){try{this.audioCtx?.close()}catch{}this.audioCtx=null,this.audioEl=null}};function Ce(e,t=12){let n=[...e.asks].sort((e,t)=>e.price-t.price).slice(0,t),r=[...e.bids].sort((e,t)=>t.price-e.price).slice(0,t),i=n.length>0?n[0].price:null,a=r.length>0?r[0].price:null,o=i!==null&&a!==null?(i+a)/2:null,s=new Map,c=e=>{let t=s.get(e);return t||(t={price:e,bidVolume:0,askVolume:0},s.set(e,t)),t};for(let e of n)c(e.price).askVolume+=e.volume;for(let e of r)c(e.price).bidVolume+=e.volume;let l=[...s.values()].sort((e,t)=>t.price-e.price),u=0;for(let e of l)u=Math.max(u,e.bidVolume,e.askVolume);return{rows:l,maxVolume:u,mid:o}}var we=class{el;bodyEl;callbacks;open=!1;levels;constructor(e,t,n=12){this.callbacks=t,this.levels=n,this.el=document.createElement(`div`),this.el.className=`tcw-ladder`,this.el.hidden=!0;let r=document.createElement(`div`);r.className=`tcw-ladder-header`;let i=document.createElement(`span`);i.textContent=`Depth Ladder`;let a=document.createElement(`button`);a.type=`button`,a.className=`tcw-ladder-close`,a.setAttribute(`aria-label`,`Close`),a.innerHTML=_(`x`,14),a.addEventListener(`click`,()=>this.close()),r.appendChild(i),r.appendChild(a),this.el.appendChild(r);let o=document.createElement(`div`);o.className=`tcw-ladder-cols`,o.innerHTML=`<span>Bid</span><span>Price</span><span>Ask</span>`,this.el.appendChild(o),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`tcw-ladder-body`,this.el.appendChild(this.bodyEl),e.appendChild(this.el)}isOpen(){return this.open}toggle(){this.open?this.close():this.openPanel()}openPanel(){this.open=!0,this.el.hidden=!1}close(){this.open=!1,this.el.hidden=!0}setData(e){if(!e){this.renderEmpty();return}this.render(Ce(e,this.levels))}destroy(){this.el.remove()}renderEmpty(){this.bodyEl.replaceChildren();let e=document.createElement(`div`);e.className=`tcw-ladder-empty`,e.textContent=`No order-book data`,this.bodyEl.appendChild(e)}render(e){if(this.bodyEl.replaceChildren(),e.rows.length===0){this.renderEmpty();return}let t=e.maxVolume>0?1/e.maxVolume:0;for(let n of e.rows){let e=n.askVolume>0,r=document.createElement(`div`);r.className=`tcw-ladder-row`;let i=document.createElement(`button`);i.type=`button`,i.className=`tcw-ladder-cell tcw-ladder-bid`,n.bidVolume>0?(i.textContent=Y(n.bidVolume),i.style.setProperty(`--w`,`${(n.bidVolume*t*100).toFixed(1)}%`),i.title=`Sell @ ${this.callbacks.formatPrice(n.price)}`,i.addEventListener(`click`,()=>this.callbacks.onTrade(`sell`,n.price))):i.disabled=!0;let a=document.createElement(`div`);a.className=`tcw-ladder-price ${e?`tcw-ask`:`tcw-bid`}`,a.textContent=this.callbacks.formatPrice(n.price);let o=document.createElement(`button`);o.type=`button`,o.className=`tcw-ladder-cell tcw-ladder-ask`,n.askVolume>0?(o.textContent=Y(n.askVolume),o.style.setProperty(`--w`,`${(n.askVolume*t*100).toFixed(1)}%`),o.title=`Buy @ ${this.callbacks.formatPrice(n.price)}`,o.addEventListener(`click`,()=>this.callbacks.onTrade(`buy`,n.price))):o.disabled=!0,r.appendChild(i),r.appendChild(a),r.appendChild(o),this.bodyEl.appendChild(r)}}};function Y(e){return e>=1e3?(e/1e3).toFixed(1)+`k`:e>=1?e.toFixed(2).replace(/\.00$/,``):e.toPrecision(2)}var Te=class{el;bodyEl;callbacks;open=!1;constructor(e,t){this.callbacks=t,this.el=document.createElement(`div`),this.el.className=`tcw-datawin`,this.el.hidden=!0;let n=document.createElement(`div`);n.className=`tcw-datawin-header`;let r=document.createElement(`span`);r.textContent=`Data Window`;let i=document.createElement(`button`);i.type=`button`,i.className=`tcw-datawin-close`,i.setAttribute(`aria-label`,`Close`),i.innerHTML=_(`x`,14),i.addEventListener(`click`,()=>this.close()),n.appendChild(r),n.appendChild(i),this.el.appendChild(n),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`tcw-datawin-body`,this.el.appendChild(this.bodyEl),e.appendChild(this.el)}isOpen(){return this.open}toggle(){this.open?this.close():this.openPanel()}openPanel(){this.open=!0,this.el.hidden=!1}close(){this.open=!1,this.el.hidden=!0}destroy(){this.el.remove()}render(e){if(!this.open)return;if(this.bodyEl.replaceChildren(),!e.ohlc){let e=document.createElement(`div`);e.className=`tcw-datawin-empty`,e.textContent=`Hover the chart`,this.bodyEl.appendChild(e);return}let t=this.callbacks.formatPrice,n=e.ohlc;this.bodyEl.appendChild(this.row(`Open`,t(n.open))),this.bodyEl.appendChild(this.row(`High`,t(n.high))),this.bodyEl.appendChild(this.row(`Low`,t(n.low))),this.bodyEl.appendChild(this.row(`Close`,t(n.close)));let r=e.change>0?`up`:e.change<0?`down`:``,i=e.change>0?`+`:``;this.bodyEl.appendChild(this.row(`Change`,`${i}${t(e.change)} (${i}${e.changePct.toFixed(2)}%)`,r)),this.bodyEl.appendChild(this.row(`Volume`,De(n.volume)));for(let t of e.indicators){let e=document.createElement(`div`);e.className=`tcw-datawin-sub`,e.textContent=t.name,this.bodyEl.appendChild(e);for(let e of t.values)this.bodyEl.appendChild(this.row(e.key,Ee(e.value)))}}row(e,t,n=``){let r=document.createElement(`div`);r.className=`tcw-datawin-row`;let i=document.createElement(`span`);i.className=`tcw-datawin-label`,i.textContent=e;let a=document.createElement(`span`);return a.className=`tcw-datawin-value${n?` tcw-${n}`:``}`,a.textContent=t,r.appendChild(i),r.appendChild(a),r}};function Ee(e){if(!Number.isFinite(e))return`—`;let t=Math.abs(e);return t>=1e3?e.toFixed(2):t>=1?e.toFixed(4):e.toPrecision(4)}function De(e){return e>=1e9?(e/1e9).toFixed(2)+`B`:e>=1e6?(e/1e6).toFixed(2)+`M`:e>=1e3?(e/1e3).toFixed(2)+`K`:e.toFixed(0)}var X=globalThis.Buffer;function Oe(e){if(X)return X.from(e,`utf8`).toString(`base64`);let t=new TextEncoder().encode(e),n=``;for(let e of t)n+=String.fromCharCode(e);return btoa(n)}function ke(e){if(X)return X.from(e,`base64`).toString(`utf8`);let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return new TextDecoder().decode(n)}function Z(e){return e.replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function Ae(e){let t=e.replace(/-/g,`+`).replace(/_/g,`/`);return t+(t.length%4==0?``:`=`.repeat(4-t.length%4))}function je(e){return Z(Oe(JSON.stringify(e)))}function Me(e){if(!e)return null;try{let t=ke(Ae(e)),n=JSON.parse(t);return!n||n.v!==1||typeof n.symbol!=`string`?null:{v:1,symbol:n.symbol,timeframe:n.timeframe,chartType:n.chartType,scaleMode:n.scaleMode??`regular`,indicators:Array.isArray(n.indicators)?n.indicators:[],drawings:Array.isArray(n.drawings)?n.drawings:[]}}catch{return null}}var Q=`tcw`;function Ne(e){let t=e.startsWith(`#`)?e.slice(1):e;for(let e of t.split(`&`)){let t=e.indexOf(`=`);if(t>0&&e.slice(0,t)===Q)return decodeURIComponent(e.slice(t+1))}return null}function Pe(e,t){let[n]=e.split(`#`);return`${n}#${Q}=${t}`}var $=[`#f7931a`,`#627eea`,`#26a17b`,`#e84142`,`#8247e5`,`#f3ba2f`],Fe=class{chart;state;toolbar=null;sidebar=null;settings=null;statusBar=null;commandPalette=null;symbolSearch=null;hotkeySheet=null;replayBar=null;dragDrop=null;alertsPanel=null;objectTree=null;indicatorSettings=null;drawingStyle=null;bracketBar=null;alertNotifier=null;depthLadder=null;dataWindow=null;lastHoverIndex=null;favoritesStore=new be;watchlist=null;watchlistSparkBuffer=new Map;sessionRefPrice=null;watchlistInterval=null;replayOriginalData=null;replayPollInterval=null;replaySpeed=5;layoutKeyPrefix=null;layoutDebounceMs=1500;activeLayoutKey=null;root;chartContainer;destroyed=!1;options;symbols;settingsState;adapter=null;boundGlobalKeydown=null;baseSeries=null;baseTimeframeMs=0;compares=[];constructor(t,n={}){if(this.options=n,this.symbols=n.symbols??l,this.settingsState={...u},n.persistLayouts){let e=n.persistLayouts===!0?{}:n.persistLayouts;this.layoutKeyPrefix=e.keyPrefix??`tcw:layout:`,this.layoutDebounceMs=e.debounceMs??1500}let r=this.resolveIsDark(n.theme),d=this.resolveTheme(n.theme);this.state={symbol:n.symbol??this.symbols[0]??`BTCUSDT`,timeframe:n.timeframe??`5m`,chartType:n.chartOptions?.chartType??`candlestick`,isDark:r,activeIndicators:new Map,activeTool:null,magnetEnabled:!0,connectionState:`connecting`,connectionMessage:`Connecting...`},m(),this.root=document.createElement(`div`),this.root.className=`tcw-root`,this.root.dataset.tcwTheme=r?`dark`:`light`,t.appendChild(this.root),n.toolbar!==!1&&(this.toolbar=new y(this.root,{symbols:this.symbols,timeframes:n.timeframes?i.filter(e=>n.timeframes.includes(e.value)):i,chartTypes:n.chartTypes?a.filter(e=>n.chartTypes.includes(e.value)):a,indicators:s,popularIndicatorIds:c},{onSymbolClick:()=>this.handleSymbolClick(),onTimeframe:e=>this.handleTimeframe(e),onChartType:e=>this.handleChartType(e),onAddIndicator:e=>this.handleAddIndicator(e),onRemoveIndicator:e=>this.handleRemoveIndicator(e),onScreenshot:()=>this.chart.screenshot(),onSettings:()=>this.openSettings(),onToggleTheme:()=>this.handleToggleTheme(),onToggleReplay:()=>this.toggleReplay(),onToggleAlerts:n.alerts===!1?void 0:()=>this.toggleAlerts(),onToggleObjects:n.objectTree===!1?void 0:()=>this.toggleObjects(),onBracket:n.trading===!1?void 0:e=>this.startBracket(e),onToggleLadder:n.trading!==!1&&n.depthLadder?()=>this.depthLadder?.toggle():void 0}));let f=document.createElement(`div`);if(f.className=`tcw-body`,n.drawingTools!==!1&&(n.drawingFavorites&&this.favoritesStore.seedDefaults(n.drawingFavorites),this.sidebar=new ie(f,{drawingToolGroups:o,favorites:this.favoritesStore.list()},{onDrawingTool:e=>this.handleDrawingTool(e),onCancelDrawing:()=>this.handleCancelDrawing(),onToggleMagnet:()=>this.handleToggleMagnet(),onToggleFavorite:e=>this.handleToggleFavorite(e),onUndo:()=>this.chart.undo(),onRedo:()=>this.chart.redo(),onClearDrawings:()=>{this.chart.clearDrawings(),this.state={...this.state,activeTool:null},this.updateUI()},onToggleStyle:()=>this.drawingStyle?.toggle()})),this.chartContainer=document.createElement(`div`),this.chartContainer.className=`tcw-chart-container`,f.appendChild(this.chartContainer),n.watchlist&&(this.watchlist=new L(f,this.symbols,{onSelect:e=>{this.setSymbol(e)}}),this.watchlist.setActive(this.state.symbol)),this.root.appendChild(f),this.chart=new e.r(this.chartContainer,{chartType:this.state.chartType,theme:d,autoScale:!0,crosshair:{mode:`magnet`},features:{drawings:!0,drawingMagnet:!0,drawingUndoRedo:!0,indicators:!0,trading:n.trading!==!1,tradingContextMenu:n.trading!==!1,volume:!0,legend:!0,crosshair:!0,keyboard:!0,screenshot:!0,alerts:!0,barCountdown:!0,logScale:!0,watermark:!0},...n.chartOptions}),n.dragDropImport!==!1&&(this.dragDrop=new e.t(this.chartContainer,{onData:(e,t,n)=>{this.setData(e),this.toast(`Loaded ${t.data.length} bars from ${n.name}`+(t.skipped>0?` (${t.skipped} skipped)`:``))},onError:(e,t)=>{this.toast(`${t.name}: ${e.message}`,`error`)}}),this.dragDrop.attach()),n.statusBar!==!1&&(this.statusBar=new b(this.root)),n.settings!==!1&&(this.settings=new oe({onChange:e=>this.applySettings(e),onReset:()=>this.resetSettings(),onClose:()=>{}})),this.symbolSearch=new S({onPick:e=>{this.setSymbol(e)},onClose:()=>{}}),this.hotkeySheet=new k({onClose:()=>{}}),this.chart.on(`barClick`,e=>{if(!this.replayBar?.isMounted())return;let t=e.payload.barIndex;typeof t==`number`&&(this.chart.getReplayState()===`playing`&&this.chart.replayPause(),this.chart.replaySeek(t),this.replayBar.setState(`paused`))}),this.dataWindow=new Te(this.root,{formatPrice:e=>this.formatAlertPrice(e)}),this.chart.on(`crosshairMove`,e=>{let t=e.payload;this.lastHoverIndex=typeof t.barIndex==`number`?t.barIndex:null,this.dataWindow?.isOpen()&&this.dataWindow.render(this.buildDataWindowModel())}),n.drawingTools!==!1&&(this.drawingStyle=new ve(this.root,{onStyleChange:e=>{this.chart.setDrawingStyle(e),this.chart.setSelectedDrawingStyle(e)},getStyle:()=>this.chart.getDrawingStyle()},new me)),n.trading!==!1&&(this.bracketBar=new xe(this.root,{onConfirm:()=>this.chart.confirmBracket(),onCancel:()=>{this.chart.cancelBracket(),this.bracketBar?.hide()}}),this.chart.on(`bracketPlace`,e=>{let t=e.payload;this.bracketBar?.hide(),this.toast(`${t.side===`buy`?`Long`:`Short`} bracket placed · ${t.riskReward.toFixed(2)}R`)}),n.depthLadder&&(this.depthLadder=new we(this.root,{onTrade:(e,t)=>{this.chart.placeOrderIntent({side:e,type:`limit`,price:t}),this.toast(`${e===`buy`?`Buy`:`Sell`} limit @ ${this.formatAlertPrice(t)}`)},formatPrice:e=>this.formatAlertPrice(e)})),this.chart.on(`dataUpdate`,e=>{let t=e.payload;t&&t.bracket===`cancelled`&&this.bracketBar?.hide()})),n.alerts!==!1&&(this.alertsPanel=new G(this.root,{onAdd:(e,t,n,r,i)=>{this.chart.addAlert(e,t,n,r,i)},onRemove:e=>this.chart.removeAlert(e),onClear:()=>this.chart.clearAlerts(),getChannelValue:e=>this.getAlertChannelValue(e),formatPrice:e=>this.formatAlertPrice(e)}),this.chart.on(`alertAdd`,()=>this.refreshAlerts()),this.chart.on(`alertRemove`,()=>this.refreshAlerts()),this.chart.on(`alertUpdate`,()=>this.refreshAlerts()),n.alertNotifications&&(this.alertNotifier=new Se(n.alertNotifications)),this.chart.on(`alertTriggered`,e=>{let t=e.payload,n=`Price ${this.formatAlertPrice(t.price)}${t.message?` — ${t.message}`:``}`;this.toast(`🔔 Alert: ${n}`,`info`),this.alertNotifier?.notify(n),this.refreshAlerts()})),n.objectTree!==!1){this.indicatorSettings=new ue(this.root,{onApply:(e,t)=>this.chart.updateIndicator(e,t),onClose:()=>{}}),this.objectTree=new K(this.root,{onRemoveIndicator:e=>this.handleRemoveIndicator(e),onConfigureIndicator:e=>this.openIndicatorSettings(e),onToggleIndicatorVisible:(e,t)=>{this.chart.setIndicatorVisible(e,t),this.refreshObjects()},onRemoveDrawing:e=>{this.chart.removeDrawing(e),this.refreshObjects()},onToggleDrawingVisible:(e,t)=>{this.chart.setDrawingVisible(e,t),this.refreshObjects()},onToggleDrawingLocked:(e,t)=>{this.chart.setDrawingLocked(e,t),this.refreshObjects()},onAddCompare:()=>this.handleAddCompare(),onRemoveCompare:e=>this.handleRemoveCompare(e)});let e=()=>{this.objectTree?.isOpen()&&this.refreshObjects()};this.chart.on(`drawingCreate`,e),this.chart.on(`drawingRemove`,e),this.chart.on(`indicatorAdd`,e),this.chart.on(`indicatorRemove`,e)}if(this.commandPalette=new x({onIndicator:e=>this.handleAddIndicator(e),onChartType:e=>this.handleChartType(e),onDrawingTool:e=>this.handleDrawingTool(e),onTimeframe:e=>this.handleTimeframe(e),onAction:e=>this.handleAction(e),onClose:()=>{}}),this.boundGlobalKeydown=e=>{if((e.ctrlKey||e.metaKey)&&e.key===`k`)e.preventDefault(),this.toggleCommandPalette();else if((e.ctrlKey||e.metaKey)&&(e.key===`p`||e.key===`P`))e.preventDefault(),this.symbolSearch?.open(this.symbols,this.state.symbol);else if(e.key===`?`&&!e.ctrlKey&&!e.metaKey&&!e.altKey){let t=document.activeElement;if(t&&(t.tagName===`INPUT`||t.tagName===`TEXTAREA`||t.isContentEditable))return;e.preventDefault(),this.hotkeySheet?.open()}},document.addEventListener(`keydown`,this.boundGlobalKeydown),n.adapter&&(this.adapter=n.adapter,this.connectStream()),this.watchlist&&(this.watchlistInterval=setInterval(()=>this.tickWatchlist(),1e3)),this.updateUI(),n.onReady?.(this.chart),n.shareUrl&&typeof location<`u`){let e=Ne(location.hash);e&&this.importState(e)}}setSymbols(e){this.symbols=e,this.watchlist?.setSymbols(e)}async setSymbol(e){this.flushActiveLayout(),this.state={...this.state,symbol:e},this.sessionRefPrice=null,this.options.onSymbolChange?.(e),this.updateUI(),this.watchlist?.setActive(e),this.adapter&&await this.connectStream()}setWatchlistEntry(e,t){this.watchlist?.setEntry(e,t)}tickWatchlist(){if(!this.watchlist)return;let e=this.chart.getData();if(e.length===0)return;let t=e[e.length-1];this.sessionRefPrice===null&&(this.sessionRefPrice=e[0].open);let n=this.watchlistSparkBuffer.get(this.state.symbol)??[];n.push(t.close),n.length>40&&n.shift(),this.watchlistSparkBuffer.set(this.state.symbol,n),this.watchlist.setEntry(this.state.symbol,{lastPrice:t.close,refPrice:this.sessionRefPrice,sparkline:n.slice()})}async setTimeframe(e){if(this.state={...this.state,timeframe:e},this.options.onTimeframeChange?.(e),this.updateUI(),this.adapter){await this.connectStream();return}this.options.resampleTimeframes!==!1&&this.applyTimeframeData()}setTheme(e){let t=this.resolveIsDark(e),n=this.resolveTheme(e);this.state={...this.state,isDark:t},this.root.dataset.tcwTheme=t?`dark`:`light`,this.chart.setTheme(n),this.updateUI()}getChart(){return this.chart}destroy(){this.destroyed||(this.destroyed=!0,this.boundGlobalKeydown&&document.removeEventListener(`keydown`,this.boundGlobalKeydown),this.flushActiveLayout(),this.commandPalette?.destroy(),this.symbolSearch?.destroy(),this.hotkeySheet?.destroy(),this.replayPollInterval&&clearInterval(this.replayPollInterval),this.replayBar?.destroy(),this.dragDrop?.detach(),this.alertsPanel?.destroy(),this.objectTree?.destroy(),this.indicatorSettings?.destroy(),this.drawingStyle?.destroy(),this.bracketBar?.destroy(),this.alertNotifier?.destroy(),this.depthLadder?.destroy(),this.dataWindow?.destroy(),this.watchlistInterval&&clearInterval(this.watchlistInterval),this.watchlist?.destroy(),this.toolbar?.destroy(),this.sidebar?.destroy(),this.settings?.destroy(),this.statusBar?.destroy(),this.chart.destroy(),this.root.remove(),h())}handleSymbolClick(){this.symbolSearch?.open(this.symbols,this.state.symbol)}handleTimeframe(e){if(this.state={...this.state,timeframe:e},this.options.onTimeframeChange?.(e),this.updateUI(),this.adapter){this.connectStream();return}if(this.options.resampleTimeframes!==!1){if(!this.baseSeries){let e=this.chart.getData();e.length>0&&(this.baseSeries=e,this.baseTimeframeMs=r(e))}this.applyTimeframeData()}}setData(e){this.baseSeries=e,this.baseTimeframeMs=r(e),this.applyTimeframeData()}applyTimeframeData(){if(!this.baseSeries)return;let e=(0,t.timeframeToMs)(this.state.timeframe);if(this.baseTimeframeMs>0&&e>this.baseTimeframeMs){let e=this.options.weekStartsOn??1;this.chart.setData(n(this.baseSeries,this.state.timeframe,{weekStartsOn:e}))}else this.chart.setData(this.baseSeries)}toggleAlerts(){this.alertsPanel&&(this.alertsPanel.toggle(),this.alertsPanel.isOpen()&&this.refreshAlerts())}handleToggleFavorite(e){let t=this.favoritesStore.toggle(e);this.sidebar?.setFavorites(this.favoritesStore.list()),this.toast(t?`Pinned to favorites`:`Unpinned`)}exportState(){let e=this.chart.getActiveIndicators().map(e=>({id:e.id,params:e.params}));return je({v:1,symbol:this.state.symbol,timeframe:this.state.timeframe,chartType:this.state.chartType,scaleMode:this.chart.getScaleMode(),indicators:e,drawings:this.chart.getDrawings()})}async importState(e){let t=Me(e);if(!t)return!1;t.symbol&&t.symbol!==this.state.symbol&&await this.setSymbol(t.symbol),t.timeframe&&t.timeframe!==this.state.timeframe&&await this.setTimeframe(t.timeframe),t.chartType&&this.handleChartType(t.chartType),this.chart.setScaleMode(t.scaleMode);for(let[,e]of this.state.activeIndicators)this.chart.removeIndicator(e);let n=new Map;for(let e of t.indicators){let t=this.chart.addIndicator(e.id,e.params);t&&n.set(e.id,t)}return this.state={...this.state,activeIndicators:n},this.chart.setDrawings(t.drawings),this.updateUI(),!0}async copyChartImage(){let e=await this.chart.copyScreenshot();this.toast(e?`Chart image copied`:`Copy failed — image clipboard unavailable`,e?`info`:`error`)}async copyShareLink(){let e=Pe(typeof location<`u`?location.href:``,this.exportState());try{await navigator.clipboard.writeText(e),this.toast(`Share link copied`)}catch{this.toast(`Copy failed — clipboard unavailable`,`error`)}}setDepth(e){this.chart.setDepthData(e),this.depthLadder?.setData(e),e&&this.chart.pushDepthSnapshot(e)}startBracket(e){this.chart.startBracket(e)&&this.bracketBar?.show(e)}buildDataWindowModel(){let e=this.chart.getData(),t=this.lastHoverIndex;if(t===null||t<0||t>=e.length)return{ohlc:null,change:0,changePct:0,indicators:[]};let n=e[t],r=t>0?e[t-1].close:n.open,i=n.close-r,a=r===0?0:i/r*100,o=this.chart.getActiveIndicators().map(e=>{let n=this.chart.getIndicatorOutput(e.instanceId)?.series?.[t]??null,r=n?Object.entries(n).filter(([,e])=>typeof e==`number`&&Number.isFinite(e)).map(([e,t])=>({key:e,value:t})):[];return{name:e.descriptor.name,values:r}}).filter(e=>e.values.length>0);return{ohlc:{open:n.open,high:n.high,low:n.low,close:n.close,volume:n.volume},change:i,changePct:a,indicators:o}}toggleDataWindow(){this.dataWindow&&(this.dataWindow.toggle(),this.dataWindow.isOpen()&&this.dataWindow.render(this.buildDataWindowModel()))}toggleObjects(){this.objectTree&&(this.objectTree.toggle(),this.objectTree.isOpen()&&this.refreshObjects())}openIndicatorSettings(e){if(!this.indicatorSettings)return;let t=this.chart.getActiveIndicators().find(t=>t.instanceId===e);t&&this.indicatorSettings.open({instanceId:e,name:t.descriptor.name,defaults:t.descriptor.defaultConfig,params:t.params})}refreshObjects(){if(!this.objectTree)return;let e=this.chart.getActiveIndicators().map(e=>({instanceId:e.instanceId,name:e.descriptor.name,visible:e.visible})),t=this.chart.getDrawings().map(e=>({id:e.id,label:se(e.type),visible:e.visible,locked:e.locked})),n=this.compares.map(e=>({id:e.id,label:e.symbol,color:e.color}));this.objectTree.setObjects(e,t,n)}async handleAddCompare(){if(!this.adapter){this.toast(`Comparison needs a live data adapter`,`error`);return}let e=new Set([this.state.symbol,...this.compares.map(e=>e.symbol)]),t=this.symbols.filter(t=>!e.has(t));this.symbolSearch?.open(t.length?t:this.symbols,this.state.symbol,e=>{this.addCompareSymbol(e)})}async addCompareSymbol(e){if(!this.adapter||this.compares.some(t=>t.symbol===e))return;let t=$[this.compares.length%$.length],n=`cmp_${e}`;try{let r=await this.adapter.fetchHistory(e,this.state.timeframe,this.options.historyLimit??500);this.compares.length===0&&this.chart.setCompareMode(`percent`),this.chart.addCompareSymbol(n,e,r,t),this.compares=[...this.compares,{id:n,symbol:e,color:t}],this.refreshObjects(),this.toast(`Comparing ${e}`)}catch(t){this.toast(`${e}: ${t instanceof Error?t.message:`failed to load`}`,`error`)}}handleRemoveCompare(e){this.chart.removeCompareSymbol(e),this.compares=this.compares.filter(t=>t.id!==e),this.refreshObjects()}async refetchCompares(){if(!this.adapter||this.compares.length===0)return;let e=this.compares.filter(e=>e.symbol===this.state.symbol);for(let t of e)this.handleRemoveCompare(t.id);for(let e of this.compares)try{let t=await this.adapter.fetchHistory(e.symbol,this.state.timeframe,this.options.historyLimit??500);this.chart.updateCompareData(e.id,t)}catch{}}refreshAlerts(){this.alertsPanel&&(this.alertsPanel.setSources(this.buildAlertSources()),this.alertsPanel.setAlerts(this.chart.getAlerts().map(e=>({id:e.id,price:e.price,condition:e.condition,message:e.message,triggered:e.triggered,channel:e.channel,label:e.label}))))}buildAlertSources(){let e=[{channel:`price`,label:`Price`}];for(let t of this.chart.getActiveIndicators()){let n=this.chart.getIndicatorOutput(t.instanceId)?.series,r=n&&n.length>0?n[n.length-1]:null,i=r?Object.keys(r).filter(e=>typeof r[e]==`number`):[];for(let n of i){let r=i.length>1?`${t.descriptor.name} ${n}`:t.descriptor.name;e.push({channel:`${t.instanceId}:${n}`,label:r})}}return e}getAlertChannelValue(e){let t=this.chart.getData();if(e===`price`)return t.length>0?t[t.length-1].close:null;let n=e.indexOf(`:`);if(n<0||t.length===0)return null;let r=e.slice(0,n),i=e.slice(n+1),a=this.chart.getIndicatorOutput(r)?.series?.[t.length-1]?.[i];return typeof a==`number`&&Number.isFinite(a)?a:null}formatAlertPrice(e){let t=Math.abs(e),n=t>=1e3?2:t>=1?4:6,r=this.settingsState.numberLocale||void 0;return e.toLocaleString(r,{minimumFractionDigits:2,maximumFractionDigits:n})}handleChartType(e){this.state={...this.state,chartType:e},this.chart.setChartType(e),this.updateUI()}handleAddIndicator(e){if(this.state.activeIndicators.has(e)){let t=this.state.activeIndicators.get(e);this.chart.removeIndicator(t);let n=new Map(this.state.activeIndicators);n.delete(e),this.state={...this.state,activeIndicators:n}}else{let t=this.chart.addIndicator(e);if(t){let n=new Map(this.state.activeIndicators);n.set(e,t),this.state={...this.state,activeIndicators:n}}}this.updateUI()}handleRemoveIndicator(e){this.chart.removeIndicator(e);let t=new Map(this.state.activeIndicators);for(let[n,r]of t.entries())if(r===e){t.delete(n);break}this.state={...this.state,activeIndicators:t},this.updateUI()}toggleCommandPalette(){if(this.commandPalette?.isOpen()){this.commandPalette.close();return}this.commandPalette?.open(this.buildCommandItems())}buildCommandItems(){let e=[];for(let t of s)e.push({id:t.id,label:t.name,category:`indicator`,active:this.state.activeIndicators.has(t.id)});for(let t of a)e.push({id:t.value,label:t.label,category:`chartType`,active:this.state.chartType===t.value});for(let t of o)for(let n of t.tools)e.push({id:n.value,label:n.label,category:`drawing`,active:this.state.activeTool===n.value});for(let t of i)e.push({id:t.value,label:t.label,category:`timeframe`,active:this.state.timeframe===t.value});return e.push({id:`screenshot`,label:`Screenshot`,category:`action`,shortcut:``},{id:`copyImage`,label:`Copy Chart Image`,category:`action`},{id:`toggleTheme`,label:`Toggle Theme`,category:`action`},{id:`settings`,label:`Settings`,category:`action`},{id:`shareView`,label:`Share View (copy link)`,category:`action`},{id:`autoFib`,label:`Auto Fibonacci (visible swing)`,category:`action`},{id:`dataWindow`,label:`Toggle Data Window`,category:`action`},{id:`clearDrawings`,label:`Clear All Drawings`,category:`action`}),e}handleAction(e){switch(e){case`screenshot`:this.chart.screenshot();break;case`toggleTheme`:this.handleToggleTheme();break;case`settings`:this.openSettings();break;case`copyImage`:this.copyChartImage();break;case`shareView`:this.copyShareLink();break;case`autoFib`:{let e=this.chart.autoFib();this.toast(e?`Auto Fibonacci added`:`No clear swing in view`);break}case`dataWindow`:this.toggleDataWindow();break;case`clearDrawings`:this.chart.clearDrawings(),this.state={...this.state,activeTool:null},this.updateUI();break}}handleDrawingTool(e){this.state={...this.state,activeTool:e},this.chart.setDrawingTool(e),this.updateUI()}handleCancelDrawing(){this.state={...this.state,activeTool:null},this.chart.setDrawingTool(null),this.updateUI()}handleToggleMagnet(){let e=!this.state.magnetEnabled;this.state={...this.state,magnetEnabled:e},this.chart.setDrawingMagnet(e),this.updateUI()}handleToggleTheme(){let e=!this.state.isDark;this.state={...this.state,isDark:e},this.root.dataset.tcwTheme=e?`dark`:`light`,this.chart.setTheme(e?t.DARK_THEME:t.LIGHT_THEME),this.chart.setWatermark(this.state.symbol.replace(`USDT`,` / USDT`),{fontSize:48,color:e?`rgba(255,255,255,0.03)`:`rgba(0,0,0,0.03)`}),this.updateUI()}openSettings(){this.settings?.open(this.settingsState)}toast(e,t=`info`){let n=document.createElement(`div`);n.className=`tcw-toast ${t===`error`?`tcw-toast-error`:``}`,n.textContent=e,this.root.appendChild(n),requestAnimationFrame(()=>n.classList.add(`tcw-toast-in`)),setTimeout(()=>{n.classList.remove(`tcw-toast-in`),n.addEventListener(`transitionend`,()=>n.remove(),{once:!0}),setTimeout(()=>n.remove(),400)},3500)}clearSavedLayout(e){if(!this.layoutKeyPrefix)return;let t=e??this.state.symbol;try{localStorage.removeItem(this.layoutKeyPrefix+t)}catch{}}applySymbolLayout(e){if(!this.layoutKeyPrefix)return;let t=this.layoutKeyPrefix+e;this.activeLayoutKey=t;try{this.chart.loadStateFromStorage(t)&&this.rebuildActiveIndicatorsMapFromChart()}catch{}this.chart.setAutoSave(t,this.layoutDebounceMs)}flushActiveLayout(){if(this.activeLayoutKey){try{this.chart.saveState(this.activeLayoutKey)}catch{}this.chart.disableAutoSave(),this.activeLayoutKey=null}}rebuildActiveIndicatorsMapFromChart(){let e=new Map;for(let t of this.chart.getActiveIndicators())e.set(t.id,t.instanceId);this.state={...this.state,activeIndicators:e},this.updateUI()}toggleReplay(){this.replayBar?.isMounted()?this.exitReplay():this.enterReplay()}enterReplay(){let e=this.chart.getData();e.length<2||(this.replayOriginalData=e.slice(),this.replayBar=new j({onPlay:()=>{this.chart.getReplayState()===`paused`?this.chart.replayResume():this.chart.replayStart({speed:this.replaySpeed,interval:200}),this.replayBar?.setState(`playing`)},onPause:()=>{this.chart.replayPause(),this.replayBar?.setState(`paused`)},onStop:()=>{this.chart.replayStop(),this.replayBar?.setState(`paused`)},onStepBack:()=>{let e=this.chart.getReplayProgress();this.chart.getReplayState()===`playing`&&this.chart.replayPause(),this.chart.replaySeek(Math.max(0,e.current-1)),this.replayBar?.setState(`paused`)},onStepForward:()=>{let e=this.chart.getReplayProgress();this.chart.getReplayState()===`playing`&&this.chart.replayPause(),this.chart.replaySeek(Math.min(e.total-1,e.current+1)),this.replayBar?.setState(`paused`)},onSeek:e=>{this.chart.getReplayState()===`playing`&&this.chart.replayPause(),this.chart.replaySeek(e),this.replayBar?.setState(`paused`)},onSpeedChange:e=>{this.replaySpeed=e,this.chart.setReplaySpeed(e)},onClose:()=>this.exitReplay()}),this.replayBar.mount(this.chartContainer,{total:e.length,speed:this.replaySpeed}),this.chart.replayStart({speed:this.replaySpeed,interval:200,startIndex:1}),this.chart.replayPause(),this.replayBar.setState(`paused`),this.replayPollInterval=setInterval(()=>{if(!this.replayBar?.isMounted())return;let e=this.chart.getReplayProgress();this.replayBar.setProgress(e.current,e.total);let t=this.chart.getReplayState();t===`stopped`?this.replayBar.setState(`paused`):this.replayBar.setState(t)},150))}exitReplay(){this.replayPollInterval&&=(clearInterval(this.replayPollInterval),null),this.chart.replayStop(),this.replayBar?.unmount(),this.replayBar=null,this.replayOriginalData&&=(this.chart.setData(this.replayOriginalData),null)}applySettings(e){this.settingsState={...this.settingsState,...e},e.gridVisible!==void 0&&this.chart.setGridVisible(e.gridVisible),e.volumeVisible!==void 0&&this.chart.setVolumeVisible(e.volumeVisible),e.volumeProfileVisible!==void 0&&this.chart.setVolumeProfileVisible(e.volumeProfileVisible),e.marketProfileVisible!==void 0&&this.chart.setMarketProfileVisible(e.marketProfileVisible),e.marketProfileSplit!==void 0&&this.chart.setMarketProfileConfig({splitBySession:e.marketProfileSplit}),e.marketProfileLetters!==void 0&&this.chart.setMarketProfileConfig({letters:e.marketProfileLetters}),e.marketProfileBuckets!==void 0&&this.chart.setMarketProfileConfig({buckets:e.marketProfileBuckets}),e.marketProfileOpacity!==void 0&&this.chart.setMarketProfileConfig({opacity:e.marketProfileOpacity}),e.depthHeatmapVisible!==void 0&&this.chart.setDepthHeatmapVisible(e.depthHeatmapVisible),e.depthHeatmapOpacity!==void 0&&this.chart.setDepthHeatmapConfig({opacity:e.depthHeatmapOpacity}),e.sessionShadingVisible!==void 0&&this.chart.setSessionShadingVisible(e.sessionShadingVisible),e.pivotMarkersVisible!==void 0&&this.chart.setPivotMarkersVisible(e.pivotMarkersVisible),e.pivotStrength!==void 0&&this.chart.setPivotMarkersConfig({left:e.pivotStrength,right:e.pivotStrength}),e.pivotStructureLabels!==void 0&&this.chart.setPivotMarkersConfig({structureLabels:e.pivotStructureLabels}),e.periodLevelsVisible!==void 0&&this.chart.setPeriodLevelsVisible(e.periodLevelsVisible),e.periodLevelsPeriod!==void 0&&this.chart.setPeriodLevelsPeriod(e.periodLevelsPeriod),e.crosshairMode!==void 0&&this.chart.setCrosshairMode(e.crosshairMode),e.autoScale!==void 0&&this.chart.setAutoScale(e.autoScale),e.scaleMode===void 0?e.logScale!==void 0&&(this.chart.setLogScale(e.logScale),this.settingsState={...this.settingsState,scaleMode:e.logScale?`logarithmic`:`regular`}):(this.chart.setScaleMode(e.scaleMode),this.settingsState={...this.settingsState,logScale:e.scaleMode===`logarithmic`}),e.numberLocale!==void 0&&this.chart.setNumberLocale(e.numberLocale),e.timezone!==void 0&&this.chart.setTimezoneOffset(e.timezone===`local`?null:Number(e.timezone));let t={...this.chart.getTheme()},n=!1;e.candleUpColor!==void 0&&(t.candleUp=e.candleUpColor,n=!0),e.candleDownColor!==void 0&&(t.candleDown=e.candleDownColor,n=!0),e.candleUpWick!==void 0&&(t.candleUpWick=e.candleUpWick,n=!0),e.candleDownWick!==void 0&&(t.candleDownWick=e.candleDownWick,n=!0),e.backgroundColor!==void 0&&(t.background=e.backgroundColor,n=!0),e.gridColor!==void 0&&(t.grid=e.gridColor,n=!0),n&&this.chart.setTheme(t)}resetSettings(){this.settingsState={...u},this.applySettings(this.settingsState)}async connectStream(){if(this.adapter){this.state={...this.state,connectionState:`connecting`,connectionMessage:`Connecting...`},this.updateUI();try{this.chart.disconnectStream(),await this.chart.connect({adapter:this.adapter,symbol:this.state.symbol,timeframe:this.state.timeframe,historyLimit:this.options.historyLimit??500}),this.chart.setWatermark(this.state.symbol.replace(`USDT`,` / USDT`),{fontSize:48,color:this.state.isDark?`rgba(255,255,255,0.03)`:`rgba(0,0,0,0.03)`}),this.applySymbolLayout(this.state.symbol),this.state={...this.state,connectionState:`connected`,connectionMessage:`Live`},this.refetchCompares()}catch(e){this.state={...this.state,connectionState:`error`,connectionMessage:e instanceof Error?e.message:`Connection failed`}}this.updateUI()}}updateUI(){this.toolbar?.update(this.state),this.sidebar?.update(this.state),this.statusBar?.update({connectionState:this.state.connectionState,message:this.state.connectionMessage,symbol:this.state.symbol,timeframe:this.state.timeframe})}resolveIsDark(e){return e===void 0||e===`dark`?!0:e===`light`?!1:typeof e==`object`&&e.background?this.isColorDark(e.background):!0}resolveTheme(e){return e===void 0||e===`dark`?t.DARK_THEME:e===`light`?t.LIGHT_THEME:typeof e==`object`?e:t.DARK_THEME}isColorDark(e){if(e.startsWith(`#`)&&e.length>=7){let t=parseInt(e.slice(1,3),16),n=parseInt(e.slice(3,5),16),r=parseInt(e.slice(5,7),16);return t+n+r<384}return!0}};exports.ChartWidget=Fe;
|
|
1456
2388
|
//# sourceMappingURL=index.cjs.map
|