@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Vibe
2
2
 
3
- **Version 4.1.1** — 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`).
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ape-egg/vibe",
3
- "version": "4.1.1",
3
+ "version": "4.1.4",
4
4
  "type": "module",
5
5
  "description": "Runtime-first reactivity for plain HTML — no build step, no virtual DOM, no new syntax to learn",
6
6
  "main": "index.js",
@@ -1,32 +1,24 @@
1
1
  import { debugLog } from './debug.js';
2
- import {
3
- PHASE_READY,
4
- FOUC_CLASS_OR_ATTR,
5
- DEHYDRATE_CLASS_OR_ATTR,
6
- NON_REACTIVE_ELEMENTS,
7
- } from './constants.js';
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 = rootElement.querySelectorAll('component[src], div.component[src]');
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(rootElement, NodeFilter.SHOW_TEXT, {
16
- acceptNode(node) {
17
- let parent = node.parentElement;
18
- while (parent && parent !== rootElement) {
19
- if (NON_REACTIVE_ELEMENTS.includes(parent.nodeName)) {
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(rootElement, NodeFilter.SHOW_ELEMENT, {
39
- acceptNode(el) {
40
- let parent = el;
41
- while (parent && parent !== rootElement) {
42
- if (NON_REACTIVE_ELEMENTS.includes(parent.nodeName)) {
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())) {
@@ -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) => !hasUnresolvedSrc(el) && !isNestedInUnprocessedComponent(el, rootElement)
669
+ (el) =>
670
+ !hasUnresolvedSrc(el) &&
671
+ !isInert(el, rootElement) &&
672
+ !isNestedInUnprocessedComponent(el, rootElement)
669
673
  );
670
674
 
671
675
  if (topLevel.length === 0) {
@@ -1,4 +1,4 @@
1
- export const VERSION = '4.1.1';
1
+ export const VERSION = '4.1.4';
2
2
 
3
3
  export const DEBUGGER_NAME = '[vibe-debug]:';
4
4
  export const FOUC_CLASS_OR_ATTR = 'vibe-fouc';
@@ -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
- let current = node;
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) => {
@@ -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
+ };
@@ -1,17 +1,4 @@
1
- export const COVER_CSS = `/* 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
- [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 }