@luxalgo/vela 0.6.3 → 0.6.5

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 (45) hide show
  1. package/dist/{DataProvider-DHX4x6-r.d.ts → DataProvider-BmHkcwvJ.d.ts} +1 -1
  2. package/dist/{DataProvider-CNmk84SH.d.cts → DataProvider-DrN7ZIou.d.cts} +1 -1
  3. package/dist/{chunk-TP56QRMK.js → chunk-2R7BANEM.js} +1 -1
  4. package/dist/{chunk-7Y7CJ7EN.js → chunk-BEJ57HP4.js} +8 -1
  5. package/dist/{chunk-7D6YIF34.js → chunk-FQBT4NFM.js} +431 -74
  6. package/dist/{chunk-U5KCQHAC.js → chunk-N6MBJHMV.js} +129 -41
  7. package/dist/{chunk-QHZ7IXFL.js → chunk-OICPLNU7.js} +59 -9
  8. package/dist/{contributions-DDpv7hEL.d.cts → contributions-2bEmCF9S.d.cts} +2 -2
  9. package/dist/{contributions-ciV6Neyd.d.ts → contributions-DatoAzMx.d.ts} +2 -2
  10. package/dist/{history-CFqZm5re.d.ts → history-BmyjaVir.d.cts} +6 -6
  11. package/dist/{history-ChoT34nz.d.cts → history-CvOtsjT5.d.ts} +6 -6
  12. package/dist/index.cjs +500 -85
  13. package/dist/index.d.cts +63 -9
  14. package/dist/index.d.ts +63 -9
  15. package/dist/index.js +4 -4
  16. package/dist/{options-BqGeFHtp.d.ts → options-YdiaaVjt.d.cts} +20 -1
  17. package/dist/{options-BqGeFHtp.d.cts → options-YdiaaVjt.d.ts} +20 -1
  18. package/dist/{plugin-C97gUCVf.d.ts → plugin-Bcone6Vh.d.ts} +9 -5
  19. package/dist/{plugin-CSb_sTiN.d.cts → plugin-DO_DX0gp.d.cts} +9 -5
  20. package/dist/plugin.cjs +8 -0
  21. package/dist/plugin.d.cts +4 -4
  22. package/dist/plugin.d.ts +4 -4
  23. package/dist/plugin.js +2 -2
  24. package/dist/providers/binance.d.cts +2 -2
  25. package/dist/providers/binance.d.ts +2 -2
  26. package/dist/providers/coinbase.d.cts +2 -2
  27. package/dist/providers/coinbase.d.ts +2 -2
  28. package/dist/providers/hyperliquid.d.cts +2 -2
  29. package/dist/providers/hyperliquid.d.ts +2 -2
  30. package/dist/ui.cjs +59 -9
  31. package/dist/ui.d.cts +10 -2
  32. package/dist/ui.d.ts +10 -2
  33. package/dist/ui.js +2 -2
  34. package/dist/vela.global.js +500 -85
  35. package/dist/vela.global.min.js +84 -47
  36. package/dist/widget.cjs +801 -227
  37. package/dist/widget.d.cts +34 -8
  38. package/dist/widget.d.ts +34 -8
  39. package/dist/widget.js +145 -73
  40. package/dist/workspace.cjs +756 -178
  41. package/dist/workspace.d.cts +29 -5
  42. package/dist/workspace.d.ts +29 -5
  43. package/dist/workspace.js +143 -67
  44. package/package.json +1 -1
  45. /package/dist/{chunk-Q3XQHLIH.js → chunk-AOGZBKUE.js} +0 -0
@@ -1,7 +1,7 @@
1
- import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel } from './chunk-7D6YIF34.js';
2
- import { chartType, widgetActions, SidePanel, sidePanels, DEFAULT_PANEL_ORDER, getDrawingType } from './chunk-7Y7CJ7EN.js';
3
- import { Tooltip, Drawer } from './chunk-TP56QRMK.js';
4
- import { Menu, Dialog } from './chunk-QHZ7IXFL.js';
1
+ import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel } from './chunk-FQBT4NFM.js';
2
+ import { chartType, widgetActions, SidePanel, sidePanels, DEFAULT_PANEL_ORDER, getDrawingType } from './chunk-BEJ57HP4.js';
3
+ import { Tooltip, Drawer } from './chunk-2R7BANEM.js';
4
+ import { Menu, Dialog } from './chunk-OICPLNU7.js';
5
5
  import { iconMarkup, registerIcon, injectStyles, iconEl, SESSION_PRE, SESSION_POST, SESSION_OFF, icon, categoricalColor } from './chunk-PN5KWFZ4.js';
6
6
 
7
7
  // src/widget/timeframe.ts
@@ -492,12 +492,14 @@ var CSS2 = `
492
492
  color: var(--vela-fg-muted);
493
493
  }
494
494
  .vela-widget-tf-caret:hover { background: var(--vela-hover); color: var(--vela-fg-bright); }
495
+ /* The merged trigger is a plain button (hover feedback only) \u2014 the highlight
496
+ background marks the CURRENT chip among favorites, and a lone trigger with a
497
+ permanent highlight would read as stuck-pressed. */
495
498
  .vela-widget-tf-caret[data-solo='1'] {
496
499
  width: auto;
497
500
  padding: 0 6px 0 9px;
498
501
  gap: 4px;
499
502
  color: var(--vela-fg-bright);
500
- background: var(--vela-hover-strong);
501
503
  font-size: 13px;
502
504
  font-weight: 550;
503
505
  white-space: nowrap;
@@ -1526,7 +1528,8 @@ var Bottombar = class {
1526
1528
  const session = doc.createElement("span");
1527
1529
  session.className = "vela-bb-session";
1528
1530
  this.sessionEl = session;
1529
- session.title = "Session \u2014 stocks & ETFs only";
1531
+ session.style.display = "none";
1532
+ session.title = "Session \u2014 regular (RTH) vs extended (ETH) hours";
1530
1533
  for (const [key, label] of [["regular", "RTH"], ["extended", "ETH"]]) {
1531
1534
  const b = doc.createElement("button");
1532
1535
  b.className = "vela-bb-session-btn" + (key === "regular" ? " is-active" : "");
@@ -1577,15 +1580,15 @@ var Bottombar = class {
1577
1580
  }
1578
1581
  /**
1579
1582
  * Reflect the ACTIVE chart's session posture. `enabled: false` (a continuous
1580
- * market, or metadata not landed yet) shows the disabled RTH-active stub the
1581
- * pre-session-model look, byte-for-byte. Enabled, the chips become clickable and
1582
- * the active one tracks the chart's current session.
1583
+ * market, or metadata not landed yet) HIDES the toggle entirelyRTH/ETH is
1584
+ * meaningless there. Enabled, the chips appear and the active one tracks the
1585
+ * chart's current session.
1583
1586
  */
1584
1587
  setSession(state) {
1585
- if (this.sessionEl) this.sessionEl.title = state.enabled ? "Session \u2014 regular (RTH) vs extended (ETH) hours" : "Session \u2014 stocks & ETFs only";
1588
+ if (this.sessionEl) this.sessionEl.style.display = state.enabled ? "" : "none";
1586
1589
  for (const [key, b] of this.sessionButtons) {
1587
1590
  b.disabled = !state.enabled;
1588
- b.classList.toggle("is-active", state.enabled ? key === state.session : key === "regular");
1591
+ b.classList.toggle("is-active", key === (state.enabled ? state.session : "regular"));
1589
1592
  }
1590
1593
  }
1591
1594
  destroy() {
@@ -1748,6 +1751,7 @@ var CSS6 = `
1748
1751
  .vela-sp-badge[data-p='hyperliquid'] { color: #50d2c1; } /* palette-exempt: venue brand mark */
1749
1752
  .vela-sp-empty { padding: var(--vela-space-3); color: var(--vela-fg-muted); text-align: center; }
1750
1753
  `;
1754
+ var PAGE = 100;
1751
1755
  var SymbolPicker = class {
1752
1756
  constructor(opts) {
1753
1757
  this.source = () => [];
@@ -1755,6 +1759,7 @@ var SymbolPicker = class {
1755
1759
  this.highlighted = 0;
1756
1760
  this.seed = "";
1757
1761
  this.activeTab = "All";
1762
+ this.visible = PAGE;
1758
1763
  const doc = (opts.host ?? document.body).ownerDocument;
1759
1764
  injectStyles(STYLE_ID6, CSS6, doc);
1760
1765
  this.input = doc.createElement("input");
@@ -1781,6 +1786,12 @@ var SymbolPicker = class {
1781
1786
  }
1782
1787
  this.list = doc.createElement("div");
1783
1788
  this.list.className = "vela-sp-list";
1789
+ this.list.addEventListener("scroll", () => {
1790
+ if (this.rows.length < this.visible) return;
1791
+ if (this.list.scrollTop + this.list.clientHeight < this.list.scrollHeight - 200) return;
1792
+ this.visible += PAGE;
1793
+ this.grow();
1794
+ });
1784
1795
  this.dialog = new Dialog({
1785
1796
  title: "Symbol Search",
1786
1797
  host: opts.host,
@@ -1846,11 +1857,15 @@ var SymbolPicker = class {
1846
1857
  } else delete el.dataset.highlighted;
1847
1858
  });
1848
1859
  }
1849
- refresh() {
1850
- const doc = this.list.ownerDocument;
1860
+ computeRows() {
1851
1861
  const TAB_TYPES = { Crypto: ["crypto"], Stocks: ["stock"], ETFs: ["etf"], Forex: ["forex"], Commodities: ["commodity"] };
1852
1862
  const pool = this.activeTab === "All" ? this.source() : this.source().filter((s) => TAB_TYPES[this.activeTab]?.includes((s.type ?? "").toLowerCase()) || this.activeTab === "Crypto" && (s.type ?? "").toLowerCase() === "futures");
1853
- this.rows = filterSymbols(pool, this.input.value);
1863
+ return filterSymbols(pool, this.input.value, this.visible);
1864
+ }
1865
+ refresh() {
1866
+ const doc = this.list.ownerDocument;
1867
+ this.visible = PAGE;
1868
+ this.rows = this.computeRows();
1854
1869
  this.highlighted = 0;
1855
1870
  this.list.replaceChildren();
1856
1871
  if (!this.rows.length) {
@@ -1860,34 +1875,42 @@ var SymbolPicker = class {
1860
1875
  this.list.appendChild(empty);
1861
1876
  return;
1862
1877
  }
1863
- for (const s of this.rows) {
1864
- const row = doc.createElement("div");
1865
- row.className = "vela-sp-row";
1866
- row.dataset.ticker = s.ticker;
1867
- const venue = s.prefix ?? s.provider;
1868
- if (venue) row.dataset.venue = venue;
1869
- const av = tickerIconEl(doc, baseOf(s), s.ticker, "vela-sp-avatar");
1870
- const main = doc.createElement("span");
1871
- main.className = "vela-sp-main";
1872
- const t = doc.createElement("span");
1873
- t.className = "vela-sp-ticker";
1874
- t.textContent = s.ticker;
1875
- const d = doc.createElement("span");
1876
- d.className = "vela-sp-desc";
1877
- d.textContent = s.description ?? (s.type ?? "");
1878
- main.append(t, d);
1879
- row.append(av, main);
1880
- if (venue) {
1881
- const badge = doc.createElement("span");
1882
- badge.className = "vela-sp-badge";
1883
- badge.dataset.p = s.provider ?? venue;
1884
- badge.textContent = venue;
1885
- row.appendChild(badge);
1886
- }
1887
- this.list.appendChild(row);
1888
- }
1878
+ for (const s of this.rows) this.list.appendChild(this.rowEl(s));
1889
1879
  this.renderHighlight();
1890
1880
  }
1881
+ /** Append the page the grown `visible` just uncovered — rows already on screen stay put. */
1882
+ grow() {
1883
+ const already = this.rows.length;
1884
+ this.rows = this.computeRows();
1885
+ for (const s of this.rows.slice(already)) this.list.appendChild(this.rowEl(s));
1886
+ }
1887
+ rowEl(s) {
1888
+ const doc = this.list.ownerDocument;
1889
+ const row = doc.createElement("div");
1890
+ row.className = "vela-sp-row";
1891
+ row.dataset.ticker = s.ticker;
1892
+ const venue = s.prefix ?? s.provider;
1893
+ if (venue) row.dataset.venue = venue;
1894
+ const av = tickerIconEl(doc, baseOf(s), s.ticker, "vela-sp-avatar");
1895
+ const main = doc.createElement("span");
1896
+ main.className = "vela-sp-main";
1897
+ const t = doc.createElement("span");
1898
+ t.className = "vela-sp-ticker";
1899
+ t.textContent = s.ticker;
1900
+ const d = doc.createElement("span");
1901
+ d.className = "vela-sp-desc";
1902
+ d.textContent = s.description ?? (s.type ?? "");
1903
+ main.append(t, d);
1904
+ row.append(av, main);
1905
+ if (venue) {
1906
+ const badge = doc.createElement("span");
1907
+ badge.className = "vela-sp-badge";
1908
+ badge.dataset.p = s.provider ?? venue;
1909
+ badge.textContent = venue;
1910
+ row.appendChild(badge);
1911
+ }
1912
+ return row;
1913
+ }
1891
1914
  };
1892
1915
 
1893
1916
  // src/widget/object-tree-model.ts
@@ -3313,6 +3336,9 @@ var CSS8 = `
3313
3336
  letter-spacing: 0.08em;
3314
3337
  }
3315
3338
  .vela-dw-group:first-child { border-top: none; margin-top: 0; padding-top: 8px; }
3339
+ /* The readout is DATA, not chrome: selectable (an exception to the UI-wide
3340
+ user-select:none) so values can be copied out. The panel header stays chrome. */
3341
+ .vela-dw-group, .vela-dw-row { user-select: text; -webkit-user-select: text; cursor: text; }
3316
3342
  .vela-dw-row {
3317
3343
  display: flex;
3318
3344
  align-items: center;
@@ -3775,6 +3801,9 @@ var ChartContextMenu = class {
3775
3801
  host,
3776
3802
  items: [],
3777
3803
  placement: "bottom-start",
3804
+ // Pointer-anchored action menu: checked state reads as a leading ✓, not a
3805
+ // washed row (which would read as hover in a menu with no trigger button).
3806
+ checkmarks: true,
3778
3807
  onSelect: (id) => this.run(id)
3779
3808
  });
3780
3809
  host.addEventListener("contextmenu", this.onContextMenu);
@@ -4506,6 +4535,65 @@ var MarketStatusTracker = class {
4506
4535
  }
4507
4536
  };
4508
4537
 
4538
+ // src/widget/session-shading.ts
4539
+ function deriveSessionZones(regular, extended) {
4540
+ const pre = [];
4541
+ const post = [];
4542
+ for (const [extStart, extEnd] of extended) {
4543
+ const inside = regular.filter(([s, e]) => e > extStart && s < extEnd).sort((a, b) => a[0] - b[0]);
4544
+ let cursor = extStart;
4545
+ for (const [regStart, regEnd] of inside) {
4546
+ if (regStart > cursor) pre.push([cursor, Math.min(regStart, extEnd)]);
4547
+ cursor = Math.max(cursor, regEnd);
4548
+ }
4549
+ if (cursor < extEnd) post.push([cursor, extEnd]);
4550
+ }
4551
+ return { pre, post };
4552
+ }
4553
+ var FETCH_AHEAD_MS2 = 10 * 864e5;
4554
+ var MIN_LOOKBACK_MS = 3 * 864e5;
4555
+ var MAX_LOOKBACK_MS = 120 * 864e5;
4556
+ var SessionShadingTracker = class {
4557
+ constructor(onZones) {
4558
+ this.onZones = onZones;
4559
+ /** Invalidates detached async work — bumped by every track()/stop(). */
4560
+ this.epoch = 0;
4561
+ }
4562
+ /** (Re)bind to a chart's data surface + market and evaluate once. */
4563
+ track(data, symbol, opts) {
4564
+ const my = ++this.epoch;
4565
+ void this.evaluate(my, data, symbol, opts);
4566
+ }
4567
+ stop() {
4568
+ this.epoch += 1;
4569
+ }
4570
+ async evaluate(my, data, symbol, opts) {
4571
+ const resolved = data.resolve(symbol);
4572
+ const provider = resolved ? data.providerInstance(resolved.provider) : void 0;
4573
+ const si = await data.symbolInfo(symbol).catch(() => void 0);
4574
+ if (my !== this.epoch) return;
4575
+ const hasSessions = typeof si?.session === "string" && si.session !== "" && si.session !== "24x7";
4576
+ if (!provider?.getCalendar || !hasSessions || !resolved) {
4577
+ this.onZones(null);
4578
+ return;
4579
+ }
4580
+ if (opts.session !== "extended") {
4581
+ this.onZones({ pre: [], post: [] });
4582
+ return;
4583
+ }
4584
+ const now = Date.now();
4585
+ const lookback = Math.max(MIN_LOOKBACK_MS, Math.min(MAX_LOOKBACK_MS, opts.lookbackMs));
4586
+ const range = { from: now - lookback, to: now + FETCH_AHEAD_MS2 };
4587
+ const [regular, extended] = await Promise.all([
4588
+ provider.getCalendar(resolved.ticker, { ...range, session: "regular" }).catch(() => null),
4589
+ provider.getCalendar(resolved.ticker, { ...range, session: "extended" }).catch(() => null)
4590
+ ]);
4591
+ if (my !== this.epoch) return;
4592
+ if (!regular || !extended) return;
4593
+ this.onZones(deriveSessionZones(regular, extended));
4594
+ }
4595
+ };
4596
+
4509
4597
  // src/widget/layout-mode.ts
4510
4598
  var MOBILE_BREAKPOINT_PX = 640;
4511
4599
  var COARSE_BREAKPOINT_PX = 920;
@@ -5872,4 +5960,4 @@ var Toast = class {
5872
5960
  }
5873
5961
  };
5874
5962
 
5875
- export { Bottombar, ChartContextMenu, DataWindow, DrawingPill, DrawingsDrawer, Glider, IndicatorPicker, LayoutModeController, MarketStatusTracker, MobileBar, MoreDrawer, ObjectTree, PAN_FAST, PanelDock, PriceScaleDrawer, RANGE_PRESETS, ShortcutsHelp, Statusline, SymbolPicker, TimeframeDrawer, TimeframeQuick, TimezoneDrawer, Toast, Topbar, Watermark, WidgetHistory, ZOOM_IN, ZOOM_OUT, dataWindowSections, decimalsFor, decodeState, encodeState, filterSymbols, fmtChange, fmtPrice, indicatorLedger, legacyWidgetState, loadPersisted, localStorageAdapter, normalizeSession, parsePersisted, parseTimeframe, prefixedSymbol, priceStyleIcon, priceStyleLabel, resolveIndicators, sanitizeState, savePersisted, statuslineInkOf, timeframeLabel, timeframeMs, toolShortcutHints };
5963
+ export { Bottombar, ChartContextMenu, DataWindow, DrawingPill, DrawingsDrawer, Glider, IndicatorPicker, LayoutModeController, MarketStatusTracker, MobileBar, MoreDrawer, ObjectTree, PAN_FAST, PanelDock, PriceScaleDrawer, RANGE_PRESETS, SessionShadingTracker, ShortcutsHelp, Statusline, SymbolPicker, TimeframeDrawer, TimeframeQuick, TimezoneDrawer, Toast, Topbar, Watermark, WidgetHistory, ZOOM_IN, ZOOM_OUT, dataWindowSections, decimalsFor, decodeState, encodeState, filterSymbols, fmtChange, fmtPrice, indicatorLedger, legacyWidgetState, loadPersisted, localStorageAdapter, normalizeSession, parsePersisted, parseTimeframe, prefixedSymbol, priceStyleIcon, priceStyleLabel, resolveIndicators, sanitizeState, savePersisted, statuslineInkOf, timeframeLabel, timeframeMs, toolShortcutHints };
@@ -86,6 +86,23 @@ var MENU_CSS = `
86
86
  background: var(--vela-hover-strong);
87
87
  color: var(--vela-fg-bright);
88
88
  }
89
+ /* Checkmark mode (context/action menus): every row reserves the leading mark column so
90
+ labels align; a checked row fills it with a \u2713 and brightens its ink \u2014 the row surface
91
+ stays free for the hover wash. */
92
+ .vela-menu-item .vela-menu-mark {
93
+ width: 14px;
94
+ flex: none;
95
+ display: inline-flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ }
99
+ .vela-menu-item .vela-menu-mark .vela-icon {
100
+ width: 14px;
101
+ height: 14px;
102
+ font-size: 14px;
103
+ color: var(--vela-fg-bright);
104
+ }
105
+ .vela-menu-item[data-checkmark] { color: var(--vela-fg-bright); }
89
106
  /* Switch rows (boolean settings in a dropdown): a right-aligned toggle pill \u2014 the
90
107
  same control language as the settings dialog's toggles. */
91
108
  .vela-menu-switch {
@@ -154,6 +171,7 @@ var Surface = class _Surface {
154
171
  this.host = opts.host;
155
172
  this.onSelect = opts.onSelect;
156
173
  this.onFavorite = opts.onFavorite;
174
+ this.checkmarks = opts.checkmarks === true;
157
175
  this.positioner = doc.createElement("div");
158
176
  this.positioner.className = "vela-ui-layer";
159
177
  this.list = doc.createElement("ul");
@@ -232,6 +250,7 @@ var Surface = class _Surface {
232
250
  build() {
233
251
  const doc = this.doc;
234
252
  this.list.replaceChildren();
253
+ const markable = this.checkmarks && this.items.some((i) => !(i.submenu && i.submenu.length > 0) && !i.toggle && i.checked !== void 0);
235
254
  for (const item of this.items) {
236
255
  if (item.separatorBefore) {
237
256
  const sep = doc.createElement("li");
@@ -245,7 +264,16 @@ var Surface = class _Surface {
245
264
  li.dataset.veiId = item.id;
246
265
  if (item.toggle) {
247
266
  li.dataset.toggle = "1";
248
- } else if (!branch && item.checked) {
267
+ }
268
+ if (markable) {
269
+ const mark = doc.createElement("span");
270
+ mark.className = "vela-menu-mark";
271
+ if (!branch && !item.toggle && item.checked) {
272
+ mark.appendChild(iconEl("check", doc));
273
+ li.dataset.checkmark = "1";
274
+ }
275
+ li.appendChild(mark);
276
+ } else if (!branch && !item.toggle && item.checked) {
249
277
  li.dataset.checked = "1";
250
278
  }
251
279
  if (item.icon) li.appendChild(iconEl(item.icon, doc));
@@ -294,6 +322,7 @@ var Surface = class _Surface {
294
322
  placement: "right-start",
295
323
  onSelect: this.onSelect,
296
324
  onFavorite: this.onFavorite,
325
+ checkmarks: this.checkmarks,
297
326
  id: `${this.mid}--${item.id}`
298
327
  });
299
328
  sub.setItems(item.submenu ?? []);
@@ -318,7 +347,8 @@ var Menu = class {
318
347
  triggerId: opts.triggerId,
319
348
  id: opts.id,
320
349
  minWidth: opts.minWidth,
321
- onFavorite: opts.onFavorite
350
+ onFavorite: opts.onFavorite,
351
+ checkmarks: opts.checkmarks
322
352
  });
323
353
  this.root.setItems(opts.items);
324
354
  }
@@ -435,8 +465,13 @@ var STATIC_CSS = `
435
465
  ${STATIC_DECLS}
436
466
  font-family: var(--vela-font, -apple-system, system-ui, sans-serif);
437
467
  box-sizing: border-box;
468
+ /* Chrome text (titles, buttons, menus, readouts) is UI, not copy \u2014 never selectable. */
469
+ user-select: none;
470
+ -webkit-user-select: none;
438
471
  }
439
472
  .vela-ui *, .vela-ui-layer * { box-sizing: border-box; }
473
+ /* Text ENTRY is the one exception: selection is part of editing. */
474
+ .vela-ui :is(input, textarea), .vela-ui-layer :is(input, textarea) { user-select: text; -webkit-user-select: text; }
440
475
  .vela-icon { display: inline-flex; align-items: center; flex: none; }
441
476
  .vela-icon svg { display: block; }
442
477
  `;
@@ -1438,6 +1473,9 @@ var NUMBER_CSS = `
1438
1473
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
1439
1474
  -moz-appearance: textfield;
1440
1475
  appearance: textfield;
1476
+ /* Selectable even under a user-select:none host (chart wrapper, .vela-ui). */
1477
+ user-select: text;
1478
+ -webkit-user-select: text;
1441
1479
  }
1442
1480
  .vela-num input::-webkit-inner-spin-button, .vela-num input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
1443
1481
  .vela-num input:hover { border-color: var(--vela-fg-muted); }
@@ -1650,6 +1688,9 @@ var TEXT_CSS = `
1650
1688
  overflow: hidden;
1651
1689
  text-overflow: ellipsis;
1652
1690
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
1691
+ /* Selectable even under a user-select:none host (chart wrapper, .vela-ui). */
1692
+ user-select: text;
1693
+ -webkit-user-select: text;
1653
1694
  }
1654
1695
  .vela-text-field:hover { border-color: var(--vela-fg-muted); }
1655
1696
  .vela-text-field:focus { border-color: var(--vela-focus); box-shadow: 0 0 0 3px var(--vela-focus-soft); }
@@ -1743,6 +1784,9 @@ var TEXTAREA_CSS = `
1743
1784
  resize: vertical;
1744
1785
  outline: none;
1745
1786
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
1787
+ /* Selectable even under a user-select:none host (chart wrapper, .vela-ui). */
1788
+ user-select: text;
1789
+ -webkit-user-select: text;
1746
1790
  }
1747
1791
  .vela-textarea-field:hover { border-color: var(--vela-fg-muted); }
1748
1792
  .vela-textarea-field:focus { border-color: var(--vela-focus); box-shadow: 0 0 0 3px var(--vela-focus-soft); }
@@ -2296,6 +2340,8 @@ var FIELD_CSS = `
2296
2340
  font-size: 14px;
2297
2341
  }
2298
2342
  .vela-field-label[data-size='sm'] { font-size: inherit; opacity: 0.85; }
2343
+ /* Titles are fully inert: spans, not label[for] \u2014 native labels propagate :hover and
2344
+ clicks onto their control, and both belong to the input alone. */
2299
2345
  .vela-field-cell { display: flex; align-items: center; gap: 8px; justify-self: start; }
2300
2346
  .vela-field-bool { display: flex; align-items: center; gap: 8px; min-height: 22px; }
2301
2347
  .vela-field-stacked { display: flex; flex-direction: column; gap: 8px; }
@@ -2354,11 +2400,17 @@ function fieldSeparator() {
2354
2400
  return el;
2355
2401
  }
2356
2402
  function labelEl(text, opts) {
2357
- const el = opts.id ? document.createElement("label") : document.createElement("span");
2358
- if (opts.id && el instanceof HTMLLabelElement) el.htmlFor = opts.id;
2403
+ const el = document.createElement("span");
2359
2404
  el.className = "vela-field-label";
2360
2405
  if (opts.size) el.dataset.size = opts.size;
2361
2406
  el.textContent = text;
2407
+ const id = opts.id;
2408
+ if (id) {
2409
+ el.id = `${id}--title`;
2410
+ queueMicrotask(() => {
2411
+ el.ownerDocument.getElementById(id)?.setAttribute("aria-labelledby", el.id);
2412
+ });
2413
+ }
2362
2414
  return el;
2363
2415
  }
2364
2416
  function asList(control) {
@@ -2387,9 +2439,7 @@ function fieldRow(opts) {
2387
2439
  it.className = "vela-field-inline-item";
2388
2440
  if (item.toggleFirst) it.style.flexDirection = "row-reverse";
2389
2441
  if (item.label) {
2390
- const lbl = labelEl(item.label, { id: item.id, size });
2391
- if (item.toggleFirst) lbl.style.cursor = "pointer";
2392
- it.appendChild(lbl);
2442
+ it.appendChild(labelEl(item.label, { id: item.id, size }));
2393
2443
  }
2394
2444
  if (item.fit) it.appendChild(item.control);
2395
2445
  else {
@@ -2414,7 +2464,7 @@ function fieldRow(opts) {
2414
2464
  tone: "bright",
2415
2465
  onChange: (v) => opts.toggle?.onChange(v)
2416
2466
  });
2417
- wrap2.append(sw.el, labelEl(opts.label, { size }));
2467
+ wrap2.append(sw.el, labelEl(opts.label, { id: opts.toggle?.id ?? opts.id, size }));
2418
2468
  if (opts.info) wrap2.appendChild(opts.info);
2419
2469
  if (opts.toggle?.get) {
2420
2470
  const get = opts.toggle.get;
@@ -2453,7 +2503,7 @@ function fieldRow(opts) {
2453
2503
  if (controls.length > 0) dimControls(controls, v);
2454
2504
  }
2455
2505
  });
2456
- left.append(sw.el, labelEl(opts.label, { size }));
2506
+ left.append(sw.el, labelEl(opts.label, { id: opts.toggle.id ?? opts.id, size }));
2457
2507
  wrap.appendChild(left);
2458
2508
  if (controls.length > 0) dimControls(controls, opts.toggle.checked);
2459
2509
  if (opts.toggle.get) {
@@ -1,5 +1,5 @@
1
- import { t as Millis, ad as InputSchema, ac as IndicatorMeta, P as PriceStyle, O as OHLCV, m as InputValue, k as IndicatorModel, j as MoveTarget, az as SeriesSpec, aa as Fill, B as Background, ar as PriceLine, a0 as DrawingLine, Y as DrawingBox, $ as DrawingLabel, a4 as DrawingPolyline, a1 as DrawingLinefill, a6 as DrawingTable, g as IndicatorStatus, a as VisibleRange, c as VelaTheme, S as SerializedDrawing, v as DrawingTypeKey, u as SnapMode, a2 as DrawingMode, I as IChartRenderer, R as RendererCapabilities, o as LegendActionView, U as Unsubscribe, C as CrosshairEvent, A as AxisLongPressEvent, r as DataWindowReadout, n as SymbolPickerFn, aL as PaneInfo, a9 as DrawingsOption, D as Drawing, b as VelaOptions, x as AddIndicatorOptions, an as MarketSwitch, am as MarketSnapshot, V as VisibleRangePreset, T as ThemeName } from './options-BqGeFHtp.cjs';
2
- import { S as SymbolInfo, B as BarRange, M as MarketDataFeed, D as DataProvider, P as ProviderInfo, a as SymbolDescriptor, b as ProviderCapabilities } from './DataProvider-CNmk84SH.cjs';
1
+ import { t as Millis, ae as InputSchema, ac as IndicatorMeta, P as PriceStyle, O as OHLCV, m as InputValue, k as IndicatorModel, j as MoveTarget, aB as SeriesSpec, aa as Fill, B as Background, at as PriceLine, a0 as DrawingLine, Y as DrawingBox, $ as DrawingLabel, a4 as DrawingPolyline, a1 as DrawingLinefill, a6 as DrawingTable, g as IndicatorStatus, a as VisibleRange, c as VelaTheme, S as SerializedDrawing, v as DrawingTypeKey, u as SnapMode, a2 as DrawingMode, I as IChartRenderer, R as RendererCapabilities, o as LegendActionView, U as Unsubscribe, C as CrosshairEvent, A as AxisLongPressEvent, r as DataWindowReadout, n as SymbolPickerFn, aO as PaneInfo, a9 as DrawingsOption, D as Drawing, b as VelaOptions, x as AddIndicatorOptions, ap as MarketSwitch, ao as MarketSnapshot, V as VisibleRangePreset, T as ThemeName } from './options-YdiaaVjt.cjs';
2
+ import { S as SymbolInfo, B as BarRange, M as MarketDataFeed, D as DataProvider, P as ProviderInfo, a as SymbolDescriptor, b as ProviderCapabilities } from './DataProvider-DrN7ZIou.cjs';
3
3
 
4
4
  /**
5
5
  * A strategy's broker state at ONE bar — the flat summary a host reads while a script
@@ -1,5 +1,5 @@
1
- import { t as Millis, ad as InputSchema, ac as IndicatorMeta, P as PriceStyle, O as OHLCV, m as InputValue, k as IndicatorModel, j as MoveTarget, az as SeriesSpec, aa as Fill, B as Background, ar as PriceLine, a0 as DrawingLine, Y as DrawingBox, $ as DrawingLabel, a4 as DrawingPolyline, a1 as DrawingLinefill, a6 as DrawingTable, g as IndicatorStatus, a as VisibleRange, c as VelaTheme, S as SerializedDrawing, v as DrawingTypeKey, u as SnapMode, a2 as DrawingMode, I as IChartRenderer, R as RendererCapabilities, o as LegendActionView, U as Unsubscribe, C as CrosshairEvent, A as AxisLongPressEvent, r as DataWindowReadout, n as SymbolPickerFn, aL as PaneInfo, a9 as DrawingsOption, D as Drawing, b as VelaOptions, x as AddIndicatorOptions, an as MarketSwitch, am as MarketSnapshot, V as VisibleRangePreset, T as ThemeName } from './options-BqGeFHtp.js';
2
- import { S as SymbolInfo, B as BarRange, M as MarketDataFeed, D as DataProvider, P as ProviderInfo, a as SymbolDescriptor, b as ProviderCapabilities } from './DataProvider-DHX4x6-r.js';
1
+ import { t as Millis, ae as InputSchema, ac as IndicatorMeta, P as PriceStyle, O as OHLCV, m as InputValue, k as IndicatorModel, j as MoveTarget, aB as SeriesSpec, aa as Fill, B as Background, at as PriceLine, a0 as DrawingLine, Y as DrawingBox, $ as DrawingLabel, a4 as DrawingPolyline, a1 as DrawingLinefill, a6 as DrawingTable, g as IndicatorStatus, a as VisibleRange, c as VelaTheme, S as SerializedDrawing, v as DrawingTypeKey, u as SnapMode, a2 as DrawingMode, I as IChartRenderer, R as RendererCapabilities, o as LegendActionView, U as Unsubscribe, C as CrosshairEvent, A as AxisLongPressEvent, r as DataWindowReadout, n as SymbolPickerFn, aO as PaneInfo, a9 as DrawingsOption, D as Drawing, b as VelaOptions, x as AddIndicatorOptions, ap as MarketSwitch, ao as MarketSnapshot, V as VisibleRangePreset, T as ThemeName } from './options-YdiaaVjt.js';
2
+ import { S as SymbolInfo, B as BarRange, M as MarketDataFeed, D as DataProvider, P as ProviderInfo, a as SymbolDescriptor, b as ProviderCapabilities } from './DataProvider-BmHkcwvJ.js';
3
3
 
4
4
  /**
5
5
  * A strategy's broker state at ONE bar — the flat summary a host reads while a script
@@ -1,6 +1,6 @@
1
- import { V as VisibleRangePreset } from './options-BqGeFHtp.js';
2
- import { D as DataProvider } from './DataProvider-DHX4x6-r.js';
3
- import { S as ScriptingEngine, V as Vela } from './contributions-ciV6Neyd.js';
1
+ import { V as VisibleRangePreset } from './options-YdiaaVjt.cjs';
2
+ import { D as DataProvider } from './DataProvider-DrN7ZIou.cjs';
3
+ import { S as ScriptingEngine, V as Vela } from './contributions-2bEmCF9S.cjs';
4
4
 
5
5
  interface RangePreset {
6
6
  /** Button label. */
@@ -49,9 +49,9 @@ declare class Bottombar {
49
49
  setActiveRange(id: string | null): void;
50
50
  /**
51
51
  * Reflect the ACTIVE chart's session posture. `enabled: false` (a continuous
52
- * market, or metadata not landed yet) shows the disabled RTH-active stub the
53
- * pre-session-model look, byte-for-byte. Enabled, the chips become clickable and
54
- * the active one tracks the chart's current session.
52
+ * market, or metadata not landed yet) HIDES the toggle entirelyRTH/ETH is
53
+ * meaningless there. Enabled, the chips appear and the active one tracks the
54
+ * chart's current session.
55
55
  */
56
56
  setSession(state: {
57
57
  session: 'regular' | 'extended';
@@ -1,6 +1,6 @@
1
- import { V as VisibleRangePreset } from './options-BqGeFHtp.cjs';
2
- import { D as DataProvider } from './DataProvider-CNmk84SH.cjs';
3
- import { S as ScriptingEngine, V as Vela } from './contributions-DDpv7hEL.cjs';
1
+ import { V as VisibleRangePreset } from './options-YdiaaVjt.js';
2
+ import { D as DataProvider } from './DataProvider-BmHkcwvJ.js';
3
+ import { S as ScriptingEngine, V as Vela } from './contributions-DatoAzMx.js';
4
4
 
5
5
  interface RangePreset {
6
6
  /** Button label. */
@@ -49,9 +49,9 @@ declare class Bottombar {
49
49
  setActiveRange(id: string | null): void;
50
50
  /**
51
51
  * Reflect the ACTIVE chart's session posture. `enabled: false` (a continuous
52
- * market, or metadata not landed yet) shows the disabled RTH-active stub the
53
- * pre-session-model look, byte-for-byte. Enabled, the chips become clickable and
54
- * the active one tracks the chart's current session.
52
+ * market, or metadata not landed yet) HIDES the toggle entirelyRTH/ETH is
53
+ * meaningless there. Enabled, the chips appear and the active one tracks the
54
+ * chart's current session.
55
55
  */
56
56
  setSession(state: {
57
57
  session: 'regular' | 'extended';