@pyreon/runtime-dom 0.12.13 → 0.12.15

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
@@ -115,6 +115,19 @@ const App = () => (
115
115
 
116
116
  `TransitionProps`, `TransitionGroupProps`, `KeepAliveProps`, `SanitizeFn`, `DevtoolsComponentEntry`, `PyreonDevtools`
117
117
 
118
+ ## Dev-mode warnings — bundler tree-shake
119
+
120
+ Dev warnings are gated on `import.meta.env?.DEV`. Tree-shake behavior depends on both the source pattern and the consumer bundler:
121
+
122
+ | Source pattern | Vite prod | Raw esbuild prod | Test |
123
+ | --- | --- | --- | --- |
124
+ | `if (!import.meta.env?.DEV) return` (inline early-return) | tree-shaken | tree-shaken | `flow/src/tests/integration.test.ts` (esbuild) |
125
+ | `const __DEV__ = ...; if (__DEV__) ...` | tree-shaken | mostly tree-shaken | `runtime-dom/src/tests/dev-gate-treeshake.test.ts` (Vite) |
126
+ | `const __DEV__ = ...; __DEV__ && cond && warn(...)` (chained &&) | tree-shaken | runtime-gated only | `runtime-dom/.../dev-gate-treeshake.test.ts` (Vite + non-Vite runtime smoke) |
127
+ | `typeof process !== 'undefined'` | dead in browser | dead in browser | `pyreon/no-process-dev-gate` lint rule |
128
+
129
+ Vite is Pyreon's primary supported bundler. Non-Vite consumers (webpack, bunchee, raw esbuild) using the chained `&&` form may retain warning strings as data, but the runtime gate evaluates to `false` when `import.meta.env.DEV` is undefined — warnings don't fire. Only a small bundle-size cost.
130
+
118
131
  ## License
119
132
 
120
133
  MIT
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
5386
5386
  </script>
5387
5387
  <script>
5388
5388
  /*<!--*/
5389
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"7c7cfc97-1","name":"delegate.ts"},{"uid":"7c7cfc97-3","name":"hydration-debug.ts"},{"uid":"7c7cfc97-5","name":"devtools.ts"},{"uid":"7c7cfc97-7","name":"nodes.ts"},{"uid":"7c7cfc97-9","name":"props.ts"},{"uid":"7c7cfc97-11","name":"mount.ts"},{"uid":"7c7cfc97-13","name":"hydrate.ts"},{"uid":"7c7cfc97-15","name":"keep-alive.ts"},{"uid":"7c7cfc97-17","name":"template.ts"},{"uid":"7c7cfc97-19","name":"transition.ts"},{"uid":"7c7cfc97-21","name":"transition-group.ts"},{"uid":"7c7cfc97-23","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"7c7cfc97-1":{"renderedLength":1990,"gzipLength":976,"brotliLength":0,"metaUid":"7c7cfc97-0"},"7c7cfc97-3":{"renderedLength":662,"gzipLength":370,"brotliLength":0,"metaUid":"7c7cfc97-2"},"7c7cfc97-5":{"renderedLength":6803,"gzipLength":2095,"brotliLength":0,"metaUid":"7c7cfc97-4"},"7c7cfc97-7":{"renderedLength":16207,"gzipLength":4334,"brotliLength":0,"metaUid":"7c7cfc97-6"},"7c7cfc97-9":{"renderedLength":6209,"gzipLength":2371,"brotliLength":0,"metaUid":"7c7cfc97-8"},"7c7cfc97-11":{"renderedLength":11597,"gzipLength":3709,"brotliLength":0,"metaUid":"7c7cfc97-10"},"7c7cfc97-13":{"renderedLength":7694,"gzipLength":2333,"brotliLength":0,"metaUid":"7c7cfc97-12"},"7c7cfc97-15":{"renderedLength":1473,"gzipLength":701,"brotliLength":0,"metaUid":"7c7cfc97-14"},"7c7cfc97-17":{"renderedLength":5319,"gzipLength":2069,"brotliLength":0,"metaUid":"7c7cfc97-16"},"7c7cfc97-19":{"renderedLength":4017,"gzipLength":1311,"brotliLength":0,"metaUid":"7c7cfc97-18"},"7c7cfc97-21":{"renderedLength":6362,"gzipLength":1937,"brotliLength":0,"metaUid":"7c7cfc97-20"},"7c7cfc97-23":{"renderedLength":769,"gzipLength":474,"brotliLength":0,"metaUid":"7c7cfc97-22"}},"nodeMetas":{"7c7cfc97-0":{"id":"/src/delegate.ts","moduleParts":{"index.js":"7c7cfc97-1"},"imported":[{"uid":"7c7cfc97-24"}],"importedBy":[{"uid":"7c7cfc97-22"},{"uid":"7c7cfc97-12"},{"uid":"7c7cfc97-8"}]},"7c7cfc97-2":{"id":"/src/hydration-debug.ts","moduleParts":{"index.js":"7c7cfc97-3"},"imported":[],"importedBy":[{"uid":"7c7cfc97-22"},{"uid":"7c7cfc97-12"}]},"7c7cfc97-4":{"id":"/src/devtools.ts","moduleParts":{"index.js":"7c7cfc97-5"},"imported":[],"importedBy":[{"uid":"7c7cfc97-22"},{"uid":"7c7cfc97-10"}]},"7c7cfc97-6":{"id":"/src/nodes.ts","moduleParts":{"index.js":"7c7cfc97-7"},"imported":[{"uid":"7c7cfc97-25"},{"uid":"7c7cfc97-24"}],"importedBy":[{"uid":"7c7cfc97-12"},{"uid":"7c7cfc97-10"}]},"7c7cfc97-8":{"id":"/src/props.ts","moduleParts":{"index.js":"7c7cfc97-9"},"imported":[{"uid":"7c7cfc97-25"},{"uid":"7c7cfc97-24"},{"uid":"7c7cfc97-0"}],"importedBy":[{"uid":"7c7cfc97-22"},{"uid":"7c7cfc97-12"},{"uid":"7c7cfc97-10"}]},"7c7cfc97-10":{"id":"/src/mount.ts","moduleParts":{"index.js":"7c7cfc97-11"},"imported":[{"uid":"7c7cfc97-25"},{"uid":"7c7cfc97-24"},{"uid":"7c7cfc97-4"},{"uid":"7c7cfc97-6"},{"uid":"7c7cfc97-8"}],"importedBy":[{"uid":"7c7cfc97-22"},{"uid":"7c7cfc97-12"},{"uid":"7c7cfc97-14"},{"uid":"7c7cfc97-16"},{"uid":"7c7cfc97-20"}]},"7c7cfc97-12":{"id":"/src/hydrate.ts","moduleParts":{"index.js":"7c7cfc97-13"},"imported":[{"uid":"7c7cfc97-25"},{"uid":"7c7cfc97-24"},{"uid":"7c7cfc97-0"},{"uid":"7c7cfc97-2"},{"uid":"7c7cfc97-10"},{"uid":"7c7cfc97-6"},{"uid":"7c7cfc97-8"}],"importedBy":[{"uid":"7c7cfc97-22"}]},"7c7cfc97-14":{"id":"/src/keep-alive.ts","moduleParts":{"index.js":"7c7cfc97-15"},"imported":[{"uid":"7c7cfc97-25"},{"uid":"7c7cfc97-24"},{"uid":"7c7cfc97-10"}],"importedBy":[{"uid":"7c7cfc97-22"}]},"7c7cfc97-16":{"id":"/src/template.ts","moduleParts":{"index.js":"7c7cfc97-17"},"imported":[{"uid":"7c7cfc97-24"},{"uid":"7c7cfc97-10"}],"importedBy":[{"uid":"7c7cfc97-22"}]},"7c7cfc97-18":{"id":"/src/transition.ts","moduleParts":{"index.js":"7c7cfc97-19"},"imported":[{"uid":"7c7cfc97-25"},{"uid":"7c7cfc97-24"}],"importedBy":[{"uid":"7c7cfc97-22"}]},"7c7cfc97-20":{"id":"/src/transition-group.ts","moduleParts":{"index.js":"7c7cfc97-21"},"imported":[{"uid":"7c7cfc97-25"},{"uid":"7c7cfc97-24"},{"uid":"7c7cfc97-10"}],"importedBy":[{"uid":"7c7cfc97-22"}]},"7c7cfc97-22":{"id":"/src/index.ts","moduleParts":{"index.js":"7c7cfc97-23"},"imported":[{"uid":"7c7cfc97-0"},{"uid":"7c7cfc97-12"},{"uid":"7c7cfc97-2"},{"uid":"7c7cfc97-14"},{"uid":"7c7cfc97-10"},{"uid":"7c7cfc97-8"},{"uid":"7c7cfc97-16"},{"uid":"7c7cfc97-18"},{"uid":"7c7cfc97-20"},{"uid":"7c7cfc97-4"}],"importedBy":[],"isEntry":true},"7c7cfc97-24":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"7c7cfc97-0"},{"uid":"7c7cfc97-12"},{"uid":"7c7cfc97-14"},{"uid":"7c7cfc97-10"},{"uid":"7c7cfc97-8"},{"uid":"7c7cfc97-16"},{"uid":"7c7cfc97-18"},{"uid":"7c7cfc97-20"},{"uid":"7c7cfc97-6"}]},"7c7cfc97-25":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"7c7cfc97-12"},{"uid":"7c7cfc97-14"},{"uid":"7c7cfc97-10"},{"uid":"7c7cfc97-8"},{"uid":"7c7cfc97-18"},{"uid":"7c7cfc97-20"},{"uid":"7c7cfc97-6"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5389
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"391d1e60-1","name":"delegate.ts"},{"uid":"391d1e60-3","name":"hydration-debug.ts"},{"uid":"391d1e60-5","name":"devtools.ts"},{"uid":"391d1e60-7","name":"nodes.ts"},{"uid":"391d1e60-9","name":"props.ts"},{"uid":"391d1e60-11","name":"mount.ts"},{"uid":"391d1e60-13","name":"hydrate.ts"},{"uid":"391d1e60-15","name":"keep-alive.ts"},{"uid":"391d1e60-17","name":"template.ts"},{"uid":"391d1e60-19","name":"transition.ts"},{"uid":"391d1e60-21","name":"transition-group.ts"},{"uid":"391d1e60-23","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"391d1e60-1":{"renderedLength":1990,"gzipLength":976,"brotliLength":0,"metaUid":"391d1e60-0"},"391d1e60-3":{"renderedLength":662,"gzipLength":370,"brotliLength":0,"metaUid":"391d1e60-2"},"391d1e60-5":{"renderedLength":6803,"gzipLength":2095,"brotliLength":0,"metaUid":"391d1e60-4"},"391d1e60-7":{"renderedLength":16207,"gzipLength":4334,"brotliLength":0,"metaUid":"391d1e60-6"},"391d1e60-9":{"renderedLength":7947,"gzipLength":3020,"brotliLength":0,"metaUid":"391d1e60-8"},"391d1e60-11":{"renderedLength":11649,"gzipLength":3717,"brotliLength":0,"metaUid":"391d1e60-10"},"391d1e60-13":{"renderedLength":8239,"gzipLength":2455,"brotliLength":0,"metaUid":"391d1e60-12"},"391d1e60-15":{"renderedLength":1473,"gzipLength":701,"brotliLength":0,"metaUid":"391d1e60-14"},"391d1e60-17":{"renderedLength":5319,"gzipLength":2069,"brotliLength":0,"metaUid":"391d1e60-16"},"391d1e60-19":{"renderedLength":4895,"gzipLength":1390,"brotliLength":0,"metaUid":"391d1e60-18"},"391d1e60-21":{"renderedLength":7942,"gzipLength":2070,"brotliLength":0,"metaUid":"391d1e60-20"},"391d1e60-23":{"renderedLength":769,"gzipLength":474,"brotliLength":0,"metaUid":"391d1e60-22"}},"nodeMetas":{"391d1e60-0":{"id":"/src/delegate.ts","moduleParts":{"index.js":"391d1e60-1"},"imported":[{"uid":"391d1e60-24"}],"importedBy":[{"uid":"391d1e60-22"},{"uid":"391d1e60-12"},{"uid":"391d1e60-8"}]},"391d1e60-2":{"id":"/src/hydration-debug.ts","moduleParts":{"index.js":"391d1e60-3"},"imported":[],"importedBy":[{"uid":"391d1e60-22"},{"uid":"391d1e60-12"}]},"391d1e60-4":{"id":"/src/devtools.ts","moduleParts":{"index.js":"391d1e60-5"},"imported":[],"importedBy":[{"uid":"391d1e60-22"},{"uid":"391d1e60-10"}]},"391d1e60-6":{"id":"/src/nodes.ts","moduleParts":{"index.js":"391d1e60-7"},"imported":[{"uid":"391d1e60-25"},{"uid":"391d1e60-24"}],"importedBy":[{"uid":"391d1e60-12"},{"uid":"391d1e60-10"}]},"391d1e60-8":{"id":"/src/props.ts","moduleParts":{"index.js":"391d1e60-9"},"imported":[{"uid":"391d1e60-25"},{"uid":"391d1e60-24"},{"uid":"391d1e60-0"}],"importedBy":[{"uid":"391d1e60-22"},{"uid":"391d1e60-12"},{"uid":"391d1e60-10"}]},"391d1e60-10":{"id":"/src/mount.ts","moduleParts":{"index.js":"391d1e60-11"},"imported":[{"uid":"391d1e60-25"},{"uid":"391d1e60-24"},{"uid":"391d1e60-4"},{"uid":"391d1e60-6"},{"uid":"391d1e60-8"}],"importedBy":[{"uid":"391d1e60-22"},{"uid":"391d1e60-12"},{"uid":"391d1e60-14"},{"uid":"391d1e60-16"},{"uid":"391d1e60-20"}]},"391d1e60-12":{"id":"/src/hydrate.ts","moduleParts":{"index.js":"391d1e60-13"},"imported":[{"uid":"391d1e60-25"},{"uid":"391d1e60-24"},{"uid":"391d1e60-0"},{"uid":"391d1e60-2"},{"uid":"391d1e60-10"},{"uid":"391d1e60-6"},{"uid":"391d1e60-8"}],"importedBy":[{"uid":"391d1e60-22"}]},"391d1e60-14":{"id":"/src/keep-alive.ts","moduleParts":{"index.js":"391d1e60-15"},"imported":[{"uid":"391d1e60-25"},{"uid":"391d1e60-24"},{"uid":"391d1e60-10"}],"importedBy":[{"uid":"391d1e60-22"}]},"391d1e60-16":{"id":"/src/template.ts","moduleParts":{"index.js":"391d1e60-17"},"imported":[{"uid":"391d1e60-24"},{"uid":"391d1e60-10"}],"importedBy":[{"uid":"391d1e60-22"}]},"391d1e60-18":{"id":"/src/transition.ts","moduleParts":{"index.js":"391d1e60-19"},"imported":[{"uid":"391d1e60-25"},{"uid":"391d1e60-24"}],"importedBy":[{"uid":"391d1e60-22"}]},"391d1e60-20":{"id":"/src/transition-group.ts","moduleParts":{"index.js":"391d1e60-21"},"imported":[{"uid":"391d1e60-25"},{"uid":"391d1e60-24"},{"uid":"391d1e60-10"}],"importedBy":[{"uid":"391d1e60-22"}]},"391d1e60-22":{"id":"/src/index.ts","moduleParts":{"index.js":"391d1e60-23"},"imported":[{"uid":"391d1e60-0"},{"uid":"391d1e60-12"},{"uid":"391d1e60-2"},{"uid":"391d1e60-14"},{"uid":"391d1e60-10"},{"uid":"391d1e60-8"},{"uid":"391d1e60-16"},{"uid":"391d1e60-18"},{"uid":"391d1e60-20"},{"uid":"391d1e60-4"}],"importedBy":[],"isEntry":true},"391d1e60-24":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"391d1e60-0"},{"uid":"391d1e60-12"},{"uid":"391d1e60-14"},{"uid":"391d1e60-10"},{"uid":"391d1e60-8"},{"uid":"391d1e60-16"},{"uid":"391d1e60-18"},{"uid":"391d1e60-20"},{"uid":"391d1e60-6"}]},"391d1e60-25":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"391d1e60-12"},{"uid":"391d1e60-14"},{"uid":"391d1e60-10"},{"uid":"391d1e60-8"},{"uid":"391d1e60-18"},{"uid":"391d1e60-20"},{"uid":"391d1e60-6"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5390
5390
 
5391
5391
  const run = () => {
5392
5392
  const width = window.innerWidth;
package/lib/index.js CHANGED
@@ -981,7 +981,7 @@ function applyEventProp(el, key, value) {
981
981
  if (__DEV__$3 && value != null) console.warn(`[Pyreon] Event handler "${key}" received a non-function value (${typeof value}). Expected a function. Did you mean ${key}={() => ...}?`);
982
982
  return null;
983
983
  }
984
- const eventName = key[2]?.toLowerCase() + key.slice(3);
984
+ const eventName = (key[2]?.toLowerCase() + key.slice(3)).toLowerCase();
985
985
  const handler = value;
986
986
  if (DELEGATED_EVENTS.has(eventName)) {
987
987
  const prop = delegatedPropName(eventName);
@@ -994,19 +994,38 @@ function applyEventProp(el, key, value) {
994
994
  el.addEventListener(eventName, batched);
995
995
  return () => el.removeEventListener(eventName, batched);
996
996
  }
997
- function applyProp(el, key, value) {
998
- if (EVENT_RE.test(key)) return applyEventProp(el, key, value);
997
+ /**
998
+ * Sink for a single prop's CALLED value (always a primitive / object /
999
+ * `null` — never a function). Called both directly for static values and
1000
+ * from the reactive `renderEffect` for accessor-bound values.
1001
+ *
1002
+ * NOTE on architecture: extracting the special-cased sinks
1003
+ * (`innerHTML` / `dangerouslySetInnerHTML`) into this single dispatch
1004
+ * function ensures every prop kind goes through the same reactive
1005
+ * wrapping at `applyProp`'s entry. Previously each special case had its
1006
+ * own early-return branch that needed to remember to handle function
1007
+ * values; missing the dance once meant the closure was stringified and
1008
+ * set as literal text. The structural fix (one reactive-wrap, then
1009
+ * dispatch) eliminates the entire bug class.
1010
+ */
1011
+ function applyStaticProp(el, key, value) {
1012
+ if (__DEV__$3 && typeof value === "function") console.warn(`[Pyreon] applyStaticProp received a function for "${key}". This likely means a new special-cased prop sink in applyProp() bypassed the reactive-wrap path. The closure would be stringified and set as a literal value. Verify the dispatch in applyProp().`);
999
1013
  if (key === "innerHTML") {
1000
- if (typeof el.setHTML === "function") el.setHTML(value);
1001
- else el.innerHTML = sanitizeHtml(value);
1002
- return null;
1014
+ const html = String(value ?? "");
1015
+ if (typeof el.setHTML === "function") el.setHTML(html);
1016
+ else el.innerHTML = sanitizeHtml(html);
1017
+ return;
1003
1018
  }
1004
1019
  if (key === "dangerouslySetInnerHTML") {
1005
- el.innerHTML = value.__html;
1006
- return null;
1020
+ el.innerHTML = value?.__html ?? "";
1021
+ return;
1007
1022
  }
1008
- if (typeof value === "function") return renderEffect(() => setStaticProp(el, key, value()));
1009
1023
  setStaticProp(el, key, value);
1024
+ }
1025
+ function applyProp(el, key, value) {
1026
+ if (EVENT_RE.test(key)) return applyEventProp(el, key, value);
1027
+ if (typeof value === "function") return renderEffect(() => applyStaticProp(el, key, value()));
1028
+ applyStaticProp(el, key, value);
1010
1029
  return null;
1011
1030
  }
1012
1031
  const URL_ATTRS = new Set([
@@ -1019,15 +1038,36 @@ const URL_ATTRS = new Set([
1019
1038
  "data"
1020
1039
  ]);
1021
1040
  const UNSAFE_URL_RE = /^\s*(?:javascript|data):/i;
1041
+ const _prevStyleKeys = /* @__PURE__ */ new WeakMap();
1022
1042
  /** Apply a style prop (string or object). */
1023
1043
  function applyStyleProp(el, value) {
1024
- if (typeof value === "string") el.style.cssText = value;
1025
- else if (value != null && typeof value === "object") {
1044
+ if (typeof value === "string") {
1045
+ el.style.cssText = value;
1046
+ _prevStyleKeys.delete(el);
1047
+ return;
1048
+ }
1049
+ const prev = _prevStyleKeys.get(el);
1050
+ if (value == null) {
1051
+ if (prev) {
1052
+ for (const propName of prev) el.style.removeProperty(propName);
1053
+ _prevStyleKeys.delete(el);
1054
+ }
1055
+ return;
1056
+ }
1057
+ if (typeof value === "object") {
1026
1058
  const obj = value;
1059
+ const next = /* @__PURE__ */ new Set();
1027
1060
  for (const k in obj) {
1061
+ const propName = k.startsWith("--") ? k : toKebabCase(k);
1062
+ next.add(propName);
1028
1063
  const css = normalizeStyleValue(k, obj[k]);
1029
- el.style.setProperty(k.startsWith("--") ? k : toKebabCase(k), css);
1064
+ el.style.setProperty(propName, css);
1030
1065
  }
1066
+ if (prev) {
1067
+ for (const propName of prev) if (!next.has(propName)) el.style.removeProperty(propName);
1068
+ }
1069
+ if (next.size === 0) _prevStyleKeys.delete(el);
1070
+ else _prevStyleKeys.set(el, next);
1031
1071
  }
1032
1072
  }
1033
1073
  function applyClassProp(el, value) {
@@ -1299,13 +1339,15 @@ function mountElement(vnode, parent, anchor) {
1299
1339
  };
1300
1340
  const refToClean = ref;
1301
1341
  return () => {
1302
- if (refToClean && typeof refToClean === "object") refToClean.current = null;
1342
+ if (refToClean) if (typeof refToClean === "function") refToClean(null);
1343
+ else refToClean.current = null;
1303
1344
  if (propCleanup) propCleanup();
1304
1345
  childCleanup();
1305
1346
  };
1306
1347
  }
1307
1348
  return () => {
1308
- if (ref && typeof ref === "object") ref.current = null;
1349
+ if (ref) if (typeof ref === "function") ref(null);
1350
+ else ref.current = null;
1309
1351
  if (propCleanup) propCleanup();
1310
1352
  childCleanup();
1311
1353
  const p = el.parentNode;
@@ -1500,7 +1542,9 @@ function hydrateReactiveChild(child, domNode, parent, anchor, path) {
1500
1542
  const initial = runUntracked(child);
1501
1543
  if (initial == null || initial === false) return [mountReactive(child, parent, insertMarker(parent, domNode, "pyreon"), mountChild), domNode];
1502
1544
  if (typeof initial === "string" || typeof initial === "number" || typeof initial === "boolean") return hydrateReactiveText(child, domNode, parent, anchor, path);
1503
- return [mountReactive(child, parent, insertMarker(parent, domNode, "pyreon"), mountChild), domNode ? nextReal(domNode) : null];
1545
+ const next = domNode ? nextReal(domNode) : null;
1546
+ if (domNode && domNode.parentNode) domNode.parentNode.removeChild(domNode);
1547
+ return [mountReactive(child, parent, insertMarker(parent, next, "pyreon"), mountChild), next];
1504
1548
  }
1505
1549
  /** Hydrate a reactive text binding against an existing text node. */
1506
1550
  function hydrateReactiveText(child, domNode, parent, anchor, path) {
@@ -1543,6 +1587,18 @@ function hydrateChild(child, domNode, parent, anchor, path = "root") {
1543
1587
  warnHydrationMismatch("text", "TextNode", domNode?.nodeType ?? "null", `${path} > text`);
1544
1588
  return [mountChild(child, parent, anchor), domNode];
1545
1589
  }
1590
+ if (child?.__isNative === true) {
1591
+ const native = child;
1592
+ const next = domNode ? nextReal(domNode) : null;
1593
+ if (domNode && domNode.parentNode) domNode.parentNode.replaceChild(native.el, domNode);
1594
+ else parent.insertBefore(native.el, anchor);
1595
+ const cleanup = () => {
1596
+ native.cleanup?.();
1597
+ const p = native.el.parentNode;
1598
+ if (p && p.isConnected !== false) p.removeChild(native.el);
1599
+ };
1600
+ return [cleanup, next];
1601
+ }
1546
1602
  return hydrateVNode(child, domNode, parent, anchor, path);
1547
1603
  }
1548
1604
  function hydrateElement(vnode, domNode, parent, anchor, path = "root") {
@@ -1559,7 +1615,8 @@ function hydrateElement(vnode, domNode, parent, anchor, path = "root") {
1559
1615
  if (ref) if (typeof ref === "function") ref(el);
1560
1616
  else ref.current = el;
1561
1617
  const cleanup = () => {
1562
- if (ref && typeof ref === "object") ref.current = null;
1618
+ if (ref) if (typeof ref === "function") ref(null);
1619
+ else ref.current = null;
1563
1620
  for (const c of cleanups) c();
1564
1621
  el.remove();
1565
1622
  };
@@ -1906,38 +1963,63 @@ function Transition(props) {
1906
1963
  };
1907
1964
  const ref = createRef();
1908
1965
  const isMounted = signal(runUntracked(props.show));
1966
+ let pendingEnterCancel = null;
1909
1967
  let pendingLeaveCancel = null;
1910
1968
  let initialized = false;
1911
1969
  const applyEnter = (el) => {
1912
1970
  pendingLeaveCancel?.();
1913
1971
  pendingLeaveCancel = null;
1972
+ pendingEnterCancel?.();
1973
+ pendingEnterCancel = null;
1914
1974
  props.onBeforeEnter?.(el);
1915
1975
  el.classList.remove(cls.lf, cls.la, cls.lt);
1916
1976
  el.classList.add(cls.ef, cls.ea);
1917
1977
  requestAnimationFrame(() => {
1918
1978
  el.classList.remove(cls.ef);
1919
1979
  el.classList.add(cls.et);
1980
+ let safetyTimer = null;
1920
1981
  const done = () => {
1921
1982
  el.removeEventListener("transitionend", done);
1922
1983
  el.removeEventListener("animationend", done);
1984
+ if (safetyTimer !== null) {
1985
+ clearTimeout(safetyTimer);
1986
+ safetyTimer = null;
1987
+ }
1988
+ pendingEnterCancel = null;
1923
1989
  el.classList.remove(cls.ea, cls.et);
1924
1990
  props.onAfterEnter?.(el);
1925
1991
  };
1992
+ pendingEnterCancel = () => {
1993
+ el.removeEventListener("transitionend", done);
1994
+ el.removeEventListener("animationend", done);
1995
+ if (safetyTimer !== null) {
1996
+ clearTimeout(safetyTimer);
1997
+ safetyTimer = null;
1998
+ }
1999
+ el.classList.remove(cls.ef, cls.ea, cls.et);
2000
+ };
1926
2001
  el.addEventListener("transitionend", done, { once: true });
1927
2002
  el.addEventListener("animationend", done, { once: true });
1928
- setTimeout(done, 5e3);
2003
+ safetyTimer = setTimeout(done, 5e3);
1929
2004
  });
1930
2005
  };
1931
2006
  const applyLeave = (el) => {
2007
+ pendingEnterCancel?.();
2008
+ pendingEnterCancel = null;
1932
2009
  props.onBeforeLeave?.(el);
1933
2010
  el.classList.remove(cls.ef, cls.ea, cls.et);
1934
2011
  el.classList.add(cls.lf, cls.la);
1935
2012
  requestAnimationFrame(() => {
1936
2013
  el.classList.remove(cls.lf);
1937
2014
  el.classList.add(cls.lt);
2015
+ let safetyTimer = null;
1938
2016
  const done = () => {
1939
2017
  el.removeEventListener("transitionend", done);
1940
2018
  el.removeEventListener("animationend", done);
2019
+ if (safetyTimer !== null) {
2020
+ clearTimeout(safetyTimer);
2021
+ safetyTimer = null;
2022
+ }
1941
2023
  el.classList.remove(cls.la, cls.lt);
1942
2024
  pendingLeaveCancel = null;
1943
2025
  isMounted.set(false);
@@ -1946,11 +2028,15 @@ function Transition(props) {
1946
2028
  pendingLeaveCancel = () => {
1947
2029
  el.removeEventListener("transitionend", done);
1948
2030
  el.removeEventListener("animationend", done);
2031
+ if (safetyTimer !== null) {
2032
+ clearTimeout(safetyTimer);
2033
+ safetyTimer = null;
2034
+ }
1949
2035
  el.classList.remove(cls.lf, cls.la, cls.lt);
1950
2036
  };
1951
2037
  el.addEventListener("transitionend", done, { once: true });
1952
2038
  el.addEventListener("animationend", done, { once: true });
1953
- setTimeout(done, 5e3);
2039
+ safetyTimer = setTimeout(done, 5e3);
1954
2040
  });
1955
2041
  };
1956
2042
  const handleVisibilityChange = (visible) => {
@@ -1977,6 +2063,8 @@ function Transition(props) {
1977
2063
  handleVisibilityChange(visible);
1978
2064
  });
1979
2065
  onUnmount(() => {
2066
+ pendingEnterCancel?.();
2067
+ pendingEnterCancel = null;
1980
2068
  pendingLeaveCancel?.();
1981
2069
  pendingLeaveCancel = null;
1982
2070
  });
@@ -2043,39 +2131,71 @@ function TransitionGroup(props) {
2043
2131
  const entries = /* @__PURE__ */ new Map();
2044
2132
  const ready = signal(false);
2045
2133
  let firstRun = true;
2046
- const applyEnter = (el) => {
2134
+ const applyEnter = (entry, el) => {
2047
2135
  props.onBeforeEnter?.(el);
2048
2136
  el.classList.remove(cls.lf, cls.la, cls.lt);
2049
2137
  el.classList.add(cls.ef, cls.ea);
2050
2138
  requestAnimationFrame(() => {
2051
2139
  el.classList.remove(cls.ef);
2052
2140
  el.classList.add(cls.et);
2141
+ let safetyTimer = null;
2053
2142
  const done = () => {
2054
2143
  el.removeEventListener("transitionend", done);
2055
2144
  el.removeEventListener("animationend", done);
2145
+ if (safetyTimer !== null) {
2146
+ clearTimeout(safetyTimer);
2147
+ safetyTimer = null;
2148
+ }
2149
+ entry.cancelTransition = null;
2056
2150
  el.classList.remove(cls.ea, cls.et);
2057
2151
  props.onAfterEnter?.(el);
2058
2152
  };
2153
+ entry.cancelTransition = () => {
2154
+ el.removeEventListener("transitionend", done);
2155
+ el.removeEventListener("animationend", done);
2156
+ if (safetyTimer !== null) {
2157
+ clearTimeout(safetyTimer);
2158
+ safetyTimer = null;
2159
+ }
2160
+ el.classList.remove(cls.ef, cls.ea, cls.et);
2161
+ };
2059
2162
  el.addEventListener("transitionend", done, { once: true });
2060
2163
  el.addEventListener("animationend", done, { once: true });
2164
+ safetyTimer = setTimeout(done, 5e3);
2061
2165
  });
2062
2166
  };
2063
- const applyLeave = (el, onDone) => {
2167
+ const applyLeave = (entry, el, onDone) => {
2064
2168
  props.onBeforeLeave?.(el);
2065
2169
  el.classList.remove(cls.ef, cls.ea, cls.et);
2066
2170
  el.classList.add(cls.lf, cls.la);
2067
2171
  requestAnimationFrame(() => {
2068
2172
  el.classList.remove(cls.lf);
2069
2173
  el.classList.add(cls.lt);
2174
+ let safetyTimer = null;
2070
2175
  const done = () => {
2071
2176
  el.removeEventListener("transitionend", done);
2072
2177
  el.removeEventListener("animationend", done);
2178
+ if (safetyTimer !== null) {
2179
+ clearTimeout(safetyTimer);
2180
+ safetyTimer = null;
2181
+ }
2182
+ entry.cancelTransition = null;
2073
2183
  el.classList.remove(cls.la, cls.lt);
2074
2184
  props.onAfterLeave?.(el);
2075
2185
  onDone();
2076
2186
  };
2187
+ entry.cancelTransition = () => {
2188
+ el.removeEventListener("transitionend", done);
2189
+ el.removeEventListener("animationend", done);
2190
+ if (safetyTimer !== null) {
2191
+ clearTimeout(safetyTimer);
2192
+ safetyTimer = null;
2193
+ }
2194
+ el.classList.remove(cls.lf, cls.la, cls.lt);
2195
+ };
2077
2196
  el.addEventListener("transitionend", done, { once: true });
2078
2197
  el.addEventListener("animationend", done, { once: true });
2198
+ safetyTimer = setTimeout(done, 5e3);
2079
2199
  });
2080
2200
  };
2081
2201
  /** Start leave animation for removed items. */
@@ -2084,7 +2204,7 @@ function TransitionGroup(props) {
2084
2204
  if (newKeys.has(key) || entry.leaving) continue;
2085
2205
  entry.leaving = true;
2086
2206
  const el = entry.ref.current;
2087
- if (el) applyLeave(el, () => {
2207
+ if (el) applyLeave(entry, el, () => {
2088
2208
  entry.cleanup();
2089
2209
  entries.delete(key);
2090
2210
  });
@@ -2113,25 +2233,42 @@ function TransitionGroup(props) {
2113
2233
  ref: itemRef
2114
2234
  }
2115
2235
  } : rawVNode, container, null),
2116
- leaving: false
2236
+ leaving: false,
2237
+ cancelTransition: null
2117
2238
  };
2118
2239
  entries.set(key, entry);
2119
2240
  newEntries.push(entry);
2120
2241
  }
2121
2242
  return newEntries;
2122
2243
  };
2123
- const startMoveAnimation = (el) => {
2244
+ const startMoveAnimation = (entry, el) => {
2124
2245
  requestAnimationFrame(() => {
2125
2246
  el.classList.add(cls.mv);
2126
2247
  el.style.transform = "";
2127
2248
  el.style.transition = "";
2249
+ let safetyTimer = null;
2128
2250
  const done = () => {
2129
2251
  el.removeEventListener("transitionend", done);
2130
2252
  el.removeEventListener("animationend", done);
2253
+ if (safetyTimer !== null) {
2254
+ clearTimeout(safetyTimer);
2255
+ safetyTimer = null;
2256
+ }
2257
+ entry.cancelTransition = null;
2258
+ el.classList.remove(cls.mv);
2259
+ };
2260
+ entry.cancelTransition = () => {
2261
+ el.removeEventListener("transitionend", done);
2262
+ el.removeEventListener("animationend", done);
2263
+ if (safetyTimer !== null) {
2264
+ clearTimeout(safetyTimer);
2265
+ safetyTimer = null;
2266
+ }
2131
2267
  el.classList.remove(cls.mv);
2132
2268
  };
2133
2269
  el.addEventListener("transitionend", done, { once: true });
2134
2270
  el.addEventListener("animationend", done, { once: true });
2271
+ safetyTimer = setTimeout(done, 5e3);
2135
2272
  });
2136
2273
  };
2137
2274
  const flipEntry = (entry, oldPos) => {
@@ -2143,7 +2280,7 @@ function TransitionGroup(props) {
2143
2280
  const el = entry.ref.current;
2144
2281
  el.style.transform = `translate(${dx}px, ${dy}px)`;
2145
2282
  el.style.transition = "none";
2146
- startMoveAnimation(el);
2283
+ startMoveAnimation(entry, el);
2147
2284
  };
2148
2285
  /** Apply FLIP move animations for items that shifted position. */
2149
2286
  const applyFlipMoves = (oldPositions) => {
@@ -2171,7 +2308,7 @@ function TransitionGroup(props) {
2171
2308
  };
2172
2309
  const animateNewEntries = (newEntries) => {
2173
2310
  for (const entry of newEntries) queueMicrotask(() => {
2174
- if (entry.ref.current) applyEnter(entry.ref.current);
2311
+ if (entry.ref.current) applyEnter(entry, entry.ref.current);
2175
2312
  });
2176
2313
  };
2177
2314
  const e = effect(() => {
@@ -2194,7 +2331,11 @@ function TransitionGroup(props) {
2194
2331
  });
2195
2332
  onUnmount(() => {
2196
2333
  e.dispose();
2197
- for (const entry of entries.values()) entry.cleanup();
2334
+ for (const entry of entries.values()) {
2335
+ entry.cancelTransition?.();
2336
+ entry.cancelTransition = null;
2337
+ entry.cleanup();
2338
+ }
2198
2339
  entries.clear();
2199
2340
  });
2200
2341
  return h(tag, { ref: containerRef });