Skip to content

Commit 78ba6bd

Browse files
yaminyassinYamin Yassin
andauthored
Adopt React Native 0.82 DOM Node APIs (#475)
* Adopt React Native 0.82 DOM Node APIs 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. * Bump example apps to Expo SDK 55 / React Native 0.83 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. * Update CHANGELOG for React Native 0.82 adoption * Use prototype delegation in useStrictDOMElement RN 0.82 settled the DOM Node prototype hierarchy, so we can stop cloning the host node. Object.create(node) makes the raw node the wrapper's prototype; strict-dom defines its overrides on top; everything else falls through. Symbol-keyed internals like INSTANCE_HANDLE_KEY stay reachable through the chain, so RN's prototype methods work when called on the wrapper. Changes vs the previous clone: * No descriptor snapshot. Reads stay in sync with the node. * No try/catch fallback. defineProperty on a fresh object can't fail in normal use. * getBoundingClientRect and the length getters only install when viewportScale isn't 1. Scale 1 skips them. * nodeName is a value descriptor now, since tagName.toUpperCase() doesn't change for a given wrapper. * writable: true removed from the value descriptors. DOM spec is read-only for nodeName, getBoundingClientRect and setSelectionRange, so strict-mode assignments throw now. * configurable: true on every override. instanceof still works: the chain is one link longer (wrapper to node to ReactNativeElement.prototype) but the class prototype is still on it. Ten tests in html-refs-test.native.js pass. * Aligned RN & React versions across packages & updated changelog --------- Co-authored-by: Yamin Yassin <Yamin.Yassin+CAG@cagtechhub.com>
1 parent bbe0ece commit 78ba6bd

13 files changed

Lines changed: 1905 additions & 2078 deletions

File tree

apps/expo-app/app.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
"resizeMode": "contain",
1313
"backgroundColor": "#ffffff"
1414
},
15-
"assetBundlePatterns": ["**/*"],
15+
"assetBundlePatterns": [
16+
"**/*"
17+
],
1618
"android": {
1719
"adaptiveIcon": {
1820
"foregroundImage": "./assets/adaptive-icon.png",
@@ -25,6 +27,9 @@
2527
"web": {
2628
"bundler": "metro",
2729
"favicon": "./assets/favicon.png"
28-
}
30+
},
31+
"plugins": [
32+
"expo-build-properties"
33+
]
2934
}
3035
}

apps/expo-app/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
"dev:web": "expo start --web --clear"
1111
},
1212
"dependencies": {
13-
"@expo/metro-runtime": "~5.0.4",
13+
"@expo/metro-runtime": "~55.0.11",
1414
"example-ui": "0.0.55",
15-
"expo": "^53.0.11",
16-
"expo-build-properties": "~0.14.6",
17-
"expo-status-bar": "~2.2.3",
18-
"react": "~19.0.0",
19-
"react-dom": "~19.0.0",
20-
"react-native": "~0.79.5",
21-
"react-native-web": "~0.20.0",
15+
"expo": "^55.0.0",
16+
"expo-build-properties": "~55.0.13",
17+
"expo-status-bar": "~55.0.6",
18+
"react": "19.2.0",
19+
"react-dom": "19.2.0",
20+
"react-native": "0.83.6",
21+
"react-native-web": "^0.21.0",
2222
"react-strict-dom": "0.0.55"
2323
},
2424
"devDependencies": {

apps/platform-tests/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
"dev:web": "expo start --web --clear"
1111
},
1212
"dependencies": {
13-
"@expo/metro-runtime": "~5.0.4",
14-
"expo": "^53.0.11",
15-
"expo-build-properties": "~0.14.6",
16-
"expo-status-bar": "~2.2.3",
17-
"react": "~19.0.0",
18-
"react-dom": "~19.0.0",
19-
"react-native": "~0.79.5",
20-
"react-native-web": "~0.20.0",
13+
"@expo/metro-runtime": "~55.0.11",
14+
"expo": "^55.0.0",
15+
"expo-build-properties": "~55.0.13",
16+
"expo-status-bar": "~55.0.6",
17+
"react": "19.2.0",
18+
"react-dom": "19.2.0",
19+
"react-native": "0.83.6",
20+
"react-native-web": "^0.21.0",
2121
"react-strict-dom": "0.0.55"
2222
},
2323
"devDependencies": {

0 commit comments

Comments
 (0)