@symbiotejs/symbiote 3.3.5 → 3.3.7
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.3.7
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **SSR hydration: Itemize list duplication.**
|
|
8
|
+
Fixed itemize SSR hydration creating duplicate items. The processor now adopts the existing SSR item tag name and element class, skips the initial subscription fire, and sets `isoMode` on the item class so upgraded elements hydrate their existing content instead of re-rendering.
|
|
9
|
+
|
|
10
|
+
## 3.3.6
|
|
11
|
+
|
|
12
|
+
### Improved
|
|
13
|
+
|
|
14
|
+
- **SSR hydration: generic property preservation.**
|
|
15
|
+
During SSR/ISO hydration, all primitive-valued bindings (`textContent`, `innerHTML`, `style.*`, `value`, etc.) now skip the initial write, preserving server-rendered DOM. Function bindings (event handlers) and non-null object bindings (component state) still fire immediately. Previously only `textContent` and attribute bindings were preserved.
|
|
16
|
+
|
|
17
|
+
- **SSR hydration: Itemize API support.**
|
|
18
|
+
Auto-generated itemize item components now inherit `ssrMode`/`isoMode` from the parent. Server-rendered list items are preserved during hydration instead of being cleared and re-created.
|
|
19
|
+
|
|
3
20
|
## 3.3.5
|
|
4
21
|
|
|
5
22
|
### Fixed
|
package/core/itemizeProcessor.js
CHANGED
|
@@ -9,6 +9,8 @@ import { initPropFallback } from './initPropFallback.js';
|
|
|
9
9
|
* @param {T} fnCtx
|
|
10
10
|
*/
|
|
11
11
|
export function itemizeProcessor(fr, fnCtx) {
|
|
12
|
+
let clientSSR = fnCtx.ssrMode && !globalThis.__SYMBIOTE_SSR;
|
|
13
|
+
|
|
12
14
|
ownElements(fr, `[${DICT.LIST_ATTR}]`).filter((el) => {
|
|
13
15
|
return !el.matches(`[${DICT.LIST_ATTR}] [${DICT.LIST_ATTR}]`);
|
|
14
16
|
}).forEach((el) => {
|
|
@@ -18,19 +20,40 @@ export function itemizeProcessor(fr, fnCtx) {
|
|
|
18
20
|
itemClass = window.customElements.get(itemTag);
|
|
19
21
|
}
|
|
20
22
|
if (!itemClass) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
// During hydration, adopt existing SSR item tag and derive template
|
|
24
|
+
if (clientSSR && el.children.length > 0) {
|
|
25
|
+
let ssrTag = el.children[0].localName;
|
|
26
|
+
itemClass = window.customElements.get(ssrTag);
|
|
27
|
+
if (!itemClass) {
|
|
28
|
+
itemClass = class extends fnCtx.Symbiote {
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
this.isoMode = true;
|
|
32
|
+
if (!itemTag) {
|
|
33
|
+
this.style.display = 'contents';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
itemClass.template = el.children[0].innerHTML;
|
|
38
|
+
itemClass.reg(ssrTag);
|
|
27
39
|
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
} else {
|
|
41
|
+
itemClass = class extends fnCtx.Symbiote {
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
if (!itemTag) {
|
|
45
|
+
this.style.display = 'contents';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
itemClass.template = el.querySelector('template')?.innerHTML || el.innerHTML;
|
|
50
|
+
itemClass.reg(itemTag);
|
|
51
|
+
}
|
|
31
52
|
}
|
|
32
|
-
|
|
33
|
-
el.firstChild
|
|
53
|
+
if (!clientSSR) {
|
|
54
|
+
while (el.firstChild) {
|
|
55
|
+
el.firstChild.remove();
|
|
56
|
+
}
|
|
34
57
|
}
|
|
35
58
|
let repeatDataKey = el.getAttribute(DICT.LIST_ATTR);
|
|
36
59
|
if (!fnCtx.has(repeatDataKey) && fnCtx.allowTemplateInits) {
|
|
@@ -87,7 +110,7 @@ export function itemizeProcessor(fr, fnCtx) {
|
|
|
87
110
|
} else {
|
|
88
111
|
console.warn(`[Symbiote] <${fnCtx.localName}>: itemize data must be Array or Object, got ${typeof data}:`, data);
|
|
89
112
|
}
|
|
90
|
-
});
|
|
113
|
+
}, !clientSSR);
|
|
91
114
|
if (!globalThis.__SYMBIOTE_SSR) {
|
|
92
115
|
el.removeAttribute(DICT.LIST_ATTR);
|
|
93
116
|
el.removeAttribute(DICT.LIST_ITEM_TAG_ATTR);
|
package/core/tpl-processors.js
CHANGED
|
@@ -70,6 +70,9 @@ function domBindProcessor(fr, fnCtx) {
|
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
let initVal = fnCtx.$[valKey];
|
|
74
|
+
let skipInit = fnCtx.ssrMode && !globalThis.__SYMBIOTE_SSR
|
|
75
|
+
&& (isAttr || (typeof initVal !== 'function' && (initVal === null || typeof initVal !== 'object')));
|
|
73
76
|
fnCtx.sub(valKey, (val) => {
|
|
74
77
|
if (castType === 'double') {
|
|
75
78
|
val = !!val;
|
|
@@ -91,7 +94,7 @@ function domBindProcessor(fr, fnCtx) {
|
|
|
91
94
|
el[DICT.SET_LATER_KEY][prop] = val;
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
|
-
}, !
|
|
97
|
+
}, !skipInit);
|
|
95
98
|
}
|
|
96
99
|
});
|
|
97
100
|
if (!globalThis.__SYMBIOTE_SSR) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@symbiotejs/symbiote",
|
|
4
|
-
"version": "3.3.
|
|
4
|
+
"version": "3.3.7",
|
|
5
5
|
"description": "Symbiote.js - zero-dependency close-to-platform frontend library to build super-powered web components",
|
|
6
6
|
"author": "team@rnd-pro.com",
|
|
7
7
|
"license": "MIT",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"itemizeProcessor.d.ts","sourceRoot":"","sources":["../../core/itemizeProcessor.js"],"names":[],"mappings":"AAUA,iCAJgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,
|
|
1
|
+
{"version":3,"file":"itemizeProcessor.d.ts","sourceRoot":"","sources":["../../core/itemizeProcessor.js"],"names":[],"mappings":"AAUA,iCAJgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,QA8GX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tpl-processors.d.ts","sourceRoot":"","sources":["../../core/tpl-processors.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"tpl-processors.d.ts","sourceRoot":"","sources":["../../core/tpl-processors.js"],"names":[],"mappings":";0BA6HgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC;;iCA5HqB,uBAAuB"}
|