Skip to content

Commit 3037414

Browse files
committed
new keyboard events example
1 parent 8a4e398 commit 3037414

File tree

1 file changed

+168
-103
lines changed

1 file changed

+168
-103
lines changed

packages/rn-tester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js

Lines changed: 168 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import type {KeyEvent} from 'react-native/Libraries/Types/CoreEventTypes';
1515
import * as React from 'react';
1616

1717
import {
18-
Button,
1918
Pressable,
2019
StyleSheet,
2120
Switch,
@@ -128,132 +127,149 @@ function BubblingExample(): React.Node {
128127
}
129128

130129
function KeyboardEventExample(): React.Node {
131-
const viewRef = React.useRef<React.ElementRef<typeof View> | null>(null);
132-
const [log, setLog] = React.useState<Array<string>>([]);
130+
const pressableRef = React.useRef<React.ElementRef<typeof Pressable> | null>(null);
131+
const [eventLog, setEventLog] = React.useState<Array<string>>([]);
133132

134-
const clearLog = React.useCallback(() => {
135-
setLog([]);
136-
}, [setLog]);
133+
function appendEvent(eventName: string, source?: string) {
134+
const limit = 12;
135+
setEventLog((current: Array<string>) => {
136+
const prefix = source != null ? `${source}: ` : '';
137+
return [`${prefix}${eventName}`].concat(current.slice(0, limit - 1));
138+
});
139+
}
137140

138-
const appendLog = React.useCallback(
139-
(line: string) => {
140-
const limit = 12;
141-
const newLog = log.slice(0, limit - 1);
142-
newLog.unshift(line);
143-
setLog(newLog);
141+
const handleSingleLineKeyDown = React.useCallback(
142+
(e: KeyEvent) => {
143+
appendEvent(`keyDown: ${e.nativeEvent.key}`, 'Single-line TextInput');
144144
},
145-
[log, setLog],
145+
[],
146146
);
147147

148-
const handleKeyDown = React.useCallback(
148+
const handleSingleLineKeyUp = React.useCallback(
149149
(e: KeyEvent) => {
150-
appendLog('Key Down:' + e.nativeEvent.key);
150+
appendEvent(`keyUp: ${e.nativeEvent.key}`, 'Single-line TextInput');
151151
},
152-
[appendLog],
152+
[],
153153
);
154154

155-
const handleKeyUp = React.useCallback(
155+
const handleMultiLineKeyDown = React.useCallback(
156156
(e: KeyEvent) => {
157-
appendLog('Key Up:' + e.nativeEvent.key);
157+
appendEvent(`keyDown: ${e.nativeEvent.key}`, 'Multi-line TextInput');
158158
},
159-
[appendLog],
159+
[],
160160
);
161161

162-
const viewText =
163-
"keyDownEvents: [{key: 'g'}, {key: 'Escape'}, {key: 'Enter'}, {key: 'ArrowLeft'}] \nkeyUpEvents: [{key: 'c'}, {key: 'd'}]";
164-
const viewKeyboardProps = {
165-
onKeyDown: handleKeyDown,
166-
keyDownEvents: [
167-
{key: 'g'},
168-
{key: 'Escape'},
169-
{key: 'Enter'},
170-
{key: 'ArrowLeft'},
171-
],
172-
onKeyUp: handleKeyUp,
173-
keyUpEvents: [{key: 'c'}, {key: 'd'}],
174-
};
175-
176-
const textInputText =
177-
"keyDownEvents: [{key: 'ArrowRight'}, {key: 'ArrowDown'}, {key: 'Enter', ctrlKey: true}, \nkeyUpEvents: [{key: 'Escape'}, {key: 'Enter'}]";
178-
const textInputKeyboardProps = {
179-
onKeyDown: handleKeyDown,
180-
keyDownEvents: [
181-
{key: 'ArrowRight'},
182-
{key: 'ArrowDown'},
183-
{key: 'Enter', ctrlKey: true},
184-
],
185-
onKeyUp: handleKeyUp,
186-
keyUpEvents: [{key: 'Escape'}, {key: 'Enter'}],
187-
};
162+
const handleMultiLineKeyUp = React.useCallback(
163+
(e: KeyEvent) => {
164+
appendEvent(`keyUp: ${e.nativeEvent.key}`, 'Multi-line TextInput');
165+
},
166+
[],
167+
);
188168

189-
const textInputUnhandledText =
190-
"keyDownEvents: [{key: 'ArrowRight'}, {key: 'ArrowDown'}, {key: 'Enter', ctrlKey: true}, \nkeyUpEvents: [{key: 'Escape'}, {key: 'Enter'}]";
191-
const textInputunHandledKeyboardProps = {
192-
onKeyDown: handleKeyDown,
193-
onKeyUp: handleKeyUp,
194-
};
169+
const handlePressableKeyDown = React.useCallback(
170+
(e: KeyEvent) => {
171+
appendEvent(`keyDown: ${e.nativeEvent.key}`, 'Focusable Pressable');
172+
},
173+
[],
174+
);
195175

196-
React.useEffect(() => {
197-
// Focus the first view on mount
198-
viewRef.current?.focus();
199-
}, []);
176+
const handlePressableKeyUp = React.useCallback(
177+
(e: KeyEvent) => {
178+
appendEvent(`keyUp: ${e.nativeEvent.key}`, 'Focusable Pressable');
179+
},
180+
[],
181+
);
200182

201183
return (
202-
<View
203-
style={{
204-
padding: 10,
205-
}}>
206-
<Text>
207-
Key events are called when a component detects a key press.To tab
208-
between views on macOS: Enable System Preferences / Keyboard / Shortcuts{' '}
209-
{'>'} Use keyboard navigation to move focus between controls.
184+
<View style={{marginTop: 10}}>
185+
<Text style={styles.description}>
186+
Examples of keyboard event handling with keyDownEvents and keyUpEvents arrays.
210187
</Text>
211-
<View>
212-
<Text style={styles.text}>{viewText}</Text>
213-
<View
214-
ref={viewRef}
215-
focusable={true}
216-
style={styles.input}
217-
{...viewKeyboardProps}
218-
/>
219-
<Text style={styles.text}>{textInputText}</Text>
188+
189+
<View style={styles.inputContainer}>
190+
<Text style={styles.inputLabel}>
191+
Single-line TextInput (keyDownEvents: g, Escape, Enter, ArrowLeft)
192+
</Text>
220193
<TextInput
221-
blurOnSubmit={false}
222-
placeholder={'Singleline textInput'}
223-
multiline={false}
224-
focusable={true}
225-
style={styles.input}
226-
{...textInputKeyboardProps}
194+
style={styles.styledTextInput}
195+
placeholder="Type here and press g, Escape, Enter, or ArrowLeft"
196+
placeholderTextColor="#999"
197+
onKeyDown={handleSingleLineKeyDown}
198+
onKeyUp={handleSingleLineKeyUp}
199+
keyDownEvents={[
200+
{key: 'g'},
201+
{key: 'Escape'},
202+
{key: 'Enter'},
203+
{key: 'ArrowLeft'},
204+
]}
205+
keyUpEvents={[{key: 'c'}, {key: 'd'}]}
227206
/>
207+
</View>
208+
209+
<View style={styles.inputContainer}>
210+
<Text style={styles.inputLabel}>
211+
Multi-line TextInput (keyDownEvents: ArrowRight, ArrowDown, Cmd+Enter)
212+
</Text>
228213
<TextInput
229-
placeholder={'Multiline textInput'}
214+
style={[styles.styledTextInput, styles.multilineInput]}
215+
placeholder="Multi-line input - try arrow keys and Cmd+Enter"
216+
placeholderTextColor="#999"
230217
multiline={true}
231-
focusable={true}
232-
style={styles.input}
233-
{...textInputKeyboardProps}
218+
onKeyDown={handleMultiLineKeyDown}
219+
onKeyUp={handleMultiLineKeyUp}
220+
keyDownEvents={[
221+
{key: 'ArrowRight'},
222+
{key: 'ArrowDown'},
223+
{key: 'Enter', metaKey: true},
224+
]}
225+
keyUpEvents={[{key: 'Escape'}, {key: 'Enter'}]}
234226
/>
235-
<Text style={styles.text}>{textInputUnhandledText}</Text>
236-
<TextInput
237-
blurOnSubmit={false}
238-
placeholder={'Singleline textInput'}
239-
multiline={false}
240-
focusable={true}
241-
style={styles.input}
242-
{...textInputunHandledKeyboardProps}
243-
/>
244-
<TextInput
245-
placeholder={'Multiline textInput'}
246-
multiline={true}
227+
</View>
228+
229+
<View style={styles.inputContainer}>
230+
<Text style={styles.inputLabel}>
231+
Focusable Pressable (keyDownEvents: Space, Enter, Tab, Backspace)
232+
</Text>
233+
<Pressable
234+
ref={pressableRef}
235+
style={({pressed}) => [
236+
styles.focusablePressable,
237+
pressed && styles.focusablePressablePressed,
238+
]}
247239
focusable={true}
248-
style={styles.input}
249-
{...textInputunHandledKeyboardProps}
250-
/>
251-
<Button
252-
testID="event_clear_button"
253-
onPress={clearLog}
254-
title="Clear event log"
255-
/>
256-
<Text>{'Events:\n' + log.join('\n')}</Text>
240+
onKeyDown={handlePressableKeyDown}
241+
onKeyUp={handlePressableKeyUp}
242+
keyDownEvents={[
243+
{key: 'Space'},
244+
{key: 'Enter'},
245+
{key: 'Tab'},
246+
{key: 'Backspace'},
247+
]}
248+
onPress={() => {
249+
pressableRef.current?.focus();
250+
}}
251+
>
252+
<Text style={styles.pressableText}>Click to focus, then press Space, Enter, Tab, or Backspace</Text>
253+
</Pressable>
254+
</View>
255+
256+
<View testID="keyboard_events_example_console" style={styles.eventLogBox}>
257+
<View style={styles.logHeaderRow}>
258+
<Text style={styles.logHeader}>Event Log</Text>
259+
<Pressable
260+
style={({pressed}) => [
261+
styles.clearButton,
262+
pressed && styles.clearButtonPressed,
263+
]}
264+
onPress={() => setEventLog([])}>
265+
<Text style={styles.clearButtonText}>Clear</Text>
266+
</Pressable>
267+
</View>
268+
{eventLog.map((e, ii) => (
269+
<Text key={ii} style={styles.logEntry}>
270+
{e}
271+
</Text>
272+
))}
257273
</View>
258274
</View>
259275
);
@@ -266,6 +282,7 @@ const styles = StyleSheet.create({
266282
height: 300,
267283
borderWidth: StyleSheet.hairlineWidth,
268284
borderColor: '#f0f0f0',
285+
borderCurve: 'continuous',
269286
backgroundColor: '#f9f9f9',
270287
},
271288
logHeaderRow: {
@@ -361,6 +378,54 @@ const styles = StyleSheet.create({
361378
fontSize: 12,
362379
paddingBottom: 4,
363380
},
381+
description: {
382+
fontSize: 14,
383+
color: '#666',
384+
marginBottom: 16,
385+
},
386+
inputContainer: {
387+
marginBottom: 16,
388+
},
389+
inputLabel: {
390+
fontSize: 13,
391+
fontWeight: '500',
392+
color: '#333',
393+
marginBottom: 6,
394+
},
395+
styledTextInput: {
396+
borderWidth: 1,
397+
borderColor: '#ddd',
398+
borderRadius: 6,
399+
paddingHorizontal: 12,
400+
paddingVertical: 8,
401+
fontSize: 14,
402+
backgroundColor: '#fff',
403+
minHeight: 36,
404+
},
405+
multilineInput: {
406+
minHeight: 72,
407+
textAlignVertical: 'top',
408+
},
409+
focusablePressable: {
410+
borderWidth: 1,
411+
borderColor: '#ddd',
412+
borderRadius: 6,
413+
paddingHorizontal: 12,
414+
paddingVertical: 16,
415+
backgroundColor: '#f8f9fa',
416+
minHeight: 50,
417+
justifyContent: 'center',
418+
alignItems: 'center',
419+
},
420+
focusablePressablePressed: {
421+
backgroundColor: '#e9ecef',
422+
borderColor: '#007AFF',
423+
},
424+
pressableText: {
425+
fontSize: 14,
426+
color: '#666',
427+
textAlign: 'center',
428+
},
364429
});
365430

366431
exports.title = 'Keyboard Events';

0 commit comments

Comments
 (0)