* refactor: add import aliases and move vite to bundler/adapters * refactor: refactored bundler code * chore: remove unused * docs: context.md * chore: unused aliases * chore: add new line before reinit in vite adapter * chore: fs promise to read file for tailwind compilation * chore: consistent type imports * chore: minor corrections * docs: update context.md * test: fix meta test after merge * chore: lint warning * chore: release v1.6.7-beta.0 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
11 KiB
Uniwind Context
This document captures working context for packages/uniwind, the published uniwind package in this monorepo. Keep it current when architecture, public APIs, supported platforms, or build/runtime contracts change.
Product
Uniwind is Tailwind CSS bindings for React Native and React Native Web. It lets users write className props on React Native components while doing as much style work as possible at build time.
Primary promise: fast Tailwind styling for React Native with web parity where practical.
Positioning: Uniwind optimizes for build-time Tailwind-to-React-Native artifacts, minimal runtime work, and React Native Web parity. It is not primarily a full design-system/runtime styling framework, a NativeWind compatibility layer, or a web-first CSS bridge.
Core user-facing features:
- Out-of-the-box
classNamebindings for React Native components. - Tailwind v4 CSS compilation into native runtime style artifacts or web CSS.
- Light, dark, and extra named themes.
active,focus,disabled, RTL, orientation, responsive, data attribute, and platform-aware variants.- CSS custom property reads and updates from React Native code.
- Scoped themes through
ScopedTheme. - Metro and Vite integration.
Supported platforms: iOS, Android, web, Android TV, and Apple TV. Other React Native targets are out of scope until tests and docs explicitly cover them.
Package Boundaries
Important paths:
packages/uniwind/src/index.ts: public package entrypoint.packages/uniwind/src/components: React Native component wrappers and web exports.packages/uniwind/src/core: runtime config, listeners, native style store, and web style extraction.packages/uniwind/src/hooks: public hooks.packages/uniwind/src/hoc:withUniwindfor custom components.packages/uniwind/src/bundler: Metro/Vite adapters, Tailwind compilation, CSS processing, artifact generation.packages/uniwind/tests: native, web, type, and e2e tests.packages/uniwind/uniwind.css: package-level CSS artifact referenced by packagestyleexport.
Public exports from src/index.ts:
Uniwindruntime/config object.ScopedThemecomponent.withUniwindHOC and related types.useCSSVariable,useResolveClassNames,useUniwindhooks.ThemeNameandUniwindConfigtypes.
Package subpath exports:
uniwind: main runtime API.uniwind/components: React Native component replacements.uniwind/components/*: individual component replacements.uniwind/metro: Metro adapter.uniwind/vite: Vite plugin.uniwind/types: generated/user-facing type support.
Stability policy: public package and subpath exports are semver-stable. Generated artifact internals are implementation details unless explicitly documented, with two notable user-facing surfaces: generated theme typings and the package style export (uniwind.css).
Dependency policy: peer dependency floors are support contracts. Raising support floors for Tailwind, React, or React Native requires semver-major unless an upstream ecosystem break makes that impossible to honor.
Runtime Model
Native runtime:
- Build output injects a generated stylesheet callback into
Uniwind.__reinit(...). UniwindStoreholds generated style records, theme variables, scoped variables, runtime state, and per-theme caches.UniwindStore.getStyles(className, props, state, context)resolves classes into React Native style objects.- Cache keys include class names, component state, and whether theme is scoped.
- Resolved styles subscribe to only dependencies they use, then invalidate cache entries on change.
- Runtime dependencies are represented by
StyleDependency: theme, dimensions, orientation, insets, font scale, RTL, adaptive themes, and variables. - Native style resolution filters rules by screen width, orientation, theme, RTL, active/focus/disabled state, and
data-*props. - Native post-processing adapts CSS concepts to RN shapes, including line-height multipliers, shadows, transforms, gradients, visibility, borders, outlines, and font variants.
Web runtime:
- Web keeps styles in CSS and passes
{ $$css: true, tailwind: className }through RNW style arrays. getWebStylesuses a hidden DOM element to compute style values when a JS value is needed, such as color extraction oruseResolveClassNames.CSSListenertracks active CSS rules and media queries, then notifies subscribers when class-dependent media rules change.ScopedThemerenders adivwith the theme class anddisplay: contentson web.- Dynamic CSS variable updates are written into a generated
#uniwind-dynamic-stylesstyle element.
Shared runtime:
Uniwind.setTheme(theme | 'system')switches explicit themes or returns to system-adaptive light/dark.Uniwind.currentThemeandUniwind.hasAdaptiveThemesbackuseUniwind.Uniwind.updateCSSVariables(theme, variables)updates theme variables and notifies variable subscribers.Uniwind.updateInsets(insets)is native-only behavior and updates safe-area-style runtime values.ScopedThemesetsUniwindContext.scopedTheme; scoped subtree ignores global theme changes for style resolution.
Build And Bundler Model
Configuration shape:
cssEntryFile: required CSS entry path, resolved fromprocess.cwd().extraThemes: optional named themes added to defaultlightanddark.dtsFile: optional generated declaration file path, defaultuniwind-types.d.ts.- Metro-only
polyfills.rem: custom rem base, default16. - Metro-only
debugandisTVflags exist in types.
Compilation flow:
compileTailwindreadscssEntryFile, runs Tailwind v4 compile, scans files under the CSS entry directory, and builds final CSS.compileCSSroutes to web or native by platform.compileWebCSSruns Lightning CSS withUniwindCSSVisitorand returns CSS.compileNativeCSSrunsProcessorBuilder, serializes variables, scoped variables, and native stylesheet metadata into JS source.UniwindBundlerConfig.generateArtifactswrites CSS artifacts and generated theme typings.- Internal package aliases such as
@/*are only safe insidepackages/uniwind/src/bundler. Bundler files are built and transformed to JS, but runtime/component/hook/HOC files are published directly as.ts/.tsxReact Native entrypoints, so aliases in those files are not rewritten.
Metro integration:
withUniwindConfig(config, uniwindConfig)patches Metro graph support for uncached modules.- Metro adds
cssas source extension and removes it from asset extensions. - Metro transformer handles the configured CSS entry file specially.
- Native platform CSS transforms into a JS module that calls
Uniwind.__reinit(...). - Web platform CSS transforms into CSS plus web runtime setup.
- Resolver swaps React Native component imports to Uniwind-aware implementations where needed.
Vite integration:
uniwind(config)returns a pre-Vite plugin.- Vite aliases
react-nativeto Uniwind web components, except imports from Uniwind internals resolve back toreact-native-web. - Vite replaces RNW
createOrderedCSSStyleSheetwith Uniwind's ordered stylesheet implementation. - Vite uses Lightning CSS with
UniwindCSSVisitor. - Vite generates artifacts on
buildStartandgenerateBundle.
CSS Processing
Native processing converts Tailwind-generated CSS into metadata-rich style records.
Important concepts:
- A
Stylerecord stores entries, breakpoint bounds, orientation, theme, RTL, native flag, dependencies, source index, class name, important properties, selector complexity, pseudo-states, and data attributes. - CSS variables live in
vars; theme and platform-scoped variables live inscopedVarswith internal prefixes. - The processor treats declarations under
:rootor outside class rules as variables. - Theme variants are recognized from known theme names.
- Data attribute variants support boolean
data-xand exactdata-x="value"matching against component props. - Media queries drive dimensions, orientation, color scheme, platform, and native/web-specific metadata.
- Important declarations are preserved as
importantProperties. - Unsupported CSS features may be silently ignored on native. Prefer documenting support coverage over adding noisy runtime failures for every unsupported CSS construct.
Web visitor behavior:
- Theme root rules in Tailwind theme layer become theme class rules.
- Theme-prefixed class rules are scoped with CSS
@scopeto selected theme classes and excluded from other themes. - Visitor state is cleaned between transforms.
Components And HOC
Native components:
- Native wrappers import the underlying
react-nativecomponent. useStyle(className, props, state)resolvesclassNamethroughUniwindStoreand subscribes to style dependencies.- Most components combine generated style before user style:
[generatedStyle, props.style], preserving user overrides. - Stateful components such as
Pressablepasspressed,focused, anddisabledstate into style resolution. - Accent-capable components use
accentColorextraction helpers where needed.
Web components:
- Web wrappers import from
react-nativeas resolved by bundler aliases. - Web wrappers map
classNameto RNW CSS style markers throughtoRNWClassName. - Web wrappers pass generated
dataSetso data attribute variants can match.
withUniwind:
- Auto mode maps
className-style props to matching RN style props and color class props to color props. - Manual mode maps custom class props to custom target props and can extract a single style property.
- Native mode resolves to concrete RN style objects.
- Web mode usually emits RNW CSS style markers and uses computed style only for extracted values.
Testing And Quality Gates
Package scripts:
bun run build: unbuild package outputs.bun run check:typescript: TypeScript no-emit check.bun run lint: oxlint onsrc.bun run circular:check: dpdm circular dependency check.bun run test:native: Jest native tests.bun run test:web: Jest web tests.bun run test:types: type-level tests.bun run test:e2e: Playwright e2e tests.
Root scripts use Turbo for monorepo-wide build, typecheck, lint, test, format, and circular checks.
Testing layout:
tests/native: component behavior and native style parsing.tests/web: web config, components, and HOC behavior.tests/type-test: public type expectations.tests/e2e: browser checks for web style extraction and generated artifacts.
Source-of-truth policy: repository code and tests win for implementation details. External docs at docs.uniwind.dev describe intended public behavior and should be updated when public behavior changes.
Engineering Constraints
- Runtime performance matters. Prefer build-time CSS processing and narrow runtime invalidation over broad recomputation.
- Preserve user style precedence when adding component wrappers.
- Keep native and web behavior aligned unless platform constraints require divergence.
- Any new runtime dependency should map to
StyleDependencyand invalidate only affected subscribers. - Theme-aware changes must account for global theme, adaptive system theme, and
ScopedTheme. - CSS variables must keep lazy getter semantics on native because values may depend on current runtime state.
- Avoid introducing compatibility paths without known consumers or persisted behavior.
- Add tests for native, web, and types when changing public API or cross-platform behavior.