@microsoft/webui-framework 0.0.22 → 0.0.23
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 +104 -38
- package/dist/decorators.js +9 -2
- package/dist/element/markers.d.ts +8 -0
- package/dist/element/markers.js +95 -16
- package/dist/element.d.ts +11 -2
- package/dist/element.js +87 -2
- package/dist/lazy-hydration-contract.d.ts +22 -0
- package/dist/lazy-hydration-contract.js +28 -0
- package/dist/lazy-hydration-coordinator.d.ts +2 -0
- package/dist/lazy-hydration-coordinator.js +380 -0
- package/dist/lazy-hydration-entry.d.ts +1 -0
- package/dist/lazy-hydration-entry.js +2 -0
- package/dist/lifecycle.d.ts +1 -0
- package/dist/lifecycle.js +29 -1
- package/dist/template-element.d.ts +37 -7
- package/dist/template-element.js +444 -132
- package/dist/template-types.d.ts +9 -8
- package/dist/template.d.ts +1 -1
- package/package.json +8 -2
package/dist/template-element.js
CHANGED
|
@@ -2,7 +2,7 @@ import { deferTemplateDefinition, getTemplate } from './template.js';
|
|
|
2
2
|
import { hydrationStart, hydrationEnd } from './lifecycle.js';
|
|
3
3
|
import { isStreamingHydrationMode, PENDING_ROOT_CONNECTED, STREAMED_HOST_ATTR, STREAMING_BOUNDARY_ACTIVATE, } from './streaming-mode.js';
|
|
4
4
|
import { createRepeatKeyState, seedHydratedRepeatKeys, syncRepeat, dotWalk, } from './element/diff.js';
|
|
5
|
-
import { collectItemMarkers, nextElement, findByOrdinal, MARKER_COND_START, MARKER_COND_END,
|
|
5
|
+
import { collectItemMarkers, nextElement, findByOrdinal, buildSSRIndex, collectTemplateElements, MARKER_COND_START, MARKER_COND_END, } from './element/markers.js';
|
|
6
6
|
import { injectModuleStyle, } from './element/styles.js';
|
|
7
7
|
import { ATTR_KIND_BOOLEAN, ATTR_KIND_COMPLEX, ATTR_KIND_TEMPLATE, hasNativeLiveProperty, } from './element/types.js';
|
|
8
8
|
import { templateHasRoot, templateRootForAttribute } from './template-roots.js';
|
|
@@ -11,6 +11,15 @@ const templateCache = new WeakMap();
|
|
|
11
11
|
const templateDOMCache = new WeakMap();
|
|
12
12
|
const rootTagCache = new WeakMap();
|
|
13
13
|
const tplOrdinalCache = new WeakMap();
|
|
14
|
+
const tplElementCache = new WeakMap();
|
|
15
|
+
function getTemplateElements(tplRoot) {
|
|
16
|
+
let cached = tplElementCache.get(tplRoot);
|
|
17
|
+
if (!cached) {
|
|
18
|
+
cached = collectTemplateElements(tplRoot);
|
|
19
|
+
tplElementCache.set(tplRoot, cached);
|
|
20
|
+
}
|
|
21
|
+
return cached;
|
|
22
|
+
}
|
|
14
23
|
function getTplOrdinals(tplNode) {
|
|
15
24
|
let map = tplOrdinalCache.get(tplNode);
|
|
16
25
|
if (map)
|
|
@@ -41,6 +50,7 @@ const ACTIVATION_ACTIVATED = 1;
|
|
|
41
50
|
const ACTIVATION_STATIC_HOST_OPT_OUT = 2;
|
|
42
51
|
const ACTIVATION_MISSING_TEMPLATE = 3;
|
|
43
52
|
const templateMetaByCtor = new WeakMap();
|
|
53
|
+
const pendingAncestorDescendants = new WeakMap();
|
|
44
54
|
function childNodesArray(parent) {
|
|
45
55
|
const children = parent.childNodes;
|
|
46
56
|
const len = children.length;
|
|
@@ -115,7 +125,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
115
125
|
this.$root = null;
|
|
116
126
|
this.$ready = false;
|
|
117
127
|
this.$hydrated = false;
|
|
118
|
-
this.$
|
|
128
|
+
this.$hasMounted = false;
|
|
119
129
|
this.$deferredSSR = false;
|
|
120
130
|
this.$activatingDeferredSSR = false;
|
|
121
131
|
this.$hasUnknownScopes = false;
|
|
@@ -125,13 +135,16 @@ export class TemplateElement extends HTMLElement {
|
|
|
125
135
|
this.$preReadyWrites = null;
|
|
126
136
|
this.$resolver = (p, s) => this.$resolveValue(p, s);
|
|
127
137
|
}
|
|
138
|
+
static { this.$ancestorReleaseQueue = []; }
|
|
139
|
+
static { this.$ancestorReleaseIndex = 0; }
|
|
140
|
+
static { this.$ancestorReleaseActive = false; }
|
|
128
141
|
[WEBUI_SET_STATE_KEY](key, value) {
|
|
129
142
|
const wasDeferred = this.$deferredSSR;
|
|
130
143
|
this.$beforeExternalStateWrite();
|
|
131
144
|
const owned = this.$setStateKey(key, value);
|
|
145
|
+
if (owned && wasDeferred)
|
|
146
|
+
this.$recordDeferredWrite(key);
|
|
132
147
|
this.$afterExternalStateWrite(owned);
|
|
133
|
-
if (owned && wasDeferred && !this.$deferredSSR)
|
|
134
|
-
this.$update(key);
|
|
135
148
|
return owned;
|
|
136
149
|
}
|
|
137
150
|
[STREAMING_BOUNDARY_ACTIVATE](state) {
|
|
@@ -148,14 +161,35 @@ export class TemplateElement extends HTMLElement {
|
|
|
148
161
|
this.$meta = meta;
|
|
149
162
|
if (!this.$shouldActivateOnBoundaryCommit())
|
|
150
163
|
return ACTIVATION_STATIC_HOST_OPT_OUT;
|
|
151
|
-
this.$
|
|
164
|
+
const ancestor = this.$nearestHydrationBarrier();
|
|
165
|
+
if (ancestor) {
|
|
166
|
+
this.$deferredByAncestor = true;
|
|
167
|
+
this.$ancestorBoundaryState = state;
|
|
168
|
+
this.$hasAncestorBoundaryState = true;
|
|
169
|
+
this.$registerWithHydrationBarrier(ancestor);
|
|
170
|
+
return ACTIVATION_ACTIVATED;
|
|
171
|
+
}
|
|
172
|
+
this.$activatingDeferredSSR = true;
|
|
173
|
+
try {
|
|
174
|
+
this.$activateDeferredSSR(state);
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
this.$activatingDeferredSSR = false;
|
|
178
|
+
}
|
|
152
179
|
return ACTIVATION_ACTIVATED;
|
|
153
180
|
}
|
|
154
181
|
[STREAMING_BOUNDARY_ABANDON]() {
|
|
182
|
+
this.$detachDeferredAncestor();
|
|
183
|
+
this.$abandonDeferredDescendants();
|
|
155
184
|
this.$deferredSSR = false;
|
|
185
|
+
this.$deferredByAncestor = undefined;
|
|
186
|
+
this.$ancestorBoundaryState = undefined;
|
|
187
|
+
this.$hasAncestorBoundaryState = undefined;
|
|
156
188
|
this.$activatingDeferredSSR = false;
|
|
157
189
|
this.$ready = false;
|
|
158
190
|
this.$preReadyWrites = null;
|
|
191
|
+
if (this.$deferredWrites)
|
|
192
|
+
this.$deferredWrites = undefined;
|
|
159
193
|
}
|
|
160
194
|
static define(tagName) {
|
|
161
195
|
const ctor = this;
|
|
@@ -170,8 +204,20 @@ export class TemplateElement extends HTMLElement {
|
|
|
170
204
|
}
|
|
171
205
|
connectedCallback() {
|
|
172
206
|
const tag = this.tagName.toLowerCase();
|
|
207
|
+
this.$adoptPendingDescendants();
|
|
173
208
|
if (this.$deferredSSR) {
|
|
174
209
|
this.$ready = true;
|
|
210
|
+
if (this.$deferredByAncestor) {
|
|
211
|
+
const ancestor = this.$nearestHydrationBarrier();
|
|
212
|
+
if (ancestor) {
|
|
213
|
+
this.$registerWithHydrationBarrier(ancestor);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this.$detachDeferredAncestor();
|
|
217
|
+
this.$releaseAncestorBarrier();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
this.$didDeferSSRHydration();
|
|
175
221
|
return;
|
|
176
222
|
}
|
|
177
223
|
if (this.$hydrated && this.$root) {
|
|
@@ -185,12 +231,15 @@ export class TemplateElement extends HTMLElement {
|
|
|
185
231
|
}
|
|
186
232
|
return;
|
|
187
233
|
}
|
|
188
|
-
if (
|
|
234
|
+
if (!this.$hasMounted &&
|
|
235
|
+
isStreamingHydrationMode() &&
|
|
236
|
+
this.hasAttribute(STREAMED_HOST_ATTR)) {
|
|
189
237
|
this.$deferredSSR = true;
|
|
190
238
|
this.$ready = true;
|
|
191
239
|
const resume = this[PENDING_ROOT_CONNECTED];
|
|
192
240
|
if (typeof resume === 'function')
|
|
193
241
|
resume.call(this);
|
|
242
|
+
this.$didDeferSSRHydration();
|
|
194
243
|
return;
|
|
195
244
|
}
|
|
196
245
|
const meta = this.$templateMeta();
|
|
@@ -200,17 +249,35 @@ export class TemplateElement extends HTMLElement {
|
|
|
200
249
|
return;
|
|
201
250
|
}
|
|
202
251
|
this.$meta = meta;
|
|
203
|
-
this.$
|
|
252
|
+
if (this.$hasMounted) {
|
|
253
|
+
this.$remount(meta);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
this.$mount(meta, false);
|
|
257
|
+
}
|
|
204
258
|
}
|
|
205
|
-
$
|
|
259
|
+
$remount(meta) {
|
|
260
|
+
this.$mount(meta, false, undefined, false, true);
|
|
261
|
+
}
|
|
262
|
+
$mount(meta, forceSSR, ssrState, hasBoundaryState = false, reconnecting = false) {
|
|
206
263
|
if (this.$hydrated)
|
|
207
264
|
return;
|
|
208
265
|
const hasShadow = !!this.shadowRoot;
|
|
209
266
|
const wantShadow = hasShadow || !!meta.sd;
|
|
267
|
+
const remountStructuralTemplate = reconnecting &&
|
|
268
|
+
((meta.c?.length ?? 0) !== 0 || (meta.r?.length ?? 0) !== 0);
|
|
210
269
|
let root;
|
|
211
270
|
let isSSR;
|
|
212
271
|
let clientRoot = null;
|
|
213
|
-
if (
|
|
272
|
+
if (remountStructuralTemplate) {
|
|
273
|
+
const renderRoot = wantShadow
|
|
274
|
+
? this.shadowRoot ?? this.attachShadow({ mode: 'open' })
|
|
275
|
+
: this;
|
|
276
|
+
renderRoot.replaceChildren();
|
|
277
|
+
root = renderRoot;
|
|
278
|
+
isSSR = false;
|
|
279
|
+
}
|
|
280
|
+
else if (hasShadow) {
|
|
214
281
|
root = this.shadowRoot;
|
|
215
282
|
isSSR = true;
|
|
216
283
|
}
|
|
@@ -226,19 +293,36 @@ export class TemplateElement extends HTMLElement {
|
|
|
226
293
|
root = this;
|
|
227
294
|
isSSR = false;
|
|
228
295
|
}
|
|
229
|
-
if (isSSR &&
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
296
|
+
if (isSSR &&
|
|
297
|
+
!forceSSR &&
|
|
298
|
+
!reconnecting) {
|
|
299
|
+
const ancestor = this.$nearestHydrationBarrier();
|
|
300
|
+
if (ancestor) {
|
|
301
|
+
this.$meta = meta;
|
|
302
|
+
this.$deferredSSR = true;
|
|
303
|
+
this.$deferredByAncestor = true;
|
|
304
|
+
this.$ready = true;
|
|
305
|
+
this.$primeSSRStateForDeferral();
|
|
306
|
+
this.$registerWithHydrationBarrier(ancestor);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (!this.$shouldDeferSSRHydration(meta)) {
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
this.$meta = meta;
|
|
313
|
+
this.$deferredSSR = true;
|
|
314
|
+
this.$ready = true;
|
|
315
|
+
this.$didDeferSSRHydration();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
234
318
|
}
|
|
235
319
|
hydrationStart();
|
|
236
320
|
try {
|
|
237
321
|
if (meta.sa)
|
|
238
322
|
injectModuleStyle(meta.sa, this.shadowRoot);
|
|
239
323
|
if (isSSR) {
|
|
240
|
-
if (this.$shouldApplySSRBootstrapState()) {
|
|
241
|
-
this.$applySSRState(
|
|
324
|
+
if (!reconnecting && this.$shouldApplySSRBootstrapState()) {
|
|
325
|
+
this.$applySSRState(hasBoundaryState ? ssrState : window.__webui?.state);
|
|
242
326
|
}
|
|
243
327
|
this.$root = this.$hydrate(root, meta, getTemplateDom(meta));
|
|
244
328
|
}
|
|
@@ -250,6 +334,11 @@ export class TemplateElement extends HTMLElement {
|
|
|
250
334
|
this.$hydrated = true;
|
|
251
335
|
this.$ready = true;
|
|
252
336
|
this.$syncAuthoredAttributes();
|
|
337
|
+
if (isSSR && this.$deferredWrites)
|
|
338
|
+
this.$replayDeferredWrites();
|
|
339
|
+
if (isSSR && reconnecting) {
|
|
340
|
+
this.$updateBindings(this.$root.texts, this.$root.attrs, this.$root.conds, this.$root.repeats, true);
|
|
341
|
+
}
|
|
253
342
|
if (isSSR && DEV)
|
|
254
343
|
this.$checkHydrationMismatch();
|
|
255
344
|
else
|
|
@@ -263,13 +352,14 @@ export class TemplateElement extends HTMLElement {
|
|
|
263
352
|
this.$appendStagedChildren(root, clientRoot);
|
|
264
353
|
this.$root.container = root;
|
|
265
354
|
}
|
|
266
|
-
this.$
|
|
355
|
+
this.$finishHydration();
|
|
267
356
|
}
|
|
268
357
|
finally {
|
|
269
358
|
hydrationEnd();
|
|
270
359
|
}
|
|
271
360
|
}
|
|
272
361
|
disconnectedCallback() {
|
|
362
|
+
this.$detachDeferredAncestor();
|
|
273
363
|
if (this.$root) {
|
|
274
364
|
queueMicrotask(() => {
|
|
275
365
|
if (!this.isConnected)
|
|
@@ -279,9 +369,16 @@ export class TemplateElement extends HTMLElement {
|
|
|
279
369
|
}
|
|
280
370
|
$destroy() {
|
|
281
371
|
if (!this.$root) {
|
|
372
|
+
this.$detachDeferredAncestor();
|
|
373
|
+
this.$abandonDeferredDescendants();
|
|
282
374
|
this.$deferredSSR = false;
|
|
375
|
+
this.$deferredByAncestor = undefined;
|
|
376
|
+
this.$ancestorBoundaryState = undefined;
|
|
377
|
+
this.$hasAncestorBoundaryState = undefined;
|
|
283
378
|
this.$ready = false;
|
|
284
379
|
this.$hasUnknownScopes = false;
|
|
380
|
+
if (this.$deferredWrites)
|
|
381
|
+
this.$deferredWrites = undefined;
|
|
285
382
|
return;
|
|
286
383
|
}
|
|
287
384
|
this.$disposeInstance(this.$root, false);
|
|
@@ -291,6 +388,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
291
388
|
this.$dirtyPaths = null;
|
|
292
389
|
this.$pendingFlush = false;
|
|
293
390
|
this.$preReadyWrites = null;
|
|
391
|
+
this.$hydrated = false;
|
|
294
392
|
this.$ready = false;
|
|
295
393
|
this.$hasUnknownScopes = false;
|
|
296
394
|
}
|
|
@@ -324,11 +422,11 @@ export class TemplateElement extends HTMLElement {
|
|
|
324
422
|
const property = this.$templateRootForAttribute(name);
|
|
325
423
|
let changed = false;
|
|
326
424
|
if (property && this.$usesTemplateState(property)) {
|
|
425
|
+
if (wasDeferred)
|
|
426
|
+
this.$recordDeferredWrite(property);
|
|
327
427
|
changed = this.$setTemplateState(property, newValue);
|
|
328
428
|
}
|
|
329
429
|
this.$afterExternalStateWrite(changed);
|
|
330
|
-
if (changed && property && wasDeferred && !this.$deferredSSR)
|
|
331
|
-
this.$update(property);
|
|
332
430
|
}
|
|
333
431
|
setState(state) {
|
|
334
432
|
const wasDeferred = this.$deferredSSR;
|
|
@@ -337,13 +435,12 @@ export class TemplateElement extends HTMLElement {
|
|
|
337
435
|
let owned = false;
|
|
338
436
|
for (let i = 0; i < keys.length; i++) {
|
|
339
437
|
const key = keys[i];
|
|
340
|
-
|
|
438
|
+
const keyOwned = this.$setStateKey(key, state[key]);
|
|
439
|
+
if (keyOwned && wasDeferred)
|
|
440
|
+
this.$recordDeferredWrite(key);
|
|
441
|
+
owned = keyOwned || owned;
|
|
341
442
|
}
|
|
342
443
|
this.$afterExternalStateWrite(owned);
|
|
343
|
-
if (owned && wasDeferred && !this.$deferredSSR) {
|
|
344
|
-
for (let i = 0; i < keys.length; i++)
|
|
345
|
-
this.$update(keys[i]);
|
|
346
|
-
}
|
|
347
444
|
this.$flushUpdates();
|
|
348
445
|
}
|
|
349
446
|
$observableNames() {
|
|
@@ -353,27 +450,220 @@ export class TemplateElement extends HTMLElement {
|
|
|
353
450
|
}
|
|
354
451
|
$afterExternalStateWrite(_applied) {
|
|
355
452
|
}
|
|
356
|
-
$shouldDeferSSRHydration() {
|
|
453
|
+
$shouldDeferSSRHydration(_meta) {
|
|
357
454
|
return false;
|
|
358
455
|
}
|
|
456
|
+
$didDeferSSRHydration() {
|
|
457
|
+
}
|
|
458
|
+
$didDeferStreamedSSRHydration(_state) {
|
|
459
|
+
this.$didDeferSSRHydration();
|
|
460
|
+
}
|
|
461
|
+
$currentTemplateMetadata() {
|
|
462
|
+
return this.$meta ?? this.$templateMeta();
|
|
463
|
+
}
|
|
464
|
+
$nearestHydrationBarrier() {
|
|
465
|
+
let current = this;
|
|
466
|
+
while (true) {
|
|
467
|
+
let parent = current.assignedSlot ?? current.parentElement;
|
|
468
|
+
if (!parent) {
|
|
469
|
+
const getRootNode = current.getRootNode;
|
|
470
|
+
const root = typeof getRootNode === 'function'
|
|
471
|
+
? getRootNode.call(current)
|
|
472
|
+
: null;
|
|
473
|
+
parent = typeof ShadowRoot !== 'undefined' &&
|
|
474
|
+
root instanceof ShadowRoot
|
|
475
|
+
? root.host
|
|
476
|
+
: null;
|
|
477
|
+
}
|
|
478
|
+
if (!parent)
|
|
479
|
+
return undefined;
|
|
480
|
+
if (parent instanceof TemplateElement) {
|
|
481
|
+
const parentMeta = parent.$meta ?? parent.$templateMeta();
|
|
482
|
+
if (parentMeta?.th) {
|
|
483
|
+
current = parent;
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (parent.$deferredSSR || !parent.$hydrated)
|
|
487
|
+
return parent;
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
const parentMeta = getTemplate(parent.tagName.toLowerCase());
|
|
491
|
+
if (parentMeta && !parentMeta.th)
|
|
492
|
+
return parent;
|
|
493
|
+
}
|
|
494
|
+
current = parent;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
$registerWithHydrationBarrier(ancestor) {
|
|
498
|
+
if (ancestor instanceof TemplateElement) {
|
|
499
|
+
ancestor.$registerDeferredDescendant(this);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
this.$detachDeferredAncestor();
|
|
503
|
+
this.$pendingAncestor = ancestor;
|
|
504
|
+
const descendants = pendingAncestorDescendants.get(ancestor);
|
|
505
|
+
if (descendants) {
|
|
506
|
+
descendants.push(this);
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
pendingAncestorDescendants.set(ancestor, [this]);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
$adoptPendingDescendants() {
|
|
513
|
+
const descendants = pendingAncestorDescendants.get(this);
|
|
514
|
+
if (!descendants)
|
|
515
|
+
return;
|
|
516
|
+
pendingAncestorDescendants.delete(this);
|
|
517
|
+
for (let i = 0; i < descendants.length; i++) {
|
|
518
|
+
const descendant = descendants[i];
|
|
519
|
+
if (descendant.$pendingAncestor !== this)
|
|
520
|
+
continue;
|
|
521
|
+
descendant.$pendingAncestor = undefined;
|
|
522
|
+
if (descendant.isConnected)
|
|
523
|
+
this.$registerDeferredDescendant(descendant);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
$registerDeferredDescendant(descendant) {
|
|
527
|
+
if (descendant.$deferredAncestor === this)
|
|
528
|
+
return;
|
|
529
|
+
descendant.$detachDeferredAncestor();
|
|
530
|
+
descendant.$deferredAncestor = this;
|
|
531
|
+
(this.$deferredDescendants ??= []).push(descendant);
|
|
532
|
+
}
|
|
533
|
+
$detachDeferredAncestor() {
|
|
534
|
+
const pendingAncestor = this.$pendingAncestor;
|
|
535
|
+
if (pendingAncestor) {
|
|
536
|
+
this.$pendingAncestor = undefined;
|
|
537
|
+
const pending = pendingAncestorDescendants.get(pendingAncestor);
|
|
538
|
+
if (pending) {
|
|
539
|
+
const pendingIndex = pending.indexOf(this);
|
|
540
|
+
if (pendingIndex >= 0)
|
|
541
|
+
pending.splice(pendingIndex, 1);
|
|
542
|
+
if (pending.length === 0) {
|
|
543
|
+
pendingAncestorDescendants.delete(pendingAncestor);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
const ancestor = this.$deferredAncestor;
|
|
548
|
+
if (!ancestor)
|
|
549
|
+
return;
|
|
550
|
+
this.$deferredAncestor = undefined;
|
|
551
|
+
const descendants = ancestor.$deferredDescendants;
|
|
552
|
+
if (!descendants)
|
|
553
|
+
return;
|
|
554
|
+
const index = descendants.indexOf(this);
|
|
555
|
+
if (index >= 0)
|
|
556
|
+
descendants.splice(index, 1);
|
|
557
|
+
if (descendants.length === 0)
|
|
558
|
+
ancestor.$deferredDescendants = undefined;
|
|
559
|
+
}
|
|
560
|
+
$releaseDeferredDescendants() {
|
|
561
|
+
const descendants = this.$deferredDescendants;
|
|
562
|
+
if (!descendants)
|
|
563
|
+
return;
|
|
564
|
+
this.$deferredDescendants = undefined;
|
|
565
|
+
const queue = TemplateElement.$ancestorReleaseQueue;
|
|
566
|
+
for (let i = 0; i < descendants.length; i++) {
|
|
567
|
+
const descendant = descendants[i];
|
|
568
|
+
if (descendant.$deferredAncestor !== this)
|
|
569
|
+
continue;
|
|
570
|
+
descendant.$deferredAncestor = undefined;
|
|
571
|
+
queue.push(descendant);
|
|
572
|
+
}
|
|
573
|
+
if (TemplateElement.$ancestorReleaseActive)
|
|
574
|
+
return;
|
|
575
|
+
TemplateElement.$ancestorReleaseActive = true;
|
|
576
|
+
let errors;
|
|
577
|
+
try {
|
|
578
|
+
while (TemplateElement.$ancestorReleaseIndex < queue.length) {
|
|
579
|
+
const descendant = queue[TemplateElement.$ancestorReleaseIndex];
|
|
580
|
+
TemplateElement.$ancestorReleaseIndex++;
|
|
581
|
+
try {
|
|
582
|
+
descendant.$releaseAncestorBarrier();
|
|
583
|
+
}
|
|
584
|
+
catch (error) {
|
|
585
|
+
(errors ??= []).push(error);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
finally {
|
|
590
|
+
queue.length = 0;
|
|
591
|
+
TemplateElement.$ancestorReleaseIndex = 0;
|
|
592
|
+
TemplateElement.$ancestorReleaseActive = false;
|
|
593
|
+
}
|
|
594
|
+
if (errors) {
|
|
595
|
+
if (errors.length === 1)
|
|
596
|
+
throw errors[0];
|
|
597
|
+
throw new AggregateError(errors, 'multiple deferred descendants failed to hydrate');
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
$releaseAncestorBarrier() {
|
|
601
|
+
if (!this.$deferredByAncestor || !this.isConnected)
|
|
602
|
+
return;
|
|
603
|
+
this.$deferredByAncestor = undefined;
|
|
604
|
+
const hasBoundaryState = this.$hasAncestorBoundaryState === true;
|
|
605
|
+
const boundaryState = this.$ancestorBoundaryState;
|
|
606
|
+
this.$hasAncestorBoundaryState = undefined;
|
|
607
|
+
this.$ancestorBoundaryState = undefined;
|
|
608
|
+
const meta = this.$meta;
|
|
609
|
+
if (meta && this.$shouldDeferSSRHydration(meta)) {
|
|
610
|
+
if (hasBoundaryState) {
|
|
611
|
+
this.$didDeferStreamedSSRHydration(boundaryState);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
this.$didDeferSSRHydration();
|
|
615
|
+
}
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (hasBoundaryState) {
|
|
619
|
+
this.$activateDeferredSSRFromBoundary(boundaryState);
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
this.$activateDeferredSSR();
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
$abandonDeferredDescendants() {
|
|
626
|
+
const descendants = this.$deferredDescendants;
|
|
627
|
+
if (!descendants)
|
|
628
|
+
return;
|
|
629
|
+
this.$deferredDescendants = undefined;
|
|
630
|
+
for (let i = 0; i < descendants.length; i++) {
|
|
631
|
+
if (descendants[i].$deferredAncestor === this) {
|
|
632
|
+
descendants[i].$deferredAncestor = undefined;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
$primeSSRStateForDeferral() {
|
|
637
|
+
if (this.$shouldApplySSRBootstrapState()) {
|
|
638
|
+
this.$applySSRState(window.__webui?.state);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
359
641
|
$shouldActivateOnBoundaryCommit() {
|
|
360
642
|
return true;
|
|
361
643
|
}
|
|
362
644
|
$activateDeferredSSR(state) {
|
|
645
|
+
this.$activateDeferredSSRWithState(state, this.$activatingDeferredSSR);
|
|
646
|
+
}
|
|
647
|
+
$activateDeferredSSRFromBoundary(state) {
|
|
648
|
+
this.$activateDeferredSSRWithState(state, true);
|
|
649
|
+
}
|
|
650
|
+
$activateDeferredSSRWithState(state, hasBoundaryState) {
|
|
363
651
|
if (!this.$deferredSSR)
|
|
364
652
|
return;
|
|
365
653
|
const meta = this.$meta;
|
|
366
654
|
if (!meta)
|
|
367
655
|
return;
|
|
368
656
|
this.$deferredSSR = false;
|
|
657
|
+
this.$guardUnknownState = true;
|
|
369
658
|
this.$ready = false;
|
|
370
659
|
this.$preReadyWrites = null;
|
|
660
|
+
const wasActivating = this.$activatingDeferredSSR;
|
|
371
661
|
this.$activatingDeferredSSR = true;
|
|
372
662
|
try {
|
|
373
|
-
this.$mount(meta, true, state);
|
|
663
|
+
this.$mount(meta, true, state, hasBoundaryState);
|
|
374
664
|
}
|
|
375
665
|
finally {
|
|
376
|
-
this.$activatingDeferredSSR =
|
|
666
|
+
this.$activatingDeferredSSR = wasActivating;
|
|
377
667
|
}
|
|
378
668
|
}
|
|
379
669
|
$shouldApplySSRBootstrapState() {
|
|
@@ -387,11 +677,33 @@ export class TemplateElement extends HTMLElement {
|
|
|
387
677
|
hydratedCallback() {
|
|
388
678
|
}
|
|
389
679
|
$notifyHydrated() {
|
|
390
|
-
if (this.$
|
|
680
|
+
if (this.$hasMounted)
|
|
391
681
|
return;
|
|
392
|
-
this.$
|
|
682
|
+
this.$hasMounted = true;
|
|
393
683
|
this.hydratedCallback();
|
|
394
684
|
}
|
|
685
|
+
$finishHydration() {
|
|
686
|
+
let callbackFailed = false;
|
|
687
|
+
let callbackError;
|
|
688
|
+
try {
|
|
689
|
+
this.$notifyHydrated();
|
|
690
|
+
}
|
|
691
|
+
catch (error) {
|
|
692
|
+
callbackFailed = true;
|
|
693
|
+
callbackError = error;
|
|
694
|
+
}
|
|
695
|
+
try {
|
|
696
|
+
this.$releaseDeferredDescendants();
|
|
697
|
+
}
|
|
698
|
+
catch (releaseError) {
|
|
699
|
+
if (callbackFailed) {
|
|
700
|
+
throw new AggregateError([callbackError, releaseError], 'component callback and deferred descendant hydration failed');
|
|
701
|
+
}
|
|
702
|
+
throw releaseError;
|
|
703
|
+
}
|
|
704
|
+
if (callbackFailed)
|
|
705
|
+
throw callbackError;
|
|
706
|
+
}
|
|
395
707
|
$shouldApplyTemplateStateFromSSR(_key) {
|
|
396
708
|
return true;
|
|
397
709
|
}
|
|
@@ -406,7 +718,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
406
718
|
if (!this.$templateState) {
|
|
407
719
|
this.$templateState = Object.create(null);
|
|
408
720
|
}
|
|
409
|
-
if (Object.
|
|
721
|
+
if (Object.prototype.hasOwnProperty.call(this.$templateState, key) &&
|
|
722
|
+
Object.is(this.$templateState[key], value))
|
|
410
723
|
return false;
|
|
411
724
|
this.$templateState[key] = value;
|
|
412
725
|
return true;
|
|
@@ -443,9 +756,12 @@ export class TemplateElement extends HTMLElement {
|
|
|
443
756
|
if (!state || typeof state !== 'object')
|
|
444
757
|
return;
|
|
445
758
|
const observableNames = this.$observableNames();
|
|
759
|
+
const deferredWrites = this.$deferredWrites;
|
|
446
760
|
const keys = Object.keys(state);
|
|
447
761
|
for (let i = 0; i < keys.length; i++) {
|
|
448
762
|
const key = keys[i];
|
|
763
|
+
if (deferredWrites?.has(key))
|
|
764
|
+
continue;
|
|
449
765
|
if (observableNames.has(key)) {
|
|
450
766
|
if (!this.$shouldApplySSRState(key))
|
|
451
767
|
continue;
|
|
@@ -458,6 +774,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
458
774
|
}
|
|
459
775
|
$update(path) {
|
|
460
776
|
if (!this.$ready || !this.$root) {
|
|
777
|
+
if (path && this.$deferredSSR)
|
|
778
|
+
this.$recordDeferredWrite(path);
|
|
461
779
|
if (DEV && path && this.isConnected)
|
|
462
780
|
this.$recordPreReadyWrite(path);
|
|
463
781
|
return;
|
|
@@ -480,11 +798,31 @@ export class TemplateElement extends HTMLElement {
|
|
|
480
798
|
this.$dirtyPaths = null;
|
|
481
799
|
this.$updateInstance(this.$root);
|
|
482
800
|
}
|
|
801
|
+
$recordDeferredWrite(path) {
|
|
802
|
+
const dot = path.indexOf('.');
|
|
803
|
+
const root = dot === -1 ? path : path.slice(0, dot);
|
|
804
|
+
(this.$deferredWrites ??= new Set()).add(root);
|
|
805
|
+
}
|
|
806
|
+
$replayDeferredWrites() {
|
|
807
|
+
const writes = this.$deferredWrites;
|
|
808
|
+
if (!writes)
|
|
809
|
+
return;
|
|
810
|
+
this.$deferredWrites = undefined;
|
|
811
|
+
if (this.$dirtyPaths) {
|
|
812
|
+
for (const path of writes)
|
|
813
|
+
this.$dirtyPaths.add(path);
|
|
814
|
+
}
|
|
815
|
+
else {
|
|
816
|
+
this.$dirtyPaths = writes;
|
|
817
|
+
}
|
|
818
|
+
this.$pendingFlush = true;
|
|
819
|
+
this.$flush(true);
|
|
820
|
+
}
|
|
483
821
|
$flushUpdates() {
|
|
484
822
|
if (this.$pendingFlush)
|
|
485
823
|
this.$flush();
|
|
486
824
|
}
|
|
487
|
-
$flush() {
|
|
825
|
+
$flush(requireKnownState = this.$guardUnknownState === true) {
|
|
488
826
|
if (!this.$ready || !this.$root) {
|
|
489
827
|
this.$dirtyPaths = null;
|
|
490
828
|
this.$pendingFlush = false;
|
|
@@ -502,14 +840,14 @@ export class TemplateElement extends HTMLElement {
|
|
|
502
840
|
this.$buildPathIndex();
|
|
503
841
|
const entry = this.$pathIndex?.get(path);
|
|
504
842
|
if (entry) {
|
|
505
|
-
this.$updateBindings(entry.texts, entry.attrs, entry.conds, entry.repeats);
|
|
843
|
+
this.$updateBindings(entry.texts, entry.attrs, entry.conds, entry.repeats, requireKnownState);
|
|
506
844
|
}
|
|
507
845
|
}
|
|
508
846
|
if (!this.$pathIndex)
|
|
509
847
|
this.$buildPathIndex();
|
|
510
848
|
if (this.$wildcardBindings) {
|
|
511
849
|
const wc = this.$wildcardBindings;
|
|
512
|
-
this.$updateBindings(wc.texts, wc.attrs, wc.conds, wc.repeats);
|
|
850
|
+
this.$updateBindings(wc.texts, wc.attrs, wc.conds, wc.repeats, requireKnownState);
|
|
513
851
|
}
|
|
514
852
|
if (!this.$pathIndex)
|
|
515
853
|
this.$buildPathIndex();
|
|
@@ -541,49 +879,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
541
879
|
const tag = this.tagName.toLowerCase();
|
|
542
880
|
void import('./hydration-mismatch.js').then((m) => m.reportHydrationMismatch(tag, writes, index, ctx));
|
|
543
881
|
}
|
|
544
|
-
$resolve(root, path, pathStart = 0) {
|
|
545
|
-
let cur = root;
|
|
546
|
-
for (let i = 0; i < pathStart; i++) {
|
|
547
|
-
const child = cur.childNodes[path[i]];
|
|
548
|
-
if (!child)
|
|
549
|
-
return null;
|
|
550
|
-
cur = child;
|
|
551
|
-
}
|
|
552
|
-
for (let i = pathStart; i < path.length; i++) {
|
|
553
|
-
const child = cur.childNodes[path[i]];
|
|
554
|
-
if (!child)
|
|
555
|
-
return null;
|
|
556
|
-
cur = child;
|
|
557
|
-
}
|
|
558
|
-
return cur;
|
|
559
|
-
}
|
|
560
|
-
$resolveSSR(ssrRoot, tplRoot, path, pathStart = 0) {
|
|
561
|
-
let ssr = ssrRoot;
|
|
562
|
-
let tpl = tplRoot;
|
|
563
|
-
for (let i = 0; i < pathStart; i++) {
|
|
564
|
-
const tplChild = tpl.childNodes[path[i]];
|
|
565
|
-
if (!tplChild)
|
|
566
|
-
return null;
|
|
567
|
-
tpl = tplChild;
|
|
568
|
-
}
|
|
569
|
-
for (let i = pathStart; i < path.length; i++) {
|
|
570
|
-
const idx = path[i];
|
|
571
|
-
const tplChild = tpl.childNodes[idx];
|
|
572
|
-
if (!tplChild)
|
|
573
|
-
return null;
|
|
574
|
-
const ordinals = getTplOrdinals(tpl);
|
|
575
|
-
const entry = ordinals.get(idx);
|
|
576
|
-
if (!entry)
|
|
577
|
-
return null;
|
|
578
|
-
const [nodeType, ordinal] = entry;
|
|
579
|
-
const child = findByOrdinal(ssr, nodeType, ordinal);
|
|
580
|
-
if (!child)
|
|
581
|
-
return null;
|
|
582
|
-
ssr = child;
|
|
583
|
-
tpl = tplChild;
|
|
584
|
-
}
|
|
585
|
-
return ssr;
|
|
586
|
-
}
|
|
587
882
|
$parseTemplate(meta) {
|
|
588
883
|
let cached = templateCache.get(meta);
|
|
589
884
|
if (cached)
|
|
@@ -644,6 +939,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
644
939
|
scope, container: root, nodes: childNodesArray(root),
|
|
645
940
|
texts: [], attrs: [], conds: [], repeats: [],
|
|
646
941
|
};
|
|
942
|
+
const elements = collectTemplateElements(root);
|
|
647
943
|
const textRefs = new Array(meta.tx?.length ?? 0);
|
|
648
944
|
let textRefCount = 0;
|
|
649
945
|
if (meta.tx) {
|
|
@@ -651,8 +947,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
651
947
|
const entry = meta.tx[i];
|
|
652
948
|
const [slot, parts] = entry;
|
|
653
949
|
const raw = entry[2] === 1;
|
|
654
|
-
const [
|
|
655
|
-
const parent =
|
|
950
|
+
const [parentIndex, beforeIndex] = slot;
|
|
951
|
+
const parent = elements[parentIndex];
|
|
656
952
|
if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
|
|
657
953
|
continue;
|
|
658
954
|
textRefs[textRefCount] = { parent, ref: parent.childNodes[beforeIndex] || null, parts, raw };
|
|
@@ -664,8 +960,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
664
960
|
if (meta.c) {
|
|
665
961
|
for (let i = 0; i < meta.c.length; i++) {
|
|
666
962
|
const [condition, blockIndex, slotMeta] = meta.c[i];
|
|
667
|
-
const [
|
|
668
|
-
const parent =
|
|
963
|
+
const [parentIndex, beforeIndex] = slotMeta;
|
|
964
|
+
const parent = elements[parentIndex];
|
|
669
965
|
if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
|
|
670
966
|
continue;
|
|
671
967
|
condRefs[condRefCount] = { parent, ref: parent.childNodes[beforeIndex] || null, condition: condition, blockIndex };
|
|
@@ -677,8 +973,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
677
973
|
if (meta.r) {
|
|
678
974
|
for (let i = 0; i < meta.r.length; i++) {
|
|
679
975
|
const [collection, itemVar, blockIndex, slotMeta, keyPath] = meta.r[i];
|
|
680
|
-
const [
|
|
681
|
-
const parent =
|
|
976
|
+
const [parentIndex, beforeIndex] = slotMeta;
|
|
977
|
+
const parent = elements[parentIndex];
|
|
682
978
|
if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
|
|
683
979
|
continue;
|
|
684
980
|
repRefs[repRefCount] = {
|
|
@@ -692,8 +988,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
692
988
|
repRefCount += 1;
|
|
693
989
|
}
|
|
694
990
|
}
|
|
695
|
-
this.$wireAttrs(instance, meta, scope, (
|
|
696
|
-
this.$finalize(instance, root, meta, (
|
|
991
|
+
this.$wireAttrs(instance, meta, scope, (i) => elements[i] ?? null);
|
|
992
|
+
this.$finalize(instance, root, meta, (_r, i) => elements[i] ?? null, scope);
|
|
697
993
|
for (let i = 0; i < textRefCount; i++) {
|
|
698
994
|
const t = textRefs[i];
|
|
699
995
|
const anchor = document.createComment('');
|
|
@@ -749,16 +1045,19 @@ export class TemplateElement extends HTMLElement {
|
|
|
749
1045
|
texts: [], attrs: [], conds: [], repeats: [],
|
|
750
1046
|
};
|
|
751
1047
|
const staleMarkers = [];
|
|
1048
|
+
const ssrIndex = buildSSRIndex(tplDom, ssrRoot, meta.c !== undefined || meta.r !== undefined, pathStart > 0);
|
|
1049
|
+
const ssrElements = ssrIndex.elements;
|
|
1050
|
+
const tplElements = getTemplateElements(tplDom);
|
|
752
1051
|
if (meta.tx) {
|
|
753
1052
|
for (let i = 0; i < meta.tx.length; i++) {
|
|
754
1053
|
const entry = meta.tx[i];
|
|
755
1054
|
const [slot, parts] = entry;
|
|
756
1055
|
const raw = entry[2] === 1;
|
|
757
|
-
const [
|
|
758
|
-
const ssrParent =
|
|
1056
|
+
const [parentIndex, beforeIndex] = slot;
|
|
1057
|
+
const ssrParent = ssrElements[parentIndex];
|
|
759
1058
|
if (!ssrParent)
|
|
760
1059
|
continue;
|
|
761
|
-
const tplParent =
|
|
1060
|
+
const tplParent = tplElements[parentIndex];
|
|
762
1061
|
if (!tplParent)
|
|
763
1062
|
continue;
|
|
764
1063
|
if (raw) {
|
|
@@ -778,21 +1077,16 @@ export class TemplateElement extends HTMLElement {
|
|
|
778
1077
|
}
|
|
779
1078
|
}
|
|
780
1079
|
}
|
|
781
|
-
this.$wireAttrs(instance, meta, scope, (
|
|
1080
|
+
this.$wireAttrs(instance, meta, scope, (i) => ssrElements[i]);
|
|
782
1081
|
if (meta.c) {
|
|
783
|
-
|
|
784
|
-
let lastCondParent = null;
|
|
1082
|
+
const condMarkers = ssrIndex.conds.length === meta.c.length ? ssrIndex.conds : null;
|
|
785
1083
|
for (let i = 0; i < meta.c.length; i++) {
|
|
786
1084
|
const [condition, blockIndex, slotMeta] = meta.c[i];
|
|
787
|
-
const [
|
|
788
|
-
const ssrParent = this.$resolveSSR(ssrRoot, tplDom, parentPath, pathStart) ?? ssrRoot;
|
|
1085
|
+
const [parentIndex] = slotMeta;
|
|
789
1086
|
const blockMeta = this.$block(blockIndex);
|
|
790
1087
|
let condInstance = null;
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
lastCondParent = ssrParent;
|
|
794
|
-
}
|
|
795
|
-
const marker = this.$findMarker(ssrParent, MARKER_COND_START, lastCondMarker);
|
|
1088
|
+
const marker = condMarkers ? condMarkers[i] : null;
|
|
1089
|
+
const ssrParent = (marker ? marker.parentNode : ssrElements[parentIndex]) ?? ssrRoot;
|
|
796
1090
|
let condAnchor;
|
|
797
1091
|
if (marker) {
|
|
798
1092
|
condAnchor = marker;
|
|
@@ -803,8 +1097,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
803
1097
|
const insertRef = ssrParent.childNodes[beforeIndex ?? ssrParent.childNodes.length] ?? null;
|
|
804
1098
|
ssrParent.insertBefore(condAnchor, insertRef);
|
|
805
1099
|
}
|
|
806
|
-
if (marker)
|
|
807
|
-
lastCondMarker = marker;
|
|
808
1100
|
if (marker && blockMeta) {
|
|
809
1101
|
condInstance = this.$hydrateCondContent(condAnchor, blockMeta, scope);
|
|
810
1102
|
if (condInstance)
|
|
@@ -825,22 +1117,17 @@ export class TemplateElement extends HTMLElement {
|
|
|
825
1117
|
}
|
|
826
1118
|
}
|
|
827
1119
|
if (meta.r) {
|
|
828
|
-
|
|
829
|
-
let lastRepParent = null;
|
|
1120
|
+
const repMarkers = ssrIndex.repeats.length === meta.r.length ? ssrIndex.repeats : null;
|
|
830
1121
|
for (let i = 0; i < meta.r.length; i++) {
|
|
831
1122
|
const [collection, itemVar, blockIndex, slotMeta, keyPath] = meta.r[i];
|
|
832
|
-
const [
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
lastRepMarker = null;
|
|
836
|
-
lastRepParent = ssrParent;
|
|
837
|
-
}
|
|
1123
|
+
const [parentIndex] = slotMeta;
|
|
1124
|
+
const marker = repMarkers ? repMarkers[i] : null;
|
|
1125
|
+
const ssrParent = (marker ? marker.parentNode : ssrElements[parentIndex]) ?? ssrRoot;
|
|
838
1126
|
const blockMeta = this.$block(blockIndex);
|
|
839
1127
|
const blockTplDom = blockMeta ? getTemplateDom(blockMeta) : null;
|
|
840
1128
|
const rootTag = blockMeta && blockTplDom?.childNodes.length === 1 && blockTplDom.children.length === 1
|
|
841
1129
|
? this.$rootTag(blockMeta)
|
|
842
1130
|
: null;
|
|
843
|
-
const marker = this.$findMarker(ssrParent, MARKER_REPEAT_START, lastRepMarker);
|
|
844
1131
|
let anchor;
|
|
845
1132
|
if (marker) {
|
|
846
1133
|
anchor = marker;
|
|
@@ -848,7 +1135,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
848
1135
|
else {
|
|
849
1136
|
anchor = document.createComment('');
|
|
850
1137
|
const [, beforeIndex] = slotMeta;
|
|
851
|
-
const tplParent =
|
|
1138
|
+
const tplParent = tplElements[parentIndex];
|
|
852
1139
|
const staticCount = tplParent ? tplParent.childNodes.length : 0;
|
|
853
1140
|
const insertRef = ssrParent.childNodes[Math.min(beforeIndex ?? staticCount, ssrParent.childNodes.length)] ?? null;
|
|
854
1141
|
ssrParent.insertBefore(anchor, insertRef);
|
|
@@ -860,7 +1147,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
860
1147
|
const { items: itemMarkers, end: endMarker } = marker
|
|
861
1148
|
? collectItemMarkers(anchor)
|
|
862
1149
|
: { items: [], end: null };
|
|
863
|
-
lastRepMarker = endMarker ?? anchor;
|
|
864
1150
|
if (blockMeta && blockTplDom && anchor.parentNode && itemMarkers.length > 0) {
|
|
865
1151
|
if (!this.$activatingDeferredSSR
|
|
866
1152
|
&& hasCollectionState
|
|
@@ -933,7 +1219,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
933
1219
|
instance.repeats.push(binding);
|
|
934
1220
|
}
|
|
935
1221
|
}
|
|
936
|
-
this.$finalize(instance, ssrRoot, meta, (
|
|
1222
|
+
this.$finalize(instance, ssrRoot, meta, (_r, i) => ssrElements[i] ?? null, scope);
|
|
937
1223
|
for (let i = 0; i < staleMarkers.length; i++) {
|
|
938
1224
|
staleMarkers[i].parentNode?.removeChild(staleMarkers[i]);
|
|
939
1225
|
}
|
|
@@ -964,13 +1250,13 @@ export class TemplateElement extends HTMLElement {
|
|
|
964
1250
|
$hasRootStructuralSlot(meta) {
|
|
965
1251
|
if (meta.c) {
|
|
966
1252
|
for (let i = 0; i < meta.c.length; i++) {
|
|
967
|
-
if (meta.c[i][2][0]
|
|
1253
|
+
if (meta.c[i][2][0] === 0)
|
|
968
1254
|
return true;
|
|
969
1255
|
}
|
|
970
1256
|
}
|
|
971
1257
|
if (meta.r) {
|
|
972
1258
|
for (let i = 0; i < meta.r.length; i++) {
|
|
973
|
-
if (meta.r[i][3][0]
|
|
1259
|
+
if (meta.r[i][3][0] === 0)
|
|
974
1260
|
return true;
|
|
975
1261
|
}
|
|
976
1262
|
}
|
|
@@ -1004,16 +1290,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
1004
1290
|
this.$replaceInstanceContainer(inst, wrapper, container);
|
|
1005
1291
|
return inst;
|
|
1006
1292
|
}
|
|
1007
|
-
$findMarker(parent, data, after) {
|
|
1008
|
-
let child = after ? after.nextSibling : parent.firstChild;
|
|
1009
|
-
while (child) {
|
|
1010
|
-
if (child.nodeType === 8 && child.data === data) {
|
|
1011
|
-
return child;
|
|
1012
|
-
}
|
|
1013
|
-
child = child.nextSibling;
|
|
1014
|
-
}
|
|
1015
|
-
return null;
|
|
1016
|
-
}
|
|
1017
1293
|
$findSSRText(ssrParent, tplParent, beforeIndex) {
|
|
1018
1294
|
const ordinals = getTplOrdinals(tplParent);
|
|
1019
1295
|
let textOrd = 0;
|
|
@@ -1069,8 +1345,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
1069
1345
|
if (!meta.a || !meta.ag)
|
|
1070
1346
|
return;
|
|
1071
1347
|
for (let g = 0; g < meta.ag.length; g++) {
|
|
1072
|
-
const [
|
|
1073
|
-
const el = resolve(
|
|
1348
|
+
const [targetIndex, start, count] = meta.ag[g];
|
|
1349
|
+
const el = resolve(targetIndex);
|
|
1074
1350
|
if (!el || el.nodeType !== 1)
|
|
1075
1351
|
continue;
|
|
1076
1352
|
for (let j = 0; j < count; j++) {
|
|
@@ -1178,28 +1454,64 @@ export class TemplateElement extends HTMLElement {
|
|
|
1178
1454
|
}
|
|
1179
1455
|
this.$pathIndex = index;
|
|
1180
1456
|
}
|
|
1181
|
-
$updateBindings(texts, attrs, conds, repeats) {
|
|
1457
|
+
$updateBindings(texts, attrs, conds, repeats, requireKnownState = false) {
|
|
1182
1458
|
const gated = this.$hasUnknownScopes;
|
|
1183
1459
|
for (let i = 0; i < texts.length; i++) {
|
|
1184
1460
|
const binding = texts[i];
|
|
1185
|
-
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1461
|
+
if ((!gated || !binding.scope || this.$scopeIsKnown(binding.scope)) &&
|
|
1462
|
+
(!requireKnownState || this.$textStateIsKnown(binding))) {
|
|
1186
1463
|
this.$patchText(binding);
|
|
1464
|
+
}
|
|
1187
1465
|
}
|
|
1188
1466
|
for (let i = 0; i < attrs.length; i++) {
|
|
1189
1467
|
const binding = attrs[i];
|
|
1190
|
-
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1468
|
+
if ((!gated || !binding.scope || this.$scopeIsKnown(binding.scope)) &&
|
|
1469
|
+
(!requireKnownState || this.$attrStateIsKnown(binding))) {
|
|
1191
1470
|
this.$patchAttr(binding);
|
|
1471
|
+
}
|
|
1192
1472
|
}
|
|
1193
1473
|
for (let i = 0; i < conds.length; i++) {
|
|
1194
1474
|
const binding = conds[i];
|
|
1195
|
-
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1475
|
+
if ((!gated || !binding.scope || this.$scopeIsKnown(binding.scope)) &&
|
|
1476
|
+
(!requireKnownState || this.$pathsAreKnown(binding.condition[1], binding.scope))) {
|
|
1196
1477
|
this.$toggleCond(binding);
|
|
1478
|
+
}
|
|
1197
1479
|
}
|
|
1198
1480
|
for (let i = 0; i < repeats.length; i++) {
|
|
1199
1481
|
const binding = repeats[i];
|
|
1200
|
-
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1482
|
+
if ((!gated || !binding.scope || this.$scopeIsKnown(binding.scope)) &&
|
|
1483
|
+
(!requireKnownState || this.$hasStateRoot(binding.collection, binding.scope))) {
|
|
1201
1484
|
syncRepeat(this, binding);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
$textStateIsKnown(binding) {
|
|
1489
|
+
if (binding.parts)
|
|
1490
|
+
return this.$partsAreKnown(binding.parts, binding.scope);
|
|
1491
|
+
return !binding.path || this.$hasStateRoot(binding.path, binding.scope);
|
|
1492
|
+
}
|
|
1493
|
+
$attrStateIsKnown(binding) {
|
|
1494
|
+
if (binding.path && !this.$hasStateRoot(binding.path, binding.scope))
|
|
1495
|
+
return false;
|
|
1496
|
+
if (binding.parts && !this.$partsAreKnown(binding.parts, binding.scope))
|
|
1497
|
+
return false;
|
|
1498
|
+
return !binding.condition
|
|
1499
|
+
|| this.$pathsAreKnown(binding.condition[1], binding.scope);
|
|
1500
|
+
}
|
|
1501
|
+
$partsAreKnown(parts, scope) {
|
|
1502
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1503
|
+
const part = parts[i];
|
|
1504
|
+
if (typeof part !== 'string' && !this.$hasStateRoot(part[0], scope))
|
|
1505
|
+
return false;
|
|
1202
1506
|
}
|
|
1507
|
+
return true;
|
|
1508
|
+
}
|
|
1509
|
+
$pathsAreKnown(paths, scope) {
|
|
1510
|
+
for (let i = 0; i < paths.length; i++) {
|
|
1511
|
+
if (!this.$hasStateRoot(paths[i], scope))
|
|
1512
|
+
return false;
|
|
1513
|
+
}
|
|
1514
|
+
return true;
|
|
1203
1515
|
}
|
|
1204
1516
|
$scopeIsKnown(scope) {
|
|
1205
1517
|
let frame = scope;
|
|
@@ -1211,7 +1523,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
1211
1523
|
return true;
|
|
1212
1524
|
}
|
|
1213
1525
|
$updateInstance(instance) {
|
|
1214
|
-
this.$updateBindings(instance.texts, instance.attrs, instance.conds, instance.repeats);
|
|
1526
|
+
this.$updateBindings(instance.texts, instance.attrs, instance.conds, instance.repeats, this.$guardUnknownState === true);
|
|
1215
1527
|
}
|
|
1216
1528
|
$patchText(b) {
|
|
1217
1529
|
let val;
|
|
@@ -1336,7 +1648,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
1336
1648
|
|| (path.length > frame.name.length
|
|
1337
1649
|
&& path.charCodeAt(frame.name.length) === 46
|
|
1338
1650
|
&& path.startsWith(frame.name))) {
|
|
1339
|
-
return frame.
|
|
1651
|
+
return frame.known !== false;
|
|
1340
1652
|
}
|
|
1341
1653
|
frame = frame.parent;
|
|
1342
1654
|
}
|