Naarni React Native Design System for EV Fleet Apps
npm install naarni-design-systemA comprehensive React Native design system for EV Fleet applications, built with TypeScript and modern React Native patterns.
- 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
``bash`
npm install @naarni/design-systemor
yarn add @naarni/design-system
This package requires the following peer dependencies:
`json`
{
"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:
1. Set up Google Maps API keys in your Android and iOS projects
2. Configure the necessary permissions for location services
For comprehensive design system guidelines, including button specifications, color schemes, and usage patterns, see DESIGN_GUIDELINES.md.
A versatile button component with multiple variants, sizes, and states.
`tsx
import { Button } from '@naarni/design-system';
// Basic usage (Black background, white text, 400 weight)
// With different variants
// Light gray background, black text
// Different sizes
// States
// With icons
variant="primary"
icon={
iconPosition="right"
>
Next
// Full width
`
Button Design System:
The Button component follows a consistent design system:
- Primary: Black background (#000000) with white text (#FFFFFF), 400 font weight#F2F1F5
- Secondary: Theme secondary color with white text, 400 font weight
- Group: Light gray background () with black text (#000000), 400 font weight#F2F1F5
- Disabled: Light gray background () with black text (#000000), 400 font weight
- Outline/Text/Ghost: Transparent background with black text, 400 font weight
Button Props:
`tsx`
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;
}
A flexible text component with predefined typography variants.
`tsx
import { Text } from '@naarni/design-system';
// Basic usage
// Typography variants
// Custom styling
Custom Styled Text
// Text truncation
This is a very long text that will be truncated after two lines...
`
Text Props:
`tsx`
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;
}
A container component with optional title, subtitle, and animations.
`tsx
import { Card } from '@naarni/design-system';
// Basic card
// Card with image
subtitle="Tesla Model 3"
image={require('./assets/tesla.jpg')}
>
// Animated cards
animated
animationType="shine"
loop={true}
>
// Custom styling
backgroundColor="#f0f0f0"
elevation={8}
style={{ marginVertical: 16 }}
>
`
Card Props:
`tsx`
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;
}
A notification component for displaying messages to users.
`tsx
import { Alert } from '@naarni/design-system';
// Basic alert
title="Success!"
message="Operation completed successfully"
/>
// Different alert types
// Dismissible alert
title="Dismissible"
message="You can close this alert"
dismissible
onDismiss={() => console.log('Alert dismissed')}
/>
// Alert with actions
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:
`tsx
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';
}
`
A form input component with validation and icon support.
`tsx
import { InputBox, InputBoxGroup } from '@naarni/design-system';
// Basic input
type="email"
label="Email Address"
/>
// Input with validation
type="password"
label="Password"
error="Password must be at least 8 characters"
leftIcon="lock"
/>
// Input with icons
leftIcon="search"
rightIcon="clear"
onRightIconPress={() => console.log('Clear pressed')}
/>
// Different variants and sizes
size="large"
placeholder="Large filled input"
/>
// Input group
`
InputBox Props:
`tsx
interface InputBoxProps extends Omit
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;
}
`
A wrapper around react-native-vector-icons for consistent icon usage.
`tsx
import { Icon } from '@naarni/design-system';
// Basic icon
// Different sizes
// With custom colors
`
Icon Props:
`tsx`
interface IconProps {
name: string;
size?: number;
color?: string;
style?: any;
}
Chart components built with React Native Skia for smooth animations.
#### LineChart
`tsx
import { LineChart } from '@naarni/design-system';
// Basic line chart
width={300}
height={200}
/>
// With customization
width={300}
height={200}
color="#007AFF"
showGrid={true}
showXAxis={true}
showYAxis={true}
showTooltip={true}
tooltipFormatter={(value, index) => Point ${index}: ${value}}`
/>
#### BarChart
`tsx
import { BarChart } from '@naarni/design-system';
// Basic bar chart
width={300}
height={200}
/>
// With customization
width={300}
height={200}
color="#34C759"
showGrid={true}
showXAxis={true}
showYAxis={true}
showTooltip={true}
tooltipFormatter={(value, index) => Bar ${index}: ${value}}`
/>
Chart Props:
`tsx
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;
}
`
A modal component that slides up from the bottom.
`tsx
import { BottomSheet } from '@naarni/design-system';
// Basic bottom sheet
onClose={() => setIsVisible(false)}
title="Bottom Sheet"
>
// With confirmation
onClose={() => setIsVisible(false)}
onConfirm={() => {
console.log('Confirmed');
setIsVisible(false);
}}
title="Confirm Action"
confirmText="Confirm"
cancelText="Cancel"
>
// Custom snap points
onClose={() => setIsVisible(false)}
snapPoints={[300, 500]}
initialSnapPoint={300}
showDragIndicator={true}
>
`
BottomSheet Props:
`tsx`
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;
}
A comprehensive map component for vehicle tracking using Google Maps.
`tsx
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'
}
];
vehicles={vehicles}
mapStyle="dark"
onVehiclePress={(vehicle) => console.log(vehicle)}
/>
// Enhanced map with controls and vehicle info
mapStyle="blackAndWhite"
showControls={true}
showVehicleInfo={true}
onVehicleSelect={(vehicle) => setSelectedVehicle(vehicle)}
/>
// Custom map styling
vehicles={vehicles}
customMapStyle={[
{
elementType: 'geometry',
stylers: [{ color: '#212121' }]
},
{
elementType: 'labels.text.fill',
stylers: [{ color: '#757575' }]
}
]}
/>
`
Map Props:
`tsx`
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;
}
`tsx
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 (
Welcome to Naarni
type="email"
label="Email Address"
value={email}
onChangeText={setEmail}
/>
type="password"
label="Password"
value={password}
onChangeText={setPassword}
/>
variant="primary"
fullWidth
style={styles.button}
onPress={() => setShowAlert(true)}
>
Login
{showAlert && (
title="Success!"
message="Login successful"
dismissible
onDismiss={() => setShowAlert(false)}
/>
)}
);
};
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;
`
`tsx
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 (
Fleet Dashboard
{/ Stats Cards /}
{/ Vehicle Map /}
vehicles={vehicles}
mapStyle="dark"
style={styles.map}
onVehiclePress={(vehicle) => console.log('Vehicle pressed:', vehicle)}
/>
{/ Charts /}
width={300}
height={200}
color="#007AFF"
showGrid={true}
showTooltip={true}
/>
width={300}
height={200}
color="#34C759"
showGrid={true}
showTooltip={true}
/>
{/ Actions /}
}>
Add Vehicle
}>
Settings
);
};
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;
`
bash
npm run build
`$3
`bash
npm run pack
npm run test:pack
`$3
`bash
Patch version (1.0.0 -> 1.0.1)
npm run publish:patchMinor version (1.0.0 -> 1.1.0)
npm run publish:minorMajor 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, codeEach 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
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. 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/Examples` directory