From b8855aca87094bb518b724bb60e1f06d464c4ee6 Mon Sep 17 00:00:00 2001 From: Henning Hall Date: Sun, 19 Feb 2023 18:40:17 +0100 Subject: [PATCH] fix: prevent closing parent modal on picker modal close (#611) * fix: modal in modal issue * chore: fix xcode warnings * refactor open/close modal logic --- ios/RNDatePicker/RNDatePickerManager.m | 10 +++--- src/DatePickerAndroid.js | 41 ++++++++++++++---------- src/DatePickerIOS.js | 43 ++++++++++++++------------ src/modal.js | 16 ++++++++++ 4 files changed, 68 insertions(+), 42 deletions(-) create mode 100644 src/modal.js diff --git a/ios/RNDatePicker/RNDatePickerManager.m b/ios/RNDatePicker/RNDatePickerManager.m index b19c62c..74f6abf 100644 --- a/ios/RNDatePicker/RNDatePickerManager.m +++ b/ios/RNDatePicker/RNDatePickerManager.m @@ -156,11 +156,11 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *) props } // Finding the top view controller which is neccessary to be able to show the picker from within modal - _topViewController = rootViewController; - while (_topViewController.presentedViewController){ - _topViewController = _topViewController.presentedViewController; + self->_topViewController = rootViewController; + while (self->_topViewController.presentedViewController){ + self->_topViewController = self->_topViewController.presentedViewController; } - [_topViewController presentViewController:alertController animated:YES completion:nil]; + [self->_topViewController presentViewController:alertController animated:YES completion:nil]; }); } @@ -168,7 +168,7 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *) props RCT_EXPORT_METHOD(closePicker) { dispatch_async(dispatch_get_main_queue(), ^{ - [_topViewController dismissViewControllerAnimated:YES completion:nil]; + [self->_topViewController dismissViewControllerAnimated:YES completion:nil]; }); } diff --git a/src/DatePickerAndroid.js b/src/DatePickerAndroid.js index 8ed7134..25f88e3 100644 --- a/src/DatePickerAndroid.js +++ b/src/DatePickerAndroid.js @@ -1,5 +1,6 @@ import React from 'react' -import { requireNativeComponent, NativeModules } from 'react-native' +import { NativeModules, requireNativeComponent } from 'react-native' +import { shouldCloseModal, shouldOpenModal } from './modal' function addMinutes(date, minutesToAdd) { return new Date(date.valueOf() + minutesToAdd * 60 * 1000) @@ -18,27 +19,27 @@ const defaultWidth = 310 class DatePickerAndroid extends React.PureComponent { render() { const props = this.getProps() - const isClosed = this._isCurrentlyClosed(); - - this.previousProps = props; - if (props.modal) { - if (props.open && isClosed) { - NativeModules.RNDatePicker.openPicker( - props, - this._onConfirm, - this.props.onCancel - ) - } else if (!props.open && !isClosed) { - NativeModules.RNDatePicker.closePicker() - } - return null + + if (shouldOpenModal(props, this.previousProps)) { + this.isClosing = false + NativeModules.RNDatePicker.openPicker( + props, + this._onConfirm, + this._onCancel + ) + } + if (shouldCloseModal(props, this.previousProps, this.isClosing)) { + this.closing = true + NativeModules.RNDatePicker.closePicker() } + this.previousProps = props + + if (props.modal) return null + return } - _isCurrentlyClosed = () => !this.previousProps || !this.previousProps.open - getProps = () => ({ ...this.props, date: this._date(), @@ -85,8 +86,14 @@ class DatePickerAndroid extends React.PureComponent { } _onConfirm = (isoDate) => { + this.isClosing = true this.props.onConfirm(this._fromIsoWithTimeZoneOffset(isoDate)) } + + _onCancel = () => { + this.isClosing = true + this.props.onCancel() + } } export default DatePickerAndroid diff --git a/src/DatePickerIOS.js b/src/DatePickerIOS.js index 6821643..a8284f3 100644 --- a/src/DatePickerIOS.js +++ b/src/DatePickerIOS.js @@ -1,9 +1,6 @@ import React from 'react' -import { - StyleSheet, - requireNativeComponent, - NativeModules, -} from 'react-native' +import { StyleSheet, requireNativeComponent, NativeModules } from 'react-native' +import { shouldCloseModal, shouldOpenModal } from './modal' const RCTDatePickerIOS = requireNativeComponent('RNDatePicker') @@ -40,27 +37,35 @@ export default class DatePickerIOS extends React.Component { } _onConfirm = ({ timestamp }) => { + this.isClosing = true this.props.onConfirm(new Date(timestamp)) } + _onCancel = () => { + this.isClosing = true + this.props.onCancel() + } + render() { const props = this._toIosProps(this.props) - const isClosed = this._isCurrentlyClosed(); - this.previousProps = props; - if (props.modal) { - if (props.open && isClosed) { - NativeModules.RNDatePickerManager.openPicker( - props, - this._onConfirm, - props.onCancel - ) - } else if (!props.open && !isClosed) { - NativeModules.RNDatePickerManager.closePicker() - } - return null + if (shouldOpenModal(props, this.previousProps)) { + this.isClosing = false + NativeModules.RNDatePickerManager.openPicker( + props, + this._onConfirm, + this._onCancel + ) + } + if (shouldCloseModal(props, this.previousProps, this.isClosing)) { + this.isClosing = true + NativeModules.RNDatePickerManager.closePicker() } + this.previousProps = props + + if (props.modal) return null + return ( ) } - - _isCurrentlyClosed = () => !this.previousProps || !this.previousProps.open } const styles = StyleSheet.create({ diff --git a/src/modal.js b/src/modal.js new file mode 100644 index 0000000..0b4ba32 --- /dev/null +++ b/src/modal.js @@ -0,0 +1,16 @@ +export const shouldOpenModal = (props, prevProps) => { + if (!props.modal) return false + if (!props.open) return false + const currentlyOpen = prevProps?.open + if (currentlyOpen) return false + return true +} + +export const shouldCloseModal = (props, prevProps, isClosing) => { + if (!props.modal) return false + if (props.open) return false + const currentlyOpen = prevProps?.open + if (!currentlyOpen) return false + if (isClosing) return false + return true +}