@linktr.ee/messaging-react 3.0.0 → 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.
Files changed (35) hide show
  1. package/dist/{Card-C-ZIQW_q.js → Card-BGOWR4lW.js} +2 -2
  2. package/dist/{Card-C-ZIQW_q.js.map → Card-BGOWR4lW.js.map} +1 -1
  3. package/dist/{Card-Cqld0-Ws.js → Card-BfvsO78k.js} +3 -3
  4. package/dist/{Card-Cqld0-Ws.js.map → Card-BfvsO78k.js.map} +1 -1
  5. package/dist/{Card-C46z9zz4.js → Card-BhO5jeP9.js} +2 -2
  6. package/dist/{Card-C46z9zz4.js.map → Card-BhO5jeP9.js.map} +1 -1
  7. package/dist/{Card-Cq0x0bbb.cjs → Card-CRJ4l5KM.cjs} +2 -2
  8. package/dist/{Card-Cq0x0bbb.cjs.map → Card-CRJ4l5KM.cjs.map} +1 -1
  9. package/dist/{Card-Drz28Q-Y.cjs → Card-Cq-cN9n1.cjs} +2 -2
  10. package/dist/{Card-Drz28Q-Y.cjs.map → Card-Cq-cN9n1.cjs.map} +1 -1
  11. package/dist/{Card-B7ePjYQ6.cjs → Card-NPXVehHb.cjs} +2 -2
  12. package/dist/{Card-B7ePjYQ6.cjs.map → Card-NPXVehHb.cjs.map} +1 -1
  13. package/dist/{LockedThumbnail--h4GTH41.cjs → LockedThumbnail-B8MKBVXz.cjs} +2 -2
  14. package/dist/{LockedThumbnail--h4GTH41.cjs.map → LockedThumbnail-B8MKBVXz.cjs.map} +1 -1
  15. package/dist/{LockedThumbnail-D5NHhET2.js → LockedThumbnail-Bu9jNPUi.js} +2 -2
  16. package/dist/{LockedThumbnail-D5NHhET2.js.map → LockedThumbnail-Bu9jNPUi.js.map} +1 -1
  17. package/dist/{index-BUT2yBvJ.js → index-CJEl_fID.js} +1417 -1391
  18. package/dist/index-CJEl_fID.js.map +1 -0
  19. package/dist/index-D-5Igybf.cjs +2 -0
  20. package/dist/index-D-5Igybf.cjs.map +1 -0
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.d.ts +33 -0
  23. package/dist/index.js +1 -1
  24. package/package.json +1 -1
  25. package/src/components/ChannelInfoDialog/ChannelInfoDialog.test.tsx +43 -1
  26. package/src/components/ChannelInfoDialog/index.tsx +55 -37
  27. package/src/components/ChannelView.stories.tsx +27 -3
  28. package/src/components/ChannelView.test.tsx +84 -5
  29. package/src/components/ChannelView.tsx +30 -2
  30. package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +40 -0
  31. package/src/components/CustomMessageInput/index.tsx +53 -9
  32. package/src/types.ts +38 -0
  33. package/dist/index-BUT2yBvJ.js.map +0 -1
  34. package/dist/index-DqNobxVj.cjs +0 -2
  35. package/dist/index-DqNobxVj.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { ArrowUpIcon } from '@phosphor-icons/react'
2
- import React from '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
@@ -30,12 +40,11 @@ const DefaultSendButton: React.FC<{
30
40
  )
31
41
 
32
42
  const CustomMessageInputInner: React.FC = () => {
33
- const { channel } = useChannelStateContext()
43
+ const disabled = useContext(ComposerLockedContext)
34
44
  const { handleSubmit } = useMessageInputContext()
35
45
 
36
46
  const hasSendableData = useMessageComposerHasSendableData()
37
- const isFrozen = channel?.data?.frozen === true
38
- const isSendDisabled = isFrozen || !hasSendableData
47
+ const isSendDisabled = disabled || !hasSendableData
39
48
 
40
49
  const {
41
50
  SendButton = DefaultSendButton,
@@ -50,16 +59,16 @@ const CustomMessageInputInner: React.FC = () => {
50
59
  <div className="flex">
51
60
  <div className="w-full ml-2 mr-4 self-center leading-[0]">
52
61
  <TextareaComposer
53
- aria-disabled={isFrozen || undefined}
62
+ aria-disabled={disabled || undefined}
54
63
  className="w-full resize-none outline-none leading-6"
55
64
  // While this might usually be considered an anti-pattern, in most
56
65
  // cases, when a message thread is rendered, we want the input to
57
66
  // gain focus automatically.
58
67
  // eslint-disable-next-line jsx-a11y/no-autofocus
59
- autoFocus={!isFrozen}
68
+ autoFocus={!disabled}
60
69
  maxRows={4}
61
- readOnly={isFrozen}
62
- tabIndex={isFrozen ? -1 : undefined}
70
+ readOnly={disabled}
71
+ tabIndex={disabled ? -1 : undefined}
63
72
  />
64
73
  </div>
65
74
  <SendButton
@@ -78,15 +87,48 @@ const CustomMessageInputInner: React.FC = () => {
78
87
  export interface CustomMessageInputProps {
79
88
  renderActions?: () => React.ReactNode
80
89
  renderFooter?: () => React.ReactNode
90
+ /**
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.
97
+ */
98
+ disabled?: boolean
99
+ /**
100
+ * Explanatory text shown inside the locked panel. Only rendered when
101
+ * `disabled` is true.
102
+ */
103
+ disabledReason?: string
81
104
  }
82
105
 
83
106
  export const CustomMessageInput: React.FC<CustomMessageInputProps> = ({
84
107
  renderActions,
85
108
  renderFooter,
109
+ disabled = false,
110
+ disabledReason,
86
111
  }) => {
87
112
  const { channel } = useChannelStateContext()
88
113
  const isFrozen = channel?.data?.frozen === true
89
114
 
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
+ }
131
+
90
132
  return (
91
133
  <div className="flex flex-col gap-4 p-4">
92
134
  <div
@@ -100,7 +142,9 @@ export const CustomMessageInput: React.FC<CustomMessageInputProps> = ({
100
142
  {renderActions()}
101
143
  </div>
102
144
  )}
103
- <MessageInput Input={CustomMessageInputInner} />
145
+ <ComposerLockedContext.Provider value={isFrozen}>
146
+ <MessageInput Input={CustomMessageInputInner} />
147
+ </ComposerLockedContext.Provider>
104
148
  </div>
105
149
  {renderFooter?.()}
106
150
  </div>
package/src/types.ts CHANGED
@@ -131,6 +131,44 @@ export interface ChannelViewProps {
131
131
  */
132
132
  onReportParticipantClick?: () => void
133
133
 
134
+ /**
135
+ * Show the "Block"/"Unblock" action in the channel info dialog.
136
+ * Defaults to true. Set false for restricted surfaces such as the
137
+ * Linktree official channel, where blocking is not offered.
138
+ */
139
+ showBlockParticipant?: boolean
140
+
141
+ /**
142
+ * Show the "Report" action in the channel info dialog.
143
+ * Defaults to true. Set false for restricted surfaces such as the
144
+ * Linktree official channel, where reporting is not offered.
145
+ */
146
+ showReportParticipant?: boolean
147
+
148
+ /**
149
+ * Show the subscription/follower-status label in the channel info dialog
150
+ * profile card. Defaults to true. Set false for restricted surfaces such
151
+ * as the Linktree official channel, where subscription status is hidden.
152
+ */
153
+ showFollowerStatus?: boolean
154
+
155
+ /**
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.
163
+ */
164
+ composerDisabled?: boolean
165
+
166
+ /**
167
+ * Explanatory text shown inside the locked panel. Only rendered when
168
+ * `composerDisabled` is true.
169
+ */
170
+ composerDisabledReason?: string
171
+
134
172
  /**
135
173
  * When true and DM agent is active on the channel (not paused),
136
174
  * messages will be sent with skip_push and silent flags to suppress