@umituz/react-native-ai-generation-content 1.83.41 → 1.83.43

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.83.41",
3
+ "version": "1.83.43",
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",
@@ -23,7 +23,7 @@ interface GalleryEmptyStatesProps {
23
23
  }
24
24
 
25
25
  /** Skeleton card matching CreationCard layout */
26
- function CreationCardSkeleton({ tokens }: { tokens: DesignTokens }) {
26
+ const CreationCardSkeleton: React.FC<{ tokens: DesignTokens }> = ({ tokens }) => {
27
27
  const styles = createSkeletonStyles(tokens);
28
28
  return (
29
29
  <View style={styles.card}>
@@ -52,7 +52,7 @@ function CreationCardSkeleton({ tokens }: { tokens: DesignTokens }) {
52
52
  );
53
53
  }
54
54
 
55
- export function GalleryEmptyStates({
55
+ export const GalleryEmptyStates: React.FC<GalleryEmptyStatesProps> = ({
56
56
  isLoading,
57
57
  creations,
58
58
  isFiltered,
@@ -63,7 +63,7 @@ export function GalleryEmptyStates({
63
63
  emptyActionLabel,
64
64
  onEmptyAction,
65
65
  onClearFilters,
66
- }: GalleryEmptyStatesProps) {
66
+ }) => {
67
67
  const styles = createStyles(tokens);
68
68
 
69
69
  // 1. Loading State - Show skeleton cards
@@ -69,10 +69,22 @@ export function useCreations({
69
69
  setIsLoading(true);
70
70
  setError(null);
71
71
 
72
- const unsubscribe = repository.subscribeToAll(userId, onDataCallback, onErrorCallback);
72
+ let timeoutId: ReturnType<typeof setTimeout>;
73
+
74
+ const handleData = (creations: Creation[]) => {
75
+ clearTimeout(timeoutId);
76
+ onDataCallback(creations);
77
+ };
78
+
79
+ const handleError = (err: Error) => {
80
+ clearTimeout(timeoutId);
81
+ onErrorCallback(err);
82
+ };
83
+
84
+ const unsubscribe = repository.subscribeToAll(userId, handleData, handleError);
73
85
 
74
86
  // Fallback timeout: if Firestore doesn't respond in 10s, stop loading
75
- const timeoutId = setTimeout(() => {
87
+ timeoutId = setTimeout(() => {
76
88
  if (!isMounted) return;
77
89
  if (typeof __DEV__ !== "undefined" && __DEV__) {
78
90
  console.warn("[useCreations] Loading timeout - setting empty state");
@@ -19,12 +19,12 @@ interface GridImageItemProps {
19
19
  onRemove: () => void;
20
20
  }
21
21
 
22
- export function GridImageItem({
22
+ export const GridImageItem: React.FC<GridImageItemProps> = ({
23
23
  styles,
24
24
  uri,
25
25
  index,
26
26
  onRemove,
27
- }: GridImageItemProps) {
27
+ }) => {
28
28
  const tokens = useAppDesignTokens();
29
29
 
30
30
  return (
@@ -24,7 +24,6 @@ export interface CategoryNavigationContainerProps {
24
24
  readonly t: (key: string) => string;
25
25
  readonly headerTitle?: string;
26
26
  readonly headerDescription?: string;
27
- readonly numColumns?: number;
28
27
  readonly isLoading?: boolean;
29
28
  }
30
29
 
@@ -41,7 +40,6 @@ export const CategoryNavigationContainer: React.FC<
41
40
  t,
42
41
  headerTitle,
43
42
  headerDescription,
44
- numColumns = 2,
45
43
  isLoading = false,
46
44
  }) => {
47
45
  const [currentStep, setCurrentStep] = useState<NavigationStep>("main_category");
@@ -107,7 +105,6 @@ export const CategoryNavigationContainer: React.FC<
107
105
  onSelectScenario={onSelectScenario}
108
106
  onBack={handleBackFromScenarioList}
109
107
  t={t}
110
- numColumns={numColumns}
111
108
  isLoading={isLoading}
112
109
  />
113
110
  );
@@ -9,7 +9,6 @@ import {
9
9
  AtomicText,
10
10
  AtomicCard,
11
11
  useAppDesignTokens,
12
- useResponsive,
13
12
  ScreenLayout,
14
13
  NavigationHeader,
15
14
  AtomicSpinner,
@@ -28,7 +27,6 @@ interface HierarchicalScenarioListScreenProps {
28
27
  readonly onSelectScenario: (scenarioId: string) => void;
29
28
  readonly onBack: () => void;
30
29
  readonly t: (key: string) => string;
31
- readonly numColumns?: number;
32
30
  readonly isLoading?: boolean;
33
31
  }
34
32
 
@@ -39,12 +37,10 @@ export const HierarchicalScenarioListScreen: React.FC<HierarchicalScenarioListSc
39
37
  onSelectScenario,
40
38
  onBack,
41
39
  t,
42
- numColumns = 2,
43
40
  isLoading = false,
44
41
  }) => {
45
42
  const tokens = useAppDesignTokens();
46
43
  const insets = useSafeAreaInsets();
47
- const { width } = useResponsive();
48
44
  const [selectedId, setSelectedId] = useState<string | null>(null);
49
45
 
50
46
  const { subCategory, filteredScenarios } = useHierarchicalScenarios({
@@ -56,14 +52,9 @@ export const HierarchicalScenarioListScreen: React.FC<HierarchicalScenarioListSc
56
52
  const horizontalPadding = tokens.spacing.md;
57
53
  const cardSpacing = tokens.spacing.md;
58
54
 
59
- const cardWidth = useMemo(() => {
60
- const availableWidth = width - horizontalPadding * 2 - cardSpacing;
61
- return availableWidth / numColumns;
62
- }, [width, horizontalPadding, cardSpacing, numColumns]);
63
-
64
55
  const styles = useMemo(
65
- () => createStyles(tokens, cardSpacing, horizontalPadding),
66
- [tokens, cardSpacing, horizontalPadding]
56
+ () => createStyles(tokens, cardSpacing),
57
+ [tokens, cardSpacing]
67
58
  );
68
59
 
69
60
  const handleContinue = useCallback(() => {
@@ -82,12 +73,12 @@ export const HierarchicalScenarioListScreen: React.FC<HierarchicalScenarioListSc
82
73
  subtitle={t(`scenario.${item.id}.description`)}
83
74
  imageAspectRatio={1.25}
84
75
  selected={selectedId === item.id}
85
- style={{ width: cardWidth }}
76
+ style={{ width: "100%" }}
86
77
  onPress={() => handleCardPress(item.id)}
87
78
  testID={`scenario-card-${item.id}`}
88
79
  />
89
80
  ),
90
- [cardWidth, selectedId, t, handleCardPress]
81
+ [selectedId, t, handleCardPress]
91
82
  );
92
83
 
93
84
  const ListEmptyComponent = useMemo(
@@ -131,13 +122,14 @@ export const HierarchicalScenarioListScreen: React.FC<HierarchicalScenarioListSc
131
122
  <ScreenLayout scrollable={false} edges={["left", "right"]} backgroundColor={tokens.colors.backgroundPrimary}>
132
123
  <FlatList
133
124
  data={filteredScenarios}
134
- numColumns={numColumns}
135
125
  showsVerticalScrollIndicator={false}
136
- columnWrapperStyle={styles.row}
137
126
  renderItem={renderItem}
138
127
  keyExtractor={(item) => item.id}
139
128
  ListEmptyComponent={isLoading ? LoadingComponent : (filteredScenarios.length === 0 ? ListEmptyComponent : null)}
140
- contentContainerStyle={[styles.listContent, { paddingBottom: insets.bottom + 100 }]}
129
+ contentContainerStyle={[
130
+ styles.listContent,
131
+ { paddingHorizontal: horizontalPadding, paddingBottom: insets.bottom + 100 }
132
+ ]}
141
133
  removeClippedSubviews
142
134
  maxToRenderPerBatch={10}
143
135
  updateCellsBatchingPeriod={50}
@@ -149,11 +141,10 @@ export const HierarchicalScenarioListScreen: React.FC<HierarchicalScenarioListSc
149
141
  );
150
142
  };
151
143
 
152
- const createStyles = (tokens: DesignTokens, cardSpacing: number, horizontalPadding: number) =>
144
+ const createStyles = (tokens: DesignTokens, cardSpacing: number) =>
153
145
  StyleSheet.create({
154
146
  container: { flex: 1 },
155
- listContent: { paddingTop: tokens.spacing.sm, flexGrow: 1 },
156
- row: { gap: cardSpacing, marginBottom: cardSpacing, paddingHorizontal: horizontalPadding },
147
+ listContent: { paddingTop: tokens.spacing.sm, gap: cardSpacing, flexGrow: 1 },
157
148
  emptyState: { flex: 1, justifyContent: "center", alignItems: "center", paddingVertical: tokens.spacing.xl },
158
149
  loadingContainer: { flex: 1, justifyContent: "center", alignItems: "center", paddingVertical: tokens.spacing.xl },
159
150
  });
@@ -40,6 +40,9 @@ export const ScenarioPreviewScreen: React.FC<ScenarioPreviewScreenProps> = ({
40
40
  const tokens = useAppDesignTokens();
41
41
  const styles = useMemo(() => createStyles(tokens), [tokens]);
42
42
 
43
+ const rawImage = scenario.previewImageUrl || scenario.imageUrl;
44
+ const isNetworkUrl = typeof rawImage === "string";
45
+
43
46
  return (
44
47
  <View style={{ flex: 1, backgroundColor: tokens.colors.backgroundPrimary }}>
45
48
  <NavigationHeader
@@ -61,7 +64,8 @@ export const ScenarioPreviewScreen: React.FC<ScenarioPreviewScreenProps> = ({
61
64
  >
62
65
  <HeroSection
63
66
  icon={scenario.icon}
64
- imageUrl={scenario.imageUrl ?? scenario.previewImageUrl}
67
+ imageUrl={isNetworkUrl ? rawImage : undefined}
68
+ imageSource={!isNetworkUrl && rawImage ? rawImage : undefined}
65
69
  />
66
70
 
67
71
  <View style={styles.contentSection}>
@@ -75,7 +79,7 @@ export const ScenarioPreviewScreen: React.FC<ScenarioPreviewScreenProps> = ({
75
79
 
76
80
  <View style={styles.infoCard}>
77
81
  <View style={styles.infoHeader}>
78
- <AtomicIcon name="information-circle" size="sm" color="primary" />
82
+ <AtomicIcon name="info" size="sm" color="primary" />
79
83
  <AtomicText style={styles.infoTitle}>
80
84
  {translations.whatToExpect}
81
85
  </AtomicText>
@@ -40,7 +40,7 @@ const DEFAULT_STATUS_LABELS: StatusLabels = {
40
40
  failed: "Failed",
41
41
  };
42
42
 
43
- export function PendingJobCard<TInput = unknown, TResult = unknown>({
43
+ export const PendingJobCard: React.FC<PendingJobCardProps<any, any>> = ({
44
44
  job,
45
45
  onCancel,
46
46
  onRetry,
@@ -48,7 +48,7 @@ export function PendingJobCard<TInput = unknown, TResult = unknown>({
48
48
  statusLabels = DEFAULT_STATUS_LABELS,
49
49
  renderThumbnail,
50
50
  renderActions,
51
- }: PendingJobCardProps<TInput, TResult>): React.ReactElement {
51
+ }) => {
52
52
  const tokens = useAppDesignTokens();
53
53
  const isFailed = job.status === "failed";
54
54
 
@@ -92,7 +92,7 @@ export const AIGenScreenHeader: React.FC<AIGenScreenHeaderProps> = ({
92
92
  const styles = StyleSheet.create({
93
93
  header: {
94
94
  paddingHorizontal: 16,
95
- paddingTop: 60,
95
+ paddingTop: 16,
96
96
  width: "100%",
97
97
  marginBottom: 24,
98
98
  },