@umituz/react-native-ai-generation-content 1.12.8 → 1.12.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.12.8",
3
+ "version": "1.12.9",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -16,8 +16,8 @@
16
16
  "src"
17
17
  ],
18
18
  "scripts": {
19
- "typecheck": "echo 'TypeScript validation passed'",
20
- "lint": "echo 'Lint passed'",
19
+ "typecheck": "tsc --noEmit",
20
+ "lint": "eslint src --ext .ts,.tsx --max-warnings 0",
21
21
  "lint:fix": "eslint src --ext .ts,.tsx --fix"
22
22
  },
23
23
  "keywords": [
@@ -73,7 +73,7 @@
73
73
  "firebase": "^11.1.0",
74
74
  "react": "19.1.0",
75
75
  "react-native": "0.81.5",
76
- "react-native-safe-area-context": "^4.0.0",
76
+ "react-native-safe-area-context": "^5.6.2",
77
77
  "typescript": "^5.3.0",
78
78
  "zustand": "^5.0.2"
79
79
  },
@@ -0,0 +1,10 @@
1
+
2
+ import { AtomicTextProps, AtomicIconProps } from "@umituz/react-native-design-system";
3
+
4
+ const textProps: AtomicTextProps = {
5
+ // This helps us see what is required/optional in IDE or tsc output
6
+ };
7
+
8
+ const iconProps: AtomicIconProps = {
9
+ name: 'check',
10
+ };
@@ -0,0 +1,77 @@
1
+ import React, { useMemo } from "react";
2
+ import { View, StyleSheet, ActivityIndicator } from "react-native";
3
+ import { useAppDesignTokens } from "@umituz/react-native-design-system";
4
+ import { EmptyState } from "./EmptyState";
5
+ import type { CreationsConfig } from "../../domain/value-objects/CreationsConfig";
6
+
7
+ interface CreationsGalleryEmptyStateProps {
8
+ readonly isLoading: boolean;
9
+ readonly hasCreations: boolean;
10
+ readonly config: CreationsConfig;
11
+ readonly t: (key: string) => string;
12
+ readonly emptyActionLabel?: string;
13
+ readonly onEmptyAction?: () => void;
14
+ readonly clearFilters: () => void;
15
+ }
16
+
17
+ export const CreationsGalleryEmptyState: React.FC<CreationsGalleryEmptyStateProps> = ({
18
+ isLoading,
19
+ hasCreations,
20
+ config,
21
+ t,
22
+ emptyActionLabel,
23
+ onEmptyAction,
24
+ clearFilters,
25
+ }) => {
26
+ const tokens = useAppDesignTokens();
27
+ const styles = useStyles(tokens);
28
+
29
+ return useMemo(() => {
30
+ // 1. Loading State
31
+ if (isLoading && !hasCreations) {
32
+ return (
33
+ <View style={styles.centerContainer}>
34
+ <ActivityIndicator size="large" color={tokens.colors.primary} />
35
+ </View>
36
+ );
37
+ }
38
+
39
+ // 2. System Empty State (User has NO creations at all)
40
+ // We check 'hasCreations' which represents the full list presence
41
+ if (!hasCreations) {
42
+ return (
43
+ <View style={styles.centerContainer}>
44
+ <EmptyState
45
+ title={t(config.translations.empty)}
46
+ description={t(config.translations.emptyDescription)}
47
+ actionLabel={emptyActionLabel}
48
+ onAction={onEmptyAction}
49
+ />
50
+ </View>
51
+ );
52
+ }
53
+
54
+ // 3. Filter Empty State (User has creations, but filter returns none)
55
+ // This component is rendered when the list is empty, but hasCreations is true.
56
+ return (
57
+ <View style={styles.centerContainer}>
58
+ <EmptyState
59
+ title={t("common.no_results") || "No results"}
60
+ description={t("common.no_results_description") || "Try changing your filters"}
61
+ actionLabel={t("common.clear_all") || "Clear All"}
62
+ onAction={clearFilters}
63
+ />
64
+ </View>
65
+ );
66
+ }, [isLoading, hasCreations, config, t, emptyActionLabel, onEmptyAction, clearFilters, styles.centerContainer, tokens.colors.primary]);
67
+ };
68
+
69
+ const useStyles = (tokens: any) => StyleSheet.create({
70
+ centerContainer: {
71
+ flex: 1,
72
+ justifyContent: 'center',
73
+ alignItems: 'center',
74
+ minHeight: 400,
75
+ paddingHorizontal: tokens.spacing.xl
76
+ },
77
+ });
@@ -10,6 +10,7 @@ export { CreationCard } from "./CreationCard";
10
10
  export { CreationThumbnail } from "./CreationThumbnail";
11
11
  export { CreationImageViewer } from "./CreationImageViewer";
12
12
  export { CreationsGrid } from "./CreationsGrid";
13
+ export { CreationsGalleryEmptyState } from "./CreationsGalleryEmptyState";
13
14
  export { FilterBottomSheet, type FilterCategory, type FilterOption } from "./FilterBottomSheet";
14
15
 
15
16
  // Detail Components
@@ -9,7 +9,7 @@ import { useDeleteCreation } from "../hooks/useDeleteCreation";
9
9
  import { useCreationsFilter } from "../hooks/useCreationsFilter";
10
10
  import { useAlert, AlertMode } from "@umituz/react-native-design-system";
11
11
  import { BottomSheetModalRef } from "@umituz/react-native-bottom-sheet";
12
- import { GalleryHeader, EmptyState, CreationsGrid, FilterBottomSheet, CreationImageViewer, type FilterCategory } from "../components";
12
+ import { GalleryHeader, CreationsGrid, FilterBottomSheet, CreationImageViewer, type FilterCategory, CreationsGalleryEmptyState } from "../components";
13
13
  import { getTranslatedTypes, getFilterCategoriesFromConfig } from "../utils/filterUtils";
14
14
  import type { Creation } from "../../domain/entities/Creation";
15
15
  import type { CreationsConfig } from "../../domain/value-objects/CreationsConfig";
@@ -91,59 +91,8 @@ export function CreationsGalleryScreen({
91
91
  setSelectedCreation(creation);
92
92
  }, []);
93
93
 
94
- const styles = useStyles(tokens);
95
-
96
- // Define empty state content based on state
97
- const renderEmptyComponent = useMemo(() => {
98
- // 1. Loading State
99
- if (isLoading && (!creations || creations?.length === 0)) {
100
- return (
101
- <View style={styles.centerContainer}>
102
- <ActivityIndicator size="large" color={tokens.colors.primary} />
103
- </View>
104
- );
105
- }
106
-
107
- // 2. System Empty State (User has NO creations at all)
108
- // We check 'creations' (the full list)
109
- if (!creations || creations?.length === 0) {
110
- return (
111
- <View style={styles.centerContainer}>
112
- <EmptyState
113
- title={t(config.translations.empty)}
114
- description={t(config.translations.emptyDescription)}
115
- actionLabel={emptyActionLabel}
116
- onAction={onEmptyAction}
117
- />
118
- </View>
119
- );
120
- }
121
-
122
- // 3. Filter Empty State (User has creations, but filter returns none)
123
- // We check 'filtered' (the displayed list)
124
- return (
125
- <View style={styles.centerContainer}>
126
- <EmptyState
127
- title={t("common.no_results") || "No results"}
128
- description={t("common.no_results_description") || "Try changing your filters"}
129
- actionLabel={t("common.clear_all") || "Clear All"}
130
- onAction={clearFilters}
131
- />
132
- </View>
133
- );
134
- }, [isLoading, creations, config, t, emptyActionLabel, onEmptyAction, clearFilters, styles.centerContainer, tokens.colors.primary]);
135
94
 
136
- if (selectedCreation) {
137
- return (
138
- <CreationDetailScreen
139
- creation={selectedCreation}
140
- onClose={() => setSelectedCreation(null)}
141
- onShare={handleShare}
142
- onDelete={handleDelete}
143
- t={t}
144
- />
145
- );
146
- }
95
+ const styles = useStyles(tokens);
147
96
 
148
97
  return (
149
98
  <View style={styles.container}>
@@ -181,7 +130,17 @@ export function CreationsGalleryScreen({
181
130
  onShare={handleShare}
182
131
  onDelete={handleDelete}
183
132
  contentContainerStyle={{ paddingBottom: insets.bottom + tokens.spacing.xl }}
184
- ListEmptyComponent={renderEmptyComponent}
133
+ ListEmptyComponent={
134
+ <CreationsGalleryEmptyState
135
+ isLoading={isLoading}
136
+ hasCreations={!!creations && creations.length > 0}
137
+ config={config}
138
+ t={t}
139
+ emptyActionLabel={emptyActionLabel}
140
+ onEmptyAction={onEmptyAction}
141
+ clearFilters={clearFilters}
142
+ />
143
+ }
185
144
  />
186
145
 
187
146
  <CreationImageViewer
@@ -209,11 +168,4 @@ export function CreationsGalleryScreen({
209
168
 
210
169
  const useStyles = (tokens: any) => StyleSheet.create({
211
170
  container: { flex: 1, backgroundColor: tokens.colors.background },
212
- centerContainer: {
213
- flex: 1,
214
- justifyContent: 'center',
215
- alignItems: 'center',
216
- minHeight: 400,
217
- paddingHorizontal: tokens.spacing.xl
218
- },
219
171
  });
@@ -43,7 +43,7 @@ export const GenerateButton: React.FC<GenerateButtonProps> = memo(
43
43
  <>
44
44
  <AtomicIcon
45
45
  name="sparkles"
46
- size={20}
46
+ size="md"
47
47
  color={disabled ? "surfaceVariant" : "onPrimary"}
48
48
  style={styles.icon}
49
49
  />
@@ -44,7 +44,7 @@ export const ImagePicker: React.FC<ImagePickerProps> = memo(
44
44
  >
45
45
  <AtomicIcon
46
46
  name="image-plus"
47
- size={20}
47
+ size="md"
48
48
  color="onPrimary"
49
49
  />
50
50
  </View>
@@ -65,7 +65,7 @@ export const ImagePicker: React.FC<ImagePickerProps> = memo(
65
65
  >
66
66
  <AtomicIcon
67
67
  name="upload"
68
- size={40}
68
+ size="lg"
69
69
  color="primary"
70
70
  />
71
71
  </View>
@@ -45,7 +45,7 @@ export const ModeSelector: React.FC<ModeSelectorProps> = memo(
45
45
  >
46
46
  <AtomicIcon
47
47
  name={mode.icon}
48
- size={20}
48
+ size="md"
49
49
  color={isActive ? "onPrimary" : "onSurface"}
50
50
  />
51
51
  </TouchableOpacity>
@@ -47,7 +47,7 @@ export const ResultDisplay: React.FC<ResultDisplayProps> = memo(
47
47
  >
48
48
  <AtomicIcon
49
49
  name="refresh-cw"
50
- size={20}
50
+ size="md"
51
51
  color="onSurface"
52
52
  />
53
53
  <AtomicText
@@ -67,7 +67,7 @@ export const ResultDisplay: React.FC<ResultDisplayProps> = memo(
67
67
  >
68
68
  <AtomicIcon
69
69
  name="download"
70
- size={20}
70
+ size="md"
71
71
  color="onPrimary"
72
72
  />
73
73
  <AtomicText
@@ -40,7 +40,7 @@ export const ResultActions: React.FC<ResultActionsProps> = ({
40
40
  <View style={styles.container}>
41
41
  {onRetry && (
42
42
  <TouchableOpacity style={styles.retryButton} onPress={onRetry}>
43
- <AtomicIcon name="refresh" size={18} customColor={tokens.colors.primary} />
43
+ <AtomicIcon name="refresh" size="sm" customColor={tokens.colors.primary} />
44
44
  <AtomicText style={styles.retryText}>{translations.retry}</AtomicText>
45
45
  </TouchableOpacity>
46
46
  )}
@@ -54,7 +54,7 @@ export const ResultActions: React.FC<ResultActionsProps> = ({
54
54
  >
55
55
  <AtomicIcon
56
56
  name={isSharing ? "hourglass" : "share-social"}
57
- size={22}
57
+ size="md"
58
58
  customColor="#fff"
59
59
  />
60
60
  <AtomicText style={styles.shareText}>
@@ -71,7 +71,7 @@ export const ResultActions: React.FC<ResultActionsProps> = ({
71
71
  >
72
72
  <AtomicIcon
73
73
  name={isSaving ? "hourglass" : "download"}
74
- size={22}
74
+ size="md"
75
75
  customColor={tokens.colors.primary}
76
76
  />
77
77
  <AtomicText style={styles.saveText}>{translations.save}</AtomicText>
@@ -29,7 +29,7 @@ export const ResultHeader: React.FC<ResultHeaderProps> = ({ title, date }) => {
29
29
  <View style={styles.badge}>
30
30
  <AtomicIcon
31
31
  name="calendar-outline"
32
- size={14}
32
+ size="sm"
33
33
  customColor={tokens.colors.primary}
34
34
  />
35
35
  <AtomicText style={styles.dateText}>{date}</AtomicText>
@@ -28,7 +28,7 @@ export const ResultImageCard: React.FC<ResultImageCardProps> = ({
28
28
  <View style={styles.frame}>
29
29
  <Image source={{ uri: imageUrl }} style={styles.image} resizeMode="cover" />
30
30
  <View style={styles.badge}>
31
- <AtomicIcon name="sparkles" size={12} customColor="#fff" />
31
+ <AtomicIcon name="sparkles" size="xs" customColor="#fff" />
32
32
  <AtomicText style={styles.badgeText}>{badgeText}</AtomicText>
33
33
  </View>
34
34
  </View>