naarni-design-system
v4.101.0
Published
Naarni React Native Design System for EV Fleet Apps
Maintainers
Readme
@naarni/design-system
A comprehensive React Native design system for EV Fleet applications, built with TypeScript and modern React Native patterns.
🚀 Features
- TypeScript First: Full TypeScript support with proper type definitions
- Modern Components: Built with React Native best practices
- Customizable: Easy to customize and extend
- Performance Optimized: Memoized components and optimized rendering
- Accessibility: Built-in accessibility support
- Theme Support: Flexible theming system
- Chart Components: Built-in LineChart and BarChart with Skia
- Form Components: InputBox with validation and grouping support
📦 Installation
npm install @naarni/design-system
# or
yarn add @naarni/design-system🔧 Peer Dependencies
This package requires the following peer dependencies:
{
"react": ">=18.0.0",
"react-native": ">=0.70.0",
"react-native-vector-icons": ">=10.0.0",
"react-native-safe-area-context": ">=4.0.0",
"react-native-maps": ">=1.7.0"
}Note: For Google Maps functionality, you'll need to:
- Set up Google Maps API keys in your Android and iOS projects
- Configure the necessary permissions for location services
📚 Design Guidelines
For comprehensive design system guidelines, including button specifications, color schemes, and usage patterns, see DESIGN_GUIDELINES.md.
🎨 Components
Button
A versatile button component with multiple variants, sizes, and states.
import { Button } from '@naarni/design-system';
// Basic usage (Black background, white text, 400 weight)
<Button variant="primary" onPress={() => console.log('Pressed!')}>
Click Me
</Button>
// With different variants
<Button variant="secondary">Secondary</Button>
<Button variant="group">Group Button</Button> // Light gray background, black text
<Button variant="outline">Outline</Button>
<Button variant="text">Text Button</Button>
<Button variant="ghost">Ghost</Button>
// Different sizes
<Button variant="primary" size="small">Small</Button>
<Button variant="primary" size="medium">Medium</Button>
<Button variant="primary" size="large">Large</Button>
// States
<Button variant="primary" loading>Loading...</Button>
<Button variant="primary" disabled>Disabled</Button>
<Button variant="primary" loading loadingText="Processing...">
Loading with Text
</Button>
// With icons
<Button
variant="primary"
icon={<Icon name="arrow-right" size={16} />}
iconPosition="right"
>
Next
</Button>
// Full width
<Button variant="primary" fullWidth>Full Width Button</Button>Button Design System:
The Button component follows a consistent design system:
- Primary: Black background (
#000000) with white text (#FFFFFF), 400 font weight - Secondary: Theme secondary color with white text, 400 font weight
- Group: Light gray background (
#F2F1F5) with black text (#000000), 400 font weight - Disabled: Light gray background (
#F2F1F5) with black text (#000000), 400 font weight - Outline/Text/Ghost: Transparent background with black text, 400 font weight
Button Props:
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'outline' | 'text' | 'ghost' | 'group';
size?: 'small' | 'medium' | 'large';
loading?: boolean;
disabled?: boolean;
fullWidth?: boolean;
style?: ViewStyle;
textStyle?: TextStyle;
icon?: React.ReactNode;
iconPosition?: 'left' | 'right';
onPress?: () => void;
onLongPress?: () => void;
activeOpacity?: number;
children: React.ReactNode;
loadingText?: string;
accessibilityLabel?: string;
accessibilityHint?: string;
testID?: string;
}Text
A flexible text component with predefined typography variants.
import { Text } from '@naarni/design-system';
// Basic usage
<Text>Hello World</Text>
// Typography variants
<Text variant="h1">Heading 1</Text>
<Text variant="h2">Heading 2</Text>
<Text variant="h3">Heading 3</Text>
<Text variant="h4">Heading 4</Text>
<Text variant="h5">Heading 5</Text>
<Text variant="h6">Heading 6</Text>
<Text variant="body1">Body text</Text>
<Text variant="body2">Smaller body text</Text>
<Text variant="subtitle1">Subtitle 1</Text>
<Text variant="subtitle2">Subtitle 2</Text>
<Text variant="button">Button text</Text>
<Text variant="caption">Caption text</Text>
<Text variant="overline">Overline text</Text>
<Text variant="code">Code text</Text>
// Custom styling
<Text variant="h1" color="#007AFF" align="center" weight="bold">
Custom Styled Text
</Text>
// Text truncation
<Text variant="body1" numberOfLines={2} ellipsizeMode="tail">
This is a very long text that will be truncated after two lines...
</Text>Text Props:
interface TextProps {
variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body1' | 'body2' |
'subtitle1' | 'subtitle2' | 'button' | 'caption' | 'overline' | 'code';
color?: string;
align?: 'auto' | 'left' | 'right' | 'center' | 'justify';
weight?: 'thin' | 'extralight' | 'light' | 'regular' | 'medium' |
'semibold' | 'bold' | 'extrabold' | 'black';
style?: TextStyle;
children: ReactNode;
numberOfLines?: number;
ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
testID?: string;
}Card
A container component with optional title, subtitle, and animations.
import { Card } from '@naarni/design-system';
// Basic card
<Card title="Card Title" subtitle="Card Subtitle">
<Text variant="body1">Card content goes here</Text>
</Card>
// Card with image
<Card
title="Vehicle Info"
subtitle="Tesla Model 3"
image={require('./assets/tesla.jpg')}
>
<Text variant="body1">Electric vehicle details...</Text>
</Card>
// Animated cards
<Card
title="Animated Card"
animated
animationType="shine"
loop={true}
>
<Text variant="body1">This card has a shine animation</Text>
</Card>
// Custom styling
<Card
title="Custom Card"
backgroundColor="#f0f0f0"
elevation={8}
style={{ marginVertical: 16 }}
>
<Text variant="body1">Custom styled card</Text>
</Card>Card Props:
interface CardProps {
title?: string;
subtitle?: string;
image?: ImageSourcePropType;
elevation?: number;
style?: ViewStyle;
children?: ReactNode;
backgroundColor?: string;
key?: string | number;
animated?: boolean;
animationType?: 'none' | 'shine' | 'sine-shine' | 'stars' | 'drops';
loop?: boolean;
}Alert
A notification component for displaying messages to users.
import { Alert } from '@naarni/design-system';
// Basic alert
<Alert
type="success"
title="Success!"
message="Operation completed successfully"
/>
// Different alert types
<Alert type="info" title="Information" message="Here's some info" />
<Alert type="warning" title="Warning" message="Please be careful" />
<Alert type="error" title="Error" message="Something went wrong" />
// Dismissible alert
<Alert
type="info"
title="Dismissible"
message="You can close this alert"
dismissible
onDismiss={() => console.log('Alert dismissed')}
/>
// Alert with actions
<Alert
type="warning"
title="Confirm Action"
message="Are you sure you want to proceed?"
actions={[
{
label: 'Cancel',
onPress: () => console.log('Cancelled'),
variant: 'outline'
},
{
label: 'Confirm',
onPress: () => console.log('Confirmed'),
variant: 'primary'
}
]}
/>Alert Props:
interface AlertProps {
variant?: 'info' | 'success' | 'warning' | 'error';
title?: string;
message: string;
dismissible?: boolean;
persistent?: boolean;
onDismiss?: () => void;
icon?: ReactNode;
style?: ViewStyle;
actions?: AlertAction[];
}
interface AlertAction {
label: string;
onPress: () => void;
variant?: 'primary' | 'secondary' | 'outline' | 'text' | 'ghost';
}InputBox
A form input component with validation and icon support.
import { InputBox, InputBoxGroup } from '@naarni/design-system';
// Basic input
<InputBox
placeholder="Enter your email"
type="email"
label="Email Address"
/>
// Input with validation
<InputBox
placeholder="Enter password"
type="password"
label="Password"
error="Password must be at least 8 characters"
leftIcon="lock"
/>
// Input with icons
<InputBox
placeholder="Search..."
leftIcon="search"
rightIcon="clear"
onRightIconPress={() => console.log('Clear pressed')}
/>
// Different variants and sizes
<InputBox
variant="filled"
size="large"
placeholder="Large filled input"
/>
// Input group
<InputBoxGroup direction="horizontal" spacing={16}>
<InputBox placeholder="First Name" />
<InputBox placeholder="Last Name" />
</InputBoxGroup>
<InputBoxGroup direction="vertical" spacing={12}>
<InputBox placeholder="Email" type="email" />
<InputBox placeholder="Password" type="password" />
<InputBox placeholder="Confirm Password" type="password" />
</InputBoxGroup>InputBox Props:
interface InputBoxProps extends Omit<TextInputProps, 'style'> {
placeholder?: string;
error?: string;
type?: 'text' | 'email' | 'password' | 'phone' | 'number' | 'url';
leftIcon?: string;
rightIcon?: string;
onRightIconPress?: () => void;
disabled?: boolean;
label?: string;
helperText?: string;
variant?: 'outlined' | 'filled';
size?: 'small' | 'medium' | 'large';
fullWidth?: boolean;
style?: any;
containerStyle?: any;
}
interface InputBoxGroupProps {
children: React.ReactNode;
direction?: 'horizontal' | 'vertical';
spacing?: number;
style?: any;
}Icon
A wrapper around react-native-vector-icons for consistent icon usage.
import { Icon } from '@naarni/design-system';
// Basic icon
<Icon name="home" size={24} color="#007AFF" />
// Different sizes
<Icon name="star" size={16} />
<Icon name="star" size={24} />
<Icon name="star" size={32} />
// With custom colors
<Icon name="heart" size={24} color="#FF3B30" />
<Icon name="check" size={24} color="#34C759" />Icon Props:
interface IconProps {
name: string;
size?: number;
color?: string;
style?: any;
}Charts
Chart components built with React Native Skia for smooth animations.
LineChart
import { LineChart } from '@naarni/design-system';
// Basic line chart
<LineChart
data={[10, 20, 15, 30, 25, 40, 35]}
width={300}
height={200}
/>
// With customization
<LineChart
data={[10, 20, 15, 30, 25, 40, 35]}
width={300}
height={200}
color="#007AFF"
showGrid={true}
showXAxis={true}
showYAxis={true}
showTooltip={true}
tooltipFormatter={(value, index) => `Point ${index}: ${value}`}
/>BarChart
import { BarChart } from '@naarni/design-system';
// Basic bar chart
<BarChart
data={[10, 20, 15, 30, 25, 40, 35]}
width={300}
height={200}
/>
// With customization
<BarChart
data={[10, 20, 15, 30, 25, 40, 35]}
width={300}
height={200}
color="#34C759"
showGrid={true}
showXAxis={true}
showYAxis={true}
showTooltip={true}
tooltipFormatter={(value, index) => `Bar ${index}: ${value}`}
/>Chart Props:
interface LineChartProps {
data: number[];
width: number;
height: number;
showXAxis?: boolean;
showYAxis?: boolean;
isLabelOnXaxis?: boolean;
isLabelOnYaxis?: boolean;
color?: string;
showGrid?: boolean;
showTooltip?: boolean;
tooltipFormatter?: (value: number, index: number) => string;
}
interface BarChartProps {
data: number[];
width: number;
height: number;
showXAxis?: boolean;
showYAxis?: boolean;
isLabelOnXaxis?: boolean;
isLabelOnYaxis?: boolean;
color?: string;
showGrid?: boolean;
showTooltip?: boolean;
tooltipFormatter?: (value: number, index: number) => string;
}BottomSheet
A modal component that slides up from the bottom.
import { BottomSheet } from '@naarni/design-system';
// Basic bottom sheet
<BottomSheet
visible={isVisible}
onClose={() => setIsVisible(false)}
title="Bottom Sheet"
>
<Text variant="body1">Bottom sheet content goes here</Text>
</BottomSheet>
// With confirmation
<BottomSheet
visible={isVisible}
onClose={() => setIsVisible(false)}
onConfirm={() => {
console.log('Confirmed');
setIsVisible(false);
}}
title="Confirm Action"
confirmText="Confirm"
cancelText="Cancel"
>
<Text variant="body1">Are you sure you want to proceed?</Text>
</BottomSheet>
// Custom snap points
<BottomSheet
visible={isVisible}
onClose={() => setIsVisible(false)}
snapPoints={[300, 500]}
initialSnapPoint={300}
showDragIndicator={true}
>
<Text variant="body1">Custom height bottom sheet</Text>
</BottomSheet>BottomSheet Props:
interface BottomSheetProps {
visible: boolean;
title?: string;
children: ReactNode;
onClose: () => void;
onConfirm?: () => void;
showDragIndicator?: boolean;
initialSnapPoint?: number;
snapPoints?: number[];
style?: ViewStyle;
contentStyle?: ViewStyle;
enablePanDownToClose?: boolean;
confirmText?: string;
cancelText?: string;
}Map
A comprehensive map component for vehicle tracking using Google Maps.
import { Map, EnhancedMap, Vehicle } from '@naarni/design-system';
// Basic map with vehicles
const vehicles: Vehicle[] = [
{
id: '1',
name: 'Tesla Model 3',
latitude: 37.78825,
longitude: -122.4324,
speed: 65,
battery: 85,
status: 'active'
}
];
<Map
vehicles={vehicles}
mapStyle="dark"
onVehiclePress={(vehicle) => console.log(vehicle)}
/>
// Enhanced map with controls and vehicle info
<EnhancedMap
vehicles={vehicles}
mapStyle="blackAndWhite"
showControls={true}
showVehicleInfo={true}
onVehicleSelect={(vehicle) => setSelectedVehicle(vehicle)}
/>
// Custom map styling
<Map
vehicles={vehicles}
customMapStyle={[
{
elementType: 'geometry',
stylers: [{ color: '#212121' }]
},
{
elementType: 'labels.text.fill',
stylers: [{ color: '#757575' }]
}
]}
/>Map Props:
interface MapProps {
vehicles?: Vehicle[];
initialRegion?: Region;
style?: ViewStyle;
mapStyle?: 'default' | 'dark' | 'light' | 'blackAndWhite';
customMapStyle?: MapStyleConfig[];
showVehicleInfo?: boolean;
autoFitToVehicles?: boolean;
onVehiclePress?: (vehicle: Vehicle) => void;
onMapPress?: (event: any) => void;
onRegionChange?: (region: Region) => void;
zoomEnabled?: boolean;
scrollEnabled?: boolean;
rotateEnabled?: boolean;
pitchEnabled?: boolean;
showsUserLocation?: boolean;
showsMyLocationButton?: boolean;
showsCompass?: boolean;
showsScale?: boolean;
loadingEnabled?: boolean;
loadingIndicatorColor?: string;
loadingBackgroundColor?: string;
testID?: string;
}interface Vehicle { id?: string; name?: string; description?: string; latitude: number; longitude: number; heading?: number; color?: string; speed?: number; battery?: number; status?: 'active' | 'inactive' | 'charging' | 'maintenance'; lastUpdate?: Date; }
**EnhancedMap Props:**
```tsx
interface EnhancedMapProps extends MapProps {
showControls?: boolean;
showVehicleInfo?: boolean;
selectedVehicle?: Vehicle | null;
onVehicleSelect?: (vehicle: Vehicle | null) => void;
}🎯 Complete Usage Examples
Basic App Setup
import React from 'react';
import { View, StyleSheet } from 'react-native';
import {
Button,
Text,
Card,
Alert,
InputBox,
InputBoxGroup
} from '@naarni/design-system';
const App = () => {
const [showAlert, setShowAlert] = React.useState(false);
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
return (
<View style={styles.container}>
<Text variant="h1" style={styles.title}>
Welcome to Naarni
</Text>
<Card title="Login Form" style={styles.card}>
<InputBoxGroup direction="vertical" spacing={16}>
<InputBox
placeholder="Enter your email"
type="email"
label="Email Address"
value={email}
onChangeText={setEmail}
/>
<InputBox
placeholder="Enter your password"
type="password"
label="Password"
value={password}
onChangeText={setPassword}
/>
</InputBoxGroup>
<Button
variant="primary"
fullWidth
style={styles.button}
onPress={() => setShowAlert(true)}
>
Login
</Button>
</Card>
{showAlert && (
<Alert
type="success"
title="Success!"
message="Login successful"
dismissible
onDismiss={() => setShowAlert(false)}
/>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#f5f5f5',
},
title: {
textAlign: 'center',
marginVertical: 32,
},
card: {
marginVertical: 16,
},
button: {
marginTop: 24,
},
});
export default App;Dashboard Example
import React from 'react';
import { View, ScrollView, StyleSheet } from 'react-native';
import {
Text,
Card,
Button,
LineChart,
BarChart,
Icon,
Map,
Vehicle
} from '@naarni/design-system';
const Dashboard = () => {
const chartData = [10, 20, 15, 30, 25, 40, 35];
const vehicles: Vehicle[] = [
{
id: '1',
name: 'Tesla Model 3',
latitude: 37.78825,
longitude: -122.4324,
speed: 65,
battery: 85,
status: 'active'
},
{
id: '2',
name: 'Nissan Leaf',
latitude: 37.78925,
longitude: -122.4314,
speed: 45,
battery: 72,
status: 'active'
}
];
return (
<ScrollView style={styles.container}>
<Text variant="h1" style={styles.title}>
Fleet Dashboard
</Text>
{/* Stats Cards */}
<View style={styles.statsRow}>
<Card style={styles.statCard}>
<Text variant="h3" color="#007AFF">24</Text>
<Text variant="body2" color="#666">Active Vehicles</Text>
</Card>
<Card style={styles.statCard}>
<Text variant="h3" color="#34C759">98%</Text>
<Text variant="body2" color="#666">Uptime</Text>
</Card>
</View>
{/* Vehicle Map */}
<Card title="Live Vehicle Locations" style={styles.mapCard}>
<Map
vehicles={vehicles}
mapStyle="dark"
style={styles.map}
onVehiclePress={(vehicle) => console.log('Vehicle pressed:', vehicle)}
/>
</Card>
{/* Charts */}
<Card title="Weekly Performance" style={styles.chartCard}>
<LineChart
data={chartData}
width={300}
height={200}
color="#007AFF"
showGrid={true}
showTooltip={true}
/>
</Card>
<Card title="Monthly Usage" style={styles.chartCard}>
<BarChart
data={chartData}
width={300}
height={200}
color="#34C759"
showGrid={true}
showTooltip={true}
/>
</Card>
{/* Actions */}
<View style={styles.actions}>
<Button variant="primary" icon={<Icon name="plus" size={16} />}>
Add Vehicle
</Button>
<Button variant="outline" icon={<Icon name="settings" size={16} />}>
Settings
</Button>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#f5f5f5',
},
title: {
marginBottom: 24,
},
statsRow: {
flexDirection: 'row',
gap: 16,
marginBottom: 24,
},
statCard: {
flex: 1,
alignItems: 'center',
padding: 16,
},
mapCard: {
height: 300,
marginBottom: 24,
},
map: {
flex: 1,
borderRadius: 8,
},
chartCard: {
marginBottom: 24,
},
actions: {
gap: 12,
marginBottom: 24,
},
});
export default Dashboard;🔧 Development
Building
npm run buildTesting Package
npm run pack
npm run test:packPublishing
# Patch version (1.0.0 -> 1.0.1)
npm run publish:patch
# Minor version (1.0.0 -> 1.1.0)
npm run publish:minor
# Major version (1.0.0 -> 2.0.0)
npm run publish:major📚 Typography System
The design system includes a comprehensive typography system with predefined text styles:
- Headings:
h1,h2,h3,h4,h5,h6 - Body Text:
body1,body2 - Subtitles:
subtitle1,subtitle2 - Special:
button,caption,overline,code
Each variant has optimized font sizes, weights, and spacing for different use cases.
🎨 Theme Support
The design system supports theming through the typography system and individual component styling. You can customize colors, spacing, and other design tokens by extending the theme files.
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
📄 License
MIT License - see LICENSE file for details
🆘 Support
For support and questions:
- Create an issue on GitHub
- Check the examples in the
src/Examplesdirectory - Review the component interfaces for detailed prop information
