@linktr.ee/messaging-react 3.25.0 → 3.27.0-rc-1785466017

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/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-QulHlER7.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageBubble=e.MessageBubble;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.optimizeMessagingAttachmentUrl=e.optimizeMessagingAttachmentUrl;exports.resolveConversationParticipant=e.resolveConversationParticipant;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-ByySBsKx.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageBubble=e.MessageBubble;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.optimizeMessagingAttachmentUrl=e.optimizeMessagingAttachmentUrl;exports.resolveConversationParticipant=e.resolveConversationParticipant;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
2
2
  //# sourceMappingURL=index.cjs.map
package/dist/index.d.ts CHANGED
@@ -87,6 +87,8 @@ export declare type BroadcastClickHandler = (broadcast: {
87
87
  name?: string;
88
88
  }) => void;
89
89
 
90
+ export declare type BroadcastNameResolver = (broadcastId: string) => string | undefined;
91
+
90
92
  /**
91
93
  * Build the meta line shown under the title in compact document / file
92
94
  * attachments — `EXT · SIZE` (`PDF · 379.5 KB`). Either part is dropped
@@ -210,7 +212,7 @@ export declare const ChannelView: default_2.NamedExoticComponent<ChannelViewProp
210
212
  * Props that MessagingShell passes through to ChannelView.
211
213
  * ChannelViewProps is the source of truth for these props.
212
214
  */
213
- declare type ChannelViewPassthroughProps = Pick<ChannelViewProps, 'renderMessageInputActions' | 'renderConversationFooter' | 'CustomChannelEmptyState' | 'onBlockParticipantClick' | 'onReportParticipantClick' | 'dmAgentEnabled' | 'onMessageSent' | 'chatbotVotingEnabled' | 'viewerLanguage' | 'renderChannelBanner' | 'customChannelActions' | 'renderChannelActions' | 'onParticipantNameClick' | 'renderMessage' | 'onMessageLinkClick' | 'onBroadcastClick' | 'showChannelInfo' | 'composerInput'>;
215
+ declare type ChannelViewPassthroughProps = Pick<ChannelViewProps, 'renderMessageInputActions' | 'renderConversationFooter' | 'CustomChannelEmptyState' | 'onBlockParticipantClick' | 'onReportParticipantClick' | 'dmAgentEnabled' | 'onMessageSent' | 'chatbotVotingEnabled' | 'viewerLanguage' | 'renderChannelBanner' | 'customChannelActions' | 'renderChannelActions' | 'onParticipantNameClick' | 'renderMessage' | 'onMessageLinkClick' | 'onBroadcastClick' | 'resolveBroadcastName' | 'showChannelInfo' | 'composerInput'>;
214
216
 
215
217
  /**
216
218
  * ChannelView component props
@@ -401,6 +403,11 @@ export declare interface ChannelViewProps {
401
403
  * Hosts own navigation so this shared package never assumes an admin URL.
402
404
  */
403
405
  onBroadcastClick?: BroadcastClickHandler;
406
+ /**
407
+ * Resolves the current campaign name for a broadcast label. The stamped
408
+ * message name remains the fallback when this returns undefined.
409
+ */
410
+ resolveBroadcastName?: BroadcastNameResolver;
404
411
  /**
405
412
  * Passed to Stream `Channel` as `SendButton`. Required for hosts that replace
406
413
  * the send control: `Channel` merges this into `ComponentContext` and an
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as c, i as u, j as L, k as h, l as p, m as d, n as v, p as C, q as A, s as k, t as F, u as b, v as P, w as f, x, o as y, y as z, z as B, B as S, D as q, E as D, G as E, H as V, I as w } from "./index-CitR7B66.js";
1
+ import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as c, i as u, j as L, k as h, l as p, m as d, n as v, p as C, q as A, s as k, t as F, u as b, v as P, w as f, x, o as y, y as z, z as B, B as S, D as q, E as D, G as E, H as V, I as w } from "./index-U1rCukFo.js";
2
2
  export {
3
3
  e as ActionButton,
4
4
  t as Avatar,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "3.25.0",
3
+ "version": "3.27.0-rc-1785466017",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@linktr.ee/component-library": "11.8.6",
53
- "@linktr.ee/messaging-core": "^2.2.0",
53
+ "@linktr.ee/messaging-core": "2.3.0-rc-1785466017",
54
54
  "@linktr.ee/messaging-taxonomy": "^0.3.0",
55
55
  "@phosphor-icons/react": "^2.1.10",
56
56
  "culori": "^4.0.2"
@@ -57,6 +57,7 @@ const ChannelViewInner: React.FC<{
57
57
  showChannelInfo?: boolean
58
58
  onParticipantNameClick?: () => void
59
59
  onBroadcastClick?: ChannelViewProps['onBroadcastClick']
60
+ resolveBroadcastName?: ChannelViewProps['resolveBroadcastName']
60
61
  composerInput?: ChannelViewProps['composerInput']
61
62
  }> = ({
62
63
  onBack,
@@ -84,6 +85,7 @@ const ChannelViewInner: React.FC<{
84
85
  showChannelInfo = true,
85
86
  onParticipantNameClick,
86
87
  onBroadcastClick,
88
+ resolveBroadcastName,
87
89
  composerInput,
88
90
  }) => {
89
91
  const { channel } = useChannelStateContext()
@@ -99,6 +101,16 @@ const ChannelViewInner: React.FC<{
99
101
  const messageBroadcastClick = onBroadcastClick
100
102
  ? stableOnBroadcastClick
101
103
  : undefined
104
+ const resolveBroadcastNameRef = useRef(resolveBroadcastName)
105
+ useEffect(() => {
106
+ resolveBroadcastNameRef.current = resolveBroadcastName
107
+ }, [resolveBroadcastName])
108
+ const stableResolveBroadcastName = useCallback<
109
+ NonNullable<ChannelViewProps['resolveBroadcastName']>
110
+ >((broadcastId) => resolveBroadcastNameRef.current?.(broadcastId), [])
111
+ const messageBroadcastName = resolveBroadcastName
112
+ ? stableResolveBroadcastName
113
+ : undefined
102
114
 
103
115
  const hasVisibleMessages = channel.state.messages.some(
104
116
  (message) => message.type !== 'deleted'
@@ -140,6 +152,7 @@ const ChannelViewInner: React.FC<{
140
152
  chatbotVotingEnabled={chatbotVotingEnabled}
141
153
  viewerLanguage={viewerLanguage}
142
154
  onBroadcastClick={messageBroadcastClick}
155
+ resolveBroadcastName={messageBroadcastName}
143
156
  />
144
157
  )
145
158
 
@@ -149,7 +162,13 @@ const ChannelViewInner: React.FC<{
149
162
 
150
163
  return renderMessage(messageNode, message)
151
164
  },
152
- [chatbotVotingEnabled, messageBroadcastClick, renderMessage, viewerLanguage]
165
+ [
166
+ chatbotVotingEnabled,
167
+ messageBroadcastClick,
168
+ messageBroadcastName,
169
+ renderMessage,
170
+ viewerLanguage,
171
+ ]
153
172
  )
154
173
 
155
174
  return (
@@ -308,6 +327,7 @@ export const ChannelView = React.memo<ChannelViewProps>(
308
327
  showChannelInfo = true,
309
328
  onParticipantNameClick,
310
329
  onBroadcastClick,
330
+ resolveBroadcastName,
311
331
  composerInput,
312
332
  }) => {
313
333
  // Custom send message handler that:
@@ -422,6 +442,7 @@ export const ChannelView = React.memo<ChannelViewProps>(
422
442
  showChannelInfo={showChannelInfo}
423
443
  onParticipantNameClick={onParticipantNameClick}
424
444
  onBroadcastClick={onBroadcastClick}
445
+ resolveBroadcastName={resolveBroadcastName}
425
446
  composerInput={composerInput}
426
447
  />
427
448
  </Channel>
@@ -23,6 +23,7 @@ import {
23
23
  storyUsers,
24
24
  } from '../../stories/decorators/storyUser'
25
25
  import { createMockStreamChatClient } from '../../testing/createMockStreamChatClient'
26
+ import type { BroadcastNameResolver } from '../../types'
26
27
  import CustomTypingIndicator from '../CustomTypingIndicator'
27
28
 
28
29
  import { CustomMessageActions } from './CustomMessageActions'
@@ -108,6 +109,7 @@ const createMockChannel = async (
108
109
  interface TemplateProps {
109
110
  currentUser: StoryUser
110
111
  typingUser?: StoryUser
112
+ resolveBroadcastName?: BroadcastNameResolver
111
113
  messages: Array<{
112
114
  id: string
113
115
  text: string
@@ -138,7 +140,8 @@ const TemplateInner: React.FC<{
138
140
  currentUser: StoryUser
139
141
  typingUser?: StoryUser
140
142
  messages: TemplateProps['messages']
141
- }> = ({ currentUser, typingUser, messages }) => {
143
+ resolveBroadcastName?: BroadcastNameResolver
144
+ }> = ({ currentUser, typingUser, messages, resolveBroadcastName }) => {
142
145
  const [client] = React.useState(() => createMockStreamChatClient(currentUser))
143
146
 
144
147
  const [channel, setChannel] = React.useState<ChannelType | null>(null)
@@ -170,10 +173,11 @@ const TemplateInner: React.FC<{
170
173
  <CustomMessage
171
174
  {...props}
172
175
  onBroadcastClick={() => undefined}
176
+ resolveBroadcastName={resolveBroadcastName}
173
177
  />
174
178
  )
175
179
  }
176
- }, [])
180
+ }, [resolveBroadcastName])
177
181
 
178
182
  if (!channel) {
179
183
  return <div className="p-4">Loading...</div>
@@ -200,12 +204,14 @@ const Template: StoryFn<TemplateProps> = ({
200
204
  currentUser = storyUsers.creator,
201
205
  typingUser,
202
206
  messages,
207
+ resolveBroadcastName,
203
208
  }) => (
204
209
  <TemplateInner
205
210
  key={currentUser.id}
206
211
  currentUser={currentUser}
207
212
  typingUser={typingUser}
208
213
  messages={messages}
214
+ resolveBroadcastName={resolveBroadcastName}
209
215
  />
210
216
  )
211
217
 
@@ -302,6 +308,12 @@ BroadcastStatusNonLatest.args = {
302
308
  ],
303
309
  }
304
310
 
311
+ export const BroadcastStatusResolved: StoryFn<TemplateProps> = Template.bind({})
312
+ BroadcastStatusResolved.args = {
313
+ ...BroadcastStatus.args,
314
+ resolveBroadcastName: () => 'July 9th Class absentee',
315
+ }
316
+
305
317
  export const WithTipTag: StoryFn<TemplateProps> = Template.bind({})
306
318
  WithTipTag.args = {
307
319
  messages: [
@@ -138,4 +138,39 @@ describe('CustomMessage', () => {
138
138
  name: 'July 9th Class attendees',
139
139
  })
140
140
  })
141
+
142
+ it('prefers a resolved broadcast name over the stamped name', () => {
143
+ renderWithProviders(
144
+ <CustomMessage
145
+ resolveBroadcastName={() => 'July 9th Class absentee'}
146
+ />
147
+ )
148
+
149
+ expect(
150
+ screen.getByTestId('sent-message-broadcast-status')
151
+ ).toHaveTextContent('July 9th Class absentee')
152
+ })
153
+
154
+ it('falls back to the stamped broadcast name when resolution is unavailable', () => {
155
+ renderWithProviders(<CustomMessage resolveBroadcastName={() => undefined} />)
156
+
157
+ expect(
158
+ screen.getByTestId('sent-message-broadcast-status')
159
+ ).toHaveTextContent('July 9th Class attendees')
160
+ })
161
+
162
+ it('renders a later resolved name when the resolver value changes', () => {
163
+ const resolvedName: { current?: string } = {}
164
+ const resolveBroadcastName = () => resolvedName.current
165
+ const { rerender } = renderWithProviders(
166
+ <CustomMessage resolveBroadcastName={resolveBroadcastName} />
167
+ )
168
+
169
+ resolvedName.current = 'July 9th Class absentee'
170
+ rerender(<CustomMessage resolveBroadcastName={resolveBroadcastName} />)
171
+
172
+ expect(
173
+ screen.getByTestId('sent-message-broadcast-status')
174
+ ).toHaveTextContent('July 9th Class absentee')
175
+ })
141
176
  })
@@ -97,13 +97,18 @@ const SendingStatus = () => {
97
97
  const BroadcastStatus = ({
98
98
  broadcastId,
99
99
  broadcastName,
100
+ resolvedBroadcastName,
100
101
  onBroadcastClick,
101
102
  }: {
102
103
  broadcastId: string
103
104
  broadcastName?: string
105
+ resolvedBroadcastName?: string
104
106
  onBroadcastClick?: (broadcast: { id: string; name?: string }) => void
105
107
  }) => {
106
- const name = broadcastName || 'Broadcast'
108
+ const name =
109
+ resolvedBroadcastName ||
110
+ broadcastName ||
111
+ 'Broadcast'
107
112
  const content = (
108
113
  <>
109
114
  <span className="sent-message-broadcast-badge" aria-hidden="true">
@@ -160,8 +165,10 @@ const FailedStatus = () => (
160
165
  */
161
166
  export const SentMessageDeliveryStatus = ({
162
167
  onBroadcastClick,
168
+ resolvedBroadcastName,
163
169
  }: {
164
170
  onBroadcastClick?: (broadcast: { id: string; name?: string }) => void
171
+ resolvedBroadcastName?: string
165
172
  }) => {
166
173
  const { isMyMessage, message, threadList } = useMessageContext(
167
174
  'SentMessageDeliveryStatus'
@@ -192,6 +199,7 @@ export const SentMessageDeliveryStatus = ({
192
199
  <BroadcastStatus
193
200
  broadcastId={broadcastId}
194
201
  broadcastName={broadcastName}
202
+ resolvedBroadcastName={resolvedBroadcastName}
195
203
  onBroadcastClick={onBroadcastClick}
196
204
  />
197
205
  ) : null
@@ -30,6 +30,7 @@ import {
30
30
  } from 'stream-chat-react'
31
31
 
32
32
  import { useMessageVote } from '../../hooks/useMessageVote'
33
+ import type { BroadcastNameResolver } from '../../types'
33
34
  import { getMessageDisplayText } from '../../utils/getMessageDisplayText'
34
35
  import { Avatar } from '../Avatar'
35
36
  import { isLinkAttachment } from '../MediaMessage'
@@ -55,12 +56,14 @@ type CustomMessageUIComponentProps = MessageUIComponentProps & {
55
56
  chatbotVotingEnabled?: boolean
56
57
  viewerLanguage?: string
57
58
  onBroadcastClick?: (broadcast: { id: string; name?: string }) => void
59
+ resolveBroadcastName?: BroadcastNameResolver
58
60
  }
59
61
 
60
62
  type CustomMessageWithContextProps = MessageContextValue & {
61
63
  chatbotVotingEnabled?: boolean
62
64
  viewerLanguage?: string
63
65
  onBroadcastClick?: (broadcast: { id: string; name?: string }) => void
66
+ resolvedBroadcastName?: string
64
67
  }
65
68
 
66
69
  const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
@@ -82,6 +85,7 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
82
85
  threadList,
83
86
  viewerLanguage,
84
87
  onBroadcastClick,
88
+ resolvedBroadcastName,
85
89
  } = props
86
90
 
87
91
  const { client } = useChatContext('CustomMessage')
@@ -426,7 +430,10 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
426
430
  )}
427
431
  </div>
428
432
  )}
429
- <SentMessageDeliveryStatus onBroadcastClick={onBroadcastClick} />
433
+ <SentMessageDeliveryStatus
434
+ onBroadcastClick={onBroadcastClick}
435
+ resolvedBroadcastName={resolvedBroadcastName}
436
+ />
430
437
  {showReplyCountButton && (
431
438
  <MessageRepliesCountButton
432
439
  onClick={handleOpenThread}
@@ -447,11 +454,23 @@ const MemoizedCustomMessage = React.memo(
447
454
  if (prev.chatbotVotingEnabled !== next.chatbotVotingEnabled) return false
448
455
  if (prev.viewerLanguage !== next.viewerLanguage) return false
449
456
  if (prev.onBroadcastClick !== next.onBroadcastClick) return false
457
+ if (prev.resolvedBroadcastName !== next.resolvedBroadcastName) return false
450
458
  return areMessageUIPropsEqual(prev, next)
451
459
  }
452
460
  ) as typeof CustomMessageWithContext
453
461
 
454
462
  export const CustomMessage = (props: CustomMessageUIComponentProps) => {
455
463
  const messageContext = useMessageContext('CustomMessage')
456
- return <MemoizedCustomMessage {...messageContext} {...props} />
464
+ const broadcastId = messageContext.message.metadata?.broadcast_id
465
+ const resolvedBroadcastName = broadcastId
466
+ ? props.resolveBroadcastName?.(broadcastId)
467
+ : undefined
468
+
469
+ return (
470
+ <MemoizedCustomMessage
471
+ {...messageContext}
472
+ {...props}
473
+ resolvedBroadcastName={resolvedBroadcastName}
474
+ />
475
+ )
457
476
  }
@@ -39,6 +39,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
39
39
  renderChannelActions,
40
40
  onParticipantNameClick,
41
41
  onBroadcastClick,
42
+ resolveBroadcastName,
42
43
  renderMessage,
43
44
  onMessageLinkClick,
44
45
  showChannelInfo,
@@ -265,6 +266,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
265
266
  renderChannelActions={renderChannelActions}
266
267
  onParticipantNameClick={onParticipantNameClick}
267
268
  onBroadcastClick={onBroadcastClick}
269
+ resolveBroadcastName={resolveBroadcastName}
268
270
  renderMessage={renderMessage}
269
271
  onMessageLinkClick={onMessageLinkClick}
270
272
  showChannelInfo={showChannelInfo}
package/src/index.ts CHANGED
@@ -61,6 +61,7 @@ export type {
61
61
  MessagingCapabilities,
62
62
  MessageLinkClickHandler,
63
63
  BroadcastClickHandler,
64
+ BroadcastNameResolver,
64
65
  Participant,
65
66
  LockedAttachmentSource,
66
67
  } from './types'
package/src/types.ts CHANGED
@@ -41,6 +41,8 @@ export type BroadcastClickHandler = (broadcast: {
41
41
  name?: string
42
42
  }) => void
43
43
 
44
+ export type BroadcastNameResolver = (broadcastId: string) => string | undefined
45
+
44
46
  export type ChannelPreviewProps = ChannelPreviewUIComponentProps & {
45
47
  selectedChannel?: Channel | null
46
48
  onChannelSelect: (channel: Channel) => void
@@ -373,6 +375,12 @@ export interface ChannelViewProps {
373
375
  */
374
376
  onBroadcastClick?: BroadcastClickHandler
375
377
 
378
+ /**
379
+ * Resolves the current campaign name for a broadcast label. The stamped
380
+ * message name remains the fallback when this returns undefined.
381
+ */
382
+ resolveBroadcastName?: BroadcastNameResolver
383
+
376
384
  /**
377
385
  * Passed to Stream `Channel` as `SendButton`. Required for hosts that replace
378
386
  * the send control: `Channel` merges this into `ComponentContext` and an
@@ -442,6 +450,7 @@ export type ChannelViewPassthroughProps = Pick<
442
450
  | 'renderMessage'
443
451
  | 'onMessageLinkClick'
444
452
  | 'onBroadcastClick'
453
+ | 'resolveBroadcastName'
445
454
  | 'showChannelInfo'
446
455
  | 'composerInput'
447
456
  >