acttrader-charts 1.0.11 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -429,6 +429,9 @@ var DEFAULT_TOP_BAR_CONFIG = {
429
429
  dropBtnFontFamily: INTER_FONT,
430
430
  drawBtnSize: "26px",
431
431
  drawBtnIconFontSize: "14px",
432
+ iconBtnSize: "26px",
433
+ mobileIconBtnSize: "28px",
434
+ mobileDrawBtnIconSize: "16px",
432
435
  flyoutRowFontSize: "12px",
433
436
  flyoutRowFontFamily: INTER_FONT,
434
437
  flyoutCategoryFontSize: "10px",
@@ -466,6 +469,12 @@ var DEFAULT_INDICATOR_OVERLAY_CONFIG = {
466
469
  dropdownRowFontFamily: INTER_FONT,
467
470
  dropdownIconFontSize: "10px"
468
471
  };
472
+ var DEFAULT_TRADE_BUTTON_CONFIG = {
473
+ size: 22,
474
+ mobileSize: 24,
475
+ iconSize: 14,
476
+ mobileIconSize: 16
477
+ };
469
478
  var DEFAULT_UI_CONFIG = {
470
479
  drawingToolbar: DEFAULT_DRAWING_TOOLBAR_CONFIG,
471
480
  topBar: DEFAULT_TOP_BAR_CONFIG,
@@ -473,7 +482,8 @@ var DEFAULT_UI_CONFIG = {
473
482
  priceAxis: DEFAULT_PRICE_AXIS_CONFIG,
474
483
  timeAxis: DEFAULT_TIME_AXIS_CONFIG,
475
484
  crosshair: DEFAULT_CROSSHAIR_CONFIG,
476
- indicatorOverlay: DEFAULT_INDICATOR_OVERLAY_CONFIG
485
+ indicatorOverlay: DEFAULT_INDICATOR_OVERLAY_CONFIG,
486
+ tradeButton: DEFAULT_TRADE_BUTTON_CONFIG
477
487
  };
478
488
  function resolveUiConfig(override) {
479
489
  if (!override) return DEFAULT_UI_CONFIG;
@@ -484,7 +494,8 @@ function resolveUiConfig(override) {
484
494
  priceAxis: { ...DEFAULT_PRICE_AXIS_CONFIG, ...override.priceAxis },
485
495
  timeAxis: { ...DEFAULT_TIME_AXIS_CONFIG, ...override.timeAxis },
486
496
  crosshair: { ...DEFAULT_CROSSHAIR_CONFIG, ...override.crosshair },
487
- indicatorOverlay: { ...DEFAULT_INDICATOR_OVERLAY_CONFIG, ...override.indicatorOverlay }
497
+ indicatorOverlay: { ...DEFAULT_INDICATOR_OVERLAY_CONFIG, ...override.indicatorOverlay },
498
+ tradeButton: { ...DEFAULT_TRADE_BUTTON_CONFIG, ...override.tradeButton }
488
499
  };
489
500
  }
490
501
 
@@ -2101,7 +2112,7 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
2101
2112
  ctx.restore();
2102
2113
  if (draggable) {
2103
2114
  drawGripHandle(ctx, gripX, boxY, boxH, colors, hovered);
2104
- const BTN_ZONE_W = EDIT_R * 2 + EDIT_GAP + CLOSE_R * 2 + BOX_PAD_X / 2;
2115
+ const BTN_ZONE_W = hideConfirmCancel ? 0 : EDIT_R * 2 + EDIT_GAP + CLOSE_R * 2 + BOX_PAD_X / 2;
2105
2116
  dragAreas.push({
2106
2117
  label: level.label,
2107
2118
  type: level.type,
@@ -2111,7 +2122,8 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
2111
2122
  y: boxY,
2112
2123
  w: GRIP_W + 2 + boxW - BTN_ZONE_W,
2113
2124
  h: boxH,
2114
- isBracket: false
2125
+ isBracket: false,
2126
+ isBox: true
2115
2127
  });
2116
2128
  dragAreas.push({
2117
2129
  label: level.label,
@@ -2124,6 +2136,19 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
2124
2136
  h: 8,
2125
2137
  isBracket: false
2126
2138
  });
2139
+ } else if (hideConfirmCancel && boxW > 0) {
2140
+ dragAreas.push({
2141
+ label: level.label,
2142
+ type: level.type,
2143
+ data: level.data,
2144
+ price: level.price,
2145
+ x: boxX,
2146
+ y: boxY,
2147
+ w: boxW,
2148
+ h: boxH,
2149
+ isBracket: false,
2150
+ isBox: true
2151
+ });
2127
2152
  }
2128
2153
  hoverAreas.push({
2129
2154
  label: level.label,
@@ -3224,6 +3249,9 @@ var TopBar = class {
3224
3249
  this.fullscreenBtn.innerHTML = active ? ICON_FULLSCREEN_EXIT : ICON_FULLSCREEN_ENTER;
3225
3250
  this.fullscreenBtn.title = active ? this.labels.exitFullscreenTitle : this.labels.toggleFullscreenTitle;
3226
3251
  this.applyIconBtnStyles(this.fullscreenBtn, this.theme, active);
3252
+ if (this.isMobileLayout) {
3253
+ this.resizeSvg(this.fullscreenBtn, this.getSvgSize(this.fullscreenBtn) + 2);
3254
+ }
3227
3255
  }
3228
3256
  setDrawingsBtnActive(active) {
3229
3257
  if (!this.drawingBtn) return;
@@ -3276,6 +3304,21 @@ var TopBar = class {
3276
3304
  }
3277
3305
  this.durationSep.style.display = btnDisplay;
3278
3306
  this.durationDropBtn.style.display = isMobile ? "" : "none";
3307
+ const containerSize = isMobile ? this.cfg.mobileIconBtnSize : this.cfg.iconBtnSize;
3308
+ for (const btn of [this.fullscreenBtn, this.settingsBtn, this.drawingBtn]) {
3309
+ if (!btn) continue;
3310
+ btn.style.width = containerSize;
3311
+ btn.style.height = containerSize;
3312
+ }
3313
+ const delta = isMobile ? 2 : -2;
3314
+ this.resizeSvg(this.fullscreenBtn, this.getSvgSize(this.fullscreenBtn) + delta);
3315
+ if (this.settingsBtn) {
3316
+ this.resizeSvg(this.settingsBtn, this.getSvgSize(this.settingsBtn) + delta);
3317
+ }
3318
+ if (this.drawingBtn) {
3319
+ const drawIconSize = isMobile ? parseInt(this.cfg.mobileDrawBtnIconSize, 10) : parseInt(this.cfg.drawBtnIconFontSize, 10);
3320
+ this.resizeSvg(this.drawingBtn, drawIconSize);
3321
+ }
3279
3322
  }
3280
3323
  setIndicatorOptions(options) {
3281
3324
  this.indicatorOptions = options;
@@ -3682,13 +3725,14 @@ var TopBar = class {
3682
3725
  }
3683
3726
  applyIconBtnStyles(btn, theme, active) {
3684
3727
  btn.dataset.active = String(active);
3728
+ const size = this.isMobileLayout ? this.cfg.mobileIconBtnSize : this.cfg.iconBtnSize;
3685
3729
  Object.assign(btn.style, {
3686
3730
  background: active ? theme.ui.accentBg : "transparent",
3687
3731
  color: active ? theme.ui.accentText : theme.topBar.btnColor,
3688
3732
  border: `1px solid ${active ? theme.ui.accent : theme.axisBorder}`,
3689
3733
  borderRadius: "5px",
3690
- width: "26px",
3691
- height: "26px",
3734
+ width: size,
3735
+ height: size,
3692
3736
  cursor: "pointer",
3693
3737
  outline: "none",
3694
3738
  display: "flex",
@@ -3699,6 +3743,20 @@ var TopBar = class {
3699
3743
  transition: "border-color 0.12s, background 0.12s"
3700
3744
  });
3701
3745
  }
3746
+ resizeSvg(btn, size) {
3747
+ if (!btn) return;
3748
+ const svg = btn.querySelector("svg");
3749
+ if (svg) {
3750
+ svg.setAttribute("width", String(size));
3751
+ svg.setAttribute("height", String(size));
3752
+ }
3753
+ }
3754
+ getSvgSize(btn) {
3755
+ if (!btn) return 0;
3756
+ const svg = btn.querySelector("svg");
3757
+ if (!svg) return 0;
3758
+ return parseInt(svg.getAttribute("width") ?? "0", 10);
3759
+ }
3702
3760
  };
3703
3761
 
3704
3762
  // src/ui/BottomBar.ts
@@ -12215,9 +12273,11 @@ var ChartSettingsDialog = class {
12215
12273
 
12216
12274
  // src/ui/TradeButton.ts
12217
12275
  var TradeButton = class {
12218
- constructor(theme, priceAxisWidth, onClick, labels = DEFAULT_LABELS.trade) {
12276
+ constructor(theme, priceAxisWidth, onClick, labels = DEFAULT_LABELS.trade, cfg = DEFAULT_TRADE_BUTTON_CONFIG) {
12219
12277
  this._visible = false;
12278
+ this._isMobile = false;
12220
12279
  this.theme = theme;
12280
+ this.cfg = cfg;
12221
12281
  this.el = document.createElement("button");
12222
12282
  this.el.innerHTML = ICON_PLUS_CIRCLE;
12223
12283
  this.el.title = labels.placeOrderTitle;
@@ -12225,8 +12285,8 @@ var TradeButton = class {
12225
12285
  position: "absolute",
12226
12286
  right: `${priceAxisWidth + 26}px`,
12227
12287
  top: "0",
12228
- width: "22px",
12229
- height: "22px",
12288
+ width: `${cfg.size}px`,
12289
+ height: `${cfg.size}px`,
12230
12290
  borderRadius: "50%",
12231
12291
  border: `1px solid ${theme.axisBorder}`,
12232
12292
  background: theme.tooltip.background,
@@ -12245,6 +12305,7 @@ var TradeButton = class {
12245
12305
  pointerEvents: "auto",
12246
12306
  userSelect: "none"
12247
12307
  });
12308
+ this.applyIconSize(cfg.iconSize);
12248
12309
  this.el.addEventListener("click", (e) => {
12249
12310
  e.stopPropagation();
12250
12311
  onClick();
@@ -12292,6 +12353,27 @@ var TradeButton = class {
12292
12353
  right: `${priceAxisWidth + 26}px`
12293
12354
  });
12294
12355
  }
12356
+ /**
12357
+ * Toggle mobile sizing. When `isMobile` is true, the button diameter and
12358
+ * inner SVG icon are swapped for the configured mobile values; when false,
12359
+ * they revert to desktop values.
12360
+ */
12361
+ setMobileMode(isMobile) {
12362
+ if (this._isMobile === isMobile) return;
12363
+ this._isMobile = isMobile;
12364
+ const size = isMobile ? this.cfg.mobileSize : this.cfg.size;
12365
+ const iconSize = isMobile ? this.cfg.mobileIconSize : this.cfg.iconSize;
12366
+ this.el.style.width = `${size}px`;
12367
+ this.el.style.height = `${size}px`;
12368
+ this.applyIconSize(iconSize);
12369
+ }
12370
+ applyIconSize(size) {
12371
+ const svg = this.el.querySelector("svg");
12372
+ if (svg) {
12373
+ svg.setAttribute("width", String(size));
12374
+ svg.setAttribute("height", String(size));
12375
+ }
12376
+ }
12295
12377
  };
12296
12378
 
12297
12379
  // src/ui/TradePopover.ts
@@ -13964,7 +14046,7 @@ var _ChartEngine = class _ChartEngine {
13964
14046
  Math.min(Math.ceil(this.viewport.endIndex), Math.round(rawBarIndex))
13965
14047
  );
13966
14048
  const bar = this.dataStore.all[clamped] ?? null;
13967
- this.crosshair = isInChartArea && !this.tradePopover?.isVisible ? { x, y, barIndex: clamped, price, bar } : null;
14049
+ this.crosshair = isInChartArea && !this.tradePopover?.isVisible && this.selectedTradeLabel === null ? { x, y, barIndex: clamped, price, bar } : null;
13968
14050
  if (this.crosshair) this.emitter.emit("crosshair", this.crosshair);
13969
14051
  const hoveringDotLevel = this.positionRenderStyle === "dot" && this.hoveredTradeLabel !== null;
13970
14052
  if (this.tradeButton) {
@@ -14303,8 +14385,9 @@ var _ChartEngine = class _ChartEngine {
14303
14385
  e.preventDefault();
14304
14386
  const level = this.levels.find((l) => l.label === dragHit.label);
14305
14387
  if (level) {
14306
- const isLimitStopDraftLevel = level.data?._isDraft === true && level.orderType !== "market";
14307
- if (this.hideLevelConfirmCancel && !dragHit.isBracket && !isLimitStopDraftLevel) {
14388
+ const isAlreadySelected = this.selectedTradeLabel === level.label;
14389
+ const isMobileDraggable = dragHit.isBracket || level.type === "pending" && level.orderType !== "market" && (isAlreadySelected || !dragHit.isBox);
14390
+ if (this.hideLevelConfirmCancel && !isMobileDraggable) {
14308
14391
  const hasPending = this.pendingLevelDrags.has(level.label);
14309
14392
  if (this.selectedTradeLabel === level.label && !hasPending) {
14310
14393
  this.selectedTradeLabel = null;
@@ -14482,7 +14565,7 @@ var _ChartEngine = class _ChartEngine {
14482
14565
  Math.min(Math.ceil(this.viewport.endIndex), Math.round(rawBarIndex))
14483
14566
  );
14484
14567
  const bar = this.dataStore.all[clamped] ?? null;
14485
- this.crosshair = { x, y, barIndex: clamped, price, bar };
14568
+ this.crosshair = this.selectedTradeLabel === null ? { x, y, barIndex: clamped, price, bar } : null;
14486
14569
  if (this.tradeButton) {
14487
14570
  this.tradeButton.setY(y);
14488
14571
  if (this._isTradingActive) {
@@ -15092,30 +15175,32 @@ var _ChartEngine = class _ChartEngine {
15092
15175
  padding: "0 2px"
15093
15176
  });
15094
15177
  this.canvasWrap.appendChild(this.textInputEl);
15095
- this.loadingOverlayEl = document.createElement("div");
15096
- Object.assign(this.loadingOverlayEl.style, {
15097
- display: "none",
15098
- position: "absolute",
15099
- top: "0",
15100
- left: "0",
15101
- width: "100%",
15102
- height: "100%",
15103
- alignItems: "center",
15104
- justifyContent: "center",
15105
- pointerEvents: "none",
15106
- zIndex: "20"
15107
- });
15108
- const loadingLabel = document.createElement("span");
15109
- loadingLabel.textContent = this.labels.chart.loading;
15110
- Object.assign(loadingLabel.style, {
15111
- color: "rgba(200,200,200,0.9)",
15112
- fontSize: "13px",
15113
- background: "rgba(0,0,0,0.45)",
15114
- padding: "4px 12px",
15115
- borderRadius: "4px"
15116
- });
15117
- this.loadingOverlayEl.appendChild(loadingLabel);
15118
- this.canvasWrap.appendChild(this.loadingOverlayEl);
15178
+ if (showUI) {
15179
+ this.loadingOverlayEl = document.createElement("div");
15180
+ Object.assign(this.loadingOverlayEl.style, {
15181
+ display: "none",
15182
+ position: "absolute",
15183
+ top: "0",
15184
+ left: "0",
15185
+ width: "100%",
15186
+ height: "100%",
15187
+ alignItems: "center",
15188
+ justifyContent: "center",
15189
+ pointerEvents: "none",
15190
+ zIndex: "20"
15191
+ });
15192
+ const loadingLabel = document.createElement("span");
15193
+ loadingLabel.textContent = this.labels.chart.loading;
15194
+ Object.assign(loadingLabel.style, {
15195
+ color: "rgba(200,200,200,0.9)",
15196
+ fontSize: "13px",
15197
+ background: "rgba(0,0,0,0.45)",
15198
+ padding: "4px 12px",
15199
+ borderRadius: "4px"
15200
+ });
15201
+ this.loadingOverlayEl.appendChild(loadingLabel);
15202
+ this.canvasWrap.appendChild(this.loadingOverlayEl);
15203
+ }
15119
15204
  if (showUI) {
15120
15205
  this.siEl = document.createElement("div");
15121
15206
  Object.assign(this.siEl.style, {
@@ -15247,7 +15332,8 @@ var _ChartEngine = class _ChartEngine {
15247
15332
  );
15248
15333
  }
15249
15334
  },
15250
- this.labels.trade
15335
+ this.labels.trade,
15336
+ this.uiConfig.tradeButton
15251
15337
  );
15252
15338
  this.canvasWrap.appendChild(this.tradeButton.el);
15253
15339
  this.tradeButton.el.addEventListener("mouseenter", () => {
@@ -15847,6 +15933,30 @@ var _ChartEngine = class _ChartEngine {
15847
15933
  this.emitStateChange();
15848
15934
  return this;
15849
15935
  }
15936
+ /** Programmatically change the active timeframe and reload data. */
15937
+ setTimeframe(tf) {
15938
+ this.timeframe = tf;
15939
+ this.topBar?.setTimeframe(tf);
15940
+ this.emitter.emit("timeframeChange", { timeframe: tf });
15941
+ this.emitStateChange();
15942
+ this.updateCountdownState();
15943
+ this.triggerLoad("timeframe");
15944
+ return this;
15945
+ }
15946
+ /** Update per-theme deep-partial color overrides and rebuild the active theme. */
15947
+ setThemeOverrides(overrides) {
15948
+ this.themeOverrides = overrides;
15949
+ this.theme = this.buildTheme(this.themeName);
15950
+ this.topBar?.setTheme(this.theme);
15951
+ this.bottomBar?.setTheme(this.theme);
15952
+ this.leftBar?.setTheme(this.theme);
15953
+ this.tradeButton?.setTheme(this.theme, this.priceAxisWidth);
15954
+ this.tradePopover?.setTheme(this.theme);
15955
+ this.indicatorSettingsDialog?.setTheme(this.theme);
15956
+ this.chartSettingsDialog?.setTheme(this.theme);
15957
+ this.scheduleRender();
15958
+ return this;
15959
+ }
15850
15960
  setSeries(series) {
15851
15961
  this.series = series;
15852
15962
  this.topBar?.setSeries(series);
@@ -16375,8 +16485,10 @@ var _ChartEngine = class _ChartEngine {
16375
16485
  addLevelBracket(label, type) {
16376
16486
  const level = this.levels.find((l) => l.label === label);
16377
16487
  if (!level) return this;
16378
- const alreadyHas = type === "sl" ? level.stopLossPrice !== void 0 : level.takeProfitPrice !== void 0;
16379
- if (alreadyHas) return this;
16488
+ const dragField = type === "sl" ? "stopLoss" : "takeProfit";
16489
+ const alreadyHasInLevel = type === "sl" ? level.stopLossPrice !== void 0 : level.takeProfitPrice !== void 0;
16490
+ const alreadyHasPending = this.pendingLevelDrags.get(label)?.some((c) => c.field === dragField && !c.isRemoval) ?? false;
16491
+ if (alreadyHasInLevel || alreadyHasPending) return this;
16380
16492
  const { priceH } = this.getChartLayout();
16381
16493
  const priceRange = this._displayedPriceRange ?? this.getScaledPriceRange(this.viewport);
16382
16494
  const entryY = this.scaleManager.yToPixel(level.price, priceRange, priceH);
@@ -16385,6 +16497,10 @@ var _ChartEngine = class _ChartEngine {
16385
16497
  const bracketY = entryY + (isBelowEntry ? 30 : -30);
16386
16498
  const defaultPrice = this.scaleManager.pixelToPrice(bracketY, priceRange, priceH);
16387
16499
  this.updateLevelBracket(label, type, defaultPrice);
16500
+ const existingDrags = this.pendingLevelDrags.get(label) ?? [];
16501
+ const filteredDrags = existingDrags.filter((c) => c.field !== dragField);
16502
+ filteredDrags.push({ field: dragField, newPrice: defaultPrice, oldPrice: defaultPrice, isNew: true });
16503
+ this.pendingLevelDrags.set(label, filteredDrags);
16388
16504
  this.emitter.emit("tradeLevelBracketActivated", {
16389
16505
  label,
16390
16506
  bracketType: type,
@@ -16447,7 +16563,20 @@ var _ChartEngine = class _ChartEngine {
16447
16563
  * No-op if the target doesn't exist or doesn't have the bracket type.
16448
16564
  */
16449
16565
  removeBracket(type, label) {
16450
- if (label) return this.updateLevelBracket(label, type, null);
16566
+ if (label) {
16567
+ const field = type === "sl" ? "stopLoss" : "takeProfit";
16568
+ const level = this.levels.find((l) => l.label === label);
16569
+ if (!level) return this;
16570
+ const existingChange = this.pendingLevelDrags.get(label)?.find((c) => c.field === field);
16571
+ const effectivePrice = existingChange && !existingChange.isRemoval ? existingChange.newPrice : type === "sl" ? level.stopLossPrice : level.takeProfitPrice;
16572
+ if (effectivePrice === void 0) return this;
16573
+ const existingDrags = this.pendingLevelDrags.get(label) ?? [];
16574
+ const filteredDrags = existingDrags.filter((c) => c.field !== field);
16575
+ filteredDrags.push({ field, newPrice: effectivePrice, oldPrice: effectivePrice, isRemoval: true });
16576
+ this.pendingLevelDrags.set(label, filteredDrags);
16577
+ this.renderTradeLayer();
16578
+ return this;
16579
+ }
16451
16580
  if (type === "sl") {
16452
16581
  this.draftBracketPnl = { ...this.draftBracketPnl, sl: void 0 };
16453
16582
  } else {
@@ -16469,12 +16598,13 @@ var _ChartEngine = class _ChartEngine {
16469
16598
  return this;
16470
16599
  }
16471
16600
  /**
16472
- * Set or clear the estimated PNL text shown on a draft order's SL or TP bracket line.
16473
- * Pass `null` to clear the text. No-op if no draft order is active.
16601
+ * Set or clear the estimated PNL text shown on the SL or TP bracket line.
16602
+ * Applies to the currently active bracket host — a draft order while drafting,
16603
+ * or the selected/hovered level while editing an existing pending order or position.
16604
+ * Pass `null` to clear the text.
16474
16605
  * Use this to display the consumer-calculated estimated profit/loss next to the bracket.
16475
16606
  */
16476
16607
  setDraftBracketPnl(type, pnlText) {
16477
- if (!this.draftOrderLabel) return this;
16478
16608
  if (type === "sl") {
16479
16609
  this.draftBracketPnl = { ...this.draftBracketPnl, sl: pnlText ?? void 0 };
16480
16610
  } else {
@@ -16552,6 +16682,7 @@ var _ChartEngine = class _ChartEngine {
16552
16682
  */
16553
16683
  selectLevel(label) {
16554
16684
  this.selectedTradeLabel = label;
16685
+ if (label !== null) this.crosshair = null;
16555
16686
  this.renderTradeLayer();
16556
16687
  return this;
16557
16688
  }
@@ -16859,25 +16990,31 @@ var _ChartEngine = class _ChartEngine {
16859
16990
  );
16860
16991
  const processedLevels = this.levels.filter((l) => !(l.type === "pending" && l.ToClose != null)).map((l) => {
16861
16992
  const draftChanges = this.pendingLevelDrags.get(l.label) ?? [];
16862
- const slDraft = draftChanges.find((c) => c.field === "stopLoss")?.newPrice;
16863
- const tpDraft = draftChanges.find((c) => c.field === "takeProfit")?.newPrice;
16993
+ const slChange = draftChanges.find((c) => c.field === "stopLoss");
16994
+ const tpChange = draftChanges.find((c) => c.field === "takeProfit");
16995
+ const slDraft = slChange && !slChange.isRemoval ? slChange.newPrice : void 0;
16996
+ const tpDraft = tpChange && !tpChange.isRemoval ? tpChange.newPrice : void 0;
16997
+ const slIsRemoval = slChange?.isRemoval ?? false;
16998
+ const tpIsRemoval = tpChange?.isRemoval ?? false;
16864
16999
  const mainDraft = draftChanges.find((c) => c.field === "main")?.newPrice;
16865
17000
  const linked = bracketOrders.filter((b) => b.ToClose === l.label);
16866
- if (linked.length === 0 && slDraft === void 0 && tpDraft === void 0 && mainDraft === void 0)
17001
+ if (linked.length === 0 && slDraft === void 0 && tpDraft === void 0 && mainDraft === void 0 && !slIsRemoval && !tpIsRemoval)
16867
17002
  return l;
16868
17003
  const clone = { ...l };
16869
17004
  if (mainDraft !== void 0) clone.price = mainDraft;
16870
17005
  if (slDraft !== void 0) clone.stopLossPrice = slDraft;
17006
+ else if (slIsRemoval) clone.stopLossPrice = void 0;
16871
17007
  if (tpDraft !== void 0) clone.takeProfitPrice = tpDraft;
17008
+ else if (tpIsRemoval) clone.takeProfitPrice = void 0;
16872
17009
  if (linked.length > 0) {
16873
17010
  const parentSide = l.side ?? "buy";
16874
17011
  for (const b of linked) {
16875
17012
  const isSL = parentSide === "buy" ? b.price < l.price : b.price > l.price;
16876
17013
  if (isSL) {
16877
- clone.stopLossPrice = slDraft ?? clone.stopLossPrice ?? b.price;
17014
+ clone.stopLossPrice = slIsRemoval ? void 0 : slDraft ?? clone.stopLossPrice ?? b.price;
16878
17015
  clone._slOrderLabel = b.label;
16879
17016
  } else {
16880
- clone.takeProfitPrice = tpDraft ?? clone.takeProfitPrice ?? b.price;
17017
+ clone.takeProfitPrice = tpIsRemoval ? void 0 : tpDraft ?? clone.takeProfitPrice ?? b.price;
16881
17018
  clone._tpOrderLabel = b.label;
16882
17019
  }
16883
17020
  }
@@ -16939,8 +17076,9 @@ var _ChartEngine = class _ChartEngine {
16939
17076
  const parentPrice = this._effectiveEntryPrice(result.label, level?.price ?? oldPrice);
16940
17077
  const isEntryOrder = level?.entryPriceEditable === true;
16941
17078
  const isDraft = level?.data?._isDraft === true;
17079
+ const isMobilePendingOrder = this.hideLevelConfirmCancel && result.type === "pending" && !isDraft;
16942
17080
  const all = this.dataStore.all;
16943
- const marketPrice = isEntryOrder || isDraft ? 0 : all[all.length - 1]?.close ?? 0;
17081
+ const marketPrice = isEntryOrder || isDraft || isMobilePendingOrder ? 0 : all[all.length - 1]?.close ?? 0;
16944
17082
  if (!TradeDragHandler.isBracketPriceValid(
16945
17083
  result.newPrice,
16946
17084
  result.bracketType,
@@ -17070,16 +17208,14 @@ var _ChartEngine = class _ChartEngine {
17070
17208
  if (!level) return;
17071
17209
  if (label === this.draftOrderLabel) {
17072
17210
  const mainEntry = changes.find((c) => c.field === "main");
17073
- const slEntry = changes.find((c) => c.field === "stopLoss" && c.isNew);
17074
- const tpEntry = changes.find((c) => c.field === "takeProfit" && c.isNew);
17075
17211
  const draft = level;
17076
17212
  this._onOrderSubmit?.({
17077
17213
  price: mainEntry?.newPrice ?? draft.price,
17078
17214
  lots: this._minLots,
17079
17215
  side: draft.side,
17080
17216
  orderType: draft.orderType,
17081
- ...slEntry ? { stopLoss: slEntry.newPrice } : {},
17082
- ...tpEntry ? { takeProfit: tpEntry.newPrice } : {}
17217
+ ...draft.stopLossPrice !== void 0 ? { stopLoss: draft.stopLossPrice } : {},
17218
+ ...draft.takeProfitPrice !== void 0 ? { takeProfit: draft.takeProfitPrice } : {}
17083
17219
  });
17084
17220
  this.emitter.emit("tradeLevelConfirmed", {
17085
17221
  label,
@@ -17649,6 +17785,7 @@ var _ChartEngine = class _ChartEngine {
17649
17785
  this._mobileLayout = isMobile;
17650
17786
  this.leftBar?.setMobileMode(isMobile);
17651
17787
  this.topBar?.setMobileLayout(isMobile);
17788
+ this.tradeButton?.setMobileMode(isMobile);
17652
17789
  if (this.siEl) {
17653
17790
  this.siEl.style.flexDirection = isMobile ? "column" : "row";
17654
17791
  this.siEl.style.alignItems = isMobile ? "flex-start" : "center";
@@ -17751,24 +17888,20 @@ var _ChartEngine = class _ChartEngine {
17751
17888
  const isDraftBracket = parentLevel?.data?._isDraft === true;
17752
17889
  if (isDraftBracket && parentLevel) {
17753
17890
  const bracketKey = closedLevel.bracketType === "stopLoss" ? "sl" : "tp";
17754
- const { priceH } = this.getChartLayout();
17755
- const priceRange = this._displayedPriceRange ?? this.getScaledPriceRange(this.viewport);
17756
- const entryY = this.scaleManager.yToPixel(
17757
- parentLevel.price,
17758
- priceRange,
17759
- priceH
17760
- );
17761
- const side = parentLevel.side ?? "buy";
17762
- const isBelowEntry = side === "buy" && bracketKey === "sl" || side === "sell" && bracketKey === "tp";
17763
- const bracketY = entryY + (isBelowEntry ? 30 : -30);
17764
- const defaultPrice = this.scaleManager.pixelToPrice(bracketY, priceRange, priceH);
17765
- this.updateDraftOrderBracket(bracketKey, defaultPrice);
17766
- this.emitter.emit("tradeLevelDrag", {
17891
+ this.updateDraftOrderBracket(bracketKey, null);
17892
+ this.emitter.emit("tradeLevelEdit", {
17767
17893
  label: closedLevel.label,
17768
- newPrice: defaultPrice,
17769
- data: parentLevel?.data,
17770
- bracketType: closedLevel.bracketType,
17771
- isFullscreen: this.isFullscreen
17894
+ type: "pending",
17895
+ data: parentLevel.data,
17896
+ isFullscreen: this.isFullscreen,
17897
+ changes: [
17898
+ {
17899
+ field: closedLevel.bracketType === "stopLoss" ? "REMOVE_SL" : "REMOVE_TP",
17900
+ newPrice: 0,
17901
+ data: parentLevel.data,
17902
+ bracketOrderLabel: void 0
17903
+ }
17904
+ ]
17772
17905
  });
17773
17906
  return;
17774
17907
  }
@@ -17817,7 +17950,7 @@ var _ChartEngine = class _ChartEngine {
17817
17950
  Math.min(Math.ceil(this.viewport.endIndex), Math.round(rawBarIndex))
17818
17951
  );
17819
17952
  const bar = this.dataStore.all[clamped] ?? null;
17820
- this.crosshair = { x, y, barIndex: clamped, price, bar };
17953
+ this.crosshair = this.selectedTradeLabel === null ? { x, y, barIndex: clamped, price, bar } : null;
17821
17954
  if (this.tradeButton) {
17822
17955
  this.tradeButton.setY(y);
17823
17956
  if (this._isTradingActive) {
@@ -17841,8 +17974,9 @@ var _ChartEngine = class _ChartEngine {
17841
17974
  this._isBracketNew = false;
17842
17975
  const isEntryOrder = level.entryPriceEditable === true;
17843
17976
  const isDraft = level.data?._isDraft === true;
17977
+ const isMobilePendingOrder = this.hideLevelConfirmCancel && level.type === "pending" && !isDraft;
17844
17978
  const all = this.dataStore.all;
17845
- const marketPrice = isEntryOrder || isDraft ? 0 : all[all.length - 1]?.close ?? 0;
17979
+ const marketPrice = isEntryOrder || isDraft || isMobilePendingOrder ? 0 : all[all.length - 1]?.close ?? 0;
17846
17980
  this.tradeDragHandler.startBracketDrag(
17847
17981
  level,
17848
17982
  dragHit.bracketType,
@@ -17900,20 +18034,9 @@ var _ChartEngine = class _ChartEngine {
17900
18034
  const initialPrice = this.scaleManager.pixelToPrice(btnCenterY, priceRange, priceH);
17901
18035
  const isEntryOrder = level.entryPriceEditable === true;
17902
18036
  const isDraft = level.data?._isDraft === true;
18037
+ const isMobilePendingOrder = this.hideLevelConfirmCancel && level.type === "pending" && !isDraft;
17903
18038
  const all = this.dataStore.all;
17904
- const marketPrice = isEntryOrder || isDraft ? 0 : all[all.length - 1]?.close ?? 0;
17905
- if (!isDraft) {
17906
- this.emitter.emit("tradeLevelEditOpen", {
17907
- label: level.label,
17908
- type: level.type,
17909
- data: level.data,
17910
- price: level.price,
17911
- side: level.side,
17912
- stopLossPrice: level.stopLossPrice,
17913
- takeProfitPrice: level.takeProfitPrice,
17914
- isFullscreen: this.isFullscreen
17915
- });
17916
- }
18039
+ const marketPrice = isEntryOrder || isDraft || isMobilePendingOrder ? 0 : all[all.length - 1]?.close ?? 0;
17917
18040
  this._pendingBracketOrderLabel = null;
17918
18041
  this._isBracketNew = true;
17919
18042
  this.tradeDragHandler.startBracketDrag(
@@ -18276,6 +18399,6 @@ function defaultTransform(msg) {
18276
18399
  };
18277
18400
  }
18278
18401
 
18279
- export { AbcdPattern, AnchoredNote, AnchoredVP, Arc, ArrowDown, ArrowMarker, ArrowUp, BatPattern, Brush, ButterflyPattern, Callout, ChartEngine, Circle, CrabPattern, CrossLine, CyclicLines, CypherPattern, DARK_THEME, DEFAULT_BOTTOM_BAR_CONFIG, DEFAULT_CROSSHAIR_CONFIG, DEFAULT_DRAWING_TOOLBAR_CONFIG, DEFAULT_INDICATOR_OVERLAY_CONFIG, DEFAULT_LABELS, DEFAULT_PRICE_AXIS_CONFIG, DEFAULT_TIME_AXIS_CONFIG, DEFAULT_TOP_BAR_CONFIG, DEFAULT_UI_CONFIG, DatePriceRange, DateRange, DisjointChannel, DrawingManager, ElliottCombination, ElliottCorrective, ElliottImpulse, ElliottTriangle, ElliottWxy, Ellipse, FibChannel, FibCircles, FibExtension, FibFan, FibProjection, FibRetracement, FibSpiral, FibTimezone, FixedRangeVP, Flag, FlatChannel, GannBox, GannFan, GannSquare, GartleyPattern, GhostFeed, HeadShoulders, Highlighter, HorizontalLine, InsidePitchfork, LIGHT_THEME, ModifiedSchiff, ParallelChannel, Path, Pitchfork, Polyline, PriceLabel, PriceNote, PriceProjection, PriceRange, Projection, Rectangle, RegressionTrend, RotatedRectangle, Ruler, SchiffPitchfork, SharkPattern, SineLine, Text, ThreeDrives, TimeCycles, TrendAngle, TrendLine, Triangle, TrianglePattern, VerticalLine, VolumeProfile, WebSocketAdapter, aggregateCandles, deepMergeTheme, resolveCssVarsInTheme, resolveLabels, resolveUiConfig };
18402
+ export { AbcdPattern, AnchoredNote, AnchoredVP, Arc, ArrowDown, ArrowMarker, ArrowUp, BatPattern, Brush, ButterflyPattern, Callout, ChartEngine, Circle, CrabPattern, CrossLine, CyclicLines, CypherPattern, DARK_THEME, DEFAULT_BOTTOM_BAR_CONFIG, DEFAULT_CROSSHAIR_CONFIG, DEFAULT_DRAWING_TOOLBAR_CONFIG, DEFAULT_INDICATOR_OVERLAY_CONFIG, DEFAULT_LABELS, DEFAULT_PRICE_AXIS_CONFIG, DEFAULT_TIME_AXIS_CONFIG, DEFAULT_TOP_BAR_CONFIG, DEFAULT_TRADE_BUTTON_CONFIG, DEFAULT_UI_CONFIG, DatePriceRange, DateRange, DisjointChannel, DrawingManager, ElliottCombination, ElliottCorrective, ElliottImpulse, ElliottTriangle, ElliottWxy, Ellipse, FibChannel, FibCircles, FibExtension, FibFan, FibProjection, FibRetracement, FibSpiral, FibTimezone, FixedRangeVP, Flag, FlatChannel, GannBox, GannFan, GannSquare, GartleyPattern, GhostFeed, HeadShoulders, Highlighter, HorizontalLine, InsidePitchfork, LIGHT_THEME, ModifiedSchiff, ParallelChannel, Path, Pitchfork, Polyline, PriceLabel, PriceNote, PriceProjection, PriceRange, Projection, Rectangle, RegressionTrend, RotatedRectangle, Ruler, SchiffPitchfork, SharkPattern, SineLine, Text, ThreeDrives, TimeCycles, TrendAngle, TrendLine, Triangle, TrianglePattern, VerticalLine, VolumeProfile, WebSocketAdapter, aggregateCandles, deepMergeTheme, resolveCssVarsInTheme, resolveLabels, resolveUiConfig };
18280
18403
  //# sourceMappingURL=index.js.map
18281
18404
  //# sourceMappingURL=index.js.map