@linktr.ee/messaging-react 3.9.1 → 3.9.2-rc-1783581484

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.
Files changed (34) hide show
  1. package/dist/{Card-Dau41drB.js → Card-0f6UozSj.js} +2 -2
  2. package/dist/{Card-Dau41drB.js.map → Card-0f6UozSj.js.map} +1 -1
  3. package/dist/{Card-D3QNullZ.js → Card-B4Rgburk.js} +2 -2
  4. package/dist/{Card-D3QNullZ.js.map → Card-B4Rgburk.js.map} +1 -1
  5. package/dist/{Card-BMau-mI5.cjs → Card-BTlJZXuO.cjs} +2 -2
  6. package/dist/{Card-BMau-mI5.cjs.map → Card-BTlJZXuO.cjs.map} +1 -1
  7. package/dist/{Card-BLLADEC_.js → Card-DBsTWA91.js} +3 -3
  8. package/dist/{Card-BLLADEC_.js.map → Card-DBsTWA91.js.map} +1 -1
  9. package/dist/{Card-MJ0x2roP.cjs → Card-DQSjcIX_.cjs} +2 -2
  10. package/dist/{Card-MJ0x2roP.cjs.map → Card-DQSjcIX_.cjs.map} +1 -1
  11. package/dist/{Card-C3rbCPM7.cjs → Card-QNGgvs9y.cjs} +2 -2
  12. package/dist/{Card-C3rbCPM7.cjs.map → Card-QNGgvs9y.cjs.map} +1 -1
  13. package/dist/{LockedThumbnail-Bq54AT8J.js → LockedThumbnail-CYzXhG5H.js} +2 -2
  14. package/dist/{LockedThumbnail-Bq54AT8J.js.map → LockedThumbnail-CYzXhG5H.js.map} +1 -1
  15. package/dist/{LockedThumbnail-a03GYGJz.cjs → LockedThumbnail-NlYrnJWD.cjs} +2 -2
  16. package/dist/{LockedThumbnail-a03GYGJz.cjs.map → LockedThumbnail-NlYrnJWD.cjs.map} +1 -1
  17. package/dist/index-D0lSJc9F.cjs +2 -0
  18. package/dist/index-D0lSJc9F.cjs.map +1 -0
  19. package/dist/{index-CBm9au-T.js → index-DYp35Tv3.js} +1177 -1195
  20. package/dist/index-DYp35Tv3.js.map +1 -0
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.js +1 -1
  23. package/package.json +2 -2
  24. package/src/components/ChannelHeaderRedesign.tsx +1 -8
  25. package/src/components/ChannelView.tsx +9 -12
  26. package/src/components/CustomMessage/SentMessageDeliveryStatus.test.tsx +51 -11
  27. package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +39 -25
  28. package/src/components/CustomMessage/StreamAttachmentMessage.stories.tsx +12 -19
  29. package/src/components/CustomMessage/StreamAttachmentMessage.test.tsx +26 -44
  30. package/src/components/CustomMessage/StreamAttachmentMessage.tsx +43 -37
  31. package/src/components/CustomMessage/index.tsx +21 -13
  32. package/dist/index-CBm9au-T.js.map +0 -1
  33. package/dist/index-CWopIWxB.cjs +0 -2
  34. package/dist/index-CWopIWxB.cjs.map +0 -1
@@ -1,10 +1,5 @@
1
1
  import React from 'react'
2
- import type { Attachment, LocalMessage } from 'stream-chat'
3
- import {
4
- MessageErrorIcon,
5
- MessageText,
6
- type MessageContextValue,
7
- } from 'stream-chat-react'
2
+ import type { Attachment } from 'stream-chat'
8
3
 
9
4
  import LinkAttachment from '../LinkAttachment'
10
5
  import { isPlayableMedia } from '../LinkAttachment/components/_shared/CardThumbnail'
@@ -17,6 +12,16 @@ export type AttachmentSegment =
17
12
  | { type: 'link'; attachments: Attachment[] }
18
13
  | { type: 'media'; kind: StreamMediaKind; attachments: Attachment[] }
19
14
 
15
+ type StreamThreadMessage = {
16
+ attachments?: Attachment[]
17
+ text?: string
18
+ }
19
+
20
+ const SENT_CAPTION_CLASS =
21
+ 'mt-[2px] max-w-[280px] whitespace-pre-wrap break-words rounded-[18px] bg-[#121110] px-4 py-2 text-white'
22
+ const RECEIVED_CAPTION_CLASS =
23
+ 'mt-[2px] max-w-[280px] whitespace-pre-wrap break-words rounded-[18px] bg-[#e9eaed] px-4 py-2 text-[#080707]'
24
+
20
25
  function trimToUndefined(value?: string | null): string | undefined {
21
26
  const trimmed = value?.trim()
22
27
  return trimmed ? trimmed : undefined
@@ -147,9 +152,19 @@ export function buildOrderedAttachmentSegments(
147
152
  return segments
148
153
  }
149
154
 
150
- export function countMediaSegmentBubbles(
155
+ export function countAttachmentSegmentBubbles(
151
156
  segments: AttachmentSegment[]
152
157
  ): number {
158
+ let count = 0
159
+
160
+ for (const segment of segments) {
161
+ count += segment.type === 'link' ? segment.attachments.length : 1
162
+ }
163
+
164
+ return count
165
+ }
166
+
167
+ export function countMediaSegmentBubbles(segments: AttachmentSegment[]): number {
153
168
  return segments.filter((segment) => segment.type === 'media').length
154
169
  }
155
170
 
@@ -289,15 +304,18 @@ function MediaClusterBubble({
289
304
  groupPosition,
290
305
  isMyMessage,
291
306
  segment,
307
+ text,
292
308
  }: {
293
309
  groupPosition: BubbleGroupPosition
294
310
  isMyMessage: boolean
295
311
  segment: Extract<AttachmentSegment, { type: 'media' }>
312
+ text?: string
296
313
  }) {
297
314
  const TypeNamespace = messageAttachmentNamespaceForKind(segment.kind)
298
315
  const props = {
299
316
  ...buildMediaClusterRenderProps(segment.kind, segment.attachments),
300
317
  groupPosition,
318
+ ...(text ? { text } : {}),
301
319
  }
302
320
 
303
321
  if (isMyMessage) {
@@ -310,19 +328,18 @@ function MediaClusterBubble({
310
328
  export interface StreamAttachmentMessageProps {
311
329
  groupPosition: BubbleGroupPosition
312
330
  isMyMessage: boolean
313
- message: LocalMessage
314
- renderText?: MessageContextValue['renderText']
331
+ message: StreamThreadMessage
315
332
  }
316
333
 
317
334
  const StreamAttachmentMessage: React.FC<StreamAttachmentMessageProps> = ({
318
335
  groupPosition,
319
336
  isMyMessage,
320
337
  message,
321
- renderText,
322
338
  }) => {
323
339
  const segments = buildOrderedAttachmentSegments(message.attachments)
324
340
  if (segments.length === 0) return null
325
341
 
342
+ const totalBubbles = countAttachmentSegmentBubbles(segments)
326
343
  const totalMediaBubbles = countMediaSegmentBubbles(segments)
327
344
  const rawCaption = message.text?.trim()
328
345
  const linkSegment = segments.find((segment) => segment.type === 'link')
@@ -336,14 +353,25 @@ const StreamAttachmentMessage: React.FC<StreamAttachmentMessageProps> = ({
336
353
  ? undefined
337
354
  : rawCaption
338
355
 
356
+ let bubbleIndex = 0
339
357
  let mediaBubbleIndex = 0
340
358
  const rows: React.ReactNode[] = []
341
359
 
342
360
  const pushLinkRow = (attachment: Attachment, key: string) => {
361
+ const isLastBubble = bubbleIndex === totalBubbles - 1
362
+ bubbleIndex += 1
363
+
343
364
  const Card = isMyMessage ? LinkAttachment.Sent : LinkAttachment.Received
344
365
 
345
366
  rows.push(
346
- <Card key={key} {...linkCardPropsFromStreamAttachment(attachment)} />
367
+ <React.Fragment key={key}>
368
+ <Card {...linkCardPropsFromStreamAttachment(attachment)} />
369
+ {isLastBubble && caption ? (
370
+ <div className={isMyMessage ? SENT_CAPTION_CLASS : RECEIVED_CAPTION_CLASS}>
371
+ {caption}
372
+ </div>
373
+ ) : null}
374
+ </React.Fragment>
347
375
  )
348
376
  }
349
377
 
@@ -351,12 +379,14 @@ const StreamAttachmentMessage: React.FC<StreamAttachmentMessageProps> = ({
351
379
  segment: Extract<AttachmentSegment, { type: 'media' }>,
352
380
  key: string
353
381
  ) => {
382
+ const isLastBubble = bubbleIndex === totalBubbles - 1
354
383
  const position = bubblePositionInRun(
355
384
  mediaBubbleIndex,
356
385
  totalMediaBubbles,
357
386
  groupPosition
358
387
  )
359
388
 
389
+ bubbleIndex += 1
360
390
  mediaBubbleIndex += 1
361
391
 
362
392
  rows.push(
@@ -365,6 +395,7 @@ const StreamAttachmentMessage: React.FC<StreamAttachmentMessageProps> = ({
365
395
  groupPosition={position}
366
396
  isMyMessage={isMyMessage}
367
397
  segment={segment}
398
+ text={isLastBubble ? caption : undefined}
368
399
  />
369
400
  )
370
401
  }
@@ -380,32 +411,7 @@ const StreamAttachmentMessage: React.FC<StreamAttachmentMessageProps> = ({
380
411
  pushMediaCluster(segment, `media-${segmentIndex}`)
381
412
  })
382
413
 
383
- return (
384
- <div className="str-chat__message-bubble-wrapper">
385
- <div
386
- className="str-chat__message-bubble"
387
- data-attachment-bubble="true"
388
- style={{
389
- background: 'transparent',
390
- borderRadius: 0,
391
- overflow: 'visible',
392
- padding: 0,
393
- }}
394
- >
395
- {rows}
396
- {!caption && <MessageErrorIcon />}
397
- </div>
398
- {caption ? (
399
- <div className="str-chat__message-bubble">
400
- <MessageText
401
- message={message}
402
- renderText={renderText}
403
- />
404
- <MessageErrorIcon />
405
- </div>
406
- ) : null}
407
- </div>
408
- )
414
+ return <>{rows}</>
409
415
  }
410
416
 
411
417
  export default StreamAttachmentMessage
@@ -326,19 +326,27 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
326
326
  /* Tip-only messages render as a standalone bubble */
327
327
  <MessageTag message={message} standalone />
328
328
  ) : canRenderAttachmentsInToolkit ? (
329
- <StreamAttachmentMessage
330
- groupPosition={streamAttachmentGroupPosition}
331
- isMyMessage={isMine}
332
- message={{
333
- ...displayMessage,
334
- attachments: finalAttachments,
335
- // MessageText prefers message.i18n[userLanguage_text] from
336
- // Stream's TranslationContext over message.text. Drop i18n so
337
- // the caption uses displayMessage.text from viewerLanguage.
338
- i18n: undefined,
339
- }}
340
- renderText={renderText}
341
- />
329
+ <div className="str-chat__message-bubble-wrapper">
330
+ <div
331
+ className="str-chat__message-bubble"
332
+ style={{
333
+ background: 'transparent',
334
+ borderRadius: 0,
335
+ overflow: 'visible',
336
+ padding: 0,
337
+ }}
338
+ >
339
+ <StreamAttachmentMessage
340
+ groupPosition={streamAttachmentGroupPosition}
341
+ isMyMessage={isMine}
342
+ message={{
343
+ attachments: finalAttachments,
344
+ text: displayMessage.text,
345
+ }}
346
+ />
347
+ <MessageErrorIcon />
348
+ </div>
349
+ </div>
342
350
  ) : (
343
351
  <div className="str-chat__message-bubble-wrapper">
344
352
  <div className="str-chat__message-bubble">