streetui 1.9.0 → 2.0.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/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/{compile-DqsMQVJk.d.cts → hydration-diagnostics-CFYDXBlm.d.cts} +353 -3
- package/dist/{compile-DqsMQVJk.d.ts → hydration-diagnostics-CFYDXBlm.d.ts} +353 -3
- package/dist/index.cjs +865 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +355 -147
- package/dist/index.d.ts +355 -147
- package/dist/index.js +851 -8
- package/dist/index.js.map +1 -1
- package/dist/renderer-interface-BUhHV7ja.d.cts +26 -0
- package/dist/renderer-interface-B_-hWnKk.d.ts +26 -0
- package/dist/{server-BYnmb_hR.d.ts → server-C0PvFBzD.d.ts} +181 -2
- package/dist/{server-DnwqBTfE.d.cts → server-DnAOFpMP.d.cts} +181 -2
- package/dist/server.cjs +217 -3
- 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 +216 -3
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +368 -6
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +3 -3
- package/dist/testing.d.ts +3 -3
- package/dist/testing.js +368 -6
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/hydration-diagnostics-4pwt6v7b.d.cts +0 -89
- package/dist/hydration-diagnostics-B2FmY05M.d.ts +0 -89
package/dist/testing.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { S as StreetApp, a as ComponentDefinition, b as ContainerBuilder } from './
|
|
2
|
-
export { V as VERSION } from './
|
|
3
|
-
import { R as RenderHandle
|
|
1
|
+
import { S as StreetApp, H as HydrationDiagnostic, a as ComponentDefinition, b as ContainerBuilder } from './hydration-diagnostics-CFYDXBlm.cjs';
|
|
2
|
+
export { V as VERSION } from './hydration-diagnostics-CFYDXBlm.cjs';
|
|
3
|
+
import { R as RenderHandle } from './renderer-interface-BUhHV7ja.cjs';
|
|
4
4
|
export * from 'streetui/diagnostics';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { S as StreetApp, a as ComponentDefinition, b as ContainerBuilder } from './
|
|
2
|
-
export { V as VERSION } from './
|
|
3
|
-
import { R as RenderHandle
|
|
1
|
+
import { S as StreetApp, H as HydrationDiagnostic, a as ComponentDefinition, b as ContainerBuilder } from './hydration-diagnostics-CFYDXBlm.js';
|
|
2
|
+
export { V as VERSION } from './hydration-diagnostics-CFYDXBlm.js';
|
|
3
|
+
import { R as RenderHandle } from './renderer-interface-B_-hWnKk.js';
|
|
4
4
|
export * from 'streetui/diagnostics';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/testing.js
CHANGED
|
@@ -265,6 +265,9 @@ var BrowserDOMAdapter = class {
|
|
|
265
265
|
body() {
|
|
266
266
|
return document.body ?? null;
|
|
267
267
|
}
|
|
268
|
+
head() {
|
|
269
|
+
return document.head ?? null;
|
|
270
|
+
}
|
|
268
271
|
activeElement() {
|
|
269
272
|
return document.activeElement ?? null;
|
|
270
273
|
}
|
|
@@ -643,6 +646,9 @@ var ServerDOMAdapter = class {
|
|
|
643
646
|
body() {
|
|
644
647
|
return null;
|
|
645
648
|
}
|
|
649
|
+
head() {
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
646
652
|
activeElement() {
|
|
647
653
|
return null;
|
|
648
654
|
}
|
|
@@ -973,7 +979,13 @@ var TAG_MAP = {
|
|
|
973
979
|
// its children are relocated to a document.body container on the browser
|
|
974
980
|
// (see the portal branch in mount.ts). On the server (no body) it renders
|
|
975
981
|
// inline, so the anchor tag is what SSR/hydration positionally match on.
|
|
976
|
-
portal: "div"
|
|
982
|
+
portal: "div",
|
|
983
|
+
// A `head()` node renders as a neutral, empty inline anchor <div> at its
|
|
984
|
+
// declaration site (like a portal anchor). Its actual contribution — title/
|
|
985
|
+
// meta/link/etc. — is applied to `document.head` by `wireHeadBehavior` on the
|
|
986
|
+
// browser, and emitted separately by `renderHead()` on the server. Keeping a
|
|
987
|
+
// one-node/one-element anchor preserves positional hydration.
|
|
988
|
+
head: "div"
|
|
977
989
|
};
|
|
978
990
|
function resolveTag(type) {
|
|
979
991
|
return TAG_MAP[type] ?? "div";
|
|
@@ -1418,6 +1430,158 @@ var TransitionController = class {
|
|
|
1418
1430
|
}
|
|
1419
1431
|
};
|
|
1420
1432
|
|
|
1433
|
+
// ../renderer/src/head.ts
|
|
1434
|
+
var HEAD_MARKER = "data-streetui-head";
|
|
1435
|
+
var HEAD_KEY = "data-streetui-head-key";
|
|
1436
|
+
function isSignalLike(v) {
|
|
1437
|
+
return v !== null && typeof v === "object" && typeof v["subscribe"] === "function" && typeof v["peek"] === "function";
|
|
1438
|
+
}
|
|
1439
|
+
function readValue(v) {
|
|
1440
|
+
if (isSignalLike(v)) return String(v.peek() ?? "");
|
|
1441
|
+
return String(v ?? "");
|
|
1442
|
+
}
|
|
1443
|
+
function resolveEntry(entry) {
|
|
1444
|
+
const attrs = {};
|
|
1445
|
+
for (const key of Object.keys(entry.attrs)) {
|
|
1446
|
+
attrs[key] = readValue(entry.attrs[key]);
|
|
1447
|
+
}
|
|
1448
|
+
const resolved = { tag: entry.tag, attrs };
|
|
1449
|
+
if (entry.tag === "title") {
|
|
1450
|
+
return { ...resolved, text: readValue(entry.text) };
|
|
1451
|
+
}
|
|
1452
|
+
return resolved;
|
|
1453
|
+
}
|
|
1454
|
+
var HeadManager = class {
|
|
1455
|
+
_dom;
|
|
1456
|
+
_head;
|
|
1457
|
+
_contributions = /* @__PURE__ */ new Map();
|
|
1458
|
+
_applied = /* @__PURE__ */ new Map();
|
|
1459
|
+
_order = 0;
|
|
1460
|
+
_adopted = false;
|
|
1461
|
+
constructor(dom, head) {
|
|
1462
|
+
this._dom = dom;
|
|
1463
|
+
this._head = head;
|
|
1464
|
+
}
|
|
1465
|
+
/** Register (or replace) a node's contribution and re-apply the merged result. */
|
|
1466
|
+
register(nodeId, entries) {
|
|
1467
|
+
this._contributions.set(nodeId, { order: this._order++, entries });
|
|
1468
|
+
this.apply();
|
|
1469
|
+
}
|
|
1470
|
+
/** Withdraw a node's contribution (unmount / route change) and re-apply. */
|
|
1471
|
+
unregister(nodeId) {
|
|
1472
|
+
if (this._contributions.delete(nodeId)) this.apply();
|
|
1473
|
+
}
|
|
1474
|
+
/** Recompute the merged head and patch `document.head` to match. */
|
|
1475
|
+
apply() {
|
|
1476
|
+
if (!this._adopted) {
|
|
1477
|
+
this._adoptServerTags();
|
|
1478
|
+
this._adopted = true;
|
|
1479
|
+
}
|
|
1480
|
+
const ordered = [...this._contributions.values()].sort((a, b) => a.order - b.order);
|
|
1481
|
+
const merged = /* @__PURE__ */ new Map();
|
|
1482
|
+
for (const contribution of ordered) {
|
|
1483
|
+
for (const entry of contribution.entries) {
|
|
1484
|
+
merged.set(entry.dedupKey, resolveEntry(entry));
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
for (const [key, desired] of merged) {
|
|
1488
|
+
const existing = this._applied.get(key);
|
|
1489
|
+
if (existing !== void 0 && existing.tag === desired.tag) {
|
|
1490
|
+
this._reconcileAttrs(existing, desired);
|
|
1491
|
+
} else {
|
|
1492
|
+
if (existing !== void 0) {
|
|
1493
|
+
this._dom.removeChild(this._head, existing.el);
|
|
1494
|
+
this._applied.delete(key);
|
|
1495
|
+
}
|
|
1496
|
+
const el = this._createTag(key, desired);
|
|
1497
|
+
this._dom.appendChild(this._head, el);
|
|
1498
|
+
this._applied.set(key, { el, attrKeys: new Set(Object.keys(desired.attrs)), tag: desired.tag });
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
for (const [key, record] of [...this._applied]) {
|
|
1502
|
+
if (!merged.has(key)) {
|
|
1503
|
+
this._dom.removeChild(this._head, record.el);
|
|
1504
|
+
this._applied.delete(key);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
_createTag(key, desired) {
|
|
1509
|
+
const el = this._dom.createElement(desired.tag);
|
|
1510
|
+
this._dom.setAttribute(el, HEAD_MARKER, "");
|
|
1511
|
+
this._dom.setAttribute(el, HEAD_KEY, key);
|
|
1512
|
+
for (const attr of Object.keys(desired.attrs)) {
|
|
1513
|
+
this._dom.setAttribute(el, attr, desired.attrs[attr]);
|
|
1514
|
+
}
|
|
1515
|
+
if (desired.tag === "title") this._dom.setTextContent(el, desired.text ?? "");
|
|
1516
|
+
return el;
|
|
1517
|
+
}
|
|
1518
|
+
_reconcileAttrs(record, desired) {
|
|
1519
|
+
const nextKeys = new Set(Object.keys(desired.attrs));
|
|
1520
|
+
for (const attr of record.attrKeys) {
|
|
1521
|
+
if (!nextKeys.has(attr)) this._dom.removeAttribute(record.el, attr);
|
|
1522
|
+
}
|
|
1523
|
+
for (const attr of nextKeys) {
|
|
1524
|
+
this._dom.setAttribute(record.el, attr, desired.attrs[attr]);
|
|
1525
|
+
}
|
|
1526
|
+
if (desired.tag === "title") this._dom.setTextContent(record.el, desired.text ?? "");
|
|
1527
|
+
record.attrKeys = nextKeys;
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Seed `_applied` from server-emitted `[data-streetui-head-key]` tags already
|
|
1531
|
+
* in `document.head`. The subsequent diff reuses these elements when the
|
|
1532
|
+
* client desires the same key (no duplicate), rewrites them if the value
|
|
1533
|
+
* changed, or removes them if the client graph no longer wants them.
|
|
1534
|
+
*/
|
|
1535
|
+
_adoptServerTags() {
|
|
1536
|
+
for (const child of this._dom.childNodes(this._head)) {
|
|
1537
|
+
if (!this._dom.isElement(child)) continue;
|
|
1538
|
+
const el = child;
|
|
1539
|
+
const key = this._dom.getAttribute(el, HEAD_KEY);
|
|
1540
|
+
if (key === null) continue;
|
|
1541
|
+
this._applied.set(key, {
|
|
1542
|
+
el,
|
|
1543
|
+
attrKeys: new Set(this._attrNames(el)),
|
|
1544
|
+
tag: this._dom.tagName(el)
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
/** The framework-managed attribute names currently on a server tag. */
|
|
1549
|
+
_attrNames(el) {
|
|
1550
|
+
const names = [];
|
|
1551
|
+
if (this._dom.getAttribute(el, HEAD_MARKER) !== null) names.push(HEAD_MARKER);
|
|
1552
|
+
if (this._dom.getAttribute(el, HEAD_KEY) !== null) names.push(HEAD_KEY);
|
|
1553
|
+
return names;
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1556
|
+
function getHeadManager(ctx) {
|
|
1557
|
+
const head = ctx.dom.head();
|
|
1558
|
+
if (head === null) return null;
|
|
1559
|
+
const mutable = ctx;
|
|
1560
|
+
if (mutable.head === void 0) mutable.head = new HeadManager(ctx.dom, head);
|
|
1561
|
+
return mutable.head;
|
|
1562
|
+
}
|
|
1563
|
+
function wireHeadBehavior(ctx, graphNode, instance) {
|
|
1564
|
+
const manager = getHeadManager(ctx);
|
|
1565
|
+
if (manager === null) return;
|
|
1566
|
+
const descFn = ctx.graph.getHandler(`__head__${graphNode.id}`);
|
|
1567
|
+
if (descFn === void 0) return;
|
|
1568
|
+
const contribution = descFn();
|
|
1569
|
+
const nodeId = graphNode.id;
|
|
1570
|
+
manager.register(nodeId, contribution.entries);
|
|
1571
|
+
for (const entry of contribution.entries) {
|
|
1572
|
+
for (const attrKey of Object.keys(entry.attrs)) {
|
|
1573
|
+
const v = entry.attrs[attrKey];
|
|
1574
|
+
if (isSignalLike(v)) {
|
|
1575
|
+
instance.trackCleanup(v.subscribe(() => manager.apply()));
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
if (isSignalLike(entry.text)) {
|
|
1579
|
+
instance.trackCleanup(entry.text.subscribe(() => manager.apply()));
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
instance.trackCleanup(() => manager.unregister(nodeId));
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1421
1585
|
// ../renderer/src/mount.ts
|
|
1422
1586
|
var SKIP_PROP_KEYS = /* @__PURE__ */ new Set([
|
|
1423
1587
|
"text",
|
|
@@ -1540,6 +1704,9 @@ function mountNode(ctx, graphNode, parentDom) {
|
|
|
1540
1704
|
const instance2 = new NodeInstance(graphNode, el2);
|
|
1541
1705
|
ctx.instances.set(graphNode.id, instance2);
|
|
1542
1706
|
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
1707
|
+
if (graphNode.stateRefs.length !== 0) {
|
|
1708
|
+
wireSignalBindings(ctx, graphNode, instance2, linkUpdate(dom, el2));
|
|
1709
|
+
}
|
|
1543
1710
|
dom.appendChild(parentDom, el2);
|
|
1544
1711
|
return instance2;
|
|
1545
1712
|
}
|
|
@@ -1595,6 +1762,16 @@ function mountNode(ctx, graphNode, parentDom) {
|
|
|
1595
1762
|
wireOverlayBehavior(ctx, graphNode, instance2, target);
|
|
1596
1763
|
return instance2;
|
|
1597
1764
|
}
|
|
1765
|
+
if (graphNode.type === "head") {
|
|
1766
|
+
const anchor = dom.createElement(resolveTag("head"));
|
|
1767
|
+
dom.setAttribute(anchor, "data-streetui-head-anchor", "");
|
|
1768
|
+
applyNodeProps(ctx, graphNode, anchor);
|
|
1769
|
+
const instance2 = new NodeInstance(graphNode, anchor);
|
|
1770
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
1771
|
+
dom.appendChild(parentDom, anchor);
|
|
1772
|
+
wireHeadBehavior(ctx, graphNode, instance2);
|
|
1773
|
+
return instance2;
|
|
1774
|
+
}
|
|
1598
1775
|
const tag = resolveTag(graphNode.type);
|
|
1599
1776
|
const el = dom.createElement(tag);
|
|
1600
1777
|
applyNodeProps(ctx, graphNode, el);
|
|
@@ -1659,6 +1836,17 @@ function buttonUpdate(dom, el) {
|
|
|
1659
1836
|
}
|
|
1660
1837
|
};
|
|
1661
1838
|
}
|
|
1839
|
+
function linkUpdate(dom, el) {
|
|
1840
|
+
return (propKey, value) => {
|
|
1841
|
+
if (propKey === "label") {
|
|
1842
|
+
dom.setTextContent(el, String(value ?? ""));
|
|
1843
|
+
} else if (propKey === "href") {
|
|
1844
|
+
dom.setAttribute(el, "href", String(value ?? ""));
|
|
1845
|
+
} else {
|
|
1846
|
+
applyProp(dom, el, propKey, value);
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1662
1850
|
function applyNodeProps(ctx, graphNode, el) {
|
|
1663
1851
|
const props = graphNode.props;
|
|
1664
1852
|
for (const key in props) {
|
|
@@ -1886,7 +2074,12 @@ function hydrateNode(ctx, graphNode, domNode, path) {
|
|
|
1886
2074
|
case "link": {
|
|
1887
2075
|
const instance = new NodeInstance(graphNode, domNode);
|
|
1888
2076
|
ctx.instances.set(graphNode.id, instance);
|
|
1889
|
-
if (graphNode.type === "link")
|
|
2077
|
+
if (graphNode.type === "link") {
|
|
2078
|
+
wireEvents(dom, graph, graphNode, domNode, instance);
|
|
2079
|
+
if (graphNode.stateRefs.length !== 0) {
|
|
2080
|
+
wireSignalBindings(ctx, graphNode, instance, linkUpdate(dom, domNode));
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
1890
2083
|
return instance;
|
|
1891
2084
|
}
|
|
1892
2085
|
case "reactive-list":
|
|
@@ -1916,6 +2109,12 @@ function hydrateNode(ctx, graphNode, domNode, path) {
|
|
|
1916
2109
|
wireOverlayBehavior(ctx, graphNode, instance, target);
|
|
1917
2110
|
return instance;
|
|
1918
2111
|
}
|
|
2112
|
+
case "head": {
|
|
2113
|
+
const instance = new NodeInstance(graphNode, domNode);
|
|
2114
|
+
ctx.instances.set(graphNode.id, instance);
|
|
2115
|
+
wireHeadBehavior(ctx, graphNode, instance);
|
|
2116
|
+
return instance;
|
|
2117
|
+
}
|
|
1919
2118
|
default: {
|
|
1920
2119
|
const instance = new NodeInstance(graphNode, domNode);
|
|
1921
2120
|
ctx.instances.set(graphNode.id, instance);
|
|
@@ -2126,7 +2325,8 @@ function analyzeGraph(graph) {
|
|
|
2126
2325
|
const isConditional = node.type === "conditional";
|
|
2127
2326
|
const isPortal = node.type === "portal";
|
|
2128
2327
|
const isComponent = node.type === "component";
|
|
2129
|
-
const
|
|
2328
|
+
const isHead = node.type === "head";
|
|
2329
|
+
const isStatic = node.stateRefs.length === 0 && !hasEvents && !isList && !isConditional && !isPortal && !isComponent && !isHead;
|
|
2130
2330
|
const isStaticSubtree = isStatic && allChildrenStatic;
|
|
2131
2331
|
nodes.set(node.id, {
|
|
2132
2332
|
isStatic,
|
|
@@ -2618,6 +2818,118 @@ function resolveTransition(config) {
|
|
|
2618
2818
|
};
|
|
2619
2819
|
}
|
|
2620
2820
|
|
|
2821
|
+
// ../dsl/src/head.ts
|
|
2822
|
+
function metaDedupKey(m) {
|
|
2823
|
+
if (m.charset !== void 0) return "meta:charset";
|
|
2824
|
+
if (m.name !== void 0) return `meta:name=${m.name}`;
|
|
2825
|
+
if (m.property !== void 0) return `meta:property=${m.property}`;
|
|
2826
|
+
if (m.httpEquiv !== void 0) return `meta:http-equiv=${m.httpEquiv}`;
|
|
2827
|
+
return void 0;
|
|
2828
|
+
}
|
|
2829
|
+
function metaAttrs(m) {
|
|
2830
|
+
const attrs = {};
|
|
2831
|
+
if (m.charset !== void 0) attrs["charset"] = m.charset;
|
|
2832
|
+
if (m.name !== void 0) attrs["name"] = m.name;
|
|
2833
|
+
if (m.property !== void 0) attrs["property"] = m.property;
|
|
2834
|
+
if (m.httpEquiv !== void 0) attrs["http-equiv"] = m.httpEquiv;
|
|
2835
|
+
if (m.content !== void 0) attrs["content"] = m.content;
|
|
2836
|
+
return attrs;
|
|
2837
|
+
}
|
|
2838
|
+
function linkAttrs(l) {
|
|
2839
|
+
const attrs = { rel: l.rel, href: l.href };
|
|
2840
|
+
if (l.sizes !== void 0) attrs["sizes"] = l.sizes;
|
|
2841
|
+
if (l.type !== void 0) attrs["type"] = l.type;
|
|
2842
|
+
if (l.media !== void 0) attrs["media"] = l.media;
|
|
2843
|
+
if (l.as !== void 0) attrs["as"] = l.as;
|
|
2844
|
+
if (l.crossorigin !== void 0) attrs["crossorigin"] = l.crossorigin;
|
|
2845
|
+
if (l.hreflang !== void 0) attrs["hreflang"] = l.hreflang;
|
|
2846
|
+
return attrs;
|
|
2847
|
+
}
|
|
2848
|
+
function resolveHead(config) {
|
|
2849
|
+
const entries = [];
|
|
2850
|
+
if (config.charset !== void 0) {
|
|
2851
|
+
entries.push({ tag: "meta", dedupKey: "meta:charset", attrs: { charset: config.charset } });
|
|
2852
|
+
}
|
|
2853
|
+
if (config.base !== void 0) {
|
|
2854
|
+
entries.push({ tag: "base", dedupKey: "base", attrs: { href: config.base } });
|
|
2855
|
+
}
|
|
2856
|
+
if (config.title !== void 0) {
|
|
2857
|
+
entries.push({ tag: "title", dedupKey: "title", attrs: {}, text: config.title });
|
|
2858
|
+
}
|
|
2859
|
+
if (config.description !== void 0) {
|
|
2860
|
+
entries.push({
|
|
2861
|
+
tag: "meta",
|
|
2862
|
+
dedupKey: "meta:name=description",
|
|
2863
|
+
attrs: { name: "description", content: config.description }
|
|
2864
|
+
});
|
|
2865
|
+
}
|
|
2866
|
+
if (config.canonical !== void 0) {
|
|
2867
|
+
entries.push({
|
|
2868
|
+
tag: "link",
|
|
2869
|
+
dedupKey: "link:rel=canonical",
|
|
2870
|
+
attrs: { rel: "canonical", href: config.canonical }
|
|
2871
|
+
});
|
|
2872
|
+
}
|
|
2873
|
+
if (config.robots !== void 0) {
|
|
2874
|
+
entries.push({
|
|
2875
|
+
tag: "meta",
|
|
2876
|
+
dedupKey: "meta:name=robots",
|
|
2877
|
+
attrs: { name: "robots", content: config.robots }
|
|
2878
|
+
});
|
|
2879
|
+
}
|
|
2880
|
+
if (config.themeColor !== void 0) {
|
|
2881
|
+
entries.push({
|
|
2882
|
+
tag: "meta",
|
|
2883
|
+
dedupKey: "meta:name=theme-color",
|
|
2884
|
+
attrs: { name: "theme-color", content: config.themeColor }
|
|
2885
|
+
});
|
|
2886
|
+
}
|
|
2887
|
+
if (config.viewport !== void 0) {
|
|
2888
|
+
entries.push({
|
|
2889
|
+
tag: "meta",
|
|
2890
|
+
dedupKey: "meta:name=viewport",
|
|
2891
|
+
attrs: { name: "viewport", content: config.viewport }
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2894
|
+
if (config.favicon !== void 0) {
|
|
2895
|
+
const l = typeof config.favicon === "string" ? { rel: "icon", href: config.favicon } : config.favicon;
|
|
2896
|
+
entries.push({ tag: "link", dedupKey: `link:rel=${l.rel}`, attrs: linkAttrs(l) });
|
|
2897
|
+
}
|
|
2898
|
+
if (config.openGraph !== void 0) {
|
|
2899
|
+
for (const key of Object.keys(config.openGraph)) {
|
|
2900
|
+
const property = `og:${key}`;
|
|
2901
|
+
entries.push({
|
|
2902
|
+
tag: "meta",
|
|
2903
|
+
dedupKey: `meta:property=${property}`,
|
|
2904
|
+
attrs: { property, content: config.openGraph[key] }
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
if (config.twitter !== void 0) {
|
|
2909
|
+
for (const key of Object.keys(config.twitter)) {
|
|
2910
|
+
const name = `twitter:${key}`;
|
|
2911
|
+
entries.push({
|
|
2912
|
+
tag: "meta",
|
|
2913
|
+
dedupKey: `meta:name=${name}`,
|
|
2914
|
+
attrs: { name, content: config.twitter[key] }
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
if (config.meta !== void 0) {
|
|
2919
|
+
for (const m of config.meta) {
|
|
2920
|
+
const key = metaDedupKey(m);
|
|
2921
|
+
if (key === void 0) continue;
|
|
2922
|
+
entries.push({ tag: "meta", dedupKey: key, attrs: metaAttrs(m) });
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
if (config.link !== void 0) {
|
|
2926
|
+
for (const l of config.link) {
|
|
2927
|
+
entries.push({ tag: "link", dedupKey: `link:rel=${l.rel}:href=${l.href}`, attrs: linkAttrs(l) });
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
return { entries };
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2621
2933
|
// ../state/src/signal.ts
|
|
2622
2934
|
var _activeConsumer = null;
|
|
2623
2935
|
function withConsumer(consumer, fn) {
|
|
@@ -3181,8 +3493,14 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
3181
3493
|
this.container(id, (c) => {
|
|
3182
3494
|
c.when(
|
|
3183
3495
|
hasError,
|
|
3184
|
-
// Error state → fallback.
|
|
3185
|
-
|
|
3496
|
+
// Error state → fallback. The fallback branch mounts exactly when the
|
|
3497
|
+
// boundary enters its error state, so this is also where the optional
|
|
3498
|
+
// `onError` reporting hook fires (observe-only; §6/§7).
|
|
3499
|
+
(fb) => {
|
|
3500
|
+
const currentError = readError();
|
|
3501
|
+
options.onError?.(currentError);
|
|
3502
|
+
options.fallback(fb, currentError, retry);
|
|
3503
|
+
},
|
|
3186
3504
|
// Healthy state → body, guarded against synchronous build throws.
|
|
3187
3505
|
(body) => {
|
|
3188
3506
|
try {
|
|
@@ -3194,6 +3512,24 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
3194
3512
|
);
|
|
3195
3513
|
}, { id });
|
|
3196
3514
|
}
|
|
3515
|
+
asyncBoundary(key, res, branches) {
|
|
3516
|
+
const isError = derived(() => res.status.get() === "error");
|
|
3517
|
+
const showSuccess = derived(
|
|
3518
|
+
() => res.status.get() !== "error" && res.data.get() !== void 0
|
|
3519
|
+
);
|
|
3520
|
+
const showLoading = derived(
|
|
3521
|
+
() => res.status.get() !== "error" && res.data.get() === void 0
|
|
3522
|
+
);
|
|
3523
|
+
const dataSignal = derived(() => res.data.get());
|
|
3524
|
+
const retry = () => {
|
|
3525
|
+
void res.refetch();
|
|
3526
|
+
};
|
|
3527
|
+
this.container(key, (c) => {
|
|
3528
|
+
c.when(isError, (fb) => branches.error?.(fb, res.error.peek(), retry));
|
|
3529
|
+
c.when(showSuccess, (sb) => branches.success(sb, dataSignal));
|
|
3530
|
+
c.when(showLoading, (lb) => branches.loading?.(lb));
|
|
3531
|
+
}, { key });
|
|
3532
|
+
}
|
|
3197
3533
|
// ── Portals & overlays ──────────────────────────────────────────────────────
|
|
3198
3534
|
portal(key, builder, options = {}) {
|
|
3199
3535
|
const node = this._graph.createNode("portal", {
|
|
@@ -3203,6 +3539,31 @@ var ContainerBuilderBase = class extends ContentBuilderBase {
|
|
|
3203
3539
|
});
|
|
3204
3540
|
builder(new ContainerBuilderImpl(node, this._graph));
|
|
3205
3541
|
}
|
|
3542
|
+
/**
|
|
3543
|
+
* Declare document metadata (2.0 §1–§3). Creates a `'head'` node — a neutral,
|
|
3544
|
+
* empty inline anchor at this position (one node / one element, so positional
|
|
3545
|
+
* hydration is preserved) — and registers a `__head__<id>` descriptor holding
|
|
3546
|
+
* this call's normalized, dedup-keyed {@link resolveHead} contribution. The
|
|
3547
|
+
* renderer applies it to `document.head` on the browser (adopting server tags
|
|
3548
|
+
* on hydration, cleaning up on unmount / route change) and emits the active
|
|
3549
|
+
* graph's merged metadata as a string on the server (`renderHead`).
|
|
3550
|
+
*
|
|
3551
|
+
* Multiple `head()` nodes may be live at once (app default + route + component)
|
|
3552
|
+
* — the renderer merges them and, per dedup key, the last in document order
|
|
3553
|
+
* wins (see head.ts). No new render path: this reuses the same graph-node +
|
|
3554
|
+
* handler-registry convention as overlays/transitions/components.
|
|
3555
|
+
*/
|
|
3556
|
+
head(metadata) {
|
|
3557
|
+
const node = this._graph.createNode("head", {
|
|
3558
|
+
parent: this._node,
|
|
3559
|
+
props: { "data-streetui-head-anchor": "" }
|
|
3560
|
+
});
|
|
3561
|
+
const contribution = resolveHead(metadata);
|
|
3562
|
+
this._graph.registerHandler(
|
|
3563
|
+
`__head__${node.id}`,
|
|
3564
|
+
() => contribution
|
|
3565
|
+
);
|
|
3566
|
+
}
|
|
3206
3567
|
/**
|
|
3207
3568
|
* Shared assembly for every overlay kind: a `portal` node whose single child
|
|
3208
3569
|
* is a `when(open, panel)` conditional. The panel container carries the
|
|
@@ -3533,6 +3894,7 @@ var ApplicationGraph = class {
|
|
|
3533
3894
|
this.handlers.delete(`__overlay__${node.id}`);
|
|
3534
3895
|
this.handlers.delete(`__component__${node.id}`);
|
|
3535
3896
|
this.handlers.delete(`__transition__${node.id}`);
|
|
3897
|
+
this.handlers.delete(`__head__${node.id}`);
|
|
3536
3898
|
}
|
|
3537
3899
|
// ── Handler registry ──────────────────────────────────────────────────────
|
|
3538
3900
|
registerHandler(key, fn) {
|
|
@@ -3710,7 +4072,7 @@ function trigger(el, type, init = {}) {
|
|
|
3710
4072
|
}
|
|
3711
4073
|
|
|
3712
4074
|
// src/version.ts
|
|
3713
|
-
var VERSION = "
|
|
4075
|
+
var VERSION = "2.0.0";
|
|
3714
4076
|
export {
|
|
3715
4077
|
VERSION,
|
|
3716
4078
|
analyzeGraph,
|