@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
@@ -7116,6 +7116,42 @@ var Vela = (function (exports) {
7116
7116
  }
7117
7117
  };
7118
7118
 
7119
+ // src/core/marks/visibility.ts
7120
+ function markGroupOwnVisible(choices, groupId, groups) {
7121
+ const chosen = choices[groupId];
7122
+ if (typeof chosen === "boolean") return chosen;
7123
+ return groups.find((g) => g.id === groupId)?.visible !== false;
7124
+ }
7125
+ function markGroupVisible(choices, groupId, groups) {
7126
+ if (groupId === void 0) return true;
7127
+ const seen = /* @__PURE__ */ new Set();
7128
+ let id = groupId;
7129
+ while (id !== void 0 && !seen.has(id)) {
7130
+ seen.add(id);
7131
+ if (!markGroupOwnVisible(choices, id, groups)) return false;
7132
+ const parent = groups.find((g) => g.id === id)?.parent;
7133
+ id = parent !== void 0 && groups.some((g) => g.id === parent) ? parent : void 0;
7134
+ }
7135
+ return true;
7136
+ }
7137
+ function markGroupRows(groups) {
7138
+ const ids = new Set(groups.map((g) => g.id));
7139
+ const out = [];
7140
+ const placed = /* @__PURE__ */ new Set();
7141
+ const place = (group, depth) => {
7142
+ if (placed.has(group.id)) return;
7143
+ placed.add(group.id);
7144
+ out.push({ group, depth });
7145
+ for (const child of groups) if (child.parent === group.id && child.id !== group.id) place(child, depth + 1);
7146
+ };
7147
+ for (const g of groups) {
7148
+ const parentKnown = g.parent !== void 0 && ids.has(g.parent) && g.parent !== g.id;
7149
+ if (!parentKnown) place(g, 0);
7150
+ }
7151
+ for (const g of groups) place(g, 0);
7152
+ return out;
7153
+ }
7154
+
7119
7155
  // src/core/marks/MarksController.ts
7120
7156
  var MarksController = class {
7121
7157
  constructor(renderer, events) {
@@ -7160,6 +7196,7 @@ var Vela = (function (exports) {
7160
7196
  defineGroup(group) {
7161
7197
  if (!group || typeof group.id !== "string" || group.id.length === 0) throw new Error("[vela] marks.defineGroup: `id` must be a non-empty string");
7162
7198
  if (typeof group.label !== "string") throw new Error(`[vela] marks.defineGroup: group "${group.id}" needs a string \`label\``);
7199
+ 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`);
7163
7200
  this.groups.set(group.id, { ...group });
7164
7201
  this.sync();
7165
7202
  }
@@ -7179,12 +7216,16 @@ var Vela = (function (exports) {
7179
7216
  }
7180
7217
  this.renderer.applyFeature("marks", { groups: { [id]: visible } });
7181
7218
  }
7182
- /** A group's effective visibility: the user's (persisted) choice, else the group's declared default, else visible. */
7219
+ /**
7220
+ * A group's effective visibility: its own switch — the user's (persisted) choice, else
7221
+ * the declared default, else visible — AND every ancestor's, so a child under a
7222
+ * switched-off parent reads hidden whatever its own choice says.
7223
+ */
7183
7224
  isGroupVisible(id) {
7184
7225
  const state = this.renderer.readFeature("marks");
7185
- const chosen = state?.groups?.[id];
7186
- if (typeof chosen === "boolean") return chosen;
7187
- return this.groups.get(id)?.visible !== false;
7226
+ const groups = {};
7227
+ for (const [gid, v] of Object.entries(state?.groups ?? {})) if (typeof v === "boolean") groups[gid] = v;
7228
+ return markGroupVisible(groups, id, [...this.groups.values()]);
7188
7229
  }
7189
7230
  destroy() {
7190
7231
  for (const unsub of this.subs) unsub();
@@ -23374,6 +23415,17 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
23374
23415
  for (const t of chartTypes()) if (t.id === style) return (t.basePainting ?? "candles") === "candles";
23375
23416
  return false;
23376
23417
  }
23418
+ var CANDLE_OVERRIDE_KEYS = [
23419
+ "candleUpColor",
23420
+ "candleDownColor",
23421
+ "candleBodyVisible",
23422
+ "candleBorderVisible",
23423
+ "candleBorderUpColor",
23424
+ "candleBorderDownColor",
23425
+ "candleWickVisible",
23426
+ "candleWickUpColor",
23427
+ "candleWickDownColor"
23428
+ ];
23377
23429
  function candleOverrideFor(style, bags) {
23378
23430
  if (!hasOwnCandlePaint(style)) return null;
23379
23431
  const bag = bags[style] ?? {};
@@ -23445,7 +23497,7 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
23445
23497
  function clampSpacing(v) {
23446
23498
  return v < 0.1 ? 0.1 : v > 10 ? 10 : v;
23447
23499
  }
23448
- function factoryResetConfig(factory) {
23500
+ function factoryResetConfig(factory, priceStyle = factory.series.style) {
23449
23501
  const bag = {};
23450
23502
  for (const t of chartTypes()) {
23451
23503
  const section = t.settings;
@@ -23467,10 +23519,16 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
23467
23519
  if (!section.instances) addRows(section.rows);
23468
23520
  bag[t.id] = defaults2;
23469
23521
  }
23522
+ for (const t of chartTypes()) {
23523
+ if (!hasOwnCandlePaint(t.id)) continue;
23524
+ const defaults2 = bag[t.id] ?? {};
23525
+ for (const key of CANDLE_OVERRIDE_KEYS) defaults2[key] = null;
23526
+ bag[t.id] = defaults2;
23527
+ }
23470
23528
  for (const [typeId, vals] of Object.entries(factory.chartTypes)) {
23471
23529
  bag[typeId] = { ...bag[typeId] ?? {}, ...vals };
23472
23530
  }
23473
- return { ...factory, chartTypes: bag };
23531
+ return { ...factory, chartTypes: bag, series: { ...factory.series, style: priceStyle } };
23474
23532
  }
23475
23533
  function mergeConfig(base, patch) {
23476
23534
  const p = asObject(patch);
@@ -25849,11 +25907,8 @@ void main() {
25849
25907
  for (const [id, v] of Object.entries(g)) if (typeof v === "boolean") groups[id] = v;
25850
25908
  return { visible: typeof p.visible === "boolean" ? p.visible : base.visible, groups };
25851
25909
  }
25852
- function markGroupVisible(state, groupId, groups) {
25853
- if (groupId === void 0) return true;
25854
- const chosen = state.groups[groupId];
25855
- if (typeof chosen === "boolean") return chosen;
25856
- return groups.find((g) => g.id === groupId)?.visible !== false;
25910
+ function markGroupVisible2(state, groupId, groups) {
25911
+ return markGroupVisible(state.groups, groupId, groups);
25857
25912
  }
25858
25913
 
25859
25914
  // src/renderers/native/core/SceneGraph.ts
@@ -28029,13 +28084,29 @@ void main() {
28029
28084
  const img = deps.icons.get(mark.glyph.icon, ink, symbolPx, deps.dpr);
28030
28085
  if (img) ctx.drawImage(img, center.x - symbolPx / 2, center.y - symbolPx / 2, symbolPx, symbolPx);
28031
28086
  } else if (mark.glyph.letter) {
28087
+ const letter = mark.glyph.letter.slice(0, 2);
28032
28088
  ctx.fillStyle = ink;
28033
- ctx.font = `600 ${Math.round(size3 * 0.58)}px ${deps.fontFamily}`;
28034
- ctx.fillText(mark.glyph.letter.slice(0, 2), center.x, center.y + 0.5);
28089
+ let px = letterFontPx(size3, letter);
28090
+ ctx.font = `600 ${px}px ${deps.fontFamily}`;
28091
+ if (letter.length > 1) {
28092
+ px = fitLetterPx(px, ctx.measureText(letter).width, symbolInnerWidth(shape, size3));
28093
+ ctx.font = `600 ${px}px ${deps.fontFamily}`;
28094
+ }
28095
+ ctx.fillText(letter, center.x, center.y + 0.5);
28035
28096
  }
28036
28097
  }
28037
28098
  ctx.restore();
28038
28099
  }
28100
+ function letterFontPx(size3, letter) {
28101
+ return Math.round(size3 * (letter.length > 1 ? 0.38 : 0.58));
28102
+ }
28103
+ function symbolInnerWidth(shape, size3) {
28104
+ return (shape === "pin" ? size3 * 0.82 : size3) - 3;
28105
+ }
28106
+ function fitLetterPx(px, width, inner) {
28107
+ if (!(width > inner) || !(width > 0)) return px;
28108
+ return Math.max(4, Math.floor(px * inner / width));
28109
+ }
28039
28110
  function traceShape(ctx, shape, x, y, size3) {
28040
28111
  const r = size3 / 2;
28041
28112
  ctx.beginPath();
@@ -28237,7 +28308,7 @@ void main() {
28237
28308
  this.markLayout = layoutMarkLane({
28238
28309
  marks: scene.timelineMarks,
28239
28310
  groups: scene.markGroups,
28240
- hidden: (groupId) => !markGroupVisible(scene.marks, groupId, scene.markGroups),
28311
+ hidden: (groupId) => !markGroupVisible2(scene.marks, groupId, scene.markGroups),
28241
28312
  barTimes: this.barTimes(scene),
28242
28313
  intervalMs: coords.barInterval,
28243
28314
  xOf: (bar) => coords.logicalToX(bar),
@@ -29004,6 +29075,10 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29004
29075
  muted and non-interactive. Applied to each row's children so it survives display:contents;
29005
29076
  !important beats the inline opacity on labels. */
29006
29077
  .vela-sd-soft>*{opacity:0.4 !important;pointer-events:none !important;}
29078
+ /* A mark group nested under a parent group on the Events tab: indented one step per level
29079
+ (--vela-sd-depth). The indent rides the first child (the switch) as a MARGIN \u2014 padding
29080
+ would push the switch's own tick out of its box. */
29081
+ .vela-sd-nested>*:first-child{margin-left:calc(var(--vela-sd-depth,1)*24px);}
29007
29082
  /* \u2500\u2500 mobile presentation (.vela-sd-mobile on the scrim; structural sizes are inline in open()) \u2500\u2500
29008
29083
  The tab rail becomes a burger-opened overlay sidebar; the group TOC becomes a sticky
29009
29084
  row of horizontally scrollable tabs; the instance strip scrolls instead of wrapping;
@@ -29052,6 +29127,8 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29052
29127
  this.hostSections = [];
29053
29128
  /** The timeline-mark groups (defined + named by marks) — one checkbox each on the Events tab. */
29054
29129
  this.markGroups = [];
29130
+ /** A group's OWN switch (what its checkbox shows) — a child under an off parent keeps its own state. */
29131
+ this.markGroupOwnVisible = () => true;
29055
29132
  this.markGroupVisible = () => true;
29056
29133
  /** The Canvas → Theme row: current app theme + where a pick is raised. The row is a
29057
29134
  * host callback, NOT a config patch — the app theme stays out of the persisted
@@ -29069,6 +29146,9 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29069
29146
  this.activeSection = null;
29070
29147
  /** Mobile chrome: fullscreen card, burger-opened section sidebar, TOC as top tabs. */
29071
29148
  this.mobileLayout = false;
29149
+ /** Opens/closes the mobile section sidebar of the CURRENT build (the burger in the
29150
+ * shell header outlives pane rebuilds, so it reaches the rail through here). */
29151
+ this.toggleRail = null;
29072
29152
  /** The visibility policy: setting ids hidden by the host (subtree semantics). */
29073
29153
  this.hiddenSettings = /* @__PURE__ */ new Set();
29074
29154
  if (getComputedStyle(container).position === "static") container.style.position = "relative";
@@ -29078,7 +29158,8 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29078
29158
  this.hostSections = sections;
29079
29159
  }
29080
29160
  /** The timeline-mark groups and their current visibility — the Events tab's rows on next open. */
29081
- setMarkGroups(groups, visible) {
29161
+ setMarkGroups(groups, visible, ownVisible = visible) {
29162
+ this.markGroupOwnVisible = ownVisible;
29082
29163
  this.markGroups = groups;
29083
29164
  this.markGroupVisible = visible;
29084
29165
  }
@@ -29144,7 +29225,6 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29144
29225
  this.onReset = onReset ?? null;
29145
29226
  ensureControlStyles();
29146
29227
  const mobile = this.mobileLayout;
29147
- let toggleRail = null;
29148
29228
  let burger;
29149
29229
  if (mobile) {
29150
29230
  burger = document.createElement("button");
@@ -29152,8 +29232,83 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29152
29232
  burger.className = "vela-sd-burger";
29153
29233
  burger.innerHTML = iconAt("burger", 16);
29154
29234
  burger.title = "Sections";
29155
- burger.addEventListener("click", () => toggleRail?.());
29235
+ burger.addEventListener("click", () => this.toggleRail?.());
29236
+ }
29237
+ const ui = new Dialog({
29238
+ host: this.container,
29239
+ title: "Chart settings",
29240
+ // Non-modal: a live-edit dialog must leave the page interactive — a modal
29241
+ // machine locks pointer events on the whole body, killing the chart, the
29242
+ // legend, and the body-portaled popovers (color picker, select lists).
29243
+ modal: false,
29244
+ contained: true,
29245
+ align: "top",
29246
+ draggable: !mobile,
29247
+ flush: true,
29248
+ className: "vela-dialog--settings",
29249
+ headerStart: burger,
29250
+ closeOnBackdrop: true,
29251
+ footer: (foot) => {
29252
+ foot.style.cssText = `padding:10px 14px;display:flex;align-items:center;justify-content:flex-start;gap:8px;`;
29253
+ const resetBtn = document.createElement("button");
29254
+ resetBtn.type = "button";
29255
+ resetBtn.textContent = "Reset defaults";
29256
+ resetBtn.className = "vela-sd-btn";
29257
+ resetBtn.addEventListener("click", () => this.onReset?.());
29258
+ foot.appendChild(resetBtn);
29259
+ },
29260
+ // A close signal may only close ITS OWN dialog: the machine reports the exit
29261
+ // asynchronously, so a close-then-reopen in one tick would otherwise see the
29262
+ // old instance's signal tear down the freshly opened one.
29263
+ onOpenChange: (open2) => {
29264
+ if (!open2 && this.ui === ui) this.close();
29265
+ }
29266
+ });
29267
+ if (mobile) ui.positioner.classList.add("vela-sd-mobile");
29268
+ ui.positioner.style.paddingTop = mobile ? "0" : "8vh";
29269
+ this.root = ui.positioner;
29270
+ this.ui = ui;
29271
+ const panes = this.buildContent(ui, config, section, mobile);
29272
+ ui.show();
29273
+ this.layoutPanes(panes);
29274
+ }
29275
+ /**
29276
+ * Re-seed every control of an OPEN dialog from `config`, in place: the shell stays
29277
+ * (no close/open transition), only the tab rail and panes rebuild, landing back on
29278
+ * the current tab. The reset path — the restored values must show without the
29279
+ * dialog re-entering. No-op while closed.
29280
+ */
29281
+ refresh(config) {
29282
+ const ui = this.ui;
29283
+ if (!ui) return;
29284
+ closeOpenPopovers();
29285
+ closeWidthPopover();
29286
+ for (const dispose of this.hintTips) dispose();
29287
+ this.hintTips = [];
29288
+ this.config = config;
29289
+ ui.body.replaceChildren();
29290
+ this.layoutPanes(this.buildContent(ui, config, this.activeSection ?? void 0, this.mobileLayout));
29291
+ }
29292
+ /** Structured chart-type panes (instance strip / group TOC) own their layout and
29293
+ * tag their rows hosts instead; each host gets its own field grid. Runs on a SHOWN
29294
+ * dialog — the grids measure their labels. */
29295
+ layoutPanes(panes) {
29296
+ for (const el of panes) {
29297
+ const hosts = [...el.querySelectorAll("[data-sd-rows-host]")];
29298
+ if (hosts.length === 0) {
29299
+ this.layoutSettingsGrids(el);
29300
+ continue;
29301
+ }
29302
+ for (const h of hosts) this.layoutSettingsGrids(h);
29156
29303
  }
29304
+ }
29305
+ /**
29306
+ * Build the tab rail + one pane per section into `ui.body` (the linear `body` of
29307
+ * section markers and rows is split afterwards), select `section` (the active
29308
+ * style's own tab when none is asked for), and return the pane elements for
29309
+ * {@link layoutPanes}.
29310
+ */
29311
+ buildContent(ui, config, section, mobile) {
29157
29312
  const body = document.createElement("div");
29158
29313
  body.style.cssText = "display:flex;flex-direction:column;gap:0;";
29159
29314
  const sid = (el, id) => {
@@ -29357,9 +29512,28 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29357
29512
  if (this.markGroups.length > 0) {
29358
29513
  body.append(sid(this.section("Events"), MARKS_SETTINGS_ID));
29359
29514
  body.append(sid(this.sectionTitle("Visible events"), MARKS_GROUPS_SETTINGS_ID));
29360
- for (const g of this.markGroups) {
29361
- body.append(sid(this.boolRow(g.label, this.markGroupVisible(g.id), (v) => this.emit({ marks: { groups: { [g.id]: v } } })), markGroupSettingsId(g.id)));
29515
+ const rowsById = /* @__PURE__ */ new Map();
29516
+ const rows = markGroupRows(this.markGroups);
29517
+ const refreshDimming = () => {
29518
+ for (const { group } of rows) {
29519
+ const el = rowsById.get(group.id);
29520
+ if (!el || group.parent === void 0) continue;
29521
+ el.classList.toggle("vela-sd-soft", !this.markGroupVisible(group.parent));
29522
+ }
29523
+ };
29524
+ for (const { group: g, depth } of rows) {
29525
+ const row = this.boolRow(g.label, this.markGroupOwnVisible(g.id), (v) => {
29526
+ this.emit({ marks: { groups: { [g.id]: v } } });
29527
+ refreshDimming();
29528
+ });
29529
+ if (depth > 0) {
29530
+ row.classList.add("vela-sd-nested");
29531
+ row.style.setProperty("--vela-sd-depth", String(depth));
29532
+ }
29533
+ rowsById.set(g.id, row);
29534
+ body.append(sid(row, markGroupSettingsId(g.id)));
29362
29535
  }
29536
+ refreshDimming();
29363
29537
  }
29364
29538
  renderChartTypeSections("end");
29365
29539
  renderHostSections("end");
@@ -29387,8 +29561,8 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29387
29561
  if (mobile) {
29388
29562
  railScrim = document.createElement("div");
29389
29563
  railScrim.className = "vela-sd-railscrim";
29390
- railScrim.addEventListener("click", () => toggleRail?.());
29391
- toggleRail = (open2) => {
29564
+ railScrim.addEventListener("click", () => this.toggleRail?.());
29565
+ this.toggleRail = (open2) => {
29392
29566
  const on = open2 ?? !rail.classList.contains("open");
29393
29567
  rail.classList.toggle("open", on);
29394
29568
  railScrim?.classList.toggle("open", on);
@@ -29428,35 +29602,6 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29428
29602
  });
29429
29603
  if (hidActive) activate(0);
29430
29604
  };
29431
- const ui = new Dialog({
29432
- host: this.container,
29433
- title: "Chart settings",
29434
- // Non-modal: a live-edit dialog must leave the page interactive — a modal
29435
- // machine locks pointer events on the whole body, killing the chart, the
29436
- // legend, and the body-portaled popovers (color picker, select lists).
29437
- modal: false,
29438
- contained: true,
29439
- align: "top",
29440
- draggable: !mobile,
29441
- flush: true,
29442
- className: "vela-dialog--settings",
29443
- headerStart: burger,
29444
- closeOnBackdrop: true,
29445
- footer: (foot) => {
29446
- foot.style.cssText = `padding:10px 14px;display:flex;align-items:center;justify-content:flex-start;gap:8px;`;
29447
- const resetBtn = document.createElement("button");
29448
- resetBtn.type = "button";
29449
- resetBtn.textContent = "Reset defaults";
29450
- resetBtn.className = "vela-sd-btn";
29451
- resetBtn.addEventListener("click", () => this.onReset?.());
29452
- foot.appendChild(resetBtn);
29453
- },
29454
- onOpenChange: (open2) => {
29455
- if (!open2) this.close();
29456
- }
29457
- });
29458
- if (mobile) ui.positioner.classList.add("vela-sd-mobile");
29459
- ui.positioner.style.paddingTop = mobile ? "0" : "8vh";
29460
29605
  const activate = (idx) => {
29461
29606
  panes.forEach((p, i) => {
29462
29607
  p.el.style.display = i === idx ? "block" : "none";
@@ -29465,7 +29610,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29465
29610
  this.activeSection = panes[idx]?.title ?? null;
29466
29611
  if (mobile) {
29467
29612
  ui.titleEl.textContent = panes[idx]?.title ?? "Chart settings";
29468
- toggleRail?.(false);
29613
+ this.toggleRail?.(false);
29469
29614
  }
29470
29615
  };
29471
29616
  panes.forEach((p, i) => {
@@ -29480,17 +29625,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29480
29625
  shell.append(rail, paneHost);
29481
29626
  if (railScrim) shell.append(railScrim);
29482
29627
  ui.body.appendChild(shell);
29483
- this.root = ui.positioner;
29484
- this.ui = ui;
29485
- ui.show();
29486
- for (const p of panes) {
29487
- const hosts = [...p.el.querySelectorAll("[data-sd-rows-host]")];
29488
- if (hosts.length === 0) {
29489
- this.layoutSettingsGrids(p.el);
29490
- continue;
29491
- }
29492
- for (const h of hosts) this.layoutSettingsGrids(h);
29493
- }
29628
+ return panes.map((p) => p.el);
29494
29629
  }
29495
29630
  close() {
29496
29631
  closeOpenPopovers();
@@ -29498,6 +29633,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
29498
29633
  const ui = this.ui;
29499
29634
  this.ui = null;
29500
29635
  this.root = null;
29636
+ this.toggleRail = null;
29501
29637
  this.tabs = [];
29502
29638
  for (const dispose of this.hintTips) dispose();
29503
29639
  this.hintTips = [];
@@ -37597,7 +37733,11 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37597
37733
  }
37598
37734
  this.settingsDialog.setTheme(this.theme);
37599
37735
  this.settingsDialog.setHostSections(this.hostSettingsSections);
37600
- this.settingsDialog.setMarkGroups(this.markGroupsInUse(), (id) => markGroupVisible(this.scene.marks, id, this.scene.markGroups));
37736
+ this.settingsDialog.setMarkGroups(
37737
+ this.markGroupsForEventsTab(),
37738
+ (id) => markGroupVisible2(this.scene.marks, id, this.scene.markGroups),
37739
+ (id) => markGroupOwnVisible(this.scene.marks.groups, id, this.scene.markGroups)
37740
+ );
37601
37741
  this.settingsDialog.setHiddenSettings(this.hiddenSettings);
37602
37742
  this.syncThemeControl();
37603
37743
  this.settingsDialog.toggle(
@@ -37605,13 +37745,24 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37605
37745
  (patch) => this.applyConfig(patch),
37606
37746
  (json) => this.applyConfig(json),
37607
37747
  () => {
37608
- if (this.factoryConfig) this.applyConfig(factoryResetConfig(this.factoryConfig));
37609
- this.settingsDialog?.close();
37610
- this.openSettingsDialog();
37748
+ if (this.factoryConfig) this.applyConfig(this.factoryResetDocument(this.factoryConfig));
37749
+ this.settingsDialog?.refresh(this.getConfig());
37611
37750
  },
37612
37751
  section
37613
37752
  );
37614
37753
  }
37754
+ /**
37755
+ * The document "Reset defaults" applies: every setting back to its first-run value,
37756
+ * with two things that are NOT settings held or resolved here — the price style
37757
+ * stays the one the user is looking at, and the timeline-mark groups (an additive
37758
+ * merge, like the type bags) are named back to their host-declared visibility.
37759
+ */
37760
+ factoryResetDocument(factory) {
37761
+ const doc = factoryResetConfig(factory, this.scene.priceStyle);
37762
+ const groups = { ...doc.marks.groups };
37763
+ for (const g of this.markGroupsInUse()) groups[g.id] = g.visible !== false;
37764
+ return { ...doc, marks: { ...doc.marks, groups } };
37765
+ }
37615
37766
  /** Close the in-chart dialogs (indicator settings + chart-settings gear). No-op when none are open. */
37616
37767
  closeDialogs() {
37617
37768
  this.inputsUI?.closeOpenDialog();
@@ -38674,6 +38825,15 @@ ${overlayScrollbarCss(".vela-sd-pane")}
38674
38825
  markGroupsInUse() {
38675
38826
  return effectiveMarkGroups(this.scene.timelineMarks, this.scene.markGroups);
38676
38827
  }
38828
+ /**
38829
+ * The groups as the Events tab lists them: nested only under a DEFINED parent. The
38830
+ * painter's visibility chain resolves parents against the defined groups alone, so a
38831
+ * parent that marks merely name must not nest (and dim) a child the painter still shows.
38832
+ */
38833
+ markGroupsForEventsTab() {
38834
+ const defined = new Set(this.scene.markGroups.map((g) => g.id));
38835
+ return this.markGroupsInUse().map((g) => g.parent !== void 0 && !defined.has(g.parent) ? { ...g, parent: void 0 } : g);
38836
+ }
38677
38837
  onViewportChange(cb) {
38678
38838
  this.viewportCbs.add(cb);
38679
38839
  return () => this.viewportCbs.delete(cb);