@linktr.ee/messaging-react 1.0.1 → 1.0.2

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": "@linktr.ee/messaging-react",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -61,7 +61,7 @@
61
61
  "react-dom": "^18.3.1",
62
62
  "storybook": "^8.5.0",
63
63
  "stream-chat": "^9.22.1",
64
- "tailwindcss": "3.2.7",
64
+ "tailwindcss": "^3.4.17",
65
65
  "tailwindcss-animate": "^1.0.7",
66
66
  "typescript": "5.9.2",
67
67
  "vite": "^6.0.7",
@@ -75,4 +75,4 @@
75
75
  "stream-chat": "^9.22.1",
76
76
  "stream-chat-react": "^13.9.0"
77
77
  }
78
- }
78
+ }
@@ -3,34 +3,33 @@
3
3
  * Uses the ID to deterministically select from design system colors
4
4
  */
5
5
  export function getAvatarColors(id: string): {
6
- bgColor: string;
7
- textColor: string;
6
+ bgColor: string
7
+ textColor: string
8
8
  } {
9
9
  // Map of color combinations from Linktree design system
10
10
  // Selected for good contrast at 20% opacity
11
11
  const colorPairs = [
12
- { bgColor: "bg-primary bg-opacity-20", textColor: "text-primary" }, // #8129D9 - purple
13
- { bgColor: "bg-forest bg-opacity-20", textColor: "text-forest" }, // #254f1a - dark green
14
- { bgColor: "bg-iris bg-opacity-20", textColor: "text-iris" }, // #061492 - dark blue
15
- { bgColor: "bg-shade bg-opacity-20", textColor: "text-shade" }, // #1e2330 - dark blue-gray
16
- { bgColor: "bg-dahlia bg-opacity-20", textColor: "text-dahlia" }, // #502274 - dark purple
17
- { bgColor: "bg-orchid bg-opacity-20", textColor: "text-orchid" }, // #d717e7 - magenta
18
- { bgColor: "bg-currant bg-opacity-20", textColor: "text-currant" }, // #780016 - dark red
19
- { bgColor: "bg-apple bg-opacity-20", textColor: "text-apple" }, // #c41500 - red
20
- { bgColor: "bg-rose bg-opacity-20", textColor: "text-rose" }, // #fc3e4b - pink
21
- { bgColor: "bg-root bg-opacity-20", textColor: "text-root" }, // #4c2e05 - brown
22
- { bgColor: "bg-poppy bg-opacity-20", textColor: "text-poppy" }, // #ff6c02 - orange
23
- { bgColor: "bg-moss bg-opacity-20", textColor: "text-moss" }, // #70764d - olive green
24
- ];
12
+ { bgColor: 'bg-primary/20', textColor: 'text-primary' }, // #8129D9 - purple
13
+ { bgColor: 'bg-forest/20', textColor: 'text-forest' }, // #254f1a - dark green
14
+ { bgColor: 'bg-iris/20', textColor: 'text-iris' }, // #061492 - dark blue
15
+ { bgColor: 'bg-shade/20', textColor: 'text-shade' }, // #1e2330 - dark blue-gray
16
+ { bgColor: 'bg-dahlia/20', textColor: 'text-dahlia' }, // #502274 - dark purple
17
+ { bgColor: 'bg-orchid/20', textColor: 'text-orchid' }, // #d717e7 - magenta
18
+ { bgColor: 'bg-currant/20', textColor: 'text-currant' }, // #780016 - dark red
19
+ { bgColor: 'bg-apple/20', textColor: 'text-apple' }, // #c41500 - red
20
+ { bgColor: 'bg-rose/20', textColor: 'text-rose' }, // #fc3e4b - pink
21
+ { bgColor: 'bg-root/20', textColor: 'text-root' }, // #4c2e05 - brown
22
+ { bgColor: 'bg-poppy/20', textColor: 'text-poppy' }, // #ff6c02 - orange
23
+ { bgColor: 'bg-moss/20', textColor: 'text-moss' }, // #70764d - olive green
24
+ ]
25
25
 
26
26
  // Simple hash function to get consistent index
27
- let hash = 0;
27
+ let hash = 0
28
28
  for (let i = 0; i < id.length; i++) {
29
- hash = ((hash << 5) - hash) + id.charCodeAt(i);
30
- hash = hash & hash; // Convert to 32bit integer
29
+ hash = (hash << 5) - hash + id.charCodeAt(i)
30
+ hash = hash & hash // Convert to 32bit integer
31
31
  }
32
-
33
- const index = Math.abs(hash) % colorPairs.length;
34
- return colorPairs[index];
35
- }
36
32
 
33
+ const index = Math.abs(hash) % colorPairs.length
34
+ return colorPairs[index]
35
+ }
@@ -1,48 +1,55 @@
1
- import React from 'react';
2
- import { ChannelPreviewUIComponentProps } from 'stream-chat-react';
3
- import { Channel } from 'stream-chat';
4
- import classNames from 'classnames';
5
- import { Avatar } from '../Avatar';
1
+ import React from 'react'
2
+ import { ChannelPreviewUIComponentProps } from 'stream-chat-react'
3
+ import { Channel } from 'stream-chat'
4
+ import classNames from 'classnames'
5
+ import { Avatar } from '../Avatar'
6
6
 
7
7
  /**
8
8
  * Custom channel preview that handles selection
9
9
  */
10
10
  const CustomChannelPreview: React.FC<
11
11
  ChannelPreviewUIComponentProps & {
12
- selectedChannel?: Channel;
13
- onChannelSelect: (channel: Channel) => void;
14
- debug?: boolean;
12
+ selectedChannel?: Channel
13
+ onChannelSelect: (channel: Channel) => void
14
+ debug?: boolean
15
15
  }
16
- > = ({ channel, selectedChannel, onChannelSelect, debug = false, ...props }) => {
17
- const isSelected = selectedChannel?.id === channel?.id;
16
+ > = ({
17
+ channel,
18
+ selectedChannel,
19
+ onChannelSelect,
20
+ debug = false,
21
+ ...props
22
+ }) => {
23
+ const isSelected = selectedChannel?.id === channel?.id
18
24
 
19
25
  const handleClick = () => {
20
26
  if (channel) {
21
- onChannelSelect(channel);
27
+ onChannelSelect(channel)
22
28
  }
23
- };
29
+ }
24
30
 
25
31
  // Get participant info
26
- const members = Object.values(channel?.state?.members || {});
27
- const participant = members.find(member =>
28
- member.user?.id && member.user.id !== channel?._client?.userID
29
- );
30
- const participantName = participant?.user?.name || 'Conversation';
31
- const participantImage = participant?.user?.image;
32
- const participantInitial = participantName.charAt(0).toUpperCase();
32
+ const members = Object.values(channel?.state?.members || {})
33
+ const participant = members.find(
34
+ (member) => member.user?.id && member.user.id !== channel?._client?.userID
35
+ )
36
+ const participantName = participant?.user?.name || 'Conversation'
37
+ const participantImage = participant?.user?.image
38
+ const participantInitial = participantName.charAt(0).toUpperCase()
33
39
 
34
40
  // Get last message and format timestamp
35
- const lastMessage = channel?.state?.messages?.[channel.state.messages.length - 1];
36
- const lastMessageText = lastMessage?.text || 'No messages yet';
41
+ const lastMessage =
42
+ channel?.state?.messages?.[channel.state.messages.length - 1]
43
+ const lastMessageText = lastMessage?.text || 'No messages yet'
37
44
  const lastMessageTime = lastMessage?.created_at
38
45
  ? new Date(lastMessage.created_at).toLocaleTimeString([], {
39
46
  hour: '2-digit',
40
47
  minute: '2-digit',
41
48
  })
42
- : '';
49
+ : ''
43
50
 
44
51
  // Get unread count from channel state
45
- const unread = channel?.state?.unreadCount || 0;
52
+ const unread = channel?.state?.unreadCount || 0
46
53
 
47
54
  if (debug) {
48
55
  console.log('📺 [ChannelList] 📋 CHANNEL PREVIEW RENDER', {
@@ -51,7 +58,7 @@ const CustomChannelPreview: React.FC<
51
58
  participantName,
52
59
  unread,
53
60
  hasTimestamp: !!lastMessageTime,
54
- });
61
+ })
55
62
  }
56
63
 
57
64
  return (
@@ -61,7 +68,7 @@ const CustomChannelPreview: React.FC<
61
68
  className={classNames(
62
69
  'w-full px-4 py-3 transition-colors border-b border-sand text-left max-w-full overflow-hidden focus-ring',
63
70
  {
64
- 'bg-primary-alt bg-opacity-10 border-l-4 border-l-primary': isSelected,
71
+ 'bg-primary-alt/10 border-l-4 border-l-primary': isSelected,
65
72
  'hover:bg-sand': !isSelected,
66
73
  }
67
74
  )}
@@ -108,7 +115,7 @@ const CustomChannelPreview: React.FC<
108
115
  </div>
109
116
  </div>
110
117
  </button>
111
- );
112
- };
118
+ )
119
+ }
113
120
 
114
- export default CustomChannelPreview;
121
+ export default CustomChannelPreview
@@ -1,22 +1,20 @@
1
- import React from 'react';
1
+ import React from 'react'
2
2
 
3
3
  /**
4
4
  * Empty state component shown when no channel is selected
5
5
  */
6
6
  export const EmptyState: React.FC<{
7
- hasChannels: boolean;
8
- onStartConversation?: () => void;
9
- participantLabel: string;
7
+ hasChannels: boolean
8
+ onStartConversation?: () => void
9
+ participantLabel: string
10
10
  }> = ({ hasChannels, onStartConversation, participantLabel }) => (
11
11
  <div className="flex items-center justify-center h-full p-8 text-balance">
12
12
  <div className="text-center max-w-sm">
13
- <div className="w-24 h-24 bg-primary-alt bg-opacity-10 rounded-full flex items-center justify-center mx-auto mb-6">
13
+ <div className="w-24 h-24 bg-primary-alt/10 rounded-full flex items-center justify-center mx-auto mb-6">
14
14
  <span className="text-4xl">💬</span>
15
15
  </div>
16
16
 
17
- <h2 className="font-semibold text-charcoal">
18
- Welcome to Messages
19
- </h2>
17
+ <h2 className="font-semibold text-charcoal">Welcome to Messages</h2>
20
18
 
21
19
  <p className="text-stone text-sm mb-6">
22
20
  {hasChannels ? (
@@ -31,25 +29,30 @@ export const EmptyState: React.FC<{
31
29
  ) : (
32
30
  onStartConversation && (
33
31
  <>
34
- <TextButton onClick={onStartConversation}>
35
- Start a new conversation with one of your {participantLabel}
36
- </TextButton>{' '}
37
- to begin messaging.
38
- </>
32
+ <TextButton onClick={onStartConversation}>
33
+ Start a new conversation with one of your {participantLabel}
34
+ </TextButton>{' '}
35
+ to begin messaging.
36
+ </>
39
37
  )
40
38
  )}
41
39
  </p>
42
40
  </div>
43
41
  </div>
44
- );
45
-
42
+ )
46
43
 
47
- const TextButton = ({ onClick, children }: { onClick: () => void, children: React.ReactNode }) => (
44
+ const TextButton = ({
45
+ onClick,
46
+ children,
47
+ }: {
48
+ onClick: () => void
49
+ children: React.ReactNode
50
+ }) => (
48
51
  <button
49
- type="button"
50
- onClick={onClick}
51
- className="inline-flex items-center gap-1 text-sm font-medium text-primary hover:text-primary-alt focus:outline-none focus:ring-2 focus:ring-primary"
52
+ type="button"
53
+ onClick={onClick}
54
+ className="inline-flex items-center gap-1 text-sm font-medium text-primary hover:text-primary-alt focus:outline-none focus:ring-2 focus:ring-primary"
52
55
  >
53
56
  {children}
54
57
  </button>
55
- )
58
+ )