@umituz/react-native-ai-generation-content 1.17.28 → 1.17.29

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.28",
3
+ "version": "1.17.29",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
package/src/index.ts CHANGED
@@ -275,6 +275,10 @@ export {
275
275
  FeatureHeader,
276
276
  // Photo Upload
277
277
  PhotoUploadCard,
278
+ // Selectors
279
+ StyleSelector,
280
+ AspectRatioSelector,
281
+ DurationSelector,
278
282
  } from "./presentation/components";
279
283
 
280
284
  export type {
@@ -314,6 +318,13 @@ export type {
314
318
  // Photo Upload
315
319
  PhotoUploadCardProps,
316
320
  PhotoUploadCardConfig,
321
+ // Selectors
322
+ StyleSelectorProps,
323
+ AspectRatioSelectorProps,
324
+ DurationSelectorProps,
325
+ StyleOption,
326
+ AspectRatioOption,
327
+ DurationValue,
317
328
  } from "./presentation/components";
318
329
 
319
330
  // =============================================================================
@@ -28,3 +28,4 @@ export * from "./buttons";
28
28
  export * from "./display";
29
29
  export * from "./headers";
30
30
  export * from "./PhotoUploadCard";
31
+ export * from "./selectors";
@@ -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;