@umituz/react-native-ai-generation-content 1.83.20 → 1.83.22
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 +1 -1
- package/src/domains/creations/presentation/components/GalleryEmptyStates.tsx +14 -23
- package/src/domains/creations/presentation/components/GalleryHeader.tsx +6 -4
- package/src/domains/creations/presentation/components/GalleryScreenHeader.tsx +13 -5
- package/src/domains/creations/presentation/hooks/useCreations.ts +15 -0
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.83.
|
|
3
|
+
"version": "1.83.22",
|
|
4
4
|
"description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -27,29 +27,23 @@ function CreationCardSkeleton({ tokens }: { tokens: DesignTokens }) {
|
|
|
27
27
|
const styles = createSkeletonStyles(tokens);
|
|
28
28
|
return (
|
|
29
29
|
<View style={styles.card}>
|
|
30
|
-
{/*
|
|
30
|
+
{/* Full-width image skeleton */}
|
|
31
31
|
<AtomicSkeleton
|
|
32
32
|
pattern="custom"
|
|
33
|
-
custom={[{ width: 100, height:
|
|
33
|
+
custom={[{ width: "100%" as unknown as number, height: 200, borderRadius: 0 }]}
|
|
34
34
|
/>
|
|
35
|
-
{/*
|
|
36
|
-
<View style={styles.
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{ width: 120, height: 18, borderRadius: 4, marginBottom: 8 },
|
|
42
|
-
{ width: 100, height: 14, borderRadius: 4 },
|
|
43
|
-
]}
|
|
44
|
-
/>
|
|
45
|
-
</View>
|
|
46
|
-
{/* Action buttons skeleton */}
|
|
35
|
+
{/* Bottom bar skeleton */}
|
|
36
|
+
<View style={styles.bottomBar}>
|
|
37
|
+
<AtomicSkeleton
|
|
38
|
+
pattern="custom"
|
|
39
|
+
custom={[{ width: 140, height: 16, borderRadius: 4 }]}
|
|
40
|
+
/>
|
|
47
41
|
<View style={styles.actions}>
|
|
48
|
-
{[1, 2, 3
|
|
42
|
+
{[1, 2, 3].map((id) => (
|
|
49
43
|
<AtomicSkeleton
|
|
50
44
|
key={id}
|
|
51
45
|
pattern="custom"
|
|
52
|
-
custom={[{ width:
|
|
46
|
+
custom={[{ width: 32, height: 32, borderRadius: 16 }]}
|
|
53
47
|
/>
|
|
54
48
|
))}
|
|
55
49
|
</View>
|
|
@@ -131,19 +125,16 @@ const createStyles = (tokens: DesignTokens) => StyleSheet.create({
|
|
|
131
125
|
|
|
132
126
|
const createSkeletonStyles = (tokens: DesignTokens) => StyleSheet.create({
|
|
133
127
|
card: {
|
|
134
|
-
flexDirection: 'row',
|
|
135
128
|
backgroundColor: tokens.colors.surface,
|
|
136
129
|
borderRadius: tokens.spacing.md,
|
|
137
130
|
overflow: 'hidden',
|
|
138
131
|
marginBottom: tokens.spacing.md,
|
|
139
132
|
},
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
133
|
+
bottomBar: {
|
|
134
|
+
flexDirection: 'row',
|
|
135
|
+
alignItems: 'center',
|
|
143
136
|
justifyContent: 'space-between',
|
|
144
|
-
|
|
145
|
-
textArea: {
|
|
146
|
-
gap: tokens.spacing.xs,
|
|
137
|
+
padding: tokens.spacing.md,
|
|
147
138
|
},
|
|
148
139
|
actions: {
|
|
149
140
|
flexDirection: 'row',
|
|
@@ -36,11 +36,13 @@ export const GalleryHeader: React.FC<GalleryHeaderProps> = ({
|
|
|
36
36
|
return (
|
|
37
37
|
<View style={[styles.headerArea, style]}>
|
|
38
38
|
<View>
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
39
|
+
{title ? (
|
|
40
|
+
<View style={styles.titleRow}>
|
|
41
|
+
<AtomicText style={styles.title}>{title}</AtomicText>
|
|
42
|
+
</View>
|
|
43
|
+
) : null}
|
|
42
44
|
<AtomicText style={styles.subtitle}>
|
|
43
|
-
{
|
|
45
|
+
{countLabel}
|
|
44
46
|
</AtomicText>
|
|
45
47
|
</View>
|
|
46
48
|
{showFilter && filterButtons.length > 0 && (
|
|
@@ -18,10 +18,15 @@ export const GalleryScreenHeader: React.FC<GalleryScreenHeaderProps> = ({ title,
|
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
20
|
<View style={styles.screenHeader}>
|
|
21
|
-
<TouchableOpacity
|
|
21
|
+
<TouchableOpacity
|
|
22
|
+
onPress={onBack}
|
|
23
|
+
style={styles.backButton}
|
|
24
|
+
activeOpacity={0.6}
|
|
25
|
+
hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
|
|
26
|
+
>
|
|
22
27
|
<AtomicIcon
|
|
23
|
-
name="chevron-
|
|
24
|
-
customSize={
|
|
28
|
+
name="chevron-back"
|
|
29
|
+
customSize={24}
|
|
25
30
|
customColor={tokens.colors.textPrimary}
|
|
26
31
|
/>
|
|
27
32
|
</TouchableOpacity>
|
|
@@ -46,9 +51,12 @@ const createStyles = (tokens: DesignTokens) =>
|
|
|
46
51
|
gap: tokens.spacing.md,
|
|
47
52
|
},
|
|
48
53
|
backButton: {
|
|
49
|
-
|
|
54
|
+
width: 40,
|
|
55
|
+
height: 40,
|
|
56
|
+
justifyContent: "center",
|
|
57
|
+
alignItems: "center",
|
|
50
58
|
},
|
|
51
59
|
placeholder: {
|
|
52
|
-
width:
|
|
60
|
+
width: 40,
|
|
53
61
|
},
|
|
54
62
|
});
|
|
@@ -70,7 +70,22 @@ export function useCreations({
|
|
|
70
70
|
|
|
71
71
|
const unsubscribe = repository.subscribeToAll(userId, onDataCallback, onErrorCallback);
|
|
72
72
|
|
|
73
|
+
// Fallback timeout: if Firestore doesn't respond in 10s, stop loading
|
|
74
|
+
const timeoutId = setTimeout(() => {
|
|
75
|
+
setIsLoading((prev) => {
|
|
76
|
+
if (prev) {
|
|
77
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
78
|
+
console.warn("[useCreations] Loading timeout - setting empty state");
|
|
79
|
+
}
|
|
80
|
+
setData((currentData) => currentData ?? []);
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return prev;
|
|
84
|
+
});
|
|
85
|
+
}, 10000);
|
|
86
|
+
|
|
73
87
|
return () => {
|
|
88
|
+
clearTimeout(timeoutId);
|
|
74
89
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
75
90
|
console.log("[useCreations] Cleaning up realtime listener");
|
|
76
91
|
}
|
|
@@ -104,20 +104,23 @@ export function CreationsGalleryScreen({
|
|
|
104
104
|
/>
|
|
105
105
|
), [callbacks, getItemTitle]);
|
|
106
106
|
|
|
107
|
+
const hasScreenHeader = Boolean(onBack);
|
|
108
|
+
|
|
107
109
|
const renderHeader = useMemo(() => {
|
|
108
110
|
if (!creations?.length && !isLoading) return null;
|
|
111
|
+
if (isLoading) return null;
|
|
109
112
|
return (
|
|
110
113
|
<View style={[styles.header, { backgroundColor: tokens.colors.surface, borderBottomColor: tokens.colors.border }]}>
|
|
111
114
|
<GalleryHeader
|
|
112
|
-
title={t(config.translations.title)}
|
|
115
|
+
title={hasScreenHeader ? "" : t(config.translations.title)}
|
|
113
116
|
count={filters.filtered.length}
|
|
114
|
-
countLabel={t(config.translations.photoCount)}
|
|
117
|
+
countLabel={t(config.translations.photoCount, { count: filters.filtered.length })}
|
|
115
118
|
showFilter={showFilter}
|
|
116
119
|
filterButtons={filterButtons}
|
|
117
120
|
/>
|
|
118
121
|
</View>
|
|
119
122
|
);
|
|
120
|
-
}, [creations, isLoading, filters.filtered.length, showFilter, filterButtons, t, config, tokens]);
|
|
123
|
+
}, [creations, isLoading, filters.filtered.length, showFilter, filterButtons, t, config, tokens, hasScreenHeader]);
|
|
121
124
|
|
|
122
125
|
const renderEmpty = useMemo(() => (
|
|
123
126
|
<GalleryEmptyStates
|