@umituz/react-native-ai-generation-content 1.17.11 → 1.17.12

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.17.11",
3
+ "version": "1.17.12",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -74,6 +74,7 @@ export type { ExecuteReplaceBackgroundOptions } from "./infrastructure";
74
74
 
75
75
  export {
76
76
  BackgroundFeature,
77
+ ReplaceBackgroundFeature,
77
78
  ImagePicker,
78
79
  PromptInput,
79
80
  GenerateButton,
@@ -85,7 +86,7 @@ export {
85
86
  ModeSelector,
86
87
  } from "./presentation/components";
87
88
 
88
- export type { BackgroundFeatureProps } from "./presentation/components";
89
+ export type { BackgroundFeatureProps, ReplaceBackgroundFeatureProps } from "./presentation/components";
89
90
 
90
91
  // =============================================================================
91
92
  // PRESENTATION LAYER - Hooks
@@ -0,0 +1,216 @@
1
+ /**
2
+ * ReplaceBackgroundFeature Component
3
+ * Self-contained background replacement feature UI component
4
+ * Uses hook internally, only requires config and translations
5
+ */
6
+
7
+ import React, { useCallback, useMemo } from "react";
8
+ import { View, ScrollView, StyleSheet, Image, Dimensions } from "react-native";
9
+ import {
10
+ useAppDesignTokens,
11
+ AtomicText,
12
+ AtomicButton,
13
+ AtomicTextInput,
14
+ } from "@umituz/react-native-design-system";
15
+ import { PhotoUploadCard } from "../../../../presentation/components/PhotoUploadCard";
16
+ import { ErrorDisplay } from "../../../../presentation/components/display/ErrorDisplay";
17
+ import { useReplaceBackgroundFeature } from "../hooks";
18
+ import type {
19
+ ReplaceBackgroundTranslations,
20
+ ReplaceBackgroundFeatureConfig,
21
+ } from "../../domain/types";
22
+
23
+ export interface ReplaceBackgroundFeatureProps {
24
+ config: ReplaceBackgroundFeatureConfig;
25
+ userId: string;
26
+ translations: ReplaceBackgroundTranslations;
27
+ onSelectImage: () => Promise<string | null>;
28
+ onSaveImage: (imageUrl: string) => Promise<void>;
29
+ renderProcessingModal?: (props: {
30
+ visible: boolean;
31
+ progress: number;
32
+ }) => React.ReactNode;
33
+ }
34
+
35
+ export const ReplaceBackgroundFeature: React.FC<ReplaceBackgroundFeatureProps> = ({
36
+ config,
37
+ userId,
38
+ translations,
39
+ onSelectImage,
40
+ onSaveImage,
41
+ renderProcessingModal,
42
+ }) => {
43
+ const tokens = useAppDesignTokens();
44
+
45
+ const feature = useReplaceBackgroundFeature({
46
+ config,
47
+ userId,
48
+ onSelectImage,
49
+ onSaveImage,
50
+ });
51
+
52
+ const photoTranslations = useMemo(
53
+ () => ({
54
+ tapToUpload: translations.uploadTitle,
55
+ selectPhoto: translations.uploadSubtitle,
56
+ change: translations.uploadChange,
57
+ analyzing: translations.uploadAnalyzing,
58
+ }),
59
+ [translations],
60
+ );
61
+
62
+ const handleProcess = useCallback(() => {
63
+ void feature.process();
64
+ }, [feature]);
65
+
66
+ const handleSave = useCallback(() => {
67
+ void feature.save();
68
+ }, [feature]);
69
+
70
+ const handleSelectImage = useCallback(() => {
71
+ void feature.selectImage();
72
+ }, [feature]);
73
+
74
+ if (feature.processedUrl) {
75
+ const screenWidth = Dimensions.get("window").width;
76
+ const imageSize = screenWidth - 48;
77
+
78
+ return (
79
+ <ScrollView
80
+ style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
81
+ contentContainerStyle={styles.content}
82
+ showsVerticalScrollIndicator={false}
83
+ >
84
+ <AtomicText
85
+ type="headlineMedium"
86
+ style={[styles.successText, { color: tokens.colors.success }]}
87
+ >
88
+ {translations.successText}
89
+ </AtomicText>
90
+
91
+ <View style={styles.resultImageContainer}>
92
+ <Image
93
+ source={{ uri: feature.processedUrl }}
94
+ style={[styles.resultImage, { width: imageSize, height: imageSize }]}
95
+ resizeMode="contain"
96
+ />
97
+ </View>
98
+
99
+ <View style={styles.resultActions}>
100
+ <AtomicButton
101
+ title={translations.saveButtonText}
102
+ onPress={handleSave}
103
+ variant="primary"
104
+ size="lg"
105
+ />
106
+ <AtomicButton
107
+ title={translations.tryAnotherText}
108
+ onPress={feature.reset}
109
+ variant="secondary"
110
+ size="lg"
111
+ />
112
+ </View>
113
+ </ScrollView>
114
+ );
115
+ }
116
+
117
+ return (
118
+ <>
119
+ <ScrollView
120
+ style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
121
+ contentContainerStyle={styles.content}
122
+ showsVerticalScrollIndicator={false}
123
+ >
124
+ <AtomicText
125
+ type="bodyLarge"
126
+ style={[styles.description, { color: tokens.colors.textSecondary }]}
127
+ >
128
+ {translations.description}
129
+ </AtomicText>
130
+
131
+ <PhotoUploadCard
132
+ imageUri={feature.imageUri}
133
+ onPress={handleSelectImage}
134
+ isValidating={feature.isProcessing}
135
+ disabled={feature.isProcessing}
136
+ translations={photoTranslations}
137
+ config={{
138
+ aspectRatio: 1,
139
+ borderRadius: 24,
140
+ showValidationStatus: false,
141
+ allowChange: true,
142
+ }}
143
+ />
144
+
145
+ <View style={styles.promptContainer}>
146
+ <AtomicTextInput
147
+ value={feature.prompt}
148
+ onChangeText={feature.setPrompt}
149
+ placeholder={translations.promptPlaceholder}
150
+ multiline
151
+ numberOfLines={3}
152
+ editable={!feature.isProcessing}
153
+ />
154
+ </View>
155
+
156
+ <ErrorDisplay error={feature.error} />
157
+
158
+ <View style={styles.buttonContainer}>
159
+ <AtomicButton
160
+ title={
161
+ feature.isProcessing
162
+ ? translations.processingText
163
+ : translations.processButtonText
164
+ }
165
+ onPress={handleProcess}
166
+ disabled={!feature.imageUri || feature.isProcessing}
167
+ variant="primary"
168
+ size="lg"
169
+ />
170
+ </View>
171
+ </ScrollView>
172
+
173
+ {renderProcessingModal?.({ visible: feature.isProcessing, progress: feature.progress })}
174
+ </>
175
+ );
176
+ };
177
+
178
+ const styles = StyleSheet.create({
179
+ container: {
180
+ flex: 1,
181
+ },
182
+ content: {
183
+ paddingVertical: 16,
184
+ },
185
+ description: {
186
+ textAlign: "center",
187
+ marginHorizontal: 24,
188
+ marginBottom: 24,
189
+ lineHeight: 24,
190
+ },
191
+ promptContainer: {
192
+ marginHorizontal: 24,
193
+ marginTop: 16,
194
+ marginBottom: 8,
195
+ },
196
+ successText: {
197
+ textAlign: "center",
198
+ marginBottom: 24,
199
+ },
200
+ resultImageContainer: {
201
+ alignItems: "center",
202
+ marginHorizontal: 24,
203
+ marginBottom: 24,
204
+ },
205
+ resultImage: {
206
+ borderRadius: 16,
207
+ },
208
+ resultActions: {
209
+ marginHorizontal: 24,
210
+ gap: 12,
211
+ },
212
+ buttonContainer: {
213
+ marginHorizontal: 24,
214
+ marginTop: 8,
215
+ },
216
+ });
@@ -5,6 +5,9 @@
5
5
  export { BackgroundFeature } from "./BackgroundFeature";
6
6
  export type { BackgroundFeatureProps } from "./BackgroundFeature";
7
7
 
8
+ export { ReplaceBackgroundFeature } from "./ReplaceBackgroundFeature";
9
+ export type { ReplaceBackgroundFeatureProps } from "./ReplaceBackgroundFeature";
10
+
8
11
  export { ImagePicker } from "./ImagePicker";
9
12
  export { PromptInput } from "./PromptInput";
10
13
  export { GenerateButton } from "./GenerateButton";