-
Notifications
You must be signed in to change notification settings - Fork 1.2k
keyboardtype parity to paper in fabric #15359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8d1e0ab
b23de66
c1d0caf
92b458b
765d2bc
ba1d99b
5a0d39e
9ccb881
af59cbf
f8e4c47
ac8dfa5
f98b4b8
321bcfa
7499e0b
1fb5a49
454fe16
9371bee
dc4035d
8af25cc
c204814
f1f58c6
ecc1316
26f0a65
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "type": "prerelease", | ||
| "comment": "Fix broken web links in markdown documentation files", | ||
| "packageName": "@react-native-windows/automation", | ||
| "email": "email not defined", | ||
| "dependentChangeType": "patch" | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "type": "prerelease", | ||
| "comment": "Fix broken web links in markdown documentation files", | ||
| "packageName": "@react-native-windows/automation-channel", | ||
| "email": "email not defined", | ||
| "dependentChangeType": "patch" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "type": "prerelease", | ||
| "comment": "Fix broken web links in markdown documentation files", | ||
| "packageName": "@react-native-windows/automation-commands", | ||
| "email": "email not defined", | ||
| "dependentChangeType": "patch" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "comment": "Add keyboardType prop support to Fabric TextInput for parity with Paper", | ||
| "type": "prerelease", | ||
| "packageName": "react-native-windows", | ||
| "email": "nitchaudhary@microsoft.com", | ||
| "dependentChangeType": "patch" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,230 @@ | ||
| /** | ||
| * Copyright (c) Microsoft Corporation. | ||
| * Licensed under the MIT License. | ||
| * @format | ||
| */ | ||
|
|
||
| import React from 'react'; | ||
| import { | ||
| AppRegistry, | ||
| StyleSheet, | ||
| ScrollView, | ||
| Text, | ||
| View, | ||
| TextInput, | ||
| } from 'react-native'; | ||
|
|
||
| class KeyboardTypeTest extends React.Component< | ||
| {}, | ||
| { | ||
| defaultValue: string; | ||
| numericValue: string; | ||
| numberPadValue: string; | ||
| decimalPadValue: string; | ||
| emailValue: string; | ||
| phonePadValue: string; | ||
| urlValue: string; | ||
| webSearchValue: string; | ||
| secureNumericValue: string; | ||
| } | ||
| > { | ||
| constructor(props: {}) { | ||
| super(props); | ||
| this.state = { | ||
| defaultValue: '', | ||
| numericValue: '', | ||
| numberPadValue: '', | ||
| decimalPadValue: '', | ||
| emailValue: '', | ||
| phonePadValue: '', | ||
| urlValue: '', | ||
| webSearchValue: '', | ||
| secureNumericValue: '', | ||
| }; | ||
| } | ||
|
|
||
| render() { | ||
| return ( | ||
| <ScrollView style={styles.container}> | ||
| <Text style={styles.title}>Keyboard Type Test (Fabric)</Text> | ||
| <Text style={styles.subtitle}>Test SetInputScopes on Parent HWND</Text> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>Default Keyboard:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="default" | ||
| value={this.state.defaultValue} | ||
| onChangeText={text => this.setState({defaultValue: text})} | ||
| placeholder="default keyboard" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>Numeric Keyboard:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="numeric" | ||
| value={this.state.numericValue} | ||
| onChangeText={text => this.setState({numericValue: text})} | ||
| placeholder="numeric keyboard" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>Number Pad:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="number-pad" | ||
| value={this.state.numberPadValue} | ||
| onChangeText={text => this.setState({numberPadValue: text})} | ||
| placeholder="number-pad" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>Decimal Pad:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="decimal-pad" | ||
| value={this.state.decimalPadValue} | ||
| onChangeText={text => this.setState({decimalPadValue: text})} | ||
| placeholder="decimal-pad" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>Email Address:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="email-address" | ||
| value={this.state.emailValue} | ||
| onChangeText={text => this.setState({emailValue: text})} | ||
| placeholder="email-address" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>Phone Pad:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="phone-pad" | ||
| value={this.state.phonePadValue} | ||
| onChangeText={text => this.setState({phonePadValue: text})} | ||
| placeholder="phone-pad" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>URL Keyboard:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="url" | ||
| value={this.state.urlValue} | ||
| onChangeText={text => this.setState({urlValue: text})} | ||
| placeholder="url" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>Web Search:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="web-search" | ||
| value={this.state.webSearchValue} | ||
| onChangeText={text => this.setState({webSearchValue: text})} | ||
| placeholder="web-search" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.inputContainer}> | ||
| <Text style={styles.label}>Secure + Numeric:</Text> | ||
| <TextInput | ||
| style={styles.input} | ||
| keyboardType="numeric" | ||
| secureTextEntry={true} | ||
| value={this.state.secureNumericValue} | ||
| onChangeText={text => this.setState({secureNumericValue: text})} | ||
| placeholder="numeric password" | ||
| /> | ||
| </View> | ||
|
|
||
| <View style={styles.instructions}> | ||
| <Text style={styles.instructionText}> | ||
| Instructions for Testing on Windows:{'\n'} | ||
| {'\n'} | ||
| This test uses SetInputScopes on the parent HWND.{'\n'} | ||
| {'\n'} | ||
| To test with Windows Touch Keyboard:{'\n'} | ||
| 1. Right-click taskbar → Show touch keyboard button{'\n'} | ||
| 2. Click the keyboard icon in system tray{'\n'} | ||
| 3. Tap/click each TextInput field to focus it{'\n'} | ||
| 4. Observe the touch keyboard layout changes{'\n'} | ||
| {'\n'} | ||
| Expected keyboard layouts:{'\n'}• default: Standard QWERTY{'\n'}• | ||
| numeric/number-pad: Number keys (IS_NUMBER/IS_DIGITS){'\n'}• | ||
| decimal-pad: Numbers with decimal point{'\n'}• email-address: QWERTY | ||
| with @ and .com keys{'\n'}• phone-pad: Phone dial pad layout{'\n'}• | ||
| url: QWERTY with .com/.net buttons{'\n'}• web-search: | ||
| Search-optimized layout{'\n'}• secure+numeric: PIN entry layout | ||
| {'\n'} | ||
| {'\n'} | ||
| Note: Physical keyboard allows all input (matches iOS/Android). | ||
| </Text> | ||
| </View> | ||
| </ScrollView> | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| flex: 1, | ||
| padding: 20, | ||
| backgroundColor: '#f5f5f5', | ||
| }, | ||
| title: { | ||
| fontSize: 24, | ||
| fontWeight: 'bold', | ||
| marginBottom: 5, | ||
| color: '#333', | ||
| }, | ||
| subtitle: { | ||
| fontSize: 14, | ||
| marginBottom: 20, | ||
| color: '#666', | ||
| fontStyle: 'italic', | ||
| }, | ||
| inputContainer: { | ||
| marginBottom: 15, | ||
| }, | ||
| label: { | ||
| fontSize: 14, | ||
| fontWeight: '600', | ||
| marginBottom: 5, | ||
| color: '#444', | ||
| }, | ||
| input: { | ||
| borderWidth: 1, | ||
| borderColor: '#ccc', | ||
| borderRadius: 4, | ||
| padding: 10, | ||
| fontSize: 16, | ||
| backgroundColor: '#fff', | ||
| }, | ||
| instructions: { | ||
| marginTop: 30, | ||
| padding: 15, | ||
| backgroundColor: '#e3f2fd', | ||
| borderRadius: 8, | ||
| borderWidth: 1, | ||
| borderColor: '#90caf9', | ||
| }, | ||
| instructionText: { | ||
| fontSize: 13, | ||
| color: '#1565c0', | ||
| lineHeight: 20, | ||
| }, | ||
| }); | ||
|
|
||
| AppRegistry.registerComponent('KeyboardTypeTest', () => KeyboardTypeTest); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -245,7 +245,13 @@ struct WindowData { | |
| DialogBox(s_instance, MAKEINTRESOURCE(IDD_OPENJSBUNDLEBOX), hwnd, &Bundle); | ||
|
|
||
| if (!m_bundleFile.empty()) { | ||
| m_appName = (m_bundleFile == LR"(Samples\rntester)") ? L"RNTesterApp" : L"Bootstrap"; | ||
| if (m_bundleFile == LR"(Samples\rntester)") { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather then adding additional entry files, you should just add the tests as a test page in RNTester. That way E2E test app will verify it doesn't crash. And it would be must easier to add automation in the future.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please check the video and do you think we should keep it like browsers ? |
||
| m_appName = L"RNTesterApp"; | ||
| } else if (m_bundleFile == LR"(Samples\KeyboardTypeTest)") { | ||
| m_appName = L"KeyboardTypeTest"; | ||
| } else { | ||
| m_appName = L"Bootstrap"; | ||
| } | ||
|
|
||
| WCHAR appDirectory[MAX_PATH]; | ||
| GetModuleFileNameW(NULL, appDirectory, MAX_PATH); | ||
|
|
@@ -370,16 +376,28 @@ struct WindowData { | |
| return FALSE; | ||
| } | ||
|
|
||
| static constexpr std::wstring_view g_bundleFiles[] = {LR"(Samples\rntester)", LR"(Samples\accessible)", | ||
| LR"(Samples\callbackTest)", LR"(Samples\calculator)", | ||
| LR"(Samples\click)", LR"(Samples\control)", | ||
| LR"(Samples\flexbox)", LR"(Samples\focusTest)", | ||
| LR"(Samples\geosample)", LR"(Samples\image)", | ||
| LR"(Samples\index)", LR"(Samples\nativeFabricComponent)", | ||
| LR"(Samples\mouse)", LR"(Samples\scrollViewSnapSample)", | ||
| LR"(Samples\simple)", LR"(Samples\text)", | ||
| LR"(Samples\textinput)", LR"(Samples\ticTacToe)", | ||
| LR"(Samples\view)", LR"(Samples\debugTest01)"}; | ||
| static constexpr std::wstring_view g_bundleFiles[] = { | ||
| LR"(Samples\rntester)", | ||
| LR"(Samples\accessible)", | ||
| LR"(Samples\callbackTest)", | ||
| LR"(Samples\calculator)", | ||
| LR"(Samples\click)", | ||
| LR"(Samples\control)", | ||
| LR"(Samples\flexbox)", | ||
| LR"(Samples\focusTest)", | ||
| LR"(Samples\geosample)", | ||
| LR"(Samples\image)", | ||
| LR"(Samples\index)", | ||
| LR"(Samples\KeyboardTypeTest)", | ||
| LR"(Samples\nativeFabricComponent)", | ||
| LR"(Samples\mouse)", | ||
| LR"(Samples\scrollViewSnapSample)", | ||
| LR"(Samples\simple)", | ||
| LR"(Samples\text)", | ||
| LR"(Samples\textinput)", | ||
| LR"(Samples\ticTacToe)", | ||
| LR"(Samples\view)", | ||
| LR"(Samples\debugTest01)"}; | ||
|
|
||
| static INT_PTR CALLBACK Bundle(HWND hwnd, UINT message, WPARAM wparam, LPARAM /*lparam*/) noexcept { | ||
| switch (message) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the change files that are unrelated to this PR.