@runitbk/native
v0.1.1
Published
React Native components for the RunItBack design system, built on rn-primitives and NativeWind.
Readme
@runitbk/native
The React Native components. Same tokens, same design language as @runitbk/react;
NativeWind v5 does the styling, rn-primitives
supplies behavior where RN core has none.
Ships raw TypeScript — no build. Your app's Metro compiles it, which is also what lets NativeWind scan its class strings.
Wiring an app
The app owns the styling runtime. This package never depends on nativewind or
react-native-css — a second copy of that runtime crashes at startup (stack
overflow), so don't add them here, and don't add them to the workspace root.
Install
nativewind+react-native-css(exact pins — they ship as a coupled pair) plus this package. See the repo README's Native section for thereact-native-workletsandlightningcsspins and the vendoredreact-native-csstarball; all load-bearing. Note:react-native-cssmust shipdist/—nativewind/metrois loaded by Node and resolves it directly.metro.config.js: wrap withwithNativewind(config, { input: "./global.css" }).postcss.config.mjs: the@tailwindcss/postcssplugin, nothing else.global.css:@import "tailwindcss/theme.css" layer(theme); @import "tailwindcss/preflight.css" layer(base); @import "tailwindcss/utilities.css"; @import "nativewind/theme"; @import "@runitbk/styles/theme.css"; @import "@runitbk/styles/native.css"; @source "../node_modules/@runitbk/native/src"; /* adjust to where it resolves */ :root { font-size: 16px; } /* rem base; the compiler defaults to 14 */native.csscarries everything the components need beyond the tokens: the per-weight font families, theduration-*utilities, and thefade-in/pop-inmount keyframes. Without it, text renders in system fonts and overlays appear without animation.Load the faces with
useFontsfromexpo-font(@expo-google-fonts/ibm-plex-sans400/500/600,.../ibm-plex-mono400/500/600) and gate rendering on them —native.cssreferences those exact registered names.Wrap the app in
<ThemeProvider>—theme="system" | "light" | "dark". Light is the:rootbaseline; dark swaps the semantic variables, like web'sdata-theme.Render
<PortalHost />once, last inside the providers — menus, dialogs, popovers, and toasts mount into it.Only if you use
Drawer: install@gorhom/bottom-sheetandreact-native-gesture-handlerin the app (this package deliberately doesn't depend on them) and nest<Drawer.Provider>inside<ThemeProvider>:<ThemeProvider theme={theme}> <Drawer.Provider> {/* app */} <PortalHost /> </Drawer.Provider> </ThemeProvider>
How components differ from web
- No text inheritance:
<Text>carries the reading defaults; the type scale and tones are classNames (text-title,text-sub), exactly like web markup. - Weight rides the font family (
font-mono-medium), notfont-weight— loaded faces are one family per weight. hover:isactive:; focus rings are a border-color swap (focus:border-focus-ring).- State styling is prop-driven (
checked,disabled,invalid) — there are no data attributes on native.
Known parity gaps
- Checkbox has no indeterminate state (rn-primitives limitation).
- Field has no validation context — wire
invalidandField.Erroryourself. - Dark-mode shadows keep their light values (variable provider is colors-only so far).
- react-native-web is untested and unthemed; web apps use
@runitbk/react.
Contributing
src/themes.tsis generated — after changing the dark block in@runitbk/styles/tokens.css, runpnpm --filter @runitbk/native generate:themes.- Shared internals live in
src/shared.tsx(PlainChildren,clamp,useThemeColor,wrapLabel, menu icons); shared class strings inmenuClasses.tsandsurfaceClasses.ts. Add to those rather than redeclaring per component. - Verify with both type programs:
pnpm --filter @runitbk/native typecheckandnpx tsc --noEmitfromplayground/— they resolve types differently and both must pass.
