@scripturecoder/rn-alpha-ui
v0.3.5
Published
Extracted React Native UI component library from @scripturecoder/rn-alpha-ui.
Readme
@scripturecoder/rn-alpha-ui
Reusable React Native UI components extracted from @scripturecoder/rn-alpha.
This package exposes themed building blocks (buttons, inputs, modals, sheets, list primitives, etc.) without the original data layer dependencies.
Installation
npm install @scripturecoder/rn-alpha-ui
# or
yarn add @scripturecoder/rn-alpha-uiThat installs only the UI library (good when the native dependencies already exist in your app).
If you haven’t configured the bundled native modules yet, you can install them alongside the library in one go:
npm install @scripturecoder/rn-alpha-ui @d11/[email protected] country-code-emoji dayjs [email protected] react-native-indicators react-native-linear-gradient react-native-material-menu react-native-otp-entry react-native-safe-area-context [email protected] react-native-keyboard-controller react-native-reanimated
# or
yarn add @scripturecoder/rn-alpha-ui @d11/[email protected] country-code-emoji dayjs [email protected] react-native-indicators react-native-linear-gradient react-native-material-menu react-native-otp-entry react-native-safe-area-context [email protected] react-native-keyboard-controller react-native-reanimatedYou'll also need the peer dependencies installed in your app (react, react-native) and should make sure any native modules (@gorhom/bottom-sheet, react-native-svg, react-native-linear-gradient, etc.) are properly configured.
Usage
Wrap your app with the provided color provider to get access to the built-in light/dark palette:
import React from 'react';
import { AlphaUIProvider, Button, Page } from '@scripturecoder/rn-alpha-ui';
const App = () => (
<AlphaUIProvider initialMode="light">
<Page>
<Button title="Tap me" onPress={() => { /* ... */ }} />
</Page>
</AlphaUIProvider>
);Every component consumes the useColor hook which reads from the AlphaUIProvider.
You can override the palette by passing a customColors object to the provider if you need to align with your brand.
Basic layout and typography
Most primitives mirror the React Native API, so you can compose them exactly as you would in a regular RN screen:
import React from 'react';
import { AlphaUIProvider, View, Text, ScrollView, Button } from '@scripturecoder/rn-alpha-ui';
const customColors = {
light: {
primary: '#3B82F6',
background: '#F9FBFF',
text: '#0F172A',
text2: '#334155',
},
dark: {
primary: '#60A5FA',
background: '#0F172A',
text: '#E2E8F0',
text2: '#94A3B8',
},
};
const componentProps = {
Text: {
size: 16,
},
Button: {
br: 8,
pv: 15,
},
};
const fontFamily = {
base: 'Inter', // Automatically generates Inter-Regular, Inter-Bold, etc.
};
export const ProfileScreen = () => (
<AlphaUIProvider
initialMode="light"
customColors={customColors}
componentProps={componentProps}
fontFamily={fontFamily}
>
<ScrollView contentContainerStyle={{ padding: 24 }}>
<View style={{ marginBottom: 16 }}>
<Text size={26} weight="ExtraBold" color="primary">Welcome back</Text>
<Text color="text2" weight="Light">
Tune the palette and component defaults by passing tokens into the provider.
</Text>
</View>
<View gap={12}>
<View padding={16} br={12} color="background">
<Text tt="uppercase" weight="Medium" color="text2">Balance</Text>
<Text size={22} weight="SemiBold" color="text">₦120,000.00</Text>
</View>
<Button
title="Make a transfer"
onPress={() => { /* navigation */ }}
color="primary"
/>
</View>
</ScrollView>
</AlphaUIProvider>
);Every layout primitive exposes typed props (color, weight, size, br, etc.) so you can reference theme tokens or pass inline values directly. Pair those with customColors and componentProps to keep styling consistent across the app.
Persisting the color mode
AlphaUIProvider can run uncontrolled (default) or in a controlled mode.
Provide the mode prop and an onModeChange handler to let your app keep the theme in state or storage:
import React from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AlphaUIProvider, Page, Button, ColorModes } from '@scripturecoder/rn-alpha-ui';
const App = () => {
const [mode, setMode] = React.useState<ColorModes>('light');
React.useEffect(() => {
AsyncStorage.getItem('theme-mode').then((value) => {
if (value === 'light' || value === 'dark') {
setMode(value);
}
});
}, []);
const handleModeChange = React.useCallback((next: ColorModes) => {
setMode(next);
AsyncStorage.setItem('theme-mode', next).catch(() => {});
}, []);
return (
<AlphaUIProvider mode={mode} onModeChange={handleModeChange}>
<Page>
<Button title="Toggle theme" onPress={() => handleModeChange(mode === 'light' ? 'dark' : 'light')} />
</Page>
</AlphaUIProvider>
);
};Any component that calls setColorMode from the context now triggers your handler, so the consuming app can persist the choice however it prefers.
Font Family Configuration
Configure your app's font family globally through the fontFamily prop:
Simple base font configuration - Just provide the base font name and the system will automatically generate weight variants:
<AlphaUIProvider fontFamily={{ base: 'Inter' }}>
<Text weight="Bold">Uses Inter-Bold</Text>
<Text weight="Regular">Uses Inter-Regular</Text>
<Text weight="Light">Uses Inter-Light</Text>
</AlphaUIProvider>Full explicit configuration - Specify each font weight individually:
<AlphaUIProvider
fontFamily={{
regular: 'Inter-Regular',
bold: 'Inter-Bold',
semiBold: 'Inter-SemiBold',
light: 'Inter-Light',
medium: 'Inter-Medium',
extraLight: 'Inter-ExtraLight',
italic: 'Inter-Italic',
extraBold: 'Inter-ExtraBold',
}}
>
{children}
</AlphaUIProvider>Mixed configuration - Use base font with specific overrides:
<AlphaUIProvider
fontFamily={{
base: 'Inter', // Generates Inter-Regular, Inter-Light, etc.
bold: 'Inter-Heavy', // Override just the bold weight
italic: 'Inter-Italic-Special', // Override italic with custom name
}}
>
<Text weight="Bold">Uses Inter-Heavy</Text>
<Text weight="Regular">Uses Inter-Regular</Text>
<Text weight="Italic">Uses Inter-Italic-Special</Text>
</AlphaUIProvider>Custom font family - Use a completely custom font:
<AlphaUIProvider
fontFamily={{
base: 'Inter', // Generates Inter-Regular, Inter-Light, etc.
custom: 'Inter-Custom', // Custom font for special cases
}}
>
<Text weight="Regular">Uses Inter-Regular</Text>
<Text weight="Custom">Uses Inter-Custom</Text>
</AlphaUIProvider>Component-wide defaults
Pass componentProps to define default props for any component:
<AlphaUIProvider
componentProps={{
Text: {
size: 16,
color: 'text',
allowFontScaling: false,
},
Button: {
br: 8,
pv: 15,
weight: 'Bold',
},
View: {
br: 4,
},
}}
>
{children}
</AlphaUIProvider>All component instances will use these defaults as their starting point, but you can still override any prop locally:
// Uses defaults: size: 16, color: 'text'
<Text>Hello</Text>
// Overrides: size: 20, color: 'primary'
<Text size={20} color="primary">Hello</Text>This system works for all components in the library and provides a clean way to maintain consistent styling across your app.
Adaptive Font Sizing
The Text component supports adaptive font sizing that automatically scales based on screen dimensions. This ensures consistent text readability across different device sizes.
Basic adaptive sizing:
// Text automatically scales based on screen width
<Text adaptiveSize size={16}>
This text scales with screen size
</Text>Custom reference width:
// Use a different reference width for scaling
<Text adaptiveSize size={18} referenceWidth={320}>
Scaled for iPhone SE (320px reference)
</Text>With size constraints:
// Set minimum and maximum font sizes
<Text
adaptiveSize
size={20}
minSize={14}
maxSize={28}
>
Constrained adaptive sizing
</Text>Combined with other features:
<Text
adaptiveSize
size={16}
weight="Bold"
color="primary"
adjustsFontSizeToFit
>
Adaptive text with other features
</Text>How it works:
- Uses a reference screen width (default: 375px - iPhone 11 width)
- Calculates scale factor:
currentWidth / referenceWidth - Applies PixelRatio for pixel-perfect rendering
- Includes device-specific adjustments (95% for small devices, 105% for large devices)
- Clamps values between
minSizeandmaxSizeprops
Props:
adaptiveSize?: boolean- Enable/disable adaptive sizingreferenceWidth?: number- Reference width for scaling (default: 375)minSize?: number- Minimum font size (default: 12)maxSize?: number- Maximum font size (default: 32)
LinearGradient Component
The LinearGradient component provides a flexible way to create gradient backgrounds with support for multiple directions and custom colors:
import { LinearGradient, Text } from '@scripturecoder/rn-alpha-ui';
// Basic usage with theme colors
<LinearGradient>
<Text>Hello World</Text>
</LinearGradient>
// Custom colors and direction
<LinearGradient
colors={['#FF6B6B', '#4ECDC4']}
direction="diagonal-down"
br={20}
pv={20}
>
<Text>Custom Gradient</Text>
</LinearGradient>
// With layout props
<LinearGradient
width="100%"
height={200}
direction="to-right"
mv={10}
ph={20}
>
<Text>Full width gradient</Text>
</LinearGradient>
// Using shortened props (w, h, p, m, size)
<LinearGradient
w="100%"
h={200}
direction="to-right"
m={10}
p={20}
>
<Text>Shortened props</Text>
</LinearGradient>
// Using size for both width and height
<LinearGradient
size={100}
direction="diagonal-down"
br={50}
>
<Text>Square gradient</Text>
</LinearGradient>
// Custom start/end points
<LinearGradient
colors={['primary', 'secondary']}
start={{x: 0, y: 0}}
end={{x: 1, y: 1}}
locations={[0, 0.5, 1]}
>
<Text>Custom gradient</Text>
</LinearGradient>Available directions:
to-right(default)to-leftto-topto-bottomto-top-rightto-top-leftto-bottom-rightto-bottom-leftdiagonal-updiagonal-down
Props:
colors- Array of colors (supports theme colors like 'primary', 'secondary')direction- Predefined gradient directionstart/end- Custom start and end points for precise controllocations- Array of numbers (0-1) to control color stopsradius/borderRadius- Border radius styling- Layout props:
width/w,height/h,size(sets both width and height),flex - Padding props:
padding/p,pv,ph,pt,pb,pl,pr - Margin props:
margin/m,mv,mh,mt,mb,ml,mr
Component Examples
Layout Components
View with styling props:
import { View, Text } from '@scripturecoder/rn-alpha-ui';
<View
flex={1}
padding={20}
br={12}
color="background"
center
>
<Text>Centered content</Text>
</View>ScrollView with content padding:
import { ScrollView, View, Text } from '@scripturecoder/rn-alpha-ui';
<ScrollView
contentPadding={20}
contentPaddingHorizontal={16}
contentPaddingVertical={24}
>
<View>
<Text>Scrollable content</Text>
</View>
</ScrollView>SafeAreaView with custom edges:
import { SafeAreaView, Text } from '@scripturecoder/rn-alpha-ui';
<SafeAreaView
edges={['top', 'left', 'right']}
color="background"
>
<Text>Safe area content</Text>
</SafeAreaView>Input Components
Basic Input:
import { Input, View } from '@scripturecoder/rn-alpha-ui';
const [value, setValue] = useState('');
<Input
label="Email"
placeholder="Enter your email"
value={value}
onChangeText={setValue}
keyboardType="email-address"
autoCapitalize="none"
/>Password Input:
import { Password } from '@scripturecoder/rn-alpha-ui';
<Password
label="Password"
placeholder="Enter password"
value={password}
onChangeText={setPassword}
/>Select Dropdown:
import { Select } from '@scripturecoder/rn-alpha-ui';
const options = [
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
{ label: 'Option 3', value: '3' },
];
<Select
label="Choose option"
options={options}
onChange={(data) => console.log(data)}
search
/>Date/Time Input:
import { DateSelect, DateTimeInput } from '@scripturecoder/rn-alpha-ui';
// Date only
<DateSelect
label="Birth Date"
value={date}
onChangeText={setDate}
minimumDate={new Date('1900-01-01')}
/>
// Date and time
<DateTimeInput
label="Appointment"
value={dateTime}
onChangeText={setDateTime}
mode="date" // or "time"
/>Search Input:
import { SearchInput } from '@scripturecoder/rn-alpha-ui';
<SearchInput
filter={searchTerm}
setFilter={setSearchTerm}
placeholder="Search..."
onSubmit={(value) => console.log('Search:', value)}
/>OTP Input:
import { OtpInput } from '@scripturecoder/rn-alpha-ui';
<OtpInput
length={6}
onComplete={(otp) => console.log('OTP:', otp)}
/>Button Components
Basic Button:
import { Button } from '@scripturecoder/rn-alpha-ui';
<Button
title="Click me"
onPress={() => console.log('Pressed')}
color="primary"
size={16}
weight="Bold"
/>Button with icon:
<Button
title="Save"
icon="save"
iconSize={20}
onPress={handleSave}
loading={isLoading}
/>Icon Button:
import { IconBtn } from '@scripturecoder/rn-alpha-ui';
<IconBtn
icon="heart"
size={24}
color="danger"
onPress={handleLike}
/>FAB Button:
import { FabButton } from '@scripturecoder/rn-alpha-ui';
<FabButton
icon="plus"
onPress={handleAdd}
color="primary"
/>Modal Components
Alert Modal:
import { AlertModal } from '@scripturecoder/rn-alpha-ui';
<AlertModal
modal={showAlert}
setModal={setShowAlert}
title="Confirm Action"
text="Are you sure you want to continue?"
color="warning"
confirm="Yes"
cancel="No"
onConfirm={handleConfirm}
onCancel={handleCancel}
/>Option Modal:
import { OptionModal } from '@scripturecoder/rn-alpha-ui';
const options = [
{ label: 'Edit', icon: 'edit', onPress: handleEdit },
{ label: 'Delete', icon: 'delete', color: 'danger', onPress: handleDelete },
{ label: 'Share', icon: 'share', onPress: handleShare },
];
<OptionModal
modal={showOptions}
setModal={setShowOptions}
options={options}
/>Custom Modal:
import { Modal } from '@scripturecoder/rn-alpha-ui';
<Modal
modal={showModal}
setModal={setShowModal}
full
enableSwipeToClose
>
<View padding={20}>
<Text>Custom modal content</Text>
</View>
</Modal>List Components
FlatList with custom styling:
import { FlatList, View, Text } from '@scripturecoder/rn-alpha-ui';
<FlatList
data={items}
renderItem={({ item }) => (
<View padding={16} br={8} color="background">
<Text>{item.title}</Text>
</View>
)}
keyExtractor={(item) => item.id}
contentPadding={16}
refreshColor="primary"
/>Form Components
Checkbox:
import { Checkbox, View, Text } from '@scripturecoder/rn-alpha-ui';
<View flexDirection="row" alignItems="center">
<Checkbox
selected={isChecked}
setSelected={setIsChecked}
color="primary"
/>
<Text marginLeft={8}>I agree to terms</Text>
</View>Switch:
import { Switch } from '@scripturecoder/rn-alpha-ui';
<Switch
active={isEnabled}
onToggle={setIsEnabled}
disabled={false}
/>Utility Components
Loader:
import { Loader } from '@scripturecoder/rn-alpha-ui';
<Loader
loading={isLoading}
text="Loading..."
color="primary"
/>Progress Bar:
import { ProgressBar } from '@scripturecoder/rn-alpha-ui';
<ProgressBar
progress={0.7}
color="primary"
background="light"
height={8}
radius={4}
/>Empty State:
import { EmptyState } from '@scripturecoder/rn-alpha-ui';
<EmptyState
title="No items found"
text="Try adjusting your search criteria"
icon="search"
/>Error View:
import { ErrorView } from '@scripturecoder/rn-alpha-ui';
<ErrorView
error="Something went wrong"
onRetry={handleRetry}
/>Advanced Usage
Custom Page with status bar:
import { Page, View, Text } from '@scripturecoder/rn-alpha-ui';
<Page
statusBarStyle="light-content"
statusBarColor="primary"
edgeToEdge
safeAreaMode="auto"
>
<View flex={1} padding={20}>
<Text>Page content</Text>
</View>
</Page>Keyboard avoiding view:
import { KeyboardView, View, Input } from '@scripturecoder/rn-alpha-ui';
<KeyboardView behavior="padding">
<View flex={1} padding={20}>
<Input label="Name" />
<Input label="Email" />
</View>
</KeyboardView>Menu component:
import { Menu, Button } from '@scripturecoder/rn-alpha-ui';
<Menu
anchor={<Button title="Menu" />}
options={[
{ label: 'Option 1', onPress: handleOption1 },
{ label: 'Option 2', onPress: handleOption2 },
]}
color="primary"
/>Icons Usage
The package includes a comprehensive set of SVG icons that can be imported and used in your components:
Importing individual icons:
import {
check,
arrowLeft,
arrowRight,
contact,
calender,
notification,
cancel,
// ... and many more
} from '@scripturecoder/rn-alpha-ui';
const MyComponent = () => (
<View>
<Text>Icons are available as SVG strings</Text>
{/* Use with Svg component */}
<Svg icon={check} size={24} color="success" />
<Svg icon={arrowLeft} size={20} color="primary" />
</View>
);Using icons with the Svg component:
import { Svg, check, arrowLeft, contact } from '@scripturecoder/rn-alpha-ui';
// Basic usage
<Svg icon={check} size={24} color="success" />
// With custom styling
<Svg
icon={arrowLeft}
size={20}
color="primary"
w={30}
h={30}
/>
// In buttons
<Button
title="Back"
icon={arrowLeft}
onPress={handleBack}
/>Available icons include:
- Navigation:
arrowLeft,arrowRight,selectToggle - Actions:
check,cancel,contact - UI Elements:
calender,notification - And many more...
Using icons in custom components:
import { check, arrowLeft } from '@scripturecoder/rn-alpha-ui';
const CustomIcon = ({ name, size = 24, color = 'currentColor' }) => {
const iconMap = {
check,
arrowLeft,
// Add more as needed
};
const iconSvg = iconMap[name];
if (!iconSvg) return null;
return (
<Svg
icon={iconSvg}
size={size}
color={color}
/>
);
};Hooks Usage
useColor hook:
import { useColor } from '@scripturecoder/rn-alpha-ui';
const MyComponent = () => {
const { colors, colorMode, setColorMode } = useColor();
return (
<View color={colors.primary}>
<Text>Current mode: {colorMode}</Text>
</View>
);
};useDimensions hook:
import { useDimensions } from '@scripturecoder/rn-alpha-ui';
const MyComponent = () => {
const { width, height, isBigDevice } = useDimensions();
return (
<Text>
Screen: {width}x{height} - {isBigDevice ? 'Big' : 'Small'} device
</Text>
);
};usePageConfig hook:
import { usePageConfig } from '@scripturecoder/rn-alpha-ui';
const MyComponent = () => {
const { insets, colors, isEdgeToEdge } = usePageConfig({
edgeToEdge: true,
statusBarColor: 'primary'
});
return (
<View paddingTop={insets.top}>
<Text>Content with safe area</Text>
</View>
);
};Building
npm run buildThe compiled output is emitted to dist/ and includes CommonJS, ESModule and type definition bundles generated via tsup.
