@linktr.ee/messaging-react 1.22.0-rc-1771903841 → 1.22.0

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.22.0-rc-1771903841",
3
+ "version": "1.22.0",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -38,7 +38,7 @@ const createMockChannel = async (
38
38
  created_at: new Date(Date.now() - 1000 * 60 * (messages.length - index)),
39
39
  updated_at: new Date(Date.now() - 1000 * 60 * (messages.length - index)),
40
40
  html: `<p>${msg.text}</p>`,
41
- attachments: msg.attachments ?? [],
41
+ attachments: [],
42
42
  latest_reactions: [],
43
43
  own_reactions: [],
44
44
  reaction_counts: {},
@@ -91,7 +91,6 @@ interface TemplateProps {
91
91
  text: string
92
92
  user: typeof mockUser | { id: string; name: string }
93
93
  type?: 'regular' | 'system'
94
- attachments?: Array<Record<string, unknown>>
95
94
  metadata?: {
96
95
  custom_type?: 'MESSAGE_TIP' | 'MESSAGE_PAID' | 'MESSAGE_CHATBOT'
97
96
  amount_text?: string
@@ -207,37 +206,3 @@ MixedTags.args = {
207
206
  { id: 'msg-9', text: 'Thanks for letting me know.', user: mockUser },
208
207
  ],
209
208
  }
210
-
211
- export const ChatbotVariants: StoryFn<TemplateProps> = Template.bind({})
212
- ChatbotVariants.args = {
213
- messages: [
214
- {
215
- id: 'msg-1',
216
- text: 'Would you like to share some details that I can relay to Rupi Kaur?',
217
- user: participant,
218
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
219
- },
220
- {
221
- id: 'msg-2',
222
- text: 'I’m sorry to hear that. Are you referring to the course you’ve recently purchased?',
223
- user: mockUser,
224
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
225
- },
226
- {
227
- id: 'msg-3',
228
- text: '',
229
- user: mockUser,
230
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
231
- attachments: [
232
- {
233
- type: 'card',
234
- title: 'The Perfect Yoga Course',
235
- title_link: 'https://linktr.ee/rupikaur/learntoyoga',
236
- text: 'linktr.ee/rupikaur/learntoyoga',
237
- image_url:
238
- 'https://images.unsplash.com/photo-1571019613914-85f342c1d4b5?auto=format&fit=crop&w=1024&q=80',
239
- },
240
- ],
241
- },
242
- ],
243
- }
@@ -64,34 +64,11 @@ Paid.args = {
64
64
  }),
65
65
  }
66
66
 
67
- export const ChatbotReceiverText: StoryFn<ComponentProps> = Template.bind({})
68
- ChatbotReceiverText.args = {
67
+ export const Chatbot: StoryFn<ComponentProps> = Template.bind({})
68
+ Chatbot.args = {
69
69
  message: createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } }),
70
70
  }
71
71
 
72
- export const ChatbotSenderText: StoryFn<ComponentProps> = (args) => {
73
- return (
74
- <div className="p-12">
75
- <div className="bg-[#121110] rounded-3xl px-4 py-3 w-[280px]">
76
- <MessageTag {...args} />
77
- </div>
78
- </div>
79
- )
80
- }
81
- ChatbotSenderText.args = {
82
- message: createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } }),
83
- isMyMessage: true,
84
- }
85
-
86
- export const ChatbotSenderAttachment: StoryFn<ComponentProps> = Template.bind(
87
- {}
88
- )
89
- ChatbotSenderAttachment.args = {
90
- message: createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } }),
91
- isMyMessage: true,
92
- hasAttachment: true,
93
- }
94
-
95
72
  export const NoTag: StoryFn<ComponentProps> = Template.bind({})
96
73
  NoTag.args = {
97
74
  message: createMockMessage(),
@@ -127,36 +104,11 @@ export const AllVariants: StoryFn = () => {
127
104
  />
128
105
  </div>
129
106
  <div className="flex items-center gap-4">
130
- <span className="text-sm w-32">Chatbot (receiver):</span>
107
+ <span className="text-sm w-32">Chatbot:</span>
131
108
  <MessageTag
132
- message={createMockMessage({
133
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
134
- })}
109
+ message={createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } })}
135
110
  />
136
111
  </div>
137
- <div className="flex items-center gap-4">
138
- <span className="text-sm w-32">Chatbot (sender):</span>
139
- <div className="bg-[#121110] rounded-3xl px-4 py-3 w-[280px]">
140
- <MessageTag
141
- message={createMockMessage({
142
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
143
- })}
144
- isMyMessage
145
- />
146
- </div>
147
- </div>
148
- <div className="flex items-center gap-4">
149
- <span className="text-sm w-32">Chatbot (attachment):</span>
150
- <div className="w-[280px]">
151
- <MessageTag
152
- message={createMockMessage({
153
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
154
- })}
155
- isMyMessage
156
- hasAttachment
157
- />
158
- </div>
159
- </div>
160
112
  <div className="flex items-center gap-4">
161
113
  <span className="text-sm w-32">No tag:</span>
162
114
  <MessageTag message={createMockMessage()} />
@@ -5,20 +5,10 @@ interface MessageTagProps {
5
5
  message: LocalMessage
6
6
  /** When true, renders as a standalone bubble instead of a small tag */
7
7
  standalone?: boolean
8
- /** When true, renders sender-side chatbot variants */
9
- isMyMessage?: boolean
10
- /** Whether the message includes an attachment */
11
- hasAttachment?: boolean
12
8
  }
13
9
 
14
- const SparkleIcon = ({ size = 12 }: { size?: number }) => (
15
- <svg
16
- width={size}
17
- height={size}
18
- viewBox="0 0 10 10"
19
- fill="none"
20
- aria-hidden="true"
21
- >
10
+ const SparkleIcon = () => (
11
+ <svg width="12" height="12" viewBox="0 0 10 10" fill="none">
22
12
  <path
23
13
  d="M10.003 5a.705.705 0 0 1-.469.67L6.7 6.7 5.67 9.535a.715.715 0 0 1-1.34 0L3.3 6.7.466 5.67a.715.715 0 0 1 0-1.34L3.3 3.3 4.33.466a.715.715 0 0 1 1.34 0L6.7 3.3l2.834 1.03a.705.705 0 0 1 .469.67"
24
14
  fill="currentColor"
@@ -54,8 +44,6 @@ export const isTipOnlyMessage = (message: LocalMessage): boolean => {
54
44
  export const MessageTag = ({
55
45
  message,
56
46
  standalone = false,
57
- isMyMessage = false,
58
- hasAttachment = false,
59
47
  }: MessageTagProps) => {
60
48
  const isTipOrPaid = isTipOrPaidMessage(message)
61
49
  const isChatbot = isChatbotMessage(message)
@@ -84,44 +72,13 @@ export const MessageTag = ({
84
72
  )
85
73
  }
86
74
 
87
- const isSenderAttachmentVariant = isMyMessage && hasAttachment
88
- const chatbotLabel = isSenderAttachmentVariant
89
- ? 'Sent with AI'
90
- : 'Sent with DM Agent'
91
-
92
- const chatbotClassName = [
93
- 'message-chatbot-indicator',
94
- isMyMessage
95
- ? 'message-chatbot-indicator--sender'
96
- : 'message-chatbot-indicator--receiver',
97
- isSenderAttachmentVariant
98
- ? 'message-chatbot-indicator--attachment'
99
- : 'message-chatbot-indicator--text',
100
- ].join(' ')
101
-
102
- const label = (
103
- <span className="message-chatbot-indicator__label">{chatbotLabel}</span>
104
- )
105
- const icon = (
106
- <span className="message-chatbot-indicator__icon">
107
- <SparkleIcon size={isSenderAttachmentVariant ? 12 : 15} />
108
- </span>
109
- )
110
-
111
- // Chatbot indicator variant
75
+ // Chatbot tag
112
76
  return (
113
- <div className={chatbotClassName} data-testid="message-chatbot-indicator">
114
- {isMyMessage && !isSenderAttachmentVariant ? (
115
- <>
116
- {label}
117
- {icon}
118
- </>
119
- ) : (
120
- <>
121
- {icon}
122
- {label}
123
- </>
124
- )}
77
+ <div className="message-tag message-tag--chatbot">
78
+ <span className="message-tag__icon" style={{ marginTop: -1 }}>
79
+ <SparkleIcon />
80
+ </span>
81
+ <span className="message-tag__label">Chatbot</span>
125
82
  </div>
126
83
  )
127
84
  }
@@ -117,12 +117,11 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
117
117
  handleClick = () => setIsBounceDialogOpen(true)
118
118
  }
119
119
 
120
- const isMine = isMyMessage()
121
120
  const rootClassName = classNames(
122
121
  'str-chat__message str-chat__message-simple',
123
122
  `str-chat__message--${message.type}`,
124
123
  `str-chat__message--${message.status}`,
125
- isMine
124
+ isMyMessage()
126
125
  ? 'str-chat__message--me str-chat__message-simple--me'
127
126
  : 'str-chat__message--other',
128
127
  message.text ? 'str-chat__message--has-text' : 'has-no-text',
@@ -143,12 +142,6 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
143
142
 
144
143
  const poll = message.poll_id && client.polls.fromState(message.poll_id)
145
144
  const isTipOnly = isTipOnlyMessage(message)
146
- const isChatbot = isChatbotMessage(message)
147
- const hasRenderableAttachments = !!(
148
- finalAttachments?.length && !message.quoted_message
149
- )
150
- const useAttachmentFooterChatbotTag =
151
- isChatbot && isMine && hasRenderableAttachments
152
145
 
153
146
  return (
154
147
  <>
@@ -198,13 +191,6 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
198
191
  ) : (
199
192
  <div className="str-chat__message-bubble-wrapper">
200
193
  <div className="str-chat__message-bubble">
201
- {isChatbot && !useAttachmentFooterChatbotTag && (
202
- <MessageTag
203
- message={message}
204
- hasAttachment={hasRenderableAttachments}
205
- isMyMessage={isMine}
206
- />
207
- )}
208
194
  {poll && <Poll poll={poll} />}
209
195
  {finalAttachments?.length && !message.quoted_message ? (
210
196
  <Attachment
@@ -222,15 +208,9 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
222
208
  )}
223
209
  <MessageErrorIcon />
224
210
  </div>
225
- {/* Tip/paid tags stay outside; chatbot attachment indicator stays outside too */}
226
- {(!isChatbot || useAttachmentFooterChatbotTag) && (
227
- <MessageTag
228
- message={message}
229
- hasAttachment={hasRenderableAttachments}
230
- isMyMessage={isMine}
231
- />
232
- )}
233
- {chatbotVotingEnabled && isChatbot && (
211
+ {/* Tag positioned outside and below the bubble */}
212
+ <MessageTag message={message} />
213
+ {chatbotVotingEnabled && isChatbotMessage(message) && (
234
214
  <MessageVoteButtons
235
215
  selected={voteState}
236
216
  onVoteUp={voteUp}
package/src/styles.css CHANGED
@@ -134,45 +134,9 @@
134
134
  color: #016630;
135
135
  }
136
136
 
137
- .message-chatbot-indicator {
138
- display: inline-flex;
139
- align-items: center;
140
- font-size: 10px;
141
- font-weight: 400;
142
- line-height: 16px;
143
- letter-spacing: 0.2px;
144
- }
145
-
146
- .message-chatbot-indicator--text {
147
- width: 100%;
148
- gap: 6px;
149
- margin-bottom: 8px;
150
- }
151
-
152
- .message-chatbot-indicator--receiver {
153
- justify-content: flex-start;
154
- color: rgba(0, 0, 0, 0.3);
155
- }
156
-
157
- .message-chatbot-indicator--sender {
158
- justify-content: flex-end;
159
- }
160
-
161
- .message-chatbot-indicator--sender.message-chatbot-indicator--text {
162
- color: rgba(255, 255, 255, 0.55);
163
- }
164
-
165
- .message-chatbot-indicator--attachment {
166
- width: 100%;
167
- gap: 8px;
168
- margin-top: 4px;
169
- color: rgba(0, 0, 0, 0.3);
170
- }
171
-
172
- .message-chatbot-indicator__icon {
173
- display: inline-flex;
174
- align-items: center;
175
- line-height: 1;
137
+ .message-tag--chatbot {
138
+ background-color: transparent;
139
+ color: #7f22fe;
176
140
  }
177
141
 
178
142
  /* Message vote buttons (chatbot feedback) */
@@ -195,9 +159,7 @@
195
159
  background-color: transparent;
196
160
  color: rgba(0, 0, 0, 0.35);
197
161
  cursor: pointer;
198
- transition:
199
- background-color 0.15s,
200
- color 0.15s;
162
+ transition: background-color 0.15s, color 0.15s;
201
163
  }
202
164
 
203
165
  .message-vote-button:hover {
@@ -1,110 +0,0 @@
1
- import { LocalMessage } from 'stream-chat'
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import { renderWithProviders, screen } from '../../test/utils'
5
-
6
- import { MessageTag } from './MessageTag'
7
-
8
- interface MockMessageOptions {
9
- metadata?: {
10
- custom_type?: 'MESSAGE_TIP' | 'MESSAGE_PAID' | 'MESSAGE_CHATBOT'
11
- amount_text?: string
12
- }
13
- text?: string
14
- }
15
-
16
- const createMockMessage = (options?: MockMessageOptions): LocalMessage =>
17
- ({
18
- id: 'msg-1',
19
- text: options?.text ?? 'Hello world',
20
- type: 'regular',
21
- created_at: new Date(),
22
- updated_at: new Date(),
23
- metadata: options?.metadata,
24
- }) as LocalMessage
25
-
26
- describe('MessageTag', () => {
27
- it('renders receiver chatbot text variant with DM Agent copy and icon first', () => {
28
- renderWithProviders(
29
- <MessageTag
30
- message={createMockMessage({
31
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
32
- })}
33
- />
34
- )
35
-
36
- const indicator = screen.getByTestId('message-chatbot-indicator')
37
- expect(indicator).toHaveTextContent('Sent with DM Agent')
38
- expect(indicator).toHaveClass('message-chatbot-indicator--receiver')
39
- expect(indicator).toHaveClass('message-chatbot-indicator--text')
40
-
41
- expect(indicator.children[0]).toHaveClass('message-chatbot-indicator__icon')
42
- expect(indicator.children[1]).toHaveClass(
43
- 'message-chatbot-indicator__label'
44
- )
45
- })
46
-
47
- it('renders sender chatbot text variant with mirrored order', () => {
48
- renderWithProviders(
49
- <MessageTag
50
- message={createMockMessage({
51
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
52
- })}
53
- isMyMessage
54
- />
55
- )
56
-
57
- const indicator = screen.getByTestId('message-chatbot-indicator')
58
- expect(indicator).toHaveTextContent('Sent with DM Agent')
59
- expect(indicator).toHaveClass('message-chatbot-indicator--sender')
60
- expect(indicator).toHaveClass('message-chatbot-indicator--text')
61
-
62
- expect(indicator.children[0]).toHaveClass(
63
- 'message-chatbot-indicator__label'
64
- )
65
- expect(indicator.children[1]).toHaveClass('message-chatbot-indicator__icon')
66
- })
67
-
68
- it('renders sender attachment chatbot variant outside-footer copy', () => {
69
- renderWithProviders(
70
- <MessageTag
71
- message={createMockMessage({
72
- metadata: { custom_type: 'MESSAGE_CHATBOT' },
73
- })}
74
- hasAttachment
75
- isMyMessage
76
- />
77
- )
78
-
79
- const indicator = screen.getByTestId('message-chatbot-indicator')
80
- expect(indicator).toHaveTextContent('Sent with AI')
81
- expect(indicator).toHaveClass('message-chatbot-indicator--sender')
82
- expect(indicator).toHaveClass('message-chatbot-indicator--attachment')
83
-
84
- expect(indicator.children[0]).toHaveClass('message-chatbot-indicator__icon')
85
- expect(indicator.children[1]).toHaveClass(
86
- 'message-chatbot-indicator__label'
87
- )
88
- })
89
-
90
- it('keeps tip tag behavior unchanged', () => {
91
- renderWithProviders(
92
- <MessageTag
93
- message={createMockMessage({
94
- metadata: { custom_type: 'MESSAGE_TIP', amount_text: '$5.50' },
95
- })}
96
- />
97
- )
98
-
99
- const tipTag = screen.getByText('Delivered with $5.50 tip')
100
- expect(tipTag.closest('.message-tag--tip')).not.toBeNull()
101
- })
102
-
103
- it('returns null for non-custom messages', () => {
104
- const { container } = renderWithProviders(
105
- <MessageTag message={createMockMessage()} />
106
- )
107
-
108
- expect(container.firstChild).toBeNull()
109
- })
110
- })