@luxalgo/vela 0.6.6 → 0.6.8

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 (43) hide show
  1. package/dist/{DataProvider-JJq7M2it.d.ts → DataProvider-BSLlBpB9.d.ts} +10 -0
  2. package/dist/{DataProvider-DDUYw2qP.d.cts → DataProvider-BsQM2WNH.d.cts} +10 -0
  3. package/dist/{chunk-OEUGUXL7.js → chunk-L3I2CCYO.js} +49 -1
  4. package/dist/{chunk-TMXK2SJR.js → chunk-N7LGMKCE.js} +523 -142
  5. package/dist/{chunk-JQFO2WMU.js → chunk-SQETIBFU.js} +83 -9
  6. package/dist/chunk-W4EJWLEO.js +12 -0
  7. package/dist/{contributions-BqCIsbaP.d.ts → contributions-DLLdV9jD.d.ts} +59 -3
  8. package/dist/{contributions-DNMqrAuw.d.cts → contributions-Vw-Hm58R.d.cts} +59 -3
  9. package/dist/index.cjs +110 -8
  10. package/dist/index.d.cts +8 -4
  11. package/dist/index.d.ts +8 -4
  12. package/dist/index.js +2 -2
  13. package/dist/{plugin-CN8U2__Q.d.cts → plugin-BnJgjLAy.d.cts} +2 -2
  14. package/dist/{plugin-WnvNNJOp.d.ts → plugin-CC7rBrOY.d.ts} +2 -2
  15. package/dist/plugin.cjs +28 -0
  16. package/dist/plugin.d.cts +3 -3
  17. package/dist/plugin.d.ts +3 -3
  18. package/dist/plugin.js +1 -1
  19. package/dist/providers/binance.cjs +16 -0
  20. package/dist/providers/binance.d.cts +4 -1
  21. package/dist/providers/binance.d.ts +4 -1
  22. package/dist/providers/binance.js +7 -0
  23. package/dist/providers/coinbase.cjs +16 -0
  24. package/dist/providers/coinbase.d.cts +4 -1
  25. package/dist/providers/coinbase.d.ts +4 -1
  26. package/dist/providers/coinbase.js +7 -0
  27. package/dist/providers/hyperliquid.cjs +16 -0
  28. package/dist/providers/hyperliquid.d.cts +4 -1
  29. package/dist/providers/hyperliquid.d.ts +4 -1
  30. package/dist/providers/hyperliquid.js +7 -0
  31. package/dist/{bottombar-COnL2Sk4.d.ts → statusline-CGkB2EOo.d.ts} +137 -8
  32. package/dist/{bottombar-DeDXbF_K.d.cts → statusline-DqzBqy42.d.cts} +137 -8
  33. package/dist/vela.global.js +136 -8
  34. package/dist/vela.global.min.js +42 -42
  35. package/dist/widget.cjs +667 -148
  36. package/dist/widget.d.cts +50 -81
  37. package/dist/widget.d.ts +50 -81
  38. package/dist/widget.js +5 -4
  39. package/dist/workspace.cjs +613 -150
  40. package/dist/workspace.d.cts +62 -9
  41. package/dist/workspace.d.ts +62 -9
  42. package/dist/workspace.js +4 -3
  43. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import { D as DataProvider } from './DataProvider-JJq7M2it.js';
2
- import { S as ScriptingEngine, V as Vela } from './contributions-BqCIsbaP.js';
1
+ import { D as DataProvider } from './DataProvider-BSLlBpB9.js';
2
+ import { S as ScriptingEngine, V as Vela } from './contributions-DLLdV9jD.js';
3
3
  import { V as VisibleRangePreset } from './options-BaVTMXaO.js';
4
4
 
5
5
  /** The linkable dimensions. `crosshair` mirrors the pointer time onto same-group
@@ -8,8 +8,10 @@ import { V as VisibleRangePreset } from './options-BaVTMXaO.js';
8
8
  * same-group cells and keeps the set linked: edits and removals of any member
9
9
  * follow. Link membership is session-scoped and survives a toggle-off (re-enabling
10
10
  * resumes edit/delete for drawings paired earlier; drawings created while off stay
11
- * independent). After a reload, every drawing is unpaired again. */
12
- type SyncKind = 'viewport' | 'symbol' | 'timeframe' | 'crosshair' | 'drawings';
11
+ * independent). After a reload, every drawing is unpaired again. `style` mirrors
12
+ * the chart's presentation settings the Canvas and Scales-and-lines slice of the
13
+ * renderer config plus the status-line display prefs — onto same-group cells. */
14
+ type SyncKind = 'viewport' | 'symbol' | 'timeframe' | 'crosshair' | 'drawings' | 'style';
13
15
  /**
14
16
  * One link's configuration: `false`/absent = off; `true` = ALL cells linked (one
15
17
  * implicit group); a record maps cell id → group name, and only cells sharing a group
@@ -22,6 +24,7 @@ interface SyncOptions {
22
24
  timeframe?: SyncSetting;
23
25
  crosshair?: SyncSetting;
24
26
  drawings?: SyncSetting;
27
+ style?: SyncSetting;
25
28
  }
26
29
  /** Splitter track weights along each grid axis. */
27
30
  interface TrackSizes {
@@ -172,6 +175,37 @@ type WidgetStorage = VelaStorage;
172
175
  */
173
176
  declare function localStorageAdapter(storageKey?: string): WidgetStorage;
174
177
 
178
+ /** The host-facing option: visible entries per side, in render order. An undeclared
179
+ * side falls back to its default list. */
180
+ interface TopbarComposition {
181
+ left?: readonly string[];
182
+ right?: readonly string[];
183
+ }
184
+ /** The built-in entry vocabulary (everything else in a list is a contributed-action id).
185
+ * `'layout'` renders only on multi-chart shells and `'indicators'` only while an
186
+ * indicator surface exists — the built-in picker (the deprecated `indicatorPicker:
187
+ * false` still removes it) or a slot OVERRIDE replacing it — so listing them is
188
+ * necessary but not sufficient. */
189
+ declare const TOPBAR_BUILTIN_IDS: readonly ["symbol", "timeframes", "style", "layout", "indicators", "actions", "undo-redo", "alerts", "panels", "screenshot"];
190
+ /** The default left side — the current shell composition, verbatim. */
191
+ declare const TOPBAR_DEFAULT_LEFT: readonly string[];
192
+ /** The default right side (the `margin-left: auto` cluster). */
193
+ declare const TOPBAR_DEFAULT_RIGHT: readonly string[];
194
+ /** A composition with both sides resolved (defaults applied, duplicates dropped). */
195
+ interface ResolvedTopbarComposition {
196
+ left: string[];
197
+ right: string[];
198
+ }
199
+ /** Resolve the host option: absent side ⇒ its default list; a duplicated id keeps its
200
+ * FIRST occurrence (left before right) so an entry never renders twice. `'actions'`
201
+ * is the exception — it is a flow SLOT each side legitimately owns (the defaults
202
+ * carry one on both), so it dedupes per side only. */
203
+ declare function resolveTopbarComposition(opt?: TopbarComposition): ResolvedTopbarComposition;
204
+ /** Whether an entry id is visible anywhere in the resolved composition. */
205
+ declare function topbarHas(comp: ResolvedTopbarComposition, id: string): boolean;
206
+ /** The non-built-in entries — contributed-action ids PINNED to a list position. */
207
+ declare function pinnedTopbarActionIds(comp: ResolvedTopbarComposition): string[];
208
+
175
209
  /** What a shell (widget or workspace) accepts BEYOND the chart options themselves. */
176
210
  interface VelaShellOptions {
177
211
  /** Provider factories, keyed by provider name. The shell owns the call cycle: the
@@ -197,10 +231,25 @@ interface VelaShellOptions {
197
231
  statusline?: boolean;
198
232
  watermark?: boolean;
199
233
  bottombar?: boolean;
234
+ /** Declarative topbar composition: `{ left, right }` lists of the VISIBLE entries,
235
+ * in render order — built-in ids (`'symbol'`, `'timeframes'`, `'style'`,
236
+ * `'layout'`, `'indicators'`, `'actions'`, `'undo-redo'`, `'alerts'`, `'panels'`,
237
+ * `'screenshot'`) and/or contributed-action ids (naming one PINS it there,
238
+ * overriding its `align`/`order`; `'actions'` is where the unlisted ones flow).
239
+ * An undeclared side keeps its default. An explicit list is that side's complete
240
+ * contract — it also FREEZES it: chrome a future release adds will not appear.
241
+ * Hiding a built-in removes its mobile entry and keyboard chord too (`mod+alt+S`
242
+ * for `'screenshot'`); Ctrl+Z / Ctrl+Y stay — they belong to editing, not to the
243
+ * `'undo-redo'` buttons. */
244
+ topbar?: TopbarComposition;
200
245
  /** The built-in indicator picker's entry points — the topbar button, the mobile-bar
201
- * item, and the `/` shortcut. `false` removes them, for hosts that replace the
202
- * picker with their own indicator UI (e.g. a contributed topbar action opening a
203
- * custom dialog). The `indicators` manifest still resolves and auto-adds. */
246
+ * item, and the `/` shortcut. `false` removes them. The `indicators` manifest
247
+ * still resolves and auto-adds.
248
+ * @deprecated Removed in 0.7.0. To HIDE the built-in surface, omit `'indicators'`
249
+ * from `topbar.left` (same effect: no button, no mobile stop, no `/`, no dialog).
250
+ * To REPLACE it, a plugin registers its action under the id `'indicators'`
251
+ * (`registerWidgetAction`) — the override takes the slot's whole surface and
252
+ * needs no shell option at all. */
204
253
  indicatorPicker?: boolean;
205
254
  /** Chrome size class. `'auto'` (default) follows the CONTAINER width plus a
206
255
  * coarse-pointer heuristic; `'mobile'` / `'desktop'` pin it. Mobile swaps the
@@ -315,4 +364,84 @@ declare class Bottombar {
315
364
  private tick;
316
365
  }
317
366
 
318
- export { Bottombar as B, type CellState as C, type IndicatorLoader as I, type PanelsState as P, type ResolvedIndicator as R, type SyncSetting as S, type TrackSizes as T, type VelaStorage as V, WidgetHistory as W, type RangePreset as a, type VelaShellOptions as b, type SyncOptions as c, type SyncKind as d, type WorkspaceState as e, type ChartState as f, decodeState as g, encodeState as h, type BottombarOptions as i, type IndicatorManifest as j, type IndicatorManifestEntry as k, RANGE_PRESETS as l, type WidgetStorage as m, localStorageAdapter as n, resolveIndicators as r, sanitizeState as s };
367
+ /** How the status line reads a bar out: the four O/H/L/C values (bar-shaped styles),
368
+ * or the single plotted value — the close — for one-line styles (line/area/baseline). */
369
+ type StatuslineReadout = 'ohlc' | 'value';
370
+ /** The market session states the status badge can wear. Crypto venues trade
371
+ * continuously and stay 'open'; the full vocabulary is ready for providers that
372
+ * carry a session model (equities RTH/ETH, exchange holidays). */
373
+ type MarketStatus = 'open' | 'pre' | 'post' | 'closed' | 'holiday';
374
+ /** The status line's toggleable segments (the settings dialog's Status line tab). */
375
+ type StatuslinePart = 'name' | 'market' | 'ohlc' | 'change';
376
+ declare class Statusline {
377
+ private readonly host;
378
+ /** The avatar's icon URL for a raw symbol — the shell routes it to the owning
379
+ * provider's `resolveSymbolIcon`. Absent ⇒ the initials badge. */
380
+ private readonly iconFor?;
381
+ readonly el: HTMLElement;
382
+ private readonly ohlcEl;
383
+ private readonly changeEl;
384
+ private readonly symbolEl;
385
+ private readonly marketEl;
386
+ private marketTip;
387
+ private avatarEl;
388
+ private metaEl;
389
+ private readonly parts;
390
+ private lastBar;
391
+ private hoverBar;
392
+ private unsubs;
393
+ /** Up/down ink for the OHLC + change values — the ACTIVE price style's configured
394
+ * colors (candle bodies, bar ticks, the line color, …); null falls back to the theme
395
+ * tokens. `isUp` overrides the close-vs-open direction rule where the style paints by
396
+ * something else (baseline: position against the baseline price). */
397
+ private upColor;
398
+ private downColor;
399
+ private isUp;
400
+ /** 'ohlc' for bar-shaped styles; 'value' (the single plotted close) for line styles. */
401
+ private readout;
402
+ /** Fit mode (multi-chart cells): one row, overflowing segments hidden — see {@link setFitMode}. */
403
+ private fitMode;
404
+ private fitRO;
405
+ constructor(host: HTMLElement, symbol: string,
406
+ /** The avatar's icon URL for a raw symbol — the shell routes it to the owning
407
+ * provider's `resolveSymbolIcon`. Absent ⇒ the initials badge. */
408
+ iconFor?: ((symbol: string) => string | undefined) | undefined);
409
+ setSymbol(symbol: string): void;
410
+ /**
411
+ * Multi-chart cells: keep the line on ONE row whatever the cell width — never wrap.
412
+ * Segments that don't fit are hidden outright rather than clipped mid-glyph, least
413
+ * important first: OHLC, then the bar change, the venue/timeframe meta, and the
414
+ * market badge; the logo + ticker always stay. Re-fits live on host resizes.
415
+ */
416
+ setFitMode(on: boolean): void;
417
+ /** Project the parts config onto the segments (the baseline fit() prunes from). */
418
+ private syncParts;
419
+ /** Hide overflowing segments until the row fits its max-width (fit mode only). */
420
+ private fit;
421
+ /** Shape + color the value readout after the active price style: its own up/down
422
+ * colors (candle bodies, bar ticks, the line color, …), the direction rule that
423
+ * picks between them (`isUp` replaces close-vs-open where the style paints by
424
+ * something else — baseline by position), and whether the readout is the four
425
+ * O/H/L/C values or the single plotted value (one-line styles). Null colors fall
426
+ * back to the theme's up/down tokens. See {@link statuslineInkOf}, which derives
427
+ * all of it from the live renderer. */
428
+ setDirectionColors(up: string | null, down: string | null, isUp?: ((bar: {
429
+ open: number;
430
+ close: number;
431
+ }) => boolean) | null, readout?: StatuslineReadout): void;
432
+ /** Show/hide one part (the settings dialog's Status line tab drives these). */
433
+ /** The "· BINANCE · 1h" segment after the symbol — venue first, then resolution. */
434
+ setMeta(timeframe: string, provider: string): void;
435
+ /** Dress the market badge for a session state: its icon, tinted circle, and the
436
+ * hover label. Callers with no session model leave the constructor's 'open'. */
437
+ setMarketStatus(status: MarketStatus): void;
438
+ setPartVisible(part: StatuslinePart, visible: boolean): void;
439
+ partVisible(part: StatuslinePart): boolean;
440
+ /** (Re)bind to a chart instance — called after every widget rebuild. */
441
+ onChart(chart: Vela): void;
442
+ destroy(): void;
443
+ private detach;
444
+ private render;
445
+ }
446
+
447
+ export { Bottombar as B, type CellState as C, type IndicatorLoader as I, type PanelsState as P, type ResolvedIndicator as R, type SyncSetting as S, type TrackSizes as T, type VelaStorage as V, WidgetHistory as W, type StatuslinePart as a, type RangePreset as b, type VelaShellOptions as c, type SyncOptions as d, type SyncKind as e, type WorkspaceState as f, type ChartState as g, decodeState as h, encodeState as i, type TopbarComposition as j, type BottombarOptions as k, type IndicatorManifest as l, type IndicatorManifestEntry as m, RANGE_PRESETS as n, type ResolvedTopbarComposition as o, Statusline as p, TOPBAR_BUILTIN_IDS as q, TOPBAR_DEFAULT_LEFT as r, sanitizeState as s, TOPBAR_DEFAULT_RIGHT as t, type WidgetStorage as u, localStorageAdapter as v, pinnedTopbarActionIds as w, resolveIndicators as x, resolveTopbarComposition as y, topbarHas as z };
@@ -1,5 +1,5 @@
1
- import { D as DataProvider } from './DataProvider-DDUYw2qP.cjs';
2
- import { S as ScriptingEngine, V as Vela } from './contributions-DNMqrAuw.cjs';
1
+ import { D as DataProvider } from './DataProvider-BsQM2WNH.cjs';
2
+ import { S as ScriptingEngine, V as Vela } from './contributions-Vw-Hm58R.cjs';
3
3
  import { V as VisibleRangePreset } from './options-BaVTMXaO.cjs';
4
4
 
5
5
  /** The linkable dimensions. `crosshair` mirrors the pointer time onto same-group
@@ -8,8 +8,10 @@ import { V as VisibleRangePreset } from './options-BaVTMXaO.cjs';
8
8
  * same-group cells and keeps the set linked: edits and removals of any member
9
9
  * follow. Link membership is session-scoped and survives a toggle-off (re-enabling
10
10
  * resumes edit/delete for drawings paired earlier; drawings created while off stay
11
- * independent). After a reload, every drawing is unpaired again. */
12
- type SyncKind = 'viewport' | 'symbol' | 'timeframe' | 'crosshair' | 'drawings';
11
+ * independent). After a reload, every drawing is unpaired again. `style` mirrors
12
+ * the chart's presentation settings the Canvas and Scales-and-lines slice of the
13
+ * renderer config plus the status-line display prefs — onto same-group cells. */
14
+ type SyncKind = 'viewport' | 'symbol' | 'timeframe' | 'crosshair' | 'drawings' | 'style';
13
15
  /**
14
16
  * One link's configuration: `false`/absent = off; `true` = ALL cells linked (one
15
17
  * implicit group); a record maps cell id → group name, and only cells sharing a group
@@ -22,6 +24,7 @@ interface SyncOptions {
22
24
  timeframe?: SyncSetting;
23
25
  crosshair?: SyncSetting;
24
26
  drawings?: SyncSetting;
27
+ style?: SyncSetting;
25
28
  }
26
29
  /** Splitter track weights along each grid axis. */
27
30
  interface TrackSizes {
@@ -172,6 +175,37 @@ type WidgetStorage = VelaStorage;
172
175
  */
173
176
  declare function localStorageAdapter(storageKey?: string): WidgetStorage;
174
177
 
178
+ /** The host-facing option: visible entries per side, in render order. An undeclared
179
+ * side falls back to its default list. */
180
+ interface TopbarComposition {
181
+ left?: readonly string[];
182
+ right?: readonly string[];
183
+ }
184
+ /** The built-in entry vocabulary (everything else in a list is a contributed-action id).
185
+ * `'layout'` renders only on multi-chart shells and `'indicators'` only while an
186
+ * indicator surface exists — the built-in picker (the deprecated `indicatorPicker:
187
+ * false` still removes it) or a slot OVERRIDE replacing it — so listing them is
188
+ * necessary but not sufficient. */
189
+ declare const TOPBAR_BUILTIN_IDS: readonly ["symbol", "timeframes", "style", "layout", "indicators", "actions", "undo-redo", "alerts", "panels", "screenshot"];
190
+ /** The default left side — the current shell composition, verbatim. */
191
+ declare const TOPBAR_DEFAULT_LEFT: readonly string[];
192
+ /** The default right side (the `margin-left: auto` cluster). */
193
+ declare const TOPBAR_DEFAULT_RIGHT: readonly string[];
194
+ /** A composition with both sides resolved (defaults applied, duplicates dropped). */
195
+ interface ResolvedTopbarComposition {
196
+ left: string[];
197
+ right: string[];
198
+ }
199
+ /** Resolve the host option: absent side ⇒ its default list; a duplicated id keeps its
200
+ * FIRST occurrence (left before right) so an entry never renders twice. `'actions'`
201
+ * is the exception — it is a flow SLOT each side legitimately owns (the defaults
202
+ * carry one on both), so it dedupes per side only. */
203
+ declare function resolveTopbarComposition(opt?: TopbarComposition): ResolvedTopbarComposition;
204
+ /** Whether an entry id is visible anywhere in the resolved composition. */
205
+ declare function topbarHas(comp: ResolvedTopbarComposition, id: string): boolean;
206
+ /** The non-built-in entries — contributed-action ids PINNED to a list position. */
207
+ declare function pinnedTopbarActionIds(comp: ResolvedTopbarComposition): string[];
208
+
175
209
  /** What a shell (widget or workspace) accepts BEYOND the chart options themselves. */
176
210
  interface VelaShellOptions {
177
211
  /** Provider factories, keyed by provider name. The shell owns the call cycle: the
@@ -197,10 +231,25 @@ interface VelaShellOptions {
197
231
  statusline?: boolean;
198
232
  watermark?: boolean;
199
233
  bottombar?: boolean;
234
+ /** Declarative topbar composition: `{ left, right }` lists of the VISIBLE entries,
235
+ * in render order — built-in ids (`'symbol'`, `'timeframes'`, `'style'`,
236
+ * `'layout'`, `'indicators'`, `'actions'`, `'undo-redo'`, `'alerts'`, `'panels'`,
237
+ * `'screenshot'`) and/or contributed-action ids (naming one PINS it there,
238
+ * overriding its `align`/`order`; `'actions'` is where the unlisted ones flow).
239
+ * An undeclared side keeps its default. An explicit list is that side's complete
240
+ * contract — it also FREEZES it: chrome a future release adds will not appear.
241
+ * Hiding a built-in removes its mobile entry and keyboard chord too (`mod+alt+S`
242
+ * for `'screenshot'`); Ctrl+Z / Ctrl+Y stay — they belong to editing, not to the
243
+ * `'undo-redo'` buttons. */
244
+ topbar?: TopbarComposition;
200
245
  /** The built-in indicator picker's entry points — the topbar button, the mobile-bar
201
- * item, and the `/` shortcut. `false` removes them, for hosts that replace the
202
- * picker with their own indicator UI (e.g. a contributed topbar action opening a
203
- * custom dialog). The `indicators` manifest still resolves and auto-adds. */
246
+ * item, and the `/` shortcut. `false` removes them. The `indicators` manifest
247
+ * still resolves and auto-adds.
248
+ * @deprecated Removed in 0.7.0. To HIDE the built-in surface, omit `'indicators'`
249
+ * from `topbar.left` (same effect: no button, no mobile stop, no `/`, no dialog).
250
+ * To REPLACE it, a plugin registers its action under the id `'indicators'`
251
+ * (`registerWidgetAction`) — the override takes the slot's whole surface and
252
+ * needs no shell option at all. */
204
253
  indicatorPicker?: boolean;
205
254
  /** Chrome size class. `'auto'` (default) follows the CONTAINER width plus a
206
255
  * coarse-pointer heuristic; `'mobile'` / `'desktop'` pin it. Mobile swaps the
@@ -315,4 +364,84 @@ declare class Bottombar {
315
364
  private tick;
316
365
  }
317
366
 
318
- export { Bottombar as B, type CellState as C, type IndicatorLoader as I, type PanelsState as P, type ResolvedIndicator as R, type SyncSetting as S, type TrackSizes as T, type VelaStorage as V, WidgetHistory as W, type RangePreset as a, type VelaShellOptions as b, type SyncOptions as c, type SyncKind as d, type WorkspaceState as e, type ChartState as f, decodeState as g, encodeState as h, type BottombarOptions as i, type IndicatorManifest as j, type IndicatorManifestEntry as k, RANGE_PRESETS as l, type WidgetStorage as m, localStorageAdapter as n, resolveIndicators as r, sanitizeState as s };
367
+ /** How the status line reads a bar out: the four O/H/L/C values (bar-shaped styles),
368
+ * or the single plotted value — the close — for one-line styles (line/area/baseline). */
369
+ type StatuslineReadout = 'ohlc' | 'value';
370
+ /** The market session states the status badge can wear. Crypto venues trade
371
+ * continuously and stay 'open'; the full vocabulary is ready for providers that
372
+ * carry a session model (equities RTH/ETH, exchange holidays). */
373
+ type MarketStatus = 'open' | 'pre' | 'post' | 'closed' | 'holiday';
374
+ /** The status line's toggleable segments (the settings dialog's Status line tab). */
375
+ type StatuslinePart = 'name' | 'market' | 'ohlc' | 'change';
376
+ declare class Statusline {
377
+ private readonly host;
378
+ /** The avatar's icon URL for a raw symbol — the shell routes it to the owning
379
+ * provider's `resolveSymbolIcon`. Absent ⇒ the initials badge. */
380
+ private readonly iconFor?;
381
+ readonly el: HTMLElement;
382
+ private readonly ohlcEl;
383
+ private readonly changeEl;
384
+ private readonly symbolEl;
385
+ private readonly marketEl;
386
+ private marketTip;
387
+ private avatarEl;
388
+ private metaEl;
389
+ private readonly parts;
390
+ private lastBar;
391
+ private hoverBar;
392
+ private unsubs;
393
+ /** Up/down ink for the OHLC + change values — the ACTIVE price style's configured
394
+ * colors (candle bodies, bar ticks, the line color, …); null falls back to the theme
395
+ * tokens. `isUp` overrides the close-vs-open direction rule where the style paints by
396
+ * something else (baseline: position against the baseline price). */
397
+ private upColor;
398
+ private downColor;
399
+ private isUp;
400
+ /** 'ohlc' for bar-shaped styles; 'value' (the single plotted close) for line styles. */
401
+ private readout;
402
+ /** Fit mode (multi-chart cells): one row, overflowing segments hidden — see {@link setFitMode}. */
403
+ private fitMode;
404
+ private fitRO;
405
+ constructor(host: HTMLElement, symbol: string,
406
+ /** The avatar's icon URL for a raw symbol — the shell routes it to the owning
407
+ * provider's `resolveSymbolIcon`. Absent ⇒ the initials badge. */
408
+ iconFor?: ((symbol: string) => string | undefined) | undefined);
409
+ setSymbol(symbol: string): void;
410
+ /**
411
+ * Multi-chart cells: keep the line on ONE row whatever the cell width — never wrap.
412
+ * Segments that don't fit are hidden outright rather than clipped mid-glyph, least
413
+ * important first: OHLC, then the bar change, the venue/timeframe meta, and the
414
+ * market badge; the logo + ticker always stay. Re-fits live on host resizes.
415
+ */
416
+ setFitMode(on: boolean): void;
417
+ /** Project the parts config onto the segments (the baseline fit() prunes from). */
418
+ private syncParts;
419
+ /** Hide overflowing segments until the row fits its max-width (fit mode only). */
420
+ private fit;
421
+ /** Shape + color the value readout after the active price style: its own up/down
422
+ * colors (candle bodies, bar ticks, the line color, …), the direction rule that
423
+ * picks between them (`isUp` replaces close-vs-open where the style paints by
424
+ * something else — baseline by position), and whether the readout is the four
425
+ * O/H/L/C values or the single plotted value (one-line styles). Null colors fall
426
+ * back to the theme's up/down tokens. See {@link statuslineInkOf}, which derives
427
+ * all of it from the live renderer. */
428
+ setDirectionColors(up: string | null, down: string | null, isUp?: ((bar: {
429
+ open: number;
430
+ close: number;
431
+ }) => boolean) | null, readout?: StatuslineReadout): void;
432
+ /** Show/hide one part (the settings dialog's Status line tab drives these). */
433
+ /** The "· BINANCE · 1h" segment after the symbol — venue first, then resolution. */
434
+ setMeta(timeframe: string, provider: string): void;
435
+ /** Dress the market badge for a session state: its icon, tinted circle, and the
436
+ * hover label. Callers with no session model leave the constructor's 'open'. */
437
+ setMarketStatus(status: MarketStatus): void;
438
+ setPartVisible(part: StatuslinePart, visible: boolean): void;
439
+ partVisible(part: StatuslinePart): boolean;
440
+ /** (Re)bind to a chart instance — called after every widget rebuild. */
441
+ onChart(chart: Vela): void;
442
+ destroy(): void;
443
+ private detach;
444
+ private render;
445
+ }
446
+
447
+ export { Bottombar as B, type CellState as C, type IndicatorLoader as I, type PanelsState as P, type ResolvedIndicator as R, type SyncSetting as S, type TrackSizes as T, type VelaStorage as V, WidgetHistory as W, type StatuslinePart as a, type RangePreset as b, type VelaShellOptions as c, type SyncOptions as d, type SyncKind as e, type WorkspaceState as f, type ChartState as g, decodeState as h, encodeState as i, type TopbarComposition as j, type BottombarOptions as k, type IndicatorManifest as l, type IndicatorManifestEntry as m, RANGE_PRESETS as n, type ResolvedTopbarComposition as o, Statusline as p, TOPBAR_BUILTIN_IDS as q, TOPBAR_DEFAULT_LEFT as r, sanitizeState as s, TOPBAR_DEFAULT_RIGHT as t, type WidgetStorage as u, localStorageAdapter as v, pinnedTopbarActionIds as w, resolveIndicators as x, resolveTopbarComposition as y, topbarHas as z };
@@ -7067,6 +7067,28 @@ var Vela = (function (exports) {
7067
7067
  const d = this.entries.get(resolved.provider)?.byTicker?.get(normTicker(resolved.ticker));
7068
7068
  return `${d?.prefix ?? resolved.provider}:${d?.ticker ?? resolved.ticker}`;
7069
7069
  }
7070
+ /** The icon URL for a DESCRIPTOR — routed to its OWNING provider's resolver (the
7071
+ * provider owns the knowledge of where its asset class's icons live). A missing
7072
+ * provider, an absent resolver, or a resolver that throws all mean "no icon" —
7073
+ * the shells' initials badge takes over, never an error. */
7074
+ symbolIconOf(d) {
7075
+ const name = d.provider ? normName(d.provider) : [...this.entries.keys()][0];
7076
+ const entry = name !== void 0 ? this.entries.get(name) : void 0;
7077
+ try {
7078
+ return entry?.provider.resolveSymbolIcon?.(d) ?? void 0;
7079
+ } catch {
7080
+ return void 0;
7081
+ }
7082
+ }
7083
+ /** The icon URL for a raw SYMBOL string (the statusline/object-tree path): resolve
7084
+ * to the owning provider, find its descriptor, route to the resolver. Before the
7085
+ * index settles (or for a lenient sole-provider resolution) a minimal synthetic
7086
+ * descriptor is offered — crypto resolvers can answer from the ticker alone. */
7087
+ symbolIcon(resolved) {
7088
+ if (!resolved) return void 0;
7089
+ const d = this.entries.get(resolved.provider)?.byTicker?.get(normTicker(resolved.ticker));
7090
+ return this.symbolIconOf({ ...d ?? { ticker: resolved.ticker }, provider: d?.provider ?? resolved.provider });
7091
+ }
7070
7092
  /** Indexed symbols for one provider (or all, concatenated) — for autocomplete. */
7071
7093
  symbolsOf(rawName) {
7072
7094
  if (rawName != null) return this.entries.get(normName(rawName))?.descriptors ?? [];
@@ -9287,6 +9309,14 @@ var Vela = (function (exports) {
9287
9309
  providerInstance(name) {
9288
9310
  return this.registry.get(name);
9289
9311
  }
9312
+ /** The icon URL for a DESCRIPTOR — its owning provider's `resolveSymbolIcon` (picker rows). */
9313
+ symbolIconOf(d) {
9314
+ return this.registry.symbolIconOf(d);
9315
+ }
9316
+ /** The icon URL for a raw SYMBOL string — resolve, then route (statusline, object tree). */
9317
+ symbolIcon(raw) {
9318
+ return this.registry.symbolIcon(this.resolveSymbol(raw));
9319
+ }
9290
9320
  symbols(name) {
9291
9321
  return this.registry.symbolsOf(name);
9292
9322
  }
@@ -9513,6 +9543,12 @@ var Vela = (function (exports) {
9513
9543
  symbols(provider) {
9514
9544
  return this.registry?.symbols(provider) ?? [];
9515
9545
  }
9546
+ /** The icon URL for `symbol` — its owning provider's `resolveSymbolIcon`, routed
9547
+ * through resolution. Undefined while unresolvable, when the provider declares no
9548
+ * resolver, or on a custom `deps.dataFeed` — the shells then show initials. */
9549
+ symbolIcon(symbol) {
9550
+ return this.registry?.symbolIcon(symbol);
9551
+ }
9516
9552
  /** Per-symbol metadata (Pine `syminfo.*`), resolved through the owning provider. */
9517
9553
  symbolInfo(symbol) {
9518
9554
  return this.registry?.symbolInfoFor(symbol) ?? Promise.resolve(void 0);
@@ -19980,12 +20016,16 @@ ${overlayScrollbarCss(".vela-dialog *")}
19980
20016
  closeOnEscape: false,
19981
20017
  footer: (foot) => {
19982
20018
  foot.append(
20019
+ this.resetAction(),
19983
20020
  this.dialogButton("Cancel", false, () => this.revertAndClose()),
19984
20021
  this.dialogButton("Ok", true, () => this.close())
19985
20022
  );
19986
20023
  },
20024
+ // Stale-guard: destroying a dialog fires its machine's onOpenChange(false)
20025
+ // asynchronously — after a reset rebuild that notification must not close
20026
+ // the replacement dialog.
19987
20027
  onOpenChange: (open2) => {
19988
- if (!open2) this.close();
20028
+ if (!open2 && this.uiDialog === ui) this.close();
19989
20029
  }
19990
20030
  });
19991
20031
  applyChromeTokens(ui.panel, t);
@@ -20116,6 +20156,30 @@ ${overlayScrollbarCss(".vela-dialog *")}
20116
20156
  }
20117
20157
  this.close();
20118
20158
  }
20159
+ /** The footer's reset button — same chip as Cancel, pinned to the LEFT edge
20160
+ * (`margin-right:auto` against the footer's flex-end keeps Cancel/Ok right). */
20161
+ resetAction() {
20162
+ const b = this.dialogButton("Reset defaults", false, () => this.resetToDefaults());
20163
+ b.style.marginRight = "auto";
20164
+ return b;
20165
+ }
20166
+ /** Restore every input to its declared default (re-running the indicator), then
20167
+ * re-open the form so each control re-reads the restored values — the same
20168
+ * rebuild-after-reset move as the chart-settings dialog. The open-time snapshot
20169
+ * survives the rebuild, so Cancel after a reset still reverts the whole session. */
20170
+ resetToDefaults() {
20171
+ const row = this.row;
20172
+ if (!row) return;
20173
+ const snap = this.snapshot;
20174
+ for (const inp of row.inputs) {
20175
+ if (row.values[inp.key] !== inp.defval) {
20176
+ row.values[inp.key] = inp.defval;
20177
+ this.host.onChange?.({ indicatorId: row.id, key: inp.key, value: inp.defval });
20178
+ }
20179
+ }
20180
+ this.open(row);
20181
+ if (snap) this.snapshot = snap;
20182
+ }
20119
20183
  /** Write one edit through: store it, notify the host, and re-apply the `when` gates. */
20120
20184
  commit(row, key, value) {
20121
20185
  row.values[key] = value;
@@ -32546,6 +32610,11 @@ ${overlayScrollbarCss(".vela-sd-pane")}
32546
32610
  }
32547
32611
 
32548
32612
  // src/renderers/native/backdrop/BackdropRenderer.ts
32613
+ function clipHighlightRect(x1, x2, left, right) {
32614
+ const x = Math.max(left, x1);
32615
+ const end = Math.min(right, x2);
32616
+ return end > x ? { x, width: end - x } : null;
32617
+ }
32549
32618
  var BackdropRenderer = class {
32550
32619
  constructor() {
32551
32620
  this.canvas = null;
@@ -32578,17 +32647,22 @@ ${overlayScrollbarCss(".vela-sd-pane")}
32578
32647
  /** Renderer-owned session highlight bands: full-height (all panes), behind the grid.
32579
32648
  * Session-zone washes (pre/post-market) paint first, host highlights on top. */
32580
32649
  drawHighlights(ctx, scene, coords) {
32581
- const bands = [...scene.sessionHighlightBands(), ...scene.highlights];
32582
- if (bands.length === 0) return;
32650
+ const sessions = scene.sessionHighlightBands();
32651
+ if (sessions.length > 0) {
32652
+ const left = Math.max(0, coords.logicalToX(-0.5));
32653
+ const right = Math.min(coords.width, coords.logicalToX(coords.barCount - 0.5));
32654
+ this.drawHighlightSet(ctx, sessions, coords, left, right);
32655
+ }
32656
+ this.drawHighlightSet(ctx, scene.highlights, coords, 0, coords.width);
32657
+ }
32658
+ drawHighlightSet(ctx, bands, coords, left, right) {
32583
32659
  for (const band of bands) {
32584
32660
  const x1 = coords.timeToX(band.from);
32585
32661
  const x2 = coords.timeToX(band.to);
32586
- if (x2 < 0 || x1 > coords.width || x2 <= x1) continue;
32587
- const cx = Math.max(0, x1);
32588
- const cw = Math.min(coords.width, x2) - cx;
32589
- if (cw <= 0) continue;
32662
+ const rect = clipHighlightRect(x1, x2, left, right);
32663
+ if (!rect) continue;
32590
32664
  ctx.fillStyle = band.color;
32591
- ctx.fillRect(cx, 0, cw, coords.height);
32665
+ ctx.fillRect(rect.x, 0, rect.width, coords.height);
32592
32666
  }
32593
32667
  }
32594
32668
  // ── grid ── vert/horz gate on `scene.showGrid` AND their own per-axis visibility
@@ -37004,6 +37078,9 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37004
37078
  return element;
37005
37079
  }
37006
37080
 
37081
+ // src/widget/topbar-composition.ts
37082
+ var TOPBAR_BUILTIN_IDS = ["symbol", "timeframes", "style", "layout", "indicators", "actions", "undo-redo", "alerts", "panels", "screenshot"];
37083
+
37007
37084
  // src/widget/contributions.ts
37008
37085
  var registry4 = /* @__PURE__ */ new Map();
37009
37086
  var attachments = /* @__PURE__ */ new Map();
@@ -37033,7 +37110,18 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37033
37110
  function sidePanels() {
37034
37111
  return [...panels.values()].sort((a, b) => (a.order ?? DEFAULT_PANEL_ORDER) - (b.order ?? DEFAULT_PANEL_ORDER));
37035
37112
  }
37113
+ var OVERRIDABLE_TOPBAR_IDS = ["indicators", "screenshot"];
37114
+ var overridableSet = new Set(OVERRIDABLE_TOPBAR_IDS);
37115
+ var builtinTopbarSet = new Set(TOPBAR_BUILTIN_IDS);
37116
+ function topbarActionOverride(id) {
37117
+ if (!overridableSet.has(id)) return void 0;
37118
+ return registry4.get(id);
37119
+ }
37036
37120
  function registerWidgetAction(desc) {
37121
+ if (builtinTopbarSet.has(desc.id) && !overridableSet.has(desc.id)) {
37122
+ console.warn(`[vela] widget action "${desc.id}": this built-in topbar slot is a stateful control and cannot be overridden \u2014 ignored. Overridable slots: ${OVERRIDABLE_TOPBAR_IDS.join(", ")}.`);
37123
+ return () => void 0;
37124
+ }
37037
37125
  registry4.set(desc.id, desc);
37038
37126
  return () => {
37039
37127
  if (registry4.get(desc.id) === desc) registry4.delete(desc.id);
@@ -37073,6 +37161,16 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37073
37161
  function statePersistenceHandlers(scope) {
37074
37162
  return [...stateHandlers.values()].filter((h) => h.scope === scope);
37075
37163
  }
37164
+ var symbolRankingHook;
37165
+ function registerSymbolRanking(hook) {
37166
+ symbolRankingHook = hook;
37167
+ return () => {
37168
+ if (symbolRankingHook === hook) symbolRankingHook = void 0;
37169
+ };
37170
+ }
37171
+ function symbolRanking() {
37172
+ return symbolRankingHook;
37173
+ }
37076
37174
  var defaultEngines = /* @__PURE__ */ new Map();
37077
37175
  function registerDefaultEngine(language, make) {
37078
37176
  defaultEngines.set(language, make);
@@ -37104,6 +37202,17 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37104
37202
  return `${parts3.instanceId}:${parts3.kind}:${normTitle}#${parts3.ordinal}`;
37105
37203
  }
37106
37204
 
37205
+ // src/data/symbol-base.ts
37206
+ function baseOf(d) {
37207
+ const fromDesc = d.description?.split("/")[0]?.trim();
37208
+ if (fromDesc) return fromDesc.replace(/\s+Perpetual$/i, "");
37209
+ return d.ticker.replace(/[-_/]?(USDT|USDC|USD1|USDS|BUSD|USD|EUR|PERP)$/i, "") || d.ticker;
37210
+ }
37211
+ function ledgerCryptoIconUrl(base) {
37212
+ const key = base.trim().toUpperCase();
37213
+ return key ? `https://crypto-icons.ledger.com/${encodeURIComponent(key)}.png` : void 0;
37214
+ }
37215
+
37107
37216
  // src/data/providers/binance/BinanceProvider.ts
37108
37217
  var SPOT_BASE = "https://api.binance.com/api/v3";
37109
37218
  var SPOT_BASE_US = "https://api.binance.us/api/v3";
@@ -37290,6 +37399,11 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37290
37399
  }
37291
37400
  return this.symbolsPromise;
37292
37401
  }
37402
+ /** Predefined icon source for a crypto venue: the Ledger crypto-icon CDN, keyed by
37403
+ * the BASE asset (the description's first segment, else the de-suffixed ticker). */
37404
+ resolveSymbolIcon(symbol) {
37405
+ return ledgerCryptoIconUrl(baseOf(symbol));
37406
+ }
37293
37407
  subscribe(ticker, timeframe, onBar) {
37294
37408
  const { apiSymbol, isFutures } = parseTicker(ticker);
37295
37409
  const interval = TF_TO_INTERVAL[normalizeTf(timeframe)];
@@ -37663,6 +37777,11 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37663
37777
  }
37664
37778
  return this.symbolsPromise;
37665
37779
  }
37780
+ /** Predefined icon source for a crypto venue: the Ledger crypto-icon CDN, keyed by
37781
+ * the BASE asset (the description's first segment, else the de-suffixed ticker). */
37782
+ resolveSymbolIcon(symbol) {
37783
+ return ledgerCryptoIconUrl(baseOf(symbol));
37784
+ }
37666
37785
  subscribe(ticker, timeframe, onBar) {
37667
37786
  const coin = parseCoin(ticker);
37668
37787
  const interval = TF_TO_INTERVAL2[normalizeTf2(timeframe)];
@@ -38083,6 +38202,11 @@ ${overlayScrollbarCss(".vela-sd-pane")}
38083
38202
  }
38084
38203
  return this.symbolsPromise;
38085
38204
  }
38205
+ /** Predefined icon source for a crypto venue: the Ledger crypto-icon CDN, keyed by
38206
+ * the BASE asset (the description's first segment, else the de-suffixed ticker). */
38207
+ resolveSymbolIcon(symbol) {
38208
+ return ledgerCryptoIconUrl(baseOf(symbol));
38209
+ }
38086
38210
  subscribe(ticker, timeframe, onBar) {
38087
38211
  const gran = TF_TO_GRAN[normalizeTf3(timeframe)];
38088
38212
  if (gran && typeof WebSocket !== "undefined") return this.streamTicker(ticker, timeframe, gran, onBar);
@@ -38336,6 +38460,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
38336
38460
  exports.MultiProviderFeed = MultiProviderFeed;
38337
38461
  exports.NEUTRAL = NEUTRAL;
38338
38462
  exports.NativeRenderer = NativeRenderer;
38463
+ exports.OVERRIDABLE_TOPBAR_IDS = OVERRIDABLE_TOPBAR_IDS;
38339
38464
  exports.RendererControl = RendererControl;
38340
38465
  exports.SERIES_LINE = SERIES_LINE;
38341
38466
  exports.SESSION_OFF = SESSION_OFF;
@@ -38379,6 +38504,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
38379
38504
  exports.registerRendererLayer = registerRendererLayer;
38380
38505
  exports.registerSidePanel = registerSidePanel;
38381
38506
  exports.registerStatePersistence = registerStatePersistence;
38507
+ exports.registerSymbolRanking = registerSymbolRanking;
38382
38508
  exports.registerWidgetAction = registerWidgetAction;
38383
38509
  exports.registerWidgetAttachment = registerWidgetAttachment;
38384
38510
  exports.rendererDefaults = rendererDefaults;
@@ -38391,8 +38517,10 @@ ${overlayScrollbarCss(".vela-sd-pane")}
38391
38517
  exports.splitColor = splitColor;
38392
38518
  exports.stableSeriesId = stableSeriesId;
38393
38519
  exports.statePersistenceHandlers = statePersistenceHandlers;
38520
+ exports.symbolRanking = symbolRanking;
38394
38521
  exports.tickerModifierIds = tickerModifierIds;
38395
38522
  exports.timeframeToMs = timeframeToMs;
38523
+ exports.topbarActionOverride = topbarActionOverride;
38396
38524
  exports.unregisterChartType = unregisterChartType;
38397
38525
  exports.unregisterDefaultEngine = unregisterDefaultEngine;
38398
38526
  exports.unregisterLegendAction = unregisterLegendAction;