react-native-windows 0.81.37 → 0.81.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Microsoft.ReactNative/Fabric/AbiComponentDescriptor.cpp +6 -2
- package/Microsoft.ReactNative/Fabric/AbiShadowNode.cpp +0 -47
- package/Microsoft.ReactNative/Fabric/AbiShadowNode.h +40 -8
- package/Microsoft.ReactNative/Fabric/AbiState.h +26 -8
- package/Microsoft.ReactNative/Fabric/AbiTextInputProps.h +51 -0
- package/Microsoft.ReactNative/Fabric/AbiTextInputShadowNode.cpp +88 -0
- package/Microsoft.ReactNative/Fabric/AbiTextInputShadowNode.h +65 -0
- package/Microsoft.ReactNative/Fabric/AbiViewComponentDescriptor.h +52 -18
- package/Microsoft.ReactNative/Fabric/AbiViewShadowNode.cpp +0 -18
- package/Microsoft.ReactNative/Fabric/AbiViewShadowNode.h +16 -4
- package/Microsoft.ReactNative/Fabric/ComponentView.cpp +2 -1
- package/Microsoft.ReactNative/Fabric/Composition/ComponentViewRegistry.cpp +1 -2
- package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +3 -2
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +6 -4
- package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +6 -4
- package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +2 -1
- package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +22 -0
- package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +2 -1
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/AbiTextInputState.h +38 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/ConcreteTextInputShadowNode.h +272 -0
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentDescriptor.h +21 -14
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +345 -90
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +24 -4
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.h +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +0 -205
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +22 -65
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.h +2 -1
- package/Microsoft.ReactNative/Fabric/WindowsComponentDescriptorRegistry.cpp +0 -1
- package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +5 -0
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +0 -1
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +60 -5
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +3 -0
- package/Microsoft.ReactNative/ViewProps.idl +11 -0
- package/Microsoft.ReactNative/Views/ViewViewManager.cpp +2 -2
- package/Microsoft.ReactNative.Cxx/ComponentView.Experimental.interop.h +12 -0
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/PropertySheets/JSEngine.props +1 -1
- package/PropertySheets/React.Cpp.props +0 -1
- package/PropertySheets/WinUI.props +2 -1
- package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/Instance.cpp +386 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/NativeToJsBridge.h +148 -0
- package/Scripts/EnableInternalWinAppSDKFeed.ps1 +12 -5
- package/Scripts/NuGetRestoreForceEvaluateAllSolutions.ps1 +2 -2
- package/Shared/Networking/WinRTWebSocketResource.h +1 -5
- package/Shared/OInstance.cpp +13 -8
- package/Shared/Shared.vcxitems +3 -3
- package/Shared/Shared.vcxitems.filters +1 -1
- package/external/folly/folly.vcxitems +10 -0
- package/index.windows.js +5 -0
- package/package.json +4 -4
- package/Microsoft.ReactNative/Fabric/AbiState.cpp +0 -29
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
#pragma once
|
|
6
6
|
|
|
7
7
|
#include "Composition.WindowsTextInputComponentView.g.h"
|
|
8
|
+
#include <ComponentView.Experimental.interop.h>
|
|
9
|
+
#include <Fabric/AbiTextInputShadowNode.h>
|
|
8
10
|
#include <ReactContext.h>
|
|
9
11
|
#include <Windows.Graphics.DirectX.Direct3D11.interop.h>
|
|
10
12
|
#include <richedit.h>
|
|
@@ -22,10 +24,16 @@ namespace winrt::Microsoft::ReactNative::Composition::implementation {
|
|
|
22
24
|
struct CompTextHost;
|
|
23
25
|
|
|
24
26
|
struct WindowsTextInputComponentView
|
|
25
|
-
: WindowsTextInputComponentViewT<
|
|
27
|
+
: public WindowsTextInputComponentViewT<
|
|
28
|
+
WindowsTextInputComponentView,
|
|
29
|
+
ViewComponentView,
|
|
30
|
+
::Microsoft::ReactNative::Composition::Experimental::ITextInputComponentInterop> {
|
|
26
31
|
friend CompTextHost;
|
|
27
32
|
|
|
28
|
-
using Super = WindowsTextInputComponentViewT<
|
|
33
|
+
using Super = WindowsTextInputComponentViewT<
|
|
34
|
+
WindowsTextInputComponentView,
|
|
35
|
+
ViewComponentView,
|
|
36
|
+
::Microsoft::ReactNative::Composition::Experimental::ITextInputComponentInterop>;
|
|
29
37
|
[[nodiscard]] static winrt::Microsoft::ReactNative::ComponentView Create(
|
|
30
38
|
const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
|
|
31
39
|
facebook::react::Tag tag,
|
|
@@ -71,6 +79,9 @@ struct WindowsTextInputComponentView
|
|
|
71
79
|
void OnContextMenuKey(
|
|
72
80
|
const winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs &args) noexcept override;
|
|
73
81
|
void onMounted() noexcept override;
|
|
82
|
+
const winrt::Microsoft::ReactNative::IComponentProps userProps(
|
|
83
|
+
facebook::react::Props::Shared const &props) noexcept override;
|
|
84
|
+
winrt::Microsoft::ReactNative::ViewProps ViewPropsInner() noexcept override;
|
|
74
85
|
|
|
75
86
|
std::optional<std::string> getAccessiblityValue() noexcept override;
|
|
76
87
|
void setAcccessiblityValue(std::string &&value) noexcept override;
|
|
@@ -80,13 +91,18 @@ struct WindowsTextInputComponentView
|
|
|
80
91
|
WindowsTextInputComponentView(
|
|
81
92
|
const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
|
|
82
93
|
facebook::react::Tag tag,
|
|
83
|
-
winrt::Microsoft::ReactNative::ReactContext const &reactContext
|
|
94
|
+
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
|
|
95
|
+
winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder = nullptr);
|
|
84
96
|
~WindowsTextInputComponentView();
|
|
85
97
|
|
|
86
98
|
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual createVisual() noexcept;
|
|
87
99
|
|
|
88
100
|
std::pair<facebook::react::Cursor, HCURSOR> cursor() const noexcept override;
|
|
89
101
|
|
|
102
|
+
HRESULT GetTextDocument(ITextDocument2 **) noexcept;
|
|
103
|
+
HRESULT GetTextServices(ITextServices2 **textServices) noexcept;
|
|
104
|
+
HRESULT GetTextHost(ITextHost **textHost) noexcept;
|
|
105
|
+
|
|
90
106
|
private:
|
|
91
107
|
struct DrawBlock {
|
|
92
108
|
DrawBlock(WindowsTextInputComponentView &view);
|
|
@@ -100,8 +116,9 @@ struct WindowsTextInputComponentView
|
|
|
100
116
|
void ShowCaret(bool show) noexcept;
|
|
101
117
|
winrt::com_ptr<::IDWriteTextLayout> CreatePlaceholderLayout();
|
|
102
118
|
void UpdateCharFormat() noexcept;
|
|
119
|
+
CHARFORMAT2W GetCharFormat(const facebook::react::TextAttributes &textAttributes) noexcept;
|
|
103
120
|
void UpdateParaFormat() noexcept;
|
|
104
|
-
void UpdateText(const
|
|
121
|
+
void UpdateText(const facebook::react::AttributedString &attributedString) noexcept;
|
|
105
122
|
void OnTextUpdated() noexcept;
|
|
106
123
|
void EmitOnScrollEvent() noexcept;
|
|
107
124
|
void OnSelectionChanged(LONG start, LONG end) noexcept;
|
|
@@ -124,6 +141,8 @@ struct WindowsTextInputComponentView
|
|
|
124
141
|
void ShowContextMenu(const winrt::Windows::Foundation::Point &position) noexcept;
|
|
125
142
|
void calculateContentVerticalOffset() noexcept;
|
|
126
143
|
|
|
144
|
+
void ensureTextHost() noexcept;
|
|
145
|
+
|
|
127
146
|
winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr};
|
|
128
147
|
winrt::Microsoft::ReactNative::Composition::Experimental::ICaretVisual m_caretVisual{nullptr};
|
|
129
148
|
winrt::Microsoft::ReactNative::Composition::Experimental::IDrawingSurfaceBrush m_drawingSurface{nullptr};
|
|
@@ -136,6 +155,7 @@ struct WindowsTextInputComponentView
|
|
|
136
155
|
winrt::com_ptr<ITextServices2> m_textServices;
|
|
137
156
|
unsigned int m_imgWidth{0}, m_imgHeight{0};
|
|
138
157
|
std::shared_ptr<facebook::react::WindowsTextInputShadowNode::ConcreteState const> m_state;
|
|
158
|
+
std::shared_ptr<::Microsoft::ReactNative::AbiTextInputShadowNode::ConcreteState const> m_abistate;
|
|
139
159
|
float m_fontSizeMultiplier{1.0};
|
|
140
160
|
int64_t m_mostRecentEventCount{0};
|
|
141
161
|
int m_nativeEventCount{0};
|
|
@@ -85,7 +85,7 @@ static inline void fromRawValue(
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
class WindowsTextInputProps
|
|
88
|
+
class WindowsTextInputProps : public ViewProps, public BaseTextProps {
|
|
89
89
|
public:
|
|
90
90
|
WindowsTextInputProps() = default;
|
|
91
91
|
WindowsTextInputProps(
|
|
@@ -1,213 +1,8 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
3
|
|
|
4
|
-
#include "WindowsTextInputShadowNode.h"
|
|
5
|
-
|
|
6
|
-
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
|
7
|
-
#include <react/renderer/attributedstring/AttributedStringBox.h>
|
|
8
|
-
#include <react/renderer/attributedstring/PlaceholderAttributedString.h>
|
|
9
|
-
#include <react/renderer/attributedstring/TextAttributes.h>
|
|
10
|
-
#include <react/renderer/components/text/BaseTextShadowNode.h>
|
|
11
|
-
#include <react/renderer/core/LayoutConstraints.h>
|
|
12
|
-
#include <react/renderer/core/LayoutContext.h>
|
|
13
|
-
#include <react/renderer/core/conversions.h>
|
|
14
|
-
#include <react/renderer/textlayoutmanager/TextLayoutContext.h>
|
|
15
|
-
|
|
16
4
|
namespace facebook::react {
|
|
17
5
|
|
|
18
6
|
extern const char WindowsTextInputComponentName[] = "WindowsTextInput";
|
|
19
7
|
|
|
20
|
-
void WindowsTextInputShadowNode::setTextLayoutManager(std::shared_ptr<const TextLayoutManager> textLayoutManager) {
|
|
21
|
-
ensureUnsealed();
|
|
22
|
-
textLayoutManager_ = std::move(textLayoutManager);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
Size WindowsTextInputShadowNode::measureContent(
|
|
26
|
-
const LayoutContext &layoutContext,
|
|
27
|
-
const LayoutConstraints &layoutConstraints) const {
|
|
28
|
-
// Layout is called right after measure.
|
|
29
|
-
// Measure is marked as `const`, and `layout` is not; so State can be
|
|
30
|
-
// updated during layout, but not during `measure`. If State is out-of-date
|
|
31
|
-
// in layout, it's too late: measure will have already operated on old
|
|
32
|
-
// State. Thus, we use the same value here that we *will* use in layout to
|
|
33
|
-
// update the state.
|
|
34
|
-
AttributedString attributedString = getMostRecentAttributedString(layoutContext);
|
|
35
|
-
|
|
36
|
-
if (attributedString.isEmpty()) {
|
|
37
|
-
attributedString = getPlaceholderAttributedString(layoutContext);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// BaseTextShadowNode only gets children. We must detect and prepend text
|
|
41
|
-
// value attributes manually.
|
|
42
|
-
if (!getConcreteProps().text.empty()) {
|
|
43
|
-
auto textAttributes = TextAttributes::defaultTextAttributes();
|
|
44
|
-
textAttributes.apply(getConcreteProps().textAttributes);
|
|
45
|
-
auto fragment = AttributedString::Fragment{};
|
|
46
|
-
fragment.string = getConcreteProps().text;
|
|
47
|
-
fragment.textAttributes = textAttributes;
|
|
48
|
-
// If the TextInput opacity is 0 < n < 1, the opacity of the TextInput and
|
|
49
|
-
// text value's background will stack. This is a hack/workaround to prevent
|
|
50
|
-
// that effect.
|
|
51
|
-
fragment.textAttributes.backgroundColor = clearColor();
|
|
52
|
-
fragment.parentShadowView = ShadowView(*this);
|
|
53
|
-
attributedString.prependFragment(std::move(fragment));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
TextLayoutContext textLayoutContext;
|
|
57
|
-
textLayoutContext.pointScaleFactor = layoutContext.pointScaleFactor;
|
|
58
|
-
|
|
59
|
-
facebook::react::ParagraphAttributes paragraphAttributes{};
|
|
60
|
-
paragraphAttributes.maximumNumberOfLines = getConcreteProps().multiline ? 0 : 1;
|
|
61
|
-
return textLayoutManager_
|
|
62
|
-
->measure(AttributedStringBox{attributedString}, paragraphAttributes, textLayoutContext, layoutConstraints)
|
|
63
|
-
.size;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
void WindowsTextInputShadowNode::layout(LayoutContext layoutContext) {
|
|
67
|
-
updateStateIfNeeded(layoutContext);
|
|
68
|
-
ConcreteViewShadowNode::layout(layoutContext);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
LayoutConstraints WindowsTextInputShadowNode::getTextConstraints(const LayoutConstraints &layoutConstraints) const {
|
|
72
|
-
if (getConcreteProps().multiline) {
|
|
73
|
-
return layoutConstraints;
|
|
74
|
-
} else {
|
|
75
|
-
// A single line TextInput acts as a horizontal scroller of infinitely
|
|
76
|
-
// expandable text, so we want to measure the text as if it is allowed to
|
|
77
|
-
// infinitely expand horizontally, and later clamp to the constraints of the
|
|
78
|
-
// input.
|
|
79
|
-
return LayoutConstraints{
|
|
80
|
-
.minimumSize = layoutConstraints.minimumSize,
|
|
81
|
-
.maximumSize =
|
|
82
|
-
Size{
|
|
83
|
-
.width = std::numeric_limits<Float>::infinity(),
|
|
84
|
-
.height = layoutConstraints.maximumSize.height,
|
|
85
|
-
},
|
|
86
|
-
.layoutDirection = layoutConstraints.layoutDirection,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
void WindowsTextInputShadowNode::updateStateIfNeeded(const LayoutContext &layoutContext) {
|
|
92
|
-
ensureUnsealed();
|
|
93
|
-
const auto &stateData = getStateData();
|
|
94
|
-
auto reactTreeAttributedString = getAttributedString(layoutContext);
|
|
95
|
-
|
|
96
|
-
// Tree is often out of sync with the value of the TextInput.
|
|
97
|
-
// This is by design - don't change the value of the TextInput in the State,
|
|
98
|
-
// and therefore in Java, unless the tree itself changes.
|
|
99
|
-
if (stateData.reactTreeAttributedString == reactTreeAttributedString) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// If props event counter is less than what we already have in state, skip it
|
|
104
|
-
const auto &props = BaseShadowNode::getConcreteProps();
|
|
105
|
-
if (props.mostRecentEventCount < stateData.mostRecentEventCount) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Store default TextAttributes in state.
|
|
110
|
-
// In the case where the TextInput is completely empty (no value, no
|
|
111
|
-
// defaultValue, no placeholder, no children) there are therefore no fragments
|
|
112
|
-
// in the AttributedString, and when State is updated, it needs some way to
|
|
113
|
-
// reconstruct a Fragment with default TextAttributes.
|
|
114
|
-
auto defaultTextAttributes = TextAttributes::defaultTextAttributes();
|
|
115
|
-
defaultTextAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
|
116
|
-
defaultTextAttributes.apply(getConcreteProps().textAttributes);
|
|
117
|
-
|
|
118
|
-
auto newEventCount = stateData.reactTreeAttributedString.isContentEqual(reactTreeAttributedString)
|
|
119
|
-
? 0
|
|
120
|
-
: getConcreteProps().mostRecentEventCount;
|
|
121
|
-
auto newAttributedString = getMostRecentAttributedString(layoutContext);
|
|
122
|
-
|
|
123
|
-
// Even if we're here and updating state, it may be only to update the layout
|
|
124
|
-
// manager If that is the case, make sure we don't update text: pass in the
|
|
125
|
-
// current attributedString unchanged, and pass in zero for the "event count"
|
|
126
|
-
// so no changes are applied There's no way to prevent a state update from
|
|
127
|
-
// flowing to Java, so we just ensure it's a noop in those cases.
|
|
128
|
-
|
|
129
|
-
setStateData(
|
|
130
|
-
WindowsTextInputState{AttributedStringBox(newAttributedString), reactTreeAttributedString, {}, newEventCount});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
AttributedString WindowsTextInputShadowNode::getAttributedString(const LayoutContext &layoutContext) const {
|
|
134
|
-
// Use BaseTextShadowNode to get attributed string from children
|
|
135
|
-
|
|
136
|
-
auto childTextAttributes = TextAttributes::defaultTextAttributes();
|
|
137
|
-
childTextAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
|
138
|
-
childTextAttributes.apply(getConcreteProps().textAttributes);
|
|
139
|
-
// Don't propagate the background color of the TextInput onto the attributed
|
|
140
|
-
// string. Android tries to render shadow of the background alongside the
|
|
141
|
-
// shadow of the text which results in weird artifacts.
|
|
142
|
-
childTextAttributes.backgroundColor = HostPlatformColor::UndefinedColor;
|
|
143
|
-
|
|
144
|
-
auto attributedString = AttributedString{};
|
|
145
|
-
auto attachments = BaseTextShadowNode::Attachments{};
|
|
146
|
-
BaseTextShadowNode::buildAttributedString(childTextAttributes, *this, attributedString, attachments);
|
|
147
|
-
attributedString.setBaseTextAttributes(childTextAttributes);
|
|
148
|
-
|
|
149
|
-
// BaseTextShadowNode only gets children. We must detect and prepend text
|
|
150
|
-
// value attributes manually.
|
|
151
|
-
if (!getConcreteProps().text.empty()) {
|
|
152
|
-
auto textAttributes = TextAttributes::defaultTextAttributes();
|
|
153
|
-
textAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
|
154
|
-
textAttributes.apply(getConcreteProps().textAttributes);
|
|
155
|
-
textAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
|
156
|
-
auto fragment = AttributedString::Fragment{};
|
|
157
|
-
fragment.string = getConcreteProps().text;
|
|
158
|
-
fragment.textAttributes = textAttributes;
|
|
159
|
-
// If the TextInput opacity is 0 < n < 1, the opacity of the TextInput and
|
|
160
|
-
// text value's background will stack. This is a hack/workaround to prevent
|
|
161
|
-
// that effect.
|
|
162
|
-
fragment.textAttributes.backgroundColor = clearColor();
|
|
163
|
-
fragment.parentShadowView = ShadowView(*this);
|
|
164
|
-
attributedString.prependFragment(std::move(fragment));
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return attributedString;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
AttributedString WindowsTextInputShadowNode::getMostRecentAttributedString(const LayoutContext &layoutContext) const {
|
|
171
|
-
const auto &state = getStateData();
|
|
172
|
-
|
|
173
|
-
auto reactTreeAttributedString = getAttributedString(layoutContext);
|
|
174
|
-
|
|
175
|
-
// Sometimes the treeAttributedString will only differ from the state
|
|
176
|
-
// not by inherent properties (string or prop attributes), but by the frame of
|
|
177
|
-
// the parent which has changed Thus, we can't directly compare the entire
|
|
178
|
-
// AttributedString
|
|
179
|
-
bool treeAttributedStringChanged =
|
|
180
|
-
!state.reactTreeAttributedString.compareTextAttributesWithoutFrame(reactTreeAttributedString);
|
|
181
|
-
|
|
182
|
-
return (!treeAttributedStringChanged ? state.attributedStringBox.getValue() : reactTreeAttributedString);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
AttributedString WindowsTextInputShadowNode::getPlaceholderAttributedString(const LayoutContext &layoutContext) const {
|
|
186
|
-
const auto &props = getConcreteProps();
|
|
187
|
-
|
|
188
|
-
AttributedString attributedString;
|
|
189
|
-
attributedString.setBaseTextAttributes(props.textAttributes);
|
|
190
|
-
//[windows
|
|
191
|
-
if (!props.placeholder.empty()) {
|
|
192
|
-
auto textAttributes = TextAttributes::defaultTextAttributes();
|
|
193
|
-
textAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
|
|
194
|
-
textAttributes.apply(props.textAttributes);
|
|
195
|
-
|
|
196
|
-
/*
|
|
197
|
-
* These props are applied to `View`, therefore they must not be a part of
|
|
198
|
-
* base text attributes.
|
|
199
|
-
*/
|
|
200
|
-
textAttributes.backgroundColor = clearColor();
|
|
201
|
-
textAttributes.opacity = 1;
|
|
202
|
-
|
|
203
|
-
attributedString.appendFragment(
|
|
204
|
-
{.string = props.placeholder, .textAttributes = textAttributes, .parentShadowView = ShadowView(*this)});
|
|
205
|
-
}
|
|
206
|
-
// windows]
|
|
207
|
-
|
|
208
|
-
return ensurePlaceholderIfEmpty_DO_NOT_USE(attributedString);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
#pragma mark - LayoutableShadowNode
|
|
212
|
-
|
|
213
8
|
} // namespace facebook::react
|
|
@@ -3,84 +3,41 @@
|
|
|
3
3
|
|
|
4
4
|
#pragma once
|
|
5
5
|
|
|
6
|
-
#include
|
|
6
|
+
#include "ConcreteTextInputShadowNode.h"
|
|
7
7
|
#include "WindowsTextInputEventEmitter.h"
|
|
8
8
|
#include "WindowsTextInputProps.h"
|
|
9
9
|
#include "WindowsTextInputState.h"
|
|
10
10
|
|
|
11
|
-
#include <react/
|
|
12
|
-
#include <unordered_map>
|
|
13
|
-
|
|
11
|
+
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
|
14
12
|
#include <react/renderer/attributedstring/AttributedString.h>
|
|
15
|
-
#include <react/renderer/
|
|
16
|
-
#include <react/
|
|
13
|
+
#include <react/renderer/attributedstring/AttributedStringBox.h>
|
|
14
|
+
#include <react/renderer/core/conversions.h>
|
|
17
15
|
|
|
18
16
|
namespace facebook::react {
|
|
19
17
|
|
|
20
18
|
extern const char WindowsTextInputComponentName[];
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
* `ShadowNode` for <WindowsTextInput> component.
|
|
24
|
-
*/
|
|
25
|
-
class WindowsTextInputShadowNode final : public ConcreteViewShadowNode<
|
|
20
|
+
class WindowsTextInputShadowNode final : public ConcreteTextInputShadowNode<
|
|
26
21
|
WindowsTextInputComponentName,
|
|
27
|
-
WindowsTextInputProps,
|
|
28
|
-
WindowsTextInputEventEmitter,
|
|
29
|
-
WindowsTextInputState> {
|
|
22
|
+
facebook::react::WindowsTextInputProps,
|
|
23
|
+
facebook::react::WindowsTextInputEventEmitter,
|
|
24
|
+
facebook::react::WindowsTextInputState> {
|
|
30
25
|
public:
|
|
31
|
-
using
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*/
|
|
46
|
-
void setTextLayoutManager(std::shared_ptr<const TextLayoutManager> textLayoutManager);
|
|
47
|
-
|
|
48
|
-
#pragma mark - LayoutableShadowNode
|
|
49
|
-
protected:
|
|
50
|
-
Size measureContent(const LayoutContext &layoutContext, const LayoutConstraints &layoutConstraints) const override;
|
|
51
|
-
|
|
52
|
-
void layout(LayoutContext layoutContext) override;
|
|
53
|
-
|
|
54
|
-
Float baseline(const LayoutContext &layoutContext, Size size) const override {
|
|
55
|
-
// Calculate baseline as 80% of the text height
|
|
56
|
-
return size.height * 0.8f;
|
|
26
|
+
using Super = ConcreteTextInputShadowNode<
|
|
27
|
+
WindowsTextInputComponentName,
|
|
28
|
+
facebook::react::WindowsTextInputProps,
|
|
29
|
+
facebook::react::WindowsTextInputEventEmitter,
|
|
30
|
+
facebook::react::WindowsTextInputState>;
|
|
31
|
+
using Super::Super;
|
|
32
|
+
|
|
33
|
+
void updateTextInputState(
|
|
34
|
+
facebook::react::AttributedStringBox attributedStringBox,
|
|
35
|
+
facebook::react::AttributedString &reactTreeAttributedString,
|
|
36
|
+
facebook::react::ParagraphAttributes paragraphAttributes,
|
|
37
|
+
int64_t mostRecentEventCount) override {
|
|
38
|
+
Super::setStateData(facebook::react::WindowsTextInputState{
|
|
39
|
+
attributedStringBox, reactTreeAttributedString, paragraphAttributes, mostRecentEventCount});
|
|
57
40
|
}
|
|
58
|
-
|
|
59
|
-
std::shared_ptr<const TextLayoutManager> textLayoutManager_;
|
|
60
|
-
|
|
61
|
-
/*
|
|
62
|
-
* Determines the constraints to use while measure the underlying text
|
|
63
|
-
*/
|
|
64
|
-
LayoutConstraints getTextConstraints(const LayoutConstraints &layoutConstraints) const;
|
|
65
|
-
|
|
66
|
-
private:
|
|
67
|
-
/*
|
|
68
|
-
* Creates a `State` object (with `AttributedText` and
|
|
69
|
-
* `TextLayoutManager`) if needed.
|
|
70
|
-
*/
|
|
71
|
-
void updateStateIfNeeded(const LayoutContext &layoutContext);
|
|
72
|
-
|
|
73
|
-
/*
|
|
74
|
-
* Returns a `AttributedString` which represents text content of the node.
|
|
75
|
-
*/
|
|
76
|
-
AttributedString getAttributedString(const LayoutContext &layoutContext) const;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Get the most up-to-date attributed string for measurement and State.
|
|
80
|
-
*/
|
|
81
|
-
AttributedString getMostRecentAttributedString(const LayoutContext &layoutContext) const;
|
|
82
|
-
|
|
83
|
-
AttributedString getPlaceholderAttributedString(const LayoutContext &layoutContext) const;
|
|
84
41
|
};
|
|
85
42
|
|
|
86
43
|
} // namespace facebook::react
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <react/renderer/attributedstring/ParagraphAttributes.h>
|
|
12
12
|
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
|
|
13
13
|
|
|
14
|
+
#include <Fabric/AbiState.h>
|
|
14
15
|
#include <folly/dynamic.h>
|
|
15
16
|
#include <react/renderer/mapbuffer/MapBuffer.h>
|
|
16
17
|
#include <react/renderer/mapbuffer/MapBufferBuilder.h> // [windows]
|
|
@@ -20,7 +21,7 @@ namespace facebook::react {
|
|
|
20
21
|
/*
|
|
21
22
|
* State for <TextInput> component.
|
|
22
23
|
*/
|
|
23
|
-
class WindowsTextInputState
|
|
24
|
+
class WindowsTextInputState {
|
|
24
25
|
public:
|
|
25
26
|
WindowsTextInputState() = default;
|
|
26
27
|
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
#include "WindowsComponentDescriptorRegistry.h"
|
|
6
6
|
|
|
7
7
|
#include <Fabric/AbiComponentDescriptor.h>
|
|
8
|
-
#include <Fabric/AbiViewComponentDescriptor.h>
|
|
9
8
|
#include <Fabric/Composition/TextInput/WindowsTextInputComponentDescriptor.h>
|
|
10
9
|
#include <react/components/rnwcore/ComponentDescriptors.h>
|
|
11
10
|
#include <react/renderer/components/image/ImageComponentDescriptor.h>
|
|
@@ -25,6 +25,10 @@ namespace Microsoft.ReactNative.Composition
|
|
|
25
25
|
[experimental]
|
|
26
26
|
delegate void PortalComponentViewInitializer(PortalComponentView view);
|
|
27
27
|
|
|
28
|
+
[webhosthidden]
|
|
29
|
+
[experimental]
|
|
30
|
+
delegate void TextInputComponentViewInitializer(WindowsTextInputComponentView view);
|
|
31
|
+
|
|
28
32
|
[experimental]
|
|
29
33
|
[webhosthidden]
|
|
30
34
|
delegate Microsoft.UI.Composition.Visual CreateVisualDelegate(Microsoft.ReactNative.ComponentView view);
|
|
@@ -69,6 +73,7 @@ namespace Microsoft.ReactNative.Composition
|
|
|
69
73
|
void SetViewComponentViewInitializer(ViewComponentViewInitializer initializer);
|
|
70
74
|
void SetContentIslandComponentViewInitializer(ComponentIslandComponentViewInitializer initializer);
|
|
71
75
|
void SetPortalComponentViewInitializer(PortalComponentViewInitializer initializer);
|
|
76
|
+
void SetTextInputComponentViewInitializer(TextInputComponentViewInitializer initializer);
|
|
72
77
|
void SetCreateVisualHandler(CreateVisualDelegate impl);
|
|
73
78
|
void SetViewFeatures(ComponentViewFeatures viewFeatures);
|
|
74
79
|
void SetUpdateLayoutMetricsHandler(UpdateLayoutMetricsDelegate impl);
|
|
@@ -97,7 +97,6 @@
|
|
|
97
97
|
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
|
|
98
98
|
<WarningLevel>Level4</WarningLevel>
|
|
99
99
|
<AdditionalOptions>%(AdditionalOptions) /bigobj /ZH:SHA_256</AdditionalOptions>
|
|
100
|
-
<AdditionalOptions Condition="'$(PlatformToolsetVersion)' != '' And $(PlatformToolsetVersion)<145">%(AdditionalOptions) /await</AdditionalOptions>
|
|
101
100
|
<AdditionalIncludeDirectories>
|
|
102
101
|
$(ExternalDir)fmt\include;
|
|
103
102
|
$(ReactNativeWindowsDir)Microsoft.ReactNative;
|
|
@@ -149,6 +149,35 @@ struct LoadedCallbackGuard {
|
|
|
149
149
|
Mso::CntPtr<ReactInstanceWin> m_reactInstance;
|
|
150
150
|
};
|
|
151
151
|
|
|
152
|
+
//=============================================================================================
|
|
153
|
+
// InitTaskGuard fails the load if an initialization task is destroyed without running.
|
|
154
|
+
// It reports the failure in the native queue. ReactHost's load action stays pending until then,
|
|
155
|
+
// so ReactHost cannot be released while the instance reports the error to it.
|
|
156
|
+
//=============================================================================================
|
|
157
|
+
|
|
158
|
+
struct InitTaskGuard {
|
|
159
|
+
InitTaskGuard(ReactInstanceWin &reactInstance) noexcept : m_reactInstance{&reactInstance} {}
|
|
160
|
+
|
|
161
|
+
InitTaskGuard(const InitTaskGuard &other) = delete;
|
|
162
|
+
InitTaskGuard &operator=(const InitTaskGuard &other) = delete;
|
|
163
|
+
|
|
164
|
+
void Dismiss() noexcept {
|
|
165
|
+
m_reactInstance = nullptr;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
~InitTaskGuard() noexcept {
|
|
169
|
+
if (auto reactInstance = std::move(m_reactInstance)) {
|
|
170
|
+
Mso::DispatchQueue queue = reactInstance->Queue();
|
|
171
|
+
queue.InvokeElsePost([instance = std::move(reactInstance)]() noexcept {
|
|
172
|
+
instance->OnReactInstanceLoaded(Mso::CancellationErrorProvider().MakeErrorCode(true));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private:
|
|
178
|
+
Mso::CntPtr<ReactInstanceWin> m_reactInstance;
|
|
179
|
+
};
|
|
180
|
+
|
|
152
181
|
struct BridgeUIBatchInstanceCallback final : public facebook::react::InstanceCallback {
|
|
153
182
|
BridgeUIBatchInstanceCallback(Mso::WeakPtr<ReactInstanceWin> wkInstance) : m_wkInstance(wkInstance) {}
|
|
154
183
|
virtual ~BridgeUIBatchInstanceCallback() = default;
|
|
@@ -624,13 +653,21 @@ void ReactInstanceWin::InitializeBridgeless() noexcept {
|
|
|
624
653
|
winrt::Microsoft::ReactNative::Composition::implementation::UriImageManager::Install(
|
|
625
654
|
ReactPropertyBag(m_reactContext->Properties()), m_options.UriImageManager);
|
|
626
655
|
|
|
627
|
-
|
|
656
|
+
// The app's UI queue, or the native queue, can destroy an initialization task without running it.
|
|
657
|
+
// Office, for example, cancels its UI queue when it starts to shut down. The load would then never
|
|
658
|
+
// complete, and ReactHost would never unload the instance, so the host could never close.
|
|
659
|
+
// The guard fails the load in that case. The native task dismisses it; the tasks that load the
|
|
660
|
+
// bundle carry their own guards.
|
|
661
|
+
auto loadGuard = std::make_shared<InitTaskGuard>(*this);
|
|
662
|
+
m_uiQueue->Post([this, weakThis = Mso::WeakPtr{this}, loadGuard]() noexcept {
|
|
628
663
|
// Objects that must be created on the UI thread
|
|
629
664
|
if (auto strongThis = weakThis.GetStrongPtr()) {
|
|
630
665
|
InitUIDependentCalls();
|
|
631
666
|
|
|
632
|
-
strongThis->Queue().Post([this, weakThis]() noexcept {
|
|
667
|
+
strongThis->Queue().Post([this, weakThis, loadGuard]() noexcept {
|
|
668
|
+
loadGuard->Dismiss();
|
|
633
669
|
if (auto strongThis = weakThis.GetStrongPtr()) {
|
|
670
|
+
m_isNativeInitStarted = true;
|
|
634
671
|
auto devSettings = strongThis->CreateDevSettings();
|
|
635
672
|
|
|
636
673
|
try {
|
|
@@ -797,12 +834,16 @@ void ReactInstanceWin::InitializeWithBridge() noexcept {
|
|
|
797
834
|
ReactPropertyBag(m_reactContext->Properties()), m_options.UriImageManager);
|
|
798
835
|
#endif
|
|
799
836
|
|
|
800
|
-
|
|
837
|
+
// See InitializeBridgeless for why the initialization tasks carry an InitTaskGuard.
|
|
838
|
+
auto loadGuard = std::make_shared<InitTaskGuard>(*this);
|
|
839
|
+
m_uiQueue->Post([this, weakThis = Mso::WeakPtr{this}, loadGuard]() noexcept {
|
|
801
840
|
// Objects that must be created on the UI thread
|
|
802
841
|
if (auto strongThis = weakThis.GetStrongPtr()) {
|
|
803
842
|
InitUIDependentCalls();
|
|
804
|
-
strongThis->Queue().Post([this, weakThis]() noexcept {
|
|
843
|
+
strongThis->Queue().Post([this, weakThis, loadGuard]() noexcept {
|
|
844
|
+
loadGuard->Dismiss();
|
|
805
845
|
if (auto strongThis = weakThis.GetStrongPtr()) {
|
|
846
|
+
m_isNativeInitStarted = true;
|
|
806
847
|
auto devSettings = strongThis->CreateDevSettings();
|
|
807
848
|
|
|
808
849
|
auto getBoolProperty = [properties = ReactPropertyBag{m_options.Properties}](
|
|
@@ -1075,7 +1116,9 @@ Mso::Future<void> ReactInstanceWin::Destroy() noexcept {
|
|
|
1075
1116
|
AbandonJSCallQueue();
|
|
1076
1117
|
|
|
1077
1118
|
// Make sure that the instance is not destroyed yet
|
|
1119
|
+
bool completesOnJSQueue = false;
|
|
1078
1120
|
if (auto instance = m_instance.Exchange(nullptr)) {
|
|
1121
|
+
completesOnJSQueue = true;
|
|
1079
1122
|
{
|
|
1080
1123
|
// Release the JSI runtime
|
|
1081
1124
|
std::scoped_lock lock{m_mutex};
|
|
@@ -1084,13 +1127,19 @@ Mso::Future<void> ReactInstanceWin::Destroy() noexcept {
|
|
|
1084
1127
|
}
|
|
1085
1128
|
// Release the message queues before the ui manager and instance.
|
|
1086
1129
|
m_nativeMessageThread.Exchange(nullptr);
|
|
1087
|
-
m_jsMessageThread.Exchange(nullptr);
|
|
1130
|
+
auto jsMessageThread = m_jsMessageThread.Exchange(nullptr);
|
|
1131
|
+
if (!m_isNativeInitStarted && jsMessageThread) {
|
|
1132
|
+
// A queue dropped the initialization task, so the bridge was never created. Destroying the bridge is
|
|
1133
|
+
// what quits the JS queue and completes m_whenDestroyed, so quit the queue here instead.
|
|
1134
|
+
jsMessageThread->quitSynchronous();
|
|
1135
|
+
}
|
|
1088
1136
|
m_instanceWrapper.Exchange(nullptr);
|
|
1089
1137
|
m_jsDispatchQueue.Exchange(nullptr);
|
|
1090
1138
|
}
|
|
1091
1139
|
|
|
1092
1140
|
#ifdef USE_FABRIC
|
|
1093
1141
|
if (m_bridgelessReactInstance) {
|
|
1142
|
+
completesOnJSQueue = true;
|
|
1094
1143
|
if (auto jsMessageThread = m_jsMessageThread.Exchange(nullptr)) {
|
|
1095
1144
|
jsMessageThread->runOnQueueSync([&]() noexcept {
|
|
1096
1145
|
// Unregister from inspector BEFORE shutting down JS thread
|
|
@@ -1119,6 +1168,12 @@ Mso::Future<void> ReactInstanceWin::Destroy() noexcept {
|
|
|
1119
1168
|
}
|
|
1120
1169
|
#endif
|
|
1121
1170
|
|
|
1171
|
+
if (!completesOnJSQueue) {
|
|
1172
|
+
// Initialization never created the instance that runs on the JS queue, for example because a queue
|
|
1173
|
+
// dropped its initialization task. No JS queue work item will complete m_whenDestroyed.
|
|
1174
|
+
m_whenDestroyed.TrySetValue();
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1122
1177
|
return m_whenDestroyedResult;
|
|
1123
1178
|
}
|
|
1124
1179
|
|
|
@@ -149,6 +149,7 @@ class ReactInstanceWin final : public Mso::ActiveObject<IReactInstanceInternal>
|
|
|
149
149
|
void OnDebuggerAttach() noexcept;
|
|
150
150
|
|
|
151
151
|
friend struct LoadedCallbackGuard;
|
|
152
|
+
friend struct InitTaskGuard;
|
|
152
153
|
void OnReactInstanceLoaded(const Mso::ErrorCode &errorCode) noexcept;
|
|
153
154
|
|
|
154
155
|
void DrainJSCallQueue() noexcept;
|
|
@@ -182,6 +183,8 @@ class ReactInstanceWin final : public Mso::ActiveObject<IReactInstanceInternal>
|
|
|
182
183
|
std::atomic<bool> m_isLoaded{false};
|
|
183
184
|
std::atomic<bool> m_isDestroyed{false};
|
|
184
185
|
std::atomic<bool> m_isRekaInitialized{false};
|
|
186
|
+
// Set on the native queue when the initialization task that runs there starts.
|
|
187
|
+
std::atomic<bool> m_isNativeInitStarted{false};
|
|
185
188
|
|
|
186
189
|
private: // fields controlled by mutex
|
|
187
190
|
mutable std::mutex m_mutex;
|
|
@@ -98,5 +98,16 @@ namespace Microsoft.ReactNative {
|
|
|
98
98
|
// TODO add accessors to all the properties on ImageProps
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
[default_interface]
|
|
102
|
+
[webhosthidden]
|
|
103
|
+
[experimental]
|
|
104
|
+
runtimeclass TextInputProps : ViewProps
|
|
105
|
+
{
|
|
106
|
+
String Placeholder { get; };
|
|
107
|
+
Boolean SecureTextEntry { get; };
|
|
108
|
+
// TODO add accessors to all the properties on TextInputProps
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
101
112
|
|
|
102
113
|
} // namespace Microsoft. ReactNative
|
|
@@ -201,14 +201,14 @@ class ViewShadowNode : public ShadowNodeBase {
|
|
|
201
201
|
auto contentControl = winrt::make<winrt::Microsoft::ReactNative::implementation::ViewControl>();
|
|
202
202
|
|
|
203
203
|
m_contentControlGotFocusRevoker = contentControl.GotFocus(winrt::auto_revoke, [=](auto &&, auto &&args) {
|
|
204
|
-
if (args.OriginalSource().try_as<xaml::UIElement>() == contentControl.as<xaml::UIElement>()) {
|
|
204
|
+
if (args.OriginalSource().template try_as<xaml::UIElement>() == contentControl.as<xaml::UIElement>()) {
|
|
205
205
|
auto tag = m_tag;
|
|
206
206
|
DispatchEvent("topFocus", std::move(folly::dynamic::object("target", tag)));
|
|
207
207
|
}
|
|
208
208
|
});
|
|
209
209
|
|
|
210
210
|
m_contentControlLostFocusRevoker = contentControl.LostFocus(winrt::auto_revoke, [=](auto &&, auto &&args) {
|
|
211
|
-
if (args.OriginalSource().try_as<xaml::UIElement>() == contentControl.as<xaml::UIElement>()) {
|
|
211
|
+
if (args.OriginalSource().template try_as<xaml::UIElement>() == contentControl.as<xaml::UIElement>()) {
|
|
212
212
|
auto tag = m_tag;
|
|
213
213
|
DispatchEvent("topBlur", std::move(folly::dynamic::object("target", tag)));
|
|
214
214
|
}
|