@symbiotejs/symbiote 3.5.8 → 3.7.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/AI_REFERENCE.md +33 -9
- package/README.md +11 -0
- package/core/Symbiote.js +54 -1
- package/core/html.js +38 -8
- package/core/itemizeProcessor-keyed.js +10 -1
- package/core/itemizeProcessor.js +4 -1
- package/core/itemizeSetup.js +3 -1
- package/core/tpl-processors.js +19 -11
- package/node/SSR.js +26 -1
- package/package.json +1 -1
- package/types/core/Symbiote.d.ts +2 -0
- package/types/core/Symbiote.d.ts.map +1 -1
- package/types/core/html.d.ts.map +1 -1
- package/types/core/itemizeProcessor-keyed.d.ts.map +1 -1
- package/types/core/itemizeProcessor.d.ts.map +1 -1
- package/types/core/itemizeSetup.d.ts +1 -0
- package/types/core/itemizeSetup.d.ts.map +1 -1
- package/types/core/tpl-processors.d.ts.map +1 -1
- package/types/node/SSR.d.ts.map +1 -1
package/AI_REFERENCE.md
CHANGED
|
@@ -441,7 +441,7 @@ class MyList extends Symbiote {
|
|
|
441
441
|
}
|
|
442
442
|
|
|
443
443
|
MyList.template = html`
|
|
444
|
-
<ul
|
|
444
|
+
<ul itemize="items">
|
|
445
445
|
<template>
|
|
446
446
|
<li>
|
|
447
447
|
<span>{{name}}</span> - <span>{{role}}</span>
|
|
@@ -452,17 +452,41 @@ MyList.template = html`
|
|
|
452
452
|
`;
|
|
453
453
|
```
|
|
454
454
|
|
|
455
|
-
> **CRITICAL**: Inside itemize
|
|
456
|
-
>
|
|
457
|
-
>
|
|
458
|
-
>
|
|
459
|
-
>
|
|
455
|
+
> **CRITICAL**: Inside itemize, each item is a Symbiote component with its own state scope.
|
|
456
|
+
> There are **two patterns** — they determine how event handlers are bound:
|
|
457
|
+
>
|
|
458
|
+
> **Pattern 1: Inline `<template>` (dumb items)** — items have no class definition, only data properties from the array.
|
|
459
|
+
> Any event handler or data must come from an **external context** — not from the item itself.
|
|
460
|
+
> All context prefixes work: `^` (parent pop-up), `APP/` (named), `*` (shared). The most common is `^`:
|
|
461
|
+
> ```html
|
|
462
|
+
> <ul itemize="items">
|
|
463
|
+
> <template>
|
|
464
|
+
> <li>{{name}} <button ${{onclick: '^onItemClick'}}>Click</button></li>
|
|
465
|
+
> </template>
|
|
466
|
+
> </ul>
|
|
467
|
+
> ```
|
|
468
|
+
> Without a context prefix, the binding looks for the handler on the item itself — which doesn't have it, so it breaks.
|
|
469
|
+
>
|
|
470
|
+
> **Pattern 2: Custom `item-tag` (smart items)** — items are full components with their own class, templates, and methods.
|
|
471
|
+
> Handlers defined on the item component itself do **NOT** need `^`:
|
|
472
|
+
> ```html
|
|
473
|
+
> <div itemize="items" item-tag="my-item"></div>
|
|
474
|
+
> ```
|
|
475
|
+
> ```js
|
|
476
|
+
> class MyItem extends Symbiote {
|
|
477
|
+
> onItemClick() { console.log(this.$.name); }
|
|
478
|
+
> }
|
|
479
|
+
> MyItem.template = html`<li>{{name}} <button ${{onclick: 'onItemClick'}}>Click</button></li>`;
|
|
480
|
+
> MyItem.reg('my-item');
|
|
481
|
+
> ```
|
|
482
|
+
> Here `onItemClick` is the item's own method — no `^` needed.
|
|
483
|
+
> You can still use `^` to reach the parent list component if needed.
|
|
460
484
|
|
|
461
485
|
### Custom item component
|
|
462
486
|
```html
|
|
463
|
-
<div
|
|
487
|
+
<div itemize="items" item-tag="my-item"></div>
|
|
464
488
|
```
|
|
465
|
-
Then define `my-item` as a separate Symbiote component.
|
|
489
|
+
Then define `my-item` as a separate Symbiote component with its own template, methods, and state.
|
|
466
490
|
|
|
467
491
|
### Data formats
|
|
468
492
|
- **Array**: `[{prop: val}, ...]` — items rendered in order
|
|
@@ -799,7 +823,7 @@ import '@symbiotejs/symbiote/core/devMessages.js';
|
|
|
799
823
|
|
|
800
824
|
1. **DON'T** use `this` in template strings — templates are decoupled from component context
|
|
801
825
|
2. **DON'T** nest property keys with dots in state: `'obj.prop'` won't work as a state key
|
|
802
|
-
3. **DON'T** forget `^` prefix when referencing **parent**
|
|
826
|
+
3. **DON'T** forget `^` prefix when referencing **parent** handlers from inline `<template>` itemize items (dumb items without their own class). Custom `item-tag` components with own methods bind directly without `^`
|
|
803
827
|
4. **DON'T** use `@` prefix directly in HTML — it's only for binding syntax (`${{'@attr': 'prop'}}`)
|
|
804
828
|
5. **DON'T** treat `init$` as a regular object — it's processed at connection time
|
|
805
829
|
6. **DON'T** define `template` inside the class body (`static template = html\`...\`` won't work) — it's a static property **setter**, assign it outside: `MyComponent.template = html\`...\``. Same applies to `rootStyles` and `shadowStyles`.
|
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ Symbiote.js gives you the convenience of a modern framework while staying close
|
|
|
23
23
|
- **Dev mode** - `Symbiote.devMode` enables verbose warnings; import `devMessages.js` for full human-readable messages.
|
|
24
24
|
- **DSD hydration** - `ssrMode` supports both light DOM and Declarative Shadow DOM.
|
|
25
25
|
- **Class property fallback** - binding keys not in `init$` fall back to own class properties/methods.
|
|
26
|
+
- **Lazy mode** - `lazyMode` flag defers component initialization and rendering based on viewport visibility. Can also be enabled via the `lazy` attribute on `itemize` containers to efficiently handle massive data sets.
|
|
26
27
|
- And [more](https://github.com/symbiotejs/symbiote.js/blob/main/CHANGELOG.md).
|
|
27
28
|
|
|
28
29
|
## Quick start
|
|
@@ -184,6 +185,8 @@ TaskList.template = html`
|
|
|
184
185
|
|
|
185
186
|
Items have their own state scope. Use the **`^` prefix** to reach higher-level component properties and handlers - `'^onItemClick'` binds to the parent's `onItemClick`, not the item's. Properties referenced via `^` must be defined in the parent's `init$`.
|
|
186
187
|
|
|
188
|
+
> **Performance Tip:** For massive lists, add the `lazy` attribute to the container (`<div itemize="tasks" lazy>`). It defers component initialization until they enter the viewport and cleans them up when they leave, heavily optimizing memory and rendering performance.
|
|
189
|
+
|
|
187
190
|
### Pop-up binding (`^`)
|
|
188
191
|
|
|
189
192
|
The `^` prefix works in any nested component template - it walks up the DOM tree to find the nearest ancestor that has the property registered in its data context (`init$` or `add$()`):
|
|
@@ -327,6 +330,7 @@ CSS values are parsed automatically - quoted strings become strings, numbers bec
|
|
|
327
330
|
## Best for
|
|
328
331
|
|
|
329
332
|
- **Complex widgets** embedded in any host application
|
|
333
|
+
- **Low-code HTML-based solutions** - simple declarative everything
|
|
330
334
|
- **Micro frontends** - standard custom elements, no framework coupling
|
|
331
335
|
- **Reusable component libraries** - works in React, Vue, Angular, or plain HTML
|
|
332
336
|
- **SSR-powered apps** - lightweight server rendering without framework lock-in
|
|
@@ -356,6 +360,13 @@ All modern browsers: Chrome, Firefox, Safari, Edge, Opera.
|
|
|
356
360
|
- [AI Reference](https://github.com/symbiotejs/symbiote.js/blob/main/AI_REFERENCE.md)
|
|
357
361
|
- [Changelog](https://github.com/symbiotejs/symbiote.js/blob/main/CHANGELOG.md)
|
|
358
362
|
|
|
363
|
+
## Related articles
|
|
364
|
+
|
|
365
|
+
- [Symbiote.js: superpowers for Web Components](https://dev.to/foxeyes/symbiotejs-superpowers-for-web-components-1gid)
|
|
366
|
+
- [Symbiote.js: v3 highlights](https://dev.to/foxeyes/symbiotejs-v3-web-components-with-ssr-in-6kb-10n6)
|
|
367
|
+
- [Symbiote.js vs Lit](https://dev.to/foxeyes/lit-vs-symbiotejs-22gj)
|
|
368
|
+
- [JSDA Stack - A Revolutionary Simple Approach to Build Modern Web](https://dev.to/foxeyes/jsda-kit-a-revolutionary-simple-approach-to-build-modern-web-1dip)
|
|
369
|
+
|
|
359
370
|
**Questions or proposals? Welcome to [Symbiote Discussions](https://github.com/symbiotejs/symbiote.js/discussions)!** ❤️
|
|
360
371
|
|
|
361
372
|
---
|
package/core/Symbiote.js
CHANGED
|
@@ -19,6 +19,9 @@ const trustedHTML = globalThis.trustedTypes ? trustedTypes.createPolicy('symbiot
|
|
|
19
19
|
|
|
20
20
|
/** @template S */
|
|
21
21
|
export class Symbiote extends HTMLElement {
|
|
22
|
+
/** @type {IntersectionObserver} */
|
|
23
|
+
static lazyObserver;
|
|
24
|
+
|
|
22
25
|
/** @type {Boolean} */
|
|
23
26
|
#initialized;
|
|
24
27
|
/** @type {String} */
|
|
@@ -187,6 +190,8 @@ export class Symbiote extends HTMLElement {
|
|
|
187
190
|
this.isVirtual = false;
|
|
188
191
|
/** @type {Boolean} */
|
|
189
192
|
this.allowTemplateInits = true;
|
|
193
|
+
/** @type {Boolean} */
|
|
194
|
+
this.lazyMode = false;
|
|
190
195
|
}
|
|
191
196
|
|
|
192
197
|
/** @returns {String} */
|
|
@@ -516,7 +521,52 @@ export class Symbiote extends HTMLElement {
|
|
|
516
521
|
}
|
|
517
522
|
|
|
518
523
|
connectedCallback() {
|
|
519
|
-
this
|
|
524
|
+
if (this.lazyMode) {
|
|
525
|
+
if (!Symbiote.lazyObserver) {
|
|
526
|
+
Symbiote.lazyObserver = new IntersectionObserver((entries) => {
|
|
527
|
+
entries.forEach((ent) => {
|
|
528
|
+
/** @type {any} */
|
|
529
|
+
let tgt = ent.target;
|
|
530
|
+
if (ent.isIntersecting) {
|
|
531
|
+
tgt.style.minHeight = '';
|
|
532
|
+
tgt.style.minWidth = '';
|
|
533
|
+
tgt.#initComponent();
|
|
534
|
+
} else {
|
|
535
|
+
tgt.#lazyDestroy();
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
Symbiote.lazyObserver.observe(this);
|
|
541
|
+
} else {
|
|
542
|
+
this.#initComponent();
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
#lazyDestroy() {
|
|
547
|
+
if (!this.connectedOnce) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
let rect = this.getBoundingClientRect();
|
|
551
|
+
if (rect.height) {
|
|
552
|
+
this.style.minHeight = rect.height + 'px';
|
|
553
|
+
this.style.minWidth = rect.width + 'px';
|
|
554
|
+
}
|
|
555
|
+
if (this.shadowRoot) {
|
|
556
|
+
this.shadowRoot.innerHTML = '';
|
|
557
|
+
} else {
|
|
558
|
+
this.innerHTML = '';
|
|
559
|
+
}
|
|
560
|
+
for (let sub of this.allSubs) {
|
|
561
|
+
sub.remove();
|
|
562
|
+
this.allSubs.delete(sub);
|
|
563
|
+
}
|
|
564
|
+
this.#localCtx = null;
|
|
565
|
+
this.templateProcessors.clear();
|
|
566
|
+
|
|
567
|
+
this.connectedOnce = false;
|
|
568
|
+
this.#dataCtxInitialized = false;
|
|
569
|
+
this.#initialized = false;
|
|
520
570
|
}
|
|
521
571
|
|
|
522
572
|
destroyCallback() {}
|
|
@@ -532,6 +582,9 @@ export class Symbiote extends HTMLElement {
|
|
|
532
582
|
destructionDelay = 100;
|
|
533
583
|
disconnectedCallback() {
|
|
534
584
|
if (globalThis.__SYMBIOTE_SSR) return;
|
|
585
|
+
if (this.lazyMode && Symbiote.lazyObserver) {
|
|
586
|
+
Symbiote.lazyObserver.unobserve(this);
|
|
587
|
+
}
|
|
535
588
|
// if element wasn't connected, there is no need to disconnect it
|
|
536
589
|
if (!this.connectedOnce) {
|
|
537
590
|
return;
|
package/core/html.js
CHANGED
|
@@ -10,6 +10,35 @@ export const RESERVED_ATTRIBUTES = [
|
|
|
10
10
|
DICT.CTX_NAME_ATTR,
|
|
11
11
|
];
|
|
12
12
|
|
|
13
|
+
const RESERVED_ATTRIBUTES_SET = new Set(RESERVED_ATTRIBUTES);
|
|
14
|
+
const SELF_CLOSING_CUSTOM_ELEMENT_RE = /<([a-z][.0-9_a-z]*-[\-.0-9_a-z]*)(\s+(?:"[^"]*"|'[^']*'|[^'"<>])*)?\/>/gi;
|
|
15
|
+
|
|
16
|
+
function hasImmediateClosingTag(htmlString, startIdx, tagName) {
|
|
17
|
+
let idx = startIdx;
|
|
18
|
+
let len = htmlString.length;
|
|
19
|
+
while (idx < len) {
|
|
20
|
+
let code = htmlString.charCodeAt(idx);
|
|
21
|
+
if (code !== 32 && code !== 9 && code !== 10 && code !== 12 && code !== 13) break;
|
|
22
|
+
idx++;
|
|
23
|
+
}
|
|
24
|
+
if (htmlString.charCodeAt(idx) !== 60 || htmlString.charCodeAt(idx + 1) !== 47) return false;
|
|
25
|
+
let tagStart = idx + 2;
|
|
26
|
+
if (htmlString.charCodeAt(tagStart + tagName.length) !== 62) return false;
|
|
27
|
+
let closingTagName = htmlString.slice(tagStart, tagStart + tagName.length);
|
|
28
|
+
return closingTagName === tagName || closingTagName.toLowerCase() === tagName.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function closeSelfClosingCustomElements(resultHtml) {
|
|
32
|
+
if (resultHtml.indexOf('/>') === -1) return resultHtml;
|
|
33
|
+
return resultHtml.replace(SELF_CLOSING_CUSTOM_ELEMENT_RE, (match, tagName, attrs = '', offset, htmlString) => {
|
|
34
|
+
let openTag = `<${tagName}${attrs && attrs.trimEnd()}>`;
|
|
35
|
+
if (hasImmediateClosingTag(htmlString, offset + match.length, tagName)) {
|
|
36
|
+
return openTag;
|
|
37
|
+
}
|
|
38
|
+
return `${openTag}</${tagName}>`;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
13
42
|
/** @typedef {Record<keyof import('./Symbiote.js').Symbiote, String>} BindDescriptor */
|
|
14
43
|
|
|
15
44
|
/**
|
|
@@ -20,19 +49,20 @@ export const RESERVED_ATTRIBUTES = [
|
|
|
20
49
|
*/
|
|
21
50
|
export function html(parts, ...props) {
|
|
22
51
|
let resultHtml = '';
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
52
|
+
let propsLength = props.length;
|
|
53
|
+
for (let idx = 0; idx < parts.length; idx++) {
|
|
54
|
+
resultHtml += parts[idx];
|
|
55
|
+
if (idx >= propsLength) continue;
|
|
26
56
|
let val = props[idx];
|
|
27
57
|
if (val === undefined || val === null) {
|
|
28
58
|
errMsg(15, val);
|
|
29
|
-
|
|
59
|
+
continue;
|
|
30
60
|
}
|
|
31
|
-
if (val
|
|
61
|
+
if (val.constructor === Object) {
|
|
32
62
|
let bindStr = '';
|
|
33
63
|
// @ts-expect-error
|
|
34
64
|
for (let key in val) {
|
|
35
|
-
if (
|
|
65
|
+
if (RESERVED_ATTRIBUTES_SET.has(key)) {
|
|
36
66
|
resultHtml += ` ${key}="${val[key]}"`;
|
|
37
67
|
} else {
|
|
38
68
|
bindStr += `${key}:${val[key]};`;
|
|
@@ -42,8 +72,8 @@ export function html(parts, ...props) {
|
|
|
42
72
|
} else {
|
|
43
73
|
resultHtml += val;
|
|
44
74
|
}
|
|
45
|
-
}
|
|
46
|
-
return resultHtml;
|
|
75
|
+
}
|
|
76
|
+
return closeSelfClosingCustomElements(resultHtml);
|
|
47
77
|
}
|
|
48
78
|
|
|
49
79
|
export default html;
|
|
@@ -30,7 +30,7 @@ import { setupItemize } from './itemizeSetup.js';
|
|
|
30
30
|
* @param {T} fnCtx
|
|
31
31
|
*/
|
|
32
32
|
export function itemizeProcessor(fr, fnCtx) {
|
|
33
|
-
setupItemize(fr, fnCtx, ({ el, itemClass, repeatDataKey, clientSSR }) => {
|
|
33
|
+
setupItemize(fr, fnCtx, ({ el, itemClass, repeatDataKey, clientSSR, isLazy }) => {
|
|
34
34
|
/** @type {*[]} */
|
|
35
35
|
let prevData = [];
|
|
36
36
|
|
|
@@ -88,6 +88,9 @@ export function itemizeProcessor(fr, fnCtx) {
|
|
|
88
88
|
let fragment = document.createDocumentFragment();
|
|
89
89
|
for (let i = prevLen; i < newLen; i++) {
|
|
90
90
|
let repeatItem = new itemClass();
|
|
91
|
+
if (isLazy) {
|
|
92
|
+
repeatItem.lazyMode = true;
|
|
93
|
+
}
|
|
91
94
|
Object.assign((repeatItem?.init$ || repeatItem), items[i]);
|
|
92
95
|
fragment.appendChild(repeatItem);
|
|
93
96
|
}
|
|
@@ -151,6 +154,9 @@ export function itemizeProcessor(fr, fnCtx) {
|
|
|
151
154
|
newChildren.push(existing);
|
|
152
155
|
} else {
|
|
153
156
|
let repeatItem = new itemClass();
|
|
157
|
+
if (isLazy) {
|
|
158
|
+
repeatItem.lazyMode = true;
|
|
159
|
+
}
|
|
154
160
|
Object.assign((repeatItem?.init$ || repeatItem), item);
|
|
155
161
|
newChildren.push(repeatItem);
|
|
156
162
|
}
|
|
@@ -193,6 +199,9 @@ export function itemizeProcessor(fr, fnCtx) {
|
|
|
193
199
|
fragment = document.createDocumentFragment();
|
|
194
200
|
}
|
|
195
201
|
let repeatItem = new itemClass();
|
|
202
|
+
if (isLazy) {
|
|
203
|
+
repeatItem.lazyMode = true;
|
|
204
|
+
}
|
|
196
205
|
Object.assign((repeatItem?.init$ || repeatItem), items[i]);
|
|
197
206
|
fragment.appendChild(repeatItem);
|
|
198
207
|
}
|
package/core/itemizeProcessor.js
CHANGED
|
@@ -8,7 +8,7 @@ import { setupItemize } from './itemizeSetup.js';
|
|
|
8
8
|
* @param {T} fnCtx
|
|
9
9
|
*/
|
|
10
10
|
export function itemizeProcessor(fr, fnCtx) {
|
|
11
|
-
setupItemize(fr, fnCtx, ({ el, itemClass, repeatDataKey, clientSSR }) => {
|
|
11
|
+
setupItemize(fr, fnCtx, ({ el, itemClass, repeatDataKey, clientSSR, isLazy }) => {
|
|
12
12
|
fnCtx.sub(repeatDataKey, (data) => {
|
|
13
13
|
if (!data) {
|
|
14
14
|
while (el.firstChild) {
|
|
@@ -34,6 +34,9 @@ export function itemizeProcessor(fr, fnCtx) {
|
|
|
34
34
|
fragment = document.createDocumentFragment();
|
|
35
35
|
}
|
|
36
36
|
let repeatItem = new itemClass();
|
|
37
|
+
if (isLazy) {
|
|
38
|
+
repeatItem.lazyMode = true;
|
|
39
|
+
}
|
|
37
40
|
Object.assign((repeatItem?.init$ || repeatItem), item);
|
|
38
41
|
fragment.appendChild(repeatItem);
|
|
39
42
|
}
|
package/core/itemizeSetup.js
CHANGED
|
@@ -8,6 +8,7 @@ import { initPropFallback } from './initPropFallback.js';
|
|
|
8
8
|
* @property {*} itemClass
|
|
9
9
|
* @property {string} repeatDataKey
|
|
10
10
|
* @property {boolean} clientSSR
|
|
11
|
+
* @property {boolean} isLazy
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -78,7 +79,8 @@ export function setupItemize(fr, fnCtx, handler) {
|
|
|
78
79
|
initPropFallback(fnCtx, repeatDataKey);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
|
|
82
|
+
let isLazy = el.hasAttribute('lazy');
|
|
83
|
+
handler({ el, itemClass, repeatDataKey, clientSSR, isLazy });
|
|
82
84
|
|
|
83
85
|
if (!globalThis.__SYMBIOTE_SSR) {
|
|
84
86
|
el.removeAttribute(DICT.LIST_ATTR);
|
package/core/tpl-processors.js
CHANGED
|
@@ -105,17 +105,25 @@ function getTextNodesWithTokens(el) {
|
|
|
105
105
|
let isCustomEl = el instanceof HTMLElement && el.localName?.includes('-');
|
|
106
106
|
let node;
|
|
107
107
|
let result = [];
|
|
108
|
-
let
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
108
|
+
let acceptNode = (txt) => {
|
|
109
|
+
if (isCustomEl && !isOwnNode(txt, el)) return NodeFilter.FILTER_REJECT;
|
|
110
|
+
return !txt.parentElement?.hasAttribute(DICT.TEXT_NODE_SKIP_ATTR)
|
|
111
|
+
&& txt.textContent.includes(DICT.TEXT_NODE_OPEN_TOKEN)
|
|
112
|
+
&& txt.textContent.includes(DICT.TEXT_NODE_CLOSE_TOKEN)
|
|
113
|
+
? NodeFilter.FILTER_ACCEPT
|
|
114
|
+
: NodeFilter.FILTER_REJECT;
|
|
115
|
+
};
|
|
116
|
+
let walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, acceptNode);
|
|
117
|
+
if (globalThis.__SYMBIOTE_SSR) {
|
|
118
|
+
while ((node = walk.nextNode())) {
|
|
119
|
+
if (acceptNode(node) === NodeFilter.FILTER_ACCEPT) {
|
|
120
|
+
result.push(node);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
while ((node = walk.nextNode())) {
|
|
125
|
+
result.push(node);
|
|
126
|
+
}
|
|
119
127
|
}
|
|
120
128
|
return result;
|
|
121
129
|
}
|
package/node/SSR.js
CHANGED
|
@@ -304,11 +304,36 @@ export class SSR {
|
|
|
304
304
|
static async init() {
|
|
305
305
|
// @ts-ignore
|
|
306
306
|
let { parseHTML } = /** @type {any} */ (await import('linkedom'));
|
|
307
|
-
let { document, window, HTMLElement, customElements, DocumentFragment, NodeFilter, MutationObserver } = parseHTML('<!DOCTYPE html><html><head></head><body></body></html>');
|
|
307
|
+
let { document, window, HTMLElement, customElements, DocumentFragment, NodeFilter, MutationObserver, Text } = parseHTML('<!DOCTYPE html><html><head></head><body></body></html>');
|
|
308
308
|
|
|
309
309
|
SSR.#doc = document;
|
|
310
310
|
SSR.#win = window;
|
|
311
311
|
|
|
312
|
+
// Polyfill splitText for linkedom:
|
|
313
|
+
if (!Text.prototype.splitText) {
|
|
314
|
+
Text.prototype.splitText = function(offset) {
|
|
315
|
+
let nextNode = document.createTextNode(this.textContent.substring(offset));
|
|
316
|
+
this.textContent = this.textContent.substring(0, offset);
|
|
317
|
+
if (this.parentNode) {
|
|
318
|
+
this.parentNode.insertBefore(nextNode, this.nextSibling);
|
|
319
|
+
}
|
|
320
|
+
return nextNode;
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Polyfill textContent on DocumentFragment for linkedom:
|
|
325
|
+
if (!('textContent' in DocumentFragment.prototype) || !Object.getOwnPropertyDescriptor(DocumentFragment.prototype, 'textContent')?.get) {
|
|
326
|
+
Object.defineProperty(DocumentFragment.prototype, 'textContent', {
|
|
327
|
+
get() {
|
|
328
|
+
return this.childNodes.map(n => n.nodeType === 3 ? n.textContent : (n.textContent || '')).join('');
|
|
329
|
+
},
|
|
330
|
+
set(val) {
|
|
331
|
+
while (this.firstChild) this.removeChild(this.firstChild);
|
|
332
|
+
this.appendChild(document.createTextNode(val));
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
312
337
|
// Polyfill CSSStyleSheet for linkedom:
|
|
313
338
|
if (!window.CSSStyleSheet || !('replaceSync' in (window.CSSStyleSheet?.prototype || {}))) {
|
|
314
339
|
class SSRStyleSheet {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@symbiotejs/symbiote",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.7.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",
|
package/types/core/Symbiote.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { html } from "./html.js";
|
|
2
2
|
export { css } from "./css.js";
|
|
3
3
|
export class Symbiote<S> extends HTMLElement {
|
|
4
|
+
static lazyObserver: IntersectionObserver;
|
|
4
5
|
static __tpl: HTMLTemplateElement;
|
|
5
6
|
static set devMode(val: boolean);
|
|
6
7
|
static get devMode(): boolean;
|
|
@@ -38,6 +39,7 @@ export class Symbiote<S> extends HTMLElement {
|
|
|
38
39
|
allowCustomTemplate: boolean;
|
|
39
40
|
isVirtual: boolean;
|
|
40
41
|
allowTemplateInits: boolean;
|
|
42
|
+
lazyMode: boolean;
|
|
41
43
|
get cssCtxName(): string;
|
|
42
44
|
get ctxName(): string;
|
|
43
45
|
get localCtx(): PubSub<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Symbiote.d.ts","sourceRoot":"","sources":["../../core/Symbiote.js"],"names":[],"mappings":";;AAoBA,sBADc,CAAC;
|
|
1
|
+
{"version":3,"file":"Symbiote.d.ts","sourceRoot":"","sources":["../../core/Symbiote.js"],"names":[],"mappings":";;AAoBA,sBADc,CAAC;IAGb,qBADW,oBAAoB,CACX;IAuBpB,cADW,mBAAmB,CACjB;IAEb,iCAEC;IAED,8BAEC;IAkBD,wBAAgB;IAgKhB,+BAJwB,CAAC,SAAZ,aAAU,uBAEZ,CAAC;;;MA0CX;IAoTD,qCAA+B;IAwC/B,iDAFa,OAAO,QAAQ,CAkB3B;IAED,wBAKC;IAGD;;aAYC;IAmHD,6BADY,SAAS,aAAa,QAOjC;IAGD,+BADY,SAAS,aAAa,QAOjC;IAGD,8BADY,SAAS,aAAa,EAIjC;IAGD,gCADY,SAAS,aAAa,EAIjC;IA5nBD,cA+BC;IA3ID,gCAEC;IAED,qBAAiB;IACjB,uBAAmB;IAiBnB,kBAHW,SAAS,gBAAgB,0BAuFnC;IAxDG,aAAiD;IA6DnD,OADW,CAAC,CACoB;IAEhC;;MAAmC;IAEnC,oBADW,GAAG,CAAC,CAAC,EAAE,EAAE,gBAAgB,gBAAW,EAAE,KAAK,eAAU,KAAK,IAAI,CAAC,CACvC;IAEnC;;MAA8B;IAC9B,kBAAwB;IAExB,qBAAwB;IAExB,sBAAyB;IAEzB,wBAA0B;IAE1B,0BAA6B;IAI7B,iBAAoB;IAEpB,6BAAgC;IAEhC,mBAAsB;IAEtB,4BAA8B;IAE9B,kBAAqB;IAIvB,yBAEC;IAGD,sBASC;IAGD,4BAKC;IAGD,6BAEC;IAuDD,IALuB,CAAC,SAAX,MAAO,CAAE,QACX,CAAC,WACD,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,wBAuC/B;IAGD,2BAIC;IAGD,uBAIC;IAQD,IALuB,CAAC,SAAX,MAAO,CAAE,qBAEX,CAAC,CAAC,CAAC,CAAC,2BAOd;IAMD,UAHW,OAAO,CAAC,CAAC,CAAC,2BAOpB;IAGD,SADc,CAAC,CA6Bd;IAMD,YAHW,OAAO,CAAC,CAAC,CAAC,mCAcpB;IAED,8BAgBC;IAdG,4CASE;IAmFF,0BAAwC;IAwB1C,uBAAyB;IAG3B,0BAqBC;IA4BD,wBAAoB;IAUpB,yBAAuB;IACvB,6BA8BC;IA+CD,oEAeC;IAMD,yDAoBC;IAYD,0BAME;IAMF,0CAFW,GAAG,QAgBb;IAED,yBAGC;IAOD,8EAmBC;;CA+BF;;mBAhyBkB,aAAa;qBAEX,iBAAiB;2BACX,iBAAiB"}
|
package/types/core/html.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../core/html.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../core/html.js"],"names":[],"mappings":"AAiDA,qBALa,CAAC,SACH,oBAAoB,YACpB,CAAC;QAAO,MAAM;CAAS,GAAG,cAAc,YAAY,CAAC,CAAC,EAAE,UA8BlE;AAxED,kCADW,QAAQ,CAOjB;;6BA+BY,MAAM,CAAC,MAAM,qCAAgC,SAAS"}
|
|
@@ -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,
|
|
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,QA2LX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"itemizeProcessor.d.ts","sourceRoot":"","sources":["../../core/itemizeProcessor.js"],"names":[],"mappings":"AASA,iCAJgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,
|
|
1
|
+
{"version":3,"file":"itemizeProcessor.d.ts","sourceRoot":"","sources":["../../core/itemizeProcessor.js"],"names":[],"mappings":"AASA,iCAJgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,QA4DX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"itemizeSetup.d.ts","sourceRoot":"","sources":["../../core/itemizeSetup.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"itemizeSetup.d.ts","sourceRoot":"","sources":["../../core/itemizeSetup.js"],"names":[],"mappings":"AAuBA,6BALgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC,WACD,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,QAoE3C;;QAnFa,OAAO;eACP,GAAC;mBACD,MAAM;eACN,OAAO;YACP,OAAO"}
|
|
@@ -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":";0BAmIgD,CAAC,SAApC,qCAAkC,MACpC,gBAAgB,SAChB,CAAC;;iCAjIqB,uBAAuB"}
|
package/types/node/SSR.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SSR.d.ts","sourceRoot":"","sources":["../../node/SSR.js"],"names":[],"mappings":"AAsSA;IAEE,8BAAmB;IACnB,8BAAmB;IAMnB;;;
|
|
1
|
+
{"version":3,"file":"SSR.d.ts","sourceRoot":"","sources":["../../node/SSR.js"],"names":[],"mappings":"AAsSA;IAEE,8BAAmB;IACnB,8BAAmB;IAMnB;;;OA2FC;IAMD,uBAYC;IAkBD,yBAZW,MAAM,YACN;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAChB,OAAO,CAAC,MAAM,CAAC,CAgC3B;IAWD,+BALW,MAAM;;iBAEN;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAChB,MAAM,CAwBlB;IAWD,+BALW,MAAM;;iBAEN;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAChB,cAAc,CAAC,MAAM,CAAC,CAqBlC;CACF"}
|