UNPKG

rn-variant

Version:

Light-weight, type-safe style variants for React Native.

134 lines (103 loc) 3.95 kB
# rn-variant Light-weight, type-safe style variants for React Native. Inspired by [Class Variance Authority](https://github.com/joe-bell/cva) and [Unistyle](https://github.com/jpudysz/react-native-unistyles), rn-variant lets you declare, combine and re-use complex styling options—with zero runtime dependencies.## Features • Tiny & dependency-free – just TypeScript + StyleSheet. • Multi-variant syntax – compose size, color, state, etc. • Compound variants – attach styles to specific variant combos. • Boolean flags – declare rounded, disabled, etc. as simple booleans. • Strict typings – variant values are autocompleted and type-checked. • Hook-based API – const { style } = useVariants({ size: 'md', color: 'primary' }). ⸻ ## 📦 Installation ```bash npm install rn-variant # or yarn add rn-variant ``` ⸻ ## ⚡ Quick start ```typescript import { createVariantStyles } from "rn-variant"; /* 1. Declare your variants */ const buttonVariants = createVariantStyles({ base: { borderRadius: 6, alignItems: "center", justifyContent: "center", paddingVertical: 12, paddingHorizontal: 24, }, variants: { size: { sm: { paddingVertical: 8, paddingHorizontal: 16 }, md: { paddingVertical: 12, paddingHorizontal: 24 }, lg: { paddingVertical: 16, paddingHorizontal: 32 }, }, color: { primary: { backgroundColor: "#007bff" }, secondary: { backgroundColor: "#6c757d" }, outline: { backgroundColor: "transparent", borderWidth: 1, borderColor: "#007bff", }, }, rounded: { // boolean flag true: { borderRadius: 9999 }, false: {}, }, }, /* optional */ compoundVariants: [ { variants: { color: "primary", size: "lg" }, style: { shadowOpacity: 0.25, shadowRadius: 4 }, }, ], }); /* 2. Extract prop types (optional) */ import type { InferVariant } from "rn-variant"; export type ButtonVariantProps = InferVariant<typeof buttonVariants>; /* 3. Use in a component */ export const Button = ({ title, ...variant }: ButtonVariantProps & { title: string; onPress?: () => void }) => { const { style } = buttonVariants.useVariants(variant); return ( <TouchableOpacity style={style} onPress={variant.onPress}> <Text style={{ color: variant.color === "outline" ? "#007bff" : "#fff" }}> {title} </Text> </TouchableOpacity> ); }; ``` ⸻ ## API ### createVariantStyles(options) | option | type | default | description | | ------------------ | ------------------------------------------------------------------ | ------- | ---------------------------------------------- | | `base` | `Partial<ViewStyle \| TextStyle \| ImageStyle>` | `{}` | style applied to all variants | | `variants` | `Record<group, Record<key, Partial<RNStyle>>>` | — | top-level variant groups (e.g. size, color) | | `compoundVariants` | `Array<{ variants: Partial<variants>; style: Partial<RNStyle>; }>` | `[]` | extra style when all matching keys are present | Returns: ```typescript { styles: { [Group in keyof variants]: { [Key in keyof variants[Group]]: { style: RNStyle } } }; useVariants(input: VariantInput): { style: RNStyle }; } ``` ### useVariants(input) Accepts an object where keys are variant groups and values are: • a variant key ('lg', 'primary', …), orboolean when the group defines { true, false }. It merges base → individual variants → matching compoundVariants and returns { style } ready for `<View style={...} />`. ### InferVariant<typeof variants> Utility type that extracts the props shape expected by useVariants, handy for declaring component props. ⸻ ## 📄 License MIT © 2025 Simon Boisset