@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,356 @@
1
+ /**
2
+ * useCalendar Hook
3
+ *
4
+ * Main hook for calendar functionality.
5
+ * Provides calendar state, events, and actions.
6
+ *
7
+ * Usage:
8
+ * ```tsx
9
+ * const {
10
+ * days,
11
+ * events,
12
+ * selectedDate,
13
+ * viewMode,
14
+ * actions
15
+ * } = useCalendar();
16
+ *
17
+ * // Navigate calendar
18
+ * actions.navigateMonth('next');
19
+ *
20
+ * // Add event
21
+ * actions.addEvent({
22
+ * title: 'Team Meeting',
23
+ * date: '2024-10-30',
24
+ * time: '14:00',
25
+ * });
26
+ * ```
27
+ */
28
+
29
+ import { useMemo, useEffect, useState, useCallback } from 'react';
30
+ import { useCalendarStore, type CalendarViewMode } from '../../infrastructure/storage/CalendarStore';
31
+ import { CalendarService } from '../../infrastructure/services/CalendarService';
32
+ import type { CalendarDay } from '../../domain/entities/CalendarDay.entity';
33
+ import type {
34
+ CalendarEvent,
35
+ SystemCalendar,
36
+ CalendarPermissionResult,
37
+ } from '../../domain/entities/CalendarEvent.entity';
38
+
39
+ /**
40
+ * Calendar hook return type
41
+ */
42
+ export interface UseCalendarReturn {
43
+ // Calendar data
44
+ days: CalendarDay[];
45
+ events: CalendarEvent[];
46
+ selectedDate: Date;
47
+ currentMonth: Date;
48
+ viewMode: CalendarViewMode;
49
+
50
+ // Computed data
51
+ selectedDateEvents: CalendarEvent[];
52
+ currentMonthEvents: CalendarEvent[];
53
+
54
+ // State
55
+ isLoading: boolean;
56
+ error: string | null;
57
+
58
+ // Actions
59
+ actions: {
60
+ loadEvents: () => Promise<void>;
61
+ addEvent: (request: any) => Promise<void>;
62
+ updateEvent: (request: any) => Promise<void>;
63
+ deleteEvent: (id: string) => Promise<void>;
64
+ completeEvent: (id: string) => Promise<void>;
65
+ uncompleteEvent: (id: string) => Promise<void>;
66
+ setSelectedDate: (date: Date) => void;
67
+ goToToday: () => void;
68
+ navigateMonth: (direction: 'prev' | 'next') => void;
69
+ navigateWeek: (direction: 'prev' | 'next') => void;
70
+ setCurrentMonth: (date: Date) => void;
71
+ setViewMode: (mode: CalendarViewMode) => void;
72
+ getEventsForDate: (date: Date) => CalendarEvent[];
73
+ getEventsForMonth: (year: number, month: number) => CalendarEvent[];
74
+ clearError: () => void;
75
+ clearAllEvents: () => Promise<void>;
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Main calendar hook
81
+ */
82
+ export const useCalendar = (): UseCalendarReturn => {
83
+ const {
84
+ events,
85
+ selectedDate,
86
+ currentMonth,
87
+ viewMode,
88
+ isLoading,
89
+ error,
90
+ actions,
91
+ } = useCalendarStore((state) => state);
92
+
93
+ // Load events on mount
94
+ useEffect(() => {
95
+ actions.loadEvents();
96
+ }, []);
97
+
98
+ // Generate calendar days for current month
99
+ const days = useMemo(() => {
100
+ const year = currentMonth.getFullYear();
101
+ const month = currentMonth.getMonth();
102
+ return CalendarService.getMonthDays(year, month, events);
103
+ }, [currentMonth, events]);
104
+
105
+ // Get events for selected date
106
+ const selectedDateEvents = useMemo(() => {
107
+ return actions.getEventsForDate(selectedDate);
108
+ }, [selectedDate, events]);
109
+
110
+ // Get events for current month
111
+ const currentMonthEvents = useMemo(() => {
112
+ const year = currentMonth.getFullYear();
113
+ const month = currentMonth.getMonth();
114
+ return actions.getEventsForMonth(year, month);
115
+ }, [currentMonth, events]);
116
+
117
+ return {
118
+ days,
119
+ events,
120
+ selectedDate,
121
+ currentMonth,
122
+ viewMode,
123
+ selectedDateEvents,
124
+ currentMonthEvents,
125
+ isLoading,
126
+ error,
127
+ actions,
128
+ };
129
+ };
130
+
131
+ /**
132
+ * Hook for calendar navigation
133
+ * Lightweight hook for just navigation actions
134
+ */
135
+ export const useCalendarNavigation = () => {
136
+ const {
137
+ selectedDate,
138
+ currentMonth,
139
+ actions: { setSelectedDate, navigateMonth, goToToday, setCurrentMonth },
140
+ } = useCalendarStore((state) => state);
141
+
142
+ return {
143
+ selectedDate,
144
+ currentMonth,
145
+ setSelectedDate,
146
+ navigateMonth,
147
+ goToToday,
148
+ setCurrentMonth,
149
+ };
150
+ };
151
+
152
+ /**
153
+ * Hook for calendar events only
154
+ * Lightweight hook for just event operations
155
+ */
156
+ export const useCalendarEvents = () => {
157
+ const {
158
+ events,
159
+ isLoading,
160
+ error,
161
+ actions: {
162
+ loadEvents,
163
+ addEvent,
164
+ updateEvent,
165
+ deleteEvent,
166
+ completeEvent,
167
+ uncompleteEvent,
168
+ clearError,
169
+ },
170
+ } = useCalendarStore((state) => state);
171
+
172
+ return {
173
+ events,
174
+ isLoading,
175
+ error,
176
+ loadEvents,
177
+ addEvent,
178
+ updateEvent,
179
+ deleteEvent,
180
+ completeEvent,
181
+ uncompleteEvent,
182
+ clearError,
183
+ };
184
+ };
185
+
186
+ /**
187
+ * Hook for system calendar integration (expo-calendar)
188
+ *
189
+ * USAGE:
190
+ * ```tsx
191
+ * const {
192
+ * systemCalendars,
193
+ * permission,
194
+ * requestPermission,
195
+ * syncEventToCalendar,
196
+ * updateSyncedEvent,
197
+ * deleteSyncedEvent,
198
+ * } = useSystemCalendar();
199
+ *
200
+ * // Request permission
201
+ * const granted = await requestPermission();
202
+ *
203
+ * // Sync event to device calendar
204
+ * await syncEventToCalendar(event);
205
+ * ```
206
+ */
207
+ export const useSystemCalendar = () => {
208
+ const [systemCalendars, setSystemCalendars] = useState<SystemCalendar[]>([]);
209
+ const [permission, setPermission] = useState<CalendarPermissionResult | null>(null);
210
+ const [isLoading, setIsLoading] = useState(false);
211
+
212
+ const { actions } = useCalendarStore((state) => state);
213
+
214
+ /**
215
+ * Request calendar permissions
216
+ */
217
+ const requestPermission = useCallback(async (): Promise<boolean> => {
218
+ setIsLoading(true);
219
+ try {
220
+ const result = await CalendarService.requestPermissions();
221
+ setPermission(result);
222
+ return result.granted;
223
+ } catch {
224
+ return false;
225
+ } finally {
226
+ setIsLoading(false);
227
+ }
228
+ }, []);
229
+
230
+ /**
231
+ * Load system calendars
232
+ */
233
+ const loadSystemCalendars = useCallback(async () => {
234
+ setIsLoading(true);
235
+ try {
236
+ const calendars = await CalendarService.getSystemCalendars();
237
+ setSystemCalendars(calendars);
238
+ } catch {
239
+ setSystemCalendars([]);
240
+ } finally {
241
+ setIsLoading(false);
242
+ }
243
+ }, []);
244
+
245
+ /**
246
+ * Sync event to system calendar
247
+ */
248
+ const syncEventToCalendar = useCallback(
249
+ async (event: CalendarEvent): Promise<boolean> => {
250
+ setIsLoading(true);
251
+ try {
252
+ const result = await CalendarService.syncToSystemCalendar(event);
253
+
254
+ if (result.success && result.eventId && result.calendarId) {
255
+ // Update event with system calendar info
256
+ await actions.updateEvent({
257
+ id: event.id,
258
+ systemCalendar: {
259
+ eventId: result.eventId,
260
+ calendarId: result.calendarId,
261
+ lastSyncedAt: new Date(),
262
+ },
263
+ });
264
+ return true;
265
+ }
266
+
267
+ return false;
268
+ } catch {
269
+ return false;
270
+ } finally {
271
+ setIsLoading(false);
272
+ }
273
+ },
274
+ [actions]
275
+ );
276
+
277
+ /**
278
+ * Update synced event in system calendar
279
+ */
280
+ const updateSyncedEvent = useCallback(async (event: CalendarEvent): Promise<boolean> => {
281
+ if (!event.systemCalendar) return false;
282
+
283
+ setIsLoading(true);
284
+ try {
285
+ const result = await CalendarService.updateSystemCalendarEvent(event);
286
+
287
+ if (result.success) {
288
+ // Update last synced timestamp
289
+ await actions.updateEvent({
290
+ id: event.id,
291
+ systemCalendar: {
292
+ ...event.systemCalendar,
293
+ lastSyncedAt: new Date(),
294
+ },
295
+ });
296
+ return true;
297
+ }
298
+
299
+ return false;
300
+ } catch {
301
+ return false;
302
+ } finally {
303
+ setIsLoading(false);
304
+ }
305
+ }, [actions]);
306
+
307
+ /**
308
+ * Delete synced event from system calendar
309
+ */
310
+ const deleteSyncedEvent = useCallback(
311
+ async (event: CalendarEvent): Promise<boolean> => {
312
+ if (!event.systemCalendar) return false;
313
+
314
+ setIsLoading(true);
315
+ try {
316
+ const result = await CalendarService.removeFromSystemCalendar(
317
+ event.systemCalendar.eventId
318
+ );
319
+
320
+ if (result.success) {
321
+ // Remove system calendar info from event
322
+ await actions.updateEvent({
323
+ id: event.id,
324
+ systemCalendar: undefined,
325
+ });
326
+ return true;
327
+ }
328
+
329
+ return false;
330
+ } catch {
331
+ return false;
332
+ } finally {
333
+ setIsLoading(false);
334
+ }
335
+ },
336
+ [actions]
337
+ );
338
+
339
+ // Load calendars when permission is granted
340
+ useEffect(() => {
341
+ if (permission?.granted) {
342
+ loadSystemCalendars();
343
+ }
344
+ }, [permission, loadSystemCalendars]);
345
+
346
+ return {
347
+ systemCalendars,
348
+ permission,
349
+ isLoading,
350
+ requestPermission,
351
+ loadSystemCalendars,
352
+ syncEventToCalendar,
353
+ updateSyncedEvent,
354
+ deleteSyncedEvent,
355
+ };
356
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Celebration Config Entity
3
+ * Single Responsibility: Define celebration configuration types
4
+ */
5
+
6
+ export interface CelebrationAction {
7
+ label: string;
8
+ onPress: () => void;
9
+ }
10
+
11
+ export interface CelebrationConfig {
12
+ title: string;
13
+ message: string;
14
+ primaryAction?: CelebrationAction;
15
+ secondaryAction?: CelebrationAction;
16
+ }
17
+
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Fireworks Config Entity
3
+ * Single Responsibility: Define fireworks configuration types and constants
4
+ */
5
+
6
+ import type { FireworksConfig as AnimationFireworksConfig } from "../../../animation";
7
+
8
+ export interface ThemeColors {
9
+ primary?: string;
10
+ success?: string;
11
+ warning?: string;
12
+ }
13
+
14
+ export interface CelebrationFireworksConfig extends Omit<AnimationFireworksConfig, 'colors'> {
15
+ colors: string[];
16
+ }
17
+
18
+ export const DEFAULT_FIREWORKS_COLORS = [
19
+ "#FF6B6B",
20
+ "#4ECDC4",
21
+ "#FFE66D",
22
+ "#A8E6CF",
23
+ "#95E1D3",
24
+ "#F38181",
25
+ "#AA96DA",
26
+ ] as const;
27
+
28
+ export const DEFAULT_FIREWORKS_CONFIG: Required<Pick<CelebrationFireworksConfig, "particleCount" | "duration">> = {
29
+ particleCount: 80,
30
+ duration: 2000,
31
+ } as const;
32
+
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @umituz/react-native-celebration - Public API
3
+ *
4
+ * Celebration animations and effects for React Native applications.
5
+ * Built on top of ../../../animation for consistent animations.
6
+ *
7
+ * Features:
8
+ * - Celebration modals with fireworks
9
+ * - Configurable animations
10
+ * - Theme integration
11
+ * - State management
12
+ *
13
+ * Usage:
14
+ * ```typescript
15
+ * import { useCelebrationState, CelebrationModal, Animated } from '@umituz/react-native-celebration';
16
+ *
17
+ * const MyCelebration = () => {
18
+ * const { visible, show, hide, config } = useCelebrationState();
19
+ *
20
+ * return (
21
+ * <CelebrationModal
22
+ * visible={visible}
23
+ * config={config!}
24
+ * onClose={hide}
25
+ * themeColors={{ primary: '#007AFF', success: '#34C759' }}
26
+ * />
27
+ * );
28
+ * };
29
+ * ```
30
+ */
31
+
32
+
33
+
34
+ // =============================================================================
35
+ // DOMAIN LAYER - Entities
36
+ // =============================================================================
37
+
38
+ export type {
39
+ CelebrationConfig,
40
+ CelebrationAction,
41
+ } from "./domain/entities/CelebrationConfig";
42
+
43
+ export type {
44
+ ThemeColors,
45
+ CelebrationFireworksConfig,
46
+ } from "./domain/entities/FireworksConfig";
47
+
48
+ export {
49
+ DEFAULT_FIREWORKS_COLORS,
50
+ DEFAULT_FIREWORKS_CONFIG,
51
+ } from "./domain/entities/FireworksConfig";
52
+
53
+ // =============================================================================
54
+ // INFRASTRUCTURE LAYER - Services
55
+ // =============================================================================
56
+
57
+ export { FireworksConfigService } from "./infrastructure/services/FireworksConfigService";
58
+
59
+
60
+
61
+ // =============================================================================
62
+ // PRESENTATION LAYER - Hooks
63
+ // =============================================================================
64
+
65
+ export { useCelebrationState } from "./presentation/hooks/useCelebrationState";
66
+ export type { UseCelebrationStateReturn } from "./presentation/hooks/useCelebrationState";
67
+
68
+ export { useCelebrationModalAnimation } from "./presentation/hooks/useCelebrationModalAnimation";
69
+ export type { UseCelebrationModalAnimationReturn } from "./presentation/hooks/useCelebrationModalAnimation";
70
+
71
+
72
+
73
+ // =============================================================================
74
+ // PRESENTATION LAYER - Components
75
+ // =============================================================================
76
+
77
+ export { CelebrationModal } from "./presentation/components/CelebrationModal";
78
+ export type { CelebrationModalProps } from "./presentation/components/CelebrationModal";
79
+
80
+ export { CelebrationModalContent } from "./presentation/components/CelebrationModalContent";
81
+ export type { CelebrationModalContentProps } from "./presentation/components/CelebrationModalContent";
82
+
83
+ export { CelebrationFireworksOverlay } from "./presentation/components/CelebrationFireworksOverlay";
84
+ export type { CelebrationFireworksOverlayProps } from "./presentation/components/CelebrationFireworksOverlay";
85
+
86
+ // =============================================================================
87
+ // PRESENTATION LAYER - Styles
88
+ // =============================================================================
89
+
90
+ export { createCelebrationModalStyles } from "./presentation/styles/CelebrationModalStyles";
91
+
92
+
93
+
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Fireworks Config Service
3
+ * Single Responsibility: Build fireworks configuration from theme colors
4
+ */
5
+
6
+ import type {
7
+ ThemeColors,
8
+ CelebrationFireworksConfig,
9
+ } from "../../domain/entities/FireworksConfig";
10
+ import {
11
+ DEFAULT_FIREWORKS_COLORS,
12
+ DEFAULT_FIREWORKS_CONFIG,
13
+ } from "../../domain/entities/FireworksConfig";
14
+
15
+ export class FireworksConfigService {
16
+ /**
17
+ * Build fireworks configuration with theme colors
18
+ * Gracefully handles missing theme colors
19
+ */
20
+ static build(
21
+ themeColors?: ThemeColors,
22
+ customConfig?: Partial<CelebrationFireworksConfig>,
23
+ ): CelebrationFireworksConfig {
24
+ const colors: string[] = [];
25
+
26
+ // Add theme colors if available
27
+ if (themeColors?.primary) {
28
+ colors.push(themeColors.primary);
29
+ }
30
+ if (themeColors?.success) {
31
+ colors.push(themeColors.success);
32
+ }
33
+ if (themeColors?.warning) {
34
+ colors.push(themeColors.warning);
35
+ }
36
+
37
+ // Add default colors
38
+ colors.push(...DEFAULT_FIREWORKS_COLORS);
39
+
40
+ return {
41
+ particleCount: customConfig?.particleCount ?? DEFAULT_FIREWORKS_CONFIG.particleCount,
42
+ duration: customConfig?.duration ?? DEFAULT_FIREWORKS_CONFIG.duration,
43
+ colors: customConfig?.colors ?? colors,
44
+ particleSize: customConfig?.particleSize,
45
+ spread: customConfig?.spread,
46
+ };
47
+ }
48
+ }
49
+
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Celebration Fireworks Overlay
3
+ * Renders fireworks effect as an overlay
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, StyleSheet } from "react-native";
8
+ import { Fireworks } from "../../../animation";
9
+ import type { FireworksConfig } from "../../../animation";
10
+
11
+ export interface CelebrationFireworksOverlayProps {
12
+ visible: boolean;
13
+ config: FireworksConfig;
14
+ }
15
+
16
+ export const CelebrationFireworksOverlay: React.FC<CelebrationFireworksOverlayProps> = ({
17
+ visible,
18
+ config,
19
+ }) => {
20
+ if (!visible) return null;
21
+
22
+ return (
23
+ <View style={StyleSheet.absoluteFill} pointerEvents="none">
24
+ <Fireworks
25
+ autoTrigger
26
+ triggerX={0.5}
27
+ triggerY={0.5}
28
+ {...config}
29
+ style={StyleSheet.absoluteFill}
30
+ />
31
+ </View>
32
+ );
33
+ };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Celebration Modal Component
3
+ * Displays celebration modal with animations using BaseModal
4
+ */
5
+
6
+ import React from "react";
7
+ import { Animated } from "../../../animation";
8
+ import { BaseModal } from "../../../BaseModal";
9
+ import { useCelebrationModalAnimation } from "../hooks/useCelebrationModalAnimation";
10
+ import { FireworksConfigService } from "../../infrastructure/services/FireworksConfigService";
11
+ import { CelebrationModalContent } from "./CelebrationModalContent";
12
+ import { CelebrationFireworksOverlay } from "./CelebrationFireworksOverlay";
13
+ import type { CelebrationConfig } from "../../domain/entities/CelebrationConfig";
14
+ import type { ThemeColors } from "../../domain/entities/FireworksConfig";
15
+ import type {
16
+ ModalAnimationConfig,
17
+ IconAnimationConfig,
18
+ } from "../../../animation";
19
+
20
+ export interface CelebrationModalProps {
21
+ visible: boolean;
22
+ config: CelebrationConfig;
23
+ onClose: () => void;
24
+ themeColors?: ThemeColors;
25
+ fireworksConfig?: Partial<import("../../../animation").FireworksConfig>;
26
+ animationConfig?: {
27
+ modal?: ModalAnimationConfig;
28
+ icon?: IconAnimationConfig;
29
+ };
30
+ renderContent?: (props: {
31
+ config: CelebrationConfig;
32
+ onClose: () => void;
33
+ iconStyle: ReturnType<typeof useCelebrationModalAnimation>["iconStyle"];
34
+ modalStyle: ReturnType<typeof useCelebrationModalAnimation>["modalStyle"];
35
+ }) => React.ReactNode;
36
+ }
37
+
38
+ export const CelebrationModal: React.FC<CelebrationModalProps> = ({
39
+ visible,
40
+ config,
41
+ onClose,
42
+ themeColors,
43
+ fireworksConfig,
44
+ animationConfig,
45
+ renderContent,
46
+ }) => {
47
+ const { isReady, iconStyle, modalStyle } =
48
+ useCelebrationModalAnimation(visible, animationConfig);
49
+
50
+ const fireworks = FireworksConfigService.build(themeColors, fireworksConfig);
51
+
52
+ return (
53
+ <>
54
+ <CelebrationFireworksOverlay visible={visible} config={fireworks} />
55
+
56
+ <BaseModal
57
+ visible={visible && isReady}
58
+ onClose={onClose}
59
+ dismissOnBackdrop={true}
60
+ testID="celebration-modal"
61
+ >
62
+ <Animated.View style={modalStyle}>
63
+ {renderContent ? (
64
+ renderContent({ config, onClose, iconStyle, modalStyle })
65
+ ) : themeColors ? (
66
+ <CelebrationModalContent
67
+ config={config}
68
+ onClose={onClose}
69
+ themeColors={themeColors}
70
+ iconStyle={iconStyle}
71
+ modalStyle={modalStyle}
72
+ />
73
+ ) : null}
74
+ </Animated.View>
75
+ </BaseModal>
76
+ </>
77
+ );
78
+ };