@luxalgo/vela 0.8.4 → 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.
- package/dist/{DataProvider-Byo8pEv0.d.ts → DataProvider-BGlB1zSc.d.ts} +1 -1
- package/dist/{DataProvider-Bw58CjYy.d.cts → DataProvider-zJGp58kb.d.cts} +1 -1
- package/dist/{chunk-MOJ4T26N.js → chunk-4WAHYL7Y.js} +1151 -474
- package/dist/chunk-O6L27KRB.js +1331 -0
- package/dist/{chunk-WY5H4S4I.js → chunk-PZN4RS4T.js} +91 -36
- package/dist/{chunk-AUOB7A5Y.js → chunk-WHPQQYH7.js} +29 -13
- package/dist/{chunk-UNUVPQFW.js → chunk-XIRSR3D6.js} +2837 -1604
- package/dist/{chunk-ALTGHKIM.js → chunk-YRCL3WMD.js} +510 -406
- package/dist/{contributions-BY3zSYiZ.d.ts → contributions-BjefWpxQ.d.ts} +106 -25
- package/dist/{contributions-DOm40g5-.d.cts → contributions-CpCJisTC.d.cts} +106 -25
- package/dist/index.cjs +4485 -2163
- package/dist/index.d.cts +67 -25
- package/dist/index.d.ts +67 -25
- package/dist/index.js +5 -5
- package/dist/{keymap-CGOz5F5f.d.ts → keymap-B9_FLhfJ.d.cts} +9 -6
- package/dist/{keymap-CGOz5F5f.d.cts → keymap-UolhuXH1.d.ts} +9 -6
- package/dist/locales/ar.cjs +2260 -0
- package/dist/locales/ar.d.cts +5 -0
- package/dist/locales/ar.d.ts +5 -0
- package/dist/locales/ar.js +2258 -0
- package/dist/locales/de.cjs +2260 -0
- package/dist/locales/de.d.cts +5 -0
- package/dist/locales/de.d.ts +5 -0
- package/dist/locales/de.js +2258 -0
- package/dist/locales/en.cjs +2260 -0
- package/dist/locales/en.d.cts +5 -0
- package/dist/locales/en.d.ts +5 -0
- package/dist/locales/en.js +2258 -0
- package/dist/locales/es.cjs +2260 -0
- package/dist/locales/es.d.cts +5 -0
- package/dist/locales/es.d.ts +5 -0
- package/dist/locales/es.js +2258 -0
- package/dist/locales/fr.cjs +2260 -0
- package/dist/locales/fr.d.cts +5 -0
- package/dist/locales/fr.d.ts +5 -0
- package/dist/locales/fr.js +2258 -0
- package/dist/locales/he.cjs +2260 -0
- package/dist/locales/he.d.cts +5 -0
- package/dist/locales/he.d.ts +5 -0
- package/dist/locales/he.js +2258 -0
- package/dist/locales/hi.cjs +2260 -0
- package/dist/locales/hi.d.cts +5 -0
- package/dist/locales/hi.d.ts +5 -0
- package/dist/locales/hi.js +2258 -0
- package/dist/locales/id.cjs +2260 -0
- package/dist/locales/id.d.cts +5 -0
- package/dist/locales/id.d.ts +5 -0
- package/dist/locales/id.js +2258 -0
- package/dist/locales/it.cjs +2260 -0
- package/dist/locales/it.d.cts +5 -0
- package/dist/locales/it.d.ts +5 -0
- package/dist/locales/it.js +2258 -0
- package/dist/locales/ja.cjs +2260 -0
- package/dist/locales/ja.d.cts +5 -0
- package/dist/locales/ja.d.ts +5 -0
- package/dist/locales/ja.js +2258 -0
- package/dist/locales/ko.cjs +2260 -0
- package/dist/locales/ko.d.cts +5 -0
- package/dist/locales/ko.d.ts +5 -0
- package/dist/locales/ko.js +2258 -0
- package/dist/locales/ms.cjs +2260 -0
- package/dist/locales/ms.d.cts +5 -0
- package/dist/locales/ms.d.ts +5 -0
- package/dist/locales/ms.js +2258 -0
- package/dist/locales/pl.cjs +2260 -0
- package/dist/locales/pl.d.cts +5 -0
- package/dist/locales/pl.d.ts +5 -0
- package/dist/locales/pl.js +2258 -0
- package/dist/locales/pt-BR.cjs +2260 -0
- package/dist/locales/pt-BR.d.cts +5 -0
- package/dist/locales/pt-BR.d.ts +5 -0
- package/dist/locales/pt-BR.js +2258 -0
- package/dist/locales/ru.cjs +2260 -0
- package/dist/locales/ru.d.cts +5 -0
- package/dist/locales/ru.d.ts +5 -0
- package/dist/locales/ru.js +2258 -0
- package/dist/locales/th.cjs +2260 -0
- package/dist/locales/th.d.cts +5 -0
- package/dist/locales/th.d.ts +5 -0
- package/dist/locales/th.js +2258 -0
- package/dist/locales/tr.cjs +2260 -0
- package/dist/locales/tr.d.cts +5 -0
- package/dist/locales/tr.d.ts +5 -0
- package/dist/locales/tr.js +2258 -0
- package/dist/locales/vi.cjs +2260 -0
- package/dist/locales/vi.d.cts +5 -0
- package/dist/locales/vi.d.ts +5 -0
- package/dist/locales/vi.js +2258 -0
- package/dist/locales/zh-Hans.cjs +2260 -0
- package/dist/locales/zh-Hans.d.cts +5 -0
- package/dist/locales/zh-Hans.d.ts +5 -0
- package/dist/locales/zh-Hans.js +2258 -0
- package/dist/locales/zh-Hant.cjs +2260 -0
- package/dist/locales/zh-Hant.d.cts +5 -0
- package/dist/locales/zh-Hant.d.ts +5 -0
- package/dist/locales/zh-Hant.js +2258 -0
- package/dist/{options-CSXbjMM5.d.cts → options-CpegHml_.d.cts} +110 -10
- package/dist/{options-CSXbjMM5.d.ts → options-D4L3_hv_.d.ts} +110 -10
- package/dist/{plugin-BDxUhGO3.d.ts → plugin-DTmulpKM.d.ts} +92 -40
- package/dist/{plugin-CiQVyETg.d.cts → plugin-DpNp4aBi.d.cts} +92 -40
- package/dist/plugin.cjs +1267 -319
- package/dist/plugin.d.cts +7 -6
- package/dist/plugin.d.ts +7 -6
- package/dist/plugin.js +3 -3
- package/dist/providers/binance.cjs +1 -1
- package/dist/providers/binance.d.cts +3 -2
- package/dist/providers/binance.d.ts +3 -2
- package/dist/providers/binance.js +1 -1
- package/dist/providers/coinbase.cjs +1 -1
- package/dist/providers/coinbase.d.cts +3 -2
- package/dist/providers/coinbase.d.ts +3 -2
- package/dist/providers/coinbase.js +1 -1
- package/dist/providers/hyperliquid.cjs +1 -1
- package/dist/providers/hyperliquid.d.cts +3 -2
- package/dist/providers/hyperliquid.d.ts +3 -2
- package/dist/providers/hyperliquid.js +1 -1
- package/dist/{side-panel-_2UK1gSm.d.ts → side-panel-BqUnpfev.d.cts} +13 -2
- package/dist/{side-panel-_2UK1gSm.d.cts → side-panel-CYmH1Opm.d.ts} +13 -2
- package/dist/{statusline-model-C9tYXuux.d.ts → statusline-model-C3yIY9WE.d.ts} +11 -3
- package/dist/{statusline-model-DUBX6Fib.d.cts → statusline-model-pGs3Xvp-.d.cts} +11 -3
- package/dist/types-BlrXRLIR.d.cts +2515 -0
- package/dist/types-BlrXRLIR.d.ts +2515 -0
- package/dist/ui.cjs +1008 -56
- package/dist/ui.d.cts +21 -2
- package/dist/ui.d.ts +21 -2
- package/dist/ui.js +3 -3
- package/dist/vela.global.js +4451 -2131
- package/dist/vela.global.min.js +57 -57
- package/dist/widget.cjs +5819 -2780
- package/dist/widget.d.cts +100 -26
- package/dist/widget.d.ts +100 -26
- package/dist/widget.js +19 -11
- package/dist/workspace.cjs +5808 -2787
- package/dist/workspace.d.cts +63 -15
- package/dist/workspace.d.ts +63 -15
- package/dist/workspace.js +6 -6
- package/package.json +9 -2
- package/dist/chunk-I2U4NZD2.js +0 -340
- /package/dist/{chunk-W5YPYZ2P.js → chunk-3EYCX2L4.js} +0 -0
package/dist/ui.cjs
CHANGED
|
@@ -186,7 +186,7 @@ var STATIC_CSS = `
|
|
|
186
186
|
${STATIC_DECLS}
|
|
187
187
|
font-family: var(--vela-font, -apple-system, system-ui, sans-serif);
|
|
188
188
|
box-sizing: border-box;
|
|
189
|
-
/* Chrome text (titles, buttons, menus, readouts) is UI, not copy
|
|
189
|
+
/* Chrome text (titles, buttons, menus, readouts) is UI, not copy — never selectable. */
|
|
190
190
|
user-select: none;
|
|
191
191
|
-webkit-user-select: none;
|
|
192
192
|
}
|
|
@@ -195,7 +195,7 @@ ${STATIC_DECLS}
|
|
|
195
195
|
.vela-ui :is(input, textarea), .vela-ui-layer :is(input, textarea) { user-select: text; -webkit-user-select: text; }
|
|
196
196
|
/* iOS Safari zooms the page when a focused field is under 16px, and often
|
|
197
197
|
keeps that zoom after the field blurs or a dialog closes. The shell's
|
|
198
|
-
mobile size class is the honest gate
|
|
198
|
+
mobile size class is the honest gate — not a media query — so an embedded
|
|
199
199
|
chart on a wide desktop still gets the rule when it is in the phone layout.
|
|
200
200
|
Scoped to the kit root so a host page's own [data-layout] is never touched. */
|
|
201
201
|
.vela-ui[data-layout='mobile'] :is(input, textarea, select) { font-size: 16px; }
|
|
@@ -383,7 +383,7 @@ registerIcon(
|
|
|
383
383
|
"send-back",
|
|
384
384
|
svg24('<rect x="8.5" y="8.5" width="7" height="7" rx="1.5" fill="currentColor" stroke="none" opacity="0.35"/><path d="M4.5 10.5V6a1.5 1.5 0 0 1 1.5-1.5h4.5"/><path d="M19.5 13.5V18a1.5 1.5 0 0 1-1.5 1.5h-4.5"/><rect x="8.5" y="8.5" width="7" height="7" rx="1.5"/>')
|
|
385
385
|
);
|
|
386
|
-
registerIcon("r-squared", '<svg viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor" stroke="none"><text x="2.5" y="17.5" font-size="14" font-family="serif">R
|
|
386
|
+
registerIcon("r-squared", '<svg viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor" stroke="none"><text x="2.5" y="17.5" font-size="14" font-family="serif">R²</text></svg>');
|
|
387
387
|
registerIcon("bands", svg24('<path d="M3 6h18"/><path d="M3 18h18"/><path d="M3 12h18" stroke-dasharray="3 3"/>'));
|
|
388
388
|
registerIcon("dedekind", svg24('<path d="M2 20h20"/><path d="M4 20a8 8 0 0 1 16 0"/><path d="M8 20a4 4 0 0 1 8 0"/><path d="M12 4v16"/>'));
|
|
389
389
|
registerIcon("sonic", svg24('<circle cx="15" cy="12" r="4"/><circle cx="12" cy="12" r="2.5"/><path d="M8 5v14"/>'));
|
|
@@ -398,14 +398,14 @@ function iconEl(id, doc = document) {
|
|
|
398
398
|
if (svg) span.innerHTML = svg;
|
|
399
399
|
return span;
|
|
400
400
|
}
|
|
401
|
-
function runMachine(machine5, props,
|
|
401
|
+
function runMachine(machine5, props, render2) {
|
|
402
402
|
const m = new vanilla.VanillaMachine(machine5, props);
|
|
403
|
-
const unsub = m.subscribe(
|
|
403
|
+
const unsub = m.subscribe(render2);
|
|
404
404
|
m.start();
|
|
405
|
-
|
|
405
|
+
render2(m.service);
|
|
406
406
|
return {
|
|
407
407
|
service: m.service,
|
|
408
|
-
flush: () =>
|
|
408
|
+
flush: () => render2(m.service),
|
|
409
409
|
stop: () => {
|
|
410
410
|
unsub();
|
|
411
411
|
m.stop();
|
|
@@ -428,6 +428,896 @@ function announceSurface(el, open2, kind, trigger = null) {
|
|
|
428
428
|
);
|
|
429
429
|
}
|
|
430
430
|
|
|
431
|
+
// src/core/i18n/message.ts
|
|
432
|
+
function msg(id, defaultMessage) {
|
|
433
|
+
return Object.freeze({ id, defaultMessage });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/core/format/numbers.ts
|
|
437
|
+
var BIDI_MARKS = /[]/g;
|
|
438
|
+
function stripBidiMarks(text) {
|
|
439
|
+
return text.replace(BIDI_MARKS, "");
|
|
440
|
+
}
|
|
441
|
+
var numberFormats = /* @__PURE__ */ new Map();
|
|
442
|
+
function numberFormat(settings, options) {
|
|
443
|
+
const key = `${settings.locale}|${settings.numberingSystem}|${JSON.stringify(options)}`;
|
|
444
|
+
let nf = numberFormats.get(key);
|
|
445
|
+
if (!nf) {
|
|
446
|
+
try {
|
|
447
|
+
nf = new Intl.NumberFormat(settings.locale, { ...options, numberingSystem: settings.numberingSystem });
|
|
448
|
+
} catch {
|
|
449
|
+
nf = new Intl.NumberFormat("en", options);
|
|
450
|
+
}
|
|
451
|
+
numberFormats.set(key, nf);
|
|
452
|
+
}
|
|
453
|
+
return nf;
|
|
454
|
+
}
|
|
455
|
+
var symbolCache = /* @__PURE__ */ new Map();
|
|
456
|
+
function numberSymbols(settings) {
|
|
457
|
+
const key = `${settings.locale}|${settings.numberingSystem}`;
|
|
458
|
+
let sym = symbolCache.get(key);
|
|
459
|
+
if (sym) return sym;
|
|
460
|
+
const parts = numberFormat(settings, { useGrouping: false, minimumFractionDigits: 1, maximumFractionDigits: 1 }).formatToParts(-1.5);
|
|
461
|
+
const decimal = stripBidiMarks(parts.find((p) => p.type === "decimal")?.value ?? ".") || ".";
|
|
462
|
+
const minus = stripBidiMarks(parts.find((p) => p.type === "minusSign")?.value ?? "-") || "-";
|
|
463
|
+
const plain = numberFormat(settings, { useGrouping: false, maximumFractionDigits: 0 });
|
|
464
|
+
const digits = Array.from({ length: 10 }, (_, d) => stripBidiMarks(plain.format(d)));
|
|
465
|
+
const ascii = decimal === "." && minus === "-" && digits.every((d, i) => d === String(i));
|
|
466
|
+
sym = { ascii, decimal, minus, digits };
|
|
467
|
+
symbolCache.set(key, sym);
|
|
468
|
+
return sym;
|
|
469
|
+
}
|
|
470
|
+
function localizeAscii(text, settings) {
|
|
471
|
+
const sym = numberSymbols(settings);
|
|
472
|
+
if (sym.ascii) return text;
|
|
473
|
+
let out = "";
|
|
474
|
+
for (const ch of text) {
|
|
475
|
+
const code = ch.charCodeAt(0);
|
|
476
|
+
if (code >= 48 && code <= 57) out += sym.digits[code - 48];
|
|
477
|
+
else if (ch === ".") out += sym.decimal;
|
|
478
|
+
else if (ch === "-") out += sym.minus;
|
|
479
|
+
else out += ch;
|
|
480
|
+
}
|
|
481
|
+
return out;
|
|
482
|
+
}
|
|
483
|
+
function localizeDigits(text, settings) {
|
|
484
|
+
const sym = numberSymbols(settings);
|
|
485
|
+
if (sym.digits.every((d, i) => d === String(i))) return text;
|
|
486
|
+
return text.replace(/[0-9]/g, (d) => sym.digits[Number(d)]);
|
|
487
|
+
}
|
|
488
|
+
var clampDecimals = (d) => Number.isFinite(d) ? Math.max(0, Math.min(20, Math.trunc(d))) : 2;
|
|
489
|
+
function formatFixed(value, decimals, settings) {
|
|
490
|
+
return localizeAscii(value.toFixed(clampDecimals(decimals)), settings);
|
|
491
|
+
}
|
|
492
|
+
function formatGrouped(value, decimals, settings) {
|
|
493
|
+
const d = clampDecimals(decimals);
|
|
494
|
+
return stripBidiMarks(numberFormat(settings, { minimumFractionDigits: d, maximumFractionDigits: d }).format(value));
|
|
495
|
+
}
|
|
496
|
+
function formatMessageNumber(value, settings, style) {
|
|
497
|
+
if (style === "integer") return stripBidiMarks(numberFormat(settings, { maximumFractionDigits: 0 }).format(value));
|
|
498
|
+
if (style === "percent") return stripBidiMarks(numberFormat(settings, { style: "percent" }).format(value));
|
|
499
|
+
return stripBidiMarks(numberFormat(settings, {}).format(value));
|
|
500
|
+
}
|
|
501
|
+
function formatPercent(value, options, settings) {
|
|
502
|
+
const d = clampDecimals(options?.decimals ?? 2);
|
|
503
|
+
const signed = options?.signed ?? true;
|
|
504
|
+
if (settings.english) {
|
|
505
|
+
const text = signed ? `${value >= 0 ? "+" : "-"}${Math.abs(value).toFixed(d)}%` : `${value.toFixed(d)}%`;
|
|
506
|
+
return localizeAscii(text, settings);
|
|
507
|
+
}
|
|
508
|
+
const nf = numberFormat(settings, { style: "percent", minimumFractionDigits: d, maximumFractionDigits: d, signDisplay: signed ? "always" : "auto" });
|
|
509
|
+
return stripBidiMarks(nf.format(value / 100));
|
|
510
|
+
}
|
|
511
|
+
function formatPrice(value, options, settings) {
|
|
512
|
+
const mode = options.mode ?? "price";
|
|
513
|
+
if (mode === "percent") return formatPercent(value, { decimals: options.decimals, signed: true }, settings);
|
|
514
|
+
if (mode === "indexed" || !options.grouping) return formatFixed(value, options.decimals, settings);
|
|
515
|
+
return formatGrouped(value, options.decimals, settings);
|
|
516
|
+
}
|
|
517
|
+
var COMPACT_STEPS = [
|
|
518
|
+
[1e9, "B"],
|
|
519
|
+
[1e6, "M"],
|
|
520
|
+
[1e3, "K"]
|
|
521
|
+
];
|
|
522
|
+
function formatCompact(value, options, settings) {
|
|
523
|
+
const d = clampDecimals(options?.decimals ?? 2);
|
|
524
|
+
const trim = options?.trimZeros ?? true;
|
|
525
|
+
if (settings.english) {
|
|
526
|
+
const a = Math.abs(value);
|
|
527
|
+
let div = 1;
|
|
528
|
+
let suffix = "";
|
|
529
|
+
for (const [step, s] of COMPACT_STEPS) {
|
|
530
|
+
if (a >= step) {
|
|
531
|
+
div = step;
|
|
532
|
+
suffix = s;
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
const scaled = value / div;
|
|
537
|
+
const text = trim ? Number(scaled.toFixed(d)).toString() : scaled.toFixed(d);
|
|
538
|
+
return localizeAscii(text, settings) + suffix;
|
|
539
|
+
}
|
|
540
|
+
const nf = numberFormat(settings, { notation: "compact", compactDisplay: "short", maximumFractionDigits: d, minimumFractionDigits: trim ? 0 : d });
|
|
541
|
+
return stripBidiMarks(nf.format(value));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/core/format/dates.ts
|
|
545
|
+
var EN_MONTHS_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
546
|
+
var EN_WEEKDAYS_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
547
|
+
var pad2 = (n) => n < 10 ? `0${n}` : String(n);
|
|
548
|
+
var DAY_MS = 864e5;
|
|
549
|
+
var zoneParsers = /* @__PURE__ */ new Map();
|
|
550
|
+
function zoneOffsetMs(ms, timeZone) {
|
|
551
|
+
if (!timeZone || timeZone === "UTC") return 0;
|
|
552
|
+
let dtf = zoneParsers.get(timeZone);
|
|
553
|
+
if (dtf === void 0) {
|
|
554
|
+
try {
|
|
555
|
+
dtf = new Intl.DateTimeFormat("en-US", {
|
|
556
|
+
timeZone,
|
|
557
|
+
hourCycle: "h23",
|
|
558
|
+
year: "numeric",
|
|
559
|
+
month: "2-digit",
|
|
560
|
+
day: "2-digit",
|
|
561
|
+
hour: "2-digit",
|
|
562
|
+
minute: "2-digit",
|
|
563
|
+
second: "2-digit"
|
|
564
|
+
});
|
|
565
|
+
} catch {
|
|
566
|
+
dtf = null;
|
|
567
|
+
}
|
|
568
|
+
zoneParsers.set(timeZone, dtf);
|
|
569
|
+
}
|
|
570
|
+
if (!dtf) return 0;
|
|
571
|
+
try {
|
|
572
|
+
const parts = dtf.formatToParts(new Date(ms));
|
|
573
|
+
const get = (t) => Number(parts.find((p) => p.type === t)?.value);
|
|
574
|
+
const asUTC = Date.UTC(get("year"), get("month") - 1, get("day"), get("hour") % 24, get("minute"), get("second"));
|
|
575
|
+
return asUTC - ms;
|
|
576
|
+
} catch {
|
|
577
|
+
return 0;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
var dateFormats = /* @__PURE__ */ new Map();
|
|
581
|
+
function dateFormat(settings, options) {
|
|
582
|
+
const key = `${settings.locale}|${settings.numberingSystem}|${JSON.stringify(options)}`;
|
|
583
|
+
let dtf = dateFormats.get(key);
|
|
584
|
+
if (!dtf) {
|
|
585
|
+
const full = { ...options, timeZone: "UTC", calendar: "gregory", numberingSystem: settings.numberingSystem };
|
|
586
|
+
try {
|
|
587
|
+
dtf = new Intl.DateTimeFormat(settings.locale, full);
|
|
588
|
+
} catch {
|
|
589
|
+
dtf = new Intl.DateTimeFormat("en", { ...options, timeZone: "UTC", calendar: "gregory" });
|
|
590
|
+
}
|
|
591
|
+
dateFormats.set(key, dtf);
|
|
592
|
+
}
|
|
593
|
+
return dtf;
|
|
594
|
+
}
|
|
595
|
+
function clockOptions(settings) {
|
|
596
|
+
if (settings.hourCycle === "h23") return { hour: "2-digit", minute: "2-digit", hourCycle: "h23" };
|
|
597
|
+
if (settings.hourCycle === "h12") return { hour: "numeric", minute: "2-digit", hourCycle: "h12" };
|
|
598
|
+
return { hour: "numeric", minute: "2-digit" };
|
|
599
|
+
}
|
|
600
|
+
function englishClock(wall, settings) {
|
|
601
|
+
if (settings.hourCycle === "h23") return localizeAscii(`${pad2(wall.getUTCHours())}:${pad2(wall.getUTCMinutes())}`, settings);
|
|
602
|
+
return stripBidiMarks(dateFormat(settings, clockOptions(settings)).format(wall));
|
|
603
|
+
}
|
|
604
|
+
var TICK_OPTIONS = {
|
|
605
|
+
year: { year: "numeric" },
|
|
606
|
+
month: { month: "short" },
|
|
607
|
+
day: { month: "short", day: "numeric" }
|
|
608
|
+
};
|
|
609
|
+
var isClockUnit = (unit) => unit === "hour" || unit === "minute" || unit === "second";
|
|
610
|
+
function formatTimeTick(ms, options, settings) {
|
|
611
|
+
const wall = new Date(ms + (options.offsetMs ?? 0));
|
|
612
|
+
const unit = options.unit;
|
|
613
|
+
if (settings.english) {
|
|
614
|
+
if (isClockUnit(unit)) return englishClock(wall, settings);
|
|
615
|
+
const month = EN_MONTHS_SHORT[wall.getUTCMonth()];
|
|
616
|
+
if (unit === "year") return localizeAscii(String(wall.getUTCFullYear()), settings);
|
|
617
|
+
if (unit === "month") return month;
|
|
618
|
+
return localizeAscii(`${month} ${wall.getUTCDate()}`, settings);
|
|
619
|
+
}
|
|
620
|
+
const opts = isClockUnit(unit) ? clockOptions(settings) : TICK_OPTIONS[unit];
|
|
621
|
+
return stripBidiMarks(dateFormat(settings, opts).format(wall));
|
|
622
|
+
}
|
|
623
|
+
function formatTimeStamp(ms, options, settings) {
|
|
624
|
+
const wall = new Date(ms + zoneOffsetMs(ms, options?.timeZone ?? "UTC"));
|
|
625
|
+
const withTime = options?.withTime ?? true;
|
|
626
|
+
if (settings.english) {
|
|
627
|
+
const date = localizeAscii(
|
|
628
|
+
`${EN_WEEKDAYS_SHORT[wall.getUTCDay()]} ${wall.getUTCDate()} ${EN_MONTHS_SHORT[wall.getUTCMonth()]} '${pad2(wall.getUTCFullYear() % 100)}`,
|
|
629
|
+
settings
|
|
630
|
+
);
|
|
631
|
+
return withTime ? `${date} ${englishClock(wall, settings)}` : date;
|
|
632
|
+
}
|
|
633
|
+
const opts = { weekday: "short", day: "numeric", month: "short", year: "2-digit", ...withTime ? clockOptions(settings) : {} };
|
|
634
|
+
return stripBidiMarks(dateFormat(settings, opts).format(wall));
|
|
635
|
+
}
|
|
636
|
+
function countdownText(ms) {
|
|
637
|
+
const total = Math.max(0, Math.ceil(ms / 1e3));
|
|
638
|
+
const s = total % 60;
|
|
639
|
+
const m = Math.floor(total / 60) % 60;
|
|
640
|
+
const h = Math.floor(total / 3600);
|
|
641
|
+
const pad = (v) => String(v).padStart(2, "0");
|
|
642
|
+
return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${pad(m)}:${pad(s)}`;
|
|
643
|
+
}
|
|
644
|
+
function spanParts(ms) {
|
|
645
|
+
const m = Math.abs(ms);
|
|
646
|
+
const HR = 36e5;
|
|
647
|
+
const MIN = 6e4;
|
|
648
|
+
if (m >= DAY_MS) {
|
|
649
|
+
const d = Math.floor(m / DAY_MS);
|
|
650
|
+
const h = Math.round(m % DAY_MS / HR);
|
|
651
|
+
return h ? [[d, "day"], [h, "hour"]] : [[d, "day"]];
|
|
652
|
+
}
|
|
653
|
+
if (m >= HR) {
|
|
654
|
+
const h = Math.floor(m / HR);
|
|
655
|
+
const mn = Math.round(m % HR / MIN);
|
|
656
|
+
return mn ? [[h, "hour"], [mn, "minute"]] : [[h, "hour"]];
|
|
657
|
+
}
|
|
658
|
+
if (m >= MIN) return [[Math.round(m / MIN), "minute"]];
|
|
659
|
+
return [[Math.round(m / 1e3), "second"]];
|
|
660
|
+
}
|
|
661
|
+
var EN_UNIT = { day: "d", hour: "h", minute: "m", second: "s" };
|
|
662
|
+
function formatDuration(ms, options, settings) {
|
|
663
|
+
if ((options?.style ?? "countdown") === "countdown") return localizeDigits(countdownText(ms), settings);
|
|
664
|
+
const parts = spanParts(ms);
|
|
665
|
+
if (settings.english) return localizeDigits(parts.map(([n, u]) => `${n}${EN_UNIT[u]}`).join(" "), settings);
|
|
666
|
+
return parts.map(([n, unit]) => stripBidiMarks(numberFormat(settings, { style: "unit", unit, unitDisplay: "narrow" }).format(n))).join(" ");
|
|
667
|
+
}
|
|
668
|
+
var clockFormats = /* @__PURE__ */ new Map();
|
|
669
|
+
function formatClock(ms, options, settings) {
|
|
670
|
+
const timeZone = options?.timeZone ?? "UTC";
|
|
671
|
+
const seconds = options?.seconds ?? true;
|
|
672
|
+
const english2 = settings.english && settings.hourCycle === "h23";
|
|
673
|
+
const key = `${english2 ? "en-GB" : settings.locale}|${settings.numberingSystem}|${settings.hourCycle}|${timeZone}|${seconds}`;
|
|
674
|
+
let dtf = clockFormats.get(key);
|
|
675
|
+
if (dtf === void 0) {
|
|
676
|
+
const base = { hour: "2-digit", minute: "2-digit", ...seconds ? { second: "2-digit" } : {}, timeZone };
|
|
677
|
+
try {
|
|
678
|
+
dtf = english2 ? new Intl.DateTimeFormat("en-GB", { ...base, hour12: false }) : new Intl.DateTimeFormat(settings.locale, {
|
|
679
|
+
...base,
|
|
680
|
+
calendar: "gregory",
|
|
681
|
+
numberingSystem: settings.numberingSystem,
|
|
682
|
+
...settings.hourCycle === "locale" ? {} : { hourCycle: settings.hourCycle }
|
|
683
|
+
});
|
|
684
|
+
} catch {
|
|
685
|
+
dtf = null;
|
|
686
|
+
}
|
|
687
|
+
clockFormats.set(key, dtf);
|
|
688
|
+
}
|
|
689
|
+
if (!dtf) return "";
|
|
690
|
+
try {
|
|
691
|
+
return stripBidiMarks(dtf.format(new Date(ms)));
|
|
692
|
+
} catch {
|
|
693
|
+
return "";
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// src/core/format/formatters.ts
|
|
698
|
+
function builtinFormatters(settings) {
|
|
699
|
+
return {
|
|
700
|
+
price: (value, options) => formatPrice(value, options, settings),
|
|
701
|
+
percent: (value, options) => formatPercent(value, options, settings),
|
|
702
|
+
compact: (value, options) => formatCompact(value, options, settings),
|
|
703
|
+
timeTick: (ms, options) => formatTimeTick(ms, options, settings),
|
|
704
|
+
timeStamp: (ms, options) => formatTimeStamp(ms, options, settings),
|
|
705
|
+
duration: (ms, options) => formatDuration(ms, options, settings),
|
|
706
|
+
clock: (ms, options) => formatClock(ms, options, settings)
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
var warned = false;
|
|
710
|
+
function viaHost(host, value, ctx, fallback) {
|
|
711
|
+
try {
|
|
712
|
+
const out = host(value, ctx);
|
|
713
|
+
if (typeof out === "string") return out;
|
|
714
|
+
} catch (err) {
|
|
715
|
+
if (!warned) {
|
|
716
|
+
warned = true;
|
|
717
|
+
console.warn("[vela] a host formatter threw; the built-in formatting is used instead.", err);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return fallback();
|
|
721
|
+
}
|
|
722
|
+
function resolveFormatters(settings, overrides) {
|
|
723
|
+
const base = builtinFormatters(settings);
|
|
724
|
+
if (!overrides) return base;
|
|
725
|
+
const ctx = (surface, defaultSurface, timeZone, fallback) => ({
|
|
726
|
+
locale: settings.locale,
|
|
727
|
+
timeZone: timeZone ?? "UTC",
|
|
728
|
+
surface: surface ?? defaultSurface,
|
|
729
|
+
fallback
|
|
730
|
+
});
|
|
731
|
+
const o = overrides;
|
|
732
|
+
return {
|
|
733
|
+
price(value, options) {
|
|
734
|
+
const fallback = () => base.price(value, options);
|
|
735
|
+
if (typeof o.price !== "function") return fallback();
|
|
736
|
+
return viaHost(o.price, value, { ...ctx(options.surface, "priceAxis", void 0, fallback), decimals: options.decimals, mintick: options.mintick, mode: options.mode ?? "price", paneId: options.paneId, grouping: options.grouping ?? false }, fallback);
|
|
737
|
+
},
|
|
738
|
+
percent(value, options) {
|
|
739
|
+
const fallback = () => base.percent(value, options);
|
|
740
|
+
if (typeof o.percent !== "function") return fallback();
|
|
741
|
+
return viaHost(o.percent, value, { ...ctx(options?.surface, "statusLine", void 0, fallback), decimals: options?.decimals ?? 2, signed: options?.signed ?? true }, fallback);
|
|
742
|
+
},
|
|
743
|
+
compact(value, options) {
|
|
744
|
+
const fallback = () => base.compact(value, options);
|
|
745
|
+
if (typeof o.compact !== "function") return fallback();
|
|
746
|
+
return viaHost(o.compact, value, { ...ctx(options?.surface, "priceAxis", void 0, fallback), decimals: options?.decimals ?? 2, trimZeros: options?.trimZeros ?? true }, fallback);
|
|
747
|
+
},
|
|
748
|
+
timeTick(ms, options) {
|
|
749
|
+
const fallback = () => base.timeTick(ms, options);
|
|
750
|
+
if (typeof o.timeTick !== "function") return fallback();
|
|
751
|
+
return viaHost(o.timeTick, ms, { ...ctx(options.surface, "timeAxis", options.timeZone, fallback), unit: options.unit, major: options.major, offsetMs: options.offsetMs ?? 0 }, fallback);
|
|
752
|
+
},
|
|
753
|
+
timeStamp(ms, options) {
|
|
754
|
+
const fallback = () => base.timeStamp(ms, options);
|
|
755
|
+
if (typeof o.timeStamp !== "function") return fallback();
|
|
756
|
+
return viaHost(o.timeStamp, ms, { ...ctx(options?.surface, "crosshair", options?.timeZone, fallback), withTime: options?.withTime ?? true }, fallback);
|
|
757
|
+
},
|
|
758
|
+
duration(ms, options) {
|
|
759
|
+
const fallback = () => base.duration(ms, options);
|
|
760
|
+
if (typeof o.duration !== "function") return fallback();
|
|
761
|
+
return viaHost(o.duration, ms, { ...ctx(options?.surface, "lastPrice", void 0, fallback), style: options?.style ?? "countdown" }, fallback);
|
|
762
|
+
},
|
|
763
|
+
clock(ms, options) {
|
|
764
|
+
const fallback = () => base.clock(ms, options);
|
|
765
|
+
if (typeof o.clock !== "function") return fallback();
|
|
766
|
+
return viaHost(o.clock, ms, { ...ctx(options?.surface, "clock", options?.timeZone, fallback), seconds: options?.seconds ?? true }, fallback);
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// src/core/i18n/icu.ts
|
|
772
|
+
var Parser = class {
|
|
773
|
+
constructor(src) {
|
|
774
|
+
this.src = src;
|
|
775
|
+
this.i = 0;
|
|
776
|
+
}
|
|
777
|
+
parse() {
|
|
778
|
+
const nodes = this.message(false, 0);
|
|
779
|
+
if (this.i < this.src.length) throw this.error("unmatched }");
|
|
780
|
+
return nodes;
|
|
781
|
+
}
|
|
782
|
+
error(what) {
|
|
783
|
+
return new SyntaxError(`[vela] message syntax: ${what} at ${this.i} in "${this.src}"`);
|
|
784
|
+
}
|
|
785
|
+
/** Text and arguments up to an unmatched `}` (left unread) or the end. */
|
|
786
|
+
message(inPlural, depth) {
|
|
787
|
+
if (depth > 8) throw this.error("nesting too deep");
|
|
788
|
+
const src = this.src;
|
|
789
|
+
const out = [];
|
|
790
|
+
let text = "";
|
|
791
|
+
const flush = () => {
|
|
792
|
+
if (text) out.push(text);
|
|
793
|
+
text = "";
|
|
794
|
+
};
|
|
795
|
+
while (this.i < src.length) {
|
|
796
|
+
const ch = src[this.i];
|
|
797
|
+
if (ch === "'") {
|
|
798
|
+
const next = src[this.i + 1];
|
|
799
|
+
if (next === "'") {
|
|
800
|
+
text += "'";
|
|
801
|
+
this.i += 2;
|
|
802
|
+
} else if (next === "{" || next === "}" || inPlural && next === "#") {
|
|
803
|
+
this.i += 1;
|
|
804
|
+
while (this.i < src.length) {
|
|
805
|
+
const c = src[this.i];
|
|
806
|
+
if (c === "'") {
|
|
807
|
+
if (src[this.i + 1] === "'") {
|
|
808
|
+
text += "'";
|
|
809
|
+
this.i += 2;
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
this.i += 1;
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
text += c;
|
|
816
|
+
this.i += 1;
|
|
817
|
+
}
|
|
818
|
+
} else {
|
|
819
|
+
text += "'";
|
|
820
|
+
this.i += 1;
|
|
821
|
+
}
|
|
822
|
+
} else if (ch === "{") {
|
|
823
|
+
flush();
|
|
824
|
+
this.i += 1;
|
|
825
|
+
out.push(this.argument(depth));
|
|
826
|
+
} else if (ch === "}") {
|
|
827
|
+
break;
|
|
828
|
+
} else if (ch === "#" && inPlural) {
|
|
829
|
+
flush();
|
|
830
|
+
out.push({ kind: "pound" });
|
|
831
|
+
this.i += 1;
|
|
832
|
+
} else {
|
|
833
|
+
text += ch;
|
|
834
|
+
this.i += 1;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
flush();
|
|
838
|
+
return out;
|
|
839
|
+
}
|
|
840
|
+
skipSpace() {
|
|
841
|
+
while (this.i < this.src.length && /\s/.test(this.src[this.i])) this.i += 1;
|
|
842
|
+
}
|
|
843
|
+
word() {
|
|
844
|
+
this.skipSpace();
|
|
845
|
+
const start = this.i;
|
|
846
|
+
while (this.i < this.src.length && !/[\s,{}]/.test(this.src[this.i])) this.i += 1;
|
|
847
|
+
return this.src.slice(start, this.i);
|
|
848
|
+
}
|
|
849
|
+
expect(ch) {
|
|
850
|
+
this.skipSpace();
|
|
851
|
+
if (this.src[this.i] !== ch) throw this.error(`expected "${ch}"`);
|
|
852
|
+
this.i += 1;
|
|
853
|
+
}
|
|
854
|
+
/** After a `{`: the argument through its closing `}`. */
|
|
855
|
+
argument(depth) {
|
|
856
|
+
const name = this.word();
|
|
857
|
+
if (!name) throw this.error("empty argument name");
|
|
858
|
+
this.skipSpace();
|
|
859
|
+
if (this.src[this.i] === "}") {
|
|
860
|
+
this.i += 1;
|
|
861
|
+
return { kind: "arg", name };
|
|
862
|
+
}
|
|
863
|
+
this.expect(",");
|
|
864
|
+
const type = this.word();
|
|
865
|
+
this.skipSpace();
|
|
866
|
+
if (type === "number") {
|
|
867
|
+
let style;
|
|
868
|
+
if (this.src[this.i] === ",") {
|
|
869
|
+
this.i += 1;
|
|
870
|
+
style = this.word() || void 0;
|
|
871
|
+
}
|
|
872
|
+
this.expect("}");
|
|
873
|
+
return { kind: "arg", name, format: "number", style };
|
|
874
|
+
}
|
|
875
|
+
if (type === "plural" || type === "selectordinal" || type === "select") {
|
|
876
|
+
this.expect(",");
|
|
877
|
+
let offset = 0;
|
|
878
|
+
this.skipSpace();
|
|
879
|
+
if (type !== "select" && this.src.startsWith("offset:", this.i)) {
|
|
880
|
+
this.i += "offset:".length;
|
|
881
|
+
offset = Number(this.word());
|
|
882
|
+
if (!Number.isFinite(offset)) throw this.error("bad offset");
|
|
883
|
+
}
|
|
884
|
+
const options = {};
|
|
885
|
+
for (; ; ) {
|
|
886
|
+
this.skipSpace();
|
|
887
|
+
if (this.src[this.i] === "}") {
|
|
888
|
+
this.i += 1;
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
const key = this.word();
|
|
892
|
+
if (!key) throw this.error("expected a selector");
|
|
893
|
+
this.expect("{");
|
|
894
|
+
options[key] = this.message(type !== "select", depth + 1);
|
|
895
|
+
this.expect("}");
|
|
896
|
+
}
|
|
897
|
+
if (!options.other) throw this.error(`"${name}" has no "other" option`);
|
|
898
|
+
return type === "select" ? { kind: "select", name, options } : { kind: "plural", name, ordinal: type === "selectordinal", offset, options };
|
|
899
|
+
}
|
|
900
|
+
throw this.error(`unknown argument type "${type}"`);
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
var parsed = /* @__PURE__ */ new Map();
|
|
904
|
+
var PARSE_CACHE_CAP = 2e3;
|
|
905
|
+
function parseMessage(source) {
|
|
906
|
+
let nodes = parsed.get(source);
|
|
907
|
+
if (!nodes) {
|
|
908
|
+
nodes = new Parser(source).parse();
|
|
909
|
+
if (parsed.size >= PARSE_CACHE_CAP) parsed.clear();
|
|
910
|
+
parsed.set(source, nodes);
|
|
911
|
+
}
|
|
912
|
+
return nodes;
|
|
913
|
+
}
|
|
914
|
+
var pluralRules = /* @__PURE__ */ new Map();
|
|
915
|
+
function rulesFor(locale, ordinal) {
|
|
916
|
+
const key = `${locale}|${ordinal ? "o" : "c"}`;
|
|
917
|
+
let pr = pluralRules.get(key);
|
|
918
|
+
if (!pr) {
|
|
919
|
+
try {
|
|
920
|
+
pr = new Intl.PluralRules(locale, { type: ordinal ? "ordinal" : "cardinal" });
|
|
921
|
+
} catch {
|
|
922
|
+
pr = new Intl.PluralRules("en", { type: ordinal ? "ordinal" : "cardinal" });
|
|
923
|
+
}
|
|
924
|
+
pluralRules.set(key, pr);
|
|
925
|
+
}
|
|
926
|
+
return pr;
|
|
927
|
+
}
|
|
928
|
+
function render(nodes, values, rt, pound) {
|
|
929
|
+
let out = "";
|
|
930
|
+
for (const node of nodes) {
|
|
931
|
+
if (typeof node === "string") {
|
|
932
|
+
out += node;
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
if (node.kind === "pound") {
|
|
936
|
+
out += pound == null ? "#" : rt.formatNumber(pound);
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
const raw = values?.[node.name];
|
|
940
|
+
if (node.kind === "arg") {
|
|
941
|
+
if (raw === void 0) out += `{${node.name}}`;
|
|
942
|
+
else if (typeof raw === "number") out += rt.formatNumber(raw, node.format === "number" ? node.style : void 0);
|
|
943
|
+
else if (node.format === "number" && raw.trim() !== "" && Number.isFinite(Number(raw))) out += rt.formatNumber(Number(raw), node.style);
|
|
944
|
+
else out += raw;
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
if (node.kind === "select") {
|
|
948
|
+
const branch2 = node.options[String(raw)] ?? node.options.other;
|
|
949
|
+
out += render(branch2, values, rt, pound);
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
953
|
+
let branch;
|
|
954
|
+
if (Number.isFinite(n)) {
|
|
955
|
+
branch = node.options[`=${n}`] ?? node.options[rulesFor(rt.locale, node.ordinal).select(n - node.offset)];
|
|
956
|
+
}
|
|
957
|
+
out += render(branch ?? node.options.other, values, rt, Number.isFinite(n) ? n - node.offset : null);
|
|
958
|
+
}
|
|
959
|
+
return out;
|
|
960
|
+
}
|
|
961
|
+
function formatMessage(source, values, rt) {
|
|
962
|
+
if (source.indexOf("{") < 0 && source.indexOf("'") < 0) return source;
|
|
963
|
+
return render(parseMessage(source), values, rt, null);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// src/core/format/calendar.ts
|
|
967
|
+
var EN_MONTHS_LONG = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
968
|
+
var EN_MONTHS_SHORT_PICKER = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
969
|
+
var EN_WEEKDAYS_MIN = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
970
|
+
function monthNames(settings, width) {
|
|
971
|
+
if (settings.english) return [...width === "long" ? EN_MONTHS_LONG : EN_MONTHS_SHORT_PICKER];
|
|
972
|
+
const dtf = dateFormat(settings, { month: width });
|
|
973
|
+
return Array.from({ length: 12 }, (_, m) => stripBidiMarks(dtf.format(Date.UTC(2e3, m, 15))));
|
|
974
|
+
}
|
|
975
|
+
function weekdayNames(settings) {
|
|
976
|
+
if (settings.english) return [...EN_WEEKDAYS_MIN];
|
|
977
|
+
const dtf = dateFormat(settings, { weekday: "short" });
|
|
978
|
+
return Array.from({ length: 7 }, (_, d) => stripBidiMarks(dtf.format(Date.UTC(2e3, 0, 2 + d))));
|
|
979
|
+
}
|
|
980
|
+
function yearLabel(settings, year) {
|
|
981
|
+
if (settings.english) return localizeAscii(String(year), settings);
|
|
982
|
+
return stripBidiMarks(dateFormat(settings, { year: "numeric" }).format(Date.UTC(year, 6, 1)));
|
|
983
|
+
}
|
|
984
|
+
function plainInteger(settings, n) {
|
|
985
|
+
return localizeAscii(String(Math.trunc(n)), settings);
|
|
986
|
+
}
|
|
987
|
+
var yearFirstCache = /* @__PURE__ */ new Map();
|
|
988
|
+
function yearBeforeMonth(settings) {
|
|
989
|
+
if (settings.english) return false;
|
|
990
|
+
const key = `${settings.locale}|${settings.numberingSystem}`;
|
|
991
|
+
let first = yearFirstCache.get(key);
|
|
992
|
+
if (first === void 0) {
|
|
993
|
+
const types = dateFormat(settings, { year: "numeric", month: "long" }).formatToParts(Date.UTC(2026, 8, 15)).map((p) => p.type);
|
|
994
|
+
first = types.indexOf("year") < types.indexOf("month");
|
|
995
|
+
yearFirstCache.set(key, first);
|
|
996
|
+
}
|
|
997
|
+
return first;
|
|
998
|
+
}
|
|
999
|
+
var SUNDAY_REGIONS = /* @__PURE__ */ new Set([
|
|
1000
|
+
"AG",
|
|
1001
|
+
"AS",
|
|
1002
|
+
"BD",
|
|
1003
|
+
"BR",
|
|
1004
|
+
"BS",
|
|
1005
|
+
"BT",
|
|
1006
|
+
"BW",
|
|
1007
|
+
"BZ",
|
|
1008
|
+
"CA",
|
|
1009
|
+
"CN",
|
|
1010
|
+
"CO",
|
|
1011
|
+
"DM",
|
|
1012
|
+
"DO",
|
|
1013
|
+
"ET",
|
|
1014
|
+
"GT",
|
|
1015
|
+
"GU",
|
|
1016
|
+
"HK",
|
|
1017
|
+
"HN",
|
|
1018
|
+
"ID",
|
|
1019
|
+
"IL",
|
|
1020
|
+
"IN",
|
|
1021
|
+
"JM",
|
|
1022
|
+
"JP",
|
|
1023
|
+
"KE",
|
|
1024
|
+
"KH",
|
|
1025
|
+
"KR",
|
|
1026
|
+
"LA",
|
|
1027
|
+
"MH",
|
|
1028
|
+
"MM",
|
|
1029
|
+
"MO",
|
|
1030
|
+
"MT",
|
|
1031
|
+
"MX",
|
|
1032
|
+
"MZ",
|
|
1033
|
+
"NI",
|
|
1034
|
+
"NP",
|
|
1035
|
+
"PA",
|
|
1036
|
+
"PE",
|
|
1037
|
+
"PH",
|
|
1038
|
+
"PK",
|
|
1039
|
+
"PR",
|
|
1040
|
+
"PT",
|
|
1041
|
+
"PY",
|
|
1042
|
+
"SA",
|
|
1043
|
+
"SG",
|
|
1044
|
+
"SV",
|
|
1045
|
+
"TH",
|
|
1046
|
+
"TT",
|
|
1047
|
+
"TW",
|
|
1048
|
+
"UM",
|
|
1049
|
+
"US",
|
|
1050
|
+
"VE",
|
|
1051
|
+
"VI",
|
|
1052
|
+
"WS",
|
|
1053
|
+
"YE",
|
|
1054
|
+
"ZA",
|
|
1055
|
+
"ZW"
|
|
1056
|
+
]);
|
|
1057
|
+
var SATURDAY_REGIONS = /* @__PURE__ */ new Set(["AE", "AF", "BH", "DJ", "DZ", "EG", "IQ", "IR", "JO", "KW", "LY", "OM", "QA", "SD", "SY"]);
|
|
1058
|
+
function localeWeekStart(locale) {
|
|
1059
|
+
let loc;
|
|
1060
|
+
try {
|
|
1061
|
+
loc = new Intl.Locale(locale);
|
|
1062
|
+
} catch {
|
|
1063
|
+
return 1;
|
|
1064
|
+
}
|
|
1065
|
+
try {
|
|
1066
|
+
const wl = loc;
|
|
1067
|
+
const info = typeof wl.getWeekInfo === "function" ? wl.getWeekInfo() : wl.weekInfo;
|
|
1068
|
+
const firstDay = info?.firstDay;
|
|
1069
|
+
if (typeof firstDay === "number") return firstDay === 7 ? 0 : firstDay === 6 ? 6 : 1;
|
|
1070
|
+
} catch {
|
|
1071
|
+
}
|
|
1072
|
+
let region = loc.region;
|
|
1073
|
+
if (!region) {
|
|
1074
|
+
try {
|
|
1075
|
+
region = loc.maximize().region;
|
|
1076
|
+
} catch {
|
|
1077
|
+
region = void 0;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
if (region && SUNDAY_REGIONS.has(region)) return 0;
|
|
1081
|
+
if (region && SATURDAY_REGIONS.has(region)) return 6;
|
|
1082
|
+
return 1;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// src/core/i18n/locale.ts
|
|
1086
|
+
function canonicalLocale(tag) {
|
|
1087
|
+
const raw = typeof tag === "string" ? tag.trim() : "";
|
|
1088
|
+
if (!raw) return "en";
|
|
1089
|
+
try {
|
|
1090
|
+
return Intl.getCanonicalLocales(raw)[0] ?? raw;
|
|
1091
|
+
} catch {
|
|
1092
|
+
return raw;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function parseLocale(tag) {
|
|
1096
|
+
try {
|
|
1097
|
+
return new Intl.Locale(tag);
|
|
1098
|
+
} catch {
|
|
1099
|
+
return null;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
function languageOf(tag) {
|
|
1103
|
+
return (parseLocale(tag)?.language ?? tag.split(/[-_]/)[0] ?? tag).toLowerCase();
|
|
1104
|
+
}
|
|
1105
|
+
function fallbackChain(tag) {
|
|
1106
|
+
const out = [];
|
|
1107
|
+
const add = (t) => {
|
|
1108
|
+
if (t && !out.includes(t)) out.push(t);
|
|
1109
|
+
};
|
|
1110
|
+
add(tag);
|
|
1111
|
+
const loc = parseLocale(tag);
|
|
1112
|
+
if (loc) {
|
|
1113
|
+
const base = loc.baseName;
|
|
1114
|
+
add(base);
|
|
1115
|
+
const parts = base.split("-");
|
|
1116
|
+
let impliedScript;
|
|
1117
|
+
if (!loc.script) {
|
|
1118
|
+
try {
|
|
1119
|
+
impliedScript = loc.maximize().script;
|
|
1120
|
+
} catch {
|
|
1121
|
+
impliedScript = void 0;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
for (let i = parts.length - 1; i >= 1; i -= 1) {
|
|
1125
|
+
if (i === 1 && impliedScript && loc.region) add(`${loc.language}-${impliedScript}`);
|
|
1126
|
+
add(parts.slice(0, i).join("-"));
|
|
1127
|
+
}
|
|
1128
|
+
if (impliedScript && !loc.region) add(`${loc.language}-${impliedScript}`);
|
|
1129
|
+
try {
|
|
1130
|
+
const usual = new Intl.Locale(loc.language).maximize();
|
|
1131
|
+
if (usual.region && usual.script === (loc.script ?? impliedScript)) add(`${loc.language}-${usual.region}`);
|
|
1132
|
+
} catch {
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
add("en");
|
|
1136
|
+
return out;
|
|
1137
|
+
}
|
|
1138
|
+
var RTL_SCRIPTS = /* @__PURE__ */ new Set(["Arab", "Hebr", "Thaa", "Syrc", "Nkoo", "Adlm", "Rohg", "Mand", "Samr", "Yezi"]);
|
|
1139
|
+
var RTL_LANGUAGES = /* @__PURE__ */ new Set(["ar", "he", "iw", "fa", "ur", "ps", "sd", "ug", "yi", "dv", "ckb", "ks"]);
|
|
1140
|
+
function localeDirection(tag) {
|
|
1141
|
+
const loc = parseLocale(tag);
|
|
1142
|
+
if (loc) {
|
|
1143
|
+
try {
|
|
1144
|
+
const tl = loc;
|
|
1145
|
+
const info = typeof tl.getTextInfo === "function" ? tl.getTextInfo() : tl.textInfo;
|
|
1146
|
+
if (info?.direction === "rtl" || info?.direction === "ltr") return info.direction;
|
|
1147
|
+
} catch {
|
|
1148
|
+
}
|
|
1149
|
+
try {
|
|
1150
|
+
const script = loc.script ?? loc.maximize().script;
|
|
1151
|
+
if (script) return RTL_SCRIPTS.has(script) ? "rtl" : "ltr";
|
|
1152
|
+
} catch {
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return RTL_LANGUAGES.has(languageOf(tag)) ? "rtl" : "ltr";
|
|
1156
|
+
}
|
|
1157
|
+
var numberingCache = /* @__PURE__ */ new Map();
|
|
1158
|
+
function resolveNumberingSystem(tag, requested) {
|
|
1159
|
+
const key = `${tag}|${requested ?? ""}`;
|
|
1160
|
+
const cached = numberingCache.get(key);
|
|
1161
|
+
if (cached) return cached;
|
|
1162
|
+
let nu = "latn";
|
|
1163
|
+
try {
|
|
1164
|
+
if (requested === "locale") nu = new Intl.NumberFormat(tag).resolvedOptions().numberingSystem;
|
|
1165
|
+
else if (requested) nu = new Intl.NumberFormat(tag, { numberingSystem: requested }).resolvedOptions().numberingSystem;
|
|
1166
|
+
else {
|
|
1167
|
+
const ext = parseLocale(tag)?.numberingSystem;
|
|
1168
|
+
if (ext) nu = new Intl.NumberFormat(tag).resolvedOptions().numberingSystem;
|
|
1169
|
+
}
|
|
1170
|
+
} catch {
|
|
1171
|
+
nu = "latn";
|
|
1172
|
+
}
|
|
1173
|
+
numberingCache.set(key, nu);
|
|
1174
|
+
return nu;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// src/core/i18n/registry.ts
|
|
1178
|
+
var entries = [];
|
|
1179
|
+
var version = 0;
|
|
1180
|
+
var merged = /* @__PURE__ */ new Map();
|
|
1181
|
+
function messagesFor(chain) {
|
|
1182
|
+
const key = chain.join("|");
|
|
1183
|
+
const hit = merged.get(key);
|
|
1184
|
+
if (hit && hit.version === version) return hit.map;
|
|
1185
|
+
const map = /* @__PURE__ */ new Map();
|
|
1186
|
+
for (let c = chain.length - 1; c >= 0; c -= 1) {
|
|
1187
|
+
const tag = chain[c];
|
|
1188
|
+
for (const e of entries) {
|
|
1189
|
+
if (e.tag !== tag) continue;
|
|
1190
|
+
for (const [id, text] of Object.entries(e.messages)) {
|
|
1191
|
+
if (typeof text === "string") map.set(id, text);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
merged.set(key, { version, map });
|
|
1196
|
+
return map;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// src/core/i18n/translator.ts
|
|
1200
|
+
function isMessageDescriptor(m) {
|
|
1201
|
+
return typeof m === "object" && m !== null && typeof m.id === "string" && typeof m.defaultMessage === "string";
|
|
1202
|
+
}
|
|
1203
|
+
var warnedSyntax = false;
|
|
1204
|
+
function resolveArgs(args, resolve) {
|
|
1205
|
+
if (!args) return void 0;
|
|
1206
|
+
let out = null;
|
|
1207
|
+
for (const key of Object.keys(args)) {
|
|
1208
|
+
const v = args[key];
|
|
1209
|
+
if (typeof v === "object" && v !== null) {
|
|
1210
|
+
out ?? (out = { ...args });
|
|
1211
|
+
out[key] = resolve(v);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return out ?? args;
|
|
1215
|
+
}
|
|
1216
|
+
var LocaleState = class {
|
|
1217
|
+
constructor(options = {}) {
|
|
1218
|
+
this.runtime = {
|
|
1219
|
+
locale: "en",
|
|
1220
|
+
formatNumber: (value, style) => formatMessageNumber(value, this.settings, style)
|
|
1221
|
+
};
|
|
1222
|
+
this.opts = { ...options };
|
|
1223
|
+
this.resolve();
|
|
1224
|
+
}
|
|
1225
|
+
/** The options as last set (unresolved). */
|
|
1226
|
+
get options() {
|
|
1227
|
+
return this.opts;
|
|
1228
|
+
}
|
|
1229
|
+
/** Whether the host chose a locale; Vela stamps `lang` only then. */
|
|
1230
|
+
get localeExplicit() {
|
|
1231
|
+
return this.opts.locale !== void 0;
|
|
1232
|
+
}
|
|
1233
|
+
/** Whether the host chose a direction; Vela stamps `dir` only then. */
|
|
1234
|
+
get directionExplicit() {
|
|
1235
|
+
return this.opts.direction !== void 0;
|
|
1236
|
+
}
|
|
1237
|
+
/** Apply a change: fields present in `next` replace (an explicit `undefined` restores
|
|
1238
|
+
* the default), absent fields keep their current value. */
|
|
1239
|
+
update(next) {
|
|
1240
|
+
const patch = typeof next === "string" ? { locale: next } : next;
|
|
1241
|
+
this.opts = { ...this.opts, ...patch };
|
|
1242
|
+
for (const key of Object.keys(this.opts)) {
|
|
1243
|
+
if (this.opts[key] === void 0) delete this.opts[key];
|
|
1244
|
+
}
|
|
1245
|
+
this.resolve();
|
|
1246
|
+
}
|
|
1247
|
+
resolve() {
|
|
1248
|
+
const o = this.opts;
|
|
1249
|
+
const locale = canonicalLocale(o.locale);
|
|
1250
|
+
const numberingSystem = resolveNumberingSystem(locale, o.numberingSystem);
|
|
1251
|
+
const hourCycle = o.hourCycle === "h12" || o.hourCycle === "locale" ? o.hourCycle : "h23";
|
|
1252
|
+
this.settings = { locale, numberingSystem, hourCycle, english: languageOf(locale) === "en" };
|
|
1253
|
+
this.chain = fallbackChain(locale);
|
|
1254
|
+
this.resolvedDirection = o.direction === "rtl" || o.direction === "ltr" ? o.direction : o.direction === "auto" ? localeDirection(locale) : "ltr";
|
|
1255
|
+
this.resolvedWeekStart = o.weekStart === 0 || o.weekStart === 1 || o.weekStart === 6 ? o.weekStart : localeWeekStart(locale);
|
|
1256
|
+
this.runtime.locale = locale;
|
|
1257
|
+
this.formatters = resolveFormatters(this.settings, o.formatters);
|
|
1258
|
+
}
|
|
1259
|
+
get locale() {
|
|
1260
|
+
return this.settings.locale;
|
|
1261
|
+
}
|
|
1262
|
+
get direction() {
|
|
1263
|
+
return this.resolvedDirection;
|
|
1264
|
+
}
|
|
1265
|
+
get numberingSystem() {
|
|
1266
|
+
return this.settings.numberingSystem;
|
|
1267
|
+
}
|
|
1268
|
+
get hourCycle() {
|
|
1269
|
+
return this.settings.hourCycle;
|
|
1270
|
+
}
|
|
1271
|
+
get weekStart() {
|
|
1272
|
+
return this.resolvedWeekStart;
|
|
1273
|
+
}
|
|
1274
|
+
get format() {
|
|
1275
|
+
return this.formatters;
|
|
1276
|
+
}
|
|
1277
|
+
/** The resolved settings the built-in formatters and calendar helpers read. */
|
|
1278
|
+
get formatSettings() {
|
|
1279
|
+
return this.settings;
|
|
1280
|
+
}
|
|
1281
|
+
t(message, args) {
|
|
1282
|
+
if (typeof message === "string") return message;
|
|
1283
|
+
if (!isMessageDescriptor(message)) return message == null ? "" : String(message);
|
|
1284
|
+
const { id, defaultMessage } = message;
|
|
1285
|
+
const bound = message.values;
|
|
1286
|
+
const values = resolveArgs(bound ? args ? { ...bound, ...args } : bound : args, (m) => this.t(m));
|
|
1287
|
+
const override = this.opts.messages?.[id];
|
|
1288
|
+
const source = typeof override === "string" ? override : messagesFor(this.chain).get(id) ?? defaultMessage;
|
|
1289
|
+
try {
|
|
1290
|
+
return formatMessage(source, values, this.runtime);
|
|
1291
|
+
} catch (err) {
|
|
1292
|
+
if (!warnedSyntax) {
|
|
1293
|
+
warnedSyntax = true;
|
|
1294
|
+
console.warn(`[vela] message "${id}" could not be formatted; the English text is used instead.`, err);
|
|
1295
|
+
}
|
|
1296
|
+
if (source === defaultMessage) return defaultMessage;
|
|
1297
|
+
try {
|
|
1298
|
+
return formatMessage(defaultMessage, values, this.runtime);
|
|
1299
|
+
} catch {
|
|
1300
|
+
return defaultMessage;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
var english = null;
|
|
1306
|
+
function englishTranslator() {
|
|
1307
|
+
english ?? (english = new LocaleState());
|
|
1308
|
+
return english;
|
|
1309
|
+
}
|
|
1310
|
+
function formatSettingsOf(i18n) {
|
|
1311
|
+
if (i18n instanceof LocaleState) return i18n.formatSettings;
|
|
1312
|
+
if (!i18n) return englishTranslator().formatSettings;
|
|
1313
|
+
return { locale: i18n.locale, numberingSystem: i18n.numberingSystem, hourCycle: i18n.hourCycle, english: languageOf(i18n.locale) === "en" };
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// src/core/i18n/text.ts
|
|
1317
|
+
function textOf(i18n, message, values) {
|
|
1318
|
+
return (i18n ?? englishTranslator()).t(message, values);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
431
1321
|
// src/ui/keymap.ts
|
|
432
1322
|
var KEY_ALIASES = {
|
|
433
1323
|
esc: "escape",
|
|
@@ -441,7 +1331,15 @@ var KEY_ALIASES = {
|
|
|
441
1331
|
up: "arrowup",
|
|
442
1332
|
down: "arrowdown"
|
|
443
1333
|
};
|
|
444
|
-
var MAC_GLYPHS = { meta: "
|
|
1334
|
+
var MAC_GLYPHS = { meta: "⌘", ctrl: "⌃", alt: "⌥", shift: "⇧" };
|
|
1335
|
+
var KEY_TEXT = {
|
|
1336
|
+
ctrl: msg("ui.keys.ctrl", "Ctrl"),
|
|
1337
|
+
alt: msg("ui.keys.alt", "Alt"),
|
|
1338
|
+
shift: msg("ui.keys.shift", "Shift"),
|
|
1339
|
+
meta: msg("ui.keys.meta", "Win"),
|
|
1340
|
+
space: msg("ui.keys.space", "Space"),
|
|
1341
|
+
general: msg("ui.keys.general", "General")
|
|
1342
|
+
};
|
|
445
1343
|
function parseChord(spec, mac) {
|
|
446
1344
|
const parts = spec.toLowerCase().split("+").map((p) => p.trim()).filter((p, i, a) => p !== "" || a[i - 1] === "");
|
|
447
1345
|
const chord = { ctrl: false, meta: false, alt: false, shift: false, key: "" };
|
|
@@ -456,10 +1354,16 @@ function parseChord(spec, mac) {
|
|
|
456
1354
|
}
|
|
457
1355
|
return chord;
|
|
458
1356
|
}
|
|
1357
|
+
function chordKeyOf(ev) {
|
|
1358
|
+
const key = String(ev.key ?? "").toLowerCase();
|
|
1359
|
+
if (key.length !== 1 || /^[a-z0-9]$/.test(key) || !/\p{L}/u.test(key)) return key;
|
|
1360
|
+
const m = /^Key([A-Z])$|^Digit([0-9])$/.exec(ev.code ?? "");
|
|
1361
|
+
return m ? (m[1] ?? m[2]).toLowerCase() : key;
|
|
1362
|
+
}
|
|
459
1363
|
function eventMatches(ev, c) {
|
|
460
1364
|
return ev.ctrlKey === c.ctrl && ev.metaKey === c.meta && ev.altKey === c.alt && // Shift is part of producing many printable keys ('?', '+') — only enforce it
|
|
461
1365
|
// when the chord names a non-printable/letter key where shift is a real modifier.
|
|
462
|
-
(c.key.length > 1 || /^[a-z0-9 ]$/.test(c.key) ? ev.shiftKey === c.shift : true) && ev
|
|
1366
|
+
(c.key.length > 1 || /^[a-z0-9 ]$/.test(c.key) ? ev.shiftKey === c.shift : true) && chordKeyOf(ev) === c.key;
|
|
463
1367
|
}
|
|
464
1368
|
function isEditableTarget(ev) {
|
|
465
1369
|
const t = ev.target;
|
|
@@ -469,13 +1373,14 @@ function isEditableTarget(ev) {
|
|
|
469
1373
|
if (t.isContentEditable === true) return true;
|
|
470
1374
|
return (typeof t.getAttribute === "function" ? t.getAttribute("role") : null) === "textbox";
|
|
471
1375
|
}
|
|
472
|
-
function displayChord(spec, mac) {
|
|
1376
|
+
function displayChord(spec, mac, i18n) {
|
|
473
1377
|
const c = parseChord(spec, mac);
|
|
474
|
-
const
|
|
1378
|
+
const name = (m) => textOf(i18n, m);
|
|
1379
|
+
const keyLabel = c.key === " " ? name(KEY_TEXT.space) : c.key.length === 1 ? c.key.toUpperCase() : c.key.charAt(0).toUpperCase() + c.key.slice(1);
|
|
475
1380
|
if (mac) {
|
|
476
1381
|
return (c.ctrl ? MAC_GLYPHS.ctrl : "") + (c.alt ? MAC_GLYPHS.alt : "") + (c.shift ? MAC_GLYPHS.shift : "") + (c.meta ? MAC_GLYPHS.meta : "") + keyLabel;
|
|
477
1382
|
}
|
|
478
|
-
const mods = [c.ctrl &&
|
|
1383
|
+
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);
|
|
479
1384
|
return [...mods, keyLabel].join("+");
|
|
480
1385
|
}
|
|
481
1386
|
var KeymapManager = class {
|
|
@@ -506,17 +1411,18 @@ var KeymapManager = class {
|
|
|
506
1411
|
if (keys === null) this.rebinds.delete(id);
|
|
507
1412
|
else this.rebinds.set(id, Array.isArray(keys) ? [...keys] : [keys]);
|
|
508
1413
|
}
|
|
509
|
-
/** Snapshot for a shortcuts help panel / rebinding UI
|
|
510
|
-
|
|
1414
|
+
/** Snapshot for a shortcuts help panel / rebinding UI: labels, categories and key
|
|
1415
|
+
* names in `i18n`'s language (English when absent). */
|
|
1416
|
+
bindings(i18n) {
|
|
511
1417
|
return [...this.descriptors.values()].map((d) => {
|
|
512
1418
|
const keys = this.activeKeys(d);
|
|
513
1419
|
return {
|
|
514
1420
|
id: d.id,
|
|
515
|
-
label: d.label,
|
|
516
|
-
category: d.category ??
|
|
1421
|
+
label: textOf(i18n, d.label),
|
|
1422
|
+
category: textOf(i18n, d.category ?? KEY_TEXT.general),
|
|
517
1423
|
scope: d.scope ?? this.baseScope,
|
|
518
1424
|
keys,
|
|
519
|
-
display: keys.map((k) => displayChord(k, this.mac))
|
|
1425
|
+
display: keys.map((k) => displayChord(k, this.mac, i18n))
|
|
520
1426
|
};
|
|
521
1427
|
});
|
|
522
1428
|
}
|
|
@@ -750,7 +1656,7 @@ var MENU_CSS = `
|
|
|
750
1656
|
.vela-menu-item .vela-icon { width: 16px; height: 16px; font-size: 16px; justify-content: center; color: var(--vela-fg-muted); }
|
|
751
1657
|
.vela-menu-item .vela-menu-label { flex: 1 1 auto; }
|
|
752
1658
|
.vela-menu-item .vela-menu-hint { color: var(--vela-fg-faint); font-size: var(--vela-font-size-sm); }
|
|
753
|
-
/* Active entry: the row surface carries the selection
|
|
1659
|
+
/* Active entry: the row surface carries the selection — a stronger background wash
|
|
754
1660
|
than the hover one, plus bright ink. Declared after the hover rule so a selected
|
|
755
1661
|
row stays visibly selected while highlighted. */
|
|
756
1662
|
.vela-menu-item[data-checked] {
|
|
@@ -758,7 +1664,7 @@ var MENU_CSS = `
|
|
|
758
1664
|
color: var(--vela-fg-bright);
|
|
759
1665
|
}
|
|
760
1666
|
/* Checkmark mode (context/action menus): every row reserves the leading mark column so
|
|
761
|
-
labels align; a checked row fills it with a
|
|
1667
|
+
labels align; a checked row fills it with a ✓ and brightens its ink — the row surface
|
|
762
1668
|
stays free for the hover wash. */
|
|
763
1669
|
.vela-menu-item .vela-menu-mark {
|
|
764
1670
|
width: 14px;
|
|
@@ -803,7 +1709,7 @@ var MENU_CSS = `
|
|
|
803
1709
|
border-color: color-mix(in srgb, var(--vela-fg-bright) 40%, transparent);
|
|
804
1710
|
color: var(--vela-surface);
|
|
805
1711
|
}
|
|
806
|
-
/* Switch rows (boolean settings in a dropdown): a right-aligned toggle pill
|
|
1712
|
+
/* Switch rows (boolean settings in a dropdown): a right-aligned toggle pill — the
|
|
807
1713
|
same control language as the settings dialog's toggles. */
|
|
808
1714
|
.vela-menu-switch {
|
|
809
1715
|
order: 99;
|
|
@@ -830,8 +1736,8 @@ var MENU_CSS = `
|
|
|
830
1736
|
}
|
|
831
1737
|
.vela-menu-switch.on { background: var(--vela-accent-bright, var(--vela-accent)); border-color: var(--vela-accent-bright, var(--vela-accent)); }
|
|
832
1738
|
.vela-menu-switch.on::after { transform: translateX(16px); background: var(--vela-bg); }
|
|
833
|
-
/* Favorite star (rows carrying \`favorite\`): reserved space always
|
|
834
|
-
hover instead of shifting the layout
|
|
1739
|
+
/* Favorite star (rows carrying \`favorite\`): reserved space always — it fades in on row
|
|
1740
|
+
hover instead of shifting the layout — and a starred row keeps its filled star visible.
|
|
835
1741
|
Same control language as the drawing toolbar's flyout stars. */
|
|
836
1742
|
.vela-menu-item .vela-menu-star {
|
|
837
1743
|
order: 98;
|
|
@@ -859,6 +1765,18 @@ var MENU_CSS = `
|
|
|
859
1765
|
}
|
|
860
1766
|
.vela-menu-item[data-state='open'] { background: var(--vela-hover); }
|
|
861
1767
|
`;
|
|
1768
|
+
|
|
1769
|
+
// src/ui/kit-text.ts
|
|
1770
|
+
var scoped = null;
|
|
1771
|
+
function kitTranslator() {
|
|
1772
|
+
return scoped;
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
// src/ui/components/menu/view.ts
|
|
1776
|
+
var TEXT = {
|
|
1777
|
+
addFavorite: msg("ui.menu.addFavorite", "Add to favorites"),
|
|
1778
|
+
removeFavorite: msg("ui.menu.removeFavorite", "Remove from favorites")
|
|
1779
|
+
};
|
|
862
1780
|
var Surface = class _Surface {
|
|
863
1781
|
constructor(doc, opts) {
|
|
864
1782
|
this.items = [];
|
|
@@ -875,6 +1793,7 @@ var Surface = class _Surface {
|
|
|
875
1793
|
this.host = opts.host;
|
|
876
1794
|
this.onSelect = opts.onSelect;
|
|
877
1795
|
this.onFavorite = opts.onFavorite;
|
|
1796
|
+
this.i18n = opts.i18n;
|
|
878
1797
|
this.checkmarks = opts.checkmarks === true;
|
|
879
1798
|
this.iconBadges = opts.iconBadges === true;
|
|
880
1799
|
this.positioner = doc.createElement("div");
|
|
@@ -1037,7 +1956,7 @@ var Surface = class _Surface {
|
|
|
1037
1956
|
if (on) star.classList.add("vela-fav");
|
|
1038
1957
|
star.removeAttribute("aria-hidden");
|
|
1039
1958
|
star.setAttribute("role", "button");
|
|
1040
|
-
star.setAttribute("aria-label", on ?
|
|
1959
|
+
star.setAttribute("aria-label", textOf(this.i18n, on ? TEXT.removeFavorite : TEXT.addFavorite));
|
|
1041
1960
|
star.setAttribute("aria-pressed", on ? "true" : "false");
|
|
1042
1961
|
for (const ev of ["pointerdown", "pointerup", "mousedown", "mouseup"]) {
|
|
1043
1962
|
star.addEventListener(ev, (e) => e.stopPropagation());
|
|
@@ -1066,6 +1985,7 @@ var Surface = class _Surface {
|
|
|
1066
1985
|
opener: li,
|
|
1067
1986
|
onSelect: this.onSelect,
|
|
1068
1987
|
onFavorite: this.onFavorite,
|
|
1988
|
+
i18n: this.i18n,
|
|
1069
1989
|
checkmarks: this.checkmarks,
|
|
1070
1990
|
iconBadges: this.iconBadges,
|
|
1071
1991
|
id: `${this.mid}--${item.id}`
|
|
@@ -1093,6 +2013,7 @@ var Menu = class {
|
|
|
1093
2013
|
id: opts.id,
|
|
1094
2014
|
minWidth: opts.minWidth,
|
|
1095
2015
|
onFavorite: opts.onFavorite,
|
|
2016
|
+
i18n: opts.i18n ?? kitTranslator(),
|
|
1096
2017
|
checkmarks: opts.checkmarks,
|
|
1097
2018
|
iconBadges: opts.iconBadges
|
|
1098
2019
|
});
|
|
@@ -1508,13 +2429,13 @@ var DIALOG_CSS = `
|
|
|
1508
2429
|
.vela-dialog-btn-primary:hover { background: var(--vela-selected-bg); color: var(--vela-selected-fg); opacity: 0.85; border-color: var(--vela-selected-bg); }
|
|
1509
2430
|
${overlayScrollbarCss(".vela-dialog-body")}
|
|
1510
2431
|
/* Scrollers NESTED in a dialog (a flush body's grid, a tab pane) get the same thin
|
|
1511
|
-
overlay bars
|
|
2432
|
+
overlay bars — the two-class selectors below stay overridable by more specific
|
|
1512
2433
|
per-dialog sheets. */
|
|
1513
2434
|
${overlayScrollbarCss(".vela-dialog *")}
|
|
1514
|
-
/*
|
|
2435
|
+
/* ── mobile chrome: dialogs fill the shell ─────────────────────────────────────────
|
|
1515
2436
|
Inside a shell in the mobile size class ([data-layout='mobile'] on the widget root,
|
|
1516
2437
|
which is position:relative) every kit dialog presents fullscreen: desktop cards are
|
|
1517
|
-
unusable at phone widths, and the shell's bounds
|
|
2438
|
+
unusable at phone widths, and the shell's bounds — not the viewport — are the honest
|
|
1518
2439
|
"screen" for an embedded chart. */
|
|
1519
2440
|
[data-layout='mobile'] .vela-dialog-backdrop { position: absolute; }
|
|
1520
2441
|
[data-layout='mobile'] .vela-dialog-positioner {
|
|
@@ -1762,7 +2683,7 @@ var DRAWER_CSS = `
|
|
|
1762
2683
|
z-index: var(--vela-z-dialog);
|
|
1763
2684
|
}
|
|
1764
2685
|
/* Inside a shell that declares a size class, the sheet scopes to the SHELL's bounds
|
|
1765
|
-
(the widget root is position:relative) instead of the whole viewport
|
|
2686
|
+
(the widget root is position:relative) instead of the whole viewport — an embedded
|
|
1766
2687
|
chart must not curtain the host page. */
|
|
1767
2688
|
[data-layout] .vela-drawer-backdrop, [data-layout] .vela-drawer-positioner { position: absolute; }
|
|
1768
2689
|
.vela-drawer {
|
|
@@ -2562,7 +3483,7 @@ var NUMBER_CSS = `
|
|
|
2562
3483
|
.vela-num input::-webkit-inner-spin-button, .vela-num input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
|
|
2563
3484
|
.vela-num input:hover { border-color: var(--vela-fg-muted); }
|
|
2564
3485
|
.vela-num input:focus { border-color: var(--vela-focus); box-shadow: 0 0 0 3px var(--vela-focus-soft); }
|
|
2565
|
-
/* The stepper gutter exists only while the steppers do (hover)
|
|
3486
|
+
/* The stepper gutter exists only while the steppers do (hover) — an idle field keeps
|
|
2566
3487
|
its full width so long values aren't cut under an invisible arrow column. */
|
|
2567
3488
|
.vela-num[data-steppers]:hover input { padding-right: 26px; }
|
|
2568
3489
|
.vela-num[data-size='sm'] { width: 64px; flex: none; }
|
|
@@ -2609,10 +3530,15 @@ var NUMBER_CSS = `
|
|
|
2609
3530
|
`;
|
|
2610
3531
|
|
|
2611
3532
|
// src/ui/components/number-input/view.ts
|
|
3533
|
+
var TEXT2 = {
|
|
3534
|
+
increase: msg("ui.numberInput.increase", "Increase"),
|
|
3535
|
+
decrease: msg("ui.numberInput.decrease", "Decrease")
|
|
3536
|
+
};
|
|
2612
3537
|
var NumberInput = class {
|
|
2613
3538
|
constructor(opts) {
|
|
2614
3539
|
const doc = document;
|
|
2615
3540
|
injectStyles(NUMBER_STYLE_ID, NUMBER_CSS, doc);
|
|
3541
|
+
this.i18n = opts.i18n ?? kitTranslator();
|
|
2616
3542
|
this.ctrl = numberInputController(opts);
|
|
2617
3543
|
this.placeholderMode = opts.placeholder !== void 0;
|
|
2618
3544
|
this.emptyValue = opts.emptyValue ?? opts.value;
|
|
@@ -2717,7 +3643,7 @@ var NumberInput = class {
|
|
|
2717
3643
|
b.addEventListener("pointercancel", stop);
|
|
2718
3644
|
return b;
|
|
2719
3645
|
};
|
|
2720
|
-
steps.append(mk(1, "chevron-up",
|
|
3646
|
+
steps.append(mk(1, "chevron-up", textOf(this.i18n, TEXT2.increase)), mk(-1, "chevron-down", textOf(this.i18n, TEXT2.decrease)));
|
|
2721
3647
|
return steps;
|
|
2722
3648
|
}
|
|
2723
3649
|
};
|
|
@@ -2886,9 +3812,9 @@ function transparencyChecker(size) {
|
|
|
2886
3812
|
return `repeating-conic-gradient(#9aa0a6 0% 25%, #d3d6da 0% 50%) 0 0 / ${size}px ${size}px`;
|
|
2887
3813
|
}
|
|
2888
3814
|
function colorPickerController(opts = {}) {
|
|
2889
|
-
const
|
|
2890
|
-
let hex6 =
|
|
2891
|
-
let alpha =
|
|
3815
|
+
const parsed2 = splitColor(opts.color ?? ACCENT_BRIGHT);
|
|
3816
|
+
let hex6 = parsed2.hex6;
|
|
3817
|
+
let alpha = parsed2.alpha;
|
|
2892
3818
|
return {
|
|
2893
3819
|
get hex6() {
|
|
2894
3820
|
return hex6;
|
|
@@ -2920,6 +3846,10 @@ var COLOR_CSS = `
|
|
|
2920
3846
|
`;
|
|
2921
3847
|
|
|
2922
3848
|
// src/ui/components/color-picker/view.ts
|
|
3849
|
+
var TEXT3 = {
|
|
3850
|
+
opacity: msg("ui.colorPicker.opacity", "Opacity"),
|
|
3851
|
+
opacityPercent: msg("ui.colorPicker.opacityPercent", "Opacity (%)")
|
|
3852
|
+
};
|
|
2923
3853
|
var PALETTE = buildPalette();
|
|
2924
3854
|
var CHECKER = transparencyChecker(10);
|
|
2925
3855
|
var FIELD_CHECKER = transparencyChecker(8);
|
|
@@ -2932,9 +3862,10 @@ function addRecent(hex6) {
|
|
|
2932
3862
|
}
|
|
2933
3863
|
function buildColorPicker(color, theme, onChange, options = {}) {
|
|
2934
3864
|
const commit = options.commit ?? "live";
|
|
2935
|
-
const
|
|
2936
|
-
|
|
2937
|
-
let
|
|
3865
|
+
const i18n = options.i18n ?? kitTranslator();
|
|
3866
|
+
const parsed2 = splitColor(color);
|
|
3867
|
+
let curHex = parsed2.hex6;
|
|
3868
|
+
let curAlpha = parsed2.alpha;
|
|
2938
3869
|
const root = document.createElement("div");
|
|
2939
3870
|
root.style.cssText = "display:flex;flex-direction:column;gap:9px;width:236px;";
|
|
2940
3871
|
const grid = document.createElement("div");
|
|
@@ -2992,7 +3923,7 @@ function buildColorPicker(color, theme, onChange, options = {}) {
|
|
|
2992
3923
|
}
|
|
2993
3924
|
};
|
|
2994
3925
|
const opLabel = document.createElement("div");
|
|
2995
|
-
opLabel.textContent =
|
|
3926
|
+
opLabel.textContent = textOf(i18n, TEXT3.opacity);
|
|
2996
3927
|
opLabel.style.cssText = `font:11px ${theme.fontFamily};color:var(--vela-fg-muted);`;
|
|
2997
3928
|
const opRow = document.createElement("div");
|
|
2998
3929
|
opRow.style.cssText = "display:flex;align-items:center;gap:10px;";
|
|
@@ -3004,7 +3935,7 @@ function buildColorPicker(color, theme, onChange, options = {}) {
|
|
|
3004
3935
|
const pctBox = document.createElement("input");
|
|
3005
3936
|
pctBox.type = "text";
|
|
3006
3937
|
pctBox.inputMode = "numeric";
|
|
3007
|
-
pctBox.title =
|
|
3938
|
+
pctBox.title = textOf(i18n, TEXT3.opacityPercent);
|
|
3008
3939
|
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;`;
|
|
3009
3940
|
pctBox.addEventListener("focus", () => {
|
|
3010
3941
|
pctBox.style.borderColor = "var(--vela-border-strong)";
|
|
@@ -3099,6 +4030,7 @@ var ColorField = class {
|
|
|
3099
4030
|
this.onVal = opts.onVal;
|
|
3100
4031
|
this.popoverOpts = opts.popover;
|
|
3101
4032
|
this.commit = opts.commit;
|
|
4033
|
+
this.i18n = opts.i18n ?? kitTranslator();
|
|
3102
4034
|
const trigger = document.createElement("button");
|
|
3103
4035
|
trigger.type = "button";
|
|
3104
4036
|
if (opts.id) trigger.id = opts.id;
|
|
@@ -3145,7 +4077,7 @@ var ColorField = class {
|
|
|
3145
4077
|
this.onVal(val);
|
|
3146
4078
|
this.paint();
|
|
3147
4079
|
},
|
|
3148
|
-
{ commit: this.commit }
|
|
4080
|
+
{ commit: this.commit, i18n: this.i18n }
|
|
3149
4081
|
)
|
|
3150
4082
|
});
|
|
3151
4083
|
pop.show();
|
|
@@ -3477,7 +4409,7 @@ var FIELD_CSS = `
|
|
|
3477
4409
|
font-size: 14px;
|
|
3478
4410
|
}
|
|
3479
4411
|
.vela-field-label[data-size='sm'] { font-size: inherit; opacity: 0.85; }
|
|
3480
|
-
/* Titles are fully inert: spans, not label[for]
|
|
4412
|
+
/* Titles are fully inert: spans, not label[for] — native labels propagate :hover and
|
|
3481
4413
|
clicks onto their control, and both belong to the input alone. */
|
|
3482
4414
|
.vela-field-cell { display: flex; align-items: center; gap: 8px; justify-self: start; }
|
|
3483
4415
|
.vela-field-bool { display: flex; align-items: center; gap: 8px; min-height: 22px; }
|
|
@@ -3817,7 +4749,7 @@ var CALLOUT_CSS = `
|
|
|
3817
4749
|
}
|
|
3818
4750
|
.vela-callout[role='button'] { cursor: pointer; }
|
|
3819
4751
|
.vela-callout svg { display: block; }
|
|
3820
|
-
/* The deployed panel
|
|
4752
|
+
/* The deployed panel — carries the kit's elevated-card look itself (the popover
|
|
3821
4753
|
shell is bare positioning chrome). */
|
|
3822
4754
|
.vela-callout-panel {
|
|
3823
4755
|
display: flex;
|
|
@@ -3974,9 +4906,14 @@ var CalloutBubble = class {
|
|
|
3974
4906
|
};
|
|
3975
4907
|
|
|
3976
4908
|
// src/ui/components/date-picker/controller.ts
|
|
3977
|
-
var
|
|
3978
|
-
|
|
3979
|
-
|
|
4909
|
+
var NAV = {
|
|
4910
|
+
prevMonth: msg("ui.datePicker.previousMonth", "Previous month"),
|
|
4911
|
+
nextMonth: msg("ui.datePicker.nextMonth", "Next month"),
|
|
4912
|
+
prevYear: msg("ui.datePicker.previousYear", "Previous year"),
|
|
4913
|
+
nextYear: msg("ui.datePicker.nextYear", "Next year"),
|
|
4914
|
+
prevDecade: msg("ui.datePicker.previousDecade", "Previous decade"),
|
|
4915
|
+
nextDecade: msg("ui.datePicker.nextDecade", "Next decade")
|
|
4916
|
+
};
|
|
3980
4917
|
function isoDate(d) {
|
|
3981
4918
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
3982
4919
|
}
|
|
@@ -4002,6 +4939,12 @@ function datePickerController(opts = {}) {
|
|
|
4002
4939
|
let year = selected?.getFullYear() ?? today.getFullYear();
|
|
4003
4940
|
let month = selected?.getMonth() ?? today.getMonth();
|
|
4004
4941
|
let panel = "date";
|
|
4942
|
+
const i18n = opts.i18n ?? englishTranslator();
|
|
4943
|
+
const settings = formatSettingsOf(i18n);
|
|
4944
|
+
const weekStart = opts.i18n ? i18n.weekStart : 0;
|
|
4945
|
+
const monthsLong = monthNames(settings, "long");
|
|
4946
|
+
const monthsShort = monthNames(settings, "short");
|
|
4947
|
+
const num = (n) => plainInteger(settings, n);
|
|
4005
4948
|
const decade = () => Math.floor(year / 10) * 10;
|
|
4006
4949
|
return {
|
|
4007
4950
|
get panel() {
|
|
@@ -4016,38 +4959,43 @@ function datePickerController(opts = {}) {
|
|
|
4016
4959
|
get value() {
|
|
4017
4960
|
return selected ? isoDate(selected) : null;
|
|
4018
4961
|
},
|
|
4962
|
+
yearFirst: yearBeforeMonth(settings),
|
|
4963
|
+
weekdays() {
|
|
4964
|
+
const names = weekdayNames(settings);
|
|
4965
|
+
return Array.from({ length: 7 }, (_, i) => names[(weekStart + i) % 7]);
|
|
4966
|
+
},
|
|
4019
4967
|
header() {
|
|
4020
4968
|
return {
|
|
4021
|
-
month:
|
|
4969
|
+
month: monthsLong[month] ?? "",
|
|
4022
4970
|
monthVisible: panel === "date",
|
|
4023
|
-
year: panel === "year" ? `${decade()}-${decade() + 9}` :
|
|
4971
|
+
year: panel === "year" ? `${num(decade())}-${num(decade() + 9)}` : yearLabel(settings, year),
|
|
4024
4972
|
yearDisabled: panel === "year"
|
|
4025
4973
|
// in the decade panel the year reads as its title
|
|
4026
4974
|
};
|
|
4027
4975
|
},
|
|
4028
4976
|
navLabels() {
|
|
4029
|
-
if (panel === "date") return { prev:
|
|
4030
|
-
if (panel === "month") return { prev:
|
|
4031
|
-
return { prev:
|
|
4977
|
+
if (panel === "date") return { prev: i18n.t(NAV.prevMonth), next: i18n.t(NAV.nextMonth) };
|
|
4978
|
+
if (panel === "month") return { prev: i18n.t(NAV.prevYear), next: i18n.t(NAV.nextYear) };
|
|
4979
|
+
return { prev: i18n.t(NAV.prevDecade), next: i18n.t(NAV.nextDecade) };
|
|
4032
4980
|
},
|
|
4033
4981
|
cells() {
|
|
4034
4982
|
const out = [];
|
|
4035
4983
|
if (panel === "date") {
|
|
4036
|
-
const startPad = new Date(year, month, 1).getDay();
|
|
4984
|
+
const startPad = (new Date(year, month, 1).getDay() - weekStart + 7) % 7;
|
|
4037
4985
|
const days = new Date(year, month + 1, 0).getDate();
|
|
4038
4986
|
const todayIso = isoDate(today);
|
|
4039
4987
|
const selectedIso = selected ? isoDate(selected) : "";
|
|
4040
4988
|
for (let i = 0; i < startPad; i++) out.push({ label: "", value: "", checked: false, today: false, blank: true });
|
|
4041
4989
|
for (let day = 1; day <= days; day++) {
|
|
4042
4990
|
const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
4043
|
-
out.push({ label:
|
|
4991
|
+
out.push({ label: num(day), value: iso, checked: iso === selectedIso, today: iso === todayIso });
|
|
4044
4992
|
}
|
|
4045
4993
|
return out;
|
|
4046
4994
|
}
|
|
4047
4995
|
if (panel === "month") {
|
|
4048
4996
|
for (let m = 0; m < 12; m++) {
|
|
4049
4997
|
out.push({
|
|
4050
|
-
label:
|
|
4998
|
+
label: monthsShort[m] ?? "",
|
|
4051
4999
|
value: m,
|
|
4052
5000
|
checked: selected?.getFullYear() === year && selected.getMonth() === m,
|
|
4053
5001
|
today: today.getFullYear() === year && today.getMonth() === m
|
|
@@ -4057,7 +5005,7 @@ function datePickerController(opts = {}) {
|
|
|
4057
5005
|
}
|
|
4058
5006
|
const d = decade();
|
|
4059
5007
|
for (let y = d - 1; y <= d + 10; y++) {
|
|
4060
|
-
out.push({ label:
|
|
5008
|
+
out.push({ label: num(y), value: y, checked: selected?.getFullYear() === y, today: today.getFullYear() === y, outside: y < d || y > d + 9 });
|
|
4061
5009
|
}
|
|
4062
5010
|
return out;
|
|
4063
5011
|
},
|
|
@@ -4137,6 +5085,8 @@ var DATE_PICKER_CSS = `
|
|
|
4137
5085
|
`;
|
|
4138
5086
|
|
|
4139
5087
|
// src/ui/components/date-picker/view.ts
|
|
5088
|
+
var CHOOSE_MONTH = msg("ui.datePicker.chooseMonth", "Choose month");
|
|
5089
|
+
var CHOOSE_YEAR = msg("ui.datePicker.chooseYear", "Choose year");
|
|
4140
5090
|
var DatePicker = class {
|
|
4141
5091
|
constructor(opts = {}) {
|
|
4142
5092
|
this.opts = opts;
|
|
@@ -4153,19 +5103,21 @@ var DatePicker = class {
|
|
|
4153
5103
|
this.prev.append(iconEl("chevron-left", doc));
|
|
4154
5104
|
this.next = button("vela-date-picker-nav");
|
|
4155
5105
|
this.next.append(iconEl("chevron-right", doc));
|
|
5106
|
+
const i18n = opts.i18n ?? englishTranslator();
|
|
4156
5107
|
this.monthBtn = button("vela-date-picker-switch");
|
|
4157
|
-
this.monthBtn.setAttribute("aria-label",
|
|
5108
|
+
this.monthBtn.setAttribute("aria-label", i18n.t(CHOOSE_MONTH));
|
|
4158
5109
|
this.yearBtn = button("vela-date-picker-switch");
|
|
4159
|
-
this.yearBtn.setAttribute("aria-label",
|
|
5110
|
+
this.yearBtn.setAttribute("aria-label", i18n.t(CHOOSE_YEAR));
|
|
4160
5111
|
const title = doc.createElement("div");
|
|
4161
5112
|
title.className = "vela-date-picker-title";
|
|
4162
|
-
title.append(this.
|
|
5113
|
+
if (this.ctrl.yearFirst) title.append(this.yearBtn, this.monthBtn);
|
|
5114
|
+
else title.append(this.monthBtn, this.yearBtn);
|
|
4163
5115
|
const head = doc.createElement("div");
|
|
4164
5116
|
head.className = "vela-date-picker-head";
|
|
4165
5117
|
head.append(this.prev, title, this.next);
|
|
4166
5118
|
this.week = doc.createElement("div");
|
|
4167
5119
|
this.week.className = "vela-date-picker-week";
|
|
4168
|
-
for (const d of
|
|
5120
|
+
for (const d of this.ctrl.weekdays()) {
|
|
4169
5121
|
const cell = doc.createElement("span");
|
|
4170
5122
|
cell.textContent = d;
|
|
4171
5123
|
this.week.appendChild(cell);
|