svelte-swipeout
Version:
iOS-style swipeable list component for Svelte 5 with delete animations and mobile-optimized touch handling
303 lines (238 loc) • 7.78 kB
Markdown
# Enhanced Swipeout Component for Svelte 5
A production-ready, accessible, and performant swipe-to-reveal actions component for Svelte 5 applications. Inspired by iOS Mail and Gmail mobile interfaces.
## ✨ Features
### Core Functionality
- 🎯 **Smooth Gesture Detection** - Advanced touch and mouse gesture recognition with velocity tracking
- 📱 **Mobile-First Design** - Optimized for touch devices with proper touch target sizes
- ⚡ **High Performance** - 60fps animations using CSS transforms and requestAnimationFrame
- 🎨 **Fully Themeable** - CSS variables for complete customization
- ♿ **Accessible** - Full keyboard navigation and screen reader support
- 🌗 **Dark Mode Ready** - Automatic dark mode adaptation
### Advanced Features
- 🔄 **State Management** - Built-in state machine for predictable behavior
- 🎭 **Multiple Actions** - Support for multiple actions on both sides
- ✨ **Overswipe Actions** - Trigger immediate actions with full swipe
- 🔔 **Haptic Feedback** - Native haptic feedback on supported devices
- 🎯 **Snap Points** - Configurable snap positions for partial reveals
- 🔒 **Confirmation Mode** - Require confirmation for destructive actions
- 📊 **Loading States** - Built-in loading indicators for async actions
- 🎪 **Spring Animations** - Physics-based animations for natural feel
## 📦 Installation
```bash
npm install @your-org/svelte-swipeout
# or
pnpm add @your-org/svelte-swipeout
```
## 🚀 Quick Start
```svelte
<script lang="ts">
import {
Swipeout,
SwipeoutItem,
SwipeoutContent,
SwipeoutActionsRight,
SwipeoutAction
} from '@your-org/svelte-swipeout';
import { Trash2 } from 'lucide-svelte';
function handleDelete() {
console.log('Item deleted');
}
</script>
<Swipeout>
<SwipeoutItem>
<SwipeoutContent>
<div class="p-4">
<h3>Swipe me!</h3>
<p>Reveal actions by swiping</p>
</div>
</SwipeoutContent>
<SwipeoutActionsRight>
<SwipeoutAction
icon={Trash2}
label="Delete"
type="destructive"
onclick={handleDelete}
/>
</SwipeoutActionsRight>
</SwipeoutItem>
</Swipeout>
```
## 📖 API Reference
### `<Swipeout>` Component
The container component that provides context and configuration.
#### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `threshold` | `number` | `40` | Minimum distance (px) to trigger swipe |
| `velocityThreshold` | `number` | `0.3` | Minimum velocity to trigger swipe |
| `animationDuration` | `number` | `300` | Animation duration in milliseconds |
| `animationType` | `'spring' \| 'ease' \| 'linear'` | `'ease'` | Animation easing type |
| `rubberBand` | `boolean` | `true` | Enable rubber band effect on overswipe |
| `closeOnOpen` | `boolean` | `true` | Close other items when opening |
| `hapticFeedback` | `boolean` | `false` | Enable haptic feedback |
| `snapPoints` | `number[]` | `[0.5, 1]` | Snap points as percentages |
| `keyboardNavigation` | `boolean` | `true` | Enable keyboard navigation |
| `disabled` | `boolean` | `false` | Disable all interactions |
#### Events
- `onSwipeStart` - Fired when swipe begins
- `onSwipeMove` - Fired during swipe movement
- `onSwipeEnd` - Fired when swipe ends
- `onOpen` - Fired when item opens
- `onClose` - Fired when item closes
#### Methods
```javascript
// Get reference to component
let swipeoutRef;
// Available methods
swipeoutRef.closeAll();
swipeoutRef.closeItem(id);
swipeoutRef.openItem(id, 'left' | 'right');
```
### `<SwipeoutItem>` Component
Individual swipeable item container.
#### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `disabled` | `boolean` | `false` | Disable this item |
| `autoCloseOnAction` | `boolean` | `true` | Close after action triggered |
| `confirmDelete` | `boolean` | `false` | Require confirmation for delete |
| `snapPoints` | `number[]` | `undefined` | Custom snap points for this item |
| `maxSwipeDistance` | `number` | `undefined` | Maximum swipe distance in pixels |
| `ariaLabel` | `string` | `undefined` | Accessibility label |
### `<SwipeoutAction>` Component
Action button component with rich features.
#### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `type` | `'default' \| 'destructive' \| 'primary' \| 'secondary'` | `'default'` | Action type for styling |
| `icon` | `Component` | `undefined` | Icon component |
| `label` | `string` | `undefined` | Text label |
| `color` | `string` | `undefined` | Custom background color |
| `overSwipe` | `boolean` | `false` | Enable overswipe trigger |
| `requireConfirm` | `boolean` | `false` | Require confirmation |
| `confirmMessage` | `string` | `'Are you sure?'` | Confirmation message |
| `loading` | `boolean` | `false` | Show loading state |
| `disabled` | `boolean` | `false` | Disable action |
| `width` | `number` | `undefined` | Custom width in pixels |
## 🎨 Theming
### CSS Variables
```css
:root {
/* Colors */
--swipeout-delete-button-bg-color: #ff3b30;
--swipeout-primary-button-bg-color: #007aff;
--swipeout-secondary-button-bg-color: #8e8e93;
--swipeout-button-text-color: #fff;
/* Sizing */
--swipeout-button-padding-horizontal: 30px;
--swipeout-button-min-width: 80px;
/* Animation */
--swipeout-animation-duration: 300ms;
--swipeout-animation-timing: cubic-bezier(0.4, 0, 0.2, 1);
/* Interaction */
--swipeout-threshold: 40px;
--swipeout-rubber-band-tension: 0.8;
}
```
### Dark Mode
The component automatically adapts to dark mode:
```css
@media (prefers-color-scheme: dark) {
.swipeout-content {
background: var(--background, #1a1a1a);
}
}
```
## ⌨️ Keyboard Navigation
| Key | Action |
|-----|--------|
| `Delete` / `Backspace` | Trigger delete action if available |
| `ArrowLeft` | Open left actions |
| `ArrowRight` | Open right actions |
| `Escape` | Close all open items |
| `Tab` | Navigate between items |
| `Enter` / `Space` | Activate focused action |
## ♿ Accessibility
- Full ARIA attributes support
- Keyboard navigation
- Screen reader announcements
- Focus management
- Minimum touch target sizes (44x44px on mobile)
- Reduced motion support
- High contrast mode support
## 🎯 Advanced Examples
### With Icon Actions
```svelte
<SwipeoutAction
icon={Archive}
label="Archive"
type="primary"
onclick={handleArchive}
/>
```
### With Confirmation
```svelte
<SwipeoutAction
icon={Trash2}
label="Delete"
type="destructive"
requireConfirm={true}
confirmMessage="Delete this item?"
onclick={handleDelete}
/>
```
### Overswipe Action
```svelte
<SwipeoutAction
icon={Check}
label="Complete"
overSwipe={true}
onclick={handleComplete}
/>
```
### Custom Styled
```svelte
<Swipeout
style="--swipeout-primary-button-bg-color: #8b5cf6;"
>
<!-- content -->
</Swipeout>
```
## 🔧 TypeScript Support
Full TypeScript support with exported types:
```typescript
import type {
SwipeoutProps,
SwipeoutItemProps,
SwipeoutActionProps,
SwipeDirection,
SwipeState,
SwipeEventDetail
} from '@your-org/svelte-swipeout';
```
## 📱 Browser Support
- iOS Safari 12+
- Chrome 80+
- Firefox 75+
- Edge 80+
- Samsung Internet 12+
## 🎭 Performance
- Hardware-accelerated animations
- Passive event listeners
- RequestAnimationFrame for smooth updates
- Efficient state management
- Minimal re-renders
- CSS containment for better paint performance
## 🤝 Contributing
Contributions are welcome! Please read our contributing guidelines.
## 📄 License
MIT © Your Organization
## 🙏 Credits
Inspired by:
- iOS Mail app
- Gmail mobile app
- Material Design swipe patterns
Built with:
- Svelte 5
- TypeScript
- Tailwind CSS