mirror of
https://github.com/expo/react-native-action-sheet.git
synced 2026-11-14 19:11:42 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
040980edcf | ||
|
|
231630b875 | ||
|
|
3c2ccec2d1 | ||
|
|
e35a4bffbb | ||
|
|
c87602ea3b | ||
|
|
8c1a319a3a | ||
|
|
ac17d305db | ||
|
|
2b9d8e5ec6 | ||
|
|
fe8df1b685 | ||
|
|
74473dc4bd | ||
|
|
2ca8d6217e | ||
|
|
cebaef95a3 | ||
|
|
15460b6a08 | ||
|
|
afb0fefd7b | ||
|
|
04a99ae94b | ||
|
|
432ae92569 | ||
|
|
2fa0e21086 | ||
|
|
33d77f4d04 | ||
|
|
883399be33 | ||
|
|
59e34c83b4 | ||
|
|
2e75f9551d | ||
|
|
2fc359b9c0 | ||
|
|
945028d34f | ||
|
|
ed82cb0047 | ||
|
|
42740e93a0 | ||
|
|
3c95b8a86d | ||
|
|
f35de5dd25 | ||
|
|
8ef0ee36e7 | ||
|
|
3a9bc50e84 | ||
|
|
7fe0aff0fe | ||
|
|
98528d9399 | ||
|
|
8ec19d3bfc | ||
|
|
3e2a8d6c1d | ||
|
|
bf5b9680aa | ||
|
|
cbba57e9c7 | ||
|
|
ebd285c342 | ||
|
|
81f64772c7 | ||
|
|
fa027c0f81 | ||
|
|
f9376eb0ca | ||
|
|
72d2e2a0ea | ||
|
|
acfd89c465 | ||
|
|
b2862ba08c | ||
|
|
dad86d74e8 | ||
|
|
f1b58141b0 | ||
|
|
dbd9da903c | ||
|
|
dfe724247c | ||
|
|
150cf5fcca | ||
|
|
da74bb03c4 | ||
|
|
eb3249f978 | ||
|
|
f1065b7ad6 | ||
|
|
ad32e911e6 | ||
|
|
621b0ad795 | ||
|
|
768a12ed0f | ||
|
|
bde52949cb | ||
|
|
1d8837090f | ||
|
|
ffdb5335d6 | ||
|
|
07b7676691 | ||
|
|
ca5c544b9e | ||
|
|
bf2c37859f | ||
|
|
215a0326a7 | ||
|
|
12623f953c | ||
|
|
ac2e2960ee | ||
|
|
15856cca3d | ||
|
|
2f3ba1b72d | ||
|
|
2ff7205f96 | ||
|
|
3c2a61de8e | ||
|
|
82887ca778 | ||
|
|
e73314d994 | ||
|
|
e901568a98 | ||
|
|
54fe453a5d | ||
|
|
d5dc960e0f | ||
|
|
83c98addea | ||
|
|
1fdcc54c92 | ||
|
|
2d1d25325a | ||
|
|
8bf86b1bf8 | ||
|
|
60fbd7d117 | ||
|
|
34a3ca1498 | ||
|
|
9b769eadc4 | ||
|
|
5d59088fea | ||
|
|
b25206f7e6 | ||
|
|
ccfc3b448a | ||
|
|
38150163c1 | ||
|
|
88d27eba92 | ||
|
|
9fee7dc244 | ||
|
|
b707cec0ae | ||
|
|
1501652c7f | ||
|
|
f577ec4908 | ||
|
|
3477e4d284 | ||
|
|
7dcd315ab2 | ||
|
|
2db7d67870 | ||
|
|
c3c57ea1d9 | ||
|
|
600b2fffc6 | ||
|
|
f799f58dba |
No files matched your search
+45
@@ -0,0 +1,45 @@
|
||||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
project.xcworkspace
|
||||
|
||||
# Android/IJ
|
||||
#
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
*.iml
|
||||
/android/app/*.keystore
|
||||
/android/app/*.apk
|
||||
|
||||
# node.js
|
||||
#
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
android/app/libs
|
||||
android/keystores/debug.keystore
|
||||
|
||||
coverage
|
||||
+265
-116
@@ -1,37 +1,55 @@
|
||||
// @flow
|
||||
|
||||
import React, { PropTypes } from 'react';
|
||||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Animated,
|
||||
BackAndroid,
|
||||
BackHandler,
|
||||
Easing,
|
||||
PixelRatio,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
Text,
|
||||
NativeModules,
|
||||
Image,
|
||||
TouchableOpacity,
|
||||
TouchableNativeFeedback,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
ScrollView,
|
||||
} from 'react-native';
|
||||
|
||||
// Not everybody has this enabled yet
|
||||
const useNativeDriver = !!NativeModules.NativeAnimatedModule;
|
||||
|
||||
type ActionSheetOptions = {
|
||||
options: Array<string>,
|
||||
destructiveButtonIndex: ?number,
|
||||
cancelButtonIndex: ?number,
|
||||
}
|
||||
icons?: ?Array<number | React.Node>,
|
||||
tintIcons?: ?boolean,
|
||||
destructiveButtonIndex?: ?number,
|
||||
cancelButtonIndex?: ?number,
|
||||
textStyle?: ?any,
|
||||
tintColor?: ?string,
|
||||
title?: ?string,
|
||||
titleTextStyle?: ?any,
|
||||
message?: ?string,
|
||||
messageTextStyle?: ?any,
|
||||
showSeparators?: ?boolean,
|
||||
separatorStyle?: ?any,
|
||||
};
|
||||
|
||||
type ActionGroupProps = {
|
||||
options: Array<string>,
|
||||
icons: ?Array<number | React.Node>,
|
||||
tintIcons: ?boolean,
|
||||
destructiveButtonIndex: ?number,
|
||||
onSelect: (i: number) => boolean,
|
||||
startIndex: number,
|
||||
length: number,
|
||||
}
|
||||
textStyle: ?any,
|
||||
tintColor: ?string,
|
||||
title: ?string,
|
||||
titleTextStyle: ?any,
|
||||
message: ?string,
|
||||
messageTextStyle: ?any,
|
||||
showSeparators: ?boolean,
|
||||
separatorStyle: ?any,
|
||||
};
|
||||
|
||||
type ActionSheetState = {
|
||||
isVisible: boolean,
|
||||
@@ -40,33 +58,36 @@ type ActionSheetState = {
|
||||
onSelect: ?(i: number) => void,
|
||||
overlayOpacity: any,
|
||||
sheetOpacity: any,
|
||||
}
|
||||
};
|
||||
|
||||
type ActionSheetProps = {
|
||||
children: ?any,
|
||||
}
|
||||
useNativeDriver: ?boolean,
|
||||
};
|
||||
|
||||
const OPACITY_ANIMATION_TIME = 150;
|
||||
const PIXEL = 1 / PixelRatio.get();
|
||||
const OPACITY_ANIMATION_IN_TIME = 225;
|
||||
const OPACITY_ANIMATION_OUT_TIME = 195;
|
||||
const EASING_OUT = Easing.bezier(0.25, 0.46, 0.45, 0.94);
|
||||
const EASING_IN = Easing.out(EASING_OUT);
|
||||
const BLACK_54PC_TRANSPARENT = '#0000008a';
|
||||
const BLACK_87PC_TRANSPARENT = '#000000de';
|
||||
const DESTRUCTIVE_COLOR = '#d32f2f';
|
||||
|
||||
class ActionGroup extends React.Component {
|
||||
props: ActionGroupProps;
|
||||
|
||||
static propTypes = {
|
||||
options: PropTypes.array.isRequired,
|
||||
destructiveButtonIndex: PropTypes.number,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
startIndex: PropTypes.number.isRequired,
|
||||
length: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
let {
|
||||
options,
|
||||
icons,
|
||||
tintIcons,
|
||||
destructiveButtonIndex,
|
||||
onSelect,
|
||||
startIndex,
|
||||
length,
|
||||
textStyle,
|
||||
tintColor,
|
||||
showSeparators,
|
||||
} = this.props;
|
||||
|
||||
let optionViews = [];
|
||||
@@ -77,9 +98,24 @@ class ActionGroup extends React.Component {
|
||||
);
|
||||
|
||||
for (let i = startIndex; i < startIndex + length; i++) {
|
||||
let color = '#444444';
|
||||
if (i === destructiveButtonIndex) {
|
||||
color = '#ff3b30';
|
||||
const defaultColor = tintColor
|
||||
? tintColor
|
||||
: (textStyle || {}).color || BLACK_87PC_TRANSPARENT;
|
||||
const color = i === destructiveButtonIndex ? DESTRUCTIVE_COLOR : defaultColor;
|
||||
const iconSource = icons != null && icons[i];
|
||||
let iconElement = undefined;
|
||||
|
||||
if (iconSource) {
|
||||
if (typeof iconSource === 'number') {
|
||||
const iconStyle = [styles.icon, { tintColor: tintIcons ? color : null }];
|
||||
iconElement = <Image
|
||||
fadeDuration={0}
|
||||
source={iconSource}
|
||||
resizeMode="contain"
|
||||
style={iconStyle}/>;
|
||||
} else {
|
||||
iconElement = <View style={styles.icon}>{iconSource}</View>;
|
||||
}
|
||||
}
|
||||
|
||||
optionViews.push(
|
||||
@@ -89,30 +125,78 @@ class ActionGroup extends React.Component {
|
||||
background={nativeFeedbackBackground}
|
||||
onPress={() => onSelect(i)}
|
||||
style={styles.button}>
|
||||
<Text style={[styles.text, {color}]}>
|
||||
{options[i]}
|
||||
</Text>
|
||||
{iconElement}
|
||||
<Text style={[styles.text, textStyle, { color }]}>{options[i]}</Text>
|
||||
</TouchableNativeFeedbackSafe>
|
||||
);
|
||||
|
||||
if (i < startIndex + length - 1) {
|
||||
optionViews.push(
|
||||
<View key={`separator-${i}`} style={styles.rowSeparator} />
|
||||
);
|
||||
if (showSeparators && i < startIndex + length - 1) {
|
||||
optionViews.push(this._renderRowSeparator(i));
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.groupContainer}>
|
||||
{optionViews}
|
||||
{this._renderTitleContent()}
|
||||
<ScrollView>{optionViews}</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderRowSeparator(key) {
|
||||
return <View key={key ? `separator-${key}` : null} style={[styles.rowSeparator, this.props.separatorStyle]} />;
|
||||
}
|
||||
|
||||
_renderTitleContent() {
|
||||
const { title, titleTextStyle, message, messageTextStyle, showSeparators } = this.props;
|
||||
|
||||
if (!title && !message) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={[styles.titleContainer, { paddingBottom: showSeparators ? 24 : 16 }]}>
|
||||
{!!title && <Text style={[styles.title, titleTextStyle]}>{title}</Text>}
|
||||
{!!message && <Text style={[styles.message, messageTextStyle]}>{message}</Text>}
|
||||
</View>
|
||||
{!!showSeparators && this._renderRowSeparator('title')}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ActionGroup.propTypes = {
|
||||
options: PropTypes.array.isRequired,
|
||||
icons: PropTypes.array,
|
||||
tintIcons: PropTypes.bool,
|
||||
destructiveButtonIndex: PropTypes.number,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
startIndex: PropTypes.number.isRequired,
|
||||
length: PropTypes.number.isRequired,
|
||||
textStyle: Text.propTypes.style,
|
||||
tintColor: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
titleTextStyle: Text.propTypes.style,
|
||||
message: PropTypes.string,
|
||||
messageTextStyle: Text.propTypes.style,
|
||||
showSeparators: PropTypes.bool,
|
||||
separatorStyle: PropTypes.object,
|
||||
};
|
||||
|
||||
ActionGroup.defaultProps = {
|
||||
title: null,
|
||||
message: null,
|
||||
showSeparators: false,
|
||||
tintIcons: true,
|
||||
textStyle: {},
|
||||
};
|
||||
|
||||
// Has same API as https://facebook.github.io/react-native/docs/actionsheetios.html
|
||||
export default class ActionSheet extends React.Component {
|
||||
props: ActionSheetProps;
|
||||
|
||||
_actionSheetHeight = 360;
|
||||
_animateOutCallback: ?() => void = null;
|
||||
|
||||
state: ActionSheetState = {
|
||||
@@ -124,47 +208,88 @@ export default class ActionSheet extends React.Component {
|
||||
sheetOpacity: new Animated.Value(0),
|
||||
};
|
||||
|
||||
render() {
|
||||
let { isVisible } = this.state;
|
||||
let overlay = isVisible ? (
|
||||
<Animated.View style={[styles.overlay, {
|
||||
opacity: this.state.overlayOpacity,
|
||||
}]} />
|
||||
) : null;
|
||||
_setActionSheetHeight = ({ nativeEvent }) =>
|
||||
this._actionSheetHeight = nativeEvent.layout.height;
|
||||
|
||||
let sheet = isVisible ? this._renderSheet() : null;
|
||||
render() {
|
||||
const { isVisible, overlayOpacity } = this.state;
|
||||
const overlay = !!isVisible && (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.overlay,
|
||||
{
|
||||
opacity: overlayOpacity,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<View style={{ flex: 1 }}>
|
||||
{React.Children.only(this.props.children)}
|
||||
{overlay}
|
||||
{sheet}
|
||||
{!!isVisible && this._renderSheet()}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderSheet() {
|
||||
if (!this.state.options) {
|
||||
return;
|
||||
const { options, isAnimating, sheetOpacity } = this.state;
|
||||
|
||||
if (!options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let numOptions = this.state.options.options.length;
|
||||
const {
|
||||
options: optionsArray,
|
||||
icons,
|
||||
tintIcons,
|
||||
destructiveButtonIndex,
|
||||
textStyle,
|
||||
tintColor,
|
||||
title,
|
||||
titleTextStyle,
|
||||
message,
|
||||
messageTextStyle,
|
||||
showSeparators,
|
||||
separatorStyle,
|
||||
} = options;
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={this._selectCancelButton}>
|
||||
<Animated.View
|
||||
needsOffscreenAlphaCompositing={this.state.isAnimating}
|
||||
style={[styles.sheetContainer, {
|
||||
opacity: this.state.sheetOpacity,
|
||||
transform: [{scale: this.state.sheetOpacity.interpolate({inputRange: [0, 0.5, 1], outputRange: [0.6, 1, 1]})}],
|
||||
}]}>
|
||||
<View style={styles.sheet}>
|
||||
needsOffscreenAlphaCompositing={isAnimating}
|
||||
style={[
|
||||
styles.sheetContainer,
|
||||
{
|
||||
opacity: sheetOpacity,
|
||||
transform: [
|
||||
{
|
||||
translateY: sheetOpacity.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [this._actionSheetHeight, 0],
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
]}>
|
||||
<View style={styles.sheet} onLayout={this._setActionSheetHeight}>
|
||||
<ActionGroup
|
||||
options={this.state.options.options}
|
||||
destructiveButtonIndex={this.state.options.destructiveButtonIndex}
|
||||
options={optionsArray}
|
||||
icons={icons}
|
||||
tintIcons={tintIcons === undefined ? true : tintIcons}
|
||||
destructiveButtonIndex={destructiveButtonIndex}
|
||||
onSelect={this._onSelect}
|
||||
startIndex={0}
|
||||
length={numOptions}
|
||||
length={optionsArray.length}
|
||||
textStyle={textStyle || {}}
|
||||
tintColor={tintColor}
|
||||
title={title || null}
|
||||
titleTextStyle={titleTextStyle}
|
||||
message={message || null}
|
||||
messageTextStyle={messageTextStyle}
|
||||
showSeparators={showSeparators}
|
||||
separatorStyle={separatorStyle}
|
||||
/>
|
||||
</View>
|
||||
</Animated.View>
|
||||
@@ -177,7 +302,9 @@ export default class ActionSheet extends React.Component {
|
||||
onSelect: (i: number) => void,
|
||||
onAnimateOut: () => void
|
||||
) {
|
||||
if (this.state.isVisible) {
|
||||
const { isVisible, overlayOpacity, sheetOpacity } = this.state;
|
||||
|
||||
if (isVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -188,21 +315,21 @@ export default class ActionSheet extends React.Component {
|
||||
isAnimating: true,
|
||||
});
|
||||
|
||||
this.state.overlayOpacity.setValue(0);
|
||||
this.state.sheetOpacity.setValue(0);
|
||||
overlayOpacity.setValue(0);
|
||||
sheetOpacity.setValue(0);
|
||||
|
||||
Animated.parallel([
|
||||
Animated.timing(this.state.overlayOpacity, {
|
||||
toValue: 0.5,
|
||||
easing: Easing.in(Easing.linear),
|
||||
duration: OPACITY_ANIMATION_TIME,
|
||||
useNativeDriver,
|
||||
Animated.timing(overlayOpacity, {
|
||||
toValue: 0.32,
|
||||
easing: EASING_OUT,
|
||||
duration: OPACITY_ANIMATION_IN_TIME,
|
||||
useNativeDriver: this.props.useNativeDriver,
|
||||
}),
|
||||
Animated.timing(this.state.sheetOpacity, {
|
||||
Animated.timing(sheetOpacity, {
|
||||
toValue: 1,
|
||||
easing: Easing.in(Easing.linear),
|
||||
duration: OPACITY_ANIMATION_TIME,
|
||||
useNativeDriver,
|
||||
easing: EASING_OUT,
|
||||
duration: OPACITY_ANIMATION_IN_TIME,
|
||||
useNativeDriver: this.props.useNativeDriver,
|
||||
}),
|
||||
]).start(result => {
|
||||
if (result.finished) {
|
||||
@@ -214,53 +341,64 @@ export default class ActionSheet extends React.Component {
|
||||
|
||||
this._animateOutCallback = onAnimateOut;
|
||||
|
||||
BackAndroid.addEventListener('actionSheetHardwareBackPress', this._selectCancelButton);
|
||||
BackHandler.addEventListener(
|
||||
'actionSheetHardwareBackPress',
|
||||
this._selectCancelButton
|
||||
);
|
||||
}
|
||||
|
||||
_selectCancelButton = () => {
|
||||
if (!this.state.options) {
|
||||
return;
|
||||
const { options } = this.state;
|
||||
if (!options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof this.state.options.cancelButtonIndex === 'number') {
|
||||
return this._onSelect(this.state.options.cancelButtonIndex);
|
||||
if (typeof options.cancelButtonIndex === 'number') {
|
||||
return this._onSelect(options.cancelButtonIndex);
|
||||
} else {
|
||||
return this._animateOut();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_onSelect = (index: number): boolean => {
|
||||
if (this.state.isAnimating) {
|
||||
const { isAnimating, onSelect } = this.state;
|
||||
|
||||
if (isAnimating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.state.onSelect && this.state.onSelect(index);
|
||||
onSelect && onSelect(index);
|
||||
return this._animateOut();
|
||||
}
|
||||
};
|
||||
|
||||
_animateOut = (): boolean => {
|
||||
if (this.state.isAnimating) {
|
||||
const { isAnimating, overlayOpacity, sheetOpacity } = this.state;
|
||||
|
||||
if (isAnimating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BackAndroid.removeEventListener('actionSheetHardwareBackPress', this._selectCancelButton);
|
||||
BackHandler.removeEventListener(
|
||||
'actionSheetHardwareBackPress',
|
||||
this._selectCancelButton
|
||||
);
|
||||
|
||||
this.setState({
|
||||
isAnimating: true,
|
||||
});
|
||||
|
||||
Animated.parallel([
|
||||
Animated.timing(this.state.overlayOpacity, {
|
||||
Animated.timing(overlayOpacity, {
|
||||
toValue: 0,
|
||||
easing: Easing.in(Easing.linear),
|
||||
duration: OPACITY_ANIMATION_TIME,
|
||||
useNativeDriver,
|
||||
easing: EASING_IN,
|
||||
duration: OPACITY_ANIMATION_OUT_TIME,
|
||||
useNativeDriver: this.props.useNativeDriver,
|
||||
}),
|
||||
Animated.timing(this.state.sheetOpacity, {
|
||||
Animated.timing(sheetOpacity, {
|
||||
toValue: 0,
|
||||
easing: Easing.in(Easing.linear),
|
||||
duration: OPACITY_ANIMATION_TIME,
|
||||
useNativeDriver,
|
||||
easing: EASING_IN,
|
||||
duration: OPACITY_ANIMATION_OUT_TIME,
|
||||
useNativeDriver: this.props.useNativeDriver,
|
||||
}),
|
||||
]).start(result => {
|
||||
if (result.finished) {
|
||||
@@ -276,16 +414,16 @@ export default class ActionSheet extends React.Component {
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ActionSheet.defaultProps = {
|
||||
useNativeDriver: true,
|
||||
};
|
||||
|
||||
let TouchableComponent;
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
TouchableComponent = Platform.Version <= 20 ? TouchableOpacity : TouchableNativeFeedback;
|
||||
} else {
|
||||
TouchableComponent = TouchableOpacity;
|
||||
}
|
||||
TouchableComponent = Platform.Version <= 20 ? TouchableOpacity : TouchableNativeFeedback;
|
||||
|
||||
if (TouchableComponent !== TouchableNativeFeedback) {
|
||||
TouchableComponent.SelectableBackground = () => ({});
|
||||
@@ -294,7 +432,6 @@ if (TouchableComponent !== TouchableNativeFeedback) {
|
||||
}
|
||||
|
||||
class TouchableNativeFeedbackSafe extends React.Component {
|
||||
|
||||
static SelectableBackground = TouchableComponent.SelectableBackground;
|
||||
static SelectableBackgroundBorderless = TouchableComponent.SelectableBackgroundBorderless;
|
||||
static Ripple = TouchableComponent.Ripple;
|
||||
@@ -303,45 +440,41 @@ class TouchableNativeFeedbackSafe extends React.Component {
|
||||
if (TouchableComponent === TouchableNativeFeedback) {
|
||||
return (
|
||||
<TouchableComponent {...this.props} style={{}}>
|
||||
<View style={this.props.style}>
|
||||
{this.props.children}
|
||||
</View>
|
||||
<View style={this.props.style}>{this.props.children}</View>
|
||||
</TouchableComponent>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<TouchableComponent {...this.props}>
|
||||
{this.props.children}
|
||||
</TouchableComponent>
|
||||
);
|
||||
return <TouchableComponent {...this.props}>{this.props.children}</TouchableComponent>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
groupContainer: {
|
||||
backgroundColor: '#fefefe',
|
||||
borderRadius: 4,
|
||||
borderColor: '#cbcbcb',
|
||||
borderWidth: PIXEL,
|
||||
backgroundColor: '#ffffff',
|
||||
overflow: 'hidden',
|
||||
marginHorizontal: 16,
|
||||
marginBottom: 8,
|
||||
},
|
||||
button: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-start',
|
||||
height: 50,
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
height: 56,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
icon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
marginRight: 32,
|
||||
},
|
||||
text: {
|
||||
fontSize: 17,
|
||||
fontWeight: '700',
|
||||
fontSize: 16,
|
||||
color: BLACK_87PC_TRANSPARENT,
|
||||
textAlignVertical: 'center',
|
||||
},
|
||||
rowSeparator: {
|
||||
backgroundColor: '#dddddd',
|
||||
height: 1,
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
},
|
||||
overlay: {
|
||||
position: 'absolute',
|
||||
@@ -358,7 +491,7 @@ let styles = StyleSheet.create({
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
backgroundColor: 'transparent',
|
||||
alignItems: 'center',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
@@ -366,4 +499,20 @@ let styles = StyleSheet.create({
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
titleContainer: {
|
||||
alignItems: 'flex-start',
|
||||
padding: 16,
|
||||
paddingTop: 24,
|
||||
},
|
||||
title: {
|
||||
fontSize: 16,
|
||||
color: BLACK_54PC_TRANSPARENT,
|
||||
textAlignVertical: 'center',
|
||||
},
|
||||
message: {
|
||||
marginTop: 12,
|
||||
fontSize: 14,
|
||||
color: BLACK_54PC_TRANSPARENT,
|
||||
textAlignVertical: 'center',
|
||||
},
|
||||
});
|
||||
+11
-10
@@ -1,21 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
ActionSheetIOS,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { ActionSheetIOS, View } from 'react-native';
|
||||
|
||||
export default class ActionSheet extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
{React.Children.only(this.props.children)}
|
||||
</View>
|
||||
);
|
||||
return <View style={{ flex: 1 }}>{React.Children.only(this.props.children)}</View>;
|
||||
}
|
||||
|
||||
showActionSheetWithOptions(options, onSelect) {
|
||||
ActionSheetIOS.showActionSheetWithOptions(options, onSelect);
|
||||
const iosOptions = {
|
||||
...options,
|
||||
// A null title or message on iOS causes a crash
|
||||
title: options.title || undefined,
|
||||
message: options.message || undefined,
|
||||
icons: undefined,
|
||||
};
|
||||
|
||||
ActionSheetIOS.showActionSheetWithOptions(iosOptions, onSelect);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ActionSheet from './ActionSheet';
|
||||
|
||||
export default class ActionSheetProvider extends React.Component {
|
||||
static propTypes = {
|
||||
textStyle: PropTypes.object,
|
||||
tintIcons: PropTypes.bool,
|
||||
tintColor: PropTypes.string,
|
||||
titleTextStyle: PropTypes.object,
|
||||
messageTextStyle: PropTypes.object,
|
||||
showSeparators: PropTypes.bool,
|
||||
separatorStyle: PropTypes.object,
|
||||
children: PropTypes.any.isRequired,
|
||||
};
|
||||
|
||||
static childContextTypes = {
|
||||
showActionSheetWithOptions: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
textStyle: {},
|
||||
tintIcons: true,
|
||||
titleTextStyle: {},
|
||||
messageTextStyle: {},
|
||||
showSeparators: false,
|
||||
separatorStyle: {},
|
||||
};
|
||||
|
||||
getNextValue = (config, propKey) => config[propKey] !== undefined ? config[propKey] : this.props[propKey];
|
||||
|
||||
getNextObject = (config, propKey) => ({...this.props[propKey], ...config[propKey]});
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
showActionSheetWithOptions: (...args) => {
|
||||
const [config, ...rest] = args;
|
||||
const nextConfig = {
|
||||
...config,
|
||||
textStyle: this.getNextObject(config, 'textStyle'),
|
||||
tintIcons: this.getNextValue(config, 'tintIcons'),
|
||||
tintColor: this.getNextValue(config, 'tintColor'),
|
||||
titleTextStyle: this.getNextObject(config, 'titleTextStyle'),
|
||||
messageTextStyle: this.getNextObject(config, 'messageTextStyle'),
|
||||
showSeparators: this.getNextValue(config, 'showSeparators'),
|
||||
separatorStyle: this.getNextObject(config, 'separatorStyle'),
|
||||
};
|
||||
|
||||
this._actionSheetRef.showActionSheetWithOptions(nextConfig, ...rest);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ActionSheet ref={component => (this._actionSheetRef = component)}>
|
||||
{React.Children.only(this.props.children)}
|
||||
</ActionSheet>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Exponent
|
||||
Copyright (c) 2015 Expo
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,61 +1,85 @@
|
||||
# react-native-action-sheet [](http://slack.exponentjs.com)
|
||||
# react-native-action-sheet [](https://slack.expo.io)
|
||||
|
||||
ActionSheet is a cross-platform React Native component that uses the native UIActionSheet on iOS and a JS implementation on Android. Almost a drop in replacement for [ActionSheetIOS](https://facebook.github.io/react-native/docs/actionsheetios.html) except it cannot be called statically.
|
||||
|
||||
## Installation
|
||||
```
|
||||
npm install @exponent/react-native-action-sheet
|
||||
npm install @expo/react-native-action-sheet
|
||||
```
|
||||
|
||||
## Usage
|
||||
## A basic ActionSheet Setup
|
||||
|
||||
Wrap your entire app in `ActionSheet`. We recommend using [context](https://facebook.github.io/react/docs/context.html) to pass `ActionSheet` to the rest of your app.
|
||||
import ActionSheetProvider & connectActionSheet
|
||||
|
||||
```js
|
||||
class MainApp extends React.Component {
|
||||
```es6
|
||||
import { ActionSheetProvider, connectActionSheet } from '@expo/react-native-action-sheet';
|
||||
```
|
||||
|
||||
static childContextTypes = {
|
||||
actionSheet: PropTypes.func,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
actionSheet: () => this._actionSheetRef,
|
||||
};
|
||||
}
|
||||
wrap your top-level component with `<ActionSheetProvider />`
|
||||
|
||||
```es6
|
||||
class AppContainer extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ActionSheet ref={component => this._actionSheetRef = component}>
|
||||
// Render the rest of your app here.
|
||||
</ActionSheet>
|
||||
<ActionSheetProvider>
|
||||
<App />
|
||||
</ActionSheetProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To open the action sheet:
|
||||
decorate the component you want to use the action sheet with `@connectActionSheet`
|
||||
|
||||
```js
|
||||
class OtherComponent extends React.Component {
|
||||
```es6
|
||||
@connectActionSheet
|
||||
class App extends React.Component { /* ... */ }
|
||||
```
|
||||
|
||||
static contextTypes = {
|
||||
actionSheet: PropTypes.func,
|
||||
};
|
||||
access actionSheet method as `this.props.showActionSheetWithOptions`
|
||||
|
||||
_onOpenActionSheet() {
|
||||
// Same interface as https://facebook.github.io/react-native/docs/actionsheetios.html
|
||||
let options = ['Delete', 'Save', 'Cancel'];
|
||||
let destructiveButtonIndex = 0;
|
||||
let cancelButtonIndex = 2;
|
||||
this.context.actionSheet().showActionSheetWithOptions({
|
||||
options,
|
||||
cancelButtonIndex,
|
||||
destructiveButtonIndex,
|
||||
},
|
||||
(buttonIndex) => {
|
||||
// Do something here
|
||||
});
|
||||
}
|
||||
```es6
|
||||
_onOpenActionSheet = () => {
|
||||
// Same interface as https://facebook.github.io/react-native/docs/actionsheetios.html
|
||||
const options = ['Delete', 'Save', 'Cancel'];
|
||||
const destructiveButtonIndex = 0;
|
||||
const cancelButtonIndex = 2;
|
||||
|
||||
this.props.showActionSheetWithOptions({
|
||||
options,
|
||||
cancelButtonIndex,
|
||||
destructiveButtonIndex,
|
||||
},
|
||||
(buttonIndex) => {
|
||||
// Do something here depending on the button index selected
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
The goal of this library is to mimic the native iOS and Android ActionSheets as closely as possible.
|
||||
|
||||
### Universal Props
|
||||
|
||||
The same options available on React Native's [ActionSheetIOS](https://facebook.github.io/react-native/docs/actionsheetios.html#showactionsheetwithoptions) component exist for both iOS and Android in this library.
|
||||
|
||||
### Android-Only Props
|
||||
|
||||
The below props allow modification of the Android ActionSheet. They have no effect on the look on iOS as the native iOS Action Sheet does not have options for modifying these options.
|
||||
|
||||
* `icons` (array of required images or icons; optional): Show icons to go along with each option. If image source paths are provided via `require`, images will be rendered for you. Alternatively, you can provide an array of elements such as vector icons, pre-rendered Images, etc.
|
||||
* `tintIcons` (boolean; optional; default: `true`): Icons by default will be tinted to match the text color. When set to false, the icons will be the color of the source image. This is useful if you want to use multicolor icons. If you provide your own nodes/pre-rendered icons rather than required images in the `icons` array, you will need to tint them appropriately before providing them in the array of `icons`; `tintColor` will not be applied to icons unless they are images from a required source.
|
||||
* `textStyle` (Text.propTypes.style; optional): Apply any text style props to the options. If the `tintColor` option is provided, it takes precedence over a color text style prop.
|
||||
* `titleTextStyle` (Text.propTypes.style; optional): Apply any text style props to the title if present.
|
||||
* `messageTextStyle` (Text.propTypes.style; optional): Apply any text style props to the message if present.
|
||||
* `showSeparators`: (boolean; optional; default: false): Show separators between items. On iOS, separators always show so this prop has no effect.
|
||||
* `separatorStyle`: (View.propTypes.style; optional): Modify the look of the separators rather than use the default look.
|
||||
|
||||
## Try it out
|
||||
|
||||
Try it in Expo: https://expo.io/@community/react-native-action-sheet-example
|
||||
|
||||
## Usage
|
||||
|
||||
See the [example app](https://github.com/expo/react-native-action-sheet/tree/master/example) for examples of how to apply different options.
|
||||
@@ -0,0 +1,20 @@
|
||||
import hoistStatics from 'hoist-non-react-statics';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function connectActionSheet(WrappedComponent) {
|
||||
const ConnectedActionSheet = (props, context) => {
|
||||
return (
|
||||
<WrappedComponent
|
||||
{...props}
|
||||
showActionSheetWithOptions={context.showActionSheetWithOptions}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
ConnectedActionSheet.contextTypes = {
|
||||
showActionSheetWithOptions: PropTypes.func,
|
||||
};
|
||||
|
||||
return hoistStatics(ConnectedActionSheet, WrappedComponent);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"presets": ["babel-preset-expo"],
|
||||
"env": {
|
||||
"development": {
|
||||
"plugins": ["transform-react-jsx-source"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules/**/*
|
||||
.expo/*
|
||||
npm-debug.*
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
import Expo from 'expo';
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View, ScrollView, SafeAreaView } from 'react-native';
|
||||
import { ActionSheetProvider, connectActionSheet } from '@expo/react-native-action-sheet';
|
||||
import ShowActionSheetButton from './ShowActionSheetButton';
|
||||
|
||||
export default class AppContainer extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ActionSheetProvider>
|
||||
<App />
|
||||
</ActionSheetProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@connectActionSheet
|
||||
class App extends React.Component {
|
||||
state = {
|
||||
selectedIndex: null,
|
||||
};
|
||||
|
||||
_updateSelectionText = (selectedIndex) => {
|
||||
this.setState({ selectedIndex });
|
||||
};
|
||||
|
||||
_renderSelectionText() {
|
||||
const { selectedIndex } = this.state;
|
||||
const text = selectedIndex === null
|
||||
? 'No Option Selected'
|
||||
: `Option #${selectedIndex + 1} Selected`;
|
||||
|
||||
return <Text style={styles.selectionText}>{text}</Text>
|
||||
}
|
||||
|
||||
_renderSectionHeader(text) {
|
||||
return <Text style={styles.sectionHeaderText}>{text}</Text>;
|
||||
}
|
||||
|
||||
_renderButtons() {
|
||||
const { showActionSheetWithOptions } = this.props;
|
||||
return (
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
{this._renderSectionHeader('Universal Options')}
|
||||
<ShowActionSheetButton
|
||||
title="Options Only"
|
||||
onSelection={this._updateSelectionText}
|
||||
showActionSheetWithOptions={showActionSheetWithOptions} />
|
||||
<ShowActionSheetButton
|
||||
title="Title"
|
||||
withTitle
|
||||
onSelection={this._updateSelectionText}
|
||||
showActionSheetWithOptions={showActionSheetWithOptions} />
|
||||
<ShowActionSheetButton
|
||||
title="Title & Message"
|
||||
withTitle
|
||||
withMessage
|
||||
onSelection={this._updateSelectionText}
|
||||
showActionSheetWithOptions={showActionSheetWithOptions} />
|
||||
{this._renderSectionHeader('Android-Only Options')}
|
||||
<ShowActionSheetButton
|
||||
title="Icons"
|
||||
withIcons
|
||||
onSelection={this._updateSelectionText}
|
||||
showActionSheetWithOptions={showActionSheetWithOptions} />
|
||||
<ShowActionSheetButton
|
||||
title="Title, Message, & Icons"
|
||||
withTitle
|
||||
withMessage
|
||||
withIcons
|
||||
onSelection={this._updateSelectionText}
|
||||
showActionSheetWithOptions={showActionSheetWithOptions} />
|
||||
<ShowActionSheetButton
|
||||
title="Use Separators"
|
||||
withTitle
|
||||
withIcons
|
||||
withSeparators
|
||||
onSelection={this._updateSelectionText}
|
||||
showActionSheetWithOptions={showActionSheetWithOptions} />
|
||||
<ShowActionSheetButton
|
||||
title="Custom Styles"
|
||||
withTitle
|
||||
withMessage
|
||||
withIcons
|
||||
withCustomStyles
|
||||
onSelection={this._updateSelectionText}
|
||||
showActionSheetWithOptions={showActionSheetWithOptions} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SafeAreaView style={styles.flex}>
|
||||
<ScrollView style={styles.flex} contentContainerStyle={styles.contentContainer}>
|
||||
<Text style={styles.headerText}>
|
||||
{"Hello!\n\nThis is a simple example app to demonstrate @expo/react-native-action-sheet."}
|
||||
</Text>
|
||||
{this._renderButtons()}
|
||||
{this._renderSelectionText()}
|
||||
<Text style={styles.notes}>
|
||||
Note: Icons and custom text styles are only available on Android. Separators can only be toggled on Android; they always show on iOS.
|
||||
</Text>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
flex: {
|
||||
flex: 1,
|
||||
},
|
||||
contentContainer: {
|
||||
padding: 16,
|
||||
paddingVertical: 20,
|
||||
},
|
||||
headerText: {
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
marginBottom: 10,
|
||||
},
|
||||
notes: {
|
||||
marginTop: 32,
|
||||
},
|
||||
sectionHeaderText: {
|
||||
color: 'orange',
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 20,
|
||||
marginTop: 20,
|
||||
marginBottom: 10,
|
||||
},
|
||||
selectionText: {
|
||||
textAlign: 'center',
|
||||
color: 'blue',
|
||||
fontSize: 16,
|
||||
marginTop: 20,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { MaterialIcons, Entypo } from '@expo/vector-icons';
|
||||
|
||||
const icon = (name) => <MaterialIcons key={name} name={name} size={24} />;
|
||||
|
||||
// A custom button that shows examples of different share sheet configurations
|
||||
class ShowActionSheetButton extends React.PureComponent {
|
||||
_showActionSheet = () => {
|
||||
const {
|
||||
withTitle,
|
||||
withMessage,
|
||||
withIcons,
|
||||
withSeparators,
|
||||
withCustomStyles,
|
||||
onSelection,
|
||||
showActionSheetWithOptions,
|
||||
} = this.props;
|
||||
// Same interface as https://facebook.github.io/react-native/docs/actionsheetios.html
|
||||
const options = ['Delete', 'Save', 'Share', 'Cancel'];
|
||||
const icons = withIcons ? [icon('delete'), icon('save'), icon('share'), icon('cancel')] : null;
|
||||
const title = withTitle ? 'Choose An Action' : null;
|
||||
const message = withMessage ? 'This library tries to mimic the native share sheets as close as possible.' : null;
|
||||
const destructiveButtonIndex = 0;
|
||||
const cancelButtonIndex = 3;
|
||||
const textStyle = withCustomStyles ? { fontSize: 20, fontWeight: '500', color: 'blue' } : null;
|
||||
const titleTextStyle = withCustomStyles ? { fontSize: 24, textAlign: 'center', fontWeight: '700', color: 'orange' } : null;
|
||||
const messageTextStyle = withCustomStyles ? { fontSize: 12, color: 'purple', textAlign: 'right' } : null;
|
||||
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
options,
|
||||
cancelButtonIndex,
|
||||
destructiveButtonIndex,
|
||||
title,
|
||||
message,
|
||||
icons, // Android only
|
||||
tintIcons: true, // Android only; default is true
|
||||
showSeparators: withSeparators, // Affects Android only; default is false
|
||||
textStyle, // Android only
|
||||
titleTextStyle, // Android only
|
||||
messageTextStyle, // Android only
|
||||
},
|
||||
buttonIndex => {
|
||||
// Do something here depending on the button index selected
|
||||
onSelection(buttonIndex);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { title } = this.props;
|
||||
return (
|
||||
<View style={{ margin: 6 }}>
|
||||
<Entypo.Button
|
||||
name="code"
|
||||
backgroundColor="#3e3e3e"
|
||||
onPress={this._showActionSheet}>
|
||||
<Text style={{
|
||||
fontSize: 15,
|
||||
color: '#fff'
|
||||
}}>{title}</Text>
|
||||
</Entypo.Button>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ShowActionSheetButton.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
onSelection: PropTypes.func,
|
||||
showActionSheetWithOptions: PropTypes.func.isRequired,
|
||||
withTitle: PropTypes.bool,
|
||||
withMessage: PropTypes.bool,
|
||||
withIcons: PropTypes.bool,
|
||||
withSeparators: PropTypes.bool,
|
||||
withCustomStyles: PropTypes.bool,
|
||||
};
|
||||
|
||||
ShowActionSheetButton.defaultProps = {
|
||||
withTitle: false,
|
||||
withMessage: false,
|
||||
withIcons: false,
|
||||
withSeparators: false,
|
||||
withCustomStyles: false,
|
||||
onSelection: null,
|
||||
};
|
||||
|
||||
export default ShowActionSheetButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "@expo/react-native-action-sheet-example",
|
||||
"description": "A cross-platform ActionSheet component. https://github.com/expo/react-native-action-sheet",
|
||||
"slug": "react-native-action-sheet-example",
|
||||
"privacy": "public",
|
||||
"sdkVersion": "25.0.0",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"primaryColor": "#cccccc",
|
||||
"icon": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png",
|
||||
"packagerOpts": {
|
||||
"assetExts": ["ttf", "mp4"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "example",
|
||||
"version": "0.0.0",
|
||||
"description": "Hello Expo!",
|
||||
"author": "[email protected]",
|
||||
"private": true,
|
||||
"main": "node_modules/expo/AppEntry.js",
|
||||
"dependencies": {
|
||||
"@expo/react-native-action-sheet": "../",
|
||||
"expo": "^25.0.0",
|
||||
"react": "16.2.0",
|
||||
"react-native": "https://github.com/expo/react-native/archive/sdk-25.0.0.tar.gz"
|
||||
}
|
||||
}
|
||||
+3985
File diff suppressed because it is too large.
Load diff
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
import { ActionSheetIOSOptions } from 'react-native';
|
||||
|
||||
export interface ActionSheetProps {
|
||||
showActionSheetWithOptions: (
|
||||
options: ActionSheetIOSOptions,
|
||||
callback: (buttonIndex: number) => void,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export function connectActionSheet<T>(
|
||||
WrappedComponent: React.ComponentType<T & ActionSheetProps>,
|
||||
): React.ComponentClass<T>;
|
||||
|
||||
export const ActionSheetProvider: React.ComponentClass;
|
||||
@@ -1 +1,4 @@
|
||||
module.exports = require('./ActionSheet');
|
||||
|
||||
module.exports.ActionSheetProvider = require('./ActionSheetProvider').default;
|
||||
module.exports.connectActionSheet = require('./connectActionSheet').default;
|
||||
+21
-6
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@exponent/react-native-action-sheet",
|
||||
"version": "0.2.1",
|
||||
"name": "@expo/react-native-action-sheet",
|
||||
"version": "2.0.1",
|
||||
"description": "A cross-platform ActionSheet for React Native",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -8,21 +8,36 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/exponentjs/react-native-action-sheet.git"
|
||||
"url": "https://github.com/expo/react-native-action-sheet.git"
|
||||
},
|
||||
"keywords": [
|
||||
"react-native",
|
||||
"action-sheet"
|
||||
],
|
||||
"files": [
|
||||
"ActionSheet.android.js",
|
||||
"ActionSheet.ios.js",
|
||||
"ActionSheetProvider.js",
|
||||
"connectActionSheet.js",
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"README.md"
|
||||
],
|
||||
"author": "Jesse Ruder <[email protected]>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/exponentjs/react-native-action-sheet/issues"
|
||||
"url": "https://github.com/expo/react-native-action-sheet/issues"
|
||||
},
|
||||
"homepage": "https://github.com/expo/react-native-action-sheet",
|
||||
"dependencies": {
|
||||
"hoist-non-react-statics": "^2.2.2",
|
||||
"prop-types": "^15.5.10"
|
||||
},
|
||||
"homepage": "https://github.com/exponentjs/react-native-action-sheet",
|
||||
"devDependencies": {
|
||||
"@types/react": "^16.4.6",
|
||||
"@types/react-native": "^0.56.0",
|
||||
"flow-bin": "^0.26.0",
|
||||
"react": "^15.2.0",
|
||||
"react": "^15.6.1",
|
||||
"react-native": "^0.28.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
ActionSheetProps,
|
||||
ActionSheetProvider,
|
||||
connectActionSheet
|
||||
} from "./index";
|
||||
import * as React from "react";
|
||||
|
||||
interface ChildOwnProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
type ChildProps = ChildOwnProps & ActionSheetProps;
|
||||
|
||||
class Child extends React.Component<ChildProps> {
|
||||
showMore = () => {
|
||||
this.props.showActionSheetWithOptions(
|
||||
{ options: ["Delete"] },
|
||||
buttonIndex => {
|
||||
console.log(buttonIndex);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return this.props.name;
|
||||
}
|
||||
}
|
||||
|
||||
const EnhancedChild = connectActionSheet(Child);
|
||||
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ActionSheetProvider>
|
||||
<EnhancedChild name="lool" />
|
||||
</ActionSheetProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user