Architecture
wombatail.config.ts (themes / breakpoints) | | | parsed at build time | imported once at the app entry | (breakpoint names, color tokens) | (StyleSheet.configure) v vWombatail Babel plugin Unistyles runtimeCompile pipeline
Section titled “Compile pipeline”TSX className="flex-row px-4 bg-surface md:px-6" | vWombatail Babel plugin - statically analyzes class expressions - resolves the supported RN utility subset - maps semantic colors -> theme.colors.* - maps breakpoints -> Unistyles breakpoint values - maps platform prefixes -> Platform.OS conditions | vGenerated source style={_wombatailStyles._u0}
StyleSheet.create(theme => ({ _u0: { flexDirection: 'row', paddingLeft: 16, paddingRight: 16, backgroundColor: theme.colors.surface, }, _u1: { paddingLeft: { md: 24 }, paddingRight: { md: 24 } } })) | vreact-native-unistyles Babel plugin | vUnistyles v3 native styling engine / FabricProduction invariants
Section titled “Production invariants”- No runtime class parser.
- Explicit
style={...}is composed last and therefore has precedence. - Unistyles style objects are never spread; composition uses React Native style arrays.
- Unsupported or non-static class syntax fails compilation by default.
- Theme has one owner: Unistyles. Wombatail emits semantic lookups only.
- Breakpoint names in Wombatail configuration must match registered Unistyles
breakpoints. With
wombatail.config.*this holds by construction: both sides read the same object. - The Wombatail Babel transform runs before the Unistyles Babel transform.
- Conflicting spacing/border/radius utilities are canonicalized to physical React Native properties before merge so source order is deterministic.
Pressablestyle callbacks remain callbacks after composition.classNamecombined with JSX spread is rejected by default because static precedence cannot be guaranteed.- The config file is parsed, never executed, so build-time analysis never runs app code; explicit Babel plugin options always override it.
Why the resolver is scoped
Section titled “Why the resolver is scoped”The public contract is Tailwind-like React Native syntax, not full CSS compatibility. The release candidate uses a focused native resolver so unsupported CSS cannot silently leak into React Native. A later backend may use Tailwind v4 candidate compilation plus CSS-to-RN normalization while preserving the JSX API and these invariants.
