react-native-windows 0.74.25 → 0.74.27

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 (87) hide show
  1. package/Libraries/Modal/Modal.windows.js +352 -0
  2. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +26 -46
  3. package/Microsoft.ReactNative/Fabric/ComponentView.h +6 -19
  4. package/Microsoft.ReactNative/Fabric/Composition/BorderPrimitive.cpp +5 -0
  5. package/Microsoft.ReactNative/Fabric/Composition/BorderPrimitive.h +4 -0
  6. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +164 -3
  7. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +7 -0
  8. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +205 -101
  9. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +21 -13
  10. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +9 -2
  11. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +2 -1
  12. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +59 -9
  13. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.h +2 -0
  14. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +78 -30
  15. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +21 -1
  16. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +10 -0
  17. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +3 -0
  18. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +14 -1
  19. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +4 -0
  20. package/Microsoft.ReactNative/Fabric/Composition/UnimplementedNativeViewComponentView.cpp +1 -1
  21. package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +25 -0
  22. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  23. package/codegen/NativeAccessibilityInfoSpec.g.h +1 -0
  24. package/codegen/NativeAccessibilityManagerSpec.g.h +1 -0
  25. package/codegen/NativeActionSheetManagerSpec.g.h +1 -0
  26. package/codegen/NativeAlertManagerSpec.g.h +1 -0
  27. package/codegen/NativeAnimatedModuleSpec.g.h +1 -0
  28. package/codegen/NativeAnimatedTurboModuleSpec.g.h +1 -0
  29. package/codegen/NativeAnimationsDebugModuleSpec.g.h +1 -0
  30. package/codegen/NativeAppStateSpec.g.h +1 -0
  31. package/codegen/NativeAppThemeSpec.g.h +1 -0
  32. package/codegen/NativeAppearanceSpec.g.h +1 -0
  33. package/codegen/NativeBlobModuleSpec.g.h +1 -0
  34. package/codegen/NativeBugReportingSpec.g.h +1 -0
  35. package/codegen/NativeClipboardSpec.g.h +1 -0
  36. package/codegen/NativeDevLoadingViewSpec.g.h +1 -0
  37. package/codegen/NativeDevMenuSpec.g.h +1 -0
  38. package/codegen/NativeDevSettingsSpec.g.h +1 -0
  39. package/codegen/NativeDevToolsSettingsManagerSpec.g.h +1 -0
  40. package/codegen/NativeDeviceEventManagerSpec.g.h +1 -0
  41. package/codegen/NativeDeviceInfoSpec.g.h +1 -0
  42. package/codegen/NativeDialogManagerAndroidSpec.g.h +1 -0
  43. package/codegen/NativeDialogManagerWindowsSpec.g.h +1 -0
  44. package/codegen/NativeExceptionsManagerSpec.g.h +1 -0
  45. package/codegen/NativeFileReaderModuleSpec.g.h +1 -0
  46. package/codegen/NativeFrameRateLoggerSpec.g.h +1 -0
  47. package/codegen/NativeHeadlessJsTaskSupportSpec.g.h +1 -0
  48. package/codegen/NativeI18nManagerSpec.g.h +1 -0
  49. package/codegen/NativeImageEditorSpec.g.h +1 -0
  50. package/codegen/NativeImageLoaderAndroidSpec.g.h +1 -0
  51. package/codegen/NativeImageLoaderIOSSpec.g.h +1 -0
  52. package/codegen/NativeImageStoreAndroidSpec.g.h +1 -0
  53. package/codegen/NativeImageStoreIOSSpec.g.h +1 -0
  54. package/codegen/NativeIntentAndroidSpec.g.h +1 -0
  55. package/codegen/NativeIntersectionObserverSpec.g.h +1 -0
  56. package/codegen/NativeJSCHeapCaptureSpec.g.h +1 -0
  57. package/codegen/NativeJSCSamplingProfilerSpec.g.h +1 -0
  58. package/codegen/NativeKeyboardObserverSpec.g.h +1 -0
  59. package/codegen/NativeLinkingManagerSpec.g.h +1 -0
  60. package/codegen/NativeLogBoxSpec.g.h +1 -0
  61. package/codegen/NativeModalManagerSpec.g.h +1 -0
  62. package/codegen/NativeMutationObserverSpec.g.h +1 -0
  63. package/codegen/NativeNetworkingAndroidSpec.g.h +1 -0
  64. package/codegen/NativeNetworkingIOSSpec.g.h +1 -0
  65. package/codegen/NativePerformanceObserverSpec.g.h +1 -0
  66. package/codegen/NativePerformanceSpec.g.h +1 -0
  67. package/codegen/NativePermissionsAndroidSpec.g.h +1 -0
  68. package/codegen/NativePlatformConstantsAndroidSpec.g.h +1 -0
  69. package/codegen/NativePlatformConstantsIOSSpec.g.h +1 -0
  70. package/codegen/NativePlatformConstantsWinSpec.g.h +1 -0
  71. package/codegen/NativePushNotificationManagerIOSSpec.g.h +1 -0
  72. package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +1 -0
  73. package/codegen/NativeRedBoxSpec.g.h +1 -0
  74. package/codegen/NativeSampleTurboModuleSpec.g.h +1 -0
  75. package/codegen/NativeSegmentFetcherSpec.g.h +1 -0
  76. package/codegen/NativeSettingsManagerSpec.g.h +1 -0
  77. package/codegen/NativeShareModuleSpec.g.h +1 -0
  78. package/codegen/NativeSoundManagerSpec.g.h +1 -0
  79. package/codegen/NativeSourceCodeSpec.g.h +1 -0
  80. package/codegen/NativeStatusBarManagerAndroidSpec.g.h +1 -0
  81. package/codegen/NativeStatusBarManagerIOSSpec.g.h +1 -0
  82. package/codegen/NativeTimingSpec.g.h +1 -0
  83. package/codegen/NativeToastAndroidSpec.g.h +1 -0
  84. package/codegen/NativeUIManagerSpec.g.h +1 -0
  85. package/codegen/NativeVibrationSpec.g.h +1 -0
  86. package/codegen/NativeWebSocketModuleSpec.g.h +1 -0
  87. package/package.json +3 -3
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @flow strict-local
9
+ */
10
+
11
+ import type {ViewProps} from '../Components/View/ViewPropTypes';
12
+ import type {RootTag} from '../ReactNative/RootTag';
13
+ import type {DirectEventHandler} from '../Types/CodegenTypes';
14
+
15
+ import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
16
+ import {type EventSubscription} from '../vendor/emitter/EventEmitter';
17
+ import ModalInjection from './ModalInjection';
18
+ import NativeModalManager from './NativeModalManager';
19
+ import RCTModalHostView from './RCTModalHostViewNativeComponent';
20
+ import {VirtualizedListContextResetter} from '@react-native/virtualized-lists';
21
+
22
+ const ScrollView = require('../Components/ScrollView/ScrollView');
23
+ const View = require('../Components/View/View');
24
+ const AppContainer = require('../ReactNative/AppContainer');
25
+ const I18nManager = require('../ReactNative/I18nManager');
26
+ const {RootTagContext} = require('../ReactNative/RootTag');
27
+ const StyleSheet = require('../StyleSheet/StyleSheet');
28
+ const Platform = require('../Utilities/Platform');
29
+ const React = require('react');
30
+
31
+ type ModalEventDefinitions = {
32
+ modalDismissed: [{modalID: number}],
33
+ };
34
+
35
+ const ModalEventEmitter =
36
+ (Platform.OS === 'ios' || Platform.OS === 'windows') && // [Windows]
37
+ NativeModalManager != null
38
+ ? new NativeEventEmitter<ModalEventDefinitions>(
39
+ // T88715063: NativeEventEmitter only used this parameter on iOS. Now it uses it on all platforms, so this code was modified automatically to preserve its behavior
40
+ // If you want to use the native module on other platforms, please remove this condition and test its behavior
41
+ Platform.OS !== 'ios' && Platform.OS !== 'windows' // [Windows]
42
+ ? null
43
+ : NativeModalManager,
44
+ )
45
+ : null;
46
+
47
+ /**
48
+ * The Modal component is a simple way to present content above an enclosing view.
49
+ *
50
+ * See https://reactnative.dev/docs/modal
51
+ */
52
+
53
+ // In order to route onDismiss callbacks, we need to uniquely identifier each
54
+ // <Modal> on screen. There can be different ones, either nested or as siblings.
55
+ // We cannot pass the onDismiss callback to native as the view will be
56
+ // destroyed before the callback is fired.
57
+ let uniqueModalIdentifier = 0;
58
+
59
+ type OrientationChangeEvent = $ReadOnly<{|
60
+ orientation: 'portrait' | 'landscape',
61
+ |}>;
62
+
63
+ export type Props = $ReadOnly<{|
64
+ ...ViewProps,
65
+
66
+ /**
67
+ * The `animationType` prop controls how the modal animates.
68
+ *
69
+ * See https://reactnative.dev/docs/modal#animationtype
70
+ */
71
+ animationType?: ?('none' | 'slide' | 'fade'),
72
+
73
+ /**
74
+ * The `presentationStyle` prop controls how the modal appears.
75
+ *
76
+ * See https://reactnative.dev/docs/modal#presentationstyle
77
+ */
78
+ presentationStyle?: ?(
79
+ | 'fullScreen'
80
+ | 'pageSheet'
81
+ | 'formSheet'
82
+ | 'overFullScreen'
83
+ ),
84
+
85
+ /**
86
+ * The `transparent` prop determines whether your modal will fill the
87
+ * entire view.
88
+ *
89
+ * See https://reactnative.dev/docs/modal#transparent
90
+ */
91
+ transparent?: ?boolean,
92
+
93
+ /**
94
+ * The `statusBarTranslucent` prop determines whether your modal should go under
95
+ * the system statusbar.
96
+ *
97
+ * See https://reactnative.dev/docs/modal.html#statusbartranslucent-android
98
+ */
99
+ statusBarTranslucent?: ?boolean,
100
+
101
+ /**
102
+ * The `hardwareAccelerated` prop controls whether to force hardware
103
+ * acceleration for the underlying window.
104
+ *
105
+ * This prop works only on Android.
106
+ *
107
+ * See https://reactnative.dev/docs/modal#hardwareaccelerated
108
+ */
109
+ hardwareAccelerated?: ?boolean,
110
+
111
+ /**
112
+ * The `visible` prop determines whether your modal is visible.
113
+ *
114
+ * See https://reactnative.dev/docs/modal#visible
115
+ */
116
+ visible?: ?boolean,
117
+
118
+ /**
119
+ * The `onRequestClose` callback is called when the user taps the hardware
120
+ * back button on Android or the menu button on Apple TV.
121
+ *
122
+ * This is required on Apple TV and Android.
123
+ *
124
+ * See https://reactnative.dev/docs/modal#onrequestclose
125
+ */
126
+ onRequestClose?: ?DirectEventHandler<null>,
127
+
128
+ /**
129
+ * The `onShow` prop allows passing a function that will be called once the
130
+ * modal has been shown.
131
+ *
132
+ * See https://reactnative.dev/docs/modal#onshow
133
+ */
134
+ onShow?: ?DirectEventHandler<null>,
135
+
136
+ /**
137
+ * The `onDismiss` prop allows passing a function that will be called once
138
+ * the modal has been dismissed.
139
+ *
140
+ * See https://reactnative.dev/docs/modal#ondismiss
141
+ */
142
+ onDismiss?: ?() => mixed,
143
+
144
+ /**
145
+ * The `supportedOrientations` prop allows the modal to be rotated to any of the specified orientations.
146
+ *
147
+ * See https://reactnative.dev/docs/modal#supportedorientations
148
+ */
149
+ supportedOrientations?: ?$ReadOnlyArray<
150
+ | 'portrait'
151
+ | 'portrait-upside-down'
152
+ | 'landscape'
153
+ | 'landscape-left'
154
+ | 'landscape-right',
155
+ >,
156
+
157
+ /**
158
+ * The `onOrientationChange` callback is called when the orientation changes while the modal is being displayed.
159
+ *
160
+ * See https://reactnative.dev/docs/modal#onorientationchange
161
+ */
162
+ onOrientationChange?: ?DirectEventHandler<OrientationChangeEvent>,
163
+
164
+ /**
165
+ * The `backdropColor` props sets the background color of the modal's container.
166
+ * Defaults to `white` if not provided and transparent is `false`. Ignored if `transparent` is `true`.
167
+ */
168
+ backdropColor?: ?string,
169
+ |}>;
170
+
171
+ function confirmProps(props: Props) {
172
+ if (__DEV__) {
173
+ if (
174
+ props.presentationStyle &&
175
+ props.presentationStyle !== 'overFullScreen' &&
176
+ props.transparent === true
177
+ ) {
178
+ console.warn(
179
+ `Modal with '${props.presentationStyle}' presentation style and 'transparent' value is not supported.`,
180
+ );
181
+ }
182
+ }
183
+ }
184
+
185
+ // Create a state to track whether the Modal is rendering or not.
186
+ // This is the only prop that controls whether the modal is rendered or not.
187
+ type State = {
188
+ isRendered: boolean,
189
+ };
190
+
191
+ class Modal extends React.Component<Props, State> {
192
+ static defaultProps: {|hardwareAccelerated: boolean, visible: boolean|} = {
193
+ visible: true,
194
+ hardwareAccelerated: false,
195
+ };
196
+
197
+ static contextType: React.Context<RootTag> = RootTagContext;
198
+
199
+ _identifier: number;
200
+ _eventSubscription: ?EventSubscription;
201
+
202
+ constructor(props: Props) {
203
+ super(props);
204
+ if (__DEV__) {
205
+ confirmProps(props);
206
+ }
207
+ this._identifier = uniqueModalIdentifier++;
208
+ this.state = {
209
+ isRendered: props.visible === true,
210
+ };
211
+ }
212
+
213
+ componentDidMount() {
214
+ // 'modalDismissed' is for the old renderer in iOS only
215
+ if (ModalEventEmitter) {
216
+ this._eventSubscription = ModalEventEmitter.addListener(
217
+ 'modalDismissed',
218
+ event => {
219
+ this.setState({isRendered: false}, () => {
220
+ if (event.modalID === this._identifier && this.props.onDismiss) {
221
+ this.props.onDismiss();
222
+ }
223
+ });
224
+ },
225
+ );
226
+ }
227
+ }
228
+
229
+ componentWillUnmount() {
230
+ if (this._eventSubscription) {
231
+ this._eventSubscription.remove();
232
+ }
233
+ }
234
+
235
+ componentDidUpdate(prevProps: Props) {
236
+ if (prevProps.visible === false && this.props.visible === true) {
237
+ this.setState({isRendered: true});
238
+ }
239
+
240
+ if (__DEV__) {
241
+ confirmProps(this.props);
242
+ }
243
+ }
244
+
245
+ // Helper function to encapsulate platform specific logic to show or not the Modal.
246
+ _shouldShowModal(): boolean {
247
+ if (Platform.OS === 'ios' || Platform.OS === 'windows') {
248
+ // [Windows]
249
+ return this.props.visible === true || this.state.isRendered === true;
250
+ }
251
+
252
+ return this.props.visible === true;
253
+ }
254
+
255
+ render(): React.Node {
256
+ if (!this._shouldShowModal()) {
257
+ return null;
258
+ }
259
+
260
+ const containerStyles = {
261
+ backgroundColor:
262
+ this.props.transparent === true
263
+ ? 'transparent'
264
+ : this.props.backdropColor ?? 'white',
265
+ };
266
+
267
+ let animationType = this.props.animationType || 'none';
268
+
269
+ let presentationStyle = this.props.presentationStyle;
270
+ if (!presentationStyle) {
271
+ presentationStyle = 'fullScreen';
272
+ if (this.props.transparent === true) {
273
+ presentationStyle = 'overFullScreen';
274
+ }
275
+ }
276
+
277
+ const innerChildren = __DEV__ ? (
278
+ <AppContainer rootTag={this.context}>{this.props.children}</AppContainer>
279
+ ) : (
280
+ this.props.children
281
+ );
282
+
283
+ const onDismiss = () => {
284
+ // OnDismiss is implemented on iOS/Windows only. // [Windows]
285
+ if (Platform.OS === 'ios' || Platform.OS === 'windows') {
286
+ // [Windows]
287
+ this.setState({isRendered: false}, () => {
288
+ if (this.props.onDismiss) {
289
+ this.props.onDismiss();
290
+ }
291
+ });
292
+ }
293
+ };
294
+
295
+ return (
296
+ <RCTModalHostView
297
+ animationType={animationType}
298
+ presentationStyle={presentationStyle}
299
+ transparent={this.props.transparent}
300
+ hardwareAccelerated={this.props.hardwareAccelerated}
301
+ onRequestClose={this.props.onRequestClose}
302
+ onShow={this.props.onShow}
303
+ onDismiss={onDismiss}
304
+ visible={this.props.visible}
305
+ statusBarTranslucent={this.props.statusBarTranslucent}
306
+ identifier={this._identifier}
307
+ style={styles.modal}
308
+ // $FlowFixMe[method-unbinding] added when improving typing for this parameters
309
+ onStartShouldSetResponder={this._shouldSetResponder}
310
+ supportedOrientations={this.props.supportedOrientations}
311
+ onOrientationChange={this.props.onOrientationChange}
312
+ testID={this.props.testID}>
313
+ <VirtualizedListContextResetter>
314
+ <ScrollView.Context.Provider value={null}>
315
+ <View
316
+ style={[styles.container, containerStyles]}
317
+ collapsable={false}>
318
+ {innerChildren}
319
+ </View>
320
+ </ScrollView.Context.Provider>
321
+ </VirtualizedListContextResetter>
322
+ </RCTModalHostView>
323
+ );
324
+ }
325
+
326
+ // We don't want any responder events bubbling out of the modal.
327
+ _shouldSetResponder(): boolean {
328
+ return true;
329
+ }
330
+ }
331
+
332
+ const side = I18nManager.getConstants().isRTL ? 'right' : 'left';
333
+ const styles = StyleSheet.create({
334
+ modal: {
335
+ position: 'absolute',
336
+ },
337
+ container: {
338
+ /* $FlowFixMe[invalid-computed-prop] (>=0.111.0 site=react_native_fb) This
339
+ * comment suppresses an error found when Flow v0.111 was deployed. To see
340
+ * the error, delete this comment and run Flow. */
341
+ [side]: 0,
342
+ top: 0,
343
+ flex: 1,
344
+ },
345
+ });
346
+
347
+ const ExportedModal: React.AbstractComponent<
348
+ React.ElementConfig<typeof Modal>,
349
+ // $FlowFixMe[incompatible-type-arg]
350
+ > = ModalInjection.unstable_Modal ?? Modal;
351
+
352
+ module.exports = ExportedModal;
@@ -22,11 +22,12 @@ struct RootComponentView;
22
22
 
23
23
  namespace winrt::Microsoft::ReactNative::implementation {
24
24
 
25
- ComponentView::ComponentView(facebook::react::Tag tag, winrt::Microsoft::ReactNative::ReactContext const &reactContext)
26
- : m_tag(tag), m_reactContext(reactContext) {}
27
-
28
- void ComponentView::MarkAsCustomComponent() noexcept {
29
- m_customComponent = true;
25
+ ComponentView::ComponentView(
26
+ facebook::react::Tag tag,
27
+ winrt::Microsoft::ReactNative::ReactContext const &reactContext,
28
+ winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder)
29
+ : m_tag(tag), m_reactContext(reactContext) {
30
+ m_builder.copy_from(builder);
30
31
  }
31
32
 
32
33
  std::vector<facebook::react::ComponentDescriptorProvider>
@@ -52,18 +53,15 @@ void ComponentView::MountChildComponentView(
52
53
  uint32_t index) noexcept {
53
54
  m_children.InsertAt(index, childComponentView);
54
55
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(childComponentView)->parent(*this);
55
- if (m_mountChildComponentViewHandler) {
56
- m_mountChildComponentViewHandler(*this, winrt::make<MountChildComponentViewArgs>(childComponentView, index));
56
+ if (m_builder && m_builder->MountChildComponentViewHandler()) {
57
+ m_builder->MountChildComponentViewHandler()(
58
+ *this, winrt::make<MountChildComponentViewArgs>(childComponentView, index));
57
59
  }
58
60
  if (m_mounted) {
59
61
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(childComponentView)->onMounted();
60
62
  }
61
63
  }
62
64
 
63
- void ComponentView::MountChildComponentViewHandler(const MountChildComponentViewDelegate &handler) noexcept {
64
- m_mountChildComponentViewHandler = handler;
65
- }
66
-
67
65
  void ComponentView::onMounted() noexcept {
68
66
  assert(!m_mounted);
69
67
  m_mounted = true;
@@ -89,16 +87,14 @@ void ComponentView::Mounted(winrt::event_token const &token) noexcept {
89
87
  void ComponentView::UnmountChildComponentView(
90
88
  const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
91
89
  uint32_t index) noexcept {
92
- if (m_mountChildComponentViewHandler) {
93
- m_mountChildComponentViewHandler(*this, winrt::make<MountChildComponentViewArgs>(childComponentView, index));
90
+ if (m_builder && m_builder->UnmountChildComponentViewHandler()) {
91
+ m_builder->UnmountChildComponentViewHandler()(
92
+ *this, winrt::make<UnmountChildComponentViewArgs>(childComponentView, index));
94
93
  }
95
94
  m_children.RemoveAt(index);
96
95
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(childComponentView)->parent(nullptr);
97
96
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(childComponentView)->onUnmounted();
98
97
  }
99
- void ComponentView::UnmountChildComponentViewHandler(const UnmountChildComponentViewDelegate &handler) noexcept {
100
- m_unmountChildComponentViewHandler = handler;
101
- }
102
98
 
103
99
  void ComponentView::onUnmounted() noexcept {
104
100
  if (!m_mounted)
@@ -148,15 +144,11 @@ uint32_t UnmountChildComponentViewArgs::Index() const noexcept {
148
144
  void ComponentView::updateProps(
149
145
  facebook::react::Props::Shared const &props,
150
146
  facebook::react::Props::Shared const &oldProps) noexcept {
151
- if (m_updatePropsDelegate) {
152
- m_updatePropsDelegate(*this, userProps(props), oldProps ? userProps(oldProps) : nullptr);
147
+ if (m_builder && m_builder->UpdatePropsHandler()) {
148
+ m_builder->UpdatePropsHandler()(*this, userProps(props), oldProps ? userProps(oldProps) : nullptr);
153
149
  }
154
150
  }
155
151
 
156
- void ComponentView::UpdatePropsHandler(const UpdatePropsDelegate &handler) noexcept {
157
- m_updatePropsDelegate = handler;
158
- }
159
-
160
152
  const winrt::Microsoft::ReactNative::IComponentProps ComponentView::userProps(
161
153
  facebook::react::Props::Shared const &props) noexcept {
162
154
  const auto &abiProps =
@@ -165,28 +157,20 @@ const winrt::Microsoft::ReactNative::IComponentProps ComponentView::userProps(
165
157
  }
166
158
 
167
159
  void ComponentView::updateEventEmitter(facebook::react::EventEmitter::Shared const &eventEmitter) noexcept {
168
- if (m_updateEventEmitterHandler) {
169
- m_updateEventEmitterHandler(*this, winrt::make<EventEmitter>(eventEmitter));
160
+ if (m_builder && m_builder->UpdateEventEmitterHandler()) {
161
+ m_builder->UpdateEventEmitterHandler()(*this, winrt::make<EventEmitter>(eventEmitter));
170
162
  }
171
163
  }
172
164
 
173
- void ComponentView::UpdateEventEmitterHandler(const UpdateEventEmitterDelegate &handler) noexcept {
174
- m_updateEventEmitterHandler = handler;
175
- }
176
-
177
165
  void ComponentView::updateState(
178
166
  facebook::react::State::Shared const &state,
179
167
  facebook::react::State::Shared const &oldState) noexcept {
180
168
  // Avoid new-ing up a new AbiComponentState on every state change if we are not a custom component
181
- if (m_updateStateDelegate) {
182
- m_updateStateDelegate(*this, winrt::make<::Microsoft::ReactNative::AbiComponentState>(state));
169
+ if (m_builder && m_builder->UpdateStateHandler()) {
170
+ m_builder->UpdateStateHandler()(*this, winrt::make<::Microsoft::ReactNative::AbiComponentState>(state));
183
171
  }
184
172
  }
185
173
 
186
- void ComponentView::UpdateStateHandler(const UpdateStateDelegate &handler) noexcept {
187
- m_updateStateDelegate = handler;
188
- }
189
-
190
174
  LayoutMetricsChangedArgs::LayoutMetricsChangedArgs(
191
175
  const winrt::Microsoft::ReactNative::LayoutMetrics &newLayoutMetrics,
192
176
  const winrt::Microsoft::ReactNative::LayoutMetrics &oldLayoutMetrics)
@@ -216,6 +200,10 @@ void ComponentView::updateLayoutMetrics(
216
200
  layoutMetrics.frame.size.height},
217
201
  layoutMetrics.pointScaleFactor};
218
202
 
203
+ if (m_builder && m_builder->UpdateLayoutMetricsHandler()) {
204
+ m_builder->UpdateLayoutMetricsHandler()(*this, newMetrics, oldMetrics);
205
+ }
206
+
219
207
  m_layoutMetrics = layoutMetrics;
220
208
 
221
209
  m_layoutMetricsChangedEvent(*this, winrt::make<LayoutMetricsChangedArgs>(newMetrics, oldMetrics));
@@ -240,13 +228,9 @@ void ComponentView::LayoutMetricsChanged(winrt::event_token const &token) noexce
240
228
  m_layoutMetricsChangedEvent.remove(token);
241
229
  }
242
230
 
243
- void ComponentView::FinalizeUpdateHandler(const UpdateFinalizerDelegate &handler) noexcept {
244
- m_finalizeUpdateHandler = handler;
245
- }
246
-
247
231
  void ComponentView::FinalizeUpdates(winrt::Microsoft::ReactNative::ComponentViewUpdateMask updateMask) noexcept {
248
- if (m_finalizeUpdateHandler) {
249
- m_finalizeUpdateHandler(*this, updateMask);
232
+ if (m_builder && m_builder->FinalizeUpdateHandler()) {
233
+ m_builder->FinalizeUpdateHandler()(*this, updateMask);
250
234
  }
251
235
  }
252
236
 
@@ -257,13 +241,9 @@ facebook::react::Props::Shared ComponentView::props() noexcept {
257
241
  return {};
258
242
  }
259
243
 
260
- void ComponentView::CustomCommandHandler(const HandleCommandDelegate &handler) noexcept {
261
- m_customCommandHandler = handler;
262
- }
263
-
264
244
  void ComponentView::HandleCommand(const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept {
265
- if (m_customCommandHandler) {
266
- m_customCommandHandler(*this, args);
245
+ if (m_builder && m_builder->CustomCommandHandler()) {
246
+ m_builder->CustomCommandHandler()(*this, args);
267
247
  }
268
248
  }
269
249
 
@@ -12,6 +12,7 @@
12
12
  #include <react/renderer/core/LayoutMetrics.h>
13
13
 
14
14
  #include <ComponentView.Experimental.interop.h>
15
+ #include <Fabric/Composition/ReactCompositionViewComponentBuilder.h>
15
16
  #include <Fabric/Composition/Theme.h>
16
17
  #include <uiautomationcore.h>
17
18
  #include <winrt/Microsoft.ReactNative.Composition.Input.h>
@@ -80,7 +81,10 @@ struct UnmountChildComponentViewArgs : public UnmountChildComponentViewArgsT<Unm
80
81
 
81
82
  struct ComponentView
82
83
  : public ComponentViewT<ComponentView, ::Microsoft::ReactNative::Composition::Experimental::IComponentViewInterop> {
83
- ComponentView(facebook::react::Tag tag, winrt::Microsoft::ReactNative::ReactContext const &reactContext);
84
+ ComponentView(
85
+ facebook::react::Tag tag,
86
+ winrt::Microsoft::ReactNative::ReactContext const &reactContext,
87
+ winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder);
84
88
 
85
89
  virtual std::vector<facebook::react::ComponentDescriptorProvider> supplementalComponentDescriptorProviders() noexcept;
86
90
  virtual void updateProps(
@@ -115,7 +119,6 @@ struct ComponentView
115
119
  virtual void onGettingFocus(const winrt::Microsoft::ReactNative::GettingFocusEventArgs &args) noexcept;
116
120
  virtual void onLostFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept;
117
121
  virtual void onGotFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept;
118
- void MarkAsCustomComponent() noexcept;
119
122
  virtual void onMounted() noexcept;
120
123
  bool isMounted() noexcept;
121
124
  virtual void onUnmounted() noexcept;
@@ -223,14 +226,6 @@ struct ComponentView
223
226
  void UserData(const winrt::IInspectable &userData) noexcept;
224
227
  winrt::IInspectable UserData() const noexcept;
225
228
 
226
- void CustomCommandHandler(const HandleCommandDelegate &handler) noexcept;
227
- void UpdatePropsHandler(const UpdatePropsDelegate &handler) noexcept;
228
- void UpdateStateHandler(const UpdateStateDelegate &handler) noexcept;
229
- void UpdateEventEmitterHandler(const UpdateEventEmitterDelegate &handler) noexcept;
230
- void MountChildComponentViewHandler(const MountChildComponentViewDelegate &handler) noexcept;
231
- void UnmountChildComponentViewHandler(const UnmountChildComponentViewDelegate &handler) noexcept;
232
- void FinalizeUpdateHandler(const UpdateFinalizerDelegate &handler) noexcept;
233
-
234
229
  virtual void MountChildComponentView(
235
230
  const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
236
231
  uint32_t index) noexcept;
@@ -258,7 +253,7 @@ struct ComponentView
258
253
  const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept;
259
254
 
260
255
  protected:
261
- bool m_customComponent : 1 {false}; // Is a user custom component, and so needs to call external override functions
256
+ winrt::com_ptr<winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder> m_builder;
262
257
  bool m_mounted : 1 {false};
263
258
  const facebook::react::Tag m_tag;
264
259
  winrt::IInspectable m_userData;
@@ -270,14 +265,6 @@ struct ComponentView
270
265
  winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::ReactNative::ComponentView> m_children{
271
266
  winrt::single_threaded_vector<winrt::Microsoft::ReactNative::ComponentView>()};
272
267
 
273
- UpdatePropsDelegate m_updatePropsDelegate{nullptr};
274
- UpdateStateDelegate m_updateStateDelegate{nullptr};
275
- HandleCommandDelegate m_customCommandHandler{nullptr};
276
- UpdateFinalizerDelegate m_finalizeUpdateHandler{nullptr};
277
- MountChildComponentViewDelegate m_mountChildComponentViewHandler{nullptr};
278
- UnmountChildComponentViewDelegate m_unmountChildComponentViewHandler{nullptr};
279
- UpdateEventEmitterDelegate m_updateEventEmitterHandler{nullptr};
280
-
281
268
  winrt::event<
282
269
  winrt::Windows::Foundation::EventHandler<winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs>>
283
270
  m_keyDownEvent;
@@ -818,6 +818,11 @@ uint8_t BorderPrimitive::numberOfVisuals() const noexcept {
818
818
  return m_numBorderVisuals;
819
819
  }
820
820
 
821
+ void BorderPrimitive::setOuter(
822
+ winrt::Microsoft::ReactNative::Composition::implementation::ComponentView *outer) noexcept {
823
+ m_outer = outer;
824
+ }
825
+
821
826
  bool BorderPrimitive::TryUpdateSpecialBorderLayers(
822
827
  winrt::Microsoft::ReactNative::Composition::implementation::Theme *theme,
823
828
  std::array<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual, SpecialBorderLayerCount>
@@ -29,6 +29,10 @@ struct BorderPrimitive {
29
29
 
30
30
  void markNeedsUpdate() noexcept;
31
31
 
32
+ // We hoist focus visuals up the tree to allow them to be higher in the z-order.
33
+ // This means a single BorderPrimitive may change the owning ComponentView as focus moves around
34
+ void setOuter(winrt::Microsoft::ReactNative::Composition::implementation::ComponentView *outer) noexcept;
35
+
32
36
  void updateProps(
33
37
  const facebook::react::ViewProps &oldViewProps,
34
38
  const facebook::react::ViewProps &newViewProps) noexcept;