react-native-windows 0.82.0-preview.1 → 0.82.0-preview.11

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 (63) hide show
  1. package/Libraries/Animated/nodes/AnimatedValue.js +0 -8
  2. package/Libraries/BatchedBridge/BatchedBridge.js +1 -0
  3. package/Libraries/BatchedBridge/MessageQueue.js +1 -0
  4. package/Libraries/Components/Switch/Switch.js +1 -1
  5. package/Libraries/Components/Switch/Switch.windows.js +1 -1
  6. package/Libraries/Core/ReactNativeVersion.js +2 -2
  7. package/Libraries/Core/Timers/JSTimers.js +1 -0
  8. package/Libraries/Core/Timers/NativeTiming.js +1 -0
  9. package/Libraries/Core/Timers/immediateShim.js +1 -0
  10. package/Libraries/Core/setUpPerformance.js +3 -5
  11. package/Libraries/Interaction/PanResponder.js +6 -51
  12. package/Microsoft.ReactNative/ComponentView.idl +2 -0
  13. package/Microsoft.ReactNative/Composition.Input.idl +7 -0
  14. package/Microsoft.ReactNative/CompositionComponentView.idl +3 -0
  15. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +18 -0
  16. package/Microsoft.ReactNative/Fabric/ComponentView.h +9 -0
  17. package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.cpp +12 -0
  18. package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.h +15 -0
  19. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +75 -0
  20. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +1 -0
  21. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +84 -17
  22. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +4 -0
  23. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +56 -82
  24. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +7 -4
  25. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +82 -14
  26. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +11 -4
  27. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +33 -0
  28. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +17 -0
  29. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +59 -31
  30. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +3 -0
  31. package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +42 -15
  32. package/Microsoft.ReactNative.Cxx/ReactCommon/react/timing/primitives.h +12 -0
  33. package/PropertySheets/Generated/PackageVersion.g.props +2 -2
  34. package/PropertySheets/Warnings.props +1 -2
  35. package/PropertySheets/WinUI.props +1 -1
  36. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.cpp +174 -0
  37. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/BaseParagraphProps.h +69 -0
  38. package/Scripts/NuGetRestoreForceEvaluateAllSolutions.ps1 +5 -11
  39. package/Scripts/rnw-dependencies.ps1 +15 -1
  40. package/Shared/Shared.vcxitems +1 -0
  41. package/Shared/Shared.vcxitems.filters +1 -3
  42. package/codegen/NativePerformanceSpec.g.h +41 -35
  43. package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +55 -49
  44. package/codegen/rnwcoreJSI-generated.cpp +434 -422
  45. package/codegen/rnwcoreJSI.h +18 -0
  46. package/index.js +6 -0
  47. package/index.windows.js +6 -0
  48. package/package.json +15 -14
  49. package/src/private/featureflags/ReactNativeFeatureFlags.js +6 -1
  50. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +2 -1
  51. package/src/private/setup/{setUpPerformanceObserver.js → setUpPerformanceModern.js} +43 -18
  52. package/src/private/specs_DEPRECATED/components/SwitchNativeComponent.js +1 -0
  53. package/src/private/specs_DEPRECATED/modules/NativeTiming.js +1 -0
  54. package/src/private/webapis/performance/EventTiming.js +34 -15
  55. package/src/private/webapis/performance/LongTasks.js +35 -2
  56. package/src/private/webapis/performance/Performance.js +49 -13
  57. package/src/private/webapis/performance/PerformanceEntry.js +21 -8
  58. package/src/private/webapis/performance/PerformanceObserver.js +30 -1
  59. package/src/private/webapis/performance/ReactNativeStartupTiming.js +3 -24
  60. package/src/private/webapis/performance/ResourceTiming.js +29 -18
  61. package/src/private/webapis/performance/UserTiming.js +33 -28
  62. package/src/private/webapis/performance/internals/RawPerformanceEntry.js +3 -4
  63. package/src/private/webapis/performance/specs/NativePerformance.js +2 -0
@@ -18,7 +18,6 @@ import type {AnimatedNodeConfig} from './AnimatedNode';
18
18
  import type AnimatedTracking from './AnimatedTracking';
19
19
 
20
20
  import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
21
- import InteractionManager from '../../Interaction/InteractionManager';
22
21
  import AnimatedInterpolation from './AnimatedInterpolation';
23
22
  import AnimatedWithChildren from './AnimatedWithChildren';
24
23
 
@@ -312,10 +311,6 @@ export default class AnimatedValue extends AnimatedWithChildren {
312
311
  * See https://reactnative.dev/docs/animatedvalue#animate
313
312
  */
314
313
  animate(animation: Animation, callback: ?EndCallback): void {
315
- let handle = null;
316
- if (animation.__isInteraction) {
317
- handle = InteractionManager.createInteractionHandle();
318
- }
319
314
  const previousAnimation = this._animation;
320
315
  this._animation && this._animation.stop();
321
316
  this._animation = animation;
@@ -328,9 +323,6 @@ export default class AnimatedValue extends AnimatedWithChildren {
328
323
  },
329
324
  result => {
330
325
  this._animation = null;
331
- if (handle !== null) {
332
- InteractionManager.clearInteractionHandle(handle);
333
- }
334
326
  callback && callback(result);
335
327
  },
336
328
  previousAnimation,
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @flow strict
8
8
  * @format
9
+ * @deprecated
9
10
  */
10
11
 
11
12
  'use strict';
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @flow strict
8
8
  * @format
9
+ * @deprecated
9
10
  */
10
11
 
11
12
  'use strict';
@@ -264,7 +264,7 @@ const Switch: component(
264
264
  disabled,
265
265
  onTintColor: trackColorForTrue,
266
266
  style: StyleSheet.compose(
267
- {height: 31, width: 51},
267
+ {alignSelf: 'flex-start' as const},
268
268
  StyleSheet.compose(
269
269
  style,
270
270
  ios_backgroundColor == null
@@ -272,7 +272,7 @@ const Switch: component(
272
272
  disabled,
273
273
  onTintColor: trackColorForTrue,
274
274
  style: StyleSheet.compose(
275
- {height: 31, width: 51},
275
+ {height: 31, width: 51}, // #windows
276
276
  StyleSheet.compose(
277
277
  style,
278
278
  ios_backgroundColor == null
@@ -28,8 +28,8 @@
28
28
  export default class ReactNativeVersion {
29
29
  static major: number = 0;
30
30
  static minor: number = 82;
31
- static patch: number = 0;
32
- static prerelease: string | null = 'rc.0';
31
+ static patch: number = 1;
32
+ static prerelease: string | null = null;
33
33
 
34
34
  static getVersionString(): string {
35
35
  return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @flow
8
8
  * @format
9
+ * @deprecated
9
10
  */
10
11
 
11
12
  import NativeTiming from './NativeTiming';
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @flow strict
8
8
  * @format
9
+ * @deprecated
9
10
  */
10
11
 
11
12
  export * from '../../../src/private/specs_DEPRECATED/modules/NativeTiming';
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @flow
8
8
  * @format
9
+ * @deprecated
9
10
  */
10
11
 
11
12
  'use strict';
@@ -4,19 +4,17 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @flow strict
7
+ * @flow strict-local
8
8
  * @format
9
9
  */
10
10
 
11
+ import setUpPerformanceModern from '../../src/private/setup/setUpPerformanceModern';
11
12
  import NativePerformance from '../../src/private/webapis/performance/specs/NativePerformance';
12
13
 
13
14
  // In case if the native implementation of the Performance API is available, use it,
14
15
  // otherwise fall back to the legacy/default one, which only defines 'Performance.now()'
15
16
  if (NativePerformance) {
16
- const Performance =
17
- require('../../src/private/webapis/performance/Performance').default;
18
- // $FlowExpectedError[cannot-write]
19
- global.performance = new Performance();
17
+ setUpPerformanceModern();
20
18
  } else {
21
19
  if (!global.performance) {
22
20
  // $FlowExpectedError[cannot-write]
@@ -12,7 +12,6 @@
12
12
 
13
13
  import type {GestureResponderEvent} from '../Types/CoreEventTypes';
14
14
 
15
- const InteractionManager = require('./InteractionManager').default;
16
15
  const TouchHistoryMath = require('./TouchHistoryMath').default;
17
16
 
18
17
  const currentCentroidXOfTouchesChangedAfter =
@@ -31,9 +30,6 @@ const currentCentroidY = TouchHistoryMath.currentCentroidY;
31
30
  * single-touch gestures resilient to extra touches, and can be used to
32
31
  * recognize simple multi-touch gestures.
33
32
  *
34
- * By default, `PanResponder` holds an `InteractionManager` handle to block
35
- * long-running JS events from interrupting active gestures.
36
- *
37
33
  * It provides a predictable wrapper of the responder handlers provided by the
38
34
  * [gesture responder system](docs/gesture-responder-system.html).
39
35
  * For each handler, it provides a new `gestureState` object alongside the
@@ -405,9 +401,6 @@ const PanResponder = {
405
401
  getInteractionHandle: () => ?number,
406
402
  panHandlers: GestureResponderHandlerMethods,
407
403
  } {
408
- const interactionState = {
409
- handle: (null: ?number),
410
- };
411
404
  const gestureState: PanResponderGestureState = {
412
405
  // Useful for debugging
413
406
  stateID: Math.random(),
@@ -464,10 +457,6 @@ const PanResponder = {
464
457
  },
465
458
 
466
459
  onResponderGrant(event: GestureResponderEvent): boolean {
467
- if (!interactionState.handle) {
468
- interactionState.handle =
469
- InteractionManager.createInteractionHandle();
470
- }
471
460
  gestureState.x0 = currentCentroidX(event.touchHistory);
472
461
  gestureState.y0 = currentCentroidY(event.touchHistory);
473
462
  gestureState.dx = 0;
@@ -482,21 +471,11 @@ const PanResponder = {
482
471
  },
483
472
 
484
473
  onResponderReject(event: GestureResponderEvent): void {
485
- clearInteractionHandle(
486
- interactionState,
487
- config.onPanResponderReject,
488
- event,
489
- gestureState,
490
- );
474
+ config.onPanResponderReject?.call(undefined, event, gestureState);
491
475
  },
492
476
 
493
477
  onResponderRelease(event: GestureResponderEvent): void {
494
- clearInteractionHandle(
495
- interactionState,
496
- config.onPanResponderRelease,
497
- event,
498
- gestureState,
499
- );
478
+ config.onPanResponderRelease?.call(undefined, event, gestureState);
500
479
  PanResponder._initializeGestureState(gestureState);
501
480
  },
502
481
 
@@ -529,21 +508,11 @@ const PanResponder = {
529
508
  onResponderEnd(event: GestureResponderEvent): void {
530
509
  const touchHistory = event.touchHistory;
531
510
  gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
532
- clearInteractionHandle(
533
- interactionState,
534
- config.onPanResponderEnd,
535
- event,
536
- gestureState,
537
- );
511
+ config.onPanResponderEnd?.call(undefined, event, gestureState);
538
512
  },
539
513
 
540
514
  onResponderTerminate(event: GestureResponderEvent): void {
541
- clearInteractionHandle(
542
- interactionState,
543
- config.onPanResponderTerminate,
544
- event,
545
- gestureState,
546
- );
515
+ config.onPanResponderTerminate?.call(undefined, event, gestureState);
547
516
  PanResponder._initializeGestureState(gestureState);
548
517
  },
549
518
 
@@ -556,27 +525,13 @@ const PanResponder = {
556
525
  return {
557
526
  panHandlers,
558
527
  getInteractionHandle(): ?number {
559
- return interactionState.handle;
528
+ // TODO: Deprecate and delete this method.
529
+ return null;
560
530
  },
561
531
  };
562
532
  },
563
533
  };
564
534
 
565
- function clearInteractionHandle(
566
- interactionState: {handle: ?number, ...},
567
- callback: ?(ActiveCallback | PassiveCallback),
568
- event: GestureResponderEvent,
569
- gestureState: PanResponderGestureState,
570
- ) {
571
- if (interactionState.handle) {
572
- InteractionManager.clearInteractionHandle(interactionState.handle);
573
- interactionState.handle = null;
574
- }
575
- if (callback) {
576
- callback(event, gestureState);
577
- }
578
- }
579
-
580
535
  export type PanResponderInstance = ReturnType<(typeof PanResponder)['create']>;
581
536
 
582
537
  export default PanResponder;
@@ -106,6 +106,8 @@ namespace Microsoft.ReactNative
106
106
  DOC_STRING("Used to handle key up events when this component is focused, or if a child component did not handle the key up")
107
107
  event Windows.Foundation.EventHandler<Microsoft.ReactNative.Composition.Input.KeyRoutedEventArgs> KeyUp;
108
108
  event Windows.Foundation.EventHandler<Microsoft.ReactNative.Composition.Input.CharacterReceivedRoutedEventArgs> CharacterReceived;
109
+ DOC_STRING("Used to handle context menu key events (SHIFT+F10 or Context Menu key) when this component is focused")
110
+ event Windows.Foundation.EventHandler<Microsoft.ReactNative.Composition.Input.ContextMenuKeyEventArgs> ContextMenuKey;
109
111
  event Windows.Foundation.EventHandler<Microsoft.ReactNative.Composition.Input.PointerRoutedEventArgs> PointerPressed;
110
112
  event Windows.Foundation.EventHandler<Microsoft.ReactNative.Composition.Input.PointerRoutedEventArgs> PointerReleased;
111
113
  event Windows.Foundation.EventHandler<Microsoft.ReactNative.Composition.Input.PointerRoutedEventArgs> PointerMoved;
@@ -34,6 +34,13 @@ namespace Microsoft.ReactNative.Composition.Input
34
34
  KeyboardSource KeyboardSource { get; };
35
35
  };
36
36
 
37
+ DOC_STRING("Event arguments for context menu key events (SHIFT+F10 or Context Menu key)")
38
+ interface ContextMenuKeyEventArgs requires RoutedEventArgs
39
+ {
40
+ DOC_STRING("Gets or sets whether the event was handled. Set to true to prevent default behavior.")
41
+ Boolean Handled { get; set; };
42
+ };
43
+
37
44
  interface IPointerPointTransform
38
45
  {
39
46
  IPointerPointTransform Inverse { get; };
@@ -154,6 +154,9 @@ namespace Microsoft.ReactNative.Composition
154
154
  [webhosthidden]
155
155
  [default_interface]
156
156
  runtimeclass ScrollViewComponentView : ViewComponentView {
157
+ // Issue #15557: Event fired when scroll position changes.
158
+ // ContentIslandComponentView uses this to update LocalToParentTransformMatrix.
159
+ event Windows.Foundation.EventHandler<IInspectable> ViewChanged;
157
160
  };
158
161
 
159
162
  [experimental]
@@ -469,6 +469,16 @@ void ComponentView::CharacterReceived(winrt::event_token const &token) noexcept
469
469
  m_characterReceivedEvent.remove(token);
470
470
  }
471
471
 
472
+ winrt::event_token ComponentView::ContextMenuKey(
473
+ winrt::Windows::Foundation::EventHandler<
474
+ winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs> const &handler) noexcept {
475
+ return m_contextMenuKeyEvent.add(handler);
476
+ }
477
+
478
+ void ComponentView::ContextMenuKey(winrt::event_token const &token) noexcept {
479
+ m_contextMenuKeyEvent.remove(token);
480
+ }
481
+
472
482
  winrt::event_token ComponentView::PointerPressed(
473
483
  winrt::Windows::Foundation::EventHandler<
474
484
  winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs> const &handler) noexcept {
@@ -609,6 +619,14 @@ void ComponentView::OnCharacterReceived(
609
619
  }
610
620
  }
611
621
 
622
+ void ComponentView::OnContextMenuKey(
623
+ const winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs &args) noexcept {
624
+ m_contextMenuKeyEvent(*this, args);
625
+ if (m_parent && !args.Handled()) {
626
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(m_parent)->OnContextMenuKey(args);
627
+ }
628
+ }
629
+
612
630
  bool ComponentView::focusable() const noexcept {
613
631
  return false;
614
632
  }
@@ -167,6 +167,10 @@ struct ComponentView
167
167
  winrt::Windows::Foundation::EventHandler<
168
168
  winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs> const &handler) noexcept;
169
169
  void CharacterReceived(winrt::event_token const &token) noexcept;
170
+ winrt::event_token ContextMenuKey(
171
+ winrt::Windows::Foundation::EventHandler<
172
+ winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs> const &handler) noexcept;
173
+ void ContextMenuKey(winrt::event_token const &token) noexcept;
170
174
  winrt::event_token PointerPressed(
171
175
  winrt::Windows::Foundation::EventHandler<
172
176
  winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs> const &handler) noexcept;
@@ -253,6 +257,8 @@ struct ComponentView
253
257
  virtual void OnKeyUp(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept;
254
258
  virtual void OnCharacterReceived(
255
259
  const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept;
260
+ virtual void OnContextMenuKey(
261
+ const winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs &args) noexcept;
256
262
 
257
263
  protected:
258
264
  winrt::com_ptr<winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder> m_builder;
@@ -277,6 +283,9 @@ struct ComponentView
277
283
  winrt::event<winrt::Windows::Foundation::EventHandler<
278
284
  winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs>>
279
285
  m_characterReceivedEvent;
286
+ winrt::event<winrt::Windows::Foundation::EventHandler<
287
+ winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs>>
288
+ m_contextMenuKeyEvent;
280
289
  winrt::event<winrt::Windows::Foundation::EventHandler<
281
290
  winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs>>
282
291
  m_pointerPressedEvent;
@@ -136,6 +136,18 @@ winrt::Microsoft::ReactNative::Composition::Input::KeyboardSource CharacterRecei
136
136
  return m_source;
137
137
  }
138
138
 
139
+ ContextMenuKeyEventArgs::ContextMenuKeyEventArgs(facebook::react::Tag tag) : m_tag(tag) {}
140
+
141
+ int32_t ContextMenuKeyEventArgs::OriginalSource() noexcept {
142
+ return m_tag;
143
+ }
144
+ bool ContextMenuKeyEventArgs::Handled() noexcept {
145
+ return m_handled;
146
+ }
147
+ void ContextMenuKeyEventArgs::Handled(bool value) noexcept {
148
+ m_handled = value;
149
+ }
150
+
139
151
  Pointer::Pointer(winrt::Microsoft::ReactNative::Composition::Input::PointerDeviceType type, uint32_t id)
140
152
  : m_type(type), m_id(id) {}
141
153
 
@@ -78,6 +78,21 @@ struct CharacterReceivedRoutedEventArgs
78
78
  const winrt::Microsoft::ReactNative::Composition::Input::KeyboardSource m_source;
79
79
  };
80
80
 
81
+ struct ContextMenuKeyEventArgs : winrt::implements<
82
+ ContextMenuKeyEventArgs,
83
+ winrt::Microsoft::ReactNative::Composition::Input::ContextMenuKeyEventArgs,
84
+ winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs> {
85
+ ContextMenuKeyEventArgs(facebook::react::Tag tag);
86
+
87
+ int32_t OriginalSource() noexcept;
88
+ bool Handled() noexcept;
89
+ void Handled(bool value) noexcept;
90
+
91
+ private:
92
+ facebook::react::Tag m_tag{-1};
93
+ bool m_handled{false};
94
+ };
95
+
81
96
  struct Pointer : PointerT<Pointer> {
82
97
  Pointer(winrt::Microsoft::ReactNative::Composition::Input::PointerDeviceType type, uint32_t id);
83
98
 
@@ -320,6 +320,32 @@ void CompositionEventHandler::Initialize() noexcept {
320
320
  }
321
321
  }
322
322
  });
323
+
324
+ m_contextMenuKeyToken =
325
+ keyboardSource.ContextMenuKey([wkThis = weak_from_this()](
326
+ winrt::Microsoft::UI::Input::InputKeyboardSource const & /*source*/,
327
+ winrt::Microsoft::UI::Input::ContextMenuKeyEventArgs const &args) {
328
+ if (auto strongThis = wkThis.lock()) {
329
+ if (auto strongRootView = strongThis->m_wkRootView.get()) {
330
+ if (strongThis->SurfaceId() == -1)
331
+ return;
332
+
333
+ auto focusedComponent = strongThis->RootComponentView().GetFocusedComponent();
334
+ if (focusedComponent) {
335
+ auto tag =
336
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(focusedComponent)
337
+ ->Tag();
338
+ auto contextMenuArgs = winrt::make<
339
+ winrt::Microsoft::ReactNative::Composition::Input::implementation::ContextMenuKeyEventArgs>(tag);
340
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(focusedComponent)
341
+ ->OnContextMenuKey(contextMenuArgs);
342
+ if (contextMenuArgs.Handled()) {
343
+ args.Handled(true);
344
+ }
345
+ }
346
+ }
347
+ }
348
+ });
323
349
  }
324
350
  }
325
351
 
@@ -336,6 +362,7 @@ CompositionEventHandler::~CompositionEventHandler() {
336
362
  keyboardSource.KeyDown(m_keyDownToken);
337
363
  keyboardSource.KeyUp(m_keyUpToken);
338
364
  keyboardSource.CharacterReceived(m_characterReceivedToken);
365
+ keyboardSource.ContextMenuKey(m_contextMenuKeyToken);
339
366
  }
340
367
  }
341
368
 
@@ -443,6 +470,54 @@ int64_t CompositionEventHandler::SendMessage(HWND hwnd, uint32_t msg, uint64_t w
443
470
  }
444
471
  return 0;
445
472
  }
473
+ case WM_RBUTTONDOWN: {
474
+ if (auto strongRootView = m_wkRootView.get()) {
475
+ auto pp = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::PointerPoint>(
476
+ hwnd, msg, wParam, lParam, strongRootView.ScaleFactor());
477
+ onPointerPressed(pp, GetKeyModifiers(wParam));
478
+ }
479
+ return 0;
480
+ }
481
+ case WM_RBUTTONUP: {
482
+ if (auto strongRootView = m_wkRootView.get()) {
483
+ auto pp = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::PointerPoint>(
484
+ hwnd, msg, wParam, lParam, strongRootView.ScaleFactor());
485
+ onPointerReleased(pp, GetKeyModifiers(wParam));
486
+ }
487
+ return 0;
488
+ }
489
+ case WM_MBUTTONDOWN: {
490
+ if (auto strongRootView = m_wkRootView.get()) {
491
+ auto pp = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::PointerPoint>(
492
+ hwnd, msg, wParam, lParam, strongRootView.ScaleFactor());
493
+ onPointerPressed(pp, GetKeyModifiers(wParam));
494
+ }
495
+ return 0;
496
+ }
497
+ case WM_MBUTTONUP: {
498
+ if (auto strongRootView = m_wkRootView.get()) {
499
+ auto pp = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::PointerPoint>(
500
+ hwnd, msg, wParam, lParam, strongRootView.ScaleFactor());
501
+ onPointerReleased(pp, GetKeyModifiers(wParam));
502
+ }
503
+ return 0;
504
+ }
505
+ case WM_XBUTTONDOWN: {
506
+ if (auto strongRootView = m_wkRootView.get()) {
507
+ auto pp = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::PointerPoint>(
508
+ hwnd, msg, wParam, lParam, strongRootView.ScaleFactor());
509
+ onPointerPressed(pp, GetKeyModifiers(wParam));
510
+ }
511
+ return 0;
512
+ }
513
+ case WM_XBUTTONUP: {
514
+ if (auto strongRootView = m_wkRootView.get()) {
515
+ auto pp = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::PointerPoint>(
516
+ hwnd, msg, wParam, lParam, strongRootView.ScaleFactor());
517
+ onPointerReleased(pp, GetKeyModifiers(wParam));
518
+ }
519
+ return 0;
520
+ }
446
521
  case WM_POINTERUP: {
447
522
  if (auto strongRootView = m_wkRootView.get()) {
448
523
  auto pp = winrt::make<winrt::Microsoft::ReactNative::Composition::Input::implementation::PointerPoint>(
@@ -175,6 +175,7 @@ class CompositionEventHandler : public std::enable_shared_from_this<CompositionE
175
175
  winrt::event_token m_keyDownToken;
176
176
  winrt::event_token m_keyUpToken;
177
177
  winrt::event_token m_characterReceivedToken;
178
+ winrt::event_token m_contextMenuKeyToken;
178
179
  };
179
180
 
180
181
  } // namespace Microsoft::ReactNative
@@ -36,10 +36,11 @@ constexpr float FOCUS_VISUAL_RADIUS = 3.0f;
36
36
 
37
37
  // m_outerVisual
38
38
  // |
39
- // |
40
39
  // ----- m_visual <-- Background / clip - Can be a custom visual depending on Component type
41
40
  // |
42
41
  // ----- Border Visuals x N (BorderPrimitive attached to m_visual)
42
+ // ----- <children> (default: directly in m_visual after border visuals)
43
+ // ----- m_childrenContainer (created on demand when overflow:hidden, children moved here)
43
44
  // ------Focus Visual Container (created when hosting focus visuals)
44
45
  // |
45
46
  // |------Inner Focus Visual
@@ -708,7 +709,9 @@ void ComponentView::applyShadowProps(const facebook::react::ViewProps &viewProps
708
709
  shadow.Color(theme()->Color(*viewProps.shadowColor));
709
710
  }
710
711
 
711
- Visual().as<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow(shadow);
712
+ // Apply shadow to OuterVisual (not Visual) because Visual may have a rounded-corner clip
713
+ // from updateClippingPath, which would clip the shadow. OuterVisual is not clipped.
714
+ OuterVisual().as<winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow(shadow);
712
715
  }
713
716
 
714
717
  void ComponentView::updateTransformProps(
@@ -892,23 +895,26 @@ void ComponentView::updateClippingPath(
892
895
  const facebook::react::ViewProps &viewProps) noexcept {
893
896
  auto borderMetrics = BorderPrimitive::resolveAndAlignBorderMetrics(layoutMetrics, viewProps);
894
897
 
895
- if (borderMetrics.borderRadii.topLeft.horizontal == 0 && borderMetrics.borderRadii.topRight.horizontal == 0 &&
896
- borderMetrics.borderRadii.bottomLeft.horizontal == 0 && borderMetrics.borderRadii.bottomRight.horizontal == 0 &&
897
- borderMetrics.borderRadii.topLeft.vertical == 0 && borderMetrics.borderRadii.topRight.vertical == 0 &&
898
- borderMetrics.borderRadii.bottomLeft.vertical == 0 && borderMetrics.borderRadii.bottomRight.vertical == 0) {
899
- Visual().as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(nullptr);
900
- } else {
898
+ bool hasRoundedCorners = borderMetrics.borderRadii.topLeft.horizontal != 0 ||
899
+ borderMetrics.borderRadii.topRight.horizontal != 0 || borderMetrics.borderRadii.bottomLeft.horizontal != 0 ||
900
+ borderMetrics.borderRadii.bottomRight.horizontal != 0 || borderMetrics.borderRadii.topLeft.vertical != 0 ||
901
+ borderMetrics.borderRadii.topRight.vertical != 0 || borderMetrics.borderRadii.bottomLeft.vertical != 0 ||
902
+ borderMetrics.borderRadii.bottomRight.vertical != 0;
903
+
904
+ const float scale = layoutMetrics.pointScaleFactor;
905
+ const float viewWidth = layoutMetrics.frame.size.width * scale;
906
+ const float viewHeight = layoutMetrics.frame.size.height * scale;
907
+
908
+ // Apply clipping to m_visual only for rounded corners
909
+ // overflow:hidden clipping is handled separately via m_childrenContainer in ViewComponentView
910
+ if (hasRoundedCorners) {
901
911
  winrt::com_ptr<ID2D1PathGeometry> pathGeometry = BorderPrimitive::GenerateRoundedRectPathGeometry(
902
- m_compContext,
903
- borderMetrics.borderRadii,
904
- {0, 0, 0, 0},
905
- {0,
906
- 0,
907
- layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor,
908
- layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor});
912
+ m_compContext, borderMetrics.borderRadii, {0, 0, 0, 0}, {0, 0, viewWidth, viewHeight});
909
913
 
910
914
  Visual().as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
911
915
  pathGeometry.get());
916
+ } else {
917
+ Visual().as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(nullptr);
912
918
  }
913
919
  }
914
920
 
@@ -1083,6 +1089,11 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual
1083
1089
  ViewComponentView::VisualToMountChildrenInto() noexcept {
1084
1090
  if (m_builder && m_builder->VisualToMountChildrenIntoHandler())
1085
1091
  return m_builder->VisualToMountChildrenIntoHandler()(*this);
1092
+ // When overflow:hidden, children are hosted in m_childrenContainer (child of m_visual)
1093
+ // so we can apply clipping without affecting borders/background.
1094
+ // Otherwise children go directly into Visual() (the original behavior).
1095
+ if (m_childrenContainer)
1096
+ return m_childrenContainer;
1086
1097
  return Visual();
1087
1098
  }
1088
1099
 
@@ -1091,9 +1102,14 @@ void ViewComponentView::MountChildComponentView(
1091
1102
  uint32_t index) noexcept {
1092
1103
  base_type::MountChildComponentView(childComponentView, index);
1093
1104
 
1094
- indexOffsetForBorder(index);
1095
1105
  ensureVisual();
1096
1106
 
1107
+ // When children are in Visual() directly, offset past border visuals.
1108
+ // When children are in m_childrenContainer, no offset needed.
1109
+ if (!m_childrenContainer) {
1110
+ indexOffsetForBorder(index);
1111
+ }
1112
+
1097
1113
  if (auto compositionChild = childComponentView.try_as<ComponentView>()) {
1098
1114
  auto visualIndex = index;
1099
1115
  // Most of the time child index will align with visual index.
@@ -1105,6 +1121,7 @@ void ViewComponentView::MountChildComponentView(
1105
1121
  }
1106
1122
  }
1107
1123
  }
1124
+
1108
1125
  VisualToMountChildrenInto().InsertAt(compositionChild->OuterVisual(), visualIndex);
1109
1126
  } else {
1110
1127
  m_hasNonVisualChildren = true;
@@ -1116,7 +1133,6 @@ void ViewComponentView::UnmountChildComponentView(
1116
1133
  uint32_t index) noexcept {
1117
1134
  base_type::UnmountChildComponentView(childComponentView, index);
1118
1135
 
1119
- indexOffsetForBorder(index);
1120
1136
  if (auto compositionChild = childComponentView.try_as<ComponentView>()) {
1121
1137
  VisualToMountChildrenInto().Remove(compositionChild->OuterVisual());
1122
1138
  }
@@ -1316,6 +1332,57 @@ void ViewComponentView::updateLayoutMetrics(
1316
1332
  Visual().Size(
1317
1333
  {layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor,
1318
1334
  layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor});
1335
+
1336
+ // Update children container clipping for overflow:hidden
1337
+ updateChildrenClippingPath(layoutMetrics, *viewProps());
1338
+ }
1339
+
1340
+ void ViewComponentView::updateChildrenClippingPath(
1341
+ facebook::react::LayoutMetrics const &layoutMetrics,
1342
+ const facebook::react::ViewProps &viewProps) noexcept {
1343
+ const float scale = layoutMetrics.pointScaleFactor;
1344
+ const float viewWidth = layoutMetrics.frame.size.width * scale;
1345
+ const float viewHeight = layoutMetrics.frame.size.height * scale;
1346
+
1347
+ if (viewProps.getClipsContentToBounds()) {
1348
+ // Create m_childrenContainer on demand (like iOS _containerView pattern)
1349
+ // m_childrenContainer is a child of m_visual, placed after border visuals.
1350
+ if (!m_childrenContainer) {
1351
+ m_childrenContainer = m_compContext.CreateSpriteVisual();
1352
+
1353
+ // Insert at the end of m_visual's children (after border visuals + existing children)
1354
+ // Then move existing children from m_visual into m_childrenContainer
1355
+ uint32_t borderCount = 0;
1356
+ indexOffsetForBorder(borderCount);
1357
+
1358
+ // Move existing child visuals from m_visual to m_childrenContainer
1359
+ uint32_t childVisualIndex = 0;
1360
+ for (auto it = m_children.begin(); it != m_children.end(); ++it) {
1361
+ if (auto compositionChild = (*it).try_as<ComponentView>()) {
1362
+ Visual().Remove(compositionChild->OuterVisual());
1363
+ m_childrenContainer.InsertAt(compositionChild->OuterVisual(), childVisualIndex++);
1364
+ }
1365
+ }
1366
+
1367
+ // Insert m_childrenContainer after border visuals in m_visual
1368
+ Visual().InsertAt(m_childrenContainer, borderCount);
1369
+
1370
+ // Use relative sizing so container automatically tracks parent's size
1371
+ m_childrenContainer.RelativeSizeWithOffset({0, 0}, {1, 1});
1372
+ }
1373
+
1374
+ // Clip children to view bounds using outer border radii (matches iOS default behavior)
1375
+ auto borderMetrics = BorderPrimitive::resolveAndAlignBorderMetrics(layoutMetrics, viewProps);
1376
+ winrt::com_ptr<ID2D1PathGeometry> pathGeometry = BorderPrimitive::GenerateRoundedRectPathGeometry(
1377
+ m_compContext, borderMetrics.borderRadii, {0, 0, 0, 0}, {0, 0, viewWidth, viewHeight});
1378
+
1379
+ m_childrenContainer.as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
1380
+ pathGeometry.get());
1381
+ } else if (m_childrenContainer) {
1382
+ // overflow changed from hidden to visible. Keep container, just remove clip.
1383
+ m_childrenContainer.as<::Microsoft::ReactNative::Composition::Experimental::IVisualInterop>()->SetClippingPath(
1384
+ nullptr);
1385
+ }
1319
1386
  }
1320
1387
 
1321
1388
  void ViewComponentView::prepareForRecycle() noexcept {}