@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
@@ -5061,6 +5061,17 @@ function hasOwnCandlePaint(style) {
5061
5061
  for (const t of chartTypes()) if (t.id === style) return (t.basePainting ?? "candles") === "candles";
5062
5062
  return false;
5063
5063
  }
5064
+ var CANDLE_OVERRIDE_KEYS = [
5065
+ "candleUpColor",
5066
+ "candleDownColor",
5067
+ "candleBodyVisible",
5068
+ "candleBorderVisible",
5069
+ "candleBorderUpColor",
5070
+ "candleBorderDownColor",
5071
+ "candleWickVisible",
5072
+ "candleWickUpColor",
5073
+ "candleWickDownColor"
5074
+ ];
5064
5075
  function candleOverrideFor(style, bags) {
5065
5076
  if (!hasOwnCandlePaint(style)) return null;
5066
5077
  const bag = bags[style] ?? {};
@@ -5132,7 +5143,7 @@ function clampLevel(v) {
5132
5143
  function clampSpacing(v) {
5133
5144
  return v < 0.1 ? 0.1 : v > 10 ? 10 : v;
5134
5145
  }
5135
- function factoryResetConfig(factory) {
5146
+ function factoryResetConfig(factory, priceStyle = factory.series.style) {
5136
5147
  const bag = {};
5137
5148
  for (const t of chartTypes()) {
5138
5149
  const section = t.settings;
@@ -5154,10 +5165,16 @@ function factoryResetConfig(factory) {
5154
5165
  if (!section.instances) addRows(section.rows);
5155
5166
  bag[t.id] = defaults2;
5156
5167
  }
5168
+ for (const t of chartTypes()) {
5169
+ if (!hasOwnCandlePaint(t.id)) continue;
5170
+ const defaults2 = bag[t.id] ?? {};
5171
+ for (const key of CANDLE_OVERRIDE_KEYS) defaults2[key] = null;
5172
+ bag[t.id] = defaults2;
5173
+ }
5157
5174
  for (const [typeId, vals] of Object.entries(factory.chartTypes)) {
5158
5175
  bag[typeId] = { ...bag[typeId] ?? {}, ...vals };
5159
5176
  }
5160
- return { ...factory, chartTypes: bag };
5177
+ return { ...factory, chartTypes: bag, series: { ...factory.series, style: priceStyle } };
5161
5178
  }
5162
5179
  function mergeConfig(base, patch) {
5163
5180
  const p = asObject(patch);
@@ -18585,6 +18602,42 @@ function presetToRange(preset, bars) {
18585
18602
  return { from: Math.max(first, from), to: last };
18586
18603
  }
18587
18604
 
18605
+ // src/core/marks/visibility.ts
18606
+ function markGroupOwnVisible(choices, groupId, groups) {
18607
+ const chosen = choices[groupId];
18608
+ if (typeof chosen === "boolean") return chosen;
18609
+ return groups.find((g) => g.id === groupId)?.visible !== false;
18610
+ }
18611
+ function markGroupVisible(choices, groupId, groups) {
18612
+ if (groupId === void 0) return true;
18613
+ const seen = /* @__PURE__ */ new Set();
18614
+ let id = groupId;
18615
+ while (id !== void 0 && !seen.has(id)) {
18616
+ seen.add(id);
18617
+ if (!markGroupOwnVisible(choices, id, groups)) return false;
18618
+ const parent = groups.find((g) => g.id === id)?.parent;
18619
+ id = parent !== void 0 && groups.some((g) => g.id === parent) ? parent : void 0;
18620
+ }
18621
+ return true;
18622
+ }
18623
+ function markGroupRows(groups) {
18624
+ const ids = new Set(groups.map((g) => g.id));
18625
+ const out = [];
18626
+ const placed = /* @__PURE__ */ new Set();
18627
+ const place = (group, depth) => {
18628
+ if (placed.has(group.id)) return;
18629
+ placed.add(group.id);
18630
+ out.push({ group, depth });
18631
+ for (const child of groups) if (child.parent === group.id && child.id !== group.id) place(child, depth + 1);
18632
+ };
18633
+ for (const g of groups) {
18634
+ const parentKnown = g.parent !== void 0 && ids.has(g.parent) && g.parent !== g.id;
18635
+ if (!parentKnown) place(g, 0);
18636
+ }
18637
+ for (const g of groups) place(g, 0);
18638
+ return out;
18639
+ }
18640
+
18588
18641
  // src/core/marks/MarksController.ts
18589
18642
  var MarksController = class {
18590
18643
  constructor(renderer, events) {
@@ -18629,6 +18682,7 @@ var MarksController = class {
18629
18682
  defineGroup(group) {
18630
18683
  if (!group || typeof group.id !== "string" || group.id.length === 0) throw new Error("[vela] marks.defineGroup: `id` must be a non-empty string");
18631
18684
  if (typeof group.label !== "string") throw new Error(`[vela] marks.defineGroup: group "${group.id}" needs a string \`label\``);
18685
+ 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`);
18632
18686
  this.groups.set(group.id, { ...group });
18633
18687
  this.sync();
18634
18688
  }
@@ -18648,12 +18702,16 @@ var MarksController = class {
18648
18702
  }
18649
18703
  this.renderer.applyFeature("marks", { groups: { [id]: visible } });
18650
18704
  }
18651
- /** A group's effective visibility: the user's (persisted) choice, else the group's declared default, else visible. */
18705
+ /**
18706
+ * A group's effective visibility: its own switch — the user's (persisted) choice, else
18707
+ * the declared default, else visible — AND every ancestor's, so a child under a
18708
+ * switched-off parent reads hidden whatever its own choice says.
18709
+ */
18652
18710
  isGroupVisible(id) {
18653
18711
  const state = this.renderer.readFeature("marks");
18654
- const chosen = state?.groups?.[id];
18655
- if (typeof chosen === "boolean") return chosen;
18656
- return this.groups.get(id)?.visible !== false;
18712
+ const groups = {};
18713
+ for (const [gid, v] of Object.entries(state?.groups ?? {})) if (typeof v === "boolean") groups[gid] = v;
18714
+ return markGroupVisible(groups, id, [...this.groups.values()]);
18657
18715
  }
18658
18716
  destroy() {
18659
18717
  for (const unsub of this.subs) unsub();
@@ -25642,11 +25700,8 @@ function mergeMarksState(base, patch) {
25642
25700
  for (const [id, v] of Object.entries(g)) if (typeof v === "boolean") groups[id] = v;
25643
25701
  return { visible: typeof p.visible === "boolean" ? p.visible : base.visible, groups };
25644
25702
  }
25645
- function markGroupVisible(state, groupId, groups) {
25646
- if (groupId === void 0) return true;
25647
- const chosen = state.groups[groupId];
25648
- if (typeof chosen === "boolean") return chosen;
25649
- return groups.find((g) => g.id === groupId)?.visible !== false;
25703
+ function markGroupVisible2(state, groupId, groups) {
25704
+ return markGroupVisible(state.groups, groupId, groups);
25650
25705
  }
25651
25706
 
25652
25707
  // src/renderers/native/core/SceneGraph.ts
@@ -27822,13 +27877,29 @@ function paintMarkLane(ctx, layout, deps) {
27822
27877
  const img = deps.icons.get(mark.glyph.icon, ink, symbolPx, deps.dpr);
27823
27878
  if (img) ctx.drawImage(img, center.x - symbolPx / 2, center.y - symbolPx / 2, symbolPx, symbolPx);
27824
27879
  } else if (mark.glyph.letter) {
27880
+ const letter = mark.glyph.letter.slice(0, 2);
27825
27881
  ctx.fillStyle = ink;
27826
- ctx.font = `600 ${Math.round(size * 0.58)}px ${deps.fontFamily}`;
27827
- ctx.fillText(mark.glyph.letter.slice(0, 2), center.x, center.y + 0.5);
27882
+ let px = letterFontPx(size, letter);
27883
+ ctx.font = `600 ${px}px ${deps.fontFamily}`;
27884
+ if (letter.length > 1) {
27885
+ px = fitLetterPx(px, ctx.measureText(letter).width, symbolInnerWidth(shape, size));
27886
+ ctx.font = `600 ${px}px ${deps.fontFamily}`;
27887
+ }
27888
+ ctx.fillText(letter, center.x, center.y + 0.5);
27828
27889
  }
27829
27890
  }
27830
27891
  ctx.restore();
27831
27892
  }
27893
+ function letterFontPx(size, letter) {
27894
+ return Math.round(size * (letter.length > 1 ? 0.38 : 0.58));
27895
+ }
27896
+ function symbolInnerWidth(shape, size) {
27897
+ return (shape === "pin" ? size * 0.82 : size) - 3;
27898
+ }
27899
+ function fitLetterPx(px, width, inner) {
27900
+ if (!(width > inner) || !(width > 0)) return px;
27901
+ return Math.max(4, Math.floor(px * inner / width));
27902
+ }
27832
27903
  function traceShape(ctx, shape, x, y, size) {
27833
27904
  const r = size / 2;
27834
27905
  ctx.beginPath();
@@ -28030,7 +28101,7 @@ var ChromeRenderer = class {
28030
28101
  this.markLayout = layoutMarkLane({
28031
28102
  marks: scene.timelineMarks,
28032
28103
  groups: scene.markGroups,
28033
- hidden: (groupId) => !markGroupVisible(scene.marks, groupId, scene.markGroups),
28104
+ hidden: (groupId) => !markGroupVisible2(scene.marks, groupId, scene.markGroups),
28034
28105
  barTimes: this.barTimes(scene),
28035
28106
  intervalMs: coords.barInterval,
28036
28107
  xOf: (bar) => coords.logicalToX(bar),
@@ -28720,6 +28791,10 @@ ${overlayScrollbarCss(".vela-sd-pane")}
28720
28791
  muted and non-interactive. Applied to each row's children so it survives display:contents;
28721
28792
  !important beats the inline opacity on labels. */
28722
28793
  .vela-sd-soft>*{opacity:0.4 !important;pointer-events:none !important;}
28794
+ /* A mark group nested under a parent group on the Events tab: indented one step per level
28795
+ (--vela-sd-depth). The indent rides the first child (the switch) as a MARGIN \u2014 padding
28796
+ would push the switch's own tick out of its box. */
28797
+ .vela-sd-nested>*:first-child{margin-left:calc(var(--vela-sd-depth,1)*24px);}
28723
28798
  /* \u2500\u2500 mobile presentation (.vela-sd-mobile on the scrim; structural sizes are inline in open()) \u2500\u2500
28724
28799
  The tab rail becomes a burger-opened overlay sidebar; the group TOC becomes a sticky
28725
28800
  row of horizontally scrollable tabs; the instance strip scrolls instead of wrapping;
@@ -28768,6 +28843,8 @@ var SettingsDialog = class {
28768
28843
  this.hostSections = [];
28769
28844
  /** The timeline-mark groups (defined + named by marks) — one checkbox each on the Events tab. */
28770
28845
  this.markGroups = [];
28846
+ /** A group's OWN switch (what its checkbox shows) — a child under an off parent keeps its own state. */
28847
+ this.markGroupOwnVisible = () => true;
28771
28848
  this.markGroupVisible = () => true;
28772
28849
  /** The Canvas → Theme row: current app theme + where a pick is raised. The row is a
28773
28850
  * host callback, NOT a config patch — the app theme stays out of the persisted
@@ -28785,6 +28862,9 @@ var SettingsDialog = class {
28785
28862
  this.activeSection = null;
28786
28863
  /** Mobile chrome: fullscreen card, burger-opened section sidebar, TOC as top tabs. */
28787
28864
  this.mobileLayout = false;
28865
+ /** Opens/closes the mobile section sidebar of the CURRENT build (the burger in the
28866
+ * shell header outlives pane rebuilds, so it reaches the rail through here). */
28867
+ this.toggleRail = null;
28788
28868
  /** The visibility policy: setting ids hidden by the host (subtree semantics). */
28789
28869
  this.hiddenSettings = /* @__PURE__ */ new Set();
28790
28870
  if (getComputedStyle(container).position === "static") container.style.position = "relative";
@@ -28794,7 +28874,8 @@ var SettingsDialog = class {
28794
28874
  this.hostSections = sections;
28795
28875
  }
28796
28876
  /** The timeline-mark groups and their current visibility — the Events tab's rows on next open. */
28797
- setMarkGroups(groups, visible) {
28877
+ setMarkGroups(groups, visible, ownVisible = visible) {
28878
+ this.markGroupOwnVisible = ownVisible;
28798
28879
  this.markGroups = groups;
28799
28880
  this.markGroupVisible = visible;
28800
28881
  }
@@ -28860,7 +28941,6 @@ var SettingsDialog = class {
28860
28941
  this.onReset = onReset ?? null;
28861
28942
  ensureControlStyles();
28862
28943
  const mobile = this.mobileLayout;
28863
- let toggleRail = null;
28864
28944
  let burger;
28865
28945
  if (mobile) {
28866
28946
  burger = document.createElement("button");
@@ -28868,8 +28948,83 @@ var SettingsDialog = class {
28868
28948
  burger.className = "vela-sd-burger";
28869
28949
  burger.innerHTML = iconAt("burger", 16);
28870
28950
  burger.title = "Sections";
28871
- burger.addEventListener("click", () => toggleRail?.());
28951
+ burger.addEventListener("click", () => this.toggleRail?.());
28872
28952
  }
28953
+ const ui = new Dialog({
28954
+ host: this.container,
28955
+ title: "Chart settings",
28956
+ // Non-modal: a live-edit dialog must leave the page interactive — a modal
28957
+ // machine locks pointer events on the whole body, killing the chart, the
28958
+ // legend, and the body-portaled popovers (color picker, select lists).
28959
+ modal: false,
28960
+ contained: true,
28961
+ align: "top",
28962
+ draggable: !mobile,
28963
+ flush: true,
28964
+ className: "vela-dialog--settings",
28965
+ headerStart: burger,
28966
+ closeOnBackdrop: true,
28967
+ footer: (foot) => {
28968
+ foot.style.cssText = `padding:10px 14px;display:flex;align-items:center;justify-content:flex-start;gap:8px;`;
28969
+ const resetBtn = document.createElement("button");
28970
+ resetBtn.type = "button";
28971
+ resetBtn.textContent = "Reset defaults";
28972
+ resetBtn.className = "vela-sd-btn";
28973
+ resetBtn.addEventListener("click", () => this.onReset?.());
28974
+ foot.appendChild(resetBtn);
28975
+ },
28976
+ // A close signal may only close ITS OWN dialog: the machine reports the exit
28977
+ // asynchronously, so a close-then-reopen in one tick would otherwise see the
28978
+ // old instance's signal tear down the freshly opened one.
28979
+ onOpenChange: (open2) => {
28980
+ if (!open2 && this.ui === ui) this.close();
28981
+ }
28982
+ });
28983
+ if (mobile) ui.positioner.classList.add("vela-sd-mobile");
28984
+ ui.positioner.style.paddingTop = mobile ? "0" : "8vh";
28985
+ this.root = ui.positioner;
28986
+ this.ui = ui;
28987
+ const panes = this.buildContent(ui, config, section, mobile);
28988
+ ui.show();
28989
+ this.layoutPanes(panes);
28990
+ }
28991
+ /**
28992
+ * Re-seed every control of an OPEN dialog from `config`, in place: the shell stays
28993
+ * (no close/open transition), only the tab rail and panes rebuild, landing back on
28994
+ * the current tab. The reset path — the restored values must show without the
28995
+ * dialog re-entering. No-op while closed.
28996
+ */
28997
+ refresh(config) {
28998
+ const ui = this.ui;
28999
+ if (!ui) return;
29000
+ closeOpenPopovers();
29001
+ closeWidthPopover();
29002
+ for (const dispose of this.hintTips) dispose();
29003
+ this.hintTips = [];
29004
+ this.config = config;
29005
+ ui.body.replaceChildren();
29006
+ this.layoutPanes(this.buildContent(ui, config, this.activeSection ?? void 0, this.mobileLayout));
29007
+ }
29008
+ /** Structured chart-type panes (instance strip / group TOC) own their layout and
29009
+ * tag their rows hosts instead; each host gets its own field grid. Runs on a SHOWN
29010
+ * dialog — the grids measure their labels. */
29011
+ layoutPanes(panes) {
29012
+ for (const el of panes) {
29013
+ const hosts = [...el.querySelectorAll("[data-sd-rows-host]")];
29014
+ if (hosts.length === 0) {
29015
+ this.layoutSettingsGrids(el);
29016
+ continue;
29017
+ }
29018
+ for (const h of hosts) this.layoutSettingsGrids(h);
29019
+ }
29020
+ }
29021
+ /**
29022
+ * Build the tab rail + one pane per section into `ui.body` (the linear `body` of
29023
+ * section markers and rows is split afterwards), select `section` (the active
29024
+ * style's own tab when none is asked for), and return the pane elements for
29025
+ * {@link layoutPanes}.
29026
+ */
29027
+ buildContent(ui, config, section, mobile) {
28873
29028
  const body = document.createElement("div");
28874
29029
  body.style.cssText = "display:flex;flex-direction:column;gap:0;";
28875
29030
  const sid = (el, id) => {
@@ -29073,9 +29228,28 @@ var SettingsDialog = class {
29073
29228
  if (this.markGroups.length > 0) {
29074
29229
  body.append(sid(this.section("Events"), MARKS_SETTINGS_ID));
29075
29230
  body.append(sid(this.sectionTitle("Visible events"), MARKS_GROUPS_SETTINGS_ID));
29076
- for (const g of this.markGroups) {
29077
- body.append(sid(this.boolRow(g.label, this.markGroupVisible(g.id), (v) => this.emit({ marks: { groups: { [g.id]: v } } })), markGroupSettingsId(g.id)));
29231
+ const rowsById = /* @__PURE__ */ new Map();
29232
+ const rows = markGroupRows(this.markGroups);
29233
+ const refreshDimming = () => {
29234
+ for (const { group } of rows) {
29235
+ const el = rowsById.get(group.id);
29236
+ if (!el || group.parent === void 0) continue;
29237
+ el.classList.toggle("vela-sd-soft", !this.markGroupVisible(group.parent));
29238
+ }
29239
+ };
29240
+ for (const { group: g, depth } of rows) {
29241
+ const row = this.boolRow(g.label, this.markGroupOwnVisible(g.id), (v) => {
29242
+ this.emit({ marks: { groups: { [g.id]: v } } });
29243
+ refreshDimming();
29244
+ });
29245
+ if (depth > 0) {
29246
+ row.classList.add("vela-sd-nested");
29247
+ row.style.setProperty("--vela-sd-depth", String(depth));
29248
+ }
29249
+ rowsById.set(g.id, row);
29250
+ body.append(sid(row, markGroupSettingsId(g.id)));
29078
29251
  }
29252
+ refreshDimming();
29079
29253
  }
29080
29254
  renderChartTypeSections("end");
29081
29255
  renderHostSections("end");
@@ -29103,8 +29277,8 @@ var SettingsDialog = class {
29103
29277
  if (mobile) {
29104
29278
  railScrim = document.createElement("div");
29105
29279
  railScrim.className = "vela-sd-railscrim";
29106
- railScrim.addEventListener("click", () => toggleRail?.());
29107
- toggleRail = (open2) => {
29280
+ railScrim.addEventListener("click", () => this.toggleRail?.());
29281
+ this.toggleRail = (open2) => {
29108
29282
  const on = open2 ?? !rail.classList.contains("open");
29109
29283
  rail.classList.toggle("open", on);
29110
29284
  railScrim?.classList.toggle("open", on);
@@ -29144,35 +29318,6 @@ var SettingsDialog = class {
29144
29318
  });
29145
29319
  if (hidActive) activate(0);
29146
29320
  };
29147
- const ui = new Dialog({
29148
- host: this.container,
29149
- title: "Chart settings",
29150
- // Non-modal: a live-edit dialog must leave the page interactive — a modal
29151
- // machine locks pointer events on the whole body, killing the chart, the
29152
- // legend, and the body-portaled popovers (color picker, select lists).
29153
- modal: false,
29154
- contained: true,
29155
- align: "top",
29156
- draggable: !mobile,
29157
- flush: true,
29158
- className: "vela-dialog--settings",
29159
- headerStart: burger,
29160
- closeOnBackdrop: true,
29161
- footer: (foot) => {
29162
- foot.style.cssText = `padding:10px 14px;display:flex;align-items:center;justify-content:flex-start;gap:8px;`;
29163
- const resetBtn = document.createElement("button");
29164
- resetBtn.type = "button";
29165
- resetBtn.textContent = "Reset defaults";
29166
- resetBtn.className = "vela-sd-btn";
29167
- resetBtn.addEventListener("click", () => this.onReset?.());
29168
- foot.appendChild(resetBtn);
29169
- },
29170
- onOpenChange: (open2) => {
29171
- if (!open2) this.close();
29172
- }
29173
- });
29174
- if (mobile) ui.positioner.classList.add("vela-sd-mobile");
29175
- ui.positioner.style.paddingTop = mobile ? "0" : "8vh";
29176
29321
  const activate = (idx) => {
29177
29322
  panes.forEach((p, i) => {
29178
29323
  p.el.style.display = i === idx ? "block" : "none";
@@ -29181,7 +29326,7 @@ var SettingsDialog = class {
29181
29326
  this.activeSection = panes[idx]?.title ?? null;
29182
29327
  if (mobile) {
29183
29328
  ui.titleEl.textContent = panes[idx]?.title ?? "Chart settings";
29184
- toggleRail?.(false);
29329
+ this.toggleRail?.(false);
29185
29330
  }
29186
29331
  };
29187
29332
  panes.forEach((p, i) => {
@@ -29196,17 +29341,7 @@ var SettingsDialog = class {
29196
29341
  shell.append(rail, paneHost);
29197
29342
  if (railScrim) shell.append(railScrim);
29198
29343
  ui.body.appendChild(shell);
29199
- this.root = ui.positioner;
29200
- this.ui = ui;
29201
- ui.show();
29202
- for (const p of panes) {
29203
- const hosts = [...p.el.querySelectorAll("[data-sd-rows-host]")];
29204
- if (hosts.length === 0) {
29205
- this.layoutSettingsGrids(p.el);
29206
- continue;
29207
- }
29208
- for (const h of hosts) this.layoutSettingsGrids(h);
29209
- }
29344
+ return panes.map((p) => p.el);
29210
29345
  }
29211
29346
  close() {
29212
29347
  closeOpenPopovers();
@@ -29214,6 +29349,7 @@ var SettingsDialog = class {
29214
29349
  const ui = this.ui;
29215
29350
  this.ui = null;
29216
29351
  this.root = null;
29352
+ this.toggleRail = null;
29217
29353
  this.tabs = [];
29218
29354
  for (const dispose of this.hintTips) dispose();
29219
29355
  this.hintTips = [];
@@ -36532,7 +36668,11 @@ var NativeRenderer = class {
36532
36668
  }
36533
36669
  this.settingsDialog.setTheme(this.theme);
36534
36670
  this.settingsDialog.setHostSections(this.hostSettingsSections);
36535
- this.settingsDialog.setMarkGroups(this.markGroupsInUse(), (id) => markGroupVisible(this.scene.marks, id, this.scene.markGroups));
36671
+ this.settingsDialog.setMarkGroups(
36672
+ this.markGroupsForEventsTab(),
36673
+ (id) => markGroupVisible2(this.scene.marks, id, this.scene.markGroups),
36674
+ (id) => markGroupOwnVisible(this.scene.marks.groups, id, this.scene.markGroups)
36675
+ );
36536
36676
  this.settingsDialog.setHiddenSettings(this.hiddenSettings);
36537
36677
  this.syncThemeControl();
36538
36678
  this.settingsDialog.toggle(
@@ -36540,13 +36680,24 @@ var NativeRenderer = class {
36540
36680
  (patch) => this.applyConfig(patch),
36541
36681
  (json) => this.applyConfig(json),
36542
36682
  () => {
36543
- if (this.factoryConfig) this.applyConfig(factoryResetConfig(this.factoryConfig));
36544
- this.settingsDialog?.close();
36545
- this.openSettingsDialog();
36683
+ if (this.factoryConfig) this.applyConfig(this.factoryResetDocument(this.factoryConfig));
36684
+ this.settingsDialog?.refresh(this.getConfig());
36546
36685
  },
36547
36686
  section
36548
36687
  );
36549
36688
  }
36689
+ /**
36690
+ * The document "Reset defaults" applies: every setting back to its first-run value,
36691
+ * with two things that are NOT settings held or resolved here — the price style
36692
+ * stays the one the user is looking at, and the timeline-mark groups (an additive
36693
+ * merge, like the type bags) are named back to their host-declared visibility.
36694
+ */
36695
+ factoryResetDocument(factory) {
36696
+ const doc = factoryResetConfig(factory, this.scene.priceStyle);
36697
+ const groups = { ...doc.marks.groups };
36698
+ for (const g of this.markGroupsInUse()) groups[g.id] = g.visible !== false;
36699
+ return { ...doc, marks: { ...doc.marks, groups } };
36700
+ }
36550
36701
  /** Close the in-chart dialogs (indicator settings + chart-settings gear). No-op when none are open. */
36551
36702
  closeDialogs() {
36552
36703
  this.inputsUI?.closeOpenDialog();
@@ -37609,6 +37760,15 @@ var NativeRenderer = class {
37609
37760
  markGroupsInUse() {
37610
37761
  return effectiveMarkGroups(this.scene.timelineMarks, this.scene.markGroups);
37611
37762
  }
37763
+ /**
37764
+ * The groups as the Events tab lists them: nested only under a DEFINED parent. The
37765
+ * painter's visibility chain resolves parents against the defined groups alone, so a
37766
+ * parent that marks merely name must not nest (and dim) a child the painter still shows.
37767
+ */
37768
+ markGroupsForEventsTab() {
37769
+ const defined = new Set(this.scene.markGroups.map((g) => g.id));
37770
+ return this.markGroupsInUse().map((g) => g.parent !== void 0 && !defined.has(g.parent) ? { ...g, parent: void 0 } : g);
37771
+ }
37612
37772
  onViewportChange(cb) {
37613
37773
  this.viewportCbs.add(cb);
37614
37774
  return () => this.viewportCbs.delete(cb);
@@ -43501,6 +43661,11 @@ var ChartCell = class {
43501
43661
  if (typeof zone === "string" && normalizeTimezone(zone) !== normalizeTimezone(this.deps.timezone())) {
43502
43662
  this.deps.setTimezone(normalizeTimezone(zone));
43503
43663
  }
43664
+ const style = this.priceStyle;
43665
+ if (style !== (this.state.priceStyle ?? "candles")) {
43666
+ this.state.priceStyle = style;
43667
+ this.deps.onPriceStyleChanged(this.id);
43668
+ }
43504
43669
  this.syncStatuslineColors();
43505
43670
  this.syncPlotOverlayTokens();
43506
43671
  });
@@ -1,9 +1,9 @@
1
- import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, I as InputValue, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-XVpfr9HV.cjs';
2
- import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as StatuslinePart, b as RangePreset, T as TrackSizes, c as VelaShellOptions, d as SyncOptions, e as SyncKind, f as WorkspaceState } from './statusline-model-Bd4qKuD6.cjs';
3
- export { g as ChartState, P as PanelsState, h as decodeState, i as encodeState, s as sanitizeState } from './statusline-model-Bd4qKuD6.cjs';
1
+ import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, I as InputValue, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-DNBoMKkX.cjs';
2
+ import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as StatuslinePart, b as RangePreset, T as TrackSizes, c as VelaShellOptions, d as SyncOptions, e as SyncKind, f as WorkspaceState } from './statusline-model-gA__yaog.cjs';
3
+ export { g as ChartState, P as PanelsState, h as decodeState, i as encodeState, s as sanitizeState } from './statusline-model-gA__yaog.cjs';
4
4
  import { K as KeymapManager } from './keymap-CGOz5F5f.cjs';
5
- import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-DpZeu7KP.cjs';
6
- import { M as MarketDataFeed } from './DataProvider-RF1axuy1.cjs';
5
+ import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-DYtiRtES.cjs';
6
+ import { M as MarketDataFeed } from './DataProvider-Dut6lXGM.cjs';
7
7
 
8
8
  /** The cells that follow `originId` under `setting` — PURE (never includes the origin). */
9
9
  declare function syncTargets(originId: string, setting: SyncSetting | undefined, cellIds: readonly string[]): string[];
@@ -1,9 +1,9 @@
1
- import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, I as InputValue, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-XVpfr9HV.js';
2
- import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as StatuslinePart, b as RangePreset, T as TrackSizes, c as VelaShellOptions, d as SyncOptions, e as SyncKind, f as WorkspaceState } from './statusline-model-CPa_hmhd.js';
3
- export { g as ChartState, P as PanelsState, h as decodeState, i as encodeState, s as sanitizeState } from './statusline-model-CPa_hmhd.js';
1
+ import { O as OHLCV, V as VisibleRangePreset, a as VisibleRange, b as VelaOptions, I as InputValue, c as VelaTheme, N as NativeBackend, d as MarketSession } from './options-DNBoMKkX.js';
2
+ import { S as SyncSetting, V as VelaStorage, C as CellState, W as WidgetHistory, R as ResolvedIndicator, a as StatuslinePart, b as RangePreset, T as TrackSizes, c as VelaShellOptions, d as SyncOptions, e as SyncKind, f as WorkspaceState } from './statusline-model-DypGXjtr.js';
3
+ export { g as ChartState, P as PanelsState, h as decodeState, i as encodeState, s as sanitizeState } from './statusline-model-DypGXjtr.js';
4
4
  import { K as KeymapManager } from './keymap-CGOz5F5f.js';
5
- import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-CspPrMAJ.js';
6
- import { M as MarketDataFeed } from './DataProvider-CVpN5sCq.js';
5
+ import { I as IndicatorHandle, S as ScriptingEngine, W as WidgetContext, V as Vela, E as ExternalIndicatorEntry, a as ScriptRun } from './contributions-CEkgJKTU.js';
6
+ import { M as MarketDataFeed } from './DataProvider-DLeFs1gE.js';
7
7
 
8
8
  /** The cells that follow `originId` under `setting` — PURE (never includes the origin). */
9
9
  declare function syncTargets(originId: string, setting: SyncSetting | undefined, cellIds: readonly string[]): string[];
package/dist/workspace.js CHANGED
@@ -1,5 +1,5 @@
1
- export { ChartCell, GRID_PICKER_MAX, VelaWorkspace, activeAfterLayout, decodeState, encodeState, ensureLayout, evenTracks, gridStyles, layoutDefinition, layoutForGrid, layoutShape, layouts, memoryStorageAdapter, rangesWithin, registerBuiltinLayouts, registerLayout, resizeTracks, sanitizeState, syncTargets, trackOffsets, unregisterLayout } from './chunk-CSFNKXUW.js';
2
- import './chunk-DUURH3RN.js';
1
+ export { ChartCell, GRID_PICKER_MAX, VelaWorkspace, activeAfterLayout, decodeState, encodeState, ensureLayout, evenTracks, gridStyles, layoutDefinition, layoutForGrid, layoutShape, layouts, memoryStorageAdapter, rangesWithin, registerBuiltinLayouts, registerLayout, resizeTracks, sanitizeState, syncTargets, trackOffsets, unregisterLayout } from './chunk-MNG5XPLV.js';
2
+ import './chunk-MCLI6B3S.js';
3
3
  import './chunk-BFA32GOU.js';
4
4
  import './chunk-ZADTVRUO.js';
5
5
  import './chunk-BKHSQ4YM.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxalgo/vela",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "description": "Open-source charting library with a native high-performance renderer, drawing tools, pluggable chart types and pluggable scripting engines.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://luxalgo.com/vela",