@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/dist/index.d.ts +11 -0
- package/dist/index.js +723 -674
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/components/MessagingShell/EmptyState.stories.tsx +4 -0
- package/src/components/MessagingShell/EmptyState.tsx +38 -4
- package/src/components/MessagingShell/index.tsx +21 -3
- package/src/providers/MessagingProvider.tsx +16 -1
- package/src/types.ts +10 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linktr.ee/messaging-react",
|
|
3
|
-
"version": "1.
|
|
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.
|
|
38
|
-
"@phosphor-icons/react": "^2.1.
|
|
39
|
-
"stream-chat-react": "^13.
|
|
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.
|
|
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.
|
|
77
|
-
"stream-chat-react": "^13.
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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,
|
|
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 {
|
|
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
|
|
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 {
|
|
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
|
}
|