armia-rn-components
v1.10.0
Published
A collection of reusable React Native components and utilities
Maintainers
Readme
RN Components NPM
A collection of reusable React Native components and utilities built with TypeScript, designed to be easily integrated into any React Native project.
Features
- 🎨 Modern Design: Clean, consistent UI components following modern design principles
- 📱 React Native Optimized: Built specifically for React Native with performance in mind
- 🔧 TypeScript Support: Full TypeScript support with comprehensive type definitions
- 🎯 Highly Customizable: Extensive customization options for all components
- 🧪 Well Tested: Comprehensive test coverage for all components and utilities
- 📦 Tree Shakeable: Optimized for tree shaking to reduce bundle size
- 🚀 Ready for Production: Production-ready components with proper error handling
Installation
npm install armia-rn-components
# or
yarn add armia-rn-componentsQuick Start
import React, { useRef } from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
import { AlertView, AlertViewRef } from 'armia-rn-components';
const App = () => {
const alertRef = useRef<AlertViewRef>(null);
const showAlert = () => {
alertRef.current?.setValues(
'success',
'Success!',
'Your action was completed successfully.',
[
{ title: 'Cancel', onPress: () => console.log('Cancelled') },
{ title: 'OK', onPress: () => console.log('Confirmed') }
]
);
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity onPress={showAlert}>
<Text>Show Alert</Text>
</TouchableOpacity>
<AlertView ref={alertRef} />
</View>
);
};Components
Button
A highly customizable button component with support for multiple variants, sizes, loading states, icons, and comprehensive styling options.
Basic Usage
import React from 'react';
import { Button } from 'armia-rn-components';
const MyComponent = () => {
return (
<Button
text="Press Me"
onPress={() => console.log('Button pressed')}
/>
);
};Advanced Usage
import React, { useState } from 'react';
import { Button } from 'armia-rn-components';
const MyComponent = () => {
const [loading, setLoading] = useState(false);
const handlePress = async () => {
setLoading(true);
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 2000));
setLoading(false);
};
return (
<Button
text="Submit"
variant="filled"
size="large"
bgColor="#007AFF"
textColor="#FFFFFF"
leftIcon="📤"
loading={loading}
loadingText="Submitting..."
onPress={handlePress}
accessibilityLabel="Submit form button"
accessibilityHint="Submits the current form"
testID="submit-button"
/>
);
};Button Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| text | string | required | Button text content |
| loadingText | string | 'Loading...' | Text shown during loading state |
| bgColor | string | colors.primary | Background color |
| textColor | string | colors.white | Text color |
| borderColor | string | colors.primary | Border color for outline variant |
| loadingColor | string | colors.white | Loading indicator color |
| variant | 'filled' \| 'outline' \| 'ghost' | 'filled' | Button style variant |
| size | 'small' \| 'medium' \| 'large' \| 'custom' | 'medium' | Button size variant |
| fullWidth | boolean | true | Whether button takes full width |
| borderRadius | number | - | Custom border radius |
| paddingHorizontal | number | - | Custom horizontal padding |
| paddingVertical | number | - | Custom vertical padding |
| fontSize | number | - | Custom font size |
| fontWeight | TextStyle['fontWeight'] | - | Custom font weight |
| fontFamily | string | - | Custom font family |
| leftIcon | ImageSourcePropType | - | Left icon |
| rightIcon | ImageSourcePropType | - | Right icon |
| iconSize | number | 20 | Icon size |
| iconColor | string | - | Icon color |
| loading | boolean | false | Show loading state |
| disabled | boolean | false | Disable button |
| pressed | boolean | false | Pressed state |
| pressOpacity | number | 0.7 | Press opacity effect |
| pressScale | number | 0.98 | Press scale effect |
| showPressEffect | boolean | true | Show press effects |
| onPress | () => void | - | Press handler |
| onPressIn | () => void | - | Press in handler |
| onPressOut | () => void | - | Press out handler |
| onLongPress | () => void | - | Long press handler |
| containerStyle | ViewStyle | - | Container custom styles |
| textStyle | TextStyle | - | Text custom styles |
| accessible | boolean | true | Accessibility enabled |
| accessibilityLabel | string | - | Accessibility label |
| accessibilityHint | string | - | Accessibility hint |
| accessibilityRole | string | 'button' | Accessibility role |
| accessibilityState | object | - | Accessibility state |
| testID | string | - | Test identifier |
Button Variants
// Filled button (default)
<Button text="Filled Button" variant="filled" />
// Outline button
<Button text="Outline Button" variant="outline" borderColor="#007AFF" />
// Ghost button
<Button text="Ghost Button" variant="ghost" textColor="#007AFF" />Button Sizes
// Small button
<Button text="Small" size="small" />
// Medium button (default)
<Button text="Medium" size="medium" />
// Large button
<Button text="Large" size="large" />
// Custom size
<Button
text="Custom"
size="custom"
paddingHorizontal={32}
paddingVertical={16}
fontSize={18}
/>Loading States
// Basic loading
<Button text="Submit" loading={true} />
// Custom loading text
<Button text="Submit" loading={true} loadingText="Please wait..." />
// Loading with custom colors
<Button
text="Submit"
loading={true}
loadingColor="#FFFFFF"
bgColor="#007AFF"
/>Icon Support
// Left icon
<Button text="Download" leftIcon="⬇️" />
// Right icon
<Button text="Next" rightIcon="→" />
// Both icons
<Button text="Share" leftIcon="📤" rightIcon="📱" />
// Custom icon styling
<Button
text="Settings"
leftIcon="⚙️"
iconSize={24}
iconColor="#007AFF"
/>Press Effects
// Custom press opacity
<Button text="Press Me" pressOpacity={0.5} />
// Custom press scale
<Button text="Press Me" pressScale={0.95} />
// Disable press effects
<Button text="Press Me" showPressEffect={false} />Accessibility
<Button
text="Submit Form"
accessibilityLabel="Submit form button"
accessibilityHint="Submits the current form data"
accessibilityRole="button"
accessibilityState={{ disabled: false }}
/>Event Handlers
<Button
text="Interactive Button"
onPress={() => console.log('Pressed')}
onPressIn={() => console.log('Press in')}
onPressOut={() => console.log('Press out')}
onLongPress={() => console.log('Long pressed')}
/>Avatar
A highly customizable avatar component with support for images, fallback content, loading states, and comprehensive styling options.
Basic Usage
import React from 'react';
import { Avatar } from 'armia-rn-components';
const MyComponent = () => {
return (
<Avatar
size={60}
uri="https://example.com/profile.jpg"
accessibilityLabel="User profile picture"
/>
);
};Advanced Usage
import React from 'react';
import { Avatar } from 'armia-rn-components';
const MyComponent = () => {
const handleImageLoad = () => {
console.log('Image loaded successfully');
};
const handleImageError = (error: any) => {
console.log('Image failed to load:', error);
};
return (
<Avatar
size={80}
uri="https://example.com/profile.jpg"
rounded={true}
borderWidth={3}
borderColor="#007AFF"
backgroundColor="#F2F2F7"
fallbackText="JD"
fallbackBackgroundColor="#007AFF"
shadowColor="#000000"
shadowOffset={{ width: 0, height: 2 }}
shadowOpacity={0.25}
shadowRadius={3.84}
elevation={5}
resizeMode="cover"
showLoadingIndicator={true}
loadingIndicatorColor="#007AFF"
loadingIndicatorSize="small"
onLoad={handleImageLoad}
onError={handleImageError}
accessibilityLabel="John Doe's profile picture"
accessibilityHint="Shows user profile picture"
testID="user-avatar"
/>
);
};Avatar Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| size | number | required | Avatar size (width and height) |
| rounded | boolean | true | Whether to make the avatar circular |
| uri | string \| null | null | Remote image URI |
| localPath | ImageSourcePropType \| null | null | Local image source |
| placeholder | ImageSourcePropType | null | Placeholder image when no source provided |
| borderWidth | number | 0 | Border width |
| borderColor | string | 'transparent' | Border color |
| backgroundColor | string | '#E1E1E1' | Background color when no image |
| shadowColor | string | '#000000' | Shadow color |
| shadowOffset | {width: number, height: number} | {0, 2} | Shadow offset |
| shadowOpacity | number | 0.25 | Shadow opacity |
| shadowRadius | number | 3.84 | Shadow radius |
| elevation | number | 5 | Android elevation |
| resizeMode | ImageResizeMode | 'cover' | Image resize mode |
| onLoadStart | () => void | - | Called when image loading starts |
| onLoad | () => void | - | Called when image loads successfully |
| onLoadEnd | () => void | - | Called when image loading ends |
| onError | (error: any) => void | - | Called when image fails to load |
| showLoadingIndicator | boolean | true | Show loading indicator |
| loadingIndicatorColor | string | '#007AFF' | Loading indicator color |
| loadingIndicatorSize | 'small' \| 'large' | 'small' | Loading indicator size |
| customLoadingComponent | React.ComponentType<any> | - | Custom loading component |
| customErrorComponent | React.ComponentType<any> | - | Custom error component |
| errorText | string | 'Failed to load image' | Error message text |
| errorTextStyle | TextStyle | - | Error text styling |
| fallbackText | string | - | Fallback text when no image |
| fallbackTextStyle | TextStyle | - | Fallback text styling |
| fallbackBackgroundColor | string | '#CCCCCC' | Fallback background color |
| containerStyle | ViewStyle | - | Container custom styles |
| imageStyle | ImageStyle | - | Image custom styles |
| accessible | boolean | true | Accessibility enabled |
| accessibilityLabel | string | - | Accessibility label |
| accessibilityHint | string | - | Accessibility hint |
| accessibilityRole | string | 'image' | Accessibility role |
| testID | string | - | Test identifier |
Image Sources
The Avatar component supports multiple image sources with priority order:
- Local Path:
localPathprop for local images - Remote URI:
uriprop for remote images - Placeholder:
placeholderprop as fallback - Fallback Text: Text display when no image is available
// Local image
<Avatar size={50} localPath={require('./assets/profile.png')} />
// Remote image
<Avatar size={50} uri="https://example.com/profile.jpg" />
// With placeholder
<Avatar
size={50}
uri="https://example.com/profile.jpg"
placeholder={require('./assets/default-avatar.png')}
/>
// Fallback text only
<Avatar size={50} fallbackText="JD" />Loading States
// Custom loading component
const CustomLoader = ({ size }: { size: number }) => (
<View style={{ width: size, height: size, backgroundColor: '#F0F0F0' }}>
<Text>Loading...</Text>
</View>
);
<Avatar
size={50}
uri="https://example.com/profile.jpg"
customLoadingComponent={CustomLoader}
showLoadingIndicator={true}
loadingIndicatorColor="#007AFF"
loadingIndicatorSize="large"
/>Error Handling
// Custom error component
const CustomError = ({ size, error }: { size: number; error: string }) => (
<View style={{ width: size, height: size, backgroundColor: '#FFE0E0' }}>
<Text style={{ color: '#FF0000' }}>{error}</Text>
</View>
);
<Avatar
size={50}
uri="https://invalid-url.com/image.jpg"
customErrorComponent={CustomError}
errorText="Image not available"
onError={(error) => console.log('Image error:', error)}
/>Accessibility
<Avatar
size={50}
uri="https://example.com/profile.jpg"
accessible={true}
accessibilityLabel="John Doe's profile picture"
accessibilityHint="Shows user profile picture"
accessibilityRole="image"
/>BottomSheet
A highly customizable bottom sheet component with support for multiple positions, animations, swipe gestures, and comprehensive styling options.
Basic Usage
import React, { useState } from 'react';
import { BottomSheet } from 'armia-rn-components';
const MyComponent = () => {
const [visible, setVisible] = useState(false);
return (
<>
<TouchableOpacity onPress={() => setVisible(true)}>
<Text>Open Bottom Sheet</Text>
</TouchableOpacity>
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
>
<View style={{ padding: 20 }}>
<Text>Bottom Sheet Content</Text>
</View>
</BottomSheet>
</>
);
};Advanced Usage
import React, { useState } from 'react';
import { BottomSheet } from 'armia-rn-components';
const MyComponent = () => {
const [visible, setVisible] = useState(false);
return (
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
heightPercentage={70}
backgroundColor="#F8F9FA"
overlayColor="#000000"
overlayOpacity={0.6}
borderRadius={20}
showHandle={true}
handleColor="#CCCCCC"
handleSize={{ width: 50, height: 6 }}
animationType="slide"
animationDuration={400}
position="bottom"
disableBackdropPress={false}
disableSwipeToClose={false}
swipeThreshold={150}
padding={24}
paddingHorizontal={20}
paddingVertical={16}
testID="custom-bottom-sheet"
>
<View style={{ flex: 1 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 16 }}>
Custom Bottom Sheet
</Text>
<Text>
This bottom sheet has custom height, colors, animation, and handle.
</Text>
</View>
</BottomSheet>
);
};BottomSheet Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| visible | boolean | required | Whether the bottom sheet is visible |
| onClose | () => void | required | Function called when bottom sheet closes |
| children | React.ReactNode | required | Content to display in the bottom sheet |
| height | number \| string | - | Fixed height of the bottom sheet |
| maxHeight | number \| string | - | Maximum height of the bottom sheet |
| heightPercentage | number | 80 | Height as percentage of screen (0-100) |
| backgroundColor | string | colors.white | Background color of the bottom sheet |
| overlayColor | string | colors.black | Color of the backdrop overlay |
| overlayOpacity | number | 0.5 | Opacity of the backdrop overlay |
| borderRadius | number | - | Border radius for all corners |
| borderTopLeftRadius | number | 10 | Top-left corner radius |
| borderTopRightRadius | number | 10 | Top-right corner radius |
| borderBottomLeftRadius | number | - | Bottom-left corner radius |
| borderBottomRightRadius | number | - | Bottom-right corner radius |
| showHandle | boolean | true | Whether to show the drag handle |
| handleColor | string | colors.gray[400] | Color of the drag handle |
| handleSize | {width: number, height: number} | {40, 5} | Size of the drag handle |
| handleStyle | ViewStyle | - | Custom styles for the handle |
| animationType | 'slide' \| 'fade' \| 'none' | 'slide' | Animation type for opening/closing |
| animationDuration | number | 300 | Duration of animations in milliseconds |
| position | 'bottom' \| 'top' \| 'center' | 'bottom' | Position of the bottom sheet |
| disableBackdropPress | boolean | false | Disable closing on backdrop press |
| disableSwipeToClose | boolean | false | Disable swipe-to-close gesture |
| swipeThreshold | number | 100 | Distance to swipe to trigger close |
| padding | number | 20 | Internal padding |
| paddingHorizontal | number | - | Horizontal padding |
| paddingVertical | number | - | Vertical padding |
| paddingTop | number | - | Top padding |
| paddingBottom | number | - | Bottom padding |
| paddingLeft | number | - | Left padding |
| paddingRight | number | - | Right padding |
| containerStyle | ViewStyle | - | Custom styles for the modal container |
| contentStyle | ViewStyle | - | Custom styles for the content container |
| overlayStyle | ViewStyle | - | Custom styles for the backdrop overlay |
| testID | string | - | Test identifier |
Height Control
// Percentage-based height
<BottomSheet heightPercentage={60} />
// Fixed height
<BottomSheet height={400} />
// Maximum height
<BottomSheet maxHeight="80%" />
// Custom height with percentage
<BottomSheet height="70%" />Position Options
// Bottom position (default)
<BottomSheet position="bottom" />
// Top position
<BottomSheet position="top" />
// Center position
<BottomSheet position="center" />Animation Types
// Slide animation (default)
<BottomSheet animationType="slide" />
// Fade animation
<BottomSheet animationType="fade" />
// No animation
<BottomSheet animationType="none" />
// Custom animation duration
<BottomSheet animationType="slide" animationDuration={500} />Handle Customization
// Hide handle
<BottomSheet showHandle={false} />
// Custom handle color
<BottomSheet handleColor="#FF0000" />
// Custom handle size
<BottomSheet handleSize={{ width: 60, height: 8 }} />
// Custom handle styles
<BottomSheet
handleStyle={{
backgroundColor: '#FF0000',
borderRadius: 10
}}
/>Backdrop Behavior
// Disable backdrop press
<BottomSheet disableBackdropPress={true} />
// Disable swipe to close
<BottomSheet disableSwipeToClose={true} />
// Custom swipe threshold
<BottomSheet swipeThreshold={200} />Padding Control
// Uniform padding
<BottomSheet padding={24} />
// Separate horizontal and vertical padding
<BottomSheet
paddingHorizontal={20}
paddingVertical={16}
/>
// Individual padding values
<BottomSheet
paddingTop={16}
paddingBottom={24}
paddingLeft={20}
paddingRight={20}
/>Custom Styling
<BottomSheet
containerStyle={{
backgroundColor: 'rgba(0, 0, 0, 0.8)',
}}
contentStyle={{
backgroundColor: '#FFFFFF',
shadowColor: '#000000',
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
}}
overlayStyle={{
backgroundColor: 'rgba(0, 0, 0, 0.6)',
}}
/>Accessibility
<BottomSheet
visible={visible}
onClose={() => setVisible(false)}
testID="bottom-sheet"
>
<View accessible={true} accessibilityLabel="Bottom sheet content">
<Text>Accessible content</Text>
</View>
</BottomSheet>TextInput
A highly customizable, feature-rich TextInput component with built-in validation, icons, password functionality, input masking, and accessibility support.
Basic Usage
import React from 'react';
import { TextInput } from 'armia-rn-components';
const MyComponent = () => {
return (
<TextInput
placeholder="Enter your name"
label="Full Name"
onChangeText={(text) => console.log(text)}
/>
);
};Advanced Usage
import React, { useState } from 'react';
import { TextInput } from 'armia-rn-components';
const MyComponent = () => {
const [formData, setFormData] = useState({
email: '',
password: '',
phone: '',
});
return (
<View>
<TextInput
placeholder="Enter email"
label="Email Address"
value={formData.email}
onChangeText={(text) => setFormData(prev => ({ ...prev, email: text }))}
leftIcon={{ source: '📧', size: 20, color: '#007AFF' }}
keyboardType="email-address"
autoCapitalize="none"
validationRules={[
{ type: 'required', message: 'Email is required' },
{ type: 'email', message: 'Please enter a valid email' }
]}
validateOnBlur
onValidationChange={(isValid, errors) => console.log(errors)}
/>
<TextInput
placeholder="Enter password"
label="Password"
value={formData.password}
onChangeText={(text) => setFormData(prev => ({ ...prev, password: text }))}
isPassword
showPasswordToggle
leftIcon={{ source: '🔒', size: 20, color: '#007AFF' }}
validationRules={[
{ type: 'required', message: 'Password is required' },
{ type: 'minLength', value: 8, message: 'Minimum 8 characters' }
]}
validateOnBlur
/>
<TextInput
placeholder="Enter phone number"
label="Phone Number"
value={formData.phone}
onChangeText={(text) => setFormData(prev => ({ ...prev, phone: text }))}
keyboardType="phone-pad"
inputMask={{ pattern: '(###) ###-####', separator: '-' }}
validationRules={[
{ type: 'required', message: 'Phone number is required' },
{ type: 'phone', message: 'Please enter a valid phone number' }
]}
validateOnBlur
/>
</View>
);
};TextInput Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| label | string | - | Label text displayed above the input |
| placeholder | string | - | Placeholder text |
| value | string | - | Controlled input value |
| defaultValue | string | - | Default input value |
| containerStyle | ViewStyle | - | Custom container styles |
| inputStyle | TextStyle | - | Custom input text styles |
| labelStyle | TextStyle | - | Custom label styles |
| errorStyle | TextStyle | - | Custom error text styles |
| helperTextStyle | TextStyle | - | Custom helper text styles |
| backgroundColor | string | colors.surface | Input background color |
| borderColor | string | colors.border | Default border color |
| focusBorderColor | string | colors.primary | Border color when focused |
| errorBorderColor | string | colors.error | Border color when error |
| placeholderTextColor | string | colors.textTertiary | Placeholder text color |
| textColor | string | colors.textPrimary | Input text color |
| labelColor | string | colors.textSecondary | Label text color |
| errorColor | string | colors.error | Error text color |
| helperTextColor | string | colors.textTertiary | Helper text color |
| borderWidth | number | 1 | Default border width |
| borderRadius | number | spacingUtils.borderRadius.md | Border radius |
| focusBorderWidth | number | 2 | Border width when focused |
| errorBorderWidth | number | 1 | Border width when error |
| paddingHorizontal | number | spacingUtils.input.paddingHorizontal | Horizontal padding |
| paddingVertical | number | spacingUtils.input.paddingVertical | Vertical padding |
| marginHorizontal | number | 0 | Horizontal margin |
| marginVertical | number | 0 | Vertical margin |
| fontSize | number | typography.fontSize.md | Input text font size |
| fontWeight | TextStyle['fontWeight'] | typography.fontWeight.regular | Input text font weight |
| fontFamily | string | - | Input text font family |
| labelFontSize | number | typography.fontSize.sm | Label font size |
| labelFontWeight | TextStyle['fontWeight'] | typography.fontWeight.medium | Label font weight |
| errorFontSize | number | typography.fontSize.xs | Error text font size |
| leftIcon | IconConfig | - | Left icon configuration |
| rightIcon | IconConfig | - | Right icon configuration |
| showPasswordIcon | IconConfig | - | Custom show password icon |
| hidePasswordIcon | IconConfig | - | Custom hide password icon |
| isPassword | boolean | false | Enable password mode |
| showPasswordToggle | boolean | true | Show password visibility toggle |
| maxLength | number | - | Maximum character limit |
| minLength | number | - | Minimum character limit |
| showCharacterCount | boolean | false | Show character count display |
| characterCountStyle | TextStyle | - | Character count text styles |
| validationRules | ValidationRule[] | [] | Array of validation rules |
| validateOnBlur | boolean | true | Validate on blur event |
| validateOnChange | boolean | false | Validate on change event |
| showValidationErrors | boolean | true | Show validation error messages |
| autoFocus | boolean | false | Auto focus on mount |
| blurOnSubmit | boolean | true | Blur on submit |
| returnKeyType | RNTextInputProps['returnKeyType'] | 'default' | Return key type |
| autoCapitalize | RNTextInputProps['autoCapitalize'] | 'sentences' | Auto capitalize |
| autoCorrect | RNTextInputProps['autoCorrect'] | true | Auto correct |
| autoComplete | RNTextInputProps['autoComplete'] | - | Auto complete |
| textContentType | RNTextInputProps['textContentType'] | - | Text content type |
| inputMask | InputMask | - | Input mask configuration |
| disabled | boolean | false | Disable the input |
| readonly | boolean | false | Make input readonly |
| error | string | - | External error message |
| helperText | string | - | Helper text below input |
| isTouched | boolean | false | Mark input as touched |
| onChangeText | (text: string) => void | - | Text change handler |
| onBlur | (e: any) => void | - | Blur event handler |
| onFocus | (e: any) => void | - | Focus event handler |
| onSubmitEditing | (e: any) => void | - | Submit editing handler |
| onValidationChange | (isValid: boolean, errors: string[]) => void | - | Validation change handler |
| enableFocusAnimation | boolean | true | Enable focus animations |
| focusAnimationDuration | number | 200 | Focus animation duration |
| errorAnimationDuration | number | 300 | Error animation duration |
| accessible | boolean | true | Accessibility enabled |
| accessibilityLabel | string | - | Accessibility label |
| accessibilityHint | string | - | Accessibility hint |
| accessibilityRole | string | 'text' | Accessibility role |
| accessibilityState | object | - | Accessibility state |
| testID | string | - | Test identifier |
Validation Rules
// Required field
{ type: 'required', message: 'This field is required' }
// Email validation
{ type: 'email', message: 'Please enter a valid email address' }
// Phone validation
{ type: 'phone', message: 'Please enter a valid phone number' }
// URL validation
{ type: 'url', message: 'Please enter a valid URL' }
// Minimum length
{ type: 'minLength', value: 5, message: 'Minimum 5 characters required' }
// Maximum length
{ type: 'maxLength', value: 100, message: 'Maximum 100 characters allowed' }
// Regex pattern
{ type: 'pattern', value: '^[a-zA-Z0-9_]+$', message: 'Only letters, numbers, and underscores allowed' }
// Custom validation
{
type: 'custom',
validator: (value) => {
const age = parseInt(value);
if (age < 18) return 'You must be at least 18 years old';
return true;
},
}Input Masks
// Phone number: (123) 456-7890
{ pattern: '(###) ###-####', separator: '-' }
// Date: MM/DD/YYYY
{ pattern: '##/##/####', separator: '/' }
// Time: HH:MM
{ pattern: '##:##', separator: ':' }
// Credit card: 1234 5678 9012 3456
{ pattern: '#### #### #### ####', separator: ' ' }
// Zip code: 12345
{ pattern: '#####' }
// Social security: 123-45-6789
{ pattern: '###-##-####', separator: '-' }Icon Configuration
// Basic icon
{ source: '🔍', size: 20, color: '#007AFF' }
// Pressable icon
{
source: '❌',
size: 16,
color: '#FF0000',
pressable: true,
onPress: () => setValue(''),
}
// Custom password icons
{
showPasswordIcon: { source: '👁️', size: 24 },
hidePasswordIcon: { source: '🙈', size: 24 },
}Character Count
<TextInput
placeholder="Tell us about yourself"
label="Bio"
multiline
numberOfLines={3}
maxLength={200}
showCharacterCount
helperText="Share a bit about yourself"
/>Custom Styled Input
<TextInput
placeholder="Custom styled input"
label="Custom Style"
backgroundColor="#F2F2F7"
borderColor="#007AFF"
focusBorderColor="#5856D6"
borderRadius={20}
paddingHorizontal={20}
paddingVertical={15}
fontSize={18}
fontWeight="600"
labelColor="#007AFF"
containerStyle={{
shadowColor: '#000000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
}}
/>Toast
A fully customizable, feature-rich Toast component with TypeScript support, multiple animation types, position control, and queue management.
Basic Usage
import React from 'react';
import { ToastProvider, useToast } from 'armia-rn-components';
const MyComponent = () => {
const { showToast } = useToast();
const handleShowToast = () => {
showToast({
message: 'This is a toast message',
type: 'success',
title: 'Success',
});
};
return (
<Button onPress={handleShowToast} text="Show Toast" />
);
};
// Wrap your app with ToastProvider
const App = () => {
return (
<ToastProvider>
<MyComponent />
</ToastProvider>
);
};Advanced Usage
import React from 'react';
import { ToastProvider, useToast } from 'armia-rn-components';
const MyComponent = () => {
const { showToast, hideAllToasts } = useToast();
const showCustomToast = () => {
showToast({
message: 'This is a custom styled toast',
type: 'custom',
title: 'Custom',
backgroundColor: '#FF5733',
textColor: '#FFFFFF',
borderColor: '#C70039',
borderRadius: 20,
position: 'top',
offsetTop: 100,
animationType: 'slide',
slideDirection: 'down',
duration: 5000,
leftIcon: '✓',
rightIcon: '→',
iconSize: 20,
onPress: () => console.log('Toast pressed'),
onDismiss: () => console.log('Toast dismissed'),
});
};
const showMultipleToasts = () => {
// High priority toast
showToast({
message: 'High priority message',
type: 'error',
priority: 3,
});
// Medium priority toast
setTimeout(() => {
showToast({
message: 'Medium priority message',
type: 'warning',
priority: 2,
});
}, 500);
// Low priority toast
setTimeout(() => {
showToast({
message: 'Low priority message',
type: 'info',
priority: 1,
});
}, 1000);
};
return (
<View>
<Button onPress={showCustomToast} text="Show Custom Toast" />
<Button onPress={showMultipleToasts} text="Show Multiple Toasts" />
<Button onPress={hideAllToasts} text="Hide All Toasts" />
</View>
);
};Toast Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| message | string | required | Toast message content |
| title | string | - | Optional toast title |
| type | 'info' \| 'success' \| 'warning' \| 'error' \| 'custom' | 'info' | Toast type variant |
| position | 'top' \| 'bottom' \| 'center' | 'bottom' | Toast position |
| offsetTop | number | 50 | Distance from top |
| offsetBottom | number | 50 | Distance from bottom |
| offsetHorizontal | number | 20 | Horizontal margin |
| duration | number | 3000 | Auto-dismiss duration (0 = no auto-dismiss) |
| autoDismiss | boolean | true | Enable/disable auto-dismiss |
| backgroundColor | string | - | Custom background color |
| textColor | string | - | Custom text color |
| borderColor | string | - | Custom border color |
| iconColor | string | - | Custom icon color |
| margin | number | spacing.sm | Outer margin |
| padding | number | spacing.md | Inner padding |
| borderRadius | number | spacing.borderRadius.md | Border radius |
| maxWidth | number | Screen width - 40 | Maximum width |
| minHeight | number | 60 | Minimum height |
| animationDuration | number | 300 | Animation duration |
| animationType | 'fade' \| 'slide' \| 'scale' | 'fade' | Animation type |
| slideDirection | 'up' \| 'down' \| 'left' \| 'right' | 'up' | Slide direction |
| leftIcon | ImageSourcePropType | - | Left icon |
| rightIcon | ImageSourcePropType | - | Right icon |
| iconSize | number | 24 | Icon size |
| onDismiss | () => void | - | Dismiss callback |
| onPress | () => void | - | Press callback |
| containerStyle | ViewStyle | - | Container custom styles |
| textStyle | TextStyle | - | Text custom styles |
| titleStyle | TextStyle | - | Title custom styles |
| swipeToDismiss | boolean | true | Enable swipe to dismiss |
| swipeDirection | 'up' \| 'down' \| 'left' \| 'right' | 'up' | Swipe direction |
| priority | number | - | Toast priority (higher = more important) |
| testID | string | - | Test identifier |
useToast Hook
Returns an object with the following methods:
| Method | Parameters | Description |
|--------|------------|-------------|
| showToast | (toast: ToastProps) => string | Show a toast and return its ID |
| hideToast | (id: string) => void | Hide a specific toast by ID |
| hideAllToasts | () => void | Hide all currently visible toasts |
| updateToast | (id: string, updates: Partial<ToastProps>) => void | Update an existing toast |
Toast Types
// Success toast
showToast({
message: 'Operation completed successfully!',
type: 'success',
title: 'Success',
});
// Error toast
showToast({
message: 'Something went wrong. Please try again.',
type: 'error',
title: 'Error',
});
// Warning toast
showToast({
message: 'Please check your input before proceeding.',
type: 'warning',
title: 'Warning',
});
// Info toast
showToast({
message: 'This is an informational message.',
type: 'info',
title: 'Info',
});
// Custom toast
showToast({
message: 'This is a custom styled toast',
type: 'custom',
title: 'Custom',
backgroundColor: '#FF5733',
textColor: '#FFFFFF',
borderColor: '#C70039',
});Position Control
// Top position
showToast({
message: 'Toast at the top',
position: 'top',
offsetTop: 100,
});
// Center position
showToast({
message: 'Toast in the center',
position: 'center',
});
// Bottom position (default)
showToast({
message: 'Toast at the bottom',
position: 'bottom',
offsetBottom: 50,
});Animation Types
// Fade animation (default)
showToast({
message: 'Fade animation',
animationType: 'fade',
animationDuration: 500,
});
// Slide animation
showToast({
message: 'Slide animation',
animationType: 'slide',
slideDirection: 'up',
animationDuration: 400,
});
// Scale animation
showToast({
message: 'Scale animation',
animationType: 'scale',
animationDuration: 300,
});Duration Control
// Long duration
showToast({
message: 'This toast will stay for 10 seconds',
duration: 10000,
});
// No auto-dismiss
showToast({
message: 'This toast will not auto-dismiss',
autoDismiss: false,
});
// Immediate dismiss
showToast({
message: 'This toast will dismiss immediately',
duration: 0,
});Multiple Toasts with Priority
// High priority toast
showToast({
message: 'High priority message',
type: 'error',
priority: 3,
});
// Medium priority toast
showToast({
message: 'Medium priority message',
type: 'warning',
priority: 2,
});
// Low priority toast
showToast({
message: 'Low priority message',
type: 'info',
priority: 1,
});Toast Management
const MyComponent = () => {
const { showToast, hideToast, hideAllToasts, updateToast } = useToast();
const [toastId, setToastId] = useState<string | null>(null);
const showPersistentToast = () => {
const id = showToast({
message: 'This toast will be updated',
type: 'info',
autoDismiss: false,
});
setToastId(id);
};
const updateMessage = () => {
if (toastId) {
updateToast(toastId, {
message: 'Message updated!',
type: 'success',
});
}
};
const hideSpecificToast = () => {
if (toastId) {
hideToast(toastId);
setToastId(null);
}
};
return (
<View>
<Button onPress={showPersistentToast} text="Show Toast" />
<Button onPress={updateMessage} text="Update Toast" />
<Button onPress={hideSpecificToast} text="Hide Toast" />
<Button onPress={hideAllToasts} text="Hide All Toasts" />
</View>
);
};AlertView
A highly customizable alert/modal component with multiple themes, animations, and styling options.
Basic Usage
import React, { useRef } from 'react';
import { AlertView, AlertViewRef } from 'armia-rn-components';
const MyComponent = () => {
const alertRef = useRef<AlertViewRef>(null);
const showSuccessAlert = () => {
alertRef.current?.setValues(
'success',
'Success!',
'Operation completed successfully.'
);
};
const showErrorAlert = () => {
alertRef.current?.setValues(
'alert',
'Error!',
'Something went wrong. Please try again.',
[
{ title: 'Cancel' },
{ title: 'Retry', onPress: () => console.log('Retrying...') }
]
);
};
return (
<>
<AlertView ref={alertRef} />
{/* Your other components */}
</>
);
};Advanced Customization
import React, { useRef } from 'react';
import { AlertView, AlertViewRef, ThemeType } from 'armia-rn-components';
const MyComponent = () => {
const alertRef = useRef<AlertViewRef>(null);
// Custom theme
const customThemes: Record<string, ThemeType> = {
warning: {
icon: {
backgroundColor: '#FF9500',
icon: 'warning',
color: '#FFFFFF',
},
titleColor: '#FF9500',
descriptionColor: '#666666',
backgroundColor: '#FFFFFF',
borderColor: '#FFE0B2',
},
};
const showCustomAlert = () => {
alertRef.current?.setValues(
'warning',
'Warning',
'This is a custom themed alert.',
[
{
title: 'Custom Button',
buttonStyle: {
backgroundColor: '#FF9500',
textStyle: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
},
},
onPress: () => console.log('Custom button pressed'),
},
]
);
};
return (
<AlertView
ref={alertRef}
customThemes={customThemes}
width={350}
borderRadius={20}
animationType="slide"
overlayColor="rgba(0, 0, 0, 0.7)"
shadowColor="#000000"
shadowOpacity={0.3}
shadowRadius={10}
elevation={8}
iconSize={40}
closeOnBackdropPress={true}
/>
);
};AlertView Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| titleStyle | TextStyleType | - | Custom title text styling |
| descriptionStyle | TextStyleType | - | Custom description text styling |
| defaultButtonStyle | ButtonStyleType | - | Default button styling |
| width | number \| string | 320 | Alert container width |
| maxWidth | number \| string | 320 | Maximum alert container width |
| height | number \| string | - | Alert container height |
| padding | number | 24 | Internal padding |
| borderRadius | number | 12 | Corner radius |
| animationType | 'none' \| 'slide' \| 'fade' | 'fade' | Modal animation type |
| transparent | boolean | true | Modal transparency |
| overlayColor | string | 'rgba(0, 0, 0, 0.5)' | Background overlay color |
| overlayOpacity | number | 1 | Background overlay opacity |
| closeOnBackdropPress | boolean | true | Close on backdrop press |
| shadowColor | string | '#000000' | Shadow color |
| shadowOpacity | number | 0.25 | Shadow opacity |
| shadowRadius | number | 3.84 | Shadow radius |
| shadowOffset | {width: number, height: number} | {0, 2} | Shadow offset |
| elevation | number | 5 | Android elevation |
| iconSize | number | 32 | Icon size |
| customIcons | Record<string, Component> | - | Custom icon components |
| customThemes | Record<string, ThemeType> | - | Custom theme definitions |
| containerStyle | ViewStyle | - | Main container styles |
| alertContainerStyle | ViewStyle | - | Alert container styles |
| iconContainerStyle | ViewStyle | - | Icon container styles |
| titleContainerStyle | ViewStyle | - | Title container styles |
| descriptionContainerStyle | ViewStyle | - | Description container styles |
| buttonContainerStyle | ViewStyle | - | Button container styles |
| testID | string | - | Test identifier |
AlertViewRef Methods
| Method | Parameters | Description |
|--------|------------|-------------|
| setValues | (theme, title, description, buttons?) | Show alert with specified content |
| dismiss | () | Hide the alert |
Built-in Themes
- alert: Red theme for errors/warnings
- success: Green theme for success messages
- info: Blue theme for informational messages
Custom Themes
const customThemes: Record<string, ThemeType> = {
custom: {
icon: {
backgroundColor: '#FF0000',
icon: 'custom',
color: '#FFFFFF',
},
titleColor: '#FF0000',
descriptionColor: '#666666',
backgroundColor: '#FFFFFF',
borderColor: '#FFE0E0',
},
};Button Configuration
const buttons = [
{
title: 'Cancel',
buttonStyle: {
backgroundColor: '#F2F2F7',
textStyle: {
color: '#666666',
fontSize: 16,
},
},
onPress: () => console.log('Cancelled'),
},
{
title: 'Confirm',
buttonStyle: {
backgroundColor: '#007AFF',
textStyle: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
},
},
onPress: () => console.log('Confirmed'),
},
];Utilities
The library also provides utility functions for consistent styling:
Colors
import { colors, getColor } from 'armia-rn-components';
// Using predefined colors
const primaryColor = colors.primary; // '#007AFF'
const gray100 = colors.gray[100]; // '#F2F2F7'
// Using color getter
const color = getColor('primary'); // '#007AFF'
const grayColor = getColor('100'); // '#F2F2F7'Spacing
import { spacing, getSpacing, getPadding, getMargin, getBorderRadius } from 'armia-rn-components';
// Using predefined spacing
const margin = spacing.md; // 16
const padding = spacing.padding.md; // 16
const borderRadius = spacing.borderRadius.lg; // 12
// Using spacing getters
const space = getSpacing('md'); // 16
const paddingValue = getPadding('lg'); // 24
const marginValue = getMargin('xl'); // 32
const radius = getBorderRadius('round'); // 50
// Component-specific spacing
const buttonPadding = spacing.button.paddingHorizontal; // 16
const cardPadding = spacing.card.padding; // 16
const modalMargin = spacing.modal.margin; // 20Typography
import { typography, getTypographyStyle, getFontSize, getFontWeight, getLineHeight, getLetterSpacing } from 'armia-rn-components';
// Using predefined typography styles
const headingStyle = typography.h1;
const bodyStyle = typography.body1;
// Using typography getters
const textStyle = getTypographyStyle('h1');
const fontSize = getFontSize('xl'); // 20
const fontWeight = getFontWeight('semibold'); // '600'
const lineHeight = getLineHeight('lg'); // 28
const letterSpacing = getLetterSpacing('wide'); // 0.5
// Available typography styles
const styles = {
h1: typography.h1, // 32px, bold, 40px line height
h2: typography.h2, // 24px, semibold, 32px line height
h3: typography.h3, // 20px, semibold, 28px line height
h4: typography.h4, // 18px, medium, 24px line height
body1: typography.body1, // 16px, regular, 24px line height
body2: typography.body2, // 14px, regular, 20px line height
caption: typography.caption, // 12px, regular, 16px line height
button: typography.button, // 16px, semibold, 24px line height
overline: typography.overline, // 10px, medium, 16px line height, uppercase
};Development
Prerequisites
- Node.js (v14 or higher)
- npm or yarn
- React Native development environment
Setup
- Clone the repository:
git clone https://gitlab.armiasystems.com/mobilelearningprojects/base-and-components/rncomponentsnpm.git
cd rncomponentsnpm- Install dependencies:
npm install- Build the project:
npm run buildAvailable Scripts
npm run build- Build the TypeScript codenpm run test- Run testsnpm run lint- Run ESLintnpm run lint:fix- Fix ESLint issuesnpm run clean- Clean build directorynpm run prepare- Build before publishing
Testing
npm testRun tests with coverage:
npm test -- --coverageLinting
npm run lintFix linting issues:
npm run lint:fixPublishing
- Update the version in
package.json - Build the project:
npm run build - Publish to npm:
npm publish
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
MIT License - see the LICENSE file for details.
Support
For support and questions, please open an issue in the GitLab repository or contact the development team.
Changelog
v1.5.0
- Added TextInput component with comprehensive customization options
- Built-in validation system with 8 validation rule types (required, email, phone, url, pattern, custom)
- Real-time validation on blur/change events with customizable error messages
- Icon support with left/right positioning and pressable functionality
- Password functionality with visibility toggle and custom icons
- Input masking for formatted inputs (phone numbers, dates, credit cards, etc.)
- Character limits with maxLength, minLength, and character count display
- Focus state customization with border colors, widths, and animations
- Comprehensive styling options (background, borders, padding, typography)
- Accessibility support with screen reader compatibility
- All React Native TextInput props supported with full forwarding
- Auto-complete, auto-correct, auto-capitalize, and keyboard type support
- Event handling with onChangeText, onFocus, onBlur, onSubmitEditing
- Validation change callbacks for form management
- Helper text and error message display
- Disabled and readonly states
- Touch state tracking for validation
- Comprehensive TypeScript support with full type definitions
- Production-ready with proper error handling and performance optimizations
- No external dependencies - built entirely with React Native
v1.4.0
- Added Toast component with comprehensive customization options
- Multiple toast types: info, success, warning, error, custom
- Position control: top, bottom, center with customizable offsets
- Animation types: fade, slide, scale with customizable duration
- Duration control: auto-dismiss with customizable timing
- Color customization: background, text, border, and icon colors
- Size and spacing: margin, padding, border radius, max width, min height
- Icon support: left and right icons with customizable size
- Multiple toast management: queue system with priority and ID
- Toast management: show, hide, update, and hide all methods
- Swipe to dismiss with configurable direction
- Press and dismiss callbacks
- Custom styling: container, text, and title style props
- Full accessibility support with testID
- Comprehensive TypeScript support
- Complete test coverage
- No external dependencies - built entirely with React Native
v1.3.0
- Added BottomSheet component with comprehensive customization options
- Multiple positions: bottom, top, center
- Animation types: slide, fade, none with customizable duration
- Height control: fixed height, percentage-based, maximum height
- Background customization: content and overlay colors with opacity
- Border radius control: uniform or individual corner radius
- Handle customization: visibility, color, size, and custom styles
- Swipe-to-close gesture with configurable threshold
- Backdrop behavior: disable press and swipe options
- Padding control: uniform, separate, or individual padding values
- Custom styling: container, content, and overlay style props
- Pan gesture support for smooth interactions
- Full accessibility support with testID
- Comprehensive TypeScript support
- Complete test coverage
v1.2.0
- Added Button component with comprehensive customization options
- Multiple variants: filled, outline, ghost
- Size variants: small, medium, large, custom
- Loading states with customizable text and colors
- Icon support with left/right positioning
- Press effects with opacity and scale
- Typography control with font size, weight, and family
- Padding customization for horizontal and vertical spacing
- Full accessibility support with screen reader props
- Event handlers for press, press in, press out, and long press
- Comprehensive TypeScript support
- Complete test coverage
v1.1.0
- Added Avatar component with comprehensive customization options
- Support for multiple image sources (URI, local path, placeholder)
- Fallback content with customizable text and styling
- Loading states with customizable indicators
- Error handling with custom error components
- Background customization and shadow effects
- Image resize mode support
- Full accessibility support
- Comprehensive TypeScript support
- Complete test coverage
v1.0.0
- Initial release
- AlertView component with comprehensive customization options
- Multiple themes (alert, success, info) with custom theme support
- Advanced styling options (shadows, borders, animations)
- Icon customization with custom icon support
- Button configuration with individual styling
- Modal customization (animation, backdrop, transparency)
- Utility functions for colors, spacing, and typography
- Comprehensive TypeScript support
- Full test coverage
