rn-vs-lb 1.0.69 → 1.0.70

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.
@@ -28,6 +28,8 @@ const meta: Meta<ChatItemProps> = {
28
28
  export default meta;
29
29
 
30
30
  const Template: StoryFn<ChatItemProps> = (args) => <ChatItem {...args} />;
31
+ const getItemLabel = (item: ChatItemProps, idx: number) =>
32
+ item.variant === 'person' ? item.chatName ?? item.senderFullName : item.chatName ?? `chat-${idx}`;
31
33
 
32
34
  export const PersonOnline = Template.bind({});
33
35
  PersonOnline.args = {
@@ -38,7 +40,7 @@ PersonOnline.args = {
38
40
  isUserOnline: true,
39
41
  lastMessage: 'See you at 6pm near the station',
40
42
  createdAt: '10:42',
41
- unread: '+',
43
+ unread: 'new',
42
44
  };
43
45
 
44
46
  export const PersonOffline = Template.bind({});
@@ -61,7 +63,7 @@ GroupWithSender.args = {
61
63
  'https://images.unsplash.com/photo-1519340241574-2cec6aef0c01?auto=format&fit=crop&w=200&q=60',
62
64
  lastMessage: 'Slides are uploaded to Drive, check the link above.',
63
65
  createdAt: 'Yesterday',
64
- unread: '+',
66
+ unread: 'new',
65
67
  };
66
68
 
67
69
  export const Bot = Template.bind({});
@@ -94,7 +96,7 @@ export const ListOfItems: StoryFn = () => {
94
96
  isUserOnline: true,
95
97
  lastMessage: 'See you soon!',
96
98
  createdAt: '10:42',
97
- unread: '+',
99
+ unread: 'new',
98
100
  },
99
101
  {
100
102
  variant: 'person',
@@ -113,7 +115,7 @@ export const ListOfItems: StoryFn = () => {
113
115
  'https://images.unsplash.com/photo-1519340241574-2cec6aef0c01?auto=format&fit=crop&w=200&q=60',
114
116
  lastMessage: 'Standup in 5 minutes.',
115
117
  createdAt: '08:55',
116
- unread: '+',
118
+ unread: 'new',
117
119
  },
118
120
  {
119
121
  variant: 'group',
@@ -166,7 +168,7 @@ export const ListOfItems: StoryFn = () => {
166
168
  <ChatItem
167
169
  key={idx}
168
170
  {...item}
169
- onPress={createPressHandler(item.chatName ?? item.senderFullName ?? `chat-${idx}`)}
171
+ onPress={createPressHandler(getItemLabel(item, idx))}
170
172
  />
171
173
  ))}
172
174
  </ScrollView>
@@ -3,65 +3,98 @@ import { ThemeType } from '../../theme';
3
3
 
4
4
  export const getStyles = (theme: ThemeType) => StyleSheet.create({
5
5
  userContainer: {
6
- flexDirection: 'row',
7
- alignItems: 'center',
8
- paddingVertical: 12,
9
- paddingHorizontal: 8,
6
+ paddingVertical: 8,
7
+ paddingHorizontal: 12,
8
+ borderRadius: 16,
9
+ backgroundColor: theme.white,
10
10
  },
11
11
  profileSection: {
12
12
  flexDirection: 'row',
13
- alignItems: 'center',
13
+ alignItems: 'flex-start',
14
14
  flex: 1,
15
15
  },
16
16
  avatar: {
17
- width: 60,
18
- height: 60,
19
- borderRadius: 40,
17
+ width: 56,
18
+ height: 56,
19
+ borderRadius: 28,
20
20
  },
21
21
  userInfo: {
22
22
  flex: 1,
23
23
  marginLeft: 12,
24
+ minHeight: 56,
25
+ justifyContent: 'center',
26
+ },
27
+ headerRow: {
28
+ flexDirection: 'row',
29
+ alignItems: 'center',
30
+ justifyContent: 'space-between',
31
+ gap: 8,
24
32
  },
25
- senderContainer: {
33
+ headerRight: {
26
34
  flexDirection: 'row',
27
- alignItems: "center",
28
- // justifyContent: "space-between",
29
- },
30
- unread: {
31
- // top:10,
32
- marginLeft: 8,
33
- width:18,
34
- height: 18,
35
- textAlign:"center",
35
+ alignItems: 'center',
36
+ gap: 8,
37
+ },
38
+ chatTitle: {
39
+ flex: 1,
40
+ },
41
+ unreadBadge: {
42
+ minHeight: 20,
43
+ paddingHorizontal: 8,
44
+ borderRadius: 999,
36
45
  backgroundColor: theme.success,
46
+ flexDirection: 'row',
47
+ alignItems: 'center',
48
+ gap: 5,
49
+ },
50
+ unreadDot: {
51
+ width: 6,
52
+ height: 6,
53
+ borderRadius: 3,
54
+ backgroundColor: theme.white,
55
+ },
56
+ unreadText: {
37
57
  color: theme.white,
38
- borderRadius: 20,
39
- fontSize: 12,
40
- lineHeight: 16,
58
+ fontSize: 10,
59
+ lineHeight: 12,
60
+ fontWeight: '700',
61
+ letterSpacing: 0.3,
62
+ textTransform: 'uppercase',
63
+ },
64
+ messageRow: {
65
+ marginTop: 4,
41
66
  },
42
67
  senderName: {
43
68
  fontSize: 14,
44
- marginRight: 4,
69
+ color: theme.placeholder,
70
+ },
71
+ senderNameUnread: {
45
72
  color: theme.text,
73
+ fontWeight: '500',
46
74
  },
47
75
  senderMessage: {
48
76
  fontSize: 13,
49
77
  fontStyle: 'italic',
78
+ color: theme.placeholder,
50
79
  },
51
80
  timeAgo: {
52
- fontSize: 13,
81
+ fontSize: 12,
53
82
  color: theme.placeholder,
83
+ fontWeight: '500',
84
+ },
85
+ timeAgoUnread: {
86
+ color: theme.text,
54
87
  },
55
88
 
56
89
  status: {
57
- position: "absolute",
58
- width:12,
90
+ position: 'absolute',
91
+ width: 12,
59
92
  height: 12,
60
93
  borderWidth: 2,
61
94
  borderColor: theme.white,
62
95
  borderRadius: 10,
63
96
  bottom: 0,
64
- right:1,
97
+ right: 1,
65
98
  },
66
99
  online: {
67
100
  backgroundColor: theme.success,
@@ -6,7 +6,7 @@ import { useTheme } from '../../theme';
6
6
  import { getStyles } from './ChatItem.styles';
7
7
 
8
8
  type BaseProps = {
9
- unread?: string;
9
+ unread?: string | boolean;
10
10
  onPress?: () => void;
11
11
  createdAt?: string;
12
12
  lastMessage?: string;
@@ -40,26 +40,42 @@ export type ChatItemProps = PersonProps | GroupProps | BotProps;
40
40
  export const ChatItem: FC<ChatItemProps> = (props) => {
41
41
  const { theme, typography } = useTheme();
42
42
  const styles = getStyles(theme);
43
+ const hasUnread = Boolean(props.unread);
44
+ const unreadLabel =
45
+ typeof props.unread === 'string' && props.unread.trim().length > 0 && props.unread.trim() !== '+'
46
+ ? props.unread.trim().toUpperCase()
47
+ : 'NEW';
43
48
 
44
49
  const handlePress = () => props.onPress?.();
45
50
 
46
- // Общий заголовок (верхняя строка) + бейдж непрочитанного
51
+ // Общий заголовок (верхняя строка) + время + бейдж непрочитанного
47
52
  const renderHeader = (title: string) => (
48
- <View style={styles.senderContainer}>
49
- <Text numberOfLines={1} ellipsizeMode="tail" style={typography.titleH6}>
53
+ <View style={styles.headerRow}>
54
+ <Text numberOfLines={1} ellipsizeMode="tail" style={[typography.titleH6, styles.chatTitle]}>
50
55
  {title}
51
56
  </Text>
52
- {props.unread ? <Text style={styles.unread}>+</Text> : null}
57
+ <View style={styles.headerRight}>
58
+ {props.createdAt ? (
59
+ <Text style={[styles.timeAgo, hasUnread && styles.timeAgoUnread]}>{props.createdAt}</Text>
60
+ ) : null}
61
+ {hasUnread ? (
62
+ <View style={styles.unreadBadge}>
63
+ <View style={styles.unreadDot} />
64
+ <Text style={styles.unreadText}>{unreadLabel}</Text>
65
+ </View>
66
+ ) : null}
67
+ </View>
53
68
  </View>
54
69
  );
55
70
 
56
71
  // Превью последнего сообщения (нижний блок)
57
72
  const renderLastMessage = () => {
58
73
  if (!props.lastMessage) return null;
74
+ const previewStyle = [styles.senderName, hasUnread && styles.senderNameUnread];
59
75
 
60
76
  if (props.variant === 'person') {
61
77
  return (
62
- <Text numberOfLines={2} ellipsizeMode="tail" style={styles.senderName}>
78
+ <Text numberOfLines={2} ellipsizeMode="tail" style={previewStyle}>
63
79
  {props.senderFullName}: <Text style={styles.senderMessage}>{props.lastMessage}</Text>
64
80
  </Text>
65
81
  );
@@ -67,7 +83,7 @@ export const ChatItem: FC<ChatItemProps> = (props) => {
67
83
 
68
84
  if (props.variant === 'group' && props.senderFullName) {
69
85
  return (
70
- <Text numberOfLines={2} ellipsizeMode="tail" style={styles.senderName}>
86
+ <Text numberOfLines={2} ellipsizeMode="tail" style={previewStyle}>
71
87
  {props.senderFullName}: <Text style={styles.senderMessage}>{props.lastMessage}</Text>
72
88
  </Text>
73
89
  );
@@ -75,7 +91,7 @@ export const ChatItem: FC<ChatItemProps> = (props) => {
75
91
 
76
92
  // bot или group без senderFullName
77
93
  return (
78
- <Text numberOfLines={2} ellipsizeMode="tail" style={styles.senderName}>
94
+ <Text numberOfLines={2} ellipsizeMode="tail" style={previewStyle}>
79
95
  {props.lastMessage}
80
96
  </Text>
81
97
  );
@@ -118,12 +134,7 @@ export const ChatItem: FC<ChatItemProps> = (props) => {
118
134
  {renderAvatar()}
119
135
  <View style={styles.userInfo}>
120
136
  {renderHeader(titleText)}
121
-
122
- <View style={styles.senderContainer}>{renderLastMessage()}</View>
123
-
124
- {props.lastMessage ? (
125
- <Text style={styles.timeAgo}>{props.createdAt}</Text>
126
- ) : null}
137
+ <View style={styles.messageRow}>{renderLastMessage()}</View>
127
138
  </View>
128
139
  </TouchableOpacity>
129
140
  </View>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-vs-lb",
3
- "version": "1.0.69",
3
+ "version": "1.0.70",
4
4
  "description": "Expo Router + Storybook template ready for npm distribution.",
5
5
  "keywords": [
6
6
  "expo",