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 🙏

© 2025 – Pkg Stats / Ryan Hefner

naarni-design-system

v4.101.0

Published

Naarni React Native Design System for EV Fleet Apps

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:

  1. Set up Google Maps API keys in your Android and iOS projects
  2. 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 build

Testing Package

npm run pack
npm run test:pack

Publishing

# 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

  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
  • Review the component interfaces for detailed prop information