Adopt React Native 0.82 DOM Node APIs#475
Open
yaminyassin wants to merge 3 commits into
Open
Conversation
added 3 commits
May 12, 2026 23:20
Bump the react-native peer dependency to >=0.82.0 and rewrite useStrictDOMElement to wrap the underlying RN host node in a thin Proxy instead of cloning it via Object.create / Object.defineProperties. React Native 0.82 shipped the stable DOM Node APIs that strict-dom helped drive into RN (DOM traversal, ownerDocument, getRootNode, children/childNodes, pointer-capture methods, etc.), so the native ref polyfill becomes a lightweight overlay rather than a parallel implementation. The Proxy traps only the keys strict-dom still needs to control: - nodeName: uppercase DOM name (RN exposes tagName as 'RN:View') - getBoundingClientRect and length getters: divided by the active viewportScale - <img>.complete: fallback to false when the underlying RN Image node does not expose it - <input>/<textarea> selection trio (setSelectionRange, selectionStart, selectionEnd): polyfilled on top of setSelection while RN's TextInput lacks the W3C selection API Everything else (ownerDocument, getRootNode, parentNode, children, childNodes, sibling navigation, pointer-capture, legacy measure*) forwards directly to the underlying RN node via Reflect.get. Function values are bound to the target so internal `this`-references inside RN's implementations resolve correctly. Identity caching via a WeakMap<Node, Proxy> is preserved so the same underlying RN node always yields the same wrapped ref. The selection polyfill is gated on the underlying property being absent, so the day RN exposes the W3C selection API on TextInput the polyfill self-disables. RN 0.83 also tightened the Flow types around Animated.createAnimatedComponent (now a single-type-arg generic) and made ImageProps / TextInputProps exact. The Animated factory call sites are updated to the new signature; the wide-spread of strict-dom's ReactNativeProps onto the exact host components is suppressed with targeted $FlowFixMe annotations (real follow-up tracked separately). Adds 10 ref tests in tests/html/html-refs-test.native.js documenting the contract: uppercase nodeName, getBoundingClientRect pass-through at scale=1, getBoundingClientRect scaled when viewportScale != 1, the DOM Node API pass-through (ownerDocument / getRootNode / childNodes / children), identity stability of the strict ref across renders, and the <img>.complete fallback (both when omitted and when provided). Bundle size: native/index.js drops ~363 minified / ~69 brotli bytes. Web build is byte-identical.
Bring apps/expo-app and apps/platform-tests onto a real RN >=0.82.0 runtime so they exercise the new useStrictDOMElement Proxy path against the DOM Node APIs from the previous commit. Note: there is no Expo SDK that pairs exactly with RN 0.82 (SDK 53 = RN 0.79, SDK 54 ~= RN 0.81, SDK 55 = RN 0.83). SDK 55 / RN 0.83.6 still satisfies the library's >=0.82.0 peer dep and ships the same DOM Node API surface, so it is the closest landing zone. Co-traveling dependency versions (@expo/metro-runtime, expo-build-properties, expo-status-bar, react-native-web, etc.) come from `npx expo install --check` for SDK 55; no hand-rolled versions. Also pin react / react-dom / react-test-renderer to ~19.2.0 across the workspace root and the two library packages' devDependencies. RN 0.82+ requires React >=19.1.1, and aligning the workspace devDeps avoids a multiple-React-instances error in the jest suite that would otherwise surface once the apps hoist React 19.2.x at the root.
Author
|
Related follow-up: #477: switches strict-dom from the deep import |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bumps
react-nativepeer dependency to>=0.82.0and rewritesuseStrictDOMElementto wrap the underlying RN host node in a thinProxyinstead of cloning it viaObject.create/Object.defineProperties. React Native 0.82 ships the stable DOM Node APIs (DOM traversal,ownerDocument,getRootNode,children/childNodes, pointer-capture, etc.) that strict-dom helped drive into RN — adopting them as the substrate turns the native ref polyfill into a lightweight overlay.Tracks discussion #462.
What's still polyfilled
The Proxy traps only the keys strict-dom still needs to control:
nodeName→ uppercase DOM name (RN exposestagNameas'RN:View')getBoundingClientRect+ length getters → divided by the activeviewportScale<img>.complete→ fallback tofalsewhen the underlying RN Image node doesn't expose it<input>/<textarea>setSelectionRange/selectionStart/selectionEnd→ polyfilled on top ofsetSelection. Self-disables the day RN exposes the W3C selection API.What now passes through to the RN node
ownerDocument,getRootNode,parentNode,parentElement,children,childNodes, sibling navigation,contains,compareDocumentPosition,setPointerCapture/hasPointerCapture/releasePointerCapture, and legacymeasure/measureInWindow/measureLayout/setNativeProps. The Proxy forwards function values bound to the underlying target so internalthis-references inside RN's implementations resolve correctly.[[GetPrototypeOf]]and Symbol reads forward by default —instanceofkeeps working.Identity caching via a
WeakMap<Node, Proxy>is preserved so the same RN node always yields the same wrapped ref.Breaking
Peer dep
react-native >=0.79.5→>=0.82.0. Apps on older RN must stay on the previous react-strict-dom release.Bundle size impact
dist/native/index.jsdrops −363 bytes minified / −69 bytes brotli. Web build is byte-identical. Other bundles unchanged.Perf benchmarks (
css.create,css.createTheme) move within ±2% — noise. Those benchmarks don't exercise the ref path, so they confirm the unrelated style system didn't regress.Notes for reviewers
>=19.1.1. The workspace root and library packages' devDependencies pinreact/react-dom/react-test-rendererto~19.2.0to keep a single React instance across the monorepo.Animated.createAnimatedComponentis now a single-type-arg generic — fixed properly by dropping the over-specified two-type-arg form.ImageProps/TextInputPropsbecame exact; the wide-spread of strict-dom'sReactNativePropsonto those hosts is covered with two targeted$FlowFixMeannotations. Properly narrowing the spread is a real follow-up.tests/html/html-refs-test.native.jspin every Proxy behavior: nodeName uppercase,getBoundingClientRectpass-through and scaled, DOM Node API pass-through (ownerDocument/getRootNode/childNodes/children), strict-ref identity stability, and<img>.completefallback / pass-through.