@luxalgo/vela 0.8.2 → 0.8.3
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-DpOWZD8F.d.ts → DataProvider-oH78tYXL.d.ts} +1 -1
- package/dist/{DataProvider-COGDs9Xg.d.cts → DataProvider-wbtJ3-Sa.d.cts} +1 -1
- package/dist/{chunk-R2JMNIHY.js → chunk-2IPXYM4B.js} +258 -169
- package/dist/{chunk-NLDTVFOI.js → chunk-G7B7ZCBF.js} +129 -10
- package/dist/{chunk-T3DZIR5Y.js → chunk-HMHA733L.js} +306 -168
- package/dist/{chunk-DPAA3SRT.js → chunk-KWI3YDBW.js} +254 -9
- package/dist/{chunk-27UTYE7T.js → chunk-TO3GIK7Z.js} +49 -7
- package/dist/{chunk-HKNO24GD.js → chunk-VHGACEHO.js} +50 -1
- package/dist/{contributions-Cgm9RJYP.d.cts → contributions-BhOBRenr.d.cts} +44 -4
- package/dist/{contributions-bWgwyiVi.d.ts → contributions-HGqnNb_P.d.ts} +44 -4
- package/dist/index.cjs +497 -79
- package/dist/index.d.cts +34 -14
- package/dist/index.d.ts +34 -14
- package/dist/index.js +5 -5
- package/dist/{options-NAUHiQEC.d.ts → options-lMUwmRwh.d.cts} +66 -1
- package/dist/{options-NAUHiQEC.d.cts → options-lMUwmRwh.d.ts} +66 -1
- package/dist/{plugin-CqxWoDKS.d.ts → plugin-Cr2Pj8q8.d.ts} +4 -4
- package/dist/{plugin-CjjzZX2F.d.cts → plugin-Do5J5xuF.d.cts} +4 -4
- package/dist/plugin.cjs +18 -0
- package/dist/plugin.d.cts +5 -5
- package/dist/plugin.d.ts +5 -5
- package/dist/plugin.js +3 -3
- package/dist/providers/binance.d.cts +2 -2
- package/dist/providers/binance.d.ts +2 -2
- package/dist/providers/coinbase.d.cts +2 -2
- package/dist/providers/coinbase.d.ts +2 -2
- package/dist/providers/hyperliquid.d.cts +2 -2
- package/dist/providers/hyperliquid.d.ts +2 -2
- package/dist/{side-panel-wMNfgyZb.d.cts → side-panel-_2UK1gSm.d.cts} +45 -3
- package/dist/{side-panel-wMNfgyZb.d.ts → side-panel-_2UK1gSm.d.ts} +45 -3
- package/dist/{statusline-model-Dpfpq54A.d.cts → statusline-model-B-2xGlB_.d.cts} +3 -3
- package/dist/{statusline-model-Dih6FGWP.d.ts → statusline-model-CY1wzxHg.d.ts} +3 -3
- package/dist/ui.cjs +224 -14
- package/dist/ui.d.cts +119 -87
- package/dist/ui.d.ts +119 -87
- package/dist/ui.js +3 -3
- package/dist/vela.global.js +497 -79
- package/dist/vela.global.min.js +86 -52
- package/dist/widget.cjs +850 -167
- package/dist/widget.d.cts +24 -10
- package/dist/widget.d.ts +24 -10
- package/dist/widget.js +7 -7
- package/dist/workspace.cjs +849 -167
- package/dist/workspace.d.cts +47 -20
- package/dist/workspace.d.ts +47 -20
- package/dist/workspace.js +6 -6
- package/package.json +1 -1
- /package/dist/{chunk-JU4CWEBF.js → chunk-W5YPYZ2P.js} +0 -0
package/dist/ui.cjs
CHANGED
|
@@ -644,6 +644,55 @@ var Tooltip = class {
|
|
|
644
644
|
this.trigger.removeAttribute("data-scope");
|
|
645
645
|
}
|
|
646
646
|
};
|
|
647
|
+
|
|
648
|
+
// src/ui/surface-exit.ts
|
|
649
|
+
var CLOSING_ATTR = "data-closing";
|
|
650
|
+
var SURFACE_EXIT_CAP_MS = 1e3;
|
|
651
|
+
function animationsOf(els) {
|
|
652
|
+
return els.flatMap((el) => el.getAnimations({ subtree: true }));
|
|
653
|
+
}
|
|
654
|
+
function ends(a) {
|
|
655
|
+
return Number.isFinite(a.effect?.getComputedTiming().endTime ?? Number.POSITIVE_INFINITY);
|
|
656
|
+
}
|
|
657
|
+
function holdForExit(els, done, opts = {}) {
|
|
658
|
+
const list = Array.isArray(els) ? els : [els];
|
|
659
|
+
if (list.length === 0 || !list.every((el) => typeof el.getAnimations === "function")) {
|
|
660
|
+
done();
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
const before = new Set(animationsOf(list));
|
|
664
|
+
for (const el of list) el.setAttribute(CLOSING_ATTR, "");
|
|
665
|
+
const exit = animationsOf(list).filter((a) => !before.has(a) && ends(a));
|
|
666
|
+
if (exit.length === 0) {
|
|
667
|
+
for (const el of list) el.removeAttribute(CLOSING_ATTR);
|
|
668
|
+
done();
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
const frozen = [...list, ...opts.inert ?? []];
|
|
672
|
+
const wasInert = frozen.map((el) => el.inert);
|
|
673
|
+
for (const el of frozen) el.inert = true;
|
|
674
|
+
let settled = false;
|
|
675
|
+
const settle = (complete) => {
|
|
676
|
+
if (settled) return;
|
|
677
|
+
settled = true;
|
|
678
|
+
clearTimeout(cap);
|
|
679
|
+
for (const el of list) el.removeAttribute(CLOSING_ATTR);
|
|
680
|
+
frozen.forEach((el, i) => {
|
|
681
|
+
el.inert = wasInert[i];
|
|
682
|
+
});
|
|
683
|
+
if (complete) done();
|
|
684
|
+
};
|
|
685
|
+
const cap = setTimeout(() => settle(true), SURFACE_EXIT_CAP_MS);
|
|
686
|
+
let pending = exit.length;
|
|
687
|
+
const one = () => {
|
|
688
|
+
if (--pending === 0) settle(true);
|
|
689
|
+
};
|
|
690
|
+
for (const a of exit) a.finished.then(one, one);
|
|
691
|
+
return {
|
|
692
|
+
cancel: () => settle(false),
|
|
693
|
+
finish: () => settle(true)
|
|
694
|
+
};
|
|
695
|
+
}
|
|
647
696
|
function menuController(opts) {
|
|
648
697
|
return {
|
|
649
698
|
machine: menu__namespace.machine,
|
|
@@ -725,6 +774,35 @@ var MENU_CSS = `
|
|
|
725
774
|
color: var(--vela-fg-bright);
|
|
726
775
|
}
|
|
727
776
|
.vela-menu-item[data-checkmark] { color: var(--vela-fg-bright); }
|
|
777
|
+
/* Badge mode (iconBadges): the row icon sits in a rounded tile and the row grows to fit
|
|
778
|
+
it. An icon-less row of the same level keeps an invisible slot, so labels align. */
|
|
779
|
+
.vela-menu[data-badges] > .vela-menu-item { padding: 5px 10px 5px 6px; }
|
|
780
|
+
.vela-menu-item .vela-menu-badge {
|
|
781
|
+
width: 24px;
|
|
782
|
+
height: 24px;
|
|
783
|
+
padding: 3px;
|
|
784
|
+
flex: none;
|
|
785
|
+
box-sizing: border-box;
|
|
786
|
+
display: inline-flex;
|
|
787
|
+
align-items: center;
|
|
788
|
+
justify-content: center;
|
|
789
|
+
border-radius: var(--vela-radius-md);
|
|
790
|
+
background: var(--vela-hover);
|
|
791
|
+
border: 1px solid var(--vela-border);
|
|
792
|
+
color: var(--vela-fg-muted);
|
|
793
|
+
transition: background var(--vela-dur-fast) var(--vela-ease), border-color var(--vela-dur-fast) var(--vela-ease), color var(--vela-dur-fast) var(--vela-ease);
|
|
794
|
+
}
|
|
795
|
+
.vela-menu-item .vela-menu-badge:empty { background: transparent; border-color: transparent; }
|
|
796
|
+
.vela-menu-item .vela-menu-badge .vela-icon { color: inherit; }
|
|
797
|
+
.vela-menu-item[data-highlighted] .vela-menu-badge:not(:empty) { color: var(--vela-fg-bright); }
|
|
798
|
+
/* The selected tile inverts: a bright fill under the surface-colored glyph. After the
|
|
799
|
+
hover rule, so a selected row keeps its tile while highlighted. */
|
|
800
|
+
.vela-menu-item[data-checked] .vela-menu-badge:not(:empty),
|
|
801
|
+
.vela-menu-item[data-checkmark] .vela-menu-badge:not(:empty) {
|
|
802
|
+
background: color-mix(in srgb, var(--vela-fg-bright) 83%, var(--vela-surface));
|
|
803
|
+
border-color: color-mix(in srgb, var(--vela-fg-bright) 40%, transparent);
|
|
804
|
+
color: var(--vela-surface);
|
|
805
|
+
}
|
|
728
806
|
/* Switch rows (boolean settings in a dropdown): a right-aligned toggle pill \u2014 the
|
|
729
807
|
same control language as the settings dialog's toggles. */
|
|
730
808
|
.vela-menu-switch {
|
|
@@ -791,11 +869,14 @@ var Surface = class _Surface {
|
|
|
791
869
|
this.pinnedAnchor = null;
|
|
792
870
|
/** The open state last announced — see {@link announce}. */
|
|
793
871
|
this.shown = false;
|
|
872
|
+
/** The list's exit animation after a close; a reopen cancels it. */
|
|
873
|
+
this.exit = null;
|
|
794
874
|
this.doc = doc;
|
|
795
875
|
this.host = opts.host;
|
|
796
876
|
this.onSelect = opts.onSelect;
|
|
797
877
|
this.onFavorite = opts.onFavorite;
|
|
798
878
|
this.checkmarks = opts.checkmarks === true;
|
|
879
|
+
this.iconBadges = opts.iconBadges === true;
|
|
799
880
|
this.positioner = doc.createElement("div");
|
|
800
881
|
this.positioner.className = "vela-ui-layer";
|
|
801
882
|
this.list = doc.createElement("ul");
|
|
@@ -826,14 +907,30 @@ var Surface = class _Surface {
|
|
|
826
907
|
if (opts.triggerId && trigger) trigger.id = opts.triggerId;
|
|
827
908
|
this.handle = runMachine(this.ctrl.machine, this.ctrl.props, (service) => {
|
|
828
909
|
const api = this.ctrl.connect(service);
|
|
829
|
-
|
|
910
|
+
const closing = this.shown && !api.open;
|
|
911
|
+
if (closing) this.announce(false);
|
|
912
|
+
if (api.open && this.exit) {
|
|
913
|
+
this.exit.cancel();
|
|
914
|
+
this.exit = null;
|
|
915
|
+
}
|
|
830
916
|
if (trigger) vanilla.spreadProps(trigger, api.getTriggerProps(), this.mid);
|
|
831
917
|
vanilla.spreadProps(this.positioner, api.getPositionerProps(), this.mid);
|
|
832
918
|
vanilla.spreadProps(this.list, api.getContentProps(), this.mid);
|
|
833
919
|
this.project(api);
|
|
920
|
+
if (closing) this.holdExit();
|
|
834
921
|
if (api.open && !this.shown) this.announce(true);
|
|
835
922
|
});
|
|
836
923
|
}
|
|
924
|
+
/** Keep the just-closed list up through its exit animation. `spreadProps` re-applies
|
|
925
|
+
* `hidden` only when the machine's value for it changes, so the list stays shown until
|
|
926
|
+
* the exit ends — or until a reopen, which projects `hidden: false` itself. */
|
|
927
|
+
holdExit() {
|
|
928
|
+
this.list.hidden = false;
|
|
929
|
+
this.exit = holdForExit(this.list, () => {
|
|
930
|
+
this.exit = null;
|
|
931
|
+
if (!this.shown) this.list.hidden = true;
|
|
932
|
+
});
|
|
933
|
+
}
|
|
837
934
|
get api() {
|
|
838
935
|
return this.ctrl.connect(this.handle.service);
|
|
839
936
|
}
|
|
@@ -857,6 +954,7 @@ var Surface = class _Surface {
|
|
|
857
954
|
destroy() {
|
|
858
955
|
for (const sub of this.subs.values()) sub.destroy();
|
|
859
956
|
this.subs.clear();
|
|
957
|
+
this.exit?.finish();
|
|
860
958
|
this.handle.stop();
|
|
861
959
|
if (this.shown) this.announce(false);
|
|
862
960
|
this.positioner.remove();
|
|
@@ -883,6 +981,10 @@ var Surface = class _Surface {
|
|
|
883
981
|
const doc = this.doc;
|
|
884
982
|
this.list.replaceChildren();
|
|
885
983
|
const markable = this.checkmarks && this.items.some((i) => !(i.submenu && i.submenu.length > 0) && !i.toggle && i.checked !== void 0);
|
|
984
|
+
const iconic = this.items.some((i) => !!i.icon);
|
|
985
|
+
const badged = this.iconBadges && iconic;
|
|
986
|
+
if (badged) this.list.dataset.badges = "1";
|
|
987
|
+
else delete this.list.dataset.badges;
|
|
886
988
|
for (const item of this.items) {
|
|
887
989
|
if (item.separatorBefore) {
|
|
888
990
|
const sep = doc.createElement("li");
|
|
@@ -908,7 +1010,16 @@ var Surface = class _Surface {
|
|
|
908
1010
|
} else if (!branch && !item.toggle && item.checked) {
|
|
909
1011
|
li.dataset.checked = "1";
|
|
910
1012
|
}
|
|
911
|
-
if (
|
|
1013
|
+
if (badged) {
|
|
1014
|
+
const badge = doc.createElement("span");
|
|
1015
|
+
badge.className = "vela-menu-badge";
|
|
1016
|
+
if (item.icon) badge.appendChild(iconEl(item.icon, doc));
|
|
1017
|
+
li.appendChild(badge);
|
|
1018
|
+
} else if (item.icon) {
|
|
1019
|
+
li.appendChild(iconEl(item.icon, doc));
|
|
1020
|
+
} else if (iconic) {
|
|
1021
|
+
li.appendChild(iconEl("", doc));
|
|
1022
|
+
}
|
|
912
1023
|
const label = doc.createElement("span");
|
|
913
1024
|
label.className = "vela-menu-label";
|
|
914
1025
|
label.textContent = item.label;
|
|
@@ -956,6 +1067,7 @@ var Surface = class _Surface {
|
|
|
956
1067
|
onSelect: this.onSelect,
|
|
957
1068
|
onFavorite: this.onFavorite,
|
|
958
1069
|
checkmarks: this.checkmarks,
|
|
1070
|
+
iconBadges: this.iconBadges,
|
|
959
1071
|
id: `${this.mid}--${item.id}`
|
|
960
1072
|
});
|
|
961
1073
|
sub.setItems(item.submenu ?? []);
|
|
@@ -981,7 +1093,8 @@ var Menu = class {
|
|
|
981
1093
|
id: opts.id,
|
|
982
1094
|
minWidth: opts.minWidth,
|
|
983
1095
|
onFavorite: opts.onFavorite,
|
|
984
|
-
checkmarks: opts.checkmarks
|
|
1096
|
+
checkmarks: opts.checkmarks,
|
|
1097
|
+
iconBadges: opts.iconBadges
|
|
985
1098
|
});
|
|
986
1099
|
this.root.setItems(opts.items);
|
|
987
1100
|
}
|
|
@@ -1085,6 +1198,7 @@ var POPOVER_CSS = `
|
|
|
1085
1198
|
|
|
1086
1199
|
// src/ui/components/popover/view.ts
|
|
1087
1200
|
var open = null;
|
|
1201
|
+
var leaving = /* @__PURE__ */ new Set();
|
|
1088
1202
|
function closeOpenPopovers() {
|
|
1089
1203
|
open?.hide();
|
|
1090
1204
|
}
|
|
@@ -1112,6 +1226,8 @@ var Popover = class {
|
|
|
1112
1226
|
this.shown = false;
|
|
1113
1227
|
/** The pending removal of a fading-out shell; a show() that reuses the shell cancels it. */
|
|
1114
1228
|
this.leaveTimer = null;
|
|
1229
|
+
/** The shell's exit animation before it leaves the DOM; a show() that reuses the shell cancels it. */
|
|
1230
|
+
this.exit = null;
|
|
1115
1231
|
const doc = opts.trigger.ownerDocument;
|
|
1116
1232
|
injectStyles(POPOVER_STYLE_ID, POPOVER_CSS, doc);
|
|
1117
1233
|
this.trigger = opts.trigger;
|
|
@@ -1148,6 +1264,10 @@ var Popover = class {
|
|
|
1148
1264
|
clearTimeout(this.leaveTimer);
|
|
1149
1265
|
this.leaveTimer = null;
|
|
1150
1266
|
}
|
|
1267
|
+
this.exit?.cancel();
|
|
1268
|
+
this.exit = null;
|
|
1269
|
+
leaving.delete(this);
|
|
1270
|
+
for (const p of [...leaving]) if (p.trigger === this.trigger) p.exit?.finish();
|
|
1151
1271
|
ensureUIHost(this.el, this.inheritsTokens ? void 0 : this.theme);
|
|
1152
1272
|
if (this.fadeMs > 0) {
|
|
1153
1273
|
this.el.style.transition = `opacity ${this.fadeMs}ms ease`;
|
|
@@ -1204,7 +1324,12 @@ var Popover = class {
|
|
|
1204
1324
|
this.el.remove();
|
|
1205
1325
|
}, this.fadeMs);
|
|
1206
1326
|
} else {
|
|
1207
|
-
this.el
|
|
1327
|
+
this.exit = holdForExit(this.el, () => {
|
|
1328
|
+
this.exit = null;
|
|
1329
|
+
leaving.delete(this);
|
|
1330
|
+
this.el.remove();
|
|
1331
|
+
});
|
|
1332
|
+
if (this.exit) leaving.add(this);
|
|
1208
1333
|
}
|
|
1209
1334
|
if (open === this) open = null;
|
|
1210
1335
|
this.ctrl.onClose?.();
|
|
@@ -1216,6 +1341,7 @@ var Popover = class {
|
|
|
1216
1341
|
}
|
|
1217
1342
|
destroy() {
|
|
1218
1343
|
this.hide();
|
|
1344
|
+
this.exit?.finish();
|
|
1219
1345
|
}
|
|
1220
1346
|
reposition() {
|
|
1221
1347
|
if (this.shown) this.place();
|
|
@@ -1413,6 +1539,9 @@ var Dialog = class {
|
|
|
1413
1539
|
constructor(opts = {}) {
|
|
1414
1540
|
this.opener = null;
|
|
1415
1541
|
this.wasOpen = false;
|
|
1542
|
+
/** The panel and scrim's exit animation after a close; a reopen cancels it. */
|
|
1543
|
+
this.exit = null;
|
|
1544
|
+
this.destroyed = false;
|
|
1416
1545
|
const doc = (opts.host ?? document.body).ownerDocument;
|
|
1417
1546
|
injectStyles(DIALOG_STYLE_ID, DIALOG_CSS, doc);
|
|
1418
1547
|
const host = opts.host ?? doc.body;
|
|
@@ -1509,19 +1638,57 @@ var Dialog = class {
|
|
|
1509
1638
|
const mid = String(this.ctrl.props.id);
|
|
1510
1639
|
this.handle = runMachine(this.ctrl.machine, this.ctrl.props, (service) => {
|
|
1511
1640
|
const api = this.ctrl.connect(service);
|
|
1512
|
-
|
|
1641
|
+
const closing = this.wasOpen && !api.open;
|
|
1642
|
+
if (closing) this.announce(false);
|
|
1513
1643
|
vanilla.spreadProps(this.backdrop, api.getBackdropProps(), mid);
|
|
1514
1644
|
vanilla.spreadProps(this.positioner, api.getPositionerProps(), mid);
|
|
1515
1645
|
vanilla.spreadProps(this.panel, api.getContentProps(), mid);
|
|
1516
1646
|
vanilla.spreadProps(title, api.getTitleProps(), mid);
|
|
1517
1647
|
vanilla.spreadProps(close, api.getCloseTriggerProps(), mid);
|
|
1518
|
-
|
|
1519
|
-
|
|
1648
|
+
if (api.open) {
|
|
1649
|
+
this.exit?.cancel();
|
|
1650
|
+
this.exit = null;
|
|
1651
|
+
this.setShown(true);
|
|
1652
|
+
} else if (closing) {
|
|
1653
|
+
this.holdExit();
|
|
1654
|
+
} else if (!this.exit) {
|
|
1655
|
+
this.setShown(false);
|
|
1656
|
+
}
|
|
1520
1657
|
if (api.open && !this.wasOpen) this.announce(true);
|
|
1521
1658
|
if (this.wasOpen && !api.open) this.restoreOpener();
|
|
1522
1659
|
this.wasOpen = api.open;
|
|
1523
1660
|
});
|
|
1524
1661
|
}
|
|
1662
|
+
setShown(shown) {
|
|
1663
|
+
this.backdrop.style.display = shown ? "" : "none";
|
|
1664
|
+
this.positioner.style.display = shown ? "" : "none";
|
|
1665
|
+
}
|
|
1666
|
+
/** Keep the just-closed dialog up through its exit animation, then hide it — or
|
|
1667
|
+
* remove it, when it was destroyed meanwhile. `spreadProps` re-applies the close
|
|
1668
|
+
* props' `hidden` only when its value changes, so lifting it keeps the panel and
|
|
1669
|
+
* scrim up until the exit ends. The positioner spans the viewport: inert, it lets
|
|
1670
|
+
* clicks through to the page while the panel animates out. */
|
|
1671
|
+
holdExit() {
|
|
1672
|
+
const held = [this.panel, this.backdrop];
|
|
1673
|
+
for (const el of held) el.hidden = false;
|
|
1674
|
+
this.exit = holdForExit(
|
|
1675
|
+
held,
|
|
1676
|
+
() => {
|
|
1677
|
+
this.exit = null;
|
|
1678
|
+
if (this.destroyed) {
|
|
1679
|
+
this.detach();
|
|
1680
|
+
} else if (!this.open) {
|
|
1681
|
+
for (const el of held) el.hidden = true;
|
|
1682
|
+
this.setShown(false);
|
|
1683
|
+
}
|
|
1684
|
+
},
|
|
1685
|
+
{ inert: [this.positioner] }
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
detach() {
|
|
1689
|
+
this.backdrop.remove();
|
|
1690
|
+
this.positioner.remove();
|
|
1691
|
+
}
|
|
1525
1692
|
/** Closing hands focus back to whatever opened it (Escape, the ✕, hide(), or a
|
|
1526
1693
|
* teardown that outruns the machine's close notification). */
|
|
1527
1694
|
restoreOpener() {
|
|
@@ -1550,15 +1717,16 @@ var Dialog = class {
|
|
|
1550
1717
|
return el?.closest(".vela-popover, .vela-menu") != null;
|
|
1551
1718
|
}
|
|
1552
1719
|
destroy() {
|
|
1720
|
+
if (this.wasOpen && !this.open) this.handle.flush();
|
|
1553
1721
|
if (this.open) this.hide();
|
|
1554
1722
|
this.handle.stop();
|
|
1723
|
+
this.destroyed = true;
|
|
1555
1724
|
if (this.wasOpen) {
|
|
1556
1725
|
this.wasOpen = false;
|
|
1557
1726
|
this.announce(false);
|
|
1558
1727
|
}
|
|
1559
1728
|
this.restoreOpener();
|
|
1560
|
-
this.
|
|
1561
|
-
this.positioner.remove();
|
|
1729
|
+
if (!this.exit) this.detach();
|
|
1562
1730
|
}
|
|
1563
1731
|
};
|
|
1564
1732
|
function drawerController(opts = {}) {
|
|
@@ -1687,6 +1855,9 @@ var Drawer = class {
|
|
|
1687
1855
|
constructor(opts = {}) {
|
|
1688
1856
|
this.opener = null;
|
|
1689
1857
|
this.wasOpen = false;
|
|
1858
|
+
/** The sheet and scrim's exit animation after a close; a reopen cancels it. */
|
|
1859
|
+
this.exit = null;
|
|
1860
|
+
this.destroyed = false;
|
|
1690
1861
|
const doc = (opts.host ?? document.body).ownerDocument;
|
|
1691
1862
|
injectStyles(DRAWER_STYLE_ID, DRAWER_CSS, doc);
|
|
1692
1863
|
const host = opts.host ?? doc.body;
|
|
@@ -1714,13 +1885,21 @@ var Drawer = class {
|
|
|
1714
1885
|
const mid = String(this.ctrl.props.id);
|
|
1715
1886
|
this.handle = runMachine(this.ctrl.machine, this.ctrl.props, (service) => {
|
|
1716
1887
|
const api = this.ctrl.connect(service);
|
|
1717
|
-
|
|
1888
|
+
const closing = this.wasOpen && !api.open;
|
|
1889
|
+
if (closing) this.announce(false);
|
|
1718
1890
|
vanilla.spreadProps(this.backdrop, api.getBackdropProps(), mid);
|
|
1719
1891
|
vanilla.spreadProps(this.positioner, api.getPositionerProps(), mid);
|
|
1720
1892
|
vanilla.spreadProps(this.panel, api.getContentProps(), mid);
|
|
1721
1893
|
vanilla.spreadProps(this.titleEl, api.getTitleProps(), mid);
|
|
1722
|
-
|
|
1723
|
-
|
|
1894
|
+
if (api.open) {
|
|
1895
|
+
this.exit?.cancel();
|
|
1896
|
+
this.exit = null;
|
|
1897
|
+
this.setShown(true);
|
|
1898
|
+
} else if (closing) {
|
|
1899
|
+
this.holdExit();
|
|
1900
|
+
} else if (!this.exit) {
|
|
1901
|
+
this.setShown(false);
|
|
1902
|
+
}
|
|
1724
1903
|
if (api.open && !this.wasOpen) this.announce(true);
|
|
1725
1904
|
if (this.wasOpen && !api.open) this.restoreOpener();
|
|
1726
1905
|
this.wasOpen = api.open;
|
|
@@ -1832,6 +2011,36 @@ var Drawer = class {
|
|
|
1832
2011
|
setTitle(title) {
|
|
1833
2012
|
this.titleEl.textContent = title;
|
|
1834
2013
|
}
|
|
2014
|
+
setShown(shown) {
|
|
2015
|
+
this.backdrop.style.display = shown ? "" : "none";
|
|
2016
|
+
this.positioner.style.display = shown ? "" : "none";
|
|
2017
|
+
}
|
|
2018
|
+
/** Keep the just-closed sheet up through its exit animation, then hide it — or
|
|
2019
|
+
* remove it, when it was destroyed meanwhile. `spreadProps` re-applies the close
|
|
2020
|
+
* props' `hidden` only when its value changes, so lifting it keeps the sheet and
|
|
2021
|
+
* scrim up until the exit ends. The positioner spans the host: inert, it lets
|
|
2022
|
+
* clicks through to the page while the sheet animates out. */
|
|
2023
|
+
holdExit() {
|
|
2024
|
+
const held = [this.panel, this.backdrop];
|
|
2025
|
+
for (const el of held) el.hidden = false;
|
|
2026
|
+
this.exit = holdForExit(
|
|
2027
|
+
held,
|
|
2028
|
+
() => {
|
|
2029
|
+
this.exit = null;
|
|
2030
|
+
if (this.destroyed) {
|
|
2031
|
+
this.detach();
|
|
2032
|
+
} else if (!this.open) {
|
|
2033
|
+
for (const el of held) el.hidden = true;
|
|
2034
|
+
this.setShown(false);
|
|
2035
|
+
}
|
|
2036
|
+
},
|
|
2037
|
+
{ inert: [this.positioner] }
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
detach() {
|
|
2041
|
+
this.backdrop.remove();
|
|
2042
|
+
this.positioner.remove();
|
|
2043
|
+
}
|
|
1835
2044
|
/** Closing hands focus back to whatever opened it (Escape, the ✕, hide(), or a
|
|
1836
2045
|
* teardown that outruns the machine's close notification). */
|
|
1837
2046
|
restoreOpener() {
|
|
@@ -1854,14 +2063,15 @@ var Drawer = class {
|
|
|
1854
2063
|
this.ctrl.connect(this.handle.service).setOpen(false);
|
|
1855
2064
|
}
|
|
1856
2065
|
destroy() {
|
|
2066
|
+
if (this.wasOpen && !this.open) this.handle.flush();
|
|
1857
2067
|
this.handle.stop();
|
|
2068
|
+
this.destroyed = true;
|
|
1858
2069
|
if (this.wasOpen) {
|
|
1859
2070
|
this.wasOpen = false;
|
|
1860
2071
|
this.announce(false);
|
|
1861
2072
|
}
|
|
1862
2073
|
this.restoreOpener();
|
|
1863
|
-
this.
|
|
1864
|
-
this.positioner.remove();
|
|
2074
|
+
if (!this.exit) this.detach();
|
|
1865
2075
|
}
|
|
1866
2076
|
};
|
|
1867
2077
|
|
package/dist/ui.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as VelaTheme } from './options-
|
|
1
|
+
import { c as VelaTheme } from './options-lMUwmRwh.cjs';
|
|
2
2
|
import { MachineSchema, Service, Machine } from '@zag-js/core';
|
|
3
3
|
export { a as KeyBindingDescriptor, K as KeymapManager, b as KeymapOptions, R as ResolvedBinding } from './keymap-CGOz5F5f.cjs';
|
|
4
4
|
import * as tooltip from '@zag-js/tooltip';
|
|
@@ -11,91 +11,6 @@ export { normalizeProps, spreadProps } from '@zag-js/vanilla';
|
|
|
11
11
|
* returned unchanged so callers can pass through `transparent`, `currentColor`, etc. */
|
|
12
12
|
declare function withAlpha(color: string, alpha: number): string;
|
|
13
13
|
|
|
14
|
-
/** A ready-to-insert element rendering the icon (empty span when unknown). */
|
|
15
|
-
declare function iconEl(id: string, doc?: Document): HTMLElement;
|
|
16
|
-
|
|
17
|
-
/** Overlay scrollbar used by settings panes, dialog bodies, and similar chrome. */
|
|
18
|
-
declare function overlayScrollbarCss(selector: string, width?: number): string;
|
|
19
|
-
/** Focus ring shared by typeable fields (combo inputs, textareas). */
|
|
20
|
-
declare const FIELD_FOCUS_CSS = "outline:none;transition:border-color .12s ease,box-shadow .12s ease;";
|
|
21
|
-
declare const FIELD_FOCUS_RING = "border-color:var(--vela-focus);box-shadow:0 0 0 3px var(--vela-focus-soft);";
|
|
22
|
-
/** Inject a stylesheet once per root (document or shadow root). Idempotent by id. */
|
|
23
|
-
declare function injectStyles(id: string, css: string, root?: Document | ShadowRoot): void;
|
|
24
|
-
|
|
25
|
-
/** Write the theme-derived custom properties onto a host element (the widget root and
|
|
26
|
-
* every floating layer — menus/tooltips portal outside the root, so layers re-apply). */
|
|
27
|
-
declare function applyThemeTokens(el: HTMLElement, t: VelaTheme): void;
|
|
28
|
-
/** Re-token a chart-overlay host (statusline, watermark, toast — chrome floating OVER
|
|
29
|
-
* the plot) from the LIVE plot surface: a config edit can recolor the plot background
|
|
30
|
-
* independently of the app theme (a white plot typed into settings on the dark theme),
|
|
31
|
-
* and the overlay ink must stay readable either way. `config` is the renderer's
|
|
32
|
-
* `getConfig()` snapshot; a missing/shapeless one falls back to the base app theme.
|
|
33
|
-
* Floating menus and dropdowns do NOT use this — they mount on {@link floatingLayerHost}
|
|
34
|
-
* so their surface follows the app theme alone. */
|
|
35
|
-
declare function applyPlotOverlayTokens(host: HTMLElement, base: VelaTheme, config: unknown): void;
|
|
36
|
-
/** Mark an element as a kit host: static token sheet + the `.vela-ui` class. */
|
|
37
|
-
declare function ensureUIHost(el: HTMLElement, theme?: VelaTheme): void;
|
|
38
|
-
|
|
39
|
-
interface MachineHandle<T extends MachineSchema> {
|
|
40
|
-
service: Service<T>;
|
|
41
|
-
/** Re-run the view projection now (e.g. after external DOM swaps). */
|
|
42
|
-
flush(): void;
|
|
43
|
-
stop(): void;
|
|
44
|
-
}
|
|
45
|
-
/** Start a machine and keep `render(service)` in sync with every transition.
|
|
46
|
-
* `render` runs once immediately (initial projection) and on each machine notification. */
|
|
47
|
-
declare function runMachine<T extends MachineSchema>(machine: Machine<T>, props: Partial<T['props']> | (() => Partial<T['props']>), render: (service: Service<T>) => void): MachineHandle<T>;
|
|
48
|
-
/** Unique ids for machine instances (Zag keys its DOM lookups on them). */
|
|
49
|
-
declare function nextUid(prefix: string): string;
|
|
50
|
-
|
|
51
|
-
/** Dispatched on a surface's element once it is shown. */
|
|
52
|
-
declare const SURFACE_OPEN_EVENT = "vela:surface-open";
|
|
53
|
-
/** Dispatched on a surface's element as it starts to close, before it hides or leaves the DOM. */
|
|
54
|
-
declare const SURFACE_CLOSE_EVENT = "vela:surface-close";
|
|
55
|
-
/** What opened or closed: a menu (submenus included), a popover (select lists, color
|
|
56
|
-
* pickers, mark cards, the layout picker), a dialog, a drawer, or a side panel. */
|
|
57
|
-
type SurfaceKind = 'menu' | 'popover' | 'dialog' | 'drawer' | 'panel';
|
|
58
|
-
/** The `detail` of a {@link SURFACE_OPEN_EVENT} / {@link SURFACE_CLOSE_EVENT} event. */
|
|
59
|
-
interface SurfaceEventDetail {
|
|
60
|
-
kind: SurfaceKind;
|
|
61
|
-
/** The element that opened it, when there is one (a menu's button, a popover's trigger). */
|
|
62
|
-
trigger: HTMLElement | null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface TooltipControllerOptions {
|
|
66
|
-
placement?: tooltip.Placement;
|
|
67
|
-
/** ms before opening on hover (default 0 — the reference tooltips are instant). */
|
|
68
|
-
openDelay?: number;
|
|
69
|
-
closeDelay?: number;
|
|
70
|
-
/** Keep open while the pointer is over the content (rich tooltips). */
|
|
71
|
-
interactive?: boolean;
|
|
72
|
-
/** Share the trigger's DOM id with other machines composed on the SAME element
|
|
73
|
-
* (each Zag machine otherwise stamps its own id — last one wins and breaks the rest). */
|
|
74
|
-
triggerId?: string;
|
|
75
|
-
}
|
|
76
|
-
type TooltipService = tooltip.Service;
|
|
77
|
-
type TooltipApi = tooltip.Api;
|
|
78
|
-
interface TooltipController {
|
|
79
|
-
machine: typeof tooltip.machine;
|
|
80
|
-
props: Partial<tooltip.Props>;
|
|
81
|
-
connect(service: TooltipService): TooltipApi;
|
|
82
|
-
}
|
|
83
|
-
declare function tooltipController(opts?: TooltipControllerOptions): TooltipController;
|
|
84
|
-
|
|
85
|
-
interface TooltipOptions extends TooltipControllerOptions {
|
|
86
|
-
content: string | Node | (() => Node);
|
|
87
|
-
host?: HTMLElement;
|
|
88
|
-
}
|
|
89
|
-
declare class Tooltip {
|
|
90
|
-
private readonly positioner;
|
|
91
|
-
private readonly content;
|
|
92
|
-
private readonly handle;
|
|
93
|
-
private readonly trigger;
|
|
94
|
-
constructor(trigger: HTMLElement, opts: TooltipOptions);
|
|
95
|
-
setContent(content: string | Node | (() => Node)): void;
|
|
96
|
-
destroy(): void;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
14
|
/** One menu entry. `id` is the selection value reported to `onSelect`. */
|
|
100
15
|
interface MenuItemDescriptor {
|
|
101
16
|
id: string;
|
|
@@ -113,7 +28,8 @@ interface MenuItemDescriptor {
|
|
|
113
28
|
* instead of the selected-row highlight, and keep the menu OPEN on selection —
|
|
114
29
|
* the shape for boolean settings living inside a dropdown. */
|
|
115
30
|
toggle?: boolean;
|
|
116
|
-
/** Icon id (see the `vela/ui` icon registry) rendered before the label.
|
|
31
|
+
/** Icon id (see the `vela/ui` icon registry) rendered before the label. A level where
|
|
32
|
+
* any row has one gives its iconless rows an empty slot, so the labels align. */
|
|
117
33
|
icon?: string;
|
|
118
34
|
/** Favorite-star affordance at the row's right edge: `false` renders an outline
|
|
119
35
|
* star revealed on row hover, `true` a filled star that stays visible. Clicking
|
|
@@ -175,6 +91,13 @@ interface MenuOptions extends MenuControllerOptions {
|
|
|
175
91
|
* edge. Submenus inherit the mode. Dropdown menus (a trigger button opening a
|
|
176
92
|
* picker) keep the default wash. */
|
|
177
93
|
checkmarks?: boolean;
|
|
94
|
+
/** Sit each row's icon in a squared badge (a 24px rounded tile with a faint fill and a soft
|
|
95
|
+
* border) instead of a bare glyph: its glyph brightens on a hovered row, and the tile
|
|
96
|
+
* inverts on the selected one. A
|
|
97
|
+
* level where some rows carry an icon reserves the badge column on all its rows so
|
|
98
|
+
* labels align; a level with no icon keeps its natural left edge. With `checkmarks`,
|
|
99
|
+
* the mark column leads and the badge follows. Submenus inherit the mode. */
|
|
100
|
+
iconBadges?: boolean;
|
|
178
101
|
}
|
|
179
102
|
declare class Menu {
|
|
180
103
|
private readonly root;
|
|
@@ -189,6 +112,91 @@ declare class Menu {
|
|
|
189
112
|
destroy(): void;
|
|
190
113
|
}
|
|
191
114
|
|
|
115
|
+
/** A ready-to-insert element rendering the icon (empty span when unknown). */
|
|
116
|
+
declare function iconEl(id: string, doc?: Document): HTMLElement;
|
|
117
|
+
|
|
118
|
+
/** Overlay scrollbar used by settings panes, dialog bodies, and similar chrome. */
|
|
119
|
+
declare function overlayScrollbarCss(selector: string, width?: number): string;
|
|
120
|
+
/** Focus ring shared by typeable fields (combo inputs, textareas). */
|
|
121
|
+
declare const FIELD_FOCUS_CSS = "outline:none;transition:border-color .12s ease,box-shadow .12s ease;";
|
|
122
|
+
declare const FIELD_FOCUS_RING = "border-color:var(--vela-focus);box-shadow:0 0 0 3px var(--vela-focus-soft);";
|
|
123
|
+
/** Inject a stylesheet once per root (document or shadow root). Idempotent by id. */
|
|
124
|
+
declare function injectStyles(id: string, css: string, root?: Document | ShadowRoot): void;
|
|
125
|
+
|
|
126
|
+
/** Write the theme-derived custom properties onto a host element (the widget root and
|
|
127
|
+
* every floating layer — menus/tooltips portal outside the root, so layers re-apply). */
|
|
128
|
+
declare function applyThemeTokens(el: HTMLElement, t: VelaTheme): void;
|
|
129
|
+
/** Re-token a chart-overlay host (statusline, watermark, toast — chrome floating OVER
|
|
130
|
+
* the plot) from the LIVE plot surface: a config edit can recolor the plot background
|
|
131
|
+
* independently of the app theme (a white plot typed into settings on the dark theme),
|
|
132
|
+
* and the overlay ink must stay readable either way. `config` is the renderer's
|
|
133
|
+
* `getConfig()` snapshot; a missing/shapeless one falls back to the base app theme.
|
|
134
|
+
* Floating menus and dropdowns do NOT use this — they mount on {@link floatingLayerHost}
|
|
135
|
+
* so their surface follows the app theme alone. */
|
|
136
|
+
declare function applyPlotOverlayTokens(host: HTMLElement, base: VelaTheme, config: unknown): void;
|
|
137
|
+
/** Mark an element as a kit host: static token sheet + the `.vela-ui` class. */
|
|
138
|
+
declare function ensureUIHost(el: HTMLElement, theme?: VelaTheme): void;
|
|
139
|
+
|
|
140
|
+
interface MachineHandle<T extends MachineSchema> {
|
|
141
|
+
service: Service<T>;
|
|
142
|
+
/** Re-run the view projection now (e.g. after external DOM swaps). */
|
|
143
|
+
flush(): void;
|
|
144
|
+
stop(): void;
|
|
145
|
+
}
|
|
146
|
+
/** Start a machine and keep `render(service)` in sync with every transition.
|
|
147
|
+
* `render` runs once immediately (initial projection) and on each machine notification. */
|
|
148
|
+
declare function runMachine<T extends MachineSchema>(machine: Machine<T>, props: Partial<T['props']> | (() => Partial<T['props']>), render: (service: Service<T>) => void): MachineHandle<T>;
|
|
149
|
+
/** Unique ids for machine instances (Zag keys its DOM lookups on them). */
|
|
150
|
+
declare function nextUid(prefix: string): string;
|
|
151
|
+
|
|
152
|
+
/** Dispatched on a surface's element once it is shown. */
|
|
153
|
+
declare const SURFACE_OPEN_EVENT = "vela:surface-open";
|
|
154
|
+
/** Dispatched on a surface's element as it starts to close, before it hides or leaves the DOM. */
|
|
155
|
+
declare const SURFACE_CLOSE_EVENT = "vela:surface-close";
|
|
156
|
+
/** What opened or closed: a menu (submenus included), a popover (select lists, color
|
|
157
|
+
* pickers, mark cards, the layout picker), a dialog, a drawer, or a side panel. */
|
|
158
|
+
type SurfaceKind = 'menu' | 'popover' | 'dialog' | 'drawer' | 'panel';
|
|
159
|
+
/** The `detail` of a {@link SURFACE_OPEN_EVENT} / {@link SURFACE_CLOSE_EVENT} event. */
|
|
160
|
+
interface SurfaceEventDetail {
|
|
161
|
+
kind: SurfaceKind;
|
|
162
|
+
/** The element that opened it, when there is one (a menu's button, a popover's trigger). */
|
|
163
|
+
trigger: HTMLElement | null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
interface TooltipControllerOptions {
|
|
167
|
+
placement?: tooltip.Placement;
|
|
168
|
+
/** ms before opening on hover (default 0 — the reference tooltips are instant). */
|
|
169
|
+
openDelay?: number;
|
|
170
|
+
closeDelay?: number;
|
|
171
|
+
/** Keep open while the pointer is over the content (rich tooltips). */
|
|
172
|
+
interactive?: boolean;
|
|
173
|
+
/** Share the trigger's DOM id with other machines composed on the SAME element
|
|
174
|
+
* (each Zag machine otherwise stamps its own id — last one wins and breaks the rest). */
|
|
175
|
+
triggerId?: string;
|
|
176
|
+
}
|
|
177
|
+
type TooltipService = tooltip.Service;
|
|
178
|
+
type TooltipApi = tooltip.Api;
|
|
179
|
+
interface TooltipController {
|
|
180
|
+
machine: typeof tooltip.machine;
|
|
181
|
+
props: Partial<tooltip.Props>;
|
|
182
|
+
connect(service: TooltipService): TooltipApi;
|
|
183
|
+
}
|
|
184
|
+
declare function tooltipController(opts?: TooltipControllerOptions): TooltipController;
|
|
185
|
+
|
|
186
|
+
interface TooltipOptions extends TooltipControllerOptions {
|
|
187
|
+
content: string | Node | (() => Node);
|
|
188
|
+
host?: HTMLElement;
|
|
189
|
+
}
|
|
190
|
+
declare class Tooltip {
|
|
191
|
+
private readonly positioner;
|
|
192
|
+
private readonly content;
|
|
193
|
+
private readonly handle;
|
|
194
|
+
private readonly trigger;
|
|
195
|
+
constructor(trigger: HTMLElement, opts: TooltipOptions);
|
|
196
|
+
setContent(content: string | Node | (() => Node)): void;
|
|
197
|
+
destroy(): void;
|
|
198
|
+
}
|
|
199
|
+
|
|
192
200
|
interface DialogControllerOptions {
|
|
193
201
|
/** Trap focus + backdrop (default true). Non-modal = floating panel. */
|
|
194
202
|
modal?: boolean;
|
|
@@ -245,6 +253,17 @@ declare class Dialog {
|
|
|
245
253
|
constructor(opts?: DialogOptions);
|
|
246
254
|
private opener;
|
|
247
255
|
private wasOpen;
|
|
256
|
+
/** The panel and scrim's exit animation after a close; a reopen cancels it. */
|
|
257
|
+
private exit;
|
|
258
|
+
private destroyed;
|
|
259
|
+
private setShown;
|
|
260
|
+
/** Keep the just-closed dialog up through its exit animation, then hide it — or
|
|
261
|
+
* remove it, when it was destroyed meanwhile. `spreadProps` re-applies the close
|
|
262
|
+
* props' `hidden` only when its value changes, so lifting it keeps the panel and
|
|
263
|
+
* scrim up until the exit ends. The positioner spans the viewport: inert, it lets
|
|
264
|
+
* clicks through to the page while the panel animates out. */
|
|
265
|
+
private holdExit;
|
|
266
|
+
private detach;
|
|
248
267
|
/** Closing hands focus back to whatever opened it (Escape, the ✕, hide(), or a
|
|
249
268
|
* teardown that outruns the machine's close notification). */
|
|
250
269
|
private restoreOpener;
|
|
@@ -312,6 +331,17 @@ declare class Drawer {
|
|
|
312
331
|
setTitle(title: string): void;
|
|
313
332
|
private opener;
|
|
314
333
|
private wasOpen;
|
|
334
|
+
/** The sheet and scrim's exit animation after a close; a reopen cancels it. */
|
|
335
|
+
private exit;
|
|
336
|
+
private destroyed;
|
|
337
|
+
private setShown;
|
|
338
|
+
/** Keep the just-closed sheet up through its exit animation, then hide it — or
|
|
339
|
+
* remove it, when it was destroyed meanwhile. `spreadProps` re-applies the close
|
|
340
|
+
* props' `hidden` only when its value changes, so lifting it keeps the sheet and
|
|
341
|
+
* scrim up until the exit ends. The positioner spans the host: inert, it lets
|
|
342
|
+
* clicks through to the page while the sheet animates out. */
|
|
343
|
+
private holdExit;
|
|
344
|
+
private detach;
|
|
315
345
|
/** Closing hands focus back to whatever opened it (Escape, the ✕, hide(), or a
|
|
316
346
|
* teardown that outruns the machine's close notification). */
|
|
317
347
|
private restoreOpener;
|
|
@@ -425,6 +455,8 @@ declare class Popover {
|
|
|
425
455
|
private readonly fadeMs;
|
|
426
456
|
/** The pending removal of a fading-out shell; a show() that reuses the shell cancels it. */
|
|
427
457
|
private leaveTimer;
|
|
458
|
+
/** The shell's exit animation before it leaves the DOM; a show() that reuses the shell cancels it. */
|
|
459
|
+
private exit;
|
|
428
460
|
constructor(opts: PopoverOptions);
|
|
429
461
|
get open(): boolean;
|
|
430
462
|
get position(): PopoverPosition;
|