From 6ee0e2e4713537f8d53888f3f2b15c627d4704d1 Mon Sep 17 00:00:00 2001 From: James Gillmore Date: Fri, 15 Apr 2016 18:56:54 -0700 Subject: [PATCH 1/4] ModalActionSheet which can be displayed from anywhere in the component tree The idea behind this thin wrapper is that it allows you to put action sheet's anywhere in your component tree, not just in a component that consumes the entire screen. It's supposed to be a drop-in replacement for plain ActionSheet. --- modal.js | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 modal.js diff --git a/modal.js b/modal.js new file mode 100644 index 0000000..c646505 --- /dev/null +++ b/modal.js @@ -0,0 +1,53 @@ +import React, {Modal} from 'react-native'; +import ActionSheet from './sheet.js'; + + +/** +The idea behind this thin wrapper is that it allows you to put action sheet's anywhere in your component tree, +not just in a component that consumes the entire screen. It's supposed to be a drop-in replacement for plain +ActionSheet. +**/ + +export default class ModalActionSheet extends React.Component { + constructor(props, context) { + super(props, context); + this.state = { + modalVisible: this.props.visible || false, + sheetVisible: false, + } + } + + show() { + this.setState({modalVisible: true}); + } + hide() { + this.setState({modalVisible: false}); + } + + componentWillReceiveProps(nextProps) { + if(nextProps.visible && !this.props.visible) this.show(); + else if(!nextProps.visible && this.props.visible) this.hide(); + } + + render() { + return ( + this.setState({sheetVisible: true})} + onDismiss={() => this.setState({sheetVisible: false})} + > + + {this.props.children} + + + ); + } +} + +ModalActionSheet.Button = ActionSheet.Button; From 989ee173c213e099ca3541e29991290a41e9ea23 Mon Sep 17 00:00:00 2001 From: James Gillmore Date: Fri, 15 Apr 2016 18:59:16 -0700 Subject: [PATCH 2/4] export ModalActionSheet --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index 0b715a0..d998ff9 100644 --- a/index.js +++ b/index.js @@ -15,6 +15,7 @@ var { var Button = require('./button.js'); var Overlay = require('./overlay.js'); +var ModalActionSheet = require('./modal.js'); var Sheet = require('./sheet.js'); module.exports = React.createClass({ @@ -46,6 +47,7 @@ module.exports = React.createClass({ }, }); module.exports.Button = Button; +module.exports.ModalActionSheet = ModalActionSheet; var styles = StyleSheet.create({ actionSheetContainer: { From d8e73b09b4e8c9e36f4415ae66239ee13be8b4a1 Mon Sep 17 00:00:00 2001 From: James Gillmore Date: Fri, 15 Apr 2016 19:40:38 -0700 Subject: [PATCH 3/4] fixes to make slide-down animation work the modal was cutting the slide-down animation short. so now they are synced so that the action sheet slides down, and then the modal hides itself. A bit of hackery was necessary as the `onDismiss` callback of `Modal` isn't working in RN22. perhaps the `onRequestClose` callback `Modal` has in RN23 will come to the rescue, but it I did manually via `setTimeout` for now to guarantee it works across RN versions. --- modal.js | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/modal.js b/modal.js index c646505..b13de81 100644 --- a/modal.js +++ b/modal.js @@ -1,12 +1,9 @@ import React, {Modal} from 'react-native'; -import ActionSheet from './sheet.js'; +import ActionSheet from '@remobile/react-native-action-sheet'; -/** -The idea behind this thin wrapper is that it allows you to put action sheet's anywhere in your component tree, -not just in a component that consumes the entire screen. It's supposed to be a drop-in replacement for plain -ActionSheet. -**/ +//The idea behind this thin wrapper is that it allows you to put action sheet's anywhere in your component tree, +//not just in a component that consumes the entire screen. export default class ModalActionSheet extends React.Component { constructor(props, context) { @@ -17,16 +14,29 @@ export default class ModalActionSheet extends React.Component { } } + componentWillReceiveProps(nextProps) { + if(nextProps.visible && !this.props.visible) this.show(); + else if(!nextProps.visible && this.props.visible) this.hide(); + } + show() { this.setState({modalVisible: true}); } hide() { - this.setState({modalVisible: false}); - } + this.setState({sheetVisible: false}); + //allow ActionSheet to slide down animation to be seen before hiding modal - componentWillReceiveProps(nextProps) { - if(nextProps.visible && !this.props.visible) this.show(); - else if(!nextProps.visible && this.props.visible) this.hide(); + setTimeout(() => { + this.setState({modalVisible: false}, () => { + //If props.onCancel sets this.props.visible === false, this.hide() will be called 2x, but it doesn't really matter, since the sheet is already hidden. + //I was tempted to set the onCancel prop of to: onCancel={this.props.onCancel || this.hide.bind(this)} + //but I rather just provide stable somewhat imperative behavior where it always closes when you press the Cancel button, whether you provide + //onCancel as a prop or not, as it's unknown whether the user will use onCancel to actually toggle the ActionSheet's visibilty or perhaps + //only for other application-specific purposes. So this.hide() potentially being called twice is the tradeoff for guaranteeing it closes as user's + //still coming from the imperative style will often expect. + this.props.onCancel && this.props.onCancel(); + }); + }, 300); } render() { @@ -36,11 +46,11 @@ export default class ModalActionSheet extends React.Component { transparent={true} visible={this.state.modalVisible} onShow={() => this.setState({sheetVisible: true})} - onDismiss={() => this.setState({sheetVisible: false})} + //onDismiss={this.onDismiss} //not working in RN 22, so timers used instead; ideally onDismiss and onCancel are used in combination similar to onShow/show; perhaps in RN 23+ when onRequestClose works > {this.props.children} From b1909d681c0e42fd815e63a04825a0735a546e0c Mon Sep 17 00:00:00 2001 From: James Gillmore Date: Sat, 16 Apr 2016 12:05:22 -0700 Subject: [PATCH 4/4] make completely declarative --- modal.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/modal.js b/modal.js index b13de81..aa6e9e6 100644 --- a/modal.js +++ b/modal.js @@ -20,6 +20,7 @@ export default class ModalActionSheet extends React.Component { } show() { + console.log('SHOW') this.setState({modalVisible: true}); } hide() { @@ -27,15 +28,7 @@ export default class ModalActionSheet extends React.Component { //allow ActionSheet to slide down animation to be seen before hiding modal setTimeout(() => { - this.setState({modalVisible: false}, () => { - //If props.onCancel sets this.props.visible === false, this.hide() will be called 2x, but it doesn't really matter, since the sheet is already hidden. - //I was tempted to set the onCancel prop of to: onCancel={this.props.onCancel || this.hide.bind(this)} - //but I rather just provide stable somewhat imperative behavior where it always closes when you press the Cancel button, whether you provide - //onCancel as a prop or not, as it's unknown whether the user will use onCancel to actually toggle the ActionSheet's visibilty or perhaps - //only for other application-specific purposes. So this.hide() potentially being called twice is the tradeoff for guaranteeing it closes as user's - //still coming from the imperative style will often expect. - this.props.onCancel && this.props.onCancel(); - }); + this.setState({modalVisible: false}); }, 300); } @@ -50,7 +43,7 @@ export default class ModalActionSheet extends React.Component { > {this.props.children}