@luxalgo/vela 0.6.17 → 0.6.19
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-B-Jz59Rf.d.ts → DataProvider-Cb-2lC5O.d.ts} +1 -1
- package/dist/{DataProvider-OfR3fXg9.d.cts → DataProvider-UtWw2CgJ.d.cts} +1 -1
- package/dist/{chunk-YCD72KGK.js → chunk-22QJKGXX.js} +565 -151
- package/dist/{chunk-OSZDSH7F.js → chunk-627A5HEV.js} +252 -120
- package/dist/{contributions-C3b0Sx5P.d.cts → contributions-5nz3PLRe.d.ts} +9 -4
- package/dist/{contributions-Swzz10fG.d.ts → contributions-DEPRtkmG.d.cts} +9 -4
- package/dist/index.cjs +563 -149
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1 -1
- package/dist/{options-CX1lSYWA.d.cts → options-BCRmYALw.d.cts} +12 -3
- package/dist/{options-CX1lSYWA.d.ts → options-BCRmYALw.d.ts} +12 -3
- package/dist/{plugin-mvddudqd.d.ts → plugin-CUtfLeqz.d.ts} +3 -3
- package/dist/{plugin-BjnEE1zA.d.cts → plugin-DVUaROPo.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-IURCya0H.d.ts → statusline-model-hY9cK4BS.d.cts} +17 -7
- package/dist/{statusline-model-D91cU2fF.d.cts → statusline-model-wW3m4in1.d.ts} +17 -7
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/vela.global.js +563 -149
- package/dist/vela.global.min.js +53 -51
- package/dist/widget.cjs +814 -268
- package/dist/widget.d.cts +39 -12
- package/dist/widget.d.ts +39 -12
- package/dist/widget.js +3 -3
- package/dist/workspace.cjs +814 -268
- package/dist/workspace.d.cts +14 -5
- package/dist/workspace.d.ts +14 -5
- package/dist/workspace.js +2 -2
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel, isGroupRow, defaultMemberOf, groupKeyOf, groupMembers, LEGEND_AT_TOP_ATTR, normalizeSession, Vela, TypedEventBus, MultiProviderFeed, registerBuiltinChartTypes, resolveTheme, buildToolbar, createCustomMark, createAttributionMark, DrawingToolbar, applyAttributionMarkTheme, sharedBarStore, timeframeToMs } from './chunk-
|
|
1
|
+
import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel, isGroupRow, defaultMemberOf, groupKeyOf, groupMembers, LEGEND_AT_TOP_ATTR, normalizeSession, Vela, TypedEventBus, MultiProviderFeed, registerBuiltinChartTypes, resolveTheme, buildToolbar, createCustomMark, createAttributionMark, DrawingToolbar, applyAttributionMarkTheme, sharedBarStore, timeframeToMs } from './chunk-22QJKGXX.js';
|
|
2
2
|
import { chartType, resolveTopbarComposition, topbarActionOverride, TOPBAR_BUILTIN_IDS, widgetActions, SidePanel, sidePanels, DEFAULT_PANEL_ORDER, symbolRanking, resolveEngines, legendActionsProviderFor, legendCalloutsProviderFor, statePersistenceHandlers, topbarHas, rendererDefaults, widgetAttachments, getDrawingType, inputDeltas } from './chunk-IFJJPXSV.js';
|
|
3
3
|
import { Tooltip, KeymapManager, isEditableTarget, Drawer } from './chunk-XCBJU674.js';
|
|
4
4
|
import { Menu, Dialog, CalloutBubble, applyPlotOverlayTokens, ensureUIHost } from './chunk-T5Z5YUCF.js';
|
|
@@ -1263,6 +1263,9 @@ function paneLabel(pane, fallbackTitle) {
|
|
|
1263
1263
|
function indicatorLabel(i, fallbackTitle) {
|
|
1264
1264
|
return i.title || fallbackTitle(i.id) || i.id;
|
|
1265
1265
|
}
|
|
1266
|
+
function indicatorRowLabel(i, fallbackTitle) {
|
|
1267
|
+
return i.shorttitle || indicatorLabel(i, fallbackTitle);
|
|
1268
|
+
}
|
|
1266
1269
|
function paneRows(pane) {
|
|
1267
1270
|
return pane.items.flatMap((it) => it.kind === "row" ? [it.row] : []);
|
|
1268
1271
|
}
|
|
@@ -1394,7 +1397,7 @@ function paneItems(snap, pane, units) {
|
|
|
1394
1397
|
const indicatorRow = (i) => ({
|
|
1395
1398
|
kind: "indicator",
|
|
1396
1399
|
id: i.id,
|
|
1397
|
-
label:
|
|
1400
|
+
label: indicatorRowLabel(i, snap.handleTitle),
|
|
1398
1401
|
visible: snap.indicatorVisible(i.id),
|
|
1399
1402
|
ownScale: i.ownScale
|
|
1400
1403
|
});
|
|
@@ -1524,9 +1527,13 @@ var CSS4 = `
|
|
|
1524
1527
|
.vela-ot-empty { padding: 20px 10px; text-align: center; color: var(--vela-fg-muted); font-size: 12px; }
|
|
1525
1528
|
|
|
1526
1529
|
/* \u2500\u2500 drawing groups \u2500\u2500 */
|
|
1527
|
-
/* One top-level entry in a pane's drawing list: a lone drawing, or a whole group block.
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
+
/* One top-level entry in a pane's drawing list: a lone drawing, or a whole group block. No
|
|
1531
|
+
border of its own \u2014 units stack flush, so consecutive highlighted rows read as one block; the
|
|
1532
|
+
drop-into-group outline is drawn inside the box instead (see the drag-and-drop rules). */
|
|
1533
|
+
.vela-ot-unit { border-radius: 6px; }
|
|
1534
|
+
/* Adjacent picked rows merge into one contiguous highlight: the shared edge loses its rounding. */
|
|
1535
|
+
.vela-ot-unit:has(> .vela-ot-row[data-picked]) + .vela-ot-unit > .vela-ot-row[data-picked] { border-top-left-radius: 0; border-top-right-radius: 0; }
|
|
1536
|
+
.vela-ot-unit:has(+ .vela-ot-unit > .vela-ot-row[data-picked]) > .vela-ot-row[data-picked] { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
|
|
1530
1537
|
.vela-ot-row[data-row-kind='group'] > .vela-icon { width: 12px; font-size: 11px; }
|
|
1531
1538
|
/* A member sits indented under its group's header. */
|
|
1532
1539
|
.vela-ot-subrow { padding-left: 26px; }
|
|
@@ -1583,8 +1590,10 @@ var CSS4 = `
|
|
|
1583
1590
|
.vela-ot-gap[data-drop] { height: 4px; background: var(--vela-fg-bright); }
|
|
1584
1591
|
.vela-ot-gap[data-drop]::before { display: none; }
|
|
1585
1592
|
/* A whole container accepts the drop: merging into a pane, or a pane with no drawings yet.
|
|
1586
|
-
The pane block's transparent border reserves the room for this outline
|
|
1593
|
+
The pane block's transparent border reserves the room for this outline; a group unit has no
|
|
1594
|
+
border to color, so it draws the same line as an inset outline (no layout footprint). */
|
|
1587
1595
|
.vela-ot [data-drop='target'] { border-color: var(--vela-fg-bright); background: var(--vela-hover); }
|
|
1596
|
+
.vela-ot-unit[data-drop='target'] { outline: 1px solid var(--vela-fg-bright); outline-offset: -1px; }
|
|
1588
1597
|
/* Where a reorder would insert. */
|
|
1589
1598
|
.vela-ot [data-drop='before'] { box-shadow: inset 0 2px 0 var(--vela-fg-bright); }
|
|
1590
1599
|
.vela-ot [data-drop='after'] { box-shadow: inset 0 -2px 0 var(--vela-fg-bright); }
|
|
@@ -1647,7 +1656,8 @@ var ObjectTree = class extends SidePanel {
|
|
|
1647
1656
|
super(host, "Object tree", "vela-ot");
|
|
1648
1657
|
this.iconFor = iconFor;
|
|
1649
1658
|
this.chart = null;
|
|
1650
|
-
|
|
1659
|
+
/** What the CHART has selected — every member of a multi-selection, mirrored as rows. */
|
|
1660
|
+
this.selectedDrawings = /* @__PURE__ */ new Set();
|
|
1651
1661
|
this.symbolName = "";
|
|
1652
1662
|
/** The raw (possibly venue-prefixed) symbol — what icon resolution routes on. */
|
|
1653
1663
|
this.symbolRaw = "";
|
|
@@ -1698,12 +1708,9 @@ var ObjectTree = class extends SidePanel {
|
|
|
1698
1708
|
this.unsubs.push(chart.on(ev, () => this.refresh()));
|
|
1699
1709
|
}
|
|
1700
1710
|
this.unsubs.push(
|
|
1701
|
-
chart.on("drawing:selected", ({
|
|
1702
|
-
this.
|
|
1703
|
-
if (!this.syncingSelection)
|
|
1704
|
-
this.picked.clear();
|
|
1705
|
-
if (id) this.picked.add(id);
|
|
1706
|
-
}
|
|
1711
|
+
chart.on("drawing:selected", ({ ids }) => {
|
|
1712
|
+
this.selectedDrawings = new Set(ids);
|
|
1713
|
+
if (!this.syncingSelection) this.picked = new Set(ids);
|
|
1707
1714
|
this.refresh();
|
|
1708
1715
|
})
|
|
1709
1716
|
);
|
|
@@ -2051,7 +2058,7 @@ var ObjectTree = class extends SidePanel {
|
|
|
2051
2058
|
el.dataset.drag = "1";
|
|
2052
2059
|
el.title = "Drag to restack, or onto another pane to move it there";
|
|
2053
2060
|
if (inGroup) el.classList.add("vela-ot-subrow");
|
|
2054
|
-
if (d.id
|
|
2061
|
+
if (this.selectedDrawings.has(d.id)) el.dataset.selected = "1";
|
|
2055
2062
|
if (this.picked.has(d.id)) el.dataset.picked = "1";
|
|
2056
2063
|
el.addEventListener("click", (e) => this.onDrawClick(e, d.id));
|
|
2057
2064
|
return el;
|
|
@@ -3228,6 +3235,20 @@ var SymbolPicker = class {
|
|
|
3228
3235
|
this.seed = initialQuery;
|
|
3229
3236
|
this.dialog.show();
|
|
3230
3237
|
}
|
|
3238
|
+
get isOpen() {
|
|
3239
|
+
return this.dialog.open;
|
|
3240
|
+
}
|
|
3241
|
+
/** Text typed at the picker that never reached its field: closed, it opens seeded
|
|
3242
|
+
* with the text; open (the field takes focus a tick after the dialog does, and a
|
|
3243
|
+
* fast typist's next key lands in that tick), it extends the query. */
|
|
3244
|
+
type(text) {
|
|
3245
|
+
if (!this.isOpen) {
|
|
3246
|
+
this.open(text);
|
|
3247
|
+
return;
|
|
3248
|
+
}
|
|
3249
|
+
this.input.value = (this.input.value + text).toUpperCase();
|
|
3250
|
+
this.refresh();
|
|
3251
|
+
}
|
|
3231
3252
|
close() {
|
|
3232
3253
|
this.dialog.hide();
|
|
3233
3254
|
}
|
|
@@ -3641,6 +3662,20 @@ var TimeframeQuick = class {
|
|
|
3641
3662
|
this.input.setSelectionRange(this.input.value.length, this.input.value.length);
|
|
3642
3663
|
}, 0);
|
|
3643
3664
|
}
|
|
3665
|
+
get isOpen() {
|
|
3666
|
+
return this.dialog.open;
|
|
3667
|
+
}
|
|
3668
|
+
/** Text typed at the entry that never reached its field: closed, it opens seeded
|
|
3669
|
+
* with the text; open (the field takes focus a tick after the dialog does, and a
|
|
3670
|
+
* fast typist's next key lands in that tick), it extends the entry. */
|
|
3671
|
+
type(text) {
|
|
3672
|
+
if (!this.isOpen) {
|
|
3673
|
+
this.open(text);
|
|
3674
|
+
return;
|
|
3675
|
+
}
|
|
3676
|
+
this.input.value += text;
|
|
3677
|
+
this.renderHint();
|
|
3678
|
+
}
|
|
3644
3679
|
close() {
|
|
3645
3680
|
this.dialog.hide();
|
|
3646
3681
|
}
|
|
@@ -3800,9 +3835,10 @@ async function resolveIndicators(config, fetchImpl = fetch) {
|
|
|
3800
3835
|
return out;
|
|
3801
3836
|
}
|
|
3802
3837
|
var ledgerEntryName = (e) => typeof e === "string" ? e : e.name;
|
|
3838
|
+
var ledgerNativeType = (e) => typeof e === "string" ? e : e.type;
|
|
3803
3839
|
function indicatorLedger(i) {
|
|
3804
3840
|
const natives = [...i.present];
|
|
3805
|
-
if (i.volumePending && !natives.
|
|
3841
|
+
if (i.volumePending && !natives.some((e) => ledgerNativeType(e) === "volume")) natives.push("volume");
|
|
3806
3842
|
return {
|
|
3807
3843
|
manifest: i.manifestSettled ? [...i.instanceEntries] : [...i.pendingManifest ?? i.instanceEntries],
|
|
3808
3844
|
natives
|
|
@@ -3886,18 +3922,28 @@ function sanitizeCell(raw) {
|
|
|
3886
3922
|
if (c.drawings != null && typeof c.drawings === "object") out.drawings = c.drawings;
|
|
3887
3923
|
const ind = c.indicators;
|
|
3888
3924
|
if (ind != null && typeof ind === "object") {
|
|
3925
|
+
const bag = (v) => v != null && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
3889
3926
|
const manifest = Array.isArray(ind.manifest) ? ind.manifest.flatMap((n) => {
|
|
3890
3927
|
if (typeof n === "string") return [n];
|
|
3891
3928
|
if (n != null && typeof n === "object" && typeof n.name === "string") {
|
|
3892
3929
|
const e = n;
|
|
3893
|
-
const bag = (v) => v != null && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
3894
3930
|
const inputs = bag(e.inputs);
|
|
3895
3931
|
const props = bag(e.props);
|
|
3896
|
-
|
|
3932
|
+
const hidden = e.hidden === true;
|
|
3933
|
+
return [inputs || props || hidden ? { name: e.name, ...inputs ? { inputs } : {}, ...props ? { props } : {}, ...hidden ? { hidden } : {} } : e.name];
|
|
3934
|
+
}
|
|
3935
|
+
return [];
|
|
3936
|
+
}) : [];
|
|
3937
|
+
const natives = Array.isArray(ind.natives) ? ind.natives.flatMap((n) => {
|
|
3938
|
+
if (typeof n === "string") return [n];
|
|
3939
|
+
if (n != null && typeof n === "object" && typeof n.type === "string") {
|
|
3940
|
+
const e = n;
|
|
3941
|
+
const inputs = bag(e.inputs);
|
|
3942
|
+
const hidden = e.hidden === true;
|
|
3943
|
+
return [inputs || hidden ? { type: e.type, ...inputs ? { inputs } : {}, ...hidden ? { hidden } : {} } : e.type];
|
|
3897
3944
|
}
|
|
3898
3945
|
return [];
|
|
3899
3946
|
}) : [];
|
|
3900
|
-
const natives = Array.isArray(ind.natives) ? ind.natives.filter((n) => typeof n === "string") : [];
|
|
3901
3947
|
out.indicators = { manifest, natives };
|
|
3902
3948
|
}
|
|
3903
3949
|
const ext = sanitizeExt(c.ext);
|
|
@@ -4033,11 +4079,34 @@ function fmtChange(open, close) {
|
|
|
4033
4079
|
const sign = diff >= 0 ? "+" : "";
|
|
4034
4080
|
return `${sign}${fmtPrice(diff, decimalsFor(close))} (${sign}${pct.toFixed(2)}%)`;
|
|
4035
4081
|
}
|
|
4082
|
+
function fmtChangePct(open, close) {
|
|
4083
|
+
if (open == null || close == null || !Number.isFinite(open) || !Number.isFinite(close) || open === 0) return "";
|
|
4084
|
+
const pct = (close - open) / open * 100;
|
|
4085
|
+
return `${pct >= 0 ? "+" : ""}${pct.toFixed(2)}%`;
|
|
4086
|
+
}
|
|
4036
4087
|
|
|
4037
4088
|
// src/widget/statusline-model.ts
|
|
4038
4089
|
function segmentVisibility(parts, chartHidden = false) {
|
|
4039
4090
|
return { avatar: parts.logo, symbol: parts.name, meta: parts.name, market: parts.market, ohlc: parts.ohlc && !chartHidden, change: parts.change && !chartHidden, eye: chartHidden };
|
|
4040
4091
|
}
|
|
4092
|
+
var STATUSLINE_LADDER = [
|
|
4093
|
+
{ stacked: false, level: "full" },
|
|
4094
|
+
{ stacked: true, level: "full" },
|
|
4095
|
+
{ stacked: true, level: "compact" },
|
|
4096
|
+
{ stacked: true, level: "minimal" }
|
|
4097
|
+
];
|
|
4098
|
+
function readoutCells(level, readout) {
|
|
4099
|
+
if (readout === "value") return [{ key: "close", label: "" }];
|
|
4100
|
+
if (level === "full") {
|
|
4101
|
+
return [
|
|
4102
|
+
{ key: "open", label: "O" },
|
|
4103
|
+
{ key: "high", label: "H" },
|
|
4104
|
+
{ key: "low", label: "L" },
|
|
4105
|
+
{ key: "close", label: "C" }
|
|
4106
|
+
];
|
|
4107
|
+
}
|
|
4108
|
+
return [{ key: "close", label: level === "compact" ? "C" : "" }];
|
|
4109
|
+
}
|
|
4041
4110
|
function statuslineMenuItems(parts, chartVisible) {
|
|
4042
4111
|
return [
|
|
4043
4112
|
{ id: "part:logo", label: "Symbol logo", checked: parts.logo },
|
|
@@ -4064,6 +4133,11 @@ var CSS10 = `
|
|
|
4064
4133
|
display: flex;
|
|
4065
4134
|
align-items: baseline;
|
|
4066
4135
|
gap: var(--vela-space-2);
|
|
4136
|
+
/* The chip never grows past the plot: fit() measures overflow against this width to
|
|
4137
|
+
* walk the layout ladder (stack, then shed values), so overflow:hidden only guards
|
|
4138
|
+
* the transient between a resize and the next measure. */
|
|
4139
|
+
max-width: calc(100% - var(--vela-toolbar-gutter, 0px) - var(--vela-scale-gutter, 0px) - 24px);
|
|
4140
|
+
overflow: hidden;
|
|
4067
4141
|
color: var(--vela-fg);
|
|
4068
4142
|
font-size: var(--vela-font-size-md);
|
|
4069
4143
|
/* Same chip treatment as the indicator legend rows (InputsUI): a translucent wash of
|
|
@@ -4085,6 +4159,31 @@ var CSS10 = `
|
|
|
4085
4159
|
/* Chart hidden (the price series' eye \u2014 renderer 'candleVisible'): the line dims to
|
|
4086
4160
|
* the same 0.5 wash a hidden indicator's legend row wears. */
|
|
4087
4161
|
.vela-statusline.vela-sl-chart-hidden { opacity: 0.5; }
|
|
4162
|
+
/* Two rows inside the chip \u2014 the identity (logo / symbol / meta / market badge) and the
|
|
4163
|
+
* value readout (O/H/L/C + change, or the show-chart eye). In the widest layout they sit
|
|
4164
|
+
* side by side on one line; the STACKED layouts (fit() decides, see the ladder in
|
|
4165
|
+
* statusline-model) turn the chip into a column so the values drop under the symbol. */
|
|
4166
|
+
.vela-statusline .vela-sl-row {
|
|
4167
|
+
display: flex;
|
|
4168
|
+
align-items: baseline;
|
|
4169
|
+
gap: var(--vela-space-2);
|
|
4170
|
+
white-space: nowrap;
|
|
4171
|
+
}
|
|
4172
|
+
.vela-statusline.vela-sl-stacked {
|
|
4173
|
+
flex-direction: column;
|
|
4174
|
+
align-items: flex-start;
|
|
4175
|
+
/* The same air between the two rows as between the values row and the legend row
|
|
4176
|
+
* that follows the chip (see the stacked legend shift below). */
|
|
4177
|
+
row-gap: var(--vela-space-1);
|
|
4178
|
+
}
|
|
4179
|
+
/* Stacked, the identity row may shrink (the meta carries the ellipsis) \u2014 the values row
|
|
4180
|
+
* never does, so its overflow is what fit() measures to keep descending the ladder. */
|
|
4181
|
+
.vela-statusline.vela-sl-stacked .vela-sl-identity { max-width: 100%; }
|
|
4182
|
+
.vela-statusline.vela-sl-stacked .vela-sl-meta {
|
|
4183
|
+
min-width: 0;
|
|
4184
|
+
overflow: hidden;
|
|
4185
|
+
text-overflow: ellipsis;
|
|
4186
|
+
}
|
|
4088
4187
|
.vela-statusline .vela-sl-avatar {
|
|
4089
4188
|
width: 18px;
|
|
4090
4189
|
height: 18px;
|
|
@@ -4136,59 +4235,13 @@ var CSS10 = `
|
|
|
4136
4235
|
* stylesheet is document-global, so a bare attribute selector here would shift every
|
|
4137
4236
|
* chart on the page, including statusline-less ones. */
|
|
4138
4237
|
.vela-has-statusline [${LEGEND_AT_TOP_ATTR}] { transform: translateY(26px); }
|
|
4139
|
-
/*
|
|
4140
|
-
*
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
*
|
|
4144
|
-
|
|
4145
|
-
[data-layout='mobile'] .vela-statusline {
|
|
4146
|
-
display: grid;
|
|
4147
|
-
grid-template-columns: auto auto minmax(0, auto) auto;
|
|
4148
|
-
justify-content: start;
|
|
4149
|
-
align-items: center;
|
|
4150
|
-
row-gap: 1px;
|
|
4151
|
-
max-width: calc(100% - var(--vela-toolbar-gutter, 0px) - var(--vela-scale-gutter, 0px) - 24px);
|
|
4152
|
-
font-size: var(--vela-font-size-sm);
|
|
4153
|
-
}
|
|
4154
|
-
[data-layout='mobile'] .vela-statusline .vela-sl-symbol {
|
|
4155
|
-
font-size: var(--vela-font-size-md);
|
|
4156
|
-
line-height: 1;
|
|
4157
|
-
}
|
|
4158
|
-
[data-layout='mobile'] .vela-statusline .vela-sl-meta {
|
|
4159
|
-
min-width: 0;
|
|
4160
|
-
overflow: hidden;
|
|
4161
|
-
text-overflow: ellipsis;
|
|
4162
|
-
white-space: nowrap;
|
|
4163
|
-
line-height: 1;
|
|
4164
|
-
}
|
|
4165
|
-
[data-layout='mobile'] .vela-statusline .vela-sl-avatar,
|
|
4166
|
-
[data-layout='mobile'] .vela-statusline .vela-sl-market { align-self: center; }
|
|
4167
|
-
[data-layout='mobile'] .vela-statusline .vela-sl-ohlc { display: none !important; }
|
|
4168
|
-
[data-layout='mobile'] .vela-statusline .vela-sl-change {
|
|
4169
|
-
/* Second row, under the text column \u2014 the avatar keeps the first column. */
|
|
4170
|
-
grid-column: 2 / -1;
|
|
4171
|
-
font-size: var(--vela-font-size-sm);
|
|
4172
|
-
line-height: 1.2;
|
|
4173
|
-
}
|
|
4174
|
-
[data-layout='mobile'] .vela-has-statusline [${LEGEND_AT_TOP_ATTR}] { transform: translateY(40px); }
|
|
4175
|
-
/* FIT mode (multi-chart cells \u2014 see setFitMode): the line never wraps; segments that
|
|
4176
|
-
* don't fit are HIDDEN by fit() (change first, then meta, then the market badge), so
|
|
4177
|
-
* overflow:hidden only guards the transient between a resize and the next measure.
|
|
4178
|
-
* Placed after the mobile block on purpose: same specificity, later wins. */
|
|
4179
|
-
.vela-statusline.vela-sl-fit {
|
|
4180
|
-
display: flex; /* undo the mobile grid \u2014 fit mode is one flex row again */
|
|
4181
|
-
flex-wrap: nowrap;
|
|
4182
|
-
align-items: center;
|
|
4183
|
-
max-width: calc(100% - var(--vela-toolbar-gutter, 0px) - var(--vela-scale-gutter, 0px) - 24px);
|
|
4184
|
-
overflow: hidden;
|
|
4185
|
-
}
|
|
4186
|
-
.vela-statusline.vela-sl-fit .vela-sl-change {
|
|
4187
|
-
flex-basis: auto;
|
|
4188
|
-
padding-left: 0;
|
|
4189
|
-
}
|
|
4190
|
-
/* One row again \u2014 the mobile two-line shift doesn't apply in fit mode. */
|
|
4191
|
-
[data-layout='mobile'] .vela-sl-fit-host.vela-has-statusline [${LEGEND_AT_TOP_ATTR}] { transform: translateY(26px); }
|
|
4238
|
+
/* A stacked chip is two lines tall \u2014 the legend shifts one more line. fit() flags the
|
|
4239
|
+
* host whenever the ladder lands on a stacked layout. */
|
|
4240
|
+
.vela-has-statusline.vela-sl-stacked-host [${LEGEND_AT_TOP_ATTR}] { transform: translateY(40px); }
|
|
4241
|
+
/* Mobile: the same ladder at the phone's type scale \u2014 the width alone decides how much
|
|
4242
|
+
* of the readout fits, exactly as on a narrow desktop chart. */
|
|
4243
|
+
[data-layout='mobile'] .vela-statusline { font-size: var(--vela-font-size-sm); }
|
|
4244
|
+
[data-layout='mobile'] .vela-statusline .vela-sl-symbol { font-size: var(--vela-font-size-md); }
|
|
4192
4245
|
`;
|
|
4193
4246
|
function baseOfTicker(ticker) {
|
|
4194
4247
|
return ticker.replace(/[-_/]?(USDT|USDC|USD1|USDS|BUSD|USD|EUR|PERP)$/i, "") || ticker;
|
|
@@ -4259,6 +4312,8 @@ var Statusline = class {
|
|
|
4259
4312
|
/** Fit mode (multi-chart cells): one row, overflowing segments hidden — see {@link setFitMode}. */
|
|
4260
4313
|
this.fitMode = false;
|
|
4261
4314
|
this.fitRO = null;
|
|
4315
|
+
/** The ladder rung currently applied — see {@link fit}. */
|
|
4316
|
+
this.layout = { stacked: false, level: "full" };
|
|
4262
4317
|
this.onContextMenu = (e) => {
|
|
4263
4318
|
if (!this.menu || !this.menuHooks) return;
|
|
4264
4319
|
e.preventDefault();
|
|
@@ -4305,8 +4360,18 @@ var Statusline = class {
|
|
|
4305
4360
|
this.menuHooks?.setChartVisible(true);
|
|
4306
4361
|
this.setChartHidden(false);
|
|
4307
4362
|
});
|
|
4308
|
-
this.
|
|
4363
|
+
this.identityRow = doc.createElement("span");
|
|
4364
|
+
this.identityRow.className = "vela-sl-row vela-sl-identity";
|
|
4365
|
+
this.identityRow.append(this.avatarEl, this.symbolEl, this.metaEl, this.marketEl);
|
|
4366
|
+
this.valuesRow = doc.createElement("span");
|
|
4367
|
+
this.valuesRow.className = "vela-sl-row vela-sl-values";
|
|
4368
|
+
this.valuesRow.append(this.ohlcEl, this.changeEl, this.eyeEl);
|
|
4369
|
+
this.el.append(this.identityRow, this.valuesRow);
|
|
4309
4370
|
host.appendChild(this.el);
|
|
4371
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
4372
|
+
this.fitRO = new ResizeObserver(() => this.fit());
|
|
4373
|
+
this.fitRO.observe(host);
|
|
4374
|
+
}
|
|
4310
4375
|
this.marketTip = new Tooltip(this.marketEl, { content: MARKET_LABELS.open, placement: "bottom" });
|
|
4311
4376
|
this.eyeTip = new Tooltip(this.eyeEl, { content: "Show chart", placement: "bottom" });
|
|
4312
4377
|
this.setMarketStatus("open");
|
|
@@ -4322,27 +4387,15 @@ var Statusline = class {
|
|
|
4322
4387
|
this.fit();
|
|
4323
4388
|
}
|
|
4324
4389
|
/**
|
|
4325
|
-
* Multi-chart cells:
|
|
4326
|
-
*
|
|
4327
|
-
*
|
|
4328
|
-
* market badge; the logo + ticker always stay.
|
|
4390
|
+
* Multi-chart cells: the same width ladder as a single chart, plus a last resort for
|
|
4391
|
+
* cells too narrow for even its bottom rung — whatever still overflows is hidden
|
|
4392
|
+
* outright rather than clipped mid-glyph, least important first: the values, the
|
|
4393
|
+
* venue/timeframe meta, then the market badge; the logo + ticker always stay.
|
|
4329
4394
|
*/
|
|
4330
4395
|
setFitMode(on) {
|
|
4331
4396
|
if (on === this.fitMode) return;
|
|
4332
4397
|
this.fitMode = on;
|
|
4333
|
-
this.
|
|
4334
|
-
this.host.classList.toggle("vela-sl-fit-host", on);
|
|
4335
|
-
if (on) {
|
|
4336
|
-
if (typeof ResizeObserver !== "undefined" && !this.fitRO) {
|
|
4337
|
-
this.fitRO = new ResizeObserver(() => this.fit());
|
|
4338
|
-
this.fitRO.observe(this.host);
|
|
4339
|
-
}
|
|
4340
|
-
this.fit();
|
|
4341
|
-
} else {
|
|
4342
|
-
this.fitRO?.disconnect();
|
|
4343
|
-
this.fitRO = null;
|
|
4344
|
-
this.syncParts();
|
|
4345
|
-
}
|
|
4398
|
+
this.fit();
|
|
4346
4399
|
}
|
|
4347
4400
|
/** Project the parts config onto the segments (the baseline fit() prunes from). */
|
|
4348
4401
|
syncParts() {
|
|
@@ -4354,22 +4407,42 @@ var Statusline = class {
|
|
|
4354
4407
|
this.ohlcEl.style.display = seg.ohlc ? "" : "none";
|
|
4355
4408
|
this.changeEl.style.display = seg.change ? "" : "none";
|
|
4356
4409
|
this.eyeEl.style.display = seg.eye ? "inline-flex" : "none";
|
|
4410
|
+
this.valuesRow.style.display = seg.ohlc || seg.change || seg.eye ? "" : "none";
|
|
4357
4411
|
}
|
|
4358
|
-
/**
|
|
4412
|
+
/** Apply one ladder rung: the stacked/inline shape and the readout's level. */
|
|
4413
|
+
applyLayout(layout) {
|
|
4414
|
+
this.layout = layout;
|
|
4415
|
+
this.el.classList.toggle("vela-sl-stacked", layout.stacked);
|
|
4416
|
+
this.host.classList.toggle("vela-sl-stacked-host", layout.stacked);
|
|
4417
|
+
this.renderValues();
|
|
4418
|
+
}
|
|
4419
|
+
/**
|
|
4420
|
+
* Walk the width ladder (see {@link STATUSLINE_LADDER}) until the chip fits its
|
|
4421
|
+
* max-width: the full one-line readout, then the values stacked under the symbol
|
|
4422
|
+
* line, then O/H/L shed, then the absolute change. In fit mode, when the last rung
|
|
4423
|
+
* still overflows, whole segments hide, least important first. Without layout
|
|
4424
|
+
* (detached host, node tests) nothing overflows, so the widest rung stays.
|
|
4425
|
+
*/
|
|
4359
4426
|
fit() {
|
|
4360
|
-
if (!this.fitMode) return;
|
|
4361
4427
|
this.syncParts();
|
|
4362
4428
|
const seg = segmentVisibility(this.parts, this.chartHidden);
|
|
4429
|
+
const overflows = () => this.el.scrollWidth > this.el.clientWidth;
|
|
4430
|
+
const hasValues = seg.ohlc || seg.change;
|
|
4431
|
+
for (const rung of STATUSLINE_LADDER) {
|
|
4432
|
+
this.applyLayout(rung);
|
|
4433
|
+
if (!hasValues || !overflows()) break;
|
|
4434
|
+
}
|
|
4435
|
+
if (!this.fitMode) return;
|
|
4363
4436
|
const order = [
|
|
4364
|
-
[this.
|
|
4365
|
-
[this.changeEl, seg.change],
|
|
4437
|
+
[this.valuesRow, hasValues],
|
|
4366
4438
|
[this.metaEl, seg.meta],
|
|
4367
4439
|
[this.marketEl, seg.market]
|
|
4368
4440
|
];
|
|
4369
4441
|
for (const [el, shown] of order) {
|
|
4370
|
-
if (
|
|
4442
|
+
if (!overflows()) break;
|
|
4371
4443
|
if (shown) el.style.display = "none";
|
|
4372
4444
|
}
|
|
4445
|
+
if (this.valuesRow.style.display === "none") this.applyLayout({ ...this.layout, stacked: false });
|
|
4373
4446
|
}
|
|
4374
4447
|
/** Shape + color the value readout after the active price style: its own up/down
|
|
4375
4448
|
* colors (candle bodies, bar ticks, the line color, …), the direction rule that
|
|
@@ -4482,7 +4555,7 @@ var Statusline = class {
|
|
|
4482
4555
|
this.marketTip.destroy();
|
|
4483
4556
|
this.eyeTip.destroy();
|
|
4484
4557
|
this.marketBubble.destroy();
|
|
4485
|
-
this.host.classList.remove("vela-has-statusline", "vela-sl-
|
|
4558
|
+
this.host.classList.remove("vela-has-statusline", "vela-sl-stacked-host");
|
|
4486
4559
|
this.el.remove();
|
|
4487
4560
|
}
|
|
4488
4561
|
detach() {
|
|
@@ -4491,6 +4564,10 @@ var Statusline = class {
|
|
|
4491
4564
|
}
|
|
4492
4565
|
render() {
|
|
4493
4566
|
if (this.menuHooks) this.setChartHidden(!this.menuHooks.chartVisible());
|
|
4567
|
+
this.fit();
|
|
4568
|
+
}
|
|
4569
|
+
/** Write the value readout for the current bar at the current ladder level. */
|
|
4570
|
+
renderValues() {
|
|
4494
4571
|
const bar = this.hoverBar ?? this.lastBar;
|
|
4495
4572
|
if (!bar) {
|
|
4496
4573
|
this.ohlcEl.replaceChildren();
|
|
@@ -4510,12 +4587,11 @@ var Statusline = class {
|
|
|
4510
4587
|
s.appendChild(b);
|
|
4511
4588
|
return s;
|
|
4512
4589
|
};
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
this.changeEl.textContent = fmtChange(bar.open, bar.close);
|
|
4590
|
+
const { level } = this.layout;
|
|
4591
|
+
this.ohlcEl.replaceChildren(...readoutCells(level, this.readout).map((c) => cell(c.label, bar[c.key])));
|
|
4592
|
+
this.changeEl.textContent = level === "minimal" ? fmtChangePct(bar.open, bar.close) : fmtChange(bar.open, bar.close);
|
|
4516
4593
|
this.changeEl.dataset.dir = up ? "up" : "down";
|
|
4517
4594
|
this.changeEl.style.color = ink;
|
|
4518
|
-
this.fit();
|
|
4519
4595
|
}
|
|
4520
4596
|
};
|
|
4521
4597
|
|
|
@@ -5442,6 +5518,11 @@ function cellDrawings(opt) {
|
|
|
5442
5518
|
if (opt === true || opt == null) return { toolbar: false };
|
|
5443
5519
|
return { ...opt, toolbar: false };
|
|
5444
5520
|
}
|
|
5521
|
+
function nativeLedgerEntry(handle) {
|
|
5522
|
+
const inputs = inputDeltas(handle.inputs, handle.inputValues());
|
|
5523
|
+
const hidden = !handle.visible;
|
|
5524
|
+
return inputs || hidden ? { type: handle.nativeType, ...inputs ? { inputs } : {}, ...hidden ? { hidden: true } : {} } : handle.nativeType;
|
|
5525
|
+
}
|
|
5445
5526
|
function instanceDeltas(handle) {
|
|
5446
5527
|
if (!handle) return void 0;
|
|
5447
5528
|
const inputs = inputDeltas(handle.inputs, handle.inputValues());
|
|
@@ -5564,10 +5645,13 @@ var ChartCell = class {
|
|
|
5564
5645
|
if (seed.rendererConfig != null) this.inner.renderer.applyConfig(seed.rendererConfig);
|
|
5565
5646
|
if (seed.drawings != null) this.inner.drawings.fromJSON(seed.drawings);
|
|
5566
5647
|
if (seed.indicators) {
|
|
5567
|
-
for (const
|
|
5648
|
+
for (const entry of seed.indicators.natives) {
|
|
5649
|
+
const handle = this.inner.addNativeIndicator(ledgerNativeType(entry));
|
|
5650
|
+
this.applyNativeLedgerEntry(handle, entry);
|
|
5651
|
+
}
|
|
5568
5652
|
this.pendingManifestNames = [...seed.indicators.manifest];
|
|
5569
5653
|
}
|
|
5570
|
-
this.volumeIntent = seed.indicators ? seed.indicators.natives.
|
|
5654
|
+
this.volumeIntent = seed.indicators ? seed.indicators.natives.some((e) => ledgerNativeType(e) === "volume") : deps.volume;
|
|
5571
5655
|
this.extState = { ...seed.ext ?? {} };
|
|
5572
5656
|
this.inner.on("load:end", () => {
|
|
5573
5657
|
this.volumeMayBePending = false;
|
|
@@ -5639,6 +5723,7 @@ var ChartCell = class {
|
|
|
5639
5723
|
this.refreshNativeCatalog();
|
|
5640
5724
|
});
|
|
5641
5725
|
this.inner.on("indicator:inputs", () => this.deps.onStateDirty());
|
|
5726
|
+
this.inner.on("indicator:visibility", () => this.deps.onStateDirty());
|
|
5642
5727
|
this.inner.on("indicator:removed", ({ id: id2 }) => {
|
|
5643
5728
|
if (this.destroyed) return;
|
|
5644
5729
|
const idx = this.instances.findIndex((it) => it.handle?.id === id2);
|
|
@@ -6083,7 +6168,7 @@ var ChartCell = class {
|
|
|
6083
6168
|
if (list.length === 0) return;
|
|
6084
6169
|
for (const led of this.pendingManifestNames) {
|
|
6085
6170
|
const entry = list.find((e) => e.name === ledgerEntryName(led));
|
|
6086
|
-
if (entry) this.addManifestInstance(entry, { record: false, ...typeof led === "object" ? { inputs: led.inputs, props: led.props } : {} });
|
|
6171
|
+
if (entry) this.addManifestInstance(entry, { record: false, ...typeof led === "object" ? { inputs: led.inputs, props: led.props, hidden: led.hidden } : {} });
|
|
6087
6172
|
}
|
|
6088
6173
|
this.pendingManifestNames = null;
|
|
6089
6174
|
return;
|
|
@@ -6102,23 +6187,35 @@ var ChartCell = class {
|
|
|
6102
6187
|
applyIndicatorLedger(led) {
|
|
6103
6188
|
const chart = this.inner;
|
|
6104
6189
|
if (!chart) return;
|
|
6105
|
-
this.volumeIntent = led.natives.
|
|
6190
|
+
this.volumeIntent = led.natives.some((e) => ledgerNativeType(e) === "volume");
|
|
6106
6191
|
this.history.silently(() => {
|
|
6107
6192
|
const owed = /* @__PURE__ */ new Map();
|
|
6108
|
-
for (const
|
|
6193
|
+
for (const e of led.natives) {
|
|
6194
|
+
const type = ledgerNativeType(e);
|
|
6195
|
+
const queue = owed.get(type);
|
|
6196
|
+
if (queue) queue.push(e);
|
|
6197
|
+
else owed.set(type, [e]);
|
|
6198
|
+
}
|
|
6109
6199
|
for (const h of this.nativeHandles()) {
|
|
6110
|
-
const
|
|
6111
|
-
|
|
6112
|
-
if (n > 0) owed.set(type, n - 1);
|
|
6200
|
+
const entry = owed.get(h.nativeType)?.shift();
|
|
6201
|
+
if (entry !== void 0) this.applyNativeLedgerEntry(h, entry);
|
|
6113
6202
|
else h.remove();
|
|
6114
6203
|
}
|
|
6115
|
-
for (const
|
|
6204
|
+
for (const queue of owed.values()) {
|
|
6205
|
+
for (const e of queue) {
|
|
6206
|
+
const h = chart.addNativeIndicator(ledgerNativeType(e));
|
|
6207
|
+
this.applyNativeLedgerEntry(h, e);
|
|
6208
|
+
}
|
|
6209
|
+
}
|
|
6116
6210
|
for (const it of [...this.instances]) this.dropInstance(it);
|
|
6117
6211
|
if (this.manifest.length > 0) {
|
|
6118
6212
|
for (const item of led.manifest) {
|
|
6119
6213
|
const entry = this.manifest.find((e) => e.name === ledgerEntryName(item));
|
|
6120
6214
|
if (entry)
|
|
6121
|
-
this.addManifestInstance(entry, {
|
|
6215
|
+
this.addManifestInstance(entry, {
|
|
6216
|
+
record: false,
|
|
6217
|
+
...typeof item === "object" ? { inputs: item.inputs, props: item.props, hidden: item.hidden } : {}
|
|
6218
|
+
});
|
|
6122
6219
|
}
|
|
6123
6220
|
this.pendingManifestNames = null;
|
|
6124
6221
|
} else if (!this.deps.manifestSettled()) {
|
|
@@ -6185,6 +6282,7 @@ var ChartCell = class {
|
|
|
6185
6282
|
if (this.destroyed) return;
|
|
6186
6283
|
const values = opts.inputs || opts.props ? { inputs: opts.inputs, props: opts.props } : void 0;
|
|
6187
6284
|
const it = { entry, handle: this.addToChart(entry, values), ...opts.external ? { external: true } : {}, ...values ? { values } : {} };
|
|
6285
|
+
if (opts.hidden) it.handle?.setVisible(false);
|
|
6188
6286
|
this.instances.push(it);
|
|
6189
6287
|
this.deps.onIndicatorsChanged(this.id);
|
|
6190
6288
|
if (opts.record === false) return;
|
|
@@ -6228,6 +6326,29 @@ var ChartCell = class {
|
|
|
6228
6326
|
/** Add a native indicator. A multi-instance type gets a fresh instance every time; a
|
|
6229
6327
|
* single-instance type already on the chart hands back its existing one — nothing
|
|
6230
6328
|
* changed, so nothing enters the undo timeline. */
|
|
6329
|
+
/**
|
|
6330
|
+
* Converge one native handle to a restored ledger entry: every schema key gets the
|
|
6331
|
+
* entry's value or its declaration default (the DOCUMENT is the truth — a live
|
|
6332
|
+
* tweak must not survive a restore that says otherwise), and visibility follows
|
|
6333
|
+
* the `hidden` flag. Skips the input write when nothing differs — `setInputs`
|
|
6334
|
+
* re-runs the indicator, and a no-op restore must not flicker every native.
|
|
6335
|
+
*/
|
|
6336
|
+
applyNativeLedgerEntry(handle, entry) {
|
|
6337
|
+
const wanted = typeof entry === "string" ? void 0 : entry.inputs;
|
|
6338
|
+
if (handle.inputs.length > 0) {
|
|
6339
|
+
const current = handle.inputValues();
|
|
6340
|
+
const next = {};
|
|
6341
|
+
for (const schema of handle.inputs) {
|
|
6342
|
+
const target = wanted?.[schema.key] ?? schema.defval;
|
|
6343
|
+
if (JSON.stringify(current[schema.key]) !== JSON.stringify(target)) next[schema.key] = target;
|
|
6344
|
+
}
|
|
6345
|
+
if (Object.keys(next).length > 0) handle.setInputs(next);
|
|
6346
|
+
} else if (wanted) {
|
|
6347
|
+
handle.setInputs(wanted);
|
|
6348
|
+
}
|
|
6349
|
+
const visible = !(typeof entry === "object" && entry.hidden);
|
|
6350
|
+
if (handle.visible !== visible) handle.setVisible(visible);
|
|
6351
|
+
}
|
|
6231
6352
|
addNative(type) {
|
|
6232
6353
|
const chart = this.inner;
|
|
6233
6354
|
if (!chart) return;
|
|
@@ -6391,10 +6512,13 @@ var ChartCell = class {
|
|
|
6391
6512
|
// (`ctx.addIndicator`) stay out: their names would never resolve against the
|
|
6392
6513
|
// manifest — their plugin persists them via the `ext` seam instead.
|
|
6393
6514
|
indicators: indicatorLedger({
|
|
6394
|
-
|
|
6515
|
+
// Live handles carry what the registry read cannot: the input DELTAS and
|
|
6516
|
+
// the hidden flag, so native settings/visibility survive the round-trip.
|
|
6517
|
+
present: this.inner ? this.nativeHandles().map((h) => nativeLedgerEntry(h)) : [],
|
|
6395
6518
|
instanceEntries: this.instances.filter((it) => !it.external).map((it) => {
|
|
6396
6519
|
const d = it.handle ? instanceDeltas(it.handle) : it.values;
|
|
6397
|
-
|
|
6520
|
+
const hidden = it.handle ? !it.handle.visible : false;
|
|
6521
|
+
return d || hidden ? { name: it.entry.name, ...d ?? {}, ...hidden ? { hidden: true } : {} } : it.entry.name;
|
|
6398
6522
|
}),
|
|
6399
6523
|
pendingManifest: this.pendingManifestNames,
|
|
6400
6524
|
manifestSettled: this.deps.manifestSettled(),
|
|
@@ -8053,6 +8177,17 @@ function nextAutoCellId(taken) {
|
|
|
8053
8177
|
if (!taken.has(`c${i}`)) return `c${i}`;
|
|
8054
8178
|
}
|
|
8055
8179
|
}
|
|
8180
|
+
function resolveTyping(key, open) {
|
|
8181
|
+
if (open.dialogs > 0) {
|
|
8182
|
+
if (key.length !== 1) return null;
|
|
8183
|
+
if (open.symbolSearch) return { target: "symbol", text: key.toUpperCase() };
|
|
8184
|
+
if (open.timeframeEntry) return { target: "timeframe", text: key };
|
|
8185
|
+
return null;
|
|
8186
|
+
}
|
|
8187
|
+
if (/^[a-zA-Z]$/.test(key)) return { target: "symbol", text: key.toUpperCase() };
|
|
8188
|
+
if (/^[0-9]$/.test(key)) return { target: "timeframe", text: key };
|
|
8189
|
+
return null;
|
|
8190
|
+
}
|
|
8056
8191
|
var VelaWorkspace = class {
|
|
8057
8192
|
constructor(container, opts = {}) {
|
|
8058
8193
|
this.events = new TypedEventBus();
|
|
@@ -9686,17 +9821,14 @@ var VelaWorkspace = class {
|
|
|
9686
9821
|
}
|
|
9687
9822
|
/** Bare-typing router: letters → symbol search (seeded), digits → timeframe entry. */
|
|
9688
9823
|
routeTyping(ev) {
|
|
9689
|
-
if (this.destroyed
|
|
9824
|
+
if (this.destroyed) return;
|
|
9690
9825
|
if (ev.ctrlKey || ev.metaKey || ev.altKey) return;
|
|
9691
9826
|
if (isEditableTarget(ev)) return;
|
|
9692
|
-
const
|
|
9693
|
-
if (
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
ev.preventDefault();
|
|
9698
|
-
this.tfQuick.open(key);
|
|
9699
|
-
}
|
|
9827
|
+
const hit = resolveTyping(ev.key, { dialogs: this.openDialogs, symbolSearch: this.symbolPicker.isOpen, timeframeEntry: this.tfQuick.isOpen });
|
|
9828
|
+
if (!hit) return;
|
|
9829
|
+
ev.preventDefault();
|
|
9830
|
+
if (hit.target === "symbol") this.symbolPicker.type(hit.text);
|
|
9831
|
+
else this.tfQuick.type(hit.text);
|
|
9700
9832
|
}
|
|
9701
9833
|
trackDialog(open) {
|
|
9702
9834
|
this.openDialogs = Math.max(0, this.openDialogs + (open ? 1 : -1));
|