@luxalgo/vela 0.6.15 → 0.6.16
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/README.md +8 -1
- package/dist/chunk-FE6V2YAQ.js +1 -0
- package/dist/{chunk-J5QIR2Z3.js → chunk-GIJYO4LO.js} +2436 -115
- package/dist/{chunk-32A7KHFM.js → chunk-I77F2SVE.js} +7 -1
- package/dist/{chunk-MWDNPGU3.js → chunk-MGU3USTP.js} +22 -15
- package/dist/{chunk-MWS4CUJL.js → chunk-Q3TFJNJW.js} +1 -1
- package/dist/{chunk-7C7NWEXH.js → chunk-SEOO6YG7.js} +82 -55
- package/dist/{contributions-x7iamlnd.d.cts → contributions-BEkxwA5F.d.cts} +27 -11
- package/dist/{contributions-h5BzEiV2.d.ts → contributions-CoAX7_SF.d.ts} +27 -11
- package/dist/index.cjs +2665 -337
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/{plugin-BLaNPh55.d.ts → plugin-CNUgbRNq.d.ts} +1 -1
- package/dist/{plugin-2sJcf5mk.d.cts → plugin-Dxyq35Zf.d.cts} +1 -1
- package/dist/plugin.d.cts +2 -2
- package/dist/plugin.d.ts +2 -2
- package/dist/plugin.js +2 -2
- package/dist/{statusline-model--tH0VWCy.d.cts → statusline-model-CbPza-Wc.d.cts} +1 -1
- package/dist/{statusline-model-CLpaO3Dl.d.ts → statusline-model-D7cWkw8A.d.ts} +1 -1
- package/dist/ui.cjs +22 -15
- package/dist/ui.js +2 -2
- package/dist/vela.global.js +2501 -173
- package/dist/vela.global.min.js +52 -52
- package/dist/widget.cjs +2563 -202
- package/dist/widget.d.cts +4 -4
- package/dist/widget.d.ts +4 -4
- package/dist/widget.js +6 -6
- package/dist/workspace.cjs +2563 -202
- package/dist/workspace.d.cts +23 -12
- package/dist/workspace.d.ts +23 -12
- package/dist/workspace.js +5 -5
- package/package.json +1 -1
- package/dist/chunk-H26BEHF4.js +0 -7
|
@@ -5890,6 +5890,12 @@ function rendererLayers() {
|
|
|
5890
5890
|
return [...registry2.values()];
|
|
5891
5891
|
}
|
|
5892
5892
|
|
|
5893
|
+
// src/core/model/identity.ts
|
|
5894
|
+
function stableSeriesId(parts) {
|
|
5895
|
+
const normTitle = parts.title.trim().toLowerCase().replace(/\s+/g, "-");
|
|
5896
|
+
return `${parts.instanceId}:${parts.kind}:${normTitle}#${parts.ordinal}`;
|
|
5897
|
+
}
|
|
5898
|
+
|
|
5893
5899
|
// src/widget/topbar-composition.ts
|
|
5894
5900
|
var TOPBAR_BUILTIN_IDS = ["symbol", "timeframes", "style", "layout", "indicators", "actions", "undo-redo", "alerts", "panels", "screenshot"];
|
|
5895
5901
|
var TOPBAR_DEFAULT_LEFT = ["symbol", "timeframes", "style", "layout", "indicators", "actions", "undo-redo"];
|
|
@@ -6359,4 +6365,4 @@ var SidePanel = class {
|
|
|
6359
6365
|
}
|
|
6360
6366
|
};
|
|
6361
6367
|
|
|
6362
|
-
export { AnchoredVwap, ArrowMark, Callout, CalloutBase, Comment, DEDEKIND_CURVATURE_OPTIONS, DEFAULT_DRAWING_COLOR, DEFAULT_PANEL_MAX_WIDTH, DEFAULT_PANEL_MIN_WIDTH, DEFAULT_PANEL_ORDER, DEFAULT_PANEL_WIDTH, DIRECTION_OPTIONS, DedekindTessellation, Drawing, FibRatios, FibSpiral, FixedRangeVolumeProfile, GANN_SQUARE_ARCS, GLYPH_OPTIONS, GannSquare, GlyphStamp, LINE_STYLE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, MAGNIFIER_TIMEFRAME_OPTIONS, MachFigure, Magnifier, MeasureBox, Note, OVERRIDABLE_TOPBAR_IDS, PatternDrawing, PositionTool, PriceLabel, PriceNote, RadialFib, RegressionChannel, STAMP_SIZE_OPTIONS, SegmentDrawing, SidePanel, Signpost, TEXT_SIZE_OPTIONS, TOPBAR_BUILTIN_IDS, TOPBAR_DEFAULT_LEFT, TOPBAR_DEFAULT_RIGHT, TextLabel, chartType, chartTypes, clampPanelWidth, createDrawing, deserializeDrawing, drawingTypes, foldBaseModulation, formatDuration, getDrawingType, getNativeIndicator, inputDeltas, inputVisible, legendActions, legendActionsProviderFor, legendCallouts, legendCalloutsProviderFor, lineSegmentIntersection, magnifierTimeframeLabel, nativeIndicatorDescriptors, nativeIndicatorTypes, normalizeSettingsRow, pinnedTopbarActionIds, registerChartType, registerDefaultEngine, registerDrawingType, registerLegendAction, registerLegendCallout, registerNativeIndicator, registerRendererDefaults, registerRendererLayer, registerSidePanel, registerStatePersistence, registerSymbolRanking, registerWidgetAction, registerWidgetAttachment, rendererDefaults, rendererLayers, resetDrawingSettings, resolveEngines, resolveTopbarComposition, settingsRowValueKeys, settingsRowVisible, sidePanels, statePersistenceHandlers, symbolRanking, tickerModifierIds, topbarActionOverride, topbarHas, unregisterChartType, unregisterDefaultEngine, unregisterLegendAction, unregisterLegendCallout, unregisterNativeIndicator, unregisterRendererDefaults, unregisterRendererLayer, unregisterSidePanel, unregisterStatePersistence, unregisterWidgetAction, unregisterWidgetAttachment, widgetActions, widgetAttachments };
|
|
6368
|
+
export { AnchoredVwap, ArrowMark, Callout, CalloutBase, Comment, DEDEKIND_CURVATURE_OPTIONS, DEFAULT_DRAWING_COLOR, DEFAULT_PANEL_MAX_WIDTH, DEFAULT_PANEL_MIN_WIDTH, DEFAULT_PANEL_ORDER, DEFAULT_PANEL_WIDTH, DIRECTION_OPTIONS, DedekindTessellation, Drawing, FibRatios, FibSpiral, FixedRangeVolumeProfile, GANN_SQUARE_ARCS, GLYPH_OPTIONS, GannSquare, GlyphStamp, LINE_STYLE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, MAGNIFIER_TIMEFRAME_OPTIONS, MachFigure, Magnifier, MeasureBox, Note, OVERRIDABLE_TOPBAR_IDS, PatternDrawing, PositionTool, PriceLabel, PriceNote, RadialFib, RegressionChannel, STAMP_SIZE_OPTIONS, SegmentDrawing, SidePanel, Signpost, TEXT_SIZE_OPTIONS, TOPBAR_BUILTIN_IDS, TOPBAR_DEFAULT_LEFT, TOPBAR_DEFAULT_RIGHT, TextLabel, chartType, chartTypes, clampPanelWidth, createDrawing, deserializeDrawing, drawingTypes, foldBaseModulation, formatDuration, getDrawingType, getNativeIndicator, inputDeltas, inputVisible, legendActions, legendActionsProviderFor, legendCallouts, legendCalloutsProviderFor, lineSegmentIntersection, magnifierTimeframeLabel, nativeIndicatorDescriptors, nativeIndicatorTypes, normalizeSettingsRow, pinnedTopbarActionIds, registerChartType, registerDefaultEngine, registerDrawingType, registerLegendAction, registerLegendCallout, registerNativeIndicator, registerRendererDefaults, registerRendererLayer, registerSidePanel, registerStatePersistence, registerSymbolRanking, registerWidgetAction, registerWidgetAttachment, rendererDefaults, rendererLayers, resetDrawingSettings, resolveEngines, resolveTopbarComposition, settingsRowValueKeys, settingsRowVisible, sidePanels, stableSeriesId, statePersistenceHandlers, symbolRanking, tickerModifierIds, topbarActionOverride, topbarHas, unregisterChartType, unregisterDefaultEngine, unregisterLegendAction, unregisterLegendCallout, unregisterNativeIndicator, unregisterRendererDefaults, unregisterRendererLayer, unregisterSidePanel, unregisterStatePersistence, unregisterWidgetAction, unregisterWidgetAttachment, widgetActions, widgetAttachments };
|
|
@@ -2185,8 +2185,21 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
2185
2185
|
};
|
|
2186
2186
|
const recentRow = document.createElement("div");
|
|
2187
2187
|
recentRow.style.cssText = "display:flex;align-items:center;gap:5px;flex-wrap:wrap;border-top:1px solid var(--vela-border);padding-top:9px;";
|
|
2188
|
+
const recentSwatches = document.createElement("div");
|
|
2189
|
+
recentSwatches.style.cssText = "display:contents;";
|
|
2190
|
+
const add = document.createElement("label");
|
|
2191
|
+
add.style.cssText = `width:17px;height:17px;border-radius:var(--vela-radius-sm);border:1px dashed var(--vela-border-strong);cursor:pointer;display:flex;align-items:center;justify-content:center;color:${theme.textColor};font:14px ${theme.fontFamily};position:relative;`;
|
|
2192
|
+
add.textContent = "+";
|
|
2193
|
+
const customInput = document.createElement("input");
|
|
2194
|
+
customInput.type = "color";
|
|
2195
|
+
customInput.value = curHex;
|
|
2196
|
+
customInput.style.cssText = "position:absolute;inset:0;opacity:0;cursor:pointer;";
|
|
2197
|
+
customInput.addEventListener("input", () => previewHex(customInput.value));
|
|
2198
|
+
customInput.addEventListener("change", () => pickHex(customInput.value, true));
|
|
2199
|
+
add.appendChild(customInput);
|
|
2200
|
+
recentRow.append(recentSwatches, add);
|
|
2188
2201
|
const renderRecents = () => {
|
|
2189
|
-
|
|
2202
|
+
recentSwatches.replaceChildren();
|
|
2190
2203
|
for (const c of recents) {
|
|
2191
2204
|
const sw = document.createElement("button");
|
|
2192
2205
|
sw.type = "button";
|
|
@@ -2195,18 +2208,8 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
2195
2208
|
e.stopPropagation();
|
|
2196
2209
|
pickHex(c);
|
|
2197
2210
|
});
|
|
2198
|
-
|
|
2211
|
+
recentSwatches.appendChild(sw);
|
|
2199
2212
|
}
|
|
2200
|
-
const add = document.createElement("label");
|
|
2201
|
-
add.style.cssText = `width:17px;height:17px;border-radius:var(--vela-radius-sm);border:1px dashed var(--vela-border-strong);cursor:pointer;display:flex;align-items:center;justify-content:center;color:${theme.textColor};font:14px ${theme.fontFamily};position:relative;`;
|
|
2202
|
-
add.textContent = "+";
|
|
2203
|
-
const input = document.createElement("input");
|
|
2204
|
-
input.type = "color";
|
|
2205
|
-
input.value = curHex;
|
|
2206
|
-
input.style.cssText = "position:absolute;inset:0;opacity:0;cursor:pointer;";
|
|
2207
|
-
input.addEventListener("input", () => pickHex(input.value, true));
|
|
2208
|
-
add.appendChild(input);
|
|
2209
|
-
recentRow.appendChild(add);
|
|
2210
2213
|
};
|
|
2211
2214
|
const opLabel = document.createElement("div");
|
|
2212
2215
|
opLabel.textContent = "Opacity";
|
|
@@ -2246,14 +2249,18 @@ function buildColorPicker(color, theme, onChange) {
|
|
|
2246
2249
|
function emit() {
|
|
2247
2250
|
onChange(combineColor(curHex, curAlpha));
|
|
2248
2251
|
}
|
|
2249
|
-
function
|
|
2252
|
+
function previewHex(hex) {
|
|
2250
2253
|
curHex = splitColor(hex).hex6;
|
|
2251
|
-
addRecent(curHex);
|
|
2252
2254
|
paintSelection();
|
|
2253
2255
|
paintOpacity();
|
|
2254
|
-
if (custom) renderRecents();
|
|
2255
2256
|
emit();
|
|
2256
2257
|
}
|
|
2258
|
+
function pickHex(hex, custom = false) {
|
|
2259
|
+
previewHex(hex);
|
|
2260
|
+
addRecent(curHex);
|
|
2261
|
+
customInput.value = curHex;
|
|
2262
|
+
if (custom) renderRecents();
|
|
2263
|
+
}
|
|
2257
2264
|
renderRecents();
|
|
2258
2265
|
paintSelection();
|
|
2259
2266
|
paintOpacity();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeProps, nextUid, runMachine, spreadProps } from './chunk-
|
|
1
|
+
import { normalizeProps, nextUid, runMachine, spreadProps } from './chunk-MGU3USTP.js';
|
|
2
2
|
import { injectStyles } from './chunk-6DPAYEGO.js';
|
|
3
3
|
import * as tooltip from '@zag-js/tooltip';
|
|
4
4
|
import * as dialog from '@zag-js/dialog';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel, isGroupRow, defaultMemberOf, groupKeyOf, groupMembers, LEGEND_AT_TOP_ATTR, Vela, TypedEventBus, MultiProviderFeed, registerBuiltinChartTypes, resolveTheme, buildToolbar, createCustomMark, createAttributionMark, DrawingToolbar, applyAttributionMarkTheme, sharedBarStore, timeframeToMs } from './chunk-
|
|
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-
|
|
3
|
-
import { Tooltip, KeymapManager, isEditableTarget, Drawer } from './chunk-
|
|
4
|
-
import { Menu, Dialog, CalloutBubble, applyPlotOverlayTokens, ensureUIHost } from './chunk-
|
|
1
|
+
import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel, isGroupRow, defaultMemberOf, groupKeyOf, groupMembers, LEGEND_AT_TOP_ATTR, Vela, TypedEventBus, MultiProviderFeed, registerBuiltinChartTypes, resolveTheme, buildToolbar, createCustomMark, createAttributionMark, DrawingToolbar, applyAttributionMarkTheme, sharedBarStore, timeframeToMs } from './chunk-GIJYO4LO.js';
|
|
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-I77F2SVE.js';
|
|
3
|
+
import { Tooltip, KeymapManager, isEditableTarget, Drawer } from './chunk-Q3TFJNJW.js';
|
|
4
|
+
import { Menu, Dialog, CalloutBubble, applyPlotOverlayTokens, ensureUIHost } from './chunk-MGU3USTP.js';
|
|
5
5
|
import { registerIcon, svg16, injectStyles, iconEl, iconMarkup, iconAt, SESSION_OFF, SESSION_POST, SESSION_PRE, icon, categoricalColor } from './chunk-6DPAYEGO.js';
|
|
6
6
|
import { baseOf } from './chunk-W4EJWLEO.js';
|
|
7
7
|
|
|
@@ -2999,17 +2999,12 @@ function filterSymbols(list, query, limit = 100, top = TOP_TICKERS) {
|
|
|
2999
2999
|
}
|
|
3000
3000
|
var STYLE_ID6 = "vela-widget-symbolpicker";
|
|
3001
3001
|
var CSS6 = `
|
|
3002
|
-
/*
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
z-index: 1;
|
|
3009
|
-
background: var(--vela-surface);
|
|
3010
|
-
margin: calc(-1 * var(--vela-space-4)) calc(-1 * var(--vela-space-4)) 0;
|
|
3011
|
-
padding: var(--vela-space-4) var(--vela-space-4) 0;
|
|
3012
|
-
}
|
|
3002
|
+
/* The dialog body is flush (a flex column): search + market tabs are a fixed head
|
|
3003
|
+
and the result list is the ONLY scroller, in both layouts. A sticky head over a
|
|
3004
|
+
scrolling padded body is not an option \u2014 browsers pin sticky boxes to the
|
|
3005
|
+
scroller's content box, so the head lands one padding below the top and covers
|
|
3006
|
+
the first row. */
|
|
3007
|
+
.vela-sp-head { flex: none; padding: var(--vela-space-4) var(--vela-space-4) 0; }
|
|
3013
3008
|
.vela-sp-searchrow {
|
|
3014
3009
|
display: flex;
|
|
3015
3010
|
align-items: center;
|
|
@@ -3034,12 +3029,13 @@ var CSS6 = `
|
|
|
3034
3029
|
.vela-sp-input::placeholder { text-transform: none; }
|
|
3035
3030
|
.vela-sp-tabs { display: flex; gap: 14px; margin: 12px 2px 0; border-bottom: 1px solid var(--vela-border); padding-bottom: 8px; }
|
|
3036
3031
|
/* Mobile (fullscreen dialog): the asset-class strip scrolls sideways instead of
|
|
3037
|
-
overflowing the body, and the result list stops capping itself \u2014
|
|
3038
|
-
the
|
|
3032
|
+
overflowing the body, and the result list stops capping itself \u2014 it fills the
|
|
3033
|
+
rest of the screen. The bottom inset (+ safe area) is the kit's: every mobile
|
|
3034
|
+
dialog body carries it, flush or not, so the list adds none of its own. */
|
|
3039
3035
|
[data-layout='mobile'] .vela-sp-tabs { overflow-x: auto; scrollbar-width: none; gap: 6px; }
|
|
3040
3036
|
[data-layout='mobile'] .vela-sp-tabs::-webkit-scrollbar { display: none; }
|
|
3041
3037
|
[data-layout='mobile'] .vela-sp-tab { flex: none; padding: 7px 10px; }
|
|
3042
|
-
[data-layout='mobile'] .vela-sp-list { max-height: none; }
|
|
3038
|
+
[data-layout='mobile'] .vela-sp-list { flex: 1 1 auto; max-height: none; margin-bottom: 0; }
|
|
3043
3039
|
.vela-sp-tab {
|
|
3044
3040
|
all: unset;
|
|
3045
3041
|
padding: 3px 10px;
|
|
@@ -3051,7 +3047,12 @@ var CSS6 = `
|
|
|
3051
3047
|
}
|
|
3052
3048
|
.vela-sp-tab:hover { color: var(--vela-fg); }
|
|
3053
3049
|
.vela-sp-tab[data-active] { background: var(--vela-selected-bg); color: var(--vela-selected-fg); }
|
|
3054
|
-
.vela-sp-list {
|
|
3050
|
+
.vela-sp-list {
|
|
3051
|
+
min-height: 0;
|
|
3052
|
+
margin: var(--vela-space-2) var(--vela-space-4) var(--vela-space-4);
|
|
3053
|
+
max-height: 46vh;
|
|
3054
|
+
overflow: auto;
|
|
3055
|
+
}
|
|
3055
3056
|
.vela-sp-list::-webkit-scrollbar { width: 8px; }
|
|
3056
3057
|
.vela-sp-list::-webkit-scrollbar-thumb {
|
|
3057
3058
|
background: var(--vela-scroll);
|
|
@@ -3144,8 +3145,8 @@ var SymbolPicker = class {
|
|
|
3144
3145
|
searchRow.append(iconEl("search", doc), this.input);
|
|
3145
3146
|
this.tabs = doc.createElement("div");
|
|
3146
3147
|
this.tabs.className = "vela-sp-tabs";
|
|
3147
|
-
const
|
|
3148
|
-
|
|
3148
|
+
const head = doc.createElement("div");
|
|
3149
|
+
head.className = "vela-sp-head";
|
|
3149
3150
|
for (const t of ["All", "Stocks", "ETFs", "Crypto", "Futures", "Forex", "Commodities"]) {
|
|
3150
3151
|
const b = doc.createElement("button");
|
|
3151
3152
|
b.className = "vela-sp-tab";
|
|
@@ -3159,7 +3160,7 @@ var SymbolPicker = class {
|
|
|
3159
3160
|
});
|
|
3160
3161
|
this.tabs.appendChild(b);
|
|
3161
3162
|
}
|
|
3162
|
-
|
|
3163
|
+
head.append(searchRow, this.tabs);
|
|
3163
3164
|
this.list = doc.createElement("div");
|
|
3164
3165
|
this.list.className = "vela-sp-list";
|
|
3165
3166
|
this.list.addEventListener("scroll", () => {
|
|
@@ -3172,7 +3173,8 @@ var SymbolPicker = class {
|
|
|
3172
3173
|
title: "Symbol Search",
|
|
3173
3174
|
host: opts.host,
|
|
3174
3175
|
closeOnInteractOutside: true,
|
|
3175
|
-
|
|
3176
|
+
flush: true,
|
|
3177
|
+
content: (body) => body.append(head, this.list),
|
|
3176
3178
|
onOpenChange: (open) => {
|
|
3177
3179
|
if (open) {
|
|
3178
3180
|
this.input.value = this.seed.toUpperCase();
|
|
@@ -5482,8 +5484,8 @@ var ChartCell = class {
|
|
|
5482
5484
|
/** The volume auto-add rides the cell's first candles (`load:end`); until then the
|
|
5483
5485
|
* registry can't show it and the dehydrated ledger reports the INTENT instead. */
|
|
5484
5486
|
this.volumeMayBePending = true;
|
|
5485
|
-
/** Sync mirror of the chart's
|
|
5486
|
-
*
|
|
5487
|
+
/** Sync mirror of the chart's native instances (id + type) — the removal handler
|
|
5488
|
+
* looks the removed id up here to learn which type an undo must re-add. */
|
|
5487
5489
|
this.presentNatives = [];
|
|
5488
5490
|
this.rangeBars = 0;
|
|
5489
5491
|
this.pendingRange = null;
|
|
@@ -5655,15 +5657,18 @@ var ChartCell = class {
|
|
|
5655
5657
|
redo: () => this.dropInstance(snapshot)
|
|
5656
5658
|
});
|
|
5657
5659
|
} else {
|
|
5658
|
-
const
|
|
5659
|
-
|
|
5660
|
+
const gone = this.presentNatives.find((n) => n.id === id2);
|
|
5661
|
+
if (gone) {
|
|
5662
|
+
const { type } = gone;
|
|
5663
|
+
let revived = null;
|
|
5660
5664
|
this.history.push({
|
|
5661
5665
|
undo: () => {
|
|
5662
|
-
this.inner?.addNativeIndicator(type);
|
|
5666
|
+
revived = this.inner?.addNativeIndicator(type) ?? null;
|
|
5663
5667
|
this.refreshNativeCatalog();
|
|
5664
5668
|
},
|
|
5665
5669
|
redo: () => {
|
|
5666
|
-
|
|
5670
|
+
revived?.remove();
|
|
5671
|
+
revived = null;
|
|
5667
5672
|
this.refreshNativeCatalog();
|
|
5668
5673
|
}
|
|
5669
5674
|
});
|
|
@@ -5968,9 +5973,9 @@ var ChartCell = class {
|
|
|
5968
5973
|
const live = this.inner?.renderer.get("priceStyle");
|
|
5969
5974
|
return typeof live === "string" ? live : this.state.priceStyle ?? "candles";
|
|
5970
5975
|
}
|
|
5971
|
-
/** Manifest instances +
|
|
5976
|
+
/** Manifest instances + native instances — the topbar indicator count. */
|
|
5972
5977
|
get indicatorCount() {
|
|
5973
|
-
return this.instances.length + this.
|
|
5978
|
+
return this.instances.length + (this.inner ? this.nativeHandles().length : this.presentNatives.length);
|
|
5974
5979
|
}
|
|
5975
5980
|
/** Switch this cell's market in place (the chart instance survives). The projection
|
|
5976
5981
|
* is OPTIMISTIC — labels and chrome show the pick before the bars load; it follows
|
|
@@ -6102,13 +6107,15 @@ var ChartCell = class {
|
|
|
6102
6107
|
if (!chart) return;
|
|
6103
6108
|
this.volumeIntent = led.natives.includes("volume");
|
|
6104
6109
|
this.history.silently(() => {
|
|
6105
|
-
const
|
|
6106
|
-
for (const type of led.natives)
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
if (
|
|
6110
|
+
const owed = /* @__PURE__ */ new Map();
|
|
6111
|
+
for (const type of led.natives) owed.set(type, (owed.get(type) ?? 0) + 1);
|
|
6112
|
+
for (const h of this.nativeHandles()) {
|
|
6113
|
+
const type = h.nativeType;
|
|
6114
|
+
const n = owed.get(type) ?? 0;
|
|
6115
|
+
if (n > 0) owed.set(type, n - 1);
|
|
6116
|
+
else h.remove();
|
|
6111
6117
|
}
|
|
6118
|
+
for (const [type, n] of owed) for (let i = 0; i < n; i++) chart.addNativeIndicator(type);
|
|
6112
6119
|
for (const it of [...this.instances]) this.dropInstance(it);
|
|
6113
6120
|
if (this.manifest.length > 0) {
|
|
6114
6121
|
for (const item of led.manifest) {
|
|
@@ -6126,34 +6133,42 @@ var ChartCell = class {
|
|
|
6126
6133
|
this.syncPresentNatives();
|
|
6127
6134
|
this.refreshNativeCatalog();
|
|
6128
6135
|
}
|
|
6129
|
-
/** The picker
|
|
6136
|
+
/** The supported natives in picker order: A→Z by title — registration order follows
|
|
6137
|
+
* the catalog's families, which is meaningless to the reader. This is the library
|
|
6138
|
+
* index space the picker hands back, so `libraryRows` and `addFromLibrary` MUST both
|
|
6139
|
+
* read it — indexing the unsorted catalog on add would land on a different study. */
|
|
6140
|
+
supportedNatives() {
|
|
6141
|
+
return this.nativeCatalog.filter((n) => n.supported).sort((a, b) => a.title.localeCompare(b.title, "en", { sensitivity: "base" }));
|
|
6142
|
+
}
|
|
6143
|
+
/** The picker's library rows: supported natives first (see {@link supportedNatives}),
|
|
6144
|
+
* then the manifest in the host's own order. */
|
|
6130
6145
|
libraryRows() {
|
|
6131
6146
|
return [
|
|
6132
|
-
...this.
|
|
6147
|
+
...this.supportedNatives().map((n) => ({ name: n.title, category: "Vela", native: true, nativeType: n.type, beta: n.beta })),
|
|
6133
6148
|
...this.manifest.map((e) => ({ name: e.name, language: e.language, category: e.category }))
|
|
6134
6149
|
];
|
|
6135
6150
|
}
|
|
6136
|
-
/** The picker's on-chart rows:
|
|
6151
|
+
/** The picker's on-chart rows: native instances first, then live script instances. */
|
|
6137
6152
|
onChartRows() {
|
|
6138
6153
|
return [
|
|
6139
|
-
...this.
|
|
6154
|
+
...this.nativeHandles().map((h) => ({ name: h.title, native: true, nativeType: h.nativeType })),
|
|
6140
6155
|
...this.instances.map((it) => ({ name: it.entry.name, language: it.entry.language }))
|
|
6141
6156
|
];
|
|
6142
6157
|
}
|
|
6143
6158
|
/** Add by picker LIBRARY index (natives precede the manifest — mirrors libraryRows). */
|
|
6144
6159
|
addFromLibrary(index) {
|
|
6145
|
-
const natives = this.
|
|
6160
|
+
const natives = this.supportedNatives();
|
|
6146
6161
|
if (index < natives.length) this.addNative(natives[index].type);
|
|
6147
6162
|
else {
|
|
6148
6163
|
const entry = this.manifest[index - natives.length];
|
|
6149
6164
|
if (entry) this.addManifestInstance(entry);
|
|
6150
6165
|
}
|
|
6151
6166
|
}
|
|
6152
|
-
/** Remove by picker ON-CHART index (
|
|
6167
|
+
/** Remove by picker ON-CHART index (native instances precede script instances — mirrors onChartRows). */
|
|
6153
6168
|
removeFromChart(index) {
|
|
6154
|
-
const
|
|
6155
|
-
if (index <
|
|
6156
|
-
else this.removeInstance(index -
|
|
6169
|
+
const natives = this.nativeHandles();
|
|
6170
|
+
if (index < natives.length) this.removeNative(natives[index]);
|
|
6171
|
+
else this.removeInstance(index - natives.length);
|
|
6157
6172
|
}
|
|
6158
6173
|
/**
|
|
6159
6174
|
* Add a script indicator through the PUBLIC seam (`ctx.addIndicator`) — same undo/
|
|
@@ -6213,30 +6228,42 @@ var ChartCell = class {
|
|
|
6213
6228
|
it.handle = null;
|
|
6214
6229
|
this.deps.onIndicatorsChanged(this.id);
|
|
6215
6230
|
}
|
|
6216
|
-
/** Add a native indicator
|
|
6231
|
+
/** Add a native indicator. A multi-instance type gets a fresh instance every time; a
|
|
6232
|
+
* single-instance type already on the chart hands back its existing one — nothing
|
|
6233
|
+
* changed, so nothing enters the undo timeline. */
|
|
6217
6234
|
addNative(type) {
|
|
6218
|
-
this.inner
|
|
6235
|
+
const chart = this.inner;
|
|
6236
|
+
if (!chart) return;
|
|
6237
|
+
const before = new Set(chart.indicators().map((h) => h.id));
|
|
6238
|
+
let added = chart.addNativeIndicator(type);
|
|
6219
6239
|
this.syncPresentNatives();
|
|
6220
6240
|
this.refreshNativeCatalog();
|
|
6241
|
+
if (before.has(added.id)) return;
|
|
6221
6242
|
this.history.push({
|
|
6222
6243
|
undo: () => {
|
|
6223
|
-
|
|
6244
|
+
added?.remove();
|
|
6245
|
+
added = null;
|
|
6224
6246
|
this.refreshNativeCatalog();
|
|
6225
6247
|
},
|
|
6226
6248
|
redo: () => {
|
|
6227
|
-
this.inner?.addNativeIndicator(type);
|
|
6249
|
+
added = this.inner?.addNativeIndicator(type) ?? null;
|
|
6228
6250
|
this.refreshNativeCatalog();
|
|
6229
6251
|
}
|
|
6230
6252
|
});
|
|
6231
6253
|
}
|
|
6232
|
-
removeNative(
|
|
6233
|
-
|
|
6254
|
+
removeNative(handle) {
|
|
6255
|
+
handle.remove();
|
|
6234
6256
|
this.refreshNativeCatalog();
|
|
6235
6257
|
}
|
|
6236
|
-
/**
|
|
6237
|
-
*
|
|
6258
|
+
/** The chart's native instances, insertion order — the picker's on-chart rows and
|
|
6259
|
+
* the removal index space (script instances follow them). */
|
|
6260
|
+
nativeHandles() {
|
|
6261
|
+
return this.inner?.indicators().filter((h) => h.nativeType !== void 0) ?? [];
|
|
6262
|
+
}
|
|
6263
|
+
/** Sync mirror of the chart's native instances — the removal handler looks the
|
|
6264
|
+
* removed id up here (the registry has already forgotten it) to record its type. */
|
|
6238
6265
|
syncPresentNatives() {
|
|
6239
|
-
this.presentNatives = this.
|
|
6266
|
+
this.presentNatives = this.nativeHandles().map((h) => ({ id: h.id, type: h.nativeType }));
|
|
6240
6267
|
}
|
|
6241
6268
|
/** Refresh the native catalog (supported/present flags) for this cell's market. */
|
|
6242
6269
|
refreshNativeCatalog() {
|
|
@@ -286,6 +286,9 @@ interface IndicatorHandle {
|
|
|
286
286
|
* (core-computed) indicator — there is no script to show. What a host editor
|
|
287
287
|
* opens when a legend action asks for "the code behind this row". */
|
|
288
288
|
readonly source?: string;
|
|
289
|
+
/** The registered type of a NATIVE (core-computed) indicator — `undefined` for a
|
|
290
|
+
* script indicator. The two are exclusive: a handle has a `source` or a `nativeType`. */
|
|
291
|
+
readonly nativeType?: string;
|
|
289
292
|
/** Inputs parsed from the Pine source (populated once the script is prepared). */
|
|
290
293
|
readonly inputs: readonly InputSchema[];
|
|
291
294
|
/** Declaration-props schema (a strategy's `initial_capital`, an indicator's
|
|
@@ -499,6 +502,13 @@ interface NativeIndicatorDescriptor {
|
|
|
499
502
|
readonly reactsToViewport?: boolean;
|
|
500
503
|
/** Marks the type as beta — surfaced in the catalog so a host "add indicator" UI can badge it. */
|
|
501
504
|
readonly beta?: boolean;
|
|
505
|
+
/**
|
|
506
|
+
* Allow several instances of this type on one chart — every add creates a new one (a study
|
|
507
|
+
* like a moving average is typically stacked at different lengths). Absent ⇒ SINGLE instance
|
|
508
|
+
* per type: a second add returns the existing handle. A type that pushes a bespoke layer
|
|
509
|
+
* payload through `pushData` must stay single-instance (the layer is keyed by type).
|
|
510
|
+
*/
|
|
511
|
+
readonly multiInstance?: boolean;
|
|
502
512
|
inputsSchema(): InputSchema[];
|
|
503
513
|
defaultInputs(): Record<string, InputValue>;
|
|
504
514
|
create(): NativeIndicator;
|
|
@@ -510,8 +520,8 @@ interface NativeIndicatorDescriptor {
|
|
|
510
520
|
}
|
|
511
521
|
/**
|
|
512
522
|
* One entry in the "add native indicator" catalog: the type's static metadata plus its live state
|
|
513
|
-
* on a specific chart — whether it applies to the current symbol (`supported`) and whether
|
|
514
|
-
* instance is already present (`present
|
|
523
|
+
* on a specific chart — whether it applies to the current symbol (`supported`) and whether at
|
|
524
|
+
* least one instance is already present (`present`). Produced by
|
|
515
525
|
* `chart.availableNativeIndicators()`.
|
|
516
526
|
*/
|
|
517
527
|
interface NativeIndicatorInfo {
|
|
@@ -519,8 +529,11 @@ interface NativeIndicatorInfo {
|
|
|
519
529
|
readonly title: string;
|
|
520
530
|
/** Applies to the current symbol (a type may need data the provider lacks). */
|
|
521
531
|
readonly supported: boolean;
|
|
522
|
-
/**
|
|
532
|
+
/** At least one instance is on the chart. For a single-instance type a second add is a no-op;
|
|
533
|
+
* a `multiInstance` type adds another instance regardless. */
|
|
523
534
|
readonly present: boolean;
|
|
535
|
+
/** The type allows several instances per chart (see `NativeIndicatorDescriptor.multiInstance`). */
|
|
536
|
+
readonly multiInstance?: boolean;
|
|
524
537
|
/** The type is flagged beta (for a badge in the picker). */
|
|
525
538
|
readonly beta?: boolean;
|
|
526
539
|
}
|
|
@@ -1344,23 +1357,26 @@ declare class Vela {
|
|
|
1344
1357
|
addIndicator(source: string, options?: AddIndicatorOptions): IndicatorHandle;
|
|
1345
1358
|
/**
|
|
1346
1359
|
* Add a built-in NATIVE indicator (core-computed, no scripting engine) by registered `type` —
|
|
1347
|
-
* e.g. `'vpvr'`. It becomes a first-class indicator (legend row, settings, hide,
|
|
1348
|
-
* events)
|
|
1349
|
-
*
|
|
1360
|
+
* e.g. `'vpvr'` or `'sma'`. It becomes a first-class indicator (legend row, settings, hide,
|
|
1361
|
+
* remove, events). Layer-backed types (`'volume'`, `'vpvr'`) are single-instance — a second
|
|
1362
|
+
* call returns the existing handle; the classic studies allow several instances, so each call
|
|
1363
|
+
* adds one more. Returns a fail-soft handle for an unregistered type. Native renderer only.
|
|
1350
1364
|
*/
|
|
1351
1365
|
addNativeIndicator(type: string, options?: {
|
|
1352
1366
|
inputs?: Record<string, InputValue>;
|
|
1353
1367
|
}): IndicatorHandle;
|
|
1354
1368
|
/**
|
|
1355
1369
|
* The catalog of built-in native indicators with their live state on this chart — each entry's
|
|
1356
|
-
* `type`, `title`, whether it `supported`s the current symbol,
|
|
1357
|
-
*
|
|
1358
|
-
* Lets a host "add indicator" UI list them, gate unsupported
|
|
1359
|
-
*
|
|
1370
|
+
* `type`, `title`, whether it `supported`s the current symbol, whether it's already `present`,
|
|
1371
|
+
* and whether it allows several instances (`multiInstance`; otherwise a second
|
|
1372
|
+
* `addNativeIndicator` is a no-op). Lets a host "add indicator" UI list them, gate unsupported
|
|
1373
|
+
* ones, and de-duplicate the single-instance ones. Async because support may probe the
|
|
1374
|
+
* provider (a type may need data the symbol lacks).
|
|
1360
1375
|
*/
|
|
1361
1376
|
availableNativeIndicators(): Promise<NativeIndicatorInfo[]>;
|
|
1362
1377
|
/**
|
|
1363
|
-
* The native-indicator types PRESENT on the chart right now
|
|
1378
|
+
* The native-indicator types PRESENT on the chart right now, one entry per instance (a
|
|
1379
|
+
* multi-instance type repeats) — the synchronous slice of
|
|
1364
1380
|
* {@link availableNativeIndicators} (only support probing is async; presence never is).
|
|
1365
1381
|
* Persistence snapshots read this: an unload-time flush must see an add/remove that
|
|
1366
1382
|
* happened microseconds ago, which an async catalog mirror cannot guarantee.
|
|
@@ -286,6 +286,9 @@ interface IndicatorHandle {
|
|
|
286
286
|
* (core-computed) indicator — there is no script to show. What a host editor
|
|
287
287
|
* opens when a legend action asks for "the code behind this row". */
|
|
288
288
|
readonly source?: string;
|
|
289
|
+
/** The registered type of a NATIVE (core-computed) indicator — `undefined` for a
|
|
290
|
+
* script indicator. The two are exclusive: a handle has a `source` or a `nativeType`. */
|
|
291
|
+
readonly nativeType?: string;
|
|
289
292
|
/** Inputs parsed from the Pine source (populated once the script is prepared). */
|
|
290
293
|
readonly inputs: readonly InputSchema[];
|
|
291
294
|
/** Declaration-props schema (a strategy's `initial_capital`, an indicator's
|
|
@@ -499,6 +502,13 @@ interface NativeIndicatorDescriptor {
|
|
|
499
502
|
readonly reactsToViewport?: boolean;
|
|
500
503
|
/** Marks the type as beta — surfaced in the catalog so a host "add indicator" UI can badge it. */
|
|
501
504
|
readonly beta?: boolean;
|
|
505
|
+
/**
|
|
506
|
+
* Allow several instances of this type on one chart — every add creates a new one (a study
|
|
507
|
+
* like a moving average is typically stacked at different lengths). Absent ⇒ SINGLE instance
|
|
508
|
+
* per type: a second add returns the existing handle. A type that pushes a bespoke layer
|
|
509
|
+
* payload through `pushData` must stay single-instance (the layer is keyed by type).
|
|
510
|
+
*/
|
|
511
|
+
readonly multiInstance?: boolean;
|
|
502
512
|
inputsSchema(): InputSchema[];
|
|
503
513
|
defaultInputs(): Record<string, InputValue>;
|
|
504
514
|
create(): NativeIndicator;
|
|
@@ -510,8 +520,8 @@ interface NativeIndicatorDescriptor {
|
|
|
510
520
|
}
|
|
511
521
|
/**
|
|
512
522
|
* One entry in the "add native indicator" catalog: the type's static metadata plus its live state
|
|
513
|
-
* on a specific chart — whether it applies to the current symbol (`supported`) and whether
|
|
514
|
-
* instance is already present (`present
|
|
523
|
+
* on a specific chart — whether it applies to the current symbol (`supported`) and whether at
|
|
524
|
+
* least one instance is already present (`present`). Produced by
|
|
515
525
|
* `chart.availableNativeIndicators()`.
|
|
516
526
|
*/
|
|
517
527
|
interface NativeIndicatorInfo {
|
|
@@ -519,8 +529,11 @@ interface NativeIndicatorInfo {
|
|
|
519
529
|
readonly title: string;
|
|
520
530
|
/** Applies to the current symbol (a type may need data the provider lacks). */
|
|
521
531
|
readonly supported: boolean;
|
|
522
|
-
/**
|
|
532
|
+
/** At least one instance is on the chart. For a single-instance type a second add is a no-op;
|
|
533
|
+
* a `multiInstance` type adds another instance regardless. */
|
|
523
534
|
readonly present: boolean;
|
|
535
|
+
/** The type allows several instances per chart (see `NativeIndicatorDescriptor.multiInstance`). */
|
|
536
|
+
readonly multiInstance?: boolean;
|
|
524
537
|
/** The type is flagged beta (for a badge in the picker). */
|
|
525
538
|
readonly beta?: boolean;
|
|
526
539
|
}
|
|
@@ -1344,23 +1357,26 @@ declare class Vela {
|
|
|
1344
1357
|
addIndicator(source: string, options?: AddIndicatorOptions): IndicatorHandle;
|
|
1345
1358
|
/**
|
|
1346
1359
|
* Add a built-in NATIVE indicator (core-computed, no scripting engine) by registered `type` —
|
|
1347
|
-
* e.g. `'vpvr'`. It becomes a first-class indicator (legend row, settings, hide,
|
|
1348
|
-
* events)
|
|
1349
|
-
*
|
|
1360
|
+
* e.g. `'vpvr'` or `'sma'`. It becomes a first-class indicator (legend row, settings, hide,
|
|
1361
|
+
* remove, events). Layer-backed types (`'volume'`, `'vpvr'`) are single-instance — a second
|
|
1362
|
+
* call returns the existing handle; the classic studies allow several instances, so each call
|
|
1363
|
+
* adds one more. Returns a fail-soft handle for an unregistered type. Native renderer only.
|
|
1350
1364
|
*/
|
|
1351
1365
|
addNativeIndicator(type: string, options?: {
|
|
1352
1366
|
inputs?: Record<string, InputValue>;
|
|
1353
1367
|
}): IndicatorHandle;
|
|
1354
1368
|
/**
|
|
1355
1369
|
* The catalog of built-in native indicators with their live state on this chart — each entry's
|
|
1356
|
-
* `type`, `title`, whether it `supported`s the current symbol,
|
|
1357
|
-
*
|
|
1358
|
-
* Lets a host "add indicator" UI list them, gate unsupported
|
|
1359
|
-
*
|
|
1370
|
+
* `type`, `title`, whether it `supported`s the current symbol, whether it's already `present`,
|
|
1371
|
+
* and whether it allows several instances (`multiInstance`; otherwise a second
|
|
1372
|
+
* `addNativeIndicator` is a no-op). Lets a host "add indicator" UI list them, gate unsupported
|
|
1373
|
+
* ones, and de-duplicate the single-instance ones. Async because support may probe the
|
|
1374
|
+
* provider (a type may need data the symbol lacks).
|
|
1360
1375
|
*/
|
|
1361
1376
|
availableNativeIndicators(): Promise<NativeIndicatorInfo[]>;
|
|
1362
1377
|
/**
|
|
1363
|
-
* The native-indicator types PRESENT on the chart right now
|
|
1378
|
+
* The native-indicator types PRESENT on the chart right now, one entry per instance (a
|
|
1379
|
+
* multi-instance type repeats) — the synchronous slice of
|
|
1364
1380
|
* {@link availableNativeIndicators} (only support probing is async; presence never is).
|
|
1365
1381
|
* Persistence snapshots read this: an unload-time flush must see an add/remove that
|
|
1366
1382
|
* happened microseconds ago, which an async catalog mirror cannot guarantee.
|