@remix-run/ui 0.4.0 → 0.6.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/README.md +74 -1
- package/dist/accordion/index.js +2 -2
- package/dist/accordion/primitives.d.ts +1 -1
- package/dist/accordion/primitives.js.map +1 -1
- package/dist/anchor/index.js.map +1 -1
- package/dist/animation/animate-layout-mixin.js +1 -1
- package/dist/animation/animate-layout-mixin.js.map +1 -1
- package/dist/animation/animate-mixins.js +2 -2
- package/dist/animation/animate-mixins.js.map +1 -1
- package/dist/animation/demos/color-interpolation.js +1 -1
- package/dist/animation/demos/color-interpolation.js.map +1 -1
- package/dist/animation/demos/drag-release.d.ts +1 -1
- package/dist/animation/demos/hold-to-confirm.d.ts +3 -3
- package/dist/animation/demos/material-ripple.js +1 -3
- package/dist/animation/demos/material-ripple.js.map +1 -1
- package/dist/animation/index.js +4 -4
- package/dist/animation/spring.js.map +1 -1
- package/dist/breadcrumbs/index.js +2 -2
- package/dist/button/index.js +25 -25
- package/dist/button/index.js.map +1 -1
- package/dist/checkbox/index.js +11 -9
- package/dist/checkbox/index.js.map +1 -1
- package/dist/combobox/index.js +4 -4
- package/dist/combobox/index.js.map +1 -1
- package/dist/combobox/primitives.d.ts +1 -1
- package/dist/combobox/primitives.js +5 -5
- package/dist/combobox/primitives.js.map +1 -1
- package/dist/dev/refresh.d.ts +1 -0
- package/dist/dev/refresh.js +2 -0
- package/dist/dev/refresh.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -14
- package/dist/input/index.js +9 -9
- package/dist/input/index.js.map +1 -1
- package/dist/jsx-runtime.js +2 -2
- package/dist/listbox/index.js +2 -2
- package/dist/menu/hover-aim.js.map +1 -1
- package/dist/menu/index.js +3 -3
- package/dist/menu/primitives.d.ts +1 -1
- package/dist/menu/primitives.js +6 -6
- package/dist/menu/primitives.js.map +1 -1
- package/dist/popover/index.js +3 -3
- package/dist/popover/scroll-lock.js.map +1 -1
- package/dist/radio/index.js +7 -7
- package/dist/radio/index.js.map +1 -1
- package/dist/runtime/client-entry-boundary.d.ts +14 -0
- package/dist/runtime/client-entry-boundary.js +29 -0
- package/dist/runtime/client-entry-boundary.js.map +1 -0
- package/dist/runtime/component.d.ts +19 -4
- package/dist/runtime/component.js +39 -9
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/attributes.js +36 -3
- package/dist/runtime/core/attributes.js.map +1 -1
- package/dist/runtime/core/children.d.ts +2 -0
- package/dist/runtime/core/children.js +26 -2
- package/dist/runtime/core/children.js.map +1 -1
- package/dist/runtime/core/props.js +2 -2
- package/dist/runtime/core/vnode.d.ts +3 -3
- package/dist/runtime/core/vnode.js +22 -1
- package/dist/runtime/core/vnode.js.map +1 -1
- package/dist/runtime/create-element.d.ts +2 -2
- package/dist/runtime/create-element.js +3 -2
- package/dist/runtime/create-element.js.map +1 -1
- package/dist/runtime/diff-dom.js +307 -220
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/diff-props.js +3 -3
- package/dist/runtime/dom.d.ts +12 -0
- package/dist/runtime/element-function.d.ts +3 -0
- package/dist/runtime/element-function.js +2 -0
- package/dist/runtime/element-function.js.map +1 -0
- package/dist/runtime/form-navigation.d.ts +25 -0
- package/dist/runtime/form-navigation.js +132 -0
- package/dist/runtime/form-navigation.js.map +1 -0
- package/dist/runtime/frame-resolution.d.ts +5 -0
- package/dist/runtime/frame-resolution.js +10 -0
- package/dist/runtime/frame-resolution.js.map +1 -0
- package/dist/runtime/frame.d.ts +59 -15
- package/dist/runtime/frame.js +383 -114
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/jsx.d.ts +1 -1
- package/dist/runtime/jsx.js +1 -1
- package/dist/runtime/jsx.js.map +1 -1
- package/dist/runtime/key.d.ts +1 -0
- package/dist/runtime/key.js +2 -0
- package/dist/runtime/key.js.map +1 -0
- package/dist/runtime/mixins/attrs-mixin.js +2 -2
- package/dist/runtime/mixins/link-mixin.js +4 -3
- package/dist/runtime/mixins/link-mixin.js.map +1 -1
- package/dist/runtime/mixins/mixin.d.ts +15 -10
- package/dist/runtime/mixins/mixin.js +4 -4
- package/dist/runtime/mixins/mixin.js.map +1 -1
- package/dist/runtime/mixins/on-mixin.js +1 -1
- package/dist/runtime/mixins/ref-mixin.js +1 -1
- package/dist/runtime/module-preloader.d.ts +8 -0
- package/dist/runtime/module-preloader.js +95 -0
- package/dist/runtime/module-preloader.js.map +1 -0
- package/dist/runtime/navigation.d.ts +4 -1
- package/dist/runtime/navigation.js +157 -32
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.d.ts +11 -10
- package/dist/runtime/reconcile.js +549 -421
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/refresh.d.ts +28 -0
- package/dist/runtime/refresh.js +31 -0
- package/dist/runtime/refresh.js.map +1 -0
- package/dist/runtime/render.js +1 -1
- package/dist/runtime/render.js.map +1 -1
- package/dist/runtime/run.d.ts +3 -1
- package/dist/runtime/run.js +15 -7
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/scheduler.js +8 -16
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/to-vnode.d.ts +2 -2
- package/dist/runtime/to-vnode.js +68 -20
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/vdom.d.ts +4 -2
- package/dist/runtime/vdom.js +87 -42
- package/dist/runtime/vdom.js.map +1 -1
- package/dist/runtime/vnode.d.ts +138 -67
- package/dist/runtime/vnode.js +17 -12
- package/dist/runtime/vnode.js.map +1 -1
- package/dist/select/index.js +11 -11
- package/dist/select/index.js.map +1 -1
- package/dist/select/primitives.d.ts +1 -1
- package/dist/select/primitives.js +6 -6
- package/dist/server/stream.d.ts +2 -0
- package/dist/server/stream.js +74 -29
- package/dist/server/stream.js.map +1 -1
- package/dist/shared/focus-styles.d.ts +1 -1
- package/dist/shared/focus-styles.js +1 -1
- package/dist/shared/focus-styles.js.map +1 -1
- package/dist/shared/listbox-popover-styles.js +1 -1
- package/dist/shared/style-values.js +26 -26
- package/dist/shared/style-values.js.map +1 -1
- package/dist/style/css-mixin.js +3 -3
- package/dist/style/index.js +2 -2
- package/dist/style/style.js +25 -6
- package/dist/style/style.js.map +1 -1
- package/dist/style/stylesheet.d.ts +0 -1
- package/dist/style/stylesheet.js +13 -54
- package/dist/style/stylesheet.js.map +1 -1
- package/dist/tabs/index.js +11 -11
- package/dist/tabs/index.js.map +1 -1
- package/dist/tabs/primitives.d.ts +1 -1
- package/dist/test.js +1 -1
- package/dist/toggle/index.js +9 -9
- package/dist/toggle/index.js.map +1 -1
- package/dist/toggle/primitives.d.ts +1 -1
- package/package.json +10 -7
- package/src/animation/animate-mixins.ts +3 -3
- package/src/animation/demos/color-interpolation.tsx +1 -1
- package/src/button/index.ts +24 -24
- package/src/checkbox/index.ts +10 -8
- package/src/combobox/index.tsx +1 -1
- package/src/dev/refresh.ts +1 -0
- package/src/index.ts +1 -1
- package/src/input/index.ts +8 -8
- package/src/radio/index.ts +6 -5
- package/src/runtime/client-entry-boundary.ts +54 -0
- package/src/runtime/component.ts +65 -16
- package/src/runtime/core/attributes.ts +35 -1
- package/src/runtime/core/children.ts +24 -2
- package/src/runtime/core/vnode.ts +25 -4
- package/src/runtime/create-element.ts +6 -5
- package/src/runtime/demos/readme.demo.tsx +4 -4
- package/src/runtime/diff-dom.ts +370 -244
- package/src/runtime/dom.ts +331 -214
- package/src/runtime/element-function.ts +1 -0
- package/src/runtime/event-listeners.ts +1 -1
- package/src/runtime/form-navigation.ts +184 -0
- package/src/runtime/frame-resolution.ts +13 -0
- package/src/runtime/frame.ts +500 -124
- package/src/runtime/jsx.ts +3 -5
- package/src/runtime/key.ts +1 -0
- package/src/runtime/mixins/link-mixin.ts +1 -0
- package/src/runtime/mixins/mixin.ts +21 -18
- package/src/runtime/module-preloader.ts +115 -0
- package/src/runtime/navigation.ts +204 -30
- package/src/runtime/reconcile.ts +762 -759
- package/src/runtime/refresh.ts +46 -0
- package/src/runtime/run.ts +12 -2
- package/src/runtime/scheduler.ts +9 -29
- package/src/runtime/to-vnode.ts +85 -23
- package/src/runtime/vdom.ts +89 -70
- package/src/runtime/vnode.ts +192 -88
- package/src/select/index.tsx +9 -9
- package/src/server/README.md +13 -0
- package/src/server/stream.ts +93 -30
- package/src/shared/focus-styles.ts +1 -1
- package/src/shared/style-values.ts +26 -26
- package/src/style/style.ts +25 -6
- package/src/style/stylesheet.ts +32 -57
- package/src/tabs/index.tsx +12 -11
- package/src/test/README.md +151 -60
- package/src/toggle/index.tsx +9 -7
package/dist/runtime/frame.js
CHANGED
|
@@ -1,14 +1,37 @@
|
|
|
1
|
-
import { jsx } from
|
|
2
|
-
import { Frame, createFrameHandle } from
|
|
3
|
-
import { createComponentErrorEvent, getComponentError } from
|
|
4
|
-
import { invariant } from
|
|
5
|
-
import { createRangeRoot, createRoot } from
|
|
6
|
-
import { diffNodes } from
|
|
7
|
-
import { createStyleManager } from
|
|
8
|
-
import { findFlushMarker } from
|
|
1
|
+
import { jsx } from './jsx.js';
|
|
2
|
+
import { Frame, createFrameHandle } from './component.js';
|
|
3
|
+
import { createComponentErrorEvent, getComponentError } from './error-event.js';
|
|
4
|
+
import { invariant } from './invariant.js';
|
|
5
|
+
import { createRangeRoot, createRoot } from './vdom.js';
|
|
6
|
+
import { diffNodes } from './diff-dom.js';
|
|
7
|
+
import { createStyleManager } from '../style/index.js';
|
|
8
|
+
import { findFlushMarker } from './stream-protocol.js';
|
|
9
|
+
import { getDocumentModulePreloader } from './module-preloader.js';
|
|
10
|
+
import { unwrapFrameResolution } from './frame-resolution.js';
|
|
11
|
+
import { disposeClientEntryBoundary, getClientEntryBoundaryOwner, setClientEntryBoundaryOwner, } from './client-entry-boundary.js';
|
|
9
12
|
const bufferedFrameTemplates = new Map();
|
|
10
13
|
const frameTemplateListeners = new Map();
|
|
11
14
|
const DOCTYPE_PATTERN = /<!doctype(?:\s[^>]*)?>/gi;
|
|
15
|
+
function createLinkedAbortController(first, second) {
|
|
16
|
+
let controller = new AbortController();
|
|
17
|
+
let signals = second ? [first, second] : [first];
|
|
18
|
+
let abort = () => controller.abort();
|
|
19
|
+
for (let signal of signals) {
|
|
20
|
+
if (signal.aborted) {
|
|
21
|
+
controller.abort();
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
controller,
|
|
28
|
+
disconnect() {
|
|
29
|
+
for (let signal of signals) {
|
|
30
|
+
signal.removeEventListener('abort', abort);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
12
35
|
function stripDoctypeMarkup(html) {
|
|
13
36
|
return html.replace(DOCTYPE_PATTERN, '');
|
|
14
37
|
}
|
|
@@ -24,11 +47,35 @@ function syncElementAttributes(target, source) {
|
|
|
24
47
|
}
|
|
25
48
|
}
|
|
26
49
|
}
|
|
50
|
+
const FRAME_RUNTIME = Symbol('FrameRuntime');
|
|
51
|
+
export function isFrameRuntime(value) {
|
|
52
|
+
return isRecord(value) && Reflect.get(value, FRAME_RUNTIME) === true;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Reloads a frame and returns response metadata used by the navigation runtime.
|
|
56
|
+
*
|
|
57
|
+
* @param frame Frame handle to reload.
|
|
58
|
+
* @param options Form submission metadata and cancellation signal.
|
|
59
|
+
* @returns The reload signal and final response URL, when redirected.
|
|
60
|
+
*/
|
|
61
|
+
export function reloadFrameForNavigation(frame, options) {
|
|
62
|
+
let runtime = frame.$runtime;
|
|
63
|
+
invariant(isFrameRuntime(runtime), 'Expected a frame runtime');
|
|
64
|
+
let reload = runtime.reloadForNavigation;
|
|
65
|
+
invariant(reload, 'Expected frame runtime to support navigation reloads');
|
|
66
|
+
return reload(options);
|
|
67
|
+
}
|
|
27
68
|
export function createFrame(root, init) {
|
|
28
69
|
let container = createContainer(root);
|
|
29
70
|
let contentRoot;
|
|
30
71
|
let reloadController;
|
|
72
|
+
// The style registry is document-level and shared by every frame; only the
|
|
73
|
+
// frame that created it (the runtime root) disposes it.
|
|
74
|
+
let ownsStyleManager = !init.styleManager;
|
|
75
|
+
let reloadAbortUnsubscribe;
|
|
76
|
+
let reloadKind;
|
|
31
77
|
let styleManager = init.styleManager ?? createStyleManager();
|
|
78
|
+
let modulePreloader = getDocumentModulePreloader(container.doc);
|
|
32
79
|
let currentMarker = init.marker;
|
|
33
80
|
let displayedContentStatus = init.marker?.status ?? 'resolved';
|
|
34
81
|
let pendingTemplateMarkerId;
|
|
@@ -36,37 +83,21 @@ export function createFrame(root, init) {
|
|
|
36
83
|
let pendingTemplateUnsubscribe;
|
|
37
84
|
let inheritedReloadPending = false;
|
|
38
85
|
let inheritedReloadAbortUnsubscribe;
|
|
86
|
+
let disposed = false;
|
|
87
|
+
let lifecycleController = new AbortController();
|
|
88
|
+
if (isDocumentNode(container.root)) {
|
|
89
|
+
modulePreloader.adoptInitialPreloadLinks(container.root);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
modulePreloader.consumePreloadLinks(container.root);
|
|
93
|
+
}
|
|
39
94
|
// Merge any rmx-data found in the current document once at startup.
|
|
40
95
|
mergeRmxDataFromDocument(init.data, container.doc);
|
|
41
|
-
let runtime = createFrameRuntime({ ...init, styleManager });
|
|
96
|
+
let runtime = createFrameRuntime({ ...init, styleManager, reloadForNavigation: reload });
|
|
42
97
|
let frame = createFrameHandle({
|
|
43
98
|
src: init.src,
|
|
44
99
|
$runtime: runtime,
|
|
45
|
-
reload: async () =>
|
|
46
|
-
reloadController?.abort();
|
|
47
|
-
let controller = new AbortController();
|
|
48
|
-
reloadController = controller;
|
|
49
|
-
frame.dispatchEvent(new Event('reloadStart'));
|
|
50
|
-
startSubFrameInheritedReloads(getContentNodes(), controller.signal);
|
|
51
|
-
try {
|
|
52
|
-
let content = await init.resolveFrame(frame.src, controller.signal, frameName);
|
|
53
|
-
if (reloadController !== controller || controller.signal.aborted)
|
|
54
|
-
return controller.signal;
|
|
55
|
-
await render(content, { signal: controller.signal });
|
|
56
|
-
return controller.signal;
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
if (reloadController !== controller || controller.signal.aborted)
|
|
60
|
-
return controller.signal;
|
|
61
|
-
init.errorTarget.dispatchEvent(createComponentErrorEvent(error));
|
|
62
|
-
throw error;
|
|
63
|
-
}
|
|
64
|
-
finally {
|
|
65
|
-
if (reloadController === controller) {
|
|
66
|
-
frame.dispatchEvent(new Event('reloadComplete'));
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
},
|
|
100
|
+
reload: async () => (await reload()).signal,
|
|
70
101
|
replace: async (content) => {
|
|
71
102
|
await render(content);
|
|
72
103
|
},
|
|
@@ -90,18 +121,41 @@ export function createFrame(root, init) {
|
|
|
90
121
|
moduleLoads: init.moduleLoads,
|
|
91
122
|
frameInstances: init.frameInstances,
|
|
92
123
|
namedFrames: init.namedFrames,
|
|
124
|
+
lifecycleSignal: lifecycleController.signal,
|
|
93
125
|
regionTailRef: container.regionTailRef,
|
|
94
126
|
regionParent: container.regionParent,
|
|
95
127
|
};
|
|
96
128
|
async function render(content, options) {
|
|
97
|
-
if (options?.signal?.aborted)
|
|
129
|
+
if (disposed || lifecycleController.signal.aborted || options?.signal?.aborted)
|
|
130
|
+
return;
|
|
131
|
+
let ownsData = options?.data === undefined;
|
|
132
|
+
let renderOptions = {
|
|
133
|
+
...options,
|
|
134
|
+
data: options?.data ?? {},
|
|
135
|
+
};
|
|
136
|
+
try {
|
|
137
|
+
await renderContent(content, renderOptions);
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
if (ownsData)
|
|
141
|
+
clearRmxData(renderOptions.data);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function renderContent(content, options) {
|
|
145
|
+
if (isRenderAborted(options.signal))
|
|
98
146
|
return;
|
|
99
147
|
if (content instanceof ReadableStream) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
148
|
+
let linkedAbort = createLinkedAbortController(lifecycleController.signal, options.signal);
|
|
149
|
+
try {
|
|
150
|
+
await renderFrameStream(content, container.doc, async (html, flushKind) => {
|
|
151
|
+
if (isRenderAborted(options.signal))
|
|
152
|
+
return;
|
|
153
|
+
await render(html, { ...options, flushKind });
|
|
154
|
+
}, linkedAbort.controller.signal);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
linkedAbort.disconnect();
|
|
158
|
+
}
|
|
105
159
|
return;
|
|
106
160
|
}
|
|
107
161
|
if (isRemixNodeFrameContent(content)) {
|
|
@@ -112,10 +166,10 @@ export function createFrame(root, init) {
|
|
|
112
166
|
clearFrameContent();
|
|
113
167
|
contentRoot = createFrameContentRoot();
|
|
114
168
|
}
|
|
115
|
-
if (options
|
|
169
|
+
if (isRenderAborted(options.signal))
|
|
116
170
|
return;
|
|
117
171
|
contentRoot.render(content);
|
|
118
|
-
displayedContentStatus = options
|
|
172
|
+
displayedContentStatus = options.contentStatus ?? 'resolved';
|
|
119
173
|
return;
|
|
120
174
|
}
|
|
121
175
|
if (contentRoot) {
|
|
@@ -136,50 +190,66 @@ export function createFrame(root, init) {
|
|
|
136
190
|
let htmlContent = typeof content === 'string' ? stripDoctypeMarkup(content) : undefined;
|
|
137
191
|
let isFullDocumentReload = container.root instanceof Document &&
|
|
138
192
|
htmlContent !== undefined &&
|
|
139
|
-
options
|
|
193
|
+
options.flushKind === 'document';
|
|
140
194
|
if (isFullDocumentReload && htmlContent !== undefined) {
|
|
141
195
|
let parsed = new DOMParser().parseFromString(htmlContent, 'text/html');
|
|
142
|
-
|
|
143
|
-
|
|
196
|
+
modulePreloader.consumePreloadLinks(parsed);
|
|
197
|
+
let responseData = options.data;
|
|
198
|
+
mergeRmxDataFromDocument(responseData, parsed);
|
|
199
|
+
let responseContext = { ...context, data: responseData };
|
|
200
|
+
context.styleManager.adoptServerStyles(collectFrameServerStyleTags(createElementContainer(parsed)));
|
|
144
201
|
syncElementAttributes(container.doc.documentElement, parsed.documentElement);
|
|
145
202
|
diffNodes([container.doc.head], [parsed.head], {
|
|
146
|
-
...
|
|
203
|
+
...responseContext,
|
|
147
204
|
regionParent: container.doc.documentElement,
|
|
148
205
|
regionTailRef: null,
|
|
149
|
-
signal: options
|
|
206
|
+
signal: options.signal,
|
|
207
|
+
isActiveModulePreload: modulePreloader.hasActivePreloads()
|
|
208
|
+
? modulePreloader.isActivePreload
|
|
209
|
+
: undefined,
|
|
150
210
|
});
|
|
151
211
|
diffNodes([container.doc.body], [parsed.body], {
|
|
152
|
-
...
|
|
212
|
+
...responseContext,
|
|
153
213
|
regionParent: container.doc.documentElement,
|
|
154
214
|
regionTailRef: null,
|
|
155
|
-
signal: options
|
|
215
|
+
signal: options.signal,
|
|
156
216
|
});
|
|
157
217
|
let bodyContainer = createElementContainer(container.doc.body);
|
|
158
|
-
if (options
|
|
218
|
+
if (isRenderAborted(options.signal))
|
|
159
219
|
return;
|
|
160
|
-
scheduleHydrationInContainer(bodyContainer,
|
|
161
|
-
await createSubFrames(bodyContainer.childNodes,
|
|
162
|
-
|
|
220
|
+
scheduleHydrationInContainer(bodyContainer, responseContext, options.initialHydrationTracker, options.signal);
|
|
221
|
+
await createSubFrames(bodyContainer.childNodes, responseContext, options);
|
|
222
|
+
if (isRenderAborted(options.signal))
|
|
223
|
+
return;
|
|
224
|
+
displayedContentStatus = options.contentStatus ?? 'resolved';
|
|
163
225
|
return;
|
|
164
226
|
}
|
|
165
227
|
let fragment = htmlContent !== undefined ? createFragmentFromString(container.doc, htmlContent) : content;
|
|
166
|
-
|
|
228
|
+
modulePreloader.consumePreloadLinks(fragment);
|
|
229
|
+
context.styleManager.adoptServerStyles(collectFrameServerStyleTags(createElementContainer(fragment)));
|
|
167
230
|
removeEmptyHeads(fragment);
|
|
168
|
-
|
|
231
|
+
let responseData = options.data;
|
|
232
|
+
mergeRmxDataFromFragment(responseData, fragment);
|
|
233
|
+
let responseContext = { ...context, data: responseData };
|
|
169
234
|
let nextContainer = createContainer(fragment);
|
|
170
|
-
if (options
|
|
235
|
+
if (isRenderAborted(options.signal))
|
|
171
236
|
return;
|
|
172
237
|
diffNodes(container.childNodes, Array.from(nextContainer.childNodes), {
|
|
173
|
-
...
|
|
238
|
+
...responseContext,
|
|
174
239
|
regionTailRef: container.regionTailRef,
|
|
175
240
|
regionParent: container.regionParent,
|
|
176
|
-
signal: options
|
|
241
|
+
signal: options.signal,
|
|
177
242
|
});
|
|
178
|
-
if (options
|
|
243
|
+
if (isRenderAborted(options.signal))
|
|
244
|
+
return;
|
|
245
|
+
scheduleHydrationInContainer(container, responseContext, options.initialHydrationTracker, options.signal);
|
|
246
|
+
await createSubFrames(container.childNodes, responseContext, options);
|
|
247
|
+
if (isRenderAborted(options.signal))
|
|
179
248
|
return;
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
249
|
+
displayedContentStatus = options.contentStatus ?? 'resolved';
|
|
250
|
+
}
|
|
251
|
+
function isRenderAborted(signal) {
|
|
252
|
+
return disposed || lifecycleController.signal.aborted || signal?.aborted === true;
|
|
183
253
|
}
|
|
184
254
|
function createFrameContentRoot() {
|
|
185
255
|
let virtualRoot;
|
|
@@ -217,18 +287,34 @@ export function createFrame(root, init) {
|
|
|
217
287
|
}
|
|
218
288
|
async function hydrateInitial() {
|
|
219
289
|
let initialHydrationTracker = createInitialHydrationTracker();
|
|
220
|
-
context.styleManager.
|
|
221
|
-
|
|
290
|
+
context.styleManager.adoptServerStyles(collectFrameServerStyleTags(container));
|
|
291
|
+
let subFramesReady = createSubFrames(container.childNodes, context);
|
|
222
292
|
scheduleHydrationInContainer(container, context, initialHydrationTracker);
|
|
223
|
-
|
|
224
|
-
await
|
|
293
|
+
try {
|
|
294
|
+
await subFramesReady;
|
|
295
|
+
if (disposed || context.lifecycleSignal.aborted)
|
|
296
|
+
return;
|
|
297
|
+
if (currentMarker?.status === 'pending') {
|
|
298
|
+
await watchPendingFrameTemplate(currentMarker, initialHydrationTracker);
|
|
299
|
+
}
|
|
300
|
+
initialHydrationTracker.finalize();
|
|
301
|
+
await initialHydrationTracker.ready();
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
clearRmxData(context.data);
|
|
225
305
|
}
|
|
226
|
-
initialHydrationTracker.finalize();
|
|
227
|
-
await initialHydrationTracker.ready();
|
|
228
306
|
}
|
|
229
307
|
function dispose() {
|
|
308
|
+
if (disposed)
|
|
309
|
+
return;
|
|
310
|
+
disposed = true;
|
|
311
|
+
lifecycleController.abort();
|
|
312
|
+
clearRmxData(context.data);
|
|
230
313
|
reloadController?.abort();
|
|
231
314
|
reloadController = undefined;
|
|
315
|
+
reloadAbortUnsubscribe?.();
|
|
316
|
+
reloadAbortUnsubscribe = undefined;
|
|
317
|
+
reloadKind = undefined;
|
|
232
318
|
contentRoot?.dispose();
|
|
233
319
|
contentRoot = undefined;
|
|
234
320
|
clearPendingFrameTemplateWatch();
|
|
@@ -236,7 +322,9 @@ export function createFrame(root, init) {
|
|
|
236
322
|
removeVirtualRoots(container.childNodes);
|
|
237
323
|
// Dispose sub-frames recursively.
|
|
238
324
|
disposeSubFrames(container.childNodes, context);
|
|
239
|
-
|
|
325
|
+
if (ownsStyleManager) {
|
|
326
|
+
context.styleManager.dispose();
|
|
327
|
+
}
|
|
240
328
|
if (frameName) {
|
|
241
329
|
if (init.namedFrames.get(frameName) === frame) {
|
|
242
330
|
init.namedFrames.delete(frameName);
|
|
@@ -250,14 +338,17 @@ export function createFrame(root, init) {
|
|
|
250
338
|
flush: () => context.scheduler.dequeue(),
|
|
251
339
|
clearPendingTemplateWatch: clearPendingFrameTemplateWatch,
|
|
252
340
|
isDisplayingResolvedContent: () => displayedContentStatus === 'resolved',
|
|
341
|
+
beginClientFrameReloadForAncestorReload,
|
|
342
|
+
cancelReload,
|
|
253
343
|
startInheritedReload,
|
|
254
344
|
updateMarker,
|
|
255
345
|
renderMarkerContent,
|
|
346
|
+
matchesIdentity: (src, name) => !disposed && frame.src === src && frameName === name,
|
|
256
347
|
dispose,
|
|
257
348
|
handle: frame,
|
|
258
349
|
};
|
|
259
350
|
async function updateMarker(marker, options) {
|
|
260
|
-
if (options?.signal?.aborted)
|
|
351
|
+
if (disposed || context.lifecycleSignal.aborted || options?.signal?.aborted)
|
|
261
352
|
return;
|
|
262
353
|
let previousMarker = currentMarker;
|
|
263
354
|
let isInheritedReload = previousMarker !== undefined && previousMarker.id !== marker.id;
|
|
@@ -280,7 +371,7 @@ export function createFrame(root, init) {
|
|
|
280
371
|
}
|
|
281
372
|
}
|
|
282
373
|
async function renderMarkerContent(marker, content, options) {
|
|
283
|
-
if (options?.signal?.aborted)
|
|
374
|
+
if (disposed || context.lifecycleSignal.aborted || options?.signal?.aborted)
|
|
284
375
|
return;
|
|
285
376
|
let previousMarker = currentMarker;
|
|
286
377
|
let isInheritedReload = previousMarker !== undefined && previousMarker.id !== marker.id;
|
|
@@ -290,10 +381,102 @@ export function createFrame(root, init) {
|
|
|
290
381
|
}
|
|
291
382
|
clearPendingFrameTemplateWatch();
|
|
292
383
|
await render(content, { ...options, contentStatus: 'resolved' });
|
|
293
|
-
if (isInheritedReload &&
|
|
384
|
+
if (isInheritedReload &&
|
|
385
|
+
!disposed &&
|
|
386
|
+
!context.lifecycleSignal.aborted &&
|
|
387
|
+
!options?.signal?.aborted) {
|
|
294
388
|
completeInheritedReload();
|
|
295
389
|
}
|
|
296
390
|
}
|
|
391
|
+
async function reload(options) {
|
|
392
|
+
let controller = startReload(options?.signal);
|
|
393
|
+
return await resolveAndRenderReload(controller, options);
|
|
394
|
+
}
|
|
395
|
+
function startReload(signal) {
|
|
396
|
+
let controller = replaceReloadController(signal);
|
|
397
|
+
reloadKind = 'direct';
|
|
398
|
+
frame.dispatchEvent(new Event('reloadStart'));
|
|
399
|
+
startSubFrameInheritedReloads(getContentNodes(), controller.signal);
|
|
400
|
+
return controller;
|
|
401
|
+
}
|
|
402
|
+
function beginClientFrameReloadForAncestorReload(signal) {
|
|
403
|
+
let inheritedReloadStarted = reuseInheritedReloadStart();
|
|
404
|
+
let continuingAncestorReload = reloadKind === 'ancestor';
|
|
405
|
+
let controller = replaceReloadController(signal);
|
|
406
|
+
reloadKind = 'ancestor';
|
|
407
|
+
if (!inheritedReloadStarted && !continuingAncestorReload) {
|
|
408
|
+
frame.dispatchEvent(new Event('reloadStart'));
|
|
409
|
+
startSubFrameInheritedReloads(getContentNodes(), controller.signal);
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
controller,
|
|
413
|
+
complete: () => completeReload(controller),
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function cancelReload() {
|
|
417
|
+
let controller = reloadController;
|
|
418
|
+
if (!controller)
|
|
419
|
+
return;
|
|
420
|
+
controller.abort();
|
|
421
|
+
completeReload(controller);
|
|
422
|
+
}
|
|
423
|
+
function replaceReloadController(signal) {
|
|
424
|
+
reloadController?.abort();
|
|
425
|
+
reloadAbortUnsubscribe?.();
|
|
426
|
+
reloadAbortUnsubscribe = undefined;
|
|
427
|
+
let controller = new AbortController();
|
|
428
|
+
reloadController = controller;
|
|
429
|
+
if (signal) {
|
|
430
|
+
if (signal.aborted) {
|
|
431
|
+
controller.abort();
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
let abort = () => controller.abort();
|
|
435
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
436
|
+
reloadAbortUnsubscribe = () => signal.removeEventListener('abort', abort);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return controller;
|
|
440
|
+
}
|
|
441
|
+
async function resolveAndRenderReload(controller, options) {
|
|
442
|
+
try {
|
|
443
|
+
let resolution = await init.resolveFrame(frame.src, {
|
|
444
|
+
...options,
|
|
445
|
+
signal: controller.signal,
|
|
446
|
+
target: frameName,
|
|
447
|
+
});
|
|
448
|
+
if (reloadController !== controller || controller.signal.aborted) {
|
|
449
|
+
return { signal: controller.signal };
|
|
450
|
+
}
|
|
451
|
+
let { content, redirectedTo } = await unwrapFrameResolution(resolution);
|
|
452
|
+
if (reloadController !== controller || controller.signal.aborted) {
|
|
453
|
+
return { signal: controller.signal };
|
|
454
|
+
}
|
|
455
|
+
await render(content, { signal: controller.signal });
|
|
456
|
+
return {
|
|
457
|
+
signal: controller.signal,
|
|
458
|
+
redirectedTo: reloadController === controller && !controller.signal.aborted ? redirectedTo : undefined,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
catch (error) {
|
|
462
|
+
if (reloadController !== controller || controller.signal.aborted) {
|
|
463
|
+
return { signal: controller.signal };
|
|
464
|
+
}
|
|
465
|
+
init.errorTarget.dispatchEvent(createComponentErrorEvent(error));
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
finally {
|
|
469
|
+
completeReload(controller);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
function completeReload(controller) {
|
|
473
|
+
if (reloadController !== controller || reloadKind === undefined)
|
|
474
|
+
return;
|
|
475
|
+
reloadAbortUnsubscribe?.();
|
|
476
|
+
reloadAbortUnsubscribe = undefined;
|
|
477
|
+
reloadKind = undefined;
|
|
478
|
+
frame.dispatchEvent(new Event('reloadComplete'));
|
|
479
|
+
}
|
|
297
480
|
function startInheritedReload(signal) {
|
|
298
481
|
if (signal?.aborted)
|
|
299
482
|
return;
|
|
@@ -312,6 +495,14 @@ export function createFrame(root, init) {
|
|
|
312
495
|
};
|
|
313
496
|
}
|
|
314
497
|
}
|
|
498
|
+
function reuseInheritedReloadStart() {
|
|
499
|
+
if (!inheritedReloadPending)
|
|
500
|
+
return false;
|
|
501
|
+
inheritedReloadPending = false;
|
|
502
|
+
inheritedReloadAbortUnsubscribe?.();
|
|
503
|
+
inheritedReloadAbortUnsubscribe = undefined;
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
315
506
|
function completeInheritedReload() {
|
|
316
507
|
if (!inheritedReloadPending)
|
|
317
508
|
return;
|
|
@@ -328,7 +519,7 @@ export function createFrame(root, init) {
|
|
|
328
519
|
if (isFrameStart(node)) {
|
|
329
520
|
let end = findEndMarker(node, isFrameStart, isFrameEnd);
|
|
330
521
|
context.frameInstances.get(node)?.startInheritedReload(signal);
|
|
331
|
-
i = nodes
|
|
522
|
+
i = findMarkerRangeEndIndex(nodes, end, i);
|
|
332
523
|
continue;
|
|
333
524
|
}
|
|
334
525
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
@@ -344,7 +535,7 @@ export function createFrame(root, init) {
|
|
|
344
535
|
pendingTemplateMarkerId = undefined;
|
|
345
536
|
}
|
|
346
537
|
async function watchPendingFrameTemplate(marker, initialHydrationTracker, signal, onResolved) {
|
|
347
|
-
if (signal?.aborted)
|
|
538
|
+
if (disposed || context.lifecycleSignal.aborted || signal?.aborted)
|
|
348
539
|
return;
|
|
349
540
|
if (pendingTemplateMarkerId === marker.id)
|
|
350
541
|
return;
|
|
@@ -354,24 +545,24 @@ export function createFrame(root, init) {
|
|
|
354
545
|
if (early) {
|
|
355
546
|
clearPendingFrameTemplateWatch();
|
|
356
547
|
await render(early, { initialHydrationTracker, signal, contentStatus: 'resolved' });
|
|
357
|
-
if (!signal?.aborted)
|
|
548
|
+
if (!disposed && !context.lifecycleSignal.aborted && !signal?.aborted)
|
|
358
549
|
onResolved?.();
|
|
359
550
|
return;
|
|
360
551
|
}
|
|
361
|
-
if (signal?.aborted) {
|
|
552
|
+
if (disposed || context.lifecycleSignal.aborted || signal?.aborted) {
|
|
362
553
|
clearPendingFrameTemplateWatch();
|
|
363
554
|
return;
|
|
364
555
|
}
|
|
365
556
|
let observer = setupTemplateObserver();
|
|
366
557
|
pendingTemplateObserver = observer;
|
|
367
558
|
let unsubscribe = subscribeFrameTemplate(marker.id, async (fragment) => {
|
|
368
|
-
if (signal?.aborted)
|
|
559
|
+
if (disposed || context.lifecycleSignal.aborted || signal?.aborted)
|
|
369
560
|
return;
|
|
370
561
|
if (pendingTemplateMarkerId !== marker.id)
|
|
371
562
|
return;
|
|
372
563
|
clearPendingFrameTemplateWatch();
|
|
373
564
|
await render(fragment, { signal, contentStatus: 'resolved' });
|
|
374
|
-
if (!signal?.aborted)
|
|
565
|
+
if (!disposed && !context.lifecycleSignal.aborted && !signal?.aborted)
|
|
375
566
|
onResolved?.();
|
|
376
567
|
});
|
|
377
568
|
pendingTemplateUnsubscribe = unsubscribe;
|
|
@@ -384,13 +575,14 @@ export function createFrame(root, init) {
|
|
|
384
575
|
if (buffered) {
|
|
385
576
|
clearPendingFrameTemplateWatch();
|
|
386
577
|
await render(buffered, { initialHydrationTracker, signal, contentStatus: 'resolved' });
|
|
387
|
-
if (!signal?.aborted)
|
|
578
|
+
if (!disposed && !context.lifecycleSignal.aborted && !signal?.aborted)
|
|
388
579
|
onResolved?.();
|
|
389
580
|
}
|
|
390
581
|
}
|
|
391
582
|
}
|
|
392
583
|
export function createFrameRuntime(init) {
|
|
393
584
|
return {
|
|
585
|
+
[FRAME_RUNTIME]: true,
|
|
394
586
|
topFrame: init.topFrame,
|
|
395
587
|
errorTarget: init.errorTarget,
|
|
396
588
|
loadModule: init.loadModule,
|
|
@@ -398,11 +590,12 @@ export function createFrameRuntime(init) {
|
|
|
398
590
|
pendingClientEntries: init.pendingClientEntries,
|
|
399
591
|
scheduler: init.scheduler,
|
|
400
592
|
styleManager: init.styleManager,
|
|
401
|
-
data: init.data,
|
|
402
593
|
moduleCache: init.moduleCache,
|
|
403
594
|
moduleLoads: init.moduleLoads,
|
|
404
595
|
frameInstances: init.frameInstances,
|
|
405
596
|
namedFrames: init.namedFrames,
|
|
597
|
+
serverFrameReload: undefined,
|
|
598
|
+
reloadForNavigation: init.reloadForNavigation,
|
|
406
599
|
};
|
|
407
600
|
}
|
|
408
601
|
function createInitialHydrationTracker() {
|
|
@@ -457,6 +650,10 @@ function mergeRmxDataFromFragment(into, fragment) {
|
|
|
457
650
|
script.remove();
|
|
458
651
|
}
|
|
459
652
|
}
|
|
653
|
+
function clearRmxData(data) {
|
|
654
|
+
delete data.h;
|
|
655
|
+
delete data.f;
|
|
656
|
+
}
|
|
460
657
|
function removeEmptyHeads(fragment) {
|
|
461
658
|
let heads = Array.from(fragment.querySelectorAll('head'));
|
|
462
659
|
for (let head of heads) {
|
|
@@ -478,14 +675,14 @@ function collectOwnedServerStyleTags(nodes, styles) {
|
|
|
478
675
|
let node = nodes[i];
|
|
479
676
|
if (isFrameStart(node)) {
|
|
480
677
|
let end = findEndMarker(node, isFrameStart, isFrameEnd);
|
|
481
|
-
i = nodes
|
|
678
|
+
i = findMarkerRangeEndIndex(nodes, end, i);
|
|
482
679
|
continue;
|
|
483
680
|
}
|
|
484
681
|
if (node instanceof HTMLStyleElement && node.matches('style[data-rmx]')) {
|
|
485
682
|
styles.push(node);
|
|
486
683
|
continue;
|
|
487
684
|
}
|
|
488
|
-
if (node
|
|
685
|
+
if (node.childNodes.length > 0) {
|
|
489
686
|
collectOwnedServerStyleTags(Array.from(node.childNodes), styles);
|
|
490
687
|
}
|
|
491
688
|
}
|
|
@@ -520,7 +717,7 @@ function copyOwnRmxEntries(target, source) {
|
|
|
520
717
|
target[key] = source[key];
|
|
521
718
|
}
|
|
522
719
|
}
|
|
523
|
-
function scheduleHydrationInContainer(container, context, initialHydrationTracker) {
|
|
720
|
+
function scheduleHydrationInContainer(container, context, initialHydrationTracker, signal) {
|
|
524
721
|
let hydrationMarkers = findHydrationMarkers(container);
|
|
525
722
|
if (hydrationMarkers.length === 0)
|
|
526
723
|
return;
|
|
@@ -531,44 +728,67 @@ function scheduleHydrationInContainer(container, context, initialHydrationTracke
|
|
|
531
728
|
let entry = hydrationData[marker.id];
|
|
532
729
|
if (!entry)
|
|
533
730
|
continue;
|
|
534
|
-
scheduleHydrationMarker(marker, entry, context, initialHydrationTracker);
|
|
731
|
+
scheduleHydrationMarker(marker, entry, context, initialHydrationTracker, signal);
|
|
535
732
|
}
|
|
536
733
|
}
|
|
537
|
-
function scheduleHydrationMarker(marker, entry, context, initialHydrationTracker) {
|
|
734
|
+
function scheduleHydrationMarker(marker, entry, context, initialHydrationTracker, signal) {
|
|
735
|
+
if (signal?.aborted || context.lifecycleSignal.aborted)
|
|
736
|
+
return;
|
|
538
737
|
let done = initialHydrationTracker?.track();
|
|
539
738
|
let key = `${entry.moduleUrl}#${entry.exportName}`;
|
|
739
|
+
let identity = {
|
|
740
|
+
moduleUrl: entry.moduleUrl,
|
|
741
|
+
exportName: entry.exportName,
|
|
742
|
+
};
|
|
743
|
+
let props = entry.props;
|
|
744
|
+
let completed = false;
|
|
745
|
+
let complete = () => {
|
|
746
|
+
if (completed)
|
|
747
|
+
return;
|
|
748
|
+
completed = true;
|
|
749
|
+
props = undefined;
|
|
750
|
+
signal?.removeEventListener('abort', complete);
|
|
751
|
+
context.lifecycleSignal.removeEventListener('abort', complete);
|
|
752
|
+
done?.();
|
|
753
|
+
};
|
|
754
|
+
signal?.addEventListener('abort', complete, { once: true });
|
|
755
|
+
context.lifecycleSignal.addEventListener('abort', complete, { once: true });
|
|
540
756
|
let hydrateWithComponent = (component) => {
|
|
757
|
+
if (signal?.aborted || context.lifecycleSignal.aborted)
|
|
758
|
+
return;
|
|
541
759
|
if (!isHydrationMarkerLive(marker, context))
|
|
542
760
|
return;
|
|
543
|
-
|
|
761
|
+
if (!props)
|
|
762
|
+
return;
|
|
763
|
+
let vElement = createElement(component, props);
|
|
544
764
|
context.pendingClientEntries.set(marker.start, [marker.end, vElement]);
|
|
545
|
-
hydrateRegion(vElement, marker.start, marker.end, context);
|
|
765
|
+
hydrateRegion(vElement, marker.start, marker.end, identity, context, signal);
|
|
546
766
|
};
|
|
547
767
|
let cached = context.moduleCache.get(key);
|
|
548
768
|
if (cached) {
|
|
549
769
|
hydrateWithComponent(cached);
|
|
550
|
-
|
|
770
|
+
complete();
|
|
551
771
|
return;
|
|
552
772
|
}
|
|
553
|
-
getOrStartModuleLoad(key,
|
|
773
|
+
getOrStartModuleLoad(key, identity, marker.id, context)
|
|
554
774
|
.then((component) => {
|
|
555
775
|
if (component) {
|
|
556
776
|
hydrateWithComponent(component);
|
|
557
777
|
}
|
|
558
778
|
})
|
|
559
779
|
.finally(() => {
|
|
560
|
-
|
|
780
|
+
complete();
|
|
561
781
|
});
|
|
562
782
|
}
|
|
563
|
-
function getOrStartModuleLoad(key,
|
|
783
|
+
function getOrStartModuleLoad(key, identity, markerId, context) {
|
|
564
784
|
let inFlight = context.moduleLoads.get(key);
|
|
565
785
|
if (inFlight)
|
|
566
786
|
return inFlight;
|
|
567
787
|
let loadPromise = (async () => {
|
|
568
788
|
try {
|
|
569
|
-
let mod = await context.loadModule(
|
|
570
|
-
if (
|
|
571
|
-
throw new Error(`Export "${
|
|
789
|
+
let mod = await context.loadModule(identity.moduleUrl, identity.exportName);
|
|
790
|
+
if (!isElementFunction(mod)) {
|
|
791
|
+
throw new Error(`Export "${identity.exportName}" from "${identity.moduleUrl}" is not a function`);
|
|
572
792
|
}
|
|
573
793
|
context.moduleCache.set(key, mod);
|
|
574
794
|
return mod;
|
|
@@ -586,8 +806,12 @@ function getOrStartModuleLoad(key, entry, markerId, context) {
|
|
|
586
806
|
}
|
|
587
807
|
function createElement(component, props) {
|
|
588
808
|
let revivedProps = reviveSerializedValue(props);
|
|
809
|
+
invariant(isRecord(revivedProps), 'Expected revived component props to be an object');
|
|
589
810
|
return jsx(component, revivedProps);
|
|
590
811
|
}
|
|
812
|
+
function isElementFunction(value) {
|
|
813
|
+
return typeof value === 'function';
|
|
814
|
+
}
|
|
591
815
|
function reviveSerializedValue(value) {
|
|
592
816
|
if (value === null || value === undefined)
|
|
593
817
|
return value;
|
|
@@ -596,6 +820,8 @@ function reviveSerializedValue(value) {
|
|
|
596
820
|
if (Array.isArray(value)) {
|
|
597
821
|
return value.map((item) => reviveSerializedValue(item));
|
|
598
822
|
}
|
|
823
|
+
if (!isRecord(value))
|
|
824
|
+
return value;
|
|
599
825
|
let record = value;
|
|
600
826
|
if (record.$rmxFrame === true) {
|
|
601
827
|
let props = reviveSerializedObject(record.props);
|
|
@@ -619,15 +845,34 @@ function reviveSerializedObject(value) {
|
|
|
619
845
|
let revived = reviveSerializedValue(value);
|
|
620
846
|
if (!revived || typeof revived !== 'object' || Array.isArray(revived))
|
|
621
847
|
return {};
|
|
622
|
-
return revived;
|
|
848
|
+
return isRecord(revived) ? revived : {};
|
|
849
|
+
}
|
|
850
|
+
function isRecord(value) {
|
|
851
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
623
852
|
}
|
|
624
|
-
function hydrateRegion(vElement, start, end, context) {
|
|
853
|
+
function hydrateRegion(vElement, start, end, identity, context, signal) {
|
|
854
|
+
if (signal?.aborted)
|
|
855
|
+
return;
|
|
625
856
|
context.pendingClientEntries.delete(start);
|
|
626
857
|
// The same marker can be discovered by overlapping hydration passes
|
|
627
858
|
// (for example, document root + nested frame root). Reuse the existing
|
|
628
859
|
// virtual root instead of redefining the marker property.
|
|
629
|
-
|
|
630
|
-
|
|
860
|
+
let owner = getClientEntryBoundaryOwner(start);
|
|
861
|
+
if (owner) {
|
|
862
|
+
if (!signal) {
|
|
863
|
+
owner.root.render(vElement);
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
let frameRuntime = context.frame.$runtime;
|
|
867
|
+
invariant(isFrameRuntime(frameRuntime), 'Expected frame runtime while rendering a preserved client entry');
|
|
868
|
+
let previousServerFrameReload = frameRuntime.serverFrameReload;
|
|
869
|
+
frameRuntime.serverFrameReload = { signal };
|
|
870
|
+
try {
|
|
871
|
+
owner.root.render(vElement);
|
|
872
|
+
}
|
|
873
|
+
finally {
|
|
874
|
+
frameRuntime.serverFrameReload = previousServerFrameReload;
|
|
875
|
+
}
|
|
631
876
|
return;
|
|
632
877
|
}
|
|
633
878
|
let root = createRangeRoot([start, end], {
|
|
@@ -640,7 +885,7 @@ function hydrateRegion(vElement, start, end, context) {
|
|
|
640
885
|
return;
|
|
641
886
|
context.errorTarget.dispatchEvent(createComponentErrorEvent(getComponentError(event)));
|
|
642
887
|
});
|
|
643
|
-
|
|
888
|
+
setClientEntryBoundaryOwner(start, identity, root);
|
|
644
889
|
root.render(vElement);
|
|
645
890
|
}
|
|
646
891
|
async function createSubFrames(nodes, context, options) {
|
|
@@ -675,6 +920,7 @@ async function createSubFrames(nodes, context, options) {
|
|
|
675
920
|
resolveFrame: context.resolveFrame,
|
|
676
921
|
pendingClientEntries: context.pendingClientEntries,
|
|
677
922
|
scheduler: context.scheduler,
|
|
923
|
+
styleManager: context.styleManager,
|
|
678
924
|
data: context.data,
|
|
679
925
|
moduleCache: context.moduleCache,
|
|
680
926
|
moduleLoads: context.moduleLoads,
|
|
@@ -684,7 +930,7 @@ async function createSubFrames(nodes, context, options) {
|
|
|
684
930
|
context.frameInstances.set(node, subFrame);
|
|
685
931
|
}
|
|
686
932
|
}
|
|
687
|
-
i = nodes
|
|
933
|
+
i = findMarkerRangeEndIndex(nodes, end, i);
|
|
688
934
|
continue;
|
|
689
935
|
}
|
|
690
936
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
@@ -719,10 +965,9 @@ function isHydrationMarkerLive(marker, context) {
|
|
|
719
965
|
function removeVirtualRoots(nodes) {
|
|
720
966
|
for (let i = 0; i < nodes.length; i++) {
|
|
721
967
|
let node = nodes[i];
|
|
722
|
-
if (
|
|
723
|
-
node.$rmx.dispose();
|
|
968
|
+
if (isCommentNode(node) && isHydrationStart(node) && disposeClientEntryBoundary(node)) {
|
|
724
969
|
let end = findEndMarker(node, isHydrationStart, isHydrationEnd);
|
|
725
|
-
i = nodes
|
|
970
|
+
i = findMarkerRangeEndIndex(nodes, end, i);
|
|
726
971
|
continue;
|
|
727
972
|
}
|
|
728
973
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
@@ -740,7 +985,7 @@ function disposeSubFrames(nodes, context) {
|
|
|
740
985
|
subFrame.dispose();
|
|
741
986
|
context.frameInstances.delete(node);
|
|
742
987
|
}
|
|
743
|
-
i = nodes
|
|
988
|
+
i = findMarkerRangeEndIndex(nodes, end, i);
|
|
744
989
|
continue;
|
|
745
990
|
}
|
|
746
991
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
@@ -801,7 +1046,9 @@ export function publishFrameTemplate(id, fragment) {
|
|
|
801
1046
|
return;
|
|
802
1047
|
}
|
|
803
1048
|
for (let listener of listeners) {
|
|
804
|
-
|
|
1049
|
+
let clone = fragment.cloneNode(true);
|
|
1050
|
+
invariant(isDocumentFragmentNode(clone), 'Expected cloned frame template fragment');
|
|
1051
|
+
listener(clone);
|
|
805
1052
|
}
|
|
806
1053
|
}
|
|
807
1054
|
export function consumeFrameTemplate(id) {
|
|
@@ -873,12 +1120,21 @@ function extractTemplatesFromBuffer(doc, buffer, onTemplate) {
|
|
|
873
1120
|
remainder: tail.slice(tailStart),
|
|
874
1121
|
};
|
|
875
1122
|
}
|
|
876
|
-
async function renderFrameStream(stream, doc, applyHtml) {
|
|
1123
|
+
async function renderFrameStream(stream, doc, applyHtml, signal) {
|
|
877
1124
|
let reader = stream.getReader();
|
|
878
1125
|
let decoder = new TextDecoder();
|
|
879
1126
|
let buffer = '';
|
|
880
1127
|
let html = '';
|
|
881
1128
|
let appliedOnce = false;
|
|
1129
|
+
let abort = () => {
|
|
1130
|
+
void reader.cancel().catch(() => { });
|
|
1131
|
+
};
|
|
1132
|
+
if (signal?.aborted) {
|
|
1133
|
+
await reader.cancel();
|
|
1134
|
+
reader.releaseLock();
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
882
1138
|
try {
|
|
883
1139
|
while (true) {
|
|
884
1140
|
let { done, value } = await reader.read();
|
|
@@ -913,6 +1169,7 @@ async function renderFrameStream(stream, doc, applyHtml) {
|
|
|
913
1169
|
}
|
|
914
1170
|
}
|
|
915
1171
|
finally {
|
|
1172
|
+
signal?.removeEventListener('abort', abort);
|
|
916
1173
|
reader.releaseLock();
|
|
917
1174
|
}
|
|
918
1175
|
}
|
|
@@ -973,7 +1230,7 @@ function createFragmentFromString(doc, content) {
|
|
|
973
1230
|
}
|
|
974
1231
|
function isRemixNodeFrameContent(content) {
|
|
975
1232
|
return !(content instanceof ReadableStream ||
|
|
976
|
-
content
|
|
1233
|
+
isDocumentFragmentNode(content) ||
|
|
977
1234
|
typeof content === 'string');
|
|
978
1235
|
}
|
|
979
1236
|
function findHydrationMarkers(container) {
|
|
@@ -998,10 +1255,10 @@ function walkCommentsInNodes(nodes, cb) {
|
|
|
998
1255
|
// are discovered and hydrated by the nested frame instance only.
|
|
999
1256
|
if (isFrameStart(node)) {
|
|
1000
1257
|
let end = findEndMarker(node, isFrameStart, isFrameEnd);
|
|
1001
|
-
i = nodes
|
|
1258
|
+
i = findMarkerRangeEndIndex(nodes, end, i);
|
|
1002
1259
|
continue;
|
|
1003
1260
|
}
|
|
1004
|
-
if (node
|
|
1261
|
+
if (isCommentNode(node))
|
|
1005
1262
|
cb(node);
|
|
1006
1263
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
1007
1264
|
walkCommentsInNodes(Array.from(node.childNodes), cb);
|
|
@@ -1014,11 +1271,8 @@ function isHydrationStart(node) {
|
|
|
1014
1271
|
function isHydrationEnd(node) {
|
|
1015
1272
|
return node.data.trim() === '/rmx:h';
|
|
1016
1273
|
}
|
|
1017
|
-
function isHydratedVirtualRootMarker(node) {
|
|
1018
|
-
return node instanceof Comment && '$rmx' in node;
|
|
1019
|
-
}
|
|
1020
1274
|
function isFrameStart(node) {
|
|
1021
|
-
return node
|
|
1275
|
+
return isCommentNode(node) && node.data.trim().startsWith('rmx:f:');
|
|
1022
1276
|
}
|
|
1023
1277
|
function isFrameEnd(node) {
|
|
1024
1278
|
return node.data.trim() === '/rmx:f';
|
|
@@ -1028,11 +1282,15 @@ function getFrameId(start) {
|
|
|
1028
1282
|
invariant(trimmed.startsWith('rmx:f:'), 'Invalid frame start marker');
|
|
1029
1283
|
return trimmed.slice('rmx:f:'.length);
|
|
1030
1284
|
}
|
|
1285
|
+
function findMarkerRangeEndIndex(nodes, end, startIndex) {
|
|
1286
|
+
// The snapshot may not contain an end marker moved by a DOM update.
|
|
1287
|
+
return Math.max(startIndex, nodes.indexOf(end));
|
|
1288
|
+
}
|
|
1031
1289
|
function findEndMarker(start, isStart, isEnd) {
|
|
1032
1290
|
let node = start.nextSibling;
|
|
1033
1291
|
let depth = 1;
|
|
1034
1292
|
while (node) {
|
|
1035
|
-
if (node
|
|
1293
|
+
if (isCommentNode(node)) {
|
|
1036
1294
|
let comment = node;
|
|
1037
1295
|
if (isStart(comment))
|
|
1038
1296
|
depth++;
|
|
@@ -1046,4 +1304,15 @@ function findEndMarker(start, isStart, isEnd) {
|
|
|
1046
1304
|
}
|
|
1047
1305
|
throw new Error('End marker not found');
|
|
1048
1306
|
}
|
|
1307
|
+
function isCommentNode(node) {
|
|
1308
|
+
return node?.nodeType === Node.COMMENT_NODE;
|
|
1309
|
+
}
|
|
1310
|
+
function isDocumentNode(node) {
|
|
1311
|
+
return node.nodeType === Node.DOCUMENT_NODE;
|
|
1312
|
+
}
|
|
1313
|
+
function isDocumentFragmentNode(value) {
|
|
1314
|
+
return (typeof value === 'object' &&
|
|
1315
|
+
value !== null &&
|
|
1316
|
+
Reflect.get(value, 'nodeType') === Node.DOCUMENT_FRAGMENT_NODE);
|
|
1317
|
+
}
|
|
1049
1318
|
//# sourceMappingURL=frame.js.map
|