Repository navigation
fix(native): seed a concrete scheme-aware __rn-css-color on every platform - #392
Open
YevheniiKotyrlo wants to merge 2 commits into
Open
YevheniiKotyrlo wants to merge 2 commits into
YevheniiKotyrlo wants to merge 2 commits into
Conversation
YevheniiKotyrlo
marked this pull request as ready for review
July 26, 2026 14:52
Contributor
Author
YevheniiKotyrlo
force-pushed
the
fix/root-color-seed
branch
from
October 11, 2026 12:35
d3047d5 to
859dc9e
Compare
This was referenced Oct 11, 2026
…tform The root seed is `color`'s initial value, `CanvasText`: black, or white in a dark scheme. A semantic `PlatformColor` fallback paints nothing on the border, ring and shadow paths of either platform, so the seed is a concrete color chosen by the root's own `prefers-color-scheme` evaluation. Every currentcolor consumer is pinned on the compile-time and runtime paths in both schemes, from raw CSS and from Tailwind's own utilities.
YevheniiKotyrlo
force-pushed
the
fix/root-color-seed
branch
from
October 22, 2026 12:37
859dc9e to
3b096e1
Compare
With inlineVariables off, `--c: currentcolor` stays a runtime variable that references `__rn-css-color`, so `border-color: var(--c)` reaches the seed through the runtime's variable lookup rather than the compiler's inlined reference.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Problem
Every color that falls back to the root
__rn-css-colorpaints nothing where the platform reads it without resolving a semantic color — everywhere on Android, and on iOS for border, outline and shadow. Tailwind v4's default ring color iscurrentcolor, soring,inset-ring,text-currentandborder-currentare the everyday triggers.Root cause
?attr/textColorPrimaryis a ColorStateList, andColorPropConverter.resolveThemeAttributereturnsoutValue.datawithout checkingoutValue.type, so the paint receives a resource reference rather than a color.UIColorhas to be resolved against a trait collection.RCTViewComponentView.mmdoes that for the background alone; border, outline and shadow read.CGColordirectly (facebook/react-native#57836).Solution
The seed is
color's initial value,CanvasText(CSS Color 4 §3.2), made concrete: black, or white underprefers-color-scheme: dark. The root observable already evaluates a seeded value's media query againstcolorScheme, so the seed stays reactive with noPlatform.OSbranch, noAppearancelistener, noas anyand no eslint suppression. An ancestor's color or a:rootcolor still overrides it.Tests
src/__tests__/native/root-color-seed.test.tsx— each of 13currentcolorconsumers compiles to the root color reference and paints#000000in a light scheme and#FFFFFFin a dark one, and so does acurrentcolorheld in a custom property the compiler keeps; no preference, a live scheme change, an ancestor color, a:rootcolor and a scheme-conditioned:rootcolor are pinned as well.src/__tests__/vendor/tailwind/current-color.test.tsx— Tailwind's owncurrentcolorutilities (text-current,bg-current,border-current,outline-current,decoration-current,caret-current,fill-current,stroke-current,ring,inset-ring,shadow-current,placeholder:text-current) in both schemes, and an explicit ring color over the default.src/__tests__/native/box-shadow.test.tsx— aplatformColor()shadow still reaches the shadow as the platform's object.PlatformColordescriptor for acurrentcolorreader now assert the painted color.On
main, 59 cases fail with thePlatformColorseed and all of them pass with this one.Two expectations follow what
maindoes: it mapsborder-inline-start-colortoborderStartColor, and writes acolor-mix()shadow color asrgba().Verification
On this head, the pull request's CI jobs run locally on Ubuntu with Node 22.18.0:
yarn build,yarn lint,yarn typecheck,yarn test --maxWorkers=2 --coverage1413 passed,node --test node/__tests__/*.mjs42 passed,yarn example expo export --platform web, and no unstaged files after the build or the export. The iOS dev build, run with Xcode 27.1 where CI pins 26.6, fails onmainas on this head, before any JavaScript is bundled: Expo'sExpoModulesJSIdoes not build with it (cannot find type '__ObjC::expo' in scope).Device evidence, before and after: #392 (comment)
Open questions
?attr/colorForegroundpoints at a plain<color>in AppCompat and Material, so it would resolve correctly and keep a custom brand theme's foreground instead of pure black or white. I chose the concrete pair because it is what CSS specifies and whatlight-dark()compiles to here; switching needs a device check I have not run.Known limits
shadow-currentkeeps Tailwind's default shadow color until fix(compiler): omit absent color-mix weights from serialized descriptors #464 lands:mainwrites an omittedcolor-mix()weight asnull, which the runtime cannot read.box-shadowortext-shadowwith no color is black until fix(native): read a runtime shadow the way the compiler does #489 lands, which reads the omitted color ascurrentcolor.Related
#410 made the root registries process-global while
colorSchemestays per module copy, so the seed's media query reads thecolorSchemeof whichever copy created the registries; #427 sharesreactivity.ts's state across the split the same way.Merge order
This overlaps #412, #494 and #498 in
src/native-internal/root.tsand #489 insrc/native/styles/shorthands/box-shadow.ts, and #391, #412 and #489 add cases that expectmain'sPlatformColorseed; I'll re-cut whichever lands after the others.