3333namespace winrt ::Microsoft::ReactNative::Composition::implementation {
3434
3535constexpr float FOCUS_VISUAL_WIDTH = 2 .0f ;
36+ constexpr float FOCUS_VISUAL_RADIUS = 3 .0f ;
3637
3738// m_outerVisual
3839// |
@@ -228,29 +229,11 @@ void ComponentView::updateFocusLayoutMetrics() noexcept {
228229 facebook::react::RectangleEdges<bool > nudgeEdges;
229230 auto scaleFactor = m_focusPrimitive->m_focusVisualComponent ->m_layoutMetrics .pointScaleFactor ;
230231 if (m_focusPrimitive) {
232+ auto nudgeEdges = m_focusPrimitive->m_focusVisualComponent ->focusNudges ();
231233 if (m_focusPrimitive->m_focusOuterPrimitive ) {
232234 auto outerFocusMetrics = m_focusPrimitive->m_focusVisualComponent ->focusLayoutMetrics (false /* inner*/ );
233-
234- if (outerFocusMetrics.frame .origin .x < 0 ) {
235- nudgeEdges.left = true ;
236- }
237- if (outerFocusMetrics.frame .origin .y < 0 ) {
238- nudgeEdges.top = true ;
239- }
240- if (outerFocusMetrics.frame .getMaxX () > m_layoutMetrics.frame .getMaxX ()) {
241- nudgeEdges.right = true ;
242- }
243- if (outerFocusMetrics.frame .getMaxY () > m_layoutMetrics.frame .getMaxY ()) {
244- nudgeEdges.bottom = true ;
245- }
246-
247235 m_focusPrimitive->m_focusOuterPrimitive ->RootVisual ().Size (
248- {outerFocusMetrics.frame .size .width * scaleFactor -
249- (nudgeEdges.left ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0 ) -
250- (nudgeEdges.right ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0 ),
251- outerFocusMetrics.frame .size .height * scaleFactor -
252- (nudgeEdges.top ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0 ) -
253- (nudgeEdges.bottom ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0 )});
236+ {outerFocusMetrics.frame .size .width * scaleFactor, outerFocusMetrics.frame .size .height * scaleFactor});
254237 m_focusPrimitive->m_focusOuterPrimitive ->RootVisual ().Offset (
255238 {nudgeEdges.left ? 0 : -(FOCUS_VISUAL_WIDTH * 2 * scaleFactor),
256239 nudgeEdges.top ? 0 : -(FOCUS_VISUAL_WIDTH * 2 * scaleFactor),
@@ -261,15 +244,10 @@ void ComponentView::updateFocusLayoutMetrics() noexcept {
261244 if (m_focusPrimitive->m_focusInnerPrimitive ) {
262245 auto innerFocusMetrics = m_focusPrimitive->m_focusVisualComponent ->focusLayoutMetrics (true /* inner*/ );
263246 m_focusPrimitive->m_focusInnerPrimitive ->RootVisual ().Size (
264- {innerFocusMetrics.frame .size .width * scaleFactor -
265- (nudgeEdges.left ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0 ) -
266- (nudgeEdges.right ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0 ),
267- innerFocusMetrics.frame .size .height * scaleFactor -
268- (nudgeEdges.top ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0 ) -
269- (nudgeEdges.bottom ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0 )});
247+ {innerFocusMetrics.frame .size .width * scaleFactor, innerFocusMetrics.frame .size .height * scaleFactor});
270248 m_focusPrimitive->m_focusInnerPrimitive ->RootVisual ().Offset (
271- {nudgeEdges.left ? 0 : -FOCUS_VISUAL_WIDTH * scaleFactor,
272- nudgeEdges.top ? 0 : -FOCUS_VISUAL_WIDTH * scaleFactor,
249+ {nudgeEdges.left ? (FOCUS_VISUAL_WIDTH * scaleFactor) : ( -FOCUS_VISUAL_WIDTH * scaleFactor) ,
250+ nudgeEdges.top ? (FOCUS_VISUAL_WIDTH * scaleFactor) : ( -FOCUS_VISUAL_WIDTH * scaleFactor) ,
273251 0 .0f });
274252 m_focusPrimitive->m_focusInnerPrimitive ->markNeedsUpdate ();
275253 }
@@ -538,7 +516,33 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ComponentView:
538516 return m_outerVisual ? m_outerVisual : Visual ();
539517}
540518
541- facebook::react::LayoutMetrics ComponentView::focusLayoutMetrics (bool inner) const noexcept {
519+ // If the focus visual would extend past the bounds of the hosting visual,
520+ // then we will nudge the focus visual back inside the hosting visuals bounds.
521+ facebook::react::RectangleEdges<bool > ComponentView::focusNudges () const noexcept {
522+ facebook::react::RectangleEdges<bool > nudgeEdges;
523+
524+ // Always use outer focus metrics to determine if we need to nudge the focus rect over to fit
525+ facebook::react::LayoutMetrics layoutMetrics = focusLayoutMetricsNoNudge (false /* inner*/ );
526+
527+ Assert (m_componentHostingFocusVisual);
528+
529+ if (layoutMetrics.frame .origin .x < 0 ) {
530+ nudgeEdges.left = true ;
531+ }
532+ if (layoutMetrics.frame .origin .y < 0 ) {
533+ nudgeEdges.top = true ;
534+ }
535+ if (layoutMetrics.frame .getMaxX () > m_componentHostingFocusVisual->m_layoutMetrics .frame .getMaxX ()) {
536+ nudgeEdges.right = true ;
537+ }
538+ if (layoutMetrics.frame .getMaxY () > m_componentHostingFocusVisual->m_layoutMetrics .frame .getMaxY ()) {
539+ nudgeEdges.bottom = true ;
540+ }
541+
542+ return nudgeEdges;
543+ }
544+
545+ facebook::react::LayoutMetrics ComponentView::focusLayoutMetricsNoNudge (bool inner) const noexcept {
542546 facebook::react::LayoutMetrics layoutMetrics = m_layoutMetrics;
543547 layoutMetrics.frame .origin .x -= FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
544548 layoutMetrics.frame .origin .y -= FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
@@ -547,6 +551,28 @@ facebook::react::LayoutMetrics ComponentView::focusLayoutMetrics(bool inner) con
547551 return layoutMetrics;
548552}
549553
554+ facebook::react::LayoutMetrics ComponentView::focusLayoutMetrics (bool inner) const noexcept {
555+ auto nudgeEdges = focusNudges ();
556+ auto layoutMetrics = focusLayoutMetricsNoNudge (inner);
557+
558+ if (nudgeEdges.left ) {
559+ layoutMetrics.frame .origin .x += FOCUS_VISUAL_WIDTH * 2 ;
560+ layoutMetrics.frame .size .width -= FOCUS_VISUAL_WIDTH * 2 ;
561+ }
562+ if (nudgeEdges.top ) {
563+ layoutMetrics.frame .origin .y += FOCUS_VISUAL_WIDTH * 2 ;
564+ layoutMetrics.frame .size .height -= FOCUS_VISUAL_WIDTH * 2 ;
565+ }
566+ if (nudgeEdges.right ) {
567+ layoutMetrics.frame .size .width -= FOCUS_VISUAL_WIDTH * 2 ;
568+ }
569+ if (nudgeEdges.bottom ) {
570+ layoutMetrics.frame .size .height -= FOCUS_VISUAL_WIDTH * 2 ;
571+ }
572+
573+ return layoutMetrics;
574+ }
575+
550576facebook::react::BorderMetrics ComponentView::focusBorderMetrics (
551577 bool inner,
552578 const facebook::react::LayoutMetrics &layoutMetrics) const noexcept {
@@ -556,22 +582,31 @@ facebook::react::BorderMetrics ComponentView::focusBorderMetrics(
556582 innerColor.m_platformColor .push_back (inner ? " FocusVisualSecondary" : " FocusVisualPrimary" );
557583 metrics.borderColors .bottom = metrics.borderColors .left = metrics.borderColors .right = metrics.borderColors .top =
558584 innerColor;
559- if (metrics.borderRadii .bottomLeft .horizontal != 0 )
560- metrics.borderRadii .bottomLeft .horizontal += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
561- if (metrics.borderRadii .bottomLeft .vertical != 0 )
562- metrics.borderRadii .bottomLeft .vertical += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
563- if (metrics.borderRadii .bottomRight .horizontal != 0 )
564- metrics.borderRadii .bottomRight .horizontal += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
565- if (metrics.borderRadii .bottomRight .vertical != 0 )
566- metrics.borderRadii .bottomRight .vertical += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
567- if (metrics.borderRadii .topLeft .horizontal != 0 )
568- metrics.borderRadii .topLeft .horizontal += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
569- if (metrics.borderRadii .topLeft .vertical != 0 )
570- metrics.borderRadii .topLeft .vertical += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
571- if (metrics.borderRadii .topRight .horizontal != 0 )
572- metrics.borderRadii .topRight .horizontal += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
573- if (metrics.borderRadii .topRight .vertical != 0 )
574- metrics.borderRadii .topRight .vertical += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
585+
586+ metrics.borderRadii .bottomLeft .horizontal =
587+ (metrics.borderRadii .bottomLeft .horizontal ? metrics.borderRadii .bottomLeft .horizontal : FOCUS_VISUAL_RADIUS) +
588+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
589+ metrics.borderRadii .bottomLeft .vertical =
590+ (metrics.borderRadii .bottomLeft .vertical ? metrics.borderRadii .bottomLeft .vertical : FOCUS_VISUAL_RADIUS) +
591+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
592+ metrics.borderRadii .bottomRight .horizontal =
593+ (metrics.borderRadii .bottomRight .horizontal ? metrics.borderRadii .bottomRight .horizontal : FOCUS_VISUAL_RADIUS) +
594+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
595+ metrics.borderRadii .bottomRight .vertical =
596+ (metrics.borderRadii .bottomRight .vertical ? metrics.borderRadii .bottomRight .vertical : FOCUS_VISUAL_RADIUS) +
597+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
598+ metrics.borderRadii .topLeft .horizontal =
599+ (metrics.borderRadii .topLeft .horizontal ? metrics.borderRadii .topLeft .horizontal : FOCUS_VISUAL_RADIUS) +
600+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
601+ metrics.borderRadii .topLeft .vertical =
602+ (metrics.borderRadii .topLeft .vertical ? metrics.borderRadii .topLeft .vertical : FOCUS_VISUAL_RADIUS) +
603+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
604+ metrics.borderRadii .topRight .horizontal =
605+ (metrics.borderRadii .topRight .horizontal ? metrics.borderRadii .topRight .horizontal : FOCUS_VISUAL_RADIUS) +
606+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
607+ metrics.borderRadii .topRight .vertical =
608+ (metrics.borderRadii .topRight .vertical ? metrics.borderRadii .topRight .vertical : FOCUS_VISUAL_RADIUS) +
609+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2 );
575610
576611 metrics.borderStyles .bottom = metrics.borderStyles .left = metrics.borderStyles .right = metrics.borderStyles .top =
577612 facebook::react::BorderStyle::Solid;
0 commit comments