@linktr.ee/messaging-react 3.6.2-rc-1783311170 → 3.6.2-rc-1783311731
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-DUoHKAuh.js → Card-0wf8lj5n.js} +2 -2
- package/dist/{Card-DUoHKAuh.js.map → Card-0wf8lj5n.js.map} +1 -1
- package/dist/{Card-CK1jw1VU.cjs → Card-4UyBK3XO.cjs} +2 -2
- package/dist/{Card-CK1jw1VU.cjs.map → Card-4UyBK3XO.cjs.map} +1 -1
- package/dist/{Card-DQtg7wWP.cjs → Card-6b4Ws9rn.cjs} +2 -2
- package/dist/{Card-DQtg7wWP.cjs.map → Card-6b4Ws9rn.cjs.map} +1 -1
- package/dist/{Card-CSwQT3wz.cjs → Card-DsQhJjj0.cjs} +2 -2
- package/dist/{Card-CSwQT3wz.cjs.map → Card-DsQhJjj0.cjs.map} +1 -1
- package/dist/{Card-DnEyeR_d.js → Card-RZ6C_IkE.js} +3 -3
- package/dist/{Card-DnEyeR_d.js.map → Card-RZ6C_IkE.js.map} +1 -1
- package/dist/{Card-CJh6R76n.js → Card-iGNcxybY.js} +2 -2
- package/dist/{Card-CJh6R76n.js.map → Card-iGNcxybY.js.map} +1 -1
- package/dist/{LockedThumbnail-C_F2Sw-9.js → LockedThumbnail-Do9udNMm.js} +2 -2
- package/dist/{LockedThumbnail-C_F2Sw-9.js.map → LockedThumbnail-Do9udNMm.js.map} +1 -1
- package/dist/{LockedThumbnail-BZLpmTpY.cjs → LockedThumbnail-N0pNOO3D.cjs} +2 -2
- package/dist/{LockedThumbnail-BZLpmTpY.cjs.map → LockedThumbnail-N0pNOO3D.cjs.map} +1 -1
- package/dist/index-B3ZJaqJY.cjs +2 -0
- package/dist/index-B3ZJaqJY.cjs.map +1 -0
- package/dist/{index-DcEVHNS3.js → index-wFe1UO9t.js} +160 -158
- package/dist/index-wFe1UO9t.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 +36 -12
- package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +46 -27
- package/src/components/CustomMessage/index.tsx +0 -7
- package/dist/index-DcEVHNS3.js.map +0 -1
- package/dist/index-LP0PQJxl.cjs +0 -2
- package/dist/index-LP0PQJxl.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-B3ZJaqJY.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-wFe1UO9t.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-
|
|
3
|
+
"version": "3.6.2-rc-1783311731",
|
|
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-
|
|
41
|
+
"@linktr.ee/messaging-core": "2.3.0-rc-1783311731",
|
|
42
42
|
"@phosphor-icons/react": "^2.1.10"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useChannelStateContext,
|
|
4
|
+
useChatContext,
|
|
5
|
+
useMessageContext,
|
|
6
|
+
} from 'stream-chat-react'
|
|
3
7
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
4
8
|
|
|
5
9
|
import { renderWithProviders, screen, within } from '../../test/utils'
|
|
@@ -7,13 +11,16 @@ import { renderWithProviders, screen, within } from '../../test/utils'
|
|
|
7
11
|
import { SentMessageDeliveryStatus } from './SentMessageDeliveryStatus'
|
|
8
12
|
|
|
9
13
|
// stream-chat-react's `MessageStatus` owns the outer gating (own message, not
|
|
10
|
-
// error, not in a thread) and
|
|
11
|
-
// this component owns is the "Delivered"
|
|
12
|
-
// (sent/delivered/read), its "last own
|
|
13
|
-
//
|
|
14
|
-
//
|
|
14
|
+
// error, not in a thread) and only exposes a terminal state once a message is
|
|
15
|
+
// stored — Stream's tested code. What this component owns is the "Delivered"
|
|
16
|
+
// label wired into the terminal slots (sent/delivered/read), its "last own
|
|
17
|
+
// message" gate derived from live channel state, and suppressing the sending
|
|
18
|
+
// spinner. Mock `MessageStatus` to render the slots it was handed, and the
|
|
19
|
+
// context hooks the label reads.
|
|
15
20
|
vi.mock('stream-chat-react', () => ({
|
|
16
21
|
useMessageContext: vi.fn(),
|
|
22
|
+
useChannelStateContext: vi.fn(),
|
|
23
|
+
useChatContext: vi.fn(),
|
|
17
24
|
MessageStatus: ({
|
|
18
25
|
MessageSentStatus,
|
|
19
26
|
MessageDeliveredStatus,
|
|
@@ -38,14 +45,24 @@ vi.mock('stream-chat-react', () => ({
|
|
|
38
45
|
}))
|
|
39
46
|
|
|
40
47
|
const mockedUseMessageContext = vi.mocked(useMessageContext)
|
|
48
|
+
const mockedUseChannelStateContext = vi.mocked(useChannelStateContext)
|
|
49
|
+
const mockedUseChatContext = vi.mocked(useChatContext)
|
|
50
|
+
|
|
51
|
+
// A run where the viewer ('me') sent the first and last messages, with an
|
|
52
|
+
// incoming message in between — the case that broke the memo-based approach.
|
|
53
|
+
const CHANNEL_MESSAGES = [
|
|
54
|
+
{ id: 'own-1', user: { id: 'me' } },
|
|
55
|
+
{ id: 'their-1', user: { id: 'them' } },
|
|
56
|
+
{ id: 'own-2', user: { id: 'me' } },
|
|
57
|
+
]
|
|
41
58
|
|
|
42
59
|
const TERMINAL_SLOTS = ['sent-slot', 'delivered-slot', 'read-slot'] as const
|
|
43
60
|
|
|
44
61
|
describe('SentMessageDeliveryStatus', () => {
|
|
45
62
|
beforeEach(() => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
63
|
+
mockedUseChatContext.mockReturnValue({ client: { user: { id: 'me' } } } as never)
|
|
64
|
+
mockedUseChannelStateContext.mockReturnValue({
|
|
65
|
+
messages: CHANNEL_MESSAGES,
|
|
49
66
|
} as never)
|
|
50
67
|
})
|
|
51
68
|
|
|
@@ -53,6 +70,10 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
53
70
|
// delivered/read fire ahead of sent in receipt channels, so all three
|
|
54
71
|
// must show the label — never Stream's default delivered icon / read
|
|
55
72
|
// avatars.
|
|
73
|
+
mockedUseMessageContext.mockReturnValue({
|
|
74
|
+
message: { id: 'own-2' },
|
|
75
|
+
} as never)
|
|
76
|
+
|
|
56
77
|
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
57
78
|
|
|
58
79
|
for (const slot of TERMINAL_SLOTS) {
|
|
@@ -62,10 +83,9 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
62
83
|
}
|
|
63
84
|
})
|
|
64
85
|
|
|
65
|
-
it('renders nothing
|
|
86
|
+
it('renders nothing for an earlier own message even though one is the last own message', () => {
|
|
66
87
|
mockedUseMessageContext.mockReturnValue({
|
|
67
|
-
|
|
68
|
-
message: { id: 'message-1' },
|
|
88
|
+
message: { id: 'own-1' },
|
|
69
89
|
} as never)
|
|
70
90
|
|
|
71
91
|
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
@@ -76,6 +96,10 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
76
96
|
})
|
|
77
97
|
|
|
78
98
|
it('always suppresses the sending spinner', () => {
|
|
99
|
+
mockedUseMessageContext.mockReturnValue({
|
|
100
|
+
message: { id: 'own-2' },
|
|
101
|
+
} as never)
|
|
102
|
+
|
|
79
103
|
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
80
104
|
|
|
81
105
|
expect(screen.getByTestId('sending-slot')).toBeEmptyDOMElement()
|
|
@@ -1,28 +1,54 @@
|
|
|
1
1
|
import { ChecksIcon } from '@phosphor-icons/react'
|
|
2
|
-
import {
|
|
2
|
+
import { useMemo } from 'react'
|
|
3
|
+
import {
|
|
4
|
+
MessageStatus,
|
|
5
|
+
useChannelStateContext,
|
|
6
|
+
useChatContext,
|
|
7
|
+
useMessageContext,
|
|
8
|
+
} from 'stream-chat-react'
|
|
3
9
|
|
|
4
10
|
/**
|
|
5
11
|
* "✓✓ Delivered" label, wired into *every* terminal `MessageStatus` state
|
|
6
12
|
* (sent / delivered / read).
|
|
7
13
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* re-apply the "last own
|
|
15
|
-
*
|
|
14
|
+
* Two reasons this is more than a static label:
|
|
15
|
+
*
|
|
16
|
+
* 1. `MessageStatus` picks its `delivered`/`read` branches ahead of `sent`
|
|
17
|
+
* whenever Stream has `deliveredTo`/`readBy`, and — unlike `sent` — those
|
|
18
|
+
* branches aren't gated to the last own message. So we override all three
|
|
19
|
+
* terminal slots with this same label (never Stream's default delivered
|
|
20
|
+
* icon / read avatars — Read is out of scope) and re-apply the "last own
|
|
21
|
+
* message" gate ourselves.
|
|
22
|
+
*
|
|
23
|
+
* 2. We derive "last own message" from **live channel state**, not the
|
|
24
|
+
* message context's `lastOwnMessage`. Stream's `Message` is memoised by
|
|
25
|
+
* `areMessagePropsEqual`, which does not compare `lastOwnMessage`; a
|
|
26
|
+
* previous own row whose message/grouping props are unchanged (e.g. after
|
|
27
|
+
* an intervening incoming message) never re-renders, so its context
|
|
28
|
+
* `lastOwnMessage` goes stale and the old bubble would keep showing
|
|
29
|
+
* "Delivered" beside the new one. `useChannelStateContext` gets a fresh
|
|
30
|
+
* `messages` array on every new message and, being a context, re-renders
|
|
31
|
+
* this leaf straight through the stale `Message`/`MessageStatus` memos —
|
|
32
|
+
* so the label reliably hops to the newest own message.
|
|
16
33
|
*
|
|
17
34
|
* Rendered inside stream's `.str-chat__message-status` span, which supplies
|
|
18
35
|
* the flex layout; icon and copy are styled via that span in `styles.css`.
|
|
19
36
|
*/
|
|
20
37
|
const DeliveredStatus = () => {
|
|
21
|
-
const {
|
|
22
|
-
|
|
23
|
-
)
|
|
38
|
+
const { message } = useMessageContext('SentMessageDeliveryStatus')
|
|
39
|
+
const { messages } = useChannelStateContext('SentMessageDeliveryStatus')
|
|
40
|
+
const { client } = useChatContext('SentMessageDeliveryStatus')
|
|
24
41
|
|
|
25
|
-
|
|
42
|
+
const ownUserId = client.user?.id
|
|
43
|
+
const lastOwnMessageId = useMemo(() => {
|
|
44
|
+
if (!ownUserId || !messages) return undefined
|
|
45
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
46
|
+
if (messages[i].user?.id === ownUserId) return messages[i].id
|
|
47
|
+
}
|
|
48
|
+
return undefined
|
|
49
|
+
}, [messages, ownUserId])
|
|
50
|
+
|
|
51
|
+
if (message.id !== lastOwnMessageId) {
|
|
26
52
|
return null
|
|
27
53
|
}
|
|
28
54
|
|
|
@@ -42,20 +68,13 @@ const NoStatus = () => null
|
|
|
42
68
|
* a right-aligned "✓✓ Delivered" that appears once Stream confirms the
|
|
43
69
|
* message is stored and updates live.
|
|
44
70
|
*
|
|
45
|
-
* Built on stream-chat-react's `MessageStatus`, which owns the gating we
|
|
46
|
-
* — own message, not an error,
|
|
47
|
-
* sending/sent/delivered/read state
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* per-recipient receipts) also render the same "Delivered" label via
|
|
53
|
-
* {@link DeliveredStatus} so we never surface a read receipt. The sending
|
|
54
|
-
* spinner is suppressed.
|
|
55
|
-
*
|
|
56
|
-
* `DeliveredStatus` reads `lastOwnMessage` from the message context, so
|
|
57
|
-
* `CustomMessage`'s memo comparator must re-render when it changes (see
|
|
58
|
-
* `index.tsx`) for the label to hop to a newer message.
|
|
71
|
+
* Built on stream-chat-react's `MessageStatus`, which owns the gating we keep
|
|
72
|
+
* — own message, not an error, not inside a thread — and only surfaces a
|
|
73
|
+
* terminal (sending/sent/delivered/read) state once the message is stored.
|
|
74
|
+
* Scope is "Delivered" only: the sending spinner is suppressed and all
|
|
75
|
+
* terminal states render {@link DeliveredStatus}, which supplies the label
|
|
76
|
+
* and the last-own-message gate (see there for why the gate is computed from
|
|
77
|
+
* live channel state rather than the context's `lastOwnMessage`).
|
|
59
78
|
*/
|
|
60
79
|
export const SentMessageDeliveryStatus = () => (
|
|
61
80
|
<MessageStatus
|
|
@@ -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
|