@umituz/react-native-ai-generation-content 1.17.144 → 1.17.145

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.
Files changed (28) hide show
  1. package/package.json +1 -1
  2. package/src/features/replace-background/index.ts +5 -50
  3. package/src/features/replace-background/presentation/components/index.ts +0 -12
  4. package/src/features/replace-background/presentation/hooks/index.ts +0 -3
  5. package/src/infrastructure/utils/index.ts +1 -0
  6. package/src/infrastructure/utils/result-validator.util.ts +0 -214
  7. package/src/infrastructure/utils/url-extractor.util.ts +209 -0
  8. package/src/presentation/hooks/flow-state.utils.ts +101 -0
  9. package/src/presentation/hooks/useGenerationFlow.ts +47 -178
  10. package/src/presentation/types/flow-config.types.ts +5 -99
  11. package/src/presentation/types/flow-default-configs.ts +106 -0
  12. package/src/features/replace-background/domain/entities/background.types.ts +0 -77
  13. package/src/features/replace-background/domain/entities/component.types.ts +0 -87
  14. package/src/features/replace-background/domain/entities/config.types.ts +0 -41
  15. package/src/features/replace-background/domain/entities/index.ts +0 -30
  16. package/src/features/replace-background/infrastructure/constants/index.ts +0 -5
  17. package/src/features/replace-background/infrastructure/constants/prompts.constants.ts +0 -15
  18. package/src/features/replace-background/infrastructure/index.ts +0 -5
  19. package/src/features/replace-background/presentation/components/BackgroundFeature.tsx +0 -143
  20. package/src/features/replace-background/presentation/components/ComparisonSlider.tsx +0 -187
  21. package/src/features/replace-background/presentation/components/ErrorDisplay.tsx +0 -60
  22. package/src/features/replace-background/presentation/components/FeatureHeader.tsx +0 -80
  23. package/src/features/replace-background/presentation/components/GenerateButton.tsx +0 -85
  24. package/src/features/replace-background/presentation/components/ImagePicker.tsx +0 -136
  25. package/src/features/replace-background/presentation/components/ModeSelector.tsx +0 -78
  26. package/src/features/replace-background/presentation/components/PromptInput.tsx +0 -142
  27. package/src/features/replace-background/presentation/components/ResultDisplay.tsx +0 -122
  28. package/src/features/replace-background/presentation/hooks/useBackgroundFeature.ts +0 -119
@@ -1,41 +0,0 @@
1
- /**
2
- * Configuration Types
3
- * @description Configuration interfaces for background feature
4
- */
5
-
6
- import type {
7
- BackgroundProcessRequest,
8
- BackgroundProcessResult,
9
- StudioMode,
10
- } from "./background.types";
11
-
12
- /**
13
- * Process request callback parameters
14
- */
15
- export interface ProcessRequestParams extends BackgroundProcessRequest {
16
- readonly onProgress?: (progress: number) => void;
17
- }
18
-
19
- /**
20
- * Background feature configuration
21
- */
22
- export interface BackgroundFeatureConfig {
23
- readonly onProcess: (
24
- params: ProcessRequestParams
25
- ) => Promise<BackgroundProcessResult>;
26
- readonly onSave?: (imageUrl: string) => Promise<void>;
27
- readonly onError?: (error: Error) => void;
28
- readonly onSuccess?: (result: BackgroundProcessResult) => void;
29
- readonly defaultMode?: StudioMode;
30
- }
31
-
32
- /**
33
- * Hook configuration
34
- */
35
- export interface UseBackgroundFeatureConfig {
36
- readonly processRequest: (
37
- params: ProcessRequestParams
38
- ) => Promise<BackgroundProcessResult>;
39
- readonly onSelectImage?: () => Promise<string | null>;
40
- readonly defaultMode?: StudioMode;
41
- }
@@ -1,30 +0,0 @@
1
- /**
2
- * Domain Entities Export
3
- */
4
-
5
- export type {
6
- BackgroundProcessRequest,
7
- BackgroundProcessResult,
8
- BackgroundFeatureState,
9
- SamplePrompt,
10
- StudioMode,
11
- StudioModeConfig,
12
- ComparisonState,
13
- } from "./background.types";
14
-
15
- export type {
16
- ImagePickerProps,
17
- PromptInputProps,
18
- GenerateButtonProps,
19
- ResultDisplayProps,
20
- ErrorDisplayProps,
21
- FeatureHeaderProps,
22
- ModeSelectorProps,
23
- ComparisonSliderProps,
24
- } from "./component.types";
25
-
26
- export type {
27
- ProcessRequestParams,
28
- BackgroundFeatureConfig,
29
- UseBackgroundFeatureConfig,
30
- } from "./config.types";
@@ -1,5 +0,0 @@
1
- /**
2
- * Infrastructure Constants Export
3
- */
4
-
5
- export { DEFAULT_SAMPLE_PROMPTS } from "./prompts.constants";
@@ -1,15 +0,0 @@
1
- /**
2
- * Default Sample Prompts
3
- * @description Default prompt suggestions for background replacement
4
- */
5
-
6
- import type { SamplePrompt } from "../../domain/entities";
7
-
8
- export const DEFAULT_SAMPLE_PROMPTS: readonly SamplePrompt[] = [
9
- { id: "beach", text: "Beach sunset with palm trees" },
10
- { id: "office", text: "Modern office with city view" },
11
- { id: "mountain", text: "Mountain landscape with snow" },
12
- { id: "living-room", text: "Cozy living room interior" },
13
- { id: "garden", text: "Japanese garden with cherry blossoms" },
14
- { id: "cityscape", text: "Futuristic cityscape at night" },
15
- ] as const;
@@ -1,5 +0,0 @@
1
- /**
2
- * Replace Background Infrastructure Export
3
- */
4
-
5
- export { DEFAULT_SAMPLE_PROMPTS } from "./constants";
@@ -1,143 +0,0 @@
1
- /**
2
- * Background Feature Component
3
- * @description Main feature component composing all sub-components
4
- */
5
-
6
- import * as React from "react";
7
- import { useCallback, useState } from "react";
8
- import { ScrollView, StyleSheet } from "react-native";
9
- import { useAppDesignTokens } from "@umituz/react-native-design-system";
10
- import type {
11
- BackgroundFeatureConfig,
12
- SamplePrompt,
13
- } from "../../domain/entities";
14
- import { ImagePicker } from "./ImagePicker";
15
- import { PromptInput } from "./PromptInput";
16
- import { GenerateButton } from "./GenerateButton";
17
- import { ResultDisplay } from "./ResultDisplay";
18
- import { ErrorDisplay } from "./ErrorDisplay";
19
- import { FeatureHeader } from "./FeatureHeader";
20
- import { useBackgroundFeature } from "../hooks";
21
- import type { ImageSourcePropType } from "react-native";
22
-
23
- export interface BackgroundFeatureProps {
24
- readonly config: BackgroundFeatureConfig;
25
- readonly onSelectImage: () => Promise<string | null>;
26
- readonly heroImage?: ImageSourcePropType;
27
- readonly description?: string;
28
- readonly promptLabel?: string;
29
- readonly promptPlaceholder?: string;
30
- readonly samplePrompts?: readonly SamplePrompt[];
31
- readonly samplePromptsLabel?: string;
32
- readonly generateButtonText?: string;
33
- readonly saveButtonText?: string;
34
- readonly resetButtonText?: string;
35
- readonly processingText?: string;
36
- readonly placeholderText?: string;
37
- readonly renderProcessingModal?: (props: { visible: boolean; progress: number; title?: string }) => React.ReactNode;
38
- }
39
-
40
- export const BackgroundFeature: React.FC<BackgroundFeatureProps> = ({
41
- config,
42
- onSelectImage,
43
- heroImage,
44
- description,
45
- promptLabel,
46
- promptPlaceholder,
47
- samplePrompts,
48
- samplePromptsLabel,
49
- generateButtonText,
50
- saveButtonText,
51
- resetButtonText,
52
- processingText,
53
- placeholderText,
54
- renderProcessingModal,
55
- }) => {
56
- const tokens = useAppDesignTokens();
57
- const [prompt, setPrompt] = useState("");
58
-
59
- const feature = useBackgroundFeature({
60
- processRequest: config.onProcess,
61
- onSelectImage,
62
- });
63
-
64
- const handleProcess = useCallback(async () => {
65
- await feature.process(prompt);
66
- if (feature.processedUrl && config.onSuccess) {
67
- config.onSuccess({
68
- success: true,
69
- imageUrl: feature.processedUrl,
70
- });
71
- }
72
- }, [feature, prompt, config]);
73
-
74
- const handleSave = useCallback(async () => {
75
- if (feature.processedUrl && config.onSave) {
76
- await config.onSave(feature.processedUrl);
77
- }
78
- }, [feature.processedUrl, config]);
79
-
80
- const handleReset = useCallback(() => {
81
- feature.reset();
82
- setPrompt("");
83
- }, [feature]);
84
-
85
- const isDisabled = !feature.imageUri || !prompt.trim();
86
-
87
- return (
88
- <>
89
- <ScrollView
90
- style={[styles.container, { padding: tokens.spacing.lg }]}
91
- showsVerticalScrollIndicator={false}
92
- >
93
- <FeatureHeader
94
- heroImage={heroImage}
95
- description={description}
96
- />
97
-
98
- <ImagePicker
99
- imageUri={feature.imageUri}
100
- isProcessing={feature.isProcessing}
101
- onSelectImage={() => { void feature.selectImage(); }}
102
- placeholderText={placeholderText}
103
- />
104
-
105
- <PromptInput
106
- value={prompt}
107
- onChangeText={setPrompt}
108
- isProcessing={feature.isProcessing}
109
- label={promptLabel}
110
- placeholder={promptPlaceholder}
111
- samplePrompts={samplePrompts}
112
- samplePromptsLabel={samplePromptsLabel}
113
- />
114
-
115
- <ErrorDisplay error={feature.error} />
116
-
117
- <ResultDisplay
118
- imageUrl={feature.processedUrl}
119
- isProcessing={feature.isProcessing}
120
- onSave={() => { void handleSave(); }}
121
- onReset={handleReset}
122
- saveButtonText={saveButtonText}
123
- resetButtonText={resetButtonText}
124
- />
125
-
126
- <GenerateButton
127
- isDisabled={isDisabled}
128
- isProcessing={feature.isProcessing}
129
- onPress={() => { void handleProcess(); }}
130
- buttonText={generateButtonText}
131
- />
132
- </ScrollView>
133
-
134
- {renderProcessingModal?.({ visible: feature.isProcessing, progress: feature.progress, title: processingText })}
135
- </>
136
- );
137
- };
138
-
139
- const styles = StyleSheet.create({
140
- container: {
141
- flex: 1,
142
- },
143
- });
@@ -1,187 +0,0 @@
1
- /**
2
- * Comparison Slider Component
3
- * @description Before/After comparison slider for images
4
- */
5
-
6
- import * as React from "react";
7
- import { memo, useState, useRef, useMemo } from "react";
8
- import { View, StyleSheet, Image, PanResponder } from "react-native";
9
- import {
10
- AtomicText,
11
- useAppDesignTokens,
12
- useResponsive,
13
- } from "@umituz/react-native-design-system";
14
- import type { ComparisonSliderProps } from "../../domain/entities";
15
-
16
- export const ComparisonSlider: React.FC<ComparisonSliderProps> = memo(
17
- function ComparisonSlider({
18
- originalUri,
19
- processedUri,
20
- beforeLabel,
21
- afterLabel,
22
- }) {
23
- const tokens = useAppDesignTokens();
24
- const { width: screenWidth, horizontalPadding } = useResponsive();
25
- const [sliderPosition, setSliderPosition] = useState(50);
26
- const containerWidth = useRef(screenWidth - horizontalPadding * 2);
27
-
28
- const panResponder = useRef(
29
- PanResponder.create({
30
- onStartShouldSetPanResponder: () => true,
31
- onMoveShouldSetPanResponder: () => true,
32
- onPanResponderMove: (_, gestureState) => {
33
- const newPosition =
34
- ((gestureState.moveX - 16) / containerWidth.current) * 100;
35
- setSliderPosition(Math.max(0, Math.min(100, newPosition)));
36
- },
37
- })
38
- ).current;
39
-
40
- const themedStyles = useMemo(() => StyleSheet.create({
41
- container: {
42
- width: "100%",
43
- aspectRatio: 1,
44
- borderRadius: 20,
45
- overflow: "hidden",
46
- },
47
- originalContainer: {
48
- position: "absolute",
49
- top: 0,
50
- left: 0,
51
- bottom: 0,
52
- overflow: "hidden",
53
- borderRightWidth: 2,
54
- borderRightColor: tokens.colors.surface,
55
- },
56
- sliderHandle: {
57
- position: "absolute",
58
- top: "50%",
59
- left: -20,
60
- width: 40,
61
- height: 40,
62
- borderRadius: 20,
63
- justifyContent: "center",
64
- alignItems: "center",
65
- marginTop: -20,
66
- backgroundColor: tokens.colors.backgroundPrimary,
67
- },
68
- labelLeft: {
69
- backgroundColor: tokens.colors.surface,
70
- },
71
- labelRight: {
72
- backgroundColor: tokens.colors.primary,
73
- }
74
- }), [tokens]);
75
-
76
- return (
77
- <View
78
- style={themedStyles.container}
79
- onLayout={(e) => {
80
- containerWidth.current = e.nativeEvent.layout.width;
81
- }}
82
- >
83
- <View style={styles.imageContainer}>
84
- <Image
85
- source={{ uri: processedUri }}
86
- style={styles.image}
87
- resizeMode="cover"
88
- />
89
-
90
- <View
91
- style={[themedStyles.originalContainer, { width: `${sliderPosition}%` }]}
92
- >
93
- <Image
94
- source={{ uri: originalUri }}
95
- style={[styles.image, { width: containerWidth.current }]}
96
- resizeMode="cover"
97
- />
98
- </View>
99
-
100
- <View
101
- style={[styles.sliderLine, { left: `${sliderPosition}%` }]}
102
- {...panResponder.panHandlers}
103
- >
104
- <View style={themedStyles.sliderHandle}>
105
- <View style={styles.handleBars}>
106
- <View
107
- style={[
108
- styles.handleBar,
109
- { backgroundColor: tokens.colors.primary },
110
- ]}
111
- />
112
- <View
113
- style={[
114
- styles.handleBar,
115
- { backgroundColor: tokens.colors.primary },
116
- ]}
117
- />
118
- </View>
119
- </View>
120
- </View>
121
-
122
- {beforeLabel && (
123
- <View style={[styles.label, styles.labelLeft, themedStyles.labelLeft]}>
124
- <AtomicText
125
-
126
-
127
- >
128
- {beforeLabel}
129
- </AtomicText>
130
- </View>
131
- )}
132
-
133
- {afterLabel && (
134
- <View style={[styles.label, styles.labelRight, themedStyles.labelRight]}>
135
- <AtomicText
136
-
137
-
138
- >
139
- {afterLabel}
140
- </AtomicText>
141
- </View>
142
- )}
143
- </View>
144
- </View>
145
- );
146
- }
147
- );
148
-
149
- const styles = StyleSheet.create({
150
- imageContainer: {
151
- flex: 1,
152
- position: "relative",
153
- },
154
- image: {
155
- width: "100%",
156
- height: "100%",
157
- },
158
- sliderLine: {
159
- position: "absolute",
160
- top: 0,
161
- bottom: 0,
162
- width: 2,
163
- marginLeft: -1,
164
- },
165
- handleBars: {
166
- flexDirection: "row",
167
- gap: 4,
168
- },
169
- handleBar: {
170
- width: 3,
171
- height: 16,
172
- borderRadius: 2,
173
- },
174
- label: {
175
- position: "absolute",
176
- top: 12,
177
- paddingHorizontal: 8,
178
- paddingVertical: 4,
179
- borderRadius: 12,
180
- },
181
- labelLeft: {
182
- left: 12,
183
- },
184
- labelRight: {
185
- right: 12,
186
- },
187
- });
@@ -1,60 +0,0 @@
1
- /**
2
- * Error Display Component
3
- * @description Displays error messages
4
- */
5
-
6
- import * as React from "react";
7
- import { memo } from "react";
8
- import { View, StyleSheet } from "react-native";
9
- import {
10
- AtomicText,
11
- AtomicIcon,
12
- useAppDesignTokens,
13
- } from "@umituz/react-native-design-system";
14
- import type { ErrorDisplayProps } from "../../domain/entities";
15
-
16
- export const ErrorDisplay: React.FC<ErrorDisplayProps> = memo(
17
- function ErrorDisplay({ error }) {
18
- const tokens = useAppDesignTokens();
19
-
20
- if (!error) {
21
- return null;
22
- }
23
-
24
- return (
25
- <View
26
- style={[
27
- styles.container,
28
- { backgroundColor: tokens.colors.errorContainer },
29
- ]}
30
- >
31
- <AtomicIcon
32
- name="alert-circle"
33
- size="sm"
34
-
35
- />
36
- <AtomicText
37
-
38
-
39
- style={styles.errorText}
40
- >
41
- {error}
42
- </AtomicText>
43
- </View>
44
- );
45
- }
46
- );
47
-
48
- const styles = StyleSheet.create({
49
- container: {
50
- flexDirection: "row",
51
- alignItems: "center",
52
- gap: 12,
53
- padding: 16,
54
- borderRadius: 12,
55
- marginVertical: 12,
56
- },
57
- errorText: {
58
- flex: 1,
59
- },
60
- });
@@ -1,80 +0,0 @@
1
- /**
2
- * Feature Header Component
3
- * @description Header with hero image and description
4
- */
5
-
6
- import React, { memo } from "react";
7
- import { View, StyleSheet, Image, Dimensions } from "react-native";
8
- import {
9
- AtomicText,
10
- useAppDesignTokens,
11
- } from "@umituz/react-native-design-system";
12
- import type { FeatureHeaderProps } from "../../domain/entities";
13
-
14
- const { width: SCREEN_WIDTH } = Dimensions.get("window");
15
- const IMAGE_WIDTH = SCREEN_WIDTH - 32;
16
- const IMAGE_HEIGHT = IMAGE_WIDTH * 0.5;
17
-
18
- export const FeatureHeader: React.FC<FeatureHeaderProps> = memo(
19
- function FeatureHeader({ heroImage, description }) {
20
- const tokens = useAppDesignTokens();
21
-
22
- if (!heroImage && !description) {
23
- return null;
24
- }
25
-
26
- return (
27
- <View style={styles.container}>
28
- {heroImage && (
29
- <View
30
- style={[
31
- styles.imageContainer,
32
- { backgroundColor: tokens.colors.surface },
33
- ]}
34
- >
35
- <Image
36
- source={heroImage}
37
- style={[
38
- styles.heroImage,
39
- { width: IMAGE_WIDTH, height: IMAGE_HEIGHT },
40
- ]}
41
- resizeMode="cover"
42
- />
43
- </View>
44
- )}
45
- {description && (
46
- <AtomicText
47
-
48
- style={[
49
- styles.description,
50
- {
51
- color: tokens.colors.textSecondary,
52
- marginTop: tokens.spacing.md,
53
- },
54
- ]}
55
- >
56
- {description}
57
- </AtomicText>
58
- )}
59
- </View>
60
- );
61
- }
62
- );
63
-
64
- const styles = StyleSheet.create({
65
- container: {
66
- marginBottom: 8,
67
- },
68
- imageContainer: {
69
- borderRadius: 16,
70
- overflow: "hidden",
71
- },
72
- heroImage: {
73
- borderRadius: 16,
74
- },
75
- description: {
76
- textAlign: "center",
77
- lineHeight: 22,
78
- paddingHorizontal: 8,
79
- },
80
- });
@@ -1,85 +0,0 @@
1
- /**
2
- * Generate Button Component
3
- * @description Action button to trigger processing
4
- */
5
-
6
- import React, { memo } from "react";
7
- import { StyleSheet, TouchableOpacity } from "react-native";
8
- import {
9
- AtomicText,
10
- AtomicIcon,
11
- AtomicSpinner,
12
- useAppDesignTokens,
13
- } from "@umituz/react-native-design-system";
14
- import type { GenerateButtonProps } from "../../domain/entities";
15
-
16
- export const GenerateButton: React.FC<GenerateButtonProps> = memo(
17
- function GenerateButton({
18
- isDisabled,
19
- isProcessing,
20
- onPress,
21
- buttonText,
22
- }) {
23
- const tokens = useAppDesignTokens();
24
-
25
- const disabled = isDisabled || isProcessing;
26
-
27
- return (
28
- <TouchableOpacity
29
- onPress={onPress}
30
- disabled={disabled}
31
- activeOpacity={0.8}
32
- style={[
33
- styles.container,
34
- {
35
- backgroundColor: disabled
36
- ? tokens.colors.surfaceSecondary
37
- : tokens.colors.primary,
38
- },
39
- ]}
40
- >
41
- {isProcessing ? (
42
- <AtomicSpinner size="sm" color={tokens.colors.backgroundPrimary} />
43
- ) : (
44
- <>
45
- <AtomicIcon
46
- name="sparkles"
47
- size="md"
48
- color={disabled ? "surfaceVariant" : "onPrimary"}
49
- />
50
- <AtomicText
51
- style={[
52
- styles.text,
53
- {
54
- color: disabled
55
- ? tokens.colors.textTertiary
56
- : tokens.colors.backgroundPrimary,
57
- },
58
- ]}
59
- >
60
- {buttonText}
61
- </AtomicText>
62
- </>
63
- )}
64
- </TouchableOpacity>
65
- );
66
- }
67
- );
68
-
69
- const styles = StyleSheet.create({
70
- container: {
71
- marginVertical: 24,
72
- borderRadius: 28,
73
- flexDirection: "row",
74
- alignItems: "center",
75
- justifyContent: "center",
76
- paddingVertical: 16,
77
- paddingHorizontal: 32,
78
- },
79
- icon: {
80
- marginRight: 8,
81
- },
82
- text: {
83
- fontWeight: "bold",
84
- },
85
- });