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.
Files changed (52) hide show
  1. package/Microsoft.ReactNative/Fabric/AbiComponentDescriptor.cpp +6 -2
  2. package/Microsoft.ReactNative/Fabric/AbiShadowNode.cpp +0 -47
  3. package/Microsoft.ReactNative/Fabric/AbiShadowNode.h +40 -8
  4. package/Microsoft.ReactNative/Fabric/AbiState.h +26 -8
  5. package/Microsoft.ReactNative/Fabric/AbiTextInputProps.h +51 -0
  6. package/Microsoft.ReactNative/Fabric/AbiTextInputShadowNode.cpp +88 -0
  7. package/Microsoft.ReactNative/Fabric/AbiTextInputShadowNode.h +65 -0
  8. package/Microsoft.ReactNative/Fabric/AbiViewComponentDescriptor.h +52 -18
  9. package/Microsoft.ReactNative/Fabric/AbiViewShadowNode.cpp +0 -18
  10. package/Microsoft.ReactNative/Fabric/AbiViewShadowNode.h +16 -4
  11. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +2 -1
  12. package/Microsoft.ReactNative/Fabric/Composition/ComponentViewRegistry.cpp +1 -2
  13. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +1 -1
  14. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +3 -2
  15. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +6 -4
  16. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +6 -4
  17. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +2 -1
  18. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +22 -0
  19. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +2 -1
  20. package/Microsoft.ReactNative/Fabric/Composition/TextInput/AbiTextInputState.h +38 -0
  21. package/Microsoft.ReactNative/Fabric/Composition/TextInput/ConcreteTextInputShadowNode.h +272 -0
  22. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentDescriptor.h +21 -14
  23. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +345 -90
  24. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +24 -4
  25. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.h +1 -1
  26. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +0 -205
  27. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +22 -65
  28. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.h +2 -1
  29. package/Microsoft.ReactNative/Fabric/WindowsComponentDescriptorRegistry.cpp +0 -1
  30. package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +5 -0
  31. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +0 -1
  32. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +60 -5
  33. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +3 -0
  34. package/Microsoft.ReactNative/ViewProps.idl +11 -0
  35. package/Microsoft.ReactNative/Views/ViewViewManager.cpp +2 -2
  36. package/Microsoft.ReactNative.Cxx/ComponentView.Experimental.interop.h +12 -0
  37. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  38. package/PropertySheets/JSEngine.props +1 -1
  39. package/PropertySheets/React.Cpp.props +0 -1
  40. package/PropertySheets/WinUI.props +2 -1
  41. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/Instance.cpp +386 -0
  42. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/NativeToJsBridge.h +148 -0
  43. package/Scripts/EnableInternalWinAppSDKFeed.ps1 +12 -5
  44. package/Scripts/NuGetRestoreForceEvaluateAllSolutions.ps1 +2 -2
  45. package/Shared/Networking/WinRTWebSocketResource.h +1 -5
  46. package/Shared/OInstance.cpp +13 -8
  47. package/Shared/Shared.vcxitems +3 -3
  48. package/Shared/Shared.vcxitems.filters +1 -1
  49. package/external/folly/folly.vcxitems +10 -0
  50. package/index.windows.js +5 -0
  51. package/package.json +4 -4
  52. 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<WindowsTextInputComponentView, ViewComponentView> {
27
+ : public WindowsTextInputComponentViewT<
28
+ WindowsTextInputComponentView,
29
+ ViewComponentView,
30
+ ::Microsoft::ReactNative::Composition::Experimental::ITextInputComponentInterop> {
26
31
  friend CompTextHost;
27
32
 
28
- using Super = WindowsTextInputComponentViewT<WindowsTextInputComponentView, ViewComponentView>;
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 std::string &str) noexcept;
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 final : public ViewProps, public BaseTextProps {
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 <react/renderer/textlayoutmanager/WindowsTextLayoutManager.h>
6
+ #include "ConcreteTextInputShadowNode.h"
7
7
  #include "WindowsTextInputEventEmitter.h"
8
8
  #include "WindowsTextInputProps.h"
9
9
  #include "WindowsTextInputState.h"
10
10
 
11
- #include <react/components/rnwcore/EventEmitters.h>
12
- #include <unordered_map>
13
-
11
+ #include <react/featureflags/ReactNativeFeatureFlags.h>
14
12
  #include <react/renderer/attributedstring/AttributedString.h>
15
- #include <react/renderer/components/view/ConcreteViewShadowNode.h>
16
- #include <react/utils/ContextContainer.h>
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 ConcreteViewShadowNode::ConcreteViewShadowNode;
32
-
33
- static ShadowNodeTraits BaseTraits() {
34
- auto traits = ConcreteViewShadowNode::BaseTraits();
35
- traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
36
- traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
37
- traits.set(ShadowNodeTraits::Trait::BaselineYogaNode);
38
- return traits;
39
- }
40
-
41
- /*
42
- * Associates a shared TextLayoutManager with the node.
43
- * `TextInputShadowNode` uses the manager to measure text content
44
- * and construct `TextInputState` objects.
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 final {
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)&lt;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
- m_uiQueue->Post([this, weakThis = Mso::WeakPtr{this}]() noexcept {
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
- m_uiQueue->Post([this, weakThis = Mso::WeakPtr{this}]() noexcept {
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
  }