acttrader-charts 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -232,6 +232,8 @@ chart.on('tradeLevelDrag', ({ label, newPrice, bracketType, isFullscreen }) => {
232
232
  | `maxSubPanes` | | `3` | Max simultaneous oscillator sub-panes |
233
233
  | `tradeDisplayFilter` | | `"all"` | Which TFC levels are visible: `"all"` · `"positions"` · `"orders"` · `"none"` |
234
234
  | `positionRenderStyle` | | auto | Force position render style: `"line"` or `"dot"` |
235
+ | `hideLevelConfirmCancel` | | `false` | Hide on-canvas ✓/✗ confirm-cancel buttons for TFC level edits |
236
+ | `hideQtyButton` | | `false` | Hide the floating Qty input overlay on draft orders |
235
237
  | `tradesThresholdForHorizontalLine` | | `2` | Level count above which render auto-switches to `"dot"` mode |
236
238
  | `canvasColors` | | — | Per-theme canvas background color overrides (persisted from Settings dialog) |
237
239
  | `aggregateFrom` | | — | Fetch finer-grained data and aggregate client-side per timeframe |
@@ -655,6 +657,7 @@ chart.on('tradeLevelClose', ({ label, type, action, data, isFullscreen }) =>
655
657
  chart.on('tradeLevelDrag', ({ label, newPrice, data, bracketType, isFullscreen }) => {}); // fires on every mouse-move during drag
656
658
  chart.on('tradeLevelEditOpen', ({ label, type, price, side, stopLossPrice, takeProfitPrice, data, isFullscreen }) => {});
657
659
  chart.on('tradeLevelConfirmed',({ label, type, isFullscreen }) => {});
660
+ chart.on('draftCancelled', ({ label, isFullscreen }) => {}); // draft order dismissed without confirming
658
661
  chart.on('tradeLevelDragEnd', ({ label, type, newPrice, data }) => {}); // deprecated — use tradeLevelEdit
659
662
  chart.on('tradeLevelBracketDrag', ({ label, bracketType, newPrice, data }) => {}); // deprecated
660
663
  ```
@@ -525,6 +525,12 @@ interface ChartConfig {
525
525
  isins?: string[];
526
526
  /** Called when the user picks a symbol from the picker modal. Parent should call setSymbol() + setData(). */
527
527
  onIsinSelect?: (isin: string) => void;
528
+ /**
529
+ * Called when the user clicks the symbol name in the top-left strip.
530
+ * When set, suppresses the built-in ISIN picker modal and fires this callback instead.
531
+ * Intended for native WebView hosts that handle symbol navigation natively.
532
+ */
533
+ onSymbolClick?: (symbol: string) => void;
528
534
  padding?: Partial<Padding>;
529
535
  /** Minimum (and default) lot size shown in the trade popover and pre-filled in the draft order qty input (default: 1) */
530
536
  minLots?: number;
@@ -727,6 +733,18 @@ interface ChartConfig {
727
733
  * }
728
734
  */
729
735
  aggregateFrom?: Partial<Record<Timeframe, Timeframe>>;
736
+ /**
737
+ * Hide the ✓ / ✗ confirm-cancel buttons on trade levels that have pending changes.
738
+ * Use when the host app provides its own native confirm/cancel controls.
739
+ * Default: `false`.
740
+ */
741
+ hideLevelConfirmCancel?: boolean;
742
+ /**
743
+ * Hide the floating Qty input overlay shown on draft orders.
744
+ * Use when the host app manages lot-size entry natively.
745
+ * Default: `false`.
746
+ */
747
+ hideQtyButton?: boolean;
730
748
  }
731
749
  interface IndicatorResult {
732
750
  index: number;
@@ -938,6 +956,19 @@ type ChartEventMap = {
938
956
  type: TradeLevelType | 'draft';
939
957
  isFullscreen: boolean;
940
958
  };
959
+ /** Emitted when a draft order is cancelled (Escape, ✕ button, or external revert). */
960
+ draftCancelled: {
961
+ label: string;
962
+ isFullscreen: boolean;
963
+ };
964
+ /** Emitted when a new draft order is shown on the chart (market or limit/stop).
965
+ * Native layer listens to open the buy/sell form. */
966
+ draftInitiated: {
967
+ side: 'buy' | 'sell';
968
+ price: number;
969
+ orderType: 'limit' | 'stop' | 'market';
970
+ isFullscreen: boolean;
971
+ };
941
972
  /** Emitted after any user-driven change to chart configuration (timeframe, series, indicators, drawings, etc.).
942
973
  * The payload is a full serializable snapshot — consumers can persist it keyed by symbol. */
943
974
  stateChange: {
@@ -525,6 +525,12 @@ interface ChartConfig {
525
525
  isins?: string[];
526
526
  /** Called when the user picks a symbol from the picker modal. Parent should call setSymbol() + setData(). */
527
527
  onIsinSelect?: (isin: string) => void;
528
+ /**
529
+ * Called when the user clicks the symbol name in the top-left strip.
530
+ * When set, suppresses the built-in ISIN picker modal and fires this callback instead.
531
+ * Intended for native WebView hosts that handle symbol navigation natively.
532
+ */
533
+ onSymbolClick?: (symbol: string) => void;
528
534
  padding?: Partial<Padding>;
529
535
  /** Minimum (and default) lot size shown in the trade popover and pre-filled in the draft order qty input (default: 1) */
530
536
  minLots?: number;
@@ -727,6 +733,18 @@ interface ChartConfig {
727
733
  * }
728
734
  */
729
735
  aggregateFrom?: Partial<Record<Timeframe, Timeframe>>;
736
+ /**
737
+ * Hide the ✓ / ✗ confirm-cancel buttons on trade levels that have pending changes.
738
+ * Use when the host app provides its own native confirm/cancel controls.
739
+ * Default: `false`.
740
+ */
741
+ hideLevelConfirmCancel?: boolean;
742
+ /**
743
+ * Hide the floating Qty input overlay shown on draft orders.
744
+ * Use when the host app manages lot-size entry natively.
745
+ * Default: `false`.
746
+ */
747
+ hideQtyButton?: boolean;
730
748
  }
731
749
  interface IndicatorResult {
732
750
  index: number;
@@ -938,6 +956,19 @@ type ChartEventMap = {
938
956
  type: TradeLevelType | 'draft';
939
957
  isFullscreen: boolean;
940
958
  };
959
+ /** Emitted when a draft order is cancelled (Escape, ✕ button, or external revert). */
960
+ draftCancelled: {
961
+ label: string;
962
+ isFullscreen: boolean;
963
+ };
964
+ /** Emitted when a new draft order is shown on the chart (market or limit/stop).
965
+ * Native layer listens to open the buy/sell form. */
966
+ draftInitiated: {
967
+ side: 'buy' | 'sell';
968
+ price: number;
969
+ orderType: 'limit' | 'stop' | 'market';
970
+ isFullscreen: boolean;
971
+ };
941
972
  /** Emitted after any user-driven change to chart configuration (timeframe, series, indicators, drawings, etc.).
942
973
  * The payload is a full serializable snapshot — consumers can persist it keyed by symbol. */
943
974
  stateChange: {
package/dist/index.cjs CHANGED
@@ -1607,7 +1607,7 @@ function isDraggable(level) {
1607
1607
  return !!level.entryPriceEditable;
1608
1608
  return false;
1609
1609
  }
1610
- function renderTradeLevels(ctx, levels, scale, priceRange, theme, chartW, priceH, precision, hoveredLabel = null, draggingLabel = null, dragNewPrice = null, selectedLabel = null, pendingLabels = /* @__PURE__ */ new Set(), positionStyle = "line") {
1610
+ function renderTradeLevels(ctx, levels, scale, priceRange, theme, chartW, priceH, precision, hoveredLabel = null, draggingLabel = null, dragNewPrice = null, selectedLabel = null, pendingLabels = /* @__PURE__ */ new Set(), positionStyle = "line", hideConfirmCancel = false) {
1611
1611
  if (levels.length === 0)
1612
1612
  return {
1613
1613
  hitAreas: [],
@@ -1703,7 +1703,8 @@ function renderTradeLevels(ctx, levels, scale, priceRange, theme, chartW, priceH
1703
1703
  hoverAreas,
1704
1704
  dragAreas,
1705
1705
  confirmAreas,
1706
- addBracketAreas
1706
+ addBracketAreas,
1707
+ hideConfirmCancel
1707
1708
  );
1708
1709
  }
1709
1710
  ctx.restore();
@@ -1767,7 +1768,7 @@ function drawDotHoverBox(ctx, level, y, dotX, dotR, theme, precision) {
1767
1768
  });
1768
1769
  ctx.restore();
1769
1770
  }
1770
- function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered, selected, scale, priceRange, priceH, draggingLabel, dragNewPrice, bracketLineXMap, hasPendingChanges, positionStyle, hitAreas, editAreas, hoverAreas, dragAreas, confirmAreas, addBracketAreas) {
1771
+ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered, selected, scale, priceRange, priceH, draggingLabel, dragNewPrice, bracketLineXMap, hasPendingChanges, positionStyle, hitAreas, editAreas, hoverAreas, dragAreas, confirmAreas, addBracketAreas, hideConfirmCancel = false) {
1771
1772
  const { y, boxY, boxW, boxH } = layout;
1772
1773
  const color = levelColor(level, colors, theme);
1773
1774
  const active = hovered || selected;
@@ -1964,7 +1965,7 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
1964
1965
  ctx.fillText(displayText, textX, midY);
1965
1966
  const btnY = midY;
1966
1967
  const d = 3.5;
1967
- if (hasPendingChanges) {
1968
+ if (!hideConfirmCancel && hasPendingChanges) {
1968
1969
  const cancelX = boxX + boxW - BOX_PAD_X / 2 - CONFIRM_R;
1969
1970
  const confirmX = cancelX - CONFIRM_R - CONFIRM_GAP - CONFIRM_R;
1970
1971
  ctx.fillStyle = theme.candle.up;
@@ -2014,7 +2015,7 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
2014
2015
  w: CONFIRM_R * 2,
2015
2016
  h: CONFIRM_R * 2
2016
2017
  });
2017
- } else {
2018
+ } else if (!hideConfirmCancel) {
2018
2019
  const closeX = boxX + boxW - BOX_PAD_X / 2 - CLOSE_R;
2019
2020
  const editX = closeX - CLOSE_R - EDIT_GAP - EDIT_R;
2020
2021
  ctx.fillStyle = monoColor(theme);
@@ -16414,6 +16415,8 @@ var _ChartEngine = class _ChartEngine {
16414
16415
  this.symbol = "";
16415
16416
  this.showBidAskLines = false;
16416
16417
  this.showActLogo = false;
16418
+ this.hideLevelConfirmCancel = false;
16419
+ this.hideQtyButton = false;
16417
16420
  this.activeIndicators = [];
16418
16421
  this.indicatorResults = /* @__PURE__ */ new Map();
16419
16422
  this.viewport = {
@@ -17371,6 +17374,7 @@ var _ChartEngine = class _ChartEngine {
17371
17374
  symbol = "",
17372
17375
  isins,
17373
17376
  onIsinSelect,
17377
+ onSymbolClick,
17374
17378
  onOrderSubmit,
17375
17379
  dataLoader,
17376
17380
  durationTimeframeMap,
@@ -17417,6 +17421,8 @@ var _ChartEngine = class _ChartEngine {
17417
17421
  this.recomputeRenderStyle();
17418
17422
  this.showBidAskLines = config.showBidAskLines ?? false;
17419
17423
  this.showActLogo = config.showActLogo ?? false;
17424
+ this.hideLevelConfirmCancel = config.hideLevelConfirmCancel ?? false;
17425
+ this.hideQtyButton = config.hideQtyButton ?? false;
17420
17426
  this.showCandleCountdown = config.showCandleCountdown ?? true;
17421
17427
  this.candleCountdownTimeframes = config.candleCountdownTimeframes;
17422
17428
  this._onOrderSubmit = onOrderSubmit;
@@ -17486,6 +17492,7 @@ var _ChartEngine = class _ChartEngine {
17486
17492
  }))
17487
17493
  );
17488
17494
  this.wrapper.appendChild(this.topBar.el);
17495
+ this.topBar.setFullscreen(this.isFullscreen);
17489
17496
  }
17490
17497
  const middleRow = document.createElement("div");
17491
17498
  Object.assign(middleRow.style, {
@@ -17639,7 +17646,16 @@ var _ChartEngine = class _ChartEngine {
17639
17646
  display: symbol ? "inline" : "none"
17640
17647
  });
17641
17648
  this.siSymbolSpan.textContent = symbol ?? "";
17642
- if (onIsinSelect) {
17649
+ if (onSymbolClick) {
17650
+ Object.assign(this.siSymbolSpan.style, {
17651
+ cursor: "pointer",
17652
+ textDecoration: "underline",
17653
+ pointerEvents: "auto"
17654
+ });
17655
+ this.siSymbolSpan.addEventListener("click", () => {
17656
+ onSymbolClick(this.siSymbolSpan?.textContent ?? "");
17657
+ });
17658
+ } else if (onIsinSelect) {
17643
17659
  if (isins) this.isins = isins;
17644
17660
  this.isinPickerModal = new IsinPickerModal(this.theme, onIsinSelect);
17645
17661
  this.getFloatingRoot().appendChild(this.isinPickerModal.el);
@@ -18756,6 +18772,7 @@ var _ChartEngine = class _ChartEngine {
18756
18772
  this.levels = [...this.levels, draftLevel];
18757
18773
  this.draftOrderLabel = label;
18758
18774
  this.renderTradeLayer();
18775
+ this.emitter.emit("draftInitiated", { side, price, orderType: "market", isFullscreen: this.isFullscreen });
18759
18776
  return this;
18760
18777
  }
18761
18778
  /**
@@ -19125,7 +19142,9 @@ var _ChartEngine = class _ChartEngine {
19125
19142
  const isNativeFs = !!document.fullscreenElement;
19126
19143
  if (!isNativeFs && !this._isCssFullscreen) {
19127
19144
  if (this.wrapper.requestFullscreen) {
19128
- this.wrapper.requestFullscreen().catch(() => {
19145
+ this.wrapper.requestFullscreen().then(() => {
19146
+ this.topBar?.setFullscreen(true);
19147
+ }).catch(() => {
19129
19148
  this._applyCssFullscreen(true);
19130
19149
  });
19131
19150
  } else {
@@ -19231,7 +19250,8 @@ var _ChartEngine = class _ChartEngine {
19231
19250
  this.tradeDragNewPrice,
19232
19251
  this.selectedTradeLabel,
19233
19252
  new Set(this.pendingLevelDrags.keys()),
19234
- this.positionRenderStyle
19253
+ this.positionRenderStyle,
19254
+ this.hideLevelConfirmCancel
19235
19255
  );
19236
19256
  ctx.restore();
19237
19257
  ctx.restore();
@@ -19334,17 +19354,20 @@ var _ChartEngine = class _ChartEngine {
19334
19354
  priceH
19335
19355
  );
19336
19356
  this.crosshair = null;
19337
- this.draftOrderQtyInput?.show(yPx, this._minLots, this.theme, priceH);
19357
+ if (!this.hideQtyButton) this.draftOrderQtyInput?.show(yPx, this._minLots, this.theme, priceH);
19338
19358
  this.renderTradeLayer();
19359
+ this.emitter.emit("draftInitiated", { side, price, orderType, isFullscreen: this.isFullscreen });
19339
19360
  }
19340
19361
  removeDraftOrder() {
19341
19362
  if (!this.draftOrderLabel) return;
19342
- this.levels = this.levels.filter((l) => l.label !== this.draftOrderLabel);
19343
- this.pendingLevelDrags.delete(this.draftOrderLabel);
19363
+ const label = this.draftOrderLabel;
19364
+ this.levels = this.levels.filter((l) => l.label !== label);
19365
+ this.pendingLevelDrags.delete(label);
19344
19366
  this.selectedTradeLabel = null;
19345
19367
  this.draftOrderLabel = null;
19346
19368
  this.draftOrderQtyInput?.hide();
19347
19369
  this.renderTradeLayer();
19370
+ this.emitter.emit("draftCancelled", { label, isFullscreen: this.isFullscreen });
19348
19371
  }
19349
19372
  applyPendingChanges(label) {
19350
19373
  const changes = this.pendingLevelDrags.get(label);