Skip to content

Commit a8aa860

Browse files
authored
[Fabric] Add placeholder text and textcolor (microsoft#12018)
* implement placeholder text for fabric * Change files * redraw if empty * format * feedback * format * use m_needsRedraw instead
1 parent 3c39f25 commit a8aa860

File tree

3 files changed

+66
-5
lines changed

3 files changed

+66
-5
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "implement placeholder text for fabric",
4+
"packageName": "react-native-windows",
5+
"email": "tatianakapos@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
// Copyright (c) Microsoft Corporation.
32
// Licensed under the MIT License.
43

@@ -639,6 +638,11 @@ void WindowsTextInputComponentView::updateProps(
639638
}
640639
}
641640

641+
if (oldTextInputProps.placeholder != newTextInputProps.placeholder ||
642+
oldTextInputProps.placeholderTextColor != newTextInputProps.placeholderTextColor) {
643+
m_needsRedraw = true;
644+
}
645+
642646
/*
643647
if (oldTextInputProps.textAttributes.foregroundColor != newTextInputProps.textAttributes.foregroundColor) {
644648
if (newTextInputProps.textAttributes.foregroundColor)
@@ -675,10 +679,6 @@ void WindowsTextInputComponentView::updateProps(
675679
m_element.IsTextScaleFactorEnabled(newTextInputProps.allowFontScaling);
676680
}
677681
678-
if (oldTextInputProps.placeholder != newTextInputProps.placeholder) {
679-
m_element.PlaceholderText(winrt::to_hstring(newTextInputProps.placeholder));
680-
}
681-
682682
if (oldTextInputProps.selection.start != newTextInputProps.selection.start ||
683683
oldTextInputProps.selection.end != newTextInputProps.selection.end) {
684684
m_element.Select(
@@ -819,6 +819,7 @@ void WindowsTextInputComponentView::OnTextUpdated() noexcept {
819819
// return;
820820
data.attributedString = getAttributedString();
821821
data.mostRecentEventCount = m_nativeEventCount;
822+
822823
m_state->updateState(std::move(data));
823824

824825
if (m_eventEmitter && !m_comingFromJS) {
@@ -865,7 +866,11 @@ void WindowsTextInputComponentView::finalizeUpdates(RNComponentViewUpdateMask up
865866
UpdateSpecialBorderLayers(m_layoutMetrics, *m_props);
866867
}
867868
ensureDrawingSurface();
869+
if (m_needsRedraw) {
870+
DrawText();
871+
}
868872
}
873+
869874
void WindowsTextInputComponentView::prepareForRecycle() noexcept {}
870875
facebook::react::Props::Shared WindowsTextInputComponentView::props() noexcept {
871876
return m_props;
@@ -982,6 +987,29 @@ void WindowsTextInputComponentView::ShowCaret(bool show) noexcept {
982987
m_caretVisual.IsVisible(show);
983988
}
984989

990+
winrt::com_ptr<::IDWriteTextLayout> WindowsTextInputComponentView::CreatePlaceholderLayout() {
991+
// Create a fragment with text attributes
992+
winrt::com_ptr<::IDWriteTextLayout> textLayout = nullptr;
993+
facebook::react::AttributedString attributedString;
994+
facebook::react::AttributedString::Fragment fragment1;
995+
facebook::react::TextAttributes textAttributes = m_props->textAttributes;
996+
if (std::isnan(m_props->textAttributes.fontSize)) {
997+
textAttributes.fontSize = 12.0f;
998+
}
999+
fragment1.string = m_props->placeholder;
1000+
fragment1.textAttributes = textAttributes;
1001+
attributedString.appendFragment(fragment1);
1002+
1003+
facebook::react::LayoutConstraints constraints;
1004+
constraints.maximumSize.width = static_cast<FLOAT>(m_imgWidth);
1005+
constraints.maximumSize.height = static_cast<FLOAT>(m_imgHeight);
1006+
1007+
facebook::react::TextLayoutManager::GetTextLayout(
1008+
facebook::react::AttributedStringBox(attributedString), {} /*TODO*/, constraints, textLayout);
1009+
1010+
return textLayout;
1011+
}
1012+
9851013
void WindowsTextInputComponentView::DrawText() noexcept {
9861014
m_needsRedraw = true;
9871015
if (m_cDrawBlock) {
@@ -1029,6 +1057,31 @@ void WindowsTextInputComponentView::DrawText() noexcept {
10291057
auto hrDraw = m_textServices->TxDrawD2D(d2dDeviceContext.get(), &rc, nullptr, TXTVIEW_ACTIVE);
10301058
winrt::check_hresult(hrDraw);
10311059

1060+
// draw placeholder text if needed
1061+
if (!m_props->placeholder.empty() && GetTextFromRichEdit().empty()) {
1062+
// set brush color
1063+
winrt::com_ptr<ID2D1SolidColorBrush> brush;
1064+
if (m_props->placeholderTextColor) {
1065+
auto color = m_props->placeholderTextColor.AsD2DColor();
1066+
winrt::check_hresult(d2dDeviceContext->CreateSolidColorBrush(color, brush.put()));
1067+
} else {
1068+
winrt::check_hresult(
1069+
d2dDeviceContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Gray, 1.0f), brush.put()));
1070+
}
1071+
1072+
// Create placeholder text layout
1073+
winrt::com_ptr<::IDWriteTextLayout> textLayout = CreatePlaceholderLayout();
1074+
1075+
// draw text
1076+
d2dDeviceContext->DrawTextLayout(
1077+
D2D1::Point2F(
1078+
static_cast<FLOAT>((offset.x + m_layoutMetrics.contentInsets.left) / m_layoutMetrics.pointScaleFactor),
1079+
static_cast<FLOAT>((offset.y + m_layoutMetrics.contentInsets.top) / m_layoutMetrics.pointScaleFactor)),
1080+
textLayout.get(),
1081+
brush.get(),
1082+
D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
1083+
}
1084+
10321085
// restore dpi state
10331086
d2dDeviceContext->SetDpi(oldDpiX, oldDpiY);
10341087

vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ struct WindowsTextInputComponentView : CompositionBaseComponentView {
7171
void ensureDrawingSurface() noexcept;
7272
void DrawText() noexcept;
7373
void ShowCaret(bool show) noexcept;
74+
winrt::com_ptr<::IDWriteTextLayout> CreatePlaceholderLayout();
7475
void UpdateCharFormat() noexcept;
7576
void UpdateParaFormat() noexcept;
7677
void UpdateText(const std::string &str) noexcept;

0 commit comments

Comments
 (0)