@luxalgo/vela 0.7.4 → 0.7.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 (37) hide show
  1. package/dist/{DataProvider-CVpN5sCq.d.ts → DataProvider-DLeFs1gE.d.ts} +1 -1
  2. package/dist/{DataProvider-RF1axuy1.d.cts → DataProvider-Dut6lXGM.d.cts} +1 -1
  3. package/dist/{chunk-DUURH3RN.js → chunk-MCLI6B3S.js} +226 -66
  4. package/dist/{chunk-CSFNKXUW.js → chunk-MNG5XPLV.js} +6 -1
  5. package/dist/{contributions-CspPrMAJ.d.ts → contributions-CEkgJKTU.d.ts} +7 -3
  6. package/dist/{contributions-DpZeu7KP.d.cts → contributions-DYtiRtES.d.cts} +7 -3
  7. package/dist/index.cjs +226 -66
  8. package/dist/index.d.cts +19 -6
  9. package/dist/index.d.ts +19 -6
  10. package/dist/index.js +1 -1
  11. package/dist/{options-XVpfr9HV.d.cts → options-DNBoMKkX.d.cts} +8 -0
  12. package/dist/{options-XVpfr9HV.d.ts → options-DNBoMKkX.d.ts} +8 -0
  13. package/dist/{plugin-BoLOkblF.d.ts → plugin-CLn--oP6.d.ts} +3 -3
  14. package/dist/{plugin-D07HD2GL.d.cts → plugin-DtkeQVAO.d.cts} +3 -3
  15. package/dist/plugin.d.cts +4 -4
  16. package/dist/plugin.d.ts +4 -4
  17. package/dist/providers/binance.d.cts +2 -2
  18. package/dist/providers/binance.d.ts +2 -2
  19. package/dist/providers/coinbase.d.cts +2 -2
  20. package/dist/providers/coinbase.d.ts +2 -2
  21. package/dist/providers/hyperliquid.d.cts +2 -2
  22. package/dist/providers/hyperliquid.d.ts +2 -2
  23. package/dist/{statusline-model-CPa_hmhd.d.ts → statusline-model-DypGXjtr.d.ts} +3 -3
  24. package/dist/{statusline-model-Bd4qKuD6.d.cts → statusline-model-gA__yaog.d.cts} +3 -3
  25. package/dist/ui.d.cts +1 -1
  26. package/dist/ui.d.ts +1 -1
  27. package/dist/vela.global.js +226 -66
  28. package/dist/vela.global.min.js +53 -49
  29. package/dist/widget.cjs +231 -66
  30. package/dist/widget.d.cts +6 -6
  31. package/dist/widget.d.ts +6 -6
  32. package/dist/widget.js +3 -3
  33. package/dist/workspace.cjs +231 -66
  34. package/dist/workspace.d.cts +5 -5
  35. package/dist/workspace.d.ts +5 -5
  36. package/dist/workspace.js +2 -2
  37. package/package.json +1 -1
package/dist/widget.cjs CHANGED
@@ -5115,6 +5115,17 @@ function hasOwnCandlePaint(style) {
5115
5115
  for (const t of chartTypes()) if (t.id === style) return (t.basePainting ?? "candles") === "candles";
5116
5116
  return false;
5117
5117
  }
5118
+ var CANDLE_OVERRIDE_KEYS = [
5119
+ "candleUpColor",
5120
+ "candleDownColor",
5121
+ "candleBodyVisible",
5122
+ "candleBorderVisible",
5123
+ "candleBorderUpColor",
5124
+ "candleBorderDownColor",
5125
+ "candleWickVisible",
5126
+ "candleWickUpColor",
5127
+ "candleWickDownColor"
5128
+ ];
5118
5129
  function candleOverrideFor(style, bags) {
5119
5130
  if (!hasOwnCandlePaint(style)) return null;
5120
5131
  const bag = bags[style] ?? {};
@@ -5186,7 +5197,7 @@ function clampLevel(v) {
5186
5197
  function clampSpacing(v) {
5187
5198
  return v < 0.1 ? 0.1 : v > 10 ? 10 : v;
5188
5199
  }
5189
- function factoryResetConfig(factory) {
5200
+ function factoryResetConfig(factory, priceStyle = factory.series.style) {
5190
5201
  const bag = {};
5191
5202
  for (const t of chartTypes()) {
5192
5203
  const section = t.settings;
@@ -5208,10 +5219,16 @@ function factoryResetConfig(factory) {
5208
5219
  if (!section.instances) addRows(section.rows);
5209
5220
  bag[t.id] = defaults2;
5210
5221
  }
5222
+ for (const t of chartTypes()) {
5223
+ if (!hasOwnCandlePaint(t.id)) continue;
5224
+ const defaults2 = bag[t.id] ?? {};
5225
+ for (const key of CANDLE_OVERRIDE_KEYS) defaults2[key] = null;
5226
+ bag[t.id] = defaults2;
5227
+ }
5211
5228
  for (const [typeId, vals] of Object.entries(factory.chartTypes)) {
5212
5229
  bag[typeId] = { ...bag[typeId] ?? {}, ...vals };
5213
5230
  }
5214
- return { ...factory, chartTypes: bag };
5231
+ return { ...factory, chartTypes: bag, series: { ...factory.series, style: priceStyle } };
5215
5232
  }
5216
5233
  function mergeConfig(base, patch) {
5217
5234
  const p = asObject(patch);
@@ -18653,6 +18670,42 @@ function presetToRange(preset, bars) {
18653
18670
  return { from: Math.max(first, from), to: last };
18654
18671
  }
18655
18672
 
18673
+ // src/core/marks/visibility.ts
18674
+ function markGroupOwnVisible(choices, groupId, groups) {
18675
+ const chosen = choices[groupId];
18676
+ if (typeof chosen === "boolean") return chosen;
18677
+ return groups.find((g) => g.id === groupId)?.visible !== false;
18678
+ }
18679
+ function markGroupVisible(choices, groupId, groups) {
18680
+ if (groupId === void 0) return true;
18681
+ const seen = /* @__PURE__ */ new Set();
18682
+ let id = groupId;
18683
+ while (id !== void 0 && !seen.has(id)) {
18684
+ seen.add(id);
18685
+ if (!markGroupOwnVisible(choices, id, groups)) return false;
18686
+ const parent = groups.find((g) => g.id === id)?.parent;
18687
+ id = parent !== void 0 && groups.some((g) => g.id === parent) ? parent : void 0;
18688
+ }
18689
+ return true;
18690
+ }
18691
+ function markGroupRows(groups) {
18692
+ const ids = new Set(groups.map((g) => g.id));
18693
+ const out = [];
18694
+ const placed = /* @__PURE__ */ new Set();
18695
+ const place = (group, depth) => {
18696
+ if (placed.has(group.id)) return;
18697
+ placed.add(group.id);
18698
+ out.push({ group, depth });
18699
+ for (const child of groups) if (child.parent === group.id && child.id !== group.id) place(child, depth + 1);
18700
+ };
18701
+ for (const g of groups) {
18702
+ const parentKnown = g.parent !== void 0 && ids.has(g.parent) && g.parent !== g.id;
18703
+ if (!parentKnown) place(g, 0);
18704
+ }
18705
+ for (const g of groups) place(g, 0);
18706
+ return out;
18707
+ }
18708
+
18656
18709
  // src/core/marks/MarksController.ts
18657
18710
  var MarksController = class {
18658
18711
  constructor(renderer, events) {
@@ -18697,6 +18750,7 @@ var MarksController = class {
18697
18750
  defineGroup(group) {
18698
18751
  if (!group || typeof group.id !== "string" || group.id.length === 0) throw new Error("[vela] marks.defineGroup: `id` must be a non-empty string");
18699
18752
  if (typeof group.label !== "string") throw new Error(`[vela] marks.defineGroup: group "${group.id}" needs a string \`label\``);
18753
+ if (group.parent !== void 0 && (typeof group.parent !== "string" || group.parent.length === 0)) throw new Error(`[vela] marks.defineGroup: group "${group.id}" has a \`parent\` that is not a group id`);
18700
18754
  this.groups.set(group.id, { ...group });
18701
18755
  this.sync();
18702
18756
  }
@@ -18716,12 +18770,16 @@ var MarksController = class {
18716
18770
  }
18717
18771
  this.renderer.applyFeature("marks", { groups: { [id]: visible } });
18718
18772
  }
18719
- /** A group's effective visibility: the user's (persisted) choice, else the group's declared default, else visible. */
18773
+ /**
18774
+ * A group's effective visibility: its own switch — the user's (persisted) choice, else
18775
+ * the declared default, else visible — AND every ancestor's, so a child under a
18776
+ * switched-off parent reads hidden whatever its own choice says.
18777
+ */
18720
18778
  isGroupVisible(id) {
18721
18779
  const state = this.renderer.readFeature("marks");
18722
- const chosen = state?.groups?.[id];
18723
- if (typeof chosen === "boolean") return chosen;
18724
- return this.groups.get(id)?.visible !== false;
18780
+ const groups = {};
18781
+ for (const [gid, v] of Object.entries(state?.groups ?? {})) if (typeof v === "boolean") groups[gid] = v;
18782
+ return markGroupVisible(groups, id, [...this.groups.values()]);
18725
18783
  }
18726
18784
  destroy() {
18727
18785
  for (const unsub of this.subs) unsub();
@@ -25710,11 +25768,8 @@ function mergeMarksState(base, patch) {
25710
25768
  for (const [id, v] of Object.entries(g)) if (typeof v === "boolean") groups[id] = v;
25711
25769
  return { visible: typeof p.visible === "boolean" ? p.visible : base.visible, groups };
25712
25770
  }
25713
- function markGroupVisible(state, groupId, groups) {
25714
- if (groupId === void 0) return true;
25715
- const chosen = state.groups[groupId];
25716
- if (typeof chosen === "boolean") return chosen;
25717
- return groups.find((g) => g.id === groupId)?.visible !== false;
25771
+ function markGroupVisible2(state, groupId, groups) {
25772
+ return markGroupVisible(state.groups, groupId, groups);
25718
25773
  }
25719
25774
 
25720
25775
  // src/renderers/native/core/SceneGraph.ts
@@ -27890,13 +27945,29 @@ function paintMarkLane(ctx, layout, deps) {
27890
27945
  const img = deps.icons.get(mark.glyph.icon, ink, symbolPx, deps.dpr);
27891
27946
  if (img) ctx.drawImage(img, center.x - symbolPx / 2, center.y - symbolPx / 2, symbolPx, symbolPx);
27892
27947
  } else if (mark.glyph.letter) {
27948
+ const letter = mark.glyph.letter.slice(0, 2);
27893
27949
  ctx.fillStyle = ink;
27894
- ctx.font = `600 ${Math.round(size * 0.58)}px ${deps.fontFamily}`;
27895
- ctx.fillText(mark.glyph.letter.slice(0, 2), center.x, center.y + 0.5);
27950
+ let px = letterFontPx(size, letter);
27951
+ ctx.font = `600 ${px}px ${deps.fontFamily}`;
27952
+ if (letter.length > 1) {
27953
+ px = fitLetterPx(px, ctx.measureText(letter).width, symbolInnerWidth(shape, size));
27954
+ ctx.font = `600 ${px}px ${deps.fontFamily}`;
27955
+ }
27956
+ ctx.fillText(letter, center.x, center.y + 0.5);
27896
27957
  }
27897
27958
  }
27898
27959
  ctx.restore();
27899
27960
  }
27961
+ function letterFontPx(size, letter) {
27962
+ return Math.round(size * (letter.length > 1 ? 0.38 : 0.58));
27963
+ }
27964
+ function symbolInnerWidth(shape, size) {
27965
+ return (shape === "pin" ? size * 0.82 : size) - 3;
27966
+ }
27967
+ function fitLetterPx(px, width, inner) {
27968
+ if (!(width > inner) || !(width > 0)) return px;
27969
+ return Math.max(4, Math.floor(px * inner / width));
27970
+ }
27900
27971
  function traceShape(ctx, shape, x, y, size) {
27901
27972
  const r = size / 2;
27902
27973
  ctx.beginPath();
@@ -28098,7 +28169,7 @@ var ChromeRenderer = class {
28098
28169
  this.markLayout = layoutMarkLane({
28099
28170
  marks: scene.timelineMarks,
28100
28171
  groups: scene.markGroups,
28101
- hidden: (groupId) => !markGroupVisible(scene.marks, groupId, scene.markGroups),
28172
+ hidden: (groupId) => !markGroupVisible2(scene.marks, groupId, scene.markGroups),
28102
28173
  barTimes: this.barTimes(scene),
28103
28174
  intervalMs: coords.barInterval,
28104
28175
  xOf: (bar) => coords.logicalToX(bar),
@@ -28788,6 +28859,10 @@ ${overlayScrollbarCss(".vela-sd-pane")}
28788
28859
  muted and non-interactive. Applied to each row's children so it survives display:contents;
28789
28860
  !important beats the inline opacity on labels. */
28790
28861
  .vela-sd-soft>*{opacity:0.4 !important;pointer-events:none !important;}
28862
+ /* A mark group nested under a parent group on the Events tab: indented one step per level
28863
+ (--vela-sd-depth). The indent rides the first child (the switch) as a MARGIN \u2014 padding
28864
+ would push the switch's own tick out of its box. */
28865
+ .vela-sd-nested>*:first-child{margin-left:calc(var(--vela-sd-depth,1)*24px);}
28791
28866
  /* \u2500\u2500 mobile presentation (.vela-sd-mobile on the scrim; structural sizes are inline in open()) \u2500\u2500
28792
28867
  The tab rail becomes a burger-opened overlay sidebar; the group TOC becomes a sticky
28793
28868
  row of horizontally scrollable tabs; the instance strip scrolls instead of wrapping;
@@ -28836,6 +28911,8 @@ var SettingsDialog = class {
28836
28911
  this.hostSections = [];
28837
28912
  /** The timeline-mark groups (defined + named by marks) — one checkbox each on the Events tab. */
28838
28913
  this.markGroups = [];
28914
+ /** A group's OWN switch (what its checkbox shows) — a child under an off parent keeps its own state. */
28915
+ this.markGroupOwnVisible = () => true;
28839
28916
  this.markGroupVisible = () => true;
28840
28917
  /** The Canvas → Theme row: current app theme + where a pick is raised. The row is a
28841
28918
  * host callback, NOT a config patch — the app theme stays out of the persisted
@@ -28853,6 +28930,9 @@ var SettingsDialog = class {
28853
28930
  this.activeSection = null;
28854
28931
  /** Mobile chrome: fullscreen card, burger-opened section sidebar, TOC as top tabs. */
28855
28932
  this.mobileLayout = false;
28933
+ /** Opens/closes the mobile section sidebar of the CURRENT build (the burger in the
28934
+ * shell header outlives pane rebuilds, so it reaches the rail through here). */
28935
+ this.toggleRail = null;
28856
28936
  /** The visibility policy: setting ids hidden by the host (subtree semantics). */
28857
28937
  this.hiddenSettings = /* @__PURE__ */ new Set();
28858
28938
  if (getComputedStyle(container).position === "static") container.style.position = "relative";
@@ -28862,7 +28942,8 @@ var SettingsDialog = class {
28862
28942
  this.hostSections = sections;
28863
28943
  }
28864
28944
  /** The timeline-mark groups and their current visibility — the Events tab's rows on next open. */
28865
- setMarkGroups(groups, visible) {
28945
+ setMarkGroups(groups, visible, ownVisible = visible) {
28946
+ this.markGroupOwnVisible = ownVisible;
28866
28947
  this.markGroups = groups;
28867
28948
  this.markGroupVisible = visible;
28868
28949
  }
@@ -28928,7 +29009,6 @@ var SettingsDialog = class {
28928
29009
  this.onReset = onReset ?? null;
28929
29010
  ensureControlStyles();
28930
29011
  const mobile = this.mobileLayout;
28931
- let toggleRail = null;
28932
29012
  let burger;
28933
29013
  if (mobile) {
28934
29014
  burger = document.createElement("button");
@@ -28936,8 +29016,83 @@ var SettingsDialog = class {
28936
29016
  burger.className = "vela-sd-burger";
28937
29017
  burger.innerHTML = iconAt("burger", 16);
28938
29018
  burger.title = "Sections";
28939
- burger.addEventListener("click", () => toggleRail?.());
29019
+ burger.addEventListener("click", () => this.toggleRail?.());
28940
29020
  }
29021
+ const ui = new Dialog({
29022
+ host: this.container,
29023
+ title: "Chart settings",
29024
+ // Non-modal: a live-edit dialog must leave the page interactive — a modal
29025
+ // machine locks pointer events on the whole body, killing the chart, the
29026
+ // legend, and the body-portaled popovers (color picker, select lists).
29027
+ modal: false,
29028
+ contained: true,
29029
+ align: "top",
29030
+ draggable: !mobile,
29031
+ flush: true,
29032
+ className: "vela-dialog--settings",
29033
+ headerStart: burger,
29034
+ closeOnBackdrop: true,
29035
+ footer: (foot) => {
29036
+ foot.style.cssText = `padding:10px 14px;display:flex;align-items:center;justify-content:flex-start;gap:8px;`;
29037
+ const resetBtn = document.createElement("button");
29038
+ resetBtn.type = "button";
29039
+ resetBtn.textContent = "Reset defaults";
29040
+ resetBtn.className = "vela-sd-btn";
29041
+ resetBtn.addEventListener("click", () => this.onReset?.());
29042
+ foot.appendChild(resetBtn);
29043
+ },
29044
+ // A close signal may only close ITS OWN dialog: the machine reports the exit
29045
+ // asynchronously, so a close-then-reopen in one tick would otherwise see the
29046
+ // old instance's signal tear down the freshly opened one.
29047
+ onOpenChange: (open2) => {
29048
+ if (!open2 && this.ui === ui) this.close();
29049
+ }
29050
+ });
29051
+ if (mobile) ui.positioner.classList.add("vela-sd-mobile");
29052
+ ui.positioner.style.paddingTop = mobile ? "0" : "8vh";
29053
+ this.root = ui.positioner;
29054
+ this.ui = ui;
29055
+ const panes = this.buildContent(ui, config, section, mobile);
29056
+ ui.show();
29057
+ this.layoutPanes(panes);
29058
+ }
29059
+ /**
29060
+ * Re-seed every control of an OPEN dialog from `config`, in place: the shell stays
29061
+ * (no close/open transition), only the tab rail and panes rebuild, landing back on
29062
+ * the current tab. The reset path — the restored values must show without the
29063
+ * dialog re-entering. No-op while closed.
29064
+ */
29065
+ refresh(config) {
29066
+ const ui = this.ui;
29067
+ if (!ui) return;
29068
+ closeOpenPopovers();
29069
+ closeWidthPopover();
29070
+ for (const dispose of this.hintTips) dispose();
29071
+ this.hintTips = [];
29072
+ this.config = config;
29073
+ ui.body.replaceChildren();
29074
+ this.layoutPanes(this.buildContent(ui, config, this.activeSection ?? void 0, this.mobileLayout));
29075
+ }
29076
+ /** Structured chart-type panes (instance strip / group TOC) own their layout and
29077
+ * tag their rows hosts instead; each host gets its own field grid. Runs on a SHOWN
29078
+ * dialog — the grids measure their labels. */
29079
+ layoutPanes(panes) {
29080
+ for (const el of panes) {
29081
+ const hosts = [...el.querySelectorAll("[data-sd-rows-host]")];
29082
+ if (hosts.length === 0) {
29083
+ this.layoutSettingsGrids(el);
29084
+ continue;
29085
+ }
29086
+ for (const h of hosts) this.layoutSettingsGrids(h);
29087
+ }
29088
+ }
29089
+ /**
29090
+ * Build the tab rail + one pane per section into `ui.body` (the linear `body` of
29091
+ * section markers and rows is split afterwards), select `section` (the active
29092
+ * style's own tab when none is asked for), and return the pane elements for
29093
+ * {@link layoutPanes}.
29094
+ */
29095
+ buildContent(ui, config, section, mobile) {
28941
29096
  const body = document.createElement("div");
28942
29097
  body.style.cssText = "display:flex;flex-direction:column;gap:0;";
28943
29098
  const sid = (el, id) => {
@@ -29141,9 +29296,28 @@ var SettingsDialog = class {
29141
29296
  if (this.markGroups.length > 0) {
29142
29297
  body.append(sid(this.section("Events"), MARKS_SETTINGS_ID));
29143
29298
  body.append(sid(this.sectionTitle("Visible events"), MARKS_GROUPS_SETTINGS_ID));
29144
- for (const g of this.markGroups) {
29145
- body.append(sid(this.boolRow(g.label, this.markGroupVisible(g.id), (v) => this.emit({ marks: { groups: { [g.id]: v } } })), markGroupSettingsId(g.id)));
29299
+ const rowsById = /* @__PURE__ */ new Map();
29300
+ const rows = markGroupRows(this.markGroups);
29301
+ const refreshDimming = () => {
29302
+ for (const { group } of rows) {
29303
+ const el = rowsById.get(group.id);
29304
+ if (!el || group.parent === void 0) continue;
29305
+ el.classList.toggle("vela-sd-soft", !this.markGroupVisible(group.parent));
29306
+ }
29307
+ };
29308
+ for (const { group: g, depth } of rows) {
29309
+ const row = this.boolRow(g.label, this.markGroupOwnVisible(g.id), (v) => {
29310
+ this.emit({ marks: { groups: { [g.id]: v } } });
29311
+ refreshDimming();
29312
+ });
29313
+ if (depth > 0) {
29314
+ row.classList.add("vela-sd-nested");
29315
+ row.style.setProperty("--vela-sd-depth", String(depth));
29316
+ }
29317
+ rowsById.set(g.id, row);
29318
+ body.append(sid(row, markGroupSettingsId(g.id)));
29146
29319
  }
29320
+ refreshDimming();
29147
29321
  }
29148
29322
  renderChartTypeSections("end");
29149
29323
  renderHostSections("end");
@@ -29171,8 +29345,8 @@ var SettingsDialog = class {
29171
29345
  if (mobile) {
29172
29346
  railScrim = document.createElement("div");
29173
29347
  railScrim.className = "vela-sd-railscrim";
29174
- railScrim.addEventListener("click", () => toggleRail?.());
29175
- toggleRail = (open2) => {
29348
+ railScrim.addEventListener("click", () => this.toggleRail?.());
29349
+ this.toggleRail = (open2) => {
29176
29350
  const on = open2 ?? !rail.classList.contains("open");
29177
29351
  rail.classList.toggle("open", on);
29178
29352
  railScrim?.classList.toggle("open", on);
@@ -29212,35 +29386,6 @@ var SettingsDialog = class {
29212
29386
  });
29213
29387
  if (hidActive) activate(0);
29214
29388
  };
29215
- const ui = new Dialog({
29216
- host: this.container,
29217
- title: "Chart settings",
29218
- // Non-modal: a live-edit dialog must leave the page interactive — a modal
29219
- // machine locks pointer events on the whole body, killing the chart, the
29220
- // legend, and the body-portaled popovers (color picker, select lists).
29221
- modal: false,
29222
- contained: true,
29223
- align: "top",
29224
- draggable: !mobile,
29225
- flush: true,
29226
- className: "vela-dialog--settings",
29227
- headerStart: burger,
29228
- closeOnBackdrop: true,
29229
- footer: (foot) => {
29230
- foot.style.cssText = `padding:10px 14px;display:flex;align-items:center;justify-content:flex-start;gap:8px;`;
29231
- const resetBtn = document.createElement("button");
29232
- resetBtn.type = "button";
29233
- resetBtn.textContent = "Reset defaults";
29234
- resetBtn.className = "vela-sd-btn";
29235
- resetBtn.addEventListener("click", () => this.onReset?.());
29236
- foot.appendChild(resetBtn);
29237
- },
29238
- onOpenChange: (open2) => {
29239
- if (!open2) this.close();
29240
- }
29241
- });
29242
- if (mobile) ui.positioner.classList.add("vela-sd-mobile");
29243
- ui.positioner.style.paddingTop = mobile ? "0" : "8vh";
29244
29389
  const activate = (idx) => {
29245
29390
  panes.forEach((p, i) => {
29246
29391
  p.el.style.display = i === idx ? "block" : "none";
@@ -29249,7 +29394,7 @@ var SettingsDialog = class {
29249
29394
  this.activeSection = panes[idx]?.title ?? null;
29250
29395
  if (mobile) {
29251
29396
  ui.titleEl.textContent = panes[idx]?.title ?? "Chart settings";
29252
- toggleRail?.(false);
29397
+ this.toggleRail?.(false);
29253
29398
  }
29254
29399
  };
29255
29400
  panes.forEach((p, i) => {
@@ -29264,17 +29409,7 @@ var SettingsDialog = class {
29264
29409
  shell.append(rail, paneHost);
29265
29410
  if (railScrim) shell.append(railScrim);
29266
29411
  ui.body.appendChild(shell);
29267
- this.root = ui.positioner;
29268
- this.ui = ui;
29269
- ui.show();
29270
- for (const p of panes) {
29271
- const hosts = [...p.el.querySelectorAll("[data-sd-rows-host]")];
29272
- if (hosts.length === 0) {
29273
- this.layoutSettingsGrids(p.el);
29274
- continue;
29275
- }
29276
- for (const h of hosts) this.layoutSettingsGrids(h);
29277
- }
29412
+ return panes.map((p) => p.el);
29278
29413
  }
29279
29414
  close() {
29280
29415
  closeOpenPopovers();
@@ -29282,6 +29417,7 @@ var SettingsDialog = class {
29282
29417
  const ui = this.ui;
29283
29418
  this.ui = null;
29284
29419
  this.root = null;
29420
+ this.toggleRail = null;
29285
29421
  this.tabs = [];
29286
29422
  for (const dispose of this.hintTips) dispose();
29287
29423
  this.hintTips = [];
@@ -36600,7 +36736,11 @@ var NativeRenderer = class {
36600
36736
  }
36601
36737
  this.settingsDialog.setTheme(this.theme);
36602
36738
  this.settingsDialog.setHostSections(this.hostSettingsSections);
36603
- this.settingsDialog.setMarkGroups(this.markGroupsInUse(), (id) => markGroupVisible(this.scene.marks, id, this.scene.markGroups));
36739
+ this.settingsDialog.setMarkGroups(
36740
+ this.markGroupsForEventsTab(),
36741
+ (id) => markGroupVisible2(this.scene.marks, id, this.scene.markGroups),
36742
+ (id) => markGroupOwnVisible(this.scene.marks.groups, id, this.scene.markGroups)
36743
+ );
36604
36744
  this.settingsDialog.setHiddenSettings(this.hiddenSettings);
36605
36745
  this.syncThemeControl();
36606
36746
  this.settingsDialog.toggle(
@@ -36608,13 +36748,24 @@ var NativeRenderer = class {
36608
36748
  (patch) => this.applyConfig(patch),
36609
36749
  (json) => this.applyConfig(json),
36610
36750
  () => {
36611
- if (this.factoryConfig) this.applyConfig(factoryResetConfig(this.factoryConfig));
36612
- this.settingsDialog?.close();
36613
- this.openSettingsDialog();
36751
+ if (this.factoryConfig) this.applyConfig(this.factoryResetDocument(this.factoryConfig));
36752
+ this.settingsDialog?.refresh(this.getConfig());
36614
36753
  },
36615
36754
  section
36616
36755
  );
36617
36756
  }
36757
+ /**
36758
+ * The document "Reset defaults" applies: every setting back to its first-run value,
36759
+ * with two things that are NOT settings held or resolved here — the price style
36760
+ * stays the one the user is looking at, and the timeline-mark groups (an additive
36761
+ * merge, like the type bags) are named back to their host-declared visibility.
36762
+ */
36763
+ factoryResetDocument(factory) {
36764
+ const doc = factoryResetConfig(factory, this.scene.priceStyle);
36765
+ const groups = { ...doc.marks.groups };
36766
+ for (const g of this.markGroupsInUse()) groups[g.id] = g.visible !== false;
36767
+ return { ...doc, marks: { ...doc.marks, groups } };
36768
+ }
36618
36769
  /** Close the in-chart dialogs (indicator settings + chart-settings gear). No-op when none are open. */
36619
36770
  closeDialogs() {
36620
36771
  this.inputsUI?.closeOpenDialog();
@@ -37677,6 +37828,15 @@ var NativeRenderer = class {
37677
37828
  markGroupsInUse() {
37678
37829
  return effectiveMarkGroups(this.scene.timelineMarks, this.scene.markGroups);
37679
37830
  }
37831
+ /**
37832
+ * The groups as the Events tab lists them: nested only under a DEFINED parent. The
37833
+ * painter's visibility chain resolves parents against the defined groups alone, so a
37834
+ * parent that marks merely name must not nest (and dim) a child the painter still shows.
37835
+ */
37836
+ markGroupsForEventsTab() {
37837
+ const defined = new Set(this.scene.markGroups.map((g) => g.id));
37838
+ return this.markGroupsInUse().map((g) => g.parent !== void 0 && !defined.has(g.parent) ? { ...g, parent: void 0 } : g);
37839
+ }
37680
37840
  onViewportChange(cb) {
37681
37841
  this.viewportCbs.add(cb);
37682
37842
  return () => this.viewportCbs.delete(cb);
@@ -43569,6 +43729,11 @@ var ChartCell = class {
43569
43729
  if (typeof zone === "string" && normalizeTimezone(zone) !== normalizeTimezone(this.deps.timezone())) {
43570
43730
  this.deps.setTimezone(normalizeTimezone(zone));
43571
43731
  }
43732
+ const style = this.priceStyle;
43733
+ if (style !== (this.state.priceStyle ?? "candles")) {
43734
+ this.state.priceStyle = style;
43735
+ this.deps.onPriceStyleChanged(this.id);
43736
+ }
43572
43737
  this.syncStatuslineColors();
43573
43738
  this.syncPlotOverlayTokens();
43574
43739
  });
package/dist/widget.d.cts CHANGED
@@ -1,10 +1,10 @@
1
- import { V as Vela, W as WidgetContext, K as SidePanelButton } from './contributions-DpZeu7KP.cjs';
2
- export { C as CellStateContext, aA as DEFAULT_PANEL_ORDER, E as ExternalIndicatorEntry, O as OVERRIDABLE_TOPBAR_IDS, Q as SidePanelDescriptor, T as SidePanelHandle, X as StatePersistenceHandler, $ as SymbolRankingHook, a4 as WidgetActionDescriptor, a5 as WidgetActionTarget, a6 as WidgetAttachment, ag as registerSidePanel, ah as registerStatePersistence, ai as registerSymbolRanking, aj as registerWidgetAction, ak as registerWidgetAttachment, am as sidePanels, an as statePersistenceHandlers, ao as symbolRanking, ap as topbarActionOverride, au as unregisterSidePanel, av as unregisterStatePersistence, aw as unregisterWidgetAction, ax as unregisterWidgetAttachment, ay as widgetActions, az as widgetAttachments } from './contributions-DpZeu7KP.cjs';
3
- import { b as VelaOptions, d as MarketSession, T as ThemeName, c as VelaTheme, v as DataWindowReadout } from './options-XVpfr9HV.cjs';
4
- import { c as VelaShellOptions, W as WidgetHistory, b as RangePreset, f as WorkspaceState, j as TopbarComposition, a as StatuslinePart, P as PanelsState } from './statusline-model-Bd4qKuD6.cjs';
5
- export { B as Bottombar, k as BottombarOptions, C as CellState, g as ChartState, I as IndicatorLoader, l as IndicatorManifest, m as IndicatorManifestEntry, n as RANGE_PRESETS, R as ResolvedIndicator, o as ResolvedTopbarComposition, p as TOPBAR_BUILTIN_IDS, q as TOPBAR_DEFAULT_LEFT, r as TOPBAR_DEFAULT_RIGHT, V as VelaStorage, t as WidgetStorage, h as decodeState, i as encodeState, u as localStorageAdapter, v as pinnedTopbarActionIds, w as resolveIndicators, x as resolveTopbarComposition, s as sanitizeState, y as topbarHas } from './statusline-model-Bd4qKuD6.cjs';
1
+ import { V as Vela, W as WidgetContext, K as SidePanelButton } from './contributions-DYtiRtES.cjs';
2
+ export { C as CellStateContext, aA as DEFAULT_PANEL_ORDER, E as ExternalIndicatorEntry, O as OVERRIDABLE_TOPBAR_IDS, Q as SidePanelDescriptor, T as SidePanelHandle, X as StatePersistenceHandler, $ as SymbolRankingHook, a4 as WidgetActionDescriptor, a5 as WidgetActionTarget, a6 as WidgetAttachment, ag as registerSidePanel, ah as registerStatePersistence, ai as registerSymbolRanking, aj as registerWidgetAction, ak as registerWidgetAttachment, am as sidePanels, an as statePersistenceHandlers, ao as symbolRanking, ap as topbarActionOverride, au as unregisterSidePanel, av as unregisterStatePersistence, aw as unregisterWidgetAction, ax as unregisterWidgetAttachment, ay as widgetActions, az as widgetAttachments } from './contributions-DYtiRtES.cjs';
3
+ import { b as VelaOptions, d as MarketSession, T as ThemeName, c as VelaTheme, v as DataWindowReadout } from './options-DNBoMKkX.cjs';
4
+ import { c as VelaShellOptions, W as WidgetHistory, b as RangePreset, f as WorkspaceState, j as TopbarComposition, a as StatuslinePart, P as PanelsState } from './statusline-model-gA__yaog.cjs';
5
+ export { B as Bottombar, k as BottombarOptions, C as CellState, g as ChartState, I as IndicatorLoader, l as IndicatorManifest, m as IndicatorManifestEntry, n as RANGE_PRESETS, R as ResolvedIndicator, o as ResolvedTopbarComposition, p as TOPBAR_BUILTIN_IDS, q as TOPBAR_DEFAULT_LEFT, r as TOPBAR_DEFAULT_RIGHT, V as VelaStorage, t as WidgetStorage, h as decodeState, i as encodeState, u as localStorageAdapter, v as pinnedTopbarActionIds, w as resolveIndicators, x as resolveTopbarComposition, s as sanitizeState, y as topbarHas } from './statusline-model-gA__yaog.cjs';
6
6
  import { K as KeymapManager } from './keymap-CGOz5F5f.cjs';
7
- import { a as SymbolDescriptor } from './DataProvider-RF1axuy1.cjs';
7
+ import { a as SymbolDescriptor } from './DataProvider-Dut6lXGM.cjs';
8
8
  import { d as SidePanel } from './side-panel-HF0IAzwf.cjs';
9
9
  export { D as DEFAULT_PANEL_MAX_WIDTH, a as DEFAULT_PANEL_MIN_WIDTH, b as DEFAULT_PANEL_WIDTH, S as SidePanelOptions, c as clampPanelWidth } from './side-panel-HF0IAzwf.cjs';
10
10
 
package/dist/widget.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { V as Vela, W as WidgetContext, K as SidePanelButton } from './contributions-CspPrMAJ.js';
2
- export { C as CellStateContext, aA as DEFAULT_PANEL_ORDER, E as ExternalIndicatorEntry, O as OVERRIDABLE_TOPBAR_IDS, Q as SidePanelDescriptor, T as SidePanelHandle, X as StatePersistenceHandler, $ as SymbolRankingHook, a4 as WidgetActionDescriptor, a5 as WidgetActionTarget, a6 as WidgetAttachment, ag as registerSidePanel, ah as registerStatePersistence, ai as registerSymbolRanking, aj as registerWidgetAction, ak as registerWidgetAttachment, am as sidePanels, an as statePersistenceHandlers, ao as symbolRanking, ap as topbarActionOverride, au as unregisterSidePanel, av as unregisterStatePersistence, aw as unregisterWidgetAction, ax as unregisterWidgetAttachment, ay as widgetActions, az as widgetAttachments } from './contributions-CspPrMAJ.js';
3
- import { b as VelaOptions, d as MarketSession, T as ThemeName, c as VelaTheme, v as DataWindowReadout } from './options-XVpfr9HV.js';
4
- import { c as VelaShellOptions, W as WidgetHistory, b as RangePreset, f as WorkspaceState, j as TopbarComposition, a as StatuslinePart, P as PanelsState } from './statusline-model-CPa_hmhd.js';
5
- export { B as Bottombar, k as BottombarOptions, C as CellState, g as ChartState, I as IndicatorLoader, l as IndicatorManifest, m as IndicatorManifestEntry, n as RANGE_PRESETS, R as ResolvedIndicator, o as ResolvedTopbarComposition, p as TOPBAR_BUILTIN_IDS, q as TOPBAR_DEFAULT_LEFT, r as TOPBAR_DEFAULT_RIGHT, V as VelaStorage, t as WidgetStorage, h as decodeState, i as encodeState, u as localStorageAdapter, v as pinnedTopbarActionIds, w as resolveIndicators, x as resolveTopbarComposition, s as sanitizeState, y as topbarHas } from './statusline-model-CPa_hmhd.js';
1
+ import { V as Vela, W as WidgetContext, K as SidePanelButton } from './contributions-CEkgJKTU.js';
2
+ export { C as CellStateContext, aA as DEFAULT_PANEL_ORDER, E as ExternalIndicatorEntry, O as OVERRIDABLE_TOPBAR_IDS, Q as SidePanelDescriptor, T as SidePanelHandle, X as StatePersistenceHandler, $ as SymbolRankingHook, a4 as WidgetActionDescriptor, a5 as WidgetActionTarget, a6 as WidgetAttachment, ag as registerSidePanel, ah as registerStatePersistence, ai as registerSymbolRanking, aj as registerWidgetAction, ak as registerWidgetAttachment, am as sidePanels, an as statePersistenceHandlers, ao as symbolRanking, ap as topbarActionOverride, au as unregisterSidePanel, av as unregisterStatePersistence, aw as unregisterWidgetAction, ax as unregisterWidgetAttachment, ay as widgetActions, az as widgetAttachments } from './contributions-CEkgJKTU.js';
3
+ import { b as VelaOptions, d as MarketSession, T as ThemeName, c as VelaTheme, v as DataWindowReadout } from './options-DNBoMKkX.js';
4
+ import { c as VelaShellOptions, W as WidgetHistory, b as RangePreset, f as WorkspaceState, j as TopbarComposition, a as StatuslinePart, P as PanelsState } from './statusline-model-DypGXjtr.js';
5
+ export { B as Bottombar, k as BottombarOptions, C as CellState, g as ChartState, I as IndicatorLoader, l as IndicatorManifest, m as IndicatorManifestEntry, n as RANGE_PRESETS, R as ResolvedIndicator, o as ResolvedTopbarComposition, p as TOPBAR_BUILTIN_IDS, q as TOPBAR_DEFAULT_LEFT, r as TOPBAR_DEFAULT_RIGHT, V as VelaStorage, t as WidgetStorage, h as decodeState, i as encodeState, u as localStorageAdapter, v as pinnedTopbarActionIds, w as resolveIndicators, x as resolveTopbarComposition, s as sanitizeState, y as topbarHas } from './statusline-model-DypGXjtr.js';
6
6
  import { K as KeymapManager } from './keymap-CGOz5F5f.js';
7
- import { a as SymbolDescriptor } from './DataProvider-CVpN5sCq.js';
7
+ import { a as SymbolDescriptor } from './DataProvider-DLeFs1gE.js';
8
8
  import { d as SidePanel } from './side-panel-HF0IAzwf.js';
9
9
  export { D as DEFAULT_PANEL_MAX_WIDTH, a as DEFAULT_PANEL_MIN_WIDTH, b as DEFAULT_PANEL_WIDTH, S as SidePanelOptions, c as clampPanelWidth } from './side-panel-HF0IAzwf.js';
10
10
 
package/dist/widget.js CHANGED
@@ -1,6 +1,6 @@
1
- import { VelaWorkspace } from './chunk-CSFNKXUW.js';
2
- export { Bottombar, ChartContextMenu, DataWindow, IndicatorPicker, ObjectTree, PanelDock, RANGE_PRESETS, ShortcutsHelp, Statusline, SymbolPicker, TimeframeQuick, Topbar, Watermark, dataWindowSections, decimalsFor, decodeState, encodeState, filterSymbols, fmtChange, fmtPrice, localStorageAdapter, parseTimeframe, priceStyleLabel, resolveIndicators, sanitizeState, timeframeLabel, timeframeMs } from './chunk-CSFNKXUW.js';
3
- export { TIMEZONES, normalizeTimezone, tzButtonLabel, tzMenuLabel, tzOffset } from './chunk-DUURH3RN.js';
1
+ import { VelaWorkspace } from './chunk-MNG5XPLV.js';
2
+ export { Bottombar, ChartContextMenu, DataWindow, IndicatorPicker, ObjectTree, PanelDock, RANGE_PRESETS, ShortcutsHelp, Statusline, SymbolPicker, TimeframeQuick, Topbar, Watermark, dataWindowSections, decimalsFor, decodeState, encodeState, filterSymbols, fmtChange, fmtPrice, localStorageAdapter, parseTimeframe, priceStyleLabel, resolveIndicators, sanitizeState, timeframeLabel, timeframeMs } from './chunk-MNG5XPLV.js';
3
+ export { TIMEZONES, normalizeTimezone, tzButtonLabel, tzMenuLabel, tzOffset } from './chunk-MCLI6B3S.js';
4
4
  export { DEFAULT_PANEL_MAX_WIDTH, DEFAULT_PANEL_MIN_WIDTH, DEFAULT_PANEL_ORDER, DEFAULT_PANEL_WIDTH, OVERRIDABLE_TOPBAR_IDS, SidePanel, TOPBAR_BUILTIN_IDS, TOPBAR_DEFAULT_LEFT, TOPBAR_DEFAULT_RIGHT, clampPanelWidth, pinnedTopbarActionIds, registerSidePanel, registerStatePersistence, registerSymbolRanking, registerWidgetAction, registerWidgetAttachment, resolveTopbarComposition, sidePanels, statePersistenceHandlers, symbolRanking, topbarActionOverride, topbarHas, unregisterSidePanel, unregisterStatePersistence, unregisterWidgetAction, unregisterWidgetAttachment, widgetActions, widgetAttachments } from './chunk-BFA32GOU.js';
5
5
  import './chunk-ZADTVRUO.js';
6
6
  import './chunk-BKHSQ4YM.js';