@umituz/react-native-loading 1.0.0
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/LICENSE +22 -0
- package/README.md +111 -0
- package/lib/domain/entities/Loading.d.ts +161 -0
- package/lib/domain/entities/Loading.d.ts.map +1 -0
- package/lib/domain/entities/Loading.js +224 -0
- package/lib/domain/entities/Loading.js.map +1 -0
- package/lib/index.d.ts +85 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +86 -0
- package/lib/index.js.map +1 -0
- package/lib/presentation/components/LoadingState.d.ts +57 -0
- package/lib/presentation/components/LoadingState.d.ts.map +1 -0
- package/lib/presentation/components/LoadingState.js +110 -0
- package/lib/presentation/components/LoadingState.js.map +1 -0
- package/lib/presentation/components/SkeletonLoader.d.ts +59 -0
- package/lib/presentation/components/SkeletonLoader.d.ts.map +1 -0
- package/lib/presentation/components/SkeletonLoader.js +112 -0
- package/lib/presentation/components/SkeletonLoader.js.map +1 -0
- package/lib/presentation/hooks/useLoading.d.ts +67 -0
- package/lib/presentation/hooks/useLoading.d.ts.map +1 -0
- package/lib/presentation/hooks/useLoading.js +124 -0
- package/lib/presentation/hooks/useLoading.js.map +1 -0
- package/package.json +55 -0
- package/src/USAGE_EXAMPLES.md +429 -0
- package/src/domain/entities/Loading.ts +295 -0
- package/src/index.ts +117 -0
- package/src/presentation/components/LoadingState.tsx +161 -0
- package/src/presentation/components/SkeletonLoader.tsx +159 -0
- package/src/presentation/hooks/useLoading.ts +170 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loading Domain - Barrel Export
|
|
3
|
+
*
|
|
4
|
+
* Public API for the loading domain.
|
|
5
|
+
* Provides consistent loading states and animations across all apps.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Breathing animation loading state (meditation-inspired)
|
|
9
|
+
* - Skeleton loaders with shimmer effect
|
|
10
|
+
* - Loading state management hooks
|
|
11
|
+
* - App-specific emoji presets
|
|
12
|
+
* - Configurable sizes and patterns
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* ```tsx
|
|
16
|
+
* import {
|
|
17
|
+
* LoadingState,
|
|
18
|
+
* SkeletonLoader,
|
|
19
|
+
* useLoading,
|
|
20
|
+
* LOADING_EMOJIS,
|
|
21
|
+
* } from '@umituz/react-native-loading';
|
|
22
|
+
*
|
|
23
|
+
* // Basic loading state
|
|
24
|
+
* const MyScreen = () => {
|
|
25
|
+
* const { isLoading, startLoading, stopLoading } = useLoading();
|
|
26
|
+
*
|
|
27
|
+
* return (
|
|
28
|
+
* <View>
|
|
29
|
+
* {isLoading ? (
|
|
30
|
+
* <LoadingState message="Loading..." />
|
|
31
|
+
* ) : (
|
|
32
|
+
* <Content />
|
|
33
|
+
* )}
|
|
34
|
+
* </View>
|
|
35
|
+
* );
|
|
36
|
+
* };
|
|
37
|
+
*
|
|
38
|
+
* // Skeleton loader for lists
|
|
39
|
+
* const ListScreen = () => {
|
|
40
|
+
* const [data, setData] = useState([]);
|
|
41
|
+
* const { isLoading } = useLoading();
|
|
42
|
+
*
|
|
43
|
+
* return (
|
|
44
|
+
* <View>
|
|
45
|
+
* {isLoading ? (
|
|
46
|
+
* <SkeletonLoader pattern="list" count={5} />
|
|
47
|
+
* ) : (
|
|
48
|
+
* <FlatList data={data} ... />
|
|
49
|
+
* )}
|
|
50
|
+
* </View>
|
|
51
|
+
* );
|
|
52
|
+
* };
|
|
53
|
+
*
|
|
54
|
+
* // With async wrapper
|
|
55
|
+
* const DataScreen = () => {
|
|
56
|
+
* const { isLoading, loadingMessage, withLoading } = useLoading();
|
|
57
|
+
*
|
|
58
|
+
* const loadData = () => withLoading(
|
|
59
|
+
* fetchData(),
|
|
60
|
+
* 'Loading data...'
|
|
61
|
+
* );
|
|
62
|
+
*
|
|
63
|
+
* return (
|
|
64
|
+
* <View>
|
|
65
|
+
* {isLoading && <LoadingState message={loadingMessage} />}
|
|
66
|
+
* <Button onPress={loadData}>Load</Button>
|
|
67
|
+
* </View>
|
|
68
|
+
* );
|
|
69
|
+
* };
|
|
70
|
+
*
|
|
71
|
+
* // Custom emoji per app
|
|
72
|
+
* const FitnessLoadingScreen = () => (
|
|
73
|
+
* <LoadingState
|
|
74
|
+
* emoji={LOADING_EMOJIS.fitness}
|
|
75
|
+
* message="Loading workouts..."
|
|
76
|
+
* />
|
|
77
|
+
* );
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export { SIZE_CONFIGS, LOADING_EMOJIS, ANIMATION_CONFIGS, SKELETON_PATTERNS, LoadingUtils, LOADING_CONSTANTS, } from './domain/entities/Loading';
|
|
81
|
+
// Presentation Components
|
|
82
|
+
export { LoadingState, } from './presentation/components/LoadingState';
|
|
83
|
+
export { SkeletonLoader, } from './presentation/components/SkeletonLoader';
|
|
84
|
+
// Presentation Hooks
|
|
85
|
+
export { useLoading, useSimpleLoading, } from './presentation/hooks/useLoading';
|
|
86
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AAaH,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AAEnC,0BAA0B;AAC1B,OAAO,EACL,YAAY,GAEb,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EACL,cAAc,GAEf,MAAM,0CAA0C,CAAC;AAElD,qBAAqB;AACrB,OAAO,EACL,UAAU,EACV,gBAAgB,GAEjB,MAAM,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loading Domain - LoadingState Component
|
|
3
|
+
*
|
|
4
|
+
* Universal loading component with breathing animation.
|
|
5
|
+
* Provides consistent, calm loading UX across all apps.
|
|
6
|
+
*
|
|
7
|
+
* Adapted from meditation_timer app's LoadingState component.
|
|
8
|
+
*
|
|
9
|
+
* @domain loading
|
|
10
|
+
* @layer presentation/components
|
|
11
|
+
*/
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { type StyleProp, type ViewStyle, type TextStyle } from 'react-native';
|
|
14
|
+
import type { LoadingSize } from '../../domain/entities/Loading';
|
|
15
|
+
/**
|
|
16
|
+
* LoadingState component props
|
|
17
|
+
*/
|
|
18
|
+
export interface LoadingStateProps {
|
|
19
|
+
/** Loading emoji - default: ⌛ (customizable per app) */
|
|
20
|
+
emoji?: string;
|
|
21
|
+
/** Loading message (optional) */
|
|
22
|
+
message?: string;
|
|
23
|
+
/** Size: small (inline), medium (section), large (full screen) */
|
|
24
|
+
size?: LoadingSize;
|
|
25
|
+
/** Full screen layout vs inline */
|
|
26
|
+
fullScreen?: boolean;
|
|
27
|
+
/** Custom container style */
|
|
28
|
+
style?: StyleProp<ViewStyle>;
|
|
29
|
+
/** Custom message style */
|
|
30
|
+
messageStyle?: StyleProp<TextStyle>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* LoadingState Component
|
|
34
|
+
*
|
|
35
|
+
* Universal loading indicator with breathing animation.
|
|
36
|
+
* Creates a calm, mindful loading experience.
|
|
37
|
+
*
|
|
38
|
+
* USAGE:
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // Basic usage
|
|
41
|
+
* <LoadingState />
|
|
42
|
+
*
|
|
43
|
+
* // With message
|
|
44
|
+
* <LoadingState message="Loading data..." size="medium" />
|
|
45
|
+
*
|
|
46
|
+
* // Full screen
|
|
47
|
+
* <LoadingState fullScreen message="Please wait..." />
|
|
48
|
+
*
|
|
49
|
+
* // Custom emoji (per app theme)
|
|
50
|
+
* <LoadingState emoji="🧘" message="Loading meditations..." />
|
|
51
|
+
*
|
|
52
|
+
* // Inline loading
|
|
53
|
+
* <LoadingState size="small" />
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare const LoadingState: React.FC<LoadingStateProps>;
|
|
57
|
+
//# sourceMappingURL=LoadingState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoadingState.d.ts","sourceRoot":"","sources":["../../../src/presentation/components/LoadingState.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAAsC,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAElH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAOjE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,mCAAmC;IACnC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,2BAA2B;IAC3B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA4EpD,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loading Domain - LoadingState Component
|
|
3
|
+
*
|
|
4
|
+
* Universal loading component with breathing animation.
|
|
5
|
+
* Provides consistent, calm loading UX across all apps.
|
|
6
|
+
*
|
|
7
|
+
* Adapted from meditation_timer app's LoadingState component.
|
|
8
|
+
*
|
|
9
|
+
* @domain loading
|
|
10
|
+
* @layer presentation/components
|
|
11
|
+
*/
|
|
12
|
+
import React, { useEffect, useRef } from 'react';
|
|
13
|
+
import { View, StyleSheet, Animated, Easing } from 'react-native';
|
|
14
|
+
import { useAppDesignTokens, AtomicText } from '@umituz/react-native-design-system';
|
|
15
|
+
import { SIZE_CONFIGS, LOADING_EMOJIS, } from '../../domain/entities/Loading';
|
|
16
|
+
/**
|
|
17
|
+
* LoadingState Component
|
|
18
|
+
*
|
|
19
|
+
* Universal loading indicator with breathing animation.
|
|
20
|
+
* Creates a calm, mindful loading experience.
|
|
21
|
+
*
|
|
22
|
+
* USAGE:
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Basic usage
|
|
25
|
+
* <LoadingState />
|
|
26
|
+
*
|
|
27
|
+
* // With message
|
|
28
|
+
* <LoadingState message="Loading data..." size="medium" />
|
|
29
|
+
*
|
|
30
|
+
* // Full screen
|
|
31
|
+
* <LoadingState fullScreen message="Please wait..." />
|
|
32
|
+
*
|
|
33
|
+
* // Custom emoji (per app theme)
|
|
34
|
+
* <LoadingState emoji="🧘" message="Loading meditations..." />
|
|
35
|
+
*
|
|
36
|
+
* // Inline loading
|
|
37
|
+
* <LoadingState size="small" />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export const LoadingState = ({ emoji = LOADING_EMOJIS.default, message, size = 'large', fullScreen = false, style, messageStyle, }) => {
|
|
41
|
+
const tokens = useAppDesignTokens();
|
|
42
|
+
const config = SIZE_CONFIGS[size];
|
|
43
|
+
// Animated value for emoji pulse (breathing effect)
|
|
44
|
+
const scaleAnim = useRef(new Animated.Value(1)).current;
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
// Meditation breathing animation: 2 second cycle (inhale/exhale)
|
|
47
|
+
const breathingAnimation = Animated.loop(Animated.sequence([
|
|
48
|
+
// Inhale - expand
|
|
49
|
+
Animated.timing(scaleAnim, {
|
|
50
|
+
toValue: 1.15,
|
|
51
|
+
duration: 1000,
|
|
52
|
+
easing: Easing.inOut(Easing.ease),
|
|
53
|
+
useNativeDriver: true,
|
|
54
|
+
}),
|
|
55
|
+
// Exhale - contract
|
|
56
|
+
Animated.timing(scaleAnim, {
|
|
57
|
+
toValue: 1,
|
|
58
|
+
duration: 1000,
|
|
59
|
+
easing: Easing.inOut(Easing.ease),
|
|
60
|
+
useNativeDriver: true,
|
|
61
|
+
}),
|
|
62
|
+
]));
|
|
63
|
+
breathingAnimation.start();
|
|
64
|
+
return () => {
|
|
65
|
+
breathingAnimation.stop();
|
|
66
|
+
};
|
|
67
|
+
}, [scaleAnim]);
|
|
68
|
+
return (<View style={[
|
|
69
|
+
styles.container,
|
|
70
|
+
fullScreen && styles.fullScreen,
|
|
71
|
+
{ gap: config.spacing },
|
|
72
|
+
style,
|
|
73
|
+
]}>
|
|
74
|
+
{/* Animated Emoji with breathing pulse */}
|
|
75
|
+
<Animated.Text style={[
|
|
76
|
+
styles.emoji,
|
|
77
|
+
{
|
|
78
|
+
fontSize: config.emojiSize,
|
|
79
|
+
transform: [{ scale: scaleAnim }],
|
|
80
|
+
},
|
|
81
|
+
]}>
|
|
82
|
+
{emoji}
|
|
83
|
+
</Animated.Text>
|
|
84
|
+
|
|
85
|
+
{/* Optional Loading Message */}
|
|
86
|
+
{config.showMessage && message && (<AtomicText type="bodySmall" color="secondary" style={[styles.message, messageStyle]}>
|
|
87
|
+
{message}
|
|
88
|
+
</AtomicText>)}
|
|
89
|
+
</View>);
|
|
90
|
+
};
|
|
91
|
+
const styles = StyleSheet.create({
|
|
92
|
+
container: {
|
|
93
|
+
justifyContent: 'center',
|
|
94
|
+
alignItems: 'center',
|
|
95
|
+
paddingVertical: 20,
|
|
96
|
+
},
|
|
97
|
+
fullScreen: {
|
|
98
|
+
flex: 1,
|
|
99
|
+
paddingVertical: 60,
|
|
100
|
+
},
|
|
101
|
+
emoji: {
|
|
102
|
+
fontFamily: 'System', // Emoji font
|
|
103
|
+
},
|
|
104
|
+
message: {
|
|
105
|
+
textAlign: 'center',
|
|
106
|
+
opacity: 0.7,
|
|
107
|
+
paddingHorizontal: 32,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=LoadingState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoadingState.js","sourceRoot":"","sources":["../../../src/presentation/components/LoadingState.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loading Domain - SkeletonLoader Component
|
|
3
|
+
*
|
|
4
|
+
* Skeleton placeholder loader with shimmer animation.
|
|
5
|
+
* Provides visual feedback during content loading.
|
|
6
|
+
*
|
|
7
|
+
* @domain loading
|
|
8
|
+
* @layer presentation/components
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { type StyleProp, type ViewStyle } from 'react-native';
|
|
12
|
+
import type { SkeletonPattern, SkeletonConfig } from '../../domain/entities/Loading';
|
|
13
|
+
/**
|
|
14
|
+
* SkeletonLoader component props
|
|
15
|
+
*/
|
|
16
|
+
export interface SkeletonLoaderProps {
|
|
17
|
+
/** Skeleton pattern preset */
|
|
18
|
+
pattern?: SkeletonPattern;
|
|
19
|
+
/** Custom skeleton configurations */
|
|
20
|
+
custom?: SkeletonConfig[];
|
|
21
|
+
/** Number of skeleton items to render */
|
|
22
|
+
count?: number;
|
|
23
|
+
/** Custom container style */
|
|
24
|
+
style?: StyleProp<ViewStyle>;
|
|
25
|
+
/** Disable shimmer animation */
|
|
26
|
+
disableAnimation?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* SkeletonLoader Component
|
|
30
|
+
*
|
|
31
|
+
* Renders skeleton placeholders with shimmer animation.
|
|
32
|
+
* Provides visual feedback while content is loading.
|
|
33
|
+
*
|
|
34
|
+
* USAGE:
|
|
35
|
+
* ```typescript
|
|
36
|
+
* // List skeleton (default)
|
|
37
|
+
* <SkeletonLoader pattern="list" count={5} />
|
|
38
|
+
*
|
|
39
|
+
* // Card skeleton
|
|
40
|
+
* <SkeletonLoader pattern="card" count={3} />
|
|
41
|
+
*
|
|
42
|
+
* // Profile skeleton
|
|
43
|
+
* <SkeletonLoader pattern="profile" />
|
|
44
|
+
*
|
|
45
|
+
* // Text skeleton
|
|
46
|
+
* <SkeletonLoader pattern="text" count={3} />
|
|
47
|
+
*
|
|
48
|
+
* // Custom skeleton
|
|
49
|
+
* <SkeletonLoader
|
|
50
|
+
* pattern="custom"
|
|
51
|
+
* custom={[
|
|
52
|
+
* { width: 100, height: 100, borderRadius: 50 },
|
|
53
|
+
* { width: '80%', height: 20, borderRadius: 4 },
|
|
54
|
+
* ]}
|
|
55
|
+
* />
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare const SkeletonLoader: React.FC<SkeletonLoaderProps>;
|
|
59
|
+
//# sourceMappingURL=SkeletonLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SkeletonLoader.d.ts","sourceRoot":"","sources":["../../../src/presentation/components/SkeletonLoader.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,EAA8B,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE1F,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAMrF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,8BAA8B;IAC9B,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,qCAAqC;IACrC,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,gCAAgC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAiFxD,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loading Domain - SkeletonLoader Component
|
|
3
|
+
*
|
|
4
|
+
* Skeleton placeholder loader with shimmer animation.
|
|
5
|
+
* Provides visual feedback during content loading.
|
|
6
|
+
*
|
|
7
|
+
* @domain loading
|
|
8
|
+
* @layer presentation/components
|
|
9
|
+
*/
|
|
10
|
+
import React, { useEffect, useRef } from 'react';
|
|
11
|
+
import { View, StyleSheet, Animated } from 'react-native';
|
|
12
|
+
import { useAppDesignTokens } from '@umituz/react-native-design-system';
|
|
13
|
+
import { SKELETON_PATTERNS, LOADING_CONSTANTS, } from '../../domain/entities/Loading';
|
|
14
|
+
/**
|
|
15
|
+
* SkeletonLoader Component
|
|
16
|
+
*
|
|
17
|
+
* Renders skeleton placeholders with shimmer animation.
|
|
18
|
+
* Provides visual feedback while content is loading.
|
|
19
|
+
*
|
|
20
|
+
* USAGE:
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // List skeleton (default)
|
|
23
|
+
* <SkeletonLoader pattern="list" count={5} />
|
|
24
|
+
*
|
|
25
|
+
* // Card skeleton
|
|
26
|
+
* <SkeletonLoader pattern="card" count={3} />
|
|
27
|
+
*
|
|
28
|
+
* // Profile skeleton
|
|
29
|
+
* <SkeletonLoader pattern="profile" />
|
|
30
|
+
*
|
|
31
|
+
* // Text skeleton
|
|
32
|
+
* <SkeletonLoader pattern="text" count={3} />
|
|
33
|
+
*
|
|
34
|
+
* // Custom skeleton
|
|
35
|
+
* <SkeletonLoader
|
|
36
|
+
* pattern="custom"
|
|
37
|
+
* custom={[
|
|
38
|
+
* { width: 100, height: 100, borderRadius: 50 },
|
|
39
|
+
* { width: '80%', height: 20, borderRadius: 4 },
|
|
40
|
+
* ]}
|
|
41
|
+
* />
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export const SkeletonLoader = ({ pattern = 'list', custom, count = 1, style, disableAnimation = false, }) => {
|
|
45
|
+
const tokens = useAppDesignTokens();
|
|
46
|
+
// Get skeleton config
|
|
47
|
+
const skeletonConfigs = pattern === 'custom' && custom
|
|
48
|
+
? custom
|
|
49
|
+
: SKELETON_PATTERNS[pattern];
|
|
50
|
+
// Animated value for shimmer effect
|
|
51
|
+
const shimmerAnim = useRef(new Animated.Value(0)).current;
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (disableAnimation)
|
|
54
|
+
return;
|
|
55
|
+
// Shimmer animation: 1.2 second cycle
|
|
56
|
+
const shimmerAnimation = Animated.loop(Animated.sequence([
|
|
57
|
+
Animated.timing(shimmerAnim, {
|
|
58
|
+
toValue: 1,
|
|
59
|
+
duration: LOADING_CONSTANTS.SKELETON_SHIMMER_DURATION,
|
|
60
|
+
useNativeDriver: false, // backgroundColor animation requires false
|
|
61
|
+
}),
|
|
62
|
+
Animated.timing(shimmerAnim, {
|
|
63
|
+
toValue: 0,
|
|
64
|
+
duration: 0,
|
|
65
|
+
useNativeDriver: false,
|
|
66
|
+
}),
|
|
67
|
+
]));
|
|
68
|
+
shimmerAnimation.start();
|
|
69
|
+
return () => {
|
|
70
|
+
shimmerAnimation.stop();
|
|
71
|
+
};
|
|
72
|
+
}, [shimmerAnim, disableAnimation]);
|
|
73
|
+
// Interpolate shimmer animation to background color
|
|
74
|
+
const backgroundColor = shimmerAnim.interpolate({
|
|
75
|
+
inputRange: [0, 0.5, 1],
|
|
76
|
+
outputRange: [
|
|
77
|
+
tokens.colors.surfaceSecondary,
|
|
78
|
+
tokens.colors.border,
|
|
79
|
+
tokens.colors.surfaceSecondary,
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
// Render skeleton items
|
|
83
|
+
const renderSkeletonItem = (index) => (<View key={`skeleton-group-${index}`} style={styles.skeletonGroup}>
|
|
84
|
+
{skeletonConfigs.map((config, configIndex) => (<Animated.View key={`skeleton-${index}-${configIndex}`} style={[
|
|
85
|
+
styles.skeleton,
|
|
86
|
+
{
|
|
87
|
+
width: config.width,
|
|
88
|
+
height: config.height,
|
|
89
|
+
borderRadius: config.borderRadius,
|
|
90
|
+
marginBottom: config.marginBottom,
|
|
91
|
+
backgroundColor: disableAnimation
|
|
92
|
+
? tokens.colors.surfaceSecondary
|
|
93
|
+
: backgroundColor,
|
|
94
|
+
},
|
|
95
|
+
]}/>))}
|
|
96
|
+
</View>);
|
|
97
|
+
return (<View style={[styles.container, style]}>
|
|
98
|
+
{Array.from({ length: count }).map((_, index) => renderSkeletonItem(index))}
|
|
99
|
+
</View>);
|
|
100
|
+
};
|
|
101
|
+
const styles = StyleSheet.create({
|
|
102
|
+
container: {
|
|
103
|
+
width: '100%',
|
|
104
|
+
},
|
|
105
|
+
skeletonGroup: {
|
|
106
|
+
width: '100%',
|
|
107
|
+
},
|
|
108
|
+
skeleton: {
|
|
109
|
+
overflow: 'hidden',
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=SkeletonLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SkeletonLoader.js","sourceRoot":"","sources":["../../../src/presentation/components/SkeletonLoader.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loading Domain - useLoading Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for managing loading states.
|
|
5
|
+
* Provides consistent loading state management across components.
|
|
6
|
+
*
|
|
7
|
+
* @domain loading
|
|
8
|
+
* @layer presentation/hooks
|
|
9
|
+
*/
|
|
10
|
+
import type { LoadingType } from '../../domain/entities/Loading';
|
|
11
|
+
/**
|
|
12
|
+
* useLoading hook return type
|
|
13
|
+
*/
|
|
14
|
+
export interface UseLoadingReturn {
|
|
15
|
+
isLoading: boolean;
|
|
16
|
+
loadingMessage: string | null;
|
|
17
|
+
loadingType: LoadingType;
|
|
18
|
+
startLoading: (message?: string, type?: LoadingType) => void;
|
|
19
|
+
stopLoading: () => void;
|
|
20
|
+
setLoadingMessage: (message: string | null) => void;
|
|
21
|
+
setLoadingType: (type: LoadingType) => void;
|
|
22
|
+
withLoading: <T>(asyncFn: Promise<T>, message?: string, type?: LoadingType) => Promise<T>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* useLoading hook for loading state management
|
|
26
|
+
*
|
|
27
|
+
* USAGE:
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const {
|
|
30
|
+
* isLoading,
|
|
31
|
+
* loadingMessage,
|
|
32
|
+
* startLoading,
|
|
33
|
+
* stopLoading,
|
|
34
|
+
* withLoading,
|
|
35
|
+
* } = useLoading();
|
|
36
|
+
*
|
|
37
|
+
* // Manual control
|
|
38
|
+
* const handleSave = async () => {
|
|
39
|
+
* startLoading('Saving data...');
|
|
40
|
+
* try {
|
|
41
|
+
* await saveData();
|
|
42
|
+
* } finally {
|
|
43
|
+
* stopLoading();
|
|
44
|
+
* }
|
|
45
|
+
* };
|
|
46
|
+
*
|
|
47
|
+
* // Automatic wrapper
|
|
48
|
+
* const handleLoad = () => withLoading(
|
|
49
|
+
* loadData(),
|
|
50
|
+
* 'Loading data...'
|
|
51
|
+
* );
|
|
52
|
+
*
|
|
53
|
+
* // In render
|
|
54
|
+
* {isLoading && <LoadingState message={loadingMessage} />}
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare const useLoading: () => UseLoadingReturn;
|
|
58
|
+
/**
|
|
59
|
+
* Convenience hook for simple loading state (no message)
|
|
60
|
+
*/
|
|
61
|
+
export declare const useSimpleLoading: () => {
|
|
62
|
+
isLoading: boolean;
|
|
63
|
+
startLoading: () => void;
|
|
64
|
+
stopLoading: () => void;
|
|
65
|
+
withLoading: <T>(asyncFn: Promise<T>) => Promise<T>;
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=useLoading.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLoading.d.ts","sourceRoot":"","sources":["../../../src/presentation/hooks/useLoading.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAE/B,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,WAAW,CAAC;IAGzB,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7D,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACpD,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAG5C,WAAW,EAAE,CAAC,CAAC,EACb,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,CAAC,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,WAAW,KACf,OAAO,CAAC,CAAC,CAAC,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,UAAU,QAAO,gBAwE7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;kBAIlB,CAAC,WAAY,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAAC;CAmB9C,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loading Domain - useLoading Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for managing loading states.
|
|
5
|
+
* Provides consistent loading state management across components.
|
|
6
|
+
*
|
|
7
|
+
* @domain loading
|
|
8
|
+
* @layer presentation/hooks
|
|
9
|
+
*/
|
|
10
|
+
import { useState, useCallback } from 'react';
|
|
11
|
+
/**
|
|
12
|
+
* useLoading hook for loading state management
|
|
13
|
+
*
|
|
14
|
+
* USAGE:
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const {
|
|
17
|
+
* isLoading,
|
|
18
|
+
* loadingMessage,
|
|
19
|
+
* startLoading,
|
|
20
|
+
* stopLoading,
|
|
21
|
+
* withLoading,
|
|
22
|
+
* } = useLoading();
|
|
23
|
+
*
|
|
24
|
+
* // Manual control
|
|
25
|
+
* const handleSave = async () => {
|
|
26
|
+
* startLoading('Saving data...');
|
|
27
|
+
* try {
|
|
28
|
+
* await saveData();
|
|
29
|
+
* } finally {
|
|
30
|
+
* stopLoading();
|
|
31
|
+
* }
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* // Automatic wrapper
|
|
35
|
+
* const handleLoad = () => withLoading(
|
|
36
|
+
* loadData(),
|
|
37
|
+
* 'Loading data...'
|
|
38
|
+
* );
|
|
39
|
+
*
|
|
40
|
+
* // In render
|
|
41
|
+
* {isLoading && <LoadingState message={loadingMessage} />}
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export const useLoading = () => {
|
|
45
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
46
|
+
const [loadingMessage, setLoadingMessage] = useState(null);
|
|
47
|
+
const [loadingType, setLoadingType] = useState('pulse');
|
|
48
|
+
/**
|
|
49
|
+
* Start loading state
|
|
50
|
+
*/
|
|
51
|
+
const startLoading = useCallback((message, type = 'pulse') => {
|
|
52
|
+
setIsLoading(true);
|
|
53
|
+
setLoadingMessage(message || null);
|
|
54
|
+
setLoadingType(type);
|
|
55
|
+
}, []);
|
|
56
|
+
/**
|
|
57
|
+
* Stop loading state
|
|
58
|
+
*/
|
|
59
|
+
const stopLoading = useCallback(() => {
|
|
60
|
+
setIsLoading(false);
|
|
61
|
+
setLoadingMessage(null);
|
|
62
|
+
}, []);
|
|
63
|
+
/**
|
|
64
|
+
* Update loading message
|
|
65
|
+
*/
|
|
66
|
+
const updateLoadingMessage = useCallback((message) => {
|
|
67
|
+
setLoadingMessage(message);
|
|
68
|
+
}, []);
|
|
69
|
+
/**
|
|
70
|
+
* Update loading type
|
|
71
|
+
*/
|
|
72
|
+
const updateLoadingType = useCallback((type) => {
|
|
73
|
+
setLoadingType(type);
|
|
74
|
+
}, []);
|
|
75
|
+
/**
|
|
76
|
+
* Async wrapper that automatically manages loading state
|
|
77
|
+
*/
|
|
78
|
+
const withLoading = useCallback(async (asyncFn, message, type = 'pulse') => {
|
|
79
|
+
startLoading(message, type);
|
|
80
|
+
try {
|
|
81
|
+
const result = await asyncFn;
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
stopLoading();
|
|
86
|
+
}
|
|
87
|
+
}, [startLoading, stopLoading]);
|
|
88
|
+
return {
|
|
89
|
+
// Loading state
|
|
90
|
+
isLoading,
|
|
91
|
+
loadingMessage,
|
|
92
|
+
loadingType,
|
|
93
|
+
// Actions
|
|
94
|
+
startLoading,
|
|
95
|
+
stopLoading,
|
|
96
|
+
setLoadingMessage: updateLoadingMessage,
|
|
97
|
+
setLoadingType: updateLoadingType,
|
|
98
|
+
// Async wrapper
|
|
99
|
+
withLoading,
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Convenience hook for simple loading state (no message)
|
|
104
|
+
*/
|
|
105
|
+
export const useSimpleLoading = () => {
|
|
106
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
107
|
+
const withLoading = useCallback(async (asyncFn) => {
|
|
108
|
+
setIsLoading(true);
|
|
109
|
+
try {
|
|
110
|
+
const result = await asyncFn;
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
setIsLoading(false);
|
|
115
|
+
}
|
|
116
|
+
}, []);
|
|
117
|
+
return {
|
|
118
|
+
isLoading,
|
|
119
|
+
startLoading: useCallback(() => setIsLoading(true), []),
|
|
120
|
+
stopLoading: useCallback(() => setIsLoading(false), []),
|
|
121
|
+
withLoading,
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=useLoading.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLoading.js","sourceRoot":"","sources":["../../../src/presentation/hooks/useLoading.ts"],"names":[],"mappings":"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"}
|