@umituz/react-native-ai-generation-content 1.17.28 → 1.17.30
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 +1 -1
- package/src/index.ts +23 -0
- package/src/presentation/components/index.ts +1 -0
- package/src/presentation/components/selectors/AspectRatioSelector.tsx +105 -0
- package/src/presentation/components/selectors/DurationSelector.tsx +98 -0
- package/src/presentation/components/selectors/StyleSelector.tsx +131 -0
- package/src/presentation/components/selectors/index.ts +18 -0
- package/src/presentation/components/selectors/types.ts +32 -0
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -121,6 +121,10 @@ export {
|
|
|
121
121
|
createJobPoller,
|
|
122
122
|
generationWrapper,
|
|
123
123
|
createGenerationWrapper,
|
|
124
|
+
executeImageFeature,
|
|
125
|
+
hasImageFeatureSupport,
|
|
126
|
+
executeVideoFeature,
|
|
127
|
+
hasVideoFeatureSupport,
|
|
124
128
|
} from "./infrastructure/services";
|
|
125
129
|
|
|
126
130
|
export type {
|
|
@@ -128,6 +132,14 @@ export type {
|
|
|
128
132
|
PollJobOptions,
|
|
129
133
|
PollJobResult,
|
|
130
134
|
WrapperConfig,
|
|
135
|
+
ImageResultExtractor,
|
|
136
|
+
ExecuteImageFeatureOptions,
|
|
137
|
+
ImageFeatureResult,
|
|
138
|
+
ImageFeatureRequest,
|
|
139
|
+
VideoResultExtractor,
|
|
140
|
+
ExecuteVideoFeatureOptions,
|
|
141
|
+
VideoFeatureResult,
|
|
142
|
+
VideoFeatureRequest,
|
|
131
143
|
} from "./infrastructure/services";
|
|
132
144
|
|
|
133
145
|
// =============================================================================
|
|
@@ -275,6 +287,10 @@ export {
|
|
|
275
287
|
FeatureHeader,
|
|
276
288
|
// Photo Upload
|
|
277
289
|
PhotoUploadCard,
|
|
290
|
+
// Selectors
|
|
291
|
+
StyleSelector,
|
|
292
|
+
AspectRatioSelector,
|
|
293
|
+
DurationSelector,
|
|
278
294
|
} from "./presentation/components";
|
|
279
295
|
|
|
280
296
|
export type {
|
|
@@ -314,6 +330,13 @@ export type {
|
|
|
314
330
|
// Photo Upload
|
|
315
331
|
PhotoUploadCardProps,
|
|
316
332
|
PhotoUploadCardConfig,
|
|
333
|
+
// Selectors
|
|
334
|
+
StyleSelectorProps,
|
|
335
|
+
AspectRatioSelectorProps,
|
|
336
|
+
DurationSelectorProps,
|
|
337
|
+
StyleOption,
|
|
338
|
+
AspectRatioOption,
|
|
339
|
+
DurationValue,
|
|
317
340
|
} from "./presentation/components";
|
|
318
341
|
|
|
319
342
|
// =============================================================================
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aspect Ratio Selector Component
|
|
3
|
+
* Generic, props-driven aspect ratio selection
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
8
|
+
import {
|
|
9
|
+
AtomicText,
|
|
10
|
+
AtomicIcon,
|
|
11
|
+
useAppDesignTokens,
|
|
12
|
+
} from "@umituz/react-native-design-system";
|
|
13
|
+
import type { AspectRatioOption } from "./types";
|
|
14
|
+
|
|
15
|
+
export interface AspectRatioSelectorProps {
|
|
16
|
+
ratios: AspectRatioOption[];
|
|
17
|
+
selectedRatio: "16:9" | "9:16" | "1:1";
|
|
18
|
+
onRatioSelect: (ratio: "16:9" | "9:16" | "1:1") => void;
|
|
19
|
+
title: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const AspectRatioSelector: React.FC<AspectRatioSelectorProps> = ({
|
|
23
|
+
ratios,
|
|
24
|
+
selectedRatio,
|
|
25
|
+
onRatioSelect,
|
|
26
|
+
title,
|
|
27
|
+
}) => {
|
|
28
|
+
const tokens = useAppDesignTokens();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View style={componentStyles.section}>
|
|
32
|
+
<AtomicText
|
|
33
|
+
type="bodyMedium"
|
|
34
|
+
style={{
|
|
35
|
+
color: tokens.colors.textPrimary,
|
|
36
|
+
fontWeight: "600",
|
|
37
|
+
marginBottom: 12,
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
{title}
|
|
41
|
+
</AtomicText>
|
|
42
|
+
<View style={componentStyles.aspectRatioGrid}>
|
|
43
|
+
{ratios.map((ratio) => (
|
|
44
|
+
<TouchableOpacity
|
|
45
|
+
key={ratio.id}
|
|
46
|
+
style={[
|
|
47
|
+
componentStyles.aspectRatioCard,
|
|
48
|
+
{
|
|
49
|
+
backgroundColor:
|
|
50
|
+
selectedRatio === ratio.id
|
|
51
|
+
? tokens.colors.primary + "20"
|
|
52
|
+
: tokens.colors.surface,
|
|
53
|
+
borderColor:
|
|
54
|
+
selectedRatio === ratio.id
|
|
55
|
+
? tokens.colors.primary
|
|
56
|
+
: tokens.colors.borderLight,
|
|
57
|
+
},
|
|
58
|
+
]}
|
|
59
|
+
onPress={() => onRatioSelect(ratio.id)}
|
|
60
|
+
>
|
|
61
|
+
<AtomicIcon
|
|
62
|
+
name={ratio.icon as never}
|
|
63
|
+
size="lg"
|
|
64
|
+
color={selectedRatio === ratio.id ? "primary" : "secondary"}
|
|
65
|
+
/>
|
|
66
|
+
<AtomicText
|
|
67
|
+
type="bodySmall"
|
|
68
|
+
style={{
|
|
69
|
+
color: tokens.colors.textPrimary,
|
|
70
|
+
fontWeight: selectedRatio === ratio.id ? "600" : "400",
|
|
71
|
+
marginTop: 8,
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
{ratio.name}
|
|
75
|
+
</AtomicText>
|
|
76
|
+
<AtomicText
|
|
77
|
+
type="labelSmall"
|
|
78
|
+
style={{ color: tokens.colors.textSecondary, marginTop: 2 }}
|
|
79
|
+
>
|
|
80
|
+
{ratio.description}
|
|
81
|
+
</AtomicText>
|
|
82
|
+
</TouchableOpacity>
|
|
83
|
+
))}
|
|
84
|
+
</View>
|
|
85
|
+
</View>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const componentStyles = StyleSheet.create({
|
|
90
|
+
section: {
|
|
91
|
+
padding: 16,
|
|
92
|
+
marginBottom: 8,
|
|
93
|
+
},
|
|
94
|
+
aspectRatioGrid: {
|
|
95
|
+
flexDirection: "row",
|
|
96
|
+
gap: 12,
|
|
97
|
+
},
|
|
98
|
+
aspectRatioCard: {
|
|
99
|
+
flex: 1,
|
|
100
|
+
padding: 16,
|
|
101
|
+
borderRadius: 12,
|
|
102
|
+
borderWidth: 2,
|
|
103
|
+
alignItems: "center",
|
|
104
|
+
},
|
|
105
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duration Selector Component
|
|
3
|
+
* Generic, props-driven duration selection for video/audio generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
8
|
+
import {
|
|
9
|
+
AtomicText,
|
|
10
|
+
useAppDesignTokens,
|
|
11
|
+
} from "@umituz/react-native-design-system";
|
|
12
|
+
import type { DurationValue } from "./types";
|
|
13
|
+
|
|
14
|
+
export interface DurationSelectorProps<T extends DurationValue> {
|
|
15
|
+
duration: T;
|
|
16
|
+
durationOptions: readonly T[];
|
|
17
|
+
onDurationSelect: (duration: T) => void;
|
|
18
|
+
title: string;
|
|
19
|
+
formatLabel?: (duration: T) => string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function DurationSelector<T extends DurationValue>({
|
|
23
|
+
duration,
|
|
24
|
+
durationOptions,
|
|
25
|
+
onDurationSelect,
|
|
26
|
+
title,
|
|
27
|
+
formatLabel = (d) => `${d}s`,
|
|
28
|
+
}: DurationSelectorProps<T>): React.ReactElement {
|
|
29
|
+
const tokens = useAppDesignTokens();
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<View style={componentStyles.section}>
|
|
33
|
+
<AtomicText
|
|
34
|
+
type="bodyMedium"
|
|
35
|
+
style={{
|
|
36
|
+
color: tokens.colors.textPrimary,
|
|
37
|
+
fontWeight: "600",
|
|
38
|
+
marginBottom: 12,
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
{title}
|
|
42
|
+
</AtomicText>
|
|
43
|
+
<View style={componentStyles.durationGrid}>
|
|
44
|
+
{durationOptions.map((sec) => (
|
|
45
|
+
<TouchableOpacity
|
|
46
|
+
key={sec}
|
|
47
|
+
style={[
|
|
48
|
+
componentStyles.durationButton,
|
|
49
|
+
{
|
|
50
|
+
backgroundColor:
|
|
51
|
+
duration === sec
|
|
52
|
+
? tokens.colors.primary
|
|
53
|
+
: tokens.colors.surface,
|
|
54
|
+
borderColor:
|
|
55
|
+
duration === sec
|
|
56
|
+
? tokens.colors.primary
|
|
57
|
+
: tokens.colors.borderLight,
|
|
58
|
+
},
|
|
59
|
+
]}
|
|
60
|
+
onPress={() => onDurationSelect(sec)}
|
|
61
|
+
>
|
|
62
|
+
<AtomicText
|
|
63
|
+
type="bodyLarge"
|
|
64
|
+
style={{
|
|
65
|
+
color:
|
|
66
|
+
duration === sec
|
|
67
|
+
? tokens.colors.textInverse
|
|
68
|
+
: tokens.colors.textPrimary,
|
|
69
|
+
fontWeight: duration === sec ? "700" : "400",
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
{formatLabel(sec)}
|
|
73
|
+
</AtomicText>
|
|
74
|
+
</TouchableOpacity>
|
|
75
|
+
))}
|
|
76
|
+
</View>
|
|
77
|
+
</View>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const componentStyles = StyleSheet.create({
|
|
82
|
+
section: {
|
|
83
|
+
padding: 16,
|
|
84
|
+
marginBottom: 8,
|
|
85
|
+
},
|
|
86
|
+
durationGrid: {
|
|
87
|
+
flexDirection: "row",
|
|
88
|
+
gap: 12,
|
|
89
|
+
},
|
|
90
|
+
durationButton: {
|
|
91
|
+
flex: 1,
|
|
92
|
+
paddingVertical: 20,
|
|
93
|
+
borderRadius: 12,
|
|
94
|
+
borderWidth: 2,
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
justifyContent: "center",
|
|
97
|
+
},
|
|
98
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Style Selector Component
|
|
3
|
+
* Generic, props-driven style selection for AI generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { View, ScrollView, TouchableOpacity, StyleSheet } from "react-native";
|
|
8
|
+
import {
|
|
9
|
+
AtomicText,
|
|
10
|
+
AtomicIcon,
|
|
11
|
+
useAppDesignTokens,
|
|
12
|
+
} from "@umituz/react-native-design-system";
|
|
13
|
+
import type { StyleOption } from "./types";
|
|
14
|
+
|
|
15
|
+
export interface StyleSelectorProps {
|
|
16
|
+
styles: StyleOption[];
|
|
17
|
+
selectedStyle: string;
|
|
18
|
+
onStyleSelect: (styleId: string) => void;
|
|
19
|
+
title: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const StyleSelector: React.FC<StyleSelectorProps> = ({
|
|
23
|
+
styles,
|
|
24
|
+
selectedStyle,
|
|
25
|
+
onStyleSelect,
|
|
26
|
+
title,
|
|
27
|
+
}) => {
|
|
28
|
+
const tokens = useAppDesignTokens();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View style={componentStyles.section}>
|
|
32
|
+
<AtomicText
|
|
33
|
+
type="bodyMedium"
|
|
34
|
+
style={{
|
|
35
|
+
color: tokens.colors.textPrimary,
|
|
36
|
+
fontWeight: "600",
|
|
37
|
+
marginBottom: 12,
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
{title}
|
|
41
|
+
</AtomicText>
|
|
42
|
+
<ScrollView
|
|
43
|
+
horizontal
|
|
44
|
+
showsHorizontalScrollIndicator={false}
|
|
45
|
+
style={componentStyles.stylesScroll}
|
|
46
|
+
>
|
|
47
|
+
{styles.map((style) => {
|
|
48
|
+
const isSelected = selectedStyle === style.id;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<TouchableOpacity
|
|
52
|
+
key={style.id}
|
|
53
|
+
style={[
|
|
54
|
+
componentStyles.styleCard,
|
|
55
|
+
{
|
|
56
|
+
backgroundColor: isSelected
|
|
57
|
+
? tokens.colors.primary
|
|
58
|
+
: tokens.colors.surface,
|
|
59
|
+
borderColor: isSelected
|
|
60
|
+
? tokens.colors.primary
|
|
61
|
+
: tokens.colors.borderLight,
|
|
62
|
+
},
|
|
63
|
+
]}
|
|
64
|
+
onPress={() => onStyleSelect(style.id)}
|
|
65
|
+
>
|
|
66
|
+
{style.thumbnail ? (
|
|
67
|
+
<AtomicText type="headlineLarge" style={{ marginBottom: 8 }}>
|
|
68
|
+
{style.thumbnail}
|
|
69
|
+
</AtomicText>
|
|
70
|
+
) : style.icon ? (
|
|
71
|
+
<AtomicIcon
|
|
72
|
+
name={style.icon as never}
|
|
73
|
+
size="lg"
|
|
74
|
+
color={isSelected ? "primary" : "secondary"}
|
|
75
|
+
/>
|
|
76
|
+
) : null}
|
|
77
|
+
<AtomicText
|
|
78
|
+
type="bodySmall"
|
|
79
|
+
style={{
|
|
80
|
+
color: isSelected
|
|
81
|
+
? tokens.colors.textInverse
|
|
82
|
+
: tokens.colors.textPrimary,
|
|
83
|
+
fontWeight: isSelected ? "600" : "400",
|
|
84
|
+
textAlign: "center",
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
{style.name}
|
|
88
|
+
</AtomicText>
|
|
89
|
+
{style.description && (
|
|
90
|
+
<AtomicText
|
|
91
|
+
type="labelSmall"
|
|
92
|
+
style={{
|
|
93
|
+
color: isSelected
|
|
94
|
+
? tokens.colors.textInverse
|
|
95
|
+
: tokens.colors.textSecondary,
|
|
96
|
+
opacity: isSelected ? 0.9 : 0.7,
|
|
97
|
+
textAlign: "center",
|
|
98
|
+
marginTop: 4,
|
|
99
|
+
}}
|
|
100
|
+
numberOfLines={2}
|
|
101
|
+
>
|
|
102
|
+
{style.description}
|
|
103
|
+
</AtomicText>
|
|
104
|
+
)}
|
|
105
|
+
</TouchableOpacity>
|
|
106
|
+
);
|
|
107
|
+
})}
|
|
108
|
+
</ScrollView>
|
|
109
|
+
</View>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const componentStyles = StyleSheet.create({
|
|
114
|
+
section: {
|
|
115
|
+
padding: 16,
|
|
116
|
+
marginBottom: 8,
|
|
117
|
+
},
|
|
118
|
+
stylesScroll: {
|
|
119
|
+
marginHorizontal: -16,
|
|
120
|
+
paddingHorizontal: 16,
|
|
121
|
+
},
|
|
122
|
+
styleCard: {
|
|
123
|
+
width: 120,
|
|
124
|
+
padding: 16,
|
|
125
|
+
borderRadius: 16,
|
|
126
|
+
borderWidth: 2,
|
|
127
|
+
marginRight: 12,
|
|
128
|
+
alignItems: "center",
|
|
129
|
+
minHeight: 140,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selector Components
|
|
3
|
+
* Generic, props-driven selection UI components
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { StyleSelector } from "./StyleSelector";
|
|
7
|
+
export { AspectRatioSelector } from "./AspectRatioSelector";
|
|
8
|
+
export { DurationSelector } from "./DurationSelector";
|
|
9
|
+
|
|
10
|
+
export type { StyleSelectorProps } from "./StyleSelector";
|
|
11
|
+
export type { AspectRatioSelectorProps } from "./AspectRatioSelector";
|
|
12
|
+
export type { DurationSelectorProps } from "./DurationSelector";
|
|
13
|
+
|
|
14
|
+
export type {
|
|
15
|
+
StyleOption,
|
|
16
|
+
AspectRatioOption,
|
|
17
|
+
DurationValue,
|
|
18
|
+
} from "./types";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selector Component Types
|
|
3
|
+
* Generic types for selector UI components
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Style option for StyleSelector
|
|
8
|
+
* All fields are required - app provides translated values
|
|
9
|
+
*/
|
|
10
|
+
export interface StyleOption {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
thumbnail?: string;
|
|
15
|
+
icon?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Aspect ratio option for AspectRatioSelector
|
|
20
|
+
* App provides translated name and description
|
|
21
|
+
*/
|
|
22
|
+
export interface AspectRatioOption {
|
|
23
|
+
id: "16:9" | "9:16" | "1:1";
|
|
24
|
+
name: string;
|
|
25
|
+
icon: string;
|
|
26
|
+
description: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Duration value type (seconds)
|
|
31
|
+
*/
|
|
32
|
+
export type DurationValue = number;
|