@streetui/renderer 1.6.0 → 1.7.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/index.cjs +162 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +165 -5
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.cjs
CHANGED
|
@@ -47,19 +47,21 @@ __export(index_exports, {
|
|
|
47
47
|
serializeState: () => serializeState,
|
|
48
48
|
textUpdate: () => textUpdate,
|
|
49
49
|
wireEvents: () => wireEvents,
|
|
50
|
+
wireOverlayBehavior: () => wireOverlayBehavior,
|
|
50
51
|
wireReactiveList: () => wireReactiveList,
|
|
51
52
|
wireSignalBindings: () => wireSignalBindings
|
|
52
53
|
});
|
|
53
54
|
module.exports = __toCommonJS(index_exports);
|
|
54
55
|
|
|
55
56
|
// src/render-context.ts
|
|
56
|
-
function createRenderContext(dom, graph, container, hydrationDiagnostics) {
|
|
57
|
+
function createRenderContext(dom, graph, container, hydrationDiagnostics, staticHTML) {
|
|
57
58
|
return {
|
|
58
59
|
dom,
|
|
59
60
|
graph,
|
|
60
61
|
instances: /* @__PURE__ */ new Map(),
|
|
61
62
|
container,
|
|
62
|
-
...hydrationDiagnostics !== void 0 ? { hydrationDiagnostics } : {}
|
|
63
|
+
...hydrationDiagnostics !== void 0 ? { hydrationDiagnostics } : {},
|
|
64
|
+
...staticHTML !== void 0 ? { staticHTML } : {}
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -191,6 +193,9 @@ function wireEvents(dom, graph, node, element, instance) {
|
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
|
|
196
|
+
// src/mount.ts
|
|
197
|
+
var import_dom = require("@streetui/dom");
|
|
198
|
+
|
|
194
199
|
// src/tag-map.ts
|
|
195
200
|
var TAG_MAP = {
|
|
196
201
|
application: "div",
|
|
@@ -209,7 +214,12 @@ var TAG_MAP = {
|
|
|
209
214
|
component: "div",
|
|
210
215
|
slot: "div",
|
|
211
216
|
fragment: "div",
|
|
212
|
-
"reactive-list": "ul"
|
|
217
|
+
"reactive-list": "ul",
|
|
218
|
+
// A portal renders as a neutral inline anchor <div> at its declaration site;
|
|
219
|
+
// its children are relocated to a document.body container on the browser
|
|
220
|
+
// (see the portal branch in mount.ts). On the server (no body) it renders
|
|
221
|
+
// inline, so the anchor tag is what SSR/hydration positionally match on.
|
|
222
|
+
portal: "div"
|
|
213
223
|
};
|
|
214
224
|
function resolveTag(type) {
|
|
215
225
|
return TAG_MAP[type] ?? "div";
|
|
@@ -488,6 +498,17 @@ function mountGraph(ctx) {
|
|
|
488
498
|
}
|
|
489
499
|
function mountNode(ctx, graphNode, parentDom) {
|
|
490
500
|
const { dom, graph } = ctx;
|
|
501
|
+
const staticHTML = ctx.staticHTML;
|
|
502
|
+
if (staticHTML !== void 0 && dom.createRawHTML !== void 0) {
|
|
503
|
+
const precomputed = staticHTML.get(graphNode.id);
|
|
504
|
+
if (precomputed !== void 0) {
|
|
505
|
+
const raw = dom.createRawHTML(precomputed);
|
|
506
|
+
dom.appendChild(parentDom, raw);
|
|
507
|
+
const instance2 = new NodeInstance(graphNode, raw);
|
|
508
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
509
|
+
return instance2;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
491
512
|
if (graphNode.type === "application") {
|
|
492
513
|
const instance2 = new NodeInstance(graphNode, parentDom);
|
|
493
514
|
ctx.instances.set(graphNode.id, instance2);
|
|
@@ -610,6 +631,28 @@ function mountNode(ctx, graphNode, parentDom) {
|
|
|
610
631
|
wireReactiveList(ctx, graphNode, instance2, el2);
|
|
611
632
|
return instance2;
|
|
612
633
|
}
|
|
634
|
+
if (graphNode.type === "portal") {
|
|
635
|
+
const anchor = dom.createElement(resolveTag("portal"));
|
|
636
|
+
dom.setAttribute(anchor, "data-streetui-portal", "");
|
|
637
|
+
applyNodeProps(ctx, graphNode, anchor);
|
|
638
|
+
const instance2 = new NodeInstance(graphNode, anchor);
|
|
639
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
640
|
+
const body = dom.body();
|
|
641
|
+
let target = anchor;
|
|
642
|
+
if (body !== null) {
|
|
643
|
+
const portalContainer = dom.createElement("div");
|
|
644
|
+
dom.setAttribute(portalContainer, "data-streetui-portal-container", "");
|
|
645
|
+
dom.appendChild(body, portalContainer);
|
|
646
|
+
instance2.trackCleanup(() => dom.removeChild(body, portalContainer));
|
|
647
|
+
target = portalContainer;
|
|
648
|
+
}
|
|
649
|
+
for (const child of graphNode.children) {
|
|
650
|
+
instance2.addChild(mountNode(ctx, child, target));
|
|
651
|
+
}
|
|
652
|
+
dom.appendChild(parentDom, anchor);
|
|
653
|
+
wireOverlayBehavior(ctx, graphNode, instance2, target);
|
|
654
|
+
return instance2;
|
|
655
|
+
}
|
|
613
656
|
const tag = resolveTag(graphNode.type);
|
|
614
657
|
const el = dom.createElement(tag);
|
|
615
658
|
applyNodeProps(ctx, graphNode, el);
|
|
@@ -759,9 +802,47 @@ function forgetInstance(ctx, instance) {
|
|
|
759
802
|
ctx.instances.delete(instance.graphNode.id);
|
|
760
803
|
for (const child of instance.children) forgetInstance(ctx, child);
|
|
761
804
|
}
|
|
805
|
+
function wireOverlayBehavior(ctx, graphNode, instance, target) {
|
|
806
|
+
const { dom, graph } = ctx;
|
|
807
|
+
if (dom.body() === null) return;
|
|
808
|
+
const descFn = graph.getHandler(`__overlay__${graphNode.id}`);
|
|
809
|
+
if (descFn === void 0) return;
|
|
810
|
+
const desc = descFn();
|
|
811
|
+
const openSig = desc.open;
|
|
812
|
+
if (openSig === void 0 || typeof openSig.subscribe !== "function") return;
|
|
813
|
+
let active = [];
|
|
814
|
+
let saved = null;
|
|
815
|
+
const teardown = () => {
|
|
816
|
+
for (const fn of active) fn();
|
|
817
|
+
active = [];
|
|
818
|
+
};
|
|
819
|
+
const onOpenChange = (isOpen) => {
|
|
820
|
+
if (isOpen) {
|
|
821
|
+
if (desc.restoreFocus) saved = (0, import_dom.saveFocus)(dom);
|
|
822
|
+
if (desc.takesFocus) (0, import_dom.focusInitial)(dom, target, desc.initialFocusId);
|
|
823
|
+
if (desc.modal) {
|
|
824
|
+
active.push((0, import_dom.trapFocus)(dom, target));
|
|
825
|
+
active.push((0, import_dom.containFocus)(dom, target));
|
|
826
|
+
}
|
|
827
|
+
if (desc.closeOnEscape && desc.onClose !== void 0) {
|
|
828
|
+
active.push((0, import_dom.onEscape)(dom, target, desc.onClose));
|
|
829
|
+
}
|
|
830
|
+
} else {
|
|
831
|
+
teardown();
|
|
832
|
+
if (desc.restoreFocus && saved !== null) {
|
|
833
|
+
(0, import_dom.restoreFocus)(dom, saved);
|
|
834
|
+
saved = null;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
const unsub = openSig.subscribe(onOpenChange);
|
|
839
|
+
instance.trackCleanup(unsub);
|
|
840
|
+
instance.trackCleanup(teardown);
|
|
841
|
+
if (openSig.peek() === true) onOpenChange(true);
|
|
842
|
+
}
|
|
762
843
|
|
|
763
844
|
// src/renderer.ts
|
|
764
|
-
var
|
|
845
|
+
var import_dom2 = require("@streetui/dom");
|
|
765
846
|
|
|
766
847
|
// src/hydration-diagnostics.ts
|
|
767
848
|
function formatHydrationDiagnostic(d) {
|
|
@@ -864,6 +945,25 @@ function hydrateNode(ctx, graphNode, domNode, path) {
|
|
|
864
945
|
wireReactiveList(ctx, graphNode, instance, domNode);
|
|
865
946
|
return instance;
|
|
866
947
|
}
|
|
948
|
+
case "portal": {
|
|
949
|
+
const instance = new NodeInstance(graphNode, domNode);
|
|
950
|
+
ctx.instances.set(graphNode.id, instance);
|
|
951
|
+
const body = dom.body();
|
|
952
|
+
let target = domNode;
|
|
953
|
+
if (body !== null) {
|
|
954
|
+
const portalContainer = dom.createElement("div");
|
|
955
|
+
dom.setAttribute(portalContainer, "data-streetui-portal-container", "");
|
|
956
|
+
for (const child of dom.childNodes(domNode)) {
|
|
957
|
+
dom.appendChild(portalContainer, child);
|
|
958
|
+
}
|
|
959
|
+
dom.appendChild(body, portalContainer);
|
|
960
|
+
instance.trackCleanup(() => dom.removeChild(body, portalContainer));
|
|
961
|
+
target = portalContainer;
|
|
962
|
+
}
|
|
963
|
+
hydrateChildren(ctx, graphNode, instance, target, path);
|
|
964
|
+
wireOverlayBehavior(ctx, graphNode, instance, target);
|
|
965
|
+
return instance;
|
|
966
|
+
}
|
|
867
967
|
default: {
|
|
868
968
|
const instance = new NodeInstance(graphNode, domNode);
|
|
869
969
|
ctx.instances.set(graphNode.id, instance);
|
|
@@ -1006,7 +1106,7 @@ var StreetRendererImpl = class {
|
|
|
1006
1106
|
_dom;
|
|
1007
1107
|
_hydrationDiagnostics;
|
|
1008
1108
|
constructor(options = {}) {
|
|
1009
|
-
this._dom = options.domAdapter ?? new
|
|
1109
|
+
this._dom = options.domAdapter ?? new import_dom2.BrowserDOMAdapter();
|
|
1010
1110
|
if (options.hydrationDiagnostics !== void 0) {
|
|
1011
1111
|
this._hydrationDiagnostics = options.hydrationDiagnostics;
|
|
1012
1112
|
}
|
|
@@ -1079,11 +1179,64 @@ function readState(dom, root) {
|
|
|
1079
1179
|
}
|
|
1080
1180
|
|
|
1081
1181
|
// src/ssr.ts
|
|
1082
|
-
var
|
|
1182
|
+
var import_dom4 = require("@streetui/dom");
|
|
1183
|
+
|
|
1184
|
+
// src/static-ssr-plan.ts
|
|
1185
|
+
var import_diagnostics = require("@streetui/compiler/diagnostics");
|
|
1186
|
+
var import_dom3 = require("@streetui/dom");
|
|
1187
|
+
function collectMaximalStaticRoots(graph) {
|
|
1188
|
+
const analysis = (0, import_diagnostics.analyzeGraph)(graph);
|
|
1189
|
+
const roots = [];
|
|
1190
|
+
const walk = (node) => {
|
|
1191
|
+
if (node.type !== "application") {
|
|
1192
|
+
const a = analysis.nodes.get(node.id);
|
|
1193
|
+
if (a !== void 0 && a.isStaticSubtree) {
|
|
1194
|
+
roots.push(node);
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
for (const child of node.children) walk(child);
|
|
1199
|
+
};
|
|
1200
|
+
walk(graph.root);
|
|
1201
|
+
return roots;
|
|
1202
|
+
}
|
|
1203
|
+
function serializeStaticSubtree(dom, graph, root) {
|
|
1204
|
+
const container = dom.createElement("div");
|
|
1205
|
+
const ctx = createRenderContext(dom, graph, container);
|
|
1206
|
+
const instance = mountNode(ctx, root, container);
|
|
1207
|
+
const html = dom.serializeInner(container);
|
|
1208
|
+
instance.dispose();
|
|
1209
|
+
ctx.instances.clear();
|
|
1210
|
+
return html;
|
|
1211
|
+
}
|
|
1212
|
+
function buildStaticSSRPlan(compiled) {
|
|
1213
|
+
const graph = compiled.graph;
|
|
1214
|
+
const roots = collectMaximalStaticRoots(graph);
|
|
1215
|
+
const plan = /* @__PURE__ */ new Map();
|
|
1216
|
+
if (roots.length === 0) return plan;
|
|
1217
|
+
const dom = new import_dom3.ServerDOMAdapter();
|
|
1218
|
+
for (const root of roots) {
|
|
1219
|
+
plan.set(root.id, serializeStaticSubtree(dom, graph, root));
|
|
1220
|
+
}
|
|
1221
|
+
return plan;
|
|
1222
|
+
}
|
|
1223
|
+
var PLAN_CACHE = /* @__PURE__ */ new WeakMap();
|
|
1224
|
+
function getStaticSSRPlan(compiled) {
|
|
1225
|
+
let plan = PLAN_CACHE.get(compiled);
|
|
1226
|
+
if (plan === void 0) {
|
|
1227
|
+
plan = buildStaticSSRPlan(compiled);
|
|
1228
|
+
PLAN_CACHE.set(compiled, plan);
|
|
1229
|
+
}
|
|
1230
|
+
return plan;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// src/ssr.ts
|
|
1083
1234
|
function renderToString(compiled, options = {}) {
|
|
1084
|
-
const dom = options.domAdapter ?? new
|
|
1235
|
+
const dom = options.domAdapter ?? new import_dom4.ServerDOMAdapter();
|
|
1236
|
+
const plan = options.staticPlan === null ? void 0 : options.staticPlan ?? getStaticSSRPlan(compiled);
|
|
1237
|
+
const staticHTML = plan !== void 0 && plan.size > 0 ? plan : void 0;
|
|
1085
1238
|
const container = dom.createElement("div");
|
|
1086
|
-
const ctx = createRenderContext(dom, compiled.graph, container);
|
|
1239
|
+
const ctx = createRenderContext(dom, compiled.graph, container, void 0, staticHTML);
|
|
1087
1240
|
const rootInstance = mountGraph(ctx);
|
|
1088
1241
|
const html = dom.serializeInner(container);
|
|
1089
1242
|
rootInstance.dispose();
|
|
@@ -1119,6 +1272,7 @@ function renderToString(compiled, options = {}) {
|
|
|
1119
1272
|
serializeState,
|
|
1120
1273
|
textUpdate,
|
|
1121
1274
|
wireEvents,
|
|
1275
|
+
wireOverlayBehavior,
|
|
1122
1276
|
wireReactiveList,
|
|
1123
1277
|
wireSignalBindings
|
|
1124
1278
|
});
|