@symbiotejs/symbiote 3.3.8 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.4.0
4
+
5
+ ### Added
6
+
7
+ - **DevMode warning for `{{prop}}` in SSR/ISO mode.** Text-node bindings produce no `bind=` attribute in SSR output, so they render correctly on the server but cannot be hydrated on the client. When `devMode = true` and the component has `ssrMode` or `isoMode` enabled, a `console.warn` now suggests using `${{textContent: 'prop'}}` for hydratable text.
8
+
9
+ ## 3.3.9
10
+
11
+ ### Improved
12
+
13
+ - **DRY itemize processors.** Extracted shared setup logic (element discovery, SSR hydration, class creation, template derivation, attribute cleanup) into `itemizeSetup.js`. Both `itemizeProcessor.js` and `itemizeProcessor-keyed.js` now use the same setup, eliminating code duplication.
14
+
15
+ - **Keyed processor SSR support.** `itemizeProcessor-keyed.js` now inherits all SSR hydration fixes: `clientSSR` detection, SSR tag adoption, `isoMode` on items, static template derivation, conditional child clearing, and `initPropFallback`.
16
+
17
+ ### Fixed
18
+
19
+ - **Keyed processor: live HTMLCollection bug.** Fixed `animateOut` failing when removing multiple items by key — the live `HTMLCollection` shifted indices during removal. Elements are now snapshotted before removal.
20
+
21
+ ## 3.3.8
22
+
23
+ ### Fixed
24
+
25
+ - **SSR hydration: Itemize template derivation.** Dynamically added itemize items now use the original template (parsed from `fnCtx.constructor.template`) instead of SSR-expanded `innerHTML`. This preserves nested custom elements (e.g. icons) in new items added after hydration.
26
+
3
27
  ## 3.3.7
4
28
 
5
29
  ### Fixed
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  A lightweight, standards-first UI library built on Web Components. No virtual DOM, no compiler, no build step required — works directly in the browser. A bundler is recommended for production performance, but entirely optional. **~6kb** gzipped.
13
13
 
14
- Symbiote.js gives you the convenience of a modern framework while staying close to the native platform — HTML, CSS, and DOM APIs. Components are real custom elements that work everywhere: in any framework, in plain HTML, or in a micro-frontend architecture.
14
+ Symbiote.js gives you the convenience of a modern framework while staying close to the native platform — HTML, CSS, and DOM APIs. Components are real custom elements that work everywhere: in any framework, in plain HTML, or in a micro-frontend architecture. And with **isomorphic mode**, the same component code works on the server and the client — server-rendered pages hydrate automatically, no diffing, no mismatch errors.
15
15
 
16
16
  ## What's new in 3.x
17
17
 
@@ -61,57 +61,57 @@ npm i @symbiotejs/symbiote
61
61
  import Symbiote, { html, css } from '@symbiotejs/symbiote';
62
62
  ```
63
63
 
64
- ## SSR simpler than you'd expect
64
+ ## Isomorphic Web Components
65
65
 
66
- Symbiote's SSR doesn't need a virtual DOM, a reconciler, or framework-specific server packages. It's one class:
66
+ One component. Server-rendered or client-rendered automatically. Set `isoMode = true` and the component figures it out: if server-rendered content exists, it hydrates; otherwise it renders from template. No conditional logic, no separate server/client versions:
67
67
 
68
68
  ```js
69
- import { SSR } from '@symbiotejs/symbiote/node/SSR.js';
70
-
71
- await SSR.init(); // patches globals with linkedom
72
- await import('./my-app.js'); // your components register normally
69
+ class MyComponent extends Symbiote {
70
+ isoMode = true;
71
+ count = 0;
72
+ increment() {
73
+ this.$.count++;
74
+ }
75
+ }
73
76
 
74
- let html = await SSR.processHtml('<my-app>slot content</my-app>');
75
- SSR.destroy(); // cleanup
77
+ MyComponent.template = html`
78
+ <h2>{{count}}</h2>
79
+ <button ${{onclick: 'increment'}}>Click me!</button>
80
+ `;
81
+ MyComponent.reg('my-component');
76
82
  ```
77
83
 
78
- On the client, components with `ssrMode = true` skip template injection and attach bindings to the existing DOM. State mutations work immediately — no hydration step, no reconciliation, no diffing. For isomorphic components that may or may not be server-rendered, use `isoMode = true` it detects children automatically.
84
+ This exact code runs **everywhere** SSR on the server, hydration on the client, or pure client rendering. No framework split, no `'use client'` directives, no hydration mismatch errors.
79
85
 
80
- ### Streaming
86
+ ### SSR — one class, zero config
81
87
 
82
- For large pages, stream HTML chunks instead of building a string:
88
+ Server rendering doesn't need a virtual DOM, a reconciler, or framework-specific packages:
83
89
 
84
90
  ```js
85
91
  import { SSR } from '@symbiotejs/symbiote/node/SSR.js';
86
92
 
87
- await SSR.init();
88
- await import('./my-app.js');
93
+ await SSR.init(); // patches globals with linkedom
94
+ await import('./my-app.js'); // components register normally
89
95
 
90
- http.createServer(async (req, res) => {
91
- res.writeHead(200, { 'Content-Type': 'text/html' });
92
- res.write('<!DOCTYPE html><html><body>');
93
- for await (let chunk of SSR.renderToStream('my-app')) {
94
- res.write(chunk);
95
- }
96
- res.end('</body></html>');
97
- }).listen(3000);
96
+ let html = await SSR.processHtml('<my-app></my-app>');
97
+ SSR.destroy();
98
98
  ```
99
99
 
100
+ For large pages, stream HTML chunks with `SSR.renderToStream()` for faster TTFB. See [SSR docs](./docs/ssr.md) and [server setup recipes](./docs/ssr-server.md).
101
+
100
102
  ### How it compares
101
103
 
102
104
  | | **Symbiote.js** | **Next.js (React)** | **Lit** (`@lit-labs/ssr`) |
103
- |--|----------------|---------------------|--------------------------|
104
- | **Architecture** | Binding-based. Client attaches to existing DOM | Virtual DOM. Client re-renders and diffs against server HTML | Template-based with comment markers |
105
- | **Hydration** | `ssrMode = true` one flag, no diffing | `hydrateRoot()` — must produce identical output or errors | Requires `ssr-client` + hydrate support module loaded before Lit |
106
- | **Packages** | 1 module (`node/SSR.js`) + `linkedom` peer dep | Next.js framework (full buy-in) | 3 packages: `ssr`, `ssr-client`, `ssr-dom-shim` |
105
+ |--|----------------|---------------------|----|
106
+ | **Isomorphic code** | Same code, `isoMode` auto-detects | Server Components vs Client Components split | Same code, but load-order constraints |
107
+ | **Hydration** | Binding-based attaches to existing DOM, no diffing | `hydrateRoot()` — must produce identical output or errors | Requires `ssr-client` + hydrate support module |
108
+ | **Packages** | 1 module + `linkedom` peer dep | Full framework buy-in | 3 packages: `ssr`, `ssr-client`, `ssr-dom-shim` |
107
109
  | **Streaming** | `renderToStream()` async generator | `renderToPipeableStream()` | Iterable `RenderResult` |
108
- | **Mismatch handling** | Not needed — bindings attach to whatever DOM exists | Hard errors or visual glitches if server/client output differs | N/A |
109
- | **Component code** | Same code, no changes | Server Components vs Client Components split | Same code, but load-order constraints |
110
+ | **Mismatch handling** | Not needed — bindings attach to whatever DOM exists | Hard errors if server/client output differs | N/A |
110
111
  | **Template output** | Clean HTML with `bind=` attributes | HTML with framework markers | HTML with `<!--lit-part-->` comment markers |
111
- | **Bundle impact** | Zero — SSR module is server-only | React runtime required on client | Zero — SSR packages are server-only |
112
112
  | **Lock-in** | None — standard Web Components | Full framework commitment | Lit-specific, but Web Components |
113
113
 
114
- **Key insight:** Symbiote's SSR is simpler because it doesn't try to reconcile server and client output. The server produces HTML with binding attributes preserved. The client reads those attributes and adds reactivity. No comparison, no diffing, no mismatch errors.
114
+ **Key insight:** There are no hydration mismatches because there's no diffing. The server produces HTML with binding attributes. The client reads those attributes and adds reactivity. That's it.
115
115
 
116
116
  ## Core concepts
117
117
 
@@ -1,6 +1,5 @@
1
- import { DICT } from './dictionary.js';
2
1
  import { animateOut } from './animateOut.js';
3
- import { ownElements } from './ownElements.js';
2
+ import { setupItemize } from './itemizeSetup.js';
4
3
 
5
4
  /**
6
5
  * Optimized itemize template processor.
@@ -30,31 +29,7 @@ import { ownElements } from './ownElements.js';
30
29
  * @param {T} fnCtx
31
30
  */
32
31
  export function itemizeProcessor(fr, fnCtx) {
33
- ownElements(fr, `[${DICT.LIST_ATTR}]`).filter((el) => {
34
- return !el.matches(`[${DICT.LIST_ATTR}] [${DICT.LIST_ATTR}]`);
35
- }).forEach((el) => {
36
- let itemTag = el.getAttribute(DICT.LIST_ITEM_TAG_ATTR);
37
- let itemClass;
38
- if (itemTag) {
39
- itemClass = window.customElements.get(itemTag);
40
- }
41
- if (!itemClass) {
42
- itemClass = class extends fnCtx.Symbiote {
43
- constructor() {
44
- super();
45
- if (!itemTag) {
46
- this.style.display = 'contents';
47
- }
48
- }
49
- };
50
- itemClass.template = el.querySelector('template')?.innerHTML || el.innerHTML;
51
- itemClass.reg(itemTag);
52
- }
53
- while (el.firstChild) {
54
- el.firstChild.remove();
55
- }
56
- let repeatDataKey = el.getAttribute(DICT.LIST_ATTR);
57
-
32
+ setupItemize(fr, fnCtx, ({ el, itemClass, repeatDataKey, clientSSR }) => {
58
33
  /** @type {*[]} */
59
34
  let prevData = [];
60
35
 
@@ -180,8 +155,9 @@ export function itemizeProcessor(fr, fnCtx) {
180
155
  }
181
156
  }
182
157
 
183
- for (let key of toRemove) {
184
- animateOut(children[prevKeyToIdx.get(key)]);
158
+ let removeEls = [...toRemove].map((key) => children[prevKeyToIdx.get(key)]);
159
+ for (let el of removeEls) {
160
+ animateOut(el);
185
161
  }
186
162
 
187
163
  for (let i = 0; i < newChildren.length; i++) {
@@ -226,10 +202,6 @@ export function itemizeProcessor(fr, fnCtx) {
226
202
  }
227
203
 
228
204
  prevData = items;
229
- });
230
- if (!globalThis.__SYMBIOTE_SSR) {
231
- el.removeAttribute(DICT.LIST_ATTR);
232
- el.removeAttribute(DICT.LIST_ITEM_TAG_ATTR);
233
- }
205
+ }, !clientSSR);
234
206
  });
235
207
  }
@@ -1,7 +1,5 @@
1
- import { DICT } from './dictionary.js';
2
1
  import { animateOut } from './animateOut.js';
3
- import { ownElements } from './ownElements.js';
4
- import { initPropFallback } from './initPropFallback.js';
2
+ import { setupItemize } from './itemizeSetup.js';
5
3
 
6
4
  /**
7
5
  * @template {import('./Symbiote.js').Symbiote} T
@@ -9,118 +7,58 @@ import { initPropFallback } from './initPropFallback.js';
9
7
  * @param {T} fnCtx
10
8
  */
11
9
  export function itemizeProcessor(fr, fnCtx) {
12
- let clientSSR = fnCtx.ssrMode && !globalThis.__SYMBIOTE_SSR;
13
-
14
- ownElements(fr, `[${DICT.LIST_ATTR}]`).filter((el) => {
15
- return !el.matches(`[${DICT.LIST_ATTR}] [${DICT.LIST_ATTR}]`);
16
- }).forEach((el) => {
17
- let itemTag = el.getAttribute(DICT.LIST_ITEM_TAG_ATTR);
18
- let repeatDataKey = el.getAttribute(DICT.LIST_ATTR);
19
- let itemClass;
20
- if (itemTag) {
21
- itemClass = window.customElements.get(itemTag);
22
- }
23
- if (!itemClass) {
24
- // During hydration, adopt existing SSR item tag and derive template
25
- if (clientSSR && el.children.length > 0) {
26
- let ssrTag = el.children[0].localName;
27
- itemClass = window.customElements.get(ssrTag);
28
- if (!itemClass) {
29
- itemClass = class extends fnCtx.Symbiote {
30
- constructor() {
31
- super();
32
- this.isoMode = true;
33
- if (!itemTag) {
34
- this.style.display = 'contents';
35
- }
36
- }
37
- };
38
- let tpl = document.createElement('template');
39
- // @ts-expect-error
40
- tpl.innerHTML = fnCtx.constructor.template;
41
- let staticEl = tpl.content.querySelector(
42
- `[${DICT.LIST_ATTR}="${repeatDataKey}"]`
43
- );
44
- itemClass.template = staticEl?.querySelector('template')?.innerHTML
45
- || el.children[0].innerHTML;
46
- itemClass.reg(ssrTag);
47
- }
48
- } else {
49
- itemClass = class extends fnCtx.Symbiote {
50
- constructor() {
51
- super();
52
- if (!itemTag) {
53
- this.style.display = 'contents';
54
- }
55
- }
56
- };
57
- itemClass.template = el.querySelector('template')?.innerHTML || el.innerHTML;
58
- itemClass.reg(itemTag);
59
- }
60
- }
61
- if (!clientSSR) {
10
+ setupItemize(fr, fnCtx, ({ el, itemClass, repeatDataKey, clientSSR }) => {
11
+ fnCtx.sub(repeatDataKey, (data) => {
12
+ if (!data) {
62
13
  while (el.firstChild) {
63
14
  el.firstChild.remove();
64
15
  }
16
+ return;
65
17
  }
66
- if (!fnCtx.has(repeatDataKey) && fnCtx.allowTemplateInits) {
67
- initPropFallback(fnCtx, repeatDataKey);
68
- }
69
- fnCtx.sub(repeatDataKey, (data) => {
70
- if (!data) {
71
- while (el.firstChild) {
72
- el.firstChild.remove();
73
- }
74
- return;
75
- }
76
- /** @type {*[]} */
77
- let currentList = [...el.children];
78
- let fragment;
79
- let fillItems = (/** @type {*[]} */ items) => {
80
- items.forEach((item, idx) => {
81
- if (currentList[idx]) {
82
- if (currentList[idx].set$) {
83
- currentList[idx].set$(item);
84
- } else {
85
- for (let k in item) {
86
- currentList[idx][k] = item[k];
87
- }
88
- }
18
+ /** @type {*[]} */
19
+ let currentList = [...el.children];
20
+ let fragment;
21
+ let fillItems = (/** @type {*[]} */ items) => {
22
+ items.forEach((item, idx) => {
23
+ if (currentList[idx]) {
24
+ if (currentList[idx].set$) {
25
+ currentList[idx].set$(item);
89
26
  } else {
90
- if (!fragment) {
91
- fragment = document.createDocumentFragment();
27
+ for (let k in item) {
28
+ currentList[idx][k] = item[k];
92
29
  }
93
- let repeatItem = new itemClass();
94
- Object.assign((repeatItem?.init$ || repeatItem), item);
95
- fragment.appendChild(repeatItem);
96
30
  }
97
- });
98
- fragment && el.appendChild(fragment);
99
- let oversize = currentList.slice(items.length, currentList.length);
100
- for (let exItm of oversize) {
101
- animateOut(exItm);
102
- }
103
- };
104
- if (data.constructor === Array) {
105
- fillItems(data);
106
- } else if (data.constructor === Object) {
107
- let items = [];
108
- for (let itemKey in data) {
109
- let init = data[itemKey];
110
- Object.defineProperty(init, '_KEY_', {
111
- value: itemKey,
112
- enumerable: true,
113
- });
114
- items.push(init);
31
+ } else {
32
+ if (!fragment) {
33
+ fragment = document.createDocumentFragment();
34
+ }
35
+ let repeatItem = new itemClass();
36
+ Object.assign((repeatItem?.init$ || repeatItem), item);
37
+ fragment.appendChild(repeatItem);
115
38
  }
116
- fillItems(items);
117
- } else {
118
- console.warn(`[Symbiote] <${fnCtx.localName}>: itemize data must be Array or Object, got ${typeof data}:`, data);
39
+ });
40
+ fragment && el.appendChild(fragment);
41
+ let oversize = currentList.slice(items.length, currentList.length);
42
+ for (let exItm of oversize) {
43
+ animateOut(exItm);
44
+ }
45
+ };
46
+ if (data.constructor === Array) {
47
+ fillItems(data);
48
+ } else if (data.constructor === Object) {
49
+ let items = [];
50
+ for (let itemKey in data) {
51
+ let init = data[itemKey];
52
+ Object.defineProperty(init, '_KEY_', {
53
+ value: itemKey,
54
+ enumerable: true,
55
+ });
56
+ items.push(init);
119
57
  }
120
- }, !clientSSR);
121
- if (!globalThis.__SYMBIOTE_SSR) {
122
- el.removeAttribute(DICT.LIST_ATTR);
123
- el.removeAttribute(DICT.LIST_ITEM_TAG_ATTR);
58
+ fillItems(items);
59
+ } else {
60
+ console.warn(`[Symbiote] <${fnCtx.localName}>: itemize data must be Array or Object, got ${typeof data}:`, data);
124
61
  }
125
- });
62
+ }, !clientSSR);
63
+ });
126
64
  }
@@ -0,0 +1,88 @@
1
+ import { DICT } from './dictionary.js';
2
+ import { ownElements } from './ownElements.js';
3
+ import { initPropFallback } from './initPropFallback.js';
4
+
5
+ /**
6
+ * @typedef {Object} ItemizeDescriptor
7
+ * @property {Element} el
8
+ * @property {*} itemClass
9
+ * @property {string} repeatDataKey
10
+ * @property {boolean} clientSSR
11
+ */
12
+
13
+ /**
14
+ * Shared setup for itemize processors.
15
+ * Handles element discovery, class creation, SSR hydration, template derivation,
16
+ * child clearing, initPropFallback, and attribute cleanup.
17
+ *
18
+ * @template {import('./Symbiote.js').Symbiote} T
19
+ * @param {DocumentFragment} fr
20
+ * @param {T} fnCtx
21
+ * @param {(desc: ItemizeDescriptor) => void} handler
22
+ */
23
+ export function setupItemize(fr, fnCtx, handler) {
24
+ let clientSSR = fnCtx.ssrMode && !globalThis.__SYMBIOTE_SSR;
25
+
26
+ ownElements(fr, `[${DICT.LIST_ATTR}]`).filter((el) => {
27
+ return !el.matches(`[${DICT.LIST_ATTR}] [${DICT.LIST_ATTR}]`);
28
+ }).forEach((el) => {
29
+ let itemTag = el.getAttribute(DICT.LIST_ITEM_TAG_ATTR);
30
+ let repeatDataKey = el.getAttribute(DICT.LIST_ATTR);
31
+ let itemClass;
32
+ if (itemTag) {
33
+ itemClass = window.customElements.get(itemTag);
34
+ }
35
+ if (!itemClass) {
36
+ if (clientSSR && el.children.length > 0) {
37
+ let ssrTag = el.children[0].localName;
38
+ itemClass = window.customElements.get(ssrTag);
39
+ if (!itemClass) {
40
+ itemClass = class extends fnCtx.Symbiote {
41
+ constructor() {
42
+ super();
43
+ this.isoMode = true;
44
+ if (!itemTag) {
45
+ this.style.display = 'contents';
46
+ }
47
+ }
48
+ };
49
+ let tpl = document.createElement('template');
50
+ // @ts-expect-error
51
+ tpl.innerHTML = fnCtx.constructor.template;
52
+ let staticEl = tpl.content.querySelector(
53
+ `[${DICT.LIST_ATTR}="${repeatDataKey}"]`
54
+ );
55
+ itemClass.template = staticEl?.querySelector('template')?.innerHTML
56
+ || el.children[0].innerHTML;
57
+ itemClass.reg(ssrTag);
58
+ }
59
+ } else {
60
+ itemClass = class extends fnCtx.Symbiote {
61
+ constructor() {
62
+ super();
63
+ if (!itemTag) {
64
+ this.style.display = 'contents';
65
+ }
66
+ }
67
+ };
68
+ itemClass.template = el.querySelector('template')?.innerHTML || el.innerHTML;
69
+ itemClass.reg(itemTag);
70
+ }
71
+ }
72
+ if (!clientSSR) {
73
+ while (el.firstChild) {
74
+ el.firstChild.remove();
75
+ }
76
+ }
77
+ if (!fnCtx.has(repeatDataKey) && fnCtx.allowTemplateInits) {
78
+ initPropFallback(fnCtx, repeatDataKey);
79
+ }
80
+
81
+ handler({ el, itemClass, repeatDataKey, clientSSR });
82
+
83
+ if (!globalThis.__SYMBIOTE_SSR) {
84
+ el.removeAttribute(DICT.LIST_ATTR);
85
+ el.removeAttribute(DICT.LIST_ITEM_TAG_ATTR);
86
+ }
87
+ });
88
+ }
@@ -155,6 +155,13 @@ const txtNodesProcessor = function (fr, fnCtx) {
155
155
  if (!fnCtx.has(prop) && fnCtx.allowTemplateInits) {
156
156
  initPropFallback(fnCtx, prop);
157
157
  }
158
+ if (fnCtx.Symbiote?.devMode && (fnCtx.ssrMode || fnCtx.isoMode)) {
159
+ console.warn(
160
+ `[Symbiote dev] <${fnCtx.localName}>: text-node binding "{{${prop}}}" has no hydration attribute. `
161
+ + 'In ssrMode/isoMode it will be rendered by the server but won\'t update on the client. '
162
+ + 'Use property binding (${{textContent: \'' + prop + '\'}}) for hydratable text.'
163
+ );
164
+ }
158
165
  fnCtx.sub(prop, (val) => {
159
166
  tNode.textContent = val;
160
167
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@symbiotejs/symbiote",
4
- "version": "3.3.8",
4
+ "version": "3.4.0",
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",
@@ -87,6 +87,10 @@
87
87
  "types": "./types/core/itemizeProcessor.d.ts",
88
88
  "default": "./core/itemizeProcessor.js"
89
89
  },
90
+ "./core/itemizeSetup.js": {
91
+ "types": "./types/core/itemizeSetup.d.ts",
92
+ "default": "./core/itemizeSetup.js"
93
+ },
90
94
  "./core/ownElements.js": {
91
95
  "types": "./types/core/ownElements.d.ts",
92
96
  "default": "./core/ownElements.js"
@@ -1 +1 @@
1
- {"version":3,"file":"itemizeProcessor-keyed.d.ts","sourceRoot":"","sources":["../../core/itemizeProcessor-keyed.js"],"names":[],"mappings":"AA+BA,iCAJgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,QA6MX"}
1
+ {"version":3,"file":"itemizeProcessor-keyed.d.ts","sourceRoot":"","sources":["../../core/itemizeProcessor-keyed.js"],"names":[],"mappings":"AA8BA,iCAJgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,QAkLX"}
@@ -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,QAqHX"}
1
+ {"version":3,"file":"itemizeProcessor.d.ts","sourceRoot":"","sources":["../../core/itemizeProcessor.js"],"names":[],"mappings":"AAQA,iCAJgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,QAyDX"}
@@ -0,0 +1,8 @@
1
+ export function setupItemize<T extends import("./Symbiote.js").Symbiote<any>>(fr: DocumentFragment, fnCtx: T, handler: (desc: ItemizeDescriptor) => void): void;
2
+ export type ItemizeDescriptor = {
3
+ el: Element;
4
+ itemClass: any;
5
+ repeatDataKey: string;
6
+ clientSSR: boolean;
7
+ };
8
+ //# sourceMappingURL=itemizeSetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"itemizeSetup.d.ts","sourceRoot":"","sources":["../../core/itemizeSetup.js"],"names":[],"mappings":"AAsBA,6BALgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,WACD,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,QAmE3C;;QAjFa,OAAO;eACP,GAAC;mBACD,MAAM;eACN,OAAO"}