streetui 1.6.1 → 1.8.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-CEom4hkp.d.cts → compile-CJJQYi71.d.cts} +215 -3
- package/dist/{compile-CEom4hkp.d.ts → compile-CJJQYi71.d.ts} +215 -3
- 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-D286jpZZ.d.cts → hydration-diagnostics-BQeehq3i.d.cts} +1 -1
- package/dist/{hydration-diagnostics-YrG-OJJe.d.ts → hydration-diagnostics-DNAJumYF.d.ts} +1 -1
- package/dist/index.cjs +402 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -7
- package/dist/index.d.ts +94 -7
- package/dist/index.js +390 -3
- package/dist/index.js.map +1 -1
- package/dist/{server-ZBh5DO-z.d.cts → server-CnLEnlYU.d.cts} +17 -1
- package/dist/{server-jbB-7oN-.d.ts → server-DNlg7ou2.d.ts} +17 -1
- package/dist/server.cjs +1025 -865
- 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 +1025 -865
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +1273 -3
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +63 -4
- package/dist/testing.d.ts +63 -4
- package/dist/testing.js +1267 -3
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var VERSION = "1.
|
|
2
|
+
var VERSION = "1.8.0";
|
|
3
3
|
|
|
4
4
|
// ../state/src/signal.ts
|
|
5
5
|
var _activeConsumer = null;
|
|
@@ -802,6 +802,8 @@ var ApplicationGraph = class {
|
|
|
802
802
|
}
|
|
803
803
|
this.handlers.delete(`__listbuild__${node.id}`);
|
|
804
804
|
this.handlers.delete(`__listplan__${node.id}`);
|
|
805
|
+
this.handlers.delete(`__overlay__${node.id}`);
|
|
806
|
+
this.handlers.delete(`__component__${node.id}`);
|
|
805
807
|
}
|
|
806
808
|
// ── Handler registry ──────────────────────────────────────────────────────
|
|
807
809
|
registerHandler(key, fn) {
|
|
@@ -916,6 +918,7 @@ function applyA11yProps(props, options) {
|
|
|
916
918
|
if (options.ariaCurrent !== void 0) props["aria-current"] = String(options.ariaCurrent);
|
|
917
919
|
if (options.ariaInvalid !== void 0) props["aria-invalid"] = String(options.ariaInvalid);
|
|
918
920
|
if (options.ariaRequired !== void 0) props["aria-required"] = String(options.ariaRequired);
|
|
921
|
+
if (options.ariaModal !== void 0) props["aria-modal"] = String(options.ariaModal);
|
|
919
922
|
}
|
|
920
923
|
function containerProps(options) {
|
|
921
924
|
const props = {};
|
|
@@ -947,6 +950,49 @@ function reactiveListItemSignature(item) {
|
|
|
947
950
|
function reactiveListItemKey(item, index) {
|
|
948
951
|
return itemIdentity(item, index);
|
|
949
952
|
}
|
|
953
|
+
var OVERLAY_KINDS = {
|
|
954
|
+
dialog: {
|
|
955
|
+
role: "dialog",
|
|
956
|
+
modal: true,
|
|
957
|
+
takesFocus: true,
|
|
958
|
+
ariaModal: true,
|
|
959
|
+
defaultCloseOnEscape: true,
|
|
960
|
+
defaultRestoreFocus: true
|
|
961
|
+
},
|
|
962
|
+
popover: {
|
|
963
|
+
role: "dialog",
|
|
964
|
+
modal: false,
|
|
965
|
+
takesFocus: true,
|
|
966
|
+
ariaModal: false,
|
|
967
|
+
defaultCloseOnEscape: true,
|
|
968
|
+
defaultRestoreFocus: true
|
|
969
|
+
},
|
|
970
|
+
tooltip: {
|
|
971
|
+
role: "tooltip",
|
|
972
|
+
modal: false,
|
|
973
|
+
takesFocus: false,
|
|
974
|
+
ariaModal: false,
|
|
975
|
+
defaultCloseOnEscape: false,
|
|
976
|
+
defaultRestoreFocus: false
|
|
977
|
+
},
|
|
978
|
+
dropdown: {
|
|
979
|
+
role: "menu",
|
|
980
|
+
modal: false,
|
|
981
|
+
takesFocus: true,
|
|
982
|
+
ariaModal: false,
|
|
983
|
+
defaultCloseOnEscape: true,
|
|
984
|
+
defaultRestoreFocus: true
|
|
985
|
+
},
|
|
986
|
+
toast: {
|
|
987
|
+
role: "status",
|
|
988
|
+
modal: false,
|
|
989
|
+
takesFocus: false,
|
|
990
|
+
ariaModal: false,
|
|
991
|
+
ariaLive: "polite",
|
|
992
|
+
defaultCloseOnEscape: false,
|
|
993
|
+
defaultRestoreFocus: false
|
|
994
|
+
}
|
|
995
|
+
};
|
|
950
996
|
var ContentBuilderBase = class {
|
|
951
997
|
constructor(_node, _graph) {
|
|
952
998
|
this._node = _node;
|
|
@@ -1219,6 +1265,131 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
1219
1265
|
);
|
|
1220
1266
|
}, { id });
|
|
1221
1267
|
}
|
|
1268
|
+
// ── Portals & overlays ──────────────────────────────────────────────────────
|
|
1269
|
+
portal(key, builder, options = {}) {
|
|
1270
|
+
const node = this._graph.createNode("portal", {
|
|
1271
|
+
key,
|
|
1272
|
+
parent: this._node,
|
|
1273
|
+
props: containerProps(options)
|
|
1274
|
+
});
|
|
1275
|
+
builder(new ContainerBuilderImpl(node, this._graph));
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Shared assembly for every overlay kind: a `portal` node whose single child
|
|
1279
|
+
* is a `when(open, panel)` conditional. The panel container carries the
|
|
1280
|
+
* kind's ARIA semantics; `builder` fills it. An `__overlay__<portalId>`
|
|
1281
|
+
* descriptor is registered so the renderer wires focus/keyboard behavior to
|
|
1282
|
+
* the same `open` signal that drives the panel. Reuses existing primitives
|
|
1283
|
+
* (portal + when + container) — no new render path.
|
|
1284
|
+
*/
|
|
1285
|
+
_overlay(kind, key, options, builder) {
|
|
1286
|
+
const graph = this._graph;
|
|
1287
|
+
const portalNode = graph.createNode("portal", {
|
|
1288
|
+
key,
|
|
1289
|
+
parent: this._node,
|
|
1290
|
+
props: { key }
|
|
1291
|
+
});
|
|
1292
|
+
const openBindable = options.open;
|
|
1293
|
+
const openSignal = isSignal(openBindable) ? openBindable : signal(openBindable);
|
|
1294
|
+
const panelOptions = {
|
|
1295
|
+
role: options.role ?? kind.role,
|
|
1296
|
+
...kind.ariaModal ? { ariaModal: true } : {},
|
|
1297
|
+
...kind.ariaLive !== void 0 ? { ariaLive: kind.ariaLive } : {},
|
|
1298
|
+
...options.class !== void 0 ? { class: options.class } : {},
|
|
1299
|
+
...options.ariaLabel !== void 0 ? { ariaLabel: options.ariaLabel } : {},
|
|
1300
|
+
...options.ariaLabelledBy !== void 0 ? { ariaLabelledBy: options.ariaLabelledBy } : {},
|
|
1301
|
+
...options.ariaDescribedBy !== void 0 ? { ariaDescribedBy: options.ariaDescribedBy } : {}
|
|
1302
|
+
};
|
|
1303
|
+
const portalBuilder = new ContainerBuilderImpl(portalNode, graph);
|
|
1304
|
+
portalBuilder.when(openSignal, (panelHost) => {
|
|
1305
|
+
panelHost.container(`${key}__panel`, builder, panelOptions);
|
|
1306
|
+
});
|
|
1307
|
+
const descriptor = {
|
|
1308
|
+
open: openSignal,
|
|
1309
|
+
modal: kind.modal,
|
|
1310
|
+
takesFocus: kind.takesFocus,
|
|
1311
|
+
closeOnEscape: options.closeOnEscape ?? kind.defaultCloseOnEscape,
|
|
1312
|
+
restoreFocus: options.restoreFocus ?? kind.defaultRestoreFocus,
|
|
1313
|
+
...options.initialFocusId !== void 0 ? { initialFocusId: options.initialFocusId } : {},
|
|
1314
|
+
...options.onClose !== void 0 ? { onClose: options.onClose } : {}
|
|
1315
|
+
};
|
|
1316
|
+
graph.registerHandler(
|
|
1317
|
+
`__overlay__${portalNode.id}`,
|
|
1318
|
+
() => descriptor
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
dialog(key, options, builder) {
|
|
1322
|
+
this._overlay(OVERLAY_KINDS.dialog, key, options, builder);
|
|
1323
|
+
}
|
|
1324
|
+
popover(key, options, builder) {
|
|
1325
|
+
this._overlay(OVERLAY_KINDS.popover, key, options, builder);
|
|
1326
|
+
}
|
|
1327
|
+
tooltip(key, options, builder) {
|
|
1328
|
+
this._overlay(OVERLAY_KINDS.tooltip, key, options, builder);
|
|
1329
|
+
}
|
|
1330
|
+
dropdown(key, options, builder) {
|
|
1331
|
+
this._overlay(OVERLAY_KINDS.dropdown, key, options, builder);
|
|
1332
|
+
}
|
|
1333
|
+
toast(key, options, builder) {
|
|
1334
|
+
this._overlay(OVERLAY_KINDS.toast, key, options, builder);
|
|
1335
|
+
}
|
|
1336
|
+
// ── Components ────────────────────────────────────────────────────────────
|
|
1337
|
+
/**
|
|
1338
|
+
* Instantiate a reusable component (§3–§9). Creates a `'component'` node
|
|
1339
|
+
* (rendered as a `<div>` wrapper — preserves the one-node/one-element
|
|
1340
|
+
* positional-hydration invariant), then runs `def.setup(props, ctx)`
|
|
1341
|
+
* synchronously to obtain the render function and fills the component's own
|
|
1342
|
+
* container scope with it — structurally identical to `container`/
|
|
1343
|
+
* `errorBoundary`. Cleanups the setup registers via `ctx.effect`/
|
|
1344
|
+
* `ctx.onCleanup` are collected into a closure and exposed to the renderer
|
|
1345
|
+
* through a `__component__<id>` handler (mirroring `__overlay__`); the mount/
|
|
1346
|
+
* hydrate paths read it and route each into `NodeInstance.trackCleanup`, so
|
|
1347
|
+
* teardown runs (children-first) when the component leaves the graph.
|
|
1348
|
+
*
|
|
1349
|
+
* `setup` runs once per instance here at build time. When this component sits
|
|
1350
|
+
* inside a keyed list / conditional, a rebuild disposes the old instance
|
|
1351
|
+
* (running its cleanups + pruning its `__component__` entry) and re-runs this
|
|
1352
|
+
* method for the new node — so re-invocation is safe and leak-free.
|
|
1353
|
+
*/
|
|
1354
|
+
component(key, def, props, children) {
|
|
1355
|
+
const graph = this._graph;
|
|
1356
|
+
const node = graph.createNode("component", {
|
|
1357
|
+
key,
|
|
1358
|
+
parent: this._node,
|
|
1359
|
+
// `data-streetui-component` is a non-underscore prop, so it reaches the
|
|
1360
|
+
// DOM as an attribute and is visible to DevTools (§21) — unlike the
|
|
1361
|
+
// internal `_`-prefixed metadata the renderer hides.
|
|
1362
|
+
props: { key, "data-streetui-component": def.name }
|
|
1363
|
+
});
|
|
1364
|
+
const cleanups = [];
|
|
1365
|
+
const ctx = {
|
|
1366
|
+
key,
|
|
1367
|
+
onCleanup(fn) {
|
|
1368
|
+
cleanups.push(fn);
|
|
1369
|
+
},
|
|
1370
|
+
effect(fn) {
|
|
1371
|
+
cleanups.push(effect(fn));
|
|
1372
|
+
},
|
|
1373
|
+
renderChildren(content) {
|
|
1374
|
+
if (children !== void 0) children(content);
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
let render;
|
|
1378
|
+
try {
|
|
1379
|
+
render = def.setup(props, ctx);
|
|
1380
|
+
render(new ContainerBuilderImpl(node, graph));
|
|
1381
|
+
} catch (err) {
|
|
1382
|
+
queueMicrotask(() => {
|
|
1383
|
+
throw err;
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
if (cleanups.length > 0) {
|
|
1387
|
+
graph.registerHandler(
|
|
1388
|
+
`__component__${node.id}`,
|
|
1389
|
+
() => cleanups
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1222
1393
|
};
|
|
1223
1394
|
var SectionBuilderImpl = class extends ContainerBuilderBase {
|
|
1224
1395
|
};
|
|
@@ -1252,6 +1423,18 @@ var AppBuilder = class {
|
|
|
1252
1423
|
}
|
|
1253
1424
|
};
|
|
1254
1425
|
|
|
1426
|
+
// ../dsl/src/component.ts
|
|
1427
|
+
function component(setup, options = {}) {
|
|
1428
|
+
return {
|
|
1429
|
+
__streetui_component: true,
|
|
1430
|
+
name: options.name ?? setup.name ?? "Component",
|
|
1431
|
+
setup
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
function isComponentDefinition(value) {
|
|
1435
|
+
return value !== null && typeof value === "object" && value.__streetui_component === true;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1255
1438
|
// ../dsl/src/dsl.ts
|
|
1256
1439
|
var StreetApp = class {
|
|
1257
1440
|
_graph;
|
|
@@ -1819,6 +2002,18 @@ var BrowserDOMAdapter = class {
|
|
|
1819
2002
|
focus(element) {
|
|
1820
2003
|
element.focus?.();
|
|
1821
2004
|
}
|
|
2005
|
+
body() {
|
|
2006
|
+
return document.body ?? null;
|
|
2007
|
+
}
|
|
2008
|
+
activeElement() {
|
|
2009
|
+
return document.activeElement ?? null;
|
|
2010
|
+
}
|
|
2011
|
+
contains(ancestor, node) {
|
|
2012
|
+
return ancestor.contains(node);
|
|
2013
|
+
}
|
|
2014
|
+
matches(element, selector) {
|
|
2015
|
+
return typeof element.matches === "function" && element.matches(selector);
|
|
2016
|
+
}
|
|
1822
2017
|
isElement(node) {
|
|
1823
2018
|
return node.nodeType === Node.ELEMENT_NODE;
|
|
1824
2019
|
}
|
|
@@ -2186,6 +2381,18 @@ var ServerDOMAdapter = class {
|
|
|
2186
2381
|
}
|
|
2187
2382
|
focus() {
|
|
2188
2383
|
}
|
|
2384
|
+
body() {
|
|
2385
|
+
return null;
|
|
2386
|
+
}
|
|
2387
|
+
activeElement() {
|
|
2388
|
+
return null;
|
|
2389
|
+
}
|
|
2390
|
+
contains(_ancestor, _node) {
|
|
2391
|
+
return false;
|
|
2392
|
+
}
|
|
2393
|
+
matches(_element, _selector) {
|
|
2394
|
+
return false;
|
|
2395
|
+
}
|
|
2189
2396
|
isElement(node) {
|
|
2190
2397
|
return asServer(node).kind === "element";
|
|
2191
2398
|
}
|
|
@@ -2251,6 +2458,66 @@ function focusFirst(dom, container, selector = FOCUSABLE_SELECTOR) {
|
|
|
2251
2458
|
dom.focus(el);
|
|
2252
2459
|
return true;
|
|
2253
2460
|
}
|
|
2461
|
+
function getFocusable(dom, container, selector = FOCUSABLE_SELECTOR) {
|
|
2462
|
+
return Array.from(dom.querySelectorAll(container, selector)).filter(
|
|
2463
|
+
(el) => dom.matches(el, selector)
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2466
|
+
function saveFocus(dom) {
|
|
2467
|
+
return dom.activeElement();
|
|
2468
|
+
}
|
|
2469
|
+
function restoreFocus(dom, saved) {
|
|
2470
|
+
if (saved !== null) dom.focus(saved);
|
|
2471
|
+
}
|
|
2472
|
+
function focusInitial(dom, container, initialFocusId) {
|
|
2473
|
+
if (initialFocusId !== void 0 && focusById(dom, container, initialFocusId)) return;
|
|
2474
|
+
focusFirst(dom, container);
|
|
2475
|
+
}
|
|
2476
|
+
function trapFocus(dom, container) {
|
|
2477
|
+
const onKeydown = (event) => {
|
|
2478
|
+
if (event.key !== "Tab") return;
|
|
2479
|
+
const items = getFocusable(dom, container);
|
|
2480
|
+
if (items.length === 0) {
|
|
2481
|
+
event.preventDefault();
|
|
2482
|
+
return;
|
|
2483
|
+
}
|
|
2484
|
+
const first = items[0];
|
|
2485
|
+
const last = items[items.length - 1];
|
|
2486
|
+
const active = dom.activeElement();
|
|
2487
|
+
if (active === null || !dom.contains(container, active)) {
|
|
2488
|
+
event.preventDefault();
|
|
2489
|
+
dom.focus(first);
|
|
2490
|
+
} else if (event.shiftKey && active === first) {
|
|
2491
|
+
event.preventDefault();
|
|
2492
|
+
dom.focus(last);
|
|
2493
|
+
} else if (!event.shiftKey && active === last) {
|
|
2494
|
+
event.preventDefault();
|
|
2495
|
+
dom.focus(first);
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
dom.addEventListener(container, "keydown", onKeydown);
|
|
2499
|
+
return () => dom.removeEventListener(container, "keydown", onKeydown);
|
|
2500
|
+
}
|
|
2501
|
+
function containFocus(dom, container) {
|
|
2502
|
+
const body = dom.body();
|
|
2503
|
+
if (body === null) return () => {
|
|
2504
|
+
};
|
|
2505
|
+
const onFocusIn = (event) => {
|
|
2506
|
+
const target = event.target;
|
|
2507
|
+
if (target !== null && !dom.contains(container, target)) {
|
|
2508
|
+
focusFirst(dom, container);
|
|
2509
|
+
}
|
|
2510
|
+
};
|
|
2511
|
+
dom.addEventListener(body, "focusin", onFocusIn);
|
|
2512
|
+
return () => dom.removeEventListener(body, "focusin", onFocusIn);
|
|
2513
|
+
}
|
|
2514
|
+
function onEscape(dom, target, handler) {
|
|
2515
|
+
const onKeydown = (event) => {
|
|
2516
|
+
if (event.key === "Escape") handler();
|
|
2517
|
+
};
|
|
2518
|
+
dom.addEventListener(target, "keydown", onKeydown);
|
|
2519
|
+
return () => dom.removeEventListener(target, "keydown", onKeydown);
|
|
2520
|
+
}
|
|
2254
2521
|
|
|
2255
2522
|
// ../renderer/src/render-context.ts
|
|
2256
2523
|
function createRenderContext(dom, graph, container, hydrationDiagnostics, staticHTML) {
|
|
@@ -2409,7 +2676,12 @@ var TAG_MAP = {
|
|
|
2409
2676
|
component: "div",
|
|
2410
2677
|
slot: "div",
|
|
2411
2678
|
fragment: "div",
|
|
2412
|
-
"reactive-list": "ul"
|
|
2679
|
+
"reactive-list": "ul",
|
|
2680
|
+
// A portal renders as a neutral inline anchor <div> at its declaration site;
|
|
2681
|
+
// its children are relocated to a document.body container on the browser
|
|
2682
|
+
// (see the portal branch in mount.ts). On the server (no body) it renders
|
|
2683
|
+
// inline, so the anchor tag is what SSR/hydration positionally match on.
|
|
2684
|
+
portal: "div"
|
|
2413
2685
|
};
|
|
2414
2686
|
function resolveTag(type) {
|
|
2415
2687
|
return TAG_MAP[type] ?? "div";
|
|
@@ -2821,6 +3093,28 @@ function mountNode(ctx, graphNode, parentDom) {
|
|
|
2821
3093
|
wireReactiveList(ctx, graphNode, instance2, el2);
|
|
2822
3094
|
return instance2;
|
|
2823
3095
|
}
|
|
3096
|
+
if (graphNode.type === "portal") {
|
|
3097
|
+
const anchor = dom.createElement(resolveTag("portal"));
|
|
3098
|
+
dom.setAttribute(anchor, "data-streetui-portal", "");
|
|
3099
|
+
applyNodeProps(ctx, graphNode, anchor);
|
|
3100
|
+
const instance2 = new NodeInstance(graphNode, anchor);
|
|
3101
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
3102
|
+
const body = dom.body();
|
|
3103
|
+
let target = anchor;
|
|
3104
|
+
if (body !== null) {
|
|
3105
|
+
const portalContainer = dom.createElement("div");
|
|
3106
|
+
dom.setAttribute(portalContainer, "data-streetui-portal-container", "");
|
|
3107
|
+
dom.appendChild(body, portalContainer);
|
|
3108
|
+
instance2.trackCleanup(() => dom.removeChild(body, portalContainer));
|
|
3109
|
+
target = portalContainer;
|
|
3110
|
+
}
|
|
3111
|
+
for (const child of graphNode.children) {
|
|
3112
|
+
instance2.addChild(mountNode(ctx, child, target));
|
|
3113
|
+
}
|
|
3114
|
+
dom.appendChild(parentDom, anchor);
|
|
3115
|
+
wireOverlayBehavior(ctx, graphNode, instance2, target);
|
|
3116
|
+
return instance2;
|
|
3117
|
+
}
|
|
2824
3118
|
const tag = resolveTag(graphNode.type);
|
|
2825
3119
|
const el = dom.createElement(tag);
|
|
2826
3120
|
applyNodeProps(ctx, graphNode, el);
|
|
@@ -2840,6 +3134,7 @@ function mountNode(ctx, graphNode, parentDom) {
|
|
|
2840
3134
|
instance.addChild(childInstance);
|
|
2841
3135
|
}
|
|
2842
3136
|
dom.appendChild(parentDom, el);
|
|
3137
|
+
if (graphNode.type === "component") wireComponentBehavior(ctx, graphNode, instance);
|
|
2843
3138
|
return instance;
|
|
2844
3139
|
}
|
|
2845
3140
|
function textUpdate(dom, el, textNode) {
|
|
@@ -2970,6 +3265,49 @@ function forgetInstance(ctx, instance) {
|
|
|
2970
3265
|
ctx.instances.delete(instance.graphNode.id);
|
|
2971
3266
|
for (const child of instance.children) forgetInstance(ctx, child);
|
|
2972
3267
|
}
|
|
3268
|
+
function wireOverlayBehavior(ctx, graphNode, instance, target) {
|
|
3269
|
+
const { dom, graph } = ctx;
|
|
3270
|
+
if (dom.body() === null) return;
|
|
3271
|
+
const descFn = graph.getHandler(`__overlay__${graphNode.id}`);
|
|
3272
|
+
if (descFn === void 0) return;
|
|
3273
|
+
const desc = descFn();
|
|
3274
|
+
const openSig = desc.open;
|
|
3275
|
+
if (openSig === void 0 || typeof openSig.subscribe !== "function") return;
|
|
3276
|
+
let active = [];
|
|
3277
|
+
let saved = null;
|
|
3278
|
+
const teardown = () => {
|
|
3279
|
+
for (const fn of active) fn();
|
|
3280
|
+
active = [];
|
|
3281
|
+
};
|
|
3282
|
+
const onOpenChange = (isOpen) => {
|
|
3283
|
+
if (isOpen) {
|
|
3284
|
+
if (desc.restoreFocus) saved = saveFocus(dom);
|
|
3285
|
+
if (desc.takesFocus) focusInitial(dom, target, desc.initialFocusId);
|
|
3286
|
+
if (desc.modal) {
|
|
3287
|
+
active.push(trapFocus(dom, target));
|
|
3288
|
+
active.push(containFocus(dom, target));
|
|
3289
|
+
}
|
|
3290
|
+
if (desc.closeOnEscape && desc.onClose !== void 0) {
|
|
3291
|
+
active.push(onEscape(dom, target, desc.onClose));
|
|
3292
|
+
}
|
|
3293
|
+
} else {
|
|
3294
|
+
teardown();
|
|
3295
|
+
if (desc.restoreFocus && saved !== null) {
|
|
3296
|
+
restoreFocus(dom, saved);
|
|
3297
|
+
saved = null;
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
};
|
|
3301
|
+
const unsub = openSig.subscribe(onOpenChange);
|
|
3302
|
+
instance.trackCleanup(unsub);
|
|
3303
|
+
instance.trackCleanup(teardown);
|
|
3304
|
+
if (openSig.peek() === true) onOpenChange(true);
|
|
3305
|
+
}
|
|
3306
|
+
function wireComponentBehavior(ctx, graphNode, instance) {
|
|
3307
|
+
const fn = ctx.graph.getHandler(`__component__${graphNode.id}`);
|
|
3308
|
+
if (fn === void 0) return;
|
|
3309
|
+
for (const cleanup of fn()) instance.trackCleanup(cleanup);
|
|
3310
|
+
}
|
|
2973
3311
|
|
|
2974
3312
|
// ../renderer/src/hydration-diagnostics.ts
|
|
2975
3313
|
function formatHydrationDiagnostic(d) {
|
|
@@ -3072,6 +3410,25 @@ function hydrateNode(ctx, graphNode, domNode, path) {
|
|
|
3072
3410
|
wireReactiveList(ctx, graphNode, instance, domNode);
|
|
3073
3411
|
return instance;
|
|
3074
3412
|
}
|
|
3413
|
+
case "portal": {
|
|
3414
|
+
const instance = new NodeInstance(graphNode, domNode);
|
|
3415
|
+
ctx.instances.set(graphNode.id, instance);
|
|
3416
|
+
const body = dom.body();
|
|
3417
|
+
let target = domNode;
|
|
3418
|
+
if (body !== null) {
|
|
3419
|
+
const portalContainer = dom.createElement("div");
|
|
3420
|
+
dom.setAttribute(portalContainer, "data-streetui-portal-container", "");
|
|
3421
|
+
for (const child of dom.childNodes(domNode)) {
|
|
3422
|
+
dom.appendChild(portalContainer, child);
|
|
3423
|
+
}
|
|
3424
|
+
dom.appendChild(body, portalContainer);
|
|
3425
|
+
instance.trackCleanup(() => dom.removeChild(body, portalContainer));
|
|
3426
|
+
target = portalContainer;
|
|
3427
|
+
}
|
|
3428
|
+
hydrateChildren(ctx, graphNode, instance, target, path);
|
|
3429
|
+
wireOverlayBehavior(ctx, graphNode, instance, target);
|
|
3430
|
+
return instance;
|
|
3431
|
+
}
|
|
3075
3432
|
default: {
|
|
3076
3433
|
const instance = new NodeInstance(graphNode, domNode);
|
|
3077
3434
|
ctx.instances.set(graphNode.id, instance);
|
|
@@ -3082,6 +3439,7 @@ function hydrateNode(ctx, graphNode, domNode, path) {
|
|
|
3082
3439
|
return instance;
|
|
3083
3440
|
}
|
|
3084
3441
|
hydrateChildren(ctx, graphNode, instance, domNode, path);
|
|
3442
|
+
if (graphNode.type === "component") wireComponentBehavior(ctx, graphNode, instance);
|
|
3085
3443
|
return instance;
|
|
3086
3444
|
}
|
|
3087
3445
|
}
|
|
@@ -3315,7 +3673,9 @@ function analyzeGraph(graph) {
|
|
|
3315
3673
|
const hasEvents = node.events.length > 0;
|
|
3316
3674
|
const isList = node.type === "reactive-list";
|
|
3317
3675
|
const isConditional = node.type === "conditional";
|
|
3318
|
-
const
|
|
3676
|
+
const isPortal = node.type === "portal";
|
|
3677
|
+
const isComponent = node.type === "component";
|
|
3678
|
+
const isStatic = node.stateRefs.length === 0 && !hasEvents && !isList && !isConditional && !isPortal && !isComponent;
|
|
3319
3679
|
const isStaticSubtree = isStatic && allChildrenStatic;
|
|
3320
3680
|
nodes.set(node.id, {
|
|
3321
3681
|
isStatic,
|
|
@@ -4022,6 +4382,21 @@ function nodeTypeStats(graph) {
|
|
|
4022
4382
|
});
|
|
4023
4383
|
return counts;
|
|
4024
4384
|
}
|
|
4385
|
+
function inspectComponents(graph) {
|
|
4386
|
+
const out = [];
|
|
4387
|
+
graph.walk((node, depth) => {
|
|
4388
|
+
if (node.type !== "component") return;
|
|
4389
|
+
const name = node.props["data-streetui-component"];
|
|
4390
|
+
out.push({
|
|
4391
|
+
id: node.id,
|
|
4392
|
+
key: node.key,
|
|
4393
|
+
name: typeof name === "string" ? name : "Component",
|
|
4394
|
+
depth,
|
|
4395
|
+
childCount: node.children.length
|
|
4396
|
+
});
|
|
4397
|
+
});
|
|
4398
|
+
return out;
|
|
4399
|
+
}
|
|
4025
4400
|
|
|
4026
4401
|
// ../devtools/src/application.ts
|
|
4027
4402
|
function collectPerf(node, distinctSignals, acc) {
|
|
@@ -4405,8 +4780,10 @@ export {
|
|
|
4405
4780
|
buttonUpdate,
|
|
4406
4781
|
compile,
|
|
4407
4782
|
compileGraph,
|
|
4783
|
+
component,
|
|
4408
4784
|
consoleDiagnosticSink,
|
|
4409
4785
|
consoleHydrationDiagnosticSink,
|
|
4786
|
+
containFocus,
|
|
4410
4787
|
createApplication,
|
|
4411
4788
|
createBrowserHistory,
|
|
4412
4789
|
createContext,
|
|
@@ -4433,17 +4810,20 @@ export {
|
|
|
4433
4810
|
flushSync,
|
|
4434
4811
|
focusById,
|
|
4435
4812
|
focusFirst,
|
|
4813
|
+
focusInitial,
|
|
4436
4814
|
formatDiagnostic,
|
|
4437
4815
|
formatDiagnosticContext,
|
|
4438
4816
|
formatHydrationDiagnostic,
|
|
4439
4817
|
frameworkError,
|
|
4440
4818
|
generateApplicationId,
|
|
4441
4819
|
generateNodeId,
|
|
4820
|
+
getFocusable,
|
|
4442
4821
|
globalEventBus,
|
|
4443
4822
|
headingUpdate,
|
|
4444
4823
|
hydrateGraph,
|
|
4445
4824
|
inputUpdate,
|
|
4446
4825
|
inspectApplication,
|
|
4826
|
+
inspectComponents,
|
|
4447
4827
|
inspectContext,
|
|
4448
4828
|
inspectForm,
|
|
4449
4829
|
inspectGraph,
|
|
@@ -4453,6 +4833,7 @@ export {
|
|
|
4453
4833
|
inspectSignal,
|
|
4454
4834
|
interpolate,
|
|
4455
4835
|
isBatching,
|
|
4836
|
+
isComponentDefinition,
|
|
4456
4837
|
matchPattern,
|
|
4457
4838
|
matchRoutes,
|
|
4458
4839
|
maxLength,
|
|
@@ -4465,6 +4846,7 @@ export {
|
|
|
4465
4846
|
nodeTypeStats,
|
|
4466
4847
|
normalizePath,
|
|
4467
4848
|
observerCount,
|
|
4849
|
+
onEscape,
|
|
4468
4850
|
patchNode,
|
|
4469
4851
|
patchProp,
|
|
4470
4852
|
pattern,
|
|
@@ -4481,8 +4863,10 @@ export {
|
|
|
4481
4863
|
resetIdCounter,
|
|
4482
4864
|
resolveTag,
|
|
4483
4865
|
resource,
|
|
4866
|
+
restoreFocus,
|
|
4484
4867
|
routerOutlet,
|
|
4485
4868
|
runValidators,
|
|
4869
|
+
saveFocus,
|
|
4486
4870
|
scheduleImmediate,
|
|
4487
4871
|
scheduleUpdate,
|
|
4488
4872
|
scheduler,
|
|
@@ -4497,8 +4881,11 @@ export {
|
|
|
4497
4881
|
textUpdate,
|
|
4498
4882
|
toIdToken,
|
|
4499
4883
|
transformGraph,
|
|
4884
|
+
trapFocus,
|
|
4500
4885
|
validateGraph,
|
|
4886
|
+
wireComponentBehavior,
|
|
4501
4887
|
wireEvents,
|
|
4888
|
+
wireOverlayBehavior,
|
|
4502
4889
|
wireReactiveList,
|
|
4503
4890
|
wireSignalBindings
|
|
4504
4891
|
};
|