@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.
@@ -0,0 +1,580 @@
1
+ # EmojiPicker
2
+
3
+ EmojiPicker, emoji seçimi için kullanılan bileşendir. `rn-emoji-keyboard` kütüphanesini wrapper'layarak temiz bir arayüz sunar. Kategori bazlı seçim, arama ve son kullanılan emoji'leri destekler.
4
+
5
+ ## Özellikler
6
+
7
+ - 😀 **Emoji Seçimi**: Geniş emoji koleksiyonu
8
+ - 📁 **Kategoriler**: Kategori bazlı navigasyon
9
+ - 🔍 **Arama**: Emoji arama özelliği
10
+ - ⏰ **Son Kullanılanlar**: Son kullanılan emoji'ler
11
+ - 🌍 **Lokalizasyon**: Çoklu dil desteği
12
+ - 🎨 **Özelleştirilebilir**: Konfigürasyon seçenekleri
13
+ - ✨ **Animasyonlar**: Smooth animasyonlar
14
+
15
+ ## Kurulum
16
+
17
+ ```tsx
18
+ import { EmojiPicker } from 'react-native-design-system';
19
+ ```
20
+
21
+ ## Temel Kullanım
22
+
23
+ ```tsx
24
+ import React, { useState } from 'react';
25
+ import { View, TouchableOpacity, Text } from 'react-native';
26
+ import { EmojiPicker } from 'react-native-design-system';
27
+
28
+ export const BasicExample = () => {
29
+ const [isOpen, setIsOpen] = useState(false);
30
+ const [emoji, setEmoji] = useState('');
31
+
32
+ const handleEmojiSelect = (emojiObject) => {
33
+ setEmoji(emojiObject.emoji);
34
+ setIsOpen(false);
35
+ };
36
+
37
+ return (
38
+ <View>
39
+ <TouchableOpacity onPress={() => setIsOpen(true)}>
40
+ <Text>{emoji || 'Emoji Seç'}</Text>
41
+ </TouchableOpacity>
42
+
43
+ <EmojiPicker
44
+ open={isOpen}
45
+ onClose={() => setIsOpen(false)}
46
+ onEmojiSelected={handleEmojiSelect}
47
+ />
48
+ </View>
49
+ );
50
+ };
51
+ ```
52
+
53
+ ## Basit Emoji Seçimi
54
+
55
+ ```tsx
56
+ export const SimpleEmojiPicker = () => {
57
+ const [open, setOpen] = useState(false);
58
+ const [selectedEmoji, setSelectedEmoji] = useState('');
59
+
60
+ return (
61
+ <View>
62
+ <Button
63
+ title={selectedEmoji || 'Emoji Seç'}
64
+ onPress={() => setOpen(true)}
65
+ />
66
+
67
+ <EmojiPicker
68
+ open={open}
69
+ onClose={() => setOpen(false)}
70
+ onEmojiSelected={(emoji) => {
71
+ setSelectedEmoji(emoji.emoji);
72
+ setOpen(false);
73
+ }}
74
+ />
75
+ </View>
76
+ );
77
+ };
78
+ ```
79
+
80
+ ## Mesajlaşma
81
+
82
+ ```tsx
83
+ export const MessageComposer = () => {
84
+ const [message, setMessage] = useState('');
85
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);
86
+
87
+ const handleEmojiSelect = (emojiObject) => {
88
+ setMessage(message + emojiObject.emoji);
89
+ };
90
+
91
+ return (
92
+ <View>
93
+ <View style={{ flexDirection: 'row', alignItems: 'center', padding: 16 }}>
94
+ <TouchableOpacity onPress={() => setEmojiPickerOpen(true)}>
95
+ <AtomicIcon name="happy-outline" size="lg" />
96
+ </TouchableOpacity>
97
+
98
+ <TextInput
99
+ style={{ flex: 1, marginLeft: 8 }}
100
+ value={message}
101
+ onChangeText={setMessage}
102
+ placeholder="Mesaj yazın..."
103
+ />
104
+
105
+ <Button
106
+ title="Gönder"
107
+ onPress={() => sendMessage(message)}
108
+ />
109
+ </View>
110
+
111
+ <EmojiPicker
112
+ open={emojiPickerOpen}
113
+ onClose={() => setEmojiPickerOpen(false)}
114
+ onEmojiSelected={handleEmojiSelect}
115
+ />
116
+ </View>
117
+ );
118
+ };
119
+ ```
120
+
121
+ ## Yorum Ekleme
122
+
123
+ ```tsx
124
+ export const CommentInput = () => {
125
+ const [comment, setComment] = useState('');
126
+ const [showEmojiPicker, setShowEmojiPicker] = useState(false);
127
+
128
+ const insertEmoji = (emojiObject) => {
129
+ setComment(comment + emojiObject.emoji);
130
+ };
131
+
132
+ return (
133
+ <View>
134
+ <View style={{ padding: 16 }}>
135
+ <View style={{ flexDirection: 'row', alignItems: 'flex-start' }}>
136
+ <Avatar
137
+ uri={currentUser.avatar}
138
+ name={currentUser.name}
139
+ size="sm"
140
+ />
141
+
142
+ <View style={{ flex: 1, marginLeft: 12 }}>
143
+ <TextInput
144
+ style={{
145
+ borderWidth: 1,
146
+ borderColor: '#e0e0e0',
147
+ borderRadius: 8,
148
+ padding: 12,
149
+ minHeight: 80,
150
+ }}
151
+ value={comment}
152
+ onChangeText={setComment}
153
+ placeholder="Yorumunuzu yazın..."
154
+ multiline
155
+ />
156
+
157
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: 8 }}>
158
+ <TouchableOpacity onPress={() => setShowEmojiPicker(true)}>
159
+ <AtomicIcon name="happy-outline" size="md" />
160
+ </TouchableOpacity>
161
+
162
+ <Button
163
+ title="Yorum Yap"
164
+ onPress={() => postComment(comment)}
165
+ />
166
+ </View>
167
+ </View>
168
+ </View>
169
+ </View>
170
+
171
+ <EmojiPicker
172
+ open={showEmojiPicker}
173
+ onClose={() => setShowEmojiPicker(false)}
174
+ onEmojiSelected={insertEmoji}
175
+ />
176
+ </View>
177
+ );
178
+ };
179
+ ```
180
+
181
+ ## Profil Reaksiyonları
182
+
183
+ ```tsx
184
+ export const ProfileReactions = () => {
185
+ const [reactions, setReactions] = useState([]);
186
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);
187
+
188
+ const addReaction = (emojiObject) => {
189
+ setReactions([...reactions, emojiObject.emoji]);
190
+ setEmojiPickerOpen(false);
191
+ };
192
+
193
+ return (
194
+ <View>
195
+ <View style={{ flexDirection: 'row', alignItems: 'center', padding: 16 }}>
196
+ <Avatar
197
+ uri={user.avatar}
198
+ name={user.name}
199
+ size="lg"
200
+ />
201
+
202
+ <View style={{ flex: 1, marginLeft: 12 }}>
203
+ <AtomicText type="titleMedium">{user.name}</AtomicText>
204
+ <AtomicText type="bodyMedium" color="secondary">
205
+ {user.bio}
206
+ </AtomicText>
207
+ </View>
208
+
209
+ <TouchableOpacity onPress={() => setEmojiPickerOpen(true)}>
210
+ <AtomicIcon name="heart-outline" size="lg" />
211
+ </TouchableOpacity>
212
+ </View>
213
+
214
+ {reactions.length > 0 && (
215
+ <View style={{ flexDirection: 'row', flexWrap: 'wrap', paddingHorizontal: 16, paddingBottom: 16 }}>
216
+ {reactions.map((emoji, index) => (
217
+ <View
218
+ key={index}
219
+ style={{
220
+ backgroundColor: '#f0f0f0',
221
+ paddingHorizontal: 12,
222
+ paddingVertical: 6,
223
+ borderRadius: 16,
224
+ marginRight: 8,
225
+ marginBottom: 8,
226
+ }}
227
+ >
228
+ <AtomicText style={{ fontSize: 18 }}>{emoji}</AtomicText>
229
+ </View>
230
+ ))}
231
+ </View>
232
+ )}
233
+
234
+ <EmojiPicker
235
+ open={emojiPickerOpen}
236
+ onClose={() => setEmojiPickerOpen(false)}
237
+ onEmojiSelected={addReaction}
238
+ />
239
+ </View>
240
+ );
241
+ };
242
+ ```
243
+
244
+ ## Post Oluşturma
245
+
246
+ ```tsx
247
+ export const PostCreator = () => {
248
+ const [content, setContent] = useState('');
249
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);
250
+
251
+ const handleEmojiSelect = (emojiObject) => {
252
+ setContent(content + emojiObject.emoji);
253
+ };
254
+
255
+ const createPost = () => {
256
+ if (content.trim()) {
257
+ publishPost(content);
258
+ setContent('');
259
+ }
260
+ };
261
+
262
+ return (
263
+ <AtomicCard variant="outlined" style={{ margin: 16 }}>
264
+ <View style={{ padding: 16 }}>
265
+ <View style={{ flexDirection: 'row', alignItems: 'flex-start' }}>
266
+ <Avatar
267
+ uri={currentUser.avatar}
268
+ name={currentUser.name}
269
+ size="md"
270
+ />
271
+
272
+ <View style={{ flex: 1, marginLeft: 12 }}>
273
+ <TextInput
274
+ style={{ minHeight: 100 }}
275
+ value={content}
276
+ onChangeText={setContent}
277
+ placeholder="Neler oluyor?"
278
+ multiline
279
+ />
280
+
281
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: 12 }}>
282
+ <View style={{ flexDirection: 'row', gap: 16 }}>
283
+ <TouchableOpacity onPress={() => setEmojiPickerOpen(true)}>
284
+ <AtomicIcon name="happy-outline" size="md" color="primary" />
285
+ </TouchableOpacity>
286
+ <TouchableOpacity>
287
+ <AtomicIcon name="image-outline" size="md" color="primary" />
288
+ </TouchableOpacity>
289
+ </View>
290
+
291
+ <Button
292
+ title="Paylaş"
293
+ onPress={createPost}
294
+ disabled={!content.trim()}
295
+ />
296
+ </View>
297
+ </View>
298
+ </View>
299
+ </View>
300
+
301
+ <EmojiPicker
302
+ open={emojiPickerOpen}
303
+ onClose={() => setEmojiPickerOpen(false)}
304
+ onEmojiSelected={handleEmojiSelect}
305
+ />
306
+ </AtomicCard>
307
+ );
308
+ };
309
+ ```
310
+
311
+ ## Grup İsmi
312
+
313
+ ```tsx
314
+ export const GroupNameEditor = () => {
315
+ const [groupName, setGroupName] = useState('');
316
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);
317
+
318
+ return (
319
+ <View style={{ padding: 16 }}>
320
+ <AtomicText type="titleMedium" style={{ marginBottom: 8 }}>
321
+ Grup İsmi
322
+ </AtomicText>
323
+
324
+ <View style={{ flexDirection: 'row', alignItems: 'center' }}>
325
+ <TouchableOpacity
326
+ style={{
327
+ width: 60,
328
+ height: 60,
329
+ borderRadius: 30,
330
+ backgroundColor: '#f0f0f0',
331
+ justifyContent: 'center',
332
+ alignItems: 'center',
333
+ }}
334
+ onPress={() => setEmojiPickerOpen(true)}
335
+ >
336
+ <AtomicText style={{ fontSize: 32 }}>
337
+ {groupName.slice(0, 1) || '📝'}
338
+ </AtomicText>
339
+ </TouchableOpacity>
340
+
341
+ <TextInput
342
+ style={{ flex: 1, marginLeft: 12 }}
343
+ value={groupName}
344
+ onChangeText={setGroupName}
345
+ placeholder="Grup adı..."
346
+ />
347
+ </View>
348
+
349
+ <EmojiPicker
350
+ open={emojiPickerOpen}
351
+ onClose={() => setEmojiPickerOpen(false)}
352
+ onEmojiSelected={(emoji) => {
353
+ setGroupName(emoji.emoji + ' ' + groupName);
354
+ setEmojiPickerOpen(false);
355
+ }}
356
+ />
357
+ </View>
358
+ );
359
+ };
360
+ ```
361
+
362
+ ## Emoji Reaksiyonları
363
+
364
+ ```tsx
365
+ export const MessageReactions = ({ message }) => {
366
+ const [reactions, setReactions] = useState(message.reactions || []);
367
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);
368
+
369
+ const addReaction = (emojiObject) => {
370
+ const existing = reactions.find(r => r.emoji === emojiObject.emoji);
371
+
372
+ if (existing) {
373
+ // Remove reaction if already exists
374
+ setReactions(reactions.filter(r => r.emoji !== emojiObject.emoji));
375
+ } else {
376
+ // Add new reaction
377
+ setReactions([...reactions, {
378
+ emoji: emojiObject.emoji,
379
+ users: [currentUser.id],
380
+ count: 1,
381
+ }]);
382
+ }
383
+
384
+ setEmojiPickerOpen(false);
385
+ };
386
+
387
+ return (
388
+ <View>
389
+ <View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 4 }}>
390
+ {reactions.map((reaction, index) => (
391
+ <TouchableOpacity
392
+ key={index}
393
+ style={{
394
+ flexDirection: 'row',
395
+ alignItems: 'center',
396
+ backgroundColor: reaction.users.includes(currentUser.id)
397
+ ? `${tokens.colors.primary}20`
398
+ : '#f0f0f0',
399
+ paddingHorizontal: 8,
400
+ paddingVertical: 4,
401
+ borderRadius: 16,
402
+ borderWidth: reaction.users.includes(currentUser.id) ? 1 : 0,
403
+ borderColor: tokens.colors.primary,
404
+ }}
405
+ onPress={() => addReaction({ emoji: reaction.emoji })}
406
+ >
407
+ <AtomicText style={{ fontSize: 16, marginRight: 4 }}>
408
+ {reaction.emoji}
409
+ </AtomicText>
410
+ <AtomicText type="labelSmall">
411
+ {reaction.count}
412
+ </AtomicText>
413
+ </TouchableOpacity>
414
+ ))}
415
+
416
+ <TouchableOpacity
417
+ style={{
418
+ flexDirection: 'row',
419
+ alignItems: 'center',
420
+ backgroundColor: '#f0f0f0',
421
+ paddingHorizontal: 8,
422
+ paddingVertical: 4,
423
+ borderRadius: 16,
424
+ }}
425
+ onPress={() => setEmojiPickerOpen(true)}
426
+ >
427
+ <AtomicIcon name="add-outline" size="sm" />
428
+ </TouchableOpacity>
429
+ </View>
430
+
431
+ <EmojiPicker
432
+ open={emojiPickerOpen}
433
+ onClose={() => setEmojiPickerOpen(false)}
434
+ onEmojiSelected={addReaction}
435
+ />
436
+ </View>
437
+ );
438
+ };
439
+ ```
440
+
441
+ ## Emoji Filtreleme
442
+
443
+ ```tsx
444
+ export const EmojiFilter = () => {
445
+ const [selectedEmoji, setSelectedEmoji] = useState('');
446
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);
447
+ const [filteredContent, setFilteredContent] = useState([]);
448
+
449
+ const handleEmojiSelect = (emojiObject) => {
450
+ setSelectedEmoji(emojiObject.emoji);
451
+ setEmojiPickerOpen(false);
452
+
453
+ // Filter content by emoji reaction
454
+ const filtered = content.filter(item =>
455
+ item.reactions?.some(r => r.emoji === emojiObject.emoji)
456
+ );
457
+ setFilteredContent(filtered);
458
+ };
459
+
460
+ return (
461
+ <View>
462
+ <View style={{ flexDirection: 'row', alignItems: 'center', padding: 16, gap: 8 }}>
463
+ <TouchableOpacity onPress={() => {
464
+ setSelectedEmoji('');
465
+ setFilteredContent(content);
466
+ }}>
467
+ <AtomicText type="labelLarge">Tümü</AtomicText>
468
+ </TouchableOpacity>
469
+
470
+ <TouchableOpacity
471
+ style={{
472
+ paddingHorizontal: 12,
473
+ paddingVertical: 6,
474
+ backgroundColor: selectedEmoji ? `${tokens.colors.primary}20` : '#f0f0f0',
475
+ borderRadius: 16,
476
+ }}
477
+ onPress={() => setEmojiPickerOpen(true)}
478
+ >
479
+ <AtomicText style={{ fontSize: 18 }}>
480
+ {selectedEmoji || '😀'}
481
+ </AtomicText>
482
+ </TouchableOpacity>
483
+ </View>
484
+
485
+ <EmojiPicker
486
+ open={emojiPickerOpen}
487
+ onClose={() => setEmojiPickerOpen(false)}
488
+ onEmojiSelected={handleEmojiSelect}
489
+ />
490
+ </View>
491
+ );
492
+ };
493
+ ```
494
+
495
+ ## Props
496
+
497
+ ### EmojiPickerProps
498
+
499
+ | Prop | Tip | Varsayılan | Açıklama |
500
+ |------|-----|------------|----------|
501
+ | `open` | `boolean` | - **(Zorunlu)** | Picker açık mı |
502
+ | `onClose` | `() => void` | - **(Zorunlu)** | Kapanma callback'i |
503
+ | `onEmojiSelected` | `(emoji) => void` | - **(Zorunlu)** | Emoji seçildiğinde |
504
+ | `config` | `EmojiPickerConfig` | `{}` | Konfigürasyon |
505
+
506
+ ### EmojiPickerConfig
507
+
508
+ | Prop | Tip | Varsayılan | Açıklama |
509
+ |------|-----|------------|----------|
510
+ | `enableRecentlyUsed` | `boolean` | `true` | Son kullanılanlar |
511
+ | `enableSearch` | `boolean` | `true` | Arama çubuğu |
512
+ | `enableCategoryTabs` | `boolean` | `true` | Kategori sekmeleri |
513
+ | `categoryOrder` | `string[]` | - | Kategori sırası |
514
+ | `translation` | `object` | - | Lokalizasyon |
515
+
516
+ ### EmojiObject
517
+
518
+ | Prop | Tip | Açıklama |
519
+ |------|-----|----------|
520
+ | `emoji` | `string` | Emoji karakteri |
521
+ | `name` | `string` | Emoji adı |
522
+ | `slug` | `string` | URL slug |
523
+ | `unicode_version` | `string` | Unicode versiyonu |
524
+
525
+ ## Best Practices
526
+
527
+ ### 1. Kullanıcı Deneyimi
528
+
529
+ ```tsx
530
+ // ✅ İyi - Hemen kapanır
531
+ onEmojiSelected={(emoji) => {
532
+ onEmojiSelect(emoji);
533
+ onClose(); // Hemen kapat
534
+ }}
535
+ ```
536
+
537
+ ### 2. State Yönetimi
538
+
539
+ ```tsx
540
+ // ✅ İyi - Ayrı state
541
+ const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);
542
+ const [selectedEmoji, setSelectedEmoji] = useState('');
543
+ ```
544
+
545
+ ### 3. Trigger Butonu
546
+
547
+ ```tsx
548
+ // ✅ İyi - İkonlu buton
549
+ <TouchableOpacity onPress={() => setEmojiPickerOpen(true)}>
550
+ <AtomicIcon name="happy-outline" size="lg" />
551
+ </TouchableOpacity>
552
+ ```
553
+
554
+ ## Erişilebilirlik
555
+
556
+ EmojiPicker, erişilebilirlik desteği sunar:
557
+
558
+ - ✅ Screen reader desteği
559
+ - ✅ Touch uygun boyut
560
+ - ✅ Semantic anlamlar
561
+
562
+ ## Performans İpuçları
563
+
564
+ 1. **Lazy Load**: Lazy loading kullanın
565
+ 2. **Cache**: Emoji'leri cache'leyin
566
+ 3. **Unmount**: Kullanılmadığında unmount edin
567
+
568
+ ## İlgili Bileşenler
569
+
570
+ - [`AtomicIcon`](../../atoms/AtomicIcon/README.md) - İkon bileşeni
571
+ - [`FormField`](../FormField/README.md) - Form alanı
572
+ - [`BaseModal`](../BaseModal/README.md) - Modal bileşeni
573
+
574
+ ## Bağımlılıklar
575
+
576
+ - `rn-emoji-keyboard` - Emoji picker UI library
577
+
578
+ ## Lisans
579
+
580
+ MIT
@@ -11,7 +11,7 @@ import type { ReactNode } from "react";
11
11
  * All colors should be provided by the main app via design tokens
12
12
  */
13
13
  export interface SplashColors {
14
- /** Background color when not using gradient */
14
+ /** Background color */
15
15
  background: string;
16
16
  /** Text color for app name and tagline */
17
17
  text: string;
@@ -25,7 +25,7 @@ export interface SplashColors {
25
25
  export interface SplashCustomColors {
26
26
  /** Text color for app name and tagline */
27
27
  textColor: string;
28
- /** Background color when not using gradient */
28
+ /** Background color */
29
29
  backgroundColor?: string;
30
30
  /** Background color for icon placeholder circle */
31
31
  iconPlaceholderColor?: string;
@@ -37,8 +37,7 @@ export interface SplashCustomColors {
37
37
  export interface SplashThemeProviderProps {
38
38
  /** Children components */
39
39
  children: ReactNode;
40
- /** Gradient colors for background */
41
- gradientColors?: readonly [string, string, ...string[]];
40
+
42
41
  /** Custom color configuration */
43
42
  customColors?: SplashCustomColors;
44
43
  }
@@ -49,8 +48,7 @@ export interface SplashThemeProviderProps {
49
48
  export interface SplashThemeContextValue {
50
49
  /** Resolved colors for splash screen */
51
50
  colors: SplashColors;
52
- /** Gradient colors if provided */
53
- gradientColors?: readonly [string, string, ...string[]];
51
+
54
52
  }
55
53
 
56
54
  /**
@@ -87,8 +85,7 @@ export interface SplashScreenProps {
87
85
  */
88
86
  colors?: SplashColors;
89
87
 
90
- /** Optional gradient colors (overrides background color) */
91
- gradientColors?: readonly [string, string, ...string[]];
88
+
92
89
 
93
90
  /** Control visibility */
94
91
  visible?: boolean;