diff --git a/src/index.js b/src/index.js index b7ce7b12..04bae2ac 100644 --- a/src/index.js +++ b/src/index.js @@ -10,9 +10,9 @@ import { Dimensions } from 'react-native'; // This height was tested thoroughly on several iPhone Models (from iPhone 8 to 14 Pro) const IOS_MODAL_HEIGHT = 262; -const preserveSpaces = (label) => { +const preserveSpaces = (label) => { return label.replace(/ /g, '\u00a0'); - } +}; export default class RNPickerSelect extends PureComponent { static propTypes = { @@ -151,6 +151,7 @@ export default class RNPickerSelect extends PureComponent { this.scrollToInput = this.scrollToInput.bind(this); this.togglePicker = this.togglePicker.bind(this); this.renderInputAccessoryView = this.renderInputAccessoryView.bind(this); + this.updatePickerState = this.updatePickerState.bind(this); } componentDidUpdate = (prevProps, prevState) => { @@ -264,23 +265,10 @@ export default class RNPickerSelect extends PureComponent { } } - togglePicker(animate = false, postToggleCallback) { - const { modalProps, disabled } = this.props; - const { showPicker } = this.state; - - if (disabled) { - return; - } - - if (!showPicker) { - Keyboard.dismiss(); - } - + updatePickerState = (animate = false, postToggleCallback) => { + const { modalProps } = this.props; const animationType = modalProps && modalProps.animationType ? modalProps.animationType : 'slide'; - - this.triggerOpenCloseCallbacks(); - this.setState( (prevState) => { return { @@ -294,6 +282,26 @@ export default class RNPickerSelect extends PureComponent { } } ); + }; + + togglePicker(animate = false, postToggleCallback) { + const { disabled } = this.props; + + if (disabled) { + return; + } + + this.triggerOpenCloseCallbacks(); + + if (Keyboard.isVisible()) { + const keyboardListener = Keyboard.addListener('keyboardDidHide', () => { + this.updatePickerState(animate, postToggleCallback); + keyboardListener.remove(); + }); + Keyboard.dismiss(); + } else { + this.updatePickerState(animate, postToggleCallback); + } } renderPickerItems() { diff --git a/test/test.js b/test/test.js index b5e6a6c9..804388c6 100644 --- a/test/test.js +++ b/test/test.js @@ -42,6 +42,8 @@ describe('RNPickerSelect', () => { beforeEach(() => { jest.resetAllMocks(); jest.spyOn(Keyboard, 'dismiss'); + jest.spyOn(Keyboard, 'addListener'); + Keyboard.isVisible = jest.fn().mockReturnValue(false); }); describe('when provided an itemKey prop', () => { @@ -144,6 +146,25 @@ describe('RNPickerSelect', () => { expect(wrapper.state().showPicker).toEqual(true); }); + it('should call Keyboard.addListener when keyboard is visible', () => { + Keyboard.isVisible.mockReturnValue(true); + const wrapper = shallow(); + + const touchable = wrapper.find('TouchableOpacity').at(1); + touchable.simulate('press'); + expect(Keyboard.addListener).toHaveBeenCalledTimes(1); + expect(Keyboard.addListener).toHaveBeenCalledWith('keyboardDidHide', expect.any(Function)); + }); + + it('should not call Keyboard.addListener when keyboard is not visible', () => { + Keyboard.isVisible.mockReturnValue(false); + const wrapper = shallow(); + + const touchable = wrapper.find('TouchableOpacity').at(1); + touchable.simulate('press'); + expect(Keyboard.addListener).not.toHaveBeenCalled(); + }); + it('should not show the picker when pressed if disabled', () => { const wrapper = shallow( { }); it('should call Keyboard.dismiss when opened', () => { + Keyboard.isVisible.mockReturnValue(true); const wrapper = shallow(); const touchable = wrapper.find('[testID="ios_touchable_wrapper"]');