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