@luxalgo/vela 0.5.3 → 0.5.4

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 (47) hide show
  1. package/README.md +3 -2
  2. package/dist/{DataProvider-DTOEXKTI.d.ts → DataProvider-Cqc_BaJ9.d.ts} +1 -1
  3. package/dist/{DataProvider-gnzv-dgc.d.cts → DataProvider-DgS2UyMc.d.cts} +1 -1
  4. package/dist/{chunk-L5NTMWPP.js → chunk-D6WM5IUE.js} +724 -851
  5. package/dist/{chunk-LJLZR44Y.js → chunk-EMS6PO2T.js} +5 -7
  6. package/dist/{chunk-EY63XBFZ.js → chunk-JBQUY2RI.js} +119 -12
  7. package/dist/chunk-OGRQW3M6.js +1328 -0
  8. package/dist/{chunk-P556H6EA.js → chunk-QWIEKZRE.js} +59 -34
  9. package/dist/{chunk-WJKLBYRM.js → chunk-ZNL2X6U2.js} +1 -1
  10. package/dist/{contributions-Ci_i3IN2.d.cts → contributions-4Nh1jbvb.d.cts} +2 -2
  11. package/dist/{contributions-b6AVrqqG.d.ts → contributions-DuIxJWeH.d.ts} +2 -2
  12. package/dist/{history-Cf1lVsap.d.cts → history-FsmvCIo4.d.ts} +5 -3
  13. package/dist/{history-Ci3M0xLV.d.ts → history-HofqYEh2.d.cts} +5 -3
  14. package/dist/index.cjs +2715 -1606
  15. package/dist/index.d.cts +6 -6
  16. package/dist/index.d.ts +6 -6
  17. package/dist/index.js +4 -4
  18. package/dist/{options-XTBpbx0s.d.ts → options-BlQ00Fju.d.cts} +3 -1
  19. package/dist/{options-XTBpbx0s.d.cts → options-BlQ00Fju.d.ts} +3 -1
  20. package/dist/{plugin-DlidwMj6.d.cts → plugin-DJR6z3e0.d.cts} +3 -3
  21. package/dist/{plugin-DP6A4t4o.d.ts → plugin-N_EaXN4-.d.ts} +3 -3
  22. package/dist/plugin.cjs +4 -0
  23. package/dist/plugin.d.cts +4 -4
  24. package/dist/plugin.d.ts +4 -4
  25. package/dist/plugin.js +2 -2
  26. package/dist/providers/binance.d.cts +2 -2
  27. package/dist/providers/binance.d.ts +2 -2
  28. package/dist/providers/coinbase.d.cts +2 -2
  29. package/dist/providers/coinbase.d.ts +2 -2
  30. package/dist/providers/hyperliquid.d.cts +2 -2
  31. package/dist/providers/hyperliquid.d.ts +2 -2
  32. package/dist/ui.cjs +1318 -4
  33. package/dist/ui.d.cts +383 -2
  34. package/dist/ui.d.ts +383 -2
  35. package/dist/ui.js +3 -3
  36. package/dist/vela.global.js +2709 -1600
  37. package/dist/vela.global.min.js +315 -66
  38. package/dist/widget.cjs +2275 -1032
  39. package/dist/widget.d.cts +25 -7
  40. package/dist/widget.d.ts +25 -7
  41. package/dist/widget.js +27 -9
  42. package/dist/workspace.cjs +2181 -926
  43. package/dist/workspace.d.cts +10 -5
  44. package/dist/workspace.d.ts +10 -5
  45. package/dist/workspace.js +25 -7
  46. package/package.json +1 -1
  47. package/dist/chunk-ATPU5CI6.js +0 -81
@@ -80,6 +80,10 @@ registerIcon(
80
80
  S('<path d="M8 1.8 14 5 8 8.2 2 5z"/><path d="M2 8l6 3.2L14 8" opacity="0.7"/><path d="M2 11l6 3.2 6-3.2" opacity="0.4"/>')
81
81
  );
82
82
  registerIcon("clock", S('<circle cx="8" cy="8" r="6.2"/><path d="M8 4.8V8l2.4 1.6"/>'));
83
+ registerIcon(
84
+ "calendar",
85
+ S('<rect x="2.2" y="3.2" width="11.6" height="10.6" rx="1.4"/><path d="M5.2 1.8v2.8M10.8 1.8v2.8M2.2 6.8h11.6"/>')
86
+ );
83
87
  registerIcon("datawindow", S('<rect x="1.8" y="2.5" width="12.4" height="11" rx="1.5"/><path d="M4.5 5.5h4M4.5 8h7M4.5 10.5h5.5"/>'));
84
88
  registerIcon("camera", S('<path d="M5.5 4 6.5 2.5h3L10.5 4h3A1 1 0 0 1 14.5 5v7.5a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z"/><circle cx="8" cy="8.5" r="2.6"/>'));
85
89
  registerIcon(
@@ -223,12 +227,6 @@ function mix(base, top, alpha) {
223
227
  const c = (x, y) => Math.round(x + (y - x) * alpha);
224
228
  return `rgb(${c(b.r, t.r)},${c(b.g, t.g)},${c(b.b, t.b)})`;
225
229
  }
226
- function toHex6(color, fallback = "#888888") {
227
- const c = parseRgb(color);
228
- if (!c) return fallback;
229
- const h = (n) => Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, "0");
230
- return `#${h(c.r)}${h(c.g)}${h(c.b)}`;
231
- }
232
230
  function isDarkColor(color) {
233
231
  const c = parseRgb(color);
234
232
  if (!c) return true;
@@ -256,4 +254,4 @@ function iconEl(id, doc = document) {
256
254
  return span;
257
255
  }
258
256
 
259
- export { ACCENT, ACCENT_BRIGHT, BEARISH, BULLISH, CATEGORICAL, CROSSHAIR, HIGHLIGHT, INFO, INVALID, MARKER, NEUTRAL, SERIES_LINE, SESSION_OFF, SESSION_POST, SESSION_PRE, SLATE, SLATE_DEEP, TRADE_EXIT, TRADE_LONG, TRADE_SHORT, VALID, WARNING, categoricalColor, icon, iconAt, iconEl, iconMarkup, injectStyles, isDarkColor, mix, registerIcon, svg16, svg24, svg24Solid, toHex6, withAlpha };
257
+ export { ACCENT, ACCENT_BRIGHT, BEARISH, BULLISH, CATEGORICAL, CROSSHAIR, HIGHLIGHT, INFO, INVALID, MARKER, NEUTRAL, SERIES_LINE, SESSION_OFF, SESSION_POST, SESSION_PRE, SLATE, SLATE_DEEP, TRADE_EXIT, TRADE_LONG, TRADE_SHORT, VALID, WARNING, categoricalColor, icon, iconAt, iconEl, iconMarkup, injectStyles, isDarkColor, mix, registerIcon, svg16, svg24, svg24Solid, withAlpha };
@@ -1,7 +1,7 @@
1
- import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel } from './chunk-L5NTMWPP.js';
2
- import { chartType, widgetActions, SidePanel, sidePanels, DEFAULT_PANEL_ORDER, getDrawingType } from './chunk-WJKLBYRM.js';
3
- import { Tooltip, Menu, Dialog, Drawer } from './chunk-P556H6EA.js';
4
- import { iconMarkup, registerIcon, injectStyles, iconEl, SESSION_PRE, SESSION_POST, SESSION_OFF, icon, categoricalColor } from './chunk-LJLZR44Y.js';
1
+ import { parseSymbol, priceStyleIds, BUILTIN_PRICE_STYLES, tzButtonLabel, TIMEZONES, normalizeTimezone, tzMenuLabel } from './chunk-D6WM5IUE.js';
2
+ import { chartType, widgetActions, SidePanel, sidePanels, DEFAULT_PANEL_ORDER, getDrawingType } from './chunk-ZNL2X6U2.js';
3
+ import { Tooltip, Menu, Dialog, Drawer } from './chunk-QWIEKZRE.js';
4
+ import { iconMarkup, registerIcon, injectStyles, iconEl, SESSION_PRE, SESSION_POST, SESSION_OFF, icon, categoricalColor } from './chunk-EMS6PO2T.js';
5
5
 
6
6
  // src/widget/timeframe.ts
7
7
  var UNIT_MS = {
@@ -74,6 +74,24 @@ function timeframeMs(value) {
74
74
  if (!Number.isFinite(count) || count < 1) return NaN;
75
75
  return count * UNIT_MS[key];
76
76
  }
77
+ function favoriteTimeframeChips(favorites) {
78
+ const seen = /* @__PURE__ */ new Set();
79
+ const out = [];
80
+ for (const tf of favorites) {
81
+ if (seen.has(tf)) continue;
82
+ seen.add(tf);
83
+ out.push(tf);
84
+ }
85
+ return out.sort((a, b) => {
86
+ const ma = timeframeMs(a);
87
+ const mb = timeframeMs(b);
88
+ const aOk = Number.isFinite(ma);
89
+ const bOk = Number.isFinite(mb);
90
+ if (aOk && bOk && ma !== mb) return ma - mb;
91
+ if (aOk !== bOk) return aOk ? -1 : 1;
92
+ return 0;
93
+ });
94
+ }
77
95
  function timeframeLabel(value) {
78
96
  const parsed = parseTimeframe(value);
79
97
  if (!parsed.valid) return value;
@@ -454,6 +472,36 @@ var CSS2 = `
454
472
  color: var(--vela-fg-bright);
455
473
  }
456
474
  .vela-widget-symbol:hover, .vela-widget-tf:hover, .vela-widget-style:hover, .vela-widget-indicators:hover, .vela-widget-action-left:hover { background: var(--vela-hover); color: var(--vela-fg-bright); }
475
+ /* Timeframe cluster: duration-sorted favorite chips, highlight in place, caret
476
+ opening the full dropdown. With no favorites the caret is the merged trigger
477
+ (label + chevron). An unstarred current value sits as an extra chip by the caret. */
478
+ .vela-widget-tf-group { display: inline-flex; align-items: center; gap: 2px; }
479
+ .vela-widget-tf-chips { display: inline-flex; align-items: center; gap: 2px; }
480
+ .vela-widget-tf-chips:empty { display: none; }
481
+ .vela-widget-tf[data-current='1'] { background: var(--vela-hover-strong); color: var(--vela-fg-bright); }
482
+ .vela-widget-tf-caret {
483
+ all: unset;
484
+ display: inline-flex;
485
+ align-items: center;
486
+ justify-content: center;
487
+ width: 18px;
488
+ height: 30px;
489
+ border-radius: 4px;
490
+ cursor: pointer;
491
+ color: var(--vela-fg-muted);
492
+ }
493
+ .vela-widget-tf-caret:hover { background: var(--vela-hover); color: var(--vela-fg-bright); }
494
+ .vela-widget-tf-caret[data-solo='1'] {
495
+ width: auto;
496
+ padding: 0 6px 0 9px;
497
+ gap: 4px;
498
+ color: var(--vela-fg-bright);
499
+ background: var(--vela-hover-strong);
500
+ font-size: 13px;
501
+ font-weight: 550;
502
+ white-space: nowrap;
503
+ }
504
+ .vela-widget-topbar .vela-widget-tf-caret .vela-icon { font-size: 14px; width: 14px; height: 14px; }
457
505
  .vela-widget-topbar .vela-icon { color: inherit; font-size: 16px; width: 16px; height: 16px; }
458
506
  /* Width is set in syncHairlines() to exactly one device pixel \u2014 a CSS 1px at
459
507
  fractional DPR (1.25, 1.5\u2026) straddles two physical pixels and siblings end
@@ -558,9 +606,16 @@ var Topbar = class {
558
606
  this.symbolEl.className = "vela-widget-symbol";
559
607
  this.symbolEl.textContent = parseSymbol(opts.symbol).ticker;
560
608
  if (opts.onSymbolClick) this.symbolEl.addEventListener("click", opts.onSymbolClick);
561
- this.tfButton = doc.createElement("button");
562
- this.tfButton.className = "vela-widget-tf";
563
- this.tfButton.textContent = timeframeLabel(this.timeframe);
609
+ this.tfFavs = [...opts.timeframeFavorites ?? []];
610
+ this.tfChipsHost = doc.createElement("span");
611
+ this.tfChipsHost.className = "vela-widget-tf-chips";
612
+ this.tfCaret = doc.createElement("button");
613
+ this.tfCaret.className = "vela-widget-tf-caret";
614
+ this.tfCaret.appendChild(iconEl("chevron-down", doc));
615
+ this.tfCaret.setAttribute("aria-label", "Timeframes");
616
+ const tfGroup = doc.createElement("span");
617
+ tfGroup.className = "vela-widget-tf-group";
618
+ tfGroup.append(this.tfChipsHost, this.tfCaret);
564
619
  this.styleButton = doc.createElement("button");
565
620
  this.styleButton.className = "vela-widget-style";
566
621
  this.renderStyleButton(doc);
@@ -600,19 +655,20 @@ var Topbar = class {
600
655
  d.className = "vela-sep";
601
656
  return d;
602
657
  };
603
- const leading = [this.symbolEl, sep(), this.tfButton, sep(), this.styleButton, sep()];
658
+ const leading = [this.symbolEl, sep(), tfGroup, sep(), this.styleButton, sep()];
604
659
  if (this.layoutButton) leading.push(this.layoutButton, sep());
605
660
  if (indicatorsBtn) leading.push(indicatorsBtn, sep());
606
661
  this.leftActionsSep = sep();
607
662
  this.leftActionsSep.hidden = true;
608
663
  this.el.append(...leading, this.leftActionsHost, this.leftActionsSep, this.undoBtn, this.redoBtn, this.actionsHost, this.alertsBtn, this.panelsHost, screenshotBtn);
609
664
  host.appendChild(this.el);
665
+ this.renderTfChips();
610
666
  this.onHairlineSync();
611
667
  this.hairlineRo = new ResizeObserver(this.onHairlineSync);
612
668
  this.hairlineRo.observe(this.el);
613
669
  doc.defaultView?.addEventListener("resize", this.onHairlineSync);
614
670
  this.renderActions();
615
- this.tooltips.push(new Tooltip(this.tfButton, { content: "Timeframe", triggerId: "vela-topbar-tf", host }));
671
+ this.tooltips.push(new Tooltip(this.tfCaret, { content: "Timeframe", triggerId: "vela-topbar-tf", host }));
616
672
  this.tooltips.push(new Tooltip(this.styleButton, { content: "Chart style", triggerId: "vela-topbar-style", host }));
617
673
  if (this.layoutButton && opts.layout) {
618
674
  this.tooltips.push(new Tooltip(this.layoutButton, { content: "Layout", triggerId: "vela-topbar-layout", host }));
@@ -629,11 +685,12 @@ var Topbar = class {
629
685
  });
630
686
  }
631
687
  this.tfMenu = new Menu({
632
- trigger: this.tfButton,
688
+ trigger: this.tfCaret,
633
689
  triggerId: "vela-topbar-tf",
634
690
  host,
635
691
  items: this.tfItems(),
636
692
  onSelect: (id) => opts.onTimeframe(id),
693
+ onFavorite: (id, on) => opts.onTimeframeFavorite?.(id, on),
637
694
  // Timeframe labels are two-or-three characters ("1m", "4h", "1D") — the
638
695
  // stylesheet's default min-width would leave the list mostly empty.
639
696
  minWidth: "84px"
@@ -651,8 +708,48 @@ var Topbar = class {
651
708
  }
652
709
  setTimeframe(tf) {
653
710
  this.timeframe = tf;
654
- this.tfButton.textContent = timeframeLabel(tf);
655
711
  this.tfMenu.setItems(this.tfItems());
712
+ this.renderTfChips();
713
+ }
714
+ /** Reflect the favorite-timeframe set — the quick-switch chips and the dropdown stars. */
715
+ setTimeframeFavorites(favs) {
716
+ this.tfFavs = [...favs];
717
+ this.renderTfChips();
718
+ this.tfMenu.setItems(this.tfItems());
719
+ }
720
+ /** Rebuild the quick-switch chips (current value changed, or the favorite set did). */
721
+ renderTfChips() {
722
+ const doc = this.el.ownerDocument;
723
+ this.tfChipsHost.replaceChildren();
724
+ const stars = this.opts.onTimeframeFavorite !== void 0;
725
+ const chips = stars ? favoriteTimeframeChips(this.tfFavs) : [];
726
+ const currentIsFav = chips.includes(this.timeframe);
727
+ const shown = currentIsFav || chips.length === 0 ? chips : [...chips, this.timeframe];
728
+ for (const tf of shown) {
729
+ const b = doc.createElement("button");
730
+ b.className = "vela-widget-tf";
731
+ const label = timeframeLabel(tf);
732
+ b.textContent = label;
733
+ if (tf === this.timeframe) {
734
+ b.dataset.current = "1";
735
+ b.setAttribute("aria-current", "true");
736
+ } else {
737
+ b.setAttribute("aria-label", `Switch timeframe to ${label}`);
738
+ b.addEventListener("click", () => this.opts.onTimeframe(tf));
739
+ }
740
+ this.tfChipsHost.appendChild(b);
741
+ }
742
+ this.tfCaret.replaceChildren();
743
+ if (chips.length === 0) {
744
+ this.tfCaret.dataset.solo = "1";
745
+ this.tfCaret.append(doc.createTextNode(timeframeLabel(this.timeframe)), iconEl("chevron-down", doc));
746
+ this.tfCaret.setAttribute("aria-label", `Timeframe \u2014 ${timeframeLabel(this.timeframe)}`);
747
+ } else {
748
+ delete this.tfCaret.dataset.solo;
749
+ this.tfCaret.appendChild(iconEl("chevron-down", doc));
750
+ this.tfCaret.setAttribute("aria-label", "Timeframes");
751
+ }
752
+ this.onHairlineSync();
656
753
  }
657
754
  setPriceStyle(style) {
658
755
  this.priceStyle = style;
@@ -770,7 +867,13 @@ var Topbar = class {
770
867
  }
771
868
  }
772
869
  tfItems() {
773
- return this.opts.timeframes.map((tf) => ({ id: tf, label: timeframeLabel(tf), checked: tf === this.timeframe }));
870
+ const stars = this.opts.onTimeframeFavorite !== void 0;
871
+ return this.opts.timeframes.map((tf) => ({
872
+ id: tf,
873
+ label: timeframeLabel(tf),
874
+ checked: tf === this.timeframe,
875
+ ...stars ? { favorite: this.tfFavs.includes(tf) } : {}
876
+ }));
774
877
  }
775
878
  styleItems() {
776
879
  return priceStyleIds().map((id, i) => ({
@@ -4140,6 +4243,10 @@ function sanitizeState(doc) {
4140
4243
  const favs = d.favorites.filter((f) => typeof f === "string");
4141
4244
  if (favs.length > 0) out.favorites = favs;
4142
4245
  }
4246
+ if (Array.isArray(d.timeframeFavorites)) {
4247
+ const favs = d.timeframeFavorites.filter((f) => typeof f === "string");
4248
+ if (favs.length > 0) out.timeframeFavorites = favs;
4249
+ }
4143
4250
  const sync = sanitizeSync(d.sync);
4144
4251
  if (sync) out.sync = sync;
4145
4252
  const tracks = sanitizeTrackSizes(d.trackSizes);