Skip to content

Commit

Permalink
TextInput edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Saadnajmi committed Jul 8, 2023
1 parent 7187c08 commit dfa985d
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 134 deletions.
10 changes: 10 additions & 0 deletions React/Views/RCTView.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#import "RCTViewKeyboardEvent.h"
#if TARGET_OS_OSX // [macOS
#import "RCTTextView.h"
#import <React/RCTSinglelineTextInputView.h>
#import <React/RCTMultilineTextInputView.h>
#import <React/RCTUITextField.h>

#endif // macOS]

RCT_MOCK_DEF(RCTView, RCTContentInsets);
Expand Down Expand Up @@ -1763,6 +1767,12 @@ - (BOOL)handleKeyboardEventModern:(NSEvent*)event {

// To ensure we only dispatch one keyboard event to JS, only dispatch it if we are the first responder.
BOOL isFirstResponder = self == [[self window] firstResponder];
if ([self isKindOfClass:[RCTSinglelineTextInputView class]]) {
isFirstResponder = [(RCTUITextField *)[(RCTSinglelineTextInputView *)self backedTextInputView] currentEditor] == [[self window] firstResponder];
}
if ([self isKindOfClass:[RCTMultilineTextInputView class]]) {
isFirstResponder = [(RCTSinglelineTextInputView *)self backedTextInputView] == [[self window] firstResponder];
}
if (isFirstResponder) {
RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyEventFromEvent:event reactTag:self.reactTag];
[_eventDispatcher sendEvent:keyboardEvent];
Expand Down
6 changes: 4 additions & 2 deletions React/Views/RCTViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -526,10 +526,12 @@ - (RCTShadowView *)shadowView
RCT_EXPORT_VIEW_PROPERTY(onDragLeave, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDrop, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(passthroughAllKeyEvents, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTDirectEventBlock) // macOS keyboard events
RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTDirectEventBlock) // macOS keyboard events
RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray<RCTHandledKey *>)
RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray<RCTHandledKey *>)
RCT_EXPORT_VIEW_PROPERTY(keyDownEvents, NSArray<RCTHandledKey *>)
RCT_EXPORT_VIEW_PROPERTY(keyUpEvents, NSArray<RCTHandledKey *>)

#endif // macOS]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ const ReactNative = require('react-native');
import {Platform} from 'react-native';
import type {KeyEvent} from 'react-native/Libraries/Types/CoreEventTypes';

const {Button, ScrollView, StyleSheet, Switch, Text, TextInput, View} =
ReactNative;
const {Button, StyleSheet, Switch, Text, TextInput, View} = ReactNative;

const switchStyle = {
alignItems: 'center',
Expand Down Expand Up @@ -116,140 +115,150 @@ function KeyboardEventExample(): React.Node {
);

return (
<ScrollView>
<View style={{padding: 10}}>
<Text>
Key events are called when a component detects a key press.To tab
between views on macOS: Enable System Preferences / Keyboard /
Shortcuts > Use keyboard navigation to move focus between controls.
</Text>
<View>
{Platform.OS === 'macos' ? (
<>
<View style={switchStyle}>
<Text style={styles.title}>View</Text>
<Switch value={showView} onValueChange={toggleShowView} />
</View>
{showView ? (
<>
<Text style={styles.text}>
validKeysDown: [g, Escape, Enter, ArrowLeft]{'\n'}
validKeysUp: [c, d]
</Text>
<View
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={['g', 'Escape', 'Enter', 'ArrowLeft']}
keyDownEvents={['g', 'Escape', 'Enter', 'ArrowLeft']}
onKeyDown={handleKeyDown}
validKeysUp={['c', 'd']}
onKeyUp={handleKeyUp}
/>
</>
) : null}
<View style={switchStyle}>
<Text style={styles.title}>TextInput</Text>
<Switch
value={showTextInput}
onValueChange={toggleShowTextInput}
<View style={{padding: 10}}>
<Text>
Key events are called when a component detects a key press.To tab
between views on macOS: Enable System Preferences / Keyboard / Shortcuts
> Use keyboard navigation to move focus between controls.
</Text>
<View>
{Platform.OS === 'macos' ? (
<>
<View style={switchStyle}>
<Text style={styles.title}>View</Text>
<Switch value={showView} onValueChange={toggleShowView} />
</View>
{showView ? (
<>
<Text style={styles.text}>
validKeysDown: [g, Escape, Enter, ArrowLeft]{'\n'}
validKeysUp: [c, d]
</Text>
<View
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={['g', 'Escape', 'Enter', 'ArrowLeft']}
keyDownEvents={['g', 'Escape', 'Enter', 'ArrowLeft']}
onKeyDown={handleKeyDown}
validKeysUp={['c', 'd']}
onKeyUp={handleKeyUp}
/>
</View>
{showTextInput ? (
<>
<Text style={styles.text}>
validKeysDown: [ArrowRight, ArrowDown, Ctrl+Enter]{'\n'}
validKeysUp: [Escape, Enter]
</Text>
<TextInput
blurOnSubmit={false}
placeholder={'Singleline textInput'}
multiline={false}
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={[
'ArrowRight',
'ArrowDown',
{key: 'Enter', ctrlKey: true},
]}
onKeyDown={handleKeyDown}
validKeysUp={['Escape', 'Enter']}
onKeyUp={handleKeyUp}
/>
<TextInput
placeholder={'Multiline textInput'}
multiline={true}
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={[
'ArrowRight',
'ArrowDown',
{key: 'Enter', ctrlKey: true},
]}
onKeyDown={handleKeyDown}
validKeysUp={['Escape', 'Enter']}
onKeyUp={handleKeyUp}
/>
</>
) : null}
<View style={switchStyle}>
<Text style={styles.title}>TextInput with no handled keys</Text>
<Switch
value={showTextInput2}
onValueChange={toggleShowTextInput2}
</>
) : null}
<View style={switchStyle}>
<Text style={styles.title}>TextInput</Text>
<Switch
value={showTextInput}
onValueChange={toggleShowTextInput}
/>
</View>
{showTextInput ? (
<>
<Text style={styles.text}>
validKeysDown: [ArrowRight, ArrowDown, Ctrl+Enter]{'\n'}
validKeysUp: [Escape, Enter]
</Text>
<TextInput
blurOnSubmit={false}
placeholder={'Singleline textInput'}
multiline={false}
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={[
'ArrowRight',
'ArrowDown',
{key: 'Enter', ctrlKey: true},
]}
keyDownEvents={[
{key: 'ArrowRight'},
{key: 'ArrowDown'},
{key: 'Enter', ctrlKey: true},
]}
onKeyDown={handleKeyDown}
validKeysUp={['Escape', 'Enter']}
onKeyUp={handleKeyUp}
/>
</View>
{showTextInput2 ? (
<>
<Text style={styles.text}>
validKeysDown: []{'\n'}
validKeysUp: []
</Text>
<TextInput
blurOnSubmit={false}
placeholder={'Singleline textInput'}
multiline={false}
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={[]}
onKeyDown={handleKeyDown}
validKeysUp={[]}
onKeyUp={handleKeyUp}
/>
<TextInput
placeholder={'Multiline textInput'}
multiline={true}
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={[]}
onKeyDown={handleKeyDown}
validKeysUp={[]}
onKeyUp={handleKeyUp}
/>
</>
) : null}
</>
) : null}
<View style={switchStyle}>
<Text>{'Pass through all key events'}</Text>
<Switch
value={passthroughAllKeyEvents}
onValueChange={toggleSwitch}
/>
</View>
<Button
testID="event_clear_button"
onPress={clearLog}
title="Clear event log"
<TextInput
placeholder={'Multiline textInput'}
multiline={true}
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={[
'ArrowRight',
'ArrowDown',
{key: 'Enter', ctrlKey: true},
]}
keyDownEvents={[
{key: 'ArrowRight'},
{key: 'ArrowDown'},
{key: 'Enter', ctrlKey: true},
]}
onKeyDown={handleKeyDown}
validKeysUp={['Escape', 'Enter']}
onKeyUp={handleKeyUp}
/>
</>
) : null}
<View style={switchStyle}>
<Text style={styles.title}>TextInput with no handled keys</Text>
<Switch
value={showTextInput2}
onValueChange={toggleShowTextInput2}
/>
</View>
{showTextInput2 ? (
<>
<Text style={styles.text}>
validKeysDown: []{'\n'}
validKeysUp: []
</Text>
<TextInput
blurOnSubmit={false}
placeholder={'Singleline textInput'}
multiline={false}
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={[]}
keyDownEvents={[]}
onKeyDown={handleKeyDown}
validKeysUp={[]}
onKeyUp={handleKeyUp}
/>
<TextInput
placeholder={'Multiline textInput'}
multiline={true}
focusable={true}
style={styles.row}
passthroughAllKeyEvents={passthroughAllKeyEvents}
validKeysDown={[]}
keyDownEvents={[]}
onKeyDown={handleKeyDown}
validKeysUp={[]}
onKeyUp={handleKeyUp}
/>
</>
) : null}
</>
) : null}
<View style={switchStyle}>
<Text>{'Pass through all key events'}</Text>
<Switch
value={passthroughAllKeyEvents}
onValueChange={toggleSwitch}
/>
<Text>{'Events:\n' + log.join('\n')}</Text>
</View>
<Button
testID="event_clear_button"
onPress={clearLog}
title="Clear event log"
/>
<Text>{'Events:\n' + log.join('\n')}</Text>
</View>
</ScrollView>
</View>
);
}

Expand Down Expand Up @@ -287,5 +296,4 @@ exports.examples = [
return <KeyboardEventExample />;
},
},

];

0 comments on commit dfa985d

Please sign in to comment.