@luxalgo/vela 0.6.3 → 0.6.4
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.
- package/dist/{DataProvider-DHX4x6-r.d.ts → DataProvider-BmHkcwvJ.d.ts} +1 -1
- package/dist/{DataProvider-CNmk84SH.d.cts → DataProvider-DrN7ZIou.d.cts} +1 -1
- package/dist/{chunk-TP56QRMK.js → chunk-2R7BANEM.js} +1 -1
- package/dist/{chunk-U5KCQHAC.js → chunk-3QX6QOCX.js} +80 -12
- package/dist/{chunk-7D6YIF34.js → chunk-6FA4TDUF.js} +325 -67
- package/dist/{chunk-7Y7CJ7EN.js → chunk-BEJ57HP4.js} +8 -1
- package/dist/{chunk-QHZ7IXFL.js → chunk-OICPLNU7.js} +59 -9
- package/dist/{contributions-DDpv7hEL.d.cts → contributions-2bEmCF9S.d.cts} +2 -2
- package/dist/{contributions-ciV6Neyd.d.ts → contributions-DatoAzMx.d.ts} +2 -2
- package/dist/{history-CFqZm5re.d.ts → history-BmyjaVir.d.cts} +6 -6
- package/dist/{history-ChoT34nz.d.cts → history-CvOtsjT5.d.ts} +6 -6
- package/dist/index.cjs +394 -78
- package/dist/index.d.cts +36 -9
- package/dist/index.d.ts +36 -9
- package/dist/index.js +4 -4
- package/dist/{options-BqGeFHtp.d.ts → options-YdiaaVjt.d.cts} +20 -1
- package/dist/{options-BqGeFHtp.d.cts → options-YdiaaVjt.d.ts} +20 -1
- package/dist/{plugin-C97gUCVf.d.ts → plugin-BeCMF1VQ.d.ts} +3 -3
- package/dist/{plugin-CSb_sTiN.d.cts → plugin-CkiStRaI.d.cts} +3 -3
- package/dist/plugin.cjs +8 -0
- package/dist/plugin.d.cts +4 -4
- package/dist/plugin.d.ts +4 -4
- package/dist/plugin.js +2 -2
- package/dist/providers/binance.d.cts +2 -2
- package/dist/providers/binance.d.ts +2 -2
- package/dist/providers/coinbase.d.cts +2 -2
- package/dist/providers/coinbase.d.ts +2 -2
- package/dist/providers/hyperliquid.d.cts +2 -2
- package/dist/providers/hyperliquid.d.ts +2 -2
- package/dist/ui.cjs +59 -9
- package/dist/ui.d.cts +10 -2
- package/dist/ui.d.ts +10 -2
- package/dist/ui.js +2 -2
- package/dist/vela.global.js +394 -78
- package/dist/vela.global.min.js +84 -47
- package/dist/widget.cjs +646 -191
- package/dist/widget.d.cts +29 -8
- package/dist/widget.d.ts +29 -8
- package/dist/widget.js +145 -73
- package/dist/workspace.cjs +601 -142
- package/dist/workspace.d.cts +29 -5
- package/dist/workspace.d.ts +29 -5
- package/dist/workspace.js +143 -67
- package/package.json +1 -1
- /package/dist/{chunk-Q3XQHLIH.js → chunk-AOGZBKUE.js} +0 -0
package/dist/vela.global.js
CHANGED
|
@@ -9872,7 +9872,7 @@ var Vela = (function (exports) {
|
|
|
9872
9872
|
} else {
|
|
9873
9873
|
const left = Math.min(a.left - h.left, Math.max(0, h.width - tip.offsetWidth - 4));
|
|
9874
9874
|
tip.style.left = `${Math.max(0, left)}px`;
|
|
9875
|
-
tip.style.top = `${a.bottom - h.top + 6}px`;
|
|
9875
|
+
tip.style.top = opts.placement === "above" ? `${Math.max(0, a.top - h.top - tip.offsetHeight - 6)}px` : `${a.bottom - h.top + 6}px`;
|
|
9876
9876
|
}
|
|
9877
9877
|
};
|
|
9878
9878
|
const arm = (e) => {
|
|
@@ -16247,6 +16247,23 @@ var Vela = (function (exports) {
|
|
|
16247
16247
|
background: var(--vela-hover-strong);
|
|
16248
16248
|
color: var(--vela-fg-bright);
|
|
16249
16249
|
}
|
|
16250
|
+
/* Checkmark mode (context/action menus): every row reserves the leading mark column so
|
|
16251
|
+
labels align; a checked row fills it with a \u2713 and brightens its ink \u2014 the row surface
|
|
16252
|
+
stays free for the hover wash. */
|
|
16253
|
+
.vela-menu-item .vela-menu-mark {
|
|
16254
|
+
width: 14px;
|
|
16255
|
+
flex: none;
|
|
16256
|
+
display: inline-flex;
|
|
16257
|
+
align-items: center;
|
|
16258
|
+
justify-content: center;
|
|
16259
|
+
}
|
|
16260
|
+
.vela-menu-item .vela-menu-mark .vela-icon {
|
|
16261
|
+
width: 14px;
|
|
16262
|
+
height: 14px;
|
|
16263
|
+
font-size: 14px;
|
|
16264
|
+
color: var(--vela-fg-bright);
|
|
16265
|
+
}
|
|
16266
|
+
.vela-menu-item[data-checkmark] { color: var(--vela-fg-bright); }
|
|
16250
16267
|
/* Switch rows (boolean settings in a dropdown): a right-aligned toggle pill \u2014 the
|
|
16251
16268
|
same control language as the settings dialog's toggles. */
|
|
16252
16269
|
.vela-menu-switch {
|
|
@@ -16317,6 +16334,7 @@ var Vela = (function (exports) {
|
|
|
16317
16334
|
this.host = opts.host;
|
|
16318
16335
|
this.onSelect = opts.onSelect;
|
|
16319
16336
|
this.onFavorite = opts.onFavorite;
|
|
16337
|
+
this.checkmarks = opts.checkmarks === true;
|
|
16320
16338
|
this.positioner = doc.createElement("div");
|
|
16321
16339
|
this.positioner.className = "vela-ui-layer";
|
|
16322
16340
|
this.list = doc.createElement("ul");
|
|
@@ -16395,6 +16413,7 @@ var Vela = (function (exports) {
|
|
|
16395
16413
|
build() {
|
|
16396
16414
|
const doc = this.doc;
|
|
16397
16415
|
this.list.replaceChildren();
|
|
16416
|
+
const markable = this.checkmarks && this.items.some((i) => !(i.submenu && i.submenu.length > 0) && !i.toggle && i.checked !== void 0);
|
|
16398
16417
|
for (const item of this.items) {
|
|
16399
16418
|
if (item.separatorBefore) {
|
|
16400
16419
|
const sep = doc.createElement("li");
|
|
@@ -16408,7 +16427,16 @@ var Vela = (function (exports) {
|
|
|
16408
16427
|
li.dataset.veiId = item.id;
|
|
16409
16428
|
if (item.toggle) {
|
|
16410
16429
|
li.dataset.toggle = "1";
|
|
16411
|
-
}
|
|
16430
|
+
}
|
|
16431
|
+
if (markable) {
|
|
16432
|
+
const mark = doc.createElement("span");
|
|
16433
|
+
mark.className = "vela-menu-mark";
|
|
16434
|
+
if (!branch && !item.toggle && item.checked) {
|
|
16435
|
+
mark.appendChild(iconEl("check", doc));
|
|
16436
|
+
li.dataset.checkmark = "1";
|
|
16437
|
+
}
|
|
16438
|
+
li.appendChild(mark);
|
|
16439
|
+
} else if (!branch && !item.toggle && item.checked) {
|
|
16412
16440
|
li.dataset.checked = "1";
|
|
16413
16441
|
}
|
|
16414
16442
|
if (item.icon) li.appendChild(iconEl(item.icon, doc));
|
|
@@ -16457,6 +16485,7 @@ var Vela = (function (exports) {
|
|
|
16457
16485
|
placement: "right-start",
|
|
16458
16486
|
onSelect: this.onSelect,
|
|
16459
16487
|
onFavorite: this.onFavorite,
|
|
16488
|
+
checkmarks: this.checkmarks,
|
|
16460
16489
|
id: `${this.mid}--${item.id}`
|
|
16461
16490
|
});
|
|
16462
16491
|
sub.setItems(item.submenu ?? []);
|
|
@@ -16481,7 +16510,8 @@ var Vela = (function (exports) {
|
|
|
16481
16510
|
triggerId: opts.triggerId,
|
|
16482
16511
|
id: opts.id,
|
|
16483
16512
|
minWidth: opts.minWidth,
|
|
16484
|
-
onFavorite: opts.onFavorite
|
|
16513
|
+
onFavorite: opts.onFavorite,
|
|
16514
|
+
checkmarks: opts.checkmarks
|
|
16485
16515
|
});
|
|
16486
16516
|
this.root.setItems(opts.items);
|
|
16487
16517
|
}
|
|
@@ -16509,6 +16539,13 @@ var Vela = (function (exports) {
|
|
|
16509
16539
|
}
|
|
16510
16540
|
};
|
|
16511
16541
|
|
|
16542
|
+
// src/core/model/inputs.ts
|
|
16543
|
+
function inputVisible(when, values) {
|
|
16544
|
+
if (!when) return true;
|
|
16545
|
+
const conds = Array.isArray(when) ? when : [when];
|
|
16546
|
+
return conds.every((c) => c.anyOf ? c.anyOf.some((x) => x === values[c.key]) : values[c.key] === c.equals);
|
|
16547
|
+
}
|
|
16548
|
+
|
|
16512
16549
|
// src/ui/tokens.ts
|
|
16513
16550
|
var STATIC_ID = "vela-ui-tokens";
|
|
16514
16551
|
var STATIC_DECLS = Object.entries(STATIC_TOKENS).map(([k, v]) => ` ${k}: ${v};`).join("\n");
|
|
@@ -16517,8 +16554,13 @@ var Vela = (function (exports) {
|
|
|
16517
16554
|
${STATIC_DECLS}
|
|
16518
16555
|
font-family: var(--vela-font, -apple-system, system-ui, sans-serif);
|
|
16519
16556
|
box-sizing: border-box;
|
|
16557
|
+
/* Chrome text (titles, buttons, menus, readouts) is UI, not copy \u2014 never selectable. */
|
|
16558
|
+
user-select: none;
|
|
16559
|
+
-webkit-user-select: none;
|
|
16520
16560
|
}
|
|
16521
16561
|
.vela-ui *, .vela-ui-layer * { box-sizing: border-box; }
|
|
16562
|
+
/* Text ENTRY is the one exception: selection is part of editing. */
|
|
16563
|
+
.vela-ui :is(input, textarea), .vela-ui-layer :is(input, textarea) { user-select: text; -webkit-user-select: text; }
|
|
16522
16564
|
.vela-icon { display: inline-flex; align-items: center; flex: none; }
|
|
16523
16565
|
.vela-icon svg { display: block; }
|
|
16524
16566
|
`;
|
|
@@ -18704,6 +18746,9 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
18704
18746
|
transition: border-color 0.12s ease, box-shadow 0.12s ease;
|
|
18705
18747
|
-moz-appearance: textfield;
|
|
18706
18748
|
appearance: textfield;
|
|
18749
|
+
/* Selectable even under a user-select:none host (chart wrapper, .vela-ui). */
|
|
18750
|
+
user-select: text;
|
|
18751
|
+
-webkit-user-select: text;
|
|
18707
18752
|
}
|
|
18708
18753
|
.vela-num input::-webkit-inner-spin-button, .vela-num input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
|
|
18709
18754
|
.vela-num input:hover { border-color: var(--vela-fg-muted); }
|
|
@@ -18916,6 +18961,9 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
18916
18961
|
overflow: hidden;
|
|
18917
18962
|
text-overflow: ellipsis;
|
|
18918
18963
|
transition: border-color 0.12s ease, box-shadow 0.12s ease;
|
|
18964
|
+
/* Selectable even under a user-select:none host (chart wrapper, .vela-ui). */
|
|
18965
|
+
user-select: text;
|
|
18966
|
+
-webkit-user-select: text;
|
|
18919
18967
|
}
|
|
18920
18968
|
.vela-text-field:hover { border-color: var(--vela-fg-muted); }
|
|
18921
18969
|
.vela-text-field:focus { border-color: var(--vela-focus); box-shadow: 0 0 0 3px var(--vela-focus-soft); }
|
|
@@ -19009,6 +19057,9 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19009
19057
|
resize: vertical;
|
|
19010
19058
|
outline: none;
|
|
19011
19059
|
transition: border-color 0.12s ease, box-shadow 0.12s ease;
|
|
19060
|
+
/* Selectable even under a user-select:none host (chart wrapper, .vela-ui). */
|
|
19061
|
+
user-select: text;
|
|
19062
|
+
-webkit-user-select: text;
|
|
19012
19063
|
}
|
|
19013
19064
|
.vela-textarea-field:hover { border-color: var(--vela-fg-muted); }
|
|
19014
19065
|
.vela-textarea-field:focus { border-color: var(--vela-focus); box-shadow: 0 0 0 3px var(--vela-focus-soft); }
|
|
@@ -19537,6 +19588,8 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19537
19588
|
font-size: 14px;
|
|
19538
19589
|
}
|
|
19539
19590
|
.vela-field-label[data-size='sm'] { font-size: inherit; opacity: 0.85; }
|
|
19591
|
+
/* Titles are fully inert: spans, not label[for] \u2014 native labels propagate :hover and
|
|
19592
|
+
clicks onto their control, and both belong to the input alone. */
|
|
19540
19593
|
.vela-field-cell { display: flex; align-items: center; gap: 8px; justify-self: start; }
|
|
19541
19594
|
.vela-field-bool { display: flex; align-items: center; gap: 8px; min-height: 22px; }
|
|
19542
19595
|
.vela-field-stacked { display: flex; flex-direction: column; gap: 8px; }
|
|
@@ -19595,11 +19648,17 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19595
19648
|
return el;
|
|
19596
19649
|
}
|
|
19597
19650
|
function labelEl(text, opts) {
|
|
19598
|
-
const el =
|
|
19599
|
-
if (opts.id && el instanceof HTMLLabelElement) el.htmlFor = opts.id;
|
|
19651
|
+
const el = document.createElement("span");
|
|
19600
19652
|
el.className = "vela-field-label";
|
|
19601
19653
|
if (opts.size) el.dataset.size = opts.size;
|
|
19602
19654
|
el.textContent = text;
|
|
19655
|
+
const id = opts.id;
|
|
19656
|
+
if (id) {
|
|
19657
|
+
el.id = `${id}--title`;
|
|
19658
|
+
queueMicrotask(() => {
|
|
19659
|
+
el.ownerDocument.getElementById(id)?.setAttribute("aria-labelledby", el.id);
|
|
19660
|
+
});
|
|
19661
|
+
}
|
|
19603
19662
|
return el;
|
|
19604
19663
|
}
|
|
19605
19664
|
function asList(control) {
|
|
@@ -19628,9 +19687,7 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19628
19687
|
it.className = "vela-field-inline-item";
|
|
19629
19688
|
if (item.toggleFirst) it.style.flexDirection = "row-reverse";
|
|
19630
19689
|
if (item.label) {
|
|
19631
|
-
|
|
19632
|
-
if (item.toggleFirst) lbl.style.cursor = "pointer";
|
|
19633
|
-
it.appendChild(lbl);
|
|
19690
|
+
it.appendChild(labelEl(item.label, { id: item.id, size: size3 }));
|
|
19634
19691
|
}
|
|
19635
19692
|
if (item.fit) it.appendChild(item.control);
|
|
19636
19693
|
else {
|
|
@@ -19655,7 +19712,7 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19655
19712
|
tone: "bright",
|
|
19656
19713
|
onChange: (v) => opts.toggle?.onChange(v)
|
|
19657
19714
|
});
|
|
19658
|
-
wrap3.append(sw.el, labelEl(opts.label, { size: size3 }));
|
|
19715
|
+
wrap3.append(sw.el, labelEl(opts.label, { id: opts.toggle?.id ?? opts.id, size: size3 }));
|
|
19659
19716
|
if (opts.info) wrap3.appendChild(opts.info);
|
|
19660
19717
|
if (opts.toggle?.get) {
|
|
19661
19718
|
const get = opts.toggle.get;
|
|
@@ -19694,7 +19751,7 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19694
19751
|
if (controls.length > 0) dimControls(controls, v);
|
|
19695
19752
|
}
|
|
19696
19753
|
});
|
|
19697
|
-
left.append(sw.el, labelEl(opts.label, { size: size3 }));
|
|
19754
|
+
left.append(sw.el, labelEl(opts.label, { id: opts.toggle.id ?? opts.id, size: size3 }));
|
|
19698
19755
|
wrap2.appendChild(left);
|
|
19699
19756
|
if (controls.length > 0) dimControls(controls, opts.toggle.checked);
|
|
19700
19757
|
if (opts.toggle.get) {
|
|
@@ -19848,6 +19905,8 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19848
19905
|
this.row = null;
|
|
19849
19906
|
this.snapshot = null;
|
|
19850
19907
|
this.dialogTips = [];
|
|
19908
|
+
/** Re-applies every `when` gate against current values; set while the dialog is open. */
|
|
19909
|
+
this.refreshVisibility = null;
|
|
19851
19910
|
this.choicePop = null;
|
|
19852
19911
|
this.calendarPop = null;
|
|
19853
19912
|
this.calendarAnchor = null;
|
|
@@ -19910,14 +19969,17 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19910
19969
|
tabs.style.cssText = `display:flex;gap:12px;padding:0 20px;border-bottom:1px solid ${border};flex:0 0 auto;`;
|
|
19911
19970
|
const tabEls = [];
|
|
19912
19971
|
const bodies = [];
|
|
19972
|
+
const gates = [];
|
|
19973
|
+
let active = 0;
|
|
19913
19974
|
const activate = (idx) => {
|
|
19975
|
+
active = idx;
|
|
19914
19976
|
for (let i = 0; i < tabEls.length; i += 1) {
|
|
19915
|
-
const
|
|
19977
|
+
const on = i === idx;
|
|
19916
19978
|
const el = tabEls[i];
|
|
19917
|
-
el.style.borderBottomColor =
|
|
19918
|
-
el.style.color =
|
|
19919
|
-
el.classList.toggle("vela-ind-tab-active",
|
|
19920
|
-
bodies[i].style.display =
|
|
19979
|
+
el.style.borderBottomColor = on ? fg : "transparent";
|
|
19980
|
+
el.style.color = on ? "inherit" : "var(--vela-fg-muted)";
|
|
19981
|
+
el.classList.toggle("vela-ind-tab-active", on);
|
|
19982
|
+
bodies[i].style.display = on ? "grid" : "none";
|
|
19921
19983
|
}
|
|
19922
19984
|
};
|
|
19923
19985
|
for (const [idx, def] of tabDefs.entries()) {
|
|
@@ -19928,11 +19990,24 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19928
19990
|
tab.addEventListener("click", () => activate(idx));
|
|
19929
19991
|
tabs.appendChild(tab);
|
|
19930
19992
|
tabEls.push(tab);
|
|
19931
|
-
bodies.push(this.buildTabBody(def.inputs, row));
|
|
19993
|
+
bodies.push(this.buildTabBody(def.inputs, row, gates));
|
|
19994
|
+
if (def.inputs.every((d) => d.when)) {
|
|
19995
|
+
gates.push({ el: tab, visible: (bag) => def.inputs.some((d) => inputVisible(d.when, bag)) });
|
|
19996
|
+
}
|
|
19932
19997
|
}
|
|
19933
19998
|
ui.body.appendChild(tabs);
|
|
19934
19999
|
for (const b of bodies) ui.body.appendChild(b);
|
|
19935
20000
|
activate(0);
|
|
20001
|
+
const refresh = () => {
|
|
20002
|
+
const bag = valuesBag(row);
|
|
20003
|
+
for (const g of gates) g.el.style.display = g.visible(bag) ? "" : "none";
|
|
20004
|
+
if (tabEls[active]?.style.display === "none") {
|
|
20005
|
+
const next2 = tabEls.findIndex((el) => el.style.display !== "none");
|
|
20006
|
+
if (next2 >= 0) activate(next2);
|
|
20007
|
+
}
|
|
20008
|
+
};
|
|
20009
|
+
this.refreshVisibility = refresh;
|
|
20010
|
+
refresh();
|
|
19936
20011
|
const onBackdropDown = (e) => {
|
|
19937
20012
|
if (e.target !== ui.backdrop && e.target !== ui.positioner) return;
|
|
19938
20013
|
if (isPopoverOpen() || eventDismissedPopover(e)) {
|
|
@@ -19952,16 +20027,27 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19952
20027
|
}
|
|
19953
20028
|
/** One tab's scrollable body — one shared grid so every group's controls share a
|
|
19954
20029
|
* left edge (a 100px number field lines up with a wider session/time pair). */
|
|
19955
|
-
buildTabBody(inputs, row) {
|
|
20030
|
+
buildTabBody(inputs, row, gates) {
|
|
19956
20031
|
const body = document.createElement("div");
|
|
19957
20032
|
body.style.cssText = inputDialogBodyStyle(this.host.mobile());
|
|
19958
20033
|
for (const group of groupInputs(inputs)) {
|
|
19959
20034
|
const section = document.createElement("div");
|
|
19960
20035
|
section.style.cssText = "display:contents;";
|
|
20036
|
+
let header = null;
|
|
19961
20037
|
if (group.name) {
|
|
19962
|
-
|
|
20038
|
+
header = fieldSection(group.name, { variant: "inputs", first: body.childElementCount === 0 });
|
|
20039
|
+
section.appendChild(header);
|
|
20040
|
+
}
|
|
20041
|
+
for (const inputRow of group.rows) {
|
|
20042
|
+
const el = this.buildInputRow(section, inputRow, row);
|
|
20043
|
+
if (inputRow.some((d) => d.when)) {
|
|
20044
|
+
gates.push({ el, visible: (bag) => rowVisible(inputRow, bag) });
|
|
20045
|
+
}
|
|
20046
|
+
}
|
|
20047
|
+
if (header && group.rows.every((r) => r.every((d) => d.when))) {
|
|
20048
|
+
const rows = group.rows;
|
|
20049
|
+
gates.push({ el: header, visible: (bag) => rows.some((r) => rowVisible(r, bag)) });
|
|
19963
20050
|
}
|
|
19964
|
-
for (const inputRow of group.rows) this.buildInputRow(section, inputRow, row);
|
|
19965
20051
|
body.appendChild(section);
|
|
19966
20052
|
}
|
|
19967
20053
|
return body;
|
|
@@ -19969,6 +20055,7 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19969
20055
|
close() {
|
|
19970
20056
|
document.removeEventListener("keydown", this.onDialogKey);
|
|
19971
20057
|
closeOpenPopovers();
|
|
20058
|
+
this.refreshVisibility = null;
|
|
19972
20059
|
this.choicePop = null;
|
|
19973
20060
|
this.calendarPop = null;
|
|
19974
20061
|
this.calendarAnchor = null;
|
|
@@ -19998,11 +20085,21 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
19998
20085
|
}
|
|
19999
20086
|
this.close();
|
|
20000
20087
|
}
|
|
20088
|
+
/** Write one edit through: store it, notify the host, and re-apply the `when` gates. */
|
|
20089
|
+
commit(row, key, value) {
|
|
20090
|
+
row.values[key] = value;
|
|
20091
|
+
this.host.onChange?.({ indicatorId: row.id, key, value });
|
|
20092
|
+
this.refreshVisibility?.();
|
|
20093
|
+
}
|
|
20001
20094
|
/** One settings row (or several `inline=` inputs) placed into a section's grid. */
|
|
20002
20095
|
buildInputRow(grid, decls, row) {
|
|
20003
20096
|
const idOf = (inp) => `vela-inp-${row.id}-${inp.key}`;
|
|
20097
|
+
const append = (el) => {
|
|
20098
|
+
grid.appendChild(el);
|
|
20099
|
+
return el;
|
|
20100
|
+
};
|
|
20004
20101
|
if (decls.length > 1) {
|
|
20005
|
-
|
|
20102
|
+
return append(fieldRow({
|
|
20006
20103
|
label: "",
|
|
20007
20104
|
inline: decls.map((d) => ({
|
|
20008
20105
|
label: nameOf(d) || void 0,
|
|
@@ -20013,14 +20110,13 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
20013
20110
|
})),
|
|
20014
20111
|
info: [...decls].reverse().find((d) => d.tooltip)?.tooltip ? this.infoButton([...decls].reverse().find((d) => d.tooltip).tooltip) : void 0
|
|
20015
20112
|
}));
|
|
20016
|
-
return;
|
|
20017
20113
|
}
|
|
20018
20114
|
const lead = decls[0];
|
|
20019
20115
|
const id = idOf(lead);
|
|
20020
20116
|
const info = lead.tooltip ? this.infoButton(lead.tooltip) : void 0;
|
|
20021
20117
|
if (lead.type === "bool") {
|
|
20022
20118
|
const current = Boolean(row.values[lead.key] ?? lead.defval);
|
|
20023
|
-
|
|
20119
|
+
return append(fieldRow({
|
|
20024
20120
|
label: nameOf(lead),
|
|
20025
20121
|
id,
|
|
20026
20122
|
bool: true,
|
|
@@ -20028,26 +20124,21 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
20028
20124
|
toggle: {
|
|
20029
20125
|
id,
|
|
20030
20126
|
checked: current,
|
|
20031
|
-
onChange: (v) =>
|
|
20032
|
-
row.values[lead.key] = v;
|
|
20033
|
-
this.host.onChange?.({ indicatorId: row.id, key: lead.key, value: v });
|
|
20034
|
-
}
|
|
20127
|
+
onChange: (v) => this.commit(row, lead.key, v)
|
|
20035
20128
|
}
|
|
20036
20129
|
}));
|
|
20037
|
-
return;
|
|
20038
20130
|
}
|
|
20039
20131
|
if (lead.type === "text_area") {
|
|
20040
|
-
|
|
20132
|
+
return append(fieldRow({
|
|
20041
20133
|
label: nameOf(lead),
|
|
20042
20134
|
id,
|
|
20043
20135
|
stacked: true,
|
|
20044
20136
|
info,
|
|
20045
20137
|
control: this.buildControl(row, lead, id)
|
|
20046
20138
|
}));
|
|
20047
|
-
return;
|
|
20048
20139
|
}
|
|
20049
20140
|
const fit = lead.type === "color" || lead.type === "session" || lead.type === "time";
|
|
20050
|
-
|
|
20141
|
+
return append(fieldRow({
|
|
20051
20142
|
label: nameOf(lead),
|
|
20052
20143
|
id,
|
|
20053
20144
|
fit,
|
|
@@ -20059,10 +20150,7 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
20059
20150
|
/** Build the typed control for one input, committing edits live via `onChange`. */
|
|
20060
20151
|
buildControl(row, inp, id) {
|
|
20061
20152
|
const current = row.values[inp.key] ?? inp.defval;
|
|
20062
|
-
const emit = (value) =>
|
|
20063
|
-
row.values[inp.key] = value;
|
|
20064
|
-
this.host.onChange?.({ indicatorId: row.id, key: inp.key, value });
|
|
20065
|
-
};
|
|
20153
|
+
const emit = (value) => this.commit(row, inp.key, value);
|
|
20066
20154
|
if (inp.type === "bool") {
|
|
20067
20155
|
return buildFieldControl({ kind: "switch", id, checked: Boolean(current), onChange: (v) => emit(v) }).el;
|
|
20068
20156
|
}
|
|
@@ -20483,6 +20571,14 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
20483
20571
|
}
|
|
20484
20572
|
return names.map((name) => ({ name, inputs: byTab.get(name) }));
|
|
20485
20573
|
}
|
|
20574
|
+
function rowVisible(decls, bag) {
|
|
20575
|
+
return decls.some((d) => inputVisible(d.when, bag));
|
|
20576
|
+
}
|
|
20577
|
+
function valuesBag(row) {
|
|
20578
|
+
const bag = {};
|
|
20579
|
+
for (const inp of row.inputs) bag[inp.key] = row.values[inp.key] ?? inp.defval;
|
|
20580
|
+
return bag;
|
|
20581
|
+
}
|
|
20486
20582
|
function groupInputs(inputs) {
|
|
20487
20583
|
const order = [];
|
|
20488
20584
|
const byGroup = /* @__PURE__ */ new Map();
|
|
@@ -20945,6 +21041,8 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
20945
21041
|
host: this.container,
|
|
20946
21042
|
items,
|
|
20947
21043
|
placement: "bottom-start",
|
|
21044
|
+
// Right-click action menu — checked state reads as a leading ✓ (see the kit Menu).
|
|
21045
|
+
checkmarks: true,
|
|
20948
21046
|
onSelect: (itemId) => {
|
|
20949
21047
|
if (itemId !== "values" || !this.rowMenuId) return;
|
|
20950
21048
|
const target = this.rows.get(this.rowMenuId);
|
|
@@ -21280,6 +21378,8 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
21280
21378
|
syncRowActions(row) {
|
|
21281
21379
|
const open2 = row.highlighted;
|
|
21282
21380
|
row.controlsEl.style.display = open2 || row.hidden ? "inline-flex" : "none";
|
|
21381
|
+
if (open2) row.el.appendChild(row.statusEl);
|
|
21382
|
+
else row.el.insertBefore(row.statusEl, row.valuesEl);
|
|
21283
21383
|
for (const child of Array.from(row.controlsEl.children)) {
|
|
21284
21384
|
if (!(child instanceof HTMLElement) || child === row.eyeEl) continue;
|
|
21285
21385
|
if (child === row.extrasEl) {
|
|
@@ -21523,6 +21623,148 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
21523
21623
|
}
|
|
21524
21624
|
};
|
|
21525
21625
|
|
|
21626
|
+
// src/renderers/native/chrome/axisLayout.ts
|
|
21627
|
+
var AXIS_MASTER_W = 64;
|
|
21628
|
+
var AXIS_MERGED_W = 56;
|
|
21629
|
+
var PANE_SEPARATOR_PX = 3;
|
|
21630
|
+
function axisColumnX(dataW, column) {
|
|
21631
|
+
return column === 0 ? dataW : dataW + AXIS_MASTER_W + (column - 1) * AXIS_MERGED_W;
|
|
21632
|
+
}
|
|
21633
|
+
|
|
21634
|
+
// src/renderers/native/chrome/AxisScaleButtons.ts
|
|
21635
|
+
var STYLE_ID2 = "vela-axis-scale-buttons";
|
|
21636
|
+
var BTN_PX = 18;
|
|
21637
|
+
var BTN_GAP = 4;
|
|
21638
|
+
var AXIS_BORDER = 1;
|
|
21639
|
+
var CLUSTER_W = AXIS_MASTER_W - AXIS_BORDER;
|
|
21640
|
+
var PAD_TOP = 8;
|
|
21641
|
+
var PAD_BOTTOM = 6;
|
|
21642
|
+
var CLUSTER_H = BTN_PX + PAD_TOP + PAD_BOTTOM;
|
|
21643
|
+
var MIN_PANE_H = 48;
|
|
21644
|
+
function ensureStyles2() {
|
|
21645
|
+
if (typeof document === "undefined" || document.getElementById(STYLE_ID2)) return;
|
|
21646
|
+
const st = document.createElement("style");
|
|
21647
|
+
st.id = STYLE_ID2;
|
|
21648
|
+
st.textContent = `
|
|
21649
|
+
.vela-axis-btn{display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;border-radius:var(--vela-radius-sm);background:transparent;cursor:pointer;font:600 10px/1 -apple-system,Segoe UI,sans-serif;color:var(--vela-fg-muted);}
|
|
21650
|
+
.vela-axis-btn:hover{background:var(--vela-active);color:var(--vela-fg-bright);}
|
|
21651
|
+
.vela-axis-on,.vela-axis-on:hover{background:var(--vela-selected-bg);color:var(--vela-selected-fg);}
|
|
21652
|
+
`;
|
|
21653
|
+
document.head.appendChild(st);
|
|
21654
|
+
}
|
|
21655
|
+
var AxisScaleButtons = class {
|
|
21656
|
+
constructor(plot, theme, deps) {
|
|
21657
|
+
this.plot = plot;
|
|
21658
|
+
this.theme = theme;
|
|
21659
|
+
this.deps = deps;
|
|
21660
|
+
this.tipDisposers = [];
|
|
21661
|
+
this.hoverPaneId = null;
|
|
21662
|
+
/** Reveal over the master scale column of the pane under the cursor (mouse only —
|
|
21663
|
+
* touch has no hover, and a drag-rescale on the axis must not sprout buttons). */
|
|
21664
|
+
this.onPlotMove = (e) => {
|
|
21665
|
+
if (e.pointerType !== "mouse") return;
|
|
21666
|
+
const rect = this.plot.getBoundingClientRect();
|
|
21667
|
+
const x = e.clientX - rect.left;
|
|
21668
|
+
const gutterLeft = rect.width - this.deps.rightAxis();
|
|
21669
|
+
let hit = null;
|
|
21670
|
+
if (x >= gutterLeft && x <= gutterLeft + AXIS_MASTER_W) {
|
|
21671
|
+
const y = e.clientY - rect.top;
|
|
21672
|
+
for (const p of this.deps.panes()) {
|
|
21673
|
+
if (p.collapsed || p.height < MIN_PANE_H) continue;
|
|
21674
|
+
if (y >= p.top && y <= p.top + p.height) {
|
|
21675
|
+
hit = p.id;
|
|
21676
|
+
break;
|
|
21677
|
+
}
|
|
21678
|
+
}
|
|
21679
|
+
}
|
|
21680
|
+
this.setHoverPane(hit);
|
|
21681
|
+
if (hit) this.sync();
|
|
21682
|
+
};
|
|
21683
|
+
this.onPlotLeave = () => this.setHoverPane(null);
|
|
21684
|
+
ensureStyles2();
|
|
21685
|
+
this.cluster = document.createElement("div");
|
|
21686
|
+
Object.assign(this.cluster.style, {
|
|
21687
|
+
position: "absolute",
|
|
21688
|
+
display: "none",
|
|
21689
|
+
justifyContent: "center",
|
|
21690
|
+
alignItems: "center",
|
|
21691
|
+
gap: `${BTN_GAP}px`,
|
|
21692
|
+
padding: `${PAD_TOP}px 0 ${PAD_BOTTOM}px`,
|
|
21693
|
+
width: `${CLUSTER_W}px`,
|
|
21694
|
+
boxSizing: "border-box",
|
|
21695
|
+
zIndex: "6",
|
|
21696
|
+
pointerEvents: "auto"
|
|
21697
|
+
});
|
|
21698
|
+
this.applyTheme();
|
|
21699
|
+
this.autoBtn = this.button("A", "Auto (fits data to screen)", () => this.deps.onToggleAuto(this.hoverPaneId ?? ""));
|
|
21700
|
+
this.logBtn = this.button("L", "Logarithmic scale", () => this.deps.onToggleLog(this.hoverPaneId ?? ""));
|
|
21701
|
+
this.cluster.append(this.autoBtn, this.logBtn);
|
|
21702
|
+
this.plot.appendChild(this.cluster);
|
|
21703
|
+
this.plot.addEventListener("pointermove", this.onPlotMove);
|
|
21704
|
+
this.plot.addEventListener("pointerleave", this.onPlotLeave);
|
|
21705
|
+
}
|
|
21706
|
+
button(label, title, onClick) {
|
|
21707
|
+
const b = document.createElement("button");
|
|
21708
|
+
b.type = "button";
|
|
21709
|
+
b.setAttribute("aria-label", title);
|
|
21710
|
+
b.textContent = label;
|
|
21711
|
+
b.className = "vela-axis-btn";
|
|
21712
|
+
Object.assign(b.style, { width: `${BTN_PX}px`, height: `${BTN_PX}px` });
|
|
21713
|
+
this.tipDisposers.push(attachChromeTooltip(b, {
|
|
21714
|
+
host: this.plot,
|
|
21715
|
+
theme: () => this.theme,
|
|
21716
|
+
text: () => title,
|
|
21717
|
+
placement: "above"
|
|
21718
|
+
}));
|
|
21719
|
+
b.addEventListener("click", (e) => {
|
|
21720
|
+
e.stopPropagation();
|
|
21721
|
+
onClick();
|
|
21722
|
+
this.sync();
|
|
21723
|
+
});
|
|
21724
|
+
return b;
|
|
21725
|
+
}
|
|
21726
|
+
/** Re-tint the chip when the plot background/border change (theme swap, config edit). */
|
|
21727
|
+
setTheme(theme) {
|
|
21728
|
+
this.theme = theme;
|
|
21729
|
+
this.applyTheme();
|
|
21730
|
+
}
|
|
21731
|
+
/** The strip is SOLID chart background: the buttons cover axis labels, never blend with them. */
|
|
21732
|
+
applyTheme() {
|
|
21733
|
+
this.cluster.style.background = this.theme.background;
|
|
21734
|
+
}
|
|
21735
|
+
setHoverPane(paneId) {
|
|
21736
|
+
if (this.hoverPaneId === paneId) return;
|
|
21737
|
+
this.hoverPaneId = paneId;
|
|
21738
|
+
this.reposition();
|
|
21739
|
+
}
|
|
21740
|
+
/** Re-place (or hide) the cluster after a hover or pane-layout change. */
|
|
21741
|
+
reposition() {
|
|
21742
|
+
const pane = this.hoverPaneId ? this.deps.panes().find((p) => p.id === this.hoverPaneId) : void 0;
|
|
21743
|
+
if (!pane || pane.collapsed || pane.height < MIN_PANE_H) {
|
|
21744
|
+
this.cluster.style.display = "none";
|
|
21745
|
+
return;
|
|
21746
|
+
}
|
|
21747
|
+
this.cluster.style.right = `${this.deps.rightAxis() - AXIS_MASTER_W}px`;
|
|
21748
|
+
this.cluster.style.top = `${pane.top + pane.height - CLUSTER_H}px`;
|
|
21749
|
+
this.cluster.style.display = "flex";
|
|
21750
|
+
this.sync();
|
|
21751
|
+
}
|
|
21752
|
+
/** Reflect the hovered pane's current auto/log state on the buttons. */
|
|
21753
|
+
sync() {
|
|
21754
|
+
const pane = this.deps.panes().find((p) => p.id === this.hoverPaneId);
|
|
21755
|
+
if (!pane) return;
|
|
21756
|
+
this.autoBtn.classList.toggle("vela-axis-on", pane.auto);
|
|
21757
|
+
this.logBtn.classList.toggle("vela-axis-on", pane.log);
|
|
21758
|
+
}
|
|
21759
|
+
destroy() {
|
|
21760
|
+
this.plot.removeEventListener("pointermove", this.onPlotMove);
|
|
21761
|
+
this.plot.removeEventListener("pointerleave", this.onPlotLeave);
|
|
21762
|
+
for (const dispose of this.tipDisposers) dispose();
|
|
21763
|
+
this.tipDisposers.length = 0;
|
|
21764
|
+
this.cluster.remove();
|
|
21765
|
+
}
|
|
21766
|
+
};
|
|
21767
|
+
|
|
21526
21768
|
// src/renderers/shared/TableOverlay.ts
|
|
21527
21769
|
var SIZE_PX3 = {
|
|
21528
21770
|
auto: 13,
|
|
@@ -21880,6 +22122,8 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
21880
22122
|
var BASELINE_FILL_ALPHA = 0.25;
|
|
21881
22123
|
var BASELINE_FILL_ALPHA_FAR = 0.05;
|
|
21882
22124
|
var BASELINE_LEVEL_DEFAULT = 50;
|
|
22125
|
+
var PREMARKET_SHADE = withAlpha(WARNING, 0.08);
|
|
22126
|
+
var POSTMARKET_SHADE = withAlpha(ACCENT, 0.08);
|
|
21883
22127
|
function defaultChartStyle() {
|
|
21884
22128
|
return {
|
|
21885
22129
|
chartTypes: {},
|
|
@@ -21910,7 +22154,8 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
21910
22154
|
bottomFillColor2: null,
|
|
21911
22155
|
width: 2,
|
|
21912
22156
|
baselineLevel: BASELINE_LEVEL_DEFAULT
|
|
21913
|
-
}
|
|
22157
|
+
},
|
|
22158
|
+
sessions: { premarketColor: PREMARKET_SHADE, postmarketColor: POSTMARKET_SHADE }
|
|
21914
22159
|
};
|
|
21915
22160
|
}
|
|
21916
22161
|
var LINE_STYLES = ["solid", "dashed", "dotted"];
|
|
@@ -22044,6 +22289,7 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
22044
22289
|
const area = asObject(p.area);
|
|
22045
22290
|
const baseline = asObject(p.baseline);
|
|
22046
22291
|
const series = asObject(p.series);
|
|
22292
|
+
const sessions = asObject(p.sessions);
|
|
22047
22293
|
const stacking = asObject(p.stacking);
|
|
22048
22294
|
const stackSeries = asObject(stacking.series);
|
|
22049
22295
|
return {
|
|
@@ -22136,6 +22382,10 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
22136
22382
|
baseline: series.baseline === null ? null : isNum(series.baseline) ? series.baseline : base.series.baseline,
|
|
22137
22383
|
spacing: isNum(series.spacing) ? clampSpacing(series.spacing) : base.series.spacing
|
|
22138
22384
|
},
|
|
22385
|
+
sessions: {
|
|
22386
|
+
premarketColor: isColor(sessions.premarketColor) ? sessions.premarketColor : base.sessions.premarketColor,
|
|
22387
|
+
postmarketColor: isColor(sessions.postmarketColor) ? sessions.postmarketColor : base.sessions.postmarketColor
|
|
22388
|
+
},
|
|
22139
22389
|
stacking: {
|
|
22140
22390
|
candles: isNum(stacking.candles) ? stacking.candles : base.stacking.candles,
|
|
22141
22391
|
// Additive like `chartTypes`: a patch names only the ids it carries; the rest keep
|
|
@@ -22382,6 +22632,8 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
22382
22632
|
this.tradeMarkers = defaultTradeMarkersState();
|
|
22383
22633
|
/** Renderer-owned shaded time bands (session highlighting), behind grid + data. */
|
|
22384
22634
|
this.highlights = [];
|
|
22635
|
+
/** Pre/post-market bands pushed by the host (`sessionZones` feature); null ⇒ no sessions. */
|
|
22636
|
+
this.sessionZones = null;
|
|
22385
22637
|
/** Draw-order key of the price candles, relative to indicator series z (see `seriesZ`).
|
|
22386
22638
|
* Indicators with z below this draw BEHIND the candles; at/above draw in front.
|
|
22387
22639
|
* Default 0 with indicators mounting at z < 0 ⇒ the price reads on top of every overlay,
|
|
@@ -22416,6 +22668,15 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
|
22416
22668
|
if (!this.orderedCache) this.orderedCache = [...this.panes.values()].sort((a, b) => a.order - b.order);
|
|
22417
22669
|
return this.orderedCache;
|
|
22418
22670
|
}
|
|
22671
|
+
/** The session zones resolved into colored bands (pre/post-market washes from the
|
|
22672
|
+
* config's session colors) — consumed by the same painting path as {@link highlights}. */
|
|
22673
|
+
sessionHighlightBands() {
|
|
22674
|
+
if (!this.sessionZones) return [];
|
|
22675
|
+
const out = [];
|
|
22676
|
+
for (const [from, to] of this.sessionZones.pre) out.push({ from, to, color: this.style.sessions.premarketColor });
|
|
22677
|
+
for (const [from, to] of this.sessionZones.post) out.push({ from, to, color: this.style.sessions.postmarketColor });
|
|
22678
|
+
return out;
|
|
22679
|
+
}
|
|
22419
22680
|
indicatorsForPane(paneId) {
|
|
22420
22681
|
const out = [];
|
|
22421
22682
|
for (const model of this.indicators.values()) if (model.paneId === paneId) out.push(model);
|
|
@@ -23346,10 +23607,12 @@ void main() {
|
|
|
23346
23607
|
}
|
|
23347
23608
|
}
|
|
23348
23609
|
}
|
|
23349
|
-
/** Renderer-owned session highlight bands, clipped per-pane (scissor reconstructs full height).
|
|
23610
|
+
/** Renderer-owned session highlight bands, clipped per-pane (scissor reconstructs full height).
|
|
23611
|
+
* Session-zone washes (pre/post-market) paint first, host highlights on top. */
|
|
23350
23612
|
emitHighlights(b, scene, pane, coords) {
|
|
23351
|
-
|
|
23352
|
-
|
|
23613
|
+
const bands = [...scene.sessionHighlightBands(), ...scene.highlights];
|
|
23614
|
+
if (bands.length === 0) return;
|
|
23615
|
+
for (const band of bands) {
|
|
23353
23616
|
const x1 = coords.timeToX(band.from);
|
|
23354
23617
|
const x2 = coords.timeToX(band.to);
|
|
23355
23618
|
if (x2 < 0 || x1 > coords.width || x2 <= x1) continue;
|
|
@@ -25323,10 +25586,12 @@ void main() {
|
|
|
25323
25586
|
ctx.fillStyle = bg.color;
|
|
25324
25587
|
ctx.fillRect(x1, pane.bounds.top, x2 - x1, pane.bounds.height);
|
|
25325
25588
|
}
|
|
25326
|
-
/** Renderer-owned session highlight bands: full-height (all panes), behind grid + data.
|
|
25589
|
+
/** Renderer-owned session highlight bands: full-height (all panes), behind grid + data.
|
|
25590
|
+
* Session-zone washes (pre/post-market) paint first, host highlights on top. */
|
|
25327
25591
|
drawHighlights(ctx, scene, coords) {
|
|
25328
|
-
|
|
25329
|
-
|
|
25592
|
+
const bands = [...scene.sessionHighlightBands(), ...scene.highlights];
|
|
25593
|
+
if (bands.length === 0) return;
|
|
25594
|
+
for (const band of bands) {
|
|
25330
25595
|
const x1 = coords.timeToX(band.from);
|
|
25331
25596
|
const x2 = coords.timeToX(band.to);
|
|
25332
25597
|
if (x2 < 0 || x1 > coords.width || x2 <= x1) continue;
|
|
@@ -26100,14 +26365,6 @@ void main() {
|
|
|
26100
26365
|
}
|
|
26101
26366
|
};
|
|
26102
26367
|
|
|
26103
|
-
// src/renderers/native/chrome/axisLayout.ts
|
|
26104
|
-
var AXIS_MASTER_W = 64;
|
|
26105
|
-
var AXIS_MERGED_W = 56;
|
|
26106
|
-
var PANE_SEPARATOR_PX = 3;
|
|
26107
|
-
function axisColumnX(dataW, column) {
|
|
26108
|
-
return column === 0 ? dataW : dataW + AXIS_MASTER_W + (column - 1) * AXIS_MERGED_W;
|
|
26109
|
-
}
|
|
26110
|
-
|
|
26111
26368
|
// src/renderers/native/chrome/ChromeRenderer.ts
|
|
26112
26369
|
var ChromeRenderer = class {
|
|
26113
26370
|
constructor() {
|
|
@@ -26990,6 +27247,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
26990
27247
|
for (const hr of hs.rows) {
|
|
26991
27248
|
if (hr.kind === "heading") body.append(this.sectionTitle(hr.label));
|
|
26992
27249
|
else if (hr.kind === "toggle") body.append(this.boolRow(hr.label, hr.get(), (v) => hr.set(v)));
|
|
27250
|
+
else if (hr.kind === "color") body.append(this.colorRow(hr.label, hr.get(), (v) => hr.set(v)));
|
|
26993
27251
|
else body.append(this.selectRowLabeled(hr.label, hr.get(), hr.options.map((o) => [o, o]), (v) => hr.set(v)));
|
|
26994
27252
|
}
|
|
26995
27253
|
}
|
|
@@ -29714,14 +29972,14 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
29714
29972
|
// src/renderers/native/drawings/DrawingSettingsPopup.ts
|
|
29715
29973
|
var BTN = 30;
|
|
29716
29974
|
var ICON = 21;
|
|
29717
|
-
var
|
|
29975
|
+
var STYLE_ID3 = "vela-drawing-popup-styles";
|
|
29718
29976
|
var STYLE_REV = "3";
|
|
29719
|
-
function
|
|
29977
|
+
function ensureStyles3() {
|
|
29720
29978
|
if (typeof document === "undefined") return;
|
|
29721
|
-
const existing = document.getElementById(
|
|
29979
|
+
const existing = document.getElementById(STYLE_ID3);
|
|
29722
29980
|
if (existing?.dataset.rev === STYLE_REV) return;
|
|
29723
29981
|
const s = existing ?? document.createElement("style");
|
|
29724
|
-
s.id =
|
|
29982
|
+
s.id = STYLE_ID3;
|
|
29725
29983
|
s.dataset.rev = STYLE_REV;
|
|
29726
29984
|
s.textContent = `
|
|
29727
29985
|
.vela-dpop-btn{background:transparent;color:var(--vela-fg-muted);transition:background var(--vela-dur-fast) ease,color var(--vela-dur-fast) ease;}
|
|
@@ -29778,7 +30036,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
29778
30036
|
* `onClose` fires on an outside-click dismissal (not a programmatic close). */
|
|
29779
30037
|
open(drawing, anchor, actions, onClose) {
|
|
29780
30038
|
this.close();
|
|
29781
|
-
|
|
30039
|
+
ensureStyles3();
|
|
29782
30040
|
this.onClose = onClose ?? null;
|
|
29783
30041
|
const t = this.theme;
|
|
29784
30042
|
const schema = drawing.schema();
|
|
@@ -30506,7 +30764,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
30506
30764
|
this.onCollapse = options.onCollapse ?? (() => {
|
|
30507
30765
|
});
|
|
30508
30766
|
this.onDrawingsSync = options.onDrawingsSync ?? null;
|
|
30509
|
-
|
|
30767
|
+
ensureStyles4();
|
|
30510
30768
|
this.root = document.createElement("div");
|
|
30511
30769
|
this.root.className = "vela-dtb";
|
|
30512
30770
|
this.styleRoot();
|
|
@@ -30989,13 +31247,13 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
30989
31247
|
}
|
|
30990
31248
|
};
|
|
30991
31249
|
var MAGNET_ID = "__magnet__";
|
|
30992
|
-
var
|
|
30993
|
-
function
|
|
31250
|
+
var STYLE_ID4 = "vela-drawing-toolbar-styles";
|
|
31251
|
+
function ensureStyles4() {
|
|
30994
31252
|
if (typeof document === "undefined") return;
|
|
30995
|
-
let s = document.getElementById(
|
|
31253
|
+
let s = document.getElementById(STYLE_ID4);
|
|
30996
31254
|
if (!s) {
|
|
30997
31255
|
s = document.createElement("style");
|
|
30998
|
-
s.id =
|
|
31256
|
+
s.id = STYLE_ID4;
|
|
30999
31257
|
document.head.appendChild(s);
|
|
31000
31258
|
}
|
|
31001
31259
|
s.textContent = `
|
|
@@ -32266,7 +32524,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
32266
32524
|
|
|
32267
32525
|
// src/renderers/native/chrome/AttributionMark.ts
|
|
32268
32526
|
var ATTRIBUTION_URL = "https://luxalgo.com/vela";
|
|
32269
|
-
var
|
|
32527
|
+
var STYLE_ID5 = "vela-attribution-styles";
|
|
32270
32528
|
var CSS2 = `
|
|
32271
32529
|
.vela-attribution {
|
|
32272
32530
|
text-decoration: none;
|
|
@@ -32329,11 +32587,11 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
32329
32587
|
[data-vela-layout='mobile'] .vela-attribution:hover .vela-attr-wordmark,
|
|
32330
32588
|
[data-layout='mobile'] .vela-attribution:hover .vela-attr-wordmark { transform: translateX(0); }
|
|
32331
32589
|
`;
|
|
32332
|
-
function
|
|
32333
|
-
let s = doc.getElementById(
|
|
32590
|
+
function ensureStyles5(doc) {
|
|
32591
|
+
let s = doc.getElementById(STYLE_ID5);
|
|
32334
32592
|
if (!s) {
|
|
32335
32593
|
s = doc.createElement("style");
|
|
32336
|
-
s.id =
|
|
32594
|
+
s.id = STYLE_ID5;
|
|
32337
32595
|
doc.head.appendChild(s);
|
|
32338
32596
|
}
|
|
32339
32597
|
s.textContent = CSS2;
|
|
@@ -32362,7 +32620,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
32362
32620
|
return el;
|
|
32363
32621
|
}
|
|
32364
32622
|
function createAttributionMark(doc, background) {
|
|
32365
|
-
|
|
32623
|
+
ensureStyles5(doc);
|
|
32366
32624
|
const a = doc.createElement("a");
|
|
32367
32625
|
a.className = "vela-attribution";
|
|
32368
32626
|
a.href = ATTRIBUTION_URL;
|
|
@@ -32874,6 +33132,8 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
32874
33132
|
// total right-gutter width (master column + merged-scale columns)
|
|
32875
33133
|
this.paneControls = null;
|
|
32876
33134
|
// per-pane hover button cluster (top-right)
|
|
33135
|
+
this.axisScaleButtons = null;
|
|
33136
|
+
// A/L hover buttons at the bottom of each pane's price scale
|
|
32877
33137
|
this.paneActionCbs = /* @__PURE__ */ new Set();
|
|
32878
33138
|
// ── data window (crosshair OHLC + per-series readout, pulled by host panels) ──
|
|
32879
33139
|
this.hoverLogical = null;
|
|
@@ -32917,7 +33177,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
32917
33177
|
this.priceStyleCbs = /* @__PURE__ */ new Set();
|
|
32918
33178
|
this.tableOverlays = /* @__PURE__ */ new Map();
|
|
32919
33179
|
this.name = "native";
|
|
32920
|
-
this.features = ["logScale", "currentPriceLine", "priceLabel", "countdown", "upColor", "downColor", "glow", "animZoom", "animPan", "intro", "zoomAnchor", "axisDrag", "paneResize", "candleZOrder", "candleVisible", "seriesOrder", "highlights", "gridlines", "axisLabels", "scaleMode", "invertScale", "paneScales", "autoScale", "timezone", "keyboard", "historyChords", "priceStyle", "priceBaseline", "baselinePrice", "settings", "attribution", "dialogHost", "tradeMarkers", "indicatorTitles", "indicatorValues"];
|
|
33180
|
+
this.features = ["logScale", "currentPriceLine", "priceLabel", "countdown", "upColor", "downColor", "glow", "animZoom", "animPan", "intro", "zoomAnchor", "axisDrag", "paneResize", "candleZOrder", "candleVisible", "seriesOrder", "highlights", "sessionZones", "gridlines", "axisLabels", "scaleMode", "invertScale", "paneScales", "autoScale", "timezone", "keyboard", "historyChords", "priceStyle", "priceBaseline", "baselinePrice", "settings", "attribution", "dialogHost", "tradeMarkers", "indicatorTitles", "indicatorValues"];
|
|
32921
33181
|
/** Track cursor proximity to the scroll button on the plot (bubbles from the button too,
|
|
32922
33182
|
* so moving onto the button doesn't count as leaving). */
|
|
32923
33183
|
this.onScrollProximityMove = (e) => {
|
|
@@ -33033,6 +33293,9 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
33033
33293
|
case "highlights":
|
|
33034
33294
|
this.scene.highlights = sanitizeHighlights(value);
|
|
33035
33295
|
break;
|
|
33296
|
+
case "sessionZones":
|
|
33297
|
+
this.scene.sessionZones = sanitizeSessionZones(value);
|
|
33298
|
+
break;
|
|
33036
33299
|
case "gridlines":
|
|
33037
33300
|
this.scene.showGrid = Boolean(value);
|
|
33038
33301
|
break;
|
|
@@ -33149,6 +33412,8 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
33149
33412
|
return this.scene.indicatorZOrder();
|
|
33150
33413
|
case "highlights":
|
|
33151
33414
|
return this.scene.highlights;
|
|
33415
|
+
case "sessionZones":
|
|
33416
|
+
return this.scene.sessionZones;
|
|
33152
33417
|
case "gridlines":
|
|
33153
33418
|
return this.scene.showGrid;
|
|
33154
33419
|
case "axisLabels":
|
|
@@ -33358,7 +33623,8 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
33358
33623
|
baselineLevel: s.baseline.baselineLevel
|
|
33359
33624
|
};
|
|
33360
33625
|
})(),
|
|
33361
|
-
series: { style: this.scene.priceStyle, baseline: this.scene.baselineValue, spacing: this.coords.spacingScale }
|
|
33626
|
+
series: { style: this.scene.priceStyle, baseline: this.scene.baselineValue, spacing: this.coords.spacingScale },
|
|
33627
|
+
sessions: { premarketColor: s.sessions.premarketColor, postmarketColor: s.sessions.postmarketColor }
|
|
33362
33628
|
};
|
|
33363
33629
|
}
|
|
33364
33630
|
/**
|
|
@@ -33440,6 +33706,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
33440
33706
|
width: next2.baseline.width,
|
|
33441
33707
|
baselineLevel: next2.baseline.baselineLevel
|
|
33442
33708
|
};
|
|
33709
|
+
s.sessions = { premarketColor: next2.sessions.premarketColor, postmarketColor: next2.sessions.postmarketColor };
|
|
33443
33710
|
this.setPriceStyle(next2.series.style);
|
|
33444
33711
|
this.scene.candleOverride = candleOverrideFor(this.scene.priceStyle, s.chartTypes);
|
|
33445
33712
|
this.scene.baselineValue = next2.series.baseline;
|
|
@@ -33453,6 +33720,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
33453
33720
|
}
|
|
33454
33721
|
this.inputsUI?.setTheme(this.theme);
|
|
33455
33722
|
this.paneControls?.setTheme(this.theme);
|
|
33723
|
+
this.axisScaleButtons?.setTheme(this.theme);
|
|
33456
33724
|
this.userDrawings?.setTheme(this.chromeTheme());
|
|
33457
33725
|
this.refreshScrollButtonTheme();
|
|
33458
33726
|
this.refreshAttributionColor();
|
|
@@ -33791,7 +34059,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
33791
34059
|
this.surfaceBackground = theme.background;
|
|
33792
34060
|
this.surfaceTextColor = theme.textColor;
|
|
33793
34061
|
this.wrapper = document.createElement("div");
|
|
33794
|
-
Object.assign(this.wrapper.style, { position: "relative", width: "100%", height: "100%", overflow: "hidden", cursor: "crosshair" });
|
|
34062
|
+
Object.assign(this.wrapper.style, { position: "relative", width: "100%", height: "100%", overflow: "hidden", cursor: "crosshair", userSelect: "none", webkitUserSelect: "none" });
|
|
33795
34063
|
applyChromeTokens(this.wrapper, this.chromeTheme());
|
|
33796
34064
|
this.volumeCanvas = document.createElement("canvas");
|
|
33797
34065
|
Object.assign(this.volumeCanvas.style, { position: "absolute", inset: "0", width: "100%", height: "100%", pointerEvents: "none" });
|
|
@@ -33960,6 +34228,15 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
33960
34228
|
this.emitPaneAction({ type: "maximize", paneId, maximized });
|
|
33961
34229
|
}
|
|
33962
34230
|
});
|
|
34231
|
+
this.axisScaleButtons = new AxisScaleButtons(this.plot, theme, {
|
|
34232
|
+
panes: () => this.axisScaleViews(),
|
|
34233
|
+
rightAxis: () => this.rightAxisW,
|
|
34234
|
+
onToggleAuto: (paneId) => this.togglePaneAuto(paneId),
|
|
34235
|
+
onToggleLog: (paneId) => {
|
|
34236
|
+
const pane = this.scene.panes.get(paneId);
|
|
34237
|
+
if (pane) this.setPaneLog(paneId, !paneLogScale(this.scene, pane));
|
|
34238
|
+
}
|
|
34239
|
+
});
|
|
33963
34240
|
this.resizeObserver = new ResizeObserver(() => this.resize());
|
|
33964
34241
|
this.resizeObserver.observe(this.wrapper);
|
|
33965
34242
|
this.watchDpr();
|
|
@@ -34036,6 +34313,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
34036
34313
|
this.applyBackground();
|
|
34037
34314
|
this.inputsUI.setTheme(theme);
|
|
34038
34315
|
this.paneControls?.setTheme(this.theme);
|
|
34316
|
+
this.axisScaleButtons?.setTheme(this.theme);
|
|
34039
34317
|
this.settingsDialog?.refreshConfig(this.getConfig());
|
|
34040
34318
|
this.syncThemeControl();
|
|
34041
34319
|
this.settingsDialog?.setTheme(this.theme);
|
|
@@ -34084,6 +34362,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
34084
34362
|
this.liveRegion = null;
|
|
34085
34363
|
this.inputsUI?.destroy();
|
|
34086
34364
|
this.paneControls?.destroy();
|
|
34365
|
+
this.axisScaleButtons?.destroy();
|
|
34087
34366
|
for (const overlay of this.tableOverlays.values()) overlay.destroy();
|
|
34088
34367
|
this.tableOverlays.clear();
|
|
34089
34368
|
this.resizeObserver?.disconnect();
|
|
@@ -35478,6 +35757,25 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35478
35757
|
invert: paneInvert(this.scene, p)
|
|
35479
35758
|
}));
|
|
35480
35759
|
}
|
|
35760
|
+
/** Thin projection of the panes for the axis A/L hover buttons (top-to-bottom order). */
|
|
35761
|
+
axisScaleViews() {
|
|
35762
|
+
return this.scene.orderedPanes().map((p) => ({
|
|
35763
|
+
id: p.id,
|
|
35764
|
+
top: p.bounds.top,
|
|
35765
|
+
height: p.bounds.height,
|
|
35766
|
+
collapsed: p.collapsed,
|
|
35767
|
+
auto: p.manualScale == null,
|
|
35768
|
+
log: paneLogScale(this.scene, p)
|
|
35769
|
+
}));
|
|
35770
|
+
}
|
|
35771
|
+
/** Toggle one pane's autoscale (the A axis button): off freezes the current window into
|
|
35772
|
+
* manual mode, on drops it — the per-pane twin of the chart-level `autoScale` feature. */
|
|
35773
|
+
togglePaneAuto(paneId) {
|
|
35774
|
+
const pane = this.scene.panes.get(paneId);
|
|
35775
|
+
if (!pane) return;
|
|
35776
|
+
pane.manualScale = pane.manualScale == null ? { ...pane.scale } : null;
|
|
35777
|
+
this.scheduler?.invalidate(4 /* Full */);
|
|
35778
|
+
}
|
|
35481
35779
|
/** Set one pane's axis mode. The price pane routes to the scene-level setting (persisted +
|
|
35482
35780
|
* keyboard shortcuts); a study pane keeps its own, so panes never affect each other. */
|
|
35483
35781
|
setPaneScaleMode(paneId, mode) {
|
|
@@ -35489,19 +35787,18 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35489
35787
|
}
|
|
35490
35788
|
this.scheduler?.invalidate(4 /* Full */);
|
|
35491
35789
|
}
|
|
35492
|
-
/** Set one pane's logarithmic flag
|
|
35493
|
-
*
|
|
35790
|
+
/** Set one pane's logarithmic flag; the price pane routes to the scene-level flag.
|
|
35791
|
+
* Log and auto are INDEPENDENT: a frozen (manual) window is kept — its price bounds
|
|
35792
|
+
* stay put and only its `log` tag flips, so the same range re-renders in the new
|
|
35793
|
+
* space instead of snapping back to autoscale. */
|
|
35494
35794
|
setPaneLog(paneId, log) {
|
|
35495
|
-
|
|
35496
|
-
|
|
35497
|
-
|
|
35498
|
-
if (
|
|
35499
|
-
|
|
35500
|
-
const p = this.scene.panes.get(paneId);
|
|
35501
|
-
if (!p) return;
|
|
35502
|
-
p.logScale = log;
|
|
35503
|
-
p.manualScale = null;
|
|
35795
|
+
const pane = paneId === PRICE_PANE_ID ? this.scene.orderedPanes().find((p) => p.kind === "price") : this.scene.panes.get(paneId);
|
|
35796
|
+
if (paneId === PRICE_PANE_ID) this.scene.logScale = log;
|
|
35797
|
+
else {
|
|
35798
|
+
if (!pane) return;
|
|
35799
|
+
pane.logScale = log;
|
|
35504
35800
|
}
|
|
35801
|
+
if (pane?.manualScale) pane.manualScale.log = log;
|
|
35505
35802
|
this.scheduler?.invalidate(4 /* Full */);
|
|
35506
35803
|
}
|
|
35507
35804
|
/** Flip one pane's axis (high at the bottom). The price pane routes to the scene-level flag
|
|
@@ -35600,6 +35897,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35600
35897
|
}
|
|
35601
35898
|
this.inputsUI?.reposition();
|
|
35602
35899
|
this.paneControls?.reposition();
|
|
35900
|
+
this.axisScaleButtons?.reposition();
|
|
35603
35901
|
this.repositionScrollButton();
|
|
35604
35902
|
this.positionAttribution();
|
|
35605
35903
|
this.publishPricePaneBounds();
|
|
@@ -35618,6 +35916,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35618
35916
|
}
|
|
35619
35917
|
this.inputsUI?.reposition();
|
|
35620
35918
|
this.paneControls?.reposition();
|
|
35919
|
+
this.axisScaleButtons?.reposition();
|
|
35621
35920
|
this.repositionScrollButton();
|
|
35622
35921
|
this.positionAttribution();
|
|
35623
35922
|
this.publishPricePaneBounds();
|
|
@@ -35825,6 +36124,22 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
35825
36124
|
}
|
|
35826
36125
|
return out.sort((a, b) => a.from - b.from);
|
|
35827
36126
|
}
|
|
36127
|
+
function sanitizeSessionZones(value) {
|
|
36128
|
+
if (value == null || typeof value !== "object") return null;
|
|
36129
|
+
const v = value;
|
|
36130
|
+
const windows = (raw) => {
|
|
36131
|
+
if (!Array.isArray(raw)) return [];
|
|
36132
|
+
const out = [];
|
|
36133
|
+
for (const w of raw) {
|
|
36134
|
+
if (!Array.isArray(w)) continue;
|
|
36135
|
+
const from = Number(w[0]);
|
|
36136
|
+
const to = Number(w[1]);
|
|
36137
|
+
if (Number.isFinite(from) && Number.isFinite(to) && to > from) out.push([from, to]);
|
|
36138
|
+
}
|
|
36139
|
+
return out.sort((a, b) => a[0] - b[0]);
|
|
36140
|
+
};
|
|
36141
|
+
return { pre: windows(v.pre), post: windows(v.post) };
|
|
36142
|
+
}
|
|
35828
36143
|
function clamp012(v) {
|
|
35829
36144
|
return Math.max(0, Math.min(1, v));
|
|
35830
36145
|
}
|
|
@@ -37703,6 +38018,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
|
|
|
37703
38018
|
exports.getDrawingType = getDrawingType;
|
|
37704
38019
|
exports.getNativeIndicator = getNativeIndicator;
|
|
37705
38020
|
exports.iconMarkup = iconMarkup;
|
|
38021
|
+
exports.inputVisible = inputVisible;
|
|
37706
38022
|
exports.legendActions = legendActions;
|
|
37707
38023
|
exports.nativeIndicatorDescriptors = nativeIndicatorDescriptors;
|
|
37708
38024
|
exports.nativeIndicatorTypes = nativeIndicatorTypes;
|