@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/index.cjs
CHANGED
|
@@ -129,10 +129,18 @@ var IndicatorRegistry = class {
|
|
|
129
129
|
this.records = /* @__PURE__ */ new Map();
|
|
130
130
|
this.counter = 0;
|
|
131
131
|
}
|
|
132
|
-
/**
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Mint a unique per-instance id. Host-supplied ids share the namespace, so a minted
|
|
134
|
+
* id skips anything already recorded — and anything `taken` reports live elsewhere
|
|
135
|
+
* (a handle the orchestrator holds outside the records, e.g. a fail-soft native).
|
|
136
|
+
*/
|
|
137
|
+
nextId(prefix = "ind", taken = () => false) {
|
|
138
|
+
let id;
|
|
139
|
+
do {
|
|
140
|
+
this.counter += 1;
|
|
141
|
+
id = `${prefix}-${this.counter}`;
|
|
142
|
+
} while (this.records.has(id) || taken(id));
|
|
143
|
+
return id;
|
|
136
144
|
}
|
|
137
145
|
add(record) {
|
|
138
146
|
this.records.set(record.id, record);
|
|
@@ -8677,7 +8685,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
8677
8685
|
this.engines.set(language, engine);
|
|
8678
8686
|
}
|
|
8679
8687
|
addIndicator(source, options = {}) {
|
|
8680
|
-
const id = this.
|
|
8688
|
+
const id = this.claimIndicatorId(options.id);
|
|
8681
8689
|
const title = options.title ?? "Indicator";
|
|
8682
8690
|
const handle = new IndicatorHandleImpl(id, title, this, source);
|
|
8683
8691
|
this.handles.set(id, handle);
|
|
@@ -8699,7 +8707,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
8699
8707
|
const existing = this.registry.all().find((r) => r.native?.type === type);
|
|
8700
8708
|
if (existing) return this.handles.get(existing.id) ?? new IndicatorHandleImpl(existing.id, existing.title, this, void 0, type);
|
|
8701
8709
|
}
|
|
8702
|
-
const id = this.registry.nextId("native");
|
|
8710
|
+
const id = this.registry.nextId("native", (candidate) => this.handles.has(candidate));
|
|
8703
8711
|
const title = descriptor?.title ?? type;
|
|
8704
8712
|
const handle = new IndicatorHandleImpl(id, title, this, void 0, type);
|
|
8705
8713
|
this.handles.set(id, handle);
|
|
@@ -8977,6 +8985,24 @@ var EngineOrchestrator = class _EngineOrchestrator {
|
|
|
8977
8985
|
this.events.clear();
|
|
8978
8986
|
}
|
|
8979
8987
|
// ── internals ───────────────────────────────────────────────
|
|
8988
|
+
/**
|
|
8989
|
+
* The id a new script indicator runs under: the host's when supplied, else a minted
|
|
8990
|
+
* one. A host id is opaque but must be a non-empty string, and it must not be live
|
|
8991
|
+
* on this chart — a duplicate is a programming error surfaced synchronously, never
|
|
8992
|
+
* renamed behind the caller's back (the whole point of supplying one is that
|
|
8993
|
+
* `handle.id` equals what was passed). "Live" reads both the records and the handle
|
|
8994
|
+
* map: a fail-soft handle never enters the registry but still owns its id.
|
|
8995
|
+
*/
|
|
8996
|
+
claimIndicatorId(requested) {
|
|
8997
|
+
if (requested === void 0) return this.registry.nextId("ind", (candidate) => this.handles.has(candidate));
|
|
8998
|
+
if (typeof requested !== "string" || requested.length === 0) {
|
|
8999
|
+
throw new TypeError("[vela] addIndicator: `id` must be a non-empty string");
|
|
9000
|
+
}
|
|
9001
|
+
if (this.handles.has(requested) || this.registry.get(requested)) {
|
|
9002
|
+
throw new Error(`[vela] addIndicator: indicator id "${requested}" is already live on this chart`);
|
|
9003
|
+
}
|
|
9004
|
+
return requested;
|
|
9005
|
+
}
|
|
8980
9006
|
async startIndicator(id, source, options, handle) {
|
|
8981
9007
|
try {
|
|
8982
9008
|
await this.readyPromise;
|
|
@@ -13119,7 +13145,8 @@ function addRecent(hex6) {
|
|
|
13119
13145
|
recents.unshift(hex6);
|
|
13120
13146
|
if (recents.length > 10) recents.length = 10;
|
|
13121
13147
|
}
|
|
13122
|
-
function buildColorPicker(color, theme, onChange) {
|
|
13148
|
+
function buildColorPicker(color, theme, onChange, options = {}) {
|
|
13149
|
+
const commit = options.commit ?? "live";
|
|
13123
13150
|
const parsed = splitColor(color);
|
|
13124
13151
|
let curHex = parsed.hex6;
|
|
13125
13152
|
let curAlpha = parsed.alpha;
|
|
@@ -13202,7 +13229,12 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
13202
13229
|
const r = track.getBoundingClientRect();
|
|
13203
13230
|
curAlpha = Math.max(0, Math.min(1, (clientX - r.left) / r.width));
|
|
13204
13231
|
paintOpacity();
|
|
13205
|
-
emit();
|
|
13232
|
+
if (commit === "live") emit();
|
|
13233
|
+
};
|
|
13234
|
+
const endDrag = () => {
|
|
13235
|
+
if (!dragging) return;
|
|
13236
|
+
dragging = false;
|
|
13237
|
+
if (commit === "release") emit();
|
|
13206
13238
|
};
|
|
13207
13239
|
track.addEventListener("pointerdown", (e) => {
|
|
13208
13240
|
e.stopPropagation();
|
|
@@ -13213,7 +13245,8 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
13213
13245
|
track.addEventListener("pointermove", (e) => {
|
|
13214
13246
|
if (dragging) onDrag(e.clientX);
|
|
13215
13247
|
});
|
|
13216
|
-
track.addEventListener("pointerup",
|
|
13248
|
+
track.addEventListener("pointerup", endDrag);
|
|
13249
|
+
track.addEventListener("pointercancel", endDrag);
|
|
13217
13250
|
function emit() {
|
|
13218
13251
|
onChange(combineColor(curHex, curAlpha));
|
|
13219
13252
|
}
|
|
@@ -13236,7 +13269,7 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
13236
13269
|
return root;
|
|
13237
13270
|
}
|
|
13238
13271
|
function colorField(theme, getVal, onVal, opts) {
|
|
13239
|
-
return new ColorField({ theme, getVal, onVal, shape: opts?.shape, id: opts?.id, popover: opts?.popover }).el;
|
|
13272
|
+
return new ColorField({ theme, getVal, onVal, shape: opts?.shape, id: opts?.id, popover: opts?.popover, commit: opts?.commit }).el;
|
|
13240
13273
|
}
|
|
13241
13274
|
var ColorField = class {
|
|
13242
13275
|
constructor(opts) {
|
|
@@ -13245,6 +13278,7 @@ var ColorField = class {
|
|
|
13245
13278
|
this.getVal = opts.getVal;
|
|
13246
13279
|
this.onVal = opts.onVal;
|
|
13247
13280
|
this.popoverOpts = opts.popover;
|
|
13281
|
+
this.commit = opts.commit;
|
|
13248
13282
|
const trigger = document.createElement("button");
|
|
13249
13283
|
trigger.type = "button";
|
|
13250
13284
|
if (opts.id) trigger.id = opts.id;
|
|
@@ -13284,10 +13318,15 @@ var ColorField = class {
|
|
|
13284
13318
|
boundary: this.popoverOpts?.boundary,
|
|
13285
13319
|
zIndex: this.popoverOpts?.zIndex,
|
|
13286
13320
|
className: "vela-color-field-pop",
|
|
13287
|
-
content: buildColorPicker(
|
|
13288
|
-
this.
|
|
13289
|
-
this.
|
|
13290
|
-
|
|
13321
|
+
content: buildColorPicker(
|
|
13322
|
+
this.getVal(),
|
|
13323
|
+
this.theme,
|
|
13324
|
+
(val) => {
|
|
13325
|
+
this.onVal(val);
|
|
13326
|
+
this.paint();
|
|
13327
|
+
},
|
|
13328
|
+
{ commit: this.commit }
|
|
13329
|
+
)
|
|
13291
13330
|
});
|
|
13292
13331
|
pop.show();
|
|
13293
13332
|
}
|
|
@@ -13768,7 +13807,8 @@ function buildFieldControl(desc) {
|
|
|
13768
13807
|
const el2 = colorField(desc.theme, desc.get, desc.onChange, {
|
|
13769
13808
|
shape: "circle",
|
|
13770
13809
|
id: desc.id,
|
|
13771
|
-
popover: desc.popover
|
|
13810
|
+
popover: desc.popover,
|
|
13811
|
+
commit: desc.commit
|
|
13772
13812
|
});
|
|
13773
13813
|
if (desc.title) el2.title = desc.title;
|
|
13774
13814
|
return { el: el2 };
|
|
@@ -14146,7 +14186,10 @@ var IndicatorInputsDialog = class {
|
|
|
14146
14186
|
id,
|
|
14147
14187
|
theme: this.host.theme(),
|
|
14148
14188
|
get: () => String(bagOf(row, inp)[inp.key] ?? inp.defval),
|
|
14149
|
-
onChange: (v) => emit(v)
|
|
14189
|
+
onChange: (v) => emit(v),
|
|
14190
|
+
// An input change re-executes the script over its whole history: commit the
|
|
14191
|
+
// opacity drag once on release, not once per pointer move.
|
|
14192
|
+
commit: "release"
|
|
14150
14193
|
}).el;
|
|
14151
14194
|
}
|
|
14152
14195
|
if (inp.type === "symbol") return this.buildSymbol(id, String(current), emit);
|
|
@@ -14393,10 +14436,6 @@ var IndicatorInputsDialog = class {
|
|
|
14393
14436
|
}
|
|
14394
14437
|
/** Open a themed month calendar under `anchor` — same surface + shadow as the choice list. */
|
|
14395
14438
|
openCalendar(anchor, current, onPick) {
|
|
14396
|
-
const parsed = parseIsoDate(current);
|
|
14397
|
-
let year = parsed?.getFullYear() ?? (/* @__PURE__ */ new Date()).getFullYear();
|
|
14398
|
-
let month = parsed?.getMonth() ?? (/* @__PURE__ */ new Date()).getMonth();
|
|
14399
|
-
const selected = parsed ? isoDate(parsed) : current;
|
|
14400
14439
|
const pop = new Popover({
|
|
14401
14440
|
trigger: anchor,
|
|
14402
14441
|
theme: this.host.theme(),
|
|
@@ -14408,80 +14447,10 @@ var IndicatorInputsDialog = class {
|
|
|
14408
14447
|
this.calendarPop = null;
|
|
14409
14448
|
this.calendarAnchor = null;
|
|
14410
14449
|
},
|
|
14411
|
-
content: (el) => {
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
prev2.type = "button";
|
|
14416
|
-
prev2.className = "vela-ind-cal-nav";
|
|
14417
|
-
prev2.setAttribute("aria-label", "Previous month");
|
|
14418
|
-
prev2.innerHTML = iconAt("chevron-left", 14);
|
|
14419
|
-
const next = document.createElement("button");
|
|
14420
|
-
next.type = "button";
|
|
14421
|
-
next.className = "vela-ind-cal-nav";
|
|
14422
|
-
next.setAttribute("aria-label", "Next month");
|
|
14423
|
-
next.innerHTML = iconAt("chevron-right", 14);
|
|
14424
|
-
const head = document.createElement("div");
|
|
14425
|
-
head.className = "vela-ind-cal-head";
|
|
14426
|
-
head.append(prev2, title, next);
|
|
14427
|
-
const week = document.createElement("div");
|
|
14428
|
-
week.className = "vela-ind-cal-week";
|
|
14429
|
-
for (const d of WEEKDAY_LABELS) {
|
|
14430
|
-
const cell = document.createElement("span");
|
|
14431
|
-
cell.textContent = d;
|
|
14432
|
-
week.appendChild(cell);
|
|
14433
|
-
}
|
|
14434
|
-
const grid = document.createElement("div");
|
|
14435
|
-
grid.className = "vela-ind-cal-grid";
|
|
14436
|
-
const paint = () => {
|
|
14437
|
-
title.textContent = `${MONTH_LABELS[month]} ${year}`;
|
|
14438
|
-
grid.replaceChildren();
|
|
14439
|
-
const first = new Date(year, month, 1);
|
|
14440
|
-
const startPad = first.getDay();
|
|
14441
|
-
const days = new Date(year, month + 1, 0).getDate();
|
|
14442
|
-
const today = isoDate(/* @__PURE__ */ new Date());
|
|
14443
|
-
for (let i = 0; i < startPad; i++) {
|
|
14444
|
-
const blank = document.createElement("span");
|
|
14445
|
-
blank.className = "vela-ind-cal-blank";
|
|
14446
|
-
grid.appendChild(blank);
|
|
14447
|
-
}
|
|
14448
|
-
for (let day = 1; day <= days; day++) {
|
|
14449
|
-
const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
14450
|
-
const b = document.createElement("button");
|
|
14451
|
-
b.type = "button";
|
|
14452
|
-
b.className = "vela-ind-cal-day";
|
|
14453
|
-
b.textContent = String(day);
|
|
14454
|
-
if (iso === selected) b.dataset.checked = "1";
|
|
14455
|
-
if (iso === today) b.dataset.today = "1";
|
|
14456
|
-
b.addEventListener("click", (e) => {
|
|
14457
|
-
e.stopPropagation();
|
|
14458
|
-
pop.hide();
|
|
14459
|
-
onPick(iso);
|
|
14460
|
-
});
|
|
14461
|
-
grid.appendChild(b);
|
|
14462
|
-
}
|
|
14463
|
-
};
|
|
14464
|
-
prev2.addEventListener("click", (e) => {
|
|
14465
|
-
e.stopPropagation();
|
|
14466
|
-
month -= 1;
|
|
14467
|
-
if (month < 0) {
|
|
14468
|
-
month = 11;
|
|
14469
|
-
year -= 1;
|
|
14470
|
-
}
|
|
14471
|
-
paint();
|
|
14472
|
-
});
|
|
14473
|
-
next.addEventListener("click", (e) => {
|
|
14474
|
-
e.stopPropagation();
|
|
14475
|
-
month += 1;
|
|
14476
|
-
if (month > 11) {
|
|
14477
|
-
month = 0;
|
|
14478
|
-
year += 1;
|
|
14479
|
-
}
|
|
14480
|
-
paint();
|
|
14481
|
-
});
|
|
14482
|
-
paint();
|
|
14483
|
-
el.append(head, week, grid);
|
|
14484
|
-
}
|
|
14450
|
+
content: (el) => fillCalendar(el, current, (iso) => {
|
|
14451
|
+
pop.hide();
|
|
14452
|
+
onPick(iso);
|
|
14453
|
+
})
|
|
14485
14454
|
});
|
|
14486
14455
|
this.calendarPop = pop;
|
|
14487
14456
|
this.calendarAnchor = anchor;
|
|
@@ -14590,7 +14559,7 @@ function groupInputs(inputs) {
|
|
|
14590
14559
|
var CALENDAR_SVG = iconAt("calendar", 14);
|
|
14591
14560
|
var CLOCK_SVG = iconAt("clock", 14);
|
|
14592
14561
|
var DIALOG_STYLE_ID2 = "vela-ind-dialog-styles";
|
|
14593
|
-
var DIALOG_STYLE_REV = "
|
|
14562
|
+
var DIALOG_STYLE_REV = "30";
|
|
14594
14563
|
var LEGEND_ICON_PX = 16;
|
|
14595
14564
|
function ensureDialogStyles() {
|
|
14596
14565
|
if (typeof document === "undefined") return;
|
|
@@ -14606,8 +14575,12 @@ function ensureDialogStyles() {
|
|
|
14606
14575
|
.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;}
|
|
14607
14576
|
.vela-ind-combo-chevron:hover{opacity:0.9;}
|
|
14608
14577
|
.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;}
|
|
14578
|
+
.vela-ind-cal [hidden]{display:none !important;}
|
|
14609
14579
|
.vela-ind-cal-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;}
|
|
14610
|
-
.vela-ind-cal-title{flex:1;
|
|
14580
|
+
.vela-ind-cal-title{flex:1;display:flex;align-items:center;justify-content:center;gap:2px;min-width:0;}
|
|
14581
|
+
.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;}
|
|
14582
|
+
.vela-ind-cal-switch:not(:disabled):hover{background:var(--vela-hover);}
|
|
14583
|
+
.vela-ind-cal-switch:disabled{cursor:default;}
|
|
14611
14584
|
.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;}
|
|
14612
14585
|
.vela-ind-cal-nav:hover{background:var(--vela-hover);color:var(--vela-fg-bright);}
|
|
14613
14586
|
.vela-ind-cal-week,.vela-ind-cal-grid{display:grid;grid-template-columns:repeat(7,28px);gap:2px;}
|
|
@@ -14618,6 +14591,12 @@ function ensureDialogStyles() {
|
|
|
14618
14591
|
.vela-ind-cal-day:hover{background:var(--vela-hover);}
|
|
14619
14592
|
.vela-ind-cal-day[data-checked]{background:var(--vela-hover-strong);color:var(--vela-fg-bright);}
|
|
14620
14593
|
.vela-ind-cal-day[data-today]:not([data-checked]){box-shadow:inset 0 0 0 1px var(--vela-border-strong);}
|
|
14594
|
+
.vela-ind-cal-cells{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;width:calc(7 * 28px + 6 * 2px);}
|
|
14595
|
+
.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;}
|
|
14596
|
+
.vela-ind-cal-cell:hover{background:var(--vela-hover);}
|
|
14597
|
+
.vela-ind-cal-cell[data-checked]{background:var(--vela-hover-strong);color:var(--vela-fg-bright);}
|
|
14598
|
+
.vela-ind-cal-cell[data-today]:not([data-checked]){box-shadow:inset 0 0 0 1px var(--vela-border-strong);}
|
|
14599
|
+
.vela-ind-cal-cell[data-outside]{opacity:0.45;}
|
|
14621
14600
|
${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
|
|
14622
14601
|
.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;}
|
|
14623
14602
|
.vela-ind-tab:not(.vela-ind-tab-active):hover{color:var(--vela-fg-bright);}
|
|
@@ -14652,6 +14631,7 @@ var TIME_OPTIONS = Array.from({ length: 48 }, (_, i) => {
|
|
|
14652
14631
|
return { value: v, label: v };
|
|
14653
14632
|
});
|
|
14654
14633
|
var MONTH_LABELS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
14634
|
+
var MONTH_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
14655
14635
|
var WEEKDAY_LABELS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
14656
14636
|
function normalizeDateInput(raw) {
|
|
14657
14637
|
const t = raw.trim();
|
|
@@ -14673,6 +14653,151 @@ function parseIsoDate(raw) {
|
|
|
14673
14653
|
function isoDate(d) {
|
|
14674
14654
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
14675
14655
|
}
|
|
14656
|
+
function fillCalendar(el, current, onPick) {
|
|
14657
|
+
const today = /* @__PURE__ */ new Date();
|
|
14658
|
+
const selected = parseIsoDate(current);
|
|
14659
|
+
let year = selected?.getFullYear() ?? today.getFullYear();
|
|
14660
|
+
let month = selected?.getMonth() ?? today.getMonth();
|
|
14661
|
+
let mode = "date";
|
|
14662
|
+
const prev2 = document.createElement("button");
|
|
14663
|
+
prev2.type = "button";
|
|
14664
|
+
prev2.className = "vela-ind-cal-nav";
|
|
14665
|
+
prev2.innerHTML = iconAt("chevron-left", 14);
|
|
14666
|
+
const next = document.createElement("button");
|
|
14667
|
+
next.type = "button";
|
|
14668
|
+
next.className = "vela-ind-cal-nav";
|
|
14669
|
+
next.innerHTML = iconAt("chevron-right", 14);
|
|
14670
|
+
const monthBtn = document.createElement("button");
|
|
14671
|
+
monthBtn.type = "button";
|
|
14672
|
+
monthBtn.className = "vela-ind-cal-switch";
|
|
14673
|
+
monthBtn.setAttribute("aria-label", "Choose month");
|
|
14674
|
+
const yearBtn = document.createElement("button");
|
|
14675
|
+
yearBtn.type = "button";
|
|
14676
|
+
yearBtn.className = "vela-ind-cal-switch";
|
|
14677
|
+
yearBtn.setAttribute("aria-label", "Choose year");
|
|
14678
|
+
const title = document.createElement("div");
|
|
14679
|
+
title.className = "vela-ind-cal-title";
|
|
14680
|
+
title.append(monthBtn, yearBtn);
|
|
14681
|
+
const head = document.createElement("div");
|
|
14682
|
+
head.className = "vela-ind-cal-head";
|
|
14683
|
+
head.append(prev2, title, next);
|
|
14684
|
+
const week = document.createElement("div");
|
|
14685
|
+
week.className = "vela-ind-cal-week";
|
|
14686
|
+
for (const d of WEEKDAY_LABELS) {
|
|
14687
|
+
const cell = document.createElement("span");
|
|
14688
|
+
cell.textContent = d;
|
|
14689
|
+
week.appendChild(cell);
|
|
14690
|
+
}
|
|
14691
|
+
const grid = document.createElement("div");
|
|
14692
|
+
const paint = () => {
|
|
14693
|
+
const decade = Math.floor(year / 10) * 10;
|
|
14694
|
+
monthBtn.hidden = mode !== "date";
|
|
14695
|
+
monthBtn.textContent = MONTH_LABELS[month] ?? "";
|
|
14696
|
+
yearBtn.textContent = mode === "year" ? `${decade}-${decade + 9}` : String(year);
|
|
14697
|
+
yearBtn.disabled = mode === "year";
|
|
14698
|
+
week.hidden = mode !== "date";
|
|
14699
|
+
prev2.setAttribute("aria-label", mode === "date" ? "Previous month" : mode === "month" ? "Previous year" : "Previous decade");
|
|
14700
|
+
next.setAttribute("aria-label", mode === "date" ? "Next month" : mode === "month" ? "Next year" : "Next decade");
|
|
14701
|
+
grid.className = mode === "date" ? "vela-ind-cal-grid" : "vela-ind-cal-cells";
|
|
14702
|
+
grid.replaceChildren();
|
|
14703
|
+
if (mode === "date") {
|
|
14704
|
+
const startPad = new Date(year, month, 1).getDay();
|
|
14705
|
+
const days = new Date(year, month + 1, 0).getDate();
|
|
14706
|
+
const todayIso = isoDate(today);
|
|
14707
|
+
const selectedIso = selected ? isoDate(selected) : "";
|
|
14708
|
+
for (let i = 0; i < startPad; i++) {
|
|
14709
|
+
const blank = document.createElement("span");
|
|
14710
|
+
blank.className = "vela-ind-cal-blank";
|
|
14711
|
+
grid.appendChild(blank);
|
|
14712
|
+
}
|
|
14713
|
+
for (let day = 1; day <= days; day++) {
|
|
14714
|
+
const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
14715
|
+
const b = document.createElement("button");
|
|
14716
|
+
b.type = "button";
|
|
14717
|
+
b.className = "vela-ind-cal-day";
|
|
14718
|
+
b.textContent = String(day);
|
|
14719
|
+
if (iso === selectedIso) b.dataset.checked = "1";
|
|
14720
|
+
if (iso === todayIso) b.dataset.today = "1";
|
|
14721
|
+
b.addEventListener("click", (e) => {
|
|
14722
|
+
e.stopPropagation();
|
|
14723
|
+
onPick(iso);
|
|
14724
|
+
});
|
|
14725
|
+
grid.appendChild(b);
|
|
14726
|
+
}
|
|
14727
|
+
return;
|
|
14728
|
+
}
|
|
14729
|
+
if (mode === "month") {
|
|
14730
|
+
for (let m = 0; m < 12; m++) {
|
|
14731
|
+
const b = document.createElement("button");
|
|
14732
|
+
b.type = "button";
|
|
14733
|
+
b.className = "vela-ind-cal-cell";
|
|
14734
|
+
b.textContent = MONTH_SHORT[m] ?? "";
|
|
14735
|
+
if (selected?.getFullYear() === year && selected.getMonth() === m) b.dataset.checked = "1";
|
|
14736
|
+
if (today.getFullYear() === year && today.getMonth() === m) b.dataset.today = "1";
|
|
14737
|
+
b.addEventListener("click", (e) => {
|
|
14738
|
+
e.stopPropagation();
|
|
14739
|
+
month = m;
|
|
14740
|
+
mode = "date";
|
|
14741
|
+
paint();
|
|
14742
|
+
});
|
|
14743
|
+
grid.appendChild(b);
|
|
14744
|
+
}
|
|
14745
|
+
return;
|
|
14746
|
+
}
|
|
14747
|
+
for (let y = decade - 1; y <= decade + 10; y++) {
|
|
14748
|
+
const b = document.createElement("button");
|
|
14749
|
+
b.type = "button";
|
|
14750
|
+
b.className = "vela-ind-cal-cell";
|
|
14751
|
+
b.textContent = String(y);
|
|
14752
|
+
if (y < decade || y > decade + 9) b.dataset.outside = "1";
|
|
14753
|
+
if (selected?.getFullYear() === y) b.dataset.checked = "1";
|
|
14754
|
+
if (today.getFullYear() === y) b.dataset.today = "1";
|
|
14755
|
+
b.addEventListener("click", (e) => {
|
|
14756
|
+
e.stopPropagation();
|
|
14757
|
+
year = y;
|
|
14758
|
+
mode = "month";
|
|
14759
|
+
paint();
|
|
14760
|
+
});
|
|
14761
|
+
grid.appendChild(b);
|
|
14762
|
+
}
|
|
14763
|
+
};
|
|
14764
|
+
const step = (dir) => {
|
|
14765
|
+
if (mode === "date") {
|
|
14766
|
+
month += dir;
|
|
14767
|
+
if (month < 0) {
|
|
14768
|
+
month = 11;
|
|
14769
|
+
year -= 1;
|
|
14770
|
+
}
|
|
14771
|
+
if (month > 11) {
|
|
14772
|
+
month = 0;
|
|
14773
|
+
year += 1;
|
|
14774
|
+
}
|
|
14775
|
+
} else {
|
|
14776
|
+
year += mode === "month" ? dir : dir * 10;
|
|
14777
|
+
}
|
|
14778
|
+
paint();
|
|
14779
|
+
};
|
|
14780
|
+
prev2.addEventListener("click", (e) => {
|
|
14781
|
+
e.stopPropagation();
|
|
14782
|
+
step(-1);
|
|
14783
|
+
});
|
|
14784
|
+
next.addEventListener("click", (e) => {
|
|
14785
|
+
e.stopPropagation();
|
|
14786
|
+
step(1);
|
|
14787
|
+
});
|
|
14788
|
+
monthBtn.addEventListener("click", (e) => {
|
|
14789
|
+
e.stopPropagation();
|
|
14790
|
+
mode = "month";
|
|
14791
|
+
paint();
|
|
14792
|
+
});
|
|
14793
|
+
yearBtn.addEventListener("click", (e) => {
|
|
14794
|
+
e.stopPropagation();
|
|
14795
|
+
mode = "year";
|
|
14796
|
+
paint();
|
|
14797
|
+
});
|
|
14798
|
+
paint();
|
|
14799
|
+
el.append(head, week, grid);
|
|
14800
|
+
}
|
|
14676
14801
|
function normalizeTimeInput(raw) {
|
|
14677
14802
|
const t = raw.trim();
|
|
14678
14803
|
const m = /^(\d{1,2}):(\d{2})$/.exec(t) ?? /^(\d{2})(\d{2})$/.exec(t);
|
|
@@ -15954,10 +16079,12 @@ var BASELINE_LEVEL_DEFAULT = 50;
|
|
|
15954
16079
|
var PREMARKET_SHADE = withAlpha(WARNING, 0.08);
|
|
15955
16080
|
var POSTMARKET_SHADE = withAlpha(ACCENT, 0.08);
|
|
15956
16081
|
var EXTENDED_SHADE = POSTMARKET_SHADE;
|
|
16082
|
+
var DEFAULT_MARGINS = { top: 10, bottom: 10, right: 10 };
|
|
15957
16083
|
function defaultChartStyle() {
|
|
15958
16084
|
return {
|
|
15959
16085
|
chartTypes: {},
|
|
15960
16086
|
fontSize: 11,
|
|
16087
|
+
margins: { ...DEFAULT_MARGINS },
|
|
15961
16088
|
gridVert: { visible: true, color: null },
|
|
15962
16089
|
gridHorz: { visible: true, color: null },
|
|
15963
16090
|
borderColor: null,
|
|
@@ -16081,6 +16208,12 @@ function clampLevel(v) {
|
|
|
16081
16208
|
function clampSpacing(v) {
|
|
16082
16209
|
return v < 0.1 ? 0.1 : v > 10 ? 10 : v;
|
|
16083
16210
|
}
|
|
16211
|
+
function clampMarginPct(v) {
|
|
16212
|
+
return v < 0 ? 0 : v > 40 ? 40 : v;
|
|
16213
|
+
}
|
|
16214
|
+
function clampMarginBars(v) {
|
|
16215
|
+
return Math.round(v < 0 ? 0 : v > 200 ? 200 : v);
|
|
16216
|
+
}
|
|
16084
16217
|
function factoryResetConfig(factory, priceStyle = factory.series.style) {
|
|
16085
16218
|
const bag = {};
|
|
16086
16219
|
for (const t of chartTypes()) {
|
|
@@ -16129,6 +16262,7 @@ function mergeConfig(base, patch) {
|
|
|
16129
16262
|
const ps = asObject(p.priceScale);
|
|
16130
16263
|
const anim = asObject(p.animations);
|
|
16131
16264
|
const panes = asObject(p.panes);
|
|
16265
|
+
const margins = asObject(p.margins);
|
|
16132
16266
|
const trades = asObject(p.trades);
|
|
16133
16267
|
const ts = asObject(p.timeScale);
|
|
16134
16268
|
const marks = asObject(p.marks);
|
|
@@ -16188,6 +16322,11 @@ function mergeConfig(base, patch) {
|
|
|
16188
16322
|
panes: {
|
|
16189
16323
|
separatorColor: isColor(panes.separatorColor) ? panes.separatorColor : base.panes.separatorColor
|
|
16190
16324
|
},
|
|
16325
|
+
margins: {
|
|
16326
|
+
top: isNum(margins.top) ? clampMarginPct(margins.top) : base.margins.top,
|
|
16327
|
+
bottom: isNum(margins.bottom) ? clampMarginPct(margins.bottom) : base.margins.bottom,
|
|
16328
|
+
right: isNum(margins.right) ? clampMarginBars(margins.right) : base.margins.right
|
|
16329
|
+
},
|
|
16191
16330
|
trades: {
|
|
16192
16331
|
visible: isBool(trades.visible) ? trades.visible : base.trades.visible,
|
|
16193
16332
|
labels: isBool(trades.labels) ? trades.labels : base.trades.labels,
|
|
@@ -21558,6 +21697,10 @@ var BUILTIN_SETTINGS_IDS = [
|
|
|
21558
21697
|
"canvas.grid",
|
|
21559
21698
|
"canvas.grid.vertical",
|
|
21560
21699
|
"canvas.grid.horizontal",
|
|
21700
|
+
"canvas.margins",
|
|
21701
|
+
"canvas.margins.top",
|
|
21702
|
+
"canvas.margins.bottom",
|
|
21703
|
+
"canvas.margins.right",
|
|
21561
21704
|
"canvas.theme"
|
|
21562
21705
|
];
|
|
21563
21706
|
function settingsIdCatalog(hostSections, markGroups = []) {
|
|
@@ -22088,6 +22231,10 @@ var SettingsDialog = class {
|
|
|
22088
22231
|
body.append(sid(this.toggleRow("Horizontal", config.grid.horzLines.visible, (v) => this.emit({ grid: { horzLines: { visible: v } } }), [
|
|
22089
22232
|
this.swatch(config.grid.horzLines.color, (v) => this.emit({ grid: { horzLines: { color: v } } }))
|
|
22090
22233
|
]), "canvas.grid.horizontal"));
|
|
22234
|
+
body.append(sid(this.sectionTitle("Margins"), "canvas.margins"));
|
|
22235
|
+
body.append(sid(this.numberRow("Top", config.margins.top, 0, 40, 1, (v) => this.emit({ margins: { top: v } }), "%"), "canvas.margins.top"));
|
|
22236
|
+
body.append(sid(this.numberRow("Bottom", config.margins.bottom, 0, 40, 1, (v) => this.emit({ margins: { bottom: v } }), "%"), "canvas.margins.bottom"));
|
|
22237
|
+
body.append(sid(this.numberRow("Right", config.margins.right, 0, 200, 1, (v) => this.emit({ margins: { right: v } }), "bars"), "canvas.margins.right"));
|
|
22091
22238
|
if (this.themeControl) {
|
|
22092
22239
|
const tc = this.themeControl;
|
|
22093
22240
|
body.append(sid(this.sectionTitle("Theme"), "canvas.theme"));
|
|
@@ -22659,23 +22806,16 @@ var SettingsDialog = class {
|
|
|
22659
22806
|
this.hintTips.push(dispose);
|
|
22660
22807
|
return el;
|
|
22661
22808
|
}
|
|
22662
|
-
|
|
22663
|
-
|
|
22664
|
-
|
|
22665
|
-
|
|
22666
|
-
|
|
22667
|
-
|
|
22668
|
-
|
|
22669
|
-
|
|
22670
|
-
|
|
22671
|
-
|
|
22672
|
-
step,
|
|
22673
|
-
fill: false,
|
|
22674
|
-
commit: "live",
|
|
22675
|
-
steppers: true,
|
|
22676
|
-
onChange
|
|
22677
|
-
}).el
|
|
22678
|
-
});
|
|
22809
|
+
/** `unit` (optional) trails the input as muted text — "%", "bars". */
|
|
22810
|
+
numberRow(label, value, min, max, step, onChange, unit) {
|
|
22811
|
+
const controls = [buildFieldControl({ kind: "number", value, min, max, step, fill: false, commit: "live", steppers: true, onChange }).el];
|
|
22812
|
+
if (unit) {
|
|
22813
|
+
const u = document.createElement("span");
|
|
22814
|
+
u.textContent = unit;
|
|
22815
|
+
u.style.cssText = "color:var(--vela-fg-muted);";
|
|
22816
|
+
controls.push(u);
|
|
22817
|
+
}
|
|
22818
|
+
return this.rowWith(label, controls);
|
|
22679
22819
|
}
|
|
22680
22820
|
/** A dropdown whose option values differ from their display labels. */
|
|
22681
22821
|
selectRowLabeled(label, value, options, onChange) {
|
|
@@ -28194,9 +28334,7 @@ function createProjector(coords, paneOf, paneIdAtY, barsInRange, seriesInRange)
|
|
|
28194
28334
|
}
|
|
28195
28335
|
|
|
28196
28336
|
// src/renderers/native/core/autoscale.ts
|
|
28197
|
-
|
|
28198
|
-
var MARGIN_BOTTOM = 1 / 7;
|
|
28199
|
-
function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log = false, offsetOf = () => 0) {
|
|
28337
|
+
function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log = false, offsetOf = () => 0, margins = DEFAULT_MARGINS) {
|
|
28200
28338
|
let min = Infinity;
|
|
28201
28339
|
let max = -Infinity;
|
|
28202
28340
|
const consider = (v) => {
|
|
@@ -28231,14 +28369,17 @@ function computePaneScale(models, bars, includeCandles, i0, i1, drawings, log =
|
|
|
28231
28369
|
const pad = Math.abs(min) * 0.1 || 1;
|
|
28232
28370
|
return { min: min - pad, max: max + pad, log: log && min - pad > 0 };
|
|
28233
28371
|
}
|
|
28372
|
+
const content = Math.max(0.1, 1 - (margins.top + margins.bottom) / 100);
|
|
28373
|
+
const above = margins.top / 100 / content;
|
|
28374
|
+
const below = margins.bottom / 100 / content;
|
|
28234
28375
|
if (log && min > 0) {
|
|
28235
28376
|
const lmin = Math.log(min);
|
|
28236
28377
|
const lmax = Math.log(max);
|
|
28237
28378
|
const lspan = lmax - lmin;
|
|
28238
|
-
return { min: Math.exp(lmin - lspan *
|
|
28379
|
+
return { min: Math.exp(lmin - lspan * below), max: Math.exp(lmax + lspan * above), log: true };
|
|
28239
28380
|
}
|
|
28240
28381
|
const span = max - min;
|
|
28241
|
-
return { min: min - span *
|
|
28382
|
+
return { min: min - span * below, max: max + span * above };
|
|
28242
28383
|
}
|
|
28243
28384
|
function considerSeries(s, i0, i1, off, consider) {
|
|
28244
28385
|
if (!seriesInScale(s)) return;
|
|
@@ -30065,6 +30206,7 @@ var NativeRenderer = class {
|
|
|
30065
30206
|
intro: this.intro.style !== false
|
|
30066
30207
|
},
|
|
30067
30208
|
panes: { separatorColor: s.separatorColor ?? t.borderColor },
|
|
30209
|
+
margins: { ...s.margins },
|
|
30068
30210
|
trades: {
|
|
30069
30211
|
visible: this.scene.tradeMarkers.visible,
|
|
30070
30212
|
labels: this.scene.tradeMarkers.labels,
|
|
@@ -30177,6 +30319,10 @@ var NativeRenderer = class {
|
|
|
30177
30319
|
this.animAutoscale.toggle(next.animations.autoscale);
|
|
30178
30320
|
this.intro = { style: next.animations.intro ? this.introOnStyle : false, duration: this.intro.duration || INTRO_DURATION_DEFAULT_MS };
|
|
30179
30321
|
s.separatorColor = keepInherit(s.separatorColor, next.panes.separatorColor, prevTheme.borderColor);
|
|
30322
|
+
if (next.margins.right !== s.margins.right && this.coords.barCount > 0) {
|
|
30323
|
+
this.applyViewport({ barSpacing: this.coords.getViewport().barSpacing, rightOffset: next.margins.right });
|
|
30324
|
+
}
|
|
30325
|
+
s.margins = { ...next.margins };
|
|
30180
30326
|
this.scene.tradeMarkers = {
|
|
30181
30327
|
visible: next.trades.visible,
|
|
30182
30328
|
labels: next.trades.labels,
|
|
@@ -30420,7 +30566,7 @@ var NativeRenderer = class {
|
|
|
30420
30566
|
/** Glide the view back to the most recent bars, keeping the current zoom (barSpacing). */
|
|
30421
30567
|
scrollToRealtime() {
|
|
30422
30568
|
if (this.coords.barCount === 0) return;
|
|
30423
|
-
this.glideRightOffset(
|
|
30569
|
+
this.glideRightOffset(this.scene.style.margins.right);
|
|
30424
30570
|
}
|
|
30425
30571
|
/** Ease rightOffset to `target` at constant zoom (see animTick's scroll glide);
|
|
30426
30572
|
* instant when the scroll glide is off. Shared by scroll-to-latest and panBy. */
|
|
@@ -32362,6 +32508,7 @@ var NativeRenderer = class {
|
|
|
32362
32508
|
const pricePane = panes.find((p) => p.kind === "price") ?? null;
|
|
32363
32509
|
this.chrome.prepare(this.scene, this.coords, this.theme);
|
|
32364
32510
|
const animating = this.animator.active;
|
|
32511
|
+
const margins = this.scene.style.margins;
|
|
32365
32512
|
for (const pane of panes) {
|
|
32366
32513
|
if (pane.manualScale) {
|
|
32367
32514
|
pane.scaleTarget = pane.manualScale;
|
|
@@ -32377,7 +32524,7 @@ var NativeRenderer = class {
|
|
|
32377
32524
|
if (or) dr = dr ? { min: Math.min(dr.min, or.min), max: Math.max(dr.max, or.max) } : or;
|
|
32378
32525
|
}
|
|
32379
32526
|
const includeCandles = pane.kind === "price" && (!this.scene.candlesHidden || this.priceLayersAnchoredToBars(masterModels) || !this.paneHasMeasurableContent(masterModels, dr));
|
|
32380
|
-
pane.scaleTarget = computePaneScale(masterModels, this.bars, includeCandles, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id));
|
|
32527
|
+
pane.scaleTarget = computePaneScale(masterModels, this.bars, includeCandles, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id), margins);
|
|
32381
32528
|
pane.percentBaseline = pane.kind === "price" ? this.bars[i0]?.close ?? 0 : this.firstVisibleValue(masterModels, i0);
|
|
32382
32529
|
pane.axisFormat = void 0;
|
|
32383
32530
|
pane.axisBands = void 0;
|
|
@@ -32388,7 +32535,7 @@ var NativeRenderer = class {
|
|
|
32388
32535
|
pane.axisFormat = "volume";
|
|
32389
32536
|
}
|
|
32390
32537
|
} else if (this.layerNativesOwnPane(pane, masterModels)) {
|
|
32391
|
-
pane.scaleTarget = computePaneScale([], this.bars, true, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id));
|
|
32538
|
+
pane.scaleTarget = computePaneScale([], this.bars, true, i0, i1, dr, paneLogScale(this.scene, pane), (id) => this.scene.offsetOf(id), margins);
|
|
32392
32539
|
pane.percentBaseline = this.bars[i0]?.close ?? 0;
|
|
32393
32540
|
if (masterModels.every((m) => m.paneAxis != null)) {
|
|
32394
32541
|
pane.axisFormat = "none";
|
|
@@ -32417,7 +32564,7 @@ var NativeRenderer = class {
|
|
|
32417
32564
|
continue;
|
|
32418
32565
|
}
|
|
32419
32566
|
const mdr = this.chrome.paneDrawingsRange([model], this.scene, false, vr);
|
|
32420
|
-
sl.scaleTarget = computePaneScale([model], this.bars, false, i0, i1, mdr, false, (id) => this.scene.offsetOf(id));
|
|
32567
|
+
sl.scaleTarget = computePaneScale([model], this.bars, false, i0, i1, mdr, false, (id) => this.scene.offsetOf(id), margins);
|
|
32421
32568
|
if (!animating || !sl.initialized) {
|
|
32422
32569
|
sl.scale = { ...sl.scaleTarget };
|
|
32423
32570
|
sl.initialized = true;
|
|
@@ -32458,13 +32605,13 @@ var NativeRenderer = class {
|
|
|
32458
32605
|
for (const pane of this.scene.panes.values()) pane.manualScale = null;
|
|
32459
32606
|
for (const sl of this.scene.indicatorScales.values()) sl.manualScale = null;
|
|
32460
32607
|
const visibleBars = Math.min(n, 200);
|
|
32461
|
-
const rightOffset =
|
|
32608
|
+
const rightOffset = this.scene.style.margins.right;
|
|
32462
32609
|
const v = this.clampViewport(w / ((visibleBars + rightOffset) * this.coords.spacingScale), rightOffset);
|
|
32463
32610
|
this.coords.setViewport(v);
|
|
32464
32611
|
this.targetBarSpacing = v.barSpacing;
|
|
32465
32612
|
}
|
|
32466
32613
|
/** Re-frame after a series replacement (a symbol/timeframe switch): keep the user's
|
|
32467
|
-
* zoom (bar spacing), re-anchor the newest bars at the
|
|
32614
|
+
* zoom (bar spacing), re-anchor the newest bars at the configured right margin.
|
|
32468
32615
|
* `clampViewport`'s fit-all-bars floor deliberately does NOT apply — a progressive
|
|
32469
32616
|
* head may still be backfilling toward the previous depth, and raising the spacing
|
|
32470
32617
|
* to its temporary bar count would lose the zoom this exists to keep. */
|
|
@@ -32473,7 +32620,7 @@ var NativeRenderer = class {
|
|
|
32473
32620
|
this.panVelocity = 0;
|
|
32474
32621
|
for (const pane of this.scene.panes.values()) pane.manualScale = null;
|
|
32475
32622
|
for (const sl of this.scene.indicatorScales.values()) sl.manualScale = null;
|
|
32476
|
-
const v = { barSpacing: clampBarSpacing(this.coords.getViewport().barSpacing), rightOffset:
|
|
32623
|
+
const v = { barSpacing: clampBarSpacing(this.coords.getViewport().barSpacing), rightOffset: this.scene.style.margins.right };
|
|
32477
32624
|
this.coords.setViewport(v);
|
|
32478
32625
|
this.targetBarSpacing = v.barSpacing;
|
|
32479
32626
|
}
|
|
@@ -35587,6 +35734,7 @@ function registerClassicIndicators() {
|
|
|
35587
35734
|
}
|
|
35588
35735
|
|
|
35589
35736
|
// src/Vela.ts
|
|
35737
|
+
var asError = (err) => err instanceof Error ? err : new Error(String(err));
|
|
35590
35738
|
var Vela = class {
|
|
35591
35739
|
constructor(container, options = {}, deps = {}) {
|
|
35592
35740
|
registerBuiltinChartTypes();
|
|
@@ -35710,7 +35858,12 @@ var Vela = class {
|
|
|
35710
35858
|
* fetch from — the same relationship `script:run` has to `context:changed`.
|
|
35711
35859
|
*/
|
|
35712
35860
|
runScript(source, options) {
|
|
35713
|
-
|
|
35861
|
+
let handle;
|
|
35862
|
+
try {
|
|
35863
|
+
handle = this.addIndicator(source, options);
|
|
35864
|
+
} catch (err) {
|
|
35865
|
+
return Promise.resolve({ ok: false, run: null, error: asError(err), onUpdate: () => () => void 0, remove: () => void 0 });
|
|
35866
|
+
}
|
|
35714
35867
|
const updates = /* @__PURE__ */ new Set();
|
|
35715
35868
|
const drop = () => {
|
|
35716
35869
|
try {
|
|
@@ -35754,7 +35907,12 @@ var Vela = class {
|
|
|
35754
35907
|
});
|
|
35755
35908
|
}
|
|
35756
35909
|
runIndicator(source, options) {
|
|
35757
|
-
|
|
35910
|
+
let handle;
|
|
35911
|
+
try {
|
|
35912
|
+
handle = this.addIndicator(source, options);
|
|
35913
|
+
} catch (err) {
|
|
35914
|
+
return Promise.resolve({ ok: false, handle: null, error: asError(err), context: null });
|
|
35915
|
+
}
|
|
35758
35916
|
return new Promise((resolve) => {
|
|
35759
35917
|
const offReady = handle.on("ready", () => {
|
|
35760
35918
|
offReady();
|