mmedui
v0.1.1
Published
A minimal, clean React Native UI component library
Maintainers
Readme
mmedui
A minimal, clean React Native UI component library with a flat design aesthetic, rounded corners, and a friendly feel.
Features
- Minimal & Clean - Generous whitespace, clear visual hierarchy
- Flat Design - No shadows, clean surfaces
- Rounded & Friendly - Generous border radii throughout
- Dark Mode - Full light and dark theme support
- Accessible - WCAG AA contrast ratios, 44px minimum touch targets
- Animated - Smooth animations powered by Rive and Reanimated
- TypeScript - Full type safety with strict mode
Installation
npm install mmeduiPeer Dependencies
npm install @rive-app/react-native expo-haptics lucide-react-native react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-svgMetro Configuration
Components that use Rive animations (Spinner, Switch, Checkbox, Radio) require .riv to be registered as an asset extension. Add this to your metro.config.js:
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.resolver.assetExts.push('riv');
module.exports = config;Quick Start
Wrap your app with the required providers:
import { ThemeProvider, TrayProvider, ToastProvider } from 'mmedui';
export default function App() {
return (
<ThemeProvider>
<TrayProvider>
<ToastProvider>
<YourApp />
</ToastProvider>
</TrayProvider>
</ThemeProvider>
);
}Components
Primitives
- Text - Typography with variants (heading, subheading, body, caption)
- Button - Primary, secondary, clear, and link variants
- IconButton - Icon-only buttons with multiple variants
- Card - Container with outlined and filled variants
- Icon - Lucide icons wrapper with size presets
- Avatar - User avatars with image or initials
- Badge - Status indicators and labels
- Divider - Visual separators
Layout
- VStack / HStack - Vertical and horizontal flex containers
- Container - Responsive content wrapper
- Spacer - Flexible space element
- SafeArea - Safe area insets handler
Forms
- TextInput - Text input with label and error states
- Switch - Toggle switch with Rive animation
- Checkbox - Checkbox with Rive animation
- Radio - Radio button group with Rive animation
- Select - Dropdown selector using Tray
- Slider - Range slider input
- SearchInput - Search field with debounce and loading
- DatePicker - Date selection with calendar in Tray
- DateRangePicker - Date range selection with calendar in Tray
- TimePicker - Time selection with wheel picker in Tray
- NumberStepper - Numeric input with +/- buttons
- NumberPadModal - Full-screen currency input with animated keypad
Feedback
- Toast - Toast notifications with action support
- Tray - Bottom sheet with navigation stack
- Spinner - Loading indicator with Rive animation
- Skeleton - Content placeholder
Lists
- List - List container
- ListItem - List row with left/right elements
Navigation
- Header - Screen header with back button
- TabBar - Bottom tab navigation
Usage Examples
Buttons
import { Button, IconButton, Icon } from 'mmedui';
<Button variant="primary" onPress={handlePress}>
Get Started
</Button>
<Button variant="secondary" leftIcon={<Icon name="Plus" />}>
Add Item
</Button>
<IconButton
icon={<Icon name="Heart" />}
variant="primary"
accessibilityLabel="Like"
/>Toast
import { useToast } from 'mmedui';
function MyComponent() {
const { show } = useToast();
const handleDelete = () => {
show({
message: 'Item deleted',
variant: 'info',
action: {
label: 'Undo',
onPress: () => restoreItem(),
confirmMessage: 'Item restored',
confirmVariant: 'success',
},
});
};
}Tray
import { useTray } from 'mmedui';
function MyComponent() {
const tray = useTray();
const openSettings = () => {
tray.open({
title: 'Settings',
content: (
<VStack spacing={4} style={{ padding: 16 }}>
<Text>Settings content here</Text>
<Button onPress={() => tray.close()}>Done</Button>
</VStack>
),
});
};
}Theme
import { useTheme } from 'mmedui';
function MyComponent() {
const { theme, mode, toggleMode } = useTheme();
return (
<View style={{ backgroundColor: theme.semantic.background }}>
<Text style={{ color: theme.semantic.text }}>
Current mode: {mode}
</Text>
<Button onPress={toggleMode}>Toggle Theme</Button>
</View>
);
}NumberPadModal
import { useState } from 'react';
import { NumberPadModal, Button } from 'mmedui';
function PaymentScreen() {
const [showPad, setShowPad] = useState(false);
const handlePayment = (amount: number) => {
console.log(`Payment amount: ${amount}`);
};
return (
<>
<Button onPress={() => setShowPad(true)}>
Enter Amount
</Button>
<NumberPadModal
visible={showPad}
onClose={() => setShowPad(false)}
title="Send Payment"
onSubmit={handlePayment}
submitLabel="Send"
maxValue={10000}
currencySymbol="₦"
/>
</>
);
}Theme Tokens
Colors
| Token | Light | Dark |
|-------|-------|------|
| primary | #272137 | #E9E5EF |
| background | #FFFFFF | #18181B |
| surface | #F4F4F6 | #27272E |
| text | #27272E | #FAFAFB |
| textSecondary | #6E6E7A | #9E9EA8 |
Semantic Colors
| Token | Value |
|-------|-------|
| success | #34D399 |
| warning | #FBBF24 |
| error | #F87171 |
| info | #60A5FA |
Spacing Scale
| Key | Value | |-----|-------| | 0 | 0px | | 1 | 4px | | 2 | 8px | | 3 | 12px | | 4 | 16px | | 5 | 20px | | 6 | 24px | | 8 | 32px | | 10 | 40px | | 12 | 48px |
Border Radii
| Key | Value |
|-----|-------|
| none | 0 |
| sm | 4px |
| md | 8px |
| lg | 12px |
| xl | 16px |
| 2xl | 24px |
| full | 9999px |
Compatibility
- Expo SDK 50+
- React Native 0.73+
- iOS 13+
- Android API 21+
License
MIT
