[change] initial example with media queries

This commit is contained in:
Nicolas Gallagher
2015-10-21 17:57:01 -07:00
parent ae2abc578a
commit a1664927ce
6 changed files with 350 additions and 205 deletions

198
examples/components/App.js Normal file
View File

@@ -0,0 +1,198 @@
import GridView from './GridView'
import Heading from './Heading'
import MediaQueryWidget from './MediaQueryWidget'
import React, { Image, StyleSheet, Text, TextInput, Touchable, View } from '../../src'
export default class App extends React.Component {
static propTypes = {
mediaQuery: React.PropTypes.object,
style: View.propTypes.style
}
render() {
const { mediaQuery } = this.props
const rootStyles = {
...(styles.root.common),
...(mediaQuery.small.matches && styles.root.mqSmall),
...(mediaQuery.large.matches && styles.root.mqLarge)
}
return (
<View accessibilityRole='main' style={rootStyles}>
<Heading size='xlarge'>React Native for Web</Heading>
<Text>React Native Web takes the core components from <Text
accessibilityRole='link' href='https://facebook.github.io/react-native/'>React
Native</Text> and brings them to the web. These components provide
simple building blocks touch handling, flexbox layout,
scroll views from which more complex components and apps can be
constructed.</Text>
<MediaQueryWidget mediaQuery={mediaQuery} />
<Heading size='large'>Image</Heading>
<Image
accessibilityLabel='accessible image'
children={<Text>Inner content</Text>}
defaultSource={{
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAIAAAAP3aGbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wkGESkdPWMDggAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAD5UlEQVR42u3UMQ0AAAgEMcC/x7eCCgaSVsIN10kK4IORADAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAswLAkAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAALi04UQW9HF910gAAAABJRU5ErkJggg=='
}}
onError={(e) => { console.log('Image.onError', e) }}
onLoad={(e) => { console.log('Image.onLoad', e) }}
onLoadEnd={() => { console.log('Image.onLoadEnd') }}
onLoadStart={() => { console.log('Image.onLoadStart') }}
resizeMode={'contain'}
source={{
height: 400,
uri: 'http://facebook.github.io/react/img/logo_og.png',
width: 400
}}
style={{
borderWidth: '5px'
}}
testID='Example.image'
/>
<Heading size='large'>Text</Heading>
<Text
onPress={(e) => { console.log('Text.onPress', e) }}
testID={'Example.text'}
>
PRESS ME.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel
lectus urna. Aliquam vitae justo porttitor, aliquam erat nec,
venenatis diam. Vivamus facilisis augue non urna mattis ultricies.
Suspendisse et vulputate enim, a maximus nulla. Vivamus imperdiet
hendrerit consequat. Aliquam lorem quam, elementum eget ex nec,
ultrices porttitor nibh. Nulla pellentesque urna leo, a aliquet elit
rhoncus a. Aenean ultricies, nunc a interdum dictum, dui odio
scelerisque mauris, a fringilla elit ligula vel sem. Sed vel aliquet
ipsum, sed rhoncus velit. Vivamus commodo pretium libero id placerat.
</Text>
<Text numberOfLines={1}>
TRUNCATED after 1 line.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel
lectus urna. Aliquam vitae justo porttitor, aliquam erat nec,
venenatis diam. Vivamus facilisis augue non urna mattis ultricies.
Suspendisse et vulputate enim, a maximus nulla. Vivamus imperdiet
hendrerit consequat.
</Text>
<Heading size='large'>TextInput</Heading>
<TextInput
keyboardType='default'
onBlur={(e) => { console.log('TextInput.onBlur', e) }}
onChange={(e) => { console.log('TextInput.onChange', e) }}
onChangeText={(e) => { console.log('TextInput.onChangeText', e) }}
onFocus={(e) => { console.log('TextInput.onFocus', e) }}
onSelectionChange={(e) => { console.log('TextInput.onSelectionChange', e) }}
/>
<TextInput secureTextEntry />
<TextInput defaultValue='read only' editable={false} />
<TextInput keyboardType='email-address' />
<TextInput keyboardType='numeric' />
<TextInput keyboardType='phone-pad' />
<TextInput keyboardType='url' selectTextOnFocus />
<TextInput
defaultValue='default value'
maxNumberOfLines={10}
multiline
numberOfLines={5}
/>
<Heading size='large'>Touchable</Heading>
<Touchable
accessibilityLabel={'Touchable element'}
activeHighlight='lightblue'
activeOpacity={0.8}
onLongPress={(e) => { console.log('Touchable.onLongPress', e) }}
onPress={(e) => { console.log('Touchable.onPress', e) }}
onPressIn={(e) => { console.log('Touchable.onPressIn', e) }}
onPressOut={(e) => { console.log('Touchable.onPressOut', e) }}
>
<View style={styles.touchableArea}>
<Text>Touchable area (press, long press)</Text>
</View>
</Touchable>
<Heading size='large'>View</Heading>
<Heading>Default layout</Heading>
<View>
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
return (
<View key={i} style={styles.box}>
<Text>{item}</Text>
</View>
)
})}
</View>
<Heading>Row layout</Heading>
<View style={styles.row}>
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
return (
<View key={i} style={styles.box}>
<Text>{item}</Text>
</View>
)
})}
</View>
<Heading>pointerEvents</Heading>
<GridView alley='10px'>
{['box-none', 'box-only', 'none'].map((value, i) => {
return (
<View
accessibilityRole='link'
children={value}
href='https://google.com'
key={i}
pointerEvents={value}
style={styles.pointerEventsBox}
/>
)
})}
</GridView>
</View>
)
}
}
const styles = StyleSheet.create({
root: {
common: {
margin: '0 auto'
},
mqSmall: {
maxWidth: '400px'
},
mqLarge: {
maxWidth: '600px'
}
},
row: {
flexDirection: 'row',
flexWrap: 'wrap'
},
box: {
alignItems: 'center',
flexGrow: 1,
justifyContent: 'center',
borderWidth: '1px'
},
boxFull: {
width: '100%'
},
pointerEventsBox: {
alignItems: 'center',
borderWidth: '1px',
flexGrow: 1,
height: '100px',
justifyContent: 'center'
},
touchableArea: {
alignItems: 'center',
borderWidth: 1,
height: '200px',
justifyContent: 'center'
}
})

View File

@@ -0,0 +1,67 @@
import React, { StyleSheet, View } from '../../src'
const { Component, PropTypes } = React
const styles = StyleSheet.create({
root: {
overflow: 'hidden'
},
contentContainer: {
flexDirection: 'row',
flexGrow: 1
},
// distribute all space (rather than extra space)
column: {
flexBasis: '0%'
}
})
export default class GridView extends Component {
static propTypes = {
alley: PropTypes.string,
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element)
]),
gutter: PropTypes.string,
style: PropTypes.object
}
static defaultProps = {
alley: '0',
gutter: '0'
}
render() {
const { alley, children, gutter, style, ...other } = this.props
const rootStyle = {
...style,
...styles.root
}
const contentContainerStyle = {
...styles.contentContainer,
margin: `0 calc(-0.5 * ${alley})`,
padding: `0 ${gutter}`
}
const newChildren = React.Children.map(children, (child) => {
return child && React.cloneElement(child, {
style: {
...child.props.style,
...styles.column,
margin: `0 calc(0.5 * ${alley})`
}
})
})
return (
<View className='GridView' {...other} style={rootStyle}>
<View style={contentContainerStyle}>
{newChildren}
</View>
</View>
)
}
}

View File

@@ -0,0 +1,31 @@
import React from 'react'
import { StyleSheet, Text } from '../../src'
const headingStyles = StyleSheet.create({
size: {
xlarge: {
fontSize: '2rem',
marginBottom: '1em'
},
large: {
fontSize: '1.5rem',
marginBottom: '1em',
marginTop: '1em'
},
normal: {
fontSize: '1.25rem',
marginBottom: '0.5em',
marginTop: '0.5em'
}
}
})
const Heading = ({ children, size = 'normal' }) => (
<Text
accessibilityRole='heading'
children={children}
style={headingStyles.size[size]}
/>
)
export default Heading

View File

@@ -0,0 +1,36 @@
import React, { StyleSheet, Text, View } from '../../src'
const styles = StyleSheet.create({
root: {
alignItems: 'center',
borderWidth: 1,
margin: '10px 0',
padding: 10,
textAlign: 'center'
},
heading: {
fontWeight: 'bold',
padding: 5
}
})
const MediaQueryWidget = ({ mediaQuery = {} }) => {
const active = Object.keys(mediaQuery).reduce((active, alias) => {
if (mediaQuery[alias].matches) {
active = {
alias,
mql: mediaQuery[alias]
}
}
return active
}, {})
return (
<View style={styles.root}>
<Text style={styles.heading}>Active Media Query</Text>
<Text>{`"${active.alias}"`} {active.mql.media}</Text>
</View>
)
}
export default MediaQueryWidget

View File

@@ -1,210 +1,22 @@
import React, { Image, StyleSheet, Text, TextInput, Touchable, View } from '../src'
import { MediaProvider, matchMedia } from 'react-media-queries'
import App from './components/App'
import createGetter from 'react-media-queries/lib/createMediaQueryGetter'
import createListener from 'react-media-queries/lib/createMediaQueryListener'
import React, { StyleSheet } from '../src'
import ReactDOM from 'react-dom'
const Heading = ({ children, size = 'normal' }) => (
<Text
accessibilityRole='heading'
children={children}
style={headingStyles.size[size]}
/>
const mediaQueries = {
small: '(min-width: 300px)',
medium: '(min-width: 400px)',
large: '(min-width: 500px)'
}
const ResponsiveApp = matchMedia()(App)
ReactDOM.render(
<MediaProvider getMedia={createGetter(mediaQueries)} listener={createListener(mediaQueries)}>
<ResponsiveApp />
</MediaProvider>,
document.getElementById('react-root')
)
const headingStyles = StyleSheet.create({
size: {
xlarge: {
fontSize: '2rem',
marginBottom: '1em'
},
large: {
fontSize: '1.5rem',
marginBottom: '1em',
marginTop: '1em'
},
normal: {
fontSize: '1.25rem',
marginBottom: '0.5em',
marginTop: '0.5em'
}
}
})
class Example extends React.Component {
static propTypes = {
style: View.propTypes.style
}
render() {
return (
<View accessibilityRole='main' style={styles.root}>
<Heading size='xlarge'>React Native Web</Heading>
<Text>React Native Web takes the core components from <Text
accessibilityRole='link' href='https://facebook.github.io/react-native/'>React
Native</Text> and brings them to the web. These components provide
simple building blocks touch handling, flexbox layout,
scroll views from which more complex components and apps can be
constructed.</Text>
<Heading size='large'>Image</Heading>
<Image
accessibilityLabel='accessible image'
children={<Text>Inner content</Text>}
defaultSource={{
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAIAAAAP3aGbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wkGESkdPWMDggAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAD5UlEQVR42u3UMQ0AAAgEMcC/x7eCCgaSVsIN10kK4IORADAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAswLAkAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAADAvAsADDAjAsAMMCDAvAsAAMCzAsAMMCMCzAsAAMC8CwAMMCMCzAsAAMC8CwAMMCMCwAwwIMC8CwAAwLMCwAwwIwLMCwAAwLwLAAwwIwLADDAgwLwLAADAswLADDAjAswLAALi04UQW9HF910gAAAABJRU5ErkJggg=='
}}
onError={(e) => { console.log('Image.onError', e) }}
onLoad={(e) => { console.log('Image.onLoad', e) }}
onLoadEnd={() => { console.log('Image.onLoadEnd') }}
onLoadStart={() => { console.log('Image.onLoadStart') }}
resizeMode={'contain'}
source={{
height: 400,
uri: 'http://facebook.github.io/react/img/logo_og.png',
width: 400
}}
style={{
borderWidth: '5px'
}}
testID='Example.image'
/>
<Heading size='large'>Text</Heading>
<Text
onPress={(e) => { console.log('Text.onPress', e) }}
testID={'Example.text'}
>
PRESS ME.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel
lectus urna. Aliquam vitae justo porttitor, aliquam erat nec,
venenatis diam. Vivamus facilisis augue non urna mattis ultricies.
Suspendisse et vulputate enim, a maximus nulla. Vivamus imperdiet
hendrerit consequat. Aliquam lorem quam, elementum eget ex nec,
ultrices porttitor nibh. Nulla pellentesque urna leo, a aliquet elit
rhoncus a. Aenean ultricies, nunc a interdum dictum, dui odio
scelerisque mauris, a fringilla elit ligula vel sem. Sed vel aliquet
ipsum, sed rhoncus velit. Vivamus commodo pretium libero id placerat.
</Text>
<Text numberOfLines={1}>
TRUNCATED after 1 line.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel
lectus urna. Aliquam vitae justo porttitor, aliquam erat nec,
venenatis diam. Vivamus facilisis augue non urna mattis ultricies.
Suspendisse et vulputate enim, a maximus nulla. Vivamus imperdiet
hendrerit consequat.
</Text>
<Heading size='large'>TextInput</Heading>
<TextInput
keyboardType='default'
onBlur={(e) => { console.log('TextInput.onBlur', e) }}
onChange={(e) => { console.log('TextInput.onChange', e) }}
onChangeText={(e) => { console.log('TextInput.onChangeText', e) }}
onFocus={(e) => { console.log('TextInput.onFocus', e) }}
onSelectionChange={(e) => { console.log('TextInput.onSelectionChange', e) }}
/>
<TextInput secureTextEntry />
<TextInput defaultValue='read only' editable={false} />
<TextInput keyboardType='email-address' />
<TextInput keyboardType='numeric' />
<TextInput keyboardType='phone-pad' />
<TextInput keyboardType='url' selectTextOnFocus />
<TextInput
defaultValue='default value'
maxNumberOfLines={10}
multiline
numberOfLines={5}
/>
<Heading size='large'>Touchable</Heading>
<Touchable
accessibilityLabel={'Touchable element'}
activeHighlight='lightblue'
activeOpacity={0.8}
onLongPress={(e) => { console.log('Touchable.onLongPress', e) }}
onPress={(e) => { console.log('Touchable.onPress', e) }}
onPressIn={(e) => { console.log('Touchable.onPressIn', e) }}
onPressOut={(e) => { console.log('Touchable.onPressOut', e) }}
>
<View style={styles.touchableArea}>
<Text>Touchable area (press, long press)</Text>
</View>
</Touchable>
<Heading size='large'>View</Heading>
<Heading>Default layout</Heading>
<View>
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
return (
<View key={i} style={styles.box}>
<Text>{item}</Text>
</View>
)
})}
</View>
<Heading>Row layout</Heading>
<View style={styles.row}>
{[ 1, 2, 3, 4, 5, 6 ].map((item, i) => {
return (
<View key={i} style={styles.box}>
<Text>{item}</Text>
</View>
)
})}
</View>
<Heading>pointerEvents</Heading>
<View style={styles.row}>
{['box-none', 'box-only', 'none'].map((value, i) => {
return (
<View
accessibilityRole='link'
children={value}
href='https://google.com'
key={i}
pointerEvents={value}
style={styles.pointerEventsBox}
/>
)
})}
</View>
</View>
)
}
}
const styles = StyleSheet.create({
root: {
maxWidth: '600px',
margin: '0 auto'
},
row: {
flexDirection: 'row',
flexWrap: 'wrap'
},
box: {
alignItems: 'center',
flexGrow: 1,
justifyContent: 'center',
borderWidth: '1px'
},
boxFull: {
width: '100%'
},
pointerEventsBox: {
alignItems: 'center',
borderWidth: '1px',
flexGrow: 1,
height: '100px',
justifyContent: 'center'
},
touchableArea: {
alignItems: 'center',
borderWidth: 1,
height: '200px',
justifyContent: 'center'
}
})
ReactDOM.render(<Example />, document.getElementById('react-root'))
document.getElementById('react-stylesheet').textContent = StyleSheet.renderToString()

View File

@@ -44,6 +44,7 @@
"react": "^0.14.0",
"react-addons-test-utils": "^0.14.0",
"react-dom": "^0.14.0",
"react-media-queries": "^2.0.0",
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.1"
},