Skip to content

Commit 146aaac

Browse files
RealBhupeshmeta-codesync[bot]
authored andcommitted
Treat NaN border widths as unset (#57789)
Summary: Resetting a `borderWidth` on Android could clip or hide children in a rounded overflow-hidden view. The root cause is how a reset width is represented. The border-width prop group is registered with `defaultFloat = Float.NaN` (ReactViewManager.kt), so removing `borderWidth` in JS calls the native setter with `Float.NaN`, not null. `BackgroundStyleApplicator.setBorderWidth` fans that value out to two consumers: - the border drawable (via `width?.dpToPx() ?: Float.NaN`), which already treats `NaN` as unset. - `BorderInsets`, which did not. `BorderInsets.resolve()` falls back with the Elvis operator (`edgeInsets[...] ?: ... ?: 0f`), and `?:` only triggers on null. A non-null `NaN` edge is returned verbatim into the inset `RectF`, which produces a `NaN` content box and inner rounded clip, so children get clipped in overflow-hidden rounded views. Fix: normalize `NaN` to unset in `BorderInsets.setBorderWidth` (`width?.takeUnless { it.isNaN() }`) so it falls back to the applicable all-edge width, matching what the drawable already does. `setBorderWidth` is the only mutator of the private `edgeInsets` array. `NaN` is never a meaningful width, so nothing legitimate is affected. - Add a regression test confirming NaN edges fall back to the applicable all-edge width. ## Changelog: [ANDROID] [FIXED] - Resetting border widths no longer clips children in rounded overflow-hidden views. Fixes #57780 Pull Request resolved: #57789 Test Plan: - Added `BorderInsetsTest.nanBorderWidthsAreTreatedAsUnset`. - Android unit tests could not run locally because this environment has no configured Android SDK (`ANDROID_HOME`/`ANDROID_SDK_ROOT`). Reviewed By: javache Differential Revision: D114520650 Pulled By: fabriziocucci fbshipit-source-id: 01afb38c8c5c0811e928e806d6912da5c3071804
1 parent 2bb56dc commit 146aaac

2 files changed

Lines changed: 35 additions & 2 deletions

File tree

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/style/BorderInsets.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ internal class BorderInsets {
2727
* Sets the border width for a specific logical edge.
2828
*
2929
* @param edge The logical edge to set
30-
* @param width The border width in pixels, or null to clear
30+
* @param width The border width in pixels, or null or NaN to clear
3131
*/
3232
fun setBorderWidth(edge: LogicalEdge, width: Float?) {
33-
edgeInsets[edge.ordinal] = width
33+
edgeInsets[edge.ordinal] = width?.takeUnless { it.isNaN() }
3434
}
3535

3636
/**
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.uimanager.style
9+
10+
import android.content.Context
11+
import android.util.LayoutDirection
12+
import org.assertj.core.api.Assertions.assertThat
13+
import org.junit.Test
14+
import org.junit.runner.RunWith
15+
import org.mockito.kotlin.mock
16+
import org.robolectric.RobolectricTestRunner
17+
18+
@RunWith(RobolectricTestRunner::class)
19+
class BorderInsetsTest {
20+
@Test
21+
fun nanBorderWidthsAreTreatedAsUnset() {
22+
val borderInsets = BorderInsets()
23+
borderInsets.setBorderWidth(LogicalEdge.ALL, 4f)
24+
borderInsets.setBorderWidth(LogicalEdge.LEFT, Float.NaN)
25+
26+
val resolved = borderInsets.resolve(LayoutDirection.LTR, mock<Context>())
27+
28+
assertThat(resolved.left).isEqualTo(4f)
29+
assertThat(resolved.top).isEqualTo(4f)
30+
assertThat(resolved.right).isEqualTo(4f)
31+
assertThat(resolved.bottom).isEqualTo(4f)
32+
}
33+
}

0 commit comments

Comments
 (0)