@luxalgo/vela 0.5.0

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.
Files changed (61) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +28 -0
  3. package/README.md +135 -0
  4. package/dist/DataProvider-DKNDHpNv.d.cts +134 -0
  5. package/dist/DataProvider-Dzd-Erlk.d.ts +134 -0
  6. package/dist/chunk-7UFX5ZIG.js +5976 -0
  7. package/dist/chunk-GYD2THPV.js +252 -0
  8. package/dist/chunk-KCCZNKH7.js +19137 -0
  9. package/dist/chunk-KM6LHB3Y.js +76 -0
  10. package/dist/chunk-OVQKKXLZ.js +3978 -0
  11. package/dist/chunk-Q3XQHLIH.js +7 -0
  12. package/dist/chunk-RHIDOUFL.js +698 -0
  13. package/dist/contributions-hX3EUyjG.d.ts +1528 -0
  14. package/dist/contributions-o1GRKPI_.d.cts +1528 -0
  15. package/dist/history-Dzxz-MQj.d.ts +298 -0
  16. package/dist/history-LJkz4-sS.d.cts +298 -0
  17. package/dist/icons-BZYbJXSV.d.cts +10 -0
  18. package/dist/icons-BZYbJXSV.d.ts +10 -0
  19. package/dist/index.cjs +25294 -0
  20. package/dist/index.d.cts +1189 -0
  21. package/dist/index.d.ts +1189 -0
  22. package/dist/index.js +5 -0
  23. package/dist/keymap-CGOz5F5f.d.cts +64 -0
  24. package/dist/keymap-CGOz5F5f.d.ts +64 -0
  25. package/dist/options-Q-576hIi.d.cts +1545 -0
  26. package/dist/options-Q-576hIi.d.ts +1545 -0
  27. package/dist/plugin-D94muTV-.d.cts +405 -0
  28. package/dist/plugin-aGUD1epn.d.ts +405 -0
  29. package/dist/plugin.cjs +5967 -0
  30. package/dist/plugin.d.cts +7 -0
  31. package/dist/plugin.d.ts +7 -0
  32. package/dist/plugin.js +3 -0
  33. package/dist/providers/binance.cjs +390 -0
  34. package/dist/providers/binance.d.cts +62 -0
  35. package/dist/providers/binance.d.ts +62 -0
  36. package/dist/providers/binance.js +388 -0
  37. package/dist/providers/coinbase.cjs +462 -0
  38. package/dist/providers/coinbase.d.cts +59 -0
  39. package/dist/providers/coinbase.d.ts +59 -0
  40. package/dist/providers/coinbase.js +460 -0
  41. package/dist/providers/hyperliquid.cjs +361 -0
  42. package/dist/providers/hyperliquid.d.cts +54 -0
  43. package/dist/providers/hyperliquid.d.ts +54 -0
  44. package/dist/providers/hyperliquid.js +359 -0
  45. package/dist/side-panel-CT9ZwIGz.d.cts +63 -0
  46. package/dist/side-panel-CT9ZwIGz.d.ts +63 -0
  47. package/dist/ui.cjs +1030 -0
  48. package/dist/ui.d.cts +188 -0
  49. package/dist/ui.d.ts +188 -0
  50. package/dist/ui.js +3 -0
  51. package/dist/vela.global.js +26509 -0
  52. package/dist/vela.global.min.js +230 -0
  53. package/dist/widget.cjs +31178 -0
  54. package/dist/widget.d.cts +799 -0
  55. package/dist/widget.d.ts +799 -0
  56. package/dist/widget.js +1060 -0
  57. package/dist/workspace.cjs +31692 -0
  58. package/dist/workspace.d.cts +579 -0
  59. package/dist/workspace.d.ts +579 -0
  60. package/dist/workspace.js +1694 -0
  61. package/package.json +95 -0
@@ -0,0 +1,799 @@
1
+ import { W as WidgetContext, V as Vela, y as SidePanelButton } from './contributions-hX3EUyjG.js';
2
+ export { ah as DEFAULT_PANEL_ORDER, z as SidePanelDescriptor, A as SidePanelHandle, U as WidgetActionDescriptor, X as WidgetActionTarget, Y as WidgetAttachment, a4 as registerSidePanel, a5 as registerWidgetAction, a6 as registerWidgetAttachment, a8 as sidePanels, ac as unregisterSidePanel, ad as unregisterWidgetAction, ae as unregisterWidgetAttachment, af as widgetActions, ag as widgetAttachments } from './contributions-hX3EUyjG.js';
3
+ import { b as VelaOptions, q as DataWindowReadout } from './options-Q-576hIi.js';
4
+ import { K as KeymapManager } from './keymap-CGOz5F5f.js';
5
+ import { W as WidgetHistory, b as VelaShellOptions, e as WorkspaceState, a as RangePreset, i as PersistedState, P as PanelsState } from './history-Dzxz-MQj.js';
6
+ export { B as Bottombar, j as BottombarOptions, C as CellState, f as ChartState, I as IndicatorLoader, k as IndicatorManifest, l as IndicatorManifestEntry, m as RANGE_PRESETS, R as ResolvedIndicator, V as VelaStorage, n as WidgetStorage, g as decodeState, h as encodeState, o as legacyWidgetState, p as loadPersisted, q as localStorageAdapter, r as parsePersisted, t as resolveIndicators, s as sanitizeState, u as savePersisted } from './history-Dzxz-MQj.js';
7
+ import { a as SymbolDescriptor } from './DataProvider-Dzd-Erlk.js';
8
+ import { d as SidePanel } from './side-panel-CT9ZwIGz.js';
9
+ export { D as DEFAULT_PANEL_MAX_WIDTH, a as DEFAULT_PANEL_MIN_WIDTH, b as DEFAULT_PANEL_WIDTH, S as SidePanelOptions, c as clampPanelWidth } from './side-panel-CT9ZwIGz.js';
10
+
11
+ interface VelaWidgetOptions extends VelaOptions, VelaShellOptions {
12
+ /** Mirror symbol/timeframe/style/timezone in the URL query (shareable links). A URL
13
+ * param wins over persisted state at load. Default false. */
14
+ urlState?: boolean;
15
+ }
16
+ declare class VelaWidget {
17
+ readonly root: HTMLElement;
18
+ /** The shortcut system — widget modules and plugins register their bindings here. */
19
+ readonly keymap: KeymapManager;
20
+ private readonly opts;
21
+ private readonly chartHost;
22
+ private readonly topbar;
23
+ private readonly statusline;
24
+ private readonly watermark;
25
+ private readonly bottombar;
26
+ private readonly objectTree;
27
+ private readonly dataWindow;
28
+ /** The side-panel column: the two panels above, plus every contributed one. */
29
+ private readonly dock;
30
+ private shortcutsHelp;
31
+ private readonly contextMenu;
32
+ private readonly symbolPicker;
33
+ private readonly indicatorPicker;
34
+ private readonly tfQuick;
35
+ private inner;
36
+ /** The manifest library (loaded once). */
37
+ private manifest;
38
+ /** Live instances — the SAME entry may be added several times. */
39
+ private instances;
40
+ /** Native-indicator catalog of the CURRENT chart (refreshed per rebuild/change). */
41
+ private nativeCatalog;
42
+ /** Present native types, mirrored SYNC from the chart (see syncPresentNatives). */
43
+ private presentNatives;
44
+ private readonly storageKey;
45
+ private readonly storage;
46
+ private openDialogs;
47
+ private readonly onRootKeydown;
48
+ private symbol;
49
+ private timeframe;
50
+ private priceStyle;
51
+ private timezone;
52
+ private bars;
53
+ private watermarkOn;
54
+ /** Indicator titles (the in-chart legend rows) shown — reapplied across rebuilds. */
55
+ private indicatorTitlesOn;
56
+ private pendingRange;
57
+ /** Symbol already reported as unservable (the core re-reports on every index settle). */
58
+ private unresolvedToasted;
59
+ /** Extra fetch depth the ACTIVE range chip needs — a view concern, kept apart from the
60
+ * user's own `bars` setting so a preset never overwrites their preference. */
61
+ private rangeBars;
62
+ private toast;
63
+ private alerts;
64
+ private alertsMenu;
65
+ private readonly glider;
66
+ /** Unified app+drawings undo timeline (Ctrl+Z / Ctrl+Y). Late-resolves the CURRENT
67
+ * inner chart so steps recorded before a rebuild never act on a destroyed instance. */
68
+ readonly history: WidgetHistory;
69
+ private lastCrossPrice;
70
+ private lastCrossTime;
71
+ /** Renderer cosmetic template carried across rebuilds (and persisted when enabled). */
72
+ private savedConfig;
73
+ /** User-drawings document carried across rebuilds (and persisted when enabled). */
74
+ private savedDrawings;
75
+ /** A restored indicator ledger waiting for the manifest to resolve. */
76
+ private pendingIndicators;
77
+ /** Volume presence decided by a RESTORED ledger (null = follow the option). */
78
+ private ledgerVolume;
79
+ /** The manifest can no longer change the instance set: it resolved, or no `indicators`
80
+ * option exists so nothing will ever resolve. Gates the ledger's pending fallback —
81
+ * once settled, a live empty set means "the user removed everything" and persists so. */
82
+ private manifestSettled;
83
+ /** The volume auto-add rides the first candles (`load:end`); until then the registry
84
+ * can't show it and the persisted ledger reports the INTENT instead. */
85
+ private volumeMayBePending;
86
+ /** True when the boot state came from the LEGACY three-key layout — the first
87
+ * unified save then drops the old `:config`/`:drawings` sub-keys. */
88
+ private legacyKeys;
89
+ private stateTimer;
90
+ private readonly stateListeners;
91
+ /** Favorite drawing-tool types — mirrored from chart events, reapplied on rebuilds. */
92
+ private favs;
93
+ /** Mounted attachment disposers (by id), torn down at destroy. */
94
+ private readonly attachmentDisposers;
95
+ private readonly onUnload;
96
+ private indicatorsPromise;
97
+ private destroyed;
98
+ private buildSeq;
99
+ constructor(container: HTMLElement | string, opts: VelaWidgetOptions);
100
+ /** Mount registered attachments not yet mounted on this widget (idempotent per id). */
101
+ private mountAttachments;
102
+ /** The context handed to contributed actions (see `registerWidgetAction`). */
103
+ context(): WidgetContext;
104
+ /** The recent engine alerts (topbar bell). */
105
+ private openAlertsMenu;
106
+ /** Re-project contributed topbar actions and side panels (after late registrations). */
107
+ refreshActions(): void;
108
+ /** The inner headless chart of the CURRENT build — becomes a new instance after a
109
+ * symbol/timeframe change; don't cache it across awaits. */
110
+ get chart(): Vela;
111
+ /** Chrome that must follow the timeframe wherever it changes from (menu, quick entry,
112
+ * range chip, API). Keeping it in one place is what stopped the status line from
113
+ * drifting out of sync with the topbar. */
114
+ private syncTimeframeChrome;
115
+ /**
116
+ * The provider name to show: the one that RESOLVED the symbol, not the one configured.
117
+ * They differ whenever the `provider` option is just a default (or names something that
118
+ * isn't registered) — the status line must not claim a venue that served nothing.
119
+ */
120
+ private providerLabel;
121
+ setTimeframe(tf: string): void;
122
+ /**
123
+ * Switch the chart symbol in place. An `EXCHANGE:` prefix pins the venue (the
124
+ * symbol picker composes one from the row the user pointed at) — a bare ticker
125
+ * resolves against the registered providers in declaration order.
126
+ */
127
+ setSymbol(symbol: string): void;
128
+ /**
129
+ * Snapshot the COMPLETE widget state as the unified shell document — the SAME
130
+ * format `VelaWorkspace.getState()` returns, with a single `c1` cell: market,
131
+ * display prefs, the renderer config document, the user-drawings document, and
132
+ * the indicator ledger. This is what `persist` writes; hosts build custom flows
133
+ * on it (server snapshots, share links, templates) — and a saved widget state
134
+ * drops into a workspace slot as-is.
135
+ */
136
+ getState(): WorkspaceState;
137
+ /**
138
+ * Restore a state document produced by {@link getState} — or by a WORKSPACE (the
139
+ * first cell of a multi-cell document applies). Untrusted-safe: malformed fields
140
+ * are dropped. Applied IN PLACE: the chart instance survives (market switches via
141
+ * `setMarket`), config/drawings/indicators are replaced. With `urlState` enabled,
142
+ * URL params still win over the document's market/prefs fields.
143
+ */
144
+ applyState(state: unknown): void;
145
+ /** Subscribe to `state:changed` — the persistable state changed (debounced ~500ms);
146
+ * re-pull {@link getState}. Returns an unsubscribe function. */
147
+ on(event: 'state:changed', handler: () => void): () => void;
148
+ /** Replace the indicator ledger: natives converge to the listed set (volume
149
+ * included — removing it sticks, the core's auto-add respects the opt-out),
150
+ * manifest instances are re-created by name — held until the manifest resolves. */
151
+ private applyIndicatorLedger;
152
+ /** SYNC boot fallback: a LEGACY three-key payload read at construction. */
153
+ private bootLegacySync;
154
+ /** ASYNC boot: resolve the unified document (or migrate a legacy payload), then
155
+ * late-apply it — the widget built with option defaults in the meantime. */
156
+ private bootAsync;
157
+ /** Show/hide the symbol watermark behind the chart (persisted). */
158
+ setWatermarkVisible(visible: boolean): void;
159
+ /** Show/hide the indicator titles — the in-chart legend rows (persisted). */
160
+ setIndicatorTitlesVisible(visible: boolean): void;
161
+ /** Applied LIVE (renderer feature) — no rebuild; persists across rebuilds. */
162
+ setPriceStyle(style: string): void;
163
+ /** OHLC/change ink in the status line follows the ACTIVE price style's configured
164
+ * colors and direction rule (candle bodies by close-vs-open, baseline by position
165
+ * against the live baseline price, …) instead of the fixed theme tokens. */
166
+ private syncStatuslineColors;
167
+ /** The widget shell (topbar, panels) keeps the app theme; the chart host's tokens
168
+ * re-derive from the LIVE plot surface (see {@link applyPlotOverlayTokens}). */
169
+ private syncPlotOverlayTokens;
170
+ /**
171
+ * Swap the widget theme at runtime — `'dark'`, `'light'`, or a full custom theme.
172
+ * Applied LIVE: the inner chart re-skins through `Vela.setTheme` and its
173
+ * `theme:changed` event re-tokens the widget chrome (topbar, menus, panels) in
174
+ * place; the choice also persists into rebuilds. Same switch the user reaches from
175
+ * chart settings → Canvas → Theme.
176
+ */
177
+ setTheme(theme: NonNullable<VelaOptions['theme']>): void;
178
+ /** Applied LIVE (renderer feature) — no rebuild; persists across rebuilds. */
179
+ setTimezone(zone: string): void;
180
+ /**
181
+ * Range chip: switch to the preset's timeframe, fetch enough history for its window,
182
+ * and frame it once ready. The in-place `setMarket` loads the depth, so it also runs
183
+ * when only the DEPTH grows (same timeframe, deeper window).
184
+ */
185
+ applyRange(preset: RangePreset): void;
186
+ destroy(): void;
187
+ /** Destroy + recreate the inner chart with the current symbol/timeframe, then
188
+ * re-register providers/engines, rebind chrome, and re-add manifest indicators. */
189
+ private rebuild;
190
+ /** Refresh the native catalog (supported/present flags) for the current chart. */
191
+ private refreshNativeCatalog;
192
+ /** Add a native indicator (single-instance per type — the core dedupes). */
193
+ private addNative;
194
+ private removeNative;
195
+ /** Sync mirror of the chart's present native types — the removal handler diffs
196
+ * against it to identify (and record) whichever type was just removed. */
197
+ private syncPresentNatives;
198
+ /** Add ONE instance of a manifest entry (repeatable — duplicates are legitimate). */
199
+ private addInstance;
200
+ /** Remove one live instance (picker trash). */
201
+ private removeInstance;
202
+ private dropInstance;
203
+ private syncIndicatorCount;
204
+ private addToChart;
205
+ /** Bare-typing router: letters → symbol search (seeded), digits → timeframe entry. */
206
+ private routeTyping;
207
+ private trackDialog;
208
+ private downloadScreenshot;
209
+ /** The persistable state changed: debounce (~500ms), then notify `state:changed`
210
+ * listeners and flush — the same cadence as the workspace. */
211
+ private markStateDirty;
212
+ /** Write the unified state document through the adapter (persist mode only) — also
213
+ * the unload/destroy flush. The first save after a LEGACY boot rewrites the main
214
+ * key in the unified format and drops the old `:config`/`:drawings` sub-keys. */
215
+ private persistNow;
216
+ }
217
+
218
+ declare function priceStyleLabel(id: string): string;
219
+ interface TopbarOptions {
220
+ symbol: string;
221
+ onSymbolClick?: () => void;
222
+ timeframe: string;
223
+ timeframes: readonly string[];
224
+ priceStyle: string;
225
+ onTimeframe: (tf: string) => void;
226
+ onPriceStyle: (style: string) => void;
227
+ /** Optional workspace LAYOUT dropdown (rendered after the style dropdown when given).
228
+ * `options` is read live, so plugin-registered layouts appear automatically. */
229
+ layout?: {
230
+ current: string;
231
+ options: () => Array<{
232
+ id: string;
233
+ label: string;
234
+ }>;
235
+ onSelect: (id: string) => void;
236
+ /** Optional TOGGLE rows appended under the layout presets (e.g. the workspace's
237
+ * "Sync crosshair"). Re-read on every open/refresh; `onToggle` flips one. */
238
+ toggles?: () => Array<{
239
+ id: string;
240
+ label: string;
241
+ checked: boolean;
242
+ }>;
243
+ onToggle?: (id: string) => void;
244
+ };
245
+ onIndicatorsClick?: () => void;
246
+ /** Unified undo/redo (same stack as Ctrl+Z / Ctrl+Y). Enabled state is pushed with
247
+ * {@link Topbar.setHistoryState}. */
248
+ onUndoClick?: () => void;
249
+ onRedoClick?: () => void;
250
+ onScreenshotClick?: () => void;
251
+ onAlertsClick?: (anchor: HTMLElement) => void;
252
+ /** Live widget context for contributed actions (topbar target). */
253
+ getContext?: () => WidgetContext;
254
+ }
255
+ declare class Topbar {
256
+ readonly el: HTMLElement;
257
+ private readonly symbolEl;
258
+ private readonly tfButton;
259
+ private readonly styleButton;
260
+ private layoutButton;
261
+ private layoutMenu;
262
+ private layoutId;
263
+ private readonly tfMenu;
264
+ private readonly styleMenu;
265
+ private readonly tooltips;
266
+ private readonly actionsHost;
267
+ /** The side-panel toggle group — filled by the dock through {@link setPanelButtons}. */
268
+ private readonly panelsHost;
269
+ private undoBtn;
270
+ private redoBtn;
271
+ private alertsBtn;
272
+ private panelBtns;
273
+ private panelTooltips;
274
+ private readonly host;
275
+ private alertsBadge;
276
+ private readonly opts;
277
+ private timeframe;
278
+ private priceStyle;
279
+ private readonly onHairlineSync;
280
+ private hairlineRo;
281
+ private hairlineRaf;
282
+ constructor(host: HTMLElement, opts: TopbarOptions);
283
+ setSymbol(symbol: string): void;
284
+ setTimeframe(tf: string): void;
285
+ setPriceStyle(style: string): void;
286
+ /** Reflect the current workspace layout (no-op without the layout dropdown). */
287
+ setLayout(id: string): void;
288
+ private renderLayoutButton;
289
+ private layoutItems;
290
+ private renderStyleButton;
291
+ /** Re-project the contributed topbar actions (call after registrations change). */
292
+ renderActions(): void;
293
+ setIndicatorCount(_n: number): void;
294
+ /** Enable/disable the undo and redo tools from the host's unified history. */
295
+ setHistoryState(canUndo: boolean, canRedo: boolean): void;
296
+ setAlertCount(n: number): void;
297
+ /**
298
+ * Replace the side-panel toggle group — one icon button per docked panel, in the dock's own
299
+ * order. The dock calls this whenever its panel set changes (built-ins at construction,
300
+ * contributed panels on every `refreshActions()`), then pushes each pressed state.
301
+ */
302
+ setPanelButtons(buttons: readonly SidePanelButton[], onClick: (id: string) => void): void;
303
+ /** Reflect a docked side panel's open state on its button — the panels toggle each other,
304
+ * so the dock pushes the state rather than the button assuming it. */
305
+ setPanelActive(id: string, open: boolean): void;
306
+ destroy(): void;
307
+ /** One icon-only tool button with its kit tooltip, parked in `sink` for disposal. */
308
+ private toolButton;
309
+ /** Paint each `.vela-sep` as exactly one device pixel, snapped to the pixel grid. */
310
+ private syncHairlines;
311
+ private tfItems;
312
+ private styleItems;
313
+ }
314
+
315
+ /** How the status line reads a bar out: the four O/H/L/C values (bar-shaped styles),
316
+ * or the single plotted value — the close — for one-line styles (line/area/baseline). */
317
+ type StatuslineReadout = 'ohlc' | 'value';
318
+ /** The market session states the status badge can wear. Crypto venues trade
319
+ * continuously and stay 'open'; the full vocabulary is ready for providers that
320
+ * carry a session model (equities RTH/ETH, exchange holidays). */
321
+ type MarketStatus = 'open' | 'pre' | 'post' | 'closed' | 'holiday';
322
+ declare class Statusline {
323
+ private readonly host;
324
+ readonly el: HTMLElement;
325
+ private readonly ohlcEl;
326
+ private readonly changeEl;
327
+ private readonly symbolEl;
328
+ private readonly marketEl;
329
+ private marketTip;
330
+ private avatarEl;
331
+ private metaEl;
332
+ private readonly parts;
333
+ private lastBar;
334
+ private hoverBar;
335
+ private unsubs;
336
+ /** Up/down ink for the OHLC + change values — the ACTIVE price style's configured
337
+ * colors (candle bodies, bar ticks, the line color, …); null falls back to the theme
338
+ * tokens. `isUp` overrides the close-vs-open direction rule where the style paints by
339
+ * something else (baseline: position against the baseline price). */
340
+ private upColor;
341
+ private downColor;
342
+ private isUp;
343
+ /** 'ohlc' for bar-shaped styles; 'value' (the single plotted close) for line styles. */
344
+ private readout;
345
+ constructor(host: HTMLElement, symbol: string);
346
+ setSymbol(symbol: string): void;
347
+ /** Shape + color the value readout after the active price style: its own up/down
348
+ * colors (candle bodies, bar ticks, the line color, …), the direction rule that
349
+ * picks between them (`isUp` replaces close-vs-open where the style paints by
350
+ * something else — baseline by position), and whether the readout is the four
351
+ * O/H/L/C values or the single plotted value (one-line styles). Null colors fall
352
+ * back to the theme's up/down tokens. See {@link statuslineInkOf}, which derives
353
+ * all of it from the live renderer. */
354
+ setDirectionColors(up: string | null, down: string | null, isUp?: ((bar: {
355
+ open: number;
356
+ close: number;
357
+ }) => boolean) | null, readout?: StatuslineReadout): void;
358
+ /** Show/hide one part (the settings dialog's Status line tab drives these). */
359
+ /** The "· BINANCE · 1h" segment after the symbol — venue first, then resolution. */
360
+ setMeta(timeframe: string, provider: string): void;
361
+ /** Dress the market badge for a session state: its icon, tinted circle, and the
362
+ * hover label. Callers with no session model leave the constructor's 'open'. */
363
+ setMarketStatus(status: MarketStatus): void;
364
+ setPartVisible(part: 'name' | 'market' | 'ohlc' | 'change', visible: boolean): void;
365
+ partVisible(part: 'name' | 'market' | 'ohlc' | 'change'): boolean;
366
+ /** (Re)bind to a chart instance — called after every widget rebuild. */
367
+ onChart(chart: Vela): void;
368
+ destroy(): void;
369
+ private detach;
370
+ private render;
371
+ }
372
+
373
+ declare class Watermark {
374
+ readonly el: HTMLElement;
375
+ constructor(host: HTMLElement, symbol: string, timeframe: string);
376
+ setVisible(visible: boolean): void;
377
+ update(symbol: string, timeframe: string): void;
378
+ destroy(): void;
379
+ }
380
+
381
+ /**
382
+ * Rank: ticker prefix > ticker substring > description substring > venue-name substring (typing
383
+ * `binance` surfaces that venue's symbols after any literal matches). An optional venue prefix
384
+ * (see {@link parseQuery}) scopes the pool first — venue alone browses it whole, alphabetically.
385
+ * Pure — unit-tested.
386
+ */
387
+ declare function filterSymbols(list: readonly SymbolDescriptor[], query: string, limit?: number): SymbolDescriptor[];
388
+ interface SymbolPickerOptions {
389
+ /** `provider` is the venue of the chosen row — absent only for a source that has none. */
390
+ /** Called with the CHOSEN symbol — `EXCHANGE:`-prefixed when the row named a venue,
391
+ * so the selection pins the venue the user actually pointed at. */
392
+ onSelect: (symbol: string) => void;
393
+ onOpenChange?: (open: boolean) => void;
394
+ host?: HTMLElement;
395
+ }
396
+ declare class SymbolPicker {
397
+ private readonly dialog;
398
+ private readonly input;
399
+ private readonly list;
400
+ private source;
401
+ private rows;
402
+ private highlighted;
403
+ private seed;
404
+ private activeTab;
405
+ private tabs;
406
+ constructor(opts: SymbolPickerOptions);
407
+ /** Wire where symbols come from (re-called on every widget rebuild). */
408
+ setSource(source: () => readonly SymbolDescriptor[]): void;
409
+ open(initialQuery?: string): void;
410
+ close(): void;
411
+ destroy(): void;
412
+ private select;
413
+ private moveHighlight;
414
+ private renderHighlight;
415
+ private refresh;
416
+ }
417
+
418
+ interface IndicatorRow {
419
+ name: string;
420
+ language?: string;
421
+ category?: string;
422
+ /** Core-computed (native) indicator — accent styling + 'native' routing. */
423
+ native?: boolean;
424
+ /** Native type id (routing key for add/remove). */
425
+ nativeType?: string;
426
+ /** Beta badge (native catalog flag). */
427
+ beta?: boolean;
428
+ }
429
+ interface IndicatorPickerOptions {
430
+ /** The manifest library — clicking a row ADDS an instance (repeatable). */
431
+ library: () => readonly IndicatorRow[];
432
+ /** The live instances on the chart — the trash removes one. */
433
+ onChart: () => readonly IndicatorRow[];
434
+ onAdd: (libraryIndex: number) => void;
435
+ onRemove: (instanceIndex: number) => void;
436
+ onOpenChange?: (open: boolean) => void;
437
+ host?: HTMLElement;
438
+ }
439
+ declare class IndicatorPicker {
440
+ private readonly dialog;
441
+ private readonly list;
442
+ private readonly search;
443
+ private readonly opts;
444
+ private isOpen;
445
+ constructor(opts: IndicatorPickerOptions);
446
+ open(): void;
447
+ /** Re-render the lists if the dialog is open (async catalog updates land late). */
448
+ sync(): void;
449
+ close(): void;
450
+ destroy(): void;
451
+ private refresh;
452
+ }
453
+
454
+ interface TimeframeQuickOptions {
455
+ onApply: (canonical: string) => void;
456
+ onOpenChange?: (open: boolean) => void;
457
+ host?: HTMLElement;
458
+ }
459
+ declare class TimeframeQuick {
460
+ private readonly dialog;
461
+ private readonly input;
462
+ private readonly hint;
463
+ constructor(opts: TimeframeQuickOptions);
464
+ open(seed?: string): void;
465
+ close(): void;
466
+ destroy(): void;
467
+ private renderHint;
468
+ }
469
+
470
+ declare function readUrlState(search: string): PersistedState;
471
+ declare function writeUrlState(state: PersistedState): void;
472
+
473
+ /** What the dock needs from whatever chrome shows its toggles. */
474
+ interface PanelChrome {
475
+ /** Replace the panel toggle group (dock order). `onClick` receives the panel id. */
476
+ setPanelButtons(buttons: readonly SidePanelButton[], onClick: (id: string) => void): void;
477
+ /** Reflect one panel's open state on its button. */
478
+ setPanelActive(id: string, open: boolean): void;
479
+ }
480
+ interface PanelDockDeps {
481
+ chrome: PanelChrome;
482
+ /** Live widget context, handed to contributed panels' `mount`. */
483
+ context(): WidgetContext;
484
+ /** The dock's persistable state changed (open panel, or a width). */
485
+ changed?(): void;
486
+ }
487
+ /** A panel the SHELL owns and destroys — the dock only docks it. */
488
+ interface BuiltInPanel {
489
+ id: string;
490
+ title: string;
491
+ icon: string;
492
+ order: number;
493
+ panel: SidePanel;
494
+ /** Rebind hook, called by {@link PanelDock.onChart}. */
495
+ onChart?(chart: Vela): void;
496
+ }
497
+ declare class PanelDock {
498
+ private readonly host;
499
+ private readonly deps;
500
+ private readonly entries;
501
+ /** Widths the USER settled, by panel id — the only ones worth persisting. */
502
+ private readonly widths;
503
+ /** A restored `open` naming a panel that has not registered yet: honored when it docks. */
504
+ private pendingOpen;
505
+ private chart;
506
+ constructor(host: HTMLElement, deps: PanelDockDeps);
507
+ /** Dock a panel the shell owns (created and destroyed by it). */
508
+ addBuiltIn(entry: BuiltInPanel): void;
509
+ /**
510
+ * (Re)build the CONTRIBUTED panels from the registry — call once after the built-ins, and
511
+ * again on `refreshActions()` so a late registration appears. Contributed panels that are
512
+ * gone from the registry are dropped; the ones still there are rebuilt, so a replaced
513
+ * descriptor takes effect.
514
+ */
515
+ refresh(): void;
516
+ /** Bind (or rebind) every docked panel to a chart instance. */
517
+ onChart(chart: Vela): void;
518
+ /** Open/close one panel by id — a bare call flips it. Unknown ids are ignored. */
519
+ toggle(id: string, open?: boolean): void;
520
+ /** The open panel's id, or null when the column is closed. */
521
+ get openId(): string | null;
522
+ /** The dock's persistable state, or null when there is nothing worth saving. */
523
+ getState(): PanelsState | null;
524
+ /**
525
+ * Restore a persisted dock state. Widths apply to any panel present, and are remembered for
526
+ * panels that register later; `open` opens that panel, and its absence closes the column —
527
+ * a document that predates the dock has no `panels` field at all, so the shell never calls
528
+ * this and the default (everything closed) stands. An `open` naming a panel that has not
529
+ * registered yet is held until it docks (a plugin loaded after the restore), unless the user
530
+ * opens something in the meantime.
531
+ */
532
+ applyState(state: PanelsState | undefined): void;
533
+ /** Drop the contributed panels (the shell destroys its own). */
534
+ destroy(): void;
535
+ private add;
536
+ private drop;
537
+ /** Push the current toggle group to the chrome, pressed states included. */
538
+ private publish;
539
+ }
540
+
541
+ declare class ObjectTree extends SidePanel {
542
+ private chart;
543
+ private selectedDrawing;
544
+ private symbolName;
545
+ /** Drawing bundles — a view-side grouping, held for the panel's lifetime and never persisted.
546
+ * Kept per chart because a workspace points this one panel at whichever chart is active, and
547
+ * each chart's bundles have to survive the switch. */
548
+ private readonly groupsPerChart;
549
+ /** Group ids currently folded shut. Ids are never reused, so entries left behind by a group
550
+ * that is gone are inert and can outlive it. */
551
+ private collapsed;
552
+ /** Drawings picked IN THE PANEL — what the selection bar and "group selection" act on. */
553
+ private picked;
554
+ /** The group showing its rename field, if any. */
555
+ private renaming;
556
+ /** Set while the panel pushes its pick to the chart, so the `drawing:selected` that comes
557
+ * back is recognised as our own echo instead of a fresh chart-side selection. */
558
+ private syncingSelection;
559
+ private groupSeq;
560
+ private unsubs;
561
+ private get groups();
562
+ private set groups(value);
563
+ /** The last render's model, kept so a right-click reads the same state the rows show. */
564
+ private pass;
565
+ private menu;
566
+ private menuActions;
567
+ private drag;
568
+ constructor(host: HTMLElement);
569
+ toggle(open?: boolean): void;
570
+ setSymbol(symbol: string): void;
571
+ /** (Re)bind to a chart instance — called after every widget rebuild. */
572
+ onChart(chart: Vela): void;
573
+ destroy(): void;
574
+ private detach;
575
+ /** Read the chart into the layout's input. Every chart query happens here, once a pass. */
576
+ private snapshot;
577
+ /**
578
+ * Repaint because something changed — unless the panel is mid-interaction. A live drag
579
+ * resolves drops against the rows as currently rendered, and a rename lives in an input
580
+ * that a repaint would destroy mid-word. Both end by painting themselves.
581
+ */
582
+ private refresh;
583
+ private render;
584
+ /** What the panel itself can do to the selected drawings: bundle them into a group, or
585
+ * duplicate all of them. Always in place, dim until there is a selection to act on. */
586
+ private selectionBar;
587
+ /** The band between two pane blocks. With re-paning available it is a drop zone that opens
588
+ * a fresh pane there; otherwise it is just the separator. `before`/`after` name the panes
589
+ * it sits between (either end is open at the edges of the list). */
590
+ private gapEl;
591
+ /**
592
+ * A pane, read top to bottom as front to back: ONE column holding its drawings, its
593
+ * indicators and (in the main pane) the candles, in draw order. Every child of the stack
594
+ * element is one slot, so a drop position is read straight off the rendered geometry.
595
+ */
596
+ private paneBlock;
597
+ /** One top-level drawing entry: a lone drawing's row, or a group block — its header plus,
598
+ * unfolded, a member row for each drawing it holds. */
599
+ private unitEl;
600
+ /** The pane's name plus its ops: a study pane can move in the stack and collapse; every
601
+ * pane can be maximized. */
602
+ private paneHead;
603
+ private rowEl;
604
+ /** A group's header: fold arrow, its name (or the rename field), then actions that apply to
605
+ * every member at once. Reports "all hidden"/"all locked" rather than a mixed state.
606
+ *
607
+ * The state comes from the whole bundle, not from the members listed under this pane: should
608
+ * a member end up on another pane, the header still speaks for the group its actions affect.
609
+ */
610
+ private groupRow;
611
+ private drawRow;
612
+ /** Clicking a drawing picks it; holding the platform's modifier extends the pick, and
613
+ * clicking the only picked row clears it. The chart mirrors whatever comes out. */
614
+ private onDrawClick;
615
+ /** Push the panel's pick onto the chart, muting the `drawing:selected` echo it causes. */
616
+ private selectOnChart;
617
+ /** The shared row shell: icon, name, optional tag, then the action buttons. */
618
+ private row;
619
+ private btn;
620
+ /** Bundle drawings into a fresh group, which takes over the pick. */
621
+ private makeGroup;
622
+ private commitRename;
623
+ /** Dissolve a group. `withMembers` also deletes the drawings it held. */
624
+ private removeGroup;
625
+ /** Apply one patch to every member of a group as a single undo step. */
626
+ private setMembers;
627
+ /** Duplicate a drawing, keeping the copy in the same group as its original — the chart has
628
+ * no notion of our groups, so the new id has to be spotted and filed here. */
629
+ private cloneInto;
630
+ private onPointerDown;
631
+ private onDragMove;
632
+ private beginDrag;
633
+ /** The rendered row a session started from — scanned rather than selected, so an id
634
+ * carrying CSS-special characters needs no escaping. */
635
+ private sourceRow;
636
+ /** What a drop at this point would do. Measured off the live geometry, which is why a
637
+ * refresh is suspended for the duration of the drag. */
638
+ private resolveDrop;
639
+ private paintDropHint;
640
+ /** Close the session out: `apply` false abandons the move (a cancelled pointer, a teardown). */
641
+ private endDrag;
642
+ private applyDrop;
643
+ /**
644
+ * Land a drop in a pane's stack: place the dragged tokens (the candles, an indicator, a
645
+ * drawing, or a group's whole run of drawings) at the measured position, then renormalize
646
+ * the pane's z keys in one sweep — `candleZOrder`/`seriesOrder` for the series, a single
647
+ * `updateMany` (one undo step) for the drawings, re-paning the ones that crossed panes.
648
+ */
649
+ private applySlotDrop;
650
+ /** Renormalize one pane's z keys from a placed token stack: the series through the
651
+ * renderer's order settings, the drawings as ONE `updateMany` (a single undo step),
652
+ * re-paning the dragged ones that arrived from another pane. */
653
+ private writeStack;
654
+ /** Move a group's whole run to an end of its pane's stack — the menu twin of dragging it
655
+ * to the top or the bottom of the column. */
656
+ private restackGroup;
657
+ /** The drawings a session moves: a group carries every member, front-most first, so the
658
+ * bundle keeps its own stacking wherever it lands. */
659
+ private draggedDrawings;
660
+ private onContextMenu;
661
+ private itemsForRow;
662
+ /** The nearest kit host, which is where anything floating has to mount: outside it the
663
+ * theme's custom properties don't resolve and the surface renders unstyled. */
664
+ private uiHost;
665
+ /** The menu, built on first use — by then the panel is mounted, so the theme host resolves. */
666
+ private ensureMenu;
667
+ private findIndicatorRow;
668
+ private priceMenu;
669
+ /** The pane's stacking extremes as of now — what a front/back command has to beat. The z
670
+ * keys are plain numbers, not commands, so the writer beats the extremes itself; with a
671
+ * shared draw-order space the drawings' keys count too. */
672
+ private stackBounds;
673
+ private indicatorMenu;
674
+ /** "Move to …" entries for an indicator — only the moves that would change something. */
675
+ private moveItems;
676
+ private drawingMenu;
677
+ /** The grouping half of a drawing's menu: what it can do about the bundle it is (or isn't)
678
+ * part of. Only the moves that mean something for this row are offered. */
679
+ private groupingItems;
680
+ private groupMenu;
681
+ /** Forget everything that refers to a drawing or group the chart no longer has — otherwise a
682
+ * deleted drawing would keep a group alive, or stay counted in the selection bar. */
683
+ private prune;
684
+ }
685
+
686
+ /** One readout line. `color` empty ⇒ the value inherits the panel's text color. */
687
+ interface DataWindowLine {
688
+ label: string;
689
+ value: string;
690
+ color: string;
691
+ }
692
+ /** A titled block of readout lines. */
693
+ interface DataWindowSection {
694
+ title: string;
695
+ lines: DataWindowLine[];
696
+ }
697
+ /**
698
+ * Lay a readout out as sections: the bar's Time, its Price block (tinted with the bar's
699
+ * direction), then one section per indicator with a line per plot in the plot's own color.
700
+ * Empty when the chart holds no bar to read.
701
+ */
702
+ declare function dataWindowSections(readout: DataWindowReadout): DataWindowSection[];
703
+ declare class DataWindow extends SidePanel {
704
+ private chart;
705
+ private unsubs;
706
+ constructor(host: HTMLElement);
707
+ toggle(open?: boolean): void;
708
+ /** (Re)bind to a chart instance — called after every widget rebuild. */
709
+ onChart(chart: Vela): void;
710
+ destroy(): void;
711
+ private detach;
712
+ private refresh;
713
+ }
714
+
715
+ declare class ShortcutsHelp {
716
+ private readonly dialog;
717
+ private readonly list;
718
+ private readonly keymap;
719
+ constructor(keymap: KeymapManager, host?: HTMLElement, onOpenChange?: (open: boolean) => void);
720
+ open(): void;
721
+ close(): void;
722
+ destroy(): void;
723
+ private refresh;
724
+ }
725
+
726
+ interface ContextMenuCallbacks {
727
+ /** Reset the view (all history, autoscale back on). */
728
+ resetView: () => void;
729
+ /** The display timezone the host holds (the time-axis menu checks it). */
730
+ timezone?: () => string;
731
+ /** Switch the display timezone through the host, so its own chrome follows. */
732
+ setTimezone?: (zone: string) => void;
733
+ /** Live widget context for contributed `context:*` actions. */
734
+ getContext?: () => WidgetContext;
735
+ }
736
+ declare class ChartContextMenu {
737
+ private readonly cbs;
738
+ private readonly menu;
739
+ private readonly host;
740
+ private chart;
741
+ private lastZone;
742
+ /** The pane whose scale the open price-axis menu targets (null ⇒ the main scale). */
743
+ private lastPane;
744
+ private readonly onContextMenu;
745
+ constructor(host: HTMLElement, cbs: ContextMenuCallbacks);
746
+ /** (Re)bind to a chart instance — called after every widget rebuild. */
747
+ onChart(chart: Vela): void;
748
+ destroy(): void;
749
+ private zoneOf;
750
+ /** The pane under the pointer, so every pane's price scale has its own menu. */
751
+ private paneAt;
752
+ private flag;
753
+ private contributed;
754
+ private itemsFor;
755
+ private run;
756
+ }
757
+
758
+ interface ParsedTimeframe {
759
+ valid: boolean;
760
+ count?: number;
761
+ unit?: string;
762
+ ms?: number;
763
+ /** What the chart consumes ("180" for 3h). */
764
+ canonical?: string;
765
+ /** Human line ("3 months"). */
766
+ label?: string;
767
+ /** Compact chip ("3M"). */
768
+ short?: string;
769
+ }
770
+ /** Parse a typed timeframe string. `valid` is false for empty/garbage input (count ≥ 1). */
771
+ declare function parseTimeframe(text: string): ParsedTimeframe;
772
+ /** Duration in ms of an existing timeframe value (`1`, `60`, `4h`, `D`, `W`, …), NaN if unknown. */
773
+ declare function timeframeMs(value: string): number;
774
+ /** Compact display label for any timeframe value ("60" → "1h", "D" → "1D"). */
775
+ declare function timeframeLabel(value: string): string;
776
+
777
+ interface TimezoneEntry {
778
+ value: string;
779
+ label: string;
780
+ }
781
+ declare const TIMEZONES: readonly TimezoneEntry[];
782
+ /** The renderer's config default is the bare `'UTC'` alias — fold it (and any other
783
+ * UTC spelling) onto the catalog's `'Etc/UTC'` so selection checks land on one entry. */
784
+ declare function normalizeTimezone(zone: string): string;
785
+ /** Current UTC offset of an IANA zone as `"UTC"`, `"UTC+2"` or `"UTC-9:30"`. */
786
+ declare function tzOffset(zone: string, date?: Date): string;
787
+ /** Dropdown row label — UTC omits the offset prefix. */
788
+ declare function tzMenuLabel(zone: string, location: string): string;
789
+ /** Compact label for the bottom-bar button ("UTC", "UTC+2 Paris"). */
790
+ declare function tzButtonLabel(zone: string): string;
791
+
792
+ /** Sensible decimal count for a price magnitude (crypto-friendly). */
793
+ declare function decimalsFor(ref: number): number;
794
+ /** Locale-formatted price; `'—'` for null/non-finite. */
795
+ declare function fmtPrice(n: number | null | undefined, dp?: number): string;
796
+ /** Signed change + percent ("+123.45 (+1.23%)") from open→close; `''` when unavailable. */
797
+ declare function fmtChange(open: number | null | undefined, close: number | null | undefined): string;
798
+
799
+ export { type BuiltInPanel, ChartContextMenu, type ContextMenuCallbacks, DataWindow, type DataWindowLine, type DataWindowSection, IndicatorPicker, type IndicatorPickerOptions, type IndicatorRow, ObjectTree, type PanelChrome, PanelDock, type PanelDockDeps, PanelsState, type ParsedTimeframe, PersistedState, RangePreset, ShortcutsHelp, SidePanel, SidePanelButton, Statusline, SymbolPicker, type SymbolPickerOptions, TIMEZONES, TimeframeQuick, type TimeframeQuickOptions, type TimezoneEntry, Topbar, type TopbarOptions, VelaShellOptions, VelaWidget, type VelaWidgetOptions, Watermark, WidgetContext, WorkspaceState, dataWindowSections, decimalsFor, filterSymbols, fmtChange, fmtPrice, normalizeTimezone, parseTimeframe, priceStyleLabel, readUrlState, timeframeLabel, timeframeMs, tzButtonLabel, tzMenuLabel, tzOffset, writeUrlState };