fix(build): verify radix dismissable layer patch

This commit is contained in:
777genius 2026-05-25 22:32:44 +03:00
parent b0b2fa2d13
commit 63cbce7d78
3 changed files with 107 additions and 11 deletions

View file

@ -439,7 +439,8 @@
],
"patchedDependencies": {
"@radix-ui/react-presence@1.1.5": "patches/@radix-ui__react-presence@1.1.5.patch",
"@radix-ui/react-focus-scope@1.1.7": "patches/@radix-ui__react-focus-scope@1.1.7.patch"
"@radix-ui/react-focus-scope@1.1.7": "patches/@radix-ui__react-focus-scope@1.1.7.patch",
"@radix-ui/react-dismissable-layer@1.1.11": "patches/@radix-ui__react-dismissable-layer@1.1.11.patch"
}
},
"knip": {

View file

@ -0,0 +1,70 @@
diff --git a/dist/index.js b/dist/index.js
--- a/dist/index.js
+++ b/dist/index.js
@@ -71,9 +71,30 @@ var DismissableLayer = React.forwardRef(
} = props;
const context = React.useContext(DismissableLayerContext);
const [node, setNode] = React.useState(null);
+ const nodeRef = React.useRef(null);
+ const nodeCleanupGenerationRef = React.useRef(0);
const ownerDocument = node?.ownerDocument ?? globalThis?.document;
const [, force] = React.useState({});
- const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node2) => setNode(node2));
+ const setNodeRef = React.useCallback((node2) => {
+ const syncNode = (nextNode) => {
+ if (nodeRef.current === nextNode) return;
+ nodeRef.current = nextNode;
+ setNode(nextNode);
+ };
+ nodeCleanupGenerationRef.current += 1;
+ const cleanupGeneration = nodeCleanupGenerationRef.current;
+ if (node2) {
+ syncNode(node2);
+ return;
+ }
+ queueMicrotask(() => {
+ if (nodeCleanupGenerationRef.current !== cleanupGeneration) {
+ return;
+ }
+ syncNode(null);
+ });
+ }, []);
+ const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, setNodeRef);
const layers = Array.from(context.layers);
const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1);
const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled);
diff --git a/dist/index.mjs b/dist/index.mjs
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -33,9 +33,30 @@ var DismissableLayer = React.forwardRef(
} = props;
const context = React.useContext(DismissableLayerContext);
const [node, setNode] = React.useState(null);
+ const nodeRef = React.useRef(null);
+ const nodeCleanupGenerationRef = React.useRef(0);
const ownerDocument = node?.ownerDocument ?? globalThis?.document;
const [, force] = React.useState({});
- const composedRefs = useComposedRefs(forwardedRef, (node2) => setNode(node2));
+ const setNodeRef = React.useCallback((node2) => {
+ const syncNode = (nextNode) => {
+ if (nodeRef.current === nextNode) return;
+ nodeRef.current = nextNode;
+ setNode(nextNode);
+ };
+ nodeCleanupGenerationRef.current += 1;
+ const cleanupGeneration = nodeCleanupGenerationRef.current;
+ if (node2) {
+ syncNode(node2);
+ return;
+ }
+ queueMicrotask(() => {
+ if (nodeCleanupGenerationRef.current !== cleanupGeneration) {
+ return;
+ }
+ syncNode(null);
+ });
+ }, []);
+ const composedRefs = useComposedRefs(forwardedRef, setNodeRef);
const layers = Array.from(context.layers);
const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1);
const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled);

View file

@ -4,26 +4,51 @@ import { dirname, join } from 'node:path';
const require = createRequire(import.meta.url);
const entrypointPath = require.resolve('@radix-ui/react-presence');
const packageRoot = dirname(dirname(entrypointPath));
const filesToCheck = ['dist/index.js', 'dist/index.mjs'];
const patchChecks = [
{
packageName: '@radix-ui/react-presence',
requiredMarkers: ['nodeCleanupGenerationRef', 'syncNode(null)'],
},
{
packageName: '@radix-ui/react-focus-scope',
resolverFromPackage: '@radix-ui/react-dialog',
requiredMarkers: ['containerCleanupGenerationRef', 'syncContainer(null)'],
},
{
packageName: '@radix-ui/react-dismissable-layer',
resolverFromPackage: '@radix-ui/react-dialog',
requiredMarkers: ['nodeCleanupGenerationRef', 'syncNode(null)'],
},
];
function resolvePackageRoot({ packageName, resolverFromPackage }) {
const packageRequire = resolverFromPackage
? createRequire(require.resolve(resolverFromPackage))
: require;
const entrypointPath = packageRequire.resolve(packageName);
return dirname(dirname(entrypointPath));
}
const requiredMarkers = ['nodeCleanupGenerationRef', 'syncNode(null)'];
const missing = [];
for (const relativePath of filesToCheck) {
const filePath = join(packageRoot, relativePath);
const source = readFileSync(filePath, 'utf8');
const missingMarkers = requiredMarkers.filter((marker) => !source.includes(marker));
if (missingMarkers.length > 0) {
missing.push(`${relativePath}: ${missingMarkers.join(', ')}`);
for (const check of patchChecks) {
const packageRoot = resolvePackageRoot(check);
for (const relativePath of filesToCheck) {
const filePath = join(packageRoot, relativePath);
const source = readFileSync(filePath, 'utf8');
const missingMarkers = check.requiredMarkers.filter((marker) => !source.includes(marker));
if (missingMarkers.length > 0) {
missing.push(`${check.packageName}/${relativePath}: ${missingMarkers.join(', ')}`);
}
}
}
if (missing.length > 0) {
console.error(
[
'@radix-ui/react-presence is installed without the local React 19 Presence patch.',
'Radix is installed without one or more local React 19 ref-cleanup patches.',
'Run `pnpm install --force` before building production artifacts.',
'',
...missing,