@luxalgo/vela 0.8.2 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/{DataProvider-DpOWZD8F.d.ts → DataProvider-oH78tYXL.d.ts} +1 -1
  2. package/dist/{DataProvider-COGDs9Xg.d.cts → DataProvider-wbtJ3-Sa.d.cts} +1 -1
  3. package/dist/{chunk-R2JMNIHY.js → chunk-2IPXYM4B.js} +258 -169
  4. package/dist/{chunk-NLDTVFOI.js → chunk-G7B7ZCBF.js} +129 -10
  5. package/dist/{chunk-T3DZIR5Y.js → chunk-HMHA733L.js} +306 -168
  6. package/dist/{chunk-DPAA3SRT.js → chunk-KWI3YDBW.js} +254 -9
  7. package/dist/{chunk-27UTYE7T.js → chunk-TO3GIK7Z.js} +49 -7
  8. package/dist/{chunk-HKNO24GD.js → chunk-VHGACEHO.js} +50 -1
  9. package/dist/{contributions-Cgm9RJYP.d.cts → contributions-BhOBRenr.d.cts} +44 -4
  10. package/dist/{contributions-bWgwyiVi.d.ts → contributions-HGqnNb_P.d.ts} +44 -4
  11. package/dist/index.cjs +497 -79
  12. package/dist/index.d.cts +34 -14
  13. package/dist/index.d.ts +34 -14
  14. package/dist/index.js +5 -5
  15. package/dist/{options-NAUHiQEC.d.ts → options-lMUwmRwh.d.cts} +66 -1
  16. package/dist/{options-NAUHiQEC.d.cts → options-lMUwmRwh.d.ts} +66 -1
  17. package/dist/{plugin-CqxWoDKS.d.ts → plugin-Cr2Pj8q8.d.ts} +4 -4
  18. package/dist/{plugin-CjjzZX2F.d.cts → plugin-Do5J5xuF.d.cts} +4 -4
  19. package/dist/plugin.cjs +18 -0
  20. package/dist/plugin.d.cts +5 -5
  21. package/dist/plugin.d.ts +5 -5
  22. package/dist/plugin.js +3 -3
  23. package/dist/providers/binance.d.cts +2 -2
  24. package/dist/providers/binance.d.ts +2 -2
  25. package/dist/providers/coinbase.d.cts +2 -2
  26. package/dist/providers/coinbase.d.ts +2 -2
  27. package/dist/providers/hyperliquid.d.cts +2 -2
  28. package/dist/providers/hyperliquid.d.ts +2 -2
  29. package/dist/{side-panel-wMNfgyZb.d.cts → side-panel-_2UK1gSm.d.cts} +45 -3
  30. package/dist/{side-panel-wMNfgyZb.d.ts → side-panel-_2UK1gSm.d.ts} +45 -3
  31. package/dist/{statusline-model-Dpfpq54A.d.cts → statusline-model-B-2xGlB_.d.cts} +3 -3
  32. package/dist/{statusline-model-Dih6FGWP.d.ts → statusline-model-CY1wzxHg.d.ts} +3 -3
  33. package/dist/ui.cjs +224 -14
  34. package/dist/ui.d.cts +119 -87
  35. package/dist/ui.d.ts +119 -87
  36. package/dist/ui.js +3 -3
  37. package/dist/vela.global.js +497 -79
  38. package/dist/vela.global.min.js +86 -52
  39. package/dist/widget.cjs +850 -167
  40. package/dist/widget.d.cts +24 -10
  41. package/dist/widget.d.ts +24 -10
  42. package/dist/widget.js +7 -7
  43. package/dist/workspace.cjs +849 -167
  44. package/dist/workspace.d.cts +47 -20
  45. package/dist/workspace.d.ts +47 -20
  46. package/dist/workspace.js +6 -6
  47. package/package.json +1 -1
  48. /package/dist/{chunk-JU4CWEBF.js → chunk-W5YPYZ2P.js} +0 -0
@@ -1,6 +1,6 @@
1
- import { deserializeDrawing, chartTypes, rendererLayers, isLineLikeSeries, seriesShownOn, foldBaseModulation, registerChartType, rendererDefaults, getDrawingType, settingsRowVisible, normalizeSettingsRow, Magnifier, TextLabel, Callout, resetDrawingSettings, registerNativeIndicator, chartType, getNativeIndicator, nativeIndicatorDescriptors, nativeInstanceChannel, drawingTypes, settingsRowValueKeys, formatDuration, RegressionChannel, FixedRangeVolumeProfile, DEFAULT_DRAWING_COLOR, SegmentDrawing, ArrowMark, GlyphStamp, RadialFib, FibSpiral, DedekindTessellation, MachFigure, GannSquare, FibRatios, MeasureBox, PositionTool, AnchoredVwap, PatternDrawing, Comment, PriceNote, Signpost, Note, PriceLabel, GANN_SQUARE_ARCS, magnifierTimeframeLabel, lineSegmentIntersection, MAGNIFIER_TIMEFRAME_OPTIONS, GLYPH_OPTIONS, STAMP_SIZE_OPTIONS, LINE_STYLE_OPTIONS, DEDEKIND_CURVATURE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, TEXT_SIZE_OPTIONS, createDrawing, inputVisible, seriesInScale, tickerModifierIds, CalloutBase, DIRECTION_OPTIONS, FibRetracement, stableSeriesId } from './chunk-DPAA3SRT.js';
2
- import { themeTokens, Dialog, closeOpenPopovers, closeWidthPopover, fieldSection, buildFieldControl, fieldSeparator, fieldGrid, fieldRow, CALLOUT_STYLE_ID, CALLOUT_CSS, Popover, blendOver, splitColor, CalloutBubble, Menu, TextArea, NumberInput, buildColorPicker, isPopoverOpen, DatePicker, eventDismissedPopover, toggleSelectList, normalizeDateInput, openPopoverTrigger, fieldGridColumns, FIELD_GAP_PX, STATIC_TOKENS } from './chunk-NLDTVFOI.js';
3
- import { icon, iconAt, withAlpha, WARNING, ACCENT, NEUTRAL, INFO, BULLISH, BEARISH, announceSurface, isDarkColor, injectStyles, SERIES_LINE, CHIP_PLATE, CROSSHAIR, TRADE_EXIT, TRADE_SHORT, TRADE_LONG, iconMarkup, overlayScrollbarCss, SLATE_DEEP, VALID, INVALID, SLATE, FIELD_FOCUS_CSS, FIELD_FOCUS_RING, svg24, svg24Solid } from './chunk-HKNO24GD.js';
1
+ import { deserializeDrawing, chartTypes, rendererLayers, isLineLikeSeries, seriesShownOn, foldBaseModulation, registerChartType, rendererDefaults, getDrawingType, normalizeTimezone, settingsRowVisible, normalizeSettingsRow, Magnifier, TextLabel, Callout, resetDrawingSettings, registerNativeIndicator, chartType, getNativeIndicator, nativeIndicatorDescriptors, nativeInstanceChannel, drawingTypes, settingsRowValueKeys, TIMEZONES, tzMenuLabel, formatDuration, RegressionChannel, FixedRangeVolumeProfile, DEFAULT_DRAWING_COLOR, SegmentDrawing, ArrowMark, GlyphStamp, RadialFib, FibSpiral, DedekindTessellation, MachFigure, GannSquare, FibRatios, MeasureBox, PositionTool, AnchoredVwap, PatternDrawing, Comment, PriceNote, Signpost, Note, PriceLabel, GANN_SQUARE_ARCS, magnifierTimeframeLabel, lineSegmentIntersection, MAGNIFIER_TIMEFRAME_OPTIONS, GLYPH_OPTIONS, STAMP_SIZE_OPTIONS, LINE_STYLE_OPTIONS, DEDEKIND_CURVATURE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, TEXT_SIZE_OPTIONS, createDrawing, inputVisible, seriesInScale, tickerModifierIds, CalloutBase, DIRECTION_OPTIONS, FibRetracement, stableSeriesId } from './chunk-KWI3YDBW.js';
2
+ import { themeTokens, Dialog, closeOpenPopovers, closeWidthPopover, fieldSection, buildFieldControl, fieldSeparator, fieldGrid, fieldRow, CALLOUT_STYLE_ID, CALLOUT_CSS, Popover, blendOver, splitColor, CalloutBubble, Menu, TextArea, NumberInput, buildColorPicker, isPopoverOpen, DatePicker, eventDismissedPopover, toggleSelectList, normalizeDateInput, openPopoverTrigger, fieldGridColumns, FIELD_GAP_PX, STATIC_TOKENS } from './chunk-G7B7ZCBF.js';
3
+ import { icon, iconAt, withAlpha, WARNING, ACCENT, NEUTRAL, INFO, BULLISH, BEARISH, announceSurface, holdForExit, isDarkColor, injectStyles, SERIES_LINE, CHIP_PLATE, CROSSHAIR, TRADE_EXIT, TRADE_SHORT, TRADE_LONG, iconMarkup, overlayScrollbarCss, SLATE_DEEP, VALID, INVALID, SLATE, FIELD_FOCUS_CSS, FIELD_FOCUS_RING, svg24, svg24Solid } from './chunk-VHGACEHO.js';
4
4
 
5
5
  // src/core/events/EventBus.ts
6
6
  var TypedEventBus = class {
@@ -1885,100 +1885,6 @@ var SecondClock = class _SecondClock {
1885
1885
  }
1886
1886
  };
1887
1887
 
1888
- // src/core/timezones.ts
1889
- var TIMEZONES = [
1890
- { value: "Etc/UTC", label: "UTC" },
1891
- { value: "Etc/GMT+12", label: "International Date Line West" },
1892
- { value: "Pacific/Pago_Pago", label: "Pago Pago" },
1893
- { value: "Pacific/Honolulu", label: "Honolulu" },
1894
- { value: "Pacific/Marquesas", label: "Marquesas Islands" },
1895
- { value: "America/Anchorage", label: "Anchorage" },
1896
- { value: "America/Los_Angeles", label: "Los Angeles" },
1897
- { value: "America/Phoenix", label: "Phoenix" },
1898
- { value: "America/Denver", label: "Denver" },
1899
- { value: "America/Chicago", label: "Chicago" },
1900
- { value: "America/Mexico_City", label: "Mexico City" },
1901
- { value: "America/New_York", label: "New York" },
1902
- { value: "America/Bogota", label: "Bogot\xE1" },
1903
- { value: "America/Caracas", label: "Caracas" },
1904
- { value: "America/Santiago", label: "Santiago" },
1905
- { value: "America/St_Johns", label: "St. John's" },
1906
- { value: "America/Sao_Paulo", label: "S\xE3o Paulo" },
1907
- { value: "America/Argentina/Buenos_Aires", label: "Buenos Aires" },
1908
- { value: "America/Noronha", label: "Fernando de Noronha" },
1909
- { value: "Atlantic/Azores", label: "Azores" },
1910
- { value: "Atlantic/Reykjavik", label: "Reykjavik" },
1911
- { value: "Europe/London", label: "London" },
1912
- { value: "Europe/Paris", label: "Paris" },
1913
- { value: "Europe/Berlin", label: "Berlin" },
1914
- { value: "Europe/Athens", label: "Athens" },
1915
- { value: "Africa/Cairo", label: "Cairo" },
1916
- { value: "Africa/Johannesburg", label: "Johannesburg" },
1917
- { value: "Europe/Moscow", label: "Moscow" },
1918
- { value: "Europe/Istanbul", label: "Istanbul" },
1919
- { value: "Asia/Tehran", label: "Tehran" },
1920
- { value: "Asia/Dubai", label: "Dubai" },
1921
- { value: "Asia/Kabul", label: "Kabul" },
1922
- { value: "Asia/Karachi", label: "Karachi" },
1923
- { value: "Asia/Kolkata", label: "Mumbai" },
1924
- { value: "Asia/Kathmandu", label: "Kathmandu" },
1925
- { value: "Asia/Dhaka", label: "Dhaka" },
1926
- { value: "Asia/Yangon", label: "Yangon" },
1927
- { value: "Asia/Bangkok", label: "Bangkok" },
1928
- { value: "Asia/Shanghai", label: "Shanghai" },
1929
- { value: "Asia/Hong_Kong", label: "Hong Kong" },
1930
- { value: "Asia/Singapore", label: "Singapore" },
1931
- { value: "Australia/Eucla", label: "Eucla" },
1932
- { value: "Asia/Tokyo", label: "Tokyo" },
1933
- { value: "Asia/Seoul", label: "Seoul" },
1934
- { value: "Australia/Adelaide", label: "Adelaide" },
1935
- { value: "Australia/Sydney", label: "Sydney" },
1936
- { value: "Australia/Lord_Howe", label: "Lord Howe Island" },
1937
- { value: "Pacific/Noumea", label: "Noum\xE9a" },
1938
- { value: "Pacific/Auckland", label: "Auckland" },
1939
- { value: "Pacific/Chatham", label: "Chatham Islands" },
1940
- { value: "Pacific/Apia", label: "Apia" },
1941
- { value: "Pacific/Kiritimati", label: "Kiritimati" }
1942
- ];
1943
- var EXCHANGE_TIMEZONE = "exchange";
1944
- function isExchangeTimezone(zone) {
1945
- return zone === EXCHANGE_TIMEZONE;
1946
- }
1947
- function resolveTimezone(zone, exchangeZone) {
1948
- if (!isExchangeTimezone(zone)) return zone;
1949
- return exchangeZone && exchangeZone !== "" ? exchangeZone : "Etc/UTC";
1950
- }
1951
- function normalizeTimezone(zone) {
1952
- return zone === "UTC" || zone === "Etc/UTC" || zone === "Etc/GMT" ? "Etc/UTC" : zone;
1953
- }
1954
- function timezoneMenuRows(current) {
1955
- const active = normalizeTimezone(current);
1956
- const [utc, ...zones] = TIMEZONES.map((t) => ({ value: t.value, label: tzMenuLabel(t.value, t.label), checked: t.value === active }));
1957
- return [utc, { value: EXCHANGE_TIMEZONE, label: "Exchange", checked: isExchangeTimezone(current) }, ...zones];
1958
- }
1959
- function tzOffset(zone, date = /* @__PURE__ */ new Date()) {
1960
- try {
1961
- const parts = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "shortOffset" }).formatToParts(date);
1962
- const raw = parts.find((p) => p.type === "timeZoneName")?.value ?? "";
1963
- const m = raw.match(/GMT(?:(\+|-)(\d{1,2})(?::(\d{2}))?)?/);
1964
- if (!m || !m[1]) return "UTC";
1965
- const sign = m[1] === "-" ? "-" : "+";
1966
- const hrs = m[2] ?? "0";
1967
- const mins = m[3] ?? "";
1968
- return mins ? `UTC${sign}${hrs}:${mins}` : `UTC${sign}${hrs}`;
1969
- } catch {
1970
- return "UTC";
1971
- }
1972
- }
1973
- function tzMenuLabel(zone, location) {
1974
- if (normalizeTimezone(zone) === "Etc/UTC") return location;
1975
- return `(${tzOffset(zone)}) ${location}`;
1976
- }
1977
- function tzButtonLabel(zone) {
1978
- if (normalizeTimezone(zone) === "Etc/UTC") return "UTC";
1979
- return tzOffset(zone);
1980
- }
1981
-
1982
1888
  // src/core/drawings/effectiveColor.ts
1983
1889
  var VALID_FILL = VALID;
1984
1890
  var INVALID_FILL = INVALID;
@@ -2602,6 +2508,7 @@ function chromeHint(text, opts) {
2602
2508
  // src/renderers/native/drawings/DrawingToolbar.ts
2603
2509
  var TOOLBAR_WIDTH = 44;
2604
2510
  var TOOLBAR_COLLAPSED_WIDTH = 16;
2511
+ var FLYOUT_GAP = 3;
2605
2512
  var DrawingToolbar = class {
2606
2513
  constructor(host, theme, onArm, onMagnet = () => {
2607
2514
  }, onMeasure = () => {
@@ -2631,6 +2538,9 @@ var DrawingToolbar = class {
2631
2538
  // group id (or MAGNET_ID) whose flyout is open
2632
2539
  this.flyoutCell = null;
2633
2540
  // the cell the open flyout is anchored to
2541
+ /** Closed flyouts still playing their exit animation, by owner id — reopening the same
2542
+ * owner takes its element back instead of stacking a second one on it. */
2543
+ this.exitingFlyouts = /* @__PURE__ */ new Map();
2634
2544
  this.groupCells = /* @__PURE__ */ new Map();
2635
2545
  // the composite cell (hover/active bg + flyout anchor)
2636
2546
  this.groupIcons = /* @__PURE__ */ new Map();
@@ -2739,6 +2649,7 @@ var DrawingToolbar = class {
2739
2649
  }
2740
2650
  destroy() {
2741
2651
  this.closeFlyout();
2652
+ for (const { exit } of [...this.exitingFlyouts.values()]) exit.finish();
2742
2653
  for (const dispose of this.tipDisposers.splice(0)) dispose();
2743
2654
  this.root.remove();
2744
2655
  }
@@ -2966,16 +2877,22 @@ var DrawingToolbar = class {
2966
2877
  * outside-dismiss. Callers fill it with items. */
2967
2878
  beginFlyout(ownerId, cell) {
2968
2879
  const t = this.theme;
2969
- const fly = document.createElement("div");
2880
+ const back = this.exitingFlyouts.get(ownerId);
2881
+ if (back) {
2882
+ this.exitingFlyouts.delete(ownerId);
2883
+ back.exit.cancel();
2884
+ back.fly.replaceChildren();
2885
+ }
2886
+ const fly = back?.fly ?? document.createElement("div");
2970
2887
  fly.className = "vela-dtb-flyout";
2971
- fly.style.cssText = `position:absolute;z-index:23;display:flex;flex-direction:column;gap:2px;padding:4px;border-radius:0 8px 8px 0;background:var(--vela-surface-elev);border:1px solid ${this.borderColor};border-left:none;box-shadow:var(--vela-shadow);pointer-events:auto;overflow-y:auto;overscroll-behavior:contain;`;
2888
+ fly.style.cssText = `position:absolute;z-index:23;display:flex;flex-direction:column;gap:2px;padding:4px;border-radius:var(--vela-radius-md);background:var(--vela-surface);border:1px solid ${this.borderOverride ?? "var(--vela-border-strong)"};box-shadow:var(--vela-shadow);pointer-events:auto;overflow-y:auto;overscroll-behavior:contain;`;
2972
2889
  applyChromeTokens(fly, t);
2973
2890
  this.host.appendChild(fly);
2974
2891
  const r = cell.getBoundingClientRect();
2975
2892
  const rootR = this.root.getBoundingClientRect();
2976
2893
  const hostR = this.host.getBoundingClientRect();
2977
2894
  const top = r.top - hostR.top;
2978
- fly.style.left = `${rootR.right - hostR.left - 1}px`;
2895
+ fly.style.left = `${rootR.right - hostR.left + FLYOUT_GAP}px`;
2979
2896
  fly.style.top = `${top}px`;
2980
2897
  fly.style.maxHeight = `${Math.max(120, hostR.height - top - 8)}px`;
2981
2898
  this.flyout = fly;
@@ -2991,6 +2908,7 @@ var DrawingToolbar = class {
2991
2908
  if (!cell) return;
2992
2909
  const fly = this.beginFlyout(group.id, cell);
2993
2910
  const sections = group.sections ?? [{ label: "", tools: group.tools }];
2911
+ const badge = sections.some((s) => s.tools.some((tool) => !!tool.icon));
2994
2912
  for (let si = 0; si < sections.length; si++) {
2995
2913
  const section = sections[si];
2996
2914
  if (section.label) {
@@ -3001,6 +2919,7 @@ var DrawingToolbar = class {
3001
2919
  fly.appendChild(
3002
2920
  this.makeFlyoutItem({
3003
2921
  icon: tool.icon,
2922
+ badge,
3004
2923
  label: tool.label,
3005
2924
  selected: tool.type === this.active,
3006
2925
  shortcut: this.shortcuts.get(tool.type),
@@ -3051,21 +2970,24 @@ var DrawingToolbar = class {
3051
2970
  div.style.cssText = `height:1px;margin:4px 8px;background:${this.borderColor};`;
3052
2971
  return div;
3053
2972
  }
3054
- /** A flyout row, left to right: optional leading icon, label, a check when it's the selected
3055
- * entry, an optional shortcut hint, and — at the far right — the favorite star (tool rows).
3056
- * Hover tint is CSS (`.vela-dtb-item:hover`), so navigating the menu stays smooth. */
2973
+ /** A flyout row, left to right: optional leading icon badge, label, a check when it's the
2974
+ * selected entry, an optional shortcut hint, and — at the far right — the favorite star (tool
2975
+ * rows). Hover tint is CSS (`.vela-dtb-item:hover`), so navigating the menu stays smooth. */
3057
2976
  makeFlyoutItem(opts) {
3058
2977
  const t = this.theme;
3059
2978
  const item = document.createElement("button");
3060
2979
  item.type = "button";
3061
2980
  item.className = "vela-dtb-item";
3062
2981
  item.setAttribute("aria-label", opts.label);
3063
- item.style.cssText = `display:flex;align-items:center;gap:8px;padding:5px 10px 5px 8px;cursor:pointer;color:${t.textColor};border-radius:var(--vela-radius-sm);font:13px ${t.fontFamily};white-space:nowrap;min-width:148px;`;
3064
- if (opts.icon) {
3065
- const icon2 = document.createElement("span");
3066
- icon2.style.cssText = "width:18px;height:18px;display:flex;align-items:center;justify-content:center;flex:none;";
3067
- icon2.innerHTML = sizedIcon(opts.icon);
3068
- item.appendChild(icon2);
2982
+ const badged = opts.badge === true || !!opts.icon;
2983
+ const box = badged ? "gap:10px;padding:4px 10px 4px 6px;" : "gap:8px;padding:5px 10px 5px 8px;";
2984
+ item.style.cssText = `display:flex;align-items:center;${box}cursor:pointer;color:${t.textColor};border-radius:var(--vela-radius-sm);font:13px ${t.fontFamily};white-space:nowrap;min-width:148px;`;
2985
+ if (opts.selected) item.dataset.selected = "1";
2986
+ if (badged) {
2987
+ const badge = document.createElement("span");
2988
+ badge.className = "vela-dtb-badge";
2989
+ if (opts.icon) badge.innerHTML = opts.icon;
2990
+ item.appendChild(badge);
3069
2991
  }
3070
2992
  const label = document.createElement("span");
3071
2993
  label.textContent = opts.label;
@@ -3110,7 +3032,12 @@ var DrawingToolbar = class {
3110
3032
  if (fly) {
3111
3033
  this.flyout = null;
3112
3034
  announceSurface(fly, false, "menu", this.flyoutCell);
3113
- fly.remove();
3035
+ const owner = this.flyoutOwnerId ?? "";
3036
+ const exit = holdForExit(fly, () => {
3037
+ if (this.exitingFlyouts.get(owner)?.fly === fly) this.exitingFlyouts.delete(owner);
3038
+ fly.remove();
3039
+ });
3040
+ if (exit) this.exitingFlyouts.set(owner, { fly, exit });
3114
3041
  this.flyoutCell?.classList.remove("vela-open");
3115
3042
  this.flyoutCell = null;
3116
3043
  this.flyoutOwnerId = null;
@@ -3194,6 +3121,11 @@ function ensureStyles() {
3194
3121
  .vela-dtb[data-collapsed='1'] .vela-dtb-collapse .vela-dtb-hit{width:14px;}
3195
3122
  .vela-dtb-item{background:transparent;border:none;transition:background var(--vela-dur-fast) ease;}
3196
3123
  .vela-dtb-item:hover{background:var(--vela-hover-strong);}
3124
+ .vela-dtb-badge{width:24px;height:24px;padding:3px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;flex:none;border-radius:var(--vela-radius-md);background:var(--vela-hover);border:1px solid var(--vela-border);color:var(--vela-fg-muted);transition:background var(--vela-dur-fast) ease,border-color var(--vela-dur-fast) ease,color var(--vela-dur-fast) ease;}
3125
+ .vela-dtb-badge:empty{background:transparent;border-color:transparent;}
3126
+ .vela-dtb-badge svg{width:100%;height:100%;}
3127
+ .vela-dtb-item:hover .vela-dtb-badge:not(:empty){background:var(--vela-active);color:var(--vela-fg-bright);}
3128
+ .vela-dtb-item[data-selected='1'] .vela-dtb-badge:not(:empty){background:color-mix(in srgb,var(--vela-fg-bright) 83%,var(--vela-surface));border-color:color-mix(in srgb,var(--vela-fg-bright) 40%,transparent);color:var(--vela-surface);}
3197
3129
  .vela-dtb-star{width:26px;height:22px;margin:-3px -5px -3px 0;padding:3px 5px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;flex:none;opacity:0;color:inherit;border-radius:var(--vela-radius-sm);transition:opacity .1s ease,color .1s ease,background .1s ease;}
3198
3130
  .vela-dtb-star svg{width:16px;height:16px;}
3199
3131
  .vela-dtb-item:hover .vela-dtb-star{opacity:.55;}
@@ -4079,7 +4011,10 @@ var LEGEND_ICON_PX2 = 16;
4079
4011
  var LEGEND_CTL_PX = 18;
4080
4012
  var LEGEND_ROW_PAD_Y = 2;
4081
4013
  var LEGEND_ROW_PAD_X = 6;
4014
+ var LEGEND_LEFT_PX = 10;
4015
+ var LEGEND_SCALE_GAP_PX = 6;
4082
4016
  var LEGEND_TITLE_VALUES_GAP_PX = 6;
4017
+ var LEGEND_VALUES_GAP_PX = 5;
4083
4018
  var LEGEND_TITLE_STATUS_GAP_PX = 8;
4084
4019
  var LEGEND_ACTION_GAP_PX = 6;
4085
4020
  var LEGEND_CTL_CSS = `cursor:pointer;display:inline-flex;align-items:center;justify-content:center;border:none;line-height:0;padding:0;width:${LEGEND_CTL_PX}px;height:${LEGEND_CTL_PX}px;border-radius:3px;box-sizing:border-box;flex:none;`;
@@ -4365,14 +4300,15 @@ var InputsUI = class {
4365
4300
  row.valuesEl.replaceChildren();
4366
4301
  return;
4367
4302
  }
4368
- row.valuesEl.style.display = "inline-flex";
4303
+ row.valuesEl.style.display = "block";
4369
4304
  row.valuesEl.replaceChildren();
4370
- for (const v of row.plotValues) {
4305
+ row.plotValues.forEach((v, i) => {
4371
4306
  const span = document.createElement("span");
4372
4307
  span.textContent = v.value;
4373
4308
  span.style.color = v.color;
4309
+ if (i > 0) span.style.marginLeft = `${LEGEND_VALUES_GAP_PX}px`;
4374
4310
  row.valuesEl.appendChild(span);
4375
- }
4311
+ });
4376
4312
  }
4377
4313
  // ── legend move/merge (menu + drag) ─────────────────────────────────────
4378
4314
  /** Open the "Move to" menu for a row, anchored under its move button. */
@@ -4473,7 +4409,7 @@ var InputsUI = class {
4473
4409
  if (!lg) {
4474
4410
  lg = document.createElement("div");
4475
4411
  lg.dataset.velaPane = paneId;
4476
- lg.style.cssText = "position:absolute;left:10px;z-index:5;display:flex;flex-direction:column;align-items:flex-start;gap:0;pointer-events:none;font:12px -apple-system,Segoe UI,sans-serif;";
4412
+ lg.style.cssText = `position:absolute;left:${LEGEND_LEFT_PX}px;z-index:5;display:flex;flex-direction:column;align-items:flex-start;gap:0;pointer-events:none;font:12px -apple-system,Segoe UI,sans-serif;`;
4477
4413
  applyChromeTokens(lg, this.theme);
4478
4414
  this.positionLegend(lg, paneId);
4479
4415
  this.container.appendChild(lg);
@@ -4485,6 +4421,7 @@ var InputsUI = class {
4485
4421
  const bounds = this.paneBoundsOf ? this.paneBoundsOf(paneId) : { top: 0, height: Infinity };
4486
4422
  lg.toggleAttribute(LEGEND_AT_TOP_ATTR, bounds.top === 0);
4487
4423
  lg.style.display = bounds.height < 4 || !this.titlesVisible ? "none" : "flex";
4424
+ lg.style.maxWidth = `calc(100% - ${(bounds.rightAxis ?? 0) + LEGEND_LEFT_PX + LEGEND_SCALE_GAP_PX}px)`;
4488
4425
  const collapsed = this.paneCollapse.has(paneId);
4489
4426
  const masterId = this.paneCollapse.get(paneId) ?? null;
4490
4427
  for (const row of this.rows.values()) {
@@ -4576,7 +4513,7 @@ var InputsUI = class {
4576
4513
  }
4577
4514
  ensureDialogStyles();
4578
4515
  const el = document.createElement("div");
4579
- el.style.cssText = `pointer-events:auto;display:flex;align-items:center;background:${this.idleRowFill()};border-radius:4px;padding:${LEGEND_ROW_PAD_Y}px ${LEGEND_ROW_PAD_X}px;margin-left:-${LEGEND_ROW_PAD_X}px;min-height:${LEGEND_ROW_MIN_H}px;box-sizing:border-box;color:${this.theme.textColor};user-select:none;-webkit-user-select:none;`;
4516
+ el.style.cssText = `pointer-events:auto;display:flex;align-items:center;background:${this.idleRowFill()};border-radius:4px;padding:${LEGEND_ROW_PAD_Y}px ${LEGEND_ROW_PAD_X}px;margin-left:-${LEGEND_ROW_PAD_X}px;max-width:calc(100% + ${LEGEND_ROW_PAD_X}px);min-height:${LEGEND_ROW_MIN_H}px;box-sizing:border-box;color:${this.theme.textColor};user-select:none;-webkit-user-select:none;`;
4580
4517
  el.addEventListener("mouseleave", () => {
4581
4518
  if (this.selectedId !== id) this.setRowHighlighted(id, false);
4582
4519
  });
@@ -4604,7 +4541,7 @@ var InputsUI = class {
4604
4541
  const statusEl = document.createElement("span");
4605
4542
  statusEl.style.cssText = "display:none;box-sizing:border-box;flex:none;";
4606
4543
  const titleWrap = document.createElement("span");
4607
- titleWrap.style.cssText = "white-space:nowrap;";
4544
+ titleWrap.style.cssText = "white-space:nowrap;min-width:0;overflow:hidden;text-overflow:ellipsis;";
4608
4545
  titleWrap.addEventListener("mouseenter", () => this.setRowHighlighted(id, true));
4609
4546
  const titleEl = document.createElement("span");
4610
4547
  titleEl.textContent = title;
@@ -4622,7 +4559,7 @@ var InputsUI = class {
4622
4559
  el.appendChild(calloutsEl);
4623
4560
  el.appendChild(statusEl);
4624
4561
  const valuesEl = document.createElement("span");
4625
- valuesEl.style.cssText = `display:none;align-items:center;gap:5px;margin-left:${LEGEND_TITLE_VALUES_GAP_PX}px;white-space:nowrap;font-variant-numeric:tabular-nums;`;
4562
+ valuesEl.style.cssText = `display:none;flex:1 1 0%;min-width:0;overflow:hidden;text-overflow:ellipsis;margin-left:${LEGEND_TITLE_VALUES_GAP_PX}px;white-space:nowrap;font-variant-numeric:tabular-nums;`;
4626
4563
  el.appendChild(valuesEl);
4627
4564
  const controlsEl = document.createElement("span");
4628
4565
  controlsEl.style.cssText = `display:none;align-items:center;gap:${LEGEND_ACTION_GAP_PX}px;flex:none;margin-left:${LEGEND_ACTION_GAP_PX}px;`;
@@ -7217,6 +7154,11 @@ var InputController = class {
7217
7154
  /** When true (the default), the separators between stacked panes are draggable to
7218
7155
  * resize the panes above/below. When false, a press there is a normal data-area pan. */
7219
7156
  this.paneResize = true;
7157
+ /** When true (the default), the user drawings take part in pointer input: they claim a
7158
+ * press over a drawing or with a tool armed, and see hover moves. When false, every press
7159
+ * is a plain pan/click and hover leaves them alone; a drawing gesture already under way
7160
+ * still finishes. */
7161
+ this.drawings = true;
7220
7162
  this.el = null;
7221
7163
  this.dragging = false;
7222
7164
  this.moved = false;
@@ -7280,18 +7222,18 @@ var InputController = class {
7280
7222
  this.onModifier = (e) => {
7281
7223
  if (e.repeat || e.key !== "Shift" && e.key !== "Control" && e.key !== "Meta") return;
7282
7224
  if (Number.isNaN(this.cursorX)) return;
7283
- if (this.dragging && this.region !== "drawing") return;
7225
+ if (this.dragging ? this.region !== "drawing" : !this.drawings) return;
7284
7226
  this.deps.drawingsPointerMove?.(this.cursorX, this.cursorY, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
7285
7227
  };
7286
7228
  this.onDown = (e) => {
7287
7229
  if (e.button === 1) {
7288
7230
  const { x: x2, y: y2 } = this.local(e);
7289
- this.middleDeleted = this.deps.drawingsDeleteAt?.(x2, y2) ?? false;
7231
+ this.middleDeleted = this.drawings && (this.deps.drawingsDeleteAt?.(x2, y2) ?? false);
7290
7232
  if (this.middleDeleted) e.preventDefault();
7291
7233
  return;
7292
7234
  }
7293
7235
  if (e.button === 2) {
7294
- this.rightCancelled = this.deps.drawingsCancelPlacement?.() ?? false;
7236
+ this.rightCancelled = this.drawings && (this.deps.drawingsCancelPlacement?.() ?? false);
7295
7237
  if (this.rightCancelled) e.preventDefault();
7296
7238
  return;
7297
7239
  }
@@ -7313,20 +7255,20 @@ var InputController = class {
7313
7255
  this.startY = y;
7314
7256
  this.prevPressDrawing = this.lastPressDrawing;
7315
7257
  this.lastPressDrawing = false;
7316
- if (this.deps.drawingsClaim?.(x, y)) {
7258
+ if (this.drawings && this.deps.drawingsClaim?.(x, y)) {
7317
7259
  this.region = "drawing";
7318
7260
  this.lastPressDrawing = true;
7319
7261
  this.deps.drawingsPointerDown?.(x, y, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
7320
7262
  this.capture(e.pointerId);
7321
7263
  return;
7322
7264
  }
7323
- if (e.shiftKey && this.regionAt(x, y) === "data" && this.deps.drawingsMeasureStart?.(x, y, this.snapMode(e))) {
7265
+ if (this.drawings && e.shiftKey && this.regionAt(x, y) === "data" && this.deps.drawingsMeasureStart?.(x, y, this.snapMode(e))) {
7324
7266
  this.region = "drawing";
7325
7267
  this.lastPressDrawing = true;
7326
7268
  this.capture(e.pointerId);
7327
7269
  return;
7328
7270
  }
7329
- if ((e.ctrlKey || e.metaKey) && this.regionAt(x, y) === "data" && this.deps.drawingsMarqueeStart?.(x, y)) {
7271
+ if (this.drawings && (e.ctrlKey || e.metaKey) && this.regionAt(x, y) === "data" && this.deps.drawingsMarqueeStart?.(x, y)) {
7330
7272
  this.region = "drawing";
7331
7273
  this.lastPressDrawing = true;
7332
7274
  this.capture(e.pointerId);
@@ -7403,7 +7345,7 @@ var InputController = class {
7403
7345
  const drawCursor = this.deps.drawingsCursor?.(x, y);
7404
7346
  const r = this.regionAt(x, y);
7405
7347
  this.el.style.cursor = drawCursor ?? (r === "price" ? "ns-resize" : r === "time" ? "ew-resize" : r === "separator" ? "row-resize" : "");
7406
- this.deps.drawingsPointerMove?.(x, y, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
7348
+ if (this.drawings) this.deps.drawingsPointerMove?.(x, y, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
7407
7349
  }
7408
7350
  if (e.pointerType !== "touch") this.deps.onPointerMove(x, y);
7409
7351
  };
@@ -7645,7 +7587,7 @@ var InputController = class {
7645
7587
  }
7646
7588
  /** Shared double-click / double-tap routing, by the region under the point. */
7647
7589
  doubleActivate(x, y) {
7648
- if (this.deps.drawingsDblClick?.(x, y)) return;
7590
+ if (this.drawings && this.deps.drawingsDblClick?.(x, y)) return;
7649
7591
  const region = this.regionAt(x, y);
7650
7592
  if (region === "price") this.deps.resetPriceScale(x, y);
7651
7593
  else if (region === "separator") this.deps.resetPaneSize(y);
@@ -9695,10 +9637,13 @@ function priceTicks(min, max, target = 6) {
9695
9637
  const norm = raw / mag;
9696
9638
  const step = (norm < 1.5 ? 1 : norm < 3 ? 2 : norm < 7 ? 5 : 10) * mag;
9697
9639
  const decimals = Math.max(0, -Math.floor(Math.log10(step)) + 1);
9698
- const out = [];
9699
9640
  const start = Math.ceil(min / step) * step;
9700
- for (let v = start; v <= max + step * 1e-6; v += step) {
9701
- out.push(Number(v.toFixed(decimals)));
9641
+ if (!(step > 0) || start + step === start) return [];
9642
+ const count = Math.floor((max - start) / step + 1e-6) + 1;
9643
+ if (!(count > 0) || count > 1e3) return [];
9644
+ const out = [];
9645
+ for (let i = 0; i < count; i += 1) {
9646
+ out.push(Number((start + i * step).toFixed(decimals)));
9702
9647
  }
9703
9648
  return out;
9704
9649
  }
@@ -9896,6 +9841,100 @@ function calendarTicks(zFrom, zTo, months, offsetMs) {
9896
9841
  return out;
9897
9842
  }
9898
9843
 
9844
+ // src/renderers/native/chrome/priceAxisTicks.ts
9845
+ var PriceAxisTickSource = class {
9846
+ constructor() {
9847
+ this.fn = null;
9848
+ this.memo = /* @__PURE__ */ new WeakMap();
9849
+ this.warned = false;
9850
+ }
9851
+ /** The host function, or null for the built-in ticks. */
9852
+ get hook() {
9853
+ return this.fn;
9854
+ }
9855
+ /** Set (or clear) the host function. Drops every memoized result, so setting the same
9856
+ * function again recomputes — how a host refreshes ticks that depend on its own state. */
9857
+ setHook(fn) {
9858
+ this.fn = fn;
9859
+ this.memo = /* @__PURE__ */ new WeakMap();
9860
+ }
9861
+ /** The pane's master-scale ticks for this frame. An unscaled pane (`axisFormat: 'none'`)
9862
+ * gets none, and the host is never asked for it. */
9863
+ ticksFor(scene, pane, coords) {
9864
+ const format = pane.axisFormat;
9865
+ if (format === "none") return [];
9866
+ const pct = percentScaleFor(scene, pane);
9867
+ const height = pane.bounds.height;
9868
+ const fn = this.fn;
9869
+ if (!fn || !(height > 0)) return paneAxisTicks(pane.scale, height, pct, scene.priceMintick, format);
9870
+ const s = pane.scale;
9871
+ const m = this.memo.get(pane);
9872
+ const fontSize = scene.style.fontSize;
9873
+ if (m && m.kind === pane.kind && m.min === s.min && m.max === s.max && m.log === !!s.log && m.invert === !!s.invert && m.height === height && m.baseline === pct?.baseline && m.indexed === !!pct?.indexed && m.mintick === scene.priceMintick && m.format === format && m.fontSize === fontSize) {
9874
+ return m.ticks;
9875
+ }
9876
+ const defaults = paneAxisTicks(s, height, pct, scene.priceMintick, format);
9877
+ const ticks = this.callHook(fn, scene, pane, coords, defaults, pct?.baseline, pct ? pct.indexed ? "indexed" : "percent" : "price");
9878
+ this.memo.set(pane, {
9879
+ kind: pane.kind,
9880
+ min: s.min,
9881
+ max: s.max,
9882
+ log: !!s.log,
9883
+ invert: !!s.invert,
9884
+ height,
9885
+ baseline: pct?.baseline,
9886
+ indexed: !!pct?.indexed,
9887
+ mintick: scene.priceMintick,
9888
+ format,
9889
+ fontSize,
9890
+ ticks
9891
+ });
9892
+ return ticks;
9893
+ }
9894
+ callHook(fn, scene, pane, coords, defaults, baseline, mode) {
9895
+ const scale = { min: pane.scale.min, max: pane.scale.max, log: !!pane.scale.log, invert: !!pane.scale.invert };
9896
+ const bounds = { top: 0, height: pane.bounds.height };
9897
+ const ctx = {
9898
+ pane: { id: pane.id, kind: pane.kind },
9899
+ min: Math.min(scale.min, scale.max),
9900
+ max: Math.max(scale.min, scale.max),
9901
+ log: !!scale.log,
9902
+ height: bounds.height,
9903
+ mode,
9904
+ baseline,
9905
+ mintick: scene.priceMintick,
9906
+ fontSize: scene.style.fontSize,
9907
+ priceToY: (price) => coords.priceToY(price, scale, bounds),
9908
+ defaults
9909
+ };
9910
+ let out;
9911
+ try {
9912
+ out = fn(ctx);
9913
+ } catch (err) {
9914
+ this.warnOnce("threw", err);
9915
+ return defaults;
9916
+ }
9917
+ if (out == null) return defaults;
9918
+ if (!Array.isArray(out)) {
9919
+ this.warnOnce("returned a non-array", out);
9920
+ return defaults;
9921
+ }
9922
+ const ticks = [];
9923
+ for (const t of out) {
9924
+ if (!t || typeof t !== "object") continue;
9925
+ const { price, label, major } = t;
9926
+ if (typeof price !== "number" || !Number.isFinite(price) || typeof label !== "string") continue;
9927
+ ticks.push(typeof major === "boolean" ? { price, label, major } : { price, label });
9928
+ }
9929
+ return ticks;
9930
+ }
9931
+ warnOnce(what, detail) {
9932
+ if (this.warned) return;
9933
+ this.warned = true;
9934
+ console.warn(`[vela] the priceAxisTicks function ${what} \u2014 the default ticks are used instead.`, detail);
9935
+ }
9936
+ };
9937
+
9899
9938
  // src/renderers/native/chrome/countdown.ts
9900
9939
  function countdownText(barOpen, barMs, now2) {
9901
9940
  if (!(barMs > 0)) return null;
@@ -10248,8 +10287,11 @@ function standaloneSvg(markup, ink, px) {
10248
10287
  }
10249
10288
 
10250
10289
  // src/renderers/native/chrome/ChromeRenderer.ts
10290
+ var MINOR_LABEL_ALPHA = 0.5;
10251
10291
  var ChromeRenderer = class {
10252
- constructor() {
10292
+ /** `axisTicks` is shared with the backdrop layer, so price labels and gridlines agree. */
10293
+ constructor(axisTicks = new PriceAxisTickSource()) {
10294
+ this.axisTicks = axisTicks;
10253
10295
  this.canvas = null;
10254
10296
  this.ctx = null;
10255
10297
  // The color for axis tick labels — the host-passed surface text, set each frame in render().
@@ -10354,7 +10396,8 @@ var ChromeRenderer = class {
10354
10396
  this.drawTimeAxis(ctx, scene, coords, theme, dataW, dataH, fullH);
10355
10397
  this.drawMarkLane(ctx, scene, coords, theme, dataW, dataH);
10356
10398
  }
10357
- /** The timeline-mark lane — after the axis, so the tokens read over the plot's bottom edge. */
10399
+ /** The timeline-mark lane — after the axis, so the tokens read over the plot's bottom edge,
10400
+ * but clipped to the data area so a glyph on the edge bar never paints over the price scale. */
10358
10401
  drawMarkLane(ctx, scene, coords, theme, dataW, dataH) {
10359
10402
  if (!scene.marks.visible || scene.timelineMarks.length === 0) {
10360
10403
  this.markLayout = { glyphs: [], stacks: /* @__PURE__ */ new Map() };
@@ -10372,6 +10415,10 @@ var ChromeRenderer = class {
10372
10415
  expanded: scene.marksExpandedStack
10373
10416
  });
10374
10417
  const nowMs = typeof performance !== "undefined" ? performance.now() : Date.now();
10418
+ ctx.save();
10419
+ ctx.beginPath();
10420
+ ctx.rect(0, 0, dataW, dataH);
10421
+ ctx.clip();
10375
10422
  paintMarkLane(ctx, this.markLayout, {
10376
10423
  axisY: dataH,
10377
10424
  background: theme.background,
@@ -10385,6 +10432,7 @@ var ChromeRenderer = class {
10385
10432
  flashKey: scene.marksFlash && scene.marksFlash.until > nowMs ? scene.marksFlash.key : null,
10386
10433
  nowMs
10387
10434
  });
10435
+ ctx.restore();
10388
10436
  }
10389
10437
  barTimes(scene) {
10390
10438
  if (this.barTimesSrc !== scene.bars || this.barTimesCache.length !== scene.bars.length) {
@@ -10441,13 +10489,19 @@ var ChromeRenderer = class {
10441
10489
  if (!scene.showAxisLabels) return;
10442
10490
  ctx.fillStyle = this.axisTextColor;
10443
10491
  ctx.textAlign = "left";
10492
+ const font = `${scene.style.fontSize}px ${theme.fontFamily}`;
10493
+ const majorFont = `600 ${font}`;
10494
+ const alpha = ctx.globalAlpha;
10444
10495
  for (const pane of panes) {
10445
10496
  if (pane.collapsed) continue;
10446
- const pct = percentScaleFor(scene, pane);
10447
- for (const t of paneAxisTicks(pane.scale, pane.bounds.height, pct, scene.priceMintick, pane.axisFormat)) {
10497
+ for (const t of this.axisTicks.ticksFor(scene, pane, coords)) {
10448
10498
  const y = coords.priceToY(t.price, pane.scale, pane.bounds);
10449
10499
  if (y < pane.bounds.top + 6 || y > pane.bounds.top + pane.bounds.height - 4) continue;
10500
+ if (t.major === true) ctx.font = majorFont;
10501
+ else if (t.major === false) ctx.globalAlpha = alpha * MINOR_LABEL_ALPHA;
10450
10502
  ctx.fillText(t.label, dataW + 6, y);
10503
+ if (t.major === true) ctx.font = font;
10504
+ else if (t.major === false) ctx.globalAlpha = alpha;
10451
10505
  }
10452
10506
  if (pane.axisBands) {
10453
10507
  for (const b of pane.axisBands) {
@@ -10689,15 +10743,23 @@ var CrosshairRenderer = class {
10689
10743
  constructor() {
10690
10744
  this.canvas = null;
10691
10745
  this.ctx = null;
10746
+ this.shade = null;
10692
10747
  }
10693
10748
  mount(canvas) {
10694
10749
  this.canvas = canvas;
10695
10750
  this.ctx = canvas.getContext("2d");
10696
10751
  }
10752
+ /** The plot area the last frame veiled for `crosshairOverride.shadeRight` — from the
10753
+ * picked bar's right edge to the price scale, full plot height (the union when both the
10754
+ * local and a synced crosshair veil) — or null when no veil was painted. */
10755
+ get shadeRightArea() {
10756
+ return this.shade;
10757
+ }
10697
10758
  /** Clear the cursor canvas and (re)draw the crosshair lines + axis chips. The optional
10698
10759
  * `separatorHoverY` highlights the draggable pane separator under the cursor;
10699
10760
  * `external` is a SYNCED ghost crosshair (another chart's pointer, pixel-resolved). */
10700
10761
  render(scene, coords, theme, separatorHoverY = null, external = null) {
10762
+ this.shade = null;
10701
10763
  const ctx = this.ctx;
10702
10764
  const canvas = this.canvas;
10703
10765
  if (!ctx || !canvas) return;
@@ -10720,12 +10782,7 @@ var CrosshairRenderer = class {
10720
10782
  const x = crisp(coords.logicalToX(logical), ov?.width ?? cs.width);
10721
10783
  if (vertical && ov?.shadeRight) {
10722
10784
  const from = Math.max(0, Math.round(coords.logicalToX(logical + 0.5)));
10723
- if (from < dataW) {
10724
- ctx.fillStyle = ov.shadeRight.color;
10725
- ctx.globalAlpha = ov.shadeRight.opacity ?? 1;
10726
- ctx.fillRect(from, 0, dataW - from, dataH);
10727
- ctx.globalAlpha = 1;
10728
- }
10785
+ if (from < dataW) this.paintShade(ctx, ov.shadeRight, from, dataW, dataH);
10729
10786
  }
10730
10787
  ctx.strokeStyle = ov?.color ?? cs.color ?? theme.textColor;
10731
10788
  ctx.lineWidth = ov?.width ?? cs.width;
@@ -10761,6 +10818,7 @@ var CrosshairRenderer = class {
10761
10818
  destroy() {
10762
10819
  this.canvas = null;
10763
10820
  this.ctx = null;
10821
+ this.shade = null;
10764
10822
  }
10765
10823
  /** The synced ghost: a dimmed vertical line at the bar the renderer resolved as
10766
10824
  * CONTAINING the foreign time (+ horizontal line when a comparable price came
@@ -10780,12 +10838,7 @@ var CrosshairRenderer = class {
10780
10838
  if (ov?.vertical === false) return;
10781
10839
  if (ov?.shadeRight) {
10782
10840
  const from = Math.max(0, Math.round(coords.logicalToX(Math.round(coords.xToLogical(ext.x)) + 0.5)));
10783
- if (from < dataW) {
10784
- ctx.fillStyle = ov.shadeRight.color;
10785
- ctx.globalAlpha = ov.shadeRight.opacity ?? 1;
10786
- ctx.fillRect(from, 0, dataW - from, dataH);
10787
- ctx.globalAlpha = 1;
10788
- }
10841
+ if (from < dataW) this.paintShade(ctx, ov.shadeRight, from, dataW, dataH);
10789
10842
  }
10790
10843
  if (ext.line === false || x < 0 || x > dataW) return;
10791
10844
  ctx.font = `${scene.style.fontSize}px ${theme.fontFamily}`;
@@ -10821,6 +10874,15 @@ var CrosshairRenderer = class {
10821
10874
  this.chip(ctx, x, dataH + 1, formatTimeStamp(ext.time, scene.timezone, coords.barInterval), chipBg, "center", true, theme.background);
10822
10875
  ctx.globalAlpha = 1;
10823
10876
  }
10877
+ /** Paint the `shadeRight` veil from `from` to the price scale and record the veiled area. */
10878
+ paintShade(ctx, shade, from, dataW, dataH) {
10879
+ ctx.fillStyle = shade.color;
10880
+ ctx.globalAlpha = shade.opacity ?? 1;
10881
+ ctx.fillRect(from, 0, dataW - from, dataH);
10882
+ ctx.globalAlpha = 1;
10883
+ const x = this.shade ? Math.min(this.shade.x, from) : from;
10884
+ this.shade = { x, width: dataW - x, height: dataH };
10885
+ }
10824
10886
  /** A soft band + a brighter crisp center line over the hovered separator, so it reads as
10825
10887
  * a draggable handle (the cursor is already `row-resize`). Spans the full width (data +
10826
10888
  * scale gutter) to match the separator itself. Theme-derived (textColor). */
@@ -14238,15 +14300,16 @@ var DrawingSettingsDialog = class {
14238
14300
  }
14239
14301
  open(drawing, actions, kind) {
14240
14302
  this.close();
14241
- const snapshot = clonePlain(drawing.serialize());
14303
+ const live = actions.resolve() ?? drawing;
14304
+ const snapshot = clonePlain(live.serialize());
14242
14305
  const grid = fieldGrid({ variant: "inputs" });
14243
14306
  grid.style.padding = "16px 20px";
14244
14307
  grid.style.overflowY = "auto";
14245
14308
  grid.style.overflowX = "hidden";
14246
14309
  grid.style.flex = "1 1 auto";
14247
- if (kind === "position" && drawing instanceof PositionTool) this.buildPosition(grid, drawing, actions);
14248
- else if (kind === "frvp" && drawing instanceof FixedRangeVolumeProfile) this.buildFrvp(grid, drawing, actions);
14249
- else if (kind === "levels") this.buildLevels(grid, drawing, actions);
14310
+ if (kind === "position" && live instanceof PositionTool) this.buildPosition(grid, live, actions);
14311
+ else if (kind === "frvp" && live instanceof FixedRangeVolumeProfile) this.buildFrvp(grid, live, actions);
14312
+ else if (kind === "levels") this.buildLevels(grid, live, actions);
14250
14313
  else return;
14251
14314
  const ui = new Dialog({
14252
14315
  host: this.host,
@@ -14893,7 +14956,7 @@ var DrawingSettingsPopup = class {
14893
14956
  this.reposition();
14894
14957
  return;
14895
14958
  }
14896
- const text = drawing.text;
14959
+ const text = (actions.resolve() ?? drawing).text;
14897
14960
  const panel = document.createElement("div");
14898
14961
  panel.style.cssText = `padding:6px;border-top:1px solid var(--vela-border);display:flex;flex-direction:column;gap:4px;`;
14899
14962
  const ta = new TextArea({
@@ -16064,6 +16127,12 @@ var UserDrawingController = class {
16064
16127
  this.render();
16065
16128
  }
16066
16129
  }
16130
+ /** Drop the hover (its handles) — the pointer no longer reaches the drawings. */
16131
+ clearHover() {
16132
+ if (this.hoveredId == null) return;
16133
+ this.hoveredId = null;
16134
+ this.render();
16135
+ }
16067
16136
  pointerUp(x, y, snap = "off") {
16068
16137
  if (this.eraserMode) {
16069
16138
  this.erasing = false;
@@ -17054,9 +17123,10 @@ function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log =
17054
17123
  consider(drawings.max);
17055
17124
  }
17056
17125
  if (min === Infinity || max === -Infinity) return { min: 0, max: 1 };
17057
- if (min === max) {
17058
- const pad = Math.abs(min) * 0.1 || 1;
17059
- return { min: min - pad, max: max + pad, log: log && min - pad > 0 };
17126
+ if (max - min <= Math.max(Math.abs(min), Math.abs(max)) * 1e-12) {
17127
+ const mid = (min + max) / 2;
17128
+ const pad = Math.abs(mid) * 0.1 || 1;
17129
+ return { min: mid - pad, max: mid + pad, log: log && mid - pad > 0 };
17060
17130
  }
17061
17131
  const content = Math.max(0.1, 1 - (margins.top + margins.bottom) / 100);
17062
17132
  const above = margins.top / 100 / content;
@@ -17560,7 +17630,9 @@ function bandEdgeSlot(logical) {
17560
17630
  return Math.ceil(logical) - 0.5;
17561
17631
  }
17562
17632
  var BackdropRenderer = class {
17563
- constructor() {
17633
+ /** `axisTicks` is shared with the chrome layer, so gridlines and price labels agree. */
17634
+ constructor(axisTicks = new PriceAxisTickSource()) {
17635
+ this.axisTicks = axisTicks;
17564
17636
  this.canvas = null;
17565
17637
  this.ctx = null;
17566
17638
  }
@@ -17637,9 +17709,8 @@ var BackdropRenderer = class {
17637
17709
  if (scene.showGrid && gridHorz.visible && !pane.collapsed) {
17638
17710
  ctx.globalAlpha = gridAlpha;
17639
17711
  ctx.strokeStyle = horzColor;
17640
- const pct = percentScaleFor(scene, pane);
17641
17712
  ctx.beginPath();
17642
- for (const t of paneAxisTicks(pane.scale, pane.bounds.height, pct, void 0, pane.axisFormat)) {
17713
+ for (const t of this.axisTicks.ticksFor(scene, pane, coords)) {
17643
17714
  const y = Math.round(coords.priceToY(t.price, pane.scale, pane.bounds)) + 0.5;
17644
17715
  if (y < pane.bounds.top || y > pane.bounds.top + pane.bounds.height) continue;
17645
17716
  ctx.moveTo(0, y);
@@ -18229,8 +18300,16 @@ var NativeRenderer = class {
18229
18300
  this.toolbarGutter = 0;
18230
18301
  // px reserved on the left for the docked drawings toolbar (0 when hidden)
18231
18302
  this.mountContainer = null;
18303
+ /** The host-styleable twin of the `shadeRight` veil (`.vela-shade-right`), directly under
18304
+ * the cursor canvas; hidden whenever the crosshair layer paints no veil. */
18305
+ this.shadeRightEl = null;
18306
+ /** The veil geometry last written to {@link shadeRightEl} ('' = hidden) — the DOM is
18307
+ * touched only when it changes, never on a plain pointer move. */
18308
+ this.shadeRightSig = "";
18232
18309
  this.userDrawings = null;
18233
- this.backdropRenderer = new BackdropRenderer();
18310
+ /** One price-axis tick source for the gridlines (backdrop) and the labels (chrome). */
18311
+ this.priceAxisTicks = new PriceAxisTickSource();
18312
+ this.backdropRenderer = new BackdropRenderer(this.priceAxisTicks);
18234
18313
  this.volumeRenderer = new VolumeRenderer();
18235
18314
  /** SDK renderer layers instantiated at mount ({@link registerRendererLayer}). */
18236
18315
  /**
@@ -18263,7 +18342,7 @@ var NativeRenderer = class {
18263
18342
  this.backendMode = "auto";
18264
18343
  this.glowAmount = 0;
18265
18344
  // WebGL2 neon-glow intensity (canvas2d ignores it)
18266
- this.chrome = new ChromeRenderer();
18345
+ this.chrome = new ChromeRenderer(this.priceAxisTicks);
18267
18346
  /** Prepaints each indicator's Pine drawings into interleave slices at the model's z. */
18268
18347
  this.indicatorSlices = new IndicatorDrawingSlices();
18269
18348
  /** Hover tooltips for Pine labels (canvas hit-rects collected by the chrome layer). */
@@ -18380,6 +18459,8 @@ var NativeRenderer = class {
18380
18459
  // pane just below it
18381
18460
  this.resizeSplitStart = null;
18382
18461
  // the two panes' shared span when the drag began
18462
+ /** The user drawings take part in pointer input (the runtime `drawingsInteractive` feature). */
18463
+ this.drawingsInteractive = true;
18383
18464
  this.hoverSeparatorY = null;
18384
18465
  // pixel y of the separator under the cursor (drives its hover highlight)
18385
18466
  // ── pane management (merge / reorder / collapse / maximize) ──
@@ -18435,8 +18516,9 @@ var NativeRenderer = class {
18435
18516
  this.toggleVisibleCbs = /* @__PURE__ */ new Set();
18436
18517
  this.moveIndicatorCbs = /* @__PURE__ */ new Set();
18437
18518
  this.priceStyleCbs = /* @__PURE__ */ new Set();
18519
+ this.priceStyleWillChangeCbs = /* @__PURE__ */ new Set();
18438
18520
  this.name = "native";
18439
- this.features = ["logScale", "currentPriceLine", "priceLabel", "countdown", "upColor", "downColor", "glow", "animZoom", "animPan", "animScroll", "animAutoscale", "animLiveBar", "intro", "zoomAnchor", "axisDrag", "paneResize", "candleZOrder", "candleVisible", "seriesOrder", "highlights", "sessionZones", "gridlines", "axisLabels", "scaleMode", "invertScale", "paneScales", "autoScale", "timezone", "keyboard", "historyChords", "priceStyle", "priceBaseline", "baselinePrice", "settings", "attribution", "dialogHost", "tradeMarkers", "marks", "indicatorTitles", "indicatorValues", "crosshairOverride"];
18521
+ this.features = ["logScale", "currentPriceLine", "priceLabel", "countdown", "upColor", "downColor", "glow", "animZoom", "animPan", "animScroll", "animAutoscale", "animLiveBar", "intro", "zoomAnchor", "axisDrag", "paneResize", "candleZOrder", "candleVisible", "seriesOrder", "highlights", "sessionZones", "gridlines", "axisLabels", "scaleMode", "invertScale", "paneScales", "autoScale", "timezone", "keyboard", "historyChords", "priceStyle", "priceBaseline", "baselinePrice", "settings", "attribution", "dialogHost", "tradeMarkers", "marks", "indicatorTitles", "indicatorValues", "crosshairOverride", "drawingsInteractive", "priceAxisTicks"];
18440
18522
  /** Track cursor proximity to the scroll button on the plot (bubbles from the button too,
18441
18523
  * so moving onto the button doesn't count as leaving). */
18442
18524
  this.onScrollProximityMove = (e) => {
@@ -18480,6 +18562,7 @@ var NativeRenderer = class {
18480
18562
  this.scene.priceStyle = opts.priceStyle;
18481
18563
  this.scene.basePainting = basePaintingOf(opts.priceStyle);
18482
18564
  this.scene.candleOverride = candleOverrideFor(opts.priceStyle, this.scene.style.chartTypes);
18565
+ if (typeof opts.priceAxisTicks === "function") this.priceAxisTicks.setHook(opts.priceAxisTicks);
18483
18566
  }
18484
18567
  this.theme = this.deriveTheme(DARK_THEME);
18485
18568
  }
@@ -18618,6 +18701,15 @@ var NativeRenderer = class {
18618
18701
  case "crosshairOverride":
18619
18702
  this.scene.crosshairOverride = sanitizeCrosshairOverride(value);
18620
18703
  break;
18704
+ case "drawingsInteractive":
18705
+ this.drawingsInteractive = value !== false;
18706
+ if (this.input) this.input.drawings = this.drawingsInteractive;
18707
+ if (!this.drawingsInteractive) this.userDrawings?.clearHover();
18708
+ return;
18709
+ // affects the next gesture only — clearHover repaints what it drops
18710
+ case "priceAxisTicks":
18711
+ this.priceAxisTicks.setHook(typeof value === "function" ? value : null);
18712
+ break;
18621
18713
  case "keyboard":
18622
18714
  this.setKeyboardEnabled(Boolean(value));
18623
18715
  return;
@@ -18733,6 +18825,10 @@ var NativeRenderer = class {
18733
18825
  return { visible: this.scene.marks.visible, groups: { ...this.scene.marks.groups } };
18734
18826
  case "crosshairOverride":
18735
18827
  return this.scene.crosshairOverride ? { ...this.scene.crosshairOverride } : null;
18828
+ case "drawingsInteractive":
18829
+ return this.drawingsInteractive;
18830
+ case "priceAxisTicks":
18831
+ return this.priceAxisTicks.hook;
18736
18832
  case "keyboard":
18737
18833
  return this.keyboardEnabled;
18738
18834
  case "historyChords":
@@ -19406,6 +19502,12 @@ var NativeRenderer = class {
19406
19502
  Object.assign(this.drawingsCanvas.style, { position: "absolute", inset: "0", width: "100%", height: "100%", pointerEvents: "none" });
19407
19503
  this.cursorCanvas = document.createElement("canvas");
19408
19504
  Object.assign(this.cursorCanvas.style, { position: "absolute", inset: "0", width: "100%", height: "100%", pointerEvents: "none" });
19505
+ this.shadeRightEl = document.createElement("div");
19506
+ this.shadeRightEl.className = "vela-shade-right";
19507
+ this.shadeRightEl.setAttribute("aria-hidden", "true");
19508
+ this.shadeRightEl.hidden = true;
19509
+ Object.assign(this.shadeRightEl.style, { position: "absolute", top: "0", left: "0", width: "0", height: "0", pointerEvents: "none", display: "none" });
19510
+ this.shadeRightSig = "";
19409
19511
  this.overlayRoot = document.createElement("div");
19410
19512
  Object.assign(this.overlayRoot.style, { position: "absolute", inset: "0", pointerEvents: "none" });
19411
19513
  this.plot = document.createElement("div");
@@ -19413,7 +19515,7 @@ var NativeRenderer = class {
19413
19515
  this.extLayers = rendererLayers().map((def) => ({ def, instance: def.create(), canvas: this.createLayerCanvas(), channel: def.id, owner: null }));
19414
19516
  const below = this.extLayers.filter((l) => l.def.placement === "below-data").map((l) => l.canvas);
19415
19517
  const above = this.extLayers.filter((l) => l.def.placement !== "below-data").map((l) => l.canvas);
19416
- this.plot.append(this.backdropCanvas, ...below, this.dataCanvas, this.volumeCanvas, this.vpvrCanvas, ...above, this.chromeCanvas, this.drawingsCanvas, this.cursorCanvas, this.overlayRoot);
19518
+ this.plot.append(this.backdropCanvas, ...below, this.dataCanvas, this.volumeCanvas, this.vpvrCanvas, ...above, this.chromeCanvas, this.drawingsCanvas, this.shadeRightEl, this.cursorCanvas, this.overlayRoot);
19417
19519
  this.layerOrderSig = "";
19418
19520
  this.wrapper.appendChild(this.plot);
19419
19521
  this.factoryConfig = this.getConfig();
@@ -19471,13 +19573,14 @@ var NativeRenderer = class {
19471
19573
  drawingsPointerDown: (x, y, snap, shift2, mod) => this.userDrawings?.pointerDown(x, y, snap, shift2, mod),
19472
19574
  drawingsPointerMove: (x, y, snap, shift2, mod) => this.userDrawings?.pointerMove(x, y, snap, shift2, mod),
19473
19575
  drawingsPointerUp: (x, y, snap) => this.userDrawings?.pointerUp(x, y, snap),
19474
- drawingsCursor: (x, y) => this.userDrawings?.cursorAt(x, y) ?? (this.chrome.markGlyphAt(x, y) ? "pointer" : null),
19576
+ drawingsCursor: (x, y) => (this.drawingsInteractive ? this.userDrawings?.cursorAt(x, y) : null) ?? (this.chrome.markGlyphAt(x, y) ? "pointer" : null),
19475
19577
  drawingsDblClick: (x, y) => this.userDrawings?.dblClick(x, y) ?? false,
19476
19578
  drawingsClearTransient: () => this.userDrawings?.clearTransient()
19477
19579
  });
19478
19580
  this.input.rightEdgeZoom = this.zoomAnchorMode === "right";
19479
19581
  this.input.axisDrag = this.axisDragEnabled;
19480
19582
  this.input.paneResize = this.paneResizeEnabled;
19583
+ this.input.drawings = this.drawingsInteractive;
19481
19584
  this.input.attach(this.dataCanvas);
19482
19585
  if (this.settingsEnabled) this.setSettingsEnabled(true);
19483
19586
  this.syncCountdownTimer();
@@ -19786,6 +19889,8 @@ var NativeRenderer = class {
19786
19889
  this.backend.destroy();
19787
19890
  this.chrome.destroy();
19788
19891
  this.crosshairLayer.destroy();
19892
+ this.shadeRightEl?.remove();
19893
+ this.shadeRightEl = null;
19789
19894
  this.attributionEl?.remove();
19790
19895
  this.attributionEl = null;
19791
19896
  this.mountContainer?.style.removeProperty("--vela-toolbar-gutter");
@@ -20132,14 +20237,21 @@ var NativeRenderer = class {
20132
20237
  this.priceStyleCbs.add(cb);
20133
20238
  return () => this.priceStyleCbs.delete(cb);
20134
20239
  }
20240
+ onPriceStyleWillChange(cb) {
20241
+ this.priceStyleWillChangeCbs.add(cb);
20242
+ return () => this.priceStyleWillChangeCbs.delete(cb);
20243
+ }
20135
20244
  /**
20136
20245
  * THE single write path for the base price style at runtime (feature set / settings dialog /
20137
- * config template — the constructor seeds the field directly, pre-listeners). Updates the
20138
- * scene, eases any reveal layer toward the new style's target, and notifies the core —
20139
- * which owns the DATA side of styles that need one (a chart type's SeriesDataEngine).
20246
+ * config template — the constructor seeds the field directly, pre-listeners). Announces the
20247
+ * switch while the scene still holds the old style (a listener may paint/capture that frame),
20248
+ * then updates the scene, eases any reveal layer toward the new style's target, and notifies
20249
+ * the core — which owns the DATA side of styles that need one (a chart type's SeriesDataEngine).
20140
20250
  */
20141
20251
  setPriceStyle(style) {
20142
20252
  if (style === this.scene.priceStyle) return;
20253
+ const from = this.scene.priceStyle;
20254
+ for (const cb of this.priceStyleWillChangeCbs) cb(from, style);
20143
20255
  this.scene.priceStyle = style;
20144
20256
  this.scene.basePainting = basePaintingOf(style);
20145
20257
  this.scene.candleOverride = candleOverrideFor(style, this.scene.style.chartTypes);
@@ -20369,7 +20481,7 @@ var NativeRenderer = class {
20369
20481
  if (this.easeLiveBar(dtMs)) active = true;
20370
20482
  this.skeletonClockMs += dtMs;
20371
20483
  this.paintData();
20372
- this.crosshairLayer.render(this.scene, this.coords, this.theme, this.hoverSeparatorY, this.externalCrossPx());
20484
+ this.renderCrosshairLayer();
20373
20485
  this.updateLegendValues();
20374
20486
  this.emitViewportChange();
20375
20487
  return active;
@@ -20944,10 +21056,31 @@ var NativeRenderer = class {
20944
21056
  this.chrome.render(this.scene, this.coords, this.theme, this.axisSurface());
20945
21057
  this.trackMarkPopover();
20946
21058
  }
20947
- this.crosshairLayer.render(this.scene, this.coords, this.theme, this.hoverSeparatorY, this.externalCrossPx());
21059
+ this.renderCrosshairLayer();
20948
21060
  if (!repaintsData(level) && this.paintedData) this.repaintCursorLayers();
20949
21061
  this.updateLegendValues();
20950
21062
  }
21063
+ /** Repaint the L2 crosshair canvas and keep the `.vela-shade-right` element on the veil it painted. */
21064
+ renderCrosshairLayer() {
21065
+ this.crosshairLayer.render(this.scene, this.coords, this.theme, this.hoverSeparatorY, this.externalCrossPx());
21066
+ this.syncShadeRight();
21067
+ }
21068
+ /** Position (or hide) the `.vela-shade-right` element over the veil of the last crosshair frame. */
21069
+ syncShadeRight() {
21070
+ const el = this.shadeRightEl;
21071
+ if (!el) return;
21072
+ const area = this.crosshairLayer.shadeRightArea;
21073
+ const sig = area ? `${area.x},${area.width},${area.height}` : "";
21074
+ if (sig === this.shadeRightSig) return;
21075
+ this.shadeRightSig = sig;
21076
+ if (!area) {
21077
+ el.hidden = true;
21078
+ el.style.display = "none";
21079
+ return;
21080
+ }
21081
+ Object.assign(el.style, { left: `${area.x}px`, width: `${area.width}px`, height: `${area.height}px`, display: "" });
21082
+ el.hidden = false;
21083
+ }
20951
21084
  /** Repaint the SDK layers that opted into cursor tracking (their own canvas only). */
20952
21085
  repaintCursorLayers() {
20953
21086
  const pane = this.scene.panes.get(PRICE_PANE_ID);
@@ -21741,7 +21874,7 @@ var NativeRenderer = class {
21741
21874
  if (this.animator.active) {
21742
21875
  this.computeScales();
21743
21876
  this.paintData();
21744
- this.crosshairLayer.render(this.scene, this.coords, this.theme, this.hoverSeparatorY, this.externalCrossPx());
21877
+ this.renderCrosshairLayer();
21745
21878
  } else {
21746
21879
  this.scheduler.flushNow(4 /* Full */);
21747
21880
  }
@@ -22381,6 +22514,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
22381
22514
  this.activeEngineStyle = null;
22382
22515
  /** The chart's current price style (tracked from the renderer's change events + initial read). */
22383
22516
  this.priceStyle = "candles";
22517
+ this.priceStyleWillChangeUnsub = null;
22384
22518
  this.unresolvedUnsub = null;
22385
22519
  /** Latest chart visible range (left/right bar times), fed to viewport-dependent scripts. */
22386
22520
  this.visibleRange = null;
@@ -22479,6 +22613,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
22479
22613
  this.renderer.onThemeSelect?.((name) => this.setTheme(resolveTheme(name)));
22480
22614
  this.viewportUnsub = this.renderer.onViewportChange((range) => this.onViewportChange(range));
22481
22615
  this.renderer.onPriceStyleChange?.((style) => this.syncPriceStyle(style));
22616
+ this.priceStyleWillChangeUnsub = this.renderer.onPriceStyleWillChange?.((from, to) => this.events.emit("priceStyle:change", { from, to })) ?? null;
22482
22617
  const initialStyle = this.renderer.readFeature("priceStyle");
22483
22618
  if (typeof initialStyle === "string") this.priceStyle = initialStyle;
22484
22619
  this.barTransform = barTransformFor(initialStyle);
@@ -24009,6 +24144,8 @@ var EngineOrchestrator = class _EngineOrchestrator {
24009
24144
  if (this.viewportTimer != null) clearTimeout(this.viewportTimer);
24010
24145
  this.viewportUnsub?.();
24011
24146
  this.paneActionUnsub?.();
24147
+ this.priceStyleWillChangeUnsub?.();
24148
+ this.priceStyleWillChangeUnsub = null;
24012
24149
  for (const record of this.registry.all()) {
24013
24150
  this.settleCode(record, { ok: false, error: new Error("[vela] updateCode \u2014 the chart was destroyed.") });
24014
24151
  record.session?.stop();
@@ -28672,7 +28809,8 @@ var Vela = class {
28672
28809
  glow: options.glow ?? 0,
28673
28810
  upColor: options.upColor ?? BULLISH,
28674
28811
  downColor: options.downColor ?? BEARISH,
28675
- priceStyle: options.priceStyle ?? "candles"
28812
+ priceStyle: options.priceStyle ?? "candles",
28813
+ priceAxisTicks: options.priceAxis?.ticks ?? null
28676
28814
  };
28677
28815
  const RendererClass = options.renderer ?? NativeRenderer;
28678
28816
  if (typeof RendererClass !== "function") {
@@ -29016,4 +29154,4 @@ function resolveElement(container) {
29016
29154
  return element;
29017
29155
  }
29018
29156
 
29019
- export { BUILTIN_PRICE_STYLES, BarStore, CachingDataFeed, DARK_THEME, DataControl, DrawingStore, DrawingToolbar, DrawingsControl, LEGEND_AT_TOP_ATTR, LIGHT_THEME, MarksControl, MultiProviderFeed, NativeRenderer, RendererControl, ReplayControl, SecondClock, TIMEZONES, TypedEventBus, Vela, applyAttributionMarkTheme, buildToolbar, createAttributionMark, createCustomMark, defaultMemberOf, defaultToolbar, groupKeyOf, groupMembers, isExchangeTimezone, isGroupRow, normalizeSession, normalizeTimezone, parseSymbol, priceStyleIds, registerBuiltinChartTypes, resolveTheme, resolveTimezone, sharedBarStore, timeframeToMs, timezoneMenuRows, tzButtonLabel, tzMenuLabel, tzOffset };
29157
+ export { BUILTIN_PRICE_STYLES, BarStore, CANDLE_OVERRIDE_KEYS, CachingDataFeed, DARK_THEME, DataControl, DrawingStore, DrawingToolbar, DrawingsControl, LEGEND_AT_TOP_ATTR, LIGHT_THEME, MarksControl, MultiProviderFeed, NativeRenderer, RendererControl, ReplayControl, SecondClock, TypedEventBus, Vela, applyAttributionMarkTheme, buildToolbar, createAttributionMark, createCustomMark, defaultMemberOf, defaultToolbar, groupKeyOf, groupMembers, isGroupRow, normalizeSession, parseSymbol, priceStyleIds, registerBuiltinChartTypes, resolveTheme, sharedBarStore, timeframeToMs };