@@ -709,9 +709,86 @@ void ComponentView::applyShadowProps(const facebook::react::ViewProps &viewProps
709709 shadow.Color (theme ()->Color (*viewProps.shadowColor ));
710710 }
711711
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+ // Check if any border radius is set
713+ auto borderMetrics = BorderPrimitive::resolveAndAlignBorderMetrics (m_layoutMetrics, viewProps);
714+ bool hasBorderRadius = borderMetrics.borderRadii .topLeft .horizontal != 0 ||
715+ borderMetrics.borderRadii .topRight .horizontal != 0 || borderMetrics.borderRadii .bottomLeft .horizontal != 0 ||
716+ borderMetrics.borderRadii .bottomRight .horizontal != 0 || borderMetrics.borderRadii .topLeft .vertical != 0 ||
717+ borderMetrics.borderRadii .topRight .vertical != 0 || borderMetrics.borderRadii .bottomLeft .vertical != 0 ||
718+ borderMetrics.borderRadii .bottomRight .vertical != 0 ;
719+
720+ if (hasBorderRadius) {
721+ // When borderRadius is set, we need to create a shadow mask that follows the rounded rectangle shape.
722+ // Use CompositionVisualSurface to capture the clipped visual's appearance as the shadow mask.
723+ bool maskSet = false ;
724+
725+ // Try Microsoft (WinUI3) Composition first
726+ auto msCompositor =
727+ winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerCompositor (
728+ m_compContext);
729+ if (msCompositor) {
730+ auto innerVisual =
731+ winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerVisual (
732+ Visual ());
733+ if (innerVisual) {
734+ // Create a VisualSurface that captures the visual (with its clip applied)
735+ auto visualSurface = msCompositor.CreateVisualSurface ();
736+ visualSurface.SourceVisual (innerVisual);
737+ visualSurface.SourceSize (
738+ {m_layoutMetrics.frame .size .width * m_layoutMetrics.pointScaleFactor ,
739+ m_layoutMetrics.frame .size .height * m_layoutMetrics.pointScaleFactor });
740+
741+ // Create a brush from the visual surface to use as shadow mask
742+ auto maskBrush = msCompositor.CreateSurfaceBrush (visualSurface);
743+ maskBrush.Stretch (winrt::Microsoft::UI::Composition::CompositionStretch::Fill);
744+
745+ // Get the inner shadow and set the mask
746+ auto innerShadow = winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::
747+ InnerDropShadow (shadow);
748+ if (innerShadow) {
749+ innerShadow.Mask (maskBrush);
750+ maskSet = true ;
751+ }
752+ }
753+ }
754+
755+ // Fallback to System (Windows.UI) Composition if Microsoft Composition is not available
756+ if (!maskSet) {
757+ auto sysCompositor =
758+ winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerCompositor (
759+ m_compContext);
760+ if (sysCompositor) {
761+ auto innerVisual =
762+ winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerVisual (
763+ Visual ());
764+ if (innerVisual) {
765+ auto visualSurface = sysCompositor.CreateVisualSurface ();
766+ visualSurface.SourceVisual (innerVisual);
767+ visualSurface.SourceSize (
768+ {m_layoutMetrics.frame .size .width * m_layoutMetrics.pointScaleFactor ,
769+ m_layoutMetrics.frame .size .height * m_layoutMetrics.pointScaleFactor });
770+
771+ auto maskBrush = sysCompositor.CreateSurfaceBrush (visualSurface);
772+ maskBrush.Stretch (winrt::Windows::UI::Composition::CompositionStretch::Fill);
773+
774+ auto innerShadow =
775+ winrt::Microsoft::ReactNative::Composition::Experimental::SystemCompositionContextHelper::InnerDropShadow (
776+ shadow);
777+ if (innerShadow) {
778+ innerShadow.Mask (maskBrush);
779+ }
780+ }
781+ }
782+ }
783+
784+ // Apply shadow to OuterVisual (which is not clipped) so the shadow can extend beyond the clip
785+ OuterVisual ().as <winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow (shadow);
786+ Visual ().as <winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow (nullptr );
787+ } else {
788+ // No border radius - apply shadow directly to Visual (original behavior)
789+ Visual ().as <winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow (shadow);
790+ OuterVisual ().as <winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual>().Shadow (nullptr );
791+ }
715792}
716793
717794void ComponentView::updateTransformProps (
0 commit comments