From 3292d5bd26a75ae4c494df53d1e9b87aa1959a17 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Thu, 9 Jan 2025 22:22:13 -0800 Subject: [PATCH] [skip ci] Align logic in BaseTextInputShadowNode to calculate placeholder string with AndroidTextInputShadowNode (#48584) Summary: [Changelog] [Internal] - Align logic in BaseTextInputShadowNode to calculate placeholder string with AndroidTextInputShadowNode As a preparation for https://github.com/facebook/react-native/pull/48165 this aligns the implementation of those 2 methods Differential Revision: D68004218 --- .../textinput/BaseTextInputShadowNode.h | 44 +++++++++++-------- .../AndroidTextInputShadowNode.cpp | 28 +++++------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h index 2aabb63ae7d1c0..9bdd9748804ae4 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h @@ -97,13 +97,7 @@ class BaseTextInputShadowNode : public ConcreteViewShadowNode< auto attributedString = getAttributedString(layoutContext); if (attributedString.isEmpty()) { - auto placeholderString = !props.placeholder.empty() - ? props.placeholder - : BaseTextShadowNode::getEmptyPlaceholder(); - auto textAttributes = - props.getEffectiveTextAttributes(layoutContext.fontSizeMultiplier); - attributedString.appendFragment( - {std::move(placeholderString), textAttributes, {}}); + attributedString = getPlaceholderAttributedString(layoutContext); } // Yoga expects a baseline relative to the Node's border-box edge instead of @@ -217,21 +211,33 @@ class BaseTextInputShadowNode : public ConcreteViewShadowNode< : getAttributedString(layoutContext); if (attributedString.isEmpty()) { - const auto& props = BaseShadowNode::getConcreteProps(); - auto placeholder = props.placeholder; - // Note: `zero-width space` is insufficient in some cases (e.g. when we - // need to measure the "hight" of the font). - // TODO T67606511: We will redefine the measurement of empty strings as - // part of T67606511 - auto string = !placeholder.empty() - ? placeholder - : BaseTextShadowNode::getEmptyPlaceholder(); - auto textAttributes = - props.getEffectiveTextAttributes(layoutContext.fontSizeMultiplier); - attributedString.appendFragment({string, textAttributes, {}}); + attributedString = getPlaceholderAttributedString(layoutContext); } return AttributedStringBox{attributedString}; } + + // For measurement purposes, we want to make sure that there's at least a + // single character in the string so that the measured height is greater + // than zero. Otherwise, empty TextInputs with no placeholder don't + // display at all. + // TODO T67606511: We will redefine the measurement of empty strings as part + // of T67606511 + AttributedString getPlaceholderAttributedString( + const LayoutContext& layoutContext) const { + const auto& props = BaseShadowNode::getConcreteProps(); + + AttributedString attributedString; + auto placeholderString = !props.placeholder.empty() + ? props.placeholder + : BaseTextShadowNode::getEmptyPlaceholder(); + auto textAttributes = + props.getEffectiveTextAttributes(layoutContext.fontSizeMultiplier); + attributedString.appendFragment( + {.string = std::move(placeholderString), + .textAttributes = textAttributes, + .parentShadowView = {}}); + return attributedString; + } }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp index b08a426b85b1e6..d0b2b5b0c54afe 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp @@ -215,25 +215,19 @@ AttributedString AndroidTextInputShadowNode::getMostRecentAttributedString() // of T67606511 AttributedString AndroidTextInputShadowNode::getPlaceholderAttributedString() const { - // Return placeholder text, since text and children are empty. - auto textAttributedString = AttributedString{}; - auto fragment = AttributedString::Fragment{}; - fragment.string = getConcreteProps().placeholder; - - if (fragment.string.empty()) { - fragment.string = BaseTextShadowNode::getEmptyPlaceholder(); - } + const auto& props = BaseShadowNode::getConcreteProps(); + AttributedString attributedString; + auto placeholderString = !props.placeholder.empty() + ? props.placeholder + : BaseTextShadowNode::getEmptyPlaceholder(); auto textAttributes = TextAttributes::defaultTextAttributes(); - textAttributes.apply(getConcreteProps().textAttributes); - - // If there's no text, it's possible that this Fragment isn't actually - // appended to the AttributedString (see implementation of appendFragment) - fragment.textAttributes = textAttributes; - fragment.parentShadowView = ShadowView(*this); - textAttributedString.appendFragment(std::move(fragment)); - - return textAttributedString; + textAttributes.apply(props.textAttributes); + attributedString.appendFragment( + {.string = std::move(placeholderString), + .textAttributes = textAttributes, + .parentShadowView = ShadowView(*this)}); + return attributedString; } } // namespace facebook::react