@azranazwer/rn-ui
v1.0.0
Published
A React Native component library using Atomic Design — colors, fonts, scale utils, and i18n are injected per project.
Maintainers
Readme
@azranazwer/rn-ui
React Native component library built with Atomic Design.
Install once. Use everywhere. Bring your own theme, fonts, and colors.
Installation
npm install @azranazwer/rn-ui
# or
yarn add @azranazwer/rn-uiSetup — Inject your project's theme
The library has no hardcoded colors or fonts. Every project feeds in its own resolved theme via ThemeProvider.
// App.tsx
import { ThemeProvider } from '@azranazwer/rn-ui';
import { FONT_FAMILY } from '~/assets/fonts';
import { useAppStore } from '~/stores/appStore';
import {
SURFACE_DARK, SURFACE_LIGHT,
BACKGROUND_DARK, BACKGROUND_LIGHT,
BACKGROUND_STATE_DARK, BACKGROUND_STATE_LIGHT,
CONTENT_DARK, CONTENT_LIGHT,
CONTENT_STATE_DARK, CONTENT_STATE_LIGHT,
BORDER_DARK, BORDER_LIGHT,
BORDER_STATE_DARK, BORDER_STATE_LIGHT,
BACKGROUND_BRAND_DARK, BACKGROUND_BRAND_LIGHT,
CONTENT_BRAND_DARK, CONTENT_BRAND_LIGHT,
BORDER_BRAND_DARK, BORDER_BRAND_LIGHT,
OVERLAY_DARK, OVERLAY_LIGHT,
} from '~/theme/colors';
export default function App() {
const isDarkMode = useAppStore(s => s.isDarkMode);
const theme = {
isDarkMode,
FONT_FAMILY,
SURFACE: isDarkMode ? SURFACE_DARK : SURFACE_LIGHT,
BACKGROUND: isDarkMode ? BACKGROUND_DARK : BACKGROUND_LIGHT,
BACKGROUND_STATE: isDarkMode ? BACKGROUND_STATE_DARK : BACKGROUND_STATE_LIGHT,
CONTENT: isDarkMode ? CONTENT_DARK : CONTENT_LIGHT,
CONTENT_STATE: isDarkMode ? CONTENT_STATE_DARK : CONTENT_STATE_LIGHT,
BORDER: isDarkMode ? BORDER_DARK : BORDER_LIGHT,
BORDER_STATE: isDarkMode ? BORDER_STATE_DARK : BORDER_STATE_LIGHT,
BACKGROUND_BRAND: isDarkMode ? BACKGROUND_BRAND_DARK : BACKGROUND_BRAND_LIGHT,
CONTENT_BRAND: isDarkMode ? CONTENT_BRAND_DARK : CONTENT_BRAND_LIGHT,
BORDER_BRAND: isDarkMode ? BORDER_BRAND_DARK : BORDER_BRAND_LIGHT,
OVERLAY: isDarkMode ? OVERLAY_DARK : OVERLAY_LIGHT,
};
return (
<ThemeProvider theme={theme}>
<RootNavigator />
</ThemeProvider>
);
}That's it — every component automatically picks up your colors and fonts.
Usage
import { Button, InputField, Card, AlertBanner, ListItem, SearchBar } from '@azranazwer/rn-ui';
export default function LoginScreen() {
return (
<Card variant="elevated" padding="lg">
<AlertBanner variant="info" message="Please sign in to continue." />
<InputField
label="Email"
placeholder="[email protected]"
keyboardType="email-address"
required
/>
<InputField
label="Password"
placeholder="••••••••"
secureTextEntry
required
/>
<Button label="Sign In" onPress={() => {}} fullWidth />
</Card>
);
}Components
⚛️ Atoms
| Component | Description | Theme tokens used |
|--------------|------------------------------------------------|----------------------------------------------|
| Button | Primary, secondary, outline, ghost, negative | BACKGROUND, BACKGROUND_STATE, CONTENT |
| AppText | Full typography scale (Display → Link) | CONTENT, CONTENT_STATE |
| Input | Text input with focus / error states | SURFACE, BORDER, BORDER_STATE, CONTENT_STATE |
| Avatar | Image or initials, 4 sizes | BACKGROUND, CONTENT |
| Badge | Status pill — info, positive, negative, notice | BACKGROUND_STATE, CONTENT_STATE |
| Divider | Horizontal separator | BORDER |
| Spinner | Loading indicator with centered option | BACKGROUND |
🧬 Molecules
| Component | Description | Theme tokens used |
|------------------|----------------------------------------------|-----------------------------------------------|
| Card | Elevated, outlined, or flat container | SURFACE, BORDER |
| InputField | Input + Label + Error message | CONTENT, CONTENT_STATE, BORDER_STATE |
| ListItem | Avatar + Title + Subtitle + Badge + Chevron | SURFACE, CONTENT |
| SearchBar | Input with search icon and clear button | SURFACE, BORDER, CONTENT, CONTENT_STATE |
| AlertBanner | Inline positive/negative/notice/info banner | BACKGROUND_STATE, BORDER_STATE, CONTENT_STATE |
| BannerMessage | Toast notifications via flash-message | BACKGROUND, BACKGROUND_STATE, CONTENT_STATE |
Typography
Typography is built from your project's font families and scales automatically using the company Figma base (390×844).
import { useTypography, useTheme } from '@azranazwer/rn-ui';
const MyScreen = () => {
const { Heading, Body, Label, BodyStrong, Link, Display } = useTypography();
const { CONTENT } = useTheme();
return (
<View>
<Text style={[Heading.M, { color: CONTENT.PRIMARY }]}>Page Title</Text>
<Text style={[Body.S, { color: CONTENT.SECONDARY }]}>Description</Text>
<Text style={[Label.XS, { color: CONTENT.TERTIARY }]}>Helper text</Text>
<Text style={[BodyStrong.M, { color: CONTENT.PRIMARY }]}>Bold body</Text>
<Text style={[Link.S, { color: CONTENT.LINK }]}>Tap here</Text>
</View>
);
};Or use the AppText atom:
import { AppText } from '@azranazwer/rn-ui';
<AppText group="Heading" scale="M" color="primary">Page Title</AppText>
<AppText group="Body" scale="S" color="secondary">Description</AppText>
<AppText group="Label" scale="XS" color="disabled">Helper text</AppText>Scale Utils & Dimensions
Shared across all projects — based on Figma base dimensions (390×844).
import { scale, verticalScale, moderateScale, CORNER_RADIUS, SECTION_CONTENT_SPACE, GAP } from '@azranazwer/rn-ui';
const styles = StyleSheet.create({
container: {
padding: SECTION_CONTENT_SPACE.M,
gap: GAP.M,
borderRadius: CORNER_RADIUS.L,
height: verticalScale(56),
},
});Banner Message (Toast)
Requires react-native-flash-message and react-native-vector-icons.
// App.tsx — initialize once, re-run on dark/light change
import { initBannerMessage } from '@azranazwer/rn-ui';
import { FONT_FAMILY } from '~/assets/fonts';
import i18n from '~/i18n';
useEffect(() => {
initBannerMessage(resolvedTheme, FONT_FAMILY, i18n.t('flightBooking.undo'));
}, [isDarkMode]);// Anywhere in the app
import { showBannerMessage } from '@azranazwer/rn-ui';
showBannerMessage({ title: 'Saved!', type: 'success' });
showBannerMessage({ title: 'Failed', description: 'Try again.', type: 'error' });
showBannerMessage({ title: 'Item deleted', type: 'undo', onUndoPress: () => restore() });Using theme tokens in your own components
import { useTheme, useTypography } from '@azranazwer/rn-ui';
export const MyComponent = () => {
const { BACKGROUND, CONTENT, BORDER, SURFACE } = useTheme();
const { Heading, Body } = useTypography();
return (
<View style={{ backgroundColor: SURFACE.L1, borderColor: BORDER.TERTIARY }}>
<Text style={[Heading.S, { color: CONTENT.PRIMARY }]}>Title</Text>
<Text style={[Body.M, { color: CONTENT.SECONDARY }]}>Body</Text>
</View>
);
};What each project provides vs what the library owns
| Token | Owned by |
|---|---|
| scale, verticalScale, moderateScale | Library — fixed Figma base (390×844) |
| CORNER_RADIUS, SECTION_CONTENT_SPACE, GAP | Library — same across all projects |
| Typography sizes, line-heights, RTL adjustments | Library |
| FONT_FAMILY (Regular, Medium, SemiBold, Bold) | Each project |
| All color tokens (BACKGROUND, CONTENT, BORDER…) | Each project |
Peer Dependencies
{
"react": ">=18.0.0",
"react-native": ">=0.72.0",
"react-native-flash-message": ">=0.3.0",
"react-native-vector-icons": ">=10.0.0"
}react-native-flash-message and react-native-vector-icons are optional — only needed if you use showBannerMessage.
Publishing a new version
npm version patch # bug fix → 1.0.1
npm version minor # new component → 1.1.0
npm version major # breaking change → 2.0.0
npm publishAuthor
Azran Azwer — npmjs.com/~azranazwer
