@umituz/react-native-ai-creations 1.2.8 → 1.2.9

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-creations",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
4
4
  "description": "AI-generated creations gallery with filtering, sharing, and management for React Native apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -27,32 +27,31 @@
27
27
  "type": "git",
28
28
  "url": "https://github.com/umituz/react-native-ai-creations"
29
29
  },
30
+ "dependencies": {
31
+ "@umituz/react-native-filter": "latest",
32
+ "@umituz/react-native-image": "latest",
33
+ "@umituz/react-native-bottom-sheet": "latest"
34
+ },
30
35
  "peerDependencies": {
31
36
  "@tanstack/react-query": ">=5.0.0",
32
37
  "@umituz/react-native-design-system": "latest",
33
38
  "@umituz/react-native-firestore": "latest",
34
- "@umituz/react-native-image": "latest",
35
39
  "@umituz/react-native-sharing": "latest",
36
40
  "firebase": ">=11.0.0",
37
41
  "react": ">=19.1.0",
38
42
  "react-native": ">=0.81.5",
39
- "react-native-safe-area-context": ">=5.0.0",
40
- "@umituz/react-native-filter": "latest",
41
- "@umituz/react-native-bottom-sheet": "latest"
43
+ "react-native-safe-area-context": ">=5.0.0"
42
44
  },
43
45
  "devDependencies": {
44
46
  "@tanstack/react-query": "^5.62.16",
45
47
  "@types/react": "^19.0.0",
46
48
  "@umituz/react-native-design-system": "latest",
47
- "@umituz/react-native-image": "latest",
48
49
  "@umituz/react-native-sharing": "latest",
49
50
  "@umituz/react-native-firestore": "latest",
50
51
  "firebase": "^11.0.0",
51
52
  "react": "19.1.0",
52
53
  "react-native": "0.81.5",
53
54
  "react-native-safe-area-context": "^5.6.0",
54
- "@umituz/react-native-filter": "latest",
55
- "@umituz/react-native-bottom-sheet": "latest",
56
55
  "typescript": "^5.3.3"
57
56
  },
58
57
  "publishConfig": {
@@ -0,0 +1,99 @@
1
+ import React from 'react';
2
+ import { View, TouchableOpacity, StyleSheet } from 'react-native';
3
+ import { AtomicText, AtomicIcon, useAppDesignTokens } from "@umituz/react-native-design-system";
4
+
5
+ interface GalleryHeaderProps {
6
+ readonly title: string;
7
+ readonly count: number;
8
+ readonly countLabel: string;
9
+ readonly isFiltered: boolean;
10
+ readonly onFilterPress: () => void;
11
+ }
12
+
13
+ export const GalleryHeader: React.FC<GalleryHeaderProps> = ({
14
+ title,
15
+ count,
16
+ countLabel,
17
+ isFiltered,
18
+ onFilterPress
19
+ }) => {
20
+ const tokens = useAppDesignTokens();
21
+ const styles = useStyles(tokens);
22
+
23
+ return (
24
+ <View style={styles.headerArea}>
25
+ <View>
26
+ <AtomicText style={styles.title}>{title}</AtomicText>
27
+ <AtomicText style={styles.subtitle}>
28
+ {count} {countLabel}
29
+ </AtomicText>
30
+ </View>
31
+ <TouchableOpacity
32
+ onPress={onFilterPress}
33
+ style={[styles.filterButton, isFiltered && styles.filterButtonActive]}
34
+ >
35
+ <AtomicIcon
36
+ name="ListFilter"
37
+ size="sm"
38
+ color={isFiltered ? "primary" : "secondary"}
39
+ />
40
+ <AtomicText style={[styles.filterText, { color: isFiltered ? tokens.colors.primary : tokens.colors.textSecondary }]}>
41
+ Filter
42
+ </AtomicText>
43
+ {isFiltered && (
44
+ <View style={styles.badge} />
45
+ )}
46
+ </TouchableOpacity>
47
+ </View>
48
+ );
49
+ };
50
+
51
+ const useStyles = (tokens: any) => StyleSheet.create({
52
+ headerArea: {
53
+ flexDirection: "row",
54
+ alignItems: "center",
55
+ justifyContent: 'space-between',
56
+ paddingHorizontal: tokens.spacing.md,
57
+ paddingVertical: tokens.spacing.sm,
58
+ marginBottom: tokens.spacing.sm,
59
+ },
60
+ title: {
61
+ fontSize: 20,
62
+ fontWeight: "700",
63
+ color: tokens.colors.textPrimary,
64
+ marginBottom: 4,
65
+ },
66
+ subtitle: {
67
+ fontSize: 14,
68
+ color: tokens.colors.textSecondary,
69
+ opacity: 0.6
70
+ },
71
+ filterButton: {
72
+ flexDirection: 'row',
73
+ alignItems: 'center',
74
+ gap: tokens.spacing.xs,
75
+ paddingVertical: tokens.spacing.xs,
76
+ paddingHorizontal: tokens.spacing.md,
77
+ borderRadius: 999,
78
+ backgroundColor: tokens.colors.surfaceVariant,
79
+ borderWidth: 1,
80
+ borderColor: 'transparent',
81
+ },
82
+ filterButtonActive: {
83
+ backgroundColor: tokens.colors.primary + "15",
84
+ borderColor: tokens.colors.primary + "30",
85
+ },
86
+ filterText: {
87
+ fontSize: 14,
88
+ fontWeight: "500",
89
+ },
90
+ badge: {
91
+ width: 8,
92
+ height: 8,
93
+ borderRadius: 4,
94
+ backgroundColor: tokens.colors.primary,
95
+ position: 'absolute',
96
+ top: 6,
97
+ right: 6,
98
+ },
99
+ });
@@ -8,10 +8,6 @@ import type { Creation } from "../../domain/entities/Creation";
8
8
 
9
9
  const ALL_FILTER = "all";
10
10
 
11
- interface UseCreationsFilterProps {
12
- readonly creations: Creation[] | undefined;
13
- }
14
-
15
11
  import { FilterUtils } from "@umituz/react-native-filter";
16
12
 
17
13
  interface UseCreationsFilterProps {
@@ -20,6 +20,7 @@ import { EmptyState } from "../components/EmptyState";
20
20
  import { FilterBottomSheet, type FilterCategory } from "@umituz/react-native-filter";
21
21
  import { BottomSheetModalRef } from "@umituz/react-native-bottom-sheet";
22
22
  import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system";
23
+ import { GalleryHeader } from "../components/GalleryHeader";
23
24
 
24
25
  interface CreationsGalleryScreenProps {
25
26
  readonly userId: string | null;
@@ -60,13 +61,13 @@ export function CreationsGalleryScreen({
60
61
  // Add dynamic types category if types exist
61
62
  if (config.types.length > 0) {
62
63
  categories.push({
63
- id: 'type', // This ID matches logic in useFilter? No, filter logic is flat ID based. 'type' is category ID.
64
+ id: 'type',
64
65
  title: t('creations.category') || 'Category',
65
66
  multiSelect: false,
66
67
  options: config.types.map(t => ({
67
68
  id: t.id,
68
- label: t.labelKey, // In a real app we'd translate this, but for now passing key or mocked
69
- icon: 'Image', // Default icon since types have emojis which might not work with AtomicIcon
69
+ label: t.labelKey,
70
+ icon: 'Image',
70
71
  }))
71
72
  });
72
73
  }
@@ -138,38 +139,6 @@ export function CreationsGalleryScreen({
138
139
  flex: 1,
139
140
  backgroundColor: tokens.colors.backgroundPrimary,
140
141
  },
141
- headerArea: {
142
- flexDirection: "row",
143
- alignItems: "center",
144
- justifyContent: 'space-between',
145
- paddingHorizontal: tokens.spacing.md,
146
- paddingVertical: tokens.spacing.sm,
147
- marginBottom: tokens.spacing.sm,
148
- },
149
- filterButton: {
150
- flexDirection: 'row',
151
- alignItems: 'center',
152
- gap: tokens.spacing.xs,
153
- paddingVertical: tokens.spacing.xs,
154
- paddingHorizontal: tokens.spacing.md,
155
- borderRadius: (tokens as any).borders?.radius?.full || 999,
156
- backgroundColor: tokens.colors.surfaceVariant,
157
- borderWidth: 1,
158
- borderColor: 'transparent',
159
- },
160
- filterButtonActive: {
161
- backgroundColor: tokens.colors.primary + "15",
162
- borderColor: tokens.colors.primary + "30",
163
- },
164
- badge: {
165
- width: 8,
166
- height: 8,
167
- borderRadius: 4,
168
- backgroundColor: tokens.colors.primary,
169
- position: 'absolute',
170
- top: 6,
171
- right: 6,
172
- },
173
142
  list: {
174
143
  paddingHorizontal: tokens.spacing.md,
175
144
  paddingBottom: insets.bottom + tokens.spacing.xl,
@@ -210,22 +179,14 @@ export function CreationsGalleryScreen({
210
179
 
211
180
  return (
212
181
  <View style={styles.container}>
213
- <View style={styles.headerArea}>
214
- <View>
215
- <AtomicText type="headlineSmall">{t(config.translations.title) || 'My Creations'}</AtomicText>
216
- <AtomicText type="bodySmall" style={{ opacity: 0.6 }}>{filtered.length} {t(config.translations.photoCount) || 'photos'}</AtomicText>
217
- </View>
218
- <TouchableOpacity
219
- onPress={() => filterSheetRef.current?.present()}
220
- style={[styles.filterButton, isFiltered && styles.filterButtonActive]}
221
- >
222
- <AtomicIcon name="ListFilter" size="sm" color={isFiltered ? "primary" : "secondary"} />
223
- <AtomicText type="labelMedium" color={isFiltered ? "primary" : "secondary"}>Filter</AtomicText>
224
- {isFiltered && (
225
- <View style={styles.badge} />
226
- )}
227
- </TouchableOpacity>
228
- </View>
182
+ <GalleryHeader
183
+ title={t(config.translations.title) || 'My Creations'}
184
+ count={filtered.length}
185
+ countLabel={t(config.translations.photoCount) || 'photos'}
186
+ isFiltered={isFiltered}
187
+ onFilterPress={() => filterSheetRef.current?.present()}
188
+ />
189
+
229
190
  <FlatList
230
191
  data={filtered}
231
192
  renderItem={renderItem}