react-native-ui-lib
Version:
[](https://stand-with-ukraine.pp.ua)
163 lines • 5.07 kB
JavaScript
import _map from "lodash/map";
import _isEmpty from "lodash/isEmpty";
import _filter from "lodash/filter";
import _isFunction from "lodash/isFunction";
import React, { Component } from 'react';
import { ActionSheetIOS, StyleSheet } from 'react-native';
import { Colors } from "../../style";
import { asBaseComponent, Constants } from "../../commons/new";
import View from "../view";
import Text from "../text";
import Image from "../image";
//@ts-ignore
import ListItem from "../listItem";
import Dialog from "../dialog";
const VERTICAL_PADDING = 8;
/**
* @description: Cross platform Action Sheet, with a support for native iOS solution
* @gif: https://media.giphy.com/media/l0HUpXOR6RqB2ct5S/giphy.gif
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/ActionSheetScreen.tsx
*/
class ActionSheet extends Component {
static displayName = 'ActionSheet';
constructor(props) {
super(props);
this.onOptionPress = this.onOptionPress.bind(this);
this.renderAction = this.renderAction.bind(this);
}
componentDidUpdate(prevProps) {
const {
useNativeIOS
} = this.props;
const wasVisible = prevProps.visible;
const willBeVisible = this.props.visible;
if (!wasVisible && willBeVisible && useNativeIOS && Constants.isIOS) {
const {
title,
message,
cancelButtonIndex,
destructiveButtonIndex,
options,
showCancelButton
} = this.props;
const optionsArray = options !== undefined ? options : [];
let cancelBtnIndex = cancelButtonIndex;
if (showCancelButton) {
optionsArray.push({
label: 'Cancel'
});
cancelBtnIndex = optionsArray.length - 1;
}
ActionSheetIOS.showActionSheetWithOptions({
title,
message,
options: optionsArray.map(option => option?.label || ''),
cancelButtonIndex: cancelBtnIndex,
destructiveButtonIndex
}, this.onOptionPress);
}
}
onOptionPress(optionIndex) {
this.props.options?.[optionIndex].onPress?.();
this.props.onDismiss?.();
}
handleRenderIcon = option => {
// @ts-ignore
let source = option.icon;
if (!source) {
source = _isFunction(option.iconSource) ? option.iconSource() : option.iconSource;
}
return source && this.renderIcon(source);
};
renderIcon(iconSource) {
return <Image source={iconSource} resizeMode={'contain'} style={{
width: 20,
height: 20,
marginRight: 16
}} />;
}
renderAction(option, index) {
return <ListItem style={{
backgroundColor: 'transparent'
}} height={48} key={index} testID={option.testID} onPress={() => this.onOptionPress(index)} activeBackgroundColor={Colors.$backgroundNeutralLight}>
<View row paddingL-16 flex centerV>
{this.handleRenderIcon(option)}
<Text text70 $textDefault numberOfLines={1} style={option.labelStyle}>
{option.label}
</Text>
</View>
</ListItem>;
}
renderActions() {
const {
title,
options,
cancelButtonIndex,
renderAction,
optionsStyle
} = this.props;
const optionsToRender = _filter(options, (_option, index) => index !== cancelButtonIndex);
return <View style={[_isEmpty(title) ? styles.listNoTitle : styles.listWithTitle, optionsStyle]}>
{_isFunction(renderAction) ? optionsToRender.map((option, index) => renderAction(option, index, this.onOptionPress)) : _map(optionsToRender, this.renderAction)}
</View>;
}
renderTitle() {
const {
title
} = this.props;
if (!_isEmpty(title)) {
return <View height={56} paddingL-16 centerV>
<Text $textNeutralLight text70 style={{
alignSelf: 'flex-start'
}}>
{title}
</Text>
</View>;
}
}
renderSheet() {
const {
renderTitle
} = this.props;
const {
containerStyle
} = this.props;
return <View style={[styles.sheet, containerStyle]}>
{_isFunction(renderTitle) ? renderTitle() : this.renderTitle()}
{this.renderActions()}
</View>;
}
render() {
const {
visible,
onDismiss,
dialogStyle,
testID,
useSafeArea,
dialogProps
} = this.props;
return <Dialog bottom centerH width="100%" direction={Dialog.directions.DOWN} {...dialogProps} useSafeArea={useSafeArea} testID={testID} containerStyle={[styles.incubatorDialog, dialogStyle]} visible={visible} onDismiss={onDismiss}>
{this.renderSheet()}
</Dialog>;
}
}
export default asBaseComponent(ActionSheet);
const styles = StyleSheet.create({
sheet: {
backgroundColor: Colors.$backgroundDefault
},
dialog: {
backgroundColor: Colors.$backgroundDefault
},
incubatorDialog: {
backgroundColor: Colors.$backgroundDefault,
marginBottom: 0
},
listWithTitle: {
paddingBottom: VERTICAL_PADDING
},
listNoTitle: {
paddingTop: VERTICAL_PADDING,
paddingBottom: VERTICAL_PADDING
}
});