@microsoft/webui-framework 0.0.23 → 0.0.25

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.
@@ -77,6 +77,7 @@ export declare class TemplateElement extends HTMLElement {
77
77
  private $usesTemplateState;
78
78
  private $setStateKey;
79
79
  private $applySSRState;
80
+ private $applyPendingParentState;
80
81
  $update(path?: string): void;
81
82
  private $recordDeferredWrite;
82
83
  private $replayDeferredWrites;
@@ -97,6 +98,8 @@ export declare class TemplateElement extends HTMLElement {
97
98
  private $findSSRSlotRef;
98
99
  private $rootTag;
99
100
  private $wireAttrs;
101
+ private $primeSSRComplexProperty;
102
+ private $writeComplexProperty;
100
103
  protected $finalize(_instance: TemplateInstance, _root: Node, _meta: TemplateBlockMeta, _resolver: (root: Node, index: TemplateNodeIndex) => Node | null, _scope?: ScopeFrame): void;
101
104
  private $makeAttr;
102
105
  private $buildPathIndex;
@@ -51,6 +51,29 @@ const ACTIVATION_STATIC_HOST_OPT_OUT = 2;
51
51
  const ACTIVATION_MISSING_TEMPLATE = 3;
52
52
  const templateMetaByCtor = new WeakMap();
53
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
+ }
54
77
  function childNodesArray(parent) {
55
78
  const children = parent.childNodes;
56
79
  const len = children.length;
@@ -320,10 +343,15 @@ export class TemplateElement extends HTMLElement {
320
343
  try {
321
344
  if (meta.sa)
322
345
  injectModuleStyle(meta.sa, this.shadowRoot);
323
- if (isSSR) {
324
- if (!reconnecting && this.$shouldApplySSRBootstrapState()) {
325
- this.$applySSRState(hasBoundaryState ? ssrState : window.__webui?.state);
346
+ if (!reconnecting) {
347
+ if (isSSR) {
348
+ if (this.$shouldApplySSRBootstrapState()) {
349
+ this.$applySSRState(hasBoundaryState ? ssrState : window.__webui?.state);
350
+ }
326
351
  }
352
+ this.$applyPendingParentState(isSSR);
353
+ }
354
+ if (isSSR) {
327
355
  this.$root = this.$hydrate(root, meta, getTemplateDom(meta));
328
356
  }
329
357
  else {
@@ -637,6 +665,7 @@ export class TemplateElement extends HTMLElement {
637
665
  if (this.$shouldApplySSRBootstrapState()) {
638
666
  this.$applySSRState(window.__webui?.state);
639
667
  }
668
+ this.$applyPendingParentState(true);
640
669
  }
641
670
  $shouldActivateOnBoundaryCommit() {
642
671
  return true;
@@ -772,6 +801,38 @@ export class TemplateElement extends HTMLElement {
772
801
  }
773
802
  }
774
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
+ }
775
836
  $update(path) {
776
837
  if (!this.$ready || !this.$root) {
777
838
  if (path && this.$deferredSSR)
@@ -1077,7 +1138,7 @@ export class TemplateElement extends HTMLElement {
1077
1138
  }
1078
1139
  }
1079
1140
  }
1080
- this.$wireAttrs(instance, meta, scope, (i) => ssrElements[i]);
1141
+ this.$wireAttrs(instance, meta, scope, (i) => ssrElements[i], true);
1081
1142
  if (meta.c) {
1082
1143
  const condMarkers = ssrIndex.conds.length === meta.c.length ? ssrIndex.conds : null;
1083
1144
  for (let i = 0; i < meta.c.length; i++) {
@@ -1341,7 +1402,7 @@ export class TemplateElement extends HTMLElement {
1341
1402
  rootTagCache.set(meta, tag);
1342
1403
  return tag;
1343
1404
  }
1344
- $wireAttrs(instance, meta, scope, resolve) {
1405
+ $wireAttrs(instance, meta, scope, resolve, primeSSRComplexProperties = false) {
1345
1406
  if (!meta.a || !meta.ag)
1346
1407
  return;
1347
1408
  for (let g = 0; g < meta.ag.length; g++) {
@@ -1351,10 +1412,41 @@ export class TemplateElement extends HTMLElement {
1351
1412
  continue;
1352
1413
  for (let j = 0; j < count; j++) {
1353
1414
  const entry = meta.a[start + j];
1354
- if (entry)
1355
- instance.attrs.push(this.$makeAttr(el, entry, scope));
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;
1356
1441
  }
1442
+ target[name] = value;
1443
+ return;
1357
1444
  }
1445
+ if (isUnupgradedWebUITarget(element)) {
1446
+ queuePendingParentState(element, name, value, replayAfterHydration);
1447
+ return;
1448
+ }
1449
+ target[name] = value;
1358
1450
  }
1359
1451
  $finalize(_instance, _root, _meta, _resolver, _scope) { }
1360
1452
  $makeAttr(el, entry, scope) {
@@ -1551,17 +1643,7 @@ export class TemplateElement extends HTMLElement {
1551
1643
  switch (b.kind) {
1552
1644
  case ATTR_KIND_COMPLEX: {
1553
1645
  const v = this.$resolveValue(b.path, b.scope);
1554
- const target = el;
1555
- const setStateKey = target[WEBUI_SET_STATE_KEY];
1556
- if (typeof setStateKey === 'function') {
1557
- if (setStateKey.call(el, b.name, v)) {
1558
- const flush = target['$flushUpdates'];
1559
- if (typeof flush === 'function')
1560
- flush.call(el);
1561
- break;
1562
- }
1563
- }
1564
- target[b.name] = v;
1646
+ this.$writeComplexProperty(el, b.name, v, true);
1565
1647
  break;
1566
1648
  }
1567
1649
  case ATTR_KIND_BOOLEAN: {
@@ -1,14 +1,15 @@
1
1
  export type { CompiledAttrGroupMeta, CompiledAttrMeta, CompiledAttrPart, CompiledCondition, CompiledConditionFn, CompiledConditionalMeta, CompiledEventArg, CompiledEventArgs, CompiledEventBindingMeta, CompiledEventGroupMeta, SerializedCompiledCondition, TemplateCondition, CompiledTextRunMeta, TemplateBlockMeta, TemplateMeta, TemplateNodeIndex, TemplateSlot, } from './template-types.js';
2
2
  import type { CompiledConditionFn, TemplateMeta } from './template-types.js';
3
3
  declare global {
4
+ interface WebUIRuntimeGlobal {
5
+ state?: Record<string, unknown>;
6
+ templates?: Record<string, TemplateMeta>;
7
+ templateFns?: Record<string, CompiledConditionFn[]>;
8
+ templateHostExclusions?: Set<string>;
9
+ [key: string]: unknown;
10
+ }
4
11
  interface Window {
5
- __webui?: {
6
- state?: Record<string, unknown>;
7
- templates?: Record<string, TemplateMeta>;
8
- templateFns?: Record<string, CompiledConditionFn[]>;
9
- templateHostExclusions?: Set<string>;
10
- [key: string]: unknown;
11
- };
12
+ __webui?: WebUIRuntimeGlobal;
12
13
  }
13
14
  }
14
15
  export declare function getTemplate(name: string): TemplateMeta | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microsoft/webui-framework",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "type": "module",
5
5
  "description": "WebUI Framework Next — Preact-inspired lightweight Web Component runtime with SSR hydration and compiled-template path mapping.",
6
6
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "@playwright/test": "^1.61.1",
38
38
  "@types/node": "^26.1.0",
39
39
  "typescript": "^6.0.3",
40
- "@microsoft/webui-test-support": "0.0.23"
40
+ "@microsoft/webui-test-support": "0.0.25"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "tsc",