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