@linktr.ee/messaging-react 2.5.2 → 2.6.0-rc-1780281100

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 (36) hide show
  1. package/dist/{Card-Bp3XzYXV.cjs → Card-BHrhU1uR.cjs} +2 -2
  2. package/dist/{Card-Bp3XzYXV.cjs.map → Card-BHrhU1uR.cjs.map} +1 -1
  3. package/dist/{Card-Obhvbcgk.cjs → Card-BdyCnBOJ.cjs} +2 -2
  4. package/dist/{Card-Obhvbcgk.cjs.map → Card-BdyCnBOJ.cjs.map} +1 -1
  5. package/dist/{Card-cl8fYGrO.js → Card-CD9KC9WP.js} +3 -3
  6. package/dist/{Card-cl8fYGrO.js.map → Card-CD9KC9WP.js.map} +1 -1
  7. package/dist/{Card-C8C9ZL55.cjs → Card-CJMJGeFI.cjs} +2 -2
  8. package/dist/{Card-C8C9ZL55.cjs.map → Card-CJMJGeFI.cjs.map} +1 -1
  9. package/dist/{Card-CBeF7eUm.js → Card-CWjGaRH2.js} +2 -2
  10. package/dist/{Card-CBeF7eUm.js.map → Card-CWjGaRH2.js.map} +1 -1
  11. package/dist/{Card-CSvw2WUm.js → Card-CbDg3PRA.js} +2 -2
  12. package/dist/{Card-CSvw2WUm.js.map → Card-CbDg3PRA.js.map} +1 -1
  13. package/dist/{LockedThumbnail-BQ5gB3Gj.js → LockedThumbnail-DzSYmmYA.js} +2 -2
  14. package/dist/{LockedThumbnail-BQ5gB3Gj.js.map → LockedThumbnail-DzSYmmYA.js.map} +1 -1
  15. package/dist/{LockedThumbnail-DR1i_N1L.cjs → LockedThumbnail-ineY4nwg.cjs} +2 -2
  16. package/dist/{LockedThumbnail-DR1i_N1L.cjs.map → LockedThumbnail-ineY4nwg.cjs.map} +1 -1
  17. package/dist/index-Be5pkdgH.cjs +2 -0
  18. package/dist/index-Be5pkdgH.cjs.map +1 -0
  19. package/dist/{index-BGwytfkX.js → index-n6fP9phm.js} +1571 -1518
  20. package/dist/index-n6fP9phm.js.map +1 -0
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.d.ts +8 -1
  23. package/dist/index.js +1 -1
  24. package/package.json +1 -1
  25. package/src/components/ChannelView.tsx +7 -0
  26. package/src/components/CustomMessage/CustomMessage.stories.tsx +43 -38
  27. package/src/components/CustomMessage/CustomMessageActions.tsx +30 -16
  28. package/src/components/CustomMessage/index.tsx +37 -28
  29. package/src/components/CustomMessageInput/CustomMessageInput.stories.tsx +126 -30
  30. package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +2 -13
  31. package/src/components/CustomMessageInput/index.tsx +51 -45
  32. package/src/components/MessagingShell/index.tsx +4 -0
  33. package/src/types.ts +10 -0
  34. package/dist/index-BGwytfkX.js.map +0 -1
  35. package/dist/index-Dgh0_9UW.cjs +0 -2
  36. package/dist/index-Dgh0_9UW.cjs.map +0 -1
@@ -1,10 +1,9 @@
1
1
  import { ArrowUpIcon } from '@phosphor-icons/react'
2
2
  import React from 'react'
3
3
  import {
4
- AttachmentPreviewList,
4
+ AttachmentPreviewList as DefaultAttachmentPreviewList,
5
5
  MessageInput,
6
6
  QuotedMessagePreview,
7
- SimpleAttachmentSelector,
8
7
  TextareaComposer,
9
8
  useChannelStateContext,
10
9
  useComponentContext,
@@ -32,71 +31,78 @@ const DefaultSendButton: React.FC<{
32
31
 
33
32
  const CustomMessageInputInner: React.FC = () => {
34
33
  const { channel } = useChannelStateContext()
35
- const isFrozen = channel?.data?.frozen === true
36
34
  const { handleSubmit } = useMessageInputContext()
37
- const { SendButton: SendButtonFromContext } =
38
- useComponentContext('CustomMessageInput')
39
- const SendButton = SendButtonFromContext ?? DefaultSendButton
35
+
40
36
  const hasSendableData = useMessageComposerHasSendableData()
37
+ const isFrozen = channel?.data?.frozen === true
41
38
  const isSendDisabled = isFrozen || !hasSendableData
42
39
 
40
+ const {
41
+ SendButton = DefaultSendButton,
42
+ AttachmentPreviewList = DefaultAttachmentPreviewList,
43
+ } = useComponentContext('CustomMessageInput')
44
+
43
45
  return (
44
- <>
45
- <div className="left-container">
46
- <SimpleAttachmentSelector />
47
- </div>
48
- <div className="central-container min-w-0 w-full p-2 bg-white rounded-[1.5rem] shadow-[0_4px_16px_0_rgba(0,0,0,0.08),0_1px_2px_0_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.04)]">
49
- <QuotedMessagePreview />
50
- <CustomLinkPreviewList />
51
- <AttachmentPreviewList />
52
- <div className="flex">
53
- <div className="w-full ml-2 mr-4 self-center leading-[0]">
54
- <TextareaComposer
55
- aria-disabled={isFrozen || undefined}
56
- className="w-full resize-none outline-none leading-6"
57
- // While this might usually be considered an anti-pattern, in most
58
- // cases, when a message thread is rendered, we want the input to
59
- // gain focus automatically.
60
- // eslint-disable-next-line jsx-a11y/no-autofocus
61
- autoFocus={!isFrozen}
62
- maxRows={4}
63
- readOnly={isFrozen}
64
- tabIndex={isFrozen ? -1 : undefined}
65
- />
66
- </div>
67
- <SendButton
68
- sendMessage={handleSubmit}
69
- aria-label="Send"
70
- className="str-chat__send-button mt-auto flex justify-center items-center flex-shrink-0 rounded-full size-8 bg-[#121110] disabled:bg-[#F1F0EE] disabled:text-black/20 text-white focus-ring"
71
- data-testid="send-button"
72
- disabled={isSendDisabled}
73
- type="button"
46
+ <div className="central-container flex flex-col gap-2 min-w-0 w-full p-2 bg-white rounded-[1.5rem] shadow-[0_4px_16px_0_rgba(0,0,0,0.08),0_1px_2px_0_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.04)]">
47
+ <QuotedMessagePreview />
48
+ <CustomLinkPreviewList />
49
+ <AttachmentPreviewList />
50
+ <div className="flex">
51
+ <div className="w-full ml-2 mr-4 self-center leading-[0]">
52
+ <TextareaComposer
53
+ aria-disabled={isFrozen || undefined}
54
+ className="w-full resize-none outline-none leading-6"
55
+ // While this might usually be considered an anti-pattern, in most
56
+ // cases, when a message thread is rendered, we want the input to
57
+ // gain focus automatically.
58
+ // eslint-disable-next-line jsx-a11y/no-autofocus
59
+ autoFocus={!isFrozen}
60
+ maxRows={4}
61
+ readOnly={isFrozen}
62
+ tabIndex={isFrozen ? -1 : undefined}
74
63
  />
75
64
  </div>
65
+ <SendButton
66
+ sendMessage={handleSubmit}
67
+ aria-label="Send"
68
+ className="str-chat__send-button mt-auto flex justify-center items-center flex-shrink-0 rounded-full size-8 bg-[#121110] disabled:bg-[#F1F0EE] disabled:text-black/20 text-white focus-ring"
69
+ data-testid="send-button"
70
+ disabled={isSendDisabled}
71
+ type="button"
72
+ />
76
73
  </div>
77
- </>
74
+ </div>
78
75
  )
79
76
  }
80
77
 
81
78
  export interface CustomMessageInputProps {
82
79
  renderActions?: () => React.ReactNode
80
+ renderFooter?: () => React.ReactNode
83
81
  }
84
82
 
85
83
  export const CustomMessageInput: React.FC<CustomMessageInputProps> = ({
86
84
  renderActions,
85
+ renderFooter,
87
86
  }) => {
88
87
  const { channel } = useChannelStateContext()
89
88
  const isFrozen = channel?.data?.frozen === true
90
89
 
91
90
  return (
92
- <div
93
- // @ts-expect-error Only React 19 onwards has `inert` in its types.
94
- inert={isFrozen ? '' : undefined}
95
- aria-disabled={isFrozen || undefined}
96
- className="message-input flex items-center gap-2 p-4 aria-disabled:opacity-40"
97
- >
98
- {renderActions?.()}
99
- <MessageInput Input={CustomMessageInputInner} />
91
+ <div className="flex flex-col gap-4">
92
+ <div
93
+ // @ts-expect-error Only React 19 onwards has `inert` in its types.
94
+ inert={isFrozen ? '' : undefined}
95
+ aria-disabled={isFrozen || undefined}
96
+ className="message-input flex items-end gap-4 aria-disabled:opacity-40"
97
+ >
98
+ {renderActions && (
99
+ <div className="flex h-12 shrink-0 items-center justify-center">
100
+ {renderActions()}
101
+ </div>
102
+ )}
103
+ <MessageInput Input={CustomMessageInputInner} />
104
+ </div>
105
+ {renderFooter?.()}
100
106
  </div>
101
107
  )
102
108
  }
@@ -18,6 +18,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
18
18
  capabilities = {},
19
19
  className,
20
20
  renderMessageInputActions,
21
+ renderMessageInputFooter,
21
22
  renderConversationFooter,
22
23
  onChannelSelect,
23
24
  initialParticipantFilter,
@@ -43,6 +44,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
43
44
  renderMessage,
44
45
  onMessageLinkClick,
45
46
  sendButton,
47
+ attachmentPreviewList,
46
48
  }) => {
47
49
  const {
48
50
  service,
@@ -404,6 +406,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
404
406
  onBack={handleBackToChannelList}
405
407
  showBackButton={!directConversationMode}
406
408
  renderMessageInputActions={renderMessageInputActions}
409
+ renderMessageInputFooter={renderMessageInputFooter}
407
410
  renderConversationFooter={renderConversationFooter}
408
411
  renderChannelBanner={renderChannelBanner}
409
412
  onLeaveConversation={handleLeaveConversation}
@@ -424,6 +427,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
424
427
  renderMessage={renderMessage}
425
428
  onMessageLinkClick={onMessageLinkClick}
426
429
  sendButton={sendButton}
430
+ attachmentPreviewList={attachmentPreviewList}
427
431
  />
428
432
  </div>
429
433
  ) : initialParticipantFilter ? (
package/src/types.ts CHANGED
@@ -123,6 +123,7 @@ export interface ChannelViewProps {
123
123
  onBack?: () => void
124
124
  showBackButton?: boolean
125
125
  renderMessageInputActions?: (channel: Channel) => React.ReactNode
126
+ renderMessageInputFooter?: (channel: Channel) => React.ReactNode
126
127
  renderConversationFooter?: (channel: Channel) => React.ReactNode
127
128
  onLeaveConversation?: (channel: Channel) => void
128
129
  onBlockParticipant?: (participantId?: string) => void
@@ -266,6 +267,13 @@ export interface ChannelViewProps {
266
267
  */
267
268
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
268
269
  sendButton?: ComponentType<any>
270
+
271
+ /**
272
+ * Custom component rendered inside the message composer bubble (above the
273
+ * textarea). Passed to Stream `Channel` as `AttachmentPreviewList`.
274
+ * Use this to render staged paid or media attachments inside the input.
275
+ */
276
+ attachmentPreviewList?: ComponentType
269
277
  }
270
278
 
271
279
  /**
@@ -275,6 +283,7 @@ export interface ChannelViewProps {
275
283
  export type ChannelViewPassthroughProps = Pick<
276
284
  ChannelViewProps,
277
285
  | 'renderMessageInputActions'
286
+ | 'renderMessageInputFooter'
278
287
  | 'renderConversationFooter'
279
288
  | 'CustomChannelEmptyState'
280
289
  | 'onDeleteConversationClick'
@@ -292,6 +301,7 @@ export type ChannelViewPassthroughProps = Pick<
292
301
  | 'renderMessage'
293
302
  | 'onMessageLinkClick'
294
303
  | 'sendButton'
304
+ | 'attachmentPreviewList'
295
305
  >
296
306
 
297
307
  /**