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