@pyreon/runtime-dom 0.12.13 → 0.12.14
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 +13 -0
- package/lib/analysis/index.js.html +1 -1
- package/lib/index.js +62 -10
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +12 -6
- package/src/hydrate.ts +35 -5
- package/src/mount.ts +8 -2
- package/src/props.ts +43 -3
- package/src/tests/callback-ref-unmount.browser.test.ts +62 -0
- package/src/tests/callback-ref-unmount.test.ts +52 -0
- package/src/tests/dev-gate-pattern.test.ts +40 -0
- package/src/tests/dev-gate-treeshake.test.ts +262 -0
- package/src/tests/mount.test.ts +6 -5
- package/src/tests/runtime-dom.browser.test.ts +295 -0
- package/src/tests/ssr-xss-round-trip.browser.test.ts +93 -0
- package/src/tests/style-key-removal.browser.test.ts +54 -0
- package/src/tests/style-key-removal.test.ts +88 -0
- package/src/tests/transition-timeout-leak.test.ts +81 -0
- package/src/tests/verified-correct-probes.test.ts +56 -0
- package/src/transition.ts +20 -2
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":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"684913b0-1","name":"delegate.ts"},{"uid":"684913b0-3","name":"hydration-debug.ts"},{"uid":"684913b0-5","name":"devtools.ts"},{"uid":"684913b0-7","name":"nodes.ts"},{"uid":"684913b0-9","name":"props.ts"},{"uid":"684913b0-11","name":"mount.ts"},{"uid":"684913b0-13","name":"hydrate.ts"},{"uid":"684913b0-15","name":"keep-alive.ts"},{"uid":"684913b0-17","name":"template.ts"},{"uid":"684913b0-19","name":"transition.ts"},{"uid":"684913b0-21","name":"transition-group.ts"},{"uid":"684913b0-23","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"684913b0-1":{"renderedLength":1990,"gzipLength":976,"brotliLength":0,"metaUid":"684913b0-0"},"684913b0-3":{"renderedLength":662,"gzipLength":370,"brotliLength":0,"metaUid":"684913b0-2"},"684913b0-5":{"renderedLength":6803,"gzipLength":2095,"brotliLength":0,"metaUid":"684913b0-4"},"684913b0-7":{"renderedLength":16207,"gzipLength":4334,"brotliLength":0,"metaUid":"684913b0-6"},"684913b0-9":{"renderedLength":6783,"gzipLength":2530,"brotliLength":0,"metaUid":"684913b0-8"},"684913b0-11":{"renderedLength":11649,"gzipLength":3717,"brotliLength":0,"metaUid":"684913b0-10"},"684913b0-13":{"renderedLength":8239,"gzipLength":2455,"brotliLength":0,"metaUid":"684913b0-12"},"684913b0-15":{"renderedLength":1473,"gzipLength":701,"brotliLength":0,"metaUid":"684913b0-14"},"684913b0-17":{"renderedLength":5319,"gzipLength":2069,"brotliLength":0,"metaUid":"684913b0-16"},"684913b0-19":{"renderedLength":4384,"gzipLength":1356,"brotliLength":0,"metaUid":"684913b0-18"},"684913b0-21":{"renderedLength":6362,"gzipLength":1937,"brotliLength":0,"metaUid":"684913b0-20"},"684913b0-23":{"renderedLength":769,"gzipLength":474,"brotliLength":0,"metaUid":"684913b0-22"}},"nodeMetas":{"684913b0-0":{"id":"/src/delegate.ts","moduleParts":{"index.js":"684913b0-1"},"imported":[{"uid":"684913b0-24"}],"importedBy":[{"uid":"684913b0-22"},{"uid":"684913b0-12"},{"uid":"684913b0-8"}]},"684913b0-2":{"id":"/src/hydration-debug.ts","moduleParts":{"index.js":"684913b0-3"},"imported":[],"importedBy":[{"uid":"684913b0-22"},{"uid":"684913b0-12"}]},"684913b0-4":{"id":"/src/devtools.ts","moduleParts":{"index.js":"684913b0-5"},"imported":[],"importedBy":[{"uid":"684913b0-22"},{"uid":"684913b0-10"}]},"684913b0-6":{"id":"/src/nodes.ts","moduleParts":{"index.js":"684913b0-7"},"imported":[{"uid":"684913b0-25"},{"uid":"684913b0-24"}],"importedBy":[{"uid":"684913b0-12"},{"uid":"684913b0-10"}]},"684913b0-8":{"id":"/src/props.ts","moduleParts":{"index.js":"684913b0-9"},"imported":[{"uid":"684913b0-25"},{"uid":"684913b0-24"},{"uid":"684913b0-0"}],"importedBy":[{"uid":"684913b0-22"},{"uid":"684913b0-12"},{"uid":"684913b0-10"}]},"684913b0-10":{"id":"/src/mount.ts","moduleParts":{"index.js":"684913b0-11"},"imported":[{"uid":"684913b0-25"},{"uid":"684913b0-24"},{"uid":"684913b0-4"},{"uid":"684913b0-6"},{"uid":"684913b0-8"}],"importedBy":[{"uid":"684913b0-22"},{"uid":"684913b0-12"},{"uid":"684913b0-14"},{"uid":"684913b0-16"},{"uid":"684913b0-20"}]},"684913b0-12":{"id":"/src/hydrate.ts","moduleParts":{"index.js":"684913b0-13"},"imported":[{"uid":"684913b0-25"},{"uid":"684913b0-24"},{"uid":"684913b0-0"},{"uid":"684913b0-2"},{"uid":"684913b0-10"},{"uid":"684913b0-6"},{"uid":"684913b0-8"}],"importedBy":[{"uid":"684913b0-22"}]},"684913b0-14":{"id":"/src/keep-alive.ts","moduleParts":{"index.js":"684913b0-15"},"imported":[{"uid":"684913b0-25"},{"uid":"684913b0-24"},{"uid":"684913b0-10"}],"importedBy":[{"uid":"684913b0-22"}]},"684913b0-16":{"id":"/src/template.ts","moduleParts":{"index.js":"684913b0-17"},"imported":[{"uid":"684913b0-24"},{"uid":"684913b0-10"}],"importedBy":[{"uid":"684913b0-22"}]},"684913b0-18":{"id":"/src/transition.ts","moduleParts":{"index.js":"684913b0-19"},"imported":[{"uid":"684913b0-25"},{"uid":"684913b0-24"}],"importedBy":[{"uid":"684913b0-22"}]},"684913b0-20":{"id":"/src/transition-group.ts","moduleParts":{"index.js":"684913b0-21"},"imported":[{"uid":"684913b0-25"},{"uid":"684913b0-24"},{"uid":"684913b0-10"}],"importedBy":[{"uid":"684913b0-22"}]},"684913b0-22":{"id":"/src/index.ts","moduleParts":{"index.js":"684913b0-23"},"imported":[{"uid":"684913b0-0"},{"uid":"684913b0-12"},{"uid":"684913b0-2"},{"uid":"684913b0-14"},{"uid":"684913b0-10"},{"uid":"684913b0-8"},{"uid":"684913b0-16"},{"uid":"684913b0-18"},{"uid":"684913b0-20"},{"uid":"684913b0-4"}],"importedBy":[],"isEntry":true},"684913b0-24":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"684913b0-0"},{"uid":"684913b0-12"},{"uid":"684913b0-14"},{"uid":"684913b0-10"},{"uid":"684913b0-8"},{"uid":"684913b0-16"},{"uid":"684913b0-18"},{"uid":"684913b0-20"},{"uid":"684913b0-6"}]},"684913b0-25":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"684913b0-12"},{"uid":"684913b0-14"},{"uid":"684913b0-10"},{"uid":"684913b0-8"},{"uid":"684913b0-18"},{"uid":"684913b0-20"},{"uid":"684913b0-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);
|
|
@@ -1019,15 +1019,36 @@ const URL_ATTRS = new Set([
|
|
|
1019
1019
|
"data"
|
|
1020
1020
|
]);
|
|
1021
1021
|
const UNSAFE_URL_RE = /^\s*(?:javascript|data):/i;
|
|
1022
|
+
const _prevStyleKeys = /* @__PURE__ */ new WeakMap();
|
|
1022
1023
|
/** Apply a style prop (string or object). */
|
|
1023
1024
|
function applyStyleProp(el, value) {
|
|
1024
|
-
if (typeof value === "string")
|
|
1025
|
-
|
|
1025
|
+
if (typeof value === "string") {
|
|
1026
|
+
el.style.cssText = value;
|
|
1027
|
+
_prevStyleKeys.delete(el);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
const prev = _prevStyleKeys.get(el);
|
|
1031
|
+
if (value == null) {
|
|
1032
|
+
if (prev) {
|
|
1033
|
+
for (const propName of prev) el.style.removeProperty(propName);
|
|
1034
|
+
_prevStyleKeys.delete(el);
|
|
1035
|
+
}
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
if (typeof value === "object") {
|
|
1026
1039
|
const obj = value;
|
|
1040
|
+
const next = /* @__PURE__ */ new Set();
|
|
1027
1041
|
for (const k in obj) {
|
|
1042
|
+
const propName = k.startsWith("--") ? k : toKebabCase(k);
|
|
1043
|
+
next.add(propName);
|
|
1028
1044
|
const css = normalizeStyleValue(k, obj[k]);
|
|
1029
|
-
el.style.setProperty(
|
|
1045
|
+
el.style.setProperty(propName, css);
|
|
1046
|
+
}
|
|
1047
|
+
if (prev) {
|
|
1048
|
+
for (const propName of prev) if (!next.has(propName)) el.style.removeProperty(propName);
|
|
1030
1049
|
}
|
|
1050
|
+
if (next.size === 0) _prevStyleKeys.delete(el);
|
|
1051
|
+
else _prevStyleKeys.set(el, next);
|
|
1031
1052
|
}
|
|
1032
1053
|
}
|
|
1033
1054
|
function applyClassProp(el, value) {
|
|
@@ -1299,13 +1320,15 @@ function mountElement(vnode, parent, anchor) {
|
|
|
1299
1320
|
};
|
|
1300
1321
|
const refToClean = ref;
|
|
1301
1322
|
return () => {
|
|
1302
|
-
if (refToClean
|
|
1323
|
+
if (refToClean) if (typeof refToClean === "function") refToClean(null);
|
|
1324
|
+
else refToClean.current = null;
|
|
1303
1325
|
if (propCleanup) propCleanup();
|
|
1304
1326
|
childCleanup();
|
|
1305
1327
|
};
|
|
1306
1328
|
}
|
|
1307
1329
|
return () => {
|
|
1308
|
-
if (ref
|
|
1330
|
+
if (ref) if (typeof ref === "function") ref(null);
|
|
1331
|
+
else ref.current = null;
|
|
1309
1332
|
if (propCleanup) propCleanup();
|
|
1310
1333
|
childCleanup();
|
|
1311
1334
|
const p = el.parentNode;
|
|
@@ -1500,7 +1523,9 @@ function hydrateReactiveChild(child, domNode, parent, anchor, path) {
|
|
|
1500
1523
|
const initial = runUntracked(child);
|
|
1501
1524
|
if (initial == null || initial === false) return [mountReactive(child, parent, insertMarker(parent, domNode, "pyreon"), mountChild), domNode];
|
|
1502
1525
|
if (typeof initial === "string" || typeof initial === "number" || typeof initial === "boolean") return hydrateReactiveText(child, domNode, parent, anchor, path);
|
|
1503
|
-
|
|
1526
|
+
const next = domNode ? nextReal(domNode) : null;
|
|
1527
|
+
if (domNode && domNode.parentNode) domNode.parentNode.removeChild(domNode);
|
|
1528
|
+
return [mountReactive(child, parent, insertMarker(parent, next, "pyreon"), mountChild), next];
|
|
1504
1529
|
}
|
|
1505
1530
|
/** Hydrate a reactive text binding against an existing text node. */
|
|
1506
1531
|
function hydrateReactiveText(child, domNode, parent, anchor, path) {
|
|
@@ -1543,6 +1568,18 @@ function hydrateChild(child, domNode, parent, anchor, path = "root") {
|
|
|
1543
1568
|
warnHydrationMismatch("text", "TextNode", domNode?.nodeType ?? "null", `${path} > text`);
|
|
1544
1569
|
return [mountChild(child, parent, anchor), domNode];
|
|
1545
1570
|
}
|
|
1571
|
+
if (child?.__isNative === true) {
|
|
1572
|
+
const native = child;
|
|
1573
|
+
const next = domNode ? nextReal(domNode) : null;
|
|
1574
|
+
if (domNode && domNode.parentNode) domNode.parentNode.replaceChild(native.el, domNode);
|
|
1575
|
+
else parent.insertBefore(native.el, anchor);
|
|
1576
|
+
const cleanup = () => {
|
|
1577
|
+
native.cleanup?.();
|
|
1578
|
+
const p = native.el.parentNode;
|
|
1579
|
+
if (p && p.isConnected !== false) p.removeChild(native.el);
|
|
1580
|
+
};
|
|
1581
|
+
return [cleanup, next];
|
|
1582
|
+
}
|
|
1546
1583
|
return hydrateVNode(child, domNode, parent, anchor, path);
|
|
1547
1584
|
}
|
|
1548
1585
|
function hydrateElement(vnode, domNode, parent, anchor, path = "root") {
|
|
@@ -1559,7 +1596,8 @@ function hydrateElement(vnode, domNode, parent, anchor, path = "root") {
|
|
|
1559
1596
|
if (ref) if (typeof ref === "function") ref(el);
|
|
1560
1597
|
else ref.current = el;
|
|
1561
1598
|
const cleanup = () => {
|
|
1562
|
-
if (ref
|
|
1599
|
+
if (ref) if (typeof ref === "function") ref(null);
|
|
1600
|
+
else ref.current = null;
|
|
1563
1601
|
for (const c of cleanups) c();
|
|
1564
1602
|
el.remove();
|
|
1565
1603
|
};
|
|
@@ -1917,15 +1955,20 @@ function Transition(props) {
|
|
|
1917
1955
|
requestAnimationFrame(() => {
|
|
1918
1956
|
el.classList.remove(cls.ef);
|
|
1919
1957
|
el.classList.add(cls.et);
|
|
1958
|
+
let safetyTimer = null;
|
|
1920
1959
|
const done = () => {
|
|
1921
1960
|
el.removeEventListener("transitionend", done);
|
|
1922
1961
|
el.removeEventListener("animationend", done);
|
|
1962
|
+
if (safetyTimer !== null) {
|
|
1963
|
+
clearTimeout(safetyTimer);
|
|
1964
|
+
safetyTimer = null;
|
|
1965
|
+
}
|
|
1923
1966
|
el.classList.remove(cls.ea, cls.et);
|
|
1924
1967
|
props.onAfterEnter?.(el);
|
|
1925
1968
|
};
|
|
1926
1969
|
el.addEventListener("transitionend", done, { once: true });
|
|
1927
1970
|
el.addEventListener("animationend", done, { once: true });
|
|
1928
|
-
setTimeout(done, 5e3);
|
|
1971
|
+
safetyTimer = setTimeout(done, 5e3);
|
|
1929
1972
|
});
|
|
1930
1973
|
};
|
|
1931
1974
|
const applyLeave = (el) => {
|
|
@@ -1935,9 +1978,14 @@ function Transition(props) {
|
|
|
1935
1978
|
requestAnimationFrame(() => {
|
|
1936
1979
|
el.classList.remove(cls.lf);
|
|
1937
1980
|
el.classList.add(cls.lt);
|
|
1981
|
+
let safetyTimer = null;
|
|
1938
1982
|
const done = () => {
|
|
1939
1983
|
el.removeEventListener("transitionend", done);
|
|
1940
1984
|
el.removeEventListener("animationend", done);
|
|
1985
|
+
if (safetyTimer !== null) {
|
|
1986
|
+
clearTimeout(safetyTimer);
|
|
1987
|
+
safetyTimer = null;
|
|
1988
|
+
}
|
|
1941
1989
|
el.classList.remove(cls.la, cls.lt);
|
|
1942
1990
|
pendingLeaveCancel = null;
|
|
1943
1991
|
isMounted.set(false);
|
|
@@ -1946,11 +1994,15 @@ function Transition(props) {
|
|
|
1946
1994
|
pendingLeaveCancel = () => {
|
|
1947
1995
|
el.removeEventListener("transitionend", done);
|
|
1948
1996
|
el.removeEventListener("animationend", done);
|
|
1997
|
+
if (safetyTimer !== null) {
|
|
1998
|
+
clearTimeout(safetyTimer);
|
|
1999
|
+
safetyTimer = null;
|
|
2000
|
+
}
|
|
1949
2001
|
el.classList.remove(cls.lf, cls.la, cls.lt);
|
|
1950
2002
|
};
|
|
1951
2003
|
el.addEventListener("transitionend", done, { once: true });
|
|
1952
2004
|
el.addEventListener("animationend", done, { once: true });
|
|
1953
|
-
setTimeout(done, 5e3);
|
|
2005
|
+
safetyTimer = setTimeout(done, 5e3);
|
|
1954
2006
|
});
|
|
1955
2007
|
};
|
|
1956
2008
|
const handleVisibilityChange = (visible) => {
|