@umituz/react-native-ai-generation-content 1.17.41 → 1.17.43

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.41",
3
+ "version": "1.17.43",
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
@@ -289,12 +289,17 @@ export {
289
289
  ErrorDisplay,
290
290
  // Headers
291
291
  FeatureHeader,
292
+ AIGenScreenHeader,
293
+
292
294
  // Photo Upload
293
295
  PhotoUploadCard,
294
296
  // Selectors
295
297
  StyleSelector,
296
298
  AspectRatioSelector,
297
299
  DurationSelector,
300
+ GridSelector,
301
+ StylePresetsGrid,
302
+
298
303
  } from "./presentation/components";
299
304
 
300
305
  export type {
@@ -326,6 +331,8 @@ export type {
326
331
  AIGenerationProgressInlineProps,
327
332
  PromptInputProps,
328
333
  AIGenerationHeroProps,
334
+ StylePresetsGridProps,
335
+ StylePreset,
329
336
  // Buttons
330
337
  GenerateButtonProps,
331
338
  // Display
@@ -334,6 +341,9 @@ export type {
334
341
  ErrorDisplayProps,
335
342
  // Headers
336
343
  FeatureHeaderProps,
344
+ AIGenScreenHeaderProps,
345
+ NavigationButtonType,
346
+
337
347
  // Photo Upload
338
348
  PhotoUploadCardProps,
339
349
  PhotoUploadCardConfig,
@@ -341,6 +351,9 @@ export type {
341
351
  StyleSelectorProps,
342
352
  AspectRatioSelectorProps,
343
353
  DurationSelectorProps,
354
+ GridSelectorProps,
355
+ GridSelectorOption,
356
+
344
357
  StyleOption,
345
358
  AspectRatioOption,
346
359
  DurationValue,
@@ -0,0 +1,131 @@
1
+ /**
2
+ * StylePresetsGrid Component
3
+ * Generic grid of preset styles with emojis, names, and optional duration badges.
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ useAppDesignTokens,
11
+ } from "@umituz/react-native-design-system";
12
+
13
+ export interface StylePreset {
14
+ readonly id: string;
15
+ readonly name: string;
16
+ readonly emoji: string;
17
+ readonly description: string;
18
+ readonly duration?: number;
19
+ }
20
+
21
+ export interface StylePresetsGridProps {
22
+ readonly presets: readonly StylePreset[];
23
+ readonly onPresetPress: (preset: StylePreset) => void;
24
+ readonly disabled?: boolean;
25
+ readonly title?: string;
26
+ }
27
+
28
+ export const StylePresetsGrid: React.FC<StylePresetsGridProps> = ({
29
+ presets,
30
+ onPresetPress,
31
+ disabled = false,
32
+ title = "Quick Start - Choose a Style",
33
+ }) => {
34
+ const tokens = useAppDesignTokens();
35
+
36
+ return (
37
+ <View style={styles.section}>
38
+ <AtomicText
39
+ type="bodyMedium"
40
+ style={[styles.title, { color: tokens.colors.textPrimary }]}
41
+ >
42
+ ⚡ {title}
43
+ </AtomicText>
44
+ <View style={styles.grid}>
45
+ {presets.map((preset) => (
46
+ <TouchableOpacity
47
+ key={preset.id}
48
+ style={[
49
+ styles.card,
50
+ { backgroundColor: tokens.colors.surface },
51
+ ]}
52
+ onPress={() => onPresetPress(preset)}
53
+ disabled={disabled}
54
+ >
55
+ <View style={styles.cardHeader}>
56
+ <Text style={styles.emoji}>{preset.emoji}</Text>
57
+ {preset.duration !== undefined && (
58
+ <View
59
+ style={[
60
+ styles.badge,
61
+ { backgroundColor: tokens.colors.primary + "20" },
62
+ ]}
63
+ >
64
+ <AtomicText
65
+ type="labelSmall"
66
+ style={{ color: tokens.colors.primary, fontSize: 10 }}
67
+ >
68
+ {preset.duration}s
69
+ </AtomicText>
70
+ </View>
71
+ )}
72
+ </View>
73
+ <AtomicText
74
+ type="bodyMedium"
75
+ style={[styles.cardTitle, { color: tokens.colors.textPrimary }]}
76
+ >
77
+ {preset.name}
78
+ </AtomicText>
79
+ <AtomicText
80
+ type="labelSmall"
81
+ style={{ color: tokens.colors.textSecondary, marginTop: 4 }}
82
+ >
83
+ {preset.description}
84
+ </AtomicText>
85
+ </TouchableOpacity>
86
+ ))}
87
+ </View>
88
+ </View>
89
+ );
90
+ };
91
+
92
+ const styles = StyleSheet.create({
93
+ section: {
94
+ padding: 16,
95
+ width: "100%",
96
+ },
97
+ title: {
98
+ fontWeight: "600",
99
+ marginBottom: 16,
100
+ },
101
+ grid: {
102
+ flexDirection: "row",
103
+ flexWrap: "wrap",
104
+ gap: 12,
105
+ },
106
+ card: {
107
+ flex: 1,
108
+ minWidth: "47%",
109
+ padding: 16,
110
+ borderRadius: 16,
111
+ borderWidth: 1,
112
+ borderColor: "rgba(0,0,0,0.05)",
113
+ },
114
+ cardHeader: {
115
+ flexDirection: "row",
116
+ alignItems: "center",
117
+ justifyContent: "space-between",
118
+ },
119
+ emoji: {
120
+ fontSize: 40,
121
+ },
122
+ badge: {
123
+ paddingHorizontal: 8,
124
+ paddingVertical: 4,
125
+ borderRadius: 12,
126
+ },
127
+ cardTitle: {
128
+ fontWeight: "600",
129
+ marginTop: 8,
130
+ },
131
+ });
@@ -0,0 +1,127 @@
1
+ import React, { ReactNode } from "react";
2
+ import { View, TouchableOpacity, StyleSheet } from "react-native";
3
+ import {
4
+ AtomicText,
5
+ AtomicIcon,
6
+ useAppDesignTokens,
7
+ } from "@umituz/react-native-design-system";
8
+
9
+ export type NavigationButtonType = "back" | "close";
10
+
11
+ export interface AIGenScreenHeaderProps {
12
+ readonly title: string;
13
+ readonly description?: string;
14
+ readonly navigationType?: NavigationButtonType;
15
+ readonly onNavigationPress: () => void;
16
+ readonly headerContent?: ReactNode;
17
+ readonly rightContent?: ReactNode;
18
+ readonly titleType?: "headlineLarge" | "titleLarge";
19
+ readonly showDescription?: boolean;
20
+ }
21
+
22
+ export const AIGenScreenHeader: React.FC<AIGenScreenHeaderProps> = ({
23
+ title,
24
+ description,
25
+ navigationType = "back",
26
+ onNavigationPress,
27
+ headerContent,
28
+ rightContent,
29
+ titleType = "titleLarge",
30
+ showDescription = !!description,
31
+ }) => {
32
+ const tokens = useAppDesignTokens();
33
+
34
+ const isCloseButton = navigationType === "close";
35
+ const buttonStyle = isCloseButton
36
+ ? [
37
+ styles.navigationButton,
38
+ styles.closeButton,
39
+ {
40
+ backgroundColor: tokens.colors.surface,
41
+ borderColor: tokens.colors.borderLight,
42
+ },
43
+ ]
44
+ : [styles.navigationButton, styles.backButton];
45
+
46
+ const iconName = isCloseButton ? "close-circle" : "chevron-back";
47
+ const iconColor = isCloseButton ? "secondary" : "primary";
48
+
49
+ return (
50
+ <View style={styles.header}>
51
+ <View style={styles.headerTop}>
52
+ <View style={styles.leftContainer}>
53
+ <TouchableOpacity
54
+ onPress={onNavigationPress}
55
+ style={buttonStyle}
56
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
57
+ >
58
+ <AtomicIcon name={iconName} size="md" color={iconColor} />
59
+ </TouchableOpacity>
60
+ <AtomicText
61
+ type={titleType}
62
+ style={{
63
+ color: tokens.colors.textPrimary,
64
+ fontWeight: "700",
65
+ marginLeft: navigationType === "back" ? 8 : 0,
66
+ }}
67
+ >
68
+ {title}
69
+ </AtomicText>
70
+ </View>
71
+ <View style={styles.headerActions}>{rightContent}</View>
72
+ </View>
73
+ {showDescription && description && (
74
+ <AtomicText
75
+ type="bodyMedium"
76
+ style={[
77
+ styles.description,
78
+ { color: tokens.colors.textSecondary, marginTop: 8 },
79
+ ]}
80
+ >
81
+ {description}
82
+ </AtomicText>
83
+ )}
84
+ {headerContent && <View style={styles.headerContent}>{headerContent}</View>}
85
+ </View>
86
+ );
87
+ };
88
+
89
+ const styles = StyleSheet.create({
90
+ header: {
91
+ padding: 16,
92
+ paddingTop: 60,
93
+ width: "100%",
94
+ },
95
+ headerTop: {
96
+ flexDirection: "row",
97
+ alignItems: "center",
98
+ justifyContent: "space-between",
99
+ },
100
+ leftContainer: {
101
+ flexDirection: "row",
102
+ alignItems: "center",
103
+ flex: 1,
104
+ },
105
+ headerActions: {
106
+ flexDirection: "row",
107
+ alignItems: "center",
108
+ gap: 12,
109
+ },
110
+ navigationButton: {
111
+ width: 40,
112
+ height: 40,
113
+ alignItems: "center",
114
+ justifyContent: "center",
115
+ },
116
+ backButton: {},
117
+ closeButton: {
118
+ borderRadius: 20,
119
+ borderWidth: 1,
120
+ },
121
+ description: {
122
+ lineHeight: 20,
123
+ },
124
+ headerContent: {
125
+ marginTop: 16,
126
+ },
127
+ });
@@ -1 +1,2 @@
1
- export { FeatureHeader, type FeatureHeaderProps } from "./FeatureHeader";
1
+ export * from "./FeatureHeader";
2
+ export * from "./AIGenScreenHeader";
@@ -7,6 +7,7 @@ export { PendingJobCardActions } from "./PendingJobCardActions";
7
7
  export { AIGenerationProgressInline } from "./AIGenerationProgressInline";
8
8
  export { PromptInput } from "./PromptInput";
9
9
  export { AIGenerationHero } from "./AIGenerationHero";
10
+ export * from "./StylePresetsGrid";
10
11
 
11
12
  export type {
12
13
  GenerationProgressModalProps,
@@ -0,0 +1,130 @@
1
+ import React from "react";
2
+ import { View, TouchableOpacity, StyleSheet } from "react-native";
3
+ import {
4
+ AtomicText,
5
+ useAppDesignTokens,
6
+ } from "@umituz/react-native-design-system";
7
+
8
+ export interface GridSelectorOption<T> {
9
+ readonly value: T;
10
+ readonly label: string;
11
+ readonly description?: string;
12
+ readonly emoji?: string;
13
+ }
14
+
15
+ export interface GridSelectorProps<T> {
16
+ readonly options: readonly GridSelectorOption<T>[];
17
+ readonly selectedValue: T;
18
+ readonly onSelect: (value: T) => void;
19
+ readonly title?: string;
20
+ readonly columns?: number;
21
+ readonly disabled?: boolean;
22
+ }
23
+
24
+ export function GridSelector<T>({
25
+ options,
26
+ selectedValue,
27
+ onSelect,
28
+ title,
29
+ disabled = false,
30
+ }: GridSelectorProps<T>): JSX.Element {
31
+ const tokens = useAppDesignTokens();
32
+
33
+ return (
34
+ <View style={styles.section}>
35
+ {title && (
36
+ <AtomicText
37
+ type="bodyMedium"
38
+ style={{
39
+ color: tokens.colors.textPrimary,
40
+ fontWeight: "600",
41
+ marginBottom: 12,
42
+ }}
43
+ >
44
+ {title}
45
+ </AtomicText>
46
+ )}
47
+ <View style={styles.grid}>
48
+ {options.map((option, index) => {
49
+ const isSelected = selectedValue === option.value;
50
+ return (
51
+ <TouchableOpacity
52
+ key={index}
53
+ style={[
54
+ styles.card,
55
+ {
56
+ backgroundColor: isSelected
57
+ ? tokens.colors.primary + "15"
58
+ : tokens.colors.surface,
59
+ borderColor: isSelected
60
+ ? tokens.colors.primary
61
+ : tokens.colors.borderLight,
62
+ },
63
+ ]}
64
+ onPress={() => onSelect(option.value)}
65
+ disabled={disabled}
66
+ >
67
+ <View style={styles.cardContent}>
68
+ {option.emoji && (
69
+ <AtomicText style={styles.emoji}>{option.emoji}</AtomicText>
70
+ )}
71
+ <AtomicText
72
+ type="bodySmall"
73
+ style={{
74
+ color: tokens.colors.textPrimary,
75
+ fontWeight: isSelected ? "600" : "400",
76
+ textAlign: "center",
77
+ }}
78
+ >
79
+ {option.label}
80
+ </AtomicText>
81
+ {option.description && (
82
+ <AtomicText
83
+ type="labelSmall"
84
+ style={{
85
+ color: tokens.colors.textSecondary,
86
+ marginTop: 4,
87
+ textAlign: "center",
88
+ fontSize: 10,
89
+ }}
90
+ >
91
+ {option.description}
92
+ </AtomicText>
93
+ )}
94
+ </View>
95
+ </TouchableOpacity>
96
+ );
97
+ })}
98
+ </View>
99
+ </View>
100
+ );
101
+ }
102
+
103
+ const styles = StyleSheet.create({
104
+ section: {
105
+ padding: 16,
106
+ width: "100%",
107
+ },
108
+ grid: {
109
+ flexDirection: "row",
110
+ flexWrap: "wrap",
111
+ gap: 12,
112
+ },
113
+ card: {
114
+ flex: 1,
115
+ minWidth: "45%",
116
+ padding: 12,
117
+ borderRadius: 12,
118
+ borderWidth: 2,
119
+ alignItems: "center",
120
+ justifyContent: "center",
121
+ },
122
+ cardContent: {
123
+ alignItems: "center",
124
+ justifyContent: "center",
125
+ },
126
+ emoji: {
127
+ fontSize: 24,
128
+ marginBottom: 4,
129
+ },
130
+ });
@@ -6,6 +6,7 @@
6
6
  export { StyleSelector } from "./StyleSelector";
7
7
  export { AspectRatioSelector } from "./AspectRatioSelector";
8
8
  export { DurationSelector } from "./DurationSelector";
9
+ export { GridSelector, type GridSelectorProps, type GridSelectorOption } from "./GridSelector";
9
10
 
10
11
  export type { StyleSelectorProps } from "./StyleSelector";
11
12
  export type { AspectRatioSelectorProps } from "./AspectRatioSelector";