diff --git a/packages/playground/Samples/index.tsx b/packages/playground/Samples/index.tsx index 54160dba7e8..82a1306a0e0 100644 --- a/packages/playground/Samples/index.tsx +++ b/packages/playground/Samples/index.tsx @@ -149,6 +149,7 @@ export default class Bootstrap extends React.Component< constructor(props: {}) { super(props); this.inputRef = React.createRef(); + this.viewRef = React.createRef(); this.state = { checkBoxIsOn: true, mouseEntered: false, @@ -161,6 +162,7 @@ export default class Bootstrap extends React.Component< } inputRef: React.RefObject; + viewRef: React.RefObject; render() { return ( @@ -678,16 +680,17 @@ export default class Bootstrap extends React.Component< /> Switch {this.state.switchIsOn ? 'ON' : 'OFF'} - + + focusable + onFocus={this.focusViewReceived} + onBlur={this.blurViewReceived} + ref={this.viewRef}> Click to focus textbox @@ -786,7 +789,11 @@ export default class Bootstrap extends React.Component< this.inputRef!.current!.focus(); }; - focusTextInputReceived = () => { + focusViewPressed = () => { + this.viewRef!.current!.focus(); + }; + + focusViewReceived = () => { console.log('View onFocus'); }; @@ -794,7 +801,7 @@ export default class Bootstrap extends React.Component< this.inputRef!.current!.blur(); }; - blurTextInputReceived = () => { + blurViewReceived = () => { console.log('View onBlur'); }; diff --git a/packages/playground/Samples/view.tsx b/packages/playground/Samples/view.tsx index e5035de1337..f1a23ac7265 100644 --- a/packages/playground/Samples/view.tsx +++ b/packages/playground/Samples/view.tsx @@ -5,7 +5,14 @@ */ import * as React from 'react'; -import {AppRegistry, StyleSheet, Switch, Text, View} from 'react-native'; +import { + AppRegistry, + StyleSheet, + Switch, + Text, + View, + TouchableHighlight, +} from 'react-native'; export default class Bootstrap extends React.Component< {}, @@ -21,6 +28,7 @@ export default class Bootstrap extends React.Component< > { constructor(props: {}) { super(props); + this.viewRef = React.createRef(); this.state = { focusable: true, hasStyle: true, @@ -32,10 +40,12 @@ export default class Bootstrap extends React.Component< }; } - focusTextInputReceived = () => { - console.log('this works lol'); + focusViewPressed = () => { + this.viewRef!.current!.focus(); }; + viewRef: React.RefObject; + render() { const styles = StyleSheet.create({ noBorder: { @@ -158,6 +168,7 @@ export default class Bootstrap extends React.Component< backgroundColor: 'azure', }}> console.log('onFocus in View!')} onBlur={() => console.log('onBlur in View')} @@ -175,6 +186,14 @@ export default class Bootstrap extends React.Component< The Text + + + Click to focus textbox + + ); } diff --git a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp index 1baee7a8039..335610479e8 100644 --- a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp +++ b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp @@ -9,6 +9,7 @@ #include #include #include "Modules/I18nManagerModule.h" +#include #include "NativeUIManager.h" #include "CppWinRTIncludes.h" @@ -1085,11 +1086,22 @@ void NativeUIManager::findSubviewIn( callback(args); } - +//winrt::Windows::Foundation::IAsyncOperation void NativeUIManager::focus(int64_t reactTag) { if (auto shadowNode = static_cast(m_host->FindShadowNodeForTag(reactTag))) { cdebug << "NativeUIManager: inside focus()" << std::endl; - xaml::Input::FocusManager::TryFocusAsync(shadowNode->GetView(), winrt::FocusState::Programmatic); + auto focusOp{ xaml::Input::FocusManager::TryFocusAsync(shadowNode->GetView(), winrt::FocusState::Keyboard)}; + /*for (int i = 0; i < 10000000; ++i) { + 2348723 % 3459; + }*/ + //while (!focusOp.Completed()) { + // ; // busy waiting in UI thread :( + //} + winrt::Windows::UI::Xaml::Input::FocusMovementResult results = focusOp.GetResults(); + bool isFocused = results.Succeeded(); + if (isFocused) { + isFocused = isFocused; + } } } diff --git a/vnext/Microsoft.ReactNative/Views/ViewViewManager.cpp b/vnext/Microsoft.ReactNative/Views/ViewViewManager.cpp index 113bc5a01b2..0197a53212d 100644 --- a/vnext/Microsoft.ReactNative/Views/ViewViewManager.cpp +++ b/vnext/Microsoft.ReactNative/Views/ViewViewManager.cpp @@ -36,7 +36,7 @@ class ViewShadowNode : public ShadowNodeBase { public: ViewShadowNode() = default; - + //void dispatchCommand(const std::string &commandId, const folly::dynamic &commandArgs) ; void createView() override { Super::createView(); @@ -60,6 +60,20 @@ class ViewShadowNode : public ShadowNodeBase { }); } + void dispatchCommand(const std::string &commandId, const folly::dynamic &commandArgs) override { + if (commandId == "focus") { + if (auto reactInstance = GetViewManager()->GetReactInstance().lock()) { + reactInstance->NativeUIManager()->focus(m_tag); + } + } else if (commandId == "blur") { + if (auto reactInstance = GetViewManager()->GetReactInstance().lock()) { + reactInstance->NativeUIManager()->blur(m_tag); + } + } else { + Super::dispatchCommand(commandId, commandArgs); + } + } + bool IsControl() { return m_isControl; } @@ -207,6 +221,7 @@ class ViewShadowNode : public ShadowNodeBase { if (args.OriginalSource().try_as() == contentControl.as()) { auto tag = m_tag; DispatchEvent("topFocus", std::move(folly::dynamic::object("target", tag))); + cdebug << "Focus on element #: " << tag << std::endl; } }); diff --git a/vnext/ReactCopies/RNTester/js/examples/Pressable/PressableExample.js b/vnext/ReactCopies/RNTester/js/examples/Pressable/PressableExample.js index 706544c5dbb..6b138476ee8 100644 --- a/vnext/ReactCopies/RNTester/js/examples/Pressable/PressableExample.js +++ b/vnext/ReactCopies/RNTester/js/examples/Pressable/PressableExample.js @@ -18,6 +18,7 @@ import { Text, Platform, View, + TouchableHighlight } from 'react-native'; const { useEffect, useRef, useState } = React; @@ -34,11 +35,16 @@ function ContentPress() { } else if (timesPressed > 0) { textLog = 'onPress'; } - + const viewRef = useRef | null>(null); + const focusViewPressed = () => { + viewRef.current.focus(); + }; return ( <> console.log('Pressable onFocus')} onBlur={() => console.log('Pressable onBlur')} onPress={() => { @@ -52,6 +58,14 @@ function ContentPress() { {textLog} + + + Click to focus textbox + + ); } diff --git a/vnext/src/Libraries/Components/TextInput/TextInputState.windows.js b/vnext/src/Libraries/Components/TextInput/TextInputState.windows.js index 2ee33160ef1..1a14893fd2c 100644 --- a/vnext/src/Libraries/Components/TextInput/TextInputState.windows.js +++ b/vnext/src/Libraries/Components/TextInput/TextInputState.windows.js @@ -16,13 +16,13 @@ const React = require('react'); const Platform = require('../../Utilities/Platform'); -const {findNodeHandle} = require('../../Renderer/shims/ReactNative'); -import {Commands as AndroidTextInputCommands} from '../../Components/TextInput/AndroidTextInputNativeComponent'; -import {Commands as iOSTextInputCommands} from '../../Components/TextInput/RCTSingelineTextInputNativeComponent'; -import {Commands as WindowsTextInputCommands} from '../../Components/TextInput/WindowsTextInputNativeCommands'; +const { findNodeHandle } = require('../../Renderer/shims/ReactNative'); +import { Commands as AndroidTextInputCommands } from '../../Components/TextInput/AndroidTextInputNativeComponent'; +import { Commands as iOSTextInputCommands } from '../../Components/TextInput/RCTSingelineTextInputNativeComponent'; +import { Commands as WindowsTextInputCommands } from '../../Components/TextInput/WindowsTextInputNativeCommands'; -import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; -import {UIManager} from 'react-native'; +import type { HostComponent } from '../../Renderer/shims/ReactNativeTypes'; +import { UIManager } from 'react-native'; type ComponentRef = React.ElementRef>; let currentlyFocusedInputRef: ?ComponentRef = null; @@ -141,7 +141,8 @@ function blurTextInput(textField: ?ComponentRef) { } // [Windows else if (Platform.OS === 'windows') { - UIManager.blur(findNodeHandle(textField)); + WindowsTextInputCommands.blur(textField); + // UIManager.blur(findNodeHandle(textField)); } // Windows] }