@linktr.ee/messaging-react 3.9.0 → 3.9.1-rc-1783576271
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/{Card-DWT-IkeK.cjs → Card-CyBRO0Ex.cjs} +2 -2
- package/dist/{Card-DWT-IkeK.cjs.map → Card-CyBRO0Ex.cjs.map} +1 -1
- package/dist/{Card-B8Zz3GRL.js → Card-DYNxwKX6.js} +2 -2
- package/dist/{Card-B8Zz3GRL.js.map → Card-DYNxwKX6.js.map} +1 -1
- package/dist/{Card-BmYSOINp.cjs → Card-DmfP-4oF.cjs} +2 -2
- package/dist/{Card-BmYSOINp.cjs.map → Card-DmfP-4oF.cjs.map} +1 -1
- package/dist/{Card-WoQGTJ5n.cjs → Card-PBfzY620.cjs} +2 -2
- package/dist/{Card-WoQGTJ5n.cjs.map → Card-PBfzY620.cjs.map} +1 -1
- package/dist/{Card-BnJLBTl6.js → Card-dZkL-om-.js} +3 -3
- package/dist/{Card-BnJLBTl6.js.map → Card-dZkL-om-.js.map} +1 -1
- package/dist/{Card-Gapf9yEL.js → Card-xR3OTXRB.js} +2 -2
- package/dist/{Card-Gapf9yEL.js.map → Card-xR3OTXRB.js.map} +1 -1
- package/dist/{LockedThumbnail-Cu3qwKAd.js → LockedThumbnail-BblFdDJp.js} +2 -2
- package/dist/{LockedThumbnail-Cu3qwKAd.js.map → LockedThumbnail-BblFdDJp.js.map} +1 -1
- package/dist/{LockedThumbnail-DFByBLYS.cjs → LockedThumbnail-eE8ljauK.cjs} +2 -2
- package/dist/{LockedThumbnail-DFByBLYS.cjs.map → LockedThumbnail-eE8ljauK.cjs.map} +1 -1
- package/dist/{index-C1Zaiccm.cjs → index-Bxezkdl6.cjs} +2 -2
- package/dist/index-Bxezkdl6.cjs.map +1 -0
- package/dist/{index-Bv79lb0u.js → index-FY6hmphi.js} +133 -134
- package/dist/index-FY6hmphi.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/src/components/CustomMessage/SentMessageDeliveryStatus.test.tsx +29 -11
- package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +22 -26
- package/dist/index-Bv79lb0u.js.map +0 -1
- package/dist/index-C1Zaiccm.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-Bxezkdl6.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-
|
|
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-FY6hmphi.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.9.
|
|
3
|
+
"version": "3.9.1-rc-1783576271",
|
|
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": "
|
|
53
|
+
"@linktr.ee/messaging-core": "2.3.0-rc-1783576271",
|
|
54
54
|
"@phosphor-icons/react": "^2.1.10"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import {
|
|
3
3
|
useChannelStateContext,
|
|
4
|
-
useChatContext,
|
|
5
4
|
useMessageContext,
|
|
6
5
|
} from 'stream-chat-react'
|
|
7
6
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
@@ -13,14 +12,13 @@ import { SentMessageDeliveryStatus } from './SentMessageDeliveryStatus'
|
|
|
13
12
|
// stream-chat-react's `MessageStatus` owns the outer gating (own message, not
|
|
14
13
|
// error, not in a thread) and only exposes a terminal state once a message is
|
|
15
14
|
// stored — Stream's tested code. What this component owns is the "Delivered"
|
|
16
|
-
// label wired into the terminal slots (sent/delivered/read), its "
|
|
17
|
-
// message" gate derived from live channel state, and suppressing
|
|
18
|
-
// spinner. Mock `MessageStatus` to render the slots it was handed,
|
|
19
|
-
// context hooks the label reads.
|
|
15
|
+
// label wired into the terminal slots (sent/delivered/read), its "latest
|
|
16
|
+
// message in the thread" gate derived from live channel state, and suppressing
|
|
17
|
+
// the sending spinner. Mock `MessageStatus` to render the slots it was handed,
|
|
18
|
+
// and the context hooks the label reads.
|
|
20
19
|
vi.mock('stream-chat-react', () => ({
|
|
21
20
|
useMessageContext: vi.fn(),
|
|
22
21
|
useChannelStateContext: vi.fn(),
|
|
23
|
-
useChatContext: vi.fn(),
|
|
24
22
|
MessageStatus: ({
|
|
25
23
|
MessageSentStatus,
|
|
26
24
|
MessageDeliveredStatus,
|
|
@@ -46,10 +44,10 @@ vi.mock('stream-chat-react', () => ({
|
|
|
46
44
|
|
|
47
45
|
const mockedUseMessageContext = vi.mocked(useMessageContext)
|
|
48
46
|
const mockedUseChannelStateContext = vi.mocked(useChannelStateContext)
|
|
49
|
-
const mockedUseChatContext = vi.mocked(useChatContext)
|
|
50
47
|
|
|
51
48
|
// A run where the viewer ('me') sent the first and last messages, with an
|
|
52
|
-
// incoming message in between — the
|
|
49
|
+
// incoming message in between — the label must sit on the last message ('own-2')
|
|
50
|
+
// and clear from the earlier one.
|
|
53
51
|
const CHANNEL_MESSAGES = [
|
|
54
52
|
{ id: 'own-1', user: { id: 'me' } },
|
|
55
53
|
{ id: 'their-1', user: { id: 'them' } },
|
|
@@ -60,13 +58,12 @@ const TERMINAL_SLOTS = ['sent-slot', 'delivered-slot', 'read-slot'] as const
|
|
|
60
58
|
|
|
61
59
|
describe('SentMessageDeliveryStatus', () => {
|
|
62
60
|
beforeEach(() => {
|
|
63
|
-
mockedUseChatContext.mockReturnValue({ client: { user: { id: 'me' } } } as never)
|
|
64
61
|
mockedUseChannelStateContext.mockReturnValue({
|
|
65
62
|
messages: CHANNEL_MESSAGES,
|
|
66
63
|
} as never)
|
|
67
64
|
})
|
|
68
65
|
|
|
69
|
-
it('renders "Delivered" in every terminal slot for the last
|
|
66
|
+
it('renders "Delivered" in every terminal slot for the last message in the thread', () => {
|
|
70
67
|
// delivered/read fire ahead of sent in receipt channels, so all three
|
|
71
68
|
// must show the label — never Stream's default delivered icon / read
|
|
72
69
|
// avatars.
|
|
@@ -83,7 +80,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
83
80
|
}
|
|
84
81
|
})
|
|
85
82
|
|
|
86
|
-
it('renders nothing for an earlier own message
|
|
83
|
+
it('renders nothing for an earlier own message once a later message exists', () => {
|
|
87
84
|
mockedUseMessageContext.mockReturnValue({
|
|
88
85
|
message: { id: 'own-1' },
|
|
89
86
|
} as never)
|
|
@@ -95,6 +92,27 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
95
92
|
}
|
|
96
93
|
})
|
|
97
94
|
|
|
95
|
+
it('renders nothing for an own message once a reply arrives after it', () => {
|
|
96
|
+
// 'own-2' was the viewer's last sent message, but 'their-1' is now the
|
|
97
|
+
// latest message in the thread — the label must clear from the bubble.
|
|
98
|
+
mockedUseChannelStateContext.mockReturnValue({
|
|
99
|
+
messages: [
|
|
100
|
+
{ id: 'own-1', user: { id: 'me' } },
|
|
101
|
+
{ id: 'own-2', user: { id: 'me' } },
|
|
102
|
+
{ id: 'their-1', user: { id: 'them' } },
|
|
103
|
+
],
|
|
104
|
+
} as never)
|
|
105
|
+
mockedUseMessageContext.mockReturnValue({
|
|
106
|
+
message: { id: 'own-2' },
|
|
107
|
+
} as never)
|
|
108
|
+
|
|
109
|
+
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
110
|
+
|
|
111
|
+
for (const slot of TERMINAL_SLOTS) {
|
|
112
|
+
expect(screen.getByTestId(slot)).toBeEmptyDOMElement()
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
98
116
|
it('always suppresses the sending spinner', () => {
|
|
99
117
|
mockedUseMessageContext.mockReturnValue({
|
|
100
118
|
message: { id: 'own-2' },
|
|
@@ -3,7 +3,6 @@ import { useMemo } from 'react'
|
|
|
3
3
|
import {
|
|
4
4
|
MessageStatus,
|
|
5
5
|
useChannelStateContext,
|
|
6
|
-
useChatContext,
|
|
7
6
|
useMessageContext,
|
|
8
7
|
} from 'stream-chat-react'
|
|
9
8
|
|
|
@@ -15,21 +14,23 @@ import {
|
|
|
15
14
|
*
|
|
16
15
|
* 1. `MessageStatus` picks its `delivered`/`read` branches ahead of `sent`
|
|
17
16
|
* whenever Stream has `deliveredTo`/`readBy`, and — unlike `sent` — those
|
|
18
|
-
* branches aren't gated to the last
|
|
17
|
+
* branches aren't gated to the last message. So we override all three
|
|
19
18
|
* terminal slots with this same label (never Stream's default delivered
|
|
20
|
-
* icon / read avatars — Read is out of scope) and re-apply the "
|
|
21
|
-
* message" gate ourselves
|
|
19
|
+
* icon / read avatars — Read is out of scope) and re-apply the "latest
|
|
20
|
+
* message in the thread" gate ourselves: the label only shows beneath the
|
|
21
|
+
* viewer's sent message while it is still the last message in the channel,
|
|
22
|
+
* and disappears as soon as a reply arrives after it.
|
|
22
23
|
*
|
|
23
|
-
* 2. We derive "
|
|
24
|
-
*
|
|
25
|
-
* `areMessagePropsEqual`, which does not compare
|
|
26
|
-
* previous own row whose message/grouping props are unchanged (e.g.
|
|
27
|
-
* an intervening incoming message) never re-renders, so
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
24
|
+
* 2. We derive "latest message" from **live channel state**, not the message
|
|
25
|
+
* context's `lastOwnMessage`/`lastReceivedId`. Stream's `Message` is
|
|
26
|
+
* memoised by `areMessagePropsEqual`, which does not compare those props;
|
|
27
|
+
* a previous own row whose message/grouping props are unchanged (e.g.
|
|
28
|
+
* after an intervening incoming message) never re-renders, so the old
|
|
29
|
+
* bubble would keep showing "Delivered" beside the new one.
|
|
30
|
+
* `useChannelStateContext` gets a fresh `messages` array on every new
|
|
31
|
+
* message and, being a context, re-renders this leaf straight through the
|
|
32
|
+
* stale `Message`/`MessageStatus` memos — so the label reliably clears
|
|
33
|
+
* once a reply lands.
|
|
33
34
|
*
|
|
34
35
|
* Rendered inside stream's `.str-chat__message-status` span, which supplies
|
|
35
36
|
* the flex layout; icon and copy are styled via that span in `styles.css`.
|
|
@@ -37,18 +38,13 @@ import {
|
|
|
37
38
|
const DeliveredStatus = () => {
|
|
38
39
|
const { message } = useMessageContext('SentMessageDeliveryStatus')
|
|
39
40
|
const { messages } = useChannelStateContext('SentMessageDeliveryStatus')
|
|
40
|
-
const { client } = useChatContext('SentMessageDeliveryStatus')
|
|
41
41
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (messages[i].user?.id === ownUserId) return messages[i].id
|
|
47
|
-
}
|
|
48
|
-
return undefined
|
|
49
|
-
}, [messages, ownUserId])
|
|
42
|
+
const lastMessageId = useMemo(
|
|
43
|
+
() => messages?.[messages.length - 1]?.id,
|
|
44
|
+
[messages]
|
|
45
|
+
)
|
|
50
46
|
|
|
51
|
-
if (message.id !==
|
|
47
|
+
if (message.id !== lastMessageId) {
|
|
52
48
|
return null
|
|
53
49
|
}
|
|
54
50
|
|
|
@@ -73,8 +69,8 @@ const NoStatus = () => null
|
|
|
73
69
|
* terminal (sending/sent/delivered/read) state once the message is stored.
|
|
74
70
|
* Scope is "Delivered" only: the sending spinner is suppressed and all
|
|
75
71
|
* terminal states render {@link DeliveredStatus}, which supplies the label
|
|
76
|
-
* and the
|
|
77
|
-
* live channel state rather than the context's
|
|
72
|
+
* and the latest-message-in-thread gate (see there for why the gate is
|
|
73
|
+
* computed from live channel state rather than the context's props).
|
|
78
74
|
*/
|
|
79
75
|
export const SentMessageDeliveryStatus = () => (
|
|
80
76
|
<MessageStatus
|