@umituz/react-native-design-system 2.6.88 → 2.6.89
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/FormField.README.md +424 -273
- package/src/molecules/List/README.md +568 -0
- package/src/molecules/StepProgress/README.md +522 -0
- package/src/molecules/emoji/README.md +580 -0
- package/src/molecules/splash/types/index.ts +5 -8
- package/src/molecules/swipe-actions/README.md +672 -0
- package/src/theme/core/colors/DarkColors.ts +0 -3
- package/src/theme/core/colors/LightColors.ts +0 -3
- package/src/theme/core/themes.ts +1 -8
- package/src/theme/infrastructure/providers/DesignSystemProvider.tsx +1 -1
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
# List
|
|
2
|
+
|
|
3
|
+
List, FlatList wrapper'ı olan responsive bir liste bileşenidir. Pull-to-refresh desteği, içerik padding'i ve theme-aware renkler sunar.
|
|
4
|
+
|
|
5
|
+
## Özellikler
|
|
6
|
+
|
|
7
|
+
- 📜 **FlatList Wrapper**: React Native FlatList'in tüm özellikleri
|
|
8
|
+
- 🔄 **Pull-to-Refresh**: Yenileme desteği
|
|
9
|
+
- 📏 **Content Padding**: Responsive içerik padding'i
|
|
10
|
+
- 🎨 **Theme-Aware**: Design token uyumlu
|
|
11
|
+
- ⚡ **Performanslı**: Optimize edilmiş liste performansı
|
|
12
|
+
- ♿ **Erişilebilir**: Tam erişilebilirlik desteği
|
|
13
|
+
|
|
14
|
+
## Kurulum
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { List } from 'react-native-design-system';
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Temel Kullanım
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import React from 'react';
|
|
24
|
+
import { View } from 'react-native';
|
|
25
|
+
import { List } from 'react-native-design-system';
|
|
26
|
+
|
|
27
|
+
export const BasicExample = () => {
|
|
28
|
+
const data = [
|
|
29
|
+
{ id: '1', title: 'Öğe 1' },
|
|
30
|
+
{ id: '2', title: 'Öğe 2' },
|
|
31
|
+
{ id: '3', title: 'Öğe 3' },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<List
|
|
36
|
+
data={data}
|
|
37
|
+
renderItem={({ item }) => (
|
|
38
|
+
<View style={{ padding: 16 }}>
|
|
39
|
+
<AtomicText>{item.title}</AtomicText>
|
|
40
|
+
</View>
|
|
41
|
+
)}
|
|
42
|
+
keyExtractor={(item) => item.id}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Basit Liste
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
const users = [
|
|
52
|
+
{ id: '1', name: 'Ahmet Yılmaz' },
|
|
53
|
+
{ id: '2', name: 'Ayşe Demir' },
|
|
54
|
+
{ id: '3', name: 'Mehmet Kaya' },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
<List
|
|
58
|
+
data={users}
|
|
59
|
+
renderItem={({ item }) => (
|
|
60
|
+
<ListItem title={item.name} />
|
|
61
|
+
)}
|
|
62
|
+
keyExtractor={(item) => item.id}
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Pull-to-Refresh
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
export const RefreshableList = () => {
|
|
70
|
+
const [data, setData] = useState([]);
|
|
71
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
72
|
+
|
|
73
|
+
const onRefresh = async () => {
|
|
74
|
+
setRefreshing(true);
|
|
75
|
+
const newData = await fetchData();
|
|
76
|
+
setData(newData);
|
|
77
|
+
setRefreshing(false);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<List
|
|
82
|
+
data={data}
|
|
83
|
+
renderItem={({ item }) => <ItemCard item={item} />}
|
|
84
|
+
keyExtractor={(item) => item.id}
|
|
85
|
+
onRefresh={onRefresh}
|
|
86
|
+
refreshing={refreshing}
|
|
87
|
+
/>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Content Padding
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<List
|
|
96
|
+
data={items}
|
|
97
|
+
renderItem={({ item }) => <ItemCard item={item} />}
|
|
98
|
+
keyExtractor={(item) => item.id}
|
|
99
|
+
contentPadding
|
|
100
|
+
/>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Örnek Kullanımlar
|
|
104
|
+
|
|
105
|
+
### Kullanıcı Listesi
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
export const UserList = () => {
|
|
109
|
+
const [users, setUsers] = useState([]);
|
|
110
|
+
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
fetchUsers().then(setUsers);
|
|
113
|
+
}, []);
|
|
114
|
+
|
|
115
|
+
const renderUser = ({ item }) => (
|
|
116
|
+
<ListItem
|
|
117
|
+
title={item.name}
|
|
118
|
+
subtitle={item.email}
|
|
119
|
+
left={() => (
|
|
120
|
+
<Avatar
|
|
121
|
+
uri={item.avatar}
|
|
122
|
+
name={item.name}
|
|
123
|
+
size="md"
|
|
124
|
+
/>
|
|
125
|
+
)}
|
|
126
|
+
onPress={() => navigation.navigate('UserProfile', { userId: item.id })}
|
|
127
|
+
/>
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<List
|
|
132
|
+
data={users}
|
|
133
|
+
renderItem={renderUser}
|
|
134
|
+
keyExtractor={(item) => item.id}
|
|
135
|
+
contentPadding
|
|
136
|
+
/>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Sonsuz Kaydırma
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
export const InfiniteList = () => {
|
|
145
|
+
const [data, setData] = useState([]);
|
|
146
|
+
const [loading, setLoading] = useState(false);
|
|
147
|
+
const [page, setPage] = useState(1);
|
|
148
|
+
|
|
149
|
+
const loadMore = async () => {
|
|
150
|
+
if (loading) return;
|
|
151
|
+
setLoading(true);
|
|
152
|
+
const newData = await fetchItems(page);
|
|
153
|
+
setData([...data, ...newData]);
|
|
154
|
+
setPage(page + 1);
|
|
155
|
+
setLoading(false);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const renderFooter = () => {
|
|
159
|
+
if (!loading) return null;
|
|
160
|
+
return (
|
|
161
|
+
<View style={{ padding: 16 }}>
|
|
162
|
+
<AtomicSpinner size="md" />
|
|
163
|
+
</View>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<List
|
|
169
|
+
data={data}
|
|
170
|
+
renderItem={({ item }) => <ItemCard item={item} />}
|
|
171
|
+
keyExtractor={(item) => item.id}
|
|
172
|
+
onEndReached={loadMore}
|
|
173
|
+
onEndReachedThreshold={0.5}
|
|
174
|
+
ListFooterComponent={renderFooter}
|
|
175
|
+
contentPadding
|
|
176
|
+
/>
|
|
177
|
+
);
|
|
178
|
+
};
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Ürün Listesi
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
export const ProductList = () => {
|
|
185
|
+
const [products, setProducts] = useState([]);
|
|
186
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
187
|
+
|
|
188
|
+
const onRefresh = async () => {
|
|
189
|
+
setRefreshing(true);
|
|
190
|
+
const data = await fetchProducts();
|
|
191
|
+
setProducts(data);
|
|
192
|
+
setRefreshing(false);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const renderProduct = ({ item }) => (
|
|
196
|
+
<MediaCard
|
|
197
|
+
uri={item.image}
|
|
198
|
+
title={item.name}
|
|
199
|
+
subtitle={`${item.price} TL`}
|
|
200
|
+
onPress={() => navigation.navigate('ProductDetail', { productId: item.id })}
|
|
201
|
+
/>
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<List
|
|
206
|
+
data={products}
|
|
207
|
+
renderItem={renderProduct}
|
|
208
|
+
keyExtractor={(item) => item.id}
|
|
209
|
+
onRefresh={onRefresh}
|
|
210
|
+
refreshing={refreshing}
|
|
211
|
+
numColumns={2}
|
|
212
|
+
columnWrapperStyle={{ gap: 8 }}
|
|
213
|
+
contentPadding
|
|
214
|
+
/>
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Haber Listesi
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
export const NewsList = () => {
|
|
223
|
+
const [articles, setArticles] = useState([]);
|
|
224
|
+
|
|
225
|
+
const renderArticle = ({ item }) => (
|
|
226
|
+
<AtomicCard
|
|
227
|
+
variant="outlined"
|
|
228
|
+
style={{ marginBottom: 16 }}
|
|
229
|
+
onPress={() => navigation.navigate('Article', { articleId: item.id })}
|
|
230
|
+
>
|
|
231
|
+
<View style={{ padding: 16 }}>
|
|
232
|
+
<AtomicText type="titleMedium" style={{ marginBottom: 8 }}>
|
|
233
|
+
{item.title}
|
|
234
|
+
</AtomicText>
|
|
235
|
+
<AtomicText type="bodyMedium" color="secondary" numberOfLines={2}>
|
|
236
|
+
{item.excerpt}
|
|
237
|
+
</AtomicText>
|
|
238
|
+
<View style={{ flexDirection: 'row', marginTop: 8 }}>
|
|
239
|
+
<AtomicText type="labelSmall" color="tertiary">
|
|
240
|
+
{item.category}
|
|
241
|
+
</AtomicText>
|
|
242
|
+
<AtomicText type="labelSmall" color="tertiary" style={{ marginLeft: 16 }}>
|
|
243
|
+
{formatDate(item.publishedAt)}
|
|
244
|
+
</AtomicText>
|
|
245
|
+
</View>
|
|
246
|
+
</View>
|
|
247
|
+
</AtomicCard>
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<List
|
|
252
|
+
data={articles}
|
|
253
|
+
renderItem={renderArticle}
|
|
254
|
+
keyExtractor={(item) => item.id}
|
|
255
|
+
contentPadding
|
|
256
|
+
/>
|
|
257
|
+
);
|
|
258
|
+
};
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Sohbet Listesi
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
export const ChatList = () => {
|
|
265
|
+
const [conversations, setConversations] = useState([]);
|
|
266
|
+
|
|
267
|
+
const renderConversation = ({ item }) => (
|
|
268
|
+
<Pressable
|
|
269
|
+
style={{ flexDirection: 'row', alignItems: 'center', padding: 16 }}
|
|
270
|
+
onPress={() => navigation.navigate('Chat', { chatId: item.id })}
|
|
271
|
+
>
|
|
272
|
+
<Avatar
|
|
273
|
+
uri={item.avatar}
|
|
274
|
+
name={item.name}
|
|
275
|
+
showStatus
|
|
276
|
+
status={item.online ? 'online' : 'offline'}
|
|
277
|
+
size="md"
|
|
278
|
+
/>
|
|
279
|
+
|
|
280
|
+
<View style={{ flex: 1, marginLeft: 12 }}>
|
|
281
|
+
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
282
|
+
<AtomicText type="bodyLarge" fontWeight="600">
|
|
283
|
+
{item.name}
|
|
284
|
+
</AtomicText>
|
|
285
|
+
<AtomicText type="bodySmall" color="tertiary">
|
|
286
|
+
{formatTime(item.lastMessageAt)}
|
|
287
|
+
</AtomicText>
|
|
288
|
+
</View>
|
|
289
|
+
|
|
290
|
+
<AtomicText
|
|
291
|
+
type="bodyMedium"
|
|
292
|
+
color="secondary"
|
|
293
|
+
numberOfLines={1}
|
|
294
|
+
style={{ marginTop: 4 }}
|
|
295
|
+
>
|
|
296
|
+
{item.lastMessage}
|
|
297
|
+
</AtomicText>
|
|
298
|
+
</View>
|
|
299
|
+
</Pressable>
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
return (
|
|
303
|
+
<List
|
|
304
|
+
data={conversations}
|
|
305
|
+
renderItem={renderConversation}
|
|
306
|
+
keyExtractor={(item) => item.id}
|
|
307
|
+
contentPadding
|
|
308
|
+
/>
|
|
309
|
+
);
|
|
310
|
+
};
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Arama Sonuçları
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
export const SearchResults = ({ query }) => {
|
|
317
|
+
const [results, setResults] = useState([]);
|
|
318
|
+
const [loading, setLoading] = useState(false);
|
|
319
|
+
|
|
320
|
+
useEffect(() => {
|
|
321
|
+
const search = async () => {
|
|
322
|
+
setLoading(true);
|
|
323
|
+
const data = await searchItems(query);
|
|
324
|
+
setResults(data);
|
|
325
|
+
setLoading(false);
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
if (query.length > 2) {
|
|
329
|
+
search();
|
|
330
|
+
}
|
|
331
|
+
}, [query]);
|
|
332
|
+
|
|
333
|
+
const renderResult = ({ item }) => (
|
|
334
|
+
<ListItem
|
|
335
|
+
title={item.title}
|
|
336
|
+
subtitle={item.description}
|
|
337
|
+
left={() => <AtomicIcon name="search-outline" size="md" />}
|
|
338
|
+
onPress={() => navigation.navigate('Detail', { id: item.id })}
|
|
339
|
+
/>
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
if (loading) {
|
|
343
|
+
return <AtomicSpinner fullContainer />;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (results.length === 0) {
|
|
347
|
+
return (
|
|
348
|
+
<EmptyState
|
|
349
|
+
icon="search-outline"
|
|
350
|
+
title="Sonuç bulunamadı"
|
|
351
|
+
message={`"${query}" için sonuç bulunamadı`}
|
|
352
|
+
/>
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return (
|
|
357
|
+
<List
|
|
358
|
+
data={results}
|
|
359
|
+
renderItem={renderResult}
|
|
360
|
+
keyExtractor={(item) => item.id}
|
|
361
|
+
contentPadding
|
|
362
|
+
/>
|
|
363
|
+
);
|
|
364
|
+
};
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Bildirim Listesi
|
|
368
|
+
|
|
369
|
+
```tsx
|
|
370
|
+
export const NotificationList = () => {
|
|
371
|
+
const [notifications, setNotifications] = useState([]);
|
|
372
|
+
|
|
373
|
+
const renderNotification = ({ item }) => (
|
|
374
|
+
<View
|
|
375
|
+
style={{
|
|
376
|
+
flexDirection: 'row',
|
|
377
|
+
padding: 16,
|
|
378
|
+
backgroundColor: item.read ? 'transparent' : `${tokens.colors.primary}10`,
|
|
379
|
+
borderBottomWidth: 1,
|
|
380
|
+
borderBottomColor: tokens.colors.border,
|
|
381
|
+
}}
|
|
382
|
+
>
|
|
383
|
+
<View style={{ marginRight: 12 }}>
|
|
384
|
+
<AtomicIcon
|
|
385
|
+
name={item.type === 'success' ? 'checkmark-circle' : 'information-circle'}
|
|
386
|
+
size="lg"
|
|
387
|
+
color={item.type === 'success' ? 'success' : 'primary'}
|
|
388
|
+
/>
|
|
389
|
+
</View>
|
|
390
|
+
|
|
391
|
+
<View style={{ flex: 1 }}>
|
|
392
|
+
<AtomicText type="bodyLarge" fontWeight="600">
|
|
393
|
+
{item.title}
|
|
394
|
+
</AtomicText>
|
|
395
|
+
<AtomicText type="bodyMedium" color="secondary" style={{ marginTop: 4 }}>
|
|
396
|
+
{item.message}
|
|
397
|
+
</AtomicText>
|
|
398
|
+
<AtomicText type="labelSmall" color="tertiary" style={{ marginTop: 8 }}>
|
|
399
|
+
{formatRelativeTime(item.createdAt)}
|
|
400
|
+
</AtomicText>
|
|
401
|
+
</View>
|
|
402
|
+
</View>
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
return (
|
|
406
|
+
<List
|
|
407
|
+
data={notifications}
|
|
408
|
+
renderItem={renderNotification}
|
|
409
|
+
keyExtractor={(item) => item.id}
|
|
410
|
+
contentPadding
|
|
411
|
+
/>
|
|
412
|
+
);
|
|
413
|
+
};
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Görev Listesi
|
|
417
|
+
|
|
418
|
+
```tsx
|
|
419
|
+
export const TaskList = () => {
|
|
420
|
+
const [tasks, setTasks] = useState([]);
|
|
421
|
+
|
|
422
|
+
const toggleTask = (taskId) => {
|
|
423
|
+
setTasks(tasks.map(task =>
|
|
424
|
+
task.id === taskId ? { ...task, completed: !task.completed } : task
|
|
425
|
+
));
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
const renderTask = ({ item }) => (
|
|
429
|
+
<View
|
|
430
|
+
style={{
|
|
431
|
+
flexDirection: 'row',
|
|
432
|
+
alignItems: 'center',
|
|
433
|
+
padding: 16,
|
|
434
|
+
borderBottomWidth: 1,
|
|
435
|
+
borderBottomColor: tokens.colors.border,
|
|
436
|
+
}}
|
|
437
|
+
>
|
|
438
|
+
<Pressable onPress={() => toggleTask(item.id)}>
|
|
439
|
+
<AtomicIcon
|
|
440
|
+
name={item.completed ? 'checkmark-circle' : 'ellipse-outline'}
|
|
441
|
+
size="md"
|
|
442
|
+
color={item.completed ? 'success' : 'secondary'}
|
|
443
|
+
/>
|
|
444
|
+
</Pressable>
|
|
445
|
+
|
|
446
|
+
<View style={{ flex: 1, marginLeft: 12 }}>
|
|
447
|
+
<AtomicText
|
|
448
|
+
type="bodyLarge"
|
|
449
|
+
style={{
|
|
450
|
+
textDecorationLine: item.completed ? 'line-through' : 'none',
|
|
451
|
+
opacity: item.completed ? 0.6 : 1,
|
|
452
|
+
}}
|
|
453
|
+
>
|
|
454
|
+
{item.title}
|
|
455
|
+
</AtomicText>
|
|
456
|
+
|
|
457
|
+
{item.dueDate && (
|
|
458
|
+
<AtomicText type="labelSmall" color="tertiary" style={{ marginTop: 4 }}>
|
|
459
|
+
{formatDate(item.dueDate)}
|
|
460
|
+
</AtomicText>
|
|
461
|
+
)}
|
|
462
|
+
</View>
|
|
463
|
+
|
|
464
|
+
{item.priority === 'high' && (
|
|
465
|
+
<AtomicIcon name="alert-circle" size="sm" color="error" />
|
|
466
|
+
)}
|
|
467
|
+
</View>
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
return (
|
|
471
|
+
<List
|
|
472
|
+
data={tasks}
|
|
473
|
+
renderItem={renderTask}
|
|
474
|
+
keyExtractor={(item) => item.id}
|
|
475
|
+
contentPadding
|
|
476
|
+
/>
|
|
477
|
+
);
|
|
478
|
+
};
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Props
|
|
482
|
+
|
|
483
|
+
### ListProps
|
|
484
|
+
|
|
485
|
+
| Prop | Tip | Varsayılan | Açıklama |
|
|
486
|
+
|------|-----|------------|----------|
|
|
487
|
+
| `data` | `T[]` | - **(Zorunlu)** | Liste verisi |
|
|
488
|
+
| `renderItem` | `ListRenderItem<T>` | - **(Zorunlu)** | Render fonksiyonu |
|
|
489
|
+
| `keyExtractor` | `(item, index) => string` | - **(Zorunlu)** | Key extractor |
|
|
490
|
+
| `onRefresh` | `() => void` | - | Yenileme callback'i |
|
|
491
|
+
| `refreshing` | `boolean` | `false` | Yeneleniyor durumunda |
|
|
492
|
+
| `contentPadding` | `boolean` | `false` | İçerik padding'i |
|
|
493
|
+
|
|
494
|
+
**Not:** List, FlatList'in tüm props'larını destekler.
|
|
495
|
+
|
|
496
|
+
## Best Practices
|
|
497
|
+
|
|
498
|
+
### 1. Key Extractor
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
// ✅ İyi - Unique ve stable
|
|
502
|
+
keyExtractor={(item) => item.id}
|
|
503
|
+
|
|
504
|
+
// ❌ Kötü - Index kullanımı
|
|
505
|
+
keyExtractor={(item, index) => index.toString()}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### 2. Performans
|
|
509
|
+
|
|
510
|
+
```tsx
|
|
511
|
+
// ✅ Memo kullan
|
|
512
|
+
const renderItem = useCallback(({ item }) => (
|
|
513
|
+
<ItemCard item={item} />
|
|
514
|
+
), []);
|
|
515
|
+
|
|
516
|
+
// ✅ Inline function değil
|
|
517
|
+
renderItem={renderItem}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### 3. Content Padding
|
|
521
|
+
|
|
522
|
+
```tsx
|
|
523
|
+
// Liste için
|
|
524
|
+
<List contentPadding />
|
|
525
|
+
|
|
526
|
+
// Manuel padding
|
|
527
|
+
<View style={{ padding: 16 }}>
|
|
528
|
+
<List />
|
|
529
|
+
</View> // ❌ Gereksiz
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### 4. Empty State
|
|
533
|
+
|
|
534
|
+
```tsx
|
|
535
|
+
{data.length === 0 ? (
|
|
536
|
+
<EmptyState />
|
|
537
|
+
) : (
|
|
538
|
+
<List data={data} />
|
|
539
|
+
)}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## Erişilebilirlik
|
|
543
|
+
|
|
544
|
+
List, tam erişilebilirlik desteği sunar:
|
|
545
|
+
|
|
546
|
+
- ✅ Screen reader desteği
|
|
547
|
+
- ✅ Semantic list anlamları
|
|
548
|
+
- ✅ Focus management
|
|
549
|
+
- ✅ Keyboard navigation
|
|
550
|
+
|
|
551
|
+
## Performans İpuçları
|
|
552
|
+
|
|
553
|
+
1. **keyExtractor**: Her item için unique key kullanın
|
|
554
|
+
2. **Memoization**: renderItem fonksiyonunu memo edin
|
|
555
|
+
3. **removeClippedSubviews**: Büyük listelerde kullanın
|
|
556
|
+
4. **getItemLayout**: Sabit boyutlu item'larda kullanın
|
|
557
|
+
5. **windowSize**: Viewport dışındaki item sayısını sınırlayın
|
|
558
|
+
|
|
559
|
+
## İlgili Bileşenler
|
|
560
|
+
|
|
561
|
+
- [`FlatList`](https://reactnative.dev/docs/flatlist) - React Native FlatList
|
|
562
|
+
- [`ListItem`](../listitem/README.md) - Liste öğesi
|
|
563
|
+
- [`MediaCard`](../media-card/README.md) - Medya kartı
|
|
564
|
+
- [`Avatar`](../avatar/README.md) - Avatar bileşeni
|
|
565
|
+
|
|
566
|
+
## Lisans
|
|
567
|
+
|
|
568
|
+
MIT
|