@microsoft/webui-framework 0.0.22 → 0.0.24
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 +40 -7
- package/dist/template-element.js +541 -147
- 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,30 @@ 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();
|
|
54
|
+
const pendingParentStateByElement = new WeakMap();
|
|
55
|
+
function queuePendingParentState(element, name, value, replayAfterHydration) {
|
|
56
|
+
let pending = pendingParentStateByElement.get(element);
|
|
57
|
+
if (!pending) {
|
|
58
|
+
pending = {
|
|
59
|
+
values: Object.create(null),
|
|
60
|
+
};
|
|
61
|
+
pendingParentStateByElement.set(element, pending);
|
|
62
|
+
}
|
|
63
|
+
pending.values[name] = value;
|
|
64
|
+
if (replayAfterHydration) {
|
|
65
|
+
(pending.replay ??= new Set()).add(name);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function isUnupgradedWebUITarget(element) {
|
|
69
|
+
const tagName = element.localName;
|
|
70
|
+
if (tagName.indexOf('-') === -1)
|
|
71
|
+
return false;
|
|
72
|
+
const ctor = customElements.get(tagName);
|
|
73
|
+
if (ctor)
|
|
74
|
+
return ctor.prototype instanceof TemplateElement;
|
|
75
|
+
return getTemplate(tagName) !== undefined;
|
|
76
|
+
}
|
|
44
77
|
function childNodesArray(parent) {
|
|
45
78
|
const children = parent.childNodes;
|
|
46
79
|
const len = children.length;
|
|
@@ -115,7 +148,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
115
148
|
this.$root = null;
|
|
116
149
|
this.$ready = false;
|
|
117
150
|
this.$hydrated = false;
|
|
118
|
-
this.$
|
|
151
|
+
this.$hasMounted = false;
|
|
119
152
|
this.$deferredSSR = false;
|
|
120
153
|
this.$activatingDeferredSSR = false;
|
|
121
154
|
this.$hasUnknownScopes = false;
|
|
@@ -125,13 +158,16 @@ export class TemplateElement extends HTMLElement {
|
|
|
125
158
|
this.$preReadyWrites = null;
|
|
126
159
|
this.$resolver = (p, s) => this.$resolveValue(p, s);
|
|
127
160
|
}
|
|
161
|
+
static { this.$ancestorReleaseQueue = []; }
|
|
162
|
+
static { this.$ancestorReleaseIndex = 0; }
|
|
163
|
+
static { this.$ancestorReleaseActive = false; }
|
|
128
164
|
[WEBUI_SET_STATE_KEY](key, value) {
|
|
129
165
|
const wasDeferred = this.$deferredSSR;
|
|
130
166
|
this.$beforeExternalStateWrite();
|
|
131
167
|
const owned = this.$setStateKey(key, value);
|
|
168
|
+
if (owned && wasDeferred)
|
|
169
|
+
this.$recordDeferredWrite(key);
|
|
132
170
|
this.$afterExternalStateWrite(owned);
|
|
133
|
-
if (owned && wasDeferred && !this.$deferredSSR)
|
|
134
|
-
this.$update(key);
|
|
135
171
|
return owned;
|
|
136
172
|
}
|
|
137
173
|
[STREAMING_BOUNDARY_ACTIVATE](state) {
|
|
@@ -148,14 +184,35 @@ export class TemplateElement extends HTMLElement {
|
|
|
148
184
|
this.$meta = meta;
|
|
149
185
|
if (!this.$shouldActivateOnBoundaryCommit())
|
|
150
186
|
return ACTIVATION_STATIC_HOST_OPT_OUT;
|
|
151
|
-
this.$
|
|
187
|
+
const ancestor = this.$nearestHydrationBarrier();
|
|
188
|
+
if (ancestor) {
|
|
189
|
+
this.$deferredByAncestor = true;
|
|
190
|
+
this.$ancestorBoundaryState = state;
|
|
191
|
+
this.$hasAncestorBoundaryState = true;
|
|
192
|
+
this.$registerWithHydrationBarrier(ancestor);
|
|
193
|
+
return ACTIVATION_ACTIVATED;
|
|
194
|
+
}
|
|
195
|
+
this.$activatingDeferredSSR = true;
|
|
196
|
+
try {
|
|
197
|
+
this.$activateDeferredSSR(state);
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
this.$activatingDeferredSSR = false;
|
|
201
|
+
}
|
|
152
202
|
return ACTIVATION_ACTIVATED;
|
|
153
203
|
}
|
|
154
204
|
[STREAMING_BOUNDARY_ABANDON]() {
|
|
205
|
+
this.$detachDeferredAncestor();
|
|
206
|
+
this.$abandonDeferredDescendants();
|
|
155
207
|
this.$deferredSSR = false;
|
|
208
|
+
this.$deferredByAncestor = undefined;
|
|
209
|
+
this.$ancestorBoundaryState = undefined;
|
|
210
|
+
this.$hasAncestorBoundaryState = undefined;
|
|
156
211
|
this.$activatingDeferredSSR = false;
|
|
157
212
|
this.$ready = false;
|
|
158
213
|
this.$preReadyWrites = null;
|
|
214
|
+
if (this.$deferredWrites)
|
|
215
|
+
this.$deferredWrites = undefined;
|
|
159
216
|
}
|
|
160
217
|
static define(tagName) {
|
|
161
218
|
const ctor = this;
|
|
@@ -170,8 +227,20 @@ export class TemplateElement extends HTMLElement {
|
|
|
170
227
|
}
|
|
171
228
|
connectedCallback() {
|
|
172
229
|
const tag = this.tagName.toLowerCase();
|
|
230
|
+
this.$adoptPendingDescendants();
|
|
173
231
|
if (this.$deferredSSR) {
|
|
174
232
|
this.$ready = true;
|
|
233
|
+
if (this.$deferredByAncestor) {
|
|
234
|
+
const ancestor = this.$nearestHydrationBarrier();
|
|
235
|
+
if (ancestor) {
|
|
236
|
+
this.$registerWithHydrationBarrier(ancestor);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
this.$detachDeferredAncestor();
|
|
240
|
+
this.$releaseAncestorBarrier();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
this.$didDeferSSRHydration();
|
|
175
244
|
return;
|
|
176
245
|
}
|
|
177
246
|
if (this.$hydrated && this.$root) {
|
|
@@ -185,12 +254,15 @@ export class TemplateElement extends HTMLElement {
|
|
|
185
254
|
}
|
|
186
255
|
return;
|
|
187
256
|
}
|
|
188
|
-
if (
|
|
257
|
+
if (!this.$hasMounted &&
|
|
258
|
+
isStreamingHydrationMode() &&
|
|
259
|
+
this.hasAttribute(STREAMED_HOST_ATTR)) {
|
|
189
260
|
this.$deferredSSR = true;
|
|
190
261
|
this.$ready = true;
|
|
191
262
|
const resume = this[PENDING_ROOT_CONNECTED];
|
|
192
263
|
if (typeof resume === 'function')
|
|
193
264
|
resume.call(this);
|
|
265
|
+
this.$didDeferSSRHydration();
|
|
194
266
|
return;
|
|
195
267
|
}
|
|
196
268
|
const meta = this.$templateMeta();
|
|
@@ -200,17 +272,35 @@ export class TemplateElement extends HTMLElement {
|
|
|
200
272
|
return;
|
|
201
273
|
}
|
|
202
274
|
this.$meta = meta;
|
|
203
|
-
this.$
|
|
275
|
+
if (this.$hasMounted) {
|
|
276
|
+
this.$remount(meta);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
this.$mount(meta, false);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
$remount(meta) {
|
|
283
|
+
this.$mount(meta, false, undefined, false, true);
|
|
204
284
|
}
|
|
205
|
-
$mount(meta, forceSSR, ssrState) {
|
|
285
|
+
$mount(meta, forceSSR, ssrState, hasBoundaryState = false, reconnecting = false) {
|
|
206
286
|
if (this.$hydrated)
|
|
207
287
|
return;
|
|
208
288
|
const hasShadow = !!this.shadowRoot;
|
|
209
289
|
const wantShadow = hasShadow || !!meta.sd;
|
|
290
|
+
const remountStructuralTemplate = reconnecting &&
|
|
291
|
+
((meta.c?.length ?? 0) !== 0 || (meta.r?.length ?? 0) !== 0);
|
|
210
292
|
let root;
|
|
211
293
|
let isSSR;
|
|
212
294
|
let clientRoot = null;
|
|
213
|
-
if (
|
|
295
|
+
if (remountStructuralTemplate) {
|
|
296
|
+
const renderRoot = wantShadow
|
|
297
|
+
? this.shadowRoot ?? this.attachShadow({ mode: 'open' })
|
|
298
|
+
: this;
|
|
299
|
+
renderRoot.replaceChildren();
|
|
300
|
+
root = renderRoot;
|
|
301
|
+
isSSR = false;
|
|
302
|
+
}
|
|
303
|
+
else if (hasShadow) {
|
|
214
304
|
root = this.shadowRoot;
|
|
215
305
|
isSSR = true;
|
|
216
306
|
}
|
|
@@ -226,20 +316,42 @@ export class TemplateElement extends HTMLElement {
|
|
|
226
316
|
root = this;
|
|
227
317
|
isSSR = false;
|
|
228
318
|
}
|
|
229
|
-
if (isSSR &&
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
319
|
+
if (isSSR &&
|
|
320
|
+
!forceSSR &&
|
|
321
|
+
!reconnecting) {
|
|
322
|
+
const ancestor = this.$nearestHydrationBarrier();
|
|
323
|
+
if (ancestor) {
|
|
324
|
+
this.$meta = meta;
|
|
325
|
+
this.$deferredSSR = true;
|
|
326
|
+
this.$deferredByAncestor = true;
|
|
327
|
+
this.$ready = true;
|
|
328
|
+
this.$primeSSRStateForDeferral();
|
|
329
|
+
this.$registerWithHydrationBarrier(ancestor);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (!this.$shouldDeferSSRHydration(meta)) {
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
this.$meta = meta;
|
|
336
|
+
this.$deferredSSR = true;
|
|
337
|
+
this.$ready = true;
|
|
338
|
+
this.$didDeferSSRHydration();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
234
341
|
}
|
|
235
342
|
hydrationStart();
|
|
236
343
|
try {
|
|
237
344
|
if (meta.sa)
|
|
238
345
|
injectModuleStyle(meta.sa, this.shadowRoot);
|
|
239
|
-
if (
|
|
240
|
-
if (
|
|
241
|
-
this.$
|
|
346
|
+
if (!reconnecting) {
|
|
347
|
+
if (isSSR) {
|
|
348
|
+
if (this.$shouldApplySSRBootstrapState()) {
|
|
349
|
+
this.$applySSRState(hasBoundaryState ? ssrState : window.__webui?.state);
|
|
350
|
+
}
|
|
242
351
|
}
|
|
352
|
+
this.$applyPendingParentState(isSSR);
|
|
353
|
+
}
|
|
354
|
+
if (isSSR) {
|
|
243
355
|
this.$root = this.$hydrate(root, meta, getTemplateDom(meta));
|
|
244
356
|
}
|
|
245
357
|
else {
|
|
@@ -250,6 +362,11 @@ export class TemplateElement extends HTMLElement {
|
|
|
250
362
|
this.$hydrated = true;
|
|
251
363
|
this.$ready = true;
|
|
252
364
|
this.$syncAuthoredAttributes();
|
|
365
|
+
if (isSSR && this.$deferredWrites)
|
|
366
|
+
this.$replayDeferredWrites();
|
|
367
|
+
if (isSSR && reconnecting) {
|
|
368
|
+
this.$updateBindings(this.$root.texts, this.$root.attrs, this.$root.conds, this.$root.repeats, true);
|
|
369
|
+
}
|
|
253
370
|
if (isSSR && DEV)
|
|
254
371
|
this.$checkHydrationMismatch();
|
|
255
372
|
else
|
|
@@ -263,13 +380,14 @@ export class TemplateElement extends HTMLElement {
|
|
|
263
380
|
this.$appendStagedChildren(root, clientRoot);
|
|
264
381
|
this.$root.container = root;
|
|
265
382
|
}
|
|
266
|
-
this.$
|
|
383
|
+
this.$finishHydration();
|
|
267
384
|
}
|
|
268
385
|
finally {
|
|
269
386
|
hydrationEnd();
|
|
270
387
|
}
|
|
271
388
|
}
|
|
272
389
|
disconnectedCallback() {
|
|
390
|
+
this.$detachDeferredAncestor();
|
|
273
391
|
if (this.$root) {
|
|
274
392
|
queueMicrotask(() => {
|
|
275
393
|
if (!this.isConnected)
|
|
@@ -279,9 +397,16 @@ export class TemplateElement extends HTMLElement {
|
|
|
279
397
|
}
|
|
280
398
|
$destroy() {
|
|
281
399
|
if (!this.$root) {
|
|
400
|
+
this.$detachDeferredAncestor();
|
|
401
|
+
this.$abandonDeferredDescendants();
|
|
282
402
|
this.$deferredSSR = false;
|
|
403
|
+
this.$deferredByAncestor = undefined;
|
|
404
|
+
this.$ancestorBoundaryState = undefined;
|
|
405
|
+
this.$hasAncestorBoundaryState = undefined;
|
|
283
406
|
this.$ready = false;
|
|
284
407
|
this.$hasUnknownScopes = false;
|
|
408
|
+
if (this.$deferredWrites)
|
|
409
|
+
this.$deferredWrites = undefined;
|
|
285
410
|
return;
|
|
286
411
|
}
|
|
287
412
|
this.$disposeInstance(this.$root, false);
|
|
@@ -291,6 +416,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
291
416
|
this.$dirtyPaths = null;
|
|
292
417
|
this.$pendingFlush = false;
|
|
293
418
|
this.$preReadyWrites = null;
|
|
419
|
+
this.$hydrated = false;
|
|
294
420
|
this.$ready = false;
|
|
295
421
|
this.$hasUnknownScopes = false;
|
|
296
422
|
}
|
|
@@ -324,11 +450,11 @@ export class TemplateElement extends HTMLElement {
|
|
|
324
450
|
const property = this.$templateRootForAttribute(name);
|
|
325
451
|
let changed = false;
|
|
326
452
|
if (property && this.$usesTemplateState(property)) {
|
|
453
|
+
if (wasDeferred)
|
|
454
|
+
this.$recordDeferredWrite(property);
|
|
327
455
|
changed = this.$setTemplateState(property, newValue);
|
|
328
456
|
}
|
|
329
457
|
this.$afterExternalStateWrite(changed);
|
|
330
|
-
if (changed && property && wasDeferred && !this.$deferredSSR)
|
|
331
|
-
this.$update(property);
|
|
332
458
|
}
|
|
333
459
|
setState(state) {
|
|
334
460
|
const wasDeferred = this.$deferredSSR;
|
|
@@ -337,13 +463,12 @@ export class TemplateElement extends HTMLElement {
|
|
|
337
463
|
let owned = false;
|
|
338
464
|
for (let i = 0; i < keys.length; i++) {
|
|
339
465
|
const key = keys[i];
|
|
340
|
-
|
|
466
|
+
const keyOwned = this.$setStateKey(key, state[key]);
|
|
467
|
+
if (keyOwned && wasDeferred)
|
|
468
|
+
this.$recordDeferredWrite(key);
|
|
469
|
+
owned = keyOwned || owned;
|
|
341
470
|
}
|
|
342
471
|
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
472
|
this.$flushUpdates();
|
|
348
473
|
}
|
|
349
474
|
$observableNames() {
|
|
@@ -353,27 +478,221 @@ export class TemplateElement extends HTMLElement {
|
|
|
353
478
|
}
|
|
354
479
|
$afterExternalStateWrite(_applied) {
|
|
355
480
|
}
|
|
356
|
-
$shouldDeferSSRHydration() {
|
|
481
|
+
$shouldDeferSSRHydration(_meta) {
|
|
357
482
|
return false;
|
|
358
483
|
}
|
|
484
|
+
$didDeferSSRHydration() {
|
|
485
|
+
}
|
|
486
|
+
$didDeferStreamedSSRHydration(_state) {
|
|
487
|
+
this.$didDeferSSRHydration();
|
|
488
|
+
}
|
|
489
|
+
$currentTemplateMetadata() {
|
|
490
|
+
return this.$meta ?? this.$templateMeta();
|
|
491
|
+
}
|
|
492
|
+
$nearestHydrationBarrier() {
|
|
493
|
+
let current = this;
|
|
494
|
+
while (true) {
|
|
495
|
+
let parent = current.assignedSlot ?? current.parentElement;
|
|
496
|
+
if (!parent) {
|
|
497
|
+
const getRootNode = current.getRootNode;
|
|
498
|
+
const root = typeof getRootNode === 'function'
|
|
499
|
+
? getRootNode.call(current)
|
|
500
|
+
: null;
|
|
501
|
+
parent = typeof ShadowRoot !== 'undefined' &&
|
|
502
|
+
root instanceof ShadowRoot
|
|
503
|
+
? root.host
|
|
504
|
+
: null;
|
|
505
|
+
}
|
|
506
|
+
if (!parent)
|
|
507
|
+
return undefined;
|
|
508
|
+
if (parent instanceof TemplateElement) {
|
|
509
|
+
const parentMeta = parent.$meta ?? parent.$templateMeta();
|
|
510
|
+
if (parentMeta?.th) {
|
|
511
|
+
current = parent;
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
if (parent.$deferredSSR || !parent.$hydrated)
|
|
515
|
+
return parent;
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
const parentMeta = getTemplate(parent.tagName.toLowerCase());
|
|
519
|
+
if (parentMeta && !parentMeta.th)
|
|
520
|
+
return parent;
|
|
521
|
+
}
|
|
522
|
+
current = parent;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
$registerWithHydrationBarrier(ancestor) {
|
|
526
|
+
if (ancestor instanceof TemplateElement) {
|
|
527
|
+
ancestor.$registerDeferredDescendant(this);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
this.$detachDeferredAncestor();
|
|
531
|
+
this.$pendingAncestor = ancestor;
|
|
532
|
+
const descendants = pendingAncestorDescendants.get(ancestor);
|
|
533
|
+
if (descendants) {
|
|
534
|
+
descendants.push(this);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
pendingAncestorDescendants.set(ancestor, [this]);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
$adoptPendingDescendants() {
|
|
541
|
+
const descendants = pendingAncestorDescendants.get(this);
|
|
542
|
+
if (!descendants)
|
|
543
|
+
return;
|
|
544
|
+
pendingAncestorDescendants.delete(this);
|
|
545
|
+
for (let i = 0; i < descendants.length; i++) {
|
|
546
|
+
const descendant = descendants[i];
|
|
547
|
+
if (descendant.$pendingAncestor !== this)
|
|
548
|
+
continue;
|
|
549
|
+
descendant.$pendingAncestor = undefined;
|
|
550
|
+
if (descendant.isConnected)
|
|
551
|
+
this.$registerDeferredDescendant(descendant);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
$registerDeferredDescendant(descendant) {
|
|
555
|
+
if (descendant.$deferredAncestor === this)
|
|
556
|
+
return;
|
|
557
|
+
descendant.$detachDeferredAncestor();
|
|
558
|
+
descendant.$deferredAncestor = this;
|
|
559
|
+
(this.$deferredDescendants ??= []).push(descendant);
|
|
560
|
+
}
|
|
561
|
+
$detachDeferredAncestor() {
|
|
562
|
+
const pendingAncestor = this.$pendingAncestor;
|
|
563
|
+
if (pendingAncestor) {
|
|
564
|
+
this.$pendingAncestor = undefined;
|
|
565
|
+
const pending = pendingAncestorDescendants.get(pendingAncestor);
|
|
566
|
+
if (pending) {
|
|
567
|
+
const pendingIndex = pending.indexOf(this);
|
|
568
|
+
if (pendingIndex >= 0)
|
|
569
|
+
pending.splice(pendingIndex, 1);
|
|
570
|
+
if (pending.length === 0) {
|
|
571
|
+
pendingAncestorDescendants.delete(pendingAncestor);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
const ancestor = this.$deferredAncestor;
|
|
576
|
+
if (!ancestor)
|
|
577
|
+
return;
|
|
578
|
+
this.$deferredAncestor = undefined;
|
|
579
|
+
const descendants = ancestor.$deferredDescendants;
|
|
580
|
+
if (!descendants)
|
|
581
|
+
return;
|
|
582
|
+
const index = descendants.indexOf(this);
|
|
583
|
+
if (index >= 0)
|
|
584
|
+
descendants.splice(index, 1);
|
|
585
|
+
if (descendants.length === 0)
|
|
586
|
+
ancestor.$deferredDescendants = undefined;
|
|
587
|
+
}
|
|
588
|
+
$releaseDeferredDescendants() {
|
|
589
|
+
const descendants = this.$deferredDescendants;
|
|
590
|
+
if (!descendants)
|
|
591
|
+
return;
|
|
592
|
+
this.$deferredDescendants = undefined;
|
|
593
|
+
const queue = TemplateElement.$ancestorReleaseQueue;
|
|
594
|
+
for (let i = 0; i < descendants.length; i++) {
|
|
595
|
+
const descendant = descendants[i];
|
|
596
|
+
if (descendant.$deferredAncestor !== this)
|
|
597
|
+
continue;
|
|
598
|
+
descendant.$deferredAncestor = undefined;
|
|
599
|
+
queue.push(descendant);
|
|
600
|
+
}
|
|
601
|
+
if (TemplateElement.$ancestorReleaseActive)
|
|
602
|
+
return;
|
|
603
|
+
TemplateElement.$ancestorReleaseActive = true;
|
|
604
|
+
let errors;
|
|
605
|
+
try {
|
|
606
|
+
while (TemplateElement.$ancestorReleaseIndex < queue.length) {
|
|
607
|
+
const descendant = queue[TemplateElement.$ancestorReleaseIndex];
|
|
608
|
+
TemplateElement.$ancestorReleaseIndex++;
|
|
609
|
+
try {
|
|
610
|
+
descendant.$releaseAncestorBarrier();
|
|
611
|
+
}
|
|
612
|
+
catch (error) {
|
|
613
|
+
(errors ??= []).push(error);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
finally {
|
|
618
|
+
queue.length = 0;
|
|
619
|
+
TemplateElement.$ancestorReleaseIndex = 0;
|
|
620
|
+
TemplateElement.$ancestorReleaseActive = false;
|
|
621
|
+
}
|
|
622
|
+
if (errors) {
|
|
623
|
+
if (errors.length === 1)
|
|
624
|
+
throw errors[0];
|
|
625
|
+
throw new AggregateError(errors, 'multiple deferred descendants failed to hydrate');
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
$releaseAncestorBarrier() {
|
|
629
|
+
if (!this.$deferredByAncestor || !this.isConnected)
|
|
630
|
+
return;
|
|
631
|
+
this.$deferredByAncestor = undefined;
|
|
632
|
+
const hasBoundaryState = this.$hasAncestorBoundaryState === true;
|
|
633
|
+
const boundaryState = this.$ancestorBoundaryState;
|
|
634
|
+
this.$hasAncestorBoundaryState = undefined;
|
|
635
|
+
this.$ancestorBoundaryState = undefined;
|
|
636
|
+
const meta = this.$meta;
|
|
637
|
+
if (meta && this.$shouldDeferSSRHydration(meta)) {
|
|
638
|
+
if (hasBoundaryState) {
|
|
639
|
+
this.$didDeferStreamedSSRHydration(boundaryState);
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
this.$didDeferSSRHydration();
|
|
643
|
+
}
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (hasBoundaryState) {
|
|
647
|
+
this.$activateDeferredSSRFromBoundary(boundaryState);
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
this.$activateDeferredSSR();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
$abandonDeferredDescendants() {
|
|
654
|
+
const descendants = this.$deferredDescendants;
|
|
655
|
+
if (!descendants)
|
|
656
|
+
return;
|
|
657
|
+
this.$deferredDescendants = undefined;
|
|
658
|
+
for (let i = 0; i < descendants.length; i++) {
|
|
659
|
+
if (descendants[i].$deferredAncestor === this) {
|
|
660
|
+
descendants[i].$deferredAncestor = undefined;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
$primeSSRStateForDeferral() {
|
|
665
|
+
if (this.$shouldApplySSRBootstrapState()) {
|
|
666
|
+
this.$applySSRState(window.__webui?.state);
|
|
667
|
+
}
|
|
668
|
+
this.$applyPendingParentState(true);
|
|
669
|
+
}
|
|
359
670
|
$shouldActivateOnBoundaryCommit() {
|
|
360
671
|
return true;
|
|
361
672
|
}
|
|
362
673
|
$activateDeferredSSR(state) {
|
|
674
|
+
this.$activateDeferredSSRWithState(state, this.$activatingDeferredSSR);
|
|
675
|
+
}
|
|
676
|
+
$activateDeferredSSRFromBoundary(state) {
|
|
677
|
+
this.$activateDeferredSSRWithState(state, true);
|
|
678
|
+
}
|
|
679
|
+
$activateDeferredSSRWithState(state, hasBoundaryState) {
|
|
363
680
|
if (!this.$deferredSSR)
|
|
364
681
|
return;
|
|
365
682
|
const meta = this.$meta;
|
|
366
683
|
if (!meta)
|
|
367
684
|
return;
|
|
368
685
|
this.$deferredSSR = false;
|
|
686
|
+
this.$guardUnknownState = true;
|
|
369
687
|
this.$ready = false;
|
|
370
688
|
this.$preReadyWrites = null;
|
|
689
|
+
const wasActivating = this.$activatingDeferredSSR;
|
|
371
690
|
this.$activatingDeferredSSR = true;
|
|
372
691
|
try {
|
|
373
|
-
this.$mount(meta, true, state);
|
|
692
|
+
this.$mount(meta, true, state, hasBoundaryState);
|
|
374
693
|
}
|
|
375
694
|
finally {
|
|
376
|
-
this.$activatingDeferredSSR =
|
|
695
|
+
this.$activatingDeferredSSR = wasActivating;
|
|
377
696
|
}
|
|
378
697
|
}
|
|
379
698
|
$shouldApplySSRBootstrapState() {
|
|
@@ -387,11 +706,33 @@ export class TemplateElement extends HTMLElement {
|
|
|
387
706
|
hydratedCallback() {
|
|
388
707
|
}
|
|
389
708
|
$notifyHydrated() {
|
|
390
|
-
if (this.$
|
|
709
|
+
if (this.$hasMounted)
|
|
391
710
|
return;
|
|
392
|
-
this.$
|
|
711
|
+
this.$hasMounted = true;
|
|
393
712
|
this.hydratedCallback();
|
|
394
713
|
}
|
|
714
|
+
$finishHydration() {
|
|
715
|
+
let callbackFailed = false;
|
|
716
|
+
let callbackError;
|
|
717
|
+
try {
|
|
718
|
+
this.$notifyHydrated();
|
|
719
|
+
}
|
|
720
|
+
catch (error) {
|
|
721
|
+
callbackFailed = true;
|
|
722
|
+
callbackError = error;
|
|
723
|
+
}
|
|
724
|
+
try {
|
|
725
|
+
this.$releaseDeferredDescendants();
|
|
726
|
+
}
|
|
727
|
+
catch (releaseError) {
|
|
728
|
+
if (callbackFailed) {
|
|
729
|
+
throw new AggregateError([callbackError, releaseError], 'component callback and deferred descendant hydration failed');
|
|
730
|
+
}
|
|
731
|
+
throw releaseError;
|
|
732
|
+
}
|
|
733
|
+
if (callbackFailed)
|
|
734
|
+
throw callbackError;
|
|
735
|
+
}
|
|
395
736
|
$shouldApplyTemplateStateFromSSR(_key) {
|
|
396
737
|
return true;
|
|
397
738
|
}
|
|
@@ -406,7 +747,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
406
747
|
if (!this.$templateState) {
|
|
407
748
|
this.$templateState = Object.create(null);
|
|
408
749
|
}
|
|
409
|
-
if (Object.
|
|
750
|
+
if (Object.prototype.hasOwnProperty.call(this.$templateState, key) &&
|
|
751
|
+
Object.is(this.$templateState[key], value))
|
|
410
752
|
return false;
|
|
411
753
|
this.$templateState[key] = value;
|
|
412
754
|
return true;
|
|
@@ -443,9 +785,12 @@ export class TemplateElement extends HTMLElement {
|
|
|
443
785
|
if (!state || typeof state !== 'object')
|
|
444
786
|
return;
|
|
445
787
|
const observableNames = this.$observableNames();
|
|
788
|
+
const deferredWrites = this.$deferredWrites;
|
|
446
789
|
const keys = Object.keys(state);
|
|
447
790
|
for (let i = 0; i < keys.length; i++) {
|
|
448
791
|
const key = keys[i];
|
|
792
|
+
if (deferredWrites?.has(key))
|
|
793
|
+
continue;
|
|
449
794
|
if (observableNames.has(key)) {
|
|
450
795
|
if (!this.$shouldApplySSRState(key))
|
|
451
796
|
continue;
|
|
@@ -456,8 +801,42 @@ export class TemplateElement extends HTMLElement {
|
|
|
456
801
|
}
|
|
457
802
|
}
|
|
458
803
|
}
|
|
804
|
+
$applyPendingParentState(replayAfterHydration) {
|
|
805
|
+
const pending = pendingParentStateByElement.get(this);
|
|
806
|
+
if (!pending)
|
|
807
|
+
return;
|
|
808
|
+
pendingParentStateByElement.delete(this);
|
|
809
|
+
const state = pending.values;
|
|
810
|
+
const observableNames = this.$observableNames();
|
|
811
|
+
const keys = Object.keys(state);
|
|
812
|
+
for (let i = 0; i < keys.length; i++) {
|
|
813
|
+
const key = keys[i];
|
|
814
|
+
if (observableNames.has(key)) {
|
|
815
|
+
this[`_${key}`] = state[key];
|
|
816
|
+
}
|
|
817
|
+
else if (this.$usesTemplateState(key)) {
|
|
818
|
+
this.$writeTemplateState(key, state[key]);
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
this[key] = state[key];
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
const replay = pending.replay;
|
|
825
|
+
if (replayAfterHydration && replay) {
|
|
826
|
+
const deferredWrites = this.$deferredWrites;
|
|
827
|
+
if (deferredWrites) {
|
|
828
|
+
for (const key of replay)
|
|
829
|
+
deferredWrites.add(key);
|
|
830
|
+
}
|
|
831
|
+
else {
|
|
832
|
+
this.$deferredWrites = replay;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
459
836
|
$update(path) {
|
|
460
837
|
if (!this.$ready || !this.$root) {
|
|
838
|
+
if (path && this.$deferredSSR)
|
|
839
|
+
this.$recordDeferredWrite(path);
|
|
461
840
|
if (DEV && path && this.isConnected)
|
|
462
841
|
this.$recordPreReadyWrite(path);
|
|
463
842
|
return;
|
|
@@ -480,11 +859,31 @@ export class TemplateElement extends HTMLElement {
|
|
|
480
859
|
this.$dirtyPaths = null;
|
|
481
860
|
this.$updateInstance(this.$root);
|
|
482
861
|
}
|
|
862
|
+
$recordDeferredWrite(path) {
|
|
863
|
+
const dot = path.indexOf('.');
|
|
864
|
+
const root = dot === -1 ? path : path.slice(0, dot);
|
|
865
|
+
(this.$deferredWrites ??= new Set()).add(root);
|
|
866
|
+
}
|
|
867
|
+
$replayDeferredWrites() {
|
|
868
|
+
const writes = this.$deferredWrites;
|
|
869
|
+
if (!writes)
|
|
870
|
+
return;
|
|
871
|
+
this.$deferredWrites = undefined;
|
|
872
|
+
if (this.$dirtyPaths) {
|
|
873
|
+
for (const path of writes)
|
|
874
|
+
this.$dirtyPaths.add(path);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
this.$dirtyPaths = writes;
|
|
878
|
+
}
|
|
879
|
+
this.$pendingFlush = true;
|
|
880
|
+
this.$flush(true);
|
|
881
|
+
}
|
|
483
882
|
$flushUpdates() {
|
|
484
883
|
if (this.$pendingFlush)
|
|
485
884
|
this.$flush();
|
|
486
885
|
}
|
|
487
|
-
$flush() {
|
|
886
|
+
$flush(requireKnownState = this.$guardUnknownState === true) {
|
|
488
887
|
if (!this.$ready || !this.$root) {
|
|
489
888
|
this.$dirtyPaths = null;
|
|
490
889
|
this.$pendingFlush = false;
|
|
@@ -502,14 +901,14 @@ export class TemplateElement extends HTMLElement {
|
|
|
502
901
|
this.$buildPathIndex();
|
|
503
902
|
const entry = this.$pathIndex?.get(path);
|
|
504
903
|
if (entry) {
|
|
505
|
-
this.$updateBindings(entry.texts, entry.attrs, entry.conds, entry.repeats);
|
|
904
|
+
this.$updateBindings(entry.texts, entry.attrs, entry.conds, entry.repeats, requireKnownState);
|
|
506
905
|
}
|
|
507
906
|
}
|
|
508
907
|
if (!this.$pathIndex)
|
|
509
908
|
this.$buildPathIndex();
|
|
510
909
|
if (this.$wildcardBindings) {
|
|
511
910
|
const wc = this.$wildcardBindings;
|
|
512
|
-
this.$updateBindings(wc.texts, wc.attrs, wc.conds, wc.repeats);
|
|
911
|
+
this.$updateBindings(wc.texts, wc.attrs, wc.conds, wc.repeats, requireKnownState);
|
|
513
912
|
}
|
|
514
913
|
if (!this.$pathIndex)
|
|
515
914
|
this.$buildPathIndex();
|
|
@@ -541,49 +940,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
541
940
|
const tag = this.tagName.toLowerCase();
|
|
542
941
|
void import('./hydration-mismatch.js').then((m) => m.reportHydrationMismatch(tag, writes, index, ctx));
|
|
543
942
|
}
|
|
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
943
|
$parseTemplate(meta) {
|
|
588
944
|
let cached = templateCache.get(meta);
|
|
589
945
|
if (cached)
|
|
@@ -644,6 +1000,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
644
1000
|
scope, container: root, nodes: childNodesArray(root),
|
|
645
1001
|
texts: [], attrs: [], conds: [], repeats: [],
|
|
646
1002
|
};
|
|
1003
|
+
const elements = collectTemplateElements(root);
|
|
647
1004
|
const textRefs = new Array(meta.tx?.length ?? 0);
|
|
648
1005
|
let textRefCount = 0;
|
|
649
1006
|
if (meta.tx) {
|
|
@@ -651,8 +1008,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
651
1008
|
const entry = meta.tx[i];
|
|
652
1009
|
const [slot, parts] = entry;
|
|
653
1010
|
const raw = entry[2] === 1;
|
|
654
|
-
const [
|
|
655
|
-
const parent =
|
|
1011
|
+
const [parentIndex, beforeIndex] = slot;
|
|
1012
|
+
const parent = elements[parentIndex];
|
|
656
1013
|
if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
|
|
657
1014
|
continue;
|
|
658
1015
|
textRefs[textRefCount] = { parent, ref: parent.childNodes[beforeIndex] || null, parts, raw };
|
|
@@ -664,8 +1021,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
664
1021
|
if (meta.c) {
|
|
665
1022
|
for (let i = 0; i < meta.c.length; i++) {
|
|
666
1023
|
const [condition, blockIndex, slotMeta] = meta.c[i];
|
|
667
|
-
const [
|
|
668
|
-
const parent =
|
|
1024
|
+
const [parentIndex, beforeIndex] = slotMeta;
|
|
1025
|
+
const parent = elements[parentIndex];
|
|
669
1026
|
if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
|
|
670
1027
|
continue;
|
|
671
1028
|
condRefs[condRefCount] = { parent, ref: parent.childNodes[beforeIndex] || null, condition: condition, blockIndex };
|
|
@@ -677,8 +1034,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
677
1034
|
if (meta.r) {
|
|
678
1035
|
for (let i = 0; i < meta.r.length; i++) {
|
|
679
1036
|
const [collection, itemVar, blockIndex, slotMeta, keyPath] = meta.r[i];
|
|
680
|
-
const [
|
|
681
|
-
const parent =
|
|
1037
|
+
const [parentIndex, beforeIndex] = slotMeta;
|
|
1038
|
+
const parent = elements[parentIndex];
|
|
682
1039
|
if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
|
|
683
1040
|
continue;
|
|
684
1041
|
repRefs[repRefCount] = {
|
|
@@ -692,8 +1049,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
692
1049
|
repRefCount += 1;
|
|
693
1050
|
}
|
|
694
1051
|
}
|
|
695
|
-
this.$wireAttrs(instance, meta, scope, (
|
|
696
|
-
this.$finalize(instance, root, meta, (
|
|
1052
|
+
this.$wireAttrs(instance, meta, scope, (i) => elements[i] ?? null);
|
|
1053
|
+
this.$finalize(instance, root, meta, (_r, i) => elements[i] ?? null, scope);
|
|
697
1054
|
for (let i = 0; i < textRefCount; i++) {
|
|
698
1055
|
const t = textRefs[i];
|
|
699
1056
|
const anchor = document.createComment('');
|
|
@@ -749,16 +1106,19 @@ export class TemplateElement extends HTMLElement {
|
|
|
749
1106
|
texts: [], attrs: [], conds: [], repeats: [],
|
|
750
1107
|
};
|
|
751
1108
|
const staleMarkers = [];
|
|
1109
|
+
const ssrIndex = buildSSRIndex(tplDom, ssrRoot, meta.c !== undefined || meta.r !== undefined, pathStart > 0);
|
|
1110
|
+
const ssrElements = ssrIndex.elements;
|
|
1111
|
+
const tplElements = getTemplateElements(tplDom);
|
|
752
1112
|
if (meta.tx) {
|
|
753
1113
|
for (let i = 0; i < meta.tx.length; i++) {
|
|
754
1114
|
const entry = meta.tx[i];
|
|
755
1115
|
const [slot, parts] = entry;
|
|
756
1116
|
const raw = entry[2] === 1;
|
|
757
|
-
const [
|
|
758
|
-
const ssrParent =
|
|
1117
|
+
const [parentIndex, beforeIndex] = slot;
|
|
1118
|
+
const ssrParent = ssrElements[parentIndex];
|
|
759
1119
|
if (!ssrParent)
|
|
760
1120
|
continue;
|
|
761
|
-
const tplParent =
|
|
1121
|
+
const tplParent = tplElements[parentIndex];
|
|
762
1122
|
if (!tplParent)
|
|
763
1123
|
continue;
|
|
764
1124
|
if (raw) {
|
|
@@ -778,21 +1138,16 @@ export class TemplateElement extends HTMLElement {
|
|
|
778
1138
|
}
|
|
779
1139
|
}
|
|
780
1140
|
}
|
|
781
|
-
this.$wireAttrs(instance, meta, scope, (
|
|
1141
|
+
this.$wireAttrs(instance, meta, scope, (i) => ssrElements[i], true);
|
|
782
1142
|
if (meta.c) {
|
|
783
|
-
|
|
784
|
-
let lastCondParent = null;
|
|
1143
|
+
const condMarkers = ssrIndex.conds.length === meta.c.length ? ssrIndex.conds : null;
|
|
785
1144
|
for (let i = 0; i < meta.c.length; i++) {
|
|
786
1145
|
const [condition, blockIndex, slotMeta] = meta.c[i];
|
|
787
|
-
const [
|
|
788
|
-
const ssrParent = this.$resolveSSR(ssrRoot, tplDom, parentPath, pathStart) ?? ssrRoot;
|
|
1146
|
+
const [parentIndex] = slotMeta;
|
|
789
1147
|
const blockMeta = this.$block(blockIndex);
|
|
790
1148
|
let condInstance = null;
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
lastCondParent = ssrParent;
|
|
794
|
-
}
|
|
795
|
-
const marker = this.$findMarker(ssrParent, MARKER_COND_START, lastCondMarker);
|
|
1149
|
+
const marker = condMarkers ? condMarkers[i] : null;
|
|
1150
|
+
const ssrParent = (marker ? marker.parentNode : ssrElements[parentIndex]) ?? ssrRoot;
|
|
796
1151
|
let condAnchor;
|
|
797
1152
|
if (marker) {
|
|
798
1153
|
condAnchor = marker;
|
|
@@ -803,8 +1158,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
803
1158
|
const insertRef = ssrParent.childNodes[beforeIndex ?? ssrParent.childNodes.length] ?? null;
|
|
804
1159
|
ssrParent.insertBefore(condAnchor, insertRef);
|
|
805
1160
|
}
|
|
806
|
-
if (marker)
|
|
807
|
-
lastCondMarker = marker;
|
|
808
1161
|
if (marker && blockMeta) {
|
|
809
1162
|
condInstance = this.$hydrateCondContent(condAnchor, blockMeta, scope);
|
|
810
1163
|
if (condInstance)
|
|
@@ -825,22 +1178,17 @@ export class TemplateElement extends HTMLElement {
|
|
|
825
1178
|
}
|
|
826
1179
|
}
|
|
827
1180
|
if (meta.r) {
|
|
828
|
-
|
|
829
|
-
let lastRepParent = null;
|
|
1181
|
+
const repMarkers = ssrIndex.repeats.length === meta.r.length ? ssrIndex.repeats : null;
|
|
830
1182
|
for (let i = 0; i < meta.r.length; i++) {
|
|
831
1183
|
const [collection, itemVar, blockIndex, slotMeta, keyPath] = meta.r[i];
|
|
832
|
-
const [
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
lastRepMarker = null;
|
|
836
|
-
lastRepParent = ssrParent;
|
|
837
|
-
}
|
|
1184
|
+
const [parentIndex] = slotMeta;
|
|
1185
|
+
const marker = repMarkers ? repMarkers[i] : null;
|
|
1186
|
+
const ssrParent = (marker ? marker.parentNode : ssrElements[parentIndex]) ?? ssrRoot;
|
|
838
1187
|
const blockMeta = this.$block(blockIndex);
|
|
839
1188
|
const blockTplDom = blockMeta ? getTemplateDom(blockMeta) : null;
|
|
840
1189
|
const rootTag = blockMeta && blockTplDom?.childNodes.length === 1 && blockTplDom.children.length === 1
|
|
841
1190
|
? this.$rootTag(blockMeta)
|
|
842
1191
|
: null;
|
|
843
|
-
const marker = this.$findMarker(ssrParent, MARKER_REPEAT_START, lastRepMarker);
|
|
844
1192
|
let anchor;
|
|
845
1193
|
if (marker) {
|
|
846
1194
|
anchor = marker;
|
|
@@ -848,7 +1196,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
848
1196
|
else {
|
|
849
1197
|
anchor = document.createComment('');
|
|
850
1198
|
const [, beforeIndex] = slotMeta;
|
|
851
|
-
const tplParent =
|
|
1199
|
+
const tplParent = tplElements[parentIndex];
|
|
852
1200
|
const staticCount = tplParent ? tplParent.childNodes.length : 0;
|
|
853
1201
|
const insertRef = ssrParent.childNodes[Math.min(beforeIndex ?? staticCount, ssrParent.childNodes.length)] ?? null;
|
|
854
1202
|
ssrParent.insertBefore(anchor, insertRef);
|
|
@@ -860,7 +1208,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
860
1208
|
const { items: itemMarkers, end: endMarker } = marker
|
|
861
1209
|
? collectItemMarkers(anchor)
|
|
862
1210
|
: { items: [], end: null };
|
|
863
|
-
lastRepMarker = endMarker ?? anchor;
|
|
864
1211
|
if (blockMeta && blockTplDom && anchor.parentNode && itemMarkers.length > 0) {
|
|
865
1212
|
if (!this.$activatingDeferredSSR
|
|
866
1213
|
&& hasCollectionState
|
|
@@ -933,7 +1280,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
933
1280
|
instance.repeats.push(binding);
|
|
934
1281
|
}
|
|
935
1282
|
}
|
|
936
|
-
this.$finalize(instance, ssrRoot, meta, (
|
|
1283
|
+
this.$finalize(instance, ssrRoot, meta, (_r, i) => ssrElements[i] ?? null, scope);
|
|
937
1284
|
for (let i = 0; i < staleMarkers.length; i++) {
|
|
938
1285
|
staleMarkers[i].parentNode?.removeChild(staleMarkers[i]);
|
|
939
1286
|
}
|
|
@@ -964,13 +1311,13 @@ export class TemplateElement extends HTMLElement {
|
|
|
964
1311
|
$hasRootStructuralSlot(meta) {
|
|
965
1312
|
if (meta.c) {
|
|
966
1313
|
for (let i = 0; i < meta.c.length; i++) {
|
|
967
|
-
if (meta.c[i][2][0]
|
|
1314
|
+
if (meta.c[i][2][0] === 0)
|
|
968
1315
|
return true;
|
|
969
1316
|
}
|
|
970
1317
|
}
|
|
971
1318
|
if (meta.r) {
|
|
972
1319
|
for (let i = 0; i < meta.r.length; i++) {
|
|
973
|
-
if (meta.r[i][3][0]
|
|
1320
|
+
if (meta.r[i][3][0] === 0)
|
|
974
1321
|
return true;
|
|
975
1322
|
}
|
|
976
1323
|
}
|
|
@@ -1004,16 +1351,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
1004
1351
|
this.$replaceInstanceContainer(inst, wrapper, container);
|
|
1005
1352
|
return inst;
|
|
1006
1353
|
}
|
|
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
1354
|
$findSSRText(ssrParent, tplParent, beforeIndex) {
|
|
1018
1355
|
const ordinals = getTplOrdinals(tplParent);
|
|
1019
1356
|
let textOrd = 0;
|
|
@@ -1065,20 +1402,51 @@ export class TemplateElement extends HTMLElement {
|
|
|
1065
1402
|
rootTagCache.set(meta, tag);
|
|
1066
1403
|
return tag;
|
|
1067
1404
|
}
|
|
1068
|
-
$wireAttrs(instance, meta, scope, resolve) {
|
|
1405
|
+
$wireAttrs(instance, meta, scope, resolve, primeSSRComplexProperties = false) {
|
|
1069
1406
|
if (!meta.a || !meta.ag)
|
|
1070
1407
|
return;
|
|
1071
1408
|
for (let g = 0; g < meta.ag.length; g++) {
|
|
1072
|
-
const [
|
|
1073
|
-
const el = resolve(
|
|
1409
|
+
const [targetIndex, start, count] = meta.ag[g];
|
|
1410
|
+
const el = resolve(targetIndex);
|
|
1074
1411
|
if (!el || el.nodeType !== 1)
|
|
1075
1412
|
continue;
|
|
1076
1413
|
for (let j = 0; j < count; j++) {
|
|
1077
1414
|
const entry = meta.a[start + j];
|
|
1078
|
-
if (entry)
|
|
1079
|
-
|
|
1415
|
+
if (!entry)
|
|
1416
|
+
continue;
|
|
1417
|
+
const binding = this.$makeAttr(el, entry, scope);
|
|
1418
|
+
instance.attrs.push(binding);
|
|
1419
|
+
if (primeSSRComplexProperties &&
|
|
1420
|
+
binding.kind === ATTR_KIND_COMPLEX &&
|
|
1421
|
+
this.$attrStateIsKnown(binding)) {
|
|
1422
|
+
this.$primeSSRComplexProperty(binding);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
$primeSSRComplexProperty(binding) {
|
|
1428
|
+
const element = binding.element;
|
|
1429
|
+
const value = this.$resolveValue(binding.path, binding.scope);
|
|
1430
|
+
this.$writeComplexProperty(element, binding.name, value, false);
|
|
1431
|
+
}
|
|
1432
|
+
$writeComplexProperty(element, name, value, replayAfterHydration) {
|
|
1433
|
+
const target = element;
|
|
1434
|
+
const setStateKey = target[WEBUI_SET_STATE_KEY];
|
|
1435
|
+
if (typeof setStateKey === 'function') {
|
|
1436
|
+
if (setStateKey.call(element, name, value)) {
|
|
1437
|
+
const flush = target['$flushUpdates'];
|
|
1438
|
+
if (typeof flush === 'function')
|
|
1439
|
+
flush.call(element);
|
|
1440
|
+
return;
|
|
1080
1441
|
}
|
|
1442
|
+
target[name] = value;
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
if (isUnupgradedWebUITarget(element)) {
|
|
1446
|
+
queuePendingParentState(element, name, value, replayAfterHydration);
|
|
1447
|
+
return;
|
|
1081
1448
|
}
|
|
1449
|
+
target[name] = value;
|
|
1082
1450
|
}
|
|
1083
1451
|
$finalize(_instance, _root, _meta, _resolver, _scope) { }
|
|
1084
1452
|
$makeAttr(el, entry, scope) {
|
|
@@ -1178,29 +1546,65 @@ export class TemplateElement extends HTMLElement {
|
|
|
1178
1546
|
}
|
|
1179
1547
|
this.$pathIndex = index;
|
|
1180
1548
|
}
|
|
1181
|
-
$updateBindings(texts, attrs, conds, repeats) {
|
|
1549
|
+
$updateBindings(texts, attrs, conds, repeats, requireKnownState = false) {
|
|
1182
1550
|
const gated = this.$hasUnknownScopes;
|
|
1183
1551
|
for (let i = 0; i < texts.length; i++) {
|
|
1184
1552
|
const binding = texts[i];
|
|
1185
|
-
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1553
|
+
if ((!gated || !binding.scope || this.$scopeIsKnown(binding.scope)) &&
|
|
1554
|
+
(!requireKnownState || this.$textStateIsKnown(binding))) {
|
|
1186
1555
|
this.$patchText(binding);
|
|
1556
|
+
}
|
|
1187
1557
|
}
|
|
1188
1558
|
for (let i = 0; i < attrs.length; i++) {
|
|
1189
1559
|
const binding = attrs[i];
|
|
1190
|
-
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1560
|
+
if ((!gated || !binding.scope || this.$scopeIsKnown(binding.scope)) &&
|
|
1561
|
+
(!requireKnownState || this.$attrStateIsKnown(binding))) {
|
|
1191
1562
|
this.$patchAttr(binding);
|
|
1563
|
+
}
|
|
1192
1564
|
}
|
|
1193
1565
|
for (let i = 0; i < conds.length; i++) {
|
|
1194
1566
|
const binding = conds[i];
|
|
1195
|
-
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1567
|
+
if ((!gated || !binding.scope || this.$scopeIsKnown(binding.scope)) &&
|
|
1568
|
+
(!requireKnownState || this.$pathsAreKnown(binding.condition[1], binding.scope))) {
|
|
1196
1569
|
this.$toggleCond(binding);
|
|
1570
|
+
}
|
|
1197
1571
|
}
|
|
1198
1572
|
for (let i = 0; i < repeats.length; i++) {
|
|
1199
1573
|
const binding = repeats[i];
|
|
1200
|
-
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1574
|
+
if ((!gated || !binding.scope || this.$scopeIsKnown(binding.scope)) &&
|
|
1575
|
+
(!requireKnownState || this.$hasStateRoot(binding.collection, binding.scope))) {
|
|
1201
1576
|
syncRepeat(this, binding);
|
|
1577
|
+
}
|
|
1202
1578
|
}
|
|
1203
1579
|
}
|
|
1580
|
+
$textStateIsKnown(binding) {
|
|
1581
|
+
if (binding.parts)
|
|
1582
|
+
return this.$partsAreKnown(binding.parts, binding.scope);
|
|
1583
|
+
return !binding.path || this.$hasStateRoot(binding.path, binding.scope);
|
|
1584
|
+
}
|
|
1585
|
+
$attrStateIsKnown(binding) {
|
|
1586
|
+
if (binding.path && !this.$hasStateRoot(binding.path, binding.scope))
|
|
1587
|
+
return false;
|
|
1588
|
+
if (binding.parts && !this.$partsAreKnown(binding.parts, binding.scope))
|
|
1589
|
+
return false;
|
|
1590
|
+
return !binding.condition
|
|
1591
|
+
|| this.$pathsAreKnown(binding.condition[1], binding.scope);
|
|
1592
|
+
}
|
|
1593
|
+
$partsAreKnown(parts, scope) {
|
|
1594
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1595
|
+
const part = parts[i];
|
|
1596
|
+
if (typeof part !== 'string' && !this.$hasStateRoot(part[0], scope))
|
|
1597
|
+
return false;
|
|
1598
|
+
}
|
|
1599
|
+
return true;
|
|
1600
|
+
}
|
|
1601
|
+
$pathsAreKnown(paths, scope) {
|
|
1602
|
+
for (let i = 0; i < paths.length; i++) {
|
|
1603
|
+
if (!this.$hasStateRoot(paths[i], scope))
|
|
1604
|
+
return false;
|
|
1605
|
+
}
|
|
1606
|
+
return true;
|
|
1607
|
+
}
|
|
1204
1608
|
$scopeIsKnown(scope) {
|
|
1205
1609
|
let frame = scope;
|
|
1206
1610
|
while (frame) {
|
|
@@ -1211,7 +1615,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
1211
1615
|
return true;
|
|
1212
1616
|
}
|
|
1213
1617
|
$updateInstance(instance) {
|
|
1214
|
-
this.$updateBindings(instance.texts, instance.attrs, instance.conds, instance.repeats);
|
|
1618
|
+
this.$updateBindings(instance.texts, instance.attrs, instance.conds, instance.repeats, this.$guardUnknownState === true);
|
|
1215
1619
|
}
|
|
1216
1620
|
$patchText(b) {
|
|
1217
1621
|
let val;
|
|
@@ -1239,17 +1643,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
1239
1643
|
switch (b.kind) {
|
|
1240
1644
|
case ATTR_KIND_COMPLEX: {
|
|
1241
1645
|
const v = this.$resolveValue(b.path, b.scope);
|
|
1242
|
-
|
|
1243
|
-
const setStateKey = target[WEBUI_SET_STATE_KEY];
|
|
1244
|
-
if (typeof setStateKey === 'function') {
|
|
1245
|
-
if (setStateKey.call(el, b.name, v)) {
|
|
1246
|
-
const flush = target['$flushUpdates'];
|
|
1247
|
-
if (typeof flush === 'function')
|
|
1248
|
-
flush.call(el);
|
|
1249
|
-
break;
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
target[b.name] = v;
|
|
1646
|
+
this.$writeComplexProperty(el, b.name, v, true);
|
|
1253
1647
|
break;
|
|
1254
1648
|
}
|
|
1255
1649
|
case ATTR_KIND_BOOLEAN: {
|
|
@@ -1336,7 +1730,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
1336
1730
|
|| (path.length > frame.name.length
|
|
1337
1731
|
&& path.charCodeAt(frame.name.length) === 46
|
|
1338
1732
|
&& path.startsWith(frame.name))) {
|
|
1339
|
-
return frame.
|
|
1733
|
+
return frame.known !== false;
|
|
1340
1734
|
}
|
|
1341
1735
|
frame = frame.parent;
|
|
1342
1736
|
}
|