@umituz/react-native-ai-generation-content 1.12.7 → 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.7",
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": [
@@ -40,7 +40,6 @@
40
40
  "peerDependencies": {
41
41
  "@react-navigation/native": ">=6.0.0",
42
42
  "@tanstack/react-query": ">=5.0.0",
43
- "@umituz/react-native-alert": "latest",
44
43
  "@umituz/react-native-animation": "latest",
45
44
  "@umituz/react-native-bottom-sheet": "latest",
46
45
  "@umituz/react-native-design-system": "latest",
@@ -62,7 +61,6 @@
62
61
  "@types/react-native": "^0.73.0",
63
62
  "@typescript-eslint/eslint-plugin": "^7.0.0",
64
63
  "@typescript-eslint/parser": "^7.0.0",
65
- "@umituz/react-native-alert": "latest",
66
64
  "@umituz/react-native-animation": "latest",
67
65
  "@umituz/react-native-bottom-sheet": "latest",
68
66
  "@umituz/react-native-design-system": "latest",
@@ -75,11 +73,11 @@
75
73
  "firebase": "^11.1.0",
76
74
  "react": "19.1.0",
77
75
  "react-native": "0.81.5",
78
- "react-native-safe-area-context": "^4.0.0",
76
+ "react-native-safe-area-context": "^5.6.2",
79
77
  "typescript": "^5.3.0",
80
78
  "zustand": "^5.0.2"
81
79
  },
82
80
  "publishConfig": {
83
81
  "access": "public"
84
82
  }
85
- }
83
+ }
@@ -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
@@ -7,9 +7,9 @@ import { useFocusEffect } from "@react-navigation/native";
7
7
  import { useCreations } from "../hooks/useCreations";
8
8
  import { useDeleteCreation } from "../hooks/useDeleteCreation";
9
9
  import { useCreationsFilter } from "../hooks/useCreationsFilter";
10
- import { useAlert } from "@umituz/react-native-alert";
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";
@@ -68,20 +68,22 @@ export function CreationsGalleryScreen({
68
68
  }, [share, t]);
69
69
 
70
70
  const handleDelete = useCallback(async (creation: Creation) => {
71
- alert.show({
72
- title: t(config.translations.deleteTitle),
73
- message: t(config.translations.deleteMessage),
74
- type: 'warning' as any,
75
- actions: [
76
- { id: 'cancel', label: t("common.cancel"), onPress: () => { } },
77
- {
78
- id: 'delete', label: t("common.delete"), variant: 'danger' as any, onPress: async () => {
79
- const success = await deleteMutation.mutateAsync(creation.id);
80
- if (success) setSelectedCreation(null);
71
+ alert.showWarning(
72
+ t(config.translations.deleteTitle),
73
+ t(config.translations.deleteMessage),
74
+ {
75
+ mode: AlertMode.MODAL,
76
+ actions: [
77
+ { id: 'cancel', label: t("common.cancel"), onPress: () => { } },
78
+ {
79
+ id: 'delete', label: t("common.delete"), style: 'destructive', onPress: async () => {
80
+ const success = await deleteMutation.mutateAsync(creation.id);
81
+ if (success) setSelectedCreation(null);
82
+ }
81
83
  }
82
- }
83
- ]
84
- });
84
+ ]
85
+ }
86
+ );
85
87
  }, [alert, config, deleteMutation, t]);
86
88
 
87
89
  // Handle viewing a creation - shows detail screen
@@ -89,59 +91,8 @@ export function CreationsGalleryScreen({
89
91
  setSelectedCreation(creation);
90
92
  }, []);
91
93
 
92
- const styles = useStyles(tokens);
93
-
94
- // Define empty state content based on state
95
- const renderEmptyComponent = useMemo(() => {
96
- // 1. Loading State
97
- if (isLoading && (!creations || creations?.length === 0)) {
98
- return (
99
- <View style={styles.centerContainer}>
100
- <ActivityIndicator size="large" color={tokens.colors.primary} />
101
- </View>
102
- );
103
- }
104
-
105
- // 2. System Empty State (User has NO creations at all)
106
- // We check 'creations' (the full list)
107
- if (!creations || creations?.length === 0) {
108
- return (
109
- <View style={styles.centerContainer}>
110
- <EmptyState
111
- title={t(config.translations.empty)}
112
- description={t(config.translations.emptyDescription)}
113
- actionLabel={emptyActionLabel}
114
- onAction={onEmptyAction}
115
- />
116
- </View>
117
- );
118
- }
119
-
120
- // 3. Filter Empty State (User has creations, but filter returns none)
121
- // We check 'filtered' (the displayed list)
122
- return (
123
- <View style={styles.centerContainer}>
124
- <EmptyState
125
- title={t("common.no_results") || "No results"}
126
- description={t("common.no_results_description") || "Try changing your filters"}
127
- actionLabel={t("common.clear_all") || "Clear All"}
128
- onAction={clearFilters}
129
- />
130
- </View>
131
- );
132
- }, [isLoading, creations, config, t, emptyActionLabel, onEmptyAction, clearFilters, styles.centerContainer, tokens.colors.primary]);
133
94
 
134
- if (selectedCreation) {
135
- return (
136
- <CreationDetailScreen
137
- creation={selectedCreation}
138
- onClose={() => setSelectedCreation(null)}
139
- onShare={handleShare}
140
- onDelete={handleDelete}
141
- t={t}
142
- />
143
- );
144
- }
95
+ const styles = useStyles(tokens);
145
96
 
146
97
  return (
147
98
  <View style={styles.container}>
@@ -179,7 +130,17 @@ export function CreationsGalleryScreen({
179
130
  onShare={handleShare}
180
131
  onDelete={handleDelete}
181
132
  contentContainerStyle={{ paddingBottom: insets.bottom + tokens.spacing.xl }}
182
- 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
+ }
183
144
  />
184
145
 
185
146
  <CreationImageViewer
@@ -207,11 +168,4 @@ export function CreationsGalleryScreen({
207
168
 
208
169
  const useStyles = (tokens: any) => StyleSheet.create({
209
170
  container: { flex: 1, backgroundColor: tokens.colors.background },
210
- centerContainer: {
211
- flex: 1,
212
- justifyContent: 'center',
213
- alignItems: 'center',
214
- minHeight: 400,
215
- paddingHorizontal: tokens.spacing.xl
216
- },
217
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>