motorinc-global-components
v3.9.6
Published
A comprehensive React Native component library with built-in theme support for consistent UI across different projects
Downloads
667
Maintainers
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-componentsPeer Dependencies
Make sure you have these peer dependencies installed:
npm install react-native-svg @react-native-async-storage/async-storageQuick 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.
