@linktr.ee/messaging-react 1.0.2 → 1.1.0-rc-1760927977
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/assets/index.css +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +836 -1079
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/components/ActionButton/ActionButton.stories.tsx +2 -1
- package/src/components/ActionButton/ActionButton.test.tsx +2 -0
- package/src/components/Avatar/Avatar.stories.tsx +2 -1
- package/src/components/Avatar/index.tsx +2 -1
- package/src/components/ChannelList/ChannelList.stories.tsx +4 -2
- package/src/components/ChannelList/CustomChannelPreview.stories.tsx +31 -27
- package/src/components/ChannelList/CustomChannelPreview.tsx +5 -11
- package/src/components/ChannelList/index.tsx +43 -35
- package/src/components/ChannelView.tsx +150 -127
- package/src/components/CloseButton/index.tsx +4 -5
- package/src/components/IconButton/IconButton.stories.tsx +3 -3
- package/src/components/Loading/Loading.stories.tsx +2 -1
- package/src/components/Loading/index.tsx +7 -9
- package/src/components/MessagingShell/EmptyState.stories.tsx +2 -1
- package/src/components/MessagingShell/ErrorState.stories.tsx +2 -1
- package/src/components/MessagingShell/LoadingState.stories.tsx +2 -1
- package/src/components/MessagingShell/LoadingState.tsx +3 -5
- package/src/components/MessagingShell/index.tsx +159 -135
- package/src/components/ParticipantPicker/ParticipantItem.stories.tsx +4 -2
- package/src/components/ParticipantPicker/ParticipantItem.tsx +25 -21
- package/src/components/ParticipantPicker/ParticipantPicker.stories.tsx +4 -2
- package/src/components/ParticipantPicker/ParticipantPicker.tsx +104 -76
- package/src/components/ParticipantPicker/index.tsx +93 -72
- package/src/components/SearchInput/SearchInput.stories.tsx +2 -1
- package/src/components/SearchInput/SearchInput.test.tsx +4 -2
- package/src/components/SearchInput/index.tsx +14 -15
- package/src/hooks/useParticipants.ts +1 -0
- package/src/index.ts +3 -0
- package/src/providers/MessagingProvider.tsx +213 -135
- package/src/stories/mocks.tsx +18 -19
- package/src/styles.css +75 -0
- package/src/test/setup.ts +11 -12
- package/src/test/utils.tsx +6 -7
- package/src/types.ts +1 -1
|
@@ -1,65 +1,78 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
ArrowLeftIcon,
|
|
3
|
+
DotsThreeIcon,
|
|
4
|
+
FlagIcon,
|
|
5
|
+
ProhibitInsetIcon,
|
|
6
|
+
SignOutIcon,
|
|
7
|
+
SpinnerGapIcon,
|
|
8
|
+
} from '@phosphor-icons/react'
|
|
9
|
+
import classNames from 'classnames'
|
|
10
|
+
import React, { useState, useCallback, useRef, useEffect } from 'react'
|
|
11
|
+
import { Channel as ChannelType, ChannelMemberResponse } from 'stream-chat'
|
|
11
12
|
import {
|
|
12
13
|
Channel,
|
|
13
14
|
Window,
|
|
14
15
|
MessageList,
|
|
15
16
|
MessageInput,
|
|
16
17
|
useChannelStateContext,
|
|
17
|
-
} from 'stream-chat-react'
|
|
18
|
-
|
|
19
|
-
import { useMessagingContext } from '../providers/MessagingProvider'
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
import ActionButton from './ActionButton'
|
|
23
|
-
import { Avatar } from './Avatar'
|
|
18
|
+
} from 'stream-chat-react'
|
|
19
|
+
|
|
20
|
+
import { useMessagingContext } from '../providers/MessagingProvider'
|
|
21
|
+
import type { ChannelViewProps } from '../types'
|
|
22
|
+
|
|
23
|
+
import ActionButton from './ActionButton'
|
|
24
|
+
import { Avatar } from './Avatar'
|
|
25
|
+
import { CloseButton } from './CloseButton'
|
|
26
|
+
import { IconButton } from './IconButton'
|
|
27
|
+
|
|
28
|
+
// Custom user type with email and username
|
|
29
|
+
type CustomUser = {
|
|
30
|
+
email?: string
|
|
31
|
+
username?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Blocked user from Stream Chat API
|
|
35
|
+
type BlockedUser = {
|
|
36
|
+
blocked_user_id: string
|
|
37
|
+
}
|
|
24
38
|
|
|
25
39
|
/**
|
|
26
40
|
* Custom message input component with render prop for actions
|
|
27
41
|
*/
|
|
28
42
|
const CustomMessageInput: React.FC<{
|
|
29
|
-
renderActions?: () => React.ReactNode
|
|
43
|
+
renderActions?: () => React.ReactNode
|
|
30
44
|
}> = ({ renderActions }) => (
|
|
31
45
|
<div className="message-input flex items-center gap-2 p-4">
|
|
32
46
|
{renderActions && renderActions()}
|
|
33
|
-
|
|
47
|
+
|
|
34
48
|
<div className="flex-1">
|
|
35
49
|
<MessageInput focus maxRows={4} />
|
|
36
50
|
</div>
|
|
37
51
|
</div>
|
|
38
|
-
)
|
|
52
|
+
)
|
|
39
53
|
|
|
40
54
|
/**
|
|
41
55
|
* Custom channel header component
|
|
42
56
|
*/
|
|
43
57
|
const CustomChannelHeader: React.FC<{
|
|
44
|
-
onBack?: () => void
|
|
45
|
-
showBackButton: boolean
|
|
46
|
-
onShowInfo?: () => void
|
|
47
|
-
canShowInfo: boolean
|
|
58
|
+
onBack?: () => void
|
|
59
|
+
showBackButton: boolean
|
|
60
|
+
onShowInfo?: () => void
|
|
61
|
+
canShowInfo: boolean
|
|
48
62
|
}> = ({ onBack, showBackButton, onShowInfo, canShowInfo }) => {
|
|
49
|
-
const { channel } = useChannelStateContext()
|
|
50
|
-
|
|
63
|
+
const { channel } = useChannelStateContext()
|
|
64
|
+
|
|
51
65
|
// Get participant info (excluding current user)
|
|
52
66
|
const participant = React.useMemo(() => {
|
|
53
|
-
const members = Object.values(channel.state.members || {})
|
|
54
|
-
return members.find(
|
|
55
|
-
member.user?.id && member.user.id !== channel._client.userID
|
|
56
|
-
)
|
|
57
|
-
}, [channel._client.userID, channel.state.members])
|
|
67
|
+
const members = Object.values(channel.state.members || {})
|
|
68
|
+
return members.find(
|
|
69
|
+
(member) => member.user?.id && member.user.id !== channel._client.userID
|
|
70
|
+
)
|
|
71
|
+
}, [channel._client.userID, channel.state.members])
|
|
58
72
|
|
|
59
|
-
const participantName =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const participantImage = participant?.user?.image;
|
|
73
|
+
const participantName =
|
|
74
|
+
participant?.user?.name || participant?.user?.id || 'Unknown member'
|
|
75
|
+
const participantImage = participant?.user?.image
|
|
63
76
|
|
|
64
77
|
return (
|
|
65
78
|
<div className="flex items-center justify-between gap-3 min-h-12">
|
|
@@ -74,7 +87,7 @@ const CustomChannelHeader: React.FC<{
|
|
|
74
87
|
<ArrowLeftIcon className="h-5 w-5 text-stone" weight="bold" />
|
|
75
88
|
</button>
|
|
76
89
|
)}
|
|
77
|
-
|
|
90
|
+
|
|
78
91
|
{/* Avatar */}
|
|
79
92
|
<Avatar
|
|
80
93
|
id={participant?.user?.id || channel.id || 'unknown'}
|
|
@@ -82,7 +95,7 @@ const CustomChannelHeader: React.FC<{
|
|
|
82
95
|
image={participantImage}
|
|
83
96
|
size={40}
|
|
84
97
|
/>
|
|
85
|
-
|
|
98
|
+
|
|
86
99
|
<div className="min-w-0">
|
|
87
100
|
<h1 className="text-lg font-semibold text-charcoal truncate">
|
|
88
101
|
{participantName}
|
|
@@ -91,168 +104,178 @@ const CustomChannelHeader: React.FC<{
|
|
|
91
104
|
</div>
|
|
92
105
|
|
|
93
106
|
{canShowInfo && onShowInfo && (
|
|
94
|
-
<IconButton
|
|
95
|
-
label="Chat info"
|
|
96
|
-
onClick={onShowInfo}
|
|
97
|
-
>
|
|
107
|
+
<IconButton label="Chat info" onClick={onShowInfo}>
|
|
98
108
|
<DotsThreeIcon className="h-6 w-6 text-charcoal" weight="bold" />
|
|
99
109
|
</IconButton>
|
|
100
110
|
)}
|
|
101
111
|
</div>
|
|
102
|
-
)
|
|
103
|
-
}
|
|
112
|
+
)
|
|
113
|
+
}
|
|
104
114
|
|
|
105
115
|
/**
|
|
106
116
|
* Channel info dialog (matching original implementation)
|
|
107
117
|
*/
|
|
108
118
|
const ChannelInfoDialog: React.FC<{
|
|
109
|
-
isOpen: boolean
|
|
110
|
-
onClose: () => void
|
|
111
|
-
participant:
|
|
112
|
-
channel:
|
|
113
|
-
followerStatusLabel?: string
|
|
114
|
-
onLeaveConversation?: (channel:
|
|
115
|
-
onBlockParticipant?: (participantId?: string) => void
|
|
116
|
-
}> = ({
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
isOpen: boolean
|
|
120
|
+
onClose: () => void
|
|
121
|
+
participant: ChannelMemberResponse | undefined
|
|
122
|
+
channel: ChannelType
|
|
123
|
+
followerStatusLabel?: string
|
|
124
|
+
onLeaveConversation?: (channel: ChannelType) => void
|
|
125
|
+
onBlockParticipant?: (participantId?: string) => void
|
|
126
|
+
}> = ({
|
|
127
|
+
isOpen,
|
|
128
|
+
onClose,
|
|
129
|
+
participant,
|
|
130
|
+
channel,
|
|
131
|
+
followerStatusLabel,
|
|
132
|
+
onLeaveConversation,
|
|
133
|
+
onBlockParticipant,
|
|
134
|
+
}) => {
|
|
135
|
+
const { service, debug } = useMessagingContext()
|
|
136
|
+
const dialogRef = useRef<HTMLDialogElement>(null)
|
|
137
|
+
const [isParticipantBlocked, setIsParticipantBlocked] = useState(false)
|
|
138
|
+
const [isLeaving, setIsLeaving] = useState(false)
|
|
139
|
+
const [isUpdatingBlockStatus, setIsUpdatingBlockStatus] = useState(false)
|
|
122
140
|
|
|
123
141
|
// Sync dialog open state with prop
|
|
124
142
|
useEffect(() => {
|
|
125
|
-
const dialog = dialogRef.current
|
|
126
|
-
if (!dialog) return
|
|
143
|
+
const dialog = dialogRef.current
|
|
144
|
+
if (!dialog) return
|
|
127
145
|
|
|
128
146
|
if (isOpen) {
|
|
129
|
-
dialog.showModal()
|
|
147
|
+
dialog.showModal()
|
|
130
148
|
} else {
|
|
131
|
-
dialog.close()
|
|
149
|
+
dialog.close()
|
|
132
150
|
}
|
|
133
|
-
}, [isOpen])
|
|
151
|
+
}, [isOpen])
|
|
134
152
|
|
|
135
153
|
// Check if participant is blocked
|
|
136
154
|
const checkIsParticipantBlocked = useCallback(async () => {
|
|
137
|
-
if (!service || !participant?.user?.id) return
|
|
138
|
-
|
|
155
|
+
if (!service || !participant?.user?.id) return
|
|
156
|
+
|
|
139
157
|
try {
|
|
140
|
-
const blockedUsers = await service.getBlockedUsers()
|
|
158
|
+
const blockedUsers = await service.getBlockedUsers()
|
|
141
159
|
const isBlocked = blockedUsers.some(
|
|
142
|
-
(user:
|
|
143
|
-
)
|
|
144
|
-
setIsParticipantBlocked(isBlocked)
|
|
160
|
+
(user: BlockedUser) => user.blocked_user_id === participant?.user?.id
|
|
161
|
+
)
|
|
162
|
+
setIsParticipantBlocked(isBlocked)
|
|
145
163
|
} catch (error) {
|
|
146
|
-
console.error(
|
|
164
|
+
console.error(
|
|
165
|
+
'[ChannelInfoDialog] Failed to check blocked status:',
|
|
166
|
+
error
|
|
167
|
+
)
|
|
147
168
|
}
|
|
148
|
-
}, [service, participant?.user?.id])
|
|
169
|
+
}, [service, participant?.user?.id])
|
|
149
170
|
|
|
150
171
|
useEffect(() => {
|
|
151
172
|
if (isOpen) {
|
|
152
|
-
checkIsParticipantBlocked()
|
|
173
|
+
checkIsParticipantBlocked()
|
|
153
174
|
}
|
|
154
|
-
}, [isOpen, checkIsParticipantBlocked])
|
|
175
|
+
}, [isOpen, checkIsParticipantBlocked])
|
|
155
176
|
|
|
156
177
|
const handleLeaveConversation = async () => {
|
|
157
|
-
if (isLeaving) return
|
|
178
|
+
if (isLeaving) return
|
|
158
179
|
|
|
159
180
|
if (debug) {
|
|
160
|
-
console.log('[ChannelInfoDialog] Leave conversation', channel.cid)
|
|
181
|
+
console.log('[ChannelInfoDialog] Leave conversation', channel.cid)
|
|
161
182
|
}
|
|
162
|
-
setIsLeaving(true)
|
|
183
|
+
setIsLeaving(true)
|
|
163
184
|
|
|
164
185
|
try {
|
|
165
|
-
const actingUserId = channel._client?.userID ?? null
|
|
166
|
-
await channel.hide(actingUserId, false)
|
|
186
|
+
const actingUserId = channel._client?.userID ?? null
|
|
187
|
+
await channel.hide(actingUserId, false)
|
|
167
188
|
|
|
168
189
|
if (onLeaveConversation) {
|
|
169
|
-
await onLeaveConversation(channel)
|
|
190
|
+
await onLeaveConversation(channel)
|
|
170
191
|
}
|
|
171
192
|
|
|
172
|
-
onClose()
|
|
193
|
+
onClose()
|
|
173
194
|
} catch (error) {
|
|
174
|
-
console.error('[ChannelInfoDialog] Failed to leave conversation', error)
|
|
195
|
+
console.error('[ChannelInfoDialog] Failed to leave conversation', error)
|
|
175
196
|
} finally {
|
|
176
|
-
setIsLeaving(false)
|
|
197
|
+
setIsLeaving(false)
|
|
177
198
|
}
|
|
178
|
-
}
|
|
199
|
+
}
|
|
179
200
|
|
|
180
201
|
const handleBlockUser = async () => {
|
|
181
|
-
if (isUpdatingBlockStatus || !service) return
|
|
202
|
+
if (isUpdatingBlockStatus || !service) return
|
|
182
203
|
|
|
183
204
|
if (debug) {
|
|
184
|
-
console.log('[ChannelInfoDialog] Block member', participant?.user?.id)
|
|
205
|
+
console.log('[ChannelInfoDialog] Block member', participant?.user?.id)
|
|
185
206
|
}
|
|
186
|
-
setIsUpdatingBlockStatus(true)
|
|
207
|
+
setIsUpdatingBlockStatus(true)
|
|
187
208
|
|
|
188
209
|
try {
|
|
189
|
-
await service.blockUser(participant?.user?.id)
|
|
210
|
+
await service.blockUser(participant?.user?.id)
|
|
190
211
|
|
|
191
212
|
if (onBlockParticipant) {
|
|
192
|
-
await onBlockParticipant(participant?.user?.id)
|
|
213
|
+
await onBlockParticipant(participant?.user?.id)
|
|
193
214
|
}
|
|
194
215
|
|
|
195
|
-
onClose()
|
|
216
|
+
onClose()
|
|
196
217
|
} catch (error) {
|
|
197
|
-
console.error('[ChannelInfoDialog] Failed to block member', error)
|
|
218
|
+
console.error('[ChannelInfoDialog] Failed to block member', error)
|
|
198
219
|
} finally {
|
|
199
|
-
setIsUpdatingBlockStatus(false)
|
|
220
|
+
setIsUpdatingBlockStatus(false)
|
|
200
221
|
}
|
|
201
|
-
}
|
|
222
|
+
}
|
|
202
223
|
|
|
203
224
|
const handleUnblockUser = async () => {
|
|
204
|
-
if (isUpdatingBlockStatus || !service) return
|
|
225
|
+
if (isUpdatingBlockStatus || !service) return
|
|
205
226
|
|
|
206
227
|
if (debug) {
|
|
207
|
-
console.log('[ChannelInfoDialog] Unblock member', participant?.user?.id)
|
|
228
|
+
console.log('[ChannelInfoDialog] Unblock member', participant?.user?.id)
|
|
208
229
|
}
|
|
209
|
-
setIsUpdatingBlockStatus(true)
|
|
230
|
+
setIsUpdatingBlockStatus(true)
|
|
210
231
|
|
|
211
232
|
try {
|
|
212
|
-
await service.unBlockUser(participant?.user?.id)
|
|
233
|
+
await service.unBlockUser(participant?.user?.id)
|
|
213
234
|
|
|
214
235
|
if (onBlockParticipant) {
|
|
215
|
-
await onBlockParticipant(participant?.user?.id)
|
|
236
|
+
await onBlockParticipant(participant?.user?.id)
|
|
216
237
|
}
|
|
217
238
|
|
|
218
|
-
onClose()
|
|
239
|
+
onClose()
|
|
219
240
|
} catch (error) {
|
|
220
|
-
console.error('[ChannelInfoDialog] Failed to unblock member', error)
|
|
241
|
+
console.error('[ChannelInfoDialog] Failed to unblock member', error)
|
|
221
242
|
} finally {
|
|
222
|
-
setIsUpdatingBlockStatus(false)
|
|
243
|
+
setIsUpdatingBlockStatus(false)
|
|
223
244
|
}
|
|
224
|
-
}
|
|
245
|
+
}
|
|
225
246
|
|
|
226
247
|
const handleReportUser = () => {
|
|
227
|
-
onClose()
|
|
248
|
+
onClose()
|
|
228
249
|
window.open(
|
|
229
250
|
'https://linktr.ee/s/about/trust-center/report',
|
|
230
251
|
'_blank',
|
|
231
|
-
'noopener,noreferrer'
|
|
232
|
-
)
|
|
233
|
-
}
|
|
252
|
+
'noopener,noreferrer'
|
|
253
|
+
)
|
|
254
|
+
}
|
|
234
255
|
|
|
235
|
-
if (!participant) return null
|
|
256
|
+
if (!participant) return null
|
|
236
257
|
|
|
237
|
-
const participantName =
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
const
|
|
258
|
+
const participantName =
|
|
259
|
+
participant.user?.name || participant.user?.id || 'Unknown member'
|
|
260
|
+
const participantImage = participant.user?.image
|
|
261
|
+
const participantEmail = (participant.user as CustomUser)?.email
|
|
262
|
+
const participantUsername = (participant.user as CustomUser)?.username
|
|
241
263
|
const participantSecondary = participantEmail
|
|
242
264
|
? participantEmail
|
|
243
265
|
: participantUsername
|
|
244
266
|
? `linktr.ee/${participantUsername}`
|
|
245
|
-
: undefined
|
|
246
|
-
const participantId = participant.user?.id || 'unknown'
|
|
267
|
+
: undefined
|
|
268
|
+
const participantId = participant.user?.id || 'unknown'
|
|
247
269
|
|
|
248
270
|
return (
|
|
271
|
+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
|
|
249
272
|
<dialog
|
|
250
273
|
ref={dialogRef}
|
|
251
274
|
className="mes-dialog"
|
|
252
275
|
onClose={onClose}
|
|
253
276
|
onClick={(e) => {
|
|
254
277
|
if (e.target === dialogRef.current) {
|
|
255
|
-
onClose()
|
|
278
|
+
onClose()
|
|
256
279
|
}
|
|
257
280
|
}}
|
|
258
281
|
>
|
|
@@ -261,7 +284,7 @@ const ChannelInfoDialog: React.FC<{
|
|
|
261
284
|
<h2 className="text-base font-semibold text-charcoal">Chat info</h2>
|
|
262
285
|
<CloseButton onClick={onClose} />
|
|
263
286
|
</div>
|
|
264
|
-
|
|
287
|
+
|
|
265
288
|
<div className="flex-1 overflow-y-auto px-6 py-6">
|
|
266
289
|
<div className="rounded-2xl bg-chalk p-4">
|
|
267
290
|
<div className="flex items-center gap-4">
|
|
@@ -343,8 +366,8 @@ const ChannelInfoDialog: React.FC<{
|
|
|
343
366
|
</div>
|
|
344
367
|
</div>
|
|
345
368
|
</dialog>
|
|
346
|
-
)
|
|
347
|
-
}
|
|
369
|
+
)
|
|
370
|
+
}
|
|
348
371
|
|
|
349
372
|
/**
|
|
350
373
|
* Channel view component with message list and input
|
|
@@ -358,28 +381,28 @@ export const ChannelView: React.FC<ChannelViewProps> = ({
|
|
|
358
381
|
onBlockParticipant,
|
|
359
382
|
className,
|
|
360
383
|
}) => {
|
|
361
|
-
const [showInfo, setShowInfo] = useState(false)
|
|
384
|
+
const [showInfo, setShowInfo] = useState(false)
|
|
362
385
|
|
|
363
386
|
// Get participant info for info dialog
|
|
364
387
|
const participant = React.useMemo(() => {
|
|
365
|
-
const members = Object.values(channel.state.members || {})
|
|
366
|
-
return members.find(
|
|
367
|
-
member.user?.id && member.user.id !== channel._client.userID
|
|
368
|
-
)
|
|
369
|
-
}, [channel._client.userID, channel.state.members])
|
|
388
|
+
const members = Object.values(channel.state.members || {})
|
|
389
|
+
return members.find(
|
|
390
|
+
(member) => member.user?.id && member.user.id !== channel._client.userID
|
|
391
|
+
)
|
|
392
|
+
}, [channel._client.userID, channel.state.members])
|
|
370
393
|
|
|
371
394
|
// Get follower status label from channel data
|
|
372
395
|
const followerStatusLabel = React.useMemo(() => {
|
|
373
396
|
const channelExtraData = (channel.data ?? {}) as {
|
|
374
|
-
followerStatus?: string
|
|
375
|
-
isFollower?: boolean
|
|
376
|
-
}
|
|
397
|
+
followerStatus?: string
|
|
398
|
+
isFollower?: boolean
|
|
399
|
+
}
|
|
377
400
|
return channelExtraData.followerStatus
|
|
378
401
|
? String(channelExtraData.followerStatus)
|
|
379
402
|
: channelExtraData.isFollower
|
|
380
403
|
? 'Subscribed to you'
|
|
381
|
-
: undefined
|
|
382
|
-
}, [channel.data])
|
|
404
|
+
: undefined
|
|
405
|
+
}, [channel.data])
|
|
383
406
|
|
|
384
407
|
return (
|
|
385
408
|
<div className={classNames('h-full flex flex-col', className)}>
|
|
@@ -418,5 +441,5 @@ export const ChannelView: React.FC<ChannelViewProps> = ({
|
|
|
418
441
|
onBlockParticipant={onBlockParticipant}
|
|
419
442
|
/>
|
|
420
443
|
</div>
|
|
421
|
-
)
|
|
422
|
-
}
|
|
444
|
+
)
|
|
445
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { XIcon } from
|
|
2
|
-
import React from "react";
|
|
1
|
+
import { XIcon } from '@phosphor-icons/react'
|
|
3
2
|
|
|
4
|
-
import { IconButton } from
|
|
3
|
+
import { IconButton } from '../IconButton'
|
|
5
4
|
|
|
6
5
|
interface CloseButtonProps {
|
|
7
|
-
onClick: () => void
|
|
6
|
+
onClick: () => void
|
|
8
7
|
}
|
|
9
8
|
|
|
10
9
|
export function CloseButton({ onClick }: CloseButtonProps) {
|
|
@@ -12,5 +11,5 @@ export function CloseButton({ onClick }: CloseButtonProps) {
|
|
|
12
11
|
<IconButton label="Close" onClick={onClick} className="p-1">
|
|
13
12
|
<XIcon className="h-5 w-5 text-stone" weight="bold" />
|
|
14
13
|
</IconButton>
|
|
15
|
-
)
|
|
14
|
+
)
|
|
16
15
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { XIcon } from '@phosphor-icons/react'
|
|
1
2
|
import type { Meta, StoryFn } from '@storybook/react'
|
|
2
|
-
import { IconButton } from '.'
|
|
3
|
-
import { XIcon } from '@phosphor-icons/react/dist/csr/X'
|
|
4
3
|
import React from 'react'
|
|
5
4
|
|
|
5
|
+
import { IconButton } from '.'
|
|
6
|
+
|
|
6
7
|
type ComponentProps = React.ComponentProps<typeof IconButton>
|
|
7
8
|
|
|
8
9
|
const meta: Meta<ComponentProps> = {
|
|
@@ -37,4 +38,3 @@ WithCustomClassName.args = {
|
|
|
37
38
|
children: <XIcon className="h-6 w-6" />,
|
|
38
39
|
className: 'bg-primary text-white size-12',
|
|
39
40
|
}
|
|
40
|
-
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import classNames from
|
|
2
|
-
import React from "react";
|
|
1
|
+
import classNames from 'classnames'
|
|
3
2
|
|
|
4
3
|
type LoadingProps = {
|
|
5
|
-
className?: string
|
|
6
|
-
message?: string
|
|
7
|
-
}
|
|
4
|
+
className?: string
|
|
5
|
+
message?: string
|
|
6
|
+
}
|
|
8
7
|
|
|
9
8
|
const Loading = ({ className, message }: LoadingProps) => (
|
|
10
9
|
<div
|
|
11
|
-
className={classNames(
|
|
10
|
+
className={classNames('flex items-center justify-center h-full', className)}
|
|
12
11
|
>
|
|
13
12
|
<svg viewBox="0 0 100 100" className="size-8 fill-pebble" stroke="none">
|
|
14
13
|
<circle cx="6" cy="50" r="6">
|
|
@@ -44,7 +43,6 @@ const Loading = ({ className, message }: LoadingProps) => (
|
|
|
44
43
|
</svg>
|
|
45
44
|
{message && <span className="text-stone">{message}</span>}
|
|
46
45
|
</div>
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
export default Loading;
|
|
46
|
+
)
|
|
50
47
|
|
|
48
|
+
export default Loading
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Meta, StoryFn } from '@storybook/react'
|
|
2
|
-
import { ErrorState } from './ErrorState'
|
|
3
2
|
import React from 'react'
|
|
4
3
|
|
|
4
|
+
import { ErrorState } from './ErrorState'
|
|
5
|
+
|
|
5
6
|
type ComponentProps = React.ComponentProps<typeof ErrorState>
|
|
6
7
|
|
|
7
8
|
const meta: Meta<ComponentProps> = {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Meta, StoryFn } from '@storybook/react'
|
|
2
|
-
import { LoadingState } from './LoadingState'
|
|
3
2
|
import React from 'react'
|
|
4
3
|
|
|
4
|
+
import { LoadingState } from './LoadingState'
|
|
5
|
+
|
|
5
6
|
type ComponentProps = React.ComponentProps<typeof LoadingState>
|
|
6
7
|
|
|
7
8
|
const meta: Meta<ComponentProps> = {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Loading from '../Loading';
|
|
1
|
+
import Loading from '../Loading'
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Loading state component
|
|
@@ -7,9 +6,8 @@ import Loading from '../Loading';
|
|
|
7
6
|
export const LoadingState = () => (
|
|
8
7
|
<div className="flex items-center justify-center h-full">
|
|
9
8
|
<div className="flex items-center">
|
|
10
|
-
<Loading className=
|
|
9
|
+
<Loading className="w-6 h-6" />
|
|
11
10
|
<span className="text-sm text-stone">Loading messages</span>
|
|
12
11
|
</div>
|
|
13
12
|
</div>
|
|
14
|
-
)
|
|
15
|
-
|
|
13
|
+
)
|