UNPKG

create-expo-cljs-app

Version:

Create a react native application with Expo and Shadow-CLJS!

669 lines (620 loc) 18.7 kB
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format * @flow */ 'use strict'; const React = require('react'); const { Animated, Image, StyleSheet, Text, TouchableHighlight, TouchableOpacity, Platform, TouchableNativeFeedback, TouchableWithoutFeedback, View, } = require('react-native'); import {useEffect, useRef, useState} from 'react'; const forceTouchAvailable = (Platform.OS === 'ios' && Platform.constants.forceTouchAvailable) || false; class TouchableHighlightBox extends React.Component<{...}, $FlowFixMeState> { state = { timesPressed: 0, }; touchableOnPress = () => { this.setState({ timesPressed: this.state.timesPressed + 1, }); }; render() { let textLog = ''; if (this.state.timesPressed > 1) { textLog = this.state.timesPressed + 'x TouchableHighlight onPress'; } else if (this.state.timesPressed > 0) { textLog = 'TouchableHighlight onPress'; } return ( <View> <View style={styles.row}> <TouchableHighlight style={styles.wrapper} testID="touchable_highlight_image_button" onPress={this.touchableOnPress}> <Image source={remoteImage} style={styles.image} /> </TouchableHighlight> <TouchableHighlight style={styles.wrapper} testID="touchable_highlight_text_button" activeOpacity={1} underlayColor="rgb(210, 230, 255)" onPress={this.touchableOnPress}> <View style={styles.wrapperCustom}> <Text style={styles.text}>Tap Here For Custom Highlight!</Text> </View> </TouchableHighlight> </View> <View style={styles.logBox}> <Text testID="touchable_highlight_console">{textLog}</Text> </View> </View> ); } } class TouchableWithoutFeedbackBox extends React.Component< {...}, $FlowFixMeState, > { state = { timesPressed: 0, }; textOnPress = () => { this.setState({ timesPressed: this.state.timesPressed + 1, }); }; render() { let textLog = ''; if (this.state.timesPressed > 1) { textLog = this.state.timesPressed + 'x TouchableWithoutFeedback onPress'; } else if (this.state.timesPressed > 0) { textLog = 'TouchableWithoutFeedback onPress'; } return ( <View> <TouchableWithoutFeedback onPress={this.textOnPress} testID="touchable_without_feedback_button"> <View style={styles.wrapperCustom}> <Text style={styles.text}>Tap Here For No Feedback!</Text> </View> </TouchableWithoutFeedback> <View style={styles.logBox}> <Text testID="touchable_without_feedback_console">{textLog}</Text> </View> </View> ); } } class TextOnPressBox extends React.Component<{...}, $FlowFixMeState> { state = { timesPressed: 0, }; textOnPress = () => { this.setState({ timesPressed: this.state.timesPressed + 1, }); }; render() { let textLog = ''; if (this.state.timesPressed > 1) { textLog = this.state.timesPressed + 'x text onPress'; } else if (this.state.timesPressed > 0) { textLog = 'text onPress'; } return ( <View> <Text style={styles.textBlock} testID="tappable_text" onPress={this.textOnPress}> Text has built-in onPress handling </Text> <View style={styles.logBox}> <Text testID="tappable_text_console">{textLog}</Text> </View> </View> ); } } class TouchableFeedbackEvents extends React.Component<{...}, $FlowFixMeState> { state = { eventLog: [], }; render() { return ( <View testID="touchable_feedback_events"> <View style={[styles.row, styles.centered]}> <TouchableOpacity style={styles.wrapper} testID="touchable_feedback_events_button" accessibilityLabel="touchable feedback events" accessibilityRole="button" onPress={() => this._appendEvent('press')} onPressIn={() => this._appendEvent('pressIn')} onPressOut={() => this._appendEvent('pressOut')} onLongPress={() => this._appendEvent('longPress')}> <Text style={styles.button}>Press Me</Text> </TouchableOpacity> </View> <View testID="touchable_feedback_events_console" style={styles.eventLogBox}> {this.state.eventLog.map((e, ii) => ( <Text key={ii}>{e}</Text> ))} </View> </View> ); } _appendEvent = eventName => { const limit = 6; const eventLog = this.state.eventLog.slice(0, limit - 1); eventLog.unshift(eventName); this.setState({eventLog}); }; } class TouchableDelayEvents extends React.Component<{...}, $FlowFixMeState> { state = { eventLog: [], }; render() { return ( <View testID="touchable_delay_events"> <View style={[styles.row, styles.centered]}> <TouchableOpacity style={styles.wrapper} testID="touchable_delay_events_button" onPress={() => this._appendEvent('press')} delayPressIn={400} onPressIn={() => this._appendEvent('pressIn - 400ms delay')} delayPressOut={1000} onPressOut={() => this._appendEvent('pressOut - 1000ms delay')} delayLongPress={800} onLongPress={() => this._appendEvent('longPress - 800ms delay')}> <Text style={styles.button}>Press Me</Text> </TouchableOpacity> </View> <View style={styles.eventLogBox} testID="touchable_delay_events_console"> {this.state.eventLog.map((e, ii) => ( <Text key={ii}>{e}</Text> ))} </View> </View> ); } _appendEvent = eventName => { const limit = 6; const eventLog = this.state.eventLog.slice(0, limit - 1); eventLog.unshift(eventName); this.setState({eventLog}); }; } class ForceTouchExample extends React.Component<{...}, $FlowFixMeState> { state = { force: 0, }; _renderConsoleText = () => { return forceTouchAvailable ? 'Force: ' + this.state.force.toFixed(3) : '3D Touch is not available on this device'; }; render() { return ( <View testID="touchable_3dtouch_event"> <View style={styles.forceTouchBox} testID="touchable_3dtouch_output"> <Text>{this._renderConsoleText()}</Text> </View> <View style={[styles.row, styles.centered]}> <View style={styles.wrapper} testID="touchable_3dtouch_button" onStartShouldSetResponder={() => true} onResponderMove={event => this.setState({force: event.nativeEvent.force}) } onResponderRelease={event => this.setState({force: 0})}> <Text style={styles.button}>Press Me</Text> </View> </View> </View> ); } } class TouchableHitSlop extends React.Component<{...}, $FlowFixMeState> { state = { timesPressed: 0, }; onPress = () => { this.setState({ timesPressed: this.state.timesPressed + 1, }); }; render() { let log = ''; if (this.state.timesPressed > 1) { log = this.state.timesPressed + 'x onPress'; } else if (this.state.timesPressed > 0) { log = 'onPress'; } return ( <View testID="touchable_hit_slop"> <View style={[styles.row, styles.centered]}> <TouchableOpacity onPress={this.onPress} style={styles.hitSlopWrapper} hitSlop={{top: 30, bottom: 30, left: 60, right: 60}} testID="touchable_hit_slop_button"> <Text style={styles.hitSlopButton}>Press Outside This View</Text> </TouchableOpacity> </View> <View style={styles.logBox}> <Text>{log}</Text> </View> </View> ); } } function TouchableNativeMethodChecker< T: React.AbstractComponent<any, any>, >(props: {|Component: T, name: string|}): React.Node { const [status, setStatus] = useState<?boolean>(null); const ref = useRef<?React.ElementRef<T>>(null); useEffect(() => { setStatus(ref.current != null && typeof ref.current.measure === 'function'); }, []); return ( <View style={[styles.row, styles.block]}> <props.Component ref={ref}> <View /> </props.Component> <Text> {props.name + ': '} {status == null ? 'Missing Ref!' : status === true ? 'Native Methods Exist' : 'Native Methods Missing!'} </Text> </View> ); } function TouchableNativeMethods() { return ( <View> <TouchableNativeMethodChecker Component={TouchableHighlight} name="TouchableHighlight" /> <TouchableNativeMethodChecker Component={TouchableOpacity} name="TouchableOpacity" /> </View> ); } class TouchableDisabled extends React.Component<{...}> { render() { return ( <View> <TouchableOpacity disabled={true} style={[styles.row, styles.block]}> <Text style={styles.disabledButton}>Disabled TouchableOpacity</Text> </TouchableOpacity> <TouchableOpacity disabled={false} style={[styles.row, styles.block]}> <Text style={styles.button}>Enabled TouchableOpacity</Text> </TouchableOpacity> <TouchableHighlight activeOpacity={1} disabled={true} underlayColor="rgb(210, 230, 255)" style={[styles.row, styles.block]} onPress={() => console.log('custom THW text - highlight')}> <Text style={styles.disabledButton}>Disabled TouchableHighlight</Text> </TouchableHighlight> <TouchableHighlight activeOpacity={1} underlayColor="rgb(210, 230, 255)" style={[styles.row, styles.block]} onPress={() => console.log('custom THW text - highlight')}> <Text style={styles.button}>Enabled TouchableHighlight</Text> </TouchableHighlight> <TouchableWithoutFeedback onPress={() => console.log('TWOF has been clicked')} disabled={true}> <View style={styles.wrapperCustom}> <Text style={[ styles.button, styles.nativeFeedbackButton, styles.disabledButton, ]}> Disabled TouchableWithoutFeedback </Text> </View> </TouchableWithoutFeedback> <TouchableWithoutFeedback onPress={() => console.log('TWOF has been clicked')} disabled={false}> <View style={styles.wrapperCustom}> <Text style={[styles.button, styles.nativeFeedbackButton]}> Enabled TouchableWithoutFeedback </Text> </View> </TouchableWithoutFeedback> {Platform.OS === 'android' && ( <> <TouchableNativeFeedback onPress={() => console.log('custom TNF has been clicked')} background={TouchableNativeFeedback.SelectableBackground()}> <View style={[styles.row, styles.block]}> <Text style={[styles.button, styles.nativeFeedbackButton]}> Enabled TouchableNativeFeedback </Text> </View> </TouchableNativeFeedback> <TouchableNativeFeedback disabled={true} onPress={() => console.log('custom TNF has been clicked')} background={TouchableNativeFeedback.SelectableBackground()}> <View style={[styles.row, styles.block]}> <Text style={[styles.disabledButton, styles.nativeFeedbackButton]}> Disabled TouchableNativeFeedback </Text> </View> </TouchableNativeFeedback> </> )} </View> ); } } function CustomRippleRadius() { if (Platform.OS !== 'android') { return null; } return ( <View style={[ styles.row, {justifyContent: 'space-around', alignItems: 'center'}, ]}> <TouchableNativeFeedback onPress={() => console.log('custom TNF has been clicked')} background={TouchableNativeFeedback.Ripple('orange', true, 30)}> <View> <Text style={[styles.button, styles.nativeFeedbackButton]}> radius 30 </Text> </View> </TouchableNativeFeedback> <TouchableNativeFeedback onPress={() => console.log('custom TNF has been clicked')} background={TouchableNativeFeedback.SelectableBackgroundBorderless( 150, )}> <View> <Text style={[styles.button, styles.nativeFeedbackButton]}> radius 150 </Text> </View> </TouchableNativeFeedback> <TouchableNativeFeedback onPress={() => console.log('custom TNF has been clicked')} background={TouchableNativeFeedback.SelectableBackground(70)}> <View style={styles.block}> <Text style={[styles.button, styles.nativeFeedbackButton]}> radius 70, with border </Text> </View> </TouchableNativeFeedback> </View> ); } const remoteImage = { uri: 'https://www.facebook.com/favicon.ico', }; const styles = StyleSheet.create({ row: { justifyContent: 'center', flexDirection: 'row', }, centered: { justifyContent: 'center', }, image: { width: 50, height: 50, }, text: { fontSize: 16, }, block: { padding: 10, }, button: { color: '#007AFF', }, disabledButton: { color: '#007AFF', opacity: 0.5, }, nativeFeedbackButton: { textAlign: 'center', margin: 10, }, hitSlopButton: { color: 'white', }, wrapper: { borderRadius: 8, }, wrapperCustom: { borderRadius: 8, padding: 6, }, hitSlopWrapper: { backgroundColor: 'red', marginVertical: 30, }, logBox: { padding: 20, margin: 10, borderWidth: StyleSheet.hairlineWidth, borderColor: '#f0f0f0', backgroundColor: '#f9f9f9', }, eventLogBox: { padding: 10, margin: 10, height: 120, borderWidth: StyleSheet.hairlineWidth, borderColor: '#f0f0f0', backgroundColor: '#f9f9f9', }, forceTouchBox: { padding: 10, margin: 10, borderWidth: StyleSheet.hairlineWidth, borderColor: '#f0f0f0', backgroundColor: '#f9f9f9', alignItems: 'center', }, textBlock: { fontWeight: '500', color: 'blue', }, }); exports.displayName = (undefined: ?string); exports.description = 'Touchable and onPress examples.'; exports.title = 'Touchable* and onPress'; exports.category = 'UI'; exports.documentationURL = 'https://reactnative.dev/docs/touchablehighlight'; exports.examples = [ { title: '<TouchableHighlight>', description: ('TouchableHighlight works by adding an extra view with a ' + 'black background under the single child view. This works best when the ' + 'child view is fully opaque, although it can be made to work as a simple ' + 'background color change as well with the activeOpacity and ' + 'underlayColor props.': string), render: function(): React.Node { return <TouchableHighlightBox />; }, }, { title: '<TouchableWithoutFeedback>', render: function(): React.Node { return <TouchableWithoutFeedbackBox />; }, }, { title: 'TouchableNativeFeedback with Animated child', description: ('TouchableNativeFeedback can have an AnimatedComponent as a' + 'direct child.': string), platform: 'android', render: function(): React.Node { const mScale = new Animated.Value(1); Animated.timing(mScale, { toValue: 0.3, duration: 1000, useNativeDriver: false, }).start(); const style = { backgroundColor: 'rgb(180, 64, 119)', width: 200, height: 100, transform: [{scale: mScale}], }; return ( <View> <View style={styles.row}> <TouchableNativeFeedback> <Animated.View style={style} /> </TouchableNativeFeedback> </View> </View> ); }, }, { title: '<Text onPress={fn}> with highlight', render: function(): React.Element<any> { return <TextOnPressBox />; }, }, { title: 'Touchable feedback events', description: ('<Touchable*> components accept onPress, onPressIn, ' + 'onPressOut, and onLongPress as props.': string), render: function(): React.Element<any> { return <TouchableFeedbackEvents />; }, }, { title: 'Touchable delay for events', description: ('<Touchable*> components also accept delayPressIn, ' + 'delayPressOut, and delayLongPress as props. These props impact the ' + 'timing of feedback events.': string), render: function(): React.Element<any> { return <TouchableDelayEvents />; }, }, { title: '3D Touch / Force Touch', description: 'iPhone 8 and 8 plus support 3D touch, which adds a force property to touches', render: function(): React.Element<any> { return <ForceTouchExample />; }, platform: 'ios', }, { title: 'Touchable Hit Slop', description: ('<Touchable*> components accept hitSlop prop which extends the touch area ' + 'without changing the view bounds.': string), render: function(): React.Element<any> { return <TouchableHitSlop />; }, }, { title: 'Touchable Native Methods', description: ('Some <Touchable*> components expose native methods like `measure`.': string), render: function(): React.Element<any> { return <TouchableNativeMethods />; }, }, { title: 'Custom Ripple Radius (Android-only)', description: ('Ripple radius on TouchableNativeFeedback can be controlled': string), render: function(): React.Element<any> { return <CustomRippleRadius />; }, }, { title: 'Disabled Touchable*', description: ('<Touchable*> components accept disabled prop which prevents ' + 'any interaction with component': string), render: function(): React.Element<any> { return <TouchableDisabled />; }, }, ];