@luxalgo/vela 0.6.16 → 0.6.17

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 (46) hide show
  1. package/README.md +4 -0
  2. package/dist/{DataProvider-XLdJB86x.d.ts → DataProvider-B-Jz59Rf.d.ts} +1 -1
  3. package/dist/{DataProvider-xH2VBcFT.d.cts → DataProvider-OfR3fXg9.d.cts} +1 -1
  4. package/dist/{chunk-6DPAYEGO.js → chunk-CAFCLMPF.js} +1 -0
  5. package/dist/{chunk-I77F2SVE.js → chunk-IFJJPXSV.js} +1 -1
  6. package/dist/{chunk-SEOO6YG7.js → chunk-OSZDSH7F.js} +5 -8
  7. package/dist/{chunk-MGU3USTP.js → chunk-T5Z5YUCF.js} +1 -1
  8. package/dist/{chunk-Q3TFJNJW.js → chunk-XCBJU674.js} +2 -2
  9. package/dist/{chunk-GIJYO4LO.js → chunk-YCD72KGK.js} +103 -40
  10. package/dist/{contributions-BEkxwA5F.d.cts → contributions-C3b0Sx5P.d.cts} +2 -2
  11. package/dist/{contributions-CoAX7_SF.d.ts → contributions-Swzz10fG.d.ts} +2 -2
  12. package/dist/index.cjs +99 -36
  13. package/dist/index.d.cts +15 -6
  14. package/dist/index.d.ts +15 -6
  15. package/dist/index.js +4 -4
  16. package/dist/{options-bdSAtp7y.d.ts → options-CX1lSYWA.d.cts} +12 -2
  17. package/dist/{options-bdSAtp7y.d.cts → options-CX1lSYWA.d.ts} +12 -2
  18. package/dist/{plugin-Dxyq35Zf.d.cts → plugin-BjnEE1zA.d.cts} +3 -3
  19. package/dist/{plugin-CNUgbRNq.d.ts → plugin-mvddudqd.d.ts} +3 -3
  20. package/dist/plugin.cjs +1 -0
  21. package/dist/plugin.d.cts +4 -4
  22. package/dist/plugin.d.ts +4 -4
  23. package/dist/plugin.js +2 -2
  24. package/dist/providers/binance.d.cts +2 -2
  25. package/dist/providers/binance.d.ts +2 -2
  26. package/dist/providers/coinbase.d.cts +2 -2
  27. package/dist/providers/coinbase.d.ts +2 -2
  28. package/dist/providers/hyperliquid.d.cts +2 -2
  29. package/dist/providers/hyperliquid.d.ts +2 -2
  30. package/dist/{statusline-model-CbPza-Wc.d.cts → statusline-model-D91cU2fF.d.cts} +3 -3
  31. package/dist/{statusline-model-D7cWkw8A.d.ts → statusline-model-IURCya0H.d.ts} +3 -3
  32. package/dist/ui.cjs +1 -0
  33. package/dist/ui.d.cts +1 -1
  34. package/dist/ui.d.ts +1 -1
  35. package/dist/ui.js +3 -3
  36. package/dist/vela.global.js +99 -36
  37. package/dist/vela.global.min.js +46 -49
  38. package/dist/widget.cjs +100 -39
  39. package/dist/widget.d.cts +6 -6
  40. package/dist/widget.d.ts +6 -6
  41. package/dist/widget.js +7 -7
  42. package/dist/workspace.cjs +100 -39
  43. package/dist/workspace.d.cts +5 -5
  44. package/dist/workspace.d.ts +5 -5
  45. package/dist/workspace.js +6 -6
  46. package/package.json +1 -1
package/README.md CHANGED
@@ -32,6 +32,10 @@ touching the rest.
32
32
 
33
33
  ## What's in the box
34
34
 
35
+ <p align="center">
36
+ <img src=".github/vela-layout.png" alt="Vela package layout" width="100%">
37
+ </p>
38
+
35
39
  - **`@luxalgo/vela`**: the headless chart. Data model, engines, drawings, providers,
36
40
  native renderer.
37
41
  - **`@luxalgo/vela/workspace`**: the full chart app. One chart or a grid of them under
@@ -1,4 +1,4 @@
1
- import { M as MarketConfig, O as OHLCV, U as Unsubscribe } from './options-bdSAtp7y.js';
1
+ import { M as MarketConfig, O as OHLCV, U as Unsubscribe } from './options-CX1lSYWA.js';
2
2
 
3
3
  /**
4
4
  * Symbol metadata an engine may need (e.g. Pine `syminfo.*`). Free-form beyond
@@ -1,4 +1,4 @@
1
- import { M as MarketConfig, O as OHLCV, U as Unsubscribe } from './options-bdSAtp7y.cjs';
1
+ import { M as MarketConfig, O as OHLCV, U as Unsubscribe } from './options-CX1lSYWA.cjs';
2
2
 
3
3
  /**
4
4
  * Symbol metadata an engine may need (e.g. Pine `syminfo.*`). Free-form beyond
@@ -151,6 +151,7 @@ registerIcon("star-filled", S('<path d="M8 2.2l1.75 3.55 3.9.55-2.8 2.75.65 3.9L
151
151
  registerIcon("grip", S('<circle cx="6" cy="3.5" r="1"/><circle cx="10" cy="3.5" r="1"/><circle cx="6" cy="8" r="1"/><circle cx="10" cy="8" r="1"/><circle cx="6" cy="12.5" r="1"/><circle cx="10" cy="12.5" r="1"/>', 'fill="currentColor" stroke="none"'));
152
152
  registerIcon("kebab", S('<circle cx="8" cy="3.2" r="1.2"/><circle cx="8" cy="8" r="1.2"/><circle cx="8" cy="12.8" r="1.2"/>', 'fill="currentColor" stroke="none"'));
153
153
  registerIcon("burger", S('<path d="M2.5 4.5h11M2.5 8h11M2.5 11.5h11"/>'));
154
+ registerIcon("info", S('<path d="M8 7.4v4.4"/><circle cx="8" cy="4.6" r="0.9" fill="currentColor" stroke="none"/>'));
154
155
  registerIcon("reset", S('<path d="M2 8a6 6 0 1 0 6-6 6.5 6.5 0 0 0-4.5 1.83L2 5.33"/><path d="M2 2v3.33h3.33"/>'));
155
156
  registerIcon("pane-collapse", S('<path d="M2.6 9.4h4v4M13.4 6.6h-4v-4"/><path d="m9.4 6.6 4.2-4.2M2.4 13.6l4.2-4.2"/>'));
156
157
  registerIcon("pane-expand", S('<path d="M9.8 2.4h3.8v3.8M6.2 13.6H2.4V9.8"/><path d="m13.6 2.4-4.4 4.4M2.4 13.6l4.4-4.4"/>'));
@@ -1,4 +1,4 @@
1
- import { svg24, NEUTRAL, BEARISH, WARNING, BULLISH, INFO, ACCENT_BRIGHT, VALID, INVALID, MARKER, ACCENT, injectStyles, iconEl } from './chunk-6DPAYEGO.js';
1
+ import { svg24, NEUTRAL, BEARISH, WARNING, BULLISH, INFO, ACCENT_BRIGHT, VALID, INVALID, MARKER, ACCENT, injectStyles, iconEl } from './chunk-CAFCLMPF.js';
2
2
 
3
3
  // src/core/native-indicators/NativeIndicator.ts
4
4
  var REGISTRY = /* @__PURE__ */ new Map();
@@ -1,8 +1,8 @@
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
- import { registerIcon, svg16, injectStyles, iconEl, iconMarkup, iconAt, SESSION_OFF, SESSION_POST, SESSION_PRE, icon, categoricalColor } from './chunk-6DPAYEGO.js';
1
+ import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel, isGroupRow, defaultMemberOf, groupKeyOf, groupMembers, LEGEND_AT_TOP_ATTR, normalizeSession, Vela, TypedEventBus, MultiProviderFeed, registerBuiltinChartTypes, resolveTheme, buildToolbar, createCustomMark, createAttributionMark, DrawingToolbar, applyAttributionMarkTheme, sharedBarStore, timeframeToMs } from './chunk-YCD72KGK.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-IFJJPXSV.js';
3
+ import { Tooltip, KeymapManager, isEditableTarget, Drawer } from './chunk-XCBJU674.js';
4
+ import { Menu, Dialog, CalloutBubble, applyPlotOverlayTokens, ensureUIHost } from './chunk-T5Z5YUCF.js';
5
+ import { registerIcon, svg16, injectStyles, iconEl, iconMarkup, iconAt, SESSION_OFF, SESSION_POST, SESSION_PRE, icon, categoricalColor } from './chunk-CAFCLMPF.js';
6
6
  import { baseOf } from './chunk-W4EJWLEO.js';
7
7
 
8
8
  // src/widget/timeframe.ts
@@ -4826,9 +4826,6 @@ var ChartContextMenu = class {
4826
4826
  }
4827
4827
  };
4828
4828
 
4829
- // src/core/options.ts
4830
- var normalizeSession = (v) => v === "regular" || v === "extended" ? v : void 0;
4831
-
4832
4829
  // src/widget/session-shading.ts
4833
4830
  var DAY_MS = 864e5;
4834
4831
  var MINUTE_MS = 6e4;
@@ -1,4 +1,4 @@
1
- import { overlayScrollbarCss, injectStyles, isDarkColor, mix, HIGHLIGHT, ACCENT_BRIGHT, ACCENT, withAlpha, iconAt, iconEl, BULLISH, BEARISH, WARNING, NEUTRAL } from './chunk-6DPAYEGO.js';
1
+ import { overlayScrollbarCss, injectStyles, isDarkColor, mix, HIGHLIGHT, ACCENT_BRIGHT, ACCENT, withAlpha, iconAt, iconEl, BULLISH, BEARISH, WARNING, NEUTRAL } from './chunk-CAFCLMPF.js';
2
2
  import { VanillaMachine, normalizeProps, spreadProps } from '@zag-js/vanilla';
3
3
  export { normalizeProps, spreadProps } from '@zag-js/vanilla';
4
4
  import * as menu from '@zag-js/menu';
@@ -1,5 +1,5 @@
1
- import { normalizeProps, nextUid, runMachine, spreadProps } from './chunk-MGU3USTP.js';
2
- import { injectStyles } from './chunk-6DPAYEGO.js';
1
+ import { normalizeProps, nextUid, runMachine, spreadProps } from './chunk-T5Z5YUCF.js';
2
+ import { injectStyles } from './chunk-CAFCLMPF.js';
3
3
  import * as tooltip from '@zag-js/tooltip';
4
4
  import * as dialog from '@zag-js/dialog';
5
5
 
@@ -1,6 +1,6 @@
1
- import { deserializeDrawing, chartTypes, rendererLayers, foldBaseModulation, registerChartType, rendererDefaults, getDrawingType, settingsRowVisible, normalizeSettingsRow, Magnifier, TextLabel, Callout, resetDrawingSettings, registerNativeIndicator, chartType, getNativeIndicator, nativeIndicatorDescriptors, drawingTypes, settingsRowValueKeys, formatDuration, RegressionChannel, FixedRangeVolumeProfile, SegmentDrawing, ArrowMark, GlyphStamp, RadialFib, FibSpiral, DedekindTessellation, MachFigure, GannSquare, FibRatios, MeasureBox, PositionTool, AnchoredVwap, PatternDrawing, Comment, PriceNote, Signpost, Note, PriceLabel, GANN_SQUARE_ARCS, magnifierTimeframeLabel, lineSegmentIntersection, DEFAULT_DRAWING_COLOR, MAGNIFIER_TIMEFRAME_OPTIONS, GLYPH_OPTIONS, STAMP_SIZE_OPTIONS, LINE_STYLE_OPTIONS, DEDEKIND_CURVATURE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, TEXT_SIZE_OPTIONS, createDrawing, inputVisible, tickerModifierIds, CalloutBase, DIRECTION_OPTIONS, stableSeriesId } from './chunk-I77F2SVE.js';
2
- import { themeTokens, Dialog, closeOpenPopovers, closeWidthPopover, fieldSection, buildFieldControl, fieldSeparator, fieldGrid, fieldRow, blendOver, splitColor, CalloutBubble, Menu, TextArea, Popover, NumberInput, buildColorPicker, isPopoverOpen, eventDismissedPopover, toggleSelectList, openPopoverTrigger, fieldGridColumns, FIELD_GAP_PX, STATIC_TOKENS } from './chunk-MGU3USTP.js';
3
- import { icon, iconAt, withAlpha, WARNING, ACCENT, NEUTRAL, BEARISH, BULLISH, isDarkColor, SERIES_LINE, CHIP_PLATE, CROSSHAIR, TRADE_EXIT, TRADE_SHORT, TRADE_LONG, overlayScrollbarCss, SLATE_DEEP, VALID, INVALID, SLATE, FIELD_FOCUS_CSS, FIELD_FOCUS_RING, INFO, svg24, svg24Solid } from './chunk-6DPAYEGO.js';
1
+ import { deserializeDrawing, chartTypes, rendererLayers, foldBaseModulation, registerChartType, rendererDefaults, getDrawingType, settingsRowVisible, normalizeSettingsRow, Magnifier, TextLabel, Callout, resetDrawingSettings, registerNativeIndicator, chartType, getNativeIndicator, nativeIndicatorDescriptors, drawingTypes, settingsRowValueKeys, formatDuration, RegressionChannel, FixedRangeVolumeProfile, SegmentDrawing, ArrowMark, GlyphStamp, RadialFib, FibSpiral, DedekindTessellation, MachFigure, GannSquare, FibRatios, MeasureBox, PositionTool, AnchoredVwap, PatternDrawing, Comment, PriceNote, Signpost, Note, PriceLabel, GANN_SQUARE_ARCS, magnifierTimeframeLabel, lineSegmentIntersection, DEFAULT_DRAWING_COLOR, MAGNIFIER_TIMEFRAME_OPTIONS, GLYPH_OPTIONS, STAMP_SIZE_OPTIONS, LINE_STYLE_OPTIONS, DEDEKIND_CURVATURE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, TEXT_SIZE_OPTIONS, createDrawing, inputVisible, tickerModifierIds, CalloutBase, DIRECTION_OPTIONS, stableSeriesId } from './chunk-IFJJPXSV.js';
2
+ import { themeTokens, Dialog, closeOpenPopovers, closeWidthPopover, fieldSection, buildFieldControl, fieldSeparator, fieldGrid, fieldRow, blendOver, splitColor, CalloutBubble, Menu, TextArea, Popover, NumberInput, buildColorPicker, isPopoverOpen, eventDismissedPopover, toggleSelectList, openPopoverTrigger, fieldGridColumns, FIELD_GAP_PX, STATIC_TOKENS } from './chunk-T5Z5YUCF.js';
3
+ import { icon, iconAt, withAlpha, WARNING, ACCENT, NEUTRAL, BEARISH, BULLISH, isDarkColor, SERIES_LINE, CHIP_PLATE, CROSSHAIR, TRADE_EXIT, TRADE_SHORT, TRADE_LONG, overlayScrollbarCss, SLATE_DEEP, VALID, INVALID, SLATE, FIELD_FOCUS_CSS, FIELD_FOCUS_RING, INFO, svg24, svg24Solid } from './chunk-CAFCLMPF.js';
4
4
 
5
5
  // src/core/events/EventBus.ts
6
6
  var TypedEventBus = class {
@@ -2368,6 +2368,23 @@ function attachChromeTooltip(anchor, opts) {
2368
2368
  clear();
2369
2369
  };
2370
2370
  }
2371
+ function chromeHint(text, opts) {
2372
+ const px = opts.size ?? 16;
2373
+ const el = document.createElement("span");
2374
+ el.className = "vela-hint";
2375
+ el.setAttribute("role", "img");
2376
+ el.setAttribute("aria-label", text);
2377
+ el.innerHTML = iconAt("info", px);
2378
+ el.style.cssText = `flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:${px}px;height:${px}px;border-radius:50%;cursor:help;user-select:none;background:var(--vela-hover);color:var(--vela-fg-muted);transition:background var(--vela-dur-fast) ease,color var(--vela-dur-fast) ease;`;
2379
+ const hover = (on) => {
2380
+ el.style.background = on ? "var(--vela-active)" : "var(--vela-hover)";
2381
+ el.style.color = on ? "var(--vela-fg-bright)" : "var(--vela-fg-muted)";
2382
+ };
2383
+ el.addEventListener("pointerenter", () => hover(true));
2384
+ el.addEventListener("pointerleave", () => hover(false));
2385
+ const dispose = attachChromeTooltip(el, { host: opts.host, theme: opts.theme, text: () => text, wrap: true, delayMs: 250 });
2386
+ return { el, dispose };
2387
+ }
2371
2388
 
2372
2389
  // src/renderers/native/drawings/DrawingToolbar.ts
2373
2390
  var TOOLBAR_WIDTH = 44;
@@ -3001,6 +3018,24 @@ function arrowHitHtml(svg) {
3001
3018
  return `<span class="vela-dtb-hit vela-dtb-hit--arrow">${iconSpan(svg, 11)}</span>`;
3002
3019
  }
3003
3020
 
3021
+ // src/core/options.ts
3022
+ var normalizeSession = (v) => v === "regular" || v === "extended" ? v : void 0;
3023
+ var LIVE_BAR_EASE_DEFAULT_MS = 90;
3024
+ var LIVE_BAR_EASE_MAX_MS = 1e3;
3025
+ function resolveLiveBarEaseMs(value) {
3026
+ if (value === true) return LIVE_BAR_EASE_DEFAULT_MS;
3027
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return 0;
3028
+ return Math.min(value, LIVE_BAR_EASE_MAX_MS);
3029
+ }
3030
+ function resolveAnimations(animations) {
3031
+ if (typeof animations === "boolean") return { animZoom: animations, animPan: animations, animLiveBar: 0 };
3032
+ return {
3033
+ animZoom: animations?.zoom ?? true,
3034
+ animPan: animations?.pan ?? true,
3035
+ animLiveBar: resolveLiveBarEaseMs(animations?.liveBar)
3036
+ };
3037
+ }
3038
+
3004
3039
  // src/core/model/series.ts
3005
3040
  function isLineLikeSeries(spec) {
3006
3041
  return spec.kind !== "candle" && spec.kind !== "bar" && spec.kind !== "markers";
@@ -3373,14 +3408,11 @@ var IndicatorInputsDialog = class {
3373
3408
  buildTextField(id, current, emit) {
3374
3409
  return buildFieldControl({ kind: "text", id, value: current, onChange: emit }).el;
3375
3410
  }
3376
- /** A hoverable ⓘ affordance carrying an input's `tooltip` (themed chrome tip; wraps). */
3411
+ /** The shared ⓘ hint carrying an input's `tooltip` (see {@link chromeHint}). */
3377
3412
  infoButton(tooltip) {
3378
- const b = document.createElement("span");
3379
- b.textContent = "i";
3380
- this.dialogTips.push(attachChromeTooltip(b, { host: this.host.container, theme: () => this.host.theme(), text: () => tooltip, wrap: true, delayMs: 250 }));
3381
- b.className = "vela-ind-hint";
3382
- b.style.cssText = "flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;font-weight:600;font-size:11px;font-family:inherit;line-height:1;cursor:help;user-select:none;";
3383
- return b;
3413
+ const { el, dispose } = chromeHint(tooltip, { host: this.host.container, theme: () => this.host.theme(), size: 18 });
3414
+ this.dialogTips.push(dispose);
3415
+ return el;
3384
3416
  }
3385
3417
  /** A dropdown over plain string options (value === label) — a thin case of {@link selectPairs}. */
3386
3418
  select(id, options, current, emit) {
@@ -3817,8 +3849,6 @@ function ensureDialogStyles() {
3817
3849
  ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
3818
3850
  .vela-ind-tab{font-weight:600;font-size:13px;line-height:20px;transition:color var(--vela-dur-fast) ease,border-color var(--vela-dur-fast) ease;}
3819
3851
  .vela-ind-tab:not(.vela-ind-tab-active):hover{color:var(--vela-fg-bright);}
3820
- .vela-ind-hint{background:var(--vela-hover);color:var(--vela-fg-muted);transition:background var(--vela-dur-fast) ease,color var(--vela-dur-fast) ease;}
3821
- .vela-ind-hint:hover{background:var(--vela-active);color:var(--vela-fg-bright);}
3822
3852
  .vela-ind-ctl,.vela-ind-close{background-color:transparent;color:inherit;transition:color var(--vela-dur-fast) ease,background-color var(--vela-dur-fast) ease;}
3823
3853
  .vela-ind-ctl svg,.vela-ind-close svg{width:${LEGEND_ICON_PX}px;height:${LEGEND_ICON_PX}px;display:block;flex:none;stroke-width:1;}
3824
3854
  .vela-ind-ctl:hover{background-color:var(--vela-hover-strong);}
@@ -5362,7 +5392,8 @@ function mergeConfig(base, patch) {
5362
5392
  labelsVisible: isBool(ps.labelsVisible) ? ps.labelsVisible : base.priceScale.labelsVisible,
5363
5393
  currentPriceLine: isBool(ps.currentPriceLine) ? ps.currentPriceLine : base.priceScale.currentPriceLine,
5364
5394
  priceLabel: isBool(ps.priceLabel) ? ps.priceLabel : base.priceScale.priceLabel,
5365
- countdown: isBool(ps.countdown) ? ps.countdown : base.priceScale.countdown
5395
+ countdown: isBool(ps.countdown) ? ps.countdown : base.priceScale.countdown,
5396
+ animateLastPrice: isBool(ps.animateLastPrice) ? ps.animateLastPrice : base.priceScale.animateLastPrice
5366
5397
  },
5367
5398
  panes: {
5368
5399
  separatorColor: isColor(panes.separatorColor) ? panes.separatorColor : base.panes.separatorColor
@@ -10149,6 +10180,8 @@ var BUILTIN_SETTINGS_IDS = [
10149
10180
  "symbol.style.baseline.fill-bottom",
10150
10181
  "symbol.style.baseline.base-level",
10151
10182
  "symbol.style.baseline.width",
10183
+ "symbol.animation",
10184
+ "symbol.animation.price-changes",
10152
10185
  "symbol.timezone",
10153
10186
  "scales",
10154
10187
  "scales.price-scale",
@@ -10291,8 +10324,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
10291
10324
  .vela-sd-mobile .vela-select-trigger,.vela-sd-mobile .vela-num input,.vela-sd-mobile .vela-width-field{height:34px;}
10292
10325
  .vela-sd-mobile .vela-sd-close{width:40px;height:40px;}
10293
10326
  .vela-sd-mobile .vela-sd-btn{height:38px;}
10294
- .vela-sd-mobile .vela-sd-row span,.vela-sd-mobile .vela-sd-bool span,.vela-sd-mobile .vela-field-label{white-space:normal !important;}
10295
- `;
10327
+ .vela-sd-mobile .vela-sd-row span,.vela-sd-mobile .vela-sd-bool span,.vela-sd-mobile .vela-field-label{white-space:normal !important;}`;
10296
10328
  if (!existing) document.head.appendChild(st);
10297
10329
  }
10298
10330
  var SettingsDialog = class {
@@ -10313,6 +10345,8 @@ var SettingsDialog = class {
10313
10345
  this.themeControl = null;
10314
10346
  /** The built tabs, by title — how `showSection` reaches a pane while the dialog is open. */
10315
10347
  this.tabs = [];
10348
+ this.hintTips = [];
10349
+ // ⓘ tooltip disposers of the open build (see hint)
10316
10350
  /** Active instance-strip tab per chart type — remembered across dialog rebuilds. */
10317
10351
  this.typeActiveInstance = /* @__PURE__ */ new Map();
10318
10352
  /** Active TOC group per structured pane (`<typeId>/<pane>` → group label). */
@@ -10501,6 +10535,13 @@ var SettingsDialog = class {
10501
10535
  body.append(g);
10502
10536
  }
10503
10537
  showActive(config.series.style);
10538
+ body.append(sid(this.sectionTitle("Animation"), "symbol.animation"));
10539
+ body.append(sid(this.boolRow(
10540
+ "Animate price changes",
10541
+ config.priceScale.animateLastPrice,
10542
+ (v) => this.emit({ priceScale: { animateLastPrice: v } }),
10543
+ this.hint("Glide the live bar to each new price instead of snapping.")
10544
+ ), "symbol.animation.price-changes"));
10504
10545
  body.append(sid(this.sectionTitle("Time zone"), "symbol.timezone"));
10505
10546
  body.append(sid(this.selectRowLabeled("Time zone", normalizeTimezone(config.timeScale.timezone), timezoneOptions(config.timeScale.timezone), (v) => this.emit({ timeScale: { timezone: v } })), "symbol.timezone"));
10506
10547
  const renderHostSections = (placement) => {
@@ -10708,6 +10749,8 @@ var SettingsDialog = class {
10708
10749
  this.ui = null;
10709
10750
  this.root = null;
10710
10751
  this.tabs = [];
10752
+ for (const dispose of this.hintTips) dispose();
10753
+ this.hintTips = [];
10711
10754
  ui?.destroy();
10712
10755
  }
10713
10756
  destroy() {
@@ -11121,23 +11164,31 @@ var SettingsDialog = class {
11121
11164
  }).el
11122
11165
  });
11123
11166
  }
11124
- /** A toggle row: the checkbox sits to the LEFT of its label (never in the control area). */
11125
- boolRow(label, value, onChange) {
11126
- return this.toggleRow(label, value, onChange, []);
11167
+ /** A toggle row: the checkbox sits to the LEFT of its label (never in the control area).
11168
+ * `info` (see {@link hint}) rides after the label. */
11169
+ boolRow(label, value, onChange, info) {
11170
+ return this.toggleRow(label, value, onChange, [], void 0, info);
11127
11171
  }
11128
11172
  /** An enable row: checkbox + label in the label column, dependent controls in the
11129
11173
  * shared control column; the control group dims and ignores input while the toggle
11130
11174
  * is off. With `get`, the row re-reads its state on a 'vela-sync' event. */
11131
- toggleRow(label, value, onToggle, controls, get) {
11175
+ toggleRow(label, value, onToggle, controls, get, info) {
11132
11176
  return fieldRow({
11133
11177
  label,
11134
11178
  labelSize: "sm",
11135
11179
  bool: controls.length === 0,
11136
11180
  toggle: { checked: value, onChange: onToggle, get },
11137
11181
  control: controls,
11182
+ info,
11138
11183
  className: controls.length === 0 ? "vela-sd-bool" : "vela-sd-row"
11139
11184
  });
11140
11185
  }
11186
+ /** The shared ⓘ hint after a row label (see {@link chromeHint}). Disposed with the dialog. */
11187
+ hint(text) {
11188
+ const { el, dispose } = chromeHint(text, { host: this.container, theme: () => this.theme });
11189
+ this.hintTips.push(dispose);
11190
+ return el;
11191
+ }
11141
11192
  numberRow(label, value, min, max, step, onChange) {
11142
11193
  return fieldRow({
11143
11194
  label,
@@ -16491,7 +16542,6 @@ var ZOOM_OUT_MARGIN_BARS = 6;
16491
16542
  var ZOOM_TAU_MS = 70;
16492
16543
  var SCALE_TAU_MS = 80;
16493
16544
  var FLING_TAU_MS = 110;
16494
- var LIVE_BAR_TAU_MS = 90;
16495
16545
  var SCROLL_TO_TAU_MS = 130;
16496
16546
  var FLING_STOP_PX = 0.02;
16497
16547
  var PRICE_SCALE_K = 4e-3;
@@ -16562,9 +16612,13 @@ var NativeRenderer = class {
16562
16612
  /** Drawings layer self-serves Ctrl+Z/Y (see the `historyChords` feature). */
16563
16613
  this.historyChordsEnabled = true;
16564
16614
  this.liveRegion = null;
16565
- // ── animation state (eased zoom + inertial pan) ──
16615
+ // ── animation state (eased zoom + inertial pan + live-bar glide) ──
16566
16616
  this.animZoom = true;
16567
16617
  this.animPan = true;
16618
+ this.animLiveBarMs = 0;
16619
+ // forming-bar OHLC glide time-constant; 0 = each tick snaps
16620
+ this.animLiveBarOnMs = LIVE_BAR_EASE_DEFAULT_MS;
16621
+ // the duration the settings-dialog on/off toggle restores (last non-zero value configured)
16568
16622
  // Brand default candles.
16569
16623
  this.candleUp = BULLISH;
16570
16624
  this.candleDown = BEARISH;
@@ -16689,7 +16743,7 @@ var NativeRenderer = class {
16689
16743
  this.moveIndicatorCbs = /* @__PURE__ */ new Set();
16690
16744
  this.priceStyleCbs = /* @__PURE__ */ new Set();
16691
16745
  this.name = "native";
16692
- this.features = ["logScale", "currentPriceLine", "priceLabel", "countdown", "upColor", "downColor", "glow", "animZoom", "animPan", "intro", "zoomAnchor", "axisDrag", "paneResize", "candleZOrder", "candleVisible", "seriesOrder", "highlights", "sessionZones", "gridlines", "axisLabels", "scaleMode", "invertScale", "paneScales", "autoScale", "timezone", "keyboard", "historyChords", "priceStyle", "priceBaseline", "baselinePrice", "settings", "attribution", "dialogHost", "tradeMarkers", "indicatorTitles", "indicatorValues"];
16746
+ this.features = ["logScale", "currentPriceLine", "priceLabel", "countdown", "upColor", "downColor", "glow", "animZoom", "animPan", "animLiveBar", "intro", "zoomAnchor", "axisDrag", "paneResize", "candleZOrder", "candleVisible", "seriesOrder", "highlights", "sessionZones", "gridlines", "axisLabels", "scaleMode", "invertScale", "paneScales", "autoScale", "timezone", "keyboard", "historyChords", "priceStyle", "priceBaseline", "baselinePrice", "settings", "attribution", "dialogHost", "tradeMarkers", "indicatorTitles", "indicatorValues"];
16693
16747
  /** Track cursor proximity to the scroll button on the plot (bubbles from the button too,
16694
16748
  * so moving onto the button doesn't count as leaving). */
16695
16749
  this.onScrollProximityMove = (e) => {
@@ -16723,6 +16777,7 @@ var NativeRenderer = class {
16723
16777
  this.backendMode = opts.nativeBackend;
16724
16778
  this.animZoom = opts.animZoom;
16725
16779
  this.animPan = opts.animPan;
16780
+ this.setLiveBarEase(resolveLiveBarEaseMs(opts.animLiveBar));
16726
16781
  this.glowAmount = opts.glow;
16727
16782
  this.candleUp = opts.upColor;
16728
16783
  this.candleDown = opts.downColor;
@@ -16772,6 +16827,10 @@ var NativeRenderer = class {
16772
16827
  case "animPan":
16773
16828
  this.animPan = Boolean(value);
16774
16829
  return;
16830
+ case "animLiveBar":
16831
+ this.setLiveBarEase(resolveLiveBarEaseMs(value));
16832
+ return;
16833
+ // affects the next tick only; a glide in flight finishes at the new rate (or snaps at 0)
16775
16834
  case "intro": {
16776
16835
  const s = value === false || value === "none" || value === "off" || value == null ? "" : String(value);
16777
16836
  this.introStyle = s;
@@ -16908,6 +16967,8 @@ var NativeRenderer = class {
16908
16967
  return this.animZoom;
16909
16968
  case "animPan":
16910
16969
  return this.animPan;
16970
+ case "animLiveBar":
16971
+ return this.animLiveBarMs;
16911
16972
  case "intro":
16912
16973
  return this.introStyle;
16913
16974
  case "zoomAnchor":
@@ -17076,7 +17137,8 @@ var NativeRenderer = class {
17076
17137
  labelsVisible: this.scene.showAxisLabels,
17077
17138
  currentPriceLine: this.scene.showPriceLine,
17078
17139
  priceLabel: this.scene.showPriceLabel,
17079
- countdown: this.scene.showCountdown
17140
+ countdown: this.scene.showCountdown,
17141
+ animateLastPrice: this.animLiveBarMs > 0
17080
17142
  },
17081
17143
  panes: { separatorColor: s.separatorColor ?? t.borderColor },
17082
17144
  trades: {
@@ -17183,6 +17245,7 @@ var NativeRenderer = class {
17183
17245
  this.scene.showPriceLabel = next.priceScale.priceLabel;
17184
17246
  this.scene.showCountdown = next.priceScale.countdown;
17185
17247
  this.syncCountdownTimer();
17248
+ this.animLiveBarMs = next.priceScale.animateLastPrice ? this.animLiveBarOnMs : 0;
17186
17249
  s.separatorColor = keepInherit(s.separatorColor, next.panes.separatorColor, prevTheme.borderColor);
17187
17250
  this.scene.tradeMarkers = {
17188
17251
  visible: next.trades.visible,
@@ -17999,8 +18062,11 @@ var NativeRenderer = class {
17999
18062
  const last = this.bars[n - 1];
18000
18063
  if (last && bar.time === last.time) {
18001
18064
  this.bars[n - 1] = bar;
18002
- if (this.liveEaseTime !== bar.time) this.syncLiveEase(bar);
18003
- this.animator.start();
18065
+ if (this.animLiveBarMs <= 0 || this.liveEaseTime !== bar.time) {
18066
+ this.syncLiveEase(bar);
18067
+ } else {
18068
+ this.animator.start();
18069
+ }
18004
18070
  } else if (!last || bar.time > last.time) {
18005
18071
  this.bars.push(bar);
18006
18072
  this.syncLiveEase(bar);
@@ -18012,6 +18078,12 @@ var NativeRenderer = class {
18012
18078
  this.scene.bars = this.bars;
18013
18079
  this.scheduler.invalidate(4 /* Full */);
18014
18080
  }
18081
+ /** Set the live-bar glide duration (0 = off). A non-zero value is also remembered as
18082
+ * what the config's on/off toggle (`priceScale.animateLastPrice`) switches back on to. */
18083
+ setLiveBarEase(ms) {
18084
+ this.animLiveBarMs = ms;
18085
+ if (ms > 0) this.animLiveBarOnMs = ms;
18086
+ }
18015
18087
  /** Snap the eased forming-bar state to `bar` — no glide (a fresh bar or the first tick of one). */
18016
18088
  syncLiveEase(bar) {
18017
18089
  this.liveEaseTime = bar.time;
@@ -18024,9 +18096,10 @@ var NativeRenderer = class {
18024
18096
  const target = this.bars[this.bars.length - 1];
18025
18097
  if (!target || this.liveEaseTime !== target.time) return false;
18026
18098
  const eps = Math.max(1e-9, Math.abs(target.close) * 1e-6);
18027
- const nh = easeToward(this.liveEaseHigh, target.high, dtMs, LIVE_BAR_TAU_MS);
18028
- const nl = easeToward(this.liveEaseLow, target.low, dtMs, LIVE_BAR_TAU_MS);
18029
- const nc = easeToward(this.liveEaseClose, target.close, dtMs, LIVE_BAR_TAU_MS);
18099
+ const tau = this.animLiveBarMs;
18100
+ const nh = easeToward(this.liveEaseHigh, target.high, dtMs, tau);
18101
+ const nl = easeToward(this.liveEaseLow, target.low, dtMs, tau);
18102
+ const nc = easeToward(this.liveEaseClose, target.close, dtMs, tau);
18030
18103
  const active = Math.abs(nh - target.high) > eps || Math.abs(nl - target.low) > eps || Math.abs(nc - target.close) > eps;
18031
18104
  this.liveEaseHigh = active ? nh : target.high;
18032
18105
  this.liveEaseLow = active ? nl : target.low;
@@ -24341,21 +24414,11 @@ var Vela = class {
24341
24414
  registerClassicIndicators();
24342
24415
  const element = resolveElement(container);
24343
24416
  const theme = resolveTheme(options.theme);
24344
- let animZoom = true;
24345
- let animPan = true;
24346
- if (typeof options.animations === "boolean") {
24347
- animZoom = options.animations;
24348
- animPan = options.animations;
24349
- } else if (options.animations) {
24350
- animZoom = options.animations.zoom ?? true;
24351
- animPan = options.animations.pan ?? true;
24352
- }
24353
24417
  const display = {
24354
24418
  currentPriceLine: options.currentPriceLine ?? true,
24355
24419
  logScale: options.logScale ?? false,
24356
24420
  nativeBackend: options.nativeBackend ?? "auto",
24357
- animZoom,
24358
- animPan,
24421
+ ...resolveAnimations(options.animations),
24359
24422
  glow: options.glow ?? 0,
24360
24423
  upColor: options.upColor ?? BULLISH,
24361
24424
  downColor: options.downColor ?? BEARISH,
@@ -24670,4 +24733,4 @@ function resolveElement(container) {
24670
24733
  return element;
24671
24734
  }
24672
24735
 
24673
- export { BUILTIN_PRICE_STYLES, BarStore, CachingDataFeed, DARK_THEME, DataControl, DrawingStore, DrawingToolbar, DrawingsControl, LEGEND_AT_TOP_ATTR, LIGHT_THEME, MultiProviderFeed, NativeRenderer, RendererControl, TIMEZONES, TypedEventBus, Vela, applyAttributionMarkTheme, buildToolbar, createAttributionMark, createCustomMark, defaultMemberOf, defaultToolbar, groupKeyOf, groupMembers, isGroupRow, normalizeTimezone, parseSymbol, priceStyleIds, registerBuiltinChartTypes, resolveTheme, sharedBarStore, timeframeToMs, tzButtonLabel, tzMenuLabel, tzOffset };
24736
+ export { BUILTIN_PRICE_STYLES, BarStore, CachingDataFeed, DARK_THEME, DataControl, DrawingStore, DrawingToolbar, DrawingsControl, LEGEND_AT_TOP_ATTR, LIGHT_THEME, MultiProviderFeed, NativeRenderer, RendererControl, TIMEZONES, TypedEventBus, Vela, applyAttributionMarkTheme, buildToolbar, createAttributionMark, createCustomMark, defaultMemberOf, defaultToolbar, groupKeyOf, groupMembers, isGroupRow, normalizeSession, normalizeTimezone, parseSymbol, priceStyleIds, registerBuiltinChartTypes, resolveTheme, sharedBarStore, timeframeToMs, tzButtonLabel, tzMenuLabel, tzOffset };
@@ -1,5 +1,5 @@
1
- import { u as Millis, ai as InputSchema, ag as IndicatorMeta, P as PriceStyle, O as OHLCV, I as InputValue, l as IndicatorModel, k as MoveTarget, au as PaneAxis, aH as SeriesSpec, ae as Fill, B as Background, az as PriceLine, a1 as DrawingLine, Z as DrawingBox, a0 as DrawingLabel, a5 as DrawingPolyline, a2 as DrawingLinefill, aa as DrawingTable, h as IndicatorStatus, a as VisibleRange, c as VelaTheme, S as SerializedDrawing, w as DrawingTypeKey, v as SnapMode, a3 as DrawingMode, e as IChartRenderer, R as RendererCapabilities, o as LegendActionView, p as LegendCalloutView, U as Unsubscribe, C as CrosshairEvent, A as AxisLongPressEvent, s as DataWindowReadout, n as SymbolPickerFn, aW as PaneInfo, ad as DrawingsOption, a7 as DrawingSeriesGateway, D as Drawing, b as VelaOptions, y as AddIndicatorOptions, at as MarketSwitch, as as MarketSnapshot, V as VisibleRangePreset, T as ThemeName } from './options-bdSAtp7y.cjs';
2
- import { S as SymbolInfo, B as BarRange, M as MarketDataFeed, D as DataProvider, P as ProviderInfo, a as SymbolDescriptor, b as ProviderCapabilities } from './DataProvider-xH2VBcFT.cjs';
1
+ import { u as Millis, aj as InputSchema, ah as IndicatorMeta, P as PriceStyle, O as OHLCV, I as InputValue, l as IndicatorModel, k as MoveTarget, av as PaneAxis, aI as SeriesSpec, af as Fill, B as Background, aA as PriceLine, a2 as DrawingLine, _ as DrawingBox, a1 as DrawingLabel, a6 as DrawingPolyline, a3 as DrawingLinefill, ab as DrawingTable, h as IndicatorStatus, a as VisibleRange, c as VelaTheme, S as SerializedDrawing, w as DrawingTypeKey, v as SnapMode, a4 as DrawingMode, e as IChartRenderer, R as RendererCapabilities, o as LegendActionView, p as LegendCalloutView, U as Unsubscribe, C as CrosshairEvent, A as AxisLongPressEvent, s as DataWindowReadout, n as SymbolPickerFn, aX as PaneInfo, ae as DrawingsOption, a8 as DrawingSeriesGateway, D as Drawing, b as VelaOptions, y as AddIndicatorOptions, au as MarketSwitch, at as MarketSnapshot, V as VisibleRangePreset, T as ThemeName } from './options-CX1lSYWA.cjs';
2
+ import { S as SymbolInfo, B as BarRange, M as MarketDataFeed, D as DataProvider, P as ProviderInfo, a as SymbolDescriptor, b as ProviderCapabilities } from './DataProvider-OfR3fXg9.cjs';
3
3
 
4
4
  /**
5
5
  * A strategy's broker state at ONE bar — the flat summary a host reads while a script
@@ -1,5 +1,5 @@
1
- import { u as Millis, ai as InputSchema, ag as IndicatorMeta, P as PriceStyle, O as OHLCV, I as InputValue, l as IndicatorModel, k as MoveTarget, au as PaneAxis, aH as SeriesSpec, ae as Fill, B as Background, az as PriceLine, a1 as DrawingLine, Z as DrawingBox, a0 as DrawingLabel, a5 as DrawingPolyline, a2 as DrawingLinefill, aa as DrawingTable, h as IndicatorStatus, a as VisibleRange, c as VelaTheme, S as SerializedDrawing, w as DrawingTypeKey, v as SnapMode, a3 as DrawingMode, e as IChartRenderer, R as RendererCapabilities, o as LegendActionView, p as LegendCalloutView, U as Unsubscribe, C as CrosshairEvent, A as AxisLongPressEvent, s as DataWindowReadout, n as SymbolPickerFn, aW as PaneInfo, ad as DrawingsOption, a7 as DrawingSeriesGateway, D as Drawing, b as VelaOptions, y as AddIndicatorOptions, at as MarketSwitch, as as MarketSnapshot, V as VisibleRangePreset, T as ThemeName } from './options-bdSAtp7y.js';
2
- import { S as SymbolInfo, B as BarRange, M as MarketDataFeed, D as DataProvider, P as ProviderInfo, a as SymbolDescriptor, b as ProviderCapabilities } from './DataProvider-XLdJB86x.js';
1
+ import { u as Millis, aj as InputSchema, ah as IndicatorMeta, P as PriceStyle, O as OHLCV, I as InputValue, l as IndicatorModel, k as MoveTarget, av as PaneAxis, aI as SeriesSpec, af as Fill, B as Background, aA as PriceLine, a2 as DrawingLine, _ as DrawingBox, a1 as DrawingLabel, a6 as DrawingPolyline, a3 as DrawingLinefill, ab as DrawingTable, h as IndicatorStatus, a as VisibleRange, c as VelaTheme, S as SerializedDrawing, w as DrawingTypeKey, v as SnapMode, a4 as DrawingMode, e as IChartRenderer, R as RendererCapabilities, o as LegendActionView, p as LegendCalloutView, U as Unsubscribe, C as CrosshairEvent, A as AxisLongPressEvent, s as DataWindowReadout, n as SymbolPickerFn, aX as PaneInfo, ae as DrawingsOption, a8 as DrawingSeriesGateway, D as Drawing, b as VelaOptions, y as AddIndicatorOptions, au as MarketSwitch, at as MarketSnapshot, V as VisibleRangePreset, T as ThemeName } from './options-CX1lSYWA.js';
2
+ import { S as SymbolInfo, B as BarRange, M as MarketDataFeed, D as DataProvider, P as ProviderInfo, a as SymbolDescriptor, b as ProviderCapabilities } from './DataProvider-B-Jz59Rf.js';
3
3
 
4
4
  /**
5
5
  * A strategy's broker state at ONE bar — the flat summary a host reads while a script