@luxalgo/vela 0.8.1 → 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/README.md +1 -1
- package/dist/{DataProvider-DwFIoV4r.d.ts → DataProvider-oH78tYXL.d.ts} +1 -1
- package/dist/{DataProvider-BrlxntPN.d.cts → DataProvider-wbtJ3-Sa.d.cts} +1 -1
- package/dist/{chunk-DBDXKZUF.js → chunk-2IPXYM4B.js} +306 -177
- package/dist/{chunk-NELQJCGK.js → chunk-G7B7ZCBF.js} +167 -10
- package/dist/{chunk-ATGTCWHJ.js → chunk-HMHA733L.js} +473 -196
- package/dist/{chunk-EZ5FWVLA.js → chunk-KWI3YDBW.js} +343 -17
- package/dist/{chunk-LMBYEGUR.js → chunk-TO3GIK7Z.js} +71 -6
- package/dist/{chunk-BZQM2XO7.js → chunk-VHGACEHO.js} +62 -1
- package/dist/{contributions-tjNExo1o.d.ts → contributions-BhOBRenr.d.cts} +79 -12
- package/dist/{contributions-CtlptxR8.d.cts → contributions-HGqnNb_P.d.ts} +79 -12
- package/dist/index.cjs +733 -113
- package/dist/index.d.cts +34 -14
- package/dist/index.d.ts +34 -14
- package/dist/index.js +5 -5
- package/dist/{options-BnEPUuVV.d.ts → options-lMUwmRwh.d.cts} +69 -4
- package/dist/{options-BnEPUuVV.d.cts → options-lMUwmRwh.d.ts} +69 -4
- package/dist/{plugin-e2WUEtiI.d.ts → plugin-Cr2Pj8q8.d.ts} +4 -4
- package/dist/{plugin-BWxJRKzS.d.cts → plugin-Do5J5xuF.d.cts} +4 -4
- package/dist/plugin.cjs +38 -6
- 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-HF0IAzwf.d.cts → side-panel-_2UK1gSm.d.cts} +58 -3
- package/dist/{side-panel-HF0IAzwf.d.ts → side-panel-_2UK1gSm.d.ts} +58 -3
- package/dist/{statusline-model-DFY7tuHj.d.cts → statusline-model-B-2xGlB_.d.cts} +3 -3
- package/dist/{statusline-model-zKXtGIjj.d.ts → statusline-model-CY1wzxHg.d.ts} +3 -3
- package/dist/ui.cjs +298 -13
- package/dist/ui.d.cts +132 -74
- package/dist/ui.d.ts +132 -74
- package/dist/ui.js +3 -3
- package/dist/vela.global.js +734 -114
- package/dist/vela.global.min.js +86 -52
- package/dist/widget.cjs +1227 -211
- package/dist/widget.d.cts +36 -12
- package/dist/widget.d.ts +36 -12
- package/dist/widget.js +7 -7
- package/dist/workspace.cjs +1226 -211
- package/dist/workspace.d.cts +47 -20
- package/dist/workspace.d.ts +47 -20
- package/dist/workspace.js +6 -6
- package/package.json +2 -2
- /package/dist/{chunk-JU4CWEBF.js → chunk-W5YPYZ2P.js} +0 -0
package/dist/ui.cjs
CHANGED
|
@@ -335,6 +335,7 @@ registerIcon("expand", S('<rect x="2.2" y="2.2" width="11.6" height="11.6" rx="1
|
|
|
335
335
|
registerIcon("plus", S('<path d="M8 2.8v10.4M2.8 8h10.4"/>'));
|
|
336
336
|
registerIcon("minus", S('<path d="M2.8 8h10.4"/>'));
|
|
337
337
|
registerIcon("maximize", S('<path d="M2.5 6V3a.5.5 0 0 1 .5-.5h3M10 2.5h3a.5.5 0 0 1 .5.5v3M13.5 10v3a.5.5 0 0 1-.5.5h-3M6 13.5H3a.5.5 0 0 1-.5-.5v-3"/>'));
|
|
338
|
+
registerIcon("restore", S('<path d="M6 2.5v3a.5.5 0 0 1-.5.5h-3M13.5 6h-3a.5.5 0 0 1-.5-.5v-3M10 13.5v-3a.5.5 0 0 1 .5-.5h3M2.5 10h3a.5.5 0 0 1 .5.5v3"/>'));
|
|
338
339
|
registerIcon("restore", S('<path d="M6.2 2.5v3.7H2.5M9.8 13.5V9.8h3.7M13.5 6.2H9.8V2.5M2.5 9.8h3.7v3.7"/>'));
|
|
339
340
|
registerIcon("star", S('<path d="M8 2.2l1.75 3.55 3.9.55-2.8 2.75.65 3.9L8 11.1l-3.5 1.85.65-3.9-2.8-2.75 3.9-.55z"/>'));
|
|
340
341
|
registerIcon("star-filled", S('<path d="M8 2.2l1.75 3.55 3.9.55-2.8 2.75.65 3.9L8 11.1l-3.5 1.85.65-3.9-2.8-2.75 3.9-.55z"/>', 'fill="currentColor"'));
|
|
@@ -416,6 +417,17 @@ function nextUid(prefix) {
|
|
|
416
417
|
return `${prefix}-${++uid}`;
|
|
417
418
|
}
|
|
418
419
|
|
|
420
|
+
// src/ui/surface-events.ts
|
|
421
|
+
var SURFACE_OPEN_EVENT = "vela:surface-open";
|
|
422
|
+
var SURFACE_CLOSE_EVENT = "vela:surface-close";
|
|
423
|
+
function announceSurface(el, open2, kind, trigger = null) {
|
|
424
|
+
const View = el.ownerDocument.defaultView;
|
|
425
|
+
if (!View) return;
|
|
426
|
+
el.dispatchEvent(
|
|
427
|
+
new View.CustomEvent(open2 ? SURFACE_OPEN_EVENT : SURFACE_CLOSE_EVENT, { bubbles: true, composed: true, detail: { kind, trigger } })
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
419
431
|
// src/ui/keymap.ts
|
|
420
432
|
var KEY_ALIASES = {
|
|
421
433
|
esc: "escape",
|
|
@@ -632,6 +644,55 @@ var Tooltip = class {
|
|
|
632
644
|
this.trigger.removeAttribute("data-scope");
|
|
633
645
|
}
|
|
634
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
|
+
}
|
|
635
696
|
function menuController(opts) {
|
|
636
697
|
return {
|
|
637
698
|
machine: menu__namespace.machine,
|
|
@@ -713,6 +774,35 @@ var MENU_CSS = `
|
|
|
713
774
|
color: var(--vela-fg-bright);
|
|
714
775
|
}
|
|
715
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
|
+
}
|
|
716
806
|
/* Switch rows (boolean settings in a dropdown): a right-aligned toggle pill \u2014 the
|
|
717
807
|
same control language as the settings dialog's toggles. */
|
|
718
808
|
.vela-menu-switch {
|
|
@@ -777,11 +867,16 @@ var Surface = class _Surface {
|
|
|
777
867
|
/** Trigger rect captured when this level opened — the list stays put if the
|
|
778
868
|
* trigger then moves (favorite chips shifting the caret). */
|
|
779
869
|
this.pinnedAnchor = null;
|
|
870
|
+
/** The open state last announced — see {@link announce}. */
|
|
871
|
+
this.shown = false;
|
|
872
|
+
/** The list's exit animation after a close; a reopen cancels it. */
|
|
873
|
+
this.exit = null;
|
|
780
874
|
this.doc = doc;
|
|
781
875
|
this.host = opts.host;
|
|
782
876
|
this.onSelect = opts.onSelect;
|
|
783
877
|
this.onFavorite = opts.onFavorite;
|
|
784
878
|
this.checkmarks = opts.checkmarks === true;
|
|
879
|
+
this.iconBadges = opts.iconBadges === true;
|
|
785
880
|
this.positioner = doc.createElement("div");
|
|
786
881
|
this.positioner.className = "vela-ui-layer";
|
|
787
882
|
this.list = doc.createElement("ul");
|
|
@@ -790,6 +885,7 @@ var Surface = class _Surface {
|
|
|
790
885
|
this.positioner.appendChild(this.list);
|
|
791
886
|
this.host.appendChild(this.positioner);
|
|
792
887
|
const trigger = opts.trigger;
|
|
888
|
+
this.opener = trigger ?? opts.opener ?? null;
|
|
793
889
|
this.ctrl = menuController({
|
|
794
890
|
items: [],
|
|
795
891
|
id: opts.id,
|
|
@@ -811,15 +907,37 @@ var Surface = class _Surface {
|
|
|
811
907
|
if (opts.triggerId && trigger) trigger.id = opts.triggerId;
|
|
812
908
|
this.handle = runMachine(this.ctrl.machine, this.ctrl.props, (service) => {
|
|
813
909
|
const api = this.ctrl.connect(service);
|
|
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
|
+
}
|
|
814
916
|
if (trigger) vanilla.spreadProps(trigger, api.getTriggerProps(), this.mid);
|
|
815
917
|
vanilla.spreadProps(this.positioner, api.getPositionerProps(), this.mid);
|
|
816
918
|
vanilla.spreadProps(this.list, api.getContentProps(), this.mid);
|
|
817
919
|
this.project(api);
|
|
920
|
+
if (closing) this.holdExit();
|
|
921
|
+
if (api.open && !this.shown) this.announce(true);
|
|
922
|
+
});
|
|
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;
|
|
818
932
|
});
|
|
819
933
|
}
|
|
820
934
|
get api() {
|
|
821
935
|
return this.ctrl.connect(this.handle.service);
|
|
822
936
|
}
|
|
937
|
+
announce(open2) {
|
|
938
|
+
this.shown = open2;
|
|
939
|
+
announceSurface(this.list, open2, "menu", this.opener);
|
|
940
|
+
}
|
|
823
941
|
setItems(items) {
|
|
824
942
|
this.items = items;
|
|
825
943
|
for (const sub of this.subs.values()) sub.destroy();
|
|
@@ -836,7 +954,9 @@ var Surface = class _Surface {
|
|
|
836
954
|
destroy() {
|
|
837
955
|
for (const sub of this.subs.values()) sub.destroy();
|
|
838
956
|
this.subs.clear();
|
|
957
|
+
this.exit?.finish();
|
|
839
958
|
this.handle.stop();
|
|
959
|
+
if (this.shown) this.announce(false);
|
|
840
960
|
this.positioner.remove();
|
|
841
961
|
}
|
|
842
962
|
byId(id) {
|
|
@@ -861,6 +981,10 @@ var Surface = class _Surface {
|
|
|
861
981
|
const doc = this.doc;
|
|
862
982
|
this.list.replaceChildren();
|
|
863
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;
|
|
864
988
|
for (const item of this.items) {
|
|
865
989
|
if (item.separatorBefore) {
|
|
866
990
|
const sep = doc.createElement("li");
|
|
@@ -886,7 +1010,16 @@ var Surface = class _Surface {
|
|
|
886
1010
|
} else if (!branch && !item.toggle && item.checked) {
|
|
887
1011
|
li.dataset.checked = "1";
|
|
888
1012
|
}
|
|
889
|
-
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
|
+
}
|
|
890
1023
|
const label = doc.createElement("span");
|
|
891
1024
|
label.className = "vela-menu-label";
|
|
892
1025
|
label.textContent = item.label;
|
|
@@ -930,9 +1063,11 @@ var Surface = class _Surface {
|
|
|
930
1063
|
const sub = new _Surface(doc, {
|
|
931
1064
|
host: this.host,
|
|
932
1065
|
placement: "right-start",
|
|
1066
|
+
opener: li,
|
|
933
1067
|
onSelect: this.onSelect,
|
|
934
1068
|
onFavorite: this.onFavorite,
|
|
935
1069
|
checkmarks: this.checkmarks,
|
|
1070
|
+
iconBadges: this.iconBadges,
|
|
936
1071
|
id: `${this.mid}--${item.id}`
|
|
937
1072
|
});
|
|
938
1073
|
sub.setItems(item.submenu ?? []);
|
|
@@ -958,7 +1093,8 @@ var Menu = class {
|
|
|
958
1093
|
id: opts.id,
|
|
959
1094
|
minWidth: opts.minWidth,
|
|
960
1095
|
onFavorite: opts.onFavorite,
|
|
961
|
-
checkmarks: opts.checkmarks
|
|
1096
|
+
checkmarks: opts.checkmarks,
|
|
1097
|
+
iconBadges: opts.iconBadges
|
|
962
1098
|
});
|
|
963
1099
|
this.root.setItems(opts.items);
|
|
964
1100
|
}
|
|
@@ -1062,6 +1198,7 @@ var POPOVER_CSS = `
|
|
|
1062
1198
|
|
|
1063
1199
|
// src/ui/components/popover/view.ts
|
|
1064
1200
|
var open = null;
|
|
1201
|
+
var leaving = /* @__PURE__ */ new Set();
|
|
1065
1202
|
function closeOpenPopovers() {
|
|
1066
1203
|
open?.hide();
|
|
1067
1204
|
}
|
|
@@ -1089,6 +1226,8 @@ var Popover = class {
|
|
|
1089
1226
|
this.shown = false;
|
|
1090
1227
|
/** The pending removal of a fading-out shell; a show() that reuses the shell cancels it. */
|
|
1091
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;
|
|
1092
1231
|
const doc = opts.trigger.ownerDocument;
|
|
1093
1232
|
injectStyles(POPOVER_STYLE_ID, POPOVER_CSS, doc);
|
|
1094
1233
|
this.trigger = opts.trigger;
|
|
@@ -1125,6 +1264,10 @@ var Popover = class {
|
|
|
1125
1264
|
clearTimeout(this.leaveTimer);
|
|
1126
1265
|
this.leaveTimer = null;
|
|
1127
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();
|
|
1128
1271
|
ensureUIHost(this.el, this.inheritsTokens ? void 0 : this.theme);
|
|
1129
1272
|
if (this.fadeMs > 0) {
|
|
1130
1273
|
this.el.style.transition = `opacity ${this.fadeMs}ms ease`;
|
|
@@ -1149,16 +1292,21 @@ var Popover = class {
|
|
|
1149
1292
|
this.hide();
|
|
1150
1293
|
};
|
|
1151
1294
|
const onReflow = () => this.place();
|
|
1152
|
-
setTimeout(() =>
|
|
1295
|
+
setTimeout(() => {
|
|
1296
|
+
if (this.onOutside === onOutside) document.addEventListener("pointerdown", onOutside, true);
|
|
1297
|
+
}, 0);
|
|
1153
1298
|
document.addEventListener("keydown", onKey, true);
|
|
1154
1299
|
window.addEventListener("resize", onReflow, true);
|
|
1155
1300
|
document.addEventListener("scroll", onReflow, true);
|
|
1156
1301
|
this.onOutside = onOutside;
|
|
1157
1302
|
this.onKey = onKey;
|
|
1158
1303
|
this.onReflow = onReflow;
|
|
1304
|
+
announceSurface(this.el, true, "popover", this.trigger);
|
|
1159
1305
|
}
|
|
1160
1306
|
hide() {
|
|
1161
1307
|
if (!this.shown) return;
|
|
1308
|
+
this.shown = false;
|
|
1309
|
+
announceSurface(this.el, false, "popover", this.trigger);
|
|
1162
1310
|
if (this.onOutside) document.removeEventListener("pointerdown", this.onOutside, true);
|
|
1163
1311
|
if (this.onKey) document.removeEventListener("keydown", this.onKey, true);
|
|
1164
1312
|
if (this.onReflow) {
|
|
@@ -1176,9 +1324,13 @@ var Popover = class {
|
|
|
1176
1324
|
this.el.remove();
|
|
1177
1325
|
}, this.fadeMs);
|
|
1178
1326
|
} else {
|
|
1179
|
-
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);
|
|
1180
1333
|
}
|
|
1181
|
-
this.shown = false;
|
|
1182
1334
|
if (open === this) open = null;
|
|
1183
1335
|
this.ctrl.onClose?.();
|
|
1184
1336
|
}
|
|
@@ -1189,6 +1341,7 @@ var Popover = class {
|
|
|
1189
1341
|
}
|
|
1190
1342
|
destroy() {
|
|
1191
1343
|
this.hide();
|
|
1344
|
+
this.exit?.finish();
|
|
1192
1345
|
}
|
|
1193
1346
|
reposition() {
|
|
1194
1347
|
if (this.shown) this.place();
|
|
@@ -1384,6 +1537,11 @@ ${overlayScrollbarCss(".vela-dialog *")}
|
|
|
1384
1537
|
`;
|
|
1385
1538
|
var Dialog = class {
|
|
1386
1539
|
constructor(opts = {}) {
|
|
1540
|
+
this.opener = null;
|
|
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;
|
|
1387
1545
|
const doc = (opts.host ?? document.body).ownerDocument;
|
|
1388
1546
|
injectStyles(DIALOG_STYLE_ID, DIALOG_CSS, doc);
|
|
1389
1547
|
const host = opts.host ?? doc.body;
|
|
@@ -1480,19 +1638,73 @@ var Dialog = class {
|
|
|
1480
1638
|
const mid = String(this.ctrl.props.id);
|
|
1481
1639
|
this.handle = runMachine(this.ctrl.machine, this.ctrl.props, (service) => {
|
|
1482
1640
|
const api = this.ctrl.connect(service);
|
|
1641
|
+
const closing = this.wasOpen && !api.open;
|
|
1642
|
+
if (closing) this.announce(false);
|
|
1483
1643
|
vanilla.spreadProps(this.backdrop, api.getBackdropProps(), mid);
|
|
1484
1644
|
vanilla.spreadProps(this.positioner, api.getPositionerProps(), mid);
|
|
1485
1645
|
vanilla.spreadProps(this.panel, api.getContentProps(), mid);
|
|
1486
1646
|
vanilla.spreadProps(title, api.getTitleProps(), mid);
|
|
1487
1647
|
vanilla.spreadProps(close, api.getCloseTriggerProps(), mid);
|
|
1488
|
-
|
|
1489
|
-
|
|
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
|
+
}
|
|
1657
|
+
if (api.open && !this.wasOpen) this.announce(true);
|
|
1658
|
+
if (this.wasOpen && !api.open) this.restoreOpener();
|
|
1659
|
+
this.wasOpen = api.open;
|
|
1490
1660
|
});
|
|
1491
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
|
+
}
|
|
1692
|
+
/** Closing hands focus back to whatever opened it (Escape, the ✕, hide(), or a
|
|
1693
|
+
* teardown that outruns the machine's close notification). */
|
|
1694
|
+
restoreOpener() {
|
|
1695
|
+
const opener = this.opener;
|
|
1696
|
+
this.opener = null;
|
|
1697
|
+
if (opener?.isConnected) opener.focus({ preventScroll: true });
|
|
1698
|
+
}
|
|
1699
|
+
announce(open2) {
|
|
1700
|
+
const opener = this.opener === this.panel.ownerDocument.body ? null : this.opener;
|
|
1701
|
+
announceSurface(this.panel, open2, "dialog", opener);
|
|
1702
|
+
}
|
|
1492
1703
|
get open() {
|
|
1493
1704
|
return this.ctrl.connect(this.handle.service).open;
|
|
1494
1705
|
}
|
|
1495
1706
|
show() {
|
|
1707
|
+
this.opener = this.panel.ownerDocument.activeElement;
|
|
1496
1708
|
this.ctrl.connect(this.handle.service).setOpen(true);
|
|
1497
1709
|
}
|
|
1498
1710
|
hide() {
|
|
@@ -1505,10 +1717,16 @@ var Dialog = class {
|
|
|
1505
1717
|
return el?.closest(".vela-popover, .vela-menu") != null;
|
|
1506
1718
|
}
|
|
1507
1719
|
destroy() {
|
|
1720
|
+
if (this.wasOpen && !this.open) this.handle.flush();
|
|
1508
1721
|
if (this.open) this.hide();
|
|
1509
1722
|
this.handle.stop();
|
|
1510
|
-
this.
|
|
1511
|
-
this.
|
|
1723
|
+
this.destroyed = true;
|
|
1724
|
+
if (this.wasOpen) {
|
|
1725
|
+
this.wasOpen = false;
|
|
1726
|
+
this.announce(false);
|
|
1727
|
+
}
|
|
1728
|
+
this.restoreOpener();
|
|
1729
|
+
if (!this.exit) this.detach();
|
|
1512
1730
|
}
|
|
1513
1731
|
};
|
|
1514
1732
|
function drawerController(opts = {}) {
|
|
@@ -1635,6 +1853,11 @@ function swipeDirection(dx, dy) {
|
|
|
1635
1853
|
}
|
|
1636
1854
|
var Drawer = class {
|
|
1637
1855
|
constructor(opts = {}) {
|
|
1856
|
+
this.opener = null;
|
|
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;
|
|
1638
1861
|
const doc = (opts.host ?? document.body).ownerDocument;
|
|
1639
1862
|
injectStyles(DRAWER_STYLE_ID, DRAWER_CSS, doc);
|
|
1640
1863
|
const host = opts.host ?? doc.body;
|
|
@@ -1662,12 +1885,24 @@ var Drawer = class {
|
|
|
1662
1885
|
const mid = String(this.ctrl.props.id);
|
|
1663
1886
|
this.handle = runMachine(this.ctrl.machine, this.ctrl.props, (service) => {
|
|
1664
1887
|
const api = this.ctrl.connect(service);
|
|
1888
|
+
const closing = this.wasOpen && !api.open;
|
|
1889
|
+
if (closing) this.announce(false);
|
|
1665
1890
|
vanilla.spreadProps(this.backdrop, api.getBackdropProps(), mid);
|
|
1666
1891
|
vanilla.spreadProps(this.positioner, api.getPositionerProps(), mid);
|
|
1667
1892
|
vanilla.spreadProps(this.panel, api.getContentProps(), mid);
|
|
1668
1893
|
vanilla.spreadProps(this.titleEl, api.getTitleProps(), mid);
|
|
1669
|
-
|
|
1670
|
-
|
|
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
|
+
}
|
|
1903
|
+
if (api.open && !this.wasOpen) this.announce(true);
|
|
1904
|
+
if (this.wasOpen && !api.open) this.restoreOpener();
|
|
1905
|
+
this.wasOpen = api.open;
|
|
1671
1906
|
});
|
|
1672
1907
|
}
|
|
1673
1908
|
/** Any element between `from` and the panel that has already been scrolled down —
|
|
@@ -1776,19 +2011,67 @@ var Drawer = class {
|
|
|
1776
2011
|
setTitle(title) {
|
|
1777
2012
|
this.titleEl.textContent = title;
|
|
1778
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
|
+
}
|
|
2044
|
+
/** Closing hands focus back to whatever opened it (Escape, the ✕, hide(), or a
|
|
2045
|
+
* teardown that outruns the machine's close notification). */
|
|
2046
|
+
restoreOpener() {
|
|
2047
|
+
const opener = this.opener;
|
|
2048
|
+
this.opener = null;
|
|
2049
|
+
if (opener?.isConnected) opener.focus({ preventScroll: true });
|
|
2050
|
+
}
|
|
2051
|
+
announce(open2) {
|
|
2052
|
+
const opener = this.opener === this.panel.ownerDocument.body ? null : this.opener;
|
|
2053
|
+
announceSurface(this.panel, open2, "drawer", opener);
|
|
2054
|
+
}
|
|
1779
2055
|
get open() {
|
|
1780
2056
|
return this.ctrl.connect(this.handle.service).open;
|
|
1781
2057
|
}
|
|
1782
2058
|
show() {
|
|
2059
|
+
this.opener = this.panel.ownerDocument.activeElement;
|
|
1783
2060
|
this.ctrl.connect(this.handle.service).setOpen(true);
|
|
1784
2061
|
}
|
|
1785
2062
|
hide() {
|
|
1786
2063
|
this.ctrl.connect(this.handle.service).setOpen(false);
|
|
1787
2064
|
}
|
|
1788
2065
|
destroy() {
|
|
2066
|
+
if (this.wasOpen && !this.open) this.handle.flush();
|
|
1789
2067
|
this.handle.stop();
|
|
1790
|
-
this.
|
|
1791
|
-
this.
|
|
2068
|
+
this.destroyed = true;
|
|
2069
|
+
if (this.wasOpen) {
|
|
2070
|
+
this.wasOpen = false;
|
|
2071
|
+
this.announce(false);
|
|
2072
|
+
}
|
|
2073
|
+
this.restoreOpener();
|
|
2074
|
+
if (!this.exit) this.detach();
|
|
1792
2075
|
}
|
|
1793
2076
|
};
|
|
1794
2077
|
|
|
@@ -3971,6 +4254,8 @@ exports.KeymapManager = KeymapManager;
|
|
|
3971
4254
|
exports.Menu = Menu;
|
|
3972
4255
|
exports.NumberInput = NumberInput;
|
|
3973
4256
|
exports.Popover = Popover;
|
|
4257
|
+
exports.SURFACE_CLOSE_EVENT = SURFACE_CLOSE_EVENT;
|
|
4258
|
+
exports.SURFACE_OPEN_EVENT = SURFACE_OPEN_EVENT;
|
|
3974
4259
|
exports.Select = Select;
|
|
3975
4260
|
exports.Switch = Switch;
|
|
3976
4261
|
exports.TextArea = TextArea;
|