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 | |
|---|---|---|---|
|
|
a34f3a95f3 | ||
|
|
929cadc442 | ||
|
|
2fc359b9c0 | ||
|
|
945028d34f | ||
|
|
98b318c94d | ||
|
|
ed82cb0047 | ||
|
|
bf5b9680aa | ||
|
|
cbba57e9c7 | ||
|
|
ebd285c342 | ||
|
|
dad86d74e8 | ||
|
|
f1b58141b0 | ||
|
|
dbd9da903c | ||
|
|
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 | ||
|
|
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
|
||||
+113
-74
@@ -1,37 +1,40 @@
|
||||
// @flow
|
||||
|
||||
import React, { PropTypes } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Animated,
|
||||
BackAndroid,
|
||||
BackHandler,
|
||||
Easing,
|
||||
PixelRatio,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
Text,
|
||||
Image,
|
||||
NativeModules,
|
||||
TouchableOpacity,
|
||||
TouchableNativeFeedback,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
ScrollView,
|
||||
} from 'react-native';
|
||||
|
||||
// Not everybody has this enabled yet
|
||||
const useNativeDriver = !!NativeModules.NativeAnimatedModule;
|
||||
|
||||
type ActionSheetOptions = {
|
||||
options: Array<string>,
|
||||
icons: ?Array<number>,
|
||||
destructiveButtonIndex: ?number,
|
||||
cancelButtonIndex: ?number,
|
||||
}
|
||||
textStyle: ?any,
|
||||
};
|
||||
|
||||
type ActionGroupProps = {
|
||||
options: Array<string>,
|
||||
icons: ?Array<number>,
|
||||
destructiveButtonIndex: ?number,
|
||||
onSelect: (i: number) => boolean,
|
||||
startIndex: number,
|
||||
length: number,
|
||||
}
|
||||
textStyle: ?any,
|
||||
};
|
||||
|
||||
type ActionSheetState = {
|
||||
isVisible: boolean,
|
||||
@@ -40,33 +43,40 @@ 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)
|
||||
|
||||
class ActionGroup extends React.Component {
|
||||
props: ActionGroupProps;
|
||||
|
||||
static propTypes = {
|
||||
options: PropTypes.array.isRequired,
|
||||
icons: PropTypes.array,
|
||||
destructiveButtonIndex: PropTypes.number,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
startIndex: PropTypes.number.isRequired,
|
||||
length: PropTypes.number.isRequired,
|
||||
textStyle: Text.propTypes.style,
|
||||
};
|
||||
|
||||
render() {
|
||||
let {
|
||||
options,
|
||||
icons,
|
||||
destructiveButtonIndex,
|
||||
onSelect,
|
||||
startIndex,
|
||||
length,
|
||||
textStyle,
|
||||
} = this.props;
|
||||
|
||||
let optionViews = [];
|
||||
@@ -77,9 +87,19 @@ class ActionGroup extends React.Component {
|
||||
);
|
||||
|
||||
for (let i = startIndex; i < startIndex + length; i++) {
|
||||
let color = '#444444';
|
||||
let color = '#212121';
|
||||
if (i === destructiveButtonIndex) {
|
||||
color = '#ff3b30';
|
||||
color = '#d32f2f';
|
||||
}
|
||||
|
||||
let iconElement = undefined;
|
||||
|
||||
if (icons && icons[i]) {
|
||||
const iconStyle = [styles.icon]
|
||||
if (textStyle.color !== undefined && textStyle.color !== null) {
|
||||
iconStyle.push({ tintColor: textStyle.color })
|
||||
}
|
||||
iconElement = <Image source={icons[i]} resizeMode="contain" style={iconStyle} />;
|
||||
}
|
||||
|
||||
optionViews.push(
|
||||
@@ -89,22 +109,19 @@ 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, { color }, textStyle]}>{options[i]}</Text>
|
||||
</TouchableNativeFeedbackSafe>
|
||||
);
|
||||
|
||||
if (i < startIndex + length - 1) {
|
||||
optionViews.push(
|
||||
<View key={`separator-${i}`} style={styles.rowSeparator} />
|
||||
);
|
||||
optionViews.push(<View key={`separator-${i}`} style={styles.rowSeparator} />);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.groupContainer}>
|
||||
{optionViews}
|
||||
<ScrollView>{optionViews}</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -113,6 +130,7 @@ class ActionGroup extends React.Component {
|
||||
// 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 = {
|
||||
@@ -127,15 +145,20 @@ export default class ActionSheet extends React.Component {
|
||||
render() {
|
||||
let { isVisible } = this.state;
|
||||
let overlay = isVisible ? (
|
||||
<Animated.View style={[styles.overlay, {
|
||||
opacity: this.state.overlayOpacity,
|
||||
}]} />
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.overlay,
|
||||
{
|
||||
opacity: this.state.overlayOpacity,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
let sheet = isVisible ? this._renderSheet() : null;
|
||||
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<View style={{ flex: 1 }}>
|
||||
{React.Children.only(this.props.children)}
|
||||
{overlay}
|
||||
{sheet}
|
||||
@@ -154,17 +177,30 @@ export default class ActionSheet extends React.Component {
|
||||
<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}>
|
||||
style={[
|
||||
styles.sheetContainer,
|
||||
{
|
||||
opacity: this.state.sheetOpacity,
|
||||
transform: [
|
||||
{
|
||||
translateY: this.state.sheetOpacity.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [this._actionSheetHeight, 0],
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
]}>
|
||||
<View style={styles.sheet}
|
||||
onLayout={(event) => { this._actionSheetHeight = event.nativeEvent.layout.height }}>
|
||||
<ActionGroup
|
||||
options={this.state.options.options}
|
||||
icons={this.state.options.icons}
|
||||
destructiveButtonIndex={this.state.options.destructiveButtonIndex}
|
||||
onSelect={this._onSelect}
|
||||
startIndex={0}
|
||||
length={numOptions}
|
||||
textStyle={this.state.options.textStyle}
|
||||
/>
|
||||
</View>
|
||||
</Animated.View>
|
||||
@@ -193,16 +229,16 @@ export default class ActionSheet extends React.Component {
|
||||
|
||||
Animated.parallel([
|
||||
Animated.timing(this.state.overlayOpacity, {
|
||||
toValue: 0.5,
|
||||
easing: Easing.in(Easing.linear),
|
||||
duration: OPACITY_ANIMATION_TIME,
|
||||
useNativeDriver,
|
||||
toValue: 0.2,
|
||||
easing: EASING_OUT,
|
||||
duration: OPACITY_ANIMATION_IN_TIME,
|
||||
useNativeDriver: this.props.useNativeDriver,
|
||||
}),
|
||||
Animated.timing(this.state.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,12 +250,15 @@ 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;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof this.state.options.cancelButtonIndex === 'number') {
|
||||
@@ -227,7 +266,7 @@ export default class ActionSheet extends React.Component {
|
||||
} else {
|
||||
return this._animateOut();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_onSelect = (index: number): boolean => {
|
||||
if (this.state.isAnimating) {
|
||||
@@ -236,14 +275,17 @@ export default class ActionSheet extends React.Component {
|
||||
|
||||
this.state.onSelect && this.state.onSelect(index);
|
||||
return this._animateOut();
|
||||
}
|
||||
};
|
||||
|
||||
_animateOut = (): boolean => {
|
||||
if (this.state.isAnimating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BackAndroid.removeEventListener('actionSheetHardwareBackPress', this._selectCancelButton);
|
||||
BackHandler.removeEventListener(
|
||||
'actionSheetHardwareBackPress',
|
||||
this._selectCancelButton
|
||||
);
|
||||
|
||||
this.setState({
|
||||
isAnimating: true,
|
||||
@@ -252,15 +294,15 @@ export default class ActionSheet extends React.Component {
|
||||
Animated.parallel([
|
||||
Animated.timing(this.state.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, {
|
||||
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 +318,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 +336,6 @@ if (TouchableComponent !== TouchableNativeFeedback) {
|
||||
}
|
||||
|
||||
class TouchableNativeFeedbackSafe extends React.Component {
|
||||
|
||||
static SelectableBackground = TouchableComponent.SelectableBackground;
|
||||
static SelectableBackgroundBorderless = TouchableComponent.SelectableBackgroundBorderless;
|
||||
static Ripple = TouchableComponent.Ripple;
|
||||
@@ -303,17 +344,11 @@ 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>;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,22 +356,26 @@ class TouchableNativeFeedbackSafe extends React.Component {
|
||||
let styles = StyleSheet.create({
|
||||
groupContainer: {
|
||||
backgroundColor: '#fefefe',
|
||||
borderRadius: 4,
|
||||
borderColor: '#cbcbcb',
|
||||
borderWidth: PIXEL,
|
||||
borderColor: '#ffffff',
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
overflow: 'hidden',
|
||||
marginHorizontal: 16,
|
||||
marginBottom: 8,
|
||||
paddingVertical: 8,
|
||||
},
|
||||
button: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-start',
|
||||
height: 50,
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
height: 48,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
icon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
marginRight: 32,
|
||||
},
|
||||
text: {
|
||||
fontSize: 17,
|
||||
fontWeight: '700',
|
||||
fontSize: 16,
|
||||
textAlignVertical: 'center',
|
||||
},
|
||||
rowSeparator: {
|
||||
backgroundColor: '#dddddd',
|
||||
@@ -358,7 +397,7 @@ let styles = StyleSheet.create({
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
backgroundColor: 'transparent',
|
||||
alignItems: 'center',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
|
||||
+2
-9
@@ -1,18 +1,11 @@
|
||||
'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) {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ActionSheet from './ActionSheet';
|
||||
|
||||
export default class ActionSheetProvider extends React.Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any,
|
||||
};
|
||||
|
||||
static childContextTypes = {
|
||||
showActionSheetWithOptions: PropTypes.func,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
showActionSheetWithOptions: (...args) =>
|
||||
this._actionSheetRef.showActionSheetWithOptions(...args),
|
||||
};
|
||||
}
|
||||
|
||||
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,67 @@
|
||||
# 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`
|
||||
|
||||
```es6
|
||||
_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.props.showActionSheetWithOptions({
|
||||
options,
|
||||
cancelButtonIndex,
|
||||
destructiveButtonIndex,
|
||||
},
|
||||
(buttonIndex) => {
|
||||
// Do something here depending on the button index selected
|
||||
});
|
||||
|
||||
_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
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Try it out
|
||||
|
||||
Try it in Expo: https://expo.io/@community/react-native-action-sheet-example
|
||||
|
||||
## Usage
|
||||
|
||||
[See the example app source](https://github.com/expo/react-native-action-sheet/tree/master/example)
|
||||
@@ -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.*
|
||||
@@ -0,0 +1,60 @@
|
||||
import Expo from 'expo';
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { Entypo } from '@expo/vector-icons';
|
||||
import { ActionSheetProvider, connectActionSheet } from '@expo/react-native-action-sheet';
|
||||
|
||||
export default class AppContainer extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ActionSheetProvider>
|
||||
<App />
|
||||
</ActionSheetProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@connectActionSheet
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={{ marginBottom: 30 }}>
|
||||
<Text style={{ textAlign: 'center' }}>
|
||||
Hello! This is a simple example app to demonstrate @expo/react-native-action-sheet.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Entypo.Button name="code" backgroundColor="#3e3e3e" onPress={this._onOpenActionSheet}>
|
||||
<Text style={{ fontSize: 15, color: '#fff' }}>Open action sheet</Text>
|
||||
</Entypo.Button>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_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.props.showActionSheetWithOptions(
|
||||
{
|
||||
options,
|
||||
cancelButtonIndex,
|
||||
destructiveButtonIndex,
|
||||
},
|
||||
buttonIndex => {
|
||||
// Do something here depending on the button index selected
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
});
|
||||
@@ -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": "1.1.2",
|
||||
"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