diff --git a/change/react-native-windows-8951004c-2587-4d8c-952a-f673c722f2a2.json b/change/react-native-windows-8951004c-2587-4d8c-952a-f673c722f2a2.json new file mode 100644 index 00000000000..cdaee7ea26d --- /dev/null +++ b/change/react-native-windows-8951004c-2587-4d8c-952a-f673c722f2a2.json @@ -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" +} diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp index ee85a8349d9..b3a6eecd011 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp @@ -1193,6 +1193,11 @@ void WindowsTextInputComponentView::updateProps( updateAutoCorrect(newTextInputProps.autoCorrect); } + if (oldTextInputProps.keyboardType != newTextInputProps.keyboardType || + oldTextInputProps.secureTextEntry != newTextInputProps.secureTextEntry) { + updateKeyboardType(newTextInputProps.keyboardType); + } + if (oldTextInputProps.selectionColor != newTextInputProps.selectionColor) { m_needsRedraw = true; } @@ -1439,6 +1444,10 @@ void WindowsTextInputComponentView::onMounted() noexcept { m_propBitsMask |= TXTBIT_CHARFORMATCHANGE; m_propBits |= TXTBIT_CHARFORMATCHANGE; } + + // Initialize keyboardType + updateKeyboardType(windowsTextInputProps().keyboardType); + InternalFinalize(); // Handle autoFocus property - focus the component when mounted if autoFocus is true @@ -1554,25 +1563,59 @@ void WindowsTextInputComponentView::UpdateParaFormat() noexcept { m_pf.dwMask = PFM_ALL; auto &textAlign = windowsTextInputProps().textAlign; + auto &baseWritingDirection = windowsTextInputProps().textAttributes.baseWritingDirection; + + // Handle writingDirection (baseWritingDirection) + // For WritingDirection::Natural, use the computed layout direction from the layout tree + // since direction can be overridden at any point in the tree + bool isRTL = false; + if (baseWritingDirection.has_value()) { + if (*baseWritingDirection == facebook::react::WritingDirection::RightToLeft) { + isRTL = true; + m_pf.dwMask |= PFM_RTLPARA; + m_pf.wEffects |= PFE_RTLPARA; + } else if (*baseWritingDirection == facebook::react::WritingDirection::LeftToRight) { + isRTL = false; + // Ensure RTL flag is not set + m_pf.wEffects &= ~PFE_RTLPARA; + } else if (*baseWritingDirection == facebook::react::WritingDirection::Natural) { + // Natural uses the layout direction computed from the tree + isRTL = (layoutMetrics().layoutDirection == facebook::react::LayoutDirection::RightToLeft); + if (isRTL) { + m_pf.dwMask |= PFM_RTLPARA; + m_pf.wEffects |= PFE_RTLPARA; + } else { + m_pf.wEffects &= ~PFE_RTLPARA; + } + } + } else { + // No explicit writing direction set - use layout direction from tree + isRTL = (layoutMetrics().layoutDirection == facebook::react::LayoutDirection::RightToLeft); + if (isRTL) { + m_pf.dwMask |= PFM_RTLPARA; + m_pf.wEffects |= PFE_RTLPARA; + } else { + m_pf.wEffects &= ~PFE_RTLPARA; + } + } + // Handle textAlign if (textAlign == facebook::react::TextAlignment::Center) { m_pf.wAlignment = PFA_CENTER; } else if (textAlign == facebook::react::TextAlignment::Right) { m_pf.wAlignment = PFA_RIGHT; + } else if (textAlign == facebook::react::TextAlignment::Justified) { + m_pf.wAlignment = PFA_JUSTIFY; + } else if (textAlign == facebook::react::TextAlignment::Natural) { + // Natural alignment respects writing direction + m_pf.wAlignment = isRTL ? PFA_RIGHT : PFA_LEFT; } else { + // Default to left alignment m_pf.wAlignment = PFA_LEFT; } m_pf.cTabCount = 1; m_pf.rgxTabs[0] = lDefaultTab; - - /* - if (m_spcontroller->IsCurrentReadingOrderRTL()) - { - m_pf.dwMask |= PFM_RTLPARA; - m_pf.wEffects |= PFE_RTLPARA; - } - */ } void WindowsTextInputComponentView::OnRenderingDeviceLost() noexcept { @@ -1877,4 +1920,10 @@ void WindowsTextInputComponentView::ShowContextMenu(const winrt::Windows::Founda DestroyMenu(menu); } +void WindowsTextInputComponentView::updateKeyboardType(const std::string &keyboardType) noexcept { + // Store the keyboard type for future use + // Note: Fabric's windowless RichEdit doesn't have direct InputScope support like Paper's XAML controls. + // The keyboard type is stored but the actual keyboard behavior is handled by the system's IME. + m_keyboardType = keyboardType; +} } // namespace winrt::Microsoft::ReactNative::Composition::implementation diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h index 26dc207961c..03f15bd1508 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h @@ -119,6 +119,7 @@ struct WindowsTextInputComponentView void updateAutoCorrect(bool value) noexcept; void updateSpellCheck(bool value) noexcept; void ShowContextMenu(const winrt::Windows::Foundation::Point &position) noexcept; + void updateKeyboardType(const std::string &keyboardType) noexcept; winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr}; winrt::Microsoft::ReactNative::Composition::Experimental::ICaretVisual m_caretVisual{nullptr}; @@ -148,6 +149,7 @@ struct WindowsTextInputComponentView HCURSOR m_hcursor{nullptr}; std::chrono::steady_clock::time_point m_lastClickTime{}; std::vector m_submitKeyEvents; + std::string m_keyboardType{}; }; } // namespace winrt::Microsoft::ReactNative::Composition::implementation