@umituz/react-native-design-system 2.3.13 → 2.3.15

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.
Files changed (106) hide show
  1. package/package.json +32 -13
  2. package/src/index.ts +116 -0
  3. package/src/layouts/ScreenLayout/ScreenLayout.example.tsx +2 -2
  4. package/src/layouts/ScreenLayout/ScreenLayout.tsx +1 -1
  5. package/src/molecules/animation/core/AnimationCore.ts +29 -0
  6. package/src/molecules/animation/domain/entities/Animation.ts +81 -0
  7. package/src/molecules/animation/domain/entities/Fireworks.ts +44 -0
  8. package/src/molecules/animation/domain/entities/Theme.ts +76 -0
  9. package/src/molecules/animation/index.ts +146 -0
  10. package/src/molecules/animation/infrastructure/services/AnimationConfigService.ts +35 -0
  11. package/src/molecules/animation/infrastructure/services/SpringAnimationConfigService.ts +67 -0
  12. package/src/molecules/animation/infrastructure/services/TimingAnimationConfigService.ts +57 -0
  13. package/src/molecules/animation/infrastructure/services/__tests__/SpringAnimationConfigService.test.ts +114 -0
  14. package/src/molecules/animation/infrastructure/services/__tests__/TimingAnimationConfigService.test.ts +105 -0
  15. package/src/molecules/animation/presentation/components/Fireworks.tsx +126 -0
  16. package/src/molecules/animation/presentation/components/__tests__/Fireworks.test.tsx +189 -0
  17. package/src/molecules/animation/presentation/hooks/__tests__/useAnimation.integration.test.ts +216 -0
  18. package/src/molecules/animation/presentation/hooks/__tests__/useFireworks.test.ts +242 -0
  19. package/src/molecules/animation/presentation/hooks/__tests__/useGesture.test.ts +111 -0
  20. package/src/molecules/animation/presentation/hooks/__tests__/useSpringAnimation.test.ts +131 -0
  21. package/src/molecules/animation/presentation/hooks/__tests__/useTimingAnimation.test.ts +175 -0
  22. package/src/molecules/animation/presentation/hooks/__tests__/useTransformAnimation.test.ts +137 -0
  23. package/src/molecules/animation/presentation/hooks/useAnimation.ts +77 -0
  24. package/src/molecules/animation/presentation/hooks/useFireworks.ts +141 -0
  25. package/src/molecules/animation/presentation/hooks/useGesture.ts +61 -0
  26. package/src/molecules/animation/presentation/hooks/useGestureCreators.ts +163 -0
  27. package/src/molecules/animation/presentation/hooks/useGestureState.ts +53 -0
  28. package/src/molecules/animation/presentation/hooks/useIconAnimations.ts +119 -0
  29. package/src/molecules/animation/presentation/hooks/useModalAnimations.ts +124 -0
  30. package/src/molecules/animation/presentation/hooks/useReanimatedReady.ts +60 -0
  31. package/src/molecules/animation/presentation/hooks/useSpringAnimation.ts +69 -0
  32. package/src/molecules/animation/presentation/hooks/useTimingAnimation.ts +111 -0
  33. package/src/molecules/animation/presentation/hooks/useTransformAnimation.ts +57 -0
  34. package/src/molecules/animation/presentation/providers/AnimationThemeProvider.tsx +62 -0
  35. package/src/molecules/animation/presentation/providers/__tests__/AnimationThemeProvider.test.tsx +165 -0
  36. package/src/molecules/animation/types/global.d.ts +97 -0
  37. package/src/molecules/calendar/domain/entities/CalendarDay.entity.ts +115 -0
  38. package/src/molecules/calendar/domain/entities/CalendarEvent.entity.ts +202 -0
  39. package/src/molecules/calendar/domain/repositories/ICalendarRepository.ts +120 -0
  40. package/src/molecules/calendar/index.ts +98 -0
  41. package/src/molecules/calendar/infrastructure/services/CalendarEvents.ts +196 -0
  42. package/src/molecules/calendar/infrastructure/services/CalendarGeneration.ts +172 -0
  43. package/src/molecules/calendar/infrastructure/services/CalendarPermissions.ts +92 -0
  44. package/src/molecules/calendar/infrastructure/services/CalendarService.ts +161 -0
  45. package/src/molecules/calendar/infrastructure/services/CalendarSync.ts +205 -0
  46. package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts +307 -0
  47. package/src/molecules/calendar/infrastructure/utils/DateUtilities.ts +128 -0
  48. package/src/molecules/calendar/presentation/components/AtomicCalendar.tsx +279 -0
  49. package/src/molecules/calendar/presentation/hooks/useCalendar.ts +356 -0
  50. package/src/molecules/celebration/domain/entities/CelebrationConfig.ts +17 -0
  51. package/src/molecules/celebration/domain/entities/FireworksConfig.ts +32 -0
  52. package/src/molecules/celebration/index.ts +93 -0
  53. package/src/molecules/celebration/infrastructure/services/FireworksConfigService.ts +49 -0
  54. package/src/molecules/celebration/presentation/components/CelebrationFireworksOverlay.tsx +33 -0
  55. package/src/molecules/celebration/presentation/components/CelebrationModal.tsx +78 -0
  56. package/src/molecules/celebration/presentation/components/CelebrationModalContent.tsx +90 -0
  57. package/src/molecules/celebration/presentation/hooks/useCelebrationModalAnimation.ts +49 -0
  58. package/src/molecules/celebration/presentation/hooks/useCelebrationState.ts +45 -0
  59. package/src/molecules/celebration/presentation/styles/CelebrationModalStyles.ts +65 -0
  60. package/src/molecules/countdown/components/Countdown.tsx +128 -0
  61. package/src/molecules/countdown/components/CountdownHeader.tsx +84 -0
  62. package/src/molecules/countdown/components/TimeUnit.tsx +73 -0
  63. package/src/molecules/countdown/hooks/useCountdown.ts +107 -0
  64. package/src/molecules/countdown/index.ts +25 -0
  65. package/src/molecules/countdown/types/CountdownTypes.ts +31 -0
  66. package/src/molecules/countdown/utils/TimeCalculator.ts +46 -0
  67. package/src/molecules/emoji/domain/entities/Emoji.ts +129 -0
  68. package/src/molecules/emoji/index.ts +177 -0
  69. package/src/molecules/emoji/presentation/components/EmojiPicker.tsx +102 -0
  70. package/src/molecules/emoji/presentation/hooks/useEmojiPicker.ts +171 -0
  71. package/src/molecules/index.ts +24 -0
  72. package/src/molecules/long-press-menu/domain/entities/MenuAction.ts +37 -0
  73. package/src/molecules/long-press-menu/index.ts +16 -0
  74. package/src/molecules/navigation/StackNavigator.tsx +75 -0
  75. package/src/molecules/navigation/TabsNavigator.tsx +94 -0
  76. package/src/molecules/navigation/components/FabButton.tsx +45 -0
  77. package/src/molecules/navigation/components/TabLabel.tsx +47 -0
  78. package/src/molecules/navigation/createStackNavigator.ts +20 -0
  79. package/src/molecules/navigation/createTabNavigator.ts +20 -0
  80. package/src/molecules/navigation/hooks/useTabBarStyles.ts +54 -0
  81. package/src/molecules/navigation/index.ts +37 -0
  82. package/src/molecules/navigation/types.ts +118 -0
  83. package/src/molecules/navigation/utils/AppNavigation.ts +101 -0
  84. package/src/molecules/navigation/utils/IconRenderer.ts +50 -0
  85. package/src/molecules/navigation/utils/LabelProcessor.ts +70 -0
  86. package/src/molecules/navigation/utils/NavigationCleanup.ts +62 -0
  87. package/src/molecules/navigation/utils/NavigationTheme.ts +21 -0
  88. package/src/molecules/navigation/utils/NavigationValidator.ts +61 -0
  89. package/src/molecules/navigation/utils/ScreenFactory.ts +115 -0
  90. package/src/molecules/navigation/utils/__tests__/IconRenderer.getIconName.test.ts +109 -0
  91. package/src/molecules/navigation/utils/__tests__/IconRenderer.renderIcon.test.ts +116 -0
  92. package/src/molecules/navigation/utils/__tests__/LabelProcessor.processLabel.test.ts +116 -0
  93. package/src/molecules/navigation/utils/__tests__/LabelProcessor.processTitle.test.ts +59 -0
  94. package/src/molecules/navigation/utils/__tests__/NavigationCleanup.test.ts +271 -0
  95. package/src/molecules/navigation/utils/__tests__/NavigationValidator.test.ts +252 -0
  96. package/src/molecules/swipe-actions/domain/entities/SwipeAction.ts +194 -0
  97. package/src/molecules/swipe-actions/index.ts +6 -0
  98. package/src/molecules/swipe-actions/presentation/components/SwipeActionButton.tsx +131 -0
  99. package/src/theme/hooks/useResponsiveDesignTokens.ts +1 -1
  100. package/src/utilities/clipboard/ClipboardUtils.ts +71 -0
  101. package/src/utilities/clipboard/index.ts +5 -0
  102. package/src/utilities/index.ts +6 -0
  103. package/src/utilities/sharing/domain/entities/Share.ts +210 -0
  104. package/src/utilities/sharing/index.ts +205 -0
  105. package/src/utilities/sharing/infrastructure/services/SharingService.ts +165 -0
  106. package/src/utilities/sharing/presentation/hooks/useSharing.ts +154 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Date Utilities
3
+ *
4
+ * Pure functions for date operations and formatting.
5
+ * No side effects, timezone-aware operations.
6
+ *
7
+ * SOLID: Single Responsibility - Only date operations
8
+ * DRY: Reusable date utility functions
9
+ * KISS: Simple, focused functions
10
+ */
11
+
12
+ export class DateUtilities {
13
+ /**
14
+ * Format date to string (YYYY-MM-DD)
15
+ */
16
+ static formatDateToString(date: Date): string {
17
+ return date.toISOString().split('T')[0];
18
+ }
19
+
20
+ /**
21
+ * Check if two dates are the same day
22
+ */
23
+ static isSameDay(date1: Date, date2: Date): boolean {
24
+ return this.formatDateToString(date1) === this.formatDateToString(date2);
25
+ }
26
+
27
+ /**
28
+ * Add days to a date
29
+ */
30
+ static addDays(date: Date, days: number): Date {
31
+ const result = new Date(date);
32
+ result.setDate(result.getDate() + days);
33
+ return result;
34
+ }
35
+
36
+ /**
37
+ * Check if date is today
38
+ */
39
+ static isToday(date: Date): boolean {
40
+ return this.isSameDay(date, new Date());
41
+ }
42
+
43
+ /**
44
+ * Get current timezone
45
+ */
46
+ static getCurrentTimezone(): string {
47
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
48
+ }
49
+
50
+ /**
51
+ * Get start of month
52
+ */
53
+ static getStartOfMonth(date: Date): Date {
54
+ return new Date(date.getFullYear(), date.getMonth(), 1);
55
+ }
56
+
57
+ /**
58
+ * Get end of month
59
+ */
60
+ static getEndOfMonth(date: Date): Date {
61
+ return new Date(date.getFullYear(), date.getMonth() + 1, 0);
62
+ }
63
+
64
+ /**
65
+ * Get number of days in month
66
+ */
67
+ static getDaysInMonth(date: Date): number {
68
+ return this.getEndOfMonth(date).getDate();
69
+ }
70
+
71
+ /**
72
+ * Get start of week (Sunday)
73
+ */
74
+ static getStartOfWeek(date: Date): Date {
75
+ const result = new Date(date);
76
+ const day = result.getDay();
77
+ const diff = result.getDate() - day;
78
+ return new Date(result.setDate(diff));
79
+ }
80
+
81
+ /**
82
+ * Get end of week (Saturday)
83
+ */
84
+ static getEndOfWeek(date: Date): Date {
85
+ const result = this.getStartOfWeek(date);
86
+ result.setDate(result.getDate() + 6);
87
+ return result;
88
+ }
89
+
90
+ /**
91
+ * Parse date from string (YYYY-MM-DD)
92
+ */
93
+ static parseDate(dateString: string): Date {
94
+ const [year, month, day] = dateString.split('-').map(Number);
95
+ return new Date(year, month - 1, day);
96
+ }
97
+
98
+ /**
99
+ * Format time to string (HH:MM)
100
+ */
101
+ static formatTimeToString(date: Date): string {
102
+ return date.toTimeString().slice(0, 5);
103
+ }
104
+
105
+ /**
106
+ * Check if date is in the past
107
+ */
108
+ static isPast(date: Date): boolean {
109
+ return date < new Date();
110
+ }
111
+
112
+ /**
113
+ * Check if date is in the future
114
+ */
115
+ static isFuture(date: Date): boolean {
116
+ return date > new Date();
117
+ }
118
+ }
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
@@ -0,0 +1,279 @@
1
+ /**
2
+ * AtomicCalendar Component
3
+ *
4
+ * Generic, reusable calendar component with month view.
5
+ * Works with any type of events (workouts, habits, tasks, etc.)
6
+ *
7
+ * Features:
8
+ * - Monthly grid view (42 days = 6 weeks)
9
+ * - Timezone-aware via calendar service
10
+ * - Event indicators (colored dots)
11
+ * - Customizable styling
12
+ * - Accessible
13
+ * - Theme-aware
14
+ *
15
+ * Usage:
16
+ * ```tsx
17
+ * import { AtomicCalendar, useCalendar } from '@umituz/react-native-calendar';
18
+ *
19
+ * const MyScreen = () => {
20
+ * const { days, selectedDate, actions } = useCalendar();
21
+ *
22
+ * return (
23
+ * <AtomicCalendar
24
+ * days={days}
25
+ * selectedDate={selectedDate}
26
+ * onDateSelect={actions.setSelectedDate}
27
+ * />
28
+ * );
29
+ * };
30
+ * ```
31
+ */
32
+
33
+ import React from 'react';
34
+ import { View, TouchableOpacity, StyleSheet, StyleProp, ViewStyle } from 'react-native';
35
+ import { useAppDesignTokens, AtomicText } from '../../../../index';
36
+ import type { CalendarDay } from '../../domain/entities/CalendarDay.entity';
37
+ import { CalendarService } from '../../infrastructure/services/CalendarService';
38
+
39
+ /**
40
+ * AtomicCalendar Props
41
+ */
42
+ export interface AtomicCalendarProps {
43
+ /**
44
+ * Calendar days to display (42 days for 6-week grid)
45
+ */
46
+ days: CalendarDay[];
47
+
48
+ /**
49
+ * Currently selected date
50
+ */
51
+ selectedDate: Date;
52
+
53
+ /**
54
+ * Callback when a date is selected
55
+ */
56
+ onDateSelect: (date: Date) => void;
57
+
58
+ /**
59
+ * Whether to show weekday headers
60
+ * @default true
61
+ */
62
+ showWeekdayHeaders?: boolean;
63
+
64
+ /**
65
+ * Maximum number of event indicators to show per day
66
+ * @default 3
67
+ */
68
+ maxEventIndicators?: number;
69
+
70
+ /**
71
+ * Custom container style
72
+ */
73
+ style?: StyleProp<ViewStyle>;
74
+
75
+ /**
76
+ * Custom day cell style
77
+ */
78
+ dayStyle?: StyleProp<ViewStyle>;
79
+
80
+ /**
81
+ * Whether to show event count when exceeds max indicators
82
+ * @default true
83
+ */
84
+ showEventCount?: boolean;
85
+
86
+ /**
87
+ * Test ID for testing
88
+ */
89
+ testID?: string;
90
+ }
91
+
92
+ /**
93
+ * AtomicCalendar Component
94
+ */
95
+ export const AtomicCalendar: React.FC<AtomicCalendarProps> = ({
96
+ days,
97
+ selectedDate,
98
+ onDateSelect,
99
+ showWeekdayHeaders = true,
100
+ maxEventIndicators = 3,
101
+ style,
102
+ dayStyle,
103
+ showEventCount = true,
104
+ testID,
105
+ }) => {
106
+ const tokens = useAppDesignTokens();
107
+
108
+ // Get weekday names (localized)
109
+ const weekdayNames = CalendarService.getWeekdayNames();
110
+
111
+ return (
112
+ <View style={[styles.container, { backgroundColor: tokens.colors.surface }, style]} testID={testID}>
113
+ {/* Weekday Headers */}
114
+ {showWeekdayHeaders && (
115
+ <View style={styles.weekdayHeader}>
116
+ {weekdayNames.map((day, index) => (
117
+ <View key={index} style={styles.weekdayCell}>
118
+ <AtomicText
119
+ type="bodySmall"
120
+ color="secondary"
121
+ style={styles.weekdayText}
122
+ >
123
+ {day}
124
+ </AtomicText>
125
+ </View>
126
+ ))}
127
+ </View>
128
+ )}
129
+
130
+ {/* Calendar Grid */}
131
+ <View style={styles.grid}>
132
+ {days.map((day, index) => {
133
+ const isSelected = CalendarService.isSameDay(day.date, selectedDate);
134
+ const eventCount = day.events.length;
135
+ const visibleEvents = day.events.slice(0, maxEventIndicators);
136
+ const hiddenEventCount = Math.max(0, eventCount - maxEventIndicators);
137
+
138
+ return (
139
+ <TouchableOpacity
140
+ key={index}
141
+ style={[
142
+ styles.dayCell,
143
+ {
144
+ backgroundColor: isSelected
145
+ ? tokens.colors.primary
146
+ : 'transparent',
147
+ borderColor: isSelected
148
+ ? tokens.colors.primary
149
+ : day.isToday
150
+ ? tokens.colors.primary
151
+ : tokens.colors.border,
152
+ borderWidth: isSelected ? 2 : day.isToday ? 2 : 1,
153
+ opacity: day.isDisabled ? 0.4 : 1,
154
+ },
155
+ dayStyle,
156
+ ]}
157
+ onPress={() => !day.isDisabled && onDateSelect(day.date)}
158
+ disabled={day.isDisabled}
159
+ testID={testID ? `${testID}-day-${index}` : undefined}
160
+ accessibilityLabel={`${day.date.toLocaleDateString()}, ${eventCount} events`}
161
+ accessibilityRole="button"
162
+ accessibilityState={{ disabled: day.isDisabled, selected: isSelected }}
163
+ >
164
+ {/* Day Number */}
165
+ <AtomicText
166
+ type="bodyMedium"
167
+ color={
168
+ isSelected
169
+ ? 'inverse'
170
+ : day.isCurrentMonth
171
+ ? 'primary'
172
+ : 'secondary'
173
+ }
174
+ style={[
175
+ styles.dayText,
176
+ day.isToday && !isSelected && { fontWeight: 'bold' },
177
+ ]}
178
+ >
179
+ {day.date.getDate()}
180
+ </AtomicText>
181
+
182
+ {/* Event Indicators */}
183
+ <View style={styles.eventIndicators}>
184
+ {/* Today indicator (if today and has no events) */}
185
+ {day.isToday && eventCount === 0 && (
186
+ <View
187
+ style={[
188
+ styles.eventDot,
189
+ { backgroundColor: tokens.colors.success },
190
+ ]}
191
+ />
192
+ )}
193
+
194
+ {/* Event dots */}
195
+ {visibleEvents.map((event, eventIndex) => (
196
+ <View
197
+ key={eventIndex}
198
+ style={[
199
+ styles.eventDot,
200
+ {
201
+ backgroundColor: event.color
202
+ ? event.color
203
+ : event.isCompleted
204
+ ? tokens.colors.success
205
+ : tokens.colors.primary,
206
+ },
207
+ ]}
208
+ />
209
+ ))}
210
+
211
+ {/* More events count */}
212
+ {showEventCount && hiddenEventCount > 0 && (
213
+ <AtomicText
214
+ type="bodySmall"
215
+ color="secondary"
216
+ style={styles.moreEventsText}
217
+ >
218
+ +{hiddenEventCount}
219
+ </AtomicText>
220
+ )}
221
+ </View>
222
+ </TouchableOpacity>
223
+ );
224
+ })}
225
+ </View>
226
+ </View>
227
+ );
228
+ };
229
+
230
+ const styles = StyleSheet.create({
231
+ container: {
232
+ borderRadius: 12,
233
+ padding: 16,
234
+ },
235
+ weekdayHeader: {
236
+ flexDirection: 'row',
237
+ marginBottom: 12,
238
+ },
239
+ weekdayCell: {
240
+ flex: 1,
241
+ alignItems: 'center',
242
+ },
243
+ weekdayText: {
244
+ textAlign: 'center',
245
+ },
246
+ grid: {
247
+ flexDirection: 'row',
248
+ flexWrap: 'wrap',
249
+ },
250
+ dayCell: {
251
+ width: `${100 / 7}%`,
252
+ aspectRatio: 1,
253
+ justifyContent: 'center',
254
+ alignItems: 'center',
255
+ borderRadius: 8,
256
+ marginBottom: 4,
257
+ padding: 4,
258
+ },
259
+ dayText: {
260
+ textAlign: 'center',
261
+ },
262
+ eventIndicators: {
263
+ flexDirection: 'row',
264
+ alignItems: 'center',
265
+ justifyContent: 'center',
266
+ marginTop: 4,
267
+ gap: 2,
268
+ flexWrap: 'wrap',
269
+ },
270
+ eventDot: {
271
+ width: 4,
272
+ height: 4,
273
+ borderRadius: 2,
274
+ },
275
+ moreEventsText: {
276
+ fontSize: 8,
277
+ marginLeft: 2,
278
+ },
279
+ });