@umituz/react-native-design-system 2.6.89 → 2.6.90
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/molecules/listitem/README.md +499 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.90",
|
|
4
4
|
"description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive and safe area utilities",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
# ListItem
|
|
2
|
+
|
|
3
|
+
ListItem is a versatile list item component with title, subtitle, and optional icons. Perfect for menus, settings, navigation lists, and more.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 📝 **Title & Subtitle**: Display primary and secondary text
|
|
8
|
+
- 🎭 **Left Icon**: Icon on the left side
|
|
9
|
+
- 🔄 **Right Icon**: Icon on the right side (for navigation)
|
|
10
|
+
- 👆 **Pressable**: Optional press handler
|
|
11
|
+
- ♿ **Accessible**: Full accessibility support
|
|
12
|
+
- 🎨 **Theme-Aware**: Design token integration
|
|
13
|
+
- ⚡ **Disabled State**: Disabled styling support
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { ListItem } from 'react-native-design-system';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Basic Usage
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import React from 'react';
|
|
25
|
+
import { View } from 'react-native';
|
|
26
|
+
import { ListItem } from 'react-native-design-system';
|
|
27
|
+
|
|
28
|
+
export const BasicExample = () => {
|
|
29
|
+
return (
|
|
30
|
+
<View>
|
|
31
|
+
<ListItem
|
|
32
|
+
title="Settings"
|
|
33
|
+
onPress={() => console.log('Settings pressed')}
|
|
34
|
+
/>
|
|
35
|
+
</View>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Basic Item
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<ListItem
|
|
44
|
+
title="Profile"
|
|
45
|
+
/>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## With Subtitle
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<ListItem
|
|
52
|
+
title="John Doe"
|
|
53
|
+
subtitle="Software Engineer"
|
|
54
|
+
/>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## With Left Icon
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
<ListItem
|
|
61
|
+
title="Settings"
|
|
62
|
+
leftIcon="settings-outline"
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Pressable with Right Icon
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
<ListItem
|
|
70
|
+
title="Notifications"
|
|
71
|
+
rightIcon="chevron-forward-outline"
|
|
72
|
+
onPress={() => navigation.navigate('Notifications')}
|
|
73
|
+
/>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## With Both Icons
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<ListItem
|
|
80
|
+
title="Dark Mode"
|
|
81
|
+
leftIcon="moon-outline"
|
|
82
|
+
rightIcon="chevron-forward-outline"
|
|
83
|
+
onPress={() => {}}
|
|
84
|
+
/>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Disabled Item
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
<ListItem
|
|
91
|
+
title="Premium Feature"
|
|
92
|
+
subtitle="Upgrade to access"
|
|
93
|
+
leftIcon="diamond-outline"
|
|
94
|
+
disabled
|
|
95
|
+
/>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Example Usages
|
|
99
|
+
|
|
100
|
+
### Settings Menu
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
export const SettingsMenu = () => {
|
|
104
|
+
const menuItems = [
|
|
105
|
+
{
|
|
106
|
+
title: 'Account',
|
|
107
|
+
subtitle: 'Personal information',
|
|
108
|
+
leftIcon: 'person-outline',
|
|
109
|
+
route: 'Account',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
title: 'Notifications',
|
|
113
|
+
subtitle: 'Push notifications',
|
|
114
|
+
leftIcon: 'notifications-outline',
|
|
115
|
+
route: 'Notifications',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
title: 'Privacy',
|
|
119
|
+
subtitle: 'Privacy settings',
|
|
120
|
+
leftIcon: 'shield-checkmark-outline',
|
|
121
|
+
route: 'Privacy',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
title: 'Help',
|
|
125
|
+
subtitle: 'FAQ and support',
|
|
126
|
+
leftIcon: 'help-circle-outline',
|
|
127
|
+
route: 'Help',
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<View>
|
|
133
|
+
{menuItems.map((item, index) => (
|
|
134
|
+
<ListItem
|
|
135
|
+
key={index}
|
|
136
|
+
title={item.title}
|
|
137
|
+
subtitle={item.subtitle}
|
|
138
|
+
leftIcon={item.leftIcon}
|
|
139
|
+
rightIcon="chevron-forward-outline"
|
|
140
|
+
onPress={() => navigation.navigate(item.route)}
|
|
141
|
+
/>
|
|
142
|
+
))}
|
|
143
|
+
</View>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### User List
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
export const UserList = ({ users }) => {
|
|
152
|
+
return (
|
|
153
|
+
<View>
|
|
154
|
+
{users.map((user) => (
|
|
155
|
+
<ListItem
|
|
156
|
+
key={user.id}
|
|
157
|
+
title={user.name}
|
|
158
|
+
subtitle={user.email}
|
|
159
|
+
leftIcon="person-outline"
|
|
160
|
+
onPress={() => navigation.navigate('UserProfile', { userId: user.id })}
|
|
161
|
+
/>
|
|
162
|
+
))}
|
|
163
|
+
</View>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Navigation Menu
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
export const NavigationMenu = () => {
|
|
172
|
+
const menuItems = [
|
|
173
|
+
{ title: 'Home', icon: 'home-outline', route: 'Home' },
|
|
174
|
+
{ title: 'Search', icon: 'search-outline', route: 'Search' },
|
|
175
|
+
{ title: 'Notifications', icon: 'notifications-outline', route: 'Notifications' },
|
|
176
|
+
{ title: 'Messages', icon: 'chatbubble-outline', route: 'Messages' },
|
|
177
|
+
{ title: 'Profile', icon: 'person-outline', route: 'Profile' },
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<View>
|
|
182
|
+
{menuItems.map((item) => (
|
|
183
|
+
<ListItem
|
|
184
|
+
key={item.route}
|
|
185
|
+
title={item.title}
|
|
186
|
+
leftIcon={item.icon}
|
|
187
|
+
onPress={() => navigation.navigate(item.route)}
|
|
188
|
+
/>
|
|
189
|
+
))}
|
|
190
|
+
</View>
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Feature List
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
export const FeatureList = () => {
|
|
199
|
+
const features = [
|
|
200
|
+
{
|
|
201
|
+
title: 'Dark Mode',
|
|
202
|
+
subtitle: 'Reduce eye strain',
|
|
203
|
+
icon: 'moon-outline',
|
|
204
|
+
available: true,
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
title: 'Biometric Login',
|
|
208
|
+
subtitle: 'Face ID / Touch ID',
|
|
209
|
+
icon: 'finger-print-outline',
|
|
210
|
+
available: true,
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
title: 'Cloud Sync',
|
|
214
|
+
subtitle: 'Sync across devices',
|
|
215
|
+
icon: 'cloud-outline',
|
|
216
|
+
available: false,
|
|
217
|
+
},
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<View>
|
|
222
|
+
{features.map((feature, index) => (
|
|
223
|
+
<ListItem
|
|
224
|
+
key={index}
|
|
225
|
+
title={feature.title}
|
|
226
|
+
subtitle={feature.subtitle}
|
|
227
|
+
leftIcon={feature.icon}
|
|
228
|
+
disabled={!feature.available}
|
|
229
|
+
onPress={feature.available ? () => enableFeature(feature) : undefined}
|
|
230
|
+
rightIcon={feature.available ? 'chevron-forward-outline' : undefined}
|
|
231
|
+
/>
|
|
232
|
+
))}
|
|
233
|
+
</View>
|
|
234
|
+
);
|
|
235
|
+
};
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Action Menu
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
export const ActionMenu = ({ onAction }) => {
|
|
242
|
+
const actions = [
|
|
243
|
+
{ title: 'Edit', icon: 'create-outline', action: 'edit' },
|
|
244
|
+
{ title: 'Share', icon: 'share-outline', action: 'share' },
|
|
245
|
+
{ title: 'Delete', icon: 'trash-outline', action: 'delete' },
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<View>
|
|
250
|
+
{actions.map((action) => (
|
|
251
|
+
<ListItem
|
|
252
|
+
key={action.action}
|
|
253
|
+
title={action.title}
|
|
254
|
+
leftIcon={action.icon}
|
|
255
|
+
onPress={() => onAction(action.action)}
|
|
256
|
+
rightIcon="chevron-forward-outline"
|
|
257
|
+
/>
|
|
258
|
+
))}
|
|
259
|
+
</View>
|
|
260
|
+
);
|
|
261
|
+
};
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Contact List
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
export const ContactList = ({ contacts }) => {
|
|
268
|
+
return (
|
|
269
|
+
<View>
|
|
270
|
+
{contacts.map((contact) => (
|
|
271
|
+
<ListItem
|
|
272
|
+
key={contact.id}
|
|
273
|
+
title={contact.name}
|
|
274
|
+
subtitle={contact.phone}
|
|
275
|
+
leftIcon="person-outline"
|
|
276
|
+
rightIcon="call-outline"
|
|
277
|
+
onPress={() => Linking.openURL(`tel:${contact.phone}`)}
|
|
278
|
+
/>
|
|
279
|
+
))}
|
|
280
|
+
</View>
|
|
281
|
+
);
|
|
282
|
+
};
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### File List
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
export const FileList = ({ files }) => {
|
|
289
|
+
const getFileIcon = (fileName) => {
|
|
290
|
+
if (fileName.endsWith('.pdf')) return 'document-text-outline';
|
|
291
|
+
if (fileName.endsWith('.jpg') || fileName.endsWith('.png')) return 'image-outline';
|
|
292
|
+
if (fileName.endsWith('.mp4')) return 'videocam-outline';
|
|
293
|
+
return 'document-outline';
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<View>
|
|
298
|
+
{files.map((file) => (
|
|
299
|
+
<ListItem
|
|
300
|
+
key={file.id}
|
|
301
|
+
title={file.name}
|
|
302
|
+
subtitle={`${file.size} • ${file.date}`}
|
|
303
|
+
leftIcon={getFileIcon(file.name)}
|
|
304
|
+
onPress={() => openFile(file)}
|
|
305
|
+
rightIcon="ellipsis-vertical-outline"
|
|
306
|
+
/>
|
|
307
|
+
))}
|
|
308
|
+
</View>
|
|
309
|
+
);
|
|
310
|
+
};
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Download List
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
export const DownloadList = ({ downloads }) => {
|
|
317
|
+
return (
|
|
318
|
+
<View>
|
|
319
|
+
{downloads.map((download) => (
|
|
320
|
+
<ListItem
|
|
321
|
+
key={download.id}
|
|
322
|
+
title={download.fileName}
|
|
323
|
+
subtitle={`${download.progress}% • ${download.status}`}
|
|
324
|
+
leftIcon="download-outline"
|
|
325
|
+
disabled={download.status === 'downloading'}
|
|
326
|
+
onPress={() => {
|
|
327
|
+
if (download.status === 'completed') {
|
|
328
|
+
openDownload(download);
|
|
329
|
+
} else if (download.status === 'pending') {
|
|
330
|
+
startDownload(download);
|
|
331
|
+
}
|
|
332
|
+
}}
|
|
333
|
+
rightIcon={download.status === 'completed' ? 'checkmark-circle' : undefined}
|
|
334
|
+
/>
|
|
335
|
+
))}
|
|
336
|
+
</View>
|
|
337
|
+
);
|
|
338
|
+
};
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Selection List
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
export const SelectionList = ({ options, selectedOption, onSelect }) => {
|
|
345
|
+
return (
|
|
346
|
+
<View>
|
|
347
|
+
{options.map((option) => (
|
|
348
|
+
<ListItem
|
|
349
|
+
key={option.id}
|
|
350
|
+
title={option.title}
|
|
351
|
+
subtitle={option.subtitle}
|
|
352
|
+
leftIcon={option.icon}
|
|
353
|
+
onPress={() => onSelect(option)}
|
|
354
|
+
rightIcon={selectedOption?.id === option.id ? 'checkmark' : undefined}
|
|
355
|
+
/>
|
|
356
|
+
))}
|
|
357
|
+
</View>
|
|
358
|
+
);
|
|
359
|
+
};
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Grouped List
|
|
363
|
+
|
|
364
|
+
```tsx
|
|
365
|
+
export const GroupedList = () => {
|
|
366
|
+
const groups = [
|
|
367
|
+
{
|
|
368
|
+
title: 'Account',
|
|
369
|
+
items: [
|
|
370
|
+
{ title: 'Profile', icon: 'person-outline' },
|
|
371
|
+
{ title: 'Security', icon: 'shield-outline' },
|
|
372
|
+
],
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
title: 'Preferences',
|
|
376
|
+
items: [
|
|
377
|
+
{ title: 'Appearance', icon: 'color-palette-outline' },
|
|
378
|
+
{ title: 'Language', icon: 'globe-outline' },
|
|
379
|
+
],
|
|
380
|
+
},
|
|
381
|
+
];
|
|
382
|
+
|
|
383
|
+
return (
|
|
384
|
+
<View>
|
|
385
|
+
{groups.map((group, groupIndex) => (
|
|
386
|
+
<View key={groupIndex}>
|
|
387
|
+
<AtomicText
|
|
388
|
+
type="labelLarge"
|
|
389
|
+
color="primary"
|
|
390
|
+
style={{ paddingHorizontal: 16, paddingVertical: 8 }}
|
|
391
|
+
>
|
|
392
|
+
{group.title}
|
|
393
|
+
</AtomicText>
|
|
394
|
+
|
|
395
|
+
{group.items.map((item, itemIndex) => (
|
|
396
|
+
<ListItem
|
|
397
|
+
key={itemIndex}
|
|
398
|
+
title={item.title}
|
|
399
|
+
leftIcon={item.icon}
|
|
400
|
+
onPress={() => handleNavigation(item.title)}
|
|
401
|
+
rightIcon="chevron-forward-outline"
|
|
402
|
+
/>
|
|
403
|
+
))}
|
|
404
|
+
</View>
|
|
405
|
+
))}
|
|
406
|
+
</View>
|
|
407
|
+
);
|
|
408
|
+
};
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Props
|
|
412
|
+
|
|
413
|
+
### ListItemProps
|
|
414
|
+
|
|
415
|
+
| Prop | Type | Default | Description |
|
|
416
|
+
|------|------|---------|-------------|
|
|
417
|
+
| `title` | `string` | - **(Required)** | Primary text |
|
|
418
|
+
| `subtitle` | `string` | - | Secondary text |
|
|
419
|
+
| `leftIcon` | `string` | - | Left icon name (Ionicons) |
|
|
420
|
+
| `rightIcon` | `string` | - | Right icon name (Ionicons) |
|
|
421
|
+
| `onPress` | `() => void` | - | Press callback (makes item pressable) |
|
|
422
|
+
| `disabled` | `boolean` | `false` | Disable the item |
|
|
423
|
+
| `style` | `ViewStyle` | - | Custom container style |
|
|
424
|
+
|
|
425
|
+
## Best Practices
|
|
426
|
+
|
|
427
|
+
### 1. Icon Selection
|
|
428
|
+
|
|
429
|
+
```tsx
|
|
430
|
+
// ✅ Good: Descriptive icons
|
|
431
|
+
<ListItem
|
|
432
|
+
title="Settings"
|
|
433
|
+
leftIcon="settings-outline"
|
|
434
|
+
/>
|
|
435
|
+
|
|
436
|
+
// ❌ Bad: Generic icons
|
|
437
|
+
<ListItem
|
|
438
|
+
title="Settings"
|
|
439
|
+
leftIcon="ellipse-outline"
|
|
440
|
+
/>
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### 2. Right Icon Usage
|
|
444
|
+
|
|
445
|
+
```tsx
|
|
446
|
+
// ✅ Good: Navigation indicator
|
|
447
|
+
<ListItem
|
|
448
|
+
title="Settings"
|
|
449
|
+
rightIcon="chevron-forward-outline"
|
|
450
|
+
onPress={() => navigate('Settings')}
|
|
451
|
+
/>
|
|
452
|
+
|
|
453
|
+
// ❌ Bad: No press handler
|
|
454
|
+
<ListItem
|
|
455
|
+
title="Settings"
|
|
456
|
+
rightIcon="chevron-forward-outline"
|
|
457
|
+
/>
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### 3. Subtitle Length
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
// ✅ Good: Concise
|
|
464
|
+
<ListItem
|
|
465
|
+
subtitle="Software Engineer at Google"
|
|
466
|
+
/>
|
|
467
|
+
|
|
468
|
+
// ❌ Bad: Too long
|
|
469
|
+
<ListItem
|
|
470
|
+
subtitle="Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
|
|
471
|
+
/>
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Accessibility
|
|
475
|
+
|
|
476
|
+
ListItem provides full accessibility support:
|
|
477
|
+
|
|
478
|
+
- ✅ Screen reader support
|
|
479
|
+
- ✅ Touch target size
|
|
480
|
+
- ✅ Accessibility labels
|
|
481
|
+
- ✅ Disabled state announcements
|
|
482
|
+
- ✅ Semantic roles
|
|
483
|
+
|
|
484
|
+
## Performance Tips
|
|
485
|
+
|
|
486
|
+
1. **Memoization**: Memo list items for large lists
|
|
487
|
+
2. **Key Prop**: Always use unique keys
|
|
488
|
+
3. **Optimization**: Use `removeClippedSubviews` for long lists
|
|
489
|
+
|
|
490
|
+
## Related Components
|
|
491
|
+
|
|
492
|
+
- [`List`](../List/README.md) - List container component
|
|
493
|
+
- [`Avatar`](../avatar/README.md) - User avatar component
|
|
494
|
+
- [`AtomicIcon`](../../atoms/AtomicIcon/README.md) - Icon component
|
|
495
|
+
- [`Divider`](../Divider/README.md) - List divider component
|
|
496
|
+
|
|
497
|
+
## License
|
|
498
|
+
|
|
499
|
+
MIT
|