@linktr.ee/messaging-react 3.6.1 → 3.6.2-rc-1783304704

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-d0_xEfdM.cjs → Card-6FOd4_j_.cjs} +2 -2
  2. package/dist/{Card-d0_xEfdM.cjs.map → Card-6FOd4_j_.cjs.map} +1 -1
  3. package/dist/{Card-DcUPqd79.cjs → Card-BhIG7T7c.cjs} +2 -2
  4. package/dist/{Card-DcUPqd79.cjs.map → Card-BhIG7T7c.cjs.map} +1 -1
  5. package/dist/{Card-BuR6mbUu.cjs → Card-CA63InbA.cjs} +2 -2
  6. package/dist/{Card-BuR6mbUu.cjs.map → Card-CA63InbA.cjs.map} +1 -1
  7. package/dist/{Card-B0lzpuYf.js → Card-C_TfROjB.js} +3 -3
  8. package/dist/{Card-B0lzpuYf.js.map → Card-C_TfROjB.js.map} +1 -1
  9. package/dist/{Card-BrC7mKtr.js → Card-DN8P8IeT.js} +2 -2
  10. package/dist/{Card-BrC7mKtr.js.map → Card-DN8P8IeT.js.map} +1 -1
  11. package/dist/{Card-CxS7GNqp.js → Card-DgWCIgWw.js} +2 -2
  12. package/dist/{Card-CxS7GNqp.js.map → Card-DgWCIgWw.js.map} +1 -1
  13. package/dist/{LockedThumbnail-BaDgF8qJ.js → LockedThumbnail-DNy4CoCm.js} +2 -2
  14. package/dist/{LockedThumbnail-BaDgF8qJ.js.map → LockedThumbnail-DNy4CoCm.js.map} +1 -1
  15. package/dist/{LockedThumbnail-BDtKMJjz.cjs → LockedThumbnail-DPlNLdpK.cjs} +2 -2
  16. package/dist/{LockedThumbnail-BDtKMJjz.cjs.map → LockedThumbnail-DPlNLdpK.cjs.map} +1 -1
  17. package/dist/index-ClREqfMm.cjs +2 -0
  18. package/dist/index-ClREqfMm.cjs.map +1 -0
  19. package/dist/{index-BPfehHDD.js → index-CxGOKFnx.js} +3786 -3876
  20. package/dist/index-CxGOKFnx.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 +231 -0
  25. package/src/components/ChannelView.stories.tsx +68 -11
  26. package/src/components/ChannelView.test.tsx +54 -13
  27. package/src/components/ChannelView.tsx +74 -28
  28. package/src/components/CustomMessage/index.tsx +0 -67
  29. package/dist/index-BPfehHDD.js.map +0 -1
  30. package/dist/index-G4pnfm4m.cjs +0 -2
  31. package/dist/index-G4pnfm4m.cjs.map +0 -1
  32. package/src/components/CustomMessage/StreamAttachmentMessage.stories.tsx +0 -178
  33. package/src/components/CustomMessage/StreamAttachmentMessage.test.tsx +0 -186
  34. package/src/components/CustomMessage/StreamAttachmentMessage.tsx +0 -417
@@ -25,6 +25,7 @@ import { resolveParticipantDisplayName } from '../utils/resolveParticipantDispla
25
25
 
26
26
  import { Avatar } from './Avatar'
27
27
  import { ChannelActionsMenu } from './ChannelActionsMenu'
28
+ import { ChannelHeaderRedesign } from './ChannelHeaderRedesign'
28
29
  import { CustomDateSeparator } from './CustomDateSeparator'
29
30
  import { CustomMessage } from './CustomMessage'
30
31
  import { CustomMessageActions } from './CustomMessage/CustomMessageActions'
@@ -464,6 +465,34 @@ const ChannelViewInner: React.FC<{
464
465
  dmAgentEnabled &&
465
466
  currentUserIsAccount === false &&
466
467
  participantIsAccount === true
468
+ const hasVisibleMessages = channel.state.messages.some(
469
+ (message) => message.type !== 'deleted'
470
+ )
471
+ const channelBanner = renderChannelBanner ? (
472
+ <React.Fragment key="lt-channel-banner">
473
+ {renderChannelBanner()}
474
+ </React.Fragment>
475
+ ) : null
476
+ const redesignedHeader = onParticipantNameClick ? (
477
+ <ChannelHeaderRedesign
478
+ onBack={onBack}
479
+ showBackButton={showBackButton}
480
+ showChannelInfo={showChannelInfo}
481
+ showStarButton={showStarButton}
482
+ dmAgentEnabled={showDmAgentHeader}
483
+ onLeaveConversation={onLeaveConversation}
484
+ onBlockParticipant={onBlockParticipant}
485
+ showDeleteConversation={showDeleteConversation}
486
+ showBlockParticipant={showBlockParticipant}
487
+ showReportParticipant={showReportParticipant}
488
+ onDeleteConversationClick={onDeleteConversationClick}
489
+ onBlockParticipantClick={onBlockParticipantClick}
490
+ onReportParticipantClick={onReportParticipantClick}
491
+ customChannelActions={customChannelActions}
492
+ renderChannelActions={renderChannelActions}
493
+ onParticipantNameClick={onParticipantNameClick}
494
+ />
495
+ ) : null
467
496
 
468
497
  // Prevents all message instances from unmounting when ChannelViewInner re-renders
469
498
  const MessageOverride = useCallback(
@@ -497,41 +526,58 @@ const ChannelViewInner: React.FC<{
497
526
  >
498
527
  <Window>
499
528
  {/* Custom Channel Header */}
500
- <div key="lt-channel-header">
501
- <CustomChannelHeader
502
- onBack={onBack}
503
- showBackButton={showBackButton}
504
- showChannelInfo={showChannelInfo}
505
- showStarButton={showStarButton}
506
- dmAgentEnabled={showDmAgentHeader}
507
- onLeaveConversation={onLeaveConversation}
508
- onBlockParticipant={onBlockParticipant}
509
- showDeleteConversation={showDeleteConversation}
510
- showBlockParticipant={showBlockParticipant}
511
- showReportParticipant={showReportParticipant}
512
- onDeleteConversationClick={onDeleteConversationClick}
513
- onBlockParticipantClick={onBlockParticipantClick}
514
- onReportParticipantClick={onReportParticipantClick}
515
- customChannelActions={customChannelActions}
516
- renderChannelActions={renderChannelActions}
517
- onParticipantNameClick={onParticipantNameClick}
518
- renderHeaderTitleBadges={renderHeaderTitleBadges}
519
- />
520
- </div>
529
+ {!onParticipantNameClick && (
530
+ <>
531
+ <div key="lt-channel-header">
532
+ <CustomChannelHeader
533
+ onBack={onBack}
534
+ showBackButton={showBackButton}
535
+ showChannelInfo={showChannelInfo}
536
+ showStarButton={showStarButton}
537
+ dmAgentEnabled={showDmAgentHeader}
538
+ onLeaveConversation={onLeaveConversation}
539
+ onBlockParticipant={onBlockParticipant}
540
+ showDeleteConversation={showDeleteConversation}
541
+ showBlockParticipant={showBlockParticipant}
542
+ showReportParticipant={showReportParticipant}
543
+ onDeleteConversationClick={onDeleteConversationClick}
544
+ onBlockParticipantClick={onBlockParticipantClick}
545
+ onReportParticipantClick={onReportParticipantClick}
546
+ customChannelActions={customChannelActions}
547
+ renderChannelActions={renderChannelActions}
548
+ renderHeaderTitleBadges={renderHeaderTitleBadges}
549
+ />
550
+ </div>
551
+ {channelBanner}
552
+ </>
553
+ )}
521
554
 
522
- {/* Custom Banner/Summary */}
523
- {renderChannelBanner ? (
524
- <React.Fragment key="lt-channel-banner">
525
- {renderChannelBanner()}
526
- </React.Fragment>
527
- ) : null}
555
+ {/* Stream only renders MessageList.head when there are messages, so
556
+ empty redesigned channels need the header and banner in normal flow. */}
557
+ {onParticipantNameClick && !hasVisibleMessages && (
558
+ <div className="px-4 @lg:px-6">
559
+ {redesignedHeader}
560
+ {channelBanner}
561
+ </div>
562
+ )}
528
563
 
529
564
  {/* Message List */}
530
565
  <div
531
566
  key="lt-channel-message-list"
532
567
  className="flex-1 overflow-hidden relative"
533
568
  >
534
- <MessageList hideDeletedMessages hideNewMessageSeparator={false} />
569
+ <MessageList
570
+ head={
571
+ onParticipantNameClick && hasVisibleMessages ? (
572
+ <div className="sticky top-0 z-10">
573
+ {redesignedHeader}
574
+ {channelBanner}
575
+ </div>
576
+ ) : undefined
577
+ }
578
+ hideDeletedMessages
579
+ hideNewMessageSeparator={false}
580
+ />
535
581
  </div>
536
582
 
537
583
  {renderConversationFooter ? (
@@ -34,9 +34,6 @@ import { getMessageDisplayText } from '../../utils/getMessageDisplayText'
34
34
  import { Avatar } from '../Avatar'
35
35
  import LockedAttachment from '../LockedAttachment'
36
36
  import { isLinkAttachment } from '../MediaMessage'
37
- import {
38
- bubbleGroupPositionFromStream as messageAttachmentGroupPositionFromStream,
39
- } from '../MessageAttachment'
40
37
 
41
38
  import { useCustomMessage } from './context'
42
39
  import {
@@ -46,9 +43,6 @@ import {
46
43
  isTipOnlyMessage,
47
44
  } from './MessageTag'
48
45
  import { MessageVoteButtons } from './MessageVoteButtons'
49
- import StreamAttachmentMessage, {
50
- buildOrderedAttachmentSegments,
51
- } from './StreamAttachmentMessage'
52
46
 
53
47
  type CustomMessageUIComponentProps = MessageUIComponentProps & {
54
48
  chatbotVotingEnabled?: boolean
@@ -119,38 +113,12 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
119
113
  const filtered = raw.filter((a) => !('type' in a) || !isLinkAttachment(a))
120
114
  return filtered.length === raw.length ? raw : filtered
121
115
  }, [message])
122
- const attachmentSegments = useMemo(
123
- () => buildOrderedAttachmentSegments(finalAttachments),
124
- [finalAttachments]
125
- )
126
116
  const displayMessage = useMemo(() => {
127
117
  const displayText = getMessageDisplayText({ message, viewerLanguage })
128
118
  return displayText === message.text
129
119
  ? message
130
120
  : { ...message, text: displayText }
131
121
  }, [message, viewerLanguage])
132
- // Route every generic Stream-attachment message (link OG previews and
133
- // image/video/audio/pdf/file media) through the toolkit renderer, so
134
- // messaging-react owns all shared attachment rendering rather than leaving
135
- // media on stream-chat-react's default Attachment. App-specific types
136
- // (locked/paid, tips, chatbot) are handled by the branches above.
137
- const hasAttachmentSegments = attachmentSegments.length > 0
138
- // Only own the message when every attachment maps to a representable segment.
139
- // Otherwise a mixed message (e.g. an unsupported shared_location alongside a
140
- // photo) would silently drop the unrepresented attachment — those fall
141
- // through to the default `Attachment` renderer, which handles all of them.
142
- const allAttachmentsRepresented =
143
- attachmentSegments.reduce(
144
- (total, segment) => total + segment.attachments.length,
145
- 0
146
- ) === (finalAttachments?.length ?? 0)
147
- const streamAttachmentGroupPosition = messageAttachmentGroupPositionFromStream(
148
- {
149
- endOfGroup,
150
- firstOfGroup,
151
- groupedByUser,
152
- }
153
- )
154
122
 
155
123
  if (isDateSeparatorMessage(message)) {
156
124
  return null
@@ -211,19 +179,6 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
211
179
  )
212
180
  const useAttachmentFooterChatbotTag =
213
181
  isChatbot && isMine && hasRenderableAttachments
214
- // Route generic Stream attachments through the toolkit renderer only when it
215
- // can faithfully own the whole message. Quoted replies (attachments are
216
- // suppressed there), polls, AI-streamed, and chatbot messages fall through to
217
- // the default branch so their Poll / StreamedMessageText / message-text and
218
- // chatbot attribution (MessageTag) handling is preserved — the accompanying
219
- // message text and attribution must never be dropped.
220
- const canRenderAttachmentsInToolkit =
221
- hasAttachmentSegments &&
222
- allAttachmentsRepresented &&
223
- !message.quoted_message &&
224
- !poll &&
225
- !isAIGenerated &&
226
- !isChatbot
227
182
 
228
183
  return (
229
184
  <>
@@ -324,28 +279,6 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
324
279
  ) : isTipOnly ? (
325
280
  /* Tip-only messages render as a standalone bubble */
326
281
  <MessageTag message={message} standalone />
327
- ) : canRenderAttachmentsInToolkit ? (
328
- <div className="str-chat__message-bubble-wrapper">
329
- <div
330
- className="str-chat__message-bubble"
331
- style={{
332
- background: 'transparent',
333
- borderRadius: 0,
334
- overflow: 'visible',
335
- padding: 0,
336
- }}
337
- >
338
- <StreamAttachmentMessage
339
- groupPosition={streamAttachmentGroupPosition}
340
- isMyMessage={isMine}
341
- message={{
342
- attachments: finalAttachments,
343
- text: displayMessage.text,
344
- }}
345
- />
346
- <MessageErrorIcon />
347
- </div>
348
- </div>
349
282
  ) : (
350
283
  <div className="str-chat__message-bubble-wrapper">
351
284
  <div className="str-chat__message-bubble">