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

motorinc-global-components

v3.9.6

Published

A comprehensive React Native component library with built-in theme support for consistent UI across different projects

Readme

MotorInc Global Components

A comprehensive React Native component library with built-in theme support for consistent UI across different projects.

Features

  • 🎨 Complete Theme System - Light/dark mode with 100+ predefined colors
  • 📱 React Native Components - Pre-built, customizable UI components
  • 🔄 Auto Theme Detection - Automatically follows system theme preferences
  • 💾 Theme Persistence - Remembers user theme preferences
  • 🎯 TypeScript Support - Full TypeScript definitions included
  • 📦 Easy Integration - Simple setup for any React Native project

Installation

npm install motorinc-global-components
# or
yarn add motorinc-global-components

Peer Dependencies

Make sure you have these peer dependencies installed:

npm install react-native-svg @react-native-async-storage/async-storage

Quick Start

1. Wrap your app with ThemeContext

import React from 'react';
import {ThemeContext} from 'motorinc-global-components';
import YourApp from './YourApp';

export default function App() {
  return (
    <ThemeContext>
      <YourApp />
    </ThemeContext>
  );
}

2. Use components in your app

import React from 'react';
import {View} from 'react-native';
import {
  PlayyText,
  IconComponent,
  NavigationHeader,
  icons,
  SPACING_16,
  SPACING_24,
} from 'motorinc-global-components';

export default function YourApp() {
  return (
    <View>
      <NavigationHeader
        title="My App"
        backIcon
        isSearch
        titlePosition="center"
      />

      <PlayyText>This text automatically uses theme colors!</PlayyText>

      <PlayyText color="#FF0000">This text is always red</PlayyText>

      <IconComponent name={icons.search} size={24} />
    </View>
  );
}

Components

Header Compound Component (NEW in v2.0.0)

A flexible compound component system for creating headers with various configurations. The Header component follows the compound component pattern, allowing you to compose exactly the header layout you need.

Basic Usage

import {Header} from 'motorinc-global-components';

// Simple header with title
<Header statusBarValue={44}>
  <Header.Row>
    <Header.Left backIcon onBackPress={() => navigation.goBack()} />
    <Header.Center title="Settings" />
    <Header.Right />
  </Header.Row>
</Header>

// Header with search
<Header statusBarValue={44}>
  <Header.Row>
    <Header.Left />
    <Header.Center title="Messages" />
    <Header.Right icons={[
      { name: 'search', onPress: () => setShowSearch(true) }
    ]} />
  </Header.Row>
  <Header.Search placeholder="Search messages..." onChangeText={handleSearch} />
</Header>

Advanced Examples

// Contact header with avatar and online status
<Header statusBarValue={44}>
  <Header.Row>
    <Header.Left
      backIcon
      onBackPress={() => navigation.goBack()}
      isContact
      contactSource={{uri: 'avatar.jpg'}}
      contactTitle="John Doe"
      contactSubTitle="Online"
      isOnline
    />
    <Header.Right
      icons={[
        { name: 'call', onPress: handleCall },
        { name: 'videocall', onPress: handleVideoCall }
      ]}
    />
  </Header.Row>
</Header>

// Header with large title
<Header statusBarValue={44}>
  <Header.Row>
    <Header.Left showLeading leadingSource={avatarSource} />
    <Header.Right
      isButton
      buttonTitle="Edit"
      onButtonPress={handleEdit}
    />
  </Header.Row>
  <Header.Title title="Good Morning!" />
</Header>

// Header with prompt message
<Header
  statusBarValue={44}
  showPrompt="This is a sample prompt message"
>
  <Header.Row>
    <Header.Left backIcon onBackPress={handleBack} label="Back" />
    <Header.Center title="Dashboard" subtitle="Welcome back!" showSubtitle />
    <Header.Right icons={[{name: 'notification', onPress: handleNotifications}]} />
  </Header.Row>
</Header>

Header Component Props

Main Header

interface HeaderProps {
  children: ReactNode;
  statusBarValue?: number; // Status bar height
  style?: StyleProp<ViewStyle>;
  showPrompt?: string; // Optional prompt message at top
}

Header.Row

interface HeaderRowProps {
  children: ReactNode; // Should contain Header.Left, Header.Center, Header.Right
}

Header.Left

interface HeaderLeftProps {
  children?: ReactNode; // Custom content (overrides other props)
  backIcon?: boolean; // Show back arrow
  backIconColor?: string;
  backIconWidth?: number;
  backIconHeight?: number;
  label?: string; // Text next to back icon
  labelColor?: string;
  onBackPress?: () => void;
  showLeading?: boolean; // Show leading avatar/image
  leadingSource?: ImageURISource;
  leadingContainerStyle?: StyleProp<ViewStyle>;
  onLeadingPress?: () => void;
  isContact?: boolean; // Show as contact header
  contactSource?: ImageURISource;
  contactName?: string;
  contactTitle?: string;
  contactSubTitle?: string;
  isOnline?: boolean; // Show online indicator
}

Header.Center

interface HeaderCenterProps {
  children?: ReactNode; // Custom content (overrides other props)
  title?: string;
  titleColor?: string;
  subtitle?: string;
  showSubtitle?: boolean;
}

Header.Right

interface HeaderRightProps {
  children?: ReactNode; // Custom content (overrides other props)
  icons?: Array<{
    name: string;
    onPress?: () => void;
    color?: string;
    size?: number;
  }>;
  isButton?: boolean; // Show as text button
  buttonTitle?: string;
  buttonTextColor?: string;
  buttonStyle?: StyleProp<ViewStyle>;
  onButtonPress?: () => void;
}

Header.Title

interface HeaderTitleProps {
  title: string; // Large title text
}

Header.Search

interface HeaderSearchProps {
  placeholder?: string; // Default: "Search"
  onChangeText?: (text: string) => void;
}

Migration from NavigationHeader

The compound component provides better composition than NavigationHeader:

// Old NavigationHeader
<NavigationHeader
  statusBarvalue={44}
  backIcon
  title="Settings"
  handleBack={() => navigation.goBack()}
  iconsList={[{ name: 'search', onPress: handleSearch }]}
/>

// New Header compound component
<Header statusBarValue={44}>
  <Header.Row>
    <Header.Left backIcon onBackPress={() => navigation.goBack()} />
    <Header.Center title="Settings" />
    <Header.Right icons={[{ name: 'search', onPress: handleSearch }]} />
  </Header.Row>
</Header>

Features

  • Compound Component Pattern: Mix and match sections as needed
  • Full TypeScript Support: Complete type definitions for all props
  • Theme Integration: Automatic theme color support
  • Status Bar Management: Cross-platform status bar handling
  • Icon Integration: Seamless IconComponent usage
  • Contact Display: Avatar, name, subtitle, online status
  • Interactive Elements: Touch handlers for buttons and icons
  • Search Functionality: Built-in search input with styling
  • Flexible Composition: Create any header layout combination

PlayyText

Enhanced Text component with automatic theme support.

// Automatic theme colors (default behavior)
<PlayyText>Uses colors.text_primary automatically</PlayyText>

// Custom color (overrides theme)
<PlayyText color="#FF0000">Always red text</PlayyText>

// Manual light/dark colors
<PlayyText lightColor="#000" darkColor="#FFF">
  Custom colors for each theme
</PlayyText>

// With styling
<PlayyText style={{ fontSize: 18, fontWeight: 'bold' }}>
  Styled text
</PlayyText>

IconComponent

SVG icon component with theme-aware styling.

<IconComponent
  name={icons.search} // Icon name from icons enum
  size={24} // Icon size
  fill="#007AFF" // Custom fill color
/>;

// Available icons
icons.search;
icons.back;
icons.microphone;

Spacing

Consistent spacing constants for your layouts.

import {
  SPACING_8,
  SPACING_16,
  SPACING_24,
  SPACING_32,
} from 'motorinc-global-components';

<View
  style={{
    padding: SPACING_16,
    margin: SPACING_8,
    gap: SPACING_12,
  }}>
  <PlayyText>Consistently spaced content</PlayyText>
</View>;

// Available spacing constants:
SPACING_2,
  SPACING_4,
  SPACING_6,
  SPACING_8,
  SPACING_10,
  SPACING_12,
  SPACING_14,
  SPACING_16,
  SPACING_18,
  SPACING_20,
  SPACING_24,
  SPACING_26,
  SPACING_30,
  SPACING_32,
  SPACING_34,
  SPACING_36,
  SPACING_40,
  SPACING_44,
  SPACING_46,
  SPACING_48,
  SPACING_52,
  SPACING_54,
  SPACING_56,
  SPACING_64,
  SPACING_72,
  SPACING_84;

NavigationHeader

Complete navigation header with customizable layout.

<NavigationHeader
  title="Page Title"
  backIcon={true}
  isSearch={true}
  titlePosition="center" // left | center | right
  showPrompt="Optional prompt message"
  statusBarvalue={100}
/>

Theme System

Using Theme Colors

The library provides 100+ predefined colors for both light and dark themes:

import {useTheme} from 'motorinc-global-components';

function MyComponent() {
  const {colors, colorScheme, toggleTheme} = useTheme();

  return (
    <View style={{backgroundColor: colors.bg_primary}}>
      <Text style={{color: colors.text_primary}}>
        Current theme: {colorScheme}
      </Text>
      <TouchableOpacity onPress={toggleTheme}>
        <Text>Toggle Theme</Text>
      </TouchableOpacity>
    </View>
  );
}

Available Theme Colors

  • Text colors: text_primary, text_secondary, text_tertiary
  • Background colors: bg_primary, bg_secondary, bg_tertiary
  • Button colors: button_primary, button_hover, button_pressed
  • Status colors: status_success, status_error, status_warning
  • Fill colors: fill_primary, fill_secondary, fill_tertiary
  • Border colors: border_light, border_medium, border_strong
  • And 80+ more colors...

Theme Management

const {colorScheme, toggleTheme, setSelectedTheme} = useTheme();

// Toggle between light and dark
toggleTheme();

// Set specific theme
setSelectedTheme('light'); // Force light mode
setSelectedTheme('dark'); // Force dark mode
setSelectedTheme('system'); // Follow system (default)

Metro Configuration

Add this to your metro.config.js for SVG support:

const {getDefaultConfig} = require('@react-native/metro-config');

module.exports = (() => {
  const config = getDefaultConfig(__dirname);

  const {transformer, resolver} = config;

  config.transformer = {
    ...transformer,
    babelTransformerPath: require.resolve('react-native-svg-transformer'),
  };
  config.resolver = {
    ...resolver,
    assetExts: resolver.assetExts.filter(ext => ext !== 'svg'),
    sourceExts: [...resolver.sourceExts, 'svg'],
  };

  return config;
})();

TypeScript Support

The library includes full TypeScript definitions. Import types as needed:

import type {
  ColorsScheme,
  PlayyTextProps,
  IconProps,
  NavigationHeaderProps,
} from 'motorinc-global-components';

ListView Component

The ListView component provides a flexible list item with optional swipe actions, similar to iOS native lists.

Basic Usage

import {ListView} from 'motorinc-global-components';

<ListView
  title="Basic List Item"
  subtitle="This is a subtitle"
  showRight={true}
  isRightArrow={true}
  handlePressListView={() => console.log('Pressed')}
/>;

ListView with Swipe Actions

import {ListView, SwipeAction} from 'motorinc-global-components';

const leftSwipeActions: SwipeAction[] = [
  {
    comp: (
      <View style={{alignItems: 'center'}}>
        <Icon name="edit" size={20} color="#FFFFFF" />
        <Text style={{color: '#FFFFFF', fontSize: 12}}>Edit</Text>
      </View>
    ),
    color: '#34C759',
    width: 80,
    onPress: () => console.log('Edit pressed'),
  },
];

const rightSwipeActions: SwipeAction[] = [
  {
    comp: (
      <View style={{alignItems: 'center'}}>
        <Icon name="delete" size={20} color="#FFFFFF" />
        <Text style={{color: '#FFFFFF', fontSize: 12}}>Delete</Text>
      </View>
    ),
    color: '#FF3B30',
    width: 80,
    onPress: () => console.log('Delete pressed'),
  },
];

<ListView
  title="Swipeable List Item"
  subtitle="Swipe left or right for actions"
  enableSwipe={true}
  swipeActions={{
    left: leftSwipeActions,
    right: rightSwipeActions,
  }}
  handlePressListView={() => console.log('Item pressed')}
/>;

ListView Props

| Prop | Type | Description | | ---------------- | --------------------------------------------- | ------------------------------ | | title | string | Main title text | | subtitle | string | Optional subtitle text | | enableSwipe | boolean | Enable swipe gestures | | swipeActions | {left?: SwipeAction[], right?: SwipeAction[]} | Grouped swipe actions | | onEdit | () => void | Legacy: Edit action callback | | onDelete | () => void | Legacy: Delete action callback | | showImage | boolean | Show leading image | | imageSource | ImageSource | Image source for leading image | | showToggle | boolean | Show toggle switch | | toggleValue | boolean | Toggle switch value | | onToggleChange | (value: boolean) => void | Toggle change callback |

SwipeAction Interface

interface SwipeAction {
  comp: React.ReactNode; // Custom component to display
  color?: string; // Background color
  width?: number; // Action width (default: 80)
  onPress?: () => void; // Action callback
}

Swipeable Component

Standalone swipeable wrapper for any content with WhatsApp-style smooth animations.

import {SwipeableComponent} from 'motorinc-global-components';

<SwipeableComponent
  leftActions={leftActions}
  rightActions={rightActions}
  leftSwipeEnabled={true}
  rightSwipeEnabled={true}>
  <YourCustomContent />
</SwipeableComponent>;

Features

  • Smooth Animations: Scale, opacity, and translation animations
  • WhatsApp-style Behavior: Elastic resistance and natural swipe limits
  • Multiple Actions: Support for multiple actions on each side
  • Auto-close: Actions automatically close after selection
  • Gesture Handler: Built on react-native-gesture-handler for performance

SwipeableListItem Component (NEW in v3.6.0)

A modern, feature-rich chat/list interface component with built-in swipe actions, perfect for messaging apps, chat lists, and swipeable item lists. Inspired by iOS WhatsApp and iMessage designs.

Features

  • Avatar Support - Image avatars with placeholder fallback
  • Rich Message Preview - Name, message text, timestamp, and icons
  • Status Indicators - Pinned badges, mention badges (@), unread count
  • Typing Indicator - Shows "User is typing..." state
  • Deleted Messages - Special styling for deleted message state
  • Swipe Actions - Customizable left/right swipe gestures
  • Fully Themed - Auto dark/light mode support
  • Performance Optimized - Ready for large lists with FlatList

Basic Usage

import {SwipeableListItem} from 'motorinc-global-components';

<SwipeableListItem
  chatProps={{
    name: 'John Doe',
    message: 'Hey, how are you?',
    timestamp: '2:30 PM',
    avatar: require('./avatar.jpg'),
    onPress: () => console.log('Chat pressed'),
  }}
/>;

Advanced Usage with Swipe Actions

import {SwipeableListItem, GLYPHS} from 'motorinc-global-components';

<SwipeableListItem
  chatProps={{
    name: 'John Doe',
    message: 'Hey, how are you?',
    timestamp: '2:30 PM',
    avatar: require('./avatar.jpg'),

    // Status indicators
    isPinned: true,
    pinnedIcon: <Text>{GLYPHS['pin-fill'].char}</Text>,
    isMentioned: true,
    unreadCount: 3,

    // Message states
    isTyping: false,
    isDeleted: false,
    messageIcon: <Text>{GLYPHS['checkmark-message-fill'].char}</Text>,

    // Swipe actions
    readStatus: 'unread',
    showPinAction: true,
    onToggleReadStatus: () => console.log('Toggle read status'),
    onTogglePin: () => console.log('Toggle pin'),
    onMute: () => console.log('Mute chat'),
    onArchive: () => console.log('Archive chat'),
    onMore: () => console.log('More options'),

    // Custom colors (optional)
    leftActionColors: {
      read: '#007AFF',
      pin: '#8E8E93',
    },
    rightActionColors: {
      mute: '#FF3B30',
      archive: '#FF9500',
      more: '#8E8E93',
    },

    onPress: () => console.log('Chat pressed'),
  }}
/>;

Usage with FlatList

import React from 'react';
import {FlatList} from 'react-native';
import {SwipeableListItem} from 'motorinc-global-components';

const chatData = [
  {
    id: '1',
    name: 'Alice Johnson',
    message: 'See you tomorrow!',
    timestamp: '2:30 PM',
    unreadCount: 2,
  },
  {
    id: '2',
    name: 'Bob Smith',
    message: 'Thanks for the update',
    timestamp: '1:15 PM',
    isPinned: true,
  },
  // ... more chats
];

function ChatListScreen() {
  return (
    <FlatList
      data={chatData}
      keyExtractor={item => item.id}
      renderItem={({item}) => (
        <SwipeableListItem
          chatProps={{
            name: item.name,
            message: item.message,
            timestamp: item.timestamp,
            avatar: item.avatar,
            isPinned: item.isPinned,
            unreadCount: item.unreadCount,
            readStatus: item.unreadCount > 0 ? 'unread' : 'read',
            showPinAction: true,
            onToggleReadStatus: () => handleToggleRead(item.id),
            onTogglePin: () => handleTogglePin(item.id),
            onMute: () => handleMute(item.id),
            onArchive: () => handleArchive(item.id),
            onPress: () => navigation.navigate('Chat', {id: item.id}),
          }}
        />
      )}
    />
  );
}

Props Interface

interface ChatItemProps {
  // Required props
  name: string; // Contact/chat name
  timestamp: string; // Time/date display

  // Content props
  message?: string; // Message preview text
  avatar?: ImageSourcePropType; // Avatar image

  // Status indicators
  isPinned?: boolean; // Show pinned badge
  pinnedIcon?: React.ReactNode; // Custom pin icon
  isMentioned?: boolean; // Show @ badge
  unreadCount?: number; // Unread message count

  // Message states
  isTyping?: boolean; // Show "User is typing..."
  isDeleted?: boolean; // Show deleted message state
  messageIcon?: React.ReactNode; // Icon in message preview

  // Swipe actions
  readStatus?: 'read' | 'unread'; // Enable read/unread toggle
  showPinAction?: boolean; // Enable pin action

  // Callbacks
  onToggleReadStatus?: () => void; // Read/unread toggle
  onTogglePin?: () => void; // Pin toggle
  onPress?: () => void; // Item press
  onMute?: () => void; // Mute action
  onArchive?: () => void; // Archive action
  onMore?: () => void; // More options

  // Custom colors (optional)
  leftActionColors?: {
    read?: string;
    pin?: string;
  };
  rightActionColors?: {
    mute?: string;
    archive?: string;
    more?: string;
  };
}

Swipe Actions

Left Swipe Actions:

  • Read/Unread (blue) - Toggle read status
  • Pin (gray) - Pin/unpin chat

Right Swipe Actions:

  • Mute (red) - Mute notifications
  • Archive (orange) - Archive chat
  • More (gray) - Additional options

Styling & Theming

The component automatically adapts to your theme:

// Light mode
background: colors.background_primary(white);
text: colors.labels_primary(black);

// Dark mode
background: colors.background_primary(black);
text: colors.labels_primary(white);

All colors are theme-aware and will automatically update when theme changes.

Examples

Complete App Example

import React from 'react';
import {View, ScrollView, TouchableOpacity} from 'react-native';
import {
  ThemeContext,
  useTheme,
  PlayyText,
  IconComponent,
  NavigationHeader,
  icons,
  SPACING_10,
  SPACING_16,
  SPACING_20,
} from 'motorinc-global-components';

function AppContent() {
  const {colors, colorScheme, toggleTheme} = useTheme();

  return (
    <View style={{flex: 1, backgroundColor: colors.bg_primary}}>
      <NavigationHeader
        title="My App"
        backIcon
        isSearch
        titlePosition="center"
      />

      <ScrollView style={{padding: SPACING_20}}>
        <PlayyText
          style={{fontSize: 24, fontWeight: 'bold', marginBottom: SPACING_10}}>
          Welcome to Motor Inc Components
        </PlayyText>

        <PlayyText style={{marginBottom: SPACING_20}}>
          Current theme: {colorScheme}
        </PlayyText>

        <TouchableOpacity
          onPress={toggleTheme}
          style={{
            backgroundColor: colors.button_primary,
            padding: SPACING_16,
            borderRadius: 8,
            alignItems: 'center',
            marginBottom: SPACING_20,
          }}>
          <PlayyText style={{color: colors.white}}>Toggle Theme</PlayyText>
        </TouchableOpacity>

        <View style={{flexDirection: 'row', justifyContent: 'space-around'}}>
          <IconComponent name={icons.search} size={30} />
          <IconComponent name={icons.back} size={30} />
          <IconComponent name={icons.microphone} size={30} />
        </View>
      </ScrollView>
    </View>
  );
}

export default function App() {
  return (
    <ThemeContext>
      <AppContent />
    </ThemeContext>
  );
}

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.