@linktr.ee/messaging-react 3.6.2-rc-1783311170 → 3.6.2-rc-1783314663

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-DnEyeR_d.js → Card-Byosl29s.js} +3 -3
  2. package/dist/{Card-DnEyeR_d.js.map → Card-Byosl29s.js.map} +1 -1
  3. package/dist/{Card-CK1jw1VU.cjs → Card-CLfoYI1R.cjs} +2 -2
  4. package/dist/{Card-CK1jw1VU.cjs.map → Card-CLfoYI1R.cjs.map} +1 -1
  5. package/dist/{Card-CSwQT3wz.cjs → Card-CSkWY9mH.cjs} +2 -2
  6. package/dist/{Card-CSwQT3wz.cjs.map → Card-CSkWY9mH.cjs.map} +1 -1
  7. package/dist/{Card-CJh6R76n.js → Card-CqEKHw9S.js} +2 -2
  8. package/dist/{Card-CJh6R76n.js.map → Card-CqEKHw9S.js.map} +1 -1
  9. package/dist/{Card-DUoHKAuh.js → Card-ILtY9lfF.js} +2 -2
  10. package/dist/{Card-DUoHKAuh.js.map → Card-ILtY9lfF.js.map} +1 -1
  11. package/dist/{Card-DQtg7wWP.cjs → Card-UN0QRlxk.cjs} +2 -2
  12. package/dist/{Card-DQtg7wWP.cjs.map → Card-UN0QRlxk.cjs.map} +1 -1
  13. package/dist/{LockedThumbnail-C_F2Sw-9.js → LockedThumbnail-BKI_6JUF.js} +2 -2
  14. package/dist/{LockedThumbnail-C_F2Sw-9.js.map → LockedThumbnail-BKI_6JUF.js.map} +1 -1
  15. package/dist/{LockedThumbnail-BZLpmTpY.cjs → LockedThumbnail-DZ6C2xsr.cjs} +2 -2
  16. package/dist/{LockedThumbnail-BZLpmTpY.cjs.map → LockedThumbnail-DZ6C2xsr.cjs.map} +1 -1
  17. package/dist/assets/index.css +1 -1
  18. package/dist/{index-DcEVHNS3.js → index-DPwo1avm.js} +682 -688
  19. package/dist/index-DPwo1avm.js.map +1 -0
  20. package/dist/index-Q0FmgUJF.cjs +2 -0
  21. package/dist/index-Q0FmgUJF.cjs.map +1 -0
  22. package/dist/index.cjs +1 -1
  23. package/dist/index.js +1 -1
  24. package/package.json +2 -2
  25. package/src/components/CustomMessage/CustomMessage.stories.tsx +18 -11
  26. package/src/components/CustomMessage/MessageDeliveryStatus.test.tsx +60 -0
  27. package/src/components/CustomMessage/MessageDeliveryStatus.tsx +43 -0
  28. package/src/components/CustomMessage/index.tsx +2 -9
  29. package/src/styles.css +16 -25
  30. package/dist/index-DcEVHNS3.js.map +0 -1
  31. package/dist/index-LP0PQJxl.cjs +0 -2
  32. package/dist/index-LP0PQJxl.cjs.map +0 -1
  33. package/src/components/CustomMessage/SentMessageDeliveryStatus.test.tsx +0 -83
  34. package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +0 -67
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-LP0PQJxl.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.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.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-Q0FmgUJF.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.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.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.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 d, m as p, n as v, o as C, p as A, q as k, s as F, t as P, u as b, v as f, w as x, x as y, y as S, z as q, B as z, D as B, E as D, G as E } from "./index-DcEVHNS3.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 d, m as p, n as v, o as C, p as A, q as k, s as F, t as P, u as b, v as f, w as x, x as y, y as S, z as q, B as z, D as B, E as D, G as E } from "./index-DPwo1avm.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.6.2-rc-1783311170",
3
+ "version": "3.6.2-rc-1783314663",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@linktr.ee/component-library": "11.8.6",
41
- "@linktr.ee/messaging-core": "2.3.0-rc-1783311170",
41
+ "@linktr.ee/messaging-core": "2.3.0-rc-1783314663",
42
42
  "@phosphor-icons/react": "^2.1.10"
43
43
  },
44
44
  "devDependencies": {
@@ -225,36 +225,43 @@ Default.args = {
225
225
  ],
226
226
  }
227
227
 
228
- // MES-1036: "✓✓ Delivered" appears below only the most recent *sent*
229
- // message. Every mock message carries status: 'received', and stream's
230
- // MessageList derives `lastOwnMessage`, so the indicator lands on the last
231
- // creator message ("Talk soon!") and not on the earlier sent bubble.
228
+ // MES-1036: "✓✓ Delivered" appears below the last bubble of *every* message
229
+ // group, on both the received (left) and sent (right) sides. Every mock
230
+ // message carries status: 'received'; the indicator is gated on stream's
231
+ // `endOfGroup`, so it shows once per consecutive same-author run here below
232
+ // "Hey there!" (received), "Talk soon!" (sent), and "See you then." (sent
233
+ // run of two).
232
234
  export const DeliveredStatus: StoryFn<TemplateProps> = Template.bind({})
233
235
  DeliveredStatus.args = {
234
236
  messages: [
235
237
  {
236
238
  id: 'msg-1',
237
- text: 'Hey, did you get my last message?',
239
+ text: 'Hey there!',
238
240
  user: storyUsers.visitor,
239
241
  },
240
242
  {
241
243
  id: 'msg-2',
242
- text: 'Yes! Just replying now.',
244
+ text: 'Hi! Great to hear from you.',
243
245
  user: storyUsers.creator,
244
246
  },
245
247
  {
246
248
  id: 'msg-3',
247
- text: 'Sounds good.',
248
- user: storyUsers.visitor,
249
+ text: 'Talk soon!',
250
+ user: storyUsers.creator,
249
251
  },
250
252
  {
251
253
  id: 'msg-4',
252
- text: 'Let me know if you need anything else.',
253
- user: storyUsers.creator,
254
+ text: 'Sounds good catch up tomorrow?',
255
+ user: storyUsers.visitor,
254
256
  },
255
257
  {
256
258
  id: 'msg-5',
257
- text: 'Talk soon!',
259
+ text: 'Absolutely.',
260
+ user: storyUsers.creator,
261
+ },
262
+ {
263
+ id: 'msg-6',
264
+ text: 'See you then.',
258
265
  user: storyUsers.creator,
259
266
  },
260
267
  ],
@@ -0,0 +1,60 @@
1
+ import type { LocalMessage } from 'stream-chat'
2
+ import { describe, expect, it } from 'vitest'
3
+
4
+ import { renderWithProviders, screen } from '../../test/utils'
5
+
6
+ import { MessageDeliveryStatus } from './MessageDeliveryStatus'
7
+
8
+ const receivedMessage = {
9
+ id: 'message-1',
10
+ status: 'received',
11
+ type: 'regular',
12
+ } as unknown as LocalMessage
13
+
14
+ const render = (
15
+ props: Partial<{ message: LocalMessage; endOfGroup: boolean }> = {}
16
+ ) =>
17
+ renderWithProviders(
18
+ <MessageDeliveryStatus
19
+ message={props.message ?? receivedMessage}
20
+ endOfGroup={props.endOfGroup ?? true}
21
+ />
22
+ )
23
+
24
+ describe('MessageDeliveryStatus', () => {
25
+ it('renders "Delivered" at the end of a group for a stored message', () => {
26
+ render()
27
+
28
+ expect(screen.getByTestId('message-delivery-status')).toHaveTextContent(
29
+ 'Delivered'
30
+ )
31
+ })
32
+
33
+ it('renders nothing for messages that are not the end of their group', () => {
34
+ const { container } = render({ endOfGroup: false })
35
+
36
+ expect(container).toBeEmptyDOMElement()
37
+ })
38
+
39
+ it.each(['sending', 'failed'] as const)(
40
+ 'renders nothing while the message status is %s',
41
+ (status) => {
42
+ const { container } = render({
43
+ message: { ...receivedMessage, status } as unknown as LocalMessage,
44
+ })
45
+
46
+ expect(container).toBeEmptyDOMElement()
47
+ }
48
+ )
49
+
50
+ it('renders nothing for error messages', () => {
51
+ const { container } = render({
52
+ message: {
53
+ ...receivedMessage,
54
+ type: 'error',
55
+ } as unknown as LocalMessage,
56
+ })
57
+
58
+ expect(container).toBeEmptyDOMElement()
59
+ })
60
+ })
@@ -0,0 +1,43 @@
1
+ import { ChecksIcon } from '@phosphor-icons/react'
2
+ import type { LocalMessage } from 'stream-chat'
3
+
4
+ interface MessageDeliveryStatusProps {
5
+ message: LocalMessage
6
+ /**
7
+ * stream's end-of-group flag — the last message in a run of consecutive
8
+ * messages from the same author.
9
+ */
10
+ endOfGroup?: boolean
11
+ }
12
+
13
+ /**
14
+ * "✓✓ Delivered" status shown beneath the last bubble of every message group,
15
+ * on both the sent (right) and received (left) sides (MES-1036). The design
16
+ * displays the status per group rather than only on the most recent message,
17
+ * so it's gated on `endOfGroup` rather than "last own message".
18
+ *
19
+ * `endOfGroup` is compared by both stream's `Message` memo
20
+ * (`areMessagePropsEqual`) and `CustomMessage`'s memo (`areMessageUIPropsEqual`),
21
+ * so the status reliably appears/updates as groups form and re-form — no
22
+ * stale-memo caveats. It renders only once a message is stored
23
+ * (`status === 'received'`, true for incoming messages too) and never on
24
+ * errors. Left/right alignment comes from the outer grid (see `styles.css`).
25
+ */
26
+ export const MessageDeliveryStatus = ({
27
+ message,
28
+ endOfGroup,
29
+ }: MessageDeliveryStatusProps) => {
30
+ if (!endOfGroup || message.type === 'error' || message.status !== 'received') {
31
+ return null
32
+ }
33
+
34
+ return (
35
+ <div
36
+ className="str-chat__message-delivery-status"
37
+ data-testid="message-delivery-status"
38
+ >
39
+ <ChecksIcon size={14} weight="bold" aria-hidden="true" />
40
+ <span>Delivered</span>
41
+ </div>
42
+ )
43
+ }
@@ -39,6 +39,7 @@ import {
39
39
  } from '../MessageAttachment'
40
40
 
41
41
  import { useCustomMessage } from './context'
42
+ import { MessageDeliveryStatus } from './MessageDeliveryStatus'
42
43
  import {
43
44
  MessageTag,
44
45
  isAttachmentMessage,
@@ -46,7 +47,6 @@ import {
46
47
  isTipOnlyMessage,
47
48
  } from './MessageTag'
48
49
  import { MessageVoteButtons } from './MessageVoteButtons'
49
- import { SentMessageDeliveryStatus } from './SentMessageDeliveryStatus'
50
50
  import StreamAttachmentMessage, {
51
51
  buildOrderedAttachmentSegments,
52
52
  } from './StreamAttachmentMessage'
@@ -398,7 +398,7 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
398
398
  )}
399
399
  </div>
400
400
  )}
401
- <SentMessageDeliveryStatus />
401
+ <MessageDeliveryStatus message={message} endOfGroup={endOfGroup} />
402
402
  {showReplyCountButton && (
403
403
  <MessageRepliesCountButton
404
404
  onClick={handleOpenThread}
@@ -418,13 +418,6 @@ const MemoizedCustomMessage = React.memo(
418
418
  (prev, next) => {
419
419
  if (prev.chatbotVotingEnabled !== next.chatbotVotingEnabled) return false
420
420
  if (prev.viewerLanguage !== next.viewerLanguage) return false
421
- // `lastOwnMessage` drives the "Delivered" indicator, which
422
- // `SentMessageDeliveryStatus` derives from stream's `MessageStatus`
423
- // (reading it off the message context inside this memoised subtree).
424
- // `areMessageUIPropsEqual` doesn't compare it, so without this a stale
425
- // "Delivered" would linger on the previous bubble after a newer message
426
- // is sent — re-render when it changes.
427
- if (prev.lastOwnMessage?.id !== next.lastOwnMessage?.id) return false
428
421
  return areMessageUIPropsEqual(prev, next)
429
422
  }
430
423
  ) as typeof CustomMessageWithContext
package/src/styles.css CHANGED
@@ -333,12 +333,16 @@
333
333
  grid-column-gap: 4px;
334
334
  }
335
335
 
336
- /* Outer grid for other (incoming) messages — add footer row after message */
336
+ /* Outer grid for other (incoming) messages — footer + delivery-status rows
337
+ after message. `delivery-status` carries the "Delivered" status on the last
338
+ bubble of each incoming group (MES-1036); it aligns under the message, not
339
+ the avatar, and collapses to 0 height on messages that don't render it. */
337
340
  .str-chat__li .str-chat__message--other {
338
341
  grid-template-areas:
339
342
  '. message-reminder'
340
343
  'avatar message'
341
344
  '. footer'
345
+ '. delivery-status'
342
346
  '. replies'
343
347
  '. translation-notice'
344
348
  '. custom-metadata'
@@ -352,9 +356,9 @@
352
356
  }
353
357
 
354
358
  /* Outer grid for me (outgoing) messages — footer + delivery-status rows
355
- after message. `delivery-status` carries the "Delivered" receipt on the
356
- last sent message (MES-1036); the row collapses to 0 height on messages
357
- that don't render it. */
359
+ after message. `delivery-status` carries the "Delivered" status on the last
360
+ bubble of each outgoing group (MES-1036); the row collapses to 0 height on
361
+ messages that don't render it. */
358
362
  .str-chat__li .str-chat__message--me {
359
363
  grid-template-areas:
360
364
  'message-reminder'
@@ -416,34 +420,21 @@
416
420
  align-items: flex-end;
417
421
  }
418
422
 
419
- /* "✓✓ Delivered" delivery status under the last sent message (MES-1036).
420
- `SentMessageDeliveryStatus` renders it through stream's `MessageStatus`,
421
- whose `.str-chat__message-status` span is the grid item here (right-aligned
422
- via the outer grid's `justify-items: end`). Stream emits that span for every
423
- own message and leaves it empty when no state is active (i.e. not the last
424
- sent message), so `:empty` collapses those away. */
425
- .str-chat__li .str-chat__message--me .str-chat__message-status {
423
+ /* "✓✓ Delivered" delivery status beneath the last bubble of each message
424
+ group (MES-1036), for both sent and received messages. It sits in the
425
+ `delivery-status` grid row and inherits left/right alignment from each
426
+ side's grid `justify-items` (start for `--other`, end for `--me`). */
427
+ .str-chat__li .str-chat__message-delivery-status {
426
428
  grid-area: delivery-status;
427
- justify-content: flex-end;
429
+ display: inline-flex;
430
+ align-items: center;
428
431
  gap: 2px;
429
432
  padding-block-start: 2px;
430
- padding-inline-end: 4px;
433
+ padding-inline: 4px;
431
434
  font-size: 12px;
432
435
  line-height: 1.4;
433
436
  color: var(--str-chat__text-low-emphasis-color, rgba(0, 0, 0, 0.5));
434
437
  }
435
- .str-chat__li .str-chat__message-status:empty {
436
- display: none;
437
- }
438
- /* Match the check icon to the label size/colour (overrides stream's default
439
- per-state icon sizing and status-colour fill). */
440
- .str-chat__li .str-chat__message--me .str-chat__message-status svg {
441
- width: 14px;
442
- height: 14px;
443
- }
444
- .str-chat__li .str-chat__message--me .str-chat__message-status svg path {
445
- fill: currentColor;
446
- }
447
438
 
448
439
  /* Channel list load-more button overrides */
449
440
  .str-chat__channel-list .str-chat__load-more-button__button {