@umituz/react-native-design-system 2.6.55 → 2.6.57
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-design-system",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.57",
|
|
4
4
|
"description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive and safe area utilities",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -287,6 +287,11 @@ export {
|
|
|
287
287
|
type AvatarShape,
|
|
288
288
|
type AvatarConfig,
|
|
289
289
|
type AvatarType,
|
|
290
|
+
// Media Card
|
|
291
|
+
MediaCard,
|
|
292
|
+
type MediaCardProps,
|
|
293
|
+
type MediaCardSize,
|
|
294
|
+
type MediaCardOverlayPosition,
|
|
290
295
|
// Bottom Sheet
|
|
291
296
|
BottomSheet,
|
|
292
297
|
BottomSheetModal,
|
package/src/molecules/index.ts
CHANGED
|
@@ -8,6 +8,14 @@ export * from './avatar';
|
|
|
8
8
|
export * from './bottom-sheet';
|
|
9
9
|
export { FormField, type FormFieldProps } from './FormField';
|
|
10
10
|
export { ListItem, type ListItemProps } from './ListItem';
|
|
11
|
+
|
|
12
|
+
// Media Card
|
|
13
|
+
export { MediaCard } from './media-card';
|
|
14
|
+
export type {
|
|
15
|
+
MediaCardProps,
|
|
16
|
+
MediaCardSize,
|
|
17
|
+
MediaCardOverlayPosition,
|
|
18
|
+
} from './media-card';
|
|
11
19
|
export { SearchBar, type SearchBarProps } from './SearchBar';
|
|
12
20
|
export { IconContainer } from './IconContainer';
|
|
13
21
|
export { BaseModal, type BaseModalProps } from './BaseModal';
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AtomicMediaCard - Reusable media card component
|
|
3
|
+
*
|
|
4
|
+
* Displays an image with optional overlay text, badge, and selection state.
|
|
5
|
+
* Used for grids of images, memes, templates, etc.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import {
|
|
10
|
+
View,
|
|
11
|
+
StyleSheet,
|
|
12
|
+
TouchableOpacity,
|
|
13
|
+
Image,
|
|
14
|
+
type ImageStyle,
|
|
15
|
+
} from 'react-native';
|
|
16
|
+
import { AtomicText, AtomicIcon } from '../../atoms';
|
|
17
|
+
import { useAppDesignTokens } from '../../theme';
|
|
18
|
+
|
|
19
|
+
import type { MediaCardProps } from './types';
|
|
20
|
+
|
|
21
|
+
export const MediaCard: React.FC<MediaCardProps> = ({
|
|
22
|
+
uri,
|
|
23
|
+
title,
|
|
24
|
+
subtitle,
|
|
25
|
+
badge,
|
|
26
|
+
selected = false,
|
|
27
|
+
size = 'md',
|
|
28
|
+
aspectRatio = 0.8,
|
|
29
|
+
overlayPosition = 'bottom',
|
|
30
|
+
showOverlay = true,
|
|
31
|
+
onPress,
|
|
32
|
+
width,
|
|
33
|
+
testID,
|
|
34
|
+
}) => {
|
|
35
|
+
const tokens = useAppDesignTokens();
|
|
36
|
+
|
|
37
|
+
const sizeConfig = {
|
|
38
|
+
sm: { width: width || 120, borderRadius: tokens.radius.sm },
|
|
39
|
+
md: { width: width || 144, borderRadius: tokens.radius.md },
|
|
40
|
+
lg: { width: width || 160, borderRadius: tokens.radius.lg },
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const config = sizeConfig[size];
|
|
44
|
+
const height = config.width / aspectRatio;
|
|
45
|
+
|
|
46
|
+
const styles = StyleSheet.create({
|
|
47
|
+
container: {
|
|
48
|
+
width: config.width,
|
|
49
|
+
height,
|
|
50
|
+
borderRadius: config.borderRadius,
|
|
51
|
+
overflow: 'hidden',
|
|
52
|
+
backgroundColor: tokens.colors.surfaceVariant,
|
|
53
|
+
borderWidth: selected ? 2 : 1,
|
|
54
|
+
borderColor: selected ? tokens.colors.primary : 'rgba(255,255,255,0.1)',
|
|
55
|
+
},
|
|
56
|
+
image: {
|
|
57
|
+
width: '100%',
|
|
58
|
+
height: '100%',
|
|
59
|
+
} as ImageStyle,
|
|
60
|
+
badge: {
|
|
61
|
+
position: 'absolute',
|
|
62
|
+
top: tokens.spacing.sm,
|
|
63
|
+
right: tokens.spacing.sm,
|
|
64
|
+
backgroundColor: tokens.colors.primary,
|
|
65
|
+
paddingHorizontal: tokens.spacing.sm,
|
|
66
|
+
paddingVertical: 2,
|
|
67
|
+
borderRadius: 999,
|
|
68
|
+
zIndex: 10,
|
|
69
|
+
},
|
|
70
|
+
badgeText: {
|
|
71
|
+
color: tokens.colors.onPrimary,
|
|
72
|
+
fontSize: 10,
|
|
73
|
+
fontWeight: 'bold',
|
|
74
|
+
},
|
|
75
|
+
overlay: {
|
|
76
|
+
...StyleSheet.absoluteFillObject,
|
|
77
|
+
backgroundColor: 'rgba(0,0,0,0.3)',
|
|
78
|
+
justifyContent:
|
|
79
|
+
overlayPosition === 'center' ? 'center' : 'flex-end',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
paddingBottom:
|
|
82
|
+
overlayPosition === 'bottom' ? tokens.spacing.md : 0,
|
|
83
|
+
},
|
|
84
|
+
textContainer: {
|
|
85
|
+
paddingHorizontal: tokens.spacing.md,
|
|
86
|
+
width: '100%',
|
|
87
|
+
},
|
|
88
|
+
title: {
|
|
89
|
+
fontSize: 14,
|
|
90
|
+
fontWeight: 'bold',
|
|
91
|
+
color: tokens.colors.textInverse,
|
|
92
|
+
textShadowColor: 'rgba(0,0,0,0.75)',
|
|
93
|
+
textShadowOffset: { width: 0, height: 1 },
|
|
94
|
+
textShadowRadius: 3,
|
|
95
|
+
textAlign: 'center',
|
|
96
|
+
},
|
|
97
|
+
subtitle: {
|
|
98
|
+
fontSize: 12,
|
|
99
|
+
color: tokens.colors.textSecondary,
|
|
100
|
+
textShadowColor: 'rgba(0,0,0,0.75)',
|
|
101
|
+
textShadowOffset: { width: 0, height: 1 },
|
|
102
|
+
textShadowRadius: 3,
|
|
103
|
+
textAlign: 'center',
|
|
104
|
+
},
|
|
105
|
+
checkCircle: {
|
|
106
|
+
backgroundColor: 'rgba(0,0,0,0.6)',
|
|
107
|
+
borderRadius: 999,
|
|
108
|
+
padding: tokens.spacing.sm,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const CardWrapper = onPress ? TouchableOpacity : View;
|
|
113
|
+
const wrapperProps = onPress
|
|
114
|
+
? {
|
|
115
|
+
onPress,
|
|
116
|
+
activeOpacity: 0.8,
|
|
117
|
+
testID,
|
|
118
|
+
}
|
|
119
|
+
: { testID };
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<CardWrapper style={styles.container} {...wrapperProps}>
|
|
123
|
+
{badge && (
|
|
124
|
+
<View style={styles.badge}>
|
|
125
|
+
<AtomicText style={styles.badgeText}>{badge}</AtomicText>
|
|
126
|
+
</View>
|
|
127
|
+
)}
|
|
128
|
+
<Image source={{ uri }} style={styles.image} contentFit="cover" />
|
|
129
|
+
|
|
130
|
+
{showOverlay && (title || subtitle) && (
|
|
131
|
+
<View style={styles.overlay}>
|
|
132
|
+
<View style={styles.textContainer}>
|
|
133
|
+
{title && (
|
|
134
|
+
<AtomicText style={styles.title} numberOfLines={1}>
|
|
135
|
+
{title}
|
|
136
|
+
</AtomicText>
|
|
137
|
+
)}
|
|
138
|
+
{subtitle && (
|
|
139
|
+
<AtomicText style={styles.subtitle} numberOfLines={1}>
|
|
140
|
+
{subtitle}
|
|
141
|
+
</AtomicText>
|
|
142
|
+
)}
|
|
143
|
+
</View>
|
|
144
|
+
</View>
|
|
145
|
+
)}
|
|
146
|
+
|
|
147
|
+
{selected && (
|
|
148
|
+
<View
|
|
149
|
+
style={[
|
|
150
|
+
styles.overlay,
|
|
151
|
+
]}
|
|
152
|
+
>
|
|
153
|
+
<View style={styles.checkCircle}>
|
|
154
|
+
<AtomicIcon name="checkmark-outline" size="md" color="primary" />
|
|
155
|
+
</View>
|
|
156
|
+
</View>
|
|
157
|
+
)}
|
|
158
|
+
</CardWrapper>
|
|
159
|
+
);
|
|
160
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type MediaCardSize = 'sm' | 'md' | 'lg';
|
|
2
|
+
export type MediaCardOverlayPosition = 'bottom' | 'center';
|
|
3
|
+
|
|
4
|
+
export interface MediaCardProps {
|
|
5
|
+
/** Image URI to display */
|
|
6
|
+
uri: string;
|
|
7
|
+
|
|
8
|
+
/** Optional title text */
|
|
9
|
+
title?: string;
|
|
10
|
+
|
|
11
|
+
/** Optional subtitle text (uses count, etc.) */
|
|
12
|
+
subtitle?: string;
|
|
13
|
+
|
|
14
|
+
/** Optional badge text (NEW, etc.) */
|
|
15
|
+
badge?: string;
|
|
16
|
+
|
|
17
|
+
/** Whether the card is selected */
|
|
18
|
+
selected?: boolean;
|
|
19
|
+
|
|
20
|
+
/** Card size */
|
|
21
|
+
size?: MediaCardSize;
|
|
22
|
+
|
|
23
|
+
/** Aspect ratio (width/height) */
|
|
24
|
+
aspectRatio?: number;
|
|
25
|
+
|
|
26
|
+
/** Overlay position */
|
|
27
|
+
overlayPosition?: MediaCardOverlayPosition;
|
|
28
|
+
|
|
29
|
+
/** Whether to show overlay */
|
|
30
|
+
showOverlay?: boolean;
|
|
31
|
+
|
|
32
|
+
/** Press handler */
|
|
33
|
+
onPress?: () => void;
|
|
34
|
+
|
|
35
|
+
/** Custom width */
|
|
36
|
+
width?: number;
|
|
37
|
+
|
|
38
|
+
/** Test ID */
|
|
39
|
+
testID?: string;
|
|
40
|
+
}
|