@ape-egg/vibe 4.1.1 → 4.1.4
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 +1 -1
- package/package.json +1 -1
- package/runtime/cleanup.js +19 -37
- package/runtime/component.js +5 -1
- package/runtime/constants.js +1 -1
- package/runtime/hydrate.js +1 -1
- package/runtime/index.js +2 -17
- package/runtime/inert.js +18 -0
- package/runtime/vibe-css.js +1 -18
- package/vibe.css +0 -17
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vibe
|
|
2
2
|
|
|
3
|
-
**Version 4.1.
|
|
3
|
+
**Version 4.1.4** — Runtime-first reactivity for plain HTML. Drop a script tag into any page and get reactive bindings, control flow, and URL-loaded components — no build step required. Compile later if you want; the compiler is a separate, optional package (`@ape-egg/vibe-compiler`).
|
|
4
4
|
|
|
5
5
|
## Security model & CSP
|
|
6
6
|
|
package/package.json
CHANGED
package/runtime/cleanup.js
CHANGED
|
@@ -1,32 +1,24 @@
|
|
|
1
1
|
import { debugLog } from './debug.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
2
|
+
import { isInert } from './inert.js';
|
|
3
|
+
import { PHASE_READY, FOUC_CLASS_OR_ATTR } from './constants.js';
|
|
4
|
+
|
|
5
|
+
const skipInert = (root) => ({
|
|
6
|
+
acceptNode: (node) => (isInert(node, root) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT),
|
|
7
|
+
});
|
|
8
8
|
|
|
9
9
|
export const shouldCleanup = (rootElement) => {
|
|
10
|
-
const componentElements =
|
|
10
|
+
const componentElements = [
|
|
11
|
+
...rootElement.querySelectorAll('component[src], div.component[src]'),
|
|
12
|
+
].filter((el) => !isInert(el, rootElement));
|
|
11
13
|
if (componentElements.length > 0) {
|
|
12
14
|
return false;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
const walker = document.createTreeWalker(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return NodeFilter.FILTER_REJECT;
|
|
21
|
-
}
|
|
22
|
-
if (parent.hasAttribute(DEHYDRATE_CLASS_OR_ATTR) || parent.classList?.contains(DEHYDRATE_CLASS_OR_ATTR)) {
|
|
23
|
-
return NodeFilter.FILTER_REJECT;
|
|
24
|
-
}
|
|
25
|
-
parent = parent.parentElement;
|
|
26
|
-
}
|
|
27
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
28
|
-
},
|
|
29
|
-
});
|
|
17
|
+
const walker = document.createTreeWalker(
|
|
18
|
+
rootElement,
|
|
19
|
+
NodeFilter.SHOW_TEXT,
|
|
20
|
+
skipInert(rootElement),
|
|
21
|
+
);
|
|
30
22
|
|
|
31
23
|
let node;
|
|
32
24
|
while ((node = walker.nextNode())) {
|
|
@@ -35,21 +27,11 @@ export const shouldCleanup = (rootElement) => {
|
|
|
35
27
|
}
|
|
36
28
|
}
|
|
37
29
|
|
|
38
|
-
const elementWalker = document.createTreeWalker(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return NodeFilter.FILTER_REJECT;
|
|
44
|
-
}
|
|
45
|
-
if (parent.hasAttribute(DEHYDRATE_CLASS_OR_ATTR) || parent.classList?.contains(DEHYDRATE_CLASS_OR_ATTR)) {
|
|
46
|
-
return NodeFilter.FILTER_REJECT;
|
|
47
|
-
}
|
|
48
|
-
parent = parent.parentElement;
|
|
49
|
-
}
|
|
50
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
51
|
-
},
|
|
52
|
-
});
|
|
30
|
+
const elementWalker = document.createTreeWalker(
|
|
31
|
+
rootElement,
|
|
32
|
+
NodeFilter.SHOW_ELEMENT,
|
|
33
|
+
skipInert(rootElement),
|
|
34
|
+
);
|
|
53
35
|
|
|
54
36
|
let el;
|
|
55
37
|
while ((el = elementWalker.nextNode())) {
|
package/runtime/component.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { debugLog } from './debug.js';
|
|
2
2
|
import { shouldCleanup } from './cleanup.js';
|
|
3
|
+
import { isInert } from './inert.js';
|
|
3
4
|
import {
|
|
4
5
|
PHASE_FETCH,
|
|
5
6
|
PHASE_FETCH_CACHED,
|
|
@@ -665,7 +666,10 @@ export const processComponent = (rootElement, onComplete, config = {}) => {
|
|
|
665
666
|
}
|
|
666
667
|
|
|
667
668
|
const topLevel = Array.from(allComponents).filter(
|
|
668
|
-
(el) =>
|
|
669
|
+
(el) =>
|
|
670
|
+
!hasUnresolvedSrc(el) &&
|
|
671
|
+
!isInert(el, rootElement) &&
|
|
672
|
+
!isNestedInUnprocessedComponent(el, rootElement)
|
|
669
673
|
);
|
|
670
674
|
|
|
671
675
|
if (topLevel.length === 0) {
|
package/runtime/constants.js
CHANGED
package/runtime/hydrate.js
CHANGED
|
@@ -240,13 +240,13 @@ export default (affected, state, manifest = {}, oldState = {}) => {
|
|
|
240
240
|
if (evaluated instanceof RawHtml && isPureBinding &&
|
|
241
241
|
(element._vibeRawHtml || element.childNodes.length === 1)) {
|
|
242
242
|
const html = evaluated.html;
|
|
243
|
+
element._vibeRawHtml = true;
|
|
243
244
|
if (element._vibeRawHtmlValue !== html) {
|
|
244
245
|
element.innerHTML = html;
|
|
245
246
|
for (const child of element.children) managedNodes.add(child);
|
|
246
247
|
markBoundValues(element, html);
|
|
247
248
|
element._vibeRawHtmlValue = html;
|
|
248
249
|
}
|
|
249
|
-
element._vibeRawHtml = true;
|
|
250
250
|
if (aff.binding?._sub) aff.binding._sub.anchor = element;
|
|
251
251
|
return;
|
|
252
252
|
}
|
package/runtime/index.js
CHANGED
|
@@ -8,9 +8,9 @@ import { unsafe } from './raw-html.js';
|
|
|
8
8
|
import { renderAllIterations, setRenderAllConditionals, releaseOrphanedIterationProps } from './iterate.js';
|
|
9
9
|
import { renderAllConditionals, branchNodeRegistry, managedNodes , settleConditionals} from './conditionals.js';
|
|
10
10
|
import { installScopeResolver } from './loop-scope.js';
|
|
11
|
+
import { isInert } from './inert.js';
|
|
11
12
|
import {
|
|
12
13
|
VERSION,
|
|
13
|
-
NON_REACTIVE_ELEMENTS,
|
|
14
14
|
PHASE_ATTACH,
|
|
15
15
|
PHASE_PARSE,
|
|
16
16
|
PHASE_MANIFEST,
|
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
PHASE_MUTATE,
|
|
23
23
|
PHASE_HYPERSPEED,
|
|
24
24
|
PHASE_READY,
|
|
25
|
-
DEHYDRATE_CLASS_OR_ATTR,
|
|
26
25
|
} from './constants.js';
|
|
27
26
|
import { processComponent, abortComponentFetch, collectComponentIds, releaseOrphanedComponentState, renderComponentTemplate, executeCompiledComponentScripts } from './component.js';
|
|
28
27
|
import { configureComponentCache, clearComponentCache } from './component-cache.js';
|
|
@@ -57,21 +56,7 @@ const shouldProcessNode = (node) => {
|
|
|
57
56
|
return false;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
while (current && current !== document.body) {
|
|
62
|
-
if (NON_REACTIVE_ELEMENTS.includes(current.nodeName)) {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
if (
|
|
66
|
-
current.hasAttribute?.(DEHYDRATE_CLASS_OR_ATTR) ||
|
|
67
|
-
current.classList?.contains(DEHYDRATE_CLASS_OR_ATTR)
|
|
68
|
-
) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
current = current.parentElement;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return true;
|
|
59
|
+
return !isInert(node);
|
|
75
60
|
};
|
|
76
61
|
|
|
77
62
|
const navigateTree = (tree, path) => {
|
package/runtime/inert.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NON_REACTIVE_ELEMENTS, DEHYDRATE_CLASS_OR_ATTR } from './constants.js';
|
|
2
|
+
|
|
3
|
+
const opaque = (node) =>
|
|
4
|
+
NON_REACTIVE_ELEMENTS.includes(node.nodeName) ||
|
|
5
|
+
node.hasAttribute?.(DEHYDRATE_CLASS_OR_ATTR) ||
|
|
6
|
+
node.classList?.contains(DEHYDRATE_CLASS_OR_ATTR);
|
|
7
|
+
|
|
8
|
+
export const isInert = (node, root = document.body) => {
|
|
9
|
+
if (opaque(node)) return true;
|
|
10
|
+
|
|
11
|
+
let current = node.parentElement;
|
|
12
|
+
while (current && current !== root) {
|
|
13
|
+
if (opaque(current) || current._vibeRawHtml) return true;
|
|
14
|
+
current = current.parentElement;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return false;
|
|
18
|
+
};
|
package/runtime/vibe-css.js
CHANGED
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
export const COVER_CSS =
|
|
2
|
-
* these themselves (linking vibe.css is not required for correctness).
|
|
3
|
-
*
|
|
4
|
-
* [vibe-fouc] covers the page until hydration completes: visibility: hidden
|
|
5
|
-
* receives no pointer events, so authored on* handlers cannot fire before
|
|
6
|
-
* boot rewrites them. Animations too, not just transitions: visibility:
|
|
7
|
-
* hidden does not pause CSS animations — a covered element still animates
|
|
8
|
-
* and still fires animationend, reaching inline handlers before the module
|
|
9
|
-
* chain defines them. Suppressed under the cover, entrance animations
|
|
10
|
-
* instead play on reveal, matching what the user actually sees.
|
|
11
|
-
*
|
|
12
|
-
* [vibe-staged]: a route/key remount stages the incoming wrapper as a hidden
|
|
13
|
-
* sibling of the outgoing page until the commit swaps them in one paint. */
|
|
14
|
-
[vibe-fouc], .vibe-fouc { visibility: hidden }
|
|
1
|
+
export const COVER_CSS = `[vibe-fouc], .vibe-fouc { visibility: hidden }
|
|
15
2
|
[vibe-staged] { display: none }
|
|
16
3
|
[vibe-fouc], .vibe-fouc, [vibe-fouc] *, .vibe-fouc * { transition: none !important; animation: none !important }`;
|
|
17
4
|
|
|
@@ -19,10 +6,6 @@ export const OPTIONAL_MARKER = '/* vibe:optional — everything below is skipped
|
|
|
19
6
|
|
|
20
7
|
export const LAYOUT_CSS = `${OPTIONAL_MARKER}
|
|
21
8
|
|
|
22
|
-
/* Component wrappers are layout-transparent: children render as if the
|
|
23
|
-
* wrapper doesn't exist. ([vibe-dehydrate] needs no rules — it is a marker
|
|
24
|
-
* attribute/class telling the runtime to skip processing, for literal @[…]
|
|
25
|
-
* syntax in docs and code samples.) */
|
|
26
9
|
component, div.component, slot, div.slot { display: contents }`;
|
|
27
10
|
|
|
28
11
|
const inject = (doc, marker, css) => {
|
package/vibe.css
CHANGED
|
@@ -1,24 +1,7 @@
|
|
|
1
|
-
/* Load-bearing pre-boot rules — the runtime, vite plugin and compiler inject
|
|
2
|
-
* these themselves (linking vibe.css is not required for correctness).
|
|
3
|
-
*
|
|
4
|
-
* [vibe-fouc] covers the page until hydration completes: visibility: hidden
|
|
5
|
-
* receives no pointer events, so authored on* handlers cannot fire before
|
|
6
|
-
* boot rewrites them. Animations too, not just transitions: visibility:
|
|
7
|
-
* hidden does not pause CSS animations — a covered element still animates
|
|
8
|
-
* and still fires animationend, reaching inline handlers before the module
|
|
9
|
-
* chain defines them. Suppressed under the cover, entrance animations
|
|
10
|
-
* instead play on reveal, matching what the user actually sees.
|
|
11
|
-
*
|
|
12
|
-
* [vibe-staged]: a route/key remount stages the incoming wrapper as a hidden
|
|
13
|
-
* sibling of the outgoing page until the commit swaps them in one paint. */
|
|
14
1
|
[vibe-fouc], .vibe-fouc { visibility: hidden }
|
|
15
2
|
[vibe-staged] { display: none }
|
|
16
3
|
[vibe-fouc], .vibe-fouc, [vibe-fouc] *, .vibe-fouc * { transition: none !important; animation: none !important }
|
|
17
4
|
|
|
18
5
|
/* vibe:optional — everything below is skipped by disableVibeCss */
|
|
19
6
|
|
|
20
|
-
/* Component wrappers are layout-transparent: children render as if the
|
|
21
|
-
* wrapper doesn't exist. ([vibe-dehydrate] needs no rules — it is a marker
|
|
22
|
-
* attribute/class telling the runtime to skip processing, for literal @[…]
|
|
23
|
-
* syntax in docs and code samples.) */
|
|
24
7
|
component, div.component, slot, div.slot { display: contents }
|