npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

armia-rn-components

v1.10.0

Published

A collection of reusable React Native components and utilities

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-components

Quick 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:

  1. Local Path: localPath prop for local images
  2. Remote URI: uri prop for remote images
  3. Placeholder: placeholder prop as fallback
  4. 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; // 20

Typography

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

  1. Clone the repository:
git clone https://gitlab.armiasystems.com/mobilelearningprojects/base-and-components/rncomponentsnpm.git
cd rncomponentsnpm
  1. Install dependencies:
npm install
  1. Build the project:
npm run build

Available Scripts

  • npm run build - Build the TypeScript code
  • npm run test - Run tests
  • npm run lint - Run ESLint
  • npm run lint:fix - Fix ESLint issues
  • npm run clean - Clean build directory
  • npm run prepare - Build before publishing

Testing

npm test

Run tests with coverage:

npm test -- --coverage

Linting

npm run lint

Fix linting issues:

npm run lint:fix

Publishing

  1. Update the version in package.json
  2. Build the project: npm run build
  3. Publish to npm: npm publish

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. 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