fix(CDS-2427): size LinearGradient svg to measured pixels under Fabric - #810
fix(CDS-2427): size LinearGradient svg to measured pixels under Fabric#810adrienzheng-cb wants to merge 2 commits into
Conversation
🟡 Heimdall Review Status
🟡
|
| Code Owner | Status | Calculation | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| ui-systems-eng-team |
🟡
0/1
|
Denominator calculation
|
|
Review Error for dh-cb @ 2026-07-27 18:51:11 UTC |
|
Review Error for dh-cb @ 2026-07-28 14:51:16 UTC |
After the CMR 8 upgrade (Expo 56 / RN 0.85 / new Yoga), the LinearGradient wrapper — a size-less `absoluteFillObject` View wrapping an `Svg` with `width/height="100%"` — expands to full screen instead of hugging its children. Measure the wrapper via `onLayout` and hand the inner container/`Svg`/`Rect` explicit pixel dimensions (seeded from numeric `style` dims when present). This mirrors the fix the Retail team validated in production on CMR v8 / RN 0.85 (consumer/react-native#71155, applied there as a downstream cds-mobile yarn patch), and lets that patch be dropped once this ships. Co-authored-by: Cursor <cursoragent@cursor.com>
599c574 to
b2c9368
Compare
cb-ekuersch
left a comment
There was a problem hiding this comment.
left a few comments - let's help the customer out and take care of that patch form them after upgrading!
|
|
||
| type Coordinate = { x: number; y: number }; | ||
|
|
||
| type PixelSize = { width: number; height: number } | null; |
There was a problem hiding this comment.
nit: can we not use a type derived from the LayoutChangeEvent type?
| }: LinearGradientProps) { | ||
| const [pixelSize, setPixelSize] = useState<PixelSize>(() => { | ||
| const flat = StyleSheet.flatten(style); | ||
| return flat && typeof flat.width === 'number' && typeof flat.height === 'number' |
There was a problem hiding this comment.
this initial state stores the computed w/h or the style properties passed in? What happens when no w/h is set in the style object on initial render?
| <Svg height="100%" width="100%"> | ||
| <View | ||
| key="GrandientSvgContainer" | ||
| style={{ position: 'absolute', top: 0, left: 0, width: svgWidth, height: svgHeight }} |
There was a problem hiding this comment.
non-memoized inline style object
What changed? Why?
After the CMR 8 upgrade (Expo SDK 56 / React Native 0.85 / new Yoga),
cds-mobile'sLinearGradientmis-sizes on Fabric — it expands to full screen instead of hugging its children.The gradient is painted by an inset-only
absoluteFillObjectViewwrapping an<Svg width="100%" height="100%">. A size-less absolute view with a percentage-sized SVG child is exactly what the new Yoga/react-native-svg-on-Fabric combination mishandles, so the wrapper blows up to the full screen.The fix measures the wrapper via
onLayoutand hands the inner container,Svg, andRectexplicit pixel dimensions (seeded from numericstylewidth/height when present so there's no first-frame flash), instead of relying onabsoluteFillObject+"100%".Root cause (required for bugfixes)
StyleSheet.absoluteFillObjectis inset-only (no width/height). Under RN 0.81's Yoga this still resolves to the parent's box, but the Yoga/react-native-svgbehavior on RN 0.85 (Expo 56) sizes the percentage SVG against an unconstrained box, expanding the gradient to fill the screen. Giving the container/SVG concrete measured pixels restores correct sizing.Validation
Manually reproduced and verified on a local Expo SDK 56 / React Native 0.85 build of
apps/expo-app(temporary dependency bump, not part of this PR): on theLinearGradientstory the gradient expands/collapses before the fix and hugs its children after it (see before/after below).Note this is not reproducible on
apps/expo-appin its committed state (Expo 54 / RN 0.81.5) — the new-Yoga behavior only manifests on 0.85. The fix also mirrors the exact approach already validated in production on CMR v8 / RN 0.85 by the Retail team inconsumer/react-native#71155, where it currently ships as a downstream@cbhq/cds-mobileYarn patch on the compiledLinearGradient.js. This PR upstreams that patch to source verbatim (sameuseState/useCallback/onLayout+ pixel-sizing), so that downstream patch can be dropped once Retail bumps to acds-mobilerelease containing it.UI changes
Captured on the local Expo 56 / RN 0.85 build described above.
Testing
How has it been tested?
Testing instructions
Added regression tests (
packages/mobile/src/gradients/__tests__/LinearGradient.test.tsx) asserting the SVG is sized from numericstyledims up front and to measured pixels afteronLayout(never"100%").mobile:test(gradient suite),mobile:typecheck, and the formatter are all clean.Manual: on a temporary local Expo 56 / RN 0.85 build, open the
LinearGradientstory — the gradient bands hug their text with the fix, and expand/collapse without it. (The native Yoga expansion can only be exercised on RN 0.85; jsdom unit tests encode the fix's intent.)Change management
type=routine
risk=low
impact=sev4
automerge=false
Fixes CDS-2427.
Made with Cursor