@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/widget.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 };
|
|
@@ -5070,10 +5084,12 @@ var BASELINE_LEVEL_DEFAULT = 50;
|
|
|
5070
5084
|
var PREMARKET_SHADE = withAlpha(WARNING, 0.08);
|
|
5071
5085
|
var POSTMARKET_SHADE = withAlpha(ACCENT, 0.08);
|
|
5072
5086
|
var EXTENDED_SHADE = POSTMARKET_SHADE;
|
|
5087
|
+
var DEFAULT_MARGINS = { top: 10, bottom: 10, right: 10 };
|
|
5073
5088
|
function defaultChartStyle() {
|
|
5074
5089
|
return {
|
|
5075
5090
|
chartTypes: {},
|
|
5076
5091
|
fontSize: 11,
|
|
5092
|
+
margins: { ...DEFAULT_MARGINS },
|
|
5077
5093
|
gridVert: { visible: true, color: null },
|
|
5078
5094
|
gridHorz: { visible: true, color: null },
|
|
5079
5095
|
borderColor: null,
|
|
@@ -5197,6 +5213,12 @@ function clampLevel(v) {
|
|
|
5197
5213
|
function clampSpacing(v) {
|
|
5198
5214
|
return v < 0.1 ? 0.1 : v > 10 ? 10 : v;
|
|
5199
5215
|
}
|
|
5216
|
+
function clampMarginPct(v) {
|
|
5217
|
+
return v < 0 ? 0 : v > 40 ? 40 : v;
|
|
5218
|
+
}
|
|
5219
|
+
function clampMarginBars(v) {
|
|
5220
|
+
return Math.round(v < 0 ? 0 : v > 200 ? 200 : v);
|
|
5221
|
+
}
|
|
5200
5222
|
function factoryResetConfig(factory, priceStyle = factory.series.style) {
|
|
5201
5223
|
const bag = {};
|
|
5202
5224
|
for (const t of chartTypes()) {
|
|
@@ -5245,6 +5267,7 @@ function mergeConfig(base, patch) {
|
|
|
5245
5267
|
const ps = asObject(p.priceScale);
|
|
5246
5268
|
const anim = asObject(p.animations);
|
|
5247
5269
|
const panes = asObject(p.panes);
|
|
5270
|
+
const margins = asObject(p.margins);
|
|
5248
5271
|
const trades = asObject(p.trades);
|
|
5249
5272
|
const ts = asObject(p.timeScale);
|
|
5250
5273
|
const marks = asObject(p.marks);
|
|
@@ -5304,6 +5327,11 @@ function mergeConfig(base, patch) {
|
|
|
5304
5327
|
panes: {
|
|
5305
5328
|
separatorColor: isColor(panes.separatorColor) ? panes.separatorColor : base.panes.separatorColor
|
|
5306
5329
|
},
|
|
5330
|
+
margins: {
|
|
5331
|
+
top: isNum(margins.top) ? clampMarginPct(margins.top) : base.margins.top,
|
|
5332
|
+
bottom: isNum(margins.bottom) ? clampMarginPct(margins.bottom) : base.margins.bottom,
|
|
5333
|
+
right: isNum(margins.right) ? clampMarginBars(margins.right) : base.margins.right
|
|
5334
|
+
},
|
|
5307
5335
|
trades: {
|
|
5308
5336
|
visible: isBool(trades.visible) ? trades.visible : base.trades.visible,
|
|
5309
5337
|
labels: isBool(trades.labels) ? trades.labels : base.trades.labels,
|
|
@@ -6125,9 +6153,22 @@ var TIMEZONES = [
|
|
|
6125
6153
|
{ value: "Pacific/Apia", label: "Apia" },
|
|
6126
6154
|
{ value: "Pacific/Kiritimati", label: "Kiritimati" }
|
|
6127
6155
|
];
|
|
6156
|
+
var EXCHANGE_TIMEZONE = "exchange";
|
|
6157
|
+
function isExchangeTimezone(zone) {
|
|
6158
|
+
return zone === EXCHANGE_TIMEZONE;
|
|
6159
|
+
}
|
|
6160
|
+
function resolveTimezone(zone, exchangeZone) {
|
|
6161
|
+
if (!isExchangeTimezone(zone)) return zone;
|
|
6162
|
+
return exchangeZone && exchangeZone !== "" ? exchangeZone : "Etc/UTC";
|
|
6163
|
+
}
|
|
6128
6164
|
function normalizeTimezone(zone) {
|
|
6129
6165
|
return zone === "UTC" || zone === "Etc/UTC" || zone === "Etc/GMT" ? "Etc/UTC" : zone;
|
|
6130
6166
|
}
|
|
6167
|
+
function timezoneMenuRows(current) {
|
|
6168
|
+
const active = normalizeTimezone(current);
|
|
6169
|
+
const [utc, ...zones] = TIMEZONES.map((t) => ({ value: t.value, label: tzMenuLabel(t.value, t.label), checked: t.value === active }));
|
|
6170
|
+
return [utc, { value: EXCHANGE_TIMEZONE, label: "Exchange", checked: isExchangeTimezone(current) }, ...zones];
|
|
6171
|
+
}
|
|
6131
6172
|
function tzOffset(zone, date = /* @__PURE__ */ new Date()) {
|
|
6132
6173
|
try {
|
|
6133
6174
|
const parts = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "shortOffset" }).formatToParts(date);
|
|
@@ -6250,6 +6291,7 @@ var Bottombar = class {
|
|
|
6250
6291
|
this.sessionButtons = /* @__PURE__ */ new Map();
|
|
6251
6292
|
this.sessionEl = null;
|
|
6252
6293
|
this.timezone = opts.timezone;
|
|
6294
|
+
this.exchangeTimezone = opts.exchangeTimezone;
|
|
6253
6295
|
const doc = host.ownerDocument;
|
|
6254
6296
|
injectStyles(STYLE_ID3, CSS4, doc);
|
|
6255
6297
|
this.el = doc.createElement("div");
|
|
@@ -6273,7 +6315,7 @@ var Bottombar = class {
|
|
|
6273
6315
|
this.clockEl = doc.createElement("span");
|
|
6274
6316
|
this.clockEl.className = "vela-bb-clock";
|
|
6275
6317
|
this.tzLabelEl = doc.createElement("span");
|
|
6276
|
-
this.tzLabelEl.textContent = tzButtonLabel(this.
|
|
6318
|
+
this.tzLabelEl.textContent = tzButtonLabel(this.displayZone);
|
|
6277
6319
|
this.tzButton.append(this.clockEl, this.tzLabelEl);
|
|
6278
6320
|
const session = doc.createElement("span");
|
|
6279
6321
|
session.className = "vela-bb-session";
|
|
@@ -6308,19 +6350,32 @@ var Bottombar = class {
|
|
|
6308
6350
|
placement: "top-end",
|
|
6309
6351
|
items: this.tzItems(),
|
|
6310
6352
|
onSelect: (zone) => {
|
|
6311
|
-
this.setTimezone(zone);
|
|
6353
|
+
this.setTimezone(zone, this.exchangeTimezone);
|
|
6312
6354
|
opts.onTimezone(zone);
|
|
6313
6355
|
}
|
|
6314
6356
|
});
|
|
6315
6357
|
this.tick();
|
|
6316
6358
|
this.unsubClock = (opts.clock ?? new SecondClock()).onTick(() => this.tick());
|
|
6317
6359
|
}
|
|
6318
|
-
|
|
6360
|
+
/**
|
|
6361
|
+
* Reflect the stored choice AND the active chart's market zone. The clock and the
|
|
6362
|
+
* offset label read the RESOLVED zone, so a workspace on the exchange rule re-labels
|
|
6363
|
+
* when the active cell (or its symbol) changes market — the host re-projects on
|
|
6364
|
+
* both. Idempotent: unchanged inputs leave the menu alone.
|
|
6365
|
+
*/
|
|
6366
|
+
setTimezone(zone, exchangeTimezone) {
|
|
6367
|
+
if (zone === this.timezone && exchangeTimezone === this.exchangeTimezone) return;
|
|
6368
|
+
const choiceChanged = zone !== this.timezone;
|
|
6319
6369
|
this.timezone = zone;
|
|
6320
|
-
this.
|
|
6321
|
-
this.
|
|
6370
|
+
this.exchangeTimezone = exchangeTimezone;
|
|
6371
|
+
this.tzLabelEl.textContent = tzButtonLabel(this.displayZone);
|
|
6372
|
+
if (choiceChanged) this.tzMenu.setItems(this.tzItems());
|
|
6322
6373
|
this.tick();
|
|
6323
6374
|
}
|
|
6375
|
+
/** The zone the bar's clock and label render in. */
|
|
6376
|
+
get displayZone() {
|
|
6377
|
+
return resolveTimezone(this.timezone, this.exchangeTimezone);
|
|
6378
|
+
}
|
|
6324
6379
|
/** Highlight (or clear with null) the active range chip — cleared on manual tf changes. */
|
|
6325
6380
|
setActiveRange(id) {
|
|
6326
6381
|
for (const [key, b] of this.rangeButtons) {
|
|
@@ -6348,11 +6403,7 @@ var Bottombar = class {
|
|
|
6348
6403
|
this.el.remove();
|
|
6349
6404
|
}
|
|
6350
6405
|
tzItems() {
|
|
6351
|
-
return
|
|
6352
|
-
id: t.value,
|
|
6353
|
-
label: tzMenuLabel(t.value, t.label),
|
|
6354
|
-
checked: t.value === normalizeTimezone(this.timezone)
|
|
6355
|
-
}));
|
|
6406
|
+
return timezoneMenuRows(this.timezone).map((r) => ({ id: r.value, label: r.label, checked: r.checked }));
|
|
6356
6407
|
}
|
|
6357
6408
|
tick() {
|
|
6358
6409
|
try {
|
|
@@ -6361,7 +6412,7 @@ var Bottombar = class {
|
|
|
6361
6412
|
minute: "2-digit",
|
|
6362
6413
|
second: "2-digit",
|
|
6363
6414
|
hour12: false,
|
|
6364
|
-
timeZone: this.
|
|
6415
|
+
timeZone: this.displayZone
|
|
6365
6416
|
}).format(/* @__PURE__ */ new Date());
|
|
6366
6417
|
} catch {
|
|
6367
6418
|
this.clockEl.textContent = "";
|
|
@@ -16011,15 +16062,14 @@ var TimezoneDrawer = class {
|
|
|
16011
16062
|
this.drawer.body.replaceChildren();
|
|
16012
16063
|
const list = doc.createElement("div");
|
|
16013
16064
|
list.className = "vela-tzd-list";
|
|
16014
|
-
const
|
|
16015
|
-
for (const tz of TIMEZONES) {
|
|
16065
|
+
for (const tz of timezoneMenuRows(this.opts.timezone())) {
|
|
16016
16066
|
const row = doc.createElement("div");
|
|
16017
16067
|
row.className = "vela-tzd-row";
|
|
16018
16068
|
const label = doc.createElement("span");
|
|
16019
16069
|
label.className = "vela-tzd-row-label";
|
|
16020
|
-
label.textContent =
|
|
16070
|
+
label.textContent = tz.label;
|
|
16021
16071
|
row.appendChild(label);
|
|
16022
|
-
if (tz.
|
|
16072
|
+
if (tz.checked) row.appendChild(iconEl("check", doc));
|
|
16023
16073
|
row.addEventListener("click", () => {
|
|
16024
16074
|
this.opts.onTimezone(tz.value);
|
|
16025
16075
|
this.drawer.hide();
|
|
@@ -16106,12 +16156,11 @@ function priceAxisItems(s) {
|
|
|
16106
16156
|
];
|
|
16107
16157
|
}
|
|
16108
16158
|
function timeAxisItems(timezone) {
|
|
16109
|
-
const active = timezone === "UTC" ? "Etc/UTC" : timezone;
|
|
16110
16159
|
return [
|
|
16111
16160
|
{
|
|
16112
16161
|
id: "timezone",
|
|
16113
16162
|
label: "Time zone",
|
|
16114
|
-
submenu:
|
|
16163
|
+
submenu: timezoneMenuRows(timezone).map((r) => ({ id: `tz:${r.value}`, label: r.label, checked: r.checked }))
|
|
16115
16164
|
},
|
|
16116
16165
|
settingsItem("time-axis", "More settings\u2026")
|
|
16117
16166
|
];
|
|
@@ -18460,10 +18509,18 @@ var IndicatorRegistry = class {
|
|
|
18460
18509
|
this.records = /* @__PURE__ */ new Map();
|
|
18461
18510
|
this.counter = 0;
|
|
18462
18511
|
}
|
|
18463
|
-
/**
|
|
18464
|
-
|
|
18465
|
-
|
|
18466
|
-
|
|
18512
|
+
/**
|
|
18513
|
+
* Mint a unique per-instance id. Host-supplied ids share the namespace, so a minted
|
|
18514
|
+
* id skips anything already recorded — and anything `taken` reports live elsewhere
|
|
18515
|
+
* (a handle the orchestrator holds outside the records, e.g. a fail-soft native).
|
|
18516
|
+
*/
|
|
18517
|
+
nextId(prefix = "ind", taken = () => false) {
|
|
18518
|
+
let id;
|
|
18519
|
+
do {
|
|
18520
|
+
this.counter += 1;
|
|
18521
|
+
id = `${prefix}-${this.counter}`;
|
|
18522
|
+
} while (this.records.has(id) || taken(id));
|
|
18523
|
+
return id;
|
|
18467
18524
|
}
|
|
18468
18525
|
add(record) {
|
|
18469
18526
|
this.records.set(record.id, record);
|
|
@@ -19846,7 +19903,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
19846
19903
|
this.engines.set(language, engine);
|
|
19847
19904
|
}
|
|
19848
19905
|
addIndicator(source, options = {}) {
|
|
19849
|
-
const id = this.
|
|
19906
|
+
const id = this.claimIndicatorId(options.id);
|
|
19850
19907
|
const title = options.title ?? "Indicator";
|
|
19851
19908
|
const handle = new IndicatorHandleImpl(id, title, this, source);
|
|
19852
19909
|
this.handles.set(id, handle);
|
|
@@ -19868,7 +19925,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
19868
19925
|
const existing = this.registry.all().find((r) => r.native?.type === type);
|
|
19869
19926
|
if (existing) return this.handles.get(existing.id) ?? new IndicatorHandleImpl(existing.id, existing.title, this, void 0, type);
|
|
19870
19927
|
}
|
|
19871
|
-
const id = this.registry.nextId("native");
|
|
19928
|
+
const id = this.registry.nextId("native", (candidate) => this.handles.has(candidate));
|
|
19872
19929
|
const title = descriptor?.title ?? type;
|
|
19873
19930
|
const handle = new IndicatorHandleImpl(id, title, this, void 0, type);
|
|
19874
19931
|
this.handles.set(id, handle);
|
|
@@ -20146,6 +20203,24 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
20146
20203
|
this.events.clear();
|
|
20147
20204
|
}
|
|
20148
20205
|
// ── internals ───────────────────────────────────────────────
|
|
20206
|
+
/**
|
|
20207
|
+
* The id a new script indicator runs under: the host's when supplied, else a minted
|
|
20208
|
+
* one. A host id is opaque but must be a non-empty string, and it must not be live
|
|
20209
|
+
* on this chart — a duplicate is a programming error surfaced synchronously, never
|
|
20210
|
+
* renamed behind the caller's back (the whole point of supplying one is that
|
|
20211
|
+
* `handle.id` equals what was passed). "Live" reads both the records and the handle
|
|
20212
|
+
* map: a fail-soft handle never enters the registry but still owns its id.
|
|
20213
|
+
*/
|
|
20214
|
+
claimIndicatorId(requested) {
|
|
20215
|
+
if (requested === void 0) return this.registry.nextId("ind", (candidate) => this.handles.has(candidate));
|
|
20216
|
+
if (typeof requested !== "string" || requested.length === 0) {
|
|
20217
|
+
throw new TypeError("[vela] addIndicator: `id` must be a non-empty string");
|
|
20218
|
+
}
|
|
20219
|
+
if (this.handles.has(requested) || this.registry.get(requested)) {
|
|
20220
|
+
throw new Error(`[vela] addIndicator: indicator id "${requested}" is already live on this chart`);
|
|
20221
|
+
}
|
|
20222
|
+
return requested;
|
|
20223
|
+
}
|
|
20149
20224
|
async startIndicator(id, source, options, handle) {
|
|
20150
20225
|
try {
|
|
20151
20226
|
await this.readyPromise;
|
|
@@ -21744,7 +21819,10 @@ var IndicatorInputsDialog = class {
|
|
|
21744
21819
|
id,
|
|
21745
21820
|
theme: this.host.theme(),
|
|
21746
21821
|
get: () => String(bagOf(row, inp)[inp.key] ?? inp.defval),
|
|
21747
|
-
onChange: (v) => emit(v)
|
|
21822
|
+
onChange: (v) => emit(v),
|
|
21823
|
+
// An input change re-executes the script over its whole history: commit the
|
|
21824
|
+
// opacity drag once on release, not once per pointer move.
|
|
21825
|
+
commit: "release"
|
|
21748
21826
|
}).el;
|
|
21749
21827
|
}
|
|
21750
21828
|
if (inp.type === "symbol") return this.buildSymbol(id, String(current), emit);
|
|
@@ -21991,10 +22069,6 @@ var IndicatorInputsDialog = class {
|
|
|
21991
22069
|
}
|
|
21992
22070
|
/** Open a themed month calendar under `anchor` — same surface + shadow as the choice list. */
|
|
21993
22071
|
openCalendar(anchor, current, onPick) {
|
|
21994
|
-
const parsed = parseIsoDate(current);
|
|
21995
|
-
let year = parsed?.getFullYear() ?? (/* @__PURE__ */ new Date()).getFullYear();
|
|
21996
|
-
let month = parsed?.getMonth() ?? (/* @__PURE__ */ new Date()).getMonth();
|
|
21997
|
-
const selected = parsed ? isoDate(parsed) : current;
|
|
21998
22072
|
const pop = new Popover({
|
|
21999
22073
|
trigger: anchor,
|
|
22000
22074
|
theme: this.host.theme(),
|
|
@@ -22006,80 +22080,10 @@ var IndicatorInputsDialog = class {
|
|
|
22006
22080
|
this.calendarPop = null;
|
|
22007
22081
|
this.calendarAnchor = null;
|
|
22008
22082
|
},
|
|
22009
|
-
content: (el) => {
|
|
22010
|
-
|
|
22011
|
-
|
|
22012
|
-
|
|
22013
|
-
prev2.type = "button";
|
|
22014
|
-
prev2.className = "vela-ind-cal-nav";
|
|
22015
|
-
prev2.setAttribute("aria-label", "Previous month");
|
|
22016
|
-
prev2.innerHTML = iconAt("chevron-left", 14);
|
|
22017
|
-
const next = document.createElement("button");
|
|
22018
|
-
next.type = "button";
|
|
22019
|
-
next.className = "vela-ind-cal-nav";
|
|
22020
|
-
next.setAttribute("aria-label", "Next month");
|
|
22021
|
-
next.innerHTML = iconAt("chevron-right", 14);
|
|
22022
|
-
const head = document.createElement("div");
|
|
22023
|
-
head.className = "vela-ind-cal-head";
|
|
22024
|
-
head.append(prev2, title, next);
|
|
22025
|
-
const week = document.createElement("div");
|
|
22026
|
-
week.className = "vela-ind-cal-week";
|
|
22027
|
-
for (const d of WEEKDAY_LABELS) {
|
|
22028
|
-
const cell = document.createElement("span");
|
|
22029
|
-
cell.textContent = d;
|
|
22030
|
-
week.appendChild(cell);
|
|
22031
|
-
}
|
|
22032
|
-
const grid = document.createElement("div");
|
|
22033
|
-
grid.className = "vela-ind-cal-grid";
|
|
22034
|
-
const paint = () => {
|
|
22035
|
-
title.textContent = `${MONTH_LABELS[month]} ${year}`;
|
|
22036
|
-
grid.replaceChildren();
|
|
22037
|
-
const first = new Date(year, month, 1);
|
|
22038
|
-
const startPad = first.getDay();
|
|
22039
|
-
const days = new Date(year, month + 1, 0).getDate();
|
|
22040
|
-
const today = isoDate(/* @__PURE__ */ new Date());
|
|
22041
|
-
for (let i = 0; i < startPad; i++) {
|
|
22042
|
-
const blank = document.createElement("span");
|
|
22043
|
-
blank.className = "vela-ind-cal-blank";
|
|
22044
|
-
grid.appendChild(blank);
|
|
22045
|
-
}
|
|
22046
|
-
for (let day = 1; day <= days; day++) {
|
|
22047
|
-
const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
22048
|
-
const b = document.createElement("button");
|
|
22049
|
-
b.type = "button";
|
|
22050
|
-
b.className = "vela-ind-cal-day";
|
|
22051
|
-
b.textContent = String(day);
|
|
22052
|
-
if (iso === selected) b.dataset.checked = "1";
|
|
22053
|
-
if (iso === today) b.dataset.today = "1";
|
|
22054
|
-
b.addEventListener("click", (e) => {
|
|
22055
|
-
e.stopPropagation();
|
|
22056
|
-
pop.hide();
|
|
22057
|
-
onPick(iso);
|
|
22058
|
-
});
|
|
22059
|
-
grid.appendChild(b);
|
|
22060
|
-
}
|
|
22061
|
-
};
|
|
22062
|
-
prev2.addEventListener("click", (e) => {
|
|
22063
|
-
e.stopPropagation();
|
|
22064
|
-
month -= 1;
|
|
22065
|
-
if (month < 0) {
|
|
22066
|
-
month = 11;
|
|
22067
|
-
year -= 1;
|
|
22068
|
-
}
|
|
22069
|
-
paint();
|
|
22070
|
-
});
|
|
22071
|
-
next.addEventListener("click", (e) => {
|
|
22072
|
-
e.stopPropagation();
|
|
22073
|
-
month += 1;
|
|
22074
|
-
if (month > 11) {
|
|
22075
|
-
month = 0;
|
|
22076
|
-
year += 1;
|
|
22077
|
-
}
|
|
22078
|
-
paint();
|
|
22079
|
-
});
|
|
22080
|
-
paint();
|
|
22081
|
-
el.append(head, week, grid);
|
|
22082
|
-
}
|
|
22083
|
+
content: (el) => fillCalendar(el, current, (iso) => {
|
|
22084
|
+
pop.hide();
|
|
22085
|
+
onPick(iso);
|
|
22086
|
+
})
|
|
22083
22087
|
});
|
|
22084
22088
|
this.calendarPop = pop;
|
|
22085
22089
|
this.calendarAnchor = anchor;
|
|
@@ -22188,7 +22192,7 @@ function groupInputs(inputs) {
|
|
|
22188
22192
|
var CALENDAR_SVG = iconAt("calendar", 14);
|
|
22189
22193
|
var CLOCK_SVG = iconAt("clock", 14);
|
|
22190
22194
|
var DIALOG_STYLE_ID2 = "vela-ind-dialog-styles";
|
|
22191
|
-
var DIALOG_STYLE_REV = "
|
|
22195
|
+
var DIALOG_STYLE_REV = "30";
|
|
22192
22196
|
var LEGEND_ICON_PX = 16;
|
|
22193
22197
|
function ensureDialogStyles() {
|
|
22194
22198
|
if (typeof document === "undefined") return;
|
|
@@ -22204,8 +22208,12 @@ function ensureDialogStyles() {
|
|
|
22204
22208
|
.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;}
|
|
22205
22209
|
.vela-ind-combo-chevron:hover{opacity:0.9;}
|
|
22206
22210
|
.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;}
|
|
22211
|
+
.vela-ind-cal [hidden]{display:none !important;}
|
|
22207
22212
|
.vela-ind-cal-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;}
|
|
22208
|
-
.vela-ind-cal-title{flex:1;
|
|
22213
|
+
.vela-ind-cal-title{flex:1;display:flex;align-items:center;justify-content:center;gap:2px;min-width:0;}
|
|
22214
|
+
.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;}
|
|
22215
|
+
.vela-ind-cal-switch:not(:disabled):hover{background:var(--vela-hover);}
|
|
22216
|
+
.vela-ind-cal-switch:disabled{cursor:default;}
|
|
22209
22217
|
.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;}
|
|
22210
22218
|
.vela-ind-cal-nav:hover{background:var(--vela-hover);color:var(--vela-fg-bright);}
|
|
22211
22219
|
.vela-ind-cal-week,.vela-ind-cal-grid{display:grid;grid-template-columns:repeat(7,28px);gap:2px;}
|
|
@@ -22216,6 +22224,12 @@ function ensureDialogStyles() {
|
|
|
22216
22224
|
.vela-ind-cal-day:hover{background:var(--vela-hover);}
|
|
22217
22225
|
.vela-ind-cal-day[data-checked]{background:var(--vela-hover-strong);color:var(--vela-fg-bright);}
|
|
22218
22226
|
.vela-ind-cal-day[data-today]:not([data-checked]){box-shadow:inset 0 0 0 1px var(--vela-border-strong);}
|
|
22227
|
+
.vela-ind-cal-cells{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;width:calc(7 * 28px + 6 * 2px);}
|
|
22228
|
+
.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;}
|
|
22229
|
+
.vela-ind-cal-cell:hover{background:var(--vela-hover);}
|
|
22230
|
+
.vela-ind-cal-cell[data-checked]{background:var(--vela-hover-strong);color:var(--vela-fg-bright);}
|
|
22231
|
+
.vela-ind-cal-cell[data-today]:not([data-checked]){box-shadow:inset 0 0 0 1px var(--vela-border-strong);}
|
|
22232
|
+
.vela-ind-cal-cell[data-outside]{opacity:0.45;}
|
|
22219
22233
|
${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
22220
22234
|
.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;}
|
|
22221
22235
|
.vela-ind-tab:not(.vela-ind-tab-active):hover{color:var(--vela-fg-bright);}
|
|
@@ -22250,6 +22264,7 @@ var TIME_OPTIONS = Array.from({ length: 48 }, (_, i) => {
|
|
|
22250
22264
|
return { value: v, label: v };
|
|
22251
22265
|
});
|
|
22252
22266
|
var MONTH_LABELS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
22267
|
+
var MONTH_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
22253
22268
|
var WEEKDAY_LABELS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
22254
22269
|
function normalizeDateInput(raw) {
|
|
22255
22270
|
const t = raw.trim();
|
|
@@ -22271,6 +22286,151 @@ function parseIsoDate(raw) {
|
|
|
22271
22286
|
function isoDate(d) {
|
|
22272
22287
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
22273
22288
|
}
|
|
22289
|
+
function fillCalendar(el, current, onPick) {
|
|
22290
|
+
const today = /* @__PURE__ */ new Date();
|
|
22291
|
+
const selected = parseIsoDate(current);
|
|
22292
|
+
let year = selected?.getFullYear() ?? today.getFullYear();
|
|
22293
|
+
let month = selected?.getMonth() ?? today.getMonth();
|
|
22294
|
+
let mode = "date";
|
|
22295
|
+
const prev2 = document.createElement("button");
|
|
22296
|
+
prev2.type = "button";
|
|
22297
|
+
prev2.className = "vela-ind-cal-nav";
|
|
22298
|
+
prev2.innerHTML = iconAt("chevron-left", 14);
|
|
22299
|
+
const next = document.createElement("button");
|
|
22300
|
+
next.type = "button";
|
|
22301
|
+
next.className = "vela-ind-cal-nav";
|
|
22302
|
+
next.innerHTML = iconAt("chevron-right", 14);
|
|
22303
|
+
const monthBtn = document.createElement("button");
|
|
22304
|
+
monthBtn.type = "button";
|
|
22305
|
+
monthBtn.className = "vela-ind-cal-switch";
|
|
22306
|
+
monthBtn.setAttribute("aria-label", "Choose month");
|
|
22307
|
+
const yearBtn = document.createElement("button");
|
|
22308
|
+
yearBtn.type = "button";
|
|
22309
|
+
yearBtn.className = "vela-ind-cal-switch";
|
|
22310
|
+
yearBtn.setAttribute("aria-label", "Choose year");
|
|
22311
|
+
const title = document.createElement("div");
|
|
22312
|
+
title.className = "vela-ind-cal-title";
|
|
22313
|
+
title.append(monthBtn, yearBtn);
|
|
22314
|
+
const head = document.createElement("div");
|
|
22315
|
+
head.className = "vela-ind-cal-head";
|
|
22316
|
+
head.append(prev2, title, next);
|
|
22317
|
+
const week = document.createElement("div");
|
|
22318
|
+
week.className = "vela-ind-cal-week";
|
|
22319
|
+
for (const d of WEEKDAY_LABELS) {
|
|
22320
|
+
const cell = document.createElement("span");
|
|
22321
|
+
cell.textContent = d;
|
|
22322
|
+
week.appendChild(cell);
|
|
22323
|
+
}
|
|
22324
|
+
const grid = document.createElement("div");
|
|
22325
|
+
const paint = () => {
|
|
22326
|
+
const decade = Math.floor(year / 10) * 10;
|
|
22327
|
+
monthBtn.hidden = mode !== "date";
|
|
22328
|
+
monthBtn.textContent = MONTH_LABELS[month] ?? "";
|
|
22329
|
+
yearBtn.textContent = mode === "year" ? `${decade}-${decade + 9}` : String(year);
|
|
22330
|
+
yearBtn.disabled = mode === "year";
|
|
22331
|
+
week.hidden = mode !== "date";
|
|
22332
|
+
prev2.setAttribute("aria-label", mode === "date" ? "Previous month" : mode === "month" ? "Previous year" : "Previous decade");
|
|
22333
|
+
next.setAttribute("aria-label", mode === "date" ? "Next month" : mode === "month" ? "Next year" : "Next decade");
|
|
22334
|
+
grid.className = mode === "date" ? "vela-ind-cal-grid" : "vela-ind-cal-cells";
|
|
22335
|
+
grid.replaceChildren();
|
|
22336
|
+
if (mode === "date") {
|
|
22337
|
+
const startPad = new Date(year, month, 1).getDay();
|
|
22338
|
+
const days = new Date(year, month + 1, 0).getDate();
|
|
22339
|
+
const todayIso = isoDate(today);
|
|
22340
|
+
const selectedIso = selected ? isoDate(selected) : "";
|
|
22341
|
+
for (let i = 0; i < startPad; i++) {
|
|
22342
|
+
const blank = document.createElement("span");
|
|
22343
|
+
blank.className = "vela-ind-cal-blank";
|
|
22344
|
+
grid.appendChild(blank);
|
|
22345
|
+
}
|
|
22346
|
+
for (let day = 1; day <= days; day++) {
|
|
22347
|
+
const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
22348
|
+
const b = document.createElement("button");
|
|
22349
|
+
b.type = "button";
|
|
22350
|
+
b.className = "vela-ind-cal-day";
|
|
22351
|
+
b.textContent = String(day);
|
|
22352
|
+
if (iso === selectedIso) b.dataset.checked = "1";
|
|
22353
|
+
if (iso === todayIso) b.dataset.today = "1";
|
|
22354
|
+
b.addEventListener("click", (e) => {
|
|
22355
|
+
e.stopPropagation();
|
|
22356
|
+
onPick(iso);
|
|
22357
|
+
});
|
|
22358
|
+
grid.appendChild(b);
|
|
22359
|
+
}
|
|
22360
|
+
return;
|
|
22361
|
+
}
|
|
22362
|
+
if (mode === "month") {
|
|
22363
|
+
for (let m = 0; m < 12; m++) {
|
|
22364
|
+
const b = document.createElement("button");
|
|
22365
|
+
b.type = "button";
|
|
22366
|
+
b.className = "vela-ind-cal-cell";
|
|
22367
|
+
b.textContent = MONTH_SHORT[m] ?? "";
|
|
22368
|
+
if (selected?.getFullYear() === year && selected.getMonth() === m) b.dataset.checked = "1";
|
|
22369
|
+
if (today.getFullYear() === year && today.getMonth() === m) b.dataset.today = "1";
|
|
22370
|
+
b.addEventListener("click", (e) => {
|
|
22371
|
+
e.stopPropagation();
|
|
22372
|
+
month = m;
|
|
22373
|
+
mode = "date";
|
|
22374
|
+
paint();
|
|
22375
|
+
});
|
|
22376
|
+
grid.appendChild(b);
|
|
22377
|
+
}
|
|
22378
|
+
return;
|
|
22379
|
+
}
|
|
22380
|
+
for (let y = decade - 1; y <= decade + 10; y++) {
|
|
22381
|
+
const b = document.createElement("button");
|
|
22382
|
+
b.type = "button";
|
|
22383
|
+
b.className = "vela-ind-cal-cell";
|
|
22384
|
+
b.textContent = String(y);
|
|
22385
|
+
if (y < decade || y > decade + 9) b.dataset.outside = "1";
|
|
22386
|
+
if (selected?.getFullYear() === y) b.dataset.checked = "1";
|
|
22387
|
+
if (today.getFullYear() === y) b.dataset.today = "1";
|
|
22388
|
+
b.addEventListener("click", (e) => {
|
|
22389
|
+
e.stopPropagation();
|
|
22390
|
+
year = y;
|
|
22391
|
+
mode = "month";
|
|
22392
|
+
paint();
|
|
22393
|
+
});
|
|
22394
|
+
grid.appendChild(b);
|
|
22395
|
+
}
|
|
22396
|
+
};
|
|
22397
|
+
const step = (dir) => {
|
|
22398
|
+
if (mode === "date") {
|
|
22399
|
+
month += dir;
|
|
22400
|
+
if (month < 0) {
|
|
22401
|
+
month = 11;
|
|
22402
|
+
year -= 1;
|
|
22403
|
+
}
|
|
22404
|
+
if (month > 11) {
|
|
22405
|
+
month = 0;
|
|
22406
|
+
year += 1;
|
|
22407
|
+
}
|
|
22408
|
+
} else {
|
|
22409
|
+
year += mode === "month" ? dir : dir * 10;
|
|
22410
|
+
}
|
|
22411
|
+
paint();
|
|
22412
|
+
};
|
|
22413
|
+
prev2.addEventListener("click", (e) => {
|
|
22414
|
+
e.stopPropagation();
|
|
22415
|
+
step(-1);
|
|
22416
|
+
});
|
|
22417
|
+
next.addEventListener("click", (e) => {
|
|
22418
|
+
e.stopPropagation();
|
|
22419
|
+
step(1);
|
|
22420
|
+
});
|
|
22421
|
+
monthBtn.addEventListener("click", (e) => {
|
|
22422
|
+
e.stopPropagation();
|
|
22423
|
+
mode = "month";
|
|
22424
|
+
paint();
|
|
22425
|
+
});
|
|
22426
|
+
yearBtn.addEventListener("click", (e) => {
|
|
22427
|
+
e.stopPropagation();
|
|
22428
|
+
mode = "year";
|
|
22429
|
+
paint();
|
|
22430
|
+
});
|
|
22431
|
+
paint();
|
|
22432
|
+
el.append(head, week, grid);
|
|
22433
|
+
}
|
|
22274
22434
|
function normalizeTimeInput(raw) {
|
|
22275
22435
|
const t = raw.trim();
|
|
22276
22436
|
const m = /^(\d{1,2}):(\d{2})$/.exec(t) ?? /^(\d{2})(\d{2})$/.exec(t);
|
|
@@ -28758,6 +28918,10 @@ var BUILTIN_SETTINGS_IDS = [
|
|
|
28758
28918
|
"canvas.grid",
|
|
28759
28919
|
"canvas.grid.vertical",
|
|
28760
28920
|
"canvas.grid.horizontal",
|
|
28921
|
+
"canvas.margins",
|
|
28922
|
+
"canvas.margins.top",
|
|
28923
|
+
"canvas.margins.bottom",
|
|
28924
|
+
"canvas.margins.right",
|
|
28761
28925
|
"canvas.theme"
|
|
28762
28926
|
];
|
|
28763
28927
|
function settingsIdCatalog(hostSections, markGroups = []) {
|
|
@@ -29288,6 +29452,10 @@ var SettingsDialog = class {
|
|
|
29288
29452
|
body.append(sid(this.toggleRow("Horizontal", config.grid.horzLines.visible, (v) => this.emit({ grid: { horzLines: { visible: v } } }), [
|
|
29289
29453
|
this.swatch(config.grid.horzLines.color, (v) => this.emit({ grid: { horzLines: { color: v } } }))
|
|
29290
29454
|
]), "canvas.grid.horizontal"));
|
|
29455
|
+
body.append(sid(this.sectionTitle("Margins"), "canvas.margins"));
|
|
29456
|
+
body.append(sid(this.numberRow("Top", config.margins.top, 0, 40, 1, (v) => this.emit({ margins: { top: v } }), "%"), "canvas.margins.top"));
|
|
29457
|
+
body.append(sid(this.numberRow("Bottom", config.margins.bottom, 0, 40, 1, (v) => this.emit({ margins: { bottom: v } }), "%"), "canvas.margins.bottom"));
|
|
29458
|
+
body.append(sid(this.numberRow("Right", config.margins.right, 0, 200, 1, (v) => this.emit({ margins: { right: v } }), "bars"), "canvas.margins.right"));
|
|
29291
29459
|
if (this.themeControl) {
|
|
29292
29460
|
const tc = this.themeControl;
|
|
29293
29461
|
body.append(sid(this.sectionTitle("Theme"), "canvas.theme"));
|
|
@@ -29859,23 +30027,16 @@ var SettingsDialog = class {
|
|
|
29859
30027
|
this.hintTips.push(dispose);
|
|
29860
30028
|
return el;
|
|
29861
30029
|
}
|
|
29862
|
-
|
|
29863
|
-
|
|
29864
|
-
|
|
29865
|
-
|
|
29866
|
-
|
|
29867
|
-
|
|
29868
|
-
|
|
29869
|
-
|
|
29870
|
-
|
|
29871
|
-
|
|
29872
|
-
step,
|
|
29873
|
-
fill: false,
|
|
29874
|
-
commit: "live",
|
|
29875
|
-
steppers: true,
|
|
29876
|
-
onChange
|
|
29877
|
-
}).el
|
|
29878
|
-
});
|
|
30030
|
+
/** `unit` (optional) trails the input as muted text — "%", "bars". */
|
|
30031
|
+
numberRow(label, value, min, max, step, onChange, unit) {
|
|
30032
|
+
const controls = [buildFieldControl({ kind: "number", value, min, max, step, fill: false, commit: "live", steppers: true, onChange }).el];
|
|
30033
|
+
if (unit) {
|
|
30034
|
+
const u = document.createElement("span");
|
|
30035
|
+
u.textContent = unit;
|
|
30036
|
+
u.style.cssText = "color:var(--vela-fg-muted);";
|
|
30037
|
+
controls.push(u);
|
|
30038
|
+
}
|
|
30039
|
+
return this.rowWith(label, controls);
|
|
29879
30040
|
}
|
|
29880
30041
|
/** A dropdown whose option values differ from their display labels. */
|
|
29881
30042
|
selectRowLabeled(label, value, options, onChange) {
|
|
@@ -34749,9 +34910,7 @@ function createProjector(coords, paneOf, paneIdAtY, barsInRange, seriesInRange)
|
|
|
34749
34910
|
}
|
|
34750
34911
|
|
|
34751
34912
|
// src/renderers/native/core/autoscale.ts
|
|
34752
|
-
|
|
34753
|
-
var MARGIN_BOTTOM = 1 / 7;
|
|
34754
|
-
function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log = false, offsetOf = () => 0) {
|
|
34913
|
+
function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log = false, offsetOf = () => 0, margins = DEFAULT_MARGINS) {
|
|
34755
34914
|
let min = Infinity;
|
|
34756
34915
|
let max = -Infinity;
|
|
34757
34916
|
const consider = (v) => {
|
|
@@ -34786,14 +34945,17 @@ function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log =
|
|
|
34786
34945
|
const pad = Math.abs(min) * 0.1 || 1;
|
|
34787
34946
|
return { min: min - pad, max: max + pad, log: log && min - pad > 0 };
|
|
34788
34947
|
}
|
|
34948
|
+
const content = Math.max(0.1, 1 - (margins.top + margins.bottom) / 100);
|
|
34949
|
+
const above = margins.top / 100 / content;
|
|
34950
|
+
const below = margins.bottom / 100 / content;
|
|
34789
34951
|
if (log && min > 0) {
|
|
34790
34952
|
const lmin = Math.log(min);
|
|
34791
34953
|
const lmax = Math.log(max);
|
|
34792
34954
|
const lspan = lmax - lmin;
|
|
34793
|
-
return { min: Math.exp(lmin - lspan *
|
|
34955
|
+
return { min: Math.exp(lmin - lspan * below), max: Math.exp(lmax + lspan * above), log: true };
|
|
34794
34956
|
}
|
|
34795
34957
|
const span = max - min;
|
|
34796
|
-
return { min: min - span *
|
|
34958
|
+
return { min: min - span * below, max: max + span * above };
|
|
34797
34959
|
}
|
|
34798
34960
|
function considerSeries(s, i0, i1, off, consider) {
|
|
34799
34961
|
if (!seriesInScale(s)) return;
|
|
@@ -36484,6 +36646,7 @@ var NativeRenderer = class {
|
|
|
36484
36646
|
intro: this.intro.style !== false
|
|
36485
36647
|
},
|
|
36486
36648
|
panes: { separatorColor: s.separatorColor ?? t.borderColor },
|
|
36649
|
+
margins: { ...s.margins },
|
|
36487
36650
|
trades: {
|
|
36488
36651
|
visible: this.scene.tradeMarkers.visible,
|
|
36489
36652
|
labels: this.scene.tradeMarkers.labels,
|
|
@@ -36596,6 +36759,10 @@ var NativeRenderer = class {
|
|
|
36596
36759
|
this.animAutoscale.toggle(next.animations.autoscale);
|
|
36597
36760
|
this.intro = { style: next.animations.intro ? this.introOnStyle : false, duration: this.intro.duration || INTRO_DURATION_DEFAULT_MS };
|
|
36598
36761
|
s.separatorColor = keepInherit(s.separatorColor, next.panes.separatorColor, prevTheme.borderColor);
|
|
36762
|
+
if (next.margins.right !== s.margins.right && this.coords.barCount > 0) {
|
|
36763
|
+
this.applyViewport({ barSpacing: this.coords.getViewport().barSpacing, rightOffset: next.margins.right });
|
|
36764
|
+
}
|
|
36765
|
+
s.margins = { ...next.margins };
|
|
36599
36766
|
this.scene.tradeMarkers = {
|
|
36600
36767
|
visible: next.trades.visible,
|
|
36601
36768
|
labels: next.trades.labels,
|
|
@@ -36839,7 +37006,7 @@ var NativeRenderer = class {
|
|
|
36839
37006
|
/** Glide the view back to the most recent bars, keeping the current zoom (barSpacing). */
|
|
36840
37007
|
scrollToRealtime() {
|
|
36841
37008
|
if (this.coords.barCount === 0) return;
|
|
36842
|
-
this.glideRightOffset(
|
|
37009
|
+
this.glideRightOffset(this.scene.style.margins.right);
|
|
36843
37010
|
}
|
|
36844
37011
|
/** Ease rightOffset to `target` at constant zoom (see animTick's scroll glide);
|
|
36845
37012
|
* instant when the scroll glide is off. Shared by scroll-to-latest and panBy. */
|
|
@@ -38781,6 +38948,7 @@ var NativeRenderer = class {
|
|
|
38781
38948
|
const pricePane = panes.find((p) => p.kind === "price") ?? null;
|
|
38782
38949
|
this.chrome.prepare(this.scene, this.coords, this.theme);
|
|
38783
38950
|
const animating = this.animator.active;
|
|
38951
|
+
const margins = this.scene.style.margins;
|
|
38784
38952
|
for (const pane of panes) {
|
|
38785
38953
|
if (pane.manualScale) {
|
|
38786
38954
|
pane.scaleTarget = pane.manualScale;
|
|
@@ -38796,7 +38964,7 @@ var NativeRenderer = class {
|
|
|
38796
38964
|
if (or) dr = dr ? { min: Math.min(dr.min, or.min), max: Math.max(dr.max, or.max) } : or;
|
|
38797
38965
|
}
|
|
38798
38966
|
const includeCandles = pane.kind === "price" && (!this.scene.candlesHidden || this.priceLayersAnchoredToBars(masterModels) || !this.paneHasMeasurableContent(masterModels, dr));
|
|
38799
|
-
pane.scaleTarget = computePaneScale(masterModels, this.bars, includeCandles, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id));
|
|
38967
|
+
pane.scaleTarget = computePaneScale(masterModels, this.bars, includeCandles, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id), margins);
|
|
38800
38968
|
pane.percentBaseline = pane.kind === "price" ? this.bars[i0]?.close ?? 0 : this.firstVisibleValue(masterModels, i0);
|
|
38801
38969
|
pane.axisFormat = void 0;
|
|
38802
38970
|
pane.axisBands = void 0;
|
|
@@ -38807,7 +38975,7 @@ var NativeRenderer = class {
|
|
|
38807
38975
|
pane.axisFormat = "volume";
|
|
38808
38976
|
}
|
|
38809
38977
|
} else if (this.layerNativesOwnPane(pane, masterModels)) {
|
|
38810
|
-
pane.scaleTarget = computePaneScale([], this.bars, true, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id));
|
|
38978
|
+
pane.scaleTarget = computePaneScale([], this.bars, true, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id), margins);
|
|
38811
38979
|
pane.percentBaseline = this.bars[i0]?.close ?? 0;
|
|
38812
38980
|
if (masterModels.every((m) => m.paneAxis != null)) {
|
|
38813
38981
|
pane.axisFormat = "none";
|
|
@@ -38836,7 +39004,7 @@ var NativeRenderer = class {
|
|
|
38836
39004
|
continue;
|
|
38837
39005
|
}
|
|
38838
39006
|
const mdr = this.chrome.paneDrawingsRange([model], this.scene, false, vr);
|
|
38839
|
-
sl.scaleTarget = computePaneScale([model], this.bars, false, i0, i1, mdr, false, (id) => this.scene.offsetOf(id));
|
|
39007
|
+
sl.scaleTarget = computePaneScale([model], this.bars, false, i0, i1, mdr, false, (id) => this.scene.offsetOf(id), margins);
|
|
38840
39008
|
if (!animating || !sl.initialized) {
|
|
38841
39009
|
sl.scale = { ...sl.scaleTarget };
|
|
38842
39010
|
sl.initialized = true;
|
|
@@ -38877,13 +39045,13 @@ var NativeRenderer = class {
|
|
|
38877
39045
|
for (const pane of this.scene.panes.values()) pane.manualScale = null;
|
|
38878
39046
|
for (const sl of this.scene.indicatorScales.values()) sl.manualScale = null;
|
|
38879
39047
|
const visibleBars = Math.min(n, 200);
|
|
38880
|
-
const rightOffset =
|
|
39048
|
+
const rightOffset = this.scene.style.margins.right;
|
|
38881
39049
|
const v = this.clampViewport(w / ((visibleBars + rightOffset) * this.coords.spacingScale), rightOffset);
|
|
38882
39050
|
this.coords.setViewport(v);
|
|
38883
39051
|
this.targetBarSpacing = v.barSpacing;
|
|
38884
39052
|
}
|
|
38885
39053
|
/** Re-frame after a series replacement (a symbol/timeframe switch): keep the user's
|
|
38886
|
-
* zoom (bar spacing), re-anchor the newest bars at the
|
|
39054
|
+
* zoom (bar spacing), re-anchor the newest bars at the configured right margin.
|
|
38887
39055
|
* `clampViewport`'s fit-all-bars floor deliberately does NOT apply — a progressive
|
|
38888
39056
|
* head may still be backfilling toward the previous depth, and raising the spacing
|
|
38889
39057
|
* to its temporary bar count would lose the zoom this exists to keep. */
|
|
@@ -38892,7 +39060,7 @@ var NativeRenderer = class {
|
|
|
38892
39060
|
this.panVelocity = 0;
|
|
38893
39061
|
for (const pane of this.scene.panes.values()) pane.manualScale = null;
|
|
38894
39062
|
for (const sl of this.scene.indicatorScales.values()) sl.manualScale = null;
|
|
38895
|
-
const v = { barSpacing: clampBarSpacing(this.coords.getViewport().barSpacing), rightOffset:
|
|
39063
|
+
const v = { barSpacing: clampBarSpacing(this.coords.getViewport().barSpacing), rightOffset: this.scene.style.margins.right };
|
|
38896
39064
|
this.coords.setViewport(v);
|
|
38897
39065
|
this.targetBarSpacing = v.barSpacing;
|
|
38898
39066
|
}
|
|
@@ -41977,6 +42145,7 @@ function registerClassicIndicators() {
|
|
|
41977
42145
|
}
|
|
41978
42146
|
|
|
41979
42147
|
// src/Vela.ts
|
|
42148
|
+
var asError = (err) => err instanceof Error ? err : new Error(String(err));
|
|
41980
42149
|
var Vela = class {
|
|
41981
42150
|
constructor(container, options = {}, deps = {}) {
|
|
41982
42151
|
registerBuiltinChartTypes();
|
|
@@ -42100,7 +42269,12 @@ var Vela = class {
|
|
|
42100
42269
|
* fetch from — the same relationship `script:run` has to `context:changed`.
|
|
42101
42270
|
*/
|
|
42102
42271
|
runScript(source, options) {
|
|
42103
|
-
|
|
42272
|
+
let handle;
|
|
42273
|
+
try {
|
|
42274
|
+
handle = this.addIndicator(source, options);
|
|
42275
|
+
} catch (err) {
|
|
42276
|
+
return Promise.resolve({ ok: false, run: null, error: asError(err), onUpdate: () => () => void 0, remove: () => void 0 });
|
|
42277
|
+
}
|
|
42104
42278
|
const updates = /* @__PURE__ */ new Set();
|
|
42105
42279
|
const drop = () => {
|
|
42106
42280
|
try {
|
|
@@ -42144,7 +42318,12 @@ var Vela = class {
|
|
|
42144
42318
|
});
|
|
42145
42319
|
}
|
|
42146
42320
|
runIndicator(source, options) {
|
|
42147
|
-
|
|
42321
|
+
let handle;
|
|
42322
|
+
try {
|
|
42323
|
+
handle = this.addIndicator(source, options);
|
|
42324
|
+
} catch (err) {
|
|
42325
|
+
return Promise.resolve({ ok: false, handle: null, error: asError(err), context: null });
|
|
42326
|
+
}
|
|
42148
42327
|
return new Promise((resolve) => {
|
|
42149
42328
|
const offReady = handle.on("ready", () => {
|
|
42150
42329
|
offReady();
|
|
@@ -43493,7 +43672,7 @@ var ChartContextMenu = class {
|
|
|
43493
43672
|
} else if (id.startsWith("tz:")) {
|
|
43494
43673
|
const zone = id.slice("tz:".length);
|
|
43495
43674
|
if (this.cbs.setTimezone) this.cbs.setTimezone(zone);
|
|
43496
|
-
else chart.renderer.set("timezone", zone);
|
|
43675
|
+
else chart.renderer.set("timezone", resolveTimezone(zone, void 0));
|
|
43497
43676
|
} else if (id === "auto") {
|
|
43498
43677
|
chart.renderer.set("autoScale", chart.renderer.get("autoScale") === false);
|
|
43499
43678
|
} else if (id === "invert") {
|
|
@@ -43726,7 +43905,7 @@ var ChartCell = class {
|
|
|
43726
43905
|
this.history.onChart(this.inner);
|
|
43727
43906
|
this.inner.renderer.onConfigChanged(() => {
|
|
43728
43907
|
const zone = this.inner?.renderer.get("timezone");
|
|
43729
|
-
if (typeof zone === "string" && normalizeTimezone(zone) !== normalizeTimezone(this.
|
|
43908
|
+
if (typeof zone === "string" && normalizeTimezone(zone) !== normalizeTimezone(this.displayTimezone)) {
|
|
43730
43909
|
this.deps.setTimezone(normalizeTimezone(zone));
|
|
43731
43910
|
}
|
|
43732
43911
|
const style = this.priceStyle;
|
|
@@ -43768,8 +43947,7 @@ var ChartCell = class {
|
|
|
43768
43947
|
this.refreshSessionShading();
|
|
43769
43948
|
});
|
|
43770
43949
|
this.inner.on("viewport:changed", (range) => this.sessionShading.updateRange(range));
|
|
43771
|
-
|
|
43772
|
-
if (tz !== "Etc/UTC") this.inner.renderer.set("timezone", tz);
|
|
43950
|
+
this.applyTimezone();
|
|
43773
43951
|
this.indicatorTitlesOn = seed.indicatorTitles ?? true;
|
|
43774
43952
|
if (!this.indicatorTitlesOn) this.inner.renderer.set("indicatorTitles", false);
|
|
43775
43953
|
this.indicatorValuesOn = seed.indicatorValues ?? true;
|
|
@@ -43791,7 +43969,7 @@ var ChartCell = class {
|
|
|
43791
43969
|
this.statusline?.setSymbol(this.state.symbol);
|
|
43792
43970
|
this.statusline?.setMeta(this.state.timeframe ?? "60", this.inner.data.displayPrefix(this.state.symbol) ?? this.state.provider ?? "");
|
|
43793
43971
|
}
|
|
43794
|
-
this.
|
|
43972
|
+
this.refreshSymbolMetadata();
|
|
43795
43973
|
if (this.inner && this.state.symbol) this.marketStatus?.track(this.inner.data, this.state.symbol);
|
|
43796
43974
|
});
|
|
43797
43975
|
this.syncStatuslineColors();
|
|
@@ -43865,7 +44043,7 @@ var ChartCell = class {
|
|
|
43865
44043
|
this.offMarket = this.inner.on("market:changed", ({ symbol: symbol2, timeframe }) => {
|
|
43866
44044
|
this.projectMarket(symbol2, timeframe);
|
|
43867
44045
|
this.refreshNativeCatalog();
|
|
43868
|
-
this.
|
|
44046
|
+
this.refreshSymbolMetadata();
|
|
43869
44047
|
if (this.inner) this.marketStatus?.track(this.inner.data, symbol2);
|
|
43870
44048
|
this.deps.onMarketChanged(this.id);
|
|
43871
44049
|
});
|
|
@@ -43906,7 +44084,35 @@ var ChartCell = class {
|
|
|
43906
44084
|
this.deps.onStateDirty();
|
|
43907
44085
|
void this.inner?.setMarket({ session });
|
|
43908
44086
|
}
|
|
43909
|
-
|
|
44087
|
+
/**
|
|
44088
|
+
* The symbol's own trading zone, once its metadata has landed — what the exchange
|
|
44089
|
+
* rule resolves to on this cell (the workspace labels the shared bottom bar with the
|
|
44090
|
+
* ACTIVE cell's). Undefined = unknown or undeclared (the rule then renders UTC).
|
|
44091
|
+
*/
|
|
44092
|
+
get exchangeTimezone() {
|
|
44093
|
+
return this.exchangeZone;
|
|
44094
|
+
}
|
|
44095
|
+
/** The IANA zone this cell's axis renders in: the workspace choice, resolved. */
|
|
44096
|
+
get displayTimezone() {
|
|
44097
|
+
return resolveTimezone(this.deps.timezone(), this.exchangeZone);
|
|
44098
|
+
}
|
|
44099
|
+
/**
|
|
44100
|
+
* Push the resolved zone to the renderer — on the workspace choice changing, and on
|
|
44101
|
+
* this cell's market zone changing under the exchange rule. Skips the write when the
|
|
44102
|
+
* renderer already holds it (its config default is the bare `'UTC'` alias).
|
|
44103
|
+
*/
|
|
44104
|
+
applyTimezone() {
|
|
44105
|
+
const chart = this.inner;
|
|
44106
|
+
if (!chart) return;
|
|
44107
|
+
const zone = this.displayTimezone;
|
|
44108
|
+
const current = chart.renderer.get("timezone");
|
|
44109
|
+
const held = typeof current === "string" && current ? current : "UTC";
|
|
44110
|
+
if (normalizeTimezone(held) === normalizeTimezone(zone)) return;
|
|
44111
|
+
chart.renderer.set("timezone", zone);
|
|
44112
|
+
}
|
|
44113
|
+
/** Re-read the symbol's metadata: session posture (RTH/ETH toggle, shading) and its
|
|
44114
|
+
* trading zone (the exchange rule). Async — the workspace re-projects when a verdict lands. */
|
|
44115
|
+
refreshSymbolMetadata() {
|
|
43910
44116
|
const chart = this.inner;
|
|
43911
44117
|
const symbol = this.state.symbol;
|
|
43912
44118
|
if (!chart || !symbol) return;
|
|
@@ -43914,7 +44120,13 @@ var ChartCell = class {
|
|
|
43914
44120
|
if (this.inner !== chart) return;
|
|
43915
44121
|
const available = typeof si?.session === "string" && si.session !== "" && si.session !== "24x7";
|
|
43916
44122
|
const overnight = parseSessionSpec(si)?.overnight === true;
|
|
43917
|
-
|
|
44123
|
+
const zone = typeof si?.timezone === "string" && si.timezone !== "" ? si.timezone : void 0;
|
|
44124
|
+
const zoneChanged = zone !== this.exchangeZone;
|
|
44125
|
+
if (zoneChanged) {
|
|
44126
|
+
this.exchangeZone = zone;
|
|
44127
|
+
this.applyTimezone();
|
|
44128
|
+
}
|
|
44129
|
+
if (available !== this.sessionAvailableFlag || overnight !== this.sessionOvernightFlag || zoneChanged) {
|
|
43918
44130
|
this.sessionAvailableFlag = available;
|
|
43919
44131
|
this.sessionOvernightFlag = overnight;
|
|
43920
44132
|
this.deps.onMarketChanged(this.id);
|
|
@@ -44373,16 +44585,19 @@ var ChartCell = class {
|
|
|
44373
44585
|
* a persistence handler's `restore` runs silently, a user-driven call records.
|
|
44374
44586
|
*/
|
|
44375
44587
|
addExternalIndicator(entry) {
|
|
44588
|
+
const { id, inputs, props, hidden, ...script } = entry;
|
|
44376
44589
|
this.addManifestInstance(
|
|
44377
|
-
{ ...
|
|
44378
|
-
{ external: true, ...
|
|
44590
|
+
{ ...script, enabled: true },
|
|
44591
|
+
{ external: true, ...id !== void 0 ? { id } : {}, ...inputs ? { inputs } : {}, ...props ? { props } : {}, ...hidden ? { hidden: true } : {} }
|
|
44379
44592
|
);
|
|
44380
44593
|
}
|
|
44381
44594
|
/** Add ONE instance of a manifest entry (repeatable — duplicates are legitimate). */
|
|
44382
44595
|
addManifestInstance(entry, opts = {}) {
|
|
44383
44596
|
if (this.destroyed) return;
|
|
44384
44597
|
const values = opts.inputs || opts.props ? { inputs: opts.inputs, props: opts.props } : void 0;
|
|
44385
|
-
const
|
|
44598
|
+
const handle = this.addToChart(entry, values, opts.id);
|
|
44599
|
+
if (!handle) return;
|
|
44600
|
+
const it = { entry, handle, id: handle.id, ...opts.external ? { external: true } : {}, ...values ? { values } : {} };
|
|
44386
44601
|
if (opts.hidden) it.handle?.setVisible(false);
|
|
44387
44602
|
this.instances.push(it);
|
|
44388
44603
|
this.deps.onIndicatorsChanged(this.id);
|
|
@@ -44391,7 +44606,7 @@ var ChartCell = class {
|
|
|
44391
44606
|
this.history.push({
|
|
44392
44607
|
undo: () => this.dropInstance(snapshot),
|
|
44393
44608
|
redo: () => {
|
|
44394
|
-
snapshot.handle = this.addToChart(snapshot.entry, snapshot.values);
|
|
44609
|
+
snapshot.handle = this.addToChart(snapshot.entry, snapshot.values, snapshot.id);
|
|
44395
44610
|
this.instances.push(snapshot);
|
|
44396
44611
|
this.deps.onIndicatorsChanged(this.id);
|
|
44397
44612
|
}
|
|
@@ -44404,7 +44619,7 @@ var ChartCell = class {
|
|
|
44404
44619
|
const snapshot = it;
|
|
44405
44620
|
this.history.push({
|
|
44406
44621
|
undo: () => {
|
|
44407
|
-
snapshot.handle = this.addToChart(snapshot.entry, snapshot.values);
|
|
44622
|
+
snapshot.handle = this.addToChart(snapshot.entry, snapshot.values, snapshot.id);
|
|
44408
44623
|
this.instances.push(snapshot);
|
|
44409
44624
|
this.deps.onIndicatorsChanged(this.id);
|
|
44410
44625
|
},
|
|
@@ -44494,9 +44709,10 @@ var ChartCell = class {
|
|
|
44494
44709
|
this.deps.onIndicatorsChanged(this.id);
|
|
44495
44710
|
});
|
|
44496
44711
|
}
|
|
44497
|
-
addToChart(entry, values) {
|
|
44712
|
+
addToChart(entry, values, id) {
|
|
44498
44713
|
try {
|
|
44499
44714
|
return this.inner?.addIndicator(entry.script, {
|
|
44715
|
+
...id !== void 0 ? { id } : {},
|
|
44500
44716
|
...entry.language !== void 0 ? { language: entry.language } : {},
|
|
44501
44717
|
...values?.inputs ? { inputs: values.inputs } : {},
|
|
44502
44718
|
...values?.props ? { props: values.props } : {}
|
|
@@ -45680,13 +45896,23 @@ var VelaWorkspace = class {
|
|
|
45680
45896
|
}
|
|
45681
45897
|
}
|
|
45682
45898
|
}
|
|
45683
|
-
/**
|
|
45899
|
+
/**
|
|
45900
|
+
* Set the workspace-global display timezone — applied to EVERY cell. An IANA zone,
|
|
45901
|
+
* or `'exchange'` (the exchange rule): each cell then renders in its OWN market's
|
|
45902
|
+
* zone (Chicago for a CME future, New York for a US equity, UTC for crypto), and the
|
|
45903
|
+
* bottom bar follows the active cell's.
|
|
45904
|
+
*/
|
|
45684
45905
|
setTimezone(zone) {
|
|
45685
45906
|
this.timezone = zone;
|
|
45686
|
-
this.
|
|
45687
|
-
for (const cell of this.cellsById.values()) cell.
|
|
45907
|
+
this.projectTimezone();
|
|
45908
|
+
for (const cell of this.cellsById.values()) cell.applyTimezone();
|
|
45688
45909
|
this.markStateDirty();
|
|
45689
45910
|
}
|
|
45911
|
+
/** Bottom bar ⇐ the stored choice + the ACTIVE cell's market zone (labels the exchange row). */
|
|
45912
|
+
projectTimezone() {
|
|
45913
|
+
const active = this.activeId ? this.cellsById.get(this.activeId) : void 0;
|
|
45914
|
+
this.bottombar?.setTimezone(this.timezone, active?.exchangeTimezone);
|
|
45915
|
+
}
|
|
45690
45916
|
/**
|
|
45691
45917
|
* Swap the workspace theme at runtime — `'dark'`, `'light'`, or a full custom theme,
|
|
45692
45918
|
* applied to the shared chrome (topbar, panels, drawing toolbar) and EVERY cell.
|
|
@@ -45891,6 +46117,7 @@ var VelaWorkspace = class {
|
|
|
45891
46117
|
this.dock.onChart(cell.chart);
|
|
45892
46118
|
this.bottombar?.setActiveRange(cell.activeRangeId);
|
|
45893
46119
|
this.bottombar?.setSession({ session: cell.session, enabled: cell.sessionAvailable });
|
|
46120
|
+
this.projectTimezone();
|
|
45894
46121
|
this.indicatorPicker?.sync();
|
|
45895
46122
|
this.glider.stop();
|
|
45896
46123
|
const d = cell.chart.drawings;
|
|
@@ -46475,6 +46702,7 @@ var VelaWorkspace = class {
|
|
|
46475
46702
|
this.mobileBar?.setTimeframe(cell.timeframe);
|
|
46476
46703
|
this.objectTree.setSymbol(cell.symbol);
|
|
46477
46704
|
this.bottombar?.setSession({ session: cell.session, enabled: cell.sessionAvailable });
|
|
46705
|
+
this.projectTimezone();
|
|
46478
46706
|
this.bottombar?.setActiveRange(cell.activeRangeId);
|
|
46479
46707
|
}
|
|
46480
46708
|
/** Trigger ② — a cell's price style changed: the topbar button/menu only if active.
|