@umituz/react-native-design-system 2.6.94 → 2.6.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/atoms/AtomicAvatar.README.md +284 -397
- package/src/atoms/AtomicBadge.README.md +123 -358
- package/src/atoms/AtomicCard.README.md +358 -247
- package/src/atoms/AtomicDatePicker.README.md +127 -332
- package/src/atoms/AtomicFab.README.md +194 -352
- package/src/atoms/AtomicIcon.README.md +241 -274
- package/src/atoms/AtomicProgress.README.md +100 -338
- package/src/atoms/AtomicSpinner.README.md +304 -337
- package/src/atoms/AtomicText.README.md +153 -389
- package/src/atoms/AtomicTextArea.README.md +267 -268
- package/src/atoms/EmptyState.README.md +247 -292
- package/src/atoms/GlassView/README.md +313 -444
- package/src/atoms/button/README.md +186 -297
- package/src/atoms/button/STRATEGY.md +252 -0
- package/src/atoms/chip/README.md +242 -290
- package/src/atoms/input/README.md +296 -290
- package/src/atoms/picker/README.md +278 -309
- package/src/atoms/skeleton/AtomicSkeleton.README.md +394 -252
- package/src/molecules/BaseModal/README.md +356 -0
- package/src/molecules/BaseModal.README.md +324 -200
- package/src/molecules/ConfirmationModal.README.md +349 -302
- package/src/molecules/Divider/README.md +293 -376
- package/src/molecules/FormField.README.md +321 -534
- package/src/molecules/GlowingCard/GlowingCard.tsx +1 -1
- package/src/molecules/GlowingCard/README.md +230 -372
- package/src/molecules/List/README.md +281 -488
- package/src/molecules/ListItem.README.md +320 -315
- package/src/molecules/SearchBar/README.md +332 -430
- package/src/molecules/StepHeader/README.md +311 -411
- package/src/molecules/StepProgress/README.md +281 -448
- package/src/molecules/alerts/README.md +272 -355
- package/src/molecules/avatar/README.md +295 -356
- package/src/molecules/bottom-sheet/README.md +303 -340
- package/src/molecules/calendar/README.md +301 -265
- package/src/molecules/countdown/README.md +347 -456
- package/src/molecules/emoji/README.md +281 -514
- package/src/molecules/listitem/README.md +307 -399
- package/src/molecules/media-card/MediaCard.tsx +31 -34
- package/src/molecules/media-card/README.md +217 -319
- package/src/molecules/navigation/README.md +263 -284
- package/src/molecules/splash/README.md +76 -80
- package/src/molecules/swipe-actions/README.md +376 -588
|
@@ -1,672 +1,460 @@
|
|
|
1
1
|
# Swipe Actions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Swipeable action buttons for list items that reveal quick actions (delete, edit, archive, etc.) when users swipe left or right.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Import & Usage
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- 📳 **Haptic Feedback**: Built-in haptic feedback support
|
|
10
|
-
- 🎯 **Multiple Actions**: Support for multiple actions
|
|
11
|
-
- 🔄 **Animated**: Smooth swipe animations
|
|
12
|
-
- ♿ **Accessible**: Full accessibility support
|
|
13
|
-
- 🎭 **Icon & Label**: Visual icons and text labels
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
```tsx
|
|
18
|
-
import { SwipeActionButton } from 'react-native-design-system';
|
|
7
|
+
```typescript
|
|
8
|
+
import { SwipeActionButton } from 'react-native-design-system/src/molecules/swipe-actions';
|
|
19
9
|
```
|
|
20
10
|
|
|
11
|
+
**Location:** `src/molecules/swipe-actions/SwipeActionButton.tsx`
|
|
12
|
+
|
|
21
13
|
## Basic Usage
|
|
22
14
|
|
|
23
15
|
```tsx
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
import { SwipeActionButton } from 'react-native-design-system';
|
|
27
|
-
|
|
28
|
-
export const BasicExample = () => {
|
|
29
|
-
const deleteAction = {
|
|
16
|
+
<SwipeActionButton
|
|
17
|
+
action={{
|
|
30
18
|
label: 'Delete',
|
|
31
19
|
icon: 'trash-outline',
|
|
32
20
|
color: '#ef4444',
|
|
33
|
-
onPress:
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
position={0}
|
|
40
|
-
totalActions={1}
|
|
41
|
-
direction="right"
|
|
42
|
-
/>
|
|
43
|
-
);
|
|
44
|
-
};
|
|
21
|
+
onPress: handleDelete,
|
|
22
|
+
}}
|
|
23
|
+
position={0}
|
|
24
|
+
totalActions={1}
|
|
25
|
+
direction="right"
|
|
26
|
+
/>
|
|
45
27
|
```
|
|
46
28
|
|
|
47
|
-
##
|
|
29
|
+
## Strategy
|
|
30
|
+
|
|
31
|
+
**Purpose**: Provide quick actions for list items through intuitive swipe gestures, improving efficiency in list interactions.
|
|
32
|
+
|
|
33
|
+
**When to Use**:
|
|
34
|
+
- Email clients (archive, delete, mark read)
|
|
35
|
+
- Task management (complete, snooze, delete)
|
|
36
|
+
- File managers (share, rename, delete)
|
|
37
|
+
- Message threads (reply, forward, delete)
|
|
38
|
+
- Contact lists (call, message, favorite)
|
|
39
|
+
- Shopping cart (wishlist, remove)
|
|
40
|
+
|
|
41
|
+
**When NOT to Use**:
|
|
42
|
+
- For critical confirmations (use modal instead)
|
|
43
|
+
- For complex multi-step actions
|
|
44
|
+
- For actions that require additional input
|
|
45
|
+
- For primary actions (use main buttons instead)
|
|
46
|
+
|
|
47
|
+
## Rules
|
|
48
|
+
|
|
49
|
+
### Required
|
|
50
|
+
|
|
51
|
+
1. **MUST** provide an `action` object with label, icon, and onPress
|
|
52
|
+
2. **MUST** specify `position` and `totalActions` for proper sizing
|
|
53
|
+
3. **MUST** specify `direction` (left or right swipe)
|
|
54
|
+
4. **ALWAYS** use haptic feedback for better UX
|
|
55
|
+
5. **SHOULD** limit to 2-3 actions per direction
|
|
56
|
+
6. **MUST** have clear, descriptive labels
|
|
57
|
+
7. **NEVER** use swipe actions for critical destructive actions without confirmation
|
|
58
|
+
|
|
59
|
+
### Action Placement
|
|
60
|
+
|
|
61
|
+
1. **Right swipe**: Destructive actions (delete, remove)
|
|
62
|
+
2. **Left swipe**: Common actions (edit, share, archive)
|
|
63
|
+
3. **Most common**: Position closest to content
|
|
64
|
+
4. **Color coding**: Red for destructive, themed for others
|
|
65
|
+
|
|
66
|
+
### Haptic Feedback
|
|
67
|
+
|
|
68
|
+
1. **Destructive actions**: Heavy intensity
|
|
69
|
+
2. **Secondary actions**: Medium intensity
|
|
70
|
+
3. **Always enable**: Haptics improve UX
|
|
71
|
+
4. **Respect settings**: Follow system preferences
|
|
72
|
+
|
|
73
|
+
### Color Guidelines
|
|
74
|
+
|
|
75
|
+
1. **Destructive**: Red (#ef4444)
|
|
76
|
+
2. **Success**: Green (#10b981)
|
|
77
|
+
3. **Primary**: Theme primary color
|
|
78
|
+
4. **Warning**: Orange/Amber (#f59e0b)
|
|
79
|
+
|
|
80
|
+
## Forbidden
|
|
81
|
+
|
|
82
|
+
❌ **NEVER** do these:
|
|
48
83
|
|
|
49
84
|
```tsx
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
};
|
|
85
|
+
// ❌ Missing required props
|
|
86
|
+
<SwipeActionButton
|
|
87
|
+
action={{ label: 'Delete' }}
|
|
88
|
+
// Missing position, totalActions, direction
|
|
89
|
+
/>
|
|
56
90
|
|
|
91
|
+
// ❌ Destructive action without confirmation
|
|
57
92
|
<SwipeActionButton
|
|
58
|
-
action={
|
|
93
|
+
action={{
|
|
94
|
+
label: 'Delete',
|
|
95
|
+
icon: 'trash-outline',
|
|
96
|
+
onPress: () => deleteAccount() // ❌ No confirmation
|
|
97
|
+
}}
|
|
59
98
|
position={0}
|
|
60
99
|
totalActions={1}
|
|
61
100
|
direction="right"
|
|
62
101
|
/>
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Theme Color
|
|
66
102
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
103
|
+
// ❌ Too many actions
|
|
104
|
+
<SwipeActionButton
|
|
105
|
+
action={action1}
|
|
106
|
+
position={0}
|
|
107
|
+
totalActions={5} // ❌ Too many
|
|
108
|
+
direction="left"
|
|
109
|
+
/>
|
|
74
110
|
|
|
111
|
+
// ❌ Vague labels
|
|
75
112
|
<SwipeActionButton
|
|
76
|
-
action={
|
|
113
|
+
action={{
|
|
114
|
+
label: 'OK', // ❌ Not descriptive
|
|
115
|
+
icon: 'checkmark-outline',
|
|
116
|
+
onPress: handleOK,
|
|
117
|
+
}}
|
|
77
118
|
position={0}
|
|
78
119
|
totalActions={1}
|
|
79
120
|
direction="left"
|
|
80
121
|
/>
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## With Haptics
|
|
84
122
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
123
|
+
// ❌ No haptic feedback
|
|
124
|
+
<SwipeActionButton
|
|
125
|
+
action={{
|
|
126
|
+
label: 'Delete',
|
|
127
|
+
icon: 'trash-outline',
|
|
128
|
+
enableHaptics: false, // ❌ Should have haptics
|
|
129
|
+
onPress: handleDelete,
|
|
130
|
+
}}
|
|
131
|
+
position={0}
|
|
132
|
+
totalActions={1}
|
|
133
|
+
direction="right"
|
|
134
|
+
/>
|
|
94
135
|
|
|
136
|
+
// ❌ Wrong color semantics
|
|
95
137
|
<SwipeActionButton
|
|
96
|
-
action={
|
|
138
|
+
action={{
|
|
139
|
+
label: 'Delete',
|
|
140
|
+
color: '#10b981', // ❌ Green for delete
|
|
141
|
+
onPress: handleDelete,
|
|
142
|
+
}}
|
|
97
143
|
position={0}
|
|
98
144
|
totalActions={1}
|
|
99
145
|
direction="right"
|
|
100
146
|
/>
|
|
101
147
|
```
|
|
102
148
|
|
|
103
|
-
##
|
|
149
|
+
## Best Practices
|
|
104
150
|
|
|
105
151
|
### Email Actions
|
|
106
152
|
|
|
153
|
+
✅ **DO**:
|
|
107
154
|
```tsx
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<>
|
|
123
|
-
{/* Right swipe actions */}
|
|
124
|
-
<SwipeActionButton
|
|
125
|
-
action={{
|
|
126
|
-
label: 'Archive',
|
|
127
|
-
icon: 'archive-outline',
|
|
128
|
-
colorKey: 'primary',
|
|
129
|
-
onPress: handleArchive,
|
|
130
|
-
}}
|
|
131
|
-
position={0}
|
|
132
|
-
totalActions={2}
|
|
133
|
-
direction="right"
|
|
134
|
-
/>
|
|
135
|
-
|
|
136
|
-
<SwipeActionButton
|
|
137
|
-
action={{
|
|
138
|
-
label: 'Delete',
|
|
139
|
-
icon: 'trash-outline',
|
|
140
|
-
colorKey: 'error',
|
|
141
|
-
onPress: handleDelete,
|
|
142
|
-
}}
|
|
143
|
-
position={1}
|
|
144
|
-
totalActions={2}
|
|
145
|
-
direction="right"
|
|
146
|
-
/>
|
|
147
|
-
</>
|
|
148
|
-
);
|
|
149
|
-
};
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Task Actions
|
|
153
|
-
|
|
154
|
-
```tsx
|
|
155
|
-
export const TaskSwipeActions = ({ taskId }) => {
|
|
156
|
-
const handleComplete = async () => {
|
|
157
|
-
await completeTask(taskId);
|
|
158
|
-
showSuccessToast('Task completed!');
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const handleSnooze = async () => {
|
|
162
|
-
await snoozeTask(taskId);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
return (
|
|
166
|
-
<>
|
|
167
|
-
<SwipeActionButton
|
|
168
|
-
action={{
|
|
169
|
-
label: 'Complete',
|
|
170
|
-
icon: 'checkmark-circle-outline',
|
|
171
|
-
colorKey: 'success',
|
|
172
|
-
enableHaptics: true,
|
|
173
|
-
hapticsIntensity: 'Heavy',
|
|
174
|
-
onPress: handleComplete,
|
|
175
|
-
}}
|
|
176
|
-
position={0}
|
|
177
|
-
totalActions={1}
|
|
178
|
-
direction="right"
|
|
179
|
-
/>
|
|
180
|
-
|
|
181
|
-
<SwipeActionButton
|
|
182
|
-
action={{
|
|
183
|
-
label: 'Snooze',
|
|
184
|
-
icon: 'time-outline',
|
|
185
|
-
colorKey: 'warning',
|
|
186
|
-
onPress: handleSnooze,
|
|
187
|
-
}}
|
|
188
|
-
position={0}
|
|
189
|
-
totalActions={1}
|
|
190
|
-
direction="left"
|
|
191
|
-
/>
|
|
192
|
-
</>
|
|
193
|
-
);
|
|
194
|
-
};
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### Message Actions
|
|
198
|
-
|
|
199
|
-
```tsx
|
|
200
|
-
export const MessageSwipeActions = ({ message }) => {
|
|
201
|
-
const handleReply = () => {
|
|
202
|
-
navigation.navigate('Reply', { messageId: message.id });
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const handleForward = () => {
|
|
206
|
-
navigation.navigate('Forward', { messageId: message.id });
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
const handleDelete = async () => {
|
|
210
|
-
showAlert({
|
|
211
|
-
variant: 'error',
|
|
212
|
-
title: 'Delete Message',
|
|
213
|
-
message: 'Are you sure you want to delete this message?',
|
|
214
|
-
onConfirm: async () => {
|
|
215
|
-
await deleteMessage(message.id);
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
return (
|
|
221
|
-
<>
|
|
222
|
-
<SwipeActionButton
|
|
223
|
-
action={{
|
|
224
|
-
label: 'Reply',
|
|
225
|
-
icon: 'arrow-undo-outline',
|
|
226
|
-
colorKey: 'primary',
|
|
227
|
-
onPress: handleReply,
|
|
228
|
-
}}
|
|
229
|
-
position={0}
|
|
230
|
-
totalActions={2}
|
|
231
|
-
direction="left"
|
|
232
|
-
/>
|
|
233
|
-
|
|
234
|
-
<SwipeActionButton
|
|
235
|
-
action={{
|
|
236
|
-
label: 'Forward',
|
|
237
|
-
icon: 'arrow-redo-outline',
|
|
238
|
-
colorKey: 'primary',
|
|
239
|
-
onPress: handleForward,
|
|
240
|
-
}}
|
|
241
|
-
position={1}
|
|
242
|
-
totalActions={2}
|
|
243
|
-
direction="left"
|
|
244
|
-
/>
|
|
245
|
-
|
|
246
|
-
<SwipeActionButton
|
|
247
|
-
action={{
|
|
248
|
-
label: 'Delete',
|
|
249
|
-
icon: 'trash-outline',
|
|
250
|
-
colorKey: 'error',
|
|
251
|
-
onPress: handleDelete,
|
|
252
|
-
}}
|
|
253
|
-
position={0}
|
|
254
|
-
totalActions={1}
|
|
255
|
-
direction="right"
|
|
256
|
-
/>
|
|
257
|
-
</>
|
|
258
|
-
);
|
|
259
|
-
};
|
|
155
|
+
<SwipeActionButton
|
|
156
|
+
action={{
|
|
157
|
+
label: 'Archive',
|
|
158
|
+
icon: 'archive-outline',
|
|
159
|
+
colorKey: 'primary',
|
|
160
|
+
enableHaptics: true,
|
|
161
|
+
hapticsIntensity: 'Medium',
|
|
162
|
+
onPress: handleArchive,
|
|
163
|
+
}}
|
|
164
|
+
position={0}
|
|
165
|
+
totalActions={2}
|
|
166
|
+
direction="right"
|
|
167
|
+
/>
|
|
260
168
|
```
|
|
261
169
|
|
|
262
|
-
|
|
263
|
-
|
|
170
|
+
❌ **DON'T**:
|
|
264
171
|
```tsx
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
showToast({
|
|
277
|
-
variant: 'success',
|
|
278
|
-
title: contact.isFavorite ? 'Removed from Favorites' : 'Added to Favorites',
|
|
279
|
-
});
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
return (
|
|
283
|
-
<>
|
|
284
|
-
<SwipeActionButton
|
|
285
|
-
action={{
|
|
286
|
-
label: 'Call',
|
|
287
|
-
icon: 'call-outline',
|
|
288
|
-
colorKey: 'success',
|
|
289
|
-
onPress: handleCall,
|
|
290
|
-
}}
|
|
291
|
-
position={0}
|
|
292
|
-
totalActions={2}
|
|
293
|
-
direction="left"
|
|
294
|
-
/>
|
|
295
|
-
|
|
296
|
-
<SwipeActionButton
|
|
297
|
-
action={{
|
|
298
|
-
label: 'Message',
|
|
299
|
-
icon: 'chatbubble-outline',
|
|
300
|
-
colorKey: 'primary',
|
|
301
|
-
onPress: handleMessage,
|
|
302
|
-
}}
|
|
303
|
-
position={1}
|
|
304
|
-
totalActions={2}
|
|
305
|
-
direction="left"
|
|
306
|
-
/>
|
|
307
|
-
|
|
308
|
-
<SwipeActionButton
|
|
309
|
-
action={{
|
|
310
|
-
label: contact.isFavorite ? 'Unfavorite' : 'Favorite',
|
|
311
|
-
icon: contact.isFavorite ? 'heart' : 'heart-outline',
|
|
312
|
-
colorKey: contact.isFavorite ? 'error' : 'error',
|
|
313
|
-
onPress: handleFavorite,
|
|
314
|
-
}}
|
|
315
|
-
position={0}
|
|
316
|
-
totalActions={1}
|
|
317
|
-
direction="right"
|
|
318
|
-
/>
|
|
319
|
-
</>
|
|
320
|
-
);
|
|
321
|
-
};
|
|
172
|
+
// ❌ Delete without confirmation
|
|
173
|
+
<SwipeActionButton
|
|
174
|
+
action={{
|
|
175
|
+
label: 'Delete',
|
|
176
|
+
icon: 'trash-outline',
|
|
177
|
+
onPress: () => deleteEmail() // No confirmation
|
|
178
|
+
}}
|
|
179
|
+
position={0}
|
|
180
|
+
totalActions={1}
|
|
181
|
+
direction="right"
|
|
182
|
+
/>
|
|
322
183
|
```
|
|
323
184
|
|
|
324
|
-
###
|
|
185
|
+
### Task Completion
|
|
325
186
|
|
|
187
|
+
✅ **DO**:
|
|
326
188
|
```tsx
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
message: `Are you sure you want to delete ${file.name}?`,
|
|
341
|
-
onConfirm: async () => {
|
|
342
|
-
await deleteFile(file.id);
|
|
343
|
-
},
|
|
344
|
-
});
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
return (
|
|
348
|
-
<>
|
|
349
|
-
<SwipeActionButton
|
|
350
|
-
action={{
|
|
351
|
-
label: 'Share',
|
|
352
|
-
icon: 'share-outline',
|
|
353
|
-
colorKey: 'primary',
|
|
354
|
-
onPress: handleShare,
|
|
355
|
-
}}
|
|
356
|
-
position={0}
|
|
357
|
-
totalActions={2}
|
|
358
|
-
direction="left"
|
|
359
|
-
/>
|
|
360
|
-
|
|
361
|
-
<SwipeActionButton
|
|
362
|
-
action={{
|
|
363
|
-
label: 'Rename',
|
|
364
|
-
icon: 'create-outline',
|
|
365
|
-
colorKey: 'tertiary',
|
|
366
|
-
onPress: handleRename,
|
|
367
|
-
}}
|
|
368
|
-
position={1}
|
|
369
|
-
totalActions={2}
|
|
370
|
-
direction="left"
|
|
371
|
-
/>
|
|
372
|
-
|
|
373
|
-
<SwipeActionButton
|
|
374
|
-
action={{
|
|
375
|
-
label: 'Delete',
|
|
376
|
-
icon: 'trash-outline',
|
|
377
|
-
colorKey: 'error',
|
|
378
|
-
onPress: handleDelete,
|
|
379
|
-
}}
|
|
380
|
-
position={0}
|
|
381
|
-
totalActions={1}
|
|
382
|
-
direction="right"
|
|
383
|
-
/>
|
|
384
|
-
</>
|
|
385
|
-
);
|
|
386
|
-
};
|
|
189
|
+
<SwipeActionButton
|
|
190
|
+
action={{
|
|
191
|
+
label: 'Complete',
|
|
192
|
+
icon: 'checkmark-circle-outline',
|
|
193
|
+
colorKey: 'success',
|
|
194
|
+
enableHaptics: true,
|
|
195
|
+
hapticsIntensity: 'Heavy',
|
|
196
|
+
onPress: handleComplete,
|
|
197
|
+
}}
|
|
198
|
+
position={0}
|
|
199
|
+
totalActions={1}
|
|
200
|
+
direction="right"
|
|
201
|
+
/>
|
|
387
202
|
```
|
|
388
203
|
|
|
389
|
-
###
|
|
204
|
+
### Action Organization
|
|
390
205
|
|
|
206
|
+
✅ **DO**:
|
|
391
207
|
```tsx
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
showToast({
|
|
400
|
-
variant: 'info',
|
|
401
|
-
title: 'Notification muted',
|
|
402
|
-
});
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
const handleDelete = async () => {
|
|
406
|
-
await deleteNotification(notification.id);
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
return (
|
|
410
|
-
<>
|
|
411
|
-
<SwipeActionButton
|
|
412
|
-
action={{
|
|
413
|
-
label: 'Mark Read',
|
|
414
|
-
icon: 'checkmark-done-outline',
|
|
415
|
-
colorKey: 'success',
|
|
416
|
-
onPress: handleMarkRead,
|
|
417
|
-
}}
|
|
418
|
-
position={0}
|
|
419
|
-
totalActions={2}
|
|
420
|
-
direction="left"
|
|
421
|
-
/>
|
|
422
|
-
|
|
423
|
-
<SwipeActionButton
|
|
424
|
-
action={{
|
|
425
|
-
label: 'Mute',
|
|
426
|
-
icon: 'volume-mute-outline',
|
|
427
|
-
colorKey: 'warning',
|
|
428
|
-
onPress: handleMute,
|
|
429
|
-
}}
|
|
430
|
-
position={1}
|
|
431
|
-
totalActions={2}
|
|
432
|
-
direction="left"
|
|
433
|
-
/>
|
|
434
|
-
|
|
435
|
-
<SwipeActionButton
|
|
436
|
-
action={{
|
|
437
|
-
label: 'Delete',
|
|
438
|
-
icon: 'trash-outline',
|
|
439
|
-
colorKey: 'error',
|
|
440
|
-
onPress: handleDelete,
|
|
441
|
-
}}
|
|
442
|
-
position={0}
|
|
443
|
-
totalActions={1}
|
|
444
|
-
direction="right"
|
|
445
|
-
/>
|
|
446
|
-
</>
|
|
447
|
-
);
|
|
448
|
-
};
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
### Cart Item Actions
|
|
208
|
+
// ✅ Right swipe - destructive
|
|
209
|
+
<SwipeActionButton
|
|
210
|
+
action={{ label: 'Delete', icon: 'trash-outline', colorKey: 'error' }}
|
|
211
|
+
position={0}
|
|
212
|
+
totalActions={1}
|
|
213
|
+
direction="right"
|
|
214
|
+
/>
|
|
452
215
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
title: 'Remove Item',
|
|
467
|
-
message: 'Remove this item from your cart?',
|
|
468
|
-
onConfirm: async () => {
|
|
469
|
-
await removeFromCart(item.id);
|
|
470
|
-
},
|
|
471
|
-
});
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
return (
|
|
475
|
-
<>
|
|
476
|
-
<SwipeActionButton
|
|
477
|
-
action={{
|
|
478
|
-
label: 'Wishlist',
|
|
479
|
-
icon: 'heart-outline',
|
|
480
|
-
colorKey: 'error',
|
|
481
|
-
onPress: handleMoveToWishlist,
|
|
482
|
-
}}
|
|
483
|
-
position={0}
|
|
484
|
-
totalActions={1}
|
|
485
|
-
direction="left"
|
|
486
|
-
/>
|
|
487
|
-
|
|
488
|
-
<SwipeActionButton
|
|
489
|
-
action={{
|
|
490
|
-
label: 'Remove',
|
|
491
|
-
icon: 'trash-outline',
|
|
492
|
-
colorKey: 'error',
|
|
493
|
-
onPress: handleRemove,
|
|
494
|
-
}}
|
|
495
|
-
position={0}
|
|
496
|
-
totalActions={1}
|
|
497
|
-
direction="right"
|
|
498
|
-
/>
|
|
499
|
-
</>
|
|
500
|
-
);
|
|
501
|
-
};
|
|
216
|
+
// ✅ Left swipe - common actions
|
|
217
|
+
<SwipeActionButton
|
|
218
|
+
action={{ label: 'Edit', icon: 'create-outline', colorKey: 'primary' }}
|
|
219
|
+
position={0}
|
|
220
|
+
totalActions={2}
|
|
221
|
+
direction="left"
|
|
222
|
+
/>
|
|
223
|
+
<SwipeActionButton
|
|
224
|
+
action={{ label: 'Share', icon: 'share-outline', colorKey: 'primary' }}
|
|
225
|
+
position={1}
|
|
226
|
+
totalActions={2}
|
|
227
|
+
direction="left"
|
|
228
|
+
/>
|
|
502
229
|
```
|
|
503
230
|
|
|
504
|
-
|
|
505
|
-
|
|
231
|
+
## AI Coding Guidelines
|
|
232
|
+
|
|
233
|
+
### For AI Agents
|
|
234
|
+
|
|
235
|
+
When generating SwipeActionButton components, follow these rules:
|
|
236
|
+
|
|
237
|
+
1. **Always import from correct path**:
|
|
238
|
+
```typescript
|
|
239
|
+
import { SwipeActionButton } from 'react-native-design-system/src/molecules/swipe-actions';
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
2. **Always provide all required props**:
|
|
243
|
+
```tsx
|
|
244
|
+
<SwipeActionButton
|
|
245
|
+
action={{
|
|
246
|
+
label: '具体的动作名称',
|
|
247
|
+
icon: '合适的图标',
|
|
248
|
+
colorKey: '根据动作类型选择颜色',
|
|
249
|
+
enableHaptics: true,
|
|
250
|
+
onPress: 具体处理函数,
|
|
251
|
+
}}
|
|
252
|
+
position={位置索引}
|
|
253
|
+
totalActions={该方向的总动作数}
|
|
254
|
+
direction="left 或 right"
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
3. **Always add confirmation for destructive actions**:
|
|
259
|
+
```tsx
|
|
260
|
+
// ✅ Good - with confirmation
|
|
261
|
+
action={{
|
|
262
|
+
label: 'Delete',
|
|
263
|
+
icon: 'trash-outline',
|
|
264
|
+
colorKey: 'error',
|
|
265
|
+
onPress: () => {
|
|
266
|
+
Alert.alert(
|
|
267
|
+
'Confirm Delete',
|
|
268
|
+
'This action cannot be undone',
|
|
269
|
+
[
|
|
270
|
+
{ text: 'Cancel', style: 'cancel' },
|
|
271
|
+
{ text: 'Delete', style: 'destructive', onPress: handleDelete },
|
|
272
|
+
]
|
|
273
|
+
);
|
|
274
|
+
},
|
|
275
|
+
}}
|
|
276
|
+
|
|
277
|
+
// ❌ Bad - immediate action
|
|
278
|
+
action={{
|
|
279
|
+
label: 'Delete',
|
|
280
|
+
onPress: handleDelete, // No confirmation
|
|
281
|
+
}}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
4. **Always use semantic colors**:
|
|
285
|
+
```tsx
|
|
286
|
+
// ✅ Good - semantic color mapping
|
|
287
|
+
const getColorByActionType = (type: 'delete' | 'edit' | 'archive') => {
|
|
288
|
+
switch (type) {
|
|
289
|
+
case 'delete': return 'error';
|
|
290
|
+
case 'edit': return 'primary';
|
|
291
|
+
case 'archive': return 'tertiary';
|
|
292
|
+
default: return 'primary';
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
5. **Always enable haptic feedback**:
|
|
298
|
+
```tsx
|
|
299
|
+
// ✅ Good - haptics enabled
|
|
300
|
+
action={{
|
|
301
|
+
label: 'Complete',
|
|
302
|
+
icon: 'checkmark-circle-outline',
|
|
303
|
+
enableHaptics: true,
|
|
304
|
+
hapticsIntensity: 'Heavy',
|
|
305
|
+
onPress: handleComplete,
|
|
306
|
+
}}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Common Patterns
|
|
310
|
+
|
|
311
|
+
#### Email Swipe Actions
|
|
506
312
|
```tsx
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
<SwipeActionButton
|
|
549
|
-
action={{
|
|
550
|
-
label: 'Reorder',
|
|
551
|
-
icon: 'refresh-outline',
|
|
552
|
-
colorKey: 'success',
|
|
553
|
-
onPress: handleReorder,
|
|
554
|
-
}}
|
|
555
|
-
position={1}
|
|
556
|
-
totalActions={2}
|
|
557
|
-
direction="left"
|
|
558
|
-
/>
|
|
559
|
-
)}
|
|
560
|
-
|
|
561
|
-
{order.canCancel && (
|
|
562
|
-
<SwipeActionButton
|
|
563
|
-
action={{
|
|
564
|
-
label: 'Cancel',
|
|
565
|
-
icon: 'close-circle-outline',
|
|
566
|
-
colorKey: 'error',
|
|
567
|
-
onPress: handleCancel,
|
|
568
|
-
}}
|
|
569
|
-
position={0}
|
|
570
|
-
totalActions={1}
|
|
571
|
-
direction="right"
|
|
572
|
-
/>
|
|
573
|
-
)}
|
|
574
|
-
</>
|
|
575
|
-
);
|
|
576
|
-
};
|
|
313
|
+
<>
|
|
314
|
+
{/* Right swipe - archive & delete */}
|
|
315
|
+
<SwipeActionButton
|
|
316
|
+
action={{
|
|
317
|
+
label: 'Archive',
|
|
318
|
+
icon: 'archive-outline',
|
|
319
|
+
colorKey: 'primary',
|
|
320
|
+
enableHaptics: true,
|
|
321
|
+
onPress: handleArchive,
|
|
322
|
+
}}
|
|
323
|
+
position={0}
|
|
324
|
+
totalActions={2}
|
|
325
|
+
direction="right"
|
|
326
|
+
/>
|
|
327
|
+
<SwipeActionButton
|
|
328
|
+
action={{
|
|
329
|
+
label: 'Delete',
|
|
330
|
+
icon: 'trash-outline',
|
|
331
|
+
colorKey: 'error',
|
|
332
|
+
enableHaptics: true,
|
|
333
|
+
onPress: () => showDeleteConfirmation(emailId),
|
|
334
|
+
}}
|
|
335
|
+
position={1}
|
|
336
|
+
totalActions={2}
|
|
337
|
+
direction="right"
|
|
338
|
+
/>
|
|
339
|
+
|
|
340
|
+
{/* Left swipe - mark read & mute */}
|
|
341
|
+
<SwipeActionButton
|
|
342
|
+
action={{
|
|
343
|
+
label: 'Mark Read',
|
|
344
|
+
icon: 'checkmark-done-outline',
|
|
345
|
+
colorKey: 'success',
|
|
346
|
+
enableHaptics: true,
|
|
347
|
+
onPress: handleMarkRead,
|
|
348
|
+
}}
|
|
349
|
+
position={0}
|
|
350
|
+
totalActions={2}
|
|
351
|
+
direction="left"
|
|
352
|
+
/>
|
|
353
|
+
</>
|
|
577
354
|
```
|
|
578
355
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
### SwipeActionButtonProps
|
|
582
|
-
|
|
583
|
-
| Prop | Type | Default | Description |
|
|
584
|
-
|------|------|---------|-------------|
|
|
585
|
-
| `action` | `SwipeActionConfig` | - **(Required)** | Action configuration |
|
|
586
|
-
| `position` | `number` | - **(Required)** | Button position index |
|
|
587
|
-
| `totalActions` | `number` | - **(Required)** | Total number of actions |
|
|
588
|
-
| `direction` | `'left' \| 'right'` | - **(Required)** | Swipe direction |
|
|
589
|
-
| `style` | `ViewStyle` | - | Custom container style |
|
|
590
|
-
|
|
591
|
-
### SwipeActionConfig
|
|
592
|
-
|
|
593
|
-
| Prop | Type | Default | Description |
|
|
594
|
-
|------|------|---------|-------------|
|
|
595
|
-
| `label` | `string` | - **(Required)** | Button label |
|
|
596
|
-
| `icon` | `string` | - **(Required)** | Icon name (Ionicons) |
|
|
597
|
-
| `onPress` | `() => void` | - **(Required)** | Press callback |
|
|
598
|
-
| `color` | `string` | - | Custom color |
|
|
599
|
-
| `colorKey` | `string` | - | Theme color key |
|
|
600
|
-
| `enableHaptics` | `boolean` | `true` | Enable haptic feedback |
|
|
601
|
-
| `hapticsIntensity` | `'Light' \| 'Medium' \| 'Heavy'` | `'Medium'` | Haptic intensity |
|
|
602
|
-
|
|
603
|
-
## Best Practices
|
|
604
|
-
|
|
605
|
-
### 1. Action Placement
|
|
606
|
-
|
|
356
|
+
#### Task Swipe Actions
|
|
607
357
|
```tsx
|
|
608
|
-
// Destructive actions on right swipe
|
|
609
358
|
<SwipeActionButton
|
|
610
|
-
action={{
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
359
|
+
action={{
|
|
360
|
+
label: 'Complete',
|
|
361
|
+
icon: 'checkmark-circle-outline',
|
|
362
|
+
colorKey: 'success',
|
|
363
|
+
enableHaptics: true,
|
|
364
|
+
hapticsIntensity: 'Heavy',
|
|
365
|
+
onPress: handleComplete,
|
|
366
|
+
}}
|
|
367
|
+
position={0}
|
|
368
|
+
totalActions={1}
|
|
369
|
+
direction="right"
|
|
618
370
|
/>
|
|
619
371
|
```
|
|
620
372
|
|
|
621
|
-
|
|
622
|
-
|
|
373
|
+
#### File Swipe Actions
|
|
623
374
|
```tsx
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}}
|
|
375
|
+
<>
|
|
376
|
+
<SwipeActionButton
|
|
377
|
+
action={{
|
|
378
|
+
label: 'Share',
|
|
379
|
+
icon: 'share-outline',
|
|
380
|
+
colorKey: 'primary',
|
|
381
|
+
enableHaptics: true,
|
|
382
|
+
onPress: handleShare,
|
|
383
|
+
}}
|
|
384
|
+
position={0}
|
|
385
|
+
totalActions={2}
|
|
386
|
+
direction="left"
|
|
387
|
+
/>
|
|
388
|
+
<SwipeActionButton
|
|
389
|
+
action={{
|
|
390
|
+
label: 'Rename',
|
|
391
|
+
icon: 'create-outline',
|
|
392
|
+
colorKey: 'tertiary',
|
|
393
|
+
enableHaptics: true,
|
|
394
|
+
onPress: handleRename,
|
|
395
|
+
}}
|
|
396
|
+
position={1}
|
|
397
|
+
totalActions={2}
|
|
398
|
+
direction="left"
|
|
399
|
+
/>
|
|
400
|
+
<SwipeActionButton
|
|
401
|
+
action={{
|
|
402
|
+
label: 'Delete',
|
|
403
|
+
icon: 'trash-outline',
|
|
404
|
+
colorKey: 'error',
|
|
405
|
+
enableHaptics: true,
|
|
406
|
+
onPress: () => showDeleteConfirmation(fileId),
|
|
407
|
+
}}
|
|
408
|
+
position={0}
|
|
409
|
+
totalActions={1}
|
|
410
|
+
direction="right"
|
|
411
|
+
/>
|
|
412
|
+
</>
|
|
633
413
|
```
|
|
634
414
|
|
|
635
|
-
|
|
415
|
+
## Props Reference
|
|
636
416
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
417
|
+
| Prop | Type | Required | Default | Description |
|
|
418
|
+
|------|------|----------|---------|-------------|
|
|
419
|
+
| `action` | `SwipeActionConfig` | **Yes** | - | Action configuration |
|
|
420
|
+
| `position` | `number` | **Yes** | - | Button position index (0-based) |
|
|
421
|
+
| `totalActions` | `number` | **Yes** | - | Total number of actions in this direction |
|
|
422
|
+
| `direction` | `'left' \| 'right'` | **Yes** | - | Swipe direction |
|
|
423
|
+
| `style` | `ViewStyle` | No | - | Custom container style |
|
|
640
424
|
|
|
641
|
-
|
|
642
|
-
label: 'OK'
|
|
643
|
-
```
|
|
425
|
+
### SwipeActionConfig
|
|
644
426
|
|
|
645
|
-
|
|
427
|
+
| Prop | Type | Required | Default | Description |
|
|
428
|
+
|------|------|----------|---------|-------------|
|
|
429
|
+
| `label` | `string` | **Yes** | - | Button label |
|
|
430
|
+
| `icon` | `string` | **Yes** | - | Icon name (Ionicons) |
|
|
431
|
+
| `onPress` | `() => void` | **Yes** | - | Press callback |
|
|
432
|
+
| `color` | `string` | No | - | Custom color (hex) |
|
|
433
|
+
| `colorKey` | `string` | No | - | Theme color key |
|
|
434
|
+
| `enableHaptics` | `boolean` | No | `true` | Enable haptic feedback |
|
|
435
|
+
| `hapticsIntensity` | `'Light' \| 'Medium' \| 'Heavy'` | No | `'Medium'` | Haptic intensity |
|
|
646
436
|
|
|
647
|
-
|
|
437
|
+
## Accessibility
|
|
648
438
|
|
|
649
|
-
- ✅ Screen reader
|
|
650
|
-
- ✅
|
|
651
|
-
- ✅
|
|
652
|
-
- ✅ Semantic
|
|
439
|
+
- ✅ Screen reader announces action label
|
|
440
|
+
- ✅ Touch target size maintained (min 44x44pt)
|
|
441
|
+
- ✅ Sufficient color contrast
|
|
442
|
+
- ✅ Semantic action roles
|
|
443
|
+
- ✅ Haptic feedback for tactile feedback
|
|
653
444
|
|
|
654
445
|
## Performance Tips
|
|
655
446
|
|
|
656
|
-
1. **
|
|
657
|
-
2. **
|
|
658
|
-
3. **Debounce**: Debounce rapid actions
|
|
447
|
+
1. **Memo action callbacks**: Use useCallback for onPress handlers
|
|
448
|
+
2. **Limit actions**: Max 2-3 actions per direction
|
|
449
|
+
3. **Debounce**: Debounce rapid swipe actions
|
|
450
|
+
4. **Optimize re-renders**: Memo action configuration objects
|
|
659
451
|
|
|
660
452
|
## Related Components
|
|
661
453
|
|
|
662
454
|
- [`ListItem`](../listitem/README.md) - List item component
|
|
663
|
-
- [`BaseModal`](../BaseModal/README.md) - Modal
|
|
455
|
+
- [`BaseModal`](../BaseModal/README.md) - Modal for confirmations
|
|
664
456
|
- [`AlertInline`](../alerts/README.md) - Alert components
|
|
665
457
|
|
|
666
|
-
## Dependencies
|
|
667
|
-
|
|
668
|
-
- `@umituz/react-native-haptics` - Haptic feedback service
|
|
669
|
-
|
|
670
458
|
## License
|
|
671
459
|
|
|
672
460
|
MIT
|