@luxalgo/vela 0.7.5 → 0.7.7
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-Dut6lXGM.d.cts → DataProvider-CGa4KHRa.d.cts} +1 -1
- package/dist/{DataProvider-DLeFs1gE.d.ts → DataProvider-CmWUtDVL.d.ts} +1 -1
- package/dist/{chunk-ZADTVRUO.js → chunk-PVGWNF7V.js} +1 -1
- package/dist/{chunk-MCLI6B3S.js → chunk-RVQWJOEE.js} +277 -120
- package/dist/{chunk-BKHSQ4YM.js → chunk-WTWGEB7K.js} +23 -9
- package/dist/{chunk-MNG5XPLV.js → chunk-ZA2XWTGH.js} +94 -37
- package/dist/{contributions-DYtiRtES.d.cts → contributions-DF_Ea07m.d.cts} +25 -2
- package/dist/{contributions-CEkgJKTU.d.ts → contributions-nKOSeLy8.d.ts} +25 -2
- package/dist/index.cjs +285 -127
- package/dist/index.d.cts +22 -7
- package/dist/index.d.ts +22 -7
- package/dist/index.js +2 -2
- package/dist/{options-DNBoMKkX.d.ts → options-D1AJKsn_.d.cts} +10 -0
- package/dist/{options-DNBoMKkX.d.cts → options-D1AJKsn_.d.ts} +10 -0
- package/dist/{plugin-CLn--oP6.d.ts → plugin-0oFDnexb.d.ts} +3 -3
- package/dist/{plugin-DtkeQVAO.d.cts → plugin-DPyVJFoA.d.cts} +3 -3
- package/dist/plugin.d.cts +4 -4
- package/dist/plugin.d.ts +4 -4
- 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/{statusline-model-gA__yaog.d.cts → statusline-model-BoWJ3cWQ.d.cts} +18 -5
- package/dist/{statusline-model-DypGXjtr.d.ts → statusline-model-DAFyqVmR.d.ts} +18 -5
- package/dist/ui.cjs +23 -9
- package/dist/ui.d.cts +20 -3
- package/dist/ui.d.ts +20 -3
- package/dist/ui.js +2 -2
- package/dist/vela.global.js +285 -127
- package/dist/vela.global.min.js +59 -49
- package/dist/widget.cjs +389 -161
- package/dist/widget.d.cts +7 -7
- package/dist/widget.d.ts +7 -7
- package/dist/widget.js +5 -5
- package/dist/workspace.cjs +389 -161
- package/dist/workspace.d.cts +40 -8
- package/dist/workspace.d.ts +40 -8
- package/dist/workspace.js +4 -4
- package/package.json +21 -1
package/dist/workspace.cjs
CHANGED
|
@@ -3521,7 +3521,8 @@ function addRecent(hex6) {
|
|
|
3521
3521
|
recents.unshift(hex6);
|
|
3522
3522
|
if (recents.length > 10) recents.length = 10;
|
|
3523
3523
|
}
|
|
3524
|
-
function buildColorPicker(color, theme, onChange) {
|
|
3524
|
+
function buildColorPicker(color, theme, onChange, options = {}) {
|
|
3525
|
+
const commit = options.commit ?? "live";
|
|
3525
3526
|
const parsed = splitColor(color);
|
|
3526
3527
|
let curHex = parsed.hex6;
|
|
3527
3528
|
let curAlpha = parsed.alpha;
|
|
@@ -3604,7 +3605,12 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
3604
3605
|
const r = track.getBoundingClientRect();
|
|
3605
3606
|
curAlpha = Math.max(0, Math.min(1, (clientX - r.left) / r.width));
|
|
3606
3607
|
paintOpacity();
|
|
3607
|
-
emit();
|
|
3608
|
+
if (commit === "live") emit();
|
|
3609
|
+
};
|
|
3610
|
+
const endDrag = () => {
|
|
3611
|
+
if (!dragging) return;
|
|
3612
|
+
dragging = false;
|
|
3613
|
+
if (commit === "release") emit();
|
|
3608
3614
|
};
|
|
3609
3615
|
track.addEventListener("pointerdown", (e) => {
|
|
3610
3616
|
e.stopPropagation();
|
|
@@ -3615,7 +3621,8 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
3615
3621
|
track.addEventListener("pointermove", (e) => {
|
|
3616
3622
|
if (dragging) onDrag(e.clientX);
|
|
3617
3623
|
});
|
|
3618
|
-
track.addEventListener("pointerup",
|
|
3624
|
+
track.addEventListener("pointerup", endDrag);
|
|
3625
|
+
track.addEventListener("pointercancel", endDrag);
|
|
3619
3626
|
function emit() {
|
|
3620
3627
|
onChange(combineColor(curHex, curAlpha));
|
|
3621
3628
|
}
|
|
@@ -3638,7 +3645,7 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
3638
3645
|
return root;
|
|
3639
3646
|
}
|
|
3640
3647
|
function colorField(theme, getVal, onVal, opts) {
|
|
3641
|
-
return new ColorField({ theme, getVal, onVal, shape: opts?.shape, id: opts?.id, popover: opts?.popover }).el;
|
|
3648
|
+
return new ColorField({ theme, getVal, onVal, shape: opts?.shape, id: opts?.id, popover: opts?.popover, commit: opts?.commit }).el;
|
|
3642
3649
|
}
|
|
3643
3650
|
var ColorField = class {
|
|
3644
3651
|
constructor(opts) {
|
|
@@ -3647,6 +3654,7 @@ var ColorField = class {
|
|
|
3647
3654
|
this.getVal = opts.getVal;
|
|
3648
3655
|
this.onVal = opts.onVal;
|
|
3649
3656
|
this.popoverOpts = opts.popover;
|
|
3657
|
+
this.commit = opts.commit;
|
|
3650
3658
|
const trigger = document.createElement("button");
|
|
3651
3659
|
trigger.type = "button";
|
|
3652
3660
|
if (opts.id) trigger.id = opts.id;
|
|
@@ -3686,10 +3694,15 @@ var ColorField = class {
|
|
|
3686
3694
|
boundary: this.popoverOpts?.boundary,
|
|
3687
3695
|
zIndex: this.popoverOpts?.zIndex,
|
|
3688
3696
|
className: "vela-color-field-pop",
|
|
3689
|
-
content: buildColorPicker(
|
|
3690
|
-
this.
|
|
3691
|
-
this.
|
|
3692
|
-
|
|
3697
|
+
content: buildColorPicker(
|
|
3698
|
+
this.getVal(),
|
|
3699
|
+
this.theme,
|
|
3700
|
+
(val) => {
|
|
3701
|
+
this.onVal(val);
|
|
3702
|
+
this.paint();
|
|
3703
|
+
},
|
|
3704
|
+
{ commit: this.commit }
|
|
3705
|
+
)
|
|
3693
3706
|
});
|
|
3694
3707
|
pop.show();
|
|
3695
3708
|
}
|
|
@@ -4277,7 +4290,8 @@ function buildFieldControl(desc) {
|
|
|
4277
4290
|
const el2 = colorField(desc.theme, desc.get, desc.onChange, {
|
|
4278
4291
|
shape: "circle",
|
|
4279
4292
|
id: desc.id,
|
|
4280
|
-
popover: desc.popover
|
|
4293
|
+
popover: desc.popover,
|
|
4294
|
+
commit: desc.commit
|
|
4281
4295
|
});
|
|
4282
4296
|
if (desc.title) el2.title = desc.title;
|
|
4283
4297
|
return { el: el2 };
|
|
@@ -5016,10 +5030,12 @@ var BASELINE_LEVEL_DEFAULT = 50;
|
|
|
5016
5030
|
var PREMARKET_SHADE = withAlpha(WARNING, 0.08);
|
|
5017
5031
|
var POSTMARKET_SHADE = withAlpha(ACCENT, 0.08);
|
|
5018
5032
|
var EXTENDED_SHADE = POSTMARKET_SHADE;
|
|
5033
|
+
var DEFAULT_MARGINS = { top: 10, bottom: 10, right: 10 };
|
|
5019
5034
|
function defaultChartStyle() {
|
|
5020
5035
|
return {
|
|
5021
5036
|
chartTypes: {},
|
|
5022
5037
|
fontSize: 11,
|
|
5038
|
+
margins: { ...DEFAULT_MARGINS },
|
|
5023
5039
|
gridVert: { visible: true, color: null },
|
|
5024
5040
|
gridHorz: { visible: true, color: null },
|
|
5025
5041
|
borderColor: null,
|
|
@@ -5143,6 +5159,12 @@ function clampLevel(v) {
|
|
|
5143
5159
|
function clampSpacing(v) {
|
|
5144
5160
|
return v < 0.1 ? 0.1 : v > 10 ? 10 : v;
|
|
5145
5161
|
}
|
|
5162
|
+
function clampMarginPct(v) {
|
|
5163
|
+
return v < 0 ? 0 : v > 40 ? 40 : v;
|
|
5164
|
+
}
|
|
5165
|
+
function clampMarginBars(v) {
|
|
5166
|
+
return Math.round(v < 0 ? 0 : v > 200 ? 200 : v);
|
|
5167
|
+
}
|
|
5146
5168
|
function factoryResetConfig(factory, priceStyle = factory.series.style) {
|
|
5147
5169
|
const bag = {};
|
|
5148
5170
|
for (const t of chartTypes()) {
|
|
@@ -5191,6 +5213,7 @@ function mergeConfig(base, patch) {
|
|
|
5191
5213
|
const ps = asObject(p.priceScale);
|
|
5192
5214
|
const anim = asObject(p.animations);
|
|
5193
5215
|
const panes = asObject(p.panes);
|
|
5216
|
+
const margins = asObject(p.margins);
|
|
5194
5217
|
const trades = asObject(p.trades);
|
|
5195
5218
|
const ts = asObject(p.timeScale);
|
|
5196
5219
|
const marks = asObject(p.marks);
|
|
@@ -5250,6 +5273,11 @@ function mergeConfig(base, patch) {
|
|
|
5250
5273
|
panes: {
|
|
5251
5274
|
separatorColor: isColor(panes.separatorColor) ? panes.separatorColor : base.panes.separatorColor
|
|
5252
5275
|
},
|
|
5276
|
+
margins: {
|
|
5277
|
+
top: isNum(margins.top) ? clampMarginPct(margins.top) : base.margins.top,
|
|
5278
|
+
bottom: isNum(margins.bottom) ? clampMarginPct(margins.bottom) : base.margins.bottom,
|
|
5279
|
+
right: isNum(margins.right) ? clampMarginBars(margins.right) : base.margins.right
|
|
5280
|
+
},
|
|
5253
5281
|
trades: {
|
|
5254
5282
|
visible: isBool(trades.visible) ? trades.visible : base.trades.visible,
|
|
5255
5283
|
labels: isBool(trades.labels) ? trades.labels : base.trades.labels,
|
|
@@ -6071,9 +6099,22 @@ var TIMEZONES = [
|
|
|
6071
6099
|
{ value: "Pacific/Apia", label: "Apia" },
|
|
6072
6100
|
{ value: "Pacific/Kiritimati", label: "Kiritimati" }
|
|
6073
6101
|
];
|
|
6102
|
+
var EXCHANGE_TIMEZONE = "exchange";
|
|
6103
|
+
function isExchangeTimezone(zone) {
|
|
6104
|
+
return zone === EXCHANGE_TIMEZONE;
|
|
6105
|
+
}
|
|
6106
|
+
function resolveTimezone(zone, exchangeZone) {
|
|
6107
|
+
if (!isExchangeTimezone(zone)) return zone;
|
|
6108
|
+
return exchangeZone && exchangeZone !== "" ? exchangeZone : "Etc/UTC";
|
|
6109
|
+
}
|
|
6074
6110
|
function normalizeTimezone(zone) {
|
|
6075
6111
|
return zone === "UTC" || zone === "Etc/UTC" || zone === "Etc/GMT" ? "Etc/UTC" : zone;
|
|
6076
6112
|
}
|
|
6113
|
+
function timezoneMenuRows(current) {
|
|
6114
|
+
const active = normalizeTimezone(current);
|
|
6115
|
+
const [utc, ...zones] = TIMEZONES.map((t) => ({ value: t.value, label: tzMenuLabel(t.value, t.label), checked: t.value === active }));
|
|
6116
|
+
return [utc, { value: EXCHANGE_TIMEZONE, label: "Exchange", checked: isExchangeTimezone(current) }, ...zones];
|
|
6117
|
+
}
|
|
6077
6118
|
function tzOffset(zone, date = /* @__PURE__ */ new Date()) {
|
|
6078
6119
|
try {
|
|
6079
6120
|
const parts = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "shortOffset" }).formatToParts(date);
|
|
@@ -6196,6 +6237,7 @@ var Bottombar = class {
|
|
|
6196
6237
|
this.sessionButtons = /* @__PURE__ */ new Map();
|
|
6197
6238
|
this.sessionEl = null;
|
|
6198
6239
|
this.timezone = opts.timezone;
|
|
6240
|
+
this.exchangeTimezone = opts.exchangeTimezone;
|
|
6199
6241
|
const doc = host.ownerDocument;
|
|
6200
6242
|
injectStyles(STYLE_ID3, CSS4, doc);
|
|
6201
6243
|
this.el = doc.createElement("div");
|
|
@@ -6219,7 +6261,7 @@ var Bottombar = class {
|
|
|
6219
6261
|
this.clockEl = doc.createElement("span");
|
|
6220
6262
|
this.clockEl.className = "vela-bb-clock";
|
|
6221
6263
|
this.tzLabelEl = doc.createElement("span");
|
|
6222
|
-
this.tzLabelEl.textContent = tzButtonLabel(this.
|
|
6264
|
+
this.tzLabelEl.textContent = tzButtonLabel(this.displayZone);
|
|
6223
6265
|
this.tzButton.append(this.clockEl, this.tzLabelEl);
|
|
6224
6266
|
const session = doc.createElement("span");
|
|
6225
6267
|
session.className = "vela-bb-session";
|
|
@@ -6254,19 +6296,32 @@ var Bottombar = class {
|
|
|
6254
6296
|
placement: "top-end",
|
|
6255
6297
|
items: this.tzItems(),
|
|
6256
6298
|
onSelect: (zone) => {
|
|
6257
|
-
this.setTimezone(zone);
|
|
6299
|
+
this.setTimezone(zone, this.exchangeTimezone);
|
|
6258
6300
|
opts.onTimezone(zone);
|
|
6259
6301
|
}
|
|
6260
6302
|
});
|
|
6261
6303
|
this.tick();
|
|
6262
6304
|
this.unsubClock = (opts.clock ?? new SecondClock()).onTick(() => this.tick());
|
|
6263
6305
|
}
|
|
6264
|
-
|
|
6306
|
+
/**
|
|
6307
|
+
* Reflect the stored choice AND the active chart's market zone. The clock and the
|
|
6308
|
+
* offset label read the RESOLVED zone, so a workspace on the exchange rule re-labels
|
|
6309
|
+
* when the active cell (or its symbol) changes market — the host re-projects on
|
|
6310
|
+
* both. Idempotent: unchanged inputs leave the menu alone.
|
|
6311
|
+
*/
|
|
6312
|
+
setTimezone(zone, exchangeTimezone) {
|
|
6313
|
+
if (zone === this.timezone && exchangeTimezone === this.exchangeTimezone) return;
|
|
6314
|
+
const choiceChanged = zone !== this.timezone;
|
|
6265
6315
|
this.timezone = zone;
|
|
6266
|
-
this.
|
|
6267
|
-
this.
|
|
6316
|
+
this.exchangeTimezone = exchangeTimezone;
|
|
6317
|
+
this.tzLabelEl.textContent = tzButtonLabel(this.displayZone);
|
|
6318
|
+
if (choiceChanged) this.tzMenu.setItems(this.tzItems());
|
|
6268
6319
|
this.tick();
|
|
6269
6320
|
}
|
|
6321
|
+
/** The zone the bar's clock and label render in. */
|
|
6322
|
+
get displayZone() {
|
|
6323
|
+
return resolveTimezone(this.timezone, this.exchangeTimezone);
|
|
6324
|
+
}
|
|
6270
6325
|
/** Highlight (or clear with null) the active range chip — cleared on manual tf changes. */
|
|
6271
6326
|
setActiveRange(id) {
|
|
6272
6327
|
for (const [key, b] of this.rangeButtons) {
|
|
@@ -6294,11 +6349,7 @@ var Bottombar = class {
|
|
|
6294
6349
|
this.el.remove();
|
|
6295
6350
|
}
|
|
6296
6351
|
tzItems() {
|
|
6297
|
-
return
|
|
6298
|
-
id: t.value,
|
|
6299
|
-
label: tzMenuLabel(t.value, t.label),
|
|
6300
|
-
checked: t.value === normalizeTimezone(this.timezone)
|
|
6301
|
-
}));
|
|
6352
|
+
return timezoneMenuRows(this.timezone).map((r) => ({ id: r.value, label: r.label, checked: r.checked }));
|
|
6302
6353
|
}
|
|
6303
6354
|
tick() {
|
|
6304
6355
|
try {
|
|
@@ -6307,7 +6358,7 @@ var Bottombar = class {
|
|
|
6307
6358
|
minute: "2-digit",
|
|
6308
6359
|
second: "2-digit",
|
|
6309
6360
|
hour12: false,
|
|
6310
|
-
timeZone: this.
|
|
6361
|
+
timeZone: this.displayZone
|
|
6311
6362
|
}).format(/* @__PURE__ */ new Date());
|
|
6312
6363
|
} catch {
|
|
6313
6364
|
this.clockEl.textContent = "";
|
|
@@ -15929,15 +15980,14 @@ var TimezoneDrawer = class {
|
|
|
15929
15980
|
this.drawer.body.replaceChildren();
|
|
15930
15981
|
const list = doc.createElement("div");
|
|
15931
15982
|
list.className = "vela-tzd-list";
|
|
15932
|
-
const
|
|
15933
|
-
for (const tz of TIMEZONES) {
|
|
15983
|
+
for (const tz of timezoneMenuRows(this.opts.timezone())) {
|
|
15934
15984
|
const row = doc.createElement("div");
|
|
15935
15985
|
row.className = "vela-tzd-row";
|
|
15936
15986
|
const label = doc.createElement("span");
|
|
15937
15987
|
label.className = "vela-tzd-row-label";
|
|
15938
|
-
label.textContent =
|
|
15988
|
+
label.textContent = tz.label;
|
|
15939
15989
|
row.appendChild(label);
|
|
15940
|
-
if (tz.
|
|
15990
|
+
if (tz.checked) row.appendChild(iconEl("check", doc));
|
|
15941
15991
|
row.addEventListener("click", () => {
|
|
15942
15992
|
this.opts.onTimezone(tz.value);
|
|
15943
15993
|
this.drawer.hide();
|
|
@@ -16024,12 +16074,11 @@ function priceAxisItems(s) {
|
|
|
16024
16074
|
];
|
|
16025
16075
|
}
|
|
16026
16076
|
function timeAxisItems(timezone) {
|
|
16027
|
-
const active = timezone === "UTC" ? "Etc/UTC" : timezone;
|
|
16028
16077
|
return [
|
|
16029
16078
|
{
|
|
16030
16079
|
id: "timezone",
|
|
16031
16080
|
label: "Time zone",
|
|
16032
|
-
submenu:
|
|
16081
|
+
submenu: timezoneMenuRows(timezone).map((r) => ({ id: `tz:${r.value}`, label: r.label, checked: r.checked }))
|
|
16033
16082
|
},
|
|
16034
16083
|
settingsItem("time-axis", "More settings\u2026")
|
|
16035
16084
|
];
|
|
@@ -18392,10 +18441,18 @@ var IndicatorRegistry = class {
|
|
|
18392
18441
|
this.records = /* @__PURE__ */ new Map();
|
|
18393
18442
|
this.counter = 0;
|
|
18394
18443
|
}
|
|
18395
|
-
/**
|
|
18396
|
-
|
|
18397
|
-
|
|
18398
|
-
|
|
18444
|
+
/**
|
|
18445
|
+
* Mint a unique per-instance id. Host-supplied ids share the namespace, so a minted
|
|
18446
|
+
* id skips anything already recorded — and anything `taken` reports live elsewhere
|
|
18447
|
+
* (a handle the orchestrator holds outside the records, e.g. a fail-soft native).
|
|
18448
|
+
*/
|
|
18449
|
+
nextId(prefix = "ind", taken = () => false) {
|
|
18450
|
+
let id;
|
|
18451
|
+
do {
|
|
18452
|
+
this.counter += 1;
|
|
18453
|
+
id = `${prefix}-${this.counter}`;
|
|
18454
|
+
} while (this.records.has(id) || taken(id));
|
|
18455
|
+
return id;
|
|
18399
18456
|
}
|
|
18400
18457
|
add(record) {
|
|
18401
18458
|
this.records.set(record.id, record);
|
|
@@ -19778,7 +19835,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
19778
19835
|
this.engines.set(language, engine);
|
|
19779
19836
|
}
|
|
19780
19837
|
addIndicator(source, options = {}) {
|
|
19781
|
-
const id = this.
|
|
19838
|
+
const id = this.claimIndicatorId(options.id);
|
|
19782
19839
|
const title = options.title ?? "Indicator";
|
|
19783
19840
|
const handle = new IndicatorHandleImpl(id, title, this, source);
|
|
19784
19841
|
this.handles.set(id, handle);
|
|
@@ -19800,7 +19857,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
19800
19857
|
const existing = this.registry.all().find((r) => r.native?.type === type);
|
|
19801
19858
|
if (existing) return this.handles.get(existing.id) ?? new IndicatorHandleImpl(existing.id, existing.title, this, void 0, type);
|
|
19802
19859
|
}
|
|
19803
|
-
const id = this.registry.nextId("native");
|
|
19860
|
+
const id = this.registry.nextId("native", (candidate) => this.handles.has(candidate));
|
|
19804
19861
|
const title = descriptor?.title ?? type;
|
|
19805
19862
|
const handle = new IndicatorHandleImpl(id, title, this, void 0, type);
|
|
19806
19863
|
this.handles.set(id, handle);
|
|
@@ -20078,6 +20135,24 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
20078
20135
|
this.events.clear();
|
|
20079
20136
|
}
|
|
20080
20137
|
// ── internals ───────────────────────────────────────────────
|
|
20138
|
+
/**
|
|
20139
|
+
* The id a new script indicator runs under: the host's when supplied, else a minted
|
|
20140
|
+
* one. A host id is opaque but must be a non-empty string, and it must not be live
|
|
20141
|
+
* on this chart — a duplicate is a programming error surfaced synchronously, never
|
|
20142
|
+
* renamed behind the caller's back (the whole point of supplying one is that
|
|
20143
|
+
* `handle.id` equals what was passed). "Live" reads both the records and the handle
|
|
20144
|
+
* map: a fail-soft handle never enters the registry but still owns its id.
|
|
20145
|
+
*/
|
|
20146
|
+
claimIndicatorId(requested) {
|
|
20147
|
+
if (requested === void 0) return this.registry.nextId("ind", (candidate) => this.handles.has(candidate));
|
|
20148
|
+
if (typeof requested !== "string" || requested.length === 0) {
|
|
20149
|
+
throw new TypeError("[vela] addIndicator: `id` must be a non-empty string");
|
|
20150
|
+
}
|
|
20151
|
+
if (this.handles.has(requested) || this.registry.get(requested)) {
|
|
20152
|
+
throw new Error(`[vela] addIndicator: indicator id "${requested}" is already live on this chart`);
|
|
20153
|
+
}
|
|
20154
|
+
return requested;
|
|
20155
|
+
}
|
|
20081
20156
|
async startIndicator(id, source, options, handle) {
|
|
20082
20157
|
try {
|
|
20083
20158
|
await this.readyPromise;
|
|
@@ -21676,7 +21751,10 @@ var IndicatorInputsDialog = class {
|
|
|
21676
21751
|
id,
|
|
21677
21752
|
theme: this.host.theme(),
|
|
21678
21753
|
get: () => String(bagOf(row, inp)[inp.key] ?? inp.defval),
|
|
21679
|
-
onChange: (v) => emit(v)
|
|
21754
|
+
onChange: (v) => emit(v),
|
|
21755
|
+
// An input change re-executes the script over its whole history: commit the
|
|
21756
|
+
// opacity drag once on release, not once per pointer move.
|
|
21757
|
+
commit: "release"
|
|
21680
21758
|
}).el;
|
|
21681
21759
|
}
|
|
21682
21760
|
if (inp.type === "symbol") return this.buildSymbol(id, String(current), emit);
|
|
@@ -21923,10 +22001,6 @@ var IndicatorInputsDialog = class {
|
|
|
21923
22001
|
}
|
|
21924
22002
|
/** Open a themed month calendar under `anchor` — same surface + shadow as the choice list. */
|
|
21925
22003
|
openCalendar(anchor, current, onPick) {
|
|
21926
|
-
const parsed = parseIsoDate(current);
|
|
21927
|
-
let year = parsed?.getFullYear() ?? (/* @__PURE__ */ new Date()).getFullYear();
|
|
21928
|
-
let month = parsed?.getMonth() ?? (/* @__PURE__ */ new Date()).getMonth();
|
|
21929
|
-
const selected = parsed ? isoDate(parsed) : current;
|
|
21930
22004
|
const pop = new Popover({
|
|
21931
22005
|
trigger: anchor,
|
|
21932
22006
|
theme: this.host.theme(),
|
|
@@ -21938,80 +22012,10 @@ var IndicatorInputsDialog = class {
|
|
|
21938
22012
|
this.calendarPop = null;
|
|
21939
22013
|
this.calendarAnchor = null;
|
|
21940
22014
|
},
|
|
21941
|
-
content: (el) => {
|
|
21942
|
-
|
|
21943
|
-
|
|
21944
|
-
|
|
21945
|
-
prev2.type = "button";
|
|
21946
|
-
prev2.className = "vela-ind-cal-nav";
|
|
21947
|
-
prev2.setAttribute("aria-label", "Previous month");
|
|
21948
|
-
prev2.innerHTML = iconAt("chevron-left", 14);
|
|
21949
|
-
const next = document.createElement("button");
|
|
21950
|
-
next.type = "button";
|
|
21951
|
-
next.className = "vela-ind-cal-nav";
|
|
21952
|
-
next.setAttribute("aria-label", "Next month");
|
|
21953
|
-
next.innerHTML = iconAt("chevron-right", 14);
|
|
21954
|
-
const head = document.createElement("div");
|
|
21955
|
-
head.className = "vela-ind-cal-head";
|
|
21956
|
-
head.append(prev2, title, next);
|
|
21957
|
-
const week = document.createElement("div");
|
|
21958
|
-
week.className = "vela-ind-cal-week";
|
|
21959
|
-
for (const d of WEEKDAY_LABELS) {
|
|
21960
|
-
const cell = document.createElement("span");
|
|
21961
|
-
cell.textContent = d;
|
|
21962
|
-
week.appendChild(cell);
|
|
21963
|
-
}
|
|
21964
|
-
const grid = document.createElement("div");
|
|
21965
|
-
grid.className = "vela-ind-cal-grid";
|
|
21966
|
-
const paint = () => {
|
|
21967
|
-
title.textContent = `${MONTH_LABELS[month]} ${year}`;
|
|
21968
|
-
grid.replaceChildren();
|
|
21969
|
-
const first = new Date(year, month, 1);
|
|
21970
|
-
const startPad = first.getDay();
|
|
21971
|
-
const days = new Date(year, month + 1, 0).getDate();
|
|
21972
|
-
const today = isoDate(/* @__PURE__ */ new Date());
|
|
21973
|
-
for (let i = 0; i < startPad; i++) {
|
|
21974
|
-
const blank = document.createElement("span");
|
|
21975
|
-
blank.className = "vela-ind-cal-blank";
|
|
21976
|
-
grid.appendChild(blank);
|
|
21977
|
-
}
|
|
21978
|
-
for (let day = 1; day <= days; day++) {
|
|
21979
|
-
const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
21980
|
-
const b = document.createElement("button");
|
|
21981
|
-
b.type = "button";
|
|
21982
|
-
b.className = "vela-ind-cal-day";
|
|
21983
|
-
b.textContent = String(day);
|
|
21984
|
-
if (iso === selected) b.dataset.checked = "1";
|
|
21985
|
-
if (iso === today) b.dataset.today = "1";
|
|
21986
|
-
b.addEventListener("click", (e) => {
|
|
21987
|
-
e.stopPropagation();
|
|
21988
|
-
pop.hide();
|
|
21989
|
-
onPick(iso);
|
|
21990
|
-
});
|
|
21991
|
-
grid.appendChild(b);
|
|
21992
|
-
}
|
|
21993
|
-
};
|
|
21994
|
-
prev2.addEventListener("click", (e) => {
|
|
21995
|
-
e.stopPropagation();
|
|
21996
|
-
month -= 1;
|
|
21997
|
-
if (month < 0) {
|
|
21998
|
-
month = 11;
|
|
21999
|
-
year -= 1;
|
|
22000
|
-
}
|
|
22001
|
-
paint();
|
|
22002
|
-
});
|
|
22003
|
-
next.addEventListener("click", (e) => {
|
|
22004
|
-
e.stopPropagation();
|
|
22005
|
-
month += 1;
|
|
22006
|
-
if (month > 11) {
|
|
22007
|
-
month = 0;
|
|
22008
|
-
year += 1;
|
|
22009
|
-
}
|
|
22010
|
-
paint();
|
|
22011
|
-
});
|
|
22012
|
-
paint();
|
|
22013
|
-
el.append(head, week, grid);
|
|
22014
|
-
}
|
|
22015
|
+
content: (el) => fillCalendar(el, current, (iso) => {
|
|
22016
|
+
pop.hide();
|
|
22017
|
+
onPick(iso);
|
|
22018
|
+
})
|
|
22015
22019
|
});
|
|
22016
22020
|
this.calendarPop = pop;
|
|
22017
22021
|
this.calendarAnchor = anchor;
|
|
@@ -22120,7 +22124,7 @@ function groupInputs(inputs) {
|
|
|
22120
22124
|
var CALENDAR_SVG = iconAt("calendar", 14);
|
|
22121
22125
|
var CLOCK_SVG = iconAt("clock", 14);
|
|
22122
22126
|
var DIALOG_STYLE_ID2 = "vela-ind-dialog-styles";
|
|
22123
|
-
var DIALOG_STYLE_REV = "
|
|
22127
|
+
var DIALOG_STYLE_REV = "30";
|
|
22124
22128
|
var LEGEND_ICON_PX = 16;
|
|
22125
22129
|
function ensureDialogStyles() {
|
|
22126
22130
|
if (typeof document === "undefined") return;
|
|
@@ -22136,8 +22140,12 @@ function ensureDialogStyles() {
|
|
|
22136
22140
|
.vela-ind-combo-chevron{position:absolute;right:0;top:0;bottom:0;width:26px;border:none;background:transparent;color:inherit;opacity:0.55;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;}
|
|
22137
22141
|
.vela-ind-combo-chevron:hover{opacity:0.9;}
|
|
22138
22142
|
.vela-ind-cal{background:var(--vela-bg);color:var(--vela-fg);border:none;border-radius:6px;box-shadow:var(--vela-shadow);font:14px var(--vela-font);padding:10px 12px;user-select:none;}
|
|
22143
|
+
.vela-ind-cal [hidden]{display:none !important;}
|
|
22139
22144
|
.vela-ind-cal-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;}
|
|
22140
|
-
.vela-ind-cal-title{flex:1;
|
|
22145
|
+
.vela-ind-cal-title{flex:1;display:flex;align-items:center;justify-content:center;gap:2px;min-width:0;}
|
|
22146
|
+
.vela-ind-cal-switch{border:none;background:transparent;color:var(--vela-fg-bright);font:inherit;font-weight:600;font-size:14px;padding:2px 6px;border-radius:4px;cursor:pointer;}
|
|
22147
|
+
.vela-ind-cal-switch:not(:disabled):hover{background:var(--vela-hover);}
|
|
22148
|
+
.vela-ind-cal-switch:disabled{cursor:default;}
|
|
22141
22149
|
.vela-ind-cal-nav{width:24px;height:24px;border:none;background:transparent;color:var(--vela-fg-muted);border-radius:4px;padding:0;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;}
|
|
22142
22150
|
.vela-ind-cal-nav:hover{background:var(--vela-hover);color:var(--vela-fg-bright);}
|
|
22143
22151
|
.vela-ind-cal-week,.vela-ind-cal-grid{display:grid;grid-template-columns:repeat(7,28px);gap:2px;}
|
|
@@ -22148,6 +22156,12 @@ function ensureDialogStyles() {
|
|
|
22148
22156
|
.vela-ind-cal-day:hover{background:var(--vela-hover);}
|
|
22149
22157
|
.vela-ind-cal-day[data-checked]{background:var(--vela-hover-strong);color:var(--vela-fg-bright);}
|
|
22150
22158
|
.vela-ind-cal-day[data-today]:not([data-checked]){box-shadow:inset 0 0 0 1px var(--vela-border-strong);}
|
|
22159
|
+
.vela-ind-cal-cells{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;width:calc(7 * 28px + 6 * 2px);}
|
|
22160
|
+
.vela-ind-cal-cell{height:36px;border:none;background:transparent;color:inherit;border-radius:4px;padding:0 4px;cursor:pointer;font:inherit;font-size:14px;}
|
|
22161
|
+
.vela-ind-cal-cell:hover{background:var(--vela-hover);}
|
|
22162
|
+
.vela-ind-cal-cell[data-checked]{background:var(--vela-hover-strong);color:var(--vela-fg-bright);}
|
|
22163
|
+
.vela-ind-cal-cell[data-today]:not([data-checked]){box-shadow:inset 0 0 0 1px var(--vela-border-strong);}
|
|
22164
|
+
.vela-ind-cal-cell[data-outside]{opacity:0.45;}
|
|
22151
22165
|
${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
22152
22166
|
.vela-ind-tab{font-weight:600;font-size:13px;line-height:20px;transition:color var(--vela-dur-fast) ease,border-color var(--vela-dur-fast) ease;}
|
|
22153
22167
|
.vela-ind-tab:not(.vela-ind-tab-active):hover{color:var(--vela-fg-bright);}
|
|
@@ -22182,6 +22196,7 @@ var TIME_OPTIONS = Array.from({ length: 48 }, (_, i) => {
|
|
|
22182
22196
|
return { value: v, label: v };
|
|
22183
22197
|
});
|
|
22184
22198
|
var MONTH_LABELS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
22199
|
+
var MONTH_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
22185
22200
|
var WEEKDAY_LABELS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
22186
22201
|
function normalizeDateInput(raw) {
|
|
22187
22202
|
const t = raw.trim();
|
|
@@ -22203,6 +22218,151 @@ function parseIsoDate(raw) {
|
|
|
22203
22218
|
function isoDate(d) {
|
|
22204
22219
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
22205
22220
|
}
|
|
22221
|
+
function fillCalendar(el, current, onPick) {
|
|
22222
|
+
const today = /* @__PURE__ */ new Date();
|
|
22223
|
+
const selected = parseIsoDate(current);
|
|
22224
|
+
let year = selected?.getFullYear() ?? today.getFullYear();
|
|
22225
|
+
let month = selected?.getMonth() ?? today.getMonth();
|
|
22226
|
+
let mode = "date";
|
|
22227
|
+
const prev2 = document.createElement("button");
|
|
22228
|
+
prev2.type = "button";
|
|
22229
|
+
prev2.className = "vela-ind-cal-nav";
|
|
22230
|
+
prev2.innerHTML = iconAt("chevron-left", 14);
|
|
22231
|
+
const next = document.createElement("button");
|
|
22232
|
+
next.type = "button";
|
|
22233
|
+
next.className = "vela-ind-cal-nav";
|
|
22234
|
+
next.innerHTML = iconAt("chevron-right", 14);
|
|
22235
|
+
const monthBtn = document.createElement("button");
|
|
22236
|
+
monthBtn.type = "button";
|
|
22237
|
+
monthBtn.className = "vela-ind-cal-switch";
|
|
22238
|
+
monthBtn.setAttribute("aria-label", "Choose month");
|
|
22239
|
+
const yearBtn = document.createElement("button");
|
|
22240
|
+
yearBtn.type = "button";
|
|
22241
|
+
yearBtn.className = "vela-ind-cal-switch";
|
|
22242
|
+
yearBtn.setAttribute("aria-label", "Choose year");
|
|
22243
|
+
const title = document.createElement("div");
|
|
22244
|
+
title.className = "vela-ind-cal-title";
|
|
22245
|
+
title.append(monthBtn, yearBtn);
|
|
22246
|
+
const head = document.createElement("div");
|
|
22247
|
+
head.className = "vela-ind-cal-head";
|
|
22248
|
+
head.append(prev2, title, next);
|
|
22249
|
+
const week = document.createElement("div");
|
|
22250
|
+
week.className = "vela-ind-cal-week";
|
|
22251
|
+
for (const d of WEEKDAY_LABELS) {
|
|
22252
|
+
const cell = document.createElement("span");
|
|
22253
|
+
cell.textContent = d;
|
|
22254
|
+
week.appendChild(cell);
|
|
22255
|
+
}
|
|
22256
|
+
const grid = document.createElement("div");
|
|
22257
|
+
const paint = () => {
|
|
22258
|
+
const decade = Math.floor(year / 10) * 10;
|
|
22259
|
+
monthBtn.hidden = mode !== "date";
|
|
22260
|
+
monthBtn.textContent = MONTH_LABELS[month] ?? "";
|
|
22261
|
+
yearBtn.textContent = mode === "year" ? `${decade}-${decade + 9}` : String(year);
|
|
22262
|
+
yearBtn.disabled = mode === "year";
|
|
22263
|
+
week.hidden = mode !== "date";
|
|
22264
|
+
prev2.setAttribute("aria-label", mode === "date" ? "Previous month" : mode === "month" ? "Previous year" : "Previous decade");
|
|
22265
|
+
next.setAttribute("aria-label", mode === "date" ? "Next month" : mode === "month" ? "Next year" : "Next decade");
|
|
22266
|
+
grid.className = mode === "date" ? "vela-ind-cal-grid" : "vela-ind-cal-cells";
|
|
22267
|
+
grid.replaceChildren();
|
|
22268
|
+
if (mode === "date") {
|
|
22269
|
+
const startPad = new Date(year, month, 1).getDay();
|
|
22270
|
+
const days = new Date(year, month + 1, 0).getDate();
|
|
22271
|
+
const todayIso = isoDate(today);
|
|
22272
|
+
const selectedIso = selected ? isoDate(selected) : "";
|
|
22273
|
+
for (let i = 0; i < startPad; i++) {
|
|
22274
|
+
const blank = document.createElement("span");
|
|
22275
|
+
blank.className = "vela-ind-cal-blank";
|
|
22276
|
+
grid.appendChild(blank);
|
|
22277
|
+
}
|
|
22278
|
+
for (let day = 1; day <= days; day++) {
|
|
22279
|
+
const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
22280
|
+
const b = document.createElement("button");
|
|
22281
|
+
b.type = "button";
|
|
22282
|
+
b.className = "vela-ind-cal-day";
|
|
22283
|
+
b.textContent = String(day);
|
|
22284
|
+
if (iso === selectedIso) b.dataset.checked = "1";
|
|
22285
|
+
if (iso === todayIso) b.dataset.today = "1";
|
|
22286
|
+
b.addEventListener("click", (e) => {
|
|
22287
|
+
e.stopPropagation();
|
|
22288
|
+
onPick(iso);
|
|
22289
|
+
});
|
|
22290
|
+
grid.appendChild(b);
|
|
22291
|
+
}
|
|
22292
|
+
return;
|
|
22293
|
+
}
|
|
22294
|
+
if (mode === "month") {
|
|
22295
|
+
for (let m = 0; m < 12; m++) {
|
|
22296
|
+
const b = document.createElement("button");
|
|
22297
|
+
b.type = "button";
|
|
22298
|
+
b.className = "vela-ind-cal-cell";
|
|
22299
|
+
b.textContent = MONTH_SHORT[m] ?? "";
|
|
22300
|
+
if (selected?.getFullYear() === year && selected.getMonth() === m) b.dataset.checked = "1";
|
|
22301
|
+
if (today.getFullYear() === year && today.getMonth() === m) b.dataset.today = "1";
|
|
22302
|
+
b.addEventListener("click", (e) => {
|
|
22303
|
+
e.stopPropagation();
|
|
22304
|
+
month = m;
|
|
22305
|
+
mode = "date";
|
|
22306
|
+
paint();
|
|
22307
|
+
});
|
|
22308
|
+
grid.appendChild(b);
|
|
22309
|
+
}
|
|
22310
|
+
return;
|
|
22311
|
+
}
|
|
22312
|
+
for (let y = decade - 1; y <= decade + 10; y++) {
|
|
22313
|
+
const b = document.createElement("button");
|
|
22314
|
+
b.type = "button";
|
|
22315
|
+
b.className = "vela-ind-cal-cell";
|
|
22316
|
+
b.textContent = String(y);
|
|
22317
|
+
if (y < decade || y > decade + 9) b.dataset.outside = "1";
|
|
22318
|
+
if (selected?.getFullYear() === y) b.dataset.checked = "1";
|
|
22319
|
+
if (today.getFullYear() === y) b.dataset.today = "1";
|
|
22320
|
+
b.addEventListener("click", (e) => {
|
|
22321
|
+
e.stopPropagation();
|
|
22322
|
+
year = y;
|
|
22323
|
+
mode = "month";
|
|
22324
|
+
paint();
|
|
22325
|
+
});
|
|
22326
|
+
grid.appendChild(b);
|
|
22327
|
+
}
|
|
22328
|
+
};
|
|
22329
|
+
const step = (dir) => {
|
|
22330
|
+
if (mode === "date") {
|
|
22331
|
+
month += dir;
|
|
22332
|
+
if (month < 0) {
|
|
22333
|
+
month = 11;
|
|
22334
|
+
year -= 1;
|
|
22335
|
+
}
|
|
22336
|
+
if (month > 11) {
|
|
22337
|
+
month = 0;
|
|
22338
|
+
year += 1;
|
|
22339
|
+
}
|
|
22340
|
+
} else {
|
|
22341
|
+
year += mode === "month" ? dir : dir * 10;
|
|
22342
|
+
}
|
|
22343
|
+
paint();
|
|
22344
|
+
};
|
|
22345
|
+
prev2.addEventListener("click", (e) => {
|
|
22346
|
+
e.stopPropagation();
|
|
22347
|
+
step(-1);
|
|
22348
|
+
});
|
|
22349
|
+
next.addEventListener("click", (e) => {
|
|
22350
|
+
e.stopPropagation();
|
|
22351
|
+
step(1);
|
|
22352
|
+
});
|
|
22353
|
+
monthBtn.addEventListener("click", (e) => {
|
|
22354
|
+
e.stopPropagation();
|
|
22355
|
+
mode = "month";
|
|
22356
|
+
paint();
|
|
22357
|
+
});
|
|
22358
|
+
yearBtn.addEventListener("click", (e) => {
|
|
22359
|
+
e.stopPropagation();
|
|
22360
|
+
mode = "year";
|
|
22361
|
+
paint();
|
|
22362
|
+
});
|
|
22363
|
+
paint();
|
|
22364
|
+
el.append(head, week, grid);
|
|
22365
|
+
}
|
|
22206
22366
|
function normalizeTimeInput(raw) {
|
|
22207
22367
|
const t = raw.trim();
|
|
22208
22368
|
const m = /^(\d{1,2}):(\d{2})$/.exec(t) ?? /^(\d{2})(\d{2})$/.exec(t);
|
|
@@ -28690,6 +28850,10 @@ var BUILTIN_SETTINGS_IDS = [
|
|
|
28690
28850
|
"canvas.grid",
|
|
28691
28851
|
"canvas.grid.vertical",
|
|
28692
28852
|
"canvas.grid.horizontal",
|
|
28853
|
+
"canvas.margins",
|
|
28854
|
+
"canvas.margins.top",
|
|
28855
|
+
"canvas.margins.bottom",
|
|
28856
|
+
"canvas.margins.right",
|
|
28693
28857
|
"canvas.theme"
|
|
28694
28858
|
];
|
|
28695
28859
|
function settingsIdCatalog(hostSections, markGroups = []) {
|
|
@@ -29220,6 +29384,10 @@ var SettingsDialog = class {
|
|
|
29220
29384
|
body.append(sid(this.toggleRow("Horizontal", config.grid.horzLines.visible, (v) => this.emit({ grid: { horzLines: { visible: v } } }), [
|
|
29221
29385
|
this.swatch(config.grid.horzLines.color, (v) => this.emit({ grid: { horzLines: { color: v } } }))
|
|
29222
29386
|
]), "canvas.grid.horizontal"));
|
|
29387
|
+
body.append(sid(this.sectionTitle("Margins"), "canvas.margins"));
|
|
29388
|
+
body.append(sid(this.numberRow("Top", config.margins.top, 0, 40, 1, (v) => this.emit({ margins: { top: v } }), "%"), "canvas.margins.top"));
|
|
29389
|
+
body.append(sid(this.numberRow("Bottom", config.margins.bottom, 0, 40, 1, (v) => this.emit({ margins: { bottom: v } }), "%"), "canvas.margins.bottom"));
|
|
29390
|
+
body.append(sid(this.numberRow("Right", config.margins.right, 0, 200, 1, (v) => this.emit({ margins: { right: v } }), "bars"), "canvas.margins.right"));
|
|
29223
29391
|
if (this.themeControl) {
|
|
29224
29392
|
const tc = this.themeControl;
|
|
29225
29393
|
body.append(sid(this.sectionTitle("Theme"), "canvas.theme"));
|
|
@@ -29791,23 +29959,16 @@ var SettingsDialog = class {
|
|
|
29791
29959
|
this.hintTips.push(dispose);
|
|
29792
29960
|
return el;
|
|
29793
29961
|
}
|
|
29794
|
-
|
|
29795
|
-
|
|
29796
|
-
|
|
29797
|
-
|
|
29798
|
-
|
|
29799
|
-
|
|
29800
|
-
|
|
29801
|
-
|
|
29802
|
-
|
|
29803
|
-
|
|
29804
|
-
step,
|
|
29805
|
-
fill: false,
|
|
29806
|
-
commit: "live",
|
|
29807
|
-
steppers: true,
|
|
29808
|
-
onChange
|
|
29809
|
-
}).el
|
|
29810
|
-
});
|
|
29962
|
+
/** `unit` (optional) trails the input as muted text — "%", "bars". */
|
|
29963
|
+
numberRow(label, value, min, max, step, onChange, unit) {
|
|
29964
|
+
const controls = [buildFieldControl({ kind: "number", value, min, max, step, fill: false, commit: "live", steppers: true, onChange }).el];
|
|
29965
|
+
if (unit) {
|
|
29966
|
+
const u = document.createElement("span");
|
|
29967
|
+
u.textContent = unit;
|
|
29968
|
+
u.style.cssText = "color:var(--vela-fg-muted);";
|
|
29969
|
+
controls.push(u);
|
|
29970
|
+
}
|
|
29971
|
+
return this.rowWith(label, controls);
|
|
29811
29972
|
}
|
|
29812
29973
|
/** A dropdown whose option values differ from their display labels. */
|
|
29813
29974
|
selectRowLabeled(label, value, options, onChange) {
|
|
@@ -34681,9 +34842,7 @@ function createProjector(coords, paneOf, paneIdAtY, barsInRange, seriesInRange)
|
|
|
34681
34842
|
}
|
|
34682
34843
|
|
|
34683
34844
|
// src/renderers/native/core/autoscale.ts
|
|
34684
|
-
|
|
34685
|
-
var MARGIN_BOTTOM = 1 / 7;
|
|
34686
|
-
function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log = false, offsetOf = () => 0) {
|
|
34845
|
+
function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log = false, offsetOf = () => 0, margins = DEFAULT_MARGINS) {
|
|
34687
34846
|
let min = Infinity;
|
|
34688
34847
|
let max = -Infinity;
|
|
34689
34848
|
const consider = (v) => {
|
|
@@ -34718,14 +34877,17 @@ function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log =
|
|
|
34718
34877
|
const pad = Math.abs(min) * 0.1 || 1;
|
|
34719
34878
|
return { min: min - pad, max: max + pad, log: log && min - pad > 0 };
|
|
34720
34879
|
}
|
|
34880
|
+
const content = Math.max(0.1, 1 - (margins.top + margins.bottom) / 100);
|
|
34881
|
+
const above = margins.top / 100 / content;
|
|
34882
|
+
const below = margins.bottom / 100 / content;
|
|
34721
34883
|
if (log && min > 0) {
|
|
34722
34884
|
const lmin = Math.log(min);
|
|
34723
34885
|
const lmax = Math.log(max);
|
|
34724
34886
|
const lspan = lmax - lmin;
|
|
34725
|
-
return { min: Math.exp(lmin - lspan *
|
|
34887
|
+
return { min: Math.exp(lmin - lspan * below), max: Math.exp(lmax + lspan * above), log: true };
|
|
34726
34888
|
}
|
|
34727
34889
|
const span = max - min;
|
|
34728
|
-
return { min: min - span *
|
|
34890
|
+
return { min: min - span * below, max: max + span * above };
|
|
34729
34891
|
}
|
|
34730
34892
|
function considerSeries(s, i0, i1, off, consider) {
|
|
34731
34893
|
if (!seriesInScale(s)) return;
|
|
@@ -36416,6 +36578,7 @@ var NativeRenderer = class {
|
|
|
36416
36578
|
intro: this.intro.style !== false
|
|
36417
36579
|
},
|
|
36418
36580
|
panes: { separatorColor: s.separatorColor ?? t.borderColor },
|
|
36581
|
+
margins: { ...s.margins },
|
|
36419
36582
|
trades: {
|
|
36420
36583
|
visible: this.scene.tradeMarkers.visible,
|
|
36421
36584
|
labels: this.scene.tradeMarkers.labels,
|
|
@@ -36528,6 +36691,10 @@ var NativeRenderer = class {
|
|
|
36528
36691
|
this.animAutoscale.toggle(next.animations.autoscale);
|
|
36529
36692
|
this.intro = { style: next.animations.intro ? this.introOnStyle : false, duration: this.intro.duration || INTRO_DURATION_DEFAULT_MS };
|
|
36530
36693
|
s.separatorColor = keepInherit(s.separatorColor, next.panes.separatorColor, prevTheme.borderColor);
|
|
36694
|
+
if (next.margins.right !== s.margins.right && this.coords.barCount > 0) {
|
|
36695
|
+
this.applyViewport({ barSpacing: this.coords.getViewport().barSpacing, rightOffset: next.margins.right });
|
|
36696
|
+
}
|
|
36697
|
+
s.margins = { ...next.margins };
|
|
36531
36698
|
this.scene.tradeMarkers = {
|
|
36532
36699
|
visible: next.trades.visible,
|
|
36533
36700
|
labels: next.trades.labels,
|
|
@@ -36771,7 +36938,7 @@ var NativeRenderer = class {
|
|
|
36771
36938
|
/** Glide the view back to the most recent bars, keeping the current zoom (barSpacing). */
|
|
36772
36939
|
scrollToRealtime() {
|
|
36773
36940
|
if (this.coords.barCount === 0) return;
|
|
36774
|
-
this.glideRightOffset(
|
|
36941
|
+
this.glideRightOffset(this.scene.style.margins.right);
|
|
36775
36942
|
}
|
|
36776
36943
|
/** Ease rightOffset to `target` at constant zoom (see animTick's scroll glide);
|
|
36777
36944
|
* instant when the scroll glide is off. Shared by scroll-to-latest and panBy. */
|
|
@@ -38713,6 +38880,7 @@ var NativeRenderer = class {
|
|
|
38713
38880
|
const pricePane = panes.find((p) => p.kind === "price") ?? null;
|
|
38714
38881
|
this.chrome.prepare(this.scene, this.coords, this.theme);
|
|
38715
38882
|
const animating = this.animator.active;
|
|
38883
|
+
const margins = this.scene.style.margins;
|
|
38716
38884
|
for (const pane of panes) {
|
|
38717
38885
|
if (pane.manualScale) {
|
|
38718
38886
|
pane.scaleTarget = pane.manualScale;
|
|
@@ -38728,7 +38896,7 @@ var NativeRenderer = class {
|
|
|
38728
38896
|
if (or) dr = dr ? { min: Math.min(dr.min, or.min), max: Math.max(dr.max, or.max) } : or;
|
|
38729
38897
|
}
|
|
38730
38898
|
const includeCandles = pane.kind === "price" && (!this.scene.candlesHidden || this.priceLayersAnchoredToBars(masterModels) || !this.paneHasMeasurableContent(masterModels, dr));
|
|
38731
|
-
pane.scaleTarget = computePaneScale(masterModels, this.bars, includeCandles, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id));
|
|
38899
|
+
pane.scaleTarget = computePaneScale(masterModels, this.bars, includeCandles, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id), margins);
|
|
38732
38900
|
pane.percentBaseline = pane.kind === "price" ? this.bars[i0]?.close ?? 0 : this.firstVisibleValue(masterModels, i0);
|
|
38733
38901
|
pane.axisFormat = void 0;
|
|
38734
38902
|
pane.axisBands = void 0;
|
|
@@ -38739,7 +38907,7 @@ var NativeRenderer = class {
|
|
|
38739
38907
|
pane.axisFormat = "volume";
|
|
38740
38908
|
}
|
|
38741
38909
|
} else if (this.layerNativesOwnPane(pane, masterModels)) {
|
|
38742
|
-
pane.scaleTarget = computePaneScale([], this.bars, true, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id));
|
|
38910
|
+
pane.scaleTarget = computePaneScale([], this.bars, true, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id), margins);
|
|
38743
38911
|
pane.percentBaseline = this.bars[i0]?.close ?? 0;
|
|
38744
38912
|
if (masterModels.every((m) => m.paneAxis != null)) {
|
|
38745
38913
|
pane.axisFormat = "none";
|
|
@@ -38768,7 +38936,7 @@ var NativeRenderer = class {
|
|
|
38768
38936
|
continue;
|
|
38769
38937
|
}
|
|
38770
38938
|
const mdr = this.chrome.paneDrawingsRange([model], this.scene, false, vr);
|
|
38771
|
-
sl.scaleTarget = computePaneScale([model], this.bars, false, i0, i1, mdr, false, (id) => this.scene.offsetOf(id));
|
|
38939
|
+
sl.scaleTarget = computePaneScale([model], this.bars, false, i0, i1, mdr, false, (id) => this.scene.offsetOf(id), margins);
|
|
38772
38940
|
if (!animating || !sl.initialized) {
|
|
38773
38941
|
sl.scale = { ...sl.scaleTarget };
|
|
38774
38942
|
sl.initialized = true;
|
|
@@ -38809,13 +38977,13 @@ var NativeRenderer = class {
|
|
|
38809
38977
|
for (const pane of this.scene.panes.values()) pane.manualScale = null;
|
|
38810
38978
|
for (const sl of this.scene.indicatorScales.values()) sl.manualScale = null;
|
|
38811
38979
|
const visibleBars = Math.min(n, 200);
|
|
38812
|
-
const rightOffset =
|
|
38980
|
+
const rightOffset = this.scene.style.margins.right;
|
|
38813
38981
|
const v = this.clampViewport(w / ((visibleBars + rightOffset) * this.coords.spacingScale), rightOffset);
|
|
38814
38982
|
this.coords.setViewport(v);
|
|
38815
38983
|
this.targetBarSpacing = v.barSpacing;
|
|
38816
38984
|
}
|
|
38817
38985
|
/** Re-frame after a series replacement (a symbol/timeframe switch): keep the user's
|
|
38818
|
-
* zoom (bar spacing), re-anchor the newest bars at the
|
|
38986
|
+
* zoom (bar spacing), re-anchor the newest bars at the configured right margin.
|
|
38819
38987
|
* `clampViewport`'s fit-all-bars floor deliberately does NOT apply — a progressive
|
|
38820
38988
|
* head may still be backfilling toward the previous depth, and raising the spacing
|
|
38821
38989
|
* to its temporary bar count would lose the zoom this exists to keep. */
|
|
@@ -38824,7 +38992,7 @@ var NativeRenderer = class {
|
|
|
38824
38992
|
this.panVelocity = 0;
|
|
38825
38993
|
for (const pane of this.scene.panes.values()) pane.manualScale = null;
|
|
38826
38994
|
for (const sl of this.scene.indicatorScales.values()) sl.manualScale = null;
|
|
38827
|
-
const v = { barSpacing: clampBarSpacing(this.coords.getViewport().barSpacing), rightOffset:
|
|
38995
|
+
const v = { barSpacing: clampBarSpacing(this.coords.getViewport().barSpacing), rightOffset: this.scene.style.margins.right };
|
|
38828
38996
|
this.coords.setViewport(v);
|
|
38829
38997
|
this.targetBarSpacing = v.barSpacing;
|
|
38830
38998
|
}
|
|
@@ -41909,6 +42077,7 @@ function registerClassicIndicators() {
|
|
|
41909
42077
|
}
|
|
41910
42078
|
|
|
41911
42079
|
// src/Vela.ts
|
|
42080
|
+
var asError = (err) => err instanceof Error ? err : new Error(String(err));
|
|
41912
42081
|
var Vela = class {
|
|
41913
42082
|
constructor(container, options = {}, deps = {}) {
|
|
41914
42083
|
registerBuiltinChartTypes();
|
|
@@ -42032,7 +42201,12 @@ var Vela = class {
|
|
|
42032
42201
|
* fetch from — the same relationship `script:run` has to `context:changed`.
|
|
42033
42202
|
*/
|
|
42034
42203
|
runScript(source, options) {
|
|
42035
|
-
|
|
42204
|
+
let handle;
|
|
42205
|
+
try {
|
|
42206
|
+
handle = this.addIndicator(source, options);
|
|
42207
|
+
} catch (err) {
|
|
42208
|
+
return Promise.resolve({ ok: false, run: null, error: asError(err), onUpdate: () => () => void 0, remove: () => void 0 });
|
|
42209
|
+
}
|
|
42036
42210
|
const updates = /* @__PURE__ */ new Set();
|
|
42037
42211
|
const drop = () => {
|
|
42038
42212
|
try {
|
|
@@ -42076,7 +42250,12 @@ var Vela = class {
|
|
|
42076
42250
|
});
|
|
42077
42251
|
}
|
|
42078
42252
|
runIndicator(source, options) {
|
|
42079
|
-
|
|
42253
|
+
let handle;
|
|
42254
|
+
try {
|
|
42255
|
+
handle = this.addIndicator(source, options);
|
|
42256
|
+
} catch (err) {
|
|
42257
|
+
return Promise.resolve({ ok: false, handle: null, error: asError(err), context: null });
|
|
42258
|
+
}
|
|
42080
42259
|
return new Promise((resolve) => {
|
|
42081
42260
|
const offReady = handle.on("ready", () => {
|
|
42082
42261
|
offReady();
|
|
@@ -43425,7 +43604,7 @@ var ChartContextMenu = class {
|
|
|
43425
43604
|
} else if (id.startsWith("tz:")) {
|
|
43426
43605
|
const zone = id.slice("tz:".length);
|
|
43427
43606
|
if (this.cbs.setTimezone) this.cbs.setTimezone(zone);
|
|
43428
|
-
else chart.renderer.set("timezone", zone);
|
|
43607
|
+
else chart.renderer.set("timezone", resolveTimezone(zone, void 0));
|
|
43429
43608
|
} else if (id === "auto") {
|
|
43430
43609
|
chart.renderer.set("autoScale", chart.renderer.get("autoScale") === false);
|
|
43431
43610
|
} else if (id === "invert") {
|
|
@@ -43658,7 +43837,7 @@ var ChartCell = class {
|
|
|
43658
43837
|
this.history.onChart(this.inner);
|
|
43659
43838
|
this.inner.renderer.onConfigChanged(() => {
|
|
43660
43839
|
const zone = this.inner?.renderer.get("timezone");
|
|
43661
|
-
if (typeof zone === "string" && normalizeTimezone(zone) !== normalizeTimezone(this.
|
|
43840
|
+
if (typeof zone === "string" && normalizeTimezone(zone) !== normalizeTimezone(this.displayTimezone)) {
|
|
43662
43841
|
this.deps.setTimezone(normalizeTimezone(zone));
|
|
43663
43842
|
}
|
|
43664
43843
|
const style = this.priceStyle;
|
|
@@ -43700,8 +43879,7 @@ var ChartCell = class {
|
|
|
43700
43879
|
this.refreshSessionShading();
|
|
43701
43880
|
});
|
|
43702
43881
|
this.inner.on("viewport:changed", (range) => this.sessionShading.updateRange(range));
|
|
43703
|
-
|
|
43704
|
-
if (tz !== "Etc/UTC") this.inner.renderer.set("timezone", tz);
|
|
43882
|
+
this.applyTimezone();
|
|
43705
43883
|
this.indicatorTitlesOn = seed.indicatorTitles ?? true;
|
|
43706
43884
|
if (!this.indicatorTitlesOn) this.inner.renderer.set("indicatorTitles", false);
|
|
43707
43885
|
this.indicatorValuesOn = seed.indicatorValues ?? true;
|
|
@@ -43723,7 +43901,7 @@ var ChartCell = class {
|
|
|
43723
43901
|
this.statusline?.setSymbol(this.state.symbol);
|
|
43724
43902
|
this.statusline?.setMeta(this.state.timeframe ?? "60", this.inner.data.displayPrefix(this.state.symbol) ?? this.state.provider ?? "");
|
|
43725
43903
|
}
|
|
43726
|
-
this.
|
|
43904
|
+
this.refreshSymbolMetadata();
|
|
43727
43905
|
if (this.inner && this.state.symbol) this.marketStatus?.track(this.inner.data, this.state.symbol);
|
|
43728
43906
|
});
|
|
43729
43907
|
this.syncStatuslineColors();
|
|
@@ -43797,7 +43975,7 @@ var ChartCell = class {
|
|
|
43797
43975
|
this.offMarket = this.inner.on("market:changed", ({ symbol: symbol2, timeframe }) => {
|
|
43798
43976
|
this.projectMarket(symbol2, timeframe);
|
|
43799
43977
|
this.refreshNativeCatalog();
|
|
43800
|
-
this.
|
|
43978
|
+
this.refreshSymbolMetadata();
|
|
43801
43979
|
if (this.inner) this.marketStatus?.track(this.inner.data, symbol2);
|
|
43802
43980
|
this.deps.onMarketChanged(this.id);
|
|
43803
43981
|
});
|
|
@@ -43838,7 +44016,35 @@ var ChartCell = class {
|
|
|
43838
44016
|
this.deps.onStateDirty();
|
|
43839
44017
|
void this.inner?.setMarket({ session });
|
|
43840
44018
|
}
|
|
43841
|
-
|
|
44019
|
+
/**
|
|
44020
|
+
* The symbol's own trading zone, once its metadata has landed — what the exchange
|
|
44021
|
+
* rule resolves to on this cell (the workspace labels the shared bottom bar with the
|
|
44022
|
+
* ACTIVE cell's). Undefined = unknown or undeclared (the rule then renders UTC).
|
|
44023
|
+
*/
|
|
44024
|
+
get exchangeTimezone() {
|
|
44025
|
+
return this.exchangeZone;
|
|
44026
|
+
}
|
|
44027
|
+
/** The IANA zone this cell's axis renders in: the workspace choice, resolved. */
|
|
44028
|
+
get displayTimezone() {
|
|
44029
|
+
return resolveTimezone(this.deps.timezone(), this.exchangeZone);
|
|
44030
|
+
}
|
|
44031
|
+
/**
|
|
44032
|
+
* Push the resolved zone to the renderer — on the workspace choice changing, and on
|
|
44033
|
+
* this cell's market zone changing under the exchange rule. Skips the write when the
|
|
44034
|
+
* renderer already holds it (its config default is the bare `'UTC'` alias).
|
|
44035
|
+
*/
|
|
44036
|
+
applyTimezone() {
|
|
44037
|
+
const chart = this.inner;
|
|
44038
|
+
if (!chart) return;
|
|
44039
|
+
const zone = this.displayTimezone;
|
|
44040
|
+
const current = chart.renderer.get("timezone");
|
|
44041
|
+
const held = typeof current === "string" && current ? current : "UTC";
|
|
44042
|
+
if (normalizeTimezone(held) === normalizeTimezone(zone)) return;
|
|
44043
|
+
chart.renderer.set("timezone", zone);
|
|
44044
|
+
}
|
|
44045
|
+
/** Re-read the symbol's metadata: session posture (RTH/ETH toggle, shading) and its
|
|
44046
|
+
* trading zone (the exchange rule). Async — the workspace re-projects when a verdict lands. */
|
|
44047
|
+
refreshSymbolMetadata() {
|
|
43842
44048
|
const chart = this.inner;
|
|
43843
44049
|
const symbol = this.state.symbol;
|
|
43844
44050
|
if (!chart || !symbol) return;
|
|
@@ -43846,7 +44052,13 @@ var ChartCell = class {
|
|
|
43846
44052
|
if (this.inner !== chart) return;
|
|
43847
44053
|
const available = typeof si?.session === "string" && si.session !== "" && si.session !== "24x7";
|
|
43848
44054
|
const overnight = parseSessionSpec(si)?.overnight === true;
|
|
43849
|
-
|
|
44055
|
+
const zone = typeof si?.timezone === "string" && si.timezone !== "" ? si.timezone : void 0;
|
|
44056
|
+
const zoneChanged = zone !== this.exchangeZone;
|
|
44057
|
+
if (zoneChanged) {
|
|
44058
|
+
this.exchangeZone = zone;
|
|
44059
|
+
this.applyTimezone();
|
|
44060
|
+
}
|
|
44061
|
+
if (available !== this.sessionAvailableFlag || overnight !== this.sessionOvernightFlag || zoneChanged) {
|
|
43850
44062
|
this.sessionAvailableFlag = available;
|
|
43851
44063
|
this.sessionOvernightFlag = overnight;
|
|
43852
44064
|
this.deps.onMarketChanged(this.id);
|
|
@@ -44305,16 +44517,19 @@ var ChartCell = class {
|
|
|
44305
44517
|
* a persistence handler's `restore` runs silently, a user-driven call records.
|
|
44306
44518
|
*/
|
|
44307
44519
|
addExternalIndicator(entry) {
|
|
44520
|
+
const { id, inputs, props, hidden, ...script } = entry;
|
|
44308
44521
|
this.addManifestInstance(
|
|
44309
|
-
{ ...
|
|
44310
|
-
{ external: true, ...
|
|
44522
|
+
{ ...script, enabled: true },
|
|
44523
|
+
{ external: true, ...id !== void 0 ? { id } : {}, ...inputs ? { inputs } : {}, ...props ? { props } : {}, ...hidden ? { hidden: true } : {} }
|
|
44311
44524
|
);
|
|
44312
44525
|
}
|
|
44313
44526
|
/** Add ONE instance of a manifest entry (repeatable — duplicates are legitimate). */
|
|
44314
44527
|
addManifestInstance(entry, opts = {}) {
|
|
44315
44528
|
if (this.destroyed) return;
|
|
44316
44529
|
const values = opts.inputs || opts.props ? { inputs: opts.inputs, props: opts.props } : void 0;
|
|
44317
|
-
const
|
|
44530
|
+
const handle = this.addToChart(entry, values, opts.id);
|
|
44531
|
+
if (!handle) return;
|
|
44532
|
+
const it = { entry, handle, id: handle.id, ...opts.external ? { external: true } : {}, ...values ? { values } : {} };
|
|
44318
44533
|
if (opts.hidden) it.handle?.setVisible(false);
|
|
44319
44534
|
this.instances.push(it);
|
|
44320
44535
|
this.deps.onIndicatorsChanged(this.id);
|
|
@@ -44323,7 +44538,7 @@ var ChartCell = class {
|
|
|
44323
44538
|
this.history.push({
|
|
44324
44539
|
undo: () => this.dropInstance(snapshot),
|
|
44325
44540
|
redo: () => {
|
|
44326
|
-
snapshot.handle = this.addToChart(snapshot.entry, snapshot.values);
|
|
44541
|
+
snapshot.handle = this.addToChart(snapshot.entry, snapshot.values, snapshot.id);
|
|
44327
44542
|
this.instances.push(snapshot);
|
|
44328
44543
|
this.deps.onIndicatorsChanged(this.id);
|
|
44329
44544
|
}
|
|
@@ -44336,7 +44551,7 @@ var ChartCell = class {
|
|
|
44336
44551
|
const snapshot = it;
|
|
44337
44552
|
this.history.push({
|
|
44338
44553
|
undo: () => {
|
|
44339
|
-
snapshot.handle = this.addToChart(snapshot.entry, snapshot.values);
|
|
44554
|
+
snapshot.handle = this.addToChart(snapshot.entry, snapshot.values, snapshot.id);
|
|
44340
44555
|
this.instances.push(snapshot);
|
|
44341
44556
|
this.deps.onIndicatorsChanged(this.id);
|
|
44342
44557
|
},
|
|
@@ -44426,9 +44641,10 @@ var ChartCell = class {
|
|
|
44426
44641
|
this.deps.onIndicatorsChanged(this.id);
|
|
44427
44642
|
});
|
|
44428
44643
|
}
|
|
44429
|
-
addToChart(entry, values) {
|
|
44644
|
+
addToChart(entry, values, id) {
|
|
44430
44645
|
try {
|
|
44431
44646
|
return this.inner?.addIndicator(entry.script, {
|
|
44647
|
+
...id !== void 0 ? { id } : {},
|
|
44432
44648
|
...entry.language !== void 0 ? { language: entry.language } : {},
|
|
44433
44649
|
...values?.inputs ? { inputs: values.inputs } : {},
|
|
44434
44650
|
...values?.props ? { props: values.props } : {}
|
|
@@ -45618,13 +45834,23 @@ var VelaWorkspace = class {
|
|
|
45618
45834
|
}
|
|
45619
45835
|
}
|
|
45620
45836
|
}
|
|
45621
|
-
/**
|
|
45837
|
+
/**
|
|
45838
|
+
* Set the workspace-global display timezone — applied to EVERY cell. An IANA zone,
|
|
45839
|
+
* or `'exchange'` (the exchange rule): each cell then renders in its OWN market's
|
|
45840
|
+
* zone (Chicago for a CME future, New York for a US equity, UTC for crypto), and the
|
|
45841
|
+
* bottom bar follows the active cell's.
|
|
45842
|
+
*/
|
|
45622
45843
|
setTimezone(zone) {
|
|
45623
45844
|
this.timezone = zone;
|
|
45624
|
-
this.
|
|
45625
|
-
for (const cell of this.cellsById.values()) cell.
|
|
45845
|
+
this.projectTimezone();
|
|
45846
|
+
for (const cell of this.cellsById.values()) cell.applyTimezone();
|
|
45626
45847
|
this.markStateDirty();
|
|
45627
45848
|
}
|
|
45849
|
+
/** Bottom bar ⇐ the stored choice + the ACTIVE cell's market zone (labels the exchange row). */
|
|
45850
|
+
projectTimezone() {
|
|
45851
|
+
const active = this.activeId ? this.cellsById.get(this.activeId) : void 0;
|
|
45852
|
+
this.bottombar?.setTimezone(this.timezone, active?.exchangeTimezone);
|
|
45853
|
+
}
|
|
45628
45854
|
/**
|
|
45629
45855
|
* Swap the workspace theme at runtime — `'dark'`, `'light'`, or a full custom theme,
|
|
45630
45856
|
* applied to the shared chrome (topbar, panels, drawing toolbar) and EVERY cell.
|
|
@@ -45829,6 +46055,7 @@ var VelaWorkspace = class {
|
|
|
45829
46055
|
this.dock.onChart(cell.chart);
|
|
45830
46056
|
this.bottombar?.setActiveRange(cell.activeRangeId);
|
|
45831
46057
|
this.bottombar?.setSession({ session: cell.session, enabled: cell.sessionAvailable });
|
|
46058
|
+
this.projectTimezone();
|
|
45832
46059
|
this.indicatorPicker?.sync();
|
|
45833
46060
|
this.glider.stop();
|
|
45834
46061
|
const d = cell.chart.drawings;
|
|
@@ -46413,6 +46640,7 @@ var VelaWorkspace = class {
|
|
|
46413
46640
|
this.mobileBar?.setTimeframe(cell.timeframe);
|
|
46414
46641
|
this.objectTree.setSymbol(cell.symbol);
|
|
46415
46642
|
this.bottombar?.setSession({ session: cell.session, enabled: cell.sessionAvailable });
|
|
46643
|
+
this.projectTimezone();
|
|
46416
46644
|
this.bottombar?.setActiveRange(cell.activeRangeId);
|
|
46417
46645
|
}
|
|
46418
46646
|
/** Trigger ② — a cell's price style changed: the topbar button/menu only if active.
|