From a85f5290ee34f644cfeea72f7bff45260af9ab46 Mon Sep 17 00:00:00 2001 From: Jacques Leupin Date: Wed, 5 Aug 2026 13:06:26 -0700 Subject: [PATCH] Reproducer for #57836: Fabric dynamic border colors resolve against the system appearance --- .../examples/Playground/RNTesterPlayground.js | 127 ++++++++++++++++-- 1 file changed, 119 insertions(+), 8 deletions(-) diff --git a/packages/rn-tester/js/examples/Playground/RNTesterPlayground.js b/packages/rn-tester/js/examples/Playground/RNTesterPlayground.js index 8e6b10479de7..e8b7f2865561 100644 --- a/packages/rn-tester/js/examples/Playground/RNTesterPlayground.js +++ b/packages/rn-tester/js/examples/Playground/RNTesterPlayground.js @@ -10,24 +10,135 @@ import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; -import RNTesterText from '../../components/RNTesterText'; import * as React from 'react'; -import {StyleSheet, View} from 'react-native'; +import {useEffect, useState} from 'react'; +import { + Appearance, + Button, + DynamicColorIOS, + StyleSheet, + Text, + useColorScheme, + View, +} from 'react-native'; + +// Reproducer for https://github.com/facebook/react-native/issues/57836 +// +// ONE dynamic color, used for both fills and borders: +// red in light mode, green in dark mode. +// +// Run RNTester on iOS with the simulator's System Appearance set to LIGHT, +// then open this Playground example. The demo forces the app dark via +// Appearance.setColorScheme('dark') after 2s and mounts a second row of +// boxes at 4s. +// +// Expected: once the app is dark, every fill and border is green. +// Actual: fills turn green, but the borders of row A (mounted before the +// override) stay red — the light variant — on both border code paths +// (border-image and CoreAnimation), and persist indefinitely. +const dynamicColor = DynamicColorIOS({light: '#ff3b30', dark: '#34c759'}); + +function Boxes({label}: {label: string}) { + return ( + + {label} + + + fill + + + border{'\n'}(image path) + + + border{'\n'}(CA path) + + + + ); +} + +function Run() { + const scheme = useColorScheme(); + const [afterOverride, setAfterOverride] = useState(false); + const [phase, setPhase] = useState('phase 0: system appearance'); + + useEffect(() => { + // Phase 1: the app forces dark while the SYSTEM stays light + // (RCTAppearance sets overrideUserInterfaceStyle on every window). + const t1 = setTimeout(() => { + Appearance.setColorScheme('dark'); + setPhase('phase 1: setColorScheme("dark"), system still Light'); + }, 2000); + // Phase 2: mount a second set of boxes while the override is active. + const t2 = setTimeout(() => { + setAfterOverride(true); + setPhase('phase 2: second row mounted under the dark override'); + }, 4000); + return () => { + clearTimeout(t1); + clearTimeout(t2); + }; + }, []); + + return ( + + useColorScheme(): {String(scheme)} + {phase} + + {afterOverride && } + + Expected: every fill and border shows the SAME color (green once the + app is dark). Bug: row A's borders stay red — the system (light) + variant — while its fill turns green. + + + ); +} function Playground() { + const [runId, setRunId] = useState(0); return ( - - - Edit "RNTesterPlayground.js" to change this file - + + +