-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[fix] 'render' export uses ReactDOM.createRoot
AppRegistry.runApplication uses `ReactDOM.createRoot` by default, but the `render` export uses the legacy `ReactDOM.render`. This patch makes those 2 APIs consistent. It also makes some adjustments to the `createSheet` internals to more reliably implement and test style sheet replication within ShadowRoot's and iframes. Fix #2612
- Loading branch information
Showing
8 changed files
with
308 additions
and
110 deletions.
There are no files selected for viewing
160 changes: 123 additions & 37 deletions
160
packages/react-native-web-examples/pages/app-registry/index.js
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,137 @@ | ||
import React from 'react'; | ||
import { AppRegistry, Text, StyleSheet } from 'react-native'; | ||
import React, { useRef, useEffect, useState } from 'react'; | ||
import { Pressable, Text, StyleSheet, View, render } from 'react-native'; | ||
import Example from '../../shared/example'; | ||
|
||
function IframeWrapper({ children }) { | ||
const iframeHost = useRef(); | ||
const reactRoot = useRef(); | ||
|
||
useEffect(() => { | ||
if (iframeHost.current) { | ||
if (!reactRoot.current) { | ||
const iframeElement = iframeHost.current; | ||
const iframeAppContainer = document.createElement('div'); | ||
iframeElement.contentWindow.document.body.appendChild( | ||
iframeAppContainer | ||
); | ||
reactRoot.current = render(children, iframeAppContainer); | ||
} | ||
reactRoot.current.render(children); | ||
} | ||
}); | ||
|
||
return <iframe ref={iframeHost} style={{ border: 'none' }} />; | ||
} | ||
|
||
function ShadowDomWrapper({ children }) { | ||
const shadowHost = useRef(); | ||
const reactRoot = useRef(); | ||
|
||
useEffect(() => { | ||
if (shadowHost.current) { | ||
if (!reactRoot.current) { | ||
const shadowRoot = shadowHost.current.attachShadow({ mode: 'open' }); | ||
reactRoot.current = render(children, shadowRoot); | ||
} | ||
reactRoot.current.render(children); | ||
} | ||
}); | ||
|
||
return <div ref={shadowHost} />; | ||
} | ||
|
||
function Heading({ children }) { | ||
return ( | ||
<Text role="heading" style={styles.heading}> | ||
{children} | ||
</Text> | ||
); | ||
} | ||
|
||
function Button({ active, onPress, title }) { | ||
return ( | ||
<Pressable | ||
onPress={() => onPress((old) => !old)} | ||
style={[styles.button, active && styles.buttonActive]} | ||
> | ||
<Text style={styles.buttonText}>{title}</Text> | ||
</Pressable> | ||
); | ||
} | ||
|
||
function App() { | ||
return <Text style={styles.text}>Should be red and bold</Text>; | ||
const [active, setActive] = useState(false); | ||
const [activeIframe, setActiveIframe] = useState(false); | ||
const [activeShadow, setActiveShadow] = useState(false); | ||
|
||
return ( | ||
<Example title="AppRegistry"> | ||
<View style={styles.app}> | ||
<View style={styles.header}> | ||
<Heading>Styles in document</Heading> | ||
<Text style={styles.text}>Should be red and bold</Text> | ||
<Button active={active} onPress={setActive} title={'Button'} /> | ||
|
||
<Heading>Styles in ShadowRoot</Heading> | ||
<ShadowDomWrapper> | ||
<Text style={styles.text}>Should be red and bold</Text> | ||
<Button | ||
active={activeShadow} | ||
onPress={setActiveShadow} | ||
title={'Button'} | ||
/> | ||
</ShadowDomWrapper> | ||
|
||
<Heading>Styles in iframe</Heading> | ||
<IframeWrapper> | ||
<Text style={styles.text}>Should be red and bold</Text> | ||
<Button | ||
active={activeIframe} | ||
onPress={setActiveIframe} | ||
title={'Button'} | ||
/> | ||
</IframeWrapper> | ||
</View> | ||
</View> | ||
</Example> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
app: { | ||
marginHorizontal: 'auto', | ||
maxWidth: 500 | ||
}, | ||
header: { | ||
padding: 20 | ||
}, | ||
heading: { | ||
fontWeight: 'bold', | ||
fontSize: '1.125rem', | ||
marginBlockStart: '1rem', | ||
marginBlockEnd: '0.25rem' | ||
}, | ||
text: { | ||
color: 'red', | ||
fontWeight: 'bold' | ||
}, | ||
button: { | ||
backgroundColor: 'red', | ||
paddingBlock: 5, | ||
paddingInline: 10 | ||
}, | ||
buttonActive: { | ||
backgroundColor: 'blue' | ||
}, | ||
buttonText: { | ||
color: 'white', | ||
fontWeight: 'bold', | ||
textAlign: 'center', | ||
textTransform: 'uppercase', | ||
userSelect: 'none' | ||
} | ||
}); | ||
|
||
AppRegistry.registerComponent('App', () => App); | ||
|
||
export default function AppStatePage() { | ||
const iframeRef = React.useRef(null); | ||
const shadowRef = React.useRef(null); | ||
|
||
React.useEffect(() => { | ||
const iframeElement = iframeRef.current; | ||
const iframeBody = iframeElement.contentWindow.document.body; | ||
const iframeRootTag = document.createElement('div'); | ||
iframeRootTag.id = 'iframe-root'; | ||
iframeBody.appendChild(iframeRootTag); | ||
const app1 = AppRegistry.runApplication('App', { rootTag: iframeRootTag }); | ||
|
||
const shadowElement = shadowRef.current; | ||
const shadowRoot = shadowElement.attachShadow({ mode: 'open' }); | ||
const shadowRootTag = document.createElement('div'); | ||
shadowRootTag.id = 'shadow-root'; | ||
shadowRoot.appendChild(shadowRootTag); | ||
const app2 = AppRegistry.runApplication('App', { rootTag: shadowRootTag }); | ||
|
||
return () => { | ||
app1.unmount(); | ||
app2.unmount(); | ||
}; | ||
}, []); | ||
|
||
return ( | ||
<Example title="AppRegistry"> | ||
<Text>Styles in iframe</Text> | ||
<iframe ref={iframeRef} /> | ||
<Text>Styles in ShadowRoot</Text> | ||
<div ref={shadowRef} /> | ||
</Example> | ||
); | ||
return <App />; | ||
} |
101 changes: 101 additions & 0 deletions
101
packages/react-native-web/src/exports/AppRegistry/__tests__/__snapshots__/index-test.js.snap
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`AppRegistry runApplication styles roots in iframes: iframe css 1`] = ` | ||
"[stylesheet-group=\\"0\\"]{} | ||
body{margin:0;} | ||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;} | ||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);} | ||
input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;} | ||
[stylesheet-group=\\"1\\"]{} | ||
.css-view-175oi2r{align-items:stretch;background-color:rgba(0,0,0,0.00);border:0 solid black;box-sizing:border-box;display:flex;flex-basis:auto;flex-direction:column;flex-shrink:0;list-style:none;margin:0px;min-height:0px;min-width:0px;padding:0px;position:relative;text-decoration:none;z-index:0;} | ||
[stylesheet-group=\\"2\\"]{} | ||
.r-display-xoduu5{display:inline-flex;} | ||
.r-flex-13awgt0{flex:1;} | ||
[stylesheet-group=\\"3\\"]{} | ||
.r-bottom-1p0dtai{bottom:0px;} | ||
.r-left-1d2f490{left:0px;} | ||
.r-pointerEvents-105ug2t{pointer-events:auto!important;} | ||
.r-pointerEvents-12vffkv>*{pointer-events:auto;} | ||
.r-pointerEvents-12vffkv{pointer-events:none!important;} | ||
.r-pointerEvents-633pao{pointer-events:none!important;} | ||
.r-pointerEvents-ah5dr5>*{pointer-events:none;} | ||
.r-pointerEvents-ah5dr5{pointer-events:auto!important;} | ||
.r-position-u8s1d{position:absolute;} | ||
.r-right-zchlnj{right:0px;} | ||
.r-top-ipm5af{top:0px;}" | ||
`; | ||
|
||
exports[`AppRegistry runApplication styles roots in iframes: iframe css 2`] = ` | ||
"[stylesheet-group=\\"0\\"]{} | ||
body{margin:0;} | ||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;} | ||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);} | ||
input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;} | ||
[stylesheet-group=\\"1\\"]{} | ||
.css-view-175oi2r{align-items:stretch;background-color:rgba(0,0,0,0.00);border:0 solid black;box-sizing:border-box;display:flex;flex-basis:auto;flex-direction:column;flex-shrink:0;list-style:none;margin:0px;min-height:0px;min-width:0px;padding:0px;position:relative;text-decoration:none;z-index:0;} | ||
[stylesheet-group=\\"2\\"]{} | ||
.r-display-xoduu5{display:inline-flex;} | ||
.r-flex-13awgt0{flex:1;} | ||
[stylesheet-group=\\"3\\"]{} | ||
.r-bottom-1p0dtai{bottom:0px;} | ||
.r-left-1d2f490{left:0px;} | ||
.r-pointerEvents-105ug2t{pointer-events:auto!important;} | ||
.r-pointerEvents-12vffkv>*{pointer-events:auto;} | ||
.r-pointerEvents-12vffkv{pointer-events:none!important;} | ||
.r-pointerEvents-633pao{pointer-events:none!important;} | ||
.r-pointerEvents-ah5dr5>*{pointer-events:none;} | ||
.r-pointerEvents-ah5dr5{pointer-events:auto!important;} | ||
.r-position-u8s1d{position:absolute;} | ||
.r-right-zchlnj{right:0px;} | ||
.r-top-ipm5af{top:0px;}" | ||
`; | ||
|
||
exports[`AppRegistry runApplication styles roots in shadow trees: shadow dom css 1`] = ` | ||
"[stylesheet-group=\\"0\\"]{} | ||
body{margin:0;} | ||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;} | ||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);} | ||
input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;} | ||
[stylesheet-group=\\"1\\"]{} | ||
.css-view-175oi2r{align-items:stretch;background-color:rgba(0,0,0,0.00);border:0 solid black;box-sizing:border-box;display:flex;flex-basis:auto;flex-direction:column;flex-shrink:0;list-style:none;margin:0px;min-height:0px;min-width:0px;padding:0px;position:relative;text-decoration:none;z-index:0;} | ||
[stylesheet-group=\\"2\\"]{} | ||
.r-display-xoduu5{display:inline-flex;} | ||
.r-flex-13awgt0{flex:1;} | ||
[stylesheet-group=\\"3\\"]{} | ||
.r-bottom-1p0dtai{bottom:0px;} | ||
.r-left-1d2f490{left:0px;} | ||
.r-pointerEvents-105ug2t{pointer-events:auto!important;} | ||
.r-pointerEvents-12vffkv>*{pointer-events:auto;} | ||
.r-pointerEvents-12vffkv{pointer-events:none!important;} | ||
.r-pointerEvents-633pao{pointer-events:none!important;} | ||
.r-pointerEvents-ah5dr5>*{pointer-events:none;} | ||
.r-pointerEvents-ah5dr5{pointer-events:auto!important;} | ||
.r-position-u8s1d{position:absolute;} | ||
.r-right-zchlnj{right:0px;} | ||
.r-top-ipm5af{top:0px;}" | ||
`; | ||
|
||
exports[`AppRegistry runApplication styles roots in shadow trees: shadow dom css 2`] = ` | ||
"[stylesheet-group=\\"0\\"]{} | ||
body{margin:0;} | ||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;} | ||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);} | ||
input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;} | ||
[stylesheet-group=\\"1\\"]{} | ||
.css-view-175oi2r{align-items:stretch;background-color:rgba(0,0,0,0.00);border:0 solid black;box-sizing:border-box;display:flex;flex-basis:auto;flex-direction:column;flex-shrink:0;list-style:none;margin:0px;min-height:0px;min-width:0px;padding:0px;position:relative;text-decoration:none;z-index:0;} | ||
[stylesheet-group=\\"2\\"]{} | ||
.r-display-xoduu5{display:inline-flex;} | ||
.r-flex-13awgt0{flex:1;} | ||
[stylesheet-group=\\"3\\"]{} | ||
.r-bottom-1p0dtai{bottom:0px;} | ||
.r-left-1d2f490{left:0px;} | ||
.r-pointerEvents-105ug2t{pointer-events:auto!important;} | ||
.r-pointerEvents-12vffkv>*{pointer-events:auto;} | ||
.r-pointerEvents-12vffkv{pointer-events:none!important;} | ||
.r-pointerEvents-633pao{pointer-events:none!important;} | ||
.r-pointerEvents-ah5dr5>*{pointer-events:none;} | ||
.r-pointerEvents-ah5dr5{pointer-events:auto!important;} | ||
.r-position-u8s1d{position:absolute;} | ||
.r-right-zchlnj{right:0px;} | ||
.r-top-ipm5af{top:0px;}" | ||
`; |
This file contains 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
This file contains 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
Oops, something went wrong.