react-native-quick-preview
Version:
A beautiful, customizable quick preview modal component for React Native
189 lines (151 loc) β’ 5.47 kB
Markdown
# react-native-quick-preview
A beautiful, customizable quick preview modal component for React Native.
Think **Gorhom Bottom Sheet**, but for quick previews.
Perfect for:
- Instagram-style **long-press previews**
- ποΈ **E-commerce product quick views**
- π° **Article teasers**
- βοΈ **Travel destination peeks**
- β¦any content that needs a **quick peek before full navigation**
## β¨ Features
- π¨ Smooth **fade, scale, and swipe-to-close animations**
- π― **Universal content** β works with any layout (products, posts, etc.)
- ποΈ **Customizable** β theme, behavior, styling, backdrop
- βΏ **Accessibility ready** β screen reader & keyboard navigation
- π± **Cross-platform** β iOS & Android
- π§ **TypeScript support**
- β‘ **Performance optimized** β native drivers
## π¦ Installation
```bash
npm install react-native-quick-preview
# or
yarn add react-native-quick-preview
```
## π Quick Start
```tsx
import React, { useState } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { QuickPreview } from 'react-native-quick-preview';
export default function App() {
const [visible, setVisible] = useState(false);
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity onPress={() => setVisible(true)}>
<Text>Show Quick Look</Text>
</TouchableOpacity>
<QuickPreview visible={visible} onClose={() => setVisible(false)}>
<View style={{ backgroundColor: '#fff', padding: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>Quick Preview Content</Text>
<Text style={{ marginTop: 10 }}>Any custom content goes here.</Text>
</View>
</QuickPreview>
</View>
);
}
```
## π Usage Examples
### ποΈ E-commerce Product Quick View
```tsx
<QuickPreview visible={visible} onClose={onClose} onPressCard={onViewDetails}>
<View>
<Image source={{ uri: product.image }} style={{ width: '100%', height: 200 }} />
<Text>{product.name}</Text>
<Text>{product.price}</Text>
</View>
</QuickPreview>
```
### π° Article Preview
```tsx
<QuickPreview visible={visible} onClose={onClose} theme="dark">
<View style={{ backgroundColor: '#1a1a1a' }}>
<Image source={{ uri: article.coverImage }} style={{ width: '100%', height: 200 }} />
<Text style={{ color: '#fff' }}>{article.title}</Text>
<Text style={{ color: '#ccc' }}>{article.excerpt}</Text>
</View>
</QuickPreview>
```
### βοΈ Travel Destination Peek
```tsx
<QuickPreview visible={visible} onClose={onClose}>
<Image source={{ uri: destination.image }} style={{ width: '100%', height: 200 }} />
<Text>{destination.title}</Text>
<Text>From ${destination.price}</Text>
</QuickPreview>
```
## ποΈ API Reference
### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `visible` | `boolean` | **required** | Controls modal visibility |
| `onClose` | `() => void` | **required** | Called when modal closes |
| `onPressCard` | `() => void` | `undefined` | Card press handler |
| `children` | `React.ReactNode` | `undefined` | Content to render |
| `theme` | `'light' \| 'dark'` | `'light'` | Overlay theme |
| `backdropOpacity` | `number` | `0.5 / 0.8` | Overlay opacity |
| `animationDuration` | `number` | `220` | Animation duration |
| `closeOnBackdropPress` | `boolean` | `true` | Close on backdrop press |
| `closeOnBackButton` | `boolean` | `true` | Close on Android back button |
| `enableSwipeToClose` | `boolean` | `true` | Swipe down to close |
| `swipeThreshold` | `number` | `80` | Swipe distance threshold |
| `unmountOnExit` | `boolean` | `true` | Unmount when hidden |
| `avoidKeyboard` | `boolean` | `false` | Avoid keyboard overlap |
| `renderBackdrop` | `(opacity) => ReactNode` | `undefined` | Custom backdrop |
| `onBackdropPress` | `() => void` | `undefined` | Backdrop press handler |
| `testID` | `string` | `'quickpreview'` | Test identifier |
| `accessibilityLabel` | `string` | `'Quick look'` | A11y label |
| `stylesOverride` | `object` | `{}` | Override default styles |
## π¨ Customization
### Custom Backdrop
```tsx
<QuickPreview
visible={visible}
onClose={onClose}
renderBackdrop={(opacity) => (
<Animated.View style={[StyleSheet.absoluteFill, { backgroundColor: 'rgba(255,0,0,0.5)', opacity }]} />
)}
>
{/* content */}
</QuickPreview>
```
### Custom Styles
```tsx
<QuickPreview
visible={visible}
onClose={onClose}
stylesOverride={{
container: { borderRadius: 24, backgroundColor: '#000' },
overlay: { backgroundColor: 'rgba(0,0,0,0.9)' }
}}
>
{/* content */}
</QuickPreview>
```
## π§ͺ Testing
```tsx
import { render, fireEvent } from '@testing-library/react-native';
test('QuickPreview closes on backdrop press', () => {
const onClose = jest.fn();
const { getByTestId } = render(
<QuickPreview visible={true} onClose={onClose} testID="quickpreview">
<Text>Test content</Text>
</QuickPreview>
);
fireEvent.press(getByTestId('ql-backdrop'));
expect(onClose).toHaveBeenCalled();
});
```
## π± Platform Support
- β
iOS 12+
- β
Android API 21+
- β
Expo SDK 48+
## π License
MIT Β© Oliver Lindblad