Repository navigation
Commit 281fc5a
Fix View style payloads that Props 2.0 sends wrong or drops (#59078)
Summary:
With Props 2.0 on Android (`enableExclusivePropsUpdateAndroid` and the related flags), `ReactViewManager` receives the payload from `HostPlatformViewProps::getDiffProps`. Some style props come out wrong:
- `backgroundSize`, `backgroundPosition`, `backgroundRepeat`: never sent, so a tiled gradient fills the whole view.
- A `perspective` transform: sent as `perspectiveX`, which Android ignores.
- A removed side border width: sent as `0` instead of falling back to `borderWidth`.
- `boxShadow` or `drop-shadow` without a color: transparent instead of black.
- A removed `shadowColor`: sent as `0`, so the elevation shadow disappears.
- A gradient color hint, as in `linear-gradient(red, 20%, blue)`: drawn as a transparent stop.
This PR sends each of them the way the Java side reads them. Nothing changes with the flags off, except that the animation backend shares the transform code and now also sends `perspective`.
## Changelog:
[ANDROID] [FIXED] - Fix View background, perspective, border width, shadow and gradient props with Props 2.0
Pull Request resolved: #59078
Test Plan:
- New `ViewPropsDiffTest`, using the payload helper from #59077. Each test fails on main. Built with the NDK and run on an Android emulator (there is no open-source gtest target).
- RNTester on an Android emulator with the Props 2.0 flags forced on: the BackgroundImage example and the Playground screen below.
**Gradient with Background Repeat**
<table>
<tr><th>Before</th><th>After</th></tr>
<tr>
<td>
https://github.com/user-attachments/assets/6e337636-608d-4c06-996f-914ff005528d
</td>
<td>
https://github.com/user-attachments/assets/6d346094-eff6-4b20-a1aa-693988c47048
</td>
</tr>
</table>
**Flip a card with `perspective: 400`**
<table>
<tr><th>Before</th><th>After</th></tr>
<tr>
<td>
https://github.com/user-attachments/assets/9fcdcbc0-ec94-43be-aa95-31e8d5b813c3
</td>
<td>
https://github.com/user-attachments/assets/7942a58c-f7c1-4292-aa02-edadb31924d3
</td>
</tr>
</table>
**Remove `borderLeftWidth` (`borderWidth: 8`)**
<table>
<tr><th>Before</th><th>After</th></tr>
<tr>
<td>
https://github.com/user-attachments/assets/5098d21a-2686-4d01-9120-07247832579e
</td>
<td>
https://github.com/user-attachments/assets/758dc39e-230e-45ec-81d5-098f601183d6
</td>
</tr>
</table>
**`boxShadow` and `drop-shadow` without a color**
<table>
<tr><th>Before</th><th>After</th></tr>
<tr>
<td>
https://github.com/user-attachments/assets/20fa2a78-240f-4e62-afa9-b0f687b1493c
</td>
<td>
https://github.com/user-attachments/assets/2c6257f5-e978-4710-b0b9-b1fdb34f1052
</td>
</tr>
</table>
**Remove `shadowColor` (`elevation: 24`)**
<table>
<tr><th>Before</th><th>After</th></tr>
<tr>
<td>
https://github.com/user-attachments/assets/e74d27b5-6c1c-45f2-be88-a27b6a5fb0cd
</td>
<td>
https://github.com/user-attachments/assets/55593913-96ea-46e5-91b8-c1fd3cf53c43
</td>
</tr>
</table>
**Add a 20% color hint**
<table>
<tr><th>Before</th><th>After</th></tr>
<tr>
<td>
https://github.com/user-attachments/assets/9f2c2b2a-8b39-4e0d-9ca6-5c972c5abf75
</td>
<td>
https://github.com/user-attachments/assets/b4ab4fa6-7d92-4705-af76-bae13b091bc4
</td>
</tr>
</table>
<details><summary><code>RNTesterPlayground.js</code>: paste into <code>packages/rn-tester/js/examples/Playground/RNTesterPlayground.js</code> and open Playground.</summary>
```js
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* flow strict-local
* format
*/
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import * as React from 'react';
import {useState} from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';
function Perspective() {
const [on, setOn] = useState(false);
return (
<View>
<Button
testID="toggle"
title={on ? 'Flip back' : 'Flip card'}
onPress={() => setOn(v => !v)}
/>
<Text testID="state">
transform: perspective 400, rotateY {on ? '60deg' : '0deg'}
</Text>
<View style={styles.row}>
<View
style={[
styles.card,
{transform: [{perspective: 400}, {rotateY: on ? '60deg' : '0deg'}]},
]}>
<Text style={styles.cardText}>CARD</Text>
</View>
</View>
</View>
);
}
function Border() {
const [on, setOn] = useState(true);
return (
<View>
<Button
testID="toggle"
title={on ? 'Remove borderLeftWidth' : 'Set borderLeftWidth'}
onPress={() => setOn(v => !v)}
/>
<Text testID="state">
borderWidth 8{on ? ', borderLeftWidth 32' : ''}
</Text>
<View style={styles.row}>
<View style={[styles.bordered, on && {borderLeftWidth: 32}]} />
</View>
</View>
);
}
function Shadows() {
const [on, setOn] = useState(true);
return (
<View>
<Button
testID="toggle"
title={on ? 'Remove shadows' : 'Set shadows'}
onPress={() => setOn(v => !v)}
/>
<Text testID="state">
{on ? 'boxShadow, drop-shadow: no color' : 'no shadows'}
</Text>
<View style={styles.row}>
<View style={[styles.box, on && {boxShadow: '0 12px 16px'}]}>
<Text>boxShadow</Text>
</View>
<View style={[styles.box, on && {filter: 'drop-shadow(0 12px 6px)'}]}>
<Text>drop-shadow</Text>
</View>
</View>
</View>
);
}
function ShadowColor() {
const [on, setOn] = useState(true);
return (
<View>
<Button
testID="toggle"
title={on ? 'Remove shadowColor' : 'Set shadowColor'}
onPress={() => setOn(v => !v)}
/>
<Text testID="state">
elevation 24, shadowColor {on ? 'red' : 'unset'}
</Text>
<View style={styles.row}>
<View style={[styles.box, styles.elevated, on && {shadowColor: 'red'}]}>
<Text>elevation</Text>
</View>
</View>
</View>
);
}
function Gradient() {
const [hint, setHint] = useState(false);
return (
<View>
<Button
testID="toggle"
title={hint ? 'Remove the 20% hint' : 'Add a 20% hint'}
onPress={() => setHint(v => !v)}
/>
<Text testID="state">
linear-gradient(red, {hint ? '20%, ' : ''}blue)
</Text>
<View style={styles.row}>
<View
style={[
styles.gradient,
{
backgroundImage: hint
? 'linear-gradient(red, 20%, blue)'
: 'linear-gradient(red, blue)',
},
]}
/>
</View>
</View>
);
}
const demos = {
perspective: Perspective,
border: Border,
shadows: Shadows,
shadowColor: ShadowColor,
gradient: Gradient,
};
function Playground() {
const [demo, setDemo] = useState<$Keys<typeof demos>>('perspective');
const Demo = demos[demo];
return (
<View style={styles.container}>
<View style={styles.tabs}>
{Object.keys(demos).map(name => (
<Button
key={name}
testID={'tab-' + name}
title={name}
onPress={() => setDemo(name)}
/>
))}
</View>
<Demo key={demo} />
</View>
);
}
const styles = StyleSheet.create({
bordered: {
backgroundColor: '#ffd54f',
borderColor: '#1a237e',
borderWidth: 8,
height: 120,
width: 200,
},
box: {
alignItems: 'center',
backgroundColor: 'white',
borderRadius: 12,
height: 120,
justifyContent: 'center',
margin: 16,
width: 140,
},
card: {
alignItems: 'center',
backgroundColor: '#1e88e5',
height: 140,
justifyContent: 'center',
width: 200,
},
cardText: {color: 'white', fontSize: 28, fontWeight: 'bold'},
container: {padding: 10},
elevated: {elevation: 24},
gradient: {height: 160, width: 240},
row: {
alignItems: 'center',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
marginTop: 24,
},
tabs: {flexDirection: 'row', flexWrap: 'wrap', gap: 6, marginBottom: 12},
});
export default {
title: 'Playground',
name: 'playground',
description: 'Test out new features and ideas.',
render: (): React.Node => <Playground />,
} as RNTesterModuleExample;
```
</details>
Differential Revision: D125438461
Pulled By: bartlomiejbloniarz1 parent 88974ca commit 281fc5a
6 files changed
Lines changed: 181 additions & 6 deletions
File tree
- packages/react-native/ReactCommon/react/renderer
- components/view
- platform/android/react/renderer/components/view
- tests
- graphics
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
162 | | - | |
| 162 | + | |
163 | 163 | | |
164 | 164 | | |
165 | 165 | | |
| |||
449 | 449 | | |
450 | 450 | | |
451 | 451 | | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
452 | 502 | | |
453 | 503 | | |
454 | 504 | | |
| |||
528 | 578 | | |
529 | 579 | | |
530 | 580 | | |
531 | | - | |
| 581 | + | |
| 582 | + | |
532 | 583 | | |
533 | 584 | | |
534 | 585 | | |
| |||
580 | 631 | | |
581 | 632 | | |
582 | 633 | | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
583 | 646 | | |
584 | 647 | | |
585 | 648 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
36 | 38 | | |
37 | 39 | | |
38 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
105 | | - | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
106 | 108 | | |
107 | 109 | | |
108 | 110 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| |||
0 commit comments