@umituz/react-native-design-system 2.6.86 → 2.6.88

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,558 @@
1
+ # Countdown
2
+
3
+ Countdown, geri sayım sayacı bileşenidir. Belirli bir tarihe/hedefe kalan süreyi gösterir. Birden fazla hedef arasında geçiş yapabilir, gün, saat, dakika ve saniye olarak gösterebilir.
4
+
5
+ ## Özellikler
6
+
7
+ - ⏰ **Geri Sayım**: Belirli bir tarihe kadar geri sayım
8
+ - 🎯 **Çoklu Hedef**: Birden fazla hedef arasında geçiş
9
+ - 📊 **Time Unit**: Gün, saat, dakika, saniye gösterimi
10
+ - 🎨 **Özelleştirilebilir**: Boyut, etiket, görünüm
11
+ - 🔄 **Hook**: useCountdown hook ile kontrol
12
+ - 🎭 **Tema Bilinci**: Design token uyumlu
13
+ - ♿ **Erişilebilir**: Screen reader desteği
14
+
15
+ ## Kurulum
16
+
17
+ ```tsx
18
+ import { Countdown, useCountdown } from 'react-native-design-system';
19
+ ```
20
+
21
+ ## Temel Kullanım
22
+
23
+ ```tsx
24
+ import React from 'react';
25
+ import { View } from 'react-native';
26
+ import { Countdown } from 'react-native-design-system';
27
+
28
+ export const BasicExample = () => {
29
+ const targetDate = new Date('2025-12-31T23:59:59');
30
+
31
+ return (
32
+ <View style={{ padding: 16 }}>
33
+ <Countdown
34
+ target={{
35
+ date: targetDate,
36
+ label: 'Yılbaşı',
37
+ }}
38
+ />
39
+ </View>
40
+ );
41
+ };
42
+ ```
43
+
44
+ ## Basit Countdown
45
+
46
+ ```tsx
47
+ <Countdown
48
+ target={{
49
+ date: new Date('2025-12-31'),
50
+ label: 'Yılbaşı',
51
+ }}
52
+ />
53
+ ```
54
+
55
+ ## Custom Görünüm
56
+
57
+ ```tsx
58
+ <Countdown
59
+ target={{
60
+ date: new Date('2025-06-30'),
61
+ label: 'Yaz Başlangıcı',
62
+ icon: 'sunny-outline',
63
+ }}
64
+ displayConfig={{
65
+ size: 'large',
66
+ showLabel: true,
67
+ showToggle: false,
68
+ }}
69
+ />
70
+ ```
71
+
72
+ ## Sadece Saat/Dakika/Saniye
73
+
74
+ ```tsx
75
+ <Countdown
76
+ target={{
77
+ date: new Date(Date.now() + 3600000), // 1 saat
78
+ label: 'Teklif Bitişi',
79
+ }}
80
+ displayConfig={{
81
+ showDays: false,
82
+ showHours: true,
83
+ showMinutes: true,
84
+ showSeconds: true,
85
+ }}
86
+ />
87
+ ```
88
+
89
+ ## Çoklu Hedef
90
+
91
+ ```tsx
92
+ <Countdown
93
+ target={{
94
+ date: new Date('2025-12-31'),
95
+ label: 'Yılbaşı',
96
+ icon: 'calendar-outline',
97
+ }}
98
+ alternateTargets={[
99
+ {
100
+ date: new Date('2025-06-30'),
101
+ label: 'Yaz Başlangıcı',
102
+ icon: 'sunny-outline',
103
+ },
104
+ {
105
+ date: new Date('2025-03-20'),
106
+ label: 'İlk Bahar',
107
+ icon: 'flower-outline',
108
+ },
109
+ ]}
110
+ />
111
+ ```
112
+
113
+ ## Custom Label Format
114
+
115
+ ```tsx
116
+ <Countdown
117
+ target={{
118
+ date: new Date('2025-12-31'),
119
+ label: 'Yılbaşı',
120
+ }}
121
+ formatLabel={(unit, value) => {
122
+ const labels = {
123
+ days: 'gün',
124
+ hours: 'saat',
125
+ minutes: 'dakika',
126
+ seconds: 'saniye',
127
+ };
128
+ return labels[unit];
129
+ }}
130
+ />
131
+ ```
132
+
133
+ ## onExpire Callback
134
+
135
+ ```tsx
136
+ <Countdown
137
+ target={{
138
+ date: new Date('2025-12-31'),
139
+ label: 'Yılbaşı',
140
+ }}
141
+ onExpire={() => {
142
+ console.log('Süre doldu!');
143
+ Alert.alert('Süre doldu!');
144
+ }}
145
+ />
146
+ ```
147
+
148
+ ## useCountdown Hook
149
+
150
+ ### Temel Kullanım
151
+
152
+ ```tsx
153
+ import { useCountdown } from 'react-native-design-system';
154
+
155
+ export const MyComponent = () => {
156
+ const { timeRemaining, isActive, isExpired, start, stop, reset } = useCountdown(
157
+ {
158
+ date: new Date('2025-12-31'),
159
+ label: 'Yılbaşı',
160
+ },
161
+ {
162
+ interval: 1000,
163
+ autoStart: true,
164
+ }
165
+ );
166
+
167
+ return (
168
+ <View>
169
+ <Text>{timeRemaining.days} gün {timeRemaining.hours} saat</Text>
170
+ <Button title={isActive ? 'Durdur' : 'Başlat'} onPress={isActive ? stop : start} />
171
+ </View>
172
+ );
173
+ };
174
+ ```
175
+
176
+ ### Manual Kontrol
177
+
178
+ ```tsx
179
+ const { timeRemaining, isActive, start, stop, reset } = useCountdown(
180
+ target,
181
+ { autoStart: false }
182
+ );
183
+
184
+ return (
185
+ <View>
186
+ <Text>{timeRemaining.totalSeconds} saniye</Text>
187
+ <Button title="Başlat" onPress={start} />
188
+ <Button title="Durdur" onPress={stop} />
189
+ <Button title="Sıfırla" onPress={reset} />
190
+ </View>
191
+ );
192
+ ```
193
+
194
+ ### onTick Callback
195
+
196
+ ```tsx
197
+ const { timeRemaining } = useCountdown(target, {
198
+ onTick: (time) => {
199
+ console.log('Kalan süre:', time.totalSeconds);
200
+ },
201
+ });
202
+ ```
203
+
204
+ ## Örnek Kullanımlar
205
+
206
+ ### Flash Sale
207
+
208
+ ```tsx
209
+ export const FlashSaleCountdown = () => {
210
+ const endDate = new Date(Date.now() + 3600000); // 1 saat
211
+
212
+ return (
213
+ <AtomicCard variant="elevated">
214
+ <Countdown
215
+ target={{
216
+ date: endDate,
217
+ label: 'Flash Sale Bitiş',
218
+ icon: 'flash-outline',
219
+ }}
220
+ displayConfig={{
221
+ showDays: false,
222
+ size: 'large',
223
+ }}
224
+ onExpire={() => {
225
+ Alert.alert('Satış bitti!');
226
+ }}
227
+ />
228
+ </AtomicCard>
229
+ );
230
+ };
231
+ ```
232
+
233
+ ### Etkinlik Sayacı
234
+
235
+ ```tsx
236
+ export const EventCountdown = () => {
237
+ const [events] = useState([
238
+ {
239
+ date: new Date('2025-06-30'),
240
+ label: 'Yaz Konseri',
241
+ icon: 'musical-notes-outline',
242
+ },
243
+ {
244
+ date: new Date('2025-09-15'),
245
+ label: 'Teknoloji Zirvesi',
246
+ icon: 'laptop-outline',
247
+ },
248
+ {
249
+ date: new Date('2025-12-25'),
250
+ label: 'Yılbaşı Partisi',
251
+ icon: 'gift-outline',
252
+ },
253
+ ]);
254
+
255
+ return (
256
+ <View style={{ padding: 16 }}>
257
+ <Countdown
258
+ target={events[0]}
259
+ alternateTargets={events.slice(1)}
260
+ displayConfig={{
261
+ size: 'medium',
262
+ showToggle: true,
263
+ }}
264
+ onTargetChange={(target) => {
265
+ console.log('Hedef değişti:', target.label);
266
+ }}
267
+ />
268
+ </View>
269
+ );
270
+ };
271
+ ```
272
+
273
+ ### Yarışma Sayacı
274
+
275
+ ```tsx
276
+ export const CompetitionCountdown = () => {
277
+ const deadline = new Date('2025-03-31T23:59:59');
278
+
279
+ return (
280
+ <View style={{ padding: 16 }}>
281
+ <AtomicText type="headlineMedium" style={{ textAlign: 'center', marginBottom: 16 }}>
282
+ Yarışma Katılım Süresi
283
+ </AtomicText>
284
+
285
+ <Countdown
286
+ target={{
287
+ date: deadline,
288
+ label: 'Son Katılım Tarihi',
289
+ icon: 'trophy-outline',
290
+ }}
291
+ displayConfig={{
292
+ size: 'large',
293
+ showLabel: true,
294
+ }}
295
+ formatLabel={(unit) => {
296
+ const labels = {
297
+ days: 'GÜN',
298
+ hours: 'SAAT',
299
+ minutes: 'DAKİKA',
300
+ seconds: 'SANİYE',
301
+ };
302
+ return labels[unit];
303
+ }}
304
+ onExpire={() => {
305
+ Alert.alert('Yarışma sona erdi!');
306
+ }}
307
+ />
308
+ </View>
309
+ );
310
+ };
311
+ ```
312
+
313
+ ### İndirim Sayacı
314
+
315
+ ```tsx
316
+ export const DiscountTimer = ({ discountPercentage, validUntil }) => {
317
+ return (
318
+ <View style={{ backgroundColor: '#ff6b6b', padding: 16, borderRadius: 8 }}>
319
+ <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 8 }}>
320
+ <AtomicIcon name="pricetag-outline" size="sm" color="#fff" />
321
+ <AtomicText type="titleMedium" style={{ color: '#fff', marginLeft: 8 }}>
322
+ %{discountPercentage} İndirim
323
+ </AtomicText>
324
+ </View>
325
+
326
+ <Countdown
327
+ target={{
328
+ date: validUntil,
329
+ label: 'Teklif Bitişi',
330
+ }}
331
+ displayConfig={{
332
+ showDays: false,
333
+ size: 'medium',
334
+ showLabel: false,
335
+ }}
336
+ />
337
+ </View>
338
+ );
339
+ };
340
+ ```
341
+
342
+ ### Oyun Sayacı
343
+
344
+ ```tsx
345
+ export const GameTimer = ({ duration, onTimeUp }) => {
346
+ const targetDate = useMemo(() => new Date(Date.now() + duration), [duration]);
347
+ const [timeLeft, setTimeLeft] = useState(duration);
348
+
349
+ const { timeRemaining, isExpired } = useCountdown(
350
+ { date: targetDate },
351
+ {
352
+ onTick: (time) => {
353
+ setTimeLeft(time.totalSeconds * 1000);
354
+ },
355
+ onExpire: () => {
356
+ onTimeUp?.();
357
+ },
358
+ }
359
+ );
360
+
361
+ return (
362
+ <View style={{ alignItems: 'center' }}>
363
+ <Countdown
364
+ target={{ date: targetDate }}
365
+ displayConfig={{
366
+ showDays: false,
367
+ showHours: false,
368
+ showMinutes: true,
369
+ showSeconds: true,
370
+ showLabel: false,
371
+ size: 'large',
372
+ }}
373
+ />
374
+
375
+ {isExpired && (
376
+ <AtomicText type="headlineLarge" style={{ color: 'red' }}>
377
+ Süre Doldu!
378
+ </AtomicText>
379
+ )}
380
+ </View>
381
+ );
382
+ };
383
+ ```
384
+
385
+ ### Günlük Hedef Sayacı
386
+
387
+ ```tsx
388
+ export const DailyResetCountdown = () => {
389
+ const getNextMidnight = () => {
390
+ const now = new Date();
391
+ const tomorrow = new Date(now);
392
+ tomorrow.setDate(tomorrow.getDate() + 1);
393
+ tomorrow.setHours(0, 0, 0, 0);
394
+ return tomorrow;
395
+ };
396
+
397
+ const [target] = useState(getNextMidnight);
398
+
399
+ return (
400
+ <View style={{ padding: 16 }}>
401
+ <AtomicText type="titleMedium" style={{ marginBottom: 8 }}>
402
+ Günlük Hedefler Sıfırlanmasına:
403
+ </AtomicText>
404
+
405
+ <Countdown
406
+ target={{
407
+ date: target,
408
+ label: 'Yarın',
409
+ }}
410
+ displayConfig={{
411
+ showDays: false,
412
+ size: 'medium',
413
+ showLabel: false,
414
+ }}
415
+ onExpire={() => {
416
+ // Refresh targets
417
+ window.location.reload();
418
+ }}
419
+ />
420
+ </View>
421
+ );
422
+ };
423
+ ```
424
+
425
+ ## Props
426
+
427
+ ### CountdownProps
428
+
429
+ | Prop | Tip | Varsayılan | Açıklama |
430
+ |------|-----|------------|----------|
431
+ | `target` | `CountdownTarget` | - **(Zorunlu)** | Hedef tarih |
432
+ | `alternateTargets` | `CountdownTarget[]` | `[]` | Alternatif hedefler |
433
+ | `displayConfig` | `CountdownDisplayConfig` | `{}` | Görünüm konfigürasyonu |
434
+ | `interval` | `number` | `1000` | Güncelleme aralığı (ms) |
435
+ | `onExpire` | `() => void` | - | Süre dolunca |
436
+ | `onTargetChange` | `(target) => void` | - | Hedef değişince |
437
+ | `formatLabel` | `(unit, value) => string` | - | Label formatlama |
438
+
439
+ ### CountdownTarget
440
+
441
+ | Prop | Tip | Açıklama |
442
+ |------|-----|----------|
443
+ | `date` | `Date` | Hedef tarih |
444
+ | `label` | `string` | Hedef etiketi |
445
+ | `icon` | `string` | İkon ismi |
446
+
447
+ ### CountdownDisplayConfig
448
+
449
+ | Prop | Tip | Varsayılan | Açıklama |
450
+ |------|-----|------------|----------|
451
+ | `showLabel` | `boolean` | `true` | Label göster |
452
+ | `showToggle` | `boolean` | `alternateTargets.length > 0` | Toggle göster |
453
+ | `size` | `'small' \| 'medium' \| 'large'` | `'medium'` | Boyut |
454
+ | `showDays` | `boolean` | `auto` | Gün göster |
455
+ | `showHours` | `boolean` | `true` | Saat göster |
456
+ | `showMinutes` | `boolean` | `true` | Dakika göster |
457
+ | `showSeconds` | `boolean` | `true` | Saniye göster |
458
+
459
+ ### useCountdown Options
460
+
461
+ | Prop | Tip | Varsayılan | Açıklama |
462
+ |------|-----|------------|----------|
463
+ | `interval` | `number` | `1000` | Güncelleme aralığı (ms) |
464
+ | `autoStart` | `boolean` | `true` | Otomatik başlat |
465
+ | `onExpire` | `() => void` | - | Süre dolunca |
466
+ | `onTick` | `(time) => void` | - | Her tick'te |
467
+
468
+ ### useCountdown Return
469
+
470
+ | Prop | Tip | Açıklama |
471
+ |------|-----|----------|
472
+ | `timeRemaining` | `TimeRemaining` | Kalan süre |
473
+ | `isActive` | `boolean` | Aktif mi |
474
+ | `isExpired` | `boolean` | Doldu mu |
475
+ | `start` | `() => void` | Başlat |
476
+ | `stop` | `() => void` | Durdur |
477
+ | `reset` | `() => void` | Sıfırla |
478
+ | `setTarget` | `(target) => void` | Hedef belirle |
479
+
480
+ ## Best Practices
481
+
482
+ ### 1. Hedef Seçimi
483
+
484
+ ```tsx
485
+ // Gelecek tarih
486
+ target={{ date: new Date('2025-12-31') }} // ✅
487
+
488
+ // Geçmiş tarih
489
+ target={{ date: new Date('2020-01-01') }} // ❌
490
+ ```
491
+
492
+ ### 2. Performans
493
+
494
+ ```tsx
495
+ // Uygun interval
496
+ interval={1000} // ✅ 1 saniye (önerilen)
497
+ interval={100} // ❌ 100ms (çok sık)
498
+ ```
499
+
500
+ ### 3. Memory Leak Önleme
501
+
502
+ ```tsx
503
+ useEffect(() => {
504
+ return () => {
505
+ // Cleanup
506
+ };
507
+ }, []);
508
+ ```
509
+
510
+ ### 4. Timezone
511
+
512
+ ```tsx
513
+ // UTC kullan
514
+ const date = new Date('2025-12-31T23:59:59Z');
515
+ ```
516
+
517
+ ## Erişilebilirlik
518
+
519
+ Countdown, tam erişilebilirlik desteği sunar:
520
+
521
+ - ✅ Screen reader desteği
522
+ - ✅ Semantic anlamlar
523
+ - ✅ Timer role
524
+ - ✅ Live region
525
+
526
+ ## Performans İpuçları
527
+
528
+ 1. **Interval**: Uygun interval kullanın (1000ms önerilen)
529
+ 2. **Memoization**: Component'leri memo edin
530
+ 3. **Cleanup**: useEffect'te cleanup yapın
531
+ 4. **Throttle**: onTick callback'ini throttle edin
532
+
533
+ ## İlgili Bileşenler
534
+
535
+ - [`TimeUnit`](#timeunit) - Zaman birimi bileşeni
536
+ - [`CountdownHeader`](#countdownheader) - Countdown başlığı
537
+ - [`AtomicText`](../../atoms/AtomicText/README.md) - Metin bileşeni
538
+ - [`AtomicIcon`](../../atoms/AtomicIcon/README.md) - İkon bileşeni
539
+
540
+ ## Yardımcı Fonksiyonlar
541
+
542
+ ```typescript
543
+ // Kalan süreyi hesapla
544
+ calculateTimeRemaining(targetDate: Date): TimeRemaining
545
+
546
+ // Sayıyı padding yap
547
+ padNumber(num: number): string
548
+
549
+ // Sonraki gün başlangıcı
550
+ getNextDayStart(): Date
551
+
552
+ // Sonraki yıl başlangıcı
553
+ getNextYearStart(): Date
554
+ ```
555
+
556
+ ## Lisans
557
+
558
+ MIT