@linktr.ee/messaging-react 1.9.2 → 1.10.0-rc-1764218520

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "1.9.2",
3
+ "version": "1.10.0-rc-1764218520",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -34,9 +34,9 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@linktr.ee/component-library": "*",
37
- "@linktr.ee/messaging-core": "^1.2.0",
38
- "@phosphor-icons/react": "^2.1.9",
39
- "stream-chat-react": "^13.9.0"
37
+ "@linktr.ee/messaging-core": "^1.5.0",
38
+ "@phosphor-icons/react": "^2.1.10",
39
+ "stream-chat-react": "^13.12.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@storybook/addon-essentials": "^8.5.0",
@@ -61,7 +61,7 @@
61
61
  "react": "^18.3.1",
62
62
  "react-dom": "^18.3.1",
63
63
  "storybook": "^8.5.0",
64
- "stream-chat": "^9.22.1",
64
+ "stream-chat": "^9.26.0",
65
65
  "tailwindcss": "^3.4.17",
66
66
  "tailwindcss-animate": "^1.0.7",
67
67
  "typescript": "5.9.2",
@@ -73,7 +73,7 @@
73
73
  "classnames": "^2.3.2",
74
74
  "react": "18.x",
75
75
  "react-dom": "18.x",
76
- "stream-chat": "^9.22.1",
77
- "stream-chat-react": "^13.9.0"
76
+ "stream-chat": "^9.26.0",
77
+ "stream-chat-react": "^13.12.0"
78
78
  }
79
79
  }
@@ -27,9 +27,13 @@ const Template: StoryFn<ComponentProps> = (args) => {
27
27
  export const NoChannels: StoryFn<ComponentProps> = Template.bind({})
28
28
  NoChannels.args = {
29
29
  hasChannels: false,
30
+ participantLabel: 'followers',
31
+ onStartConversation: () => console.log('Start conversation clicked'),
30
32
  }
31
33
 
32
34
  export const WithChannels: StoryFn<ComponentProps> = Template.bind({})
33
35
  WithChannels.args = {
34
36
  hasChannels: true,
37
+ participantLabel: 'participants',
38
+ onStartConversation: () => console.log('Start conversation clicked'),
35
39
  }
@@ -5,7 +5,9 @@ import React from 'react'
5
5
  */
6
6
  export const EmptyState: React.FC<{
7
7
  hasChannels: boolean
8
- }> = ({ hasChannels }) => (
8
+ onStartConversation?: () => void
9
+ participantLabel: string
10
+ }> = ({ hasChannels, onStartConversation, participantLabel }) => (
9
11
  <div className="messaging-empty-state flex items-center justify-center h-full p-8 text-balance">
10
12
  <div className="text-center max-w-sm">
11
13
  <div className="w-24 h-24 bg-primary-alt/10 rounded-full flex items-center justify-center mx-auto mb-6">
@@ -15,10 +17,42 @@ export const EmptyState: React.FC<{
15
17
  <h2 className="font-semibold text-charcoal">Welcome to Messages</h2>
16
18
 
17
19
  <p className="text-stone text-sm mb-6">
18
- {hasChannels
19
- ? 'Choose a conversation from the list.'
20
- : 'No conversations yet.'}
20
+ {hasChannels ? (
21
+ <>
22
+ Choose a conversation from the list or{' '}
23
+ {onStartConversation && (
24
+ <TextButton onClick={onStartConversation}>
25
+ start a new conversation with a {participantLabel.slice(0, -1)}.
26
+ </TextButton>
27
+ )}
28
+ </>
29
+ ) : (
30
+ onStartConversation && (
31
+ <>
32
+ <TextButton onClick={onStartConversation}>
33
+ Start a new conversation with one of your {participantLabel}
34
+ </TextButton>{' '}
35
+ to begin messaging.
36
+ </>
37
+ )
38
+ )}
21
39
  </p>
22
40
  </div>
23
41
  </div>
24
42
  )
43
+
44
+ const TextButton = ({
45
+ onClick,
46
+ children,
47
+ }: {
48
+ onClick: () => void
49
+ children: React.ReactNode
50
+ }) => (
51
+ <button
52
+ type="button"
53
+ onClick={onClick}
54
+ className="inline-flex items-center gap-1 text-sm font-medium text-primary hover:text-primary-alt focus:outline-none focus:ring-2 focus:ring-primary"
55
+ >
56
+ {children}
57
+ </button>
58
+ )
@@ -44,7 +44,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
44
44
  const [existingParticipantIds, setExistingParticipantIds] = useState<
45
45
  Set<string>
46
46
  >(new Set())
47
- const [pickerKey, _setPickerKey] = useState(0) // Key to force remount of ParticipantPicker
47
+ const [pickerKey, setPickerKey] = useState(0) // Key to force remount of ParticipantPicker
48
48
  const [directConversationMode, setDirectConversationMode] = useState(false)
49
49
  const [directConversationError, setDirectConversationError] = useState<
50
50
  string | null
@@ -52,7 +52,11 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
52
52
 
53
53
  const participantPickerRef = useRef<HTMLDialogElement>(null)
54
54
 
55
- const { participantSource, participantLabel = 'participants' } = capabilities
55
+ const {
56
+ showStartConversation = false,
57
+ participantSource,
58
+ participantLabel = 'participants',
59
+ } = capabilities
56
60
 
57
61
  // Create default filters and merge with provided filters
58
62
  const channelFilters = React.useMemo(() => {
@@ -272,6 +276,14 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
272
276
  setSelectedChannel(null)
273
277
  }, [directConversationMode])
274
278
 
279
+ const handleStartConversation = useCallback(() => {
280
+ if (participantSource) {
281
+ setPickerKey((prev) => prev + 1) // Increment key to force remount
282
+ setShowParticipantPicker(true)
283
+ participantPickerRef.current?.showModal()
284
+ }
285
+ }, [participantSource])
286
+
275
287
  const handleSelectParticipant = useCallback(
276
288
  async (participant: Participant) => {
277
289
  if (!service) return
@@ -448,7 +460,13 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
448
460
  />
449
461
  </div>
450
462
  ) : (
451
- <EmptyState hasChannels={hasChannels} />
463
+ <EmptyState
464
+ hasChannels={hasChannels}
465
+ onStartConversation={
466
+ showStartConversation ? handleStartConversation : undefined
467
+ }
468
+ participantLabel={participantLabel}
469
+ />
452
470
  )}
453
471
  </div>
454
472
  </div>
@@ -10,7 +10,11 @@ import React, {
10
10
  import type { StreamChat } from 'stream-chat'
11
11
  import { Chat } from 'stream-chat-react'
12
12
 
13
- import type { MessagingProviderProps, MessagingCapabilities } from '../types'
13
+ import type {
14
+ MessagingProviderProps,
15
+ MessagingCapabilities,
16
+ MessagingCustomization,
17
+ } from '../types'
14
18
 
15
19
  /**
16
20
  * Context value for messaging state and service
@@ -22,6 +26,7 @@ export interface MessagingContextValue {
22
26
  isLoading: boolean
23
27
  error: string | null
24
28
  capabilities: MessagingCapabilities
29
+ customization: MessagingCustomization
25
30
  refreshConnection: () => Promise<void>
26
31
  debug: boolean
27
32
  }
@@ -33,6 +38,7 @@ const MessagingContext = createContext<MessagingContextValue>({
33
38
  isLoading: false,
34
39
  error: null,
35
40
  capabilities: {},
41
+ customization: {},
36
42
  refreshConnection: async () => {},
37
43
  debug: false,
38
44
  })
@@ -51,6 +57,7 @@ export const MessagingProvider: React.FC<MessagingProviderProps> = ({
51
57
  serviceConfig,
52
58
  apiKey,
53
59
  capabilities = {},
60
+ customization = {},
54
61
  debug = false,
55
62
  }) => {
56
63
  // Create debug logger that respects the debug prop
@@ -68,6 +75,7 @@ export const MessagingProvider: React.FC<MessagingProviderProps> = ({
68
75
  apiKey: apiKey?.substring(0, 8) + '...',
69
76
  serviceConfig: !!serviceConfig,
70
77
  capabilities: Object.keys(capabilities),
78
+ customization: Object.keys(customization),
71
79
  })
72
80
 
73
81
  const [service, setService] = useState<StreamChatService | null>(null)
@@ -85,6 +93,7 @@ export const MessagingProvider: React.FC<MessagingProviderProps> = ({
85
93
  apiKey,
86
94
  serviceConfig,
87
95
  capabilities,
96
+ customization,
88
97
  })
89
98
  const renderCountRef = useRef(0)
90
99
  renderCountRef.current++
@@ -98,6 +107,8 @@ export const MessagingProvider: React.FC<MessagingProviderProps> = ({
98
107
  serviceConfigChanged:
99
108
  prevPropsRef.current.serviceConfig !== serviceConfig,
100
109
  capabilitiesChanged: prevPropsRef.current.capabilities !== capabilities,
110
+ customizationChanged:
111
+ prevPropsRef.current.customization !== customization,
101
112
  },
102
113
  })
103
114
 
@@ -106,6 +117,7 @@ export const MessagingProvider: React.FC<MessagingProviderProps> = ({
106
117
  apiKey,
107
118
  serviceConfig,
108
119
  capabilities,
120
+ customization,
109
121
  }
110
122
 
111
123
  // Initialize service when config changes
@@ -303,6 +315,7 @@ export const MessagingProvider: React.FC<MessagingProviderProps> = ({
303
315
  isLoading,
304
316
  hasError: !!error,
305
317
  capabilitiesKeys: Object.keys(capabilities),
318
+ customizationKeys: Object.keys(customization),
306
319
  })
307
320
 
308
321
  return {
@@ -312,6 +325,7 @@ export const MessagingProvider: React.FC<MessagingProviderProps> = ({
312
325
  isLoading,
313
326
  error,
314
327
  capabilities,
328
+ customization,
315
329
  refreshConnection,
316
330
  debug,
317
331
  }
@@ -322,6 +336,7 @@ export const MessagingProvider: React.FC<MessagingProviderProps> = ({
322
336
  isLoading,
323
337
  error,
324
338
  capabilities,
339
+ customization,
325
340
  refreshConnection,
326
341
  debug,
327
342
  debugLog,
package/src/types.ts CHANGED
@@ -44,11 +44,20 @@ export interface MessagingCapabilities {
44
44
  participantLabel?: string // e.g., "followers", "team members"
45
45
  }
46
46
 
47
+ /**
48
+ * Customization options
49
+ */
50
+ export interface MessagingCustomization {
51
+ theme?: 'light' | 'dark' | 'auto'
52
+ accentColor?: string
53
+ }
54
+
47
55
  /**
48
56
  * Main MessagingShell component props
49
57
  */
50
58
  export interface MessagingShellProps {
51
59
  capabilities?: MessagingCapabilities
60
+ customization?: MessagingCustomization
52
61
  className?: string
53
62
  renderMessageInputActions?: (channel: Channel) => React.ReactNode
54
63
  onChannelSelect?: (channel: Channel) => void
@@ -148,5 +157,6 @@ export interface MessagingProviderProps {
148
157
  serviceConfig: Omit<StreamChatServiceConfig, 'apiKey'>
149
158
  apiKey: string
150
159
  capabilities?: MessagingCapabilities
160
+ customization?: MessagingCustomization
151
161
  debug?: boolean
152
162
  }