Skip to content

Take any colour in the color prop of RNTester's legacy native view on Android, as iOS does - #59230

Open
YevheniiKotyrlo wants to merge 3 commits into
react:mainfrom
YevheniiKotyrlo:fix/rntester-legacy-view-color-prop
Open

YevheniiKotyrlo wants to merge 3 commits into
react:mainfrom
YevheniiKotyrlo:fix/rntester-legacy-view-color-prop

Conversation

@YevheniiKotyrlo

@YevheniiKotyrlo YevheniiKotyrlo commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

RNTester's legacy native view takes a color prop that iOS declares a UIColor (RNTMyLegacyNativeViewManager.mm), so the view config runs processColor on it. MyLegacyViewManager on Android takes it as a String and parses it with Color.parseColor, which reads Android's colour grammar rather than React Native's: rgb(), hsl() and most named colours throw IllegalArgumentException: Unknown color from the prop setter and end the app, an eight-digit hex is read as #AARRGGBB instead of CSS's #RRGGBBAA, and a PlatformColor can't be passed.

This declares the setter @ReactProp(customType = "Color") with an Int?, as ReactAndroid's own colour props do, so processColor runs on Android too, and types the prop ColorValue. The view's commands keep taking a #RRGGBB string, the one form both platforms read alike and the one RNTester passes them.

RNTester's example set no color on the legacy view, so nothing reached the setter. Its new "Set Color Prop" button steps the view through rgb(255, 255, 255), hsl(240, 100%, 50%) and steelblue, and new-arch-examples.yml asserts the colour the view reports back after the first press, h: 0, s: 0, b: 1, a: 255 on both platforms, so the e2e jobs cover the prop.

Changelog:

[INTERNAL] [FIXED] - Take any colour in the color prop of RNTester's legacy native view on Android, as iOS does

Test Plan:

On a Galaxy S23 (Android 14), with RNTester release builds under an application id of their own:

  • A root component that draws each colour as a View's backgroundColor and as the legacy view's color, side by side, on main and with this change: on main, rgb(70, 130, 180) ends the app on launch (Unknown color from MyLegacyViewManager.setColor) and #4682B480 draws #ddeadc beside the View's #a2c0d9; with this change every row — hex, rgb(), hsl(), steelblue and a PlatformColor — matches the View beside it. Screenshots and the crash are in the comment below.
  • maestro test -e APP_ID=com.facebook.react.uiapp.rn470 packages/rn-tester/.maestro/new-arch-examples.yml: passes with this change. With the example and flow changes over main's MyLegacyViewManager, tapping "Set Color Prop" ends the app (Error while updating property 'color' of a view managed by: RNTMyLegacyNativeView) and the flow fails at the new assertion.

On an iPad Pro 12.9-inch (4th generation), iOS 27.0.1, with an RNTester release build of this change:

  • The flow's steps, driven over WebDriverAgent: the view reads HSBA: h: 0, s: 0, b: 1, a: 255 after "Set Color Prop", as the flow asserts, and h: 240, s: 1, b: 1, a: 255 after a second press. Maestro needs a simulator on iOS, which I don't have, so CI's iOS e2e job is the first run of the flow itself there.

And in the Android CI image:

  • ./gradlew :packages:rn-tester:android:app:assembleRelease -PreactNativeArchitectures=arm64-v8a -PenableWarningsAsErrors=true: BUILD SUCCESSFUL.
  • yarn flow-check: Found 0 errors.
  • yarn eslint --max-warnings 0 and yarn prettier --check on the changed JavaScript and YAML files, and yarn format-check-kotlin: no findings.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 20, 2026
@YevheniiKotyrlo

YevheniiKotyrlo commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor Author

Device evidence — before / after

RNTester release builds of main at a613baf9d1 and of this PR on a Galaxy S23, Android 14, with the scene below as the root component and a label naming the build. Each row draws its colour as a View's backgroundColor on the left and as the legacy view's color on the right.

main with this PR

With the functional rows added, main ends on launch:

com.facebook.react.bridge.JSApplicationIllegalArgumentException: Error while updating property 'color' of a view managed by: RNTMyLegacyNativeView
	at com.facebook.react.uimanager.ViewManager.updateProperties
	at com.facebook.react.uimanager.ViewManager.createViewInstance
	…
Caused by: java.lang.IllegalArgumentException: Unknown color
	at android.graphics.Color.parseColor(Color.java:1399)
	at com.facebook.react.uiapp.component.MyLegacyViewManager.setColor

and with this PR every row draws:

Each swatch's colour in the full frames:

Row main: View · legacy view with this PR: View · legacy view
#4682B4 #4682b4 · #4682b4 #4682b4 · #4682b4
#4682B480 #a2c0d9 · #ddeadc #a2c0d9 · #a2c0d9
rgb(70, 130, 180) ends on launch #4682b4 · #4682b4
hsl(207, 44%, 49%) — #4682b4 · #4682b4
steelblue — #4682b4 · #4682b4
PlatformColor('@android:color/holo_blue_dark') — #0099cc · #0099cc

#ddeadc is #4682B480 read as #AARRGGBB, rgb(130, 180, 128) at alpha 0x46, over white.

Scene

BUILD and ROWS_MODE are replaced before each build is bundled: hex renders the first two rows, all every row.

import * as React from 'react';
import {PlatformColor, ScrollView, StyleSheet, Text, View} from 'react-native';
import MyLegacyViewNativeComponent from '../NativeComponentExample/js/MyLegacyViewNativeComponent';

const BUILD = 'unset';
const ROWS_MODE = 'unset';

const HEX_ROWS = [
  {label: '#4682B4 (control)', color: '#4682B4'},
  {label: '#4682B480, CSS alpha last', color: '#4682B480'},
];

const FUNCTIONAL_ROWS = [
  {label: 'rgb(70, 130, 180)', color: 'rgb(70, 130, 180)'},
  {label: 'hsl(207, 44%, 49%)', color: 'hsl(207, 44%, 49%)'},
  {label: 'steelblue', color: 'steelblue'},
  {
    label: "PlatformColor('@android:color/holo_blue_dark')",
    color: PlatformColor('@android:color/holo_blue_dark'),
  },
];

const ROWS = ROWS_MODE === 'hex' ? HEX_ROWS : [...HEX_ROWS, ...FUNCTIONAL_ROWS];

function Row({label, color}) {
  return (
    <View style={styles.row}>
      <Text style={styles.label}>{label}</Text>
      <View style={[styles.swatch, {backgroundColor: color}]} />
      <MyLegacyViewNativeComponent color={color} style={styles.swatch} />
    </View>
  );
}

export default function LegacyViewColorProbe() {
  return (
    <View style={styles.container}>
      <ScrollView contentContainerStyle={styles.content}>
        <Text style={styles.build}>{BUILD}</Text>
        <Text style={styles.legend}>left: View backgroundColor · right: legacy view color</Text>
        {ROWS.map(row => (
          <Row key={row.label} label={row.label} color={row.color} />
        ))}
      </ScrollView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: 'white'},
  content: {padding: 16, gap: 12},
  build: {fontSize: 14, color: 'black'},
  legend: {fontSize: 12, color: 'black'},
  row: {flexDirection: 'row', alignItems: 'center', gap: 12, height: 64},
  label: {flex: 1, fontSize: 13, color: 'black'},
  swatch: {width: 48, height: 48},
});

New Architecture Examples with this PR

"Set Color Prop" after "Change Background", as new-arch-examples.yml presses them. The first press gives the legacy view rgb(255, 255, 255), whose reading the flow asserts, and the second hsl(240, 100%, 50%).

Galaxy S23, Android 14 iPad Pro 12.9-inch (4th generation), iOS 27.0.1
first press
second press

@YevheniiKotyrlo
YevheniiKotyrlo marked this pull request as ready for review October 20, 2026 14:47
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 20, 2026
@YevheniiKotyrlo
YevheniiKotyrlo marked this pull request as draft October 20, 2026 16:20
RNTester's example set no color on the legacy view, so no e2e job reached
the setter. A "Set Color Prop" button gives the view rgb(255, 255, 255),
and new-arch-examples.yml asserts the HSBA the view reports back, which
reads h: 0, s: 0, b: 1, a: 255 on both platforms.
@YevheniiKotyrlo YevheniiKotyrlo changed the title Draw any colour on RNTester's legacy native view on Android, as iOS does Take any colour in the color prop of RNTester's legacy native view on Android, as iOS does Oct 20, 2026
@YevheniiKotyrlo
YevheniiKotyrlo marked this pull request as ready for review October 21, 2026 12:02

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant