@linktr.ee/messaging-react 1.33.2 → 1.33.3-rc-1777507218
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/Card-BfA8wq8O.js +181 -0
- package/dist/Card-BfA8wq8O.js.map +1 -0
- package/dist/{Card-Ddi8bg90.js → Card-Bpud_enW.js} +55 -55
- package/dist/Card-Bpud_enW.js.map +1 -0
- package/dist/assets/index.css +1 -1
- package/dist/index-Ydi1pTAi.js +3130 -0
- package/dist/index-Ydi1pTAi.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/ChannelInfoDialog/index.tsx +3 -1
- package/src/components/ChannelView.tsx +24 -6
- package/src/components/LockedAttachment/components/Creator/Card.tsx +33 -24
- package/src/components/LockedAttachment/components/MediaPlayer.tsx +10 -1
- package/src/components/LockedAttachment/components/Visitor/Card.tsx +9 -9
- package/src/components/LockedAttachment/components/Visitor/CardActions.tsx +2 -2
- package/src/components/MediaMessage/MediaMessage.stories.tsx +82 -19
- package/src/components/MediaMessage/MediaMessage.test.tsx +277 -18
- package/src/components/MediaMessage/index.tsx +388 -77
- package/src/styles.css +49 -0
- package/dist/Card-DEe10CiS.js +0 -171
- package/dist/Card-DEe10CiS.js.map +0 -1
- package/dist/Card-Ddi8bg90.js.map +0 -1
- package/dist/index-BePLvyvi.js +0 -2868
- package/dist/index-BePLvyvi.js.map +0 -1
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import type { LocalMessage } from 'stream-chat'
|
|
3
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { beforeAll, describe, expect, it, vi } from 'vitest'
|
|
4
4
|
|
|
5
|
-
import { renderWithProviders, screen } from '../../test/utils'
|
|
5
|
+
import { renderWithProviders, screen, fireEvent } from '../../test/utils'
|
|
6
6
|
|
|
7
7
|
import { MediaMessage } from '.'
|
|
8
8
|
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
HTMLDialogElement.prototype.showModal = vi.fn(function (this: HTMLDialogElement) {
|
|
11
|
+
this.setAttribute('open', '')
|
|
12
|
+
})
|
|
13
|
+
HTMLDialogElement.prototype.close = vi.fn(function (this: HTMLDialogElement) {
|
|
14
|
+
this.removeAttribute('open')
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
|
|
9
18
|
vi.mock('../Avatar', () => ({
|
|
10
19
|
Avatar: ({ id }: { id: string }) => (
|
|
11
20
|
<div data-testid="avatar" data-user-id={id} />
|
|
@@ -16,14 +25,20 @@ vi.mock('../LockedAttachment/components/MediaPlayer', () => ({
|
|
|
16
25
|
default: ({
|
|
17
26
|
source,
|
|
18
27
|
mimeType,
|
|
28
|
+
onContainerClick,
|
|
19
29
|
}: {
|
|
20
30
|
source: string
|
|
21
31
|
mimeType: string
|
|
32
|
+
onContainerClick?: (e: React.MouseEvent) => void
|
|
22
33
|
}) => (
|
|
23
34
|
<div
|
|
35
|
+
role="button"
|
|
36
|
+
tabIndex={0}
|
|
24
37
|
data-testid="media-player"
|
|
25
38
|
data-source={source}
|
|
26
39
|
data-mime-type={mimeType}
|
|
40
|
+
onClick={onContainerClick}
|
|
41
|
+
onKeyDown={undefined}
|
|
27
42
|
/>
|
|
28
43
|
),
|
|
29
44
|
}))
|
|
@@ -41,7 +56,6 @@ vi.mock('../LockedAttachment/utils/mimeType', () => ({
|
|
|
41
56
|
},
|
|
42
57
|
}))
|
|
43
58
|
|
|
44
|
-
// Cast through unknown to avoid satisfying every optional field of LocalMessage
|
|
45
59
|
const msg = (overrides: Record<string, unknown> = {}): LocalMessage =>
|
|
46
60
|
({
|
|
47
61
|
id: 'msg-1',
|
|
@@ -63,7 +77,7 @@ describe('MediaMessage', () => {
|
|
|
63
77
|
expect(container.firstChild).toBeNull()
|
|
64
78
|
})
|
|
65
79
|
|
|
66
|
-
it('renders MediaPlayer for a video attachment', () => {
|
|
80
|
+
it('renders MediaPlayer immediately for a video attachment', () => {
|
|
67
81
|
renderWithProviders(
|
|
68
82
|
<MediaMessage
|
|
69
83
|
message={msg({
|
|
@@ -72,6 +86,7 @@ describe('MediaMessage', () => {
|
|
|
72
86
|
type: 'video',
|
|
73
87
|
asset_url: 'https://cdn.example.com/clip.mp4',
|
|
74
88
|
mime_type: 'video/mp4',
|
|
89
|
+
title: 'My Clip',
|
|
75
90
|
},
|
|
76
91
|
],
|
|
77
92
|
})}
|
|
@@ -80,11 +95,28 @@ describe('MediaMessage', () => {
|
|
|
80
95
|
|
|
81
96
|
const player = screen.getByTestId('media-player')
|
|
82
97
|
expect(player).toBeInTheDocument()
|
|
83
|
-
expect(player).toHaveAttribute(
|
|
84
|
-
|
|
85
|
-
|
|
98
|
+
expect(player).toHaveAttribute('data-source', 'https://cdn.example.com/clip.mp4')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('opens viewer when the video player container is clicked', () => {
|
|
102
|
+
renderWithProviders(
|
|
103
|
+
<MediaMessage
|
|
104
|
+
message={msg({
|
|
105
|
+
attachments: [
|
|
106
|
+
{
|
|
107
|
+
type: 'video',
|
|
108
|
+
asset_url: 'https://cdn.example.com/clip.mp4',
|
|
109
|
+
mime_type: 'video/mp4',
|
|
110
|
+
title: 'My Clip',
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
})}
|
|
114
|
+
/>
|
|
86
115
|
)
|
|
87
|
-
|
|
116
|
+
|
|
117
|
+
fireEvent.click(screen.getByTestId('media-player'))
|
|
118
|
+
expect(HTMLDialogElement.prototype.showModal).toHaveBeenCalled()
|
|
119
|
+
expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument()
|
|
88
120
|
})
|
|
89
121
|
|
|
90
122
|
it('renders MediaPlayer for an audio attachment', () => {
|
|
@@ -108,7 +140,27 @@ describe('MediaMessage', () => {
|
|
|
108
140
|
)
|
|
109
141
|
})
|
|
110
142
|
|
|
111
|
-
it('
|
|
143
|
+
it('does not show viewer or expand button for audio', () => {
|
|
144
|
+
renderWithProviders(
|
|
145
|
+
<MediaMessage
|
|
146
|
+
message={msg({
|
|
147
|
+
attachments: [
|
|
148
|
+
{
|
|
149
|
+
type: 'audio',
|
|
150
|
+
asset_url: 'https://cdn.example.com/track.mp3',
|
|
151
|
+
mime_type: 'audio/mpeg',
|
|
152
|
+
title: 'My Track',
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
})}
|
|
156
|
+
/>
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
expect(screen.queryByRole('button', { name: 'View full screen' })).not.toBeInTheDocument()
|
|
160
|
+
expect(screen.queryByRole('button', { name: 'Close' })).not.toBeInTheDocument()
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('renders an img for an image attachment and opens viewer on click', () => {
|
|
112
164
|
renderWithProviders(
|
|
113
165
|
<MediaMessage
|
|
114
166
|
message={msg({
|
|
@@ -126,9 +178,36 @@ describe('MediaMessage', () => {
|
|
|
126
178
|
|
|
127
179
|
const image = screen.getByRole('img', { name: 'My Photo' })
|
|
128
180
|
expect(image).toHaveAttribute('src', 'https://cdn.example.com/photo.jpg')
|
|
181
|
+
|
|
182
|
+
// Clicking the image button opens the viewer
|
|
183
|
+
fireEvent.click(screen.getByRole('button', { name: 'My Photo' }))
|
|
184
|
+
expect(HTMLDialogElement.prototype.showModal).toHaveBeenCalled()
|
|
185
|
+
const viewerImages = screen.getAllByRole('img', { name: 'My Photo' })
|
|
186
|
+
expect(viewerImages.some((img) => img.classList.contains('rounded-2xl'))).toBe(true)
|
|
129
187
|
})
|
|
130
188
|
|
|
131
|
-
it('
|
|
189
|
+
it('does not show expand button in chin for images, only download', () => {
|
|
190
|
+
renderWithProviders(
|
|
191
|
+
<MediaMessage
|
|
192
|
+
message={msg({
|
|
193
|
+
attachments: [
|
|
194
|
+
{
|
|
195
|
+
type: 'image',
|
|
196
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
197
|
+
mime_type: 'image/jpeg',
|
|
198
|
+
title: 'My Photo',
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
})}
|
|
202
|
+
/>
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
// Thumbnail button + download button — no separate expand/fullscreen button
|
|
206
|
+
expect(screen.queryByRole('button', { name: 'View full screen' })).not.toBeInTheDocument()
|
|
207
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('renders PDF card with a viewer button', () => {
|
|
132
211
|
renderWithProviders(
|
|
133
212
|
<MediaMessage
|
|
134
213
|
message={msg({
|
|
@@ -144,13 +223,56 @@ describe('MediaMessage', () => {
|
|
|
144
223
|
/>
|
|
145
224
|
)
|
|
146
225
|
|
|
147
|
-
|
|
148
|
-
expect(link).toHaveAttribute('href', 'https://cdn.example.com/report.pdf')
|
|
226
|
+
expect(screen.getByRole('button', { name: 'Open PDF viewer' })).toBeInTheDocument()
|
|
149
227
|
expect(screen.getByText('Annual Report')).toBeInTheDocument()
|
|
150
|
-
expect(screen.getByTestId('type-icon')).toBeInTheDocument()
|
|
151
228
|
})
|
|
152
229
|
|
|
153
|
-
it('
|
|
230
|
+
it('opens PDF viewer when PDF thumbnail is clicked', () => {
|
|
231
|
+
renderWithProviders(
|
|
232
|
+
<MediaMessage
|
|
233
|
+
message={msg({
|
|
234
|
+
attachments: [
|
|
235
|
+
{
|
|
236
|
+
type: 'file',
|
|
237
|
+
asset_url: 'https://cdn.example.com/report.pdf',
|
|
238
|
+
mime_type: 'application/pdf',
|
|
239
|
+
title: 'Annual Report',
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
})}
|
|
243
|
+
/>
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
fireEvent.click(screen.getByRole('button', { name: 'Open PDF viewer' }))
|
|
247
|
+
expect(HTMLDialogElement.prototype.showModal).toHaveBeenCalled()
|
|
248
|
+
expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument()
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('renders unknown file as a link with no viewer button', () => {
|
|
252
|
+
renderWithProviders(
|
|
253
|
+
<MediaMessage
|
|
254
|
+
message={msg({
|
|
255
|
+
attachments: [
|
|
256
|
+
{
|
|
257
|
+
type: 'file',
|
|
258
|
+
asset_url: 'https://cdn.example.com/data.bin',
|
|
259
|
+
mime_type: 'application/octet-stream',
|
|
260
|
+
title: 'Unknown File',
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
})}
|
|
264
|
+
/>
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
// No viewer button for unknown files
|
|
268
|
+
expect(screen.queryByRole('button', { name: 'Open PDF viewer' })).not.toBeInTheDocument()
|
|
269
|
+
// Thumbnail is a plain link (opens in new tab)
|
|
270
|
+
const links = screen.getAllByRole('link')
|
|
271
|
+
expect(links.some((l) => l.getAttribute('href') === 'https://cdn.example.com/data.bin')).toBe(true)
|
|
272
|
+
expect(screen.getByText('Unknown File')).toBeInTheDocument()
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('shows title and file size in chin', () => {
|
|
154
276
|
renderWithProviders(
|
|
155
277
|
<MediaMessage
|
|
156
278
|
message={msg({
|
|
@@ -188,10 +310,7 @@ describe('MediaMessage', () => {
|
|
|
188
310
|
)
|
|
189
311
|
|
|
190
312
|
expect(screen.getByTestId('avatar')).toBeInTheDocument()
|
|
191
|
-
expect(screen.getByTestId('avatar')).toHaveAttribute(
|
|
192
|
-
'data-user-id',
|
|
193
|
-
'user-1'
|
|
194
|
-
)
|
|
313
|
+
expect(screen.getByTestId('avatar')).toHaveAttribute('data-user-id', 'user-1')
|
|
195
314
|
})
|
|
196
315
|
|
|
197
316
|
it('does not render Avatar for own messages', () => {
|
|
@@ -258,4 +377,144 @@ describe('MediaMessage', () => {
|
|
|
258
377
|
|
|
259
378
|
expect(container.firstChild).toBeNull()
|
|
260
379
|
})
|
|
380
|
+
|
|
381
|
+
it('renders a link card for a link attachment', () => {
|
|
382
|
+
renderWithProviders(
|
|
383
|
+
<MediaMessage
|
|
384
|
+
message={msg({
|
|
385
|
+
attachments: [
|
|
386
|
+
{
|
|
387
|
+
type: 'link',
|
|
388
|
+
og_scrape_url: 'https://linktr.ee/someone',
|
|
389
|
+
title: 'My Linktree',
|
|
390
|
+
text: 'Check out my links',
|
|
391
|
+
image_url: 'https://cdn.example.com/thumb.jpg',
|
|
392
|
+
},
|
|
393
|
+
],
|
|
394
|
+
})}
|
|
395
|
+
/>
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
const link = screen.getByRole('link')
|
|
399
|
+
expect(link).toHaveAttribute('href', 'https://linktr.ee/someone')
|
|
400
|
+
expect(screen.getByText('My Linktree')).toBeInTheDocument()
|
|
401
|
+
expect(screen.getByText('Check out my links')).toBeInTheDocument()
|
|
402
|
+
expect(screen.getByText('https://linktr.ee/someone')).toBeInTheDocument()
|
|
403
|
+
const img = screen.getByRole('img', { name: 'My Linktree' })
|
|
404
|
+
expect(img).toHaveAttribute('src', 'https://cdn.example.com/thumb.jpg')
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
it('renders a link fallback icon when link has no image', () => {
|
|
408
|
+
renderWithProviders(
|
|
409
|
+
<MediaMessage
|
|
410
|
+
message={msg({
|
|
411
|
+
attachments: [
|
|
412
|
+
{
|
|
413
|
+
type: 'link',
|
|
414
|
+
og_scrape_url: 'https://linktr.ee/someone',
|
|
415
|
+
title: 'My Linktree',
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
})}
|
|
419
|
+
/>
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
expect(screen.queryByRole('img')).not.toBeInTheDocument()
|
|
423
|
+
expect(screen.getByText('My Linktree')).toBeInTheDocument()
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
it('uses dark card background for sent messages', () => {
|
|
427
|
+
const { container } = renderWithProviders(
|
|
428
|
+
<MediaMessage
|
|
429
|
+
isMyMessage={true}
|
|
430
|
+
message={msg({
|
|
431
|
+
attachments: [
|
|
432
|
+
{
|
|
433
|
+
type: 'image',
|
|
434
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
435
|
+
mime_type: 'image/jpeg',
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
})}
|
|
439
|
+
/>
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
expect(container.querySelector('.bg-\\[\\#121110\\]')).toBeInTheDocument()
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
it('uses light card background for received messages', () => {
|
|
446
|
+
const { container } = renderWithProviders(
|
|
447
|
+
<MediaMessage
|
|
448
|
+
isMyMessage={false}
|
|
449
|
+
message={msg({
|
|
450
|
+
attachments: [
|
|
451
|
+
{
|
|
452
|
+
type: 'image',
|
|
453
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
454
|
+
mime_type: 'image/jpeg',
|
|
455
|
+
},
|
|
456
|
+
],
|
|
457
|
+
})}
|
|
458
|
+
/>
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
expect(container.querySelector('.bg-\\[\\#F3F3F1\\]')).toBeInTheDocument()
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
it('shows download button for image attachment', () => {
|
|
465
|
+
renderWithProviders(
|
|
466
|
+
<MediaMessage
|
|
467
|
+
message={msg({
|
|
468
|
+
attachments: [
|
|
469
|
+
{
|
|
470
|
+
type: 'image',
|
|
471
|
+
image_url: 'https://cdn.example.com/photo.jpg',
|
|
472
|
+
mime_type: 'image/jpeg',
|
|
473
|
+
title: 'My Photo',
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
})}
|
|
477
|
+
/>
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
it('shows download button for audio attachment', () => {
|
|
484
|
+
renderWithProviders(
|
|
485
|
+
<MediaMessage
|
|
486
|
+
message={msg({
|
|
487
|
+
attachments: [
|
|
488
|
+
{
|
|
489
|
+
type: 'audio',
|
|
490
|
+
asset_url: 'https://cdn.example.com/track.mp3',
|
|
491
|
+
mime_type: 'audio/mpeg',
|
|
492
|
+
title: 'My Track',
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
})}
|
|
496
|
+
/>
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
expect(screen.getByRole('button', { name: 'Download' })).toBeInTheDocument()
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
it('does not show download or expand buttons for link cards', () => {
|
|
503
|
+
renderWithProviders(
|
|
504
|
+
<MediaMessage
|
|
505
|
+
message={msg({
|
|
506
|
+
attachments: [
|
|
507
|
+
{
|
|
508
|
+
type: 'link',
|
|
509
|
+
og_scrape_url: 'https://linktr.ee/someone',
|
|
510
|
+
title: 'My Linktree',
|
|
511
|
+
},
|
|
512
|
+
],
|
|
513
|
+
})}
|
|
514
|
+
/>
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
expect(screen.queryByRole('button', { name: 'Download' })).not.toBeInTheDocument()
|
|
518
|
+
expect(screen.queryByRole('button', { name: 'View full screen' })).not.toBeInTheDocument()
|
|
519
|
+
})
|
|
261
520
|
})
|