@luxalgo/vela 0.8.5 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/dist/{DataProvider-BUdlkx9I.d.ts → DataProvider-BGlB1zSc.d.ts} +1 -1
  2. package/dist/{DataProvider-DdqMxKdl.d.cts → DataProvider-zJGp58kb.d.cts} +1 -1
  3. package/dist/{chunk-BN4DNS3O.js → chunk-4WAHYL7Y.js} +1125 -468
  4. package/dist/chunk-O6L27KRB.js +1331 -0
  5. package/dist/{chunk-WY5H4S4I.js → chunk-PZN4RS4T.js} +91 -36
  6. package/dist/{chunk-AUOB7A5Y.js → chunk-WHPQQYH7.js} +29 -13
  7. package/dist/{chunk-QYIO37K7.js → chunk-XIRSR3D6.js} +2374 -1529
  8. package/dist/{chunk-ALTGHKIM.js → chunk-YRCL3WMD.js} +510 -406
  9. package/dist/{contributions-D8xuYc9U.d.cts → contributions-BjefWpxQ.d.ts} +71 -22
  10. package/dist/{contributions-P9fBBuY1.d.ts → contributions-CpCJisTC.d.cts} +71 -22
  11. package/dist/index.cjs +4022 -2088
  12. package/dist/index.d.cts +51 -25
  13. package/dist/index.d.ts +51 -25
  14. package/dist/index.js +5 -5
  15. package/dist/{keymap-CGOz5F5f.d.ts → keymap-B9_FLhfJ.d.cts} +9 -6
  16. package/dist/{keymap-CGOz5F5f.d.cts → keymap-UolhuXH1.d.ts} +9 -6
  17. package/dist/locales/ar.cjs +2260 -0
  18. package/dist/locales/ar.d.cts +5 -0
  19. package/dist/locales/ar.d.ts +5 -0
  20. package/dist/locales/ar.js +2258 -0
  21. package/dist/locales/de.cjs +2260 -0
  22. package/dist/locales/de.d.cts +5 -0
  23. package/dist/locales/de.d.ts +5 -0
  24. package/dist/locales/de.js +2258 -0
  25. package/dist/locales/en.cjs +2260 -0
  26. package/dist/locales/en.d.cts +5 -0
  27. package/dist/locales/en.d.ts +5 -0
  28. package/dist/locales/en.js +2258 -0
  29. package/dist/locales/es.cjs +2260 -0
  30. package/dist/locales/es.d.cts +5 -0
  31. package/dist/locales/es.d.ts +5 -0
  32. package/dist/locales/es.js +2258 -0
  33. package/dist/locales/fr.cjs +2260 -0
  34. package/dist/locales/fr.d.cts +5 -0
  35. package/dist/locales/fr.d.ts +5 -0
  36. package/dist/locales/fr.js +2258 -0
  37. package/dist/locales/he.cjs +2260 -0
  38. package/dist/locales/he.d.cts +5 -0
  39. package/dist/locales/he.d.ts +5 -0
  40. package/dist/locales/he.js +2258 -0
  41. package/dist/locales/hi.cjs +2260 -0
  42. package/dist/locales/hi.d.cts +5 -0
  43. package/dist/locales/hi.d.ts +5 -0
  44. package/dist/locales/hi.js +2258 -0
  45. package/dist/locales/id.cjs +2260 -0
  46. package/dist/locales/id.d.cts +5 -0
  47. package/dist/locales/id.d.ts +5 -0
  48. package/dist/locales/id.js +2258 -0
  49. package/dist/locales/it.cjs +2260 -0
  50. package/dist/locales/it.d.cts +5 -0
  51. package/dist/locales/it.d.ts +5 -0
  52. package/dist/locales/it.js +2258 -0
  53. package/dist/locales/ja.cjs +2260 -0
  54. package/dist/locales/ja.d.cts +5 -0
  55. package/dist/locales/ja.d.ts +5 -0
  56. package/dist/locales/ja.js +2258 -0
  57. package/dist/locales/ko.cjs +2260 -0
  58. package/dist/locales/ko.d.cts +5 -0
  59. package/dist/locales/ko.d.ts +5 -0
  60. package/dist/locales/ko.js +2258 -0
  61. package/dist/locales/ms.cjs +2260 -0
  62. package/dist/locales/ms.d.cts +5 -0
  63. package/dist/locales/ms.d.ts +5 -0
  64. package/dist/locales/ms.js +2258 -0
  65. package/dist/locales/pl.cjs +2260 -0
  66. package/dist/locales/pl.d.cts +5 -0
  67. package/dist/locales/pl.d.ts +5 -0
  68. package/dist/locales/pl.js +2258 -0
  69. package/dist/locales/pt-BR.cjs +2260 -0
  70. package/dist/locales/pt-BR.d.cts +5 -0
  71. package/dist/locales/pt-BR.d.ts +5 -0
  72. package/dist/locales/pt-BR.js +2258 -0
  73. package/dist/locales/ru.cjs +2260 -0
  74. package/dist/locales/ru.d.cts +5 -0
  75. package/dist/locales/ru.d.ts +5 -0
  76. package/dist/locales/ru.js +2258 -0
  77. package/dist/locales/th.cjs +2260 -0
  78. package/dist/locales/th.d.cts +5 -0
  79. package/dist/locales/th.d.ts +5 -0
  80. package/dist/locales/th.js +2258 -0
  81. package/dist/locales/tr.cjs +2260 -0
  82. package/dist/locales/tr.d.cts +5 -0
  83. package/dist/locales/tr.d.ts +5 -0
  84. package/dist/locales/tr.js +2258 -0
  85. package/dist/locales/vi.cjs +2260 -0
  86. package/dist/locales/vi.d.cts +5 -0
  87. package/dist/locales/vi.d.ts +5 -0
  88. package/dist/locales/vi.js +2258 -0
  89. package/dist/locales/zh-Hans.cjs +2260 -0
  90. package/dist/locales/zh-Hans.d.cts +5 -0
  91. package/dist/locales/zh-Hans.d.ts +5 -0
  92. package/dist/locales/zh-Hans.js +2258 -0
  93. package/dist/locales/zh-Hant.cjs +2260 -0
  94. package/dist/locales/zh-Hant.d.cts +5 -0
  95. package/dist/locales/zh-Hant.d.ts +5 -0
  96. package/dist/locales/zh-Hant.js +2258 -0
  97. package/dist/{options-BI5Tp32b.d.cts → options-CpegHml_.d.cts} +74 -9
  98. package/dist/{options-BI5Tp32b.d.ts → options-D4L3_hv_.d.ts} +74 -9
  99. package/dist/{plugin-D5Z-Q6TX.d.ts → plugin-DTmulpKM.d.ts} +81 -35
  100. package/dist/{plugin-B8F1nor8.d.cts → plugin-DpNp4aBi.d.cts} +81 -35
  101. package/dist/plugin.cjs +1267 -319
  102. package/dist/plugin.d.cts +7 -6
  103. package/dist/plugin.d.ts +7 -6
  104. package/dist/plugin.js +3 -3
  105. package/dist/providers/binance.cjs +1 -1
  106. package/dist/providers/binance.d.cts +3 -2
  107. package/dist/providers/binance.d.ts +3 -2
  108. package/dist/providers/binance.js +1 -1
  109. package/dist/providers/coinbase.cjs +1 -1
  110. package/dist/providers/coinbase.d.cts +3 -2
  111. package/dist/providers/coinbase.d.ts +3 -2
  112. package/dist/providers/coinbase.js +1 -1
  113. package/dist/providers/hyperliquid.cjs +1 -1
  114. package/dist/providers/hyperliquid.d.cts +3 -2
  115. package/dist/providers/hyperliquid.d.ts +3 -2
  116. package/dist/providers/hyperliquid.js +1 -1
  117. package/dist/{side-panel-_2UK1gSm.d.ts → side-panel-BqUnpfev.d.cts} +13 -2
  118. package/dist/{side-panel-_2UK1gSm.d.cts → side-panel-CYmH1Opm.d.ts} +13 -2
  119. package/dist/{statusline-model-CTwtDIca.d.cts → statusline-model-C3yIY9WE.d.ts} +11 -3
  120. package/dist/{statusline-model-D9kWC9X5.d.ts → statusline-model-pGs3Xvp-.d.cts} +11 -3
  121. package/dist/types-BlrXRLIR.d.cts +2515 -0
  122. package/dist/types-BlrXRLIR.d.ts +2515 -0
  123. package/dist/ui.cjs +1008 -56
  124. package/dist/ui.d.cts +21 -2
  125. package/dist/ui.d.ts +21 -2
  126. package/dist/ui.js +3 -3
  127. package/dist/vela.global.js +3987 -2055
  128. package/dist/vela.global.min.js +57 -57
  129. package/dist/widget.cjs +5330 -2699
  130. package/dist/widget.d.cts +100 -26
  131. package/dist/widget.d.ts +100 -26
  132. package/dist/widget.js +19 -11
  133. package/dist/workspace.cjs +5319 -2706
  134. package/dist/workspace.d.cts +63 -15
  135. package/dist/workspace.d.ts +63 -15
  136. package/dist/workspace.js +6 -6
  137. package/package.json +9 -2
  138. package/dist/chunk-I2U4NZD2.js +0 -340
  139. /package/dist/{chunk-W5YPYZ2P.js → chunk-3EYCX2L4.js} +0 -0
@@ -1,4 +1,4 @@
1
- import { overlayScrollbarCss, isDarkColor, mix, HIGHLIGHT, ACCENT_BRIGHT, ACCENT, withAlpha, injectStyles, announceSurface, holdForExit, iconAt, iconEl, BULLISH, BEARISH, WARNING, NEUTRAL } from './chunk-I2U4NZD2.js';
1
+ import { msg, overlayScrollbarCss, isDarkColor, mix, HIGHLIGHT, ACCENT_BRIGHT, ACCENT, withAlpha, injectStyles, announceSurface, holdForExit, iconAt, iconEl, englishTranslator, formatSettingsOf, monthNames, yearLabel, weekdayNames, yearBeforeMonth, textOf, BULLISH, BEARISH, WARNING, NEUTRAL, plainInteger } from './chunk-O6L27KRB.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';
@@ -112,7 +112,7 @@ var STATIC_CSS = `
112
112
  ${STATIC_DECLS}
113
113
  font-family: var(--vela-font, -apple-system, system-ui, sans-serif);
114
114
  box-sizing: border-box;
115
- /* Chrome text (titles, buttons, menus, readouts) is UI, not copy \u2014 never selectable. */
115
+ /* Chrome text (titles, buttons, menus, readouts) is UI, not copy — never selectable. */
116
116
  user-select: none;
117
117
  -webkit-user-select: none;
118
118
  }
@@ -121,7 +121,7 @@ ${STATIC_DECLS}
121
121
  .vela-ui :is(input, textarea), .vela-ui-layer :is(input, textarea) { user-select: text; -webkit-user-select: text; }
122
122
  /* iOS Safari zooms the page when a focused field is under 16px, and often
123
123
  keeps that zoom after the field blurs or a dialog closes. The shell's
124
- mobile size class is the honest gate \u2014 not a media query \u2014 so an embedded
124
+ mobile size class is the honest gate — not a media query — so an embedded
125
125
  chart on a wide desktop still gets the rule when it is in the phone layout.
126
126
  Scoped to the kit root so a host page's own [data-layout] is never touched. */
127
127
  .vela-ui[data-layout='mobile'] :is(input, textarea, select) { font-size: 16px; }
@@ -202,7 +202,7 @@ var MENU_CSS = `
202
202
  .vela-menu-item .vela-icon { width: 16px; height: 16px; font-size: 16px; justify-content: center; color: var(--vela-fg-muted); }
203
203
  .vela-menu-item .vela-menu-label { flex: 1 1 auto; }
204
204
  .vela-menu-item .vela-menu-hint { color: var(--vela-fg-faint); font-size: var(--vela-font-size-sm); }
205
- /* Active entry: the row surface carries the selection \u2014 a stronger background wash
205
+ /* Active entry: the row surface carries the selection — a stronger background wash
206
206
  than the hover one, plus bright ink. Declared after the hover rule so a selected
207
207
  row stays visibly selected while highlighted. */
208
208
  .vela-menu-item[data-checked] {
@@ -210,7 +210,7 @@ var MENU_CSS = `
210
210
  color: var(--vela-fg-bright);
211
211
  }
212
212
  /* Checkmark mode (context/action menus): every row reserves the leading mark column so
213
- labels align; a checked row fills it with a \u2713 and brightens its ink \u2014 the row surface
213
+ labels align; a checked row fills it with a ✓ and brightens its ink — the row surface
214
214
  stays free for the hover wash. */
215
215
  .vela-menu-item .vela-menu-mark {
216
216
  width: 14px;
@@ -255,7 +255,7 @@ var MENU_CSS = `
255
255
  border-color: color-mix(in srgb, var(--vela-fg-bright) 40%, transparent);
256
256
  color: var(--vela-surface);
257
257
  }
258
- /* Switch rows (boolean settings in a dropdown): a right-aligned toggle pill \u2014 the
258
+ /* Switch rows (boolean settings in a dropdown): a right-aligned toggle pill — the
259
259
  same control language as the settings dialog's toggles. */
260
260
  .vela-menu-switch {
261
261
  order: 99;
@@ -282,8 +282,8 @@ var MENU_CSS = `
282
282
  }
283
283
  .vela-menu-switch.on { background: var(--vela-accent-bright, var(--vela-accent)); border-color: var(--vela-accent-bright, var(--vela-accent)); }
284
284
  .vela-menu-switch.on::after { transform: translateX(16px); background: var(--vela-bg); }
285
- /* Favorite star (rows carrying \`favorite\`): reserved space always \u2014 it fades in on row
286
- hover instead of shifting the layout \u2014 and a starred row keeps its filled star visible.
285
+ /* Favorite star (rows carrying \`favorite\`): reserved space always — it fades in on row
286
+ hover instead of shifting the layout — and a starred row keeps its filled star visible.
287
287
  Same control language as the drawing toolbar's flyout stars. */
288
288
  .vela-menu-item .vela-menu-star {
289
289
  order: 98;
@@ -311,6 +311,27 @@ var MENU_CSS = `
311
311
  }
312
312
  .vela-menu-item[data-state='open'] { background: var(--vela-hover); }
313
313
  `;
314
+
315
+ // src/ui/kit-text.ts
316
+ var scoped = null;
317
+ function withKitTranslator(i18n, build) {
318
+ const previous = scoped;
319
+ scoped = i18n ?? null;
320
+ try {
321
+ return build();
322
+ } finally {
323
+ scoped = previous;
324
+ }
325
+ }
326
+ function kitTranslator() {
327
+ return scoped;
328
+ }
329
+
330
+ // src/ui/components/menu/view.ts
331
+ var TEXT = {
332
+ addFavorite: msg("ui.menu.addFavorite", "Add to favorites"),
333
+ removeFavorite: msg("ui.menu.removeFavorite", "Remove from favorites")
334
+ };
314
335
  var Surface = class _Surface {
315
336
  constructor(doc, opts) {
316
337
  this.items = [];
@@ -327,6 +348,7 @@ var Surface = class _Surface {
327
348
  this.host = opts.host;
328
349
  this.onSelect = opts.onSelect;
329
350
  this.onFavorite = opts.onFavorite;
351
+ this.i18n = opts.i18n;
330
352
  this.checkmarks = opts.checkmarks === true;
331
353
  this.iconBadges = opts.iconBadges === true;
332
354
  this.positioner = doc.createElement("div");
@@ -489,7 +511,7 @@ var Surface = class _Surface {
489
511
  if (on) star.classList.add("vela-fav");
490
512
  star.removeAttribute("aria-hidden");
491
513
  star.setAttribute("role", "button");
492
- star.setAttribute("aria-label", on ? "Remove from favorites" : "Add to favorites");
514
+ star.setAttribute("aria-label", textOf(this.i18n, on ? TEXT.removeFavorite : TEXT.addFavorite));
493
515
  star.setAttribute("aria-pressed", on ? "true" : "false");
494
516
  for (const ev of ["pointerdown", "pointerup", "mousedown", "mouseup"]) {
495
517
  star.addEventListener(ev, (e) => e.stopPropagation());
@@ -518,6 +540,7 @@ var Surface = class _Surface {
518
540
  opener: li,
519
541
  onSelect: this.onSelect,
520
542
  onFavorite: this.onFavorite,
543
+ i18n: this.i18n,
521
544
  checkmarks: this.checkmarks,
522
545
  iconBadges: this.iconBadges,
523
546
  id: `${this.mid}--${item.id}`
@@ -545,6 +568,7 @@ var Menu = class {
545
568
  id: opts.id,
546
569
  minWidth: opts.minWidth,
547
570
  onFavorite: opts.onFavorite,
571
+ i18n: opts.i18n ?? kitTranslator(),
548
572
  checkmarks: opts.checkmarks,
549
573
  iconBadges: opts.iconBadges
550
574
  });
@@ -865,7 +889,7 @@ var CALLOUT_CSS = `
865
889
  }
866
890
  .vela-callout[role='button'] { cursor: pointer; }
867
891
  .vela-callout svg { display: block; }
868
- /* The deployed panel \u2014 carries the kit's elevated-card look itself (the popover
892
+ /* The deployed panel — carries the kit's elevated-card look itself (the popover
869
893
  shell is bare positioning chrome). */
870
894
  .vela-callout-panel {
871
895
  display: flex;
@@ -1440,13 +1464,13 @@ var DIALOG_CSS = `
1440
1464
  .vela-dialog-btn-primary:hover { background: var(--vela-selected-bg); color: var(--vela-selected-fg); opacity: 0.85; border-color: var(--vela-selected-bg); }
1441
1465
  ${overlayScrollbarCss(".vela-dialog-body")}
1442
1466
  /* Scrollers NESTED in a dialog (a flush body's grid, a tab pane) get the same thin
1443
- overlay bars \u2014 the two-class selectors below stay overridable by more specific
1467
+ overlay bars — the two-class selectors below stay overridable by more specific
1444
1468
  per-dialog sheets. */
1445
1469
  ${overlayScrollbarCss(".vela-dialog *")}
1446
- /* \u2500\u2500 mobile chrome: dialogs fill the shell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1470
+ /* ── mobile chrome: dialogs fill the shell ─────────────────────────────────────────
1447
1471
  Inside a shell in the mobile size class ([data-layout='mobile'] on the widget root,
1448
1472
  which is position:relative) every kit dialog presents fullscreen: desktop cards are
1449
- unusable at phone widths, and the shell's bounds \u2014 not the viewport \u2014 are the honest
1473
+ unusable at phone widths, and the shell's bounds — not the viewport — are the honest
1450
1474
  "screen" for an embedded chart. */
1451
1475
  [data-layout='mobile'] .vela-dialog-backdrop { position: absolute; }
1452
1476
  [data-layout='mobile'] .vela-dialog-positioner {
@@ -1663,9 +1687,14 @@ var Dialog = class {
1663
1687
  };
1664
1688
 
1665
1689
  // src/ui/components/date-picker/controller.ts
1666
- var MONTH_LABELS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
1667
- var MONTH_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
1668
- var WEEKDAY_LABELS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
1690
+ var NAV = {
1691
+ prevMonth: msg("ui.datePicker.previousMonth", "Previous month"),
1692
+ nextMonth: msg("ui.datePicker.nextMonth", "Next month"),
1693
+ prevYear: msg("ui.datePicker.previousYear", "Previous year"),
1694
+ nextYear: msg("ui.datePicker.nextYear", "Next year"),
1695
+ prevDecade: msg("ui.datePicker.previousDecade", "Previous decade"),
1696
+ nextDecade: msg("ui.datePicker.nextDecade", "Next decade")
1697
+ };
1669
1698
  function isoDate(d) {
1670
1699
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
1671
1700
  }
@@ -1691,6 +1720,12 @@ function datePickerController(opts = {}) {
1691
1720
  let year = selected?.getFullYear() ?? today.getFullYear();
1692
1721
  let month = selected?.getMonth() ?? today.getMonth();
1693
1722
  let panel = "date";
1723
+ const i18n = opts.i18n ?? englishTranslator();
1724
+ const settings = formatSettingsOf(i18n);
1725
+ const weekStart = opts.i18n ? i18n.weekStart : 0;
1726
+ const monthsLong = monthNames(settings, "long");
1727
+ const monthsShort = monthNames(settings, "short");
1728
+ const num = (n) => plainInteger(settings, n);
1694
1729
  const decade = () => Math.floor(year / 10) * 10;
1695
1730
  return {
1696
1731
  get panel() {
@@ -1705,38 +1740,43 @@ function datePickerController(opts = {}) {
1705
1740
  get value() {
1706
1741
  return selected ? isoDate(selected) : null;
1707
1742
  },
1743
+ yearFirst: yearBeforeMonth(settings),
1744
+ weekdays() {
1745
+ const names = weekdayNames(settings);
1746
+ return Array.from({ length: 7 }, (_, i) => names[(weekStart + i) % 7]);
1747
+ },
1708
1748
  header() {
1709
1749
  return {
1710
- month: MONTH_LABELS[month] ?? "",
1750
+ month: monthsLong[month] ?? "",
1711
1751
  monthVisible: panel === "date",
1712
- year: panel === "year" ? `${decade()}-${decade() + 9}` : String(year),
1752
+ year: panel === "year" ? `${num(decade())}-${num(decade() + 9)}` : yearLabel(settings, year),
1713
1753
  yearDisabled: panel === "year"
1714
1754
  // in the decade panel the year reads as its title
1715
1755
  };
1716
1756
  },
1717
1757
  navLabels() {
1718
- if (panel === "date") return { prev: "Previous month", next: "Next month" };
1719
- if (panel === "month") return { prev: "Previous year", next: "Next year" };
1720
- return { prev: "Previous decade", next: "Next decade" };
1758
+ if (panel === "date") return { prev: i18n.t(NAV.prevMonth), next: i18n.t(NAV.nextMonth) };
1759
+ if (panel === "month") return { prev: i18n.t(NAV.prevYear), next: i18n.t(NAV.nextYear) };
1760
+ return { prev: i18n.t(NAV.prevDecade), next: i18n.t(NAV.nextDecade) };
1721
1761
  },
1722
1762
  cells() {
1723
1763
  const out = [];
1724
1764
  if (panel === "date") {
1725
- const startPad = new Date(year, month, 1).getDay();
1765
+ const startPad = (new Date(year, month, 1).getDay() - weekStart + 7) % 7;
1726
1766
  const days = new Date(year, month + 1, 0).getDate();
1727
1767
  const todayIso = isoDate(today);
1728
1768
  const selectedIso = selected ? isoDate(selected) : "";
1729
1769
  for (let i = 0; i < startPad; i++) out.push({ label: "", value: "", checked: false, today: false, blank: true });
1730
1770
  for (let day = 1; day <= days; day++) {
1731
1771
  const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
1732
- out.push({ label: String(day), value: iso, checked: iso === selectedIso, today: iso === todayIso });
1772
+ out.push({ label: num(day), value: iso, checked: iso === selectedIso, today: iso === todayIso });
1733
1773
  }
1734
1774
  return out;
1735
1775
  }
1736
1776
  if (panel === "month") {
1737
1777
  for (let m = 0; m < 12; m++) {
1738
1778
  out.push({
1739
- label: MONTH_SHORT[m] ?? "",
1779
+ label: monthsShort[m] ?? "",
1740
1780
  value: m,
1741
1781
  checked: selected?.getFullYear() === year && selected.getMonth() === m,
1742
1782
  today: today.getFullYear() === year && today.getMonth() === m
@@ -1746,7 +1786,7 @@ function datePickerController(opts = {}) {
1746
1786
  }
1747
1787
  const d = decade();
1748
1788
  for (let y = d - 1; y <= d + 10; y++) {
1749
- out.push({ label: String(y), value: y, checked: selected?.getFullYear() === y, today: today.getFullYear() === y, outside: y < d || y > d + 9 });
1789
+ out.push({ label: num(y), value: y, checked: selected?.getFullYear() === y, today: today.getFullYear() === y, outside: y < d || y > d + 9 });
1750
1790
  }
1751
1791
  return out;
1752
1792
  },
@@ -1826,6 +1866,8 @@ var DATE_PICKER_CSS = `
1826
1866
  `;
1827
1867
 
1828
1868
  // src/ui/components/date-picker/view.ts
1869
+ var CHOOSE_MONTH = msg("ui.datePicker.chooseMonth", "Choose month");
1870
+ var CHOOSE_YEAR = msg("ui.datePicker.chooseYear", "Choose year");
1829
1871
  var DatePicker = class {
1830
1872
  constructor(opts = {}) {
1831
1873
  this.opts = opts;
@@ -1842,19 +1884,21 @@ var DatePicker = class {
1842
1884
  this.prev.append(iconEl("chevron-left", doc));
1843
1885
  this.next = button("vela-date-picker-nav");
1844
1886
  this.next.append(iconEl("chevron-right", doc));
1887
+ const i18n = opts.i18n ?? englishTranslator();
1845
1888
  this.monthBtn = button("vela-date-picker-switch");
1846
- this.monthBtn.setAttribute("aria-label", "Choose month");
1889
+ this.monthBtn.setAttribute("aria-label", i18n.t(CHOOSE_MONTH));
1847
1890
  this.yearBtn = button("vela-date-picker-switch");
1848
- this.yearBtn.setAttribute("aria-label", "Choose year");
1891
+ this.yearBtn.setAttribute("aria-label", i18n.t(CHOOSE_YEAR));
1849
1892
  const title = doc.createElement("div");
1850
1893
  title.className = "vela-date-picker-title";
1851
- title.append(this.monthBtn, this.yearBtn);
1894
+ if (this.ctrl.yearFirst) title.append(this.yearBtn, this.monthBtn);
1895
+ else title.append(this.monthBtn, this.yearBtn);
1852
1896
  const head = doc.createElement("div");
1853
1897
  head.className = "vela-date-picker-head";
1854
1898
  head.append(this.prev, title, this.next);
1855
1899
  this.week = doc.createElement("div");
1856
1900
  this.week.className = "vela-date-picker-week";
1857
- for (const d of WEEKDAY_LABELS) {
1901
+ for (const d of this.ctrl.weekdays()) {
1858
1902
  const cell = doc.createElement("span");
1859
1903
  cell.textContent = d;
1860
1904
  this.week.appendChild(cell);
@@ -2117,7 +2161,7 @@ var NUMBER_CSS = `
2117
2161
  .vela-num input::-webkit-inner-spin-button, .vela-num input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
2118
2162
  .vela-num input:hover { border-color: var(--vela-fg-muted); }
2119
2163
  .vela-num input:focus { border-color: var(--vela-focus); box-shadow: 0 0 0 3px var(--vela-focus-soft); }
2120
- /* The stepper gutter exists only while the steppers do (hover) \u2014 an idle field keeps
2164
+ /* The stepper gutter exists only while the steppers do (hover) — an idle field keeps
2121
2165
  its full width so long values aren't cut under an invisible arrow column. */
2122
2166
  .vela-num[data-steppers]:hover input { padding-right: 26px; }
2123
2167
  .vela-num[data-size='sm'] { width: 64px; flex: none; }
@@ -2164,10 +2208,15 @@ var NUMBER_CSS = `
2164
2208
  `;
2165
2209
 
2166
2210
  // src/ui/components/number-input/view.ts
2211
+ var TEXT2 = {
2212
+ increase: msg("ui.numberInput.increase", "Increase"),
2213
+ decrease: msg("ui.numberInput.decrease", "Decrease")
2214
+ };
2167
2215
  var NumberInput = class {
2168
2216
  constructor(opts) {
2169
2217
  const doc = document;
2170
2218
  injectStyles(NUMBER_STYLE_ID, NUMBER_CSS, doc);
2219
+ this.i18n = opts.i18n ?? kitTranslator();
2171
2220
  this.ctrl = numberInputController(opts);
2172
2221
  this.placeholderMode = opts.placeholder !== void 0;
2173
2222
  this.emptyValue = opts.emptyValue ?? opts.value;
@@ -2272,7 +2321,7 @@ var NumberInput = class {
2272
2321
  b.addEventListener("pointercancel", stop);
2273
2322
  return b;
2274
2323
  };
2275
- steps.append(mk(1, "chevron-up", "Increase"), mk(-1, "chevron-down", "Decrease"));
2324
+ steps.append(mk(1, "chevron-up", textOf(this.i18n, TEXT2.increase)), mk(-1, "chevron-down", textOf(this.i18n, TEXT2.decrease)));
2276
2325
  return steps;
2277
2326
  }
2278
2327
  };
@@ -2582,6 +2631,10 @@ var COLOR_CSS = `
2582
2631
  `;
2583
2632
 
2584
2633
  // src/ui/components/color-picker/view.ts
2634
+ var TEXT3 = {
2635
+ opacity: msg("ui.colorPicker.opacity", "Opacity"),
2636
+ opacityPercent: msg("ui.colorPicker.opacityPercent", "Opacity (%)")
2637
+ };
2585
2638
  var PALETTE = buildPalette();
2586
2639
  var CHECKER = transparencyChecker(10);
2587
2640
  var FIELD_CHECKER = transparencyChecker(8);
@@ -2594,6 +2647,7 @@ function addRecent(hex6) {
2594
2647
  }
2595
2648
  function buildColorPicker(color, theme, onChange, options = {}) {
2596
2649
  const commit = options.commit ?? "live";
2650
+ const i18n = options.i18n ?? kitTranslator();
2597
2651
  const parsed = splitColor(color);
2598
2652
  let curHex = parsed.hex6;
2599
2653
  let curAlpha = parsed.alpha;
@@ -2654,7 +2708,7 @@ function buildColorPicker(color, theme, onChange, options = {}) {
2654
2708
  }
2655
2709
  };
2656
2710
  const opLabel = document.createElement("div");
2657
- opLabel.textContent = "Opacity";
2711
+ opLabel.textContent = textOf(i18n, TEXT3.opacity);
2658
2712
  opLabel.style.cssText = `font:11px ${theme.fontFamily};color:var(--vela-fg-muted);`;
2659
2713
  const opRow = document.createElement("div");
2660
2714
  opRow.style.cssText = "display:flex;align-items:center;gap:10px;";
@@ -2666,7 +2720,7 @@ function buildColorPicker(color, theme, onChange, options = {}) {
2666
2720
  const pctBox = document.createElement("input");
2667
2721
  pctBox.type = "text";
2668
2722
  pctBox.inputMode = "numeric";
2669
- pctBox.title = "Opacity (%)";
2723
+ pctBox.title = textOf(i18n, TEXT3.opacityPercent);
2670
2724
  pctBox.style.cssText = `width:46px;box-sizing:border-box;text-align:center;font:var(--vela-font-size-md) ${theme.fontFamily};color:var(--vela-fg);background:transparent;border:1px solid var(--vela-border);border-radius:5px;padding:3px 4px;outline:none;`;
2671
2725
  pctBox.addEventListener("focus", () => {
2672
2726
  pctBox.style.borderColor = "var(--vela-border-strong)";
@@ -2761,6 +2815,7 @@ var ColorField = class {
2761
2815
  this.onVal = opts.onVal;
2762
2816
  this.popoverOpts = opts.popover;
2763
2817
  this.commit = opts.commit;
2818
+ this.i18n = opts.i18n ?? kitTranslator();
2764
2819
  const trigger = document.createElement("button");
2765
2820
  trigger.type = "button";
2766
2821
  if (opts.id) trigger.id = opts.id;
@@ -2807,7 +2862,7 @@ var ColorField = class {
2807
2862
  this.onVal(val);
2808
2863
  this.paint();
2809
2864
  },
2810
- { commit: this.commit }
2865
+ { commit: this.commit, i18n: this.i18n }
2811
2866
  )
2812
2867
  });
2813
2868
  pop.show();
@@ -3032,7 +3087,7 @@ var FIELD_CSS = `
3032
3087
  font-size: 14px;
3033
3088
  }
3034
3089
  .vela-field-label[data-size='sm'] { font-size: inherit; opacity: 0.85; }
3035
- /* Titles are fully inert: spans, not label[for] \u2014 native labels propagate :hover and
3090
+ /* Titles are fully inert: spans, not label[for] — native labels propagate :hover and
3036
3091
  clicks onto their control, and both belong to the input alone. */
3037
3092
  .vela-field-cell { display: flex; align-items: center; gap: 8px; justify-self: start; }
3038
3093
  .vela-field-bool { display: flex; align-items: center; gap: 8px; min-height: 22px; }
@@ -3338,4 +3393,4 @@ function buildFieldControl(desc) {
3338
3393
  return { el };
3339
3394
  }
3340
3395
 
3341
- export { CALLOUT_CSS, CALLOUT_STYLE_ID, CalloutBubble, ColorField, DatePicker, Dialog, FIELD_GAP_PX, GlyphSelect, Menu, NumberInput, Popover, STATIC_TOKENS, Select, Switch, TextArea, TextField, WIDTH_FIELD_OPTIONS, applyPlotOverlayTokens, applyThemeTokens, blendOver, buildColorPicker, buildFieldControl, buildPalette, calloutPanelRows, clampNumber, closeColorPopover, closeOpenPopovers, closeWidthPopover, closesPanel, colorField, colorPickerController, combineColor, datePickerController, decorateSelectScroll, dialogController, ensureUIHost, eventDismissedPopover, fieldGrid, fieldGridColumns, fieldRow, fieldSection, fieldSeparator, fillSelectList, glyphSelectController, hslHex, insetRect, intersectRects, isPopoverOpen, isoDate, lineWidthGlyph, menuController, nextUid, normalizeDateInput, numberInputController, openPopoverTrigger, openSelectList, placePopover, popoverController, runMachine, selectController, snapToStep, splitColor, switchController, textAreaController, textFieldController, themeTokens, toggleSelectList, transparencyChecker, viewportRect, widthField, widthFieldOptions };
3396
+ export { CALLOUT_CSS, CALLOUT_STYLE_ID, CalloutBubble, ColorField, DatePicker, Dialog, FIELD_GAP_PX, GlyphSelect, Menu, NumberInput, Popover, STATIC_TOKENS, Select, Switch, TextArea, TextField, WIDTH_FIELD_OPTIONS, applyPlotOverlayTokens, applyThemeTokens, blendOver, buildColorPicker, buildFieldControl, buildPalette, calloutPanelRows, clampNumber, closeColorPopover, closeOpenPopovers, closeWidthPopover, closesPanel, colorField, colorPickerController, combineColor, datePickerController, decorateSelectScroll, dialogController, ensureUIHost, eventDismissedPopover, fieldGrid, fieldGridColumns, fieldRow, fieldSection, fieldSeparator, fillSelectList, glyphSelectController, hslHex, insetRect, intersectRects, isPopoverOpen, isoDate, lineWidthGlyph, menuController, nextUid, normalizeDateInput, numberInputController, openPopoverTrigger, openSelectList, placePopover, popoverController, runMachine, selectController, snapToStep, splitColor, switchController, textAreaController, textFieldController, themeTokens, toggleSelectList, transparencyChecker, viewportRect, widthField, widthFieldOptions, withKitTranslator };
@@ -1,5 +1,5 @@
1
- import { normalizeProps, nextUid, runMachine, spreadProps } from './chunk-WY5H4S4I.js';
2
- import { injectStyles, holdForExit, announceSurface } from './chunk-I2U4NZD2.js';
1
+ import { normalizeProps, nextUid, runMachine, spreadProps } from './chunk-PZN4RS4T.js';
2
+ import { msg, textOf, injectStyles, holdForExit, announceSurface } from './chunk-O6L27KRB.js';
3
3
  import * as tooltip from '@zag-js/tooltip';
4
4
  import * as dialog from '@zag-js/dialog';
5
5
 
@@ -16,7 +16,15 @@ var KEY_ALIASES = {
16
16
  up: "arrowup",
17
17
  down: "arrowdown"
18
18
  };
19
- var MAC_GLYPHS = { meta: "\u2318", ctrl: "\u2303", alt: "\u2325", shift: "\u21E7" };
19
+ var MAC_GLYPHS = { meta: "⌘", ctrl: "⌃", alt: "⌥", shift: "⇧" };
20
+ var KEY_TEXT = {
21
+ ctrl: msg("ui.keys.ctrl", "Ctrl"),
22
+ alt: msg("ui.keys.alt", "Alt"),
23
+ shift: msg("ui.keys.shift", "Shift"),
24
+ meta: msg("ui.keys.meta", "Win"),
25
+ space: msg("ui.keys.space", "Space"),
26
+ general: msg("ui.keys.general", "General")
27
+ };
20
28
  function parseChord(spec, mac) {
21
29
  const parts = spec.toLowerCase().split("+").map((p) => p.trim()).filter((p, i, a) => p !== "" || a[i - 1] === "");
22
30
  const chord = { ctrl: false, meta: false, alt: false, shift: false, key: "" };
@@ -31,10 +39,16 @@ function parseChord(spec, mac) {
31
39
  }
32
40
  return chord;
33
41
  }
42
+ function chordKeyOf(ev) {
43
+ const key = String(ev.key ?? "").toLowerCase();
44
+ if (key.length !== 1 || /^[a-z0-9]$/.test(key) || !/\p{L}/u.test(key)) return key;
45
+ const m = /^Key([A-Z])$|^Digit([0-9])$/.exec(ev.code ?? "");
46
+ return m ? (m[1] ?? m[2]).toLowerCase() : key;
47
+ }
34
48
  function eventMatches(ev, c) {
35
49
  return ev.ctrlKey === c.ctrl && ev.metaKey === c.meta && ev.altKey === c.alt && // Shift is part of producing many printable keys ('?', '+') — only enforce it
36
50
  // when the chord names a non-printable/letter key where shift is a real modifier.
37
- (c.key.length > 1 || /^[a-z0-9 ]$/.test(c.key) ? ev.shiftKey === c.shift : true) && ev.key.toLowerCase() === c.key;
51
+ (c.key.length > 1 || /^[a-z0-9 ]$/.test(c.key) ? ev.shiftKey === c.shift : true) && chordKeyOf(ev) === c.key;
38
52
  }
39
53
  function isEditableTarget(ev) {
40
54
  const t = ev.target;
@@ -44,13 +58,14 @@ function isEditableTarget(ev) {
44
58
  if (t.isContentEditable === true) return true;
45
59
  return (typeof t.getAttribute === "function" ? t.getAttribute("role") : null) === "textbox";
46
60
  }
47
- function displayChord(spec, mac) {
61
+ function displayChord(spec, mac, i18n) {
48
62
  const c = parseChord(spec, mac);
49
- const keyLabel = c.key === " " ? "Space" : c.key.length === 1 ? c.key.toUpperCase() : c.key.charAt(0).toUpperCase() + c.key.slice(1);
63
+ const name = (m) => textOf(i18n, m);
64
+ const keyLabel = c.key === " " ? name(KEY_TEXT.space) : c.key.length === 1 ? c.key.toUpperCase() : c.key.charAt(0).toUpperCase() + c.key.slice(1);
50
65
  if (mac) {
51
66
  return (c.ctrl ? MAC_GLYPHS.ctrl : "") + (c.alt ? MAC_GLYPHS.alt : "") + (c.shift ? MAC_GLYPHS.shift : "") + (c.meta ? MAC_GLYPHS.meta : "") + keyLabel;
52
67
  }
53
- const mods = [c.ctrl && "Ctrl", c.alt && "Alt", c.shift && "Shift", c.meta && "Win"].filter(Boolean);
68
+ const mods = [c.ctrl && name(KEY_TEXT.ctrl), c.alt && name(KEY_TEXT.alt), c.shift && name(KEY_TEXT.shift), c.meta && name(KEY_TEXT.meta)].filter(Boolean);
54
69
  return [...mods, keyLabel].join("+");
55
70
  }
56
71
  var KeymapManager = class {
@@ -81,17 +96,18 @@ var KeymapManager = class {
81
96
  if (keys === null) this.rebinds.delete(id);
82
97
  else this.rebinds.set(id, Array.isArray(keys) ? [...keys] : [keys]);
83
98
  }
84
- /** Snapshot for a shortcuts help panel / rebinding UI. */
85
- bindings() {
99
+ /** Snapshot for a shortcuts help panel / rebinding UI: labels, categories and key
100
+ * names in `i18n`'s language (English when absent). */
101
+ bindings(i18n) {
86
102
  return [...this.descriptors.values()].map((d) => {
87
103
  const keys = this.activeKeys(d);
88
104
  return {
89
105
  id: d.id,
90
- label: d.label,
91
- category: d.category ?? "General",
106
+ label: textOf(i18n, d.label),
107
+ category: textOf(i18n, d.category ?? KEY_TEXT.general),
92
108
  scope: d.scope ?? this.baseScope,
93
109
  keys,
94
- display: keys.map((k) => displayChord(k, this.mac))
110
+ display: keys.map((k) => displayChord(k, this.mac, i18n))
95
111
  };
96
112
  });
97
113
  }
@@ -252,7 +268,7 @@ var DRAWER_CSS = `
252
268
  z-index: var(--vela-z-dialog);
253
269
  }
254
270
  /* Inside a shell that declares a size class, the sheet scopes to the SHELL's bounds
255
- (the widget root is position:relative) instead of the whole viewport \u2014 an embedded
271
+ (the widget root is position:relative) instead of the whole viewport — an embedded
256
272
  chart must not curtain the host page. */
257
273
  [data-layout] .vela-drawer-backdrop, [data-layout] .vela-drawer-positioner { position: absolute; }
258
274
  .vela-drawer {