streetui 1.8.0 → 1.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/bin.cjs +1 -1
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/{compile-CJJQYi71.d.cts → compile-DqsMQVJk.d.cts} +120 -4
- package/dist/{compile-CJJQYi71.d.ts → compile-DqsMQVJk.d.ts} +120 -4
- package/dist/create-bin.cjs +1 -1
- package/dist/create-bin.cjs.map +1 -1
- package/dist/create-bin.js +1 -1
- package/dist/create-bin.js.map +1 -1
- package/dist/{hydration-diagnostics-BQeehq3i.d.cts → hydration-diagnostics-4pwt6v7b.d.cts} +1 -1
- package/dist/{hydration-diagnostics-DNAJumYF.d.ts → hydration-diagnostics-B2FmY05M.d.ts} +1 -1
- package/dist/index.cjs +537 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +261 -18
- package/dist/index.d.ts +261 -18
- package/dist/index.js +529 -40
- package/dist/index.js.map +1 -1
- package/dist/{server-DNlg7ou2.d.ts → server-BYnmb_hR.d.ts} +1 -1
- package/dist/{server-CnLEnlYU.d.cts → server-DnwqBTfE.d.cts} +1 -1
- package/dist/server.cjs +266 -30
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +266 -30
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +387 -36
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +42 -4
- package/dist/testing.d.ts +42 -4
- package/dist/testing.js +379 -35
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/testing.js
CHANGED
|
@@ -756,18 +756,25 @@ function trapFocus(dom, container) {
|
|
|
756
756
|
dom.addEventListener(container, "keydown", onKeydown);
|
|
757
757
|
return () => dom.removeEventListener(container, "keydown", onKeydown);
|
|
758
758
|
}
|
|
759
|
+
var containmentStack = [];
|
|
759
760
|
function containFocus(dom, container) {
|
|
760
761
|
const body = dom.body();
|
|
761
762
|
if (body === null) return () => {
|
|
762
763
|
};
|
|
764
|
+
containmentStack.push(container);
|
|
763
765
|
const onFocusIn = (event) => {
|
|
766
|
+
if (containmentStack[containmentStack.length - 1] !== container) return;
|
|
764
767
|
const target = event.target;
|
|
765
768
|
if (target !== null && !dom.contains(container, target)) {
|
|
766
769
|
focusFirst(dom, container);
|
|
767
770
|
}
|
|
768
771
|
};
|
|
769
772
|
dom.addEventListener(body, "focusin", onFocusIn);
|
|
770
|
-
return () =>
|
|
773
|
+
return () => {
|
|
774
|
+
dom.removeEventListener(body, "focusin", onFocusIn);
|
|
775
|
+
const index = containmentStack.lastIndexOf(container);
|
|
776
|
+
if (index !== -1) containmentStack.splice(index, 1);
|
|
777
|
+
};
|
|
771
778
|
}
|
|
772
779
|
function onEscape(dom, target, handler) {
|
|
773
780
|
const onKeydown = (event) => {
|
|
@@ -776,6 +783,33 @@ function onEscape(dom, target, handler) {
|
|
|
776
783
|
dom.addEventListener(target, "keydown", onKeydown);
|
|
777
784
|
return () => dom.removeEventListener(target, "keydown", onKeydown);
|
|
778
785
|
}
|
|
786
|
+
function rovingMenu(dom, container, selector = FOCUSABLE_SELECTOR) {
|
|
787
|
+
const onKeydown = (event) => {
|
|
788
|
+
const key = event.key;
|
|
789
|
+
const isActivate = key === "Enter" || key === " " || key === "Spacebar";
|
|
790
|
+
const isMove = key === "ArrowDown" || key === "ArrowUp" || key === "Home" || key === "End";
|
|
791
|
+
if (!isActivate && !isMove) return;
|
|
792
|
+
const items = getFocusable(dom, container, selector);
|
|
793
|
+
if (items.length === 0) return;
|
|
794
|
+
const active = dom.activeElement();
|
|
795
|
+
const index = active === null ? -1 : items.indexOf(active);
|
|
796
|
+
if (isActivate) {
|
|
797
|
+
if (index < 0) return;
|
|
798
|
+
event.preventDefault();
|
|
799
|
+
items[index].click?.();
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
event.preventDefault();
|
|
803
|
+
let next;
|
|
804
|
+
if (key === "Home") next = 0;
|
|
805
|
+
else if (key === "End") next = items.length - 1;
|
|
806
|
+
else if (key === "ArrowDown") next = index < 0 ? 0 : (index + 1) % items.length;
|
|
807
|
+
else next = index <= 0 ? items.length - 1 : index - 1;
|
|
808
|
+
dom.focus(items[next]);
|
|
809
|
+
};
|
|
810
|
+
dom.addEventListener(container, "keydown", onKeydown);
|
|
811
|
+
return () => dom.removeEventListener(container, "keydown", onKeydown);
|
|
812
|
+
}
|
|
779
813
|
|
|
780
814
|
// ../renderer/src/render-context.ts
|
|
781
815
|
function createRenderContext(dom, graph, container, hydrationDiagnostics, staticHTML) {
|
|
@@ -987,7 +1021,7 @@ function patchNode(ctx, graphNode, propKey, newValue) {
|
|
|
987
1021
|
}
|
|
988
1022
|
|
|
989
1023
|
// ../renderer/src/reconciliation.ts
|
|
990
|
-
function reconcileChildren(ctx, parentDom, oldInstances, newNodes, mountFn) {
|
|
1024
|
+
function reconcileChildren(ctx, parentDom, oldInstances, newNodes, mountFn, hooks) {
|
|
991
1025
|
const oldByKey = /* @__PURE__ */ new Map();
|
|
992
1026
|
for (const inst of oldInstances) {
|
|
993
1027
|
const key = inst.graphNode.key ?? inst.graphNode.id;
|
|
@@ -1008,28 +1042,33 @@ function reconcileChildren(ctx, parentDom, oldInstances, newNodes, mountFn) {
|
|
|
1008
1042
|
}
|
|
1009
1043
|
newInstances.push(existing);
|
|
1010
1044
|
} else {
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1045
|
+
const reclaimed = hooks?.takeLeaving(key);
|
|
1046
|
+
if (reclaimed !== void 0) {
|
|
1047
|
+
patchExistingInstance(ctx, reclaimed, newNode);
|
|
1048
|
+
reconcileItemChildren(ctx, reclaimed, newNode, mountFn);
|
|
1049
|
+
hooks?.onEnter(reclaimed);
|
|
1050
|
+
newInstances.push(reclaimed);
|
|
1051
|
+
} else {
|
|
1052
|
+
const inst = mountFn(newNode, parentDom);
|
|
1053
|
+
hooks?.onEnter(inst);
|
|
1054
|
+
newInstances.push(inst);
|
|
1055
|
+
}
|
|
1013
1056
|
}
|
|
1014
1057
|
}
|
|
1015
1058
|
const removed = [];
|
|
1016
1059
|
for (const inst of oldInstances) {
|
|
1017
1060
|
const key = inst.graphNode.key ?? inst.graphNode.id;
|
|
1018
|
-
if (
|
|
1019
|
-
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
for (const inst of removed) {
|
|
1061
|
+
if (usedKeys.has(key)) continue;
|
|
1062
|
+
if (hooks !== void 0 && hooks.beginLeave(inst)) continue;
|
|
1023
1063
|
const parent = ctx.dom.parentNode(inst.domNode);
|
|
1024
|
-
if (parent !== null)
|
|
1025
|
-
ctx.dom.removeChild(parent, inst.domNode);
|
|
1026
|
-
}
|
|
1064
|
+
if (parent !== null) ctx.dom.removeChild(parent, inst.domNode);
|
|
1027
1065
|
inst.dispose();
|
|
1066
|
+
removed.push(inst);
|
|
1028
1067
|
}
|
|
1029
1068
|
reorderDom(ctx, parentDom, newInstances);
|
|
1030
1069
|
return { instances: newInstances, removed };
|
|
1031
1070
|
}
|
|
1032
|
-
function reconcileChildrenByPlan(ctx, parentDom, oldInstances, plan, mountFn) {
|
|
1071
|
+
function reconcileChildrenByPlan(ctx, parentDom, oldInstances, plan, mountFn, hooks) {
|
|
1033
1072
|
const oldByKey = /* @__PURE__ */ new Map();
|
|
1034
1073
|
for (const inst of oldInstances) {
|
|
1035
1074
|
oldByKey.set(inst.graphNode.key ?? inst.graphNode.id, inst);
|
|
@@ -1056,21 +1095,34 @@ function reconcileChildrenByPlan(ctx, parentDom, oldInstances, plan, mountFn) {
|
|
|
1056
1095
|
}
|
|
1057
1096
|
newInstances.push(existing);
|
|
1058
1097
|
} else {
|
|
1059
|
-
const
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1098
|
+
const reclaimed = hooks?.takeLeaving(entry.key);
|
|
1099
|
+
if (reclaimed !== void 0) {
|
|
1100
|
+
const freshNode = entry.build();
|
|
1101
|
+
built.push(freshNode);
|
|
1102
|
+
patchExistingInstance(ctx, reclaimed, freshNode);
|
|
1103
|
+
reconcileItemChildren(ctx, reclaimed, freshNode, mountFn);
|
|
1104
|
+
reclaimed.graphNode.setProp("_sig", freshNode.getProp("_sig"));
|
|
1105
|
+
reclaimed.graphNode.setProp("_item", entry.item);
|
|
1106
|
+
hooks?.onEnter(reclaimed);
|
|
1107
|
+
newInstances.push(reclaimed);
|
|
1108
|
+
} else {
|
|
1109
|
+
const freshNode = entry.build();
|
|
1110
|
+
built.push(freshNode);
|
|
1111
|
+
const inst = mountFn(freshNode, parentDom);
|
|
1112
|
+
hooks?.onEnter(inst);
|
|
1113
|
+
newInstances.push(inst);
|
|
1114
|
+
}
|
|
1063
1115
|
}
|
|
1064
1116
|
}
|
|
1065
1117
|
const removed = [];
|
|
1066
1118
|
for (const inst of oldInstances) {
|
|
1067
1119
|
const key = inst.graphNode.key ?? inst.graphNode.id;
|
|
1068
|
-
if (
|
|
1069
|
-
|
|
1070
|
-
for (const inst of removed) {
|
|
1120
|
+
if (usedKeys.has(key)) continue;
|
|
1121
|
+
if (hooks !== void 0 && hooks.beginLeave(inst)) continue;
|
|
1071
1122
|
const parent = ctx.dom.parentNode(inst.domNode);
|
|
1072
1123
|
if (parent !== null) ctx.dom.removeChild(parent, inst.domNode);
|
|
1073
1124
|
inst.dispose();
|
|
1125
|
+
removed.push(inst);
|
|
1074
1126
|
}
|
|
1075
1127
|
reorderDomMinimal(ctx, parentDom, oldInstances, newInstances);
|
|
1076
1128
|
return { instances: newInstances, removed, built };
|
|
@@ -1196,6 +1248,176 @@ function patchExistingInstance(ctx, instance, newNode) {
|
|
|
1196
1248
|
}
|
|
1197
1249
|
}
|
|
1198
1250
|
|
|
1251
|
+
// ../renderer/src/transition.ts
|
|
1252
|
+
function getResolvedTransition(graph, nodeId) {
|
|
1253
|
+
const fn = graph.getHandler(`__transition__${nodeId}`);
|
|
1254
|
+
return fn === void 0 ? void 0 : fn();
|
|
1255
|
+
}
|
|
1256
|
+
function host() {
|
|
1257
|
+
return globalThis;
|
|
1258
|
+
}
|
|
1259
|
+
function nextFrame(cb) {
|
|
1260
|
+
const h = host();
|
|
1261
|
+
const raf = h.requestAnimationFrame;
|
|
1262
|
+
if (typeof raf === "function") {
|
|
1263
|
+
raf(() => raf(cb));
|
|
1264
|
+
} else {
|
|
1265
|
+
h.setTimeout(cb, 0);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
function splitClass(value) {
|
|
1269
|
+
if (value === null) return [];
|
|
1270
|
+
const out = [];
|
|
1271
|
+
for (const t of value.split(/\s+/)) if (t.length > 0) out.push(t);
|
|
1272
|
+
return out;
|
|
1273
|
+
}
|
|
1274
|
+
function addClasses(dom, el, classes2) {
|
|
1275
|
+
if (classes2.length === 0) return;
|
|
1276
|
+
const current = splitClass(dom.getAttribute(el, "class"));
|
|
1277
|
+
let changed = false;
|
|
1278
|
+
for (const c of classes2) {
|
|
1279
|
+
if (!current.includes(c)) {
|
|
1280
|
+
current.push(c);
|
|
1281
|
+
changed = true;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
if (changed) dom.setAttribute(el, "class", current.join(" "));
|
|
1285
|
+
}
|
|
1286
|
+
function removeClasses(dom, el, classes2) {
|
|
1287
|
+
if (classes2.length === 0) return;
|
|
1288
|
+
const current = splitClass(dom.getAttribute(el, "class"));
|
|
1289
|
+
const next = current.filter((c) => !classes2.includes(c));
|
|
1290
|
+
if (next.length !== current.length) {
|
|
1291
|
+
if (next.length === 0) dom.removeAttribute(el, "class");
|
|
1292
|
+
else dom.setAttribute(el, "class", next.join(" "));
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
function startRun(dom, el, active, from, to, duration, onDone) {
|
|
1296
|
+
const h = host();
|
|
1297
|
+
let finished = false;
|
|
1298
|
+
let timer = null;
|
|
1299
|
+
const onEvent = (e) => {
|
|
1300
|
+
if (e.target !== el) return;
|
|
1301
|
+
finish();
|
|
1302
|
+
};
|
|
1303
|
+
const detach = () => {
|
|
1304
|
+
dom.removeEventListener(el, "transitionend", onEvent);
|
|
1305
|
+
dom.removeEventListener(el, "animationend", onEvent);
|
|
1306
|
+
if (timer !== null) {
|
|
1307
|
+
h.clearTimeout(timer);
|
|
1308
|
+
timer = null;
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
const finish = () => {
|
|
1312
|
+
if (finished) return;
|
|
1313
|
+
finished = true;
|
|
1314
|
+
detach();
|
|
1315
|
+
removeClasses(dom, el, active);
|
|
1316
|
+
removeClasses(dom, el, to);
|
|
1317
|
+
removeClasses(dom, el, from);
|
|
1318
|
+
onDone();
|
|
1319
|
+
};
|
|
1320
|
+
addClasses(dom, el, from);
|
|
1321
|
+
addClasses(dom, el, active);
|
|
1322
|
+
dom.addEventListener(el, "transitionend", onEvent);
|
|
1323
|
+
dom.addEventListener(el, "animationend", onEvent);
|
|
1324
|
+
timer = h.setTimeout(finish, duration);
|
|
1325
|
+
nextFrame(() => {
|
|
1326
|
+
if (finished) return;
|
|
1327
|
+
removeClasses(dom, el, from);
|
|
1328
|
+
addClasses(dom, el, to);
|
|
1329
|
+
});
|
|
1330
|
+
return {
|
|
1331
|
+
cancel: () => {
|
|
1332
|
+
if (finished) return;
|
|
1333
|
+
finished = true;
|
|
1334
|
+
detach();
|
|
1335
|
+
removeClasses(dom, el, active);
|
|
1336
|
+
removeClasses(dom, el, to);
|
|
1337
|
+
removeClasses(dom, el, from);
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
var TransitionController = class {
|
|
1342
|
+
constructor(dom, graph, finalize) {
|
|
1343
|
+
this.dom = dom;
|
|
1344
|
+
this.graph = graph;
|
|
1345
|
+
this.finalize = finalize;
|
|
1346
|
+
}
|
|
1347
|
+
leaving = /* @__PURE__ */ new Map();
|
|
1348
|
+
/** True only in a real DOM environment (browser). */
|
|
1349
|
+
get browser() {
|
|
1350
|
+
return this.dom.body() !== null;
|
|
1351
|
+
}
|
|
1352
|
+
keyOf(inst) {
|
|
1353
|
+
return inst.graphNode.key ?? inst.graphNode.id;
|
|
1354
|
+
}
|
|
1355
|
+
resolved(node) {
|
|
1356
|
+
return getResolvedTransition(this.graph, node.id);
|
|
1357
|
+
}
|
|
1358
|
+
/** Run the enter animation for `inst` if it carries a transition (browser only). */
|
|
1359
|
+
enter(inst) {
|
|
1360
|
+
if (!this.browser) return;
|
|
1361
|
+
const rt = this.resolved(inst.graphNode);
|
|
1362
|
+
if (rt === void 0) return;
|
|
1363
|
+
const el = inst.domNode;
|
|
1364
|
+
if (!this.dom.isElement(el)) return;
|
|
1365
|
+
startRun(this.dom, el, rt.enterActive, rt.enterFrom, rt.enterTo, rt.duration, () => {
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Play `appear` for any initial child that opted into it (fresh browser mount
|
|
1370
|
+
* only — hydration must never animate appear, §22, and this is called only on
|
|
1371
|
+
* the mount path).
|
|
1372
|
+
*/
|
|
1373
|
+
appear(children) {
|
|
1374
|
+
if (!this.browser) return;
|
|
1375
|
+
for (const child of children) {
|
|
1376
|
+
const rt = this.resolved(child.graphNode);
|
|
1377
|
+
if (rt !== void 0 && rt.appear) this.enter(child);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
hooks() {
|
|
1381
|
+
return {
|
|
1382
|
+
takeLeaving: (key) => {
|
|
1383
|
+
const entry = this.leaving.get(key);
|
|
1384
|
+
if (entry === void 0) return void 0;
|
|
1385
|
+
entry.run.cancel();
|
|
1386
|
+
this.leaving.delete(key);
|
|
1387
|
+
return entry.inst;
|
|
1388
|
+
},
|
|
1389
|
+
beginLeave: (inst) => {
|
|
1390
|
+
if (!this.browser) return false;
|
|
1391
|
+
const rt = this.resolved(inst.graphNode);
|
|
1392
|
+
if (rt === void 0) return false;
|
|
1393
|
+
const el = inst.domNode;
|
|
1394
|
+
if (!this.dom.isElement(el)) return false;
|
|
1395
|
+
const key = this.keyOf(inst);
|
|
1396
|
+
const prior = this.leaving.get(key);
|
|
1397
|
+
if (prior !== void 0) prior.run.cancel();
|
|
1398
|
+
const run = startRun(
|
|
1399
|
+
this.dom,
|
|
1400
|
+
el,
|
|
1401
|
+
rt.leaveActive,
|
|
1402
|
+
rt.leaveFrom,
|
|
1403
|
+
rt.leaveTo,
|
|
1404
|
+
rt.duration,
|
|
1405
|
+
() => {
|
|
1406
|
+
const current = this.leaving.get(key);
|
|
1407
|
+
if (current !== void 0 && current.run === run) {
|
|
1408
|
+
this.leaving.delete(key);
|
|
1409
|
+
this.finalize(inst);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
);
|
|
1413
|
+
this.leaving.set(key, { inst, run });
|
|
1414
|
+
return true;
|
|
1415
|
+
},
|
|
1416
|
+
onEnter: (inst) => this.enter(inst)
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
|
|
1199
1421
|
// ../renderer/src/mount.ts
|
|
1200
1422
|
var SKIP_PROP_KEYS = /* @__PURE__ */ new Set([
|
|
1201
1423
|
"text",
|
|
@@ -1348,7 +1570,7 @@ function mountNode(ctx, graphNode, parentDom) {
|
|
|
1348
1570
|
instance2.addChild(childInstance);
|
|
1349
1571
|
}
|
|
1350
1572
|
dom.appendChild(parentDom, el2);
|
|
1351
|
-
wireReactiveList(ctx, graphNode, instance2, el2);
|
|
1573
|
+
wireReactiveList(ctx, graphNode, instance2, el2, true);
|
|
1352
1574
|
return instance2;
|
|
1353
1575
|
}
|
|
1354
1576
|
if (graphNode.type === "portal") {
|
|
@@ -1457,32 +1679,42 @@ function wireSignalBindings(ctx, graphNode, instance, onUpdate) {
|
|
|
1457
1679
|
instance.trackCleanup(unsub);
|
|
1458
1680
|
}
|
|
1459
1681
|
}
|
|
1460
|
-
function wireReactiveList(ctx, graphNode, instance, el) {
|
|
1682
|
+
function wireReactiveList(ctx, graphNode, instance, el, runAppear = false) {
|
|
1461
1683
|
const plan = ctx.graph.getHandler(`__listplan__${graphNode.id}`);
|
|
1462
1684
|
const build = ctx.graph.getHandler(`__listbuild__${graphNode.id}`);
|
|
1463
1685
|
if (plan === void 0 && build === void 0) return;
|
|
1686
|
+
const controller = new TransitionController(ctx.dom, ctx.graph, (leaving) => {
|
|
1687
|
+
const parent = ctx.dom.parentNode(leaving.domNode);
|
|
1688
|
+
if (parent !== null) ctx.dom.removeChild(parent, leaving.domNode);
|
|
1689
|
+
leaving.dispose();
|
|
1690
|
+
forgetInstance(ctx, leaving);
|
|
1691
|
+
ctx.graph.detachNode(leaving.graphNode);
|
|
1692
|
+
});
|
|
1693
|
+
const hooks = controller.hooks();
|
|
1694
|
+
if (runAppear) controller.appear(instance.children);
|
|
1464
1695
|
for (const stateRef of graphNode.stateRefs) {
|
|
1465
1696
|
if (stateRef.propKey !== "items") continue;
|
|
1466
1697
|
const sig = ctx.graph.getHandler(`__signal__${stateRef.signalId}`);
|
|
1467
1698
|
if (sig === void 0 || typeof sig.subscribe !== "function") continue;
|
|
1468
1699
|
const unsub = sig.subscribe((value) => {
|
|
1469
1700
|
if (plan !== void 0) {
|
|
1470
|
-
reconcileReactiveListByPlan(ctx, graphNode, instance, el, plan(value));
|
|
1701
|
+
reconcileReactiveListByPlan(ctx, graphNode, instance, el, plan(value), hooks);
|
|
1471
1702
|
} else {
|
|
1472
|
-
reconcileReactiveList(ctx, graphNode, instance, el, build(value));
|
|
1703
|
+
reconcileReactiveList(ctx, graphNode, instance, el, build(value), hooks);
|
|
1473
1704
|
}
|
|
1474
1705
|
});
|
|
1475
1706
|
instance.trackCleanup(unsub);
|
|
1476
1707
|
}
|
|
1477
1708
|
}
|
|
1478
|
-
function reconcileReactiveListByPlan(ctx, listNode, listInstance, listEl, plan) {
|
|
1709
|
+
function reconcileReactiveListByPlan(ctx, listNode, listInstance, listEl, plan, hooks) {
|
|
1479
1710
|
const oldInstances = [...listInstance.children];
|
|
1480
1711
|
const result = reconcileChildrenByPlan(
|
|
1481
1712
|
ctx,
|
|
1482
1713
|
listEl,
|
|
1483
1714
|
oldInstances,
|
|
1484
1715
|
plan,
|
|
1485
|
-
(node, parent) => mountNode(ctx, node, parent)
|
|
1716
|
+
(node, parent) => mountNode(ctx, node, parent),
|
|
1717
|
+
hooks
|
|
1486
1718
|
);
|
|
1487
1719
|
listInstance.children.length = 0;
|
|
1488
1720
|
for (const inst of result.instances) listInstance.children.push(inst);
|
|
@@ -1497,14 +1729,15 @@ function reconcileReactiveListByPlan(ctx, listNode, listInstance, listEl, plan)
|
|
|
1497
1729
|
for (const child of [...listNode.children]) listNode.removeChild(child);
|
|
1498
1730
|
for (const inst of result.instances) listNode.appendChild(inst.graphNode);
|
|
1499
1731
|
}
|
|
1500
|
-
function reconcileReactiveList(ctx, listNode, listInstance, listEl, newNodes) {
|
|
1732
|
+
function reconcileReactiveList(ctx, listNode, listInstance, listEl, newNodes, hooks) {
|
|
1501
1733
|
const oldInstances = [...listInstance.children];
|
|
1502
1734
|
const result = reconcileChildren(
|
|
1503
1735
|
ctx,
|
|
1504
1736
|
listEl,
|
|
1505
1737
|
oldInstances,
|
|
1506
1738
|
newNodes,
|
|
1507
|
-
(node, parent) => mountNode(ctx, node, parent)
|
|
1739
|
+
(node, parent) => mountNode(ctx, node, parent),
|
|
1740
|
+
hooks
|
|
1508
1741
|
);
|
|
1509
1742
|
listInstance.children.length = 0;
|
|
1510
1743
|
for (const inst of result.instances) listInstance.children.push(inst);
|
|
@@ -1540,11 +1773,14 @@ function wireOverlayBehavior(ctx, graphNode, instance, target) {
|
|
|
1540
1773
|
const onOpenChange = (isOpen) => {
|
|
1541
1774
|
if (isOpen) {
|
|
1542
1775
|
if (desc.restoreFocus) saved = saveFocus(dom);
|
|
1543
|
-
if (desc.takesFocus) focusInitial(dom, target, desc.initialFocusId);
|
|
1544
1776
|
if (desc.modal) {
|
|
1545
1777
|
active.push(trapFocus(dom, target));
|
|
1546
1778
|
active.push(containFocus(dom, target));
|
|
1547
1779
|
}
|
|
1780
|
+
if (desc.menu) {
|
|
1781
|
+
active.push(rovingMenu(dom, target));
|
|
1782
|
+
}
|
|
1783
|
+
if (desc.takesFocus) focusInitial(dom, target, desc.initialFocusId);
|
|
1548
1784
|
if (desc.closeOnEscape && desc.onClose !== void 0) {
|
|
1549
1785
|
active.push(onEscape(dom, target, desc.onClose));
|
|
1550
1786
|
}
|
|
@@ -2221,6 +2457,37 @@ async function waitFor(check, options = {}) {
|
|
|
2221
2457
|
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
2222
2458
|
}
|
|
2223
2459
|
}
|
|
2460
|
+
function focus(el) {
|
|
2461
|
+
el.focus?.();
|
|
2462
|
+
}
|
|
2463
|
+
function blur(el) {
|
|
2464
|
+
el.blur?.();
|
|
2465
|
+
}
|
|
2466
|
+
function pressKey(key, el = document.activeElement, init = {}) {
|
|
2467
|
+
if (el === null) return;
|
|
2468
|
+
el.dispatchEvent(
|
|
2469
|
+
new KeyboardEvent("keydown", { key, bubbles: true, cancelable: true, ...init })
|
|
2470
|
+
);
|
|
2471
|
+
}
|
|
2472
|
+
function clickOutside(container, target = document.body) {
|
|
2473
|
+
if (container.contains(target)) {
|
|
2474
|
+
throw new Error("[StreetUI Testing] clickOutside: target is inside the container");
|
|
2475
|
+
}
|
|
2476
|
+
target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true }));
|
|
2477
|
+
target.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
2478
|
+
}
|
|
2479
|
+
async function openOverlay(open) {
|
|
2480
|
+
open.set(true);
|
|
2481
|
+
await flushUpdates();
|
|
2482
|
+
}
|
|
2483
|
+
async function closeOverlay(open) {
|
|
2484
|
+
open.set(false);
|
|
2485
|
+
await flushUpdates();
|
|
2486
|
+
}
|
|
2487
|
+
async function waitForTransition(el) {
|
|
2488
|
+
el.dispatchEvent(new Event("transitionend", { bubbles: true }));
|
|
2489
|
+
await flushUpdates();
|
|
2490
|
+
}
|
|
2224
2491
|
function findByText(container, text) {
|
|
2225
2492
|
const match = Array.from(container.querySelectorAll("*")).find(
|
|
2226
2493
|
(el) => el.children.length === 0 && (el.textContent?.includes(text) ?? false)
|
|
@@ -2315,6 +2582,42 @@ function renderServerThenHydrate(build, options = {}) {
|
|
|
2315
2582
|
};
|
|
2316
2583
|
}
|
|
2317
2584
|
|
|
2585
|
+
// ../dsl/src/transition.ts
|
|
2586
|
+
function classes(value) {
|
|
2587
|
+
if (value === void 0) return [];
|
|
2588
|
+
const out = [];
|
|
2589
|
+
for (const token of value.split(/\s+/)) {
|
|
2590
|
+
if (token.length > 0 && !out.includes(token)) out.push(token);
|
|
2591
|
+
}
|
|
2592
|
+
return out;
|
|
2593
|
+
}
|
|
2594
|
+
function merge(a, b) {
|
|
2595
|
+
const out = [...a];
|
|
2596
|
+
for (const token of b) if (!out.includes(token)) out.push(token);
|
|
2597
|
+
return out;
|
|
2598
|
+
}
|
|
2599
|
+
function resolveTransition(config) {
|
|
2600
|
+
const n = config.name;
|
|
2601
|
+
const enterActive = merge(
|
|
2602
|
+
classes(config.enter),
|
|
2603
|
+
classes(config.enterActive ?? (n !== void 0 ? `${n}-enter-active` : void 0))
|
|
2604
|
+
);
|
|
2605
|
+
const leaveActive = merge(
|
|
2606
|
+
classes(config.leave),
|
|
2607
|
+
classes(config.leaveActive ?? (n !== void 0 ? `${n}-leave-active` : void 0))
|
|
2608
|
+
);
|
|
2609
|
+
return {
|
|
2610
|
+
enterActive,
|
|
2611
|
+
enterFrom: classes(config.enterFrom ?? (n !== void 0 ? `${n}-enter-from` : void 0)),
|
|
2612
|
+
enterTo: classes(config.enterTo ?? (n !== void 0 ? `${n}-enter-to` : void 0)),
|
|
2613
|
+
leaveActive,
|
|
2614
|
+
leaveFrom: classes(config.leaveFrom ?? (n !== void 0 ? `${n}-leave-from` : void 0)),
|
|
2615
|
+
leaveTo: classes(config.leaveTo ?? (n !== void 0 ? `${n}-leave-to` : void 0)),
|
|
2616
|
+
appear: config.appear ?? false,
|
|
2617
|
+
duration: config.duration ?? 1e3
|
|
2618
|
+
};
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2318
2621
|
// ../state/src/signal.ts
|
|
2319
2622
|
var _activeConsumer = null;
|
|
2320
2623
|
function withConsumer(consumer, fn) {
|
|
@@ -2524,6 +2827,18 @@ function applyA11yProps(props, options) {
|
|
|
2524
2827
|
if (options.ariaInvalid !== void 0) props["aria-invalid"] = String(options.ariaInvalid);
|
|
2525
2828
|
if (options.ariaRequired !== void 0) props["aria-required"] = String(options.ariaRequired);
|
|
2526
2829
|
if (options.ariaModal !== void 0) props["aria-modal"] = String(options.ariaModal);
|
|
2830
|
+
if (options.ariaOwns !== void 0) props["aria-owns"] = options.ariaOwns;
|
|
2831
|
+
if (options.ariaActiveDescendant !== void 0) props["aria-activedescendant"] = options.ariaActiveDescendant;
|
|
2832
|
+
if (options.ariaHasPopup !== void 0) props["aria-haspopup"] = String(options.ariaHasPopup);
|
|
2833
|
+
if (options.ariaSelected !== void 0) props["aria-selected"] = String(options.ariaSelected);
|
|
2834
|
+
}
|
|
2835
|
+
function registerTransition(graph, node, config) {
|
|
2836
|
+
if (config === void 0) return;
|
|
2837
|
+
const resolved = resolveTransition(config);
|
|
2838
|
+
graph.registerHandler(
|
|
2839
|
+
`__transition__${node.id}`,
|
|
2840
|
+
() => resolved
|
|
2841
|
+
);
|
|
2527
2842
|
}
|
|
2528
2843
|
function containerProps(options) {
|
|
2529
2844
|
const props = {};
|
|
@@ -2584,6 +2899,7 @@ var OVERLAY_KINDS = {
|
|
|
2584
2899
|
role: "menu",
|
|
2585
2900
|
modal: false,
|
|
2586
2901
|
takesFocus: true,
|
|
2902
|
+
menu: true,
|
|
2587
2903
|
ariaModal: false,
|
|
2588
2904
|
defaultCloseOnEscape: true,
|
|
2589
2905
|
defaultRestoreFocus: true
|
|
@@ -2716,6 +3032,7 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
2716
3032
|
parent: this._node,
|
|
2717
3033
|
props: containerProps(options)
|
|
2718
3034
|
});
|
|
3035
|
+
registerTransition(this._graph, node, options.transition);
|
|
2719
3036
|
builder(new SectionBuilderImpl(node, this._graph));
|
|
2720
3037
|
}
|
|
2721
3038
|
container(key, builder, options = {}) {
|
|
@@ -2724,6 +3041,7 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
2724
3041
|
parent: this._node,
|
|
2725
3042
|
props: containerProps(options)
|
|
2726
3043
|
});
|
|
3044
|
+
registerTransition(this._graph, node, options.transition);
|
|
2727
3045
|
builder(new ContainerBuilderImpl(node, this._graph));
|
|
2728
3046
|
}
|
|
2729
3047
|
list(key, builder, options = {}) {
|
|
@@ -2732,6 +3050,7 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
2732
3050
|
parent: this._node,
|
|
2733
3051
|
props: containerProps(options)
|
|
2734
3052
|
});
|
|
3053
|
+
registerTransition(this._graph, node, options.transition);
|
|
2735
3054
|
builder(new ListBuilderImpl(node, this._graph));
|
|
2736
3055
|
}
|
|
2737
3056
|
listOf(key, items, renderItem, options = {}) {
|
|
@@ -2741,6 +3060,7 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
2741
3060
|
parent: this._node,
|
|
2742
3061
|
props: containerProps(options)
|
|
2743
3062
|
});
|
|
3063
|
+
registerTransition(graph, node, options.transition);
|
|
2744
3064
|
const signalId = `${node.id}:items`;
|
|
2745
3065
|
node.stateRefs.push({ signalId, propKey: "items" });
|
|
2746
3066
|
graph.registerHandler(`__signal__${signalId}`, items);
|
|
@@ -2762,6 +3082,7 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
2762
3082
|
}
|
|
2763
3083
|
});
|
|
2764
3084
|
renderItem(item, index, new ContainerBuilderImpl(itemNode, graph));
|
|
3085
|
+
registerTransition(graph, itemNode, options.itemTransition);
|
|
2765
3086
|
return itemNode;
|
|
2766
3087
|
};
|
|
2767
3088
|
const buildPlan = (raw) => {
|
|
@@ -2793,6 +3114,7 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
2793
3114
|
parent: this._node,
|
|
2794
3115
|
props
|
|
2795
3116
|
});
|
|
3117
|
+
registerTransition(this._graph, node, options.transition);
|
|
2796
3118
|
if (options.onSubmit !== void 0) {
|
|
2797
3119
|
const handlerKey = `submit:${node.id}`;
|
|
2798
3120
|
this._graph.registerHandler(handlerKey, options.onSubmit);
|
|
@@ -2800,18 +3122,20 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
2800
3122
|
}
|
|
2801
3123
|
builder(new FormBuilderImpl(node, this._graph));
|
|
2802
3124
|
}
|
|
2803
|
-
when(condition, builder, elseBuilder) {
|
|
3125
|
+
when(condition, builder, elseBuilder, options = {}) {
|
|
2804
3126
|
const graph = this._graph;
|
|
2805
3127
|
const node = graph.createNode("conditional", {
|
|
2806
3128
|
parent: this._node,
|
|
2807
3129
|
props: containerProps({})
|
|
2808
3130
|
});
|
|
3131
|
+
const branchTransition = options.transition !== void 0 && options.appear === true ? { ...options.transition, appear: true } : options.transition;
|
|
2809
3132
|
const buildBranch = (build, tag) => {
|
|
2810
3133
|
const branchKey = `when-${tag}:${node.id}`;
|
|
2811
3134
|
const branch = graph.createNode("container", {
|
|
2812
3135
|
key: branchKey,
|
|
2813
3136
|
props: { key: branchKey }
|
|
2814
3137
|
});
|
|
3138
|
+
registerTransition(graph, branch, branchTransition);
|
|
2815
3139
|
build(new ContainerBuilderImpl(branch, graph));
|
|
2816
3140
|
return branch;
|
|
2817
3141
|
};
|
|
@@ -2906,13 +3230,24 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
2906
3230
|
...options.ariaDescribedBy !== void 0 ? { ariaDescribedBy: options.ariaDescribedBy } : {}
|
|
2907
3231
|
};
|
|
2908
3232
|
const portalBuilder = new ContainerBuilderImpl(portalNode, graph);
|
|
2909
|
-
portalBuilder.when(
|
|
2910
|
-
|
|
2911
|
-
|
|
3233
|
+
portalBuilder.when(
|
|
3234
|
+
openSignal,
|
|
3235
|
+
(panelHost) => {
|
|
3236
|
+
panelHost.container(`${key}__panel`, builder, panelOptions);
|
|
3237
|
+
},
|
|
3238
|
+
void 0,
|
|
3239
|
+
// Overlay open/close rides the panel's `when`; a transition animates the
|
|
3240
|
+
// panel in on open and — via the reconciler's deferred-leave — plays the
|
|
3241
|
+
// leave before the panel is removed (§10). Focus is restored at close-
|
|
3242
|
+
// request time (see wireOverlayBehavior), so it never stays trapped inside
|
|
3243
|
+
// a panel that is animating away.
|
|
3244
|
+
options.transition !== void 0 ? { transition: options.transition } : {}
|
|
3245
|
+
);
|
|
2912
3246
|
const descriptor = {
|
|
2913
3247
|
open: openSignal,
|
|
2914
3248
|
modal: kind.modal,
|
|
2915
3249
|
takesFocus: kind.takesFocus,
|
|
3250
|
+
menu: kind.menu ?? false,
|
|
2916
3251
|
closeOnEscape: options.closeOnEscape ?? kind.defaultCloseOnEscape,
|
|
2917
3252
|
restoreFocus: options.restoreFocus ?? kind.defaultRestoreFocus,
|
|
2918
3253
|
...options.initialFocusId !== void 0 ? { initialFocusId: options.initialFocusId } : {},
|
|
@@ -3009,6 +3344,7 @@ var ListBuilderImpl = class extends ContentBuilderBase {
|
|
|
3009
3344
|
parent: this._node,
|
|
3010
3345
|
props: containerProps(options)
|
|
3011
3346
|
});
|
|
3347
|
+
registerTransition(this._graph, node, options.transition);
|
|
3012
3348
|
builder(new ContainerBuilderImpl(node, this._graph));
|
|
3013
3349
|
}
|
|
3014
3350
|
};
|
|
@@ -3196,6 +3532,7 @@ var ApplicationGraph = class {
|
|
|
3196
3532
|
this.handlers.delete(`__listplan__${node.id}`);
|
|
3197
3533
|
this.handlers.delete(`__overlay__${node.id}`);
|
|
3198
3534
|
this.handlers.delete(`__component__${node.id}`);
|
|
3535
|
+
this.handlers.delete(`__transition__${node.id}`);
|
|
3199
3536
|
}
|
|
3200
3537
|
// ── Handler registry ──────────────────────────────────────────────────────
|
|
3201
3538
|
registerHandler(key, fn) {
|
|
@@ -3373,25 +3710,32 @@ function trigger(el, type, init = {}) {
|
|
|
3373
3710
|
}
|
|
3374
3711
|
|
|
3375
3712
|
// src/version.ts
|
|
3376
|
-
var VERSION = "1.
|
|
3713
|
+
var VERSION = "1.9.0";
|
|
3377
3714
|
export {
|
|
3378
3715
|
VERSION,
|
|
3379
3716
|
analyzeGraph,
|
|
3717
|
+
blur,
|
|
3718
|
+
clickOutside,
|
|
3719
|
+
closeOverlay,
|
|
3380
3720
|
findAllByRole,
|
|
3381
3721
|
findAllComponents,
|
|
3382
3722
|
findByRole,
|
|
3383
3723
|
findByText,
|
|
3384
3724
|
findComponent,
|
|
3385
3725
|
flushUpdates,
|
|
3726
|
+
focus,
|
|
3386
3727
|
formatInspection,
|
|
3387
3728
|
getComponentName,
|
|
3388
3729
|
hydrateComponent,
|
|
3389
3730
|
inspectCompilation,
|
|
3731
|
+
openOverlay,
|
|
3732
|
+
pressKey,
|
|
3390
3733
|
render,
|
|
3391
3734
|
renderComponent,
|
|
3392
3735
|
renderOnce,
|
|
3393
3736
|
renderServerThenHydrate,
|
|
3394
3737
|
trigger,
|
|
3395
|
-
waitFor
|
|
3738
|
+
waitFor,
|
|
3739
|
+
waitForTransition
|
|
3396
3740
|
};
|
|
3397
3741
|
//# sourceMappingURL=testing.js.map
|