@linktr.ee/messaging-react 3.1.0-rc-1780514752 → 3.1.0
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-DZVa2CeI.js → Card-BGOWR4lW.js} +2 -2
- package/dist/{Card-DZVa2CeI.js.map → Card-BGOWR4lW.js.map} +1 -1
- package/dist/{Card-0TLA8XHU.js → Card-BfvsO78k.js} +3 -3
- package/dist/{Card-0TLA8XHU.js.map → Card-BfvsO78k.js.map} +1 -1
- package/dist/{Card-BaaerKBC.js → Card-BhO5jeP9.js} +2 -2
- package/dist/{Card-BaaerKBC.js.map → Card-BhO5jeP9.js.map} +1 -1
- package/dist/{Card-Bfxdewx_.cjs → Card-CRJ4l5KM.cjs} +2 -2
- package/dist/{Card-Bfxdewx_.cjs.map → Card-CRJ4l5KM.cjs.map} +1 -1
- package/dist/{Card-DbdWDBMe.cjs → Card-Cq-cN9n1.cjs} +2 -2
- package/dist/{Card-DbdWDBMe.cjs.map → Card-Cq-cN9n1.cjs.map} +1 -1
- package/dist/{Card-B-D_LbnV.cjs → Card-NPXVehHb.cjs} +2 -2
- package/dist/{Card-B-D_LbnV.cjs.map → Card-NPXVehHb.cjs.map} +1 -1
- package/dist/{LockedThumbnail-DkwFwgpU.cjs → LockedThumbnail-B8MKBVXz.cjs} +2 -2
- package/dist/{LockedThumbnail-DkwFwgpU.cjs.map → LockedThumbnail-B8MKBVXz.cjs.map} +1 -1
- package/dist/{LockedThumbnail-B4gDHeh7.js → LockedThumbnail-Bu9jNPUi.js} +2 -2
- package/dist/{LockedThumbnail-B4gDHeh7.js.map → LockedThumbnail-Bu9jNPUi.js.map} +1 -1
- package/dist/{index-BmCc1-F3.js → index-CJEl_fID.js} +503 -506
- package/dist/index-CJEl_fID.js.map +1 -0
- package/dist/index-D-5Igybf.cjs +2 -0
- package/dist/index-D-5Igybf.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/ChannelView.stories.tsx +5 -6
- package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +21 -23
- package/src/components/CustomMessageInput/index.tsx +42 -24
- package/src/types.ts +9 -6
- package/dist/index-BmCc1-F3.js.map +0 -1
- package/dist/index-Cg-bxSZn.cjs +0 -2
- package/dist/index-Cg-bxSZn.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-D-5Igybf.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.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.ts
CHANGED
|
@@ -200,15 +200,18 @@ export declare interface ChannelViewProps {
|
|
|
200
200
|
*/
|
|
201
201
|
showFollowerStatus?: boolean;
|
|
202
202
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
203
|
+
* Replace the message composer with a non-interactive locked panel showing
|
|
204
|
+
* `composerDisabledReason`. Defaults to false. Used by the Linktree official
|
|
205
|
+
* channel, where the linker cannot message Linktree from the inbox (they
|
|
206
|
+
* message Linktree from its public profile instead).
|
|
207
|
+
*
|
|
208
|
+
* Distinct from the channel's `frozen` flag, which keeps the composer
|
|
209
|
+
* rendered but read-only/dimmed.
|
|
207
210
|
*/
|
|
208
211
|
composerDisabled?: boolean;
|
|
209
212
|
/**
|
|
210
|
-
* Explanatory text
|
|
211
|
-
*
|
|
213
|
+
* Explanatory text shown inside the locked panel. Only rendered when
|
|
214
|
+
* `composerDisabled` is true.
|
|
212
215
|
*/
|
|
213
216
|
composerDisabledReason?: string;
|
|
214
217
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, b as t, C as i, c as n, d as o, e as m, F as g, f as l, L as r, h as M, M as u, i as L, j as c, k as h, l as d, m as p, n as v, o as A, p as C, q as F, s as k, t as b, u as f, v as x, w as y, x as P, y as S, z as q, B as z, D as B } from "./index-
|
|
1
|
+
import { a as e, b as t, C as i, c as n, d as o, e as m, F as g, f as l, L as r, h as M, M as u, i as L, j as c, k as h, l as d, m as p, n as v, o as A, p as C, q as F, s as k, t as b, u as f, v as x, w as y, x as P, y as S, z as q, B as z, D as B } from "./index-CJEl_fID.js";
|
|
2
2
|
export {
|
|
3
3
|
e as ActionButton,
|
|
4
4
|
t as Avatar,
|
package/package.json
CHANGED
|
@@ -225,7 +225,7 @@ const Template: StoryFn<TemplateProps> = (args) => {
|
|
|
225
225
|
|
|
226
226
|
return (
|
|
227
227
|
<Chat client={client}>
|
|
228
|
-
<div className="h-screen w-full bg-
|
|
228
|
+
<div className="h-screen w-full bg-[#FBFAF9]">
|
|
229
229
|
<ChannelView {...channelViewProps} channel={channel} />
|
|
230
230
|
</div>
|
|
231
231
|
</Chat>
|
|
@@ -279,8 +279,7 @@ RestrictedOfficialChannel.args = {
|
|
|
279
279
|
showReportParticipant: false,
|
|
280
280
|
showFollowerStatus: false,
|
|
281
281
|
composerDisabled: true,
|
|
282
|
-
composerDisabledReason:
|
|
283
|
-
'Message Linktree from your profile to start the conversation',
|
|
282
|
+
composerDisabledReason: 'Only Linktree can send messages on this thread',
|
|
284
283
|
followerStatus: true, // would normally render "Subscribed to you" — suppressed here
|
|
285
284
|
onLeaveConversation: (channel) =>
|
|
286
285
|
console.log('Leave conversation:', channel.id),
|
|
@@ -289,7 +288,7 @@ RestrictedOfficialChannel.parameters = {
|
|
|
289
288
|
docs: {
|
|
290
289
|
description: {
|
|
291
290
|
story:
|
|
292
|
-
'Restricted action surface used by the Linktree official channel: block, report, and the subscription-status label are hidden, and the composer is locked
|
|
291
|
+
'Restricted action surface used by the Linktree official channel: block, report, and the subscription-status label are hidden, and the composer is replaced by a locked panel explaining the linker cannot send messages on this thread. Delete conversation, favorite, and chat info remain available. Open the chat info dialog (3-dot / name click) to see block & report removed.',
|
|
293
292
|
},
|
|
294
293
|
},
|
|
295
294
|
}
|
|
@@ -463,7 +462,7 @@ const WithStarButtonTemplate: StoryFn<ComponentProps> = (args) => {
|
|
|
463
462
|
|
|
464
463
|
return (
|
|
465
464
|
<Chat client={client}>
|
|
466
|
-
<div className="h-screen w-full bg-
|
|
465
|
+
<div className="h-screen w-full bg-[#FBFAF9]">
|
|
467
466
|
<ChannelView {...args} channel={channel} />
|
|
468
467
|
</div>
|
|
469
468
|
</Chat>
|
|
@@ -520,7 +519,7 @@ const EmptyTemplate: StoryFn<ComponentProps> = (args) => {
|
|
|
520
519
|
|
|
521
520
|
return (
|
|
522
521
|
<Chat client={client}>
|
|
523
|
-
<div className="h-screen w-full bg-
|
|
522
|
+
<div className="h-screen w-full bg-[#FBFAF9]">
|
|
524
523
|
<ChannelView {...args} channel={channel} />
|
|
525
524
|
</div>
|
|
526
525
|
</Chat>
|
|
@@ -178,45 +178,43 @@ describe('CustomMessageInput', () => {
|
|
|
178
178
|
expect(sendButton).toBeDisabled()
|
|
179
179
|
})
|
|
180
180
|
|
|
181
|
-
it('
|
|
181
|
+
it('replaces the composer with the locked panel when disabled (channel not frozen)', () => {
|
|
182
182
|
mockChannelData = {}
|
|
183
183
|
|
|
184
|
-
const { container } = renderWithProviders(
|
|
185
|
-
|
|
186
|
-
const messageInput = container.querySelector('.message-input')
|
|
187
|
-
expect(messageInput).toHaveAttribute('aria-disabled', 'true')
|
|
188
|
-
expect(messageInput).toHaveAttribute('inert')
|
|
189
|
-
|
|
190
|
-
const textarea = screen.getByTestId('textarea-composer')
|
|
191
|
-
expect(textarea).toHaveAttribute('readonly')
|
|
192
|
-
expect(textarea).toHaveAttribute('tabindex', '-1')
|
|
193
|
-
|
|
194
|
-
const sendButton = screen.getByRole('button', { name: /send/i })
|
|
195
|
-
expect(sendButton).toBeDisabled()
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
it('renders the disabled reason when the composer is disabled with a reason', () => {
|
|
199
|
-
mockChannelData = {}
|
|
200
|
-
|
|
201
|
-
renderWithProviders(
|
|
184
|
+
const { container } = renderWithProviders(
|
|
202
185
|
<CustomMessageInput
|
|
203
186
|
disabled
|
|
204
|
-
disabledReason="
|
|
187
|
+
disabledReason="Only Linktree can send messages on this thread"
|
|
205
188
|
/>
|
|
206
189
|
)
|
|
207
190
|
|
|
191
|
+
// The interactive input is gone entirely — no textarea, no send button.
|
|
192
|
+
expect(
|
|
193
|
+
screen.queryByTestId('stream-message-input')
|
|
194
|
+
).not.toBeInTheDocument()
|
|
195
|
+
expect(screen.queryByTestId('textarea-composer')).not.toBeInTheDocument()
|
|
196
|
+
expect(container.querySelector('.message-input')).not.toBeInTheDocument()
|
|
197
|
+
|
|
198
|
+
// The locked panel with the reason replaces it.
|
|
208
199
|
expect(
|
|
209
|
-
|
|
200
|
+
container.querySelector('.messaging-composer-locked-panel')
|
|
201
|
+
).toBeInTheDocument()
|
|
202
|
+
expect(
|
|
203
|
+
screen.getByText(/Only Linktree can send messages on this thread/i)
|
|
210
204
|
).toBeInTheDocument()
|
|
211
205
|
})
|
|
212
206
|
|
|
213
|
-
it('does not render the
|
|
207
|
+
it('does not render the locked panel when the composer is not disabled', () => {
|
|
214
208
|
mockChannelData = {}
|
|
215
209
|
|
|
216
|
-
renderWithProviders(
|
|
210
|
+
const { container } = renderWithProviders(
|
|
217
211
|
<CustomMessageInput disabledReason="should not show" />
|
|
218
212
|
)
|
|
219
213
|
|
|
214
|
+
expect(
|
|
215
|
+
container.querySelector('.messaging-composer-locked-panel')
|
|
216
|
+
).not.toBeInTheDocument()
|
|
220
217
|
expect(screen.queryByText(/should not show/i)).not.toBeInTheDocument()
|
|
218
|
+
expect(screen.getByTestId('stream-message-input')).toBeInTheDocument()
|
|
221
219
|
})
|
|
222
220
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArrowUpIcon } from '@phosphor-icons/react'
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useContext } from 'react'
|
|
3
3
|
import {
|
|
4
4
|
AttachmentPreviewList as DefaultAttachmentPreviewList,
|
|
5
5
|
MessageInput,
|
|
@@ -13,6 +13,16 @@ import {
|
|
|
13
13
|
|
|
14
14
|
import { CustomLinkPreviewList } from '../CustomLinkPreviewList'
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Carries the channel's `frozen` state down to CustomMessageInputInner, which
|
|
18
|
+
* renders the composer as a read-only/disabled input. Using a context — rather
|
|
19
|
+
* than closing the value into the `Input` component passed to Stream's
|
|
20
|
+
* <MessageInput> — keeps CustomMessageInputInner a stable reference, so the
|
|
21
|
+
* value toggling re-renders the composer instead of unmounting and remounting
|
|
22
|
+
* it (which would drop textarea focus and interrupt IME composition).
|
|
23
|
+
*/
|
|
24
|
+
const ComposerLockedContext = React.createContext(false)
|
|
25
|
+
|
|
16
26
|
const DefaultSendButton: React.FC<{
|
|
17
27
|
sendMessage: () => void
|
|
18
28
|
disabled?: boolean
|
|
@@ -29,9 +39,8 @@ const DefaultSendButton: React.FC<{
|
|
|
29
39
|
</button>
|
|
30
40
|
)
|
|
31
41
|
|
|
32
|
-
const CustomMessageInputInner: React.FC
|
|
33
|
-
disabled =
|
|
34
|
-
}) => {
|
|
42
|
+
const CustomMessageInputInner: React.FC = () => {
|
|
43
|
+
const disabled = useContext(ComposerLockedContext)
|
|
35
44
|
const { handleSubmit } = useMessageInputContext()
|
|
36
45
|
|
|
37
46
|
const hasSendableData = useMessageComposerHasSendableData()
|
|
@@ -79,16 +88,17 @@ export interface CustomMessageInputProps {
|
|
|
79
88
|
renderActions?: () => React.ReactNode
|
|
80
89
|
renderFooter?: () => React.ReactNode
|
|
81
90
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
91
|
+
* Replace the composer entirely with a non-interactive locked panel that
|
|
92
|
+
* shows `disabledReason`. Used by the Linktree official channel, where the
|
|
93
|
+
* linker cannot message Linktree from the inbox. Defaults to false.
|
|
94
|
+
*
|
|
95
|
+
* Distinct from the channel's `frozen` flag, which keeps the composer
|
|
96
|
+
* rendered but read-only/dimmed.
|
|
87
97
|
*/
|
|
88
98
|
disabled?: boolean
|
|
89
99
|
/**
|
|
90
|
-
* Explanatory text
|
|
91
|
-
*
|
|
100
|
+
* Explanatory text shown inside the locked panel. Only rendered when
|
|
101
|
+
* `disabled` is true.
|
|
92
102
|
*/
|
|
93
103
|
disabledReason?: string
|
|
94
104
|
}
|
|
@@ -101,19 +111,30 @@ export const CustomMessageInput: React.FC<CustomMessageInputProps> = ({
|
|
|
101
111
|
}) => {
|
|
102
112
|
const { channel } = useChannelStateContext()
|
|
103
113
|
const isFrozen = channel?.data?.frozen === true
|
|
104
|
-
const isLocked = isFrozen || disabled
|
|
105
114
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
115
|
+
// Linktree official channel: the composer is replaced by an info panel
|
|
116
|
+
// explaining the linker cannot send messages on this thread.
|
|
117
|
+
if (disabled) {
|
|
118
|
+
return (
|
|
119
|
+
<>
|
|
120
|
+
<div className="messaging-composer-locked-panel flex w-full flex-col items-center justify-center gap-3 px-6 py-4">
|
|
121
|
+
{disabledReason ? (
|
|
122
|
+
<p className="max-w-[345px] text-center text-xs font-normal leading-[1.3] tracking-[0.12px] text-black/40">
|
|
123
|
+
{disabledReason}
|
|
124
|
+
</p>
|
|
125
|
+
) : null}
|
|
126
|
+
</div>
|
|
127
|
+
{renderFooter?.()}
|
|
128
|
+
</>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
110
131
|
|
|
111
132
|
return (
|
|
112
133
|
<div className="flex flex-col gap-4 p-4">
|
|
113
134
|
<div
|
|
114
135
|
// @ts-expect-error Only React 19 onwards has `inert` in its types.
|
|
115
|
-
inert={
|
|
116
|
-
aria-disabled={
|
|
136
|
+
inert={isFrozen ? '' : undefined}
|
|
137
|
+
aria-disabled={isFrozen || undefined}
|
|
117
138
|
className="message-input flex items-end gap-4 aria-disabled:opacity-40"
|
|
118
139
|
>
|
|
119
140
|
{renderActions && (
|
|
@@ -121,13 +142,10 @@ export const CustomMessageInput: React.FC<CustomMessageInputProps> = ({
|
|
|
121
142
|
{renderActions()}
|
|
122
143
|
</div>
|
|
123
144
|
)}
|
|
124
|
-
<
|
|
145
|
+
<ComposerLockedContext.Provider value={isFrozen}>
|
|
146
|
+
<MessageInput Input={CustomMessageInputInner} />
|
|
147
|
+
</ComposerLockedContext.Provider>
|
|
125
148
|
</div>
|
|
126
|
-
{isLocked && disabledReason ? (
|
|
127
|
-
<p className="message-input-disabled-reason px-2 text-center text-sm text-black/55">
|
|
128
|
-
{disabledReason}
|
|
129
|
-
</p>
|
|
130
|
-
) : null}
|
|
131
149
|
{renderFooter?.()}
|
|
132
150
|
</div>
|
|
133
151
|
)
|
package/src/types.ts
CHANGED
|
@@ -153,16 +153,19 @@ export interface ChannelViewProps {
|
|
|
153
153
|
showFollowerStatus?: boolean
|
|
154
154
|
|
|
155
155
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
156
|
+
* Replace the message composer with a non-interactive locked panel showing
|
|
157
|
+
* `composerDisabledReason`. Defaults to false. Used by the Linktree official
|
|
158
|
+
* channel, where the linker cannot message Linktree from the inbox (they
|
|
159
|
+
* message Linktree from its public profile instead).
|
|
160
|
+
*
|
|
161
|
+
* Distinct from the channel's `frozen` flag, which keeps the composer
|
|
162
|
+
* rendered but read-only/dimmed.
|
|
160
163
|
*/
|
|
161
164
|
composerDisabled?: boolean
|
|
162
165
|
|
|
163
166
|
/**
|
|
164
|
-
* Explanatory text
|
|
165
|
-
*
|
|
167
|
+
* Explanatory text shown inside the locked panel. Only rendered when
|
|
168
|
+
* `composerDisabled` is true.
|
|
166
169
|
*/
|
|
167
170
|
composerDisabledReason?: string
|
|
168
171
|
|