@umituz/react-native-ai-generation-content 1.12.43 → 1.12.44

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.12.43",
3
+ "version": "1.12.44",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -102,4 +102,4 @@
102
102
  "publishConfig": {
103
103
  "access": "public"
104
104
  }
105
- }
105
+ }
@@ -75,6 +75,10 @@ export { CreationCard } from "./presentation/components/CreationCard";
75
75
  export { CreationsHomeCard } from "./presentation/components/CreationsHomeCard";
76
76
  export { FilterChips } from "./presentation/components/FilterChips";
77
77
  export { EmptyState } from "./presentation/components/EmptyState";
78
+ export {
79
+ CreationsProvider,
80
+ useCreationsProvider,
81
+ } from "./presentation/components/CreationsProvider";
78
82
 
79
83
  // =============================================================================
80
84
  // PRESENTATION LAYER - Screens
@@ -9,9 +9,10 @@ import { timezoneService } from "@umituz/react-native-timezone";
9
9
  import type { Creation } from "../../domain/entities/Creation";
10
10
  import type { CreationType } from "../../domain/value-objects/CreationsConfig";
11
11
 
12
+ import { useCreationsProvider } from "./CreationsProvider";
13
+
12
14
  interface CreationCardProps {
13
15
  readonly creation: Creation;
14
- readonly types: readonly CreationType[];
15
16
  readonly onView?: (creation: Creation) => void;
16
17
  readonly onShare: (creation: Creation) => void;
17
18
  readonly onDelete: (creation: Creation) => void;
@@ -21,7 +22,6 @@ interface CreationCardProps {
21
22
 
22
23
  export function CreationCard({
23
24
  creation,
24
- types,
25
25
  onView,
26
26
  onShare,
27
27
  onDelete,
@@ -29,10 +29,12 @@ export function CreationCard({
29
29
  locale = "en-US",
30
30
  }: CreationCardProps) {
31
31
  const tokens = useAppDesignTokens();
32
+ const { translatedTypes, t } = useCreationsProvider();
32
33
 
33
- const typeConfig = types.find((t) => t.id === creation.type);
34
+ const typeConfig = translatedTypes.find((t) => t.id === creation.type);
34
35
  const icon = typeConfig?.icon;
35
- const label = typeConfig?.labelKey || creation.type;
36
+ // Use manual name if available, otherwise use translated label from config
37
+ const label = (creation.metadata?.names as string) || typeConfig?.labelKey || creation.type;
36
38
 
37
39
  const handleView = useCallback(() => onView?.(creation), [creation, onView]);
38
40
  const handleShare = useCallback(() => onShare(creation), [creation, onShare]);
@@ -2,7 +2,6 @@
2
2
  import React from 'react';
3
3
  import { View, StyleSheet, TouchableOpacity } from 'react-native';
4
4
  import { AtomicText, AtomicIcon, useAppDesignTokens, type DesignTokens } from "@umituz/react-native-design-system";
5
- import { type EdgeInsets, useSafeAreaInsets } from 'react-native-safe-area-context';
6
5
 
7
6
  interface DetailHeaderProps {
8
7
  readonly title: string;
@@ -12,8 +11,7 @@ interface DetailHeaderProps {
12
11
 
13
12
  export const DetailHeader: React.FC<DetailHeaderProps> = ({ title, date, onClose }) => {
14
13
  const tokens = useAppDesignTokens();
15
- const insets = useSafeAreaInsets();
16
- const styles = useStyles(tokens, insets);
14
+ const styles = useStyles(tokens);
17
15
 
18
16
  return (
19
17
  <View style={styles.headerContainer}>
@@ -34,11 +32,11 @@ export const DetailHeader: React.FC<DetailHeaderProps> = ({ title, date, onClose
34
32
  );
35
33
  };
36
34
 
37
- const useStyles = (tokens: DesignTokens, insets: EdgeInsets) => StyleSheet.create({
35
+ const useStyles = (tokens: DesignTokens) => StyleSheet.create({
38
36
  headerContainer: {
39
37
  flexDirection: 'row',
40
38
  alignItems: 'center',
41
- paddingTop: insets.top + tokens.spacing.sm,
39
+ paddingTop: tokens.spacing.sm,
42
40
  paddingBottom: tokens.spacing.md,
43
41
  paddingHorizontal: tokens.spacing.md,
44
42
  backgroundColor: tokens.colors.background,
@@ -7,7 +7,6 @@ import { CreationCard } from "./CreationCard";
7
7
 
8
8
  interface CreationsGridProps {
9
9
  readonly creations: Creation[];
10
- readonly types: readonly CreationType[];
11
10
  readonly isLoading: boolean;
12
11
  readonly onRefresh: () => void;
13
12
  readonly onView: (creation: Creation) => void;
@@ -22,7 +21,6 @@ interface CreationsGridProps {
22
21
 
23
22
  export const CreationsGrid: React.FC<CreationsGridProps> = ({
24
23
  creations,
25
- types,
26
24
  isLoading,
27
25
  onRefresh,
28
26
  onView,
@@ -40,7 +38,6 @@ export const CreationsGrid: React.FC<CreationsGridProps> = ({
40
38
  const renderItem = ({ item }: { item: Creation }) => (
41
39
  <CreationCard
42
40
  creation={item}
43
- types={types as CreationType[]}
44
41
  onView={() => onView(item)}
45
42
  onShare={() => onShare(item)}
46
43
  onDelete={() => onDelete(item)}
@@ -1,13 +1,14 @@
1
-
2
1
  import React from 'react';
3
- import { View, StyleSheet, ScrollView } from 'react-native';
4
- import { useAppDesignTokens, type DesignTokens } from "@umituz/react-native-design-system";
2
+ import { StyleSheet } from 'react-native';
3
+ import { useAppDesignTokens, type DesignTokens, ScreenLayout } from "@umituz/react-native-design-system";
5
4
  import type { Creation } from '../../domain/entities/Creation';
6
5
  import { DetailHeader } from '../components/CreationDetail/DetailHeader';
7
6
  import { DetailImage } from '../components/CreationDetail/DetailImage';
8
7
  import { DetailStory } from '../components/CreationDetail/DetailStory';
9
8
  import { DetailActions } from '../components/CreationDetail/DetailActions';
10
9
 
10
+ import { useCreationsProvider } from '../components/CreationsProvider';
11
+
11
12
  interface CreationDetailScreenProps {
12
13
  readonly creation: Creation;
13
14
  readonly onClose: () => void;
@@ -31,47 +32,52 @@ export const CreationDetailScreen: React.FC<CreationDetailScreenProps> = ({
31
32
  t
32
33
  }) => {
33
34
  const tokens = useAppDesignTokens();
35
+ const { getLocalizedTitle } = useCreationsProvider();
34
36
 
35
37
  // Extract data safely
36
38
  const metadata = (creation.metadata || {}) as CreationMetadata;
37
- const title = metadata.names || creation.type;
39
+
40
+ // Resolve title:
41
+ // 1. Manually set names in metadata
42
+ // 2. Localized title from config types mapping
43
+ // 3. Fallback to raw creation type (formatted)
44
+ const title = metadata.names || getLocalizedTitle(creation.type);
38
45
  const story = metadata.story || metadata.description || "";
39
46
  const date = metadata.date || new Date(creation.createdAt).toLocaleDateString();
40
47
 
41
48
  const styles = useStyles(tokens);
42
49
 
43
50
  return (
44
- <View style={styles.container}>
45
- <DetailHeader
46
- title={title}
47
- date={date}
48
- onClose={onClose}
49
- />
50
-
51
- <ScrollView
52
- contentContainerStyle={styles.scrollContent}
53
- showsVerticalScrollIndicator={false}
54
- >
55
- <DetailImage uri={creation.uri} />
51
+ <ScreenLayout
52
+ scrollable={true}
53
+ edges={['top', 'bottom']}
54
+ backgroundColor={tokens.colors.background}
55
+ header={
56
+ <DetailHeader
57
+ title={title}
58
+ date={date}
59
+ onClose={onClose}
60
+ />
61
+ }
62
+ contentContainerStyle={styles.scrollContent}
63
+ >
64
+ <DetailImage uri={creation.uri} />
56
65
 
66
+ {story ? (
57
67
  <DetailStory story={story} />
68
+ ) : null}
58
69
 
59
- <DetailActions
60
- onShare={() => onShare(creation)}
61
- onDelete={() => onDelete(creation)}
62
- shareLabel={t("result.shareButton") || "Share"}
63
- deleteLabel={t("common.delete") || "Delete"}
64
- />
65
- </ScrollView>
66
- </View>
70
+ <DetailActions
71
+ onShare={() => onShare(creation)}
72
+ onDelete={() => onDelete(creation)}
73
+ shareLabel={t("result.shareButton") || "Share"}
74
+ deleteLabel={t("common.delete") || "Delete"}
75
+ />
76
+ </ScreenLayout>
67
77
  );
68
78
  };
69
79
 
70
80
  const useStyles = (tokens: DesignTokens) => StyleSheet.create({
71
- container: {
72
- flex: 1,
73
- backgroundColor: tokens.colors.background,
74
- },
75
81
  scrollContent: {
76
82
  paddingBottom: tokens.spacing.xxl,
77
83
  },
@@ -10,7 +10,8 @@ import {
10
10
  useSharing,
11
11
  FilterBottomSheet,
12
12
  type DesignTokens,
13
- type BottomSheetModalRef
13
+ type BottomSheetModalRef,
14
+ ScreenLayout
14
15
  } from "@umituz/react-native-design-system";
15
16
  import { useSafeAreaInsets } from "react-native-safe-area-context";
16
17
  import { useFocusEffect } from "@react-navigation/native";
@@ -37,7 +38,17 @@ interface CreationsGalleryScreenProps {
37
38
  readonly showFilter?: boolean;
38
39
  }
39
40
 
40
- export function CreationsGalleryScreen({
41
+ import { CreationsProvider } from "../components/CreationsProvider";
42
+
43
+ export function CreationsGalleryScreen(props: CreationsGalleryScreenProps) {
44
+ return (
45
+ <CreationsProvider config={props.config} t={props.t}>
46
+ <CreationsGalleryScreenContent {...props} />
47
+ </CreationsProvider>
48
+ );
49
+ }
50
+
51
+ function CreationsGalleryScreenContent({
41
52
  userId,
42
53
  repository,
43
54
  config,
@@ -149,40 +160,38 @@ export function CreationsGalleryScreen({
149
160
  );
150
161
  }
151
162
 
152
- const handleLayout = (event: LayoutChangeEvent) => {
153
- // Keep internal logic if needed, currently empty but handles the event correctly
154
- void event;
155
- };
156
-
157
163
  return (
158
- <View style={styles.container} onLayout={handleLayout}>
159
- {(!creations || creations?.length === 0) && !isLoading ? null : (
160
- <GalleryHeader
161
- title={t(config.translations.title) || 'My Creations'}
162
- count={filtered.length}
163
- countLabel={t(config.translations.photoCount) || 'photos'}
164
- isFiltered={isFiltered}
165
- showFilter={showFilter}
166
- filterLabel={t(config.translations.filterLabel) || 'Filter'}
167
- onFilterPress={() => {
168
- if (__DEV__) {
169
- // eslint-disable-next-line no-console
170
- console.log('[CreationsGallery] Filter button pressed');
171
- // eslint-disable-next-line no-console
172
- console.log('[CreationsGallery] filterSheetRef.current:', filterSheetRef.current);
173
- // eslint-disable-next-line no-console
174
- console.log('[CreationsGallery] allCategories:', allCategories);
175
- }
176
- filterSheetRef.current?.present();
177
- }}
178
- style={{ paddingTop: insets.top + tokens.spacing.md }}
179
- />
180
- )}
181
-
164
+ <ScreenLayout
165
+ scrollable={false}
166
+ edges={["top"]}
167
+ backgroundColor={tokens.colors.background}
168
+ header={
169
+ (!creations || creations?.length === 0) && !isLoading ? null : (
170
+ <GalleryHeader
171
+ title={t(config.translations.title) || 'My Creations'}
172
+ count={filtered.length}
173
+ countLabel={t(config.translations.photoCount) || 'photos'}
174
+ isFiltered={isFiltered}
175
+ showFilter={showFilter}
176
+ filterLabel={t(config.translations.filterLabel) || 'Filter'}
177
+ onFilterPress={() => {
178
+ if (__DEV__) {
179
+ // eslint-disable-next-line no-console
180
+ console.log('[CreationsGallery] Filter button pressed');
181
+ // eslint-disable-next-line no-console
182
+ console.log('[CreationsGallery] filterSheetRef.current:', filterSheetRef.current);
183
+ // eslint-disable-next-line no-console
184
+ console.log('[CreationsGallery] allCategories:', allCategories);
185
+ }
186
+ filterSheetRef.current?.present();
187
+ }}
188
+ />
189
+ )
190
+ }
191
+ >
182
192
  {/* Main Content Grid - handles empty/loading via ListEmptyComponent */}
183
193
  <CreationsGrid
184
194
  creations={filtered}
185
- types={translatedTypes}
186
195
  isLoading={isLoading}
187
196
  onRefresh={() => void refetch()}
188
197
  onView={handleView}
@@ -190,7 +199,7 @@ export function CreationsGalleryScreen({
190
199
  onDelete={handleDelete}
191
200
  onFavorite={handleFavorite}
192
201
  locale={locale}
193
- contentContainerStyle={{ paddingBottom: insets.bottom + tokens.spacing.xl }}
202
+ contentContainerStyle={{ paddingBottom: tokens.spacing.xl }}
194
203
  ListEmptyComponent={renderEmptyComponent}
195
204
  />
196
205
 
@@ -215,7 +224,7 @@ export function CreationsGalleryScreen({
215
224
  onClearFilters={clearFilters}
216
225
  title={t(config.translations.filterTitle) || t("common.filter")}
217
226
  />
218
- </View>
227
+ </ScreenLayout>
219
228
  );
220
229
  }
221
230