@umituz/react-native-design-system 2.3.14 → 2.3.16
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 +19 -2
- package/src/index.ts +105 -0
- package/src/layouts/ScreenLayout/ScreenLayout.example.tsx +2 -2
- package/src/layouts/ScreenLayout/ScreenLayout.tsx +1 -1
- package/src/molecules/animation/core/AnimationCore.ts +29 -0
- package/src/molecules/animation/domain/entities/Animation.ts +81 -0
- package/src/molecules/animation/domain/entities/Fireworks.ts +44 -0
- package/src/molecules/animation/domain/entities/Theme.ts +76 -0
- package/src/molecules/animation/index.ts +146 -0
- package/src/molecules/animation/infrastructure/services/AnimationConfigService.ts +35 -0
- package/src/molecules/animation/infrastructure/services/SpringAnimationConfigService.ts +67 -0
- package/src/molecules/animation/infrastructure/services/TimingAnimationConfigService.ts +57 -0
- package/src/molecules/animation/infrastructure/services/__tests__/SpringAnimationConfigService.test.ts +114 -0
- package/src/molecules/animation/infrastructure/services/__tests__/TimingAnimationConfigService.test.ts +105 -0
- package/src/molecules/animation/presentation/components/Fireworks.tsx +126 -0
- package/src/molecules/animation/presentation/components/__tests__/Fireworks.test.tsx +189 -0
- package/src/molecules/animation/presentation/hooks/__tests__/useAnimation.integration.test.ts +216 -0
- package/src/molecules/animation/presentation/hooks/__tests__/useFireworks.test.ts +242 -0
- package/src/molecules/animation/presentation/hooks/__tests__/useGesture.test.ts +111 -0
- package/src/molecules/animation/presentation/hooks/__tests__/useSpringAnimation.test.ts +131 -0
- package/src/molecules/animation/presentation/hooks/__tests__/useTimingAnimation.test.ts +175 -0
- package/src/molecules/animation/presentation/hooks/__tests__/useTransformAnimation.test.ts +137 -0
- package/src/molecules/animation/presentation/hooks/useAnimation.ts +77 -0
- package/src/molecules/animation/presentation/hooks/useFireworks.ts +141 -0
- package/src/molecules/animation/presentation/hooks/useGesture.ts +61 -0
- package/src/molecules/animation/presentation/hooks/useGestureCreators.ts +163 -0
- package/src/molecules/animation/presentation/hooks/useGestureState.ts +53 -0
- package/src/molecules/animation/presentation/hooks/useIconAnimations.ts +119 -0
- package/src/molecules/animation/presentation/hooks/useModalAnimations.ts +124 -0
- package/src/molecules/animation/presentation/hooks/useReanimatedReady.ts +60 -0
- package/src/molecules/animation/presentation/hooks/useSpringAnimation.ts +69 -0
- package/src/molecules/animation/presentation/hooks/useTimingAnimation.ts +111 -0
- package/src/molecules/animation/presentation/hooks/useTransformAnimation.ts +57 -0
- package/src/molecules/animation/presentation/providers/AnimationThemeProvider.tsx +62 -0
- package/src/molecules/animation/presentation/providers/__tests__/AnimationThemeProvider.test.tsx +165 -0
- package/src/molecules/animation/types/global.d.ts +97 -0
- package/src/molecules/celebration/domain/entities/CelebrationConfig.ts +17 -0
- package/src/molecules/celebration/domain/entities/FireworksConfig.ts +32 -0
- package/src/molecules/celebration/index.ts +93 -0
- package/src/molecules/celebration/infrastructure/services/FireworksConfigService.ts +49 -0
- package/src/molecules/celebration/presentation/components/CelebrationFireworksOverlay.tsx +33 -0
- package/src/molecules/celebration/presentation/components/CelebrationModal.tsx +78 -0
- package/src/molecules/celebration/presentation/components/CelebrationModalContent.tsx +90 -0
- package/src/molecules/celebration/presentation/hooks/useCelebrationModalAnimation.ts +49 -0
- package/src/molecules/celebration/presentation/hooks/useCelebrationState.ts +45 -0
- package/src/molecules/celebration/presentation/styles/CelebrationModalStyles.ts +65 -0
- package/src/molecules/countdown/components/Countdown.tsx +128 -0
- package/src/molecules/countdown/components/CountdownHeader.tsx +84 -0
- package/src/molecules/countdown/components/TimeUnit.tsx +73 -0
- package/src/molecules/countdown/hooks/useCountdown.ts +107 -0
- package/src/molecules/countdown/index.ts +25 -0
- package/src/molecules/countdown/types/CountdownTypes.ts +31 -0
- package/src/molecules/countdown/utils/TimeCalculator.ts +46 -0
- package/src/molecules/emoji/domain/entities/Emoji.ts +129 -0
- package/src/molecules/emoji/index.ts +177 -0
- package/src/molecules/emoji/presentation/components/EmojiPicker.tsx +102 -0
- package/src/molecules/emoji/presentation/hooks/useEmojiPicker.ts +171 -0
- package/src/molecules/index.ts +21 -0
- package/src/molecules/long-press-menu/domain/entities/MenuAction.ts +37 -0
- package/src/molecules/long-press-menu/index.ts +16 -0
- package/src/molecules/navigation/StackNavigator.tsx +75 -0
- package/src/molecules/navigation/TabsNavigator.tsx +94 -0
- package/src/molecules/navigation/components/FabButton.tsx +45 -0
- package/src/molecules/navigation/components/TabLabel.tsx +47 -0
- package/src/molecules/navigation/createStackNavigator.ts +20 -0
- package/src/molecules/navigation/createTabNavigator.ts +20 -0
- package/src/molecules/navigation/hooks/useTabBarStyles.ts +54 -0
- package/src/molecules/navigation/index.ts +37 -0
- package/src/molecules/navigation/types.ts +118 -0
- package/src/molecules/navigation/utils/AppNavigation.ts +101 -0
- package/src/molecules/navigation/utils/IconRenderer.ts +50 -0
- package/src/molecules/navigation/utils/LabelProcessor.ts +70 -0
- package/src/molecules/navigation/utils/NavigationCleanup.ts +62 -0
- package/src/molecules/navigation/utils/NavigationTheme.ts +21 -0
- package/src/molecules/navigation/utils/NavigationValidator.ts +61 -0
- package/src/molecules/navigation/utils/ScreenFactory.ts +115 -0
- package/src/molecules/navigation/utils/__tests__/IconRenderer.getIconName.test.ts +109 -0
- package/src/molecules/navigation/utils/__tests__/IconRenderer.renderIcon.test.ts +116 -0
- package/src/molecules/navigation/utils/__tests__/LabelProcessor.processLabel.test.ts +116 -0
- package/src/molecules/navigation/utils/__tests__/LabelProcessor.processTitle.test.ts +59 -0
- package/src/molecules/navigation/utils/__tests__/NavigationCleanup.test.ts +271 -0
- package/src/molecules/navigation/utils/__tests__/NavigationValidator.test.ts +252 -0
- package/src/molecules/swipe-actions/domain/entities/SwipeAction.ts +194 -0
- package/src/molecules/swipe-actions/index.ts +6 -0
- package/src/molecules/swipe-actions/presentation/components/SwipeActionButton.tsx +131 -0
- package/src/theme/hooks/useResponsiveDesignTokens.ts +1 -1
- package/src/utilities/clipboard/ClipboardUtils.ts +71 -0
- package/src/utilities/clipboard/index.ts +5 -0
- package/src/utilities/index.ts +6 -0
- package/src/utilities/sharing/domain/entities/Share.ts +210 -0
- package/src/utilities/sharing/index.ts +205 -0
- package/src/utilities/sharing/infrastructure/services/SharingService.ts +165 -0
- package/src/utilities/sharing/presentation/hooks/useSharing.ts +154 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTransformAnimation Hook
|
|
3
|
+
*
|
|
4
|
+
* Hook for transform-based animations (spin, pulse, shake).
|
|
5
|
+
* Single Responsibility: Handle transform animations only.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useCallback } from 'react';
|
|
9
|
+
import {
|
|
10
|
+
useSharedValue,
|
|
11
|
+
withTiming,
|
|
12
|
+
withSequence,
|
|
13
|
+
withRepeat,
|
|
14
|
+
Easing,
|
|
15
|
+
} from 'react-native-reanimated';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hook for transform-based animations
|
|
19
|
+
*/
|
|
20
|
+
export const useTransformAnimation = () => {
|
|
21
|
+
const translateX = useSharedValue(0);
|
|
22
|
+
const scale = useSharedValue(1);
|
|
23
|
+
const rotate = useSharedValue(0);
|
|
24
|
+
|
|
25
|
+
const shake = useCallback(() => {
|
|
26
|
+
translateX.value = withSequence(
|
|
27
|
+
withTiming(-10, { duration: 50 }),
|
|
28
|
+
withRepeat(withTiming(10, { duration: 50 }), 4, true),
|
|
29
|
+
withTiming(0, { duration: 50 })
|
|
30
|
+
);
|
|
31
|
+
}, [translateX]);
|
|
32
|
+
|
|
33
|
+
const pulse = useCallback((repeatCount = -1) => {
|
|
34
|
+
scale.value = withRepeat(
|
|
35
|
+
withSequence(withTiming(1.1, { duration: 500 }), withTiming(1, { duration: 500 })),
|
|
36
|
+
repeatCount,
|
|
37
|
+
false
|
|
38
|
+
);
|
|
39
|
+
}, [scale]);
|
|
40
|
+
|
|
41
|
+
const spin = useCallback((repeatCount = -1) => {
|
|
42
|
+
rotate.value = withRepeat(
|
|
43
|
+
withTiming(360, { duration: 1000, easing: Easing.linear }),
|
|
44
|
+
repeatCount,
|
|
45
|
+
false
|
|
46
|
+
);
|
|
47
|
+
}, [rotate]);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
shake,
|
|
51
|
+
pulse,
|
|
52
|
+
spin,
|
|
53
|
+
translateX,
|
|
54
|
+
scale,
|
|
55
|
+
rotate,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Provider for Animation Package
|
|
3
|
+
*
|
|
4
|
+
* React context provider for theme management.
|
|
5
|
+
* Allows consumers to customize animation appearance.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
|
9
|
+
import type { AnimationTheme, ThemeContext } from '../../domain/entities/Theme';
|
|
10
|
+
import { DEFAULT_ANIMATION_THEME } from '../../domain/entities/Theme';
|
|
11
|
+
|
|
12
|
+
const ThemeContext = createContext<ThemeContext | undefined>(undefined);
|
|
13
|
+
|
|
14
|
+
export interface AnimationThemeProviderProps {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
theme?: Partial<AnimationTheme>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Theme provider component
|
|
21
|
+
*/
|
|
22
|
+
export const AnimationThemeProvider: React.FC<AnimationThemeProviderProps> = ({
|
|
23
|
+
children,
|
|
24
|
+
theme: initialTheme,
|
|
25
|
+
}) => {
|
|
26
|
+
const [theme, setTheme] = useState<AnimationTheme>(() => ({
|
|
27
|
+
...DEFAULT_ANIMATION_THEME,
|
|
28
|
+
...initialTheme,
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const updateTheme = (newTheme: Partial<AnimationTheme>) => {
|
|
32
|
+
setTheme(prev => ({ ...prev, ...newTheme }));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const contextValue: ThemeContext = {
|
|
36
|
+
theme,
|
|
37
|
+
setTheme: updateTheme,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<ThemeContext.Provider value={contextValue}>
|
|
42
|
+
{children}
|
|
43
|
+
</ThemeContext.Provider>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Hook to use theme
|
|
49
|
+
*/
|
|
50
|
+
export const useAnimationTheme = (): ThemeContext => {
|
|
51
|
+
const context = useContext(ThemeContext);
|
|
52
|
+
if (!context) {
|
|
53
|
+
if (__DEV__) {
|
|
54
|
+
console.warn('useAnimationTheme must be used within AnimationThemeProvider');
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
theme: DEFAULT_ANIMATION_THEME,
|
|
58
|
+
setTheme: () => {},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return context;
|
|
62
|
+
};
|
package/src/molecules/animation/presentation/providers/__tests__/AnimationThemeProvider.test.tsx
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnimationThemeProvider Tests
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for theme system functionality.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { render, screen } from '@testing-library/react-native';
|
|
9
|
+
import { AnimationThemeProvider, useAnimationTheme } from '../AnimationThemeProvider';
|
|
10
|
+
import { DEFAULT_ANIMATION_THEME } from '../../../domain/entities/AnimationTheme';
|
|
11
|
+
|
|
12
|
+
// Mock console.warn
|
|
13
|
+
const originalWarn = console.warn;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
console.warn = jest.fn();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
console.warn = originalWarn;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('AnimationThemeProvider', () => {
|
|
23
|
+
it('should render children', () => {
|
|
24
|
+
const TestComponent = () => <div>Test Child</div>;
|
|
25
|
+
|
|
26
|
+
render(
|
|
27
|
+
<AnimationThemeProvider>
|
|
28
|
+
<TestComponent />
|
|
29
|
+
</AnimationThemeProvider>
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
expect(screen.getByText('Test Child')).toBeTruthy();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should provide default theme when no custom theme provided', () => {
|
|
36
|
+
const TestComponent = () => {
|
|
37
|
+
const { theme } = useAnimationTheme();
|
|
38
|
+
return <div>{theme.colors.primary}</div>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
render(
|
|
42
|
+
<AnimationThemeProvider>
|
|
43
|
+
<TestComponent />
|
|
44
|
+
</AnimationThemeProvider>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
expect(screen.getByText(DEFAULT_ANIMATION_THEME.colors.primary)).toBeTruthy();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should merge custom theme with default theme', () => {
|
|
51
|
+
const customTheme = {
|
|
52
|
+
colors: {
|
|
53
|
+
primary: '#custom-color',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const TestComponent = () => {
|
|
58
|
+
const { theme } = useAnimationTheme();
|
|
59
|
+
return <div>{theme.colors.primary}</div>;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
render(
|
|
63
|
+
<AnimationThemeProvider theme={customTheme}>
|
|
64
|
+
<TestComponent />
|
|
65
|
+
</AnimationThemeProvider>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(screen.getByText('#custom-color')).toBeTruthy();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should preserve default values for non-overridden properties', () => {
|
|
72
|
+
const customTheme = {
|
|
73
|
+
colors: {
|
|
74
|
+
primary: '#custom-color',
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const TestComponent = () => {
|
|
79
|
+
const { theme } = useAnimationTheme();
|
|
80
|
+
return <div>{theme.colors.secondary}</div>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
render(
|
|
84
|
+
<AnimationThemeProvider theme={customTheme}>
|
|
85
|
+
<TestComponent />
|
|
86
|
+
</AnimationThemeProvider>
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
expect(screen.getByText(DEFAULT_ANIMATION_THEME.colors.secondary)).toBeTruthy();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should allow theme updates', () => {
|
|
93
|
+
const TestComponent = () => {
|
|
94
|
+
const { theme, setTheme } = useAnimationTheme();
|
|
95
|
+
|
|
96
|
+
React.useEffect(() => {
|
|
97
|
+
setTheme({ colors: { primary: '#updated-color' } });
|
|
98
|
+
}, [setTheme]);
|
|
99
|
+
|
|
100
|
+
return <div>{theme.colors.primary}</div>;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
render(
|
|
104
|
+
<AnimationThemeProvider>
|
|
105
|
+
<TestComponent />
|
|
106
|
+
</AnimationThemeProvider>
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
expect(screen.getByText('#updated-color')).toBeTruthy();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('useAnimationTheme', () => {
|
|
114
|
+
it('should return theme and setTheme', () => {
|
|
115
|
+
const TestComponent = () => {
|
|
116
|
+
const { theme, setTheme } = useAnimationTheme();
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<div>
|
|
120
|
+
<div testID="theme">{JSON.stringify(theme)}</div>
|
|
121
|
+
<div testID="set-theme">{typeof setTheme}</div>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
render(
|
|
127
|
+
<AnimationThemeProvider>
|
|
128
|
+
<TestComponent />
|
|
129
|
+
</AnimationThemeProvider>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(screen.getByTestId('set-theme')).toHaveTextContent('function');
|
|
133
|
+
|
|
134
|
+
const themeElement = screen.getByTestId('theme');
|
|
135
|
+
const theme = JSON.parse(themeElement.props.children);
|
|
136
|
+
expect(theme).toHaveProperty('colors');
|
|
137
|
+
expect(theme).toHaveProperty('spacing');
|
|
138
|
+
expect(theme).toHaveProperty('borderRadius');
|
|
139
|
+
expect(theme).toHaveProperty('opacity');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should warn when used outside provider', () => {
|
|
143
|
+
const TestComponent = () => {
|
|
144
|
+
const { theme } = useAnimationTheme();
|
|
145
|
+
return <div>{theme.colors.primary}</div>;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
render(<TestComponent />);
|
|
149
|
+
|
|
150
|
+
expect(console.warn).toHaveBeenCalledWith(
|
|
151
|
+
'useAnimationTheme must be used within AnimationThemeProvider'
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should return default theme when used outside provider', () => {
|
|
156
|
+
const TestComponent = () => {
|
|
157
|
+
const { theme } = useAnimationTheme();
|
|
158
|
+
return <div>{theme.colors.primary}</div>;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
render(<TestComponent />);
|
|
162
|
+
|
|
163
|
+
expect(screen.getByText(DEFAULT_ANIMATION_THEME.colors.primary)).toBeTruthy();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
/// <reference types="react-native" />
|
|
3
|
+
|
|
4
|
+
declare module 'react-native-reanimated' {
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { ViewProps, ViewStyle } from 'react-native';
|
|
7
|
+
|
|
8
|
+
export interface WithTimingConfig {
|
|
9
|
+
duration?: number;
|
|
10
|
+
easing?: (value: number) => number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface WithSpringConfig {
|
|
14
|
+
damping?: number;
|
|
15
|
+
stiffness?: number;
|
|
16
|
+
mass?: number;
|
|
17
|
+
overshootClamping?: boolean;
|
|
18
|
+
restDisplacementThreshold?: number;
|
|
19
|
+
restSpeedThreshold?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SharedValue<T> {
|
|
23
|
+
value: T;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Animated: {
|
|
27
|
+
View: React.ComponentType<any>;
|
|
28
|
+
Text: React.ComponentType<any>;
|
|
29
|
+
Image: React.ComponentType<any>;
|
|
30
|
+
ScrollView: React.ComponentType<any>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export function useSharedValue<T>(initialValue: T): SharedValue<T>;
|
|
34
|
+
export function useAnimatedStyle<T>(styleFactory: () => T): T;
|
|
35
|
+
export function withTiming(toValue: any, config?: WithTimingConfig): any;
|
|
36
|
+
export function withSpring(toValue: any, config?: WithSpringConfig): any;
|
|
37
|
+
export function withSequence(...animations: any[]): any;
|
|
38
|
+
export function withRepeat(animation: any, count?: number, reverse?: boolean): any;
|
|
39
|
+
export function runOnUI<T>(fn: () => T): () => T;
|
|
40
|
+
export function runOnJS<T extends (...args: any[]) => any>(fn: T): T;
|
|
41
|
+
export function cancelAnimation(sharedValue: SharedValue<any>): void;
|
|
42
|
+
|
|
43
|
+
export const Easing: {
|
|
44
|
+
linear: (t: number) => number;
|
|
45
|
+
ease: (t: number) => number;
|
|
46
|
+
easeIn: (t: number) => number;
|
|
47
|
+
easeOut: (t: number) => number;
|
|
48
|
+
easeInOut: (t: number) => number;
|
|
49
|
+
step0: (t: number) => number;
|
|
50
|
+
step1: (t: number) => number;
|
|
51
|
+
bezier: (x1: number, y1: number, x2: number, y2: number) => (t: number) => number;
|
|
52
|
+
cubic: (x1: number, y1: number, x2: number, y2: number) => (t: number) => number;
|
|
53
|
+
in: (easing: (t: number) => number) => (t: number) => number;
|
|
54
|
+
out: (easing: (t: number) => number) => (t: number) => number;
|
|
55
|
+
inOut: (easing: (t: number) => number) => (t: number) => number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
declare module 'react-native-gesture-handler' {
|
|
60
|
+
import React from 'react';
|
|
61
|
+
import { ViewStyle } from 'react-native';
|
|
62
|
+
|
|
63
|
+
export interface PanGestureHandlerProps {
|
|
64
|
+
onGestureEvent?: (event: any) => void;
|
|
65
|
+
onHandlerStateChange?: (event: any) => void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface TapGestureHandlerProps {
|
|
69
|
+
onHandlerStateChange?: (event: any) => void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface PinchGestureHandlerProps {
|
|
73
|
+
onGestureEvent?: (event: any) => void;
|
|
74
|
+
onHandlerStateChange?: (event: any) => void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface LongPressGestureHandlerProps {
|
|
78
|
+
onHandlerStateChange?: (event: any) => void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const GestureDetector: React.FC<{
|
|
82
|
+
gesture: any;
|
|
83
|
+
children: React.ReactNode;
|
|
84
|
+
}>;
|
|
85
|
+
|
|
86
|
+
export const Gesture: {
|
|
87
|
+
Tap: () => any;
|
|
88
|
+
Pan: () => any;
|
|
89
|
+
Pinch: () => any;
|
|
90
|
+
LongPress: () => any;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const PanGestureHandler: React.FC<PanGestureHandlerProps>;
|
|
94
|
+
export const TapGestureHandler: React.FC<TapGestureHandlerProps>;
|
|
95
|
+
export const PinchGestureHandler: React.FC<PinchGestureHandlerProps>;
|
|
96
|
+
export const LongPressGestureHandler: React.FC<LongPressGestureHandlerProps>;
|
|
97
|
+
}
|
|
@@ -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
|
+
};
|