@linktr.ee/messaging-react 1.27.0 → 1.28.0-rc-1776225927
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/Creator-D38dWn2X.js +318 -0
- package/dist/Creator-D38dWn2X.js.map +1 -0
- package/dist/MediaPlayer-DE9MC6k6.js +599 -0
- package/dist/MediaPlayer-DE9MC6k6.js.map +1 -0
- package/dist/Visitor-BG-9-3HU.js +199 -0
- package/dist/Visitor-BG-9-3HU.js.map +1 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/CustomMessage/CustomMessage.stories.tsx +1 -1
- package/src/components/LockedAttachment/LockedAttachment.stories.tsx +143 -49
- package/src/components/LockedAttachment/components/Creator.tsx +410 -112
- package/src/components/LockedAttachment/components/MediaPlayer.tsx +112 -52
- package/src/components/LockedAttachment/components/Visitor.tsx +206 -143
- package/src/components/LockedAttachment/types.ts +2 -3
- package/src/components/LockedAttachment/utils/icons.ts +2 -1
- package/src/components/LockedAttachment/utils/mimeType.test.ts +29 -7
- package/src/components/LockedAttachment/utils/mimeType.ts +3 -1
- package/src/types.ts +0 -1
- package/dist/Creator-B6M8dB0U.js +0 -87
- package/dist/Creator-B6M8dB0U.js.map +0 -1
- package/dist/MediaPlayer-DsjlYGGH.js +0 -539
- package/dist/MediaPlayer-DsjlYGGH.js.map +0 -1
- package/dist/Visitor-CpmFZRGO.js +0 -175
- package/dist/Visitor-CpmFZRGO.js.map +0 -1
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CircleNotchIcon,
|
|
3
|
-
PauseIcon,
|
|
4
|
-
PlayIcon,
|
|
5
|
-
} from '@phosphor-icons/react'
|
|
1
|
+
import { CircleNotchIcon, PauseIcon, PlayIcon } from '@phosphor-icons/react'
|
|
6
2
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
7
3
|
import ReactPlayer from 'react-player'
|
|
8
4
|
|
|
@@ -27,6 +23,8 @@ export interface MediaPlayerProps {
|
|
|
27
23
|
mimeType: string
|
|
28
24
|
poster?: string
|
|
29
25
|
autoPlay?: boolean
|
|
26
|
+
/** Controlled playing state. When provided, syncs to internal play/pause. */
|
|
27
|
+
playing?: boolean
|
|
30
28
|
loop?: boolean
|
|
31
29
|
controls?: boolean
|
|
32
30
|
showProgress?: boolean
|
|
@@ -40,6 +38,7 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
|
|
|
40
38
|
mimeType,
|
|
41
39
|
poster,
|
|
42
40
|
autoPlay = false,
|
|
41
|
+
playing: playingProp,
|
|
43
42
|
loop = false,
|
|
44
43
|
controls = true,
|
|
45
44
|
showProgress = false,
|
|
@@ -48,6 +47,18 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
|
|
|
48
47
|
}) => {
|
|
49
48
|
const sourceType = getSourceType(mimeType)
|
|
50
49
|
const [playing, setPlaying] = useState(autoPlay)
|
|
50
|
+
|
|
51
|
+
// Sync controlled playing prop to internal state
|
|
52
|
+
const prevPlayingPropRef = useRef(playingProp)
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (
|
|
55
|
+
playingProp !== undefined &&
|
|
56
|
+
playingProp !== prevPlayingPropRef.current
|
|
57
|
+
) {
|
|
58
|
+
prevPlayingPropRef.current = playingProp
|
|
59
|
+
setPlaying(playingProp)
|
|
60
|
+
}
|
|
61
|
+
}, [playingProp])
|
|
51
62
|
const [played, setPlayed] = useState(0)
|
|
52
63
|
const [seeking, setSeeking] = useState(false)
|
|
53
64
|
const [scrubberHovered, setScrubberHovered] = useState(false)
|
|
@@ -123,7 +134,9 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
|
|
|
123
134
|
if (el && el.duration) el.currentTime = fraction * el.duration
|
|
124
135
|
}, [])
|
|
125
136
|
|
|
126
|
-
const handleTrackPointerDown = (
|
|
137
|
+
const handleTrackPointerDown = (
|
|
138
|
+
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>
|
|
139
|
+
) => {
|
|
127
140
|
e.stopPropagation()
|
|
128
141
|
setSeeking(true)
|
|
129
142
|
const fraction = getFraction(e)
|
|
@@ -151,7 +164,9 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
|
|
|
151
164
|
}, [seeking, getFraction, seekTo])
|
|
152
165
|
|
|
153
166
|
// Use natural aspect ratio once metadata loads, fall back to 16:9 before then.
|
|
154
|
-
const aspectStyle = videoAspect
|
|
167
|
+
const aspectStyle = videoAspect
|
|
168
|
+
? { aspectRatio: String(videoAspect) }
|
|
169
|
+
: undefined
|
|
155
170
|
const aspectClass = !videoAspect ? ' aspect-video' : ''
|
|
156
171
|
const scrubberPercent = Math.round(played * 100)
|
|
157
172
|
|
|
@@ -163,7 +178,10 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
|
|
|
163
178
|
style={aspectStyle}
|
|
164
179
|
onClick={() => {
|
|
165
180
|
if (manualPlayRequired) return
|
|
166
|
-
if (onContainerClick) {
|
|
181
|
+
if (onContainerClick) {
|
|
182
|
+
onContainerClick()
|
|
183
|
+
return
|
|
184
|
+
}
|
|
167
185
|
if (controls) setPlaying((p) => !p)
|
|
168
186
|
}}
|
|
169
187
|
onKeyDown={(e) => {
|
|
@@ -178,11 +196,18 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
|
|
|
178
196
|
}}
|
|
179
197
|
>
|
|
180
198
|
{poster && (
|
|
181
|
-
<img
|
|
199
|
+
<img
|
|
200
|
+
src={poster}
|
|
201
|
+
alt=""
|
|
202
|
+
className="absolute inset-0 h-full w-full object-cover"
|
|
203
|
+
/>
|
|
182
204
|
)}
|
|
183
205
|
{!poster && (
|
|
184
206
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
185
|
-
{renderTypeIcon(mimeType, {
|
|
207
|
+
{renderTypeIcon(mimeType, {
|
|
208
|
+
className: 'size-12 text-black/20',
|
|
209
|
+
weight: 'regular',
|
|
210
|
+
})}
|
|
186
211
|
</div>
|
|
187
212
|
)}
|
|
188
213
|
<div className="absolute inset-0">
|
|
@@ -216,7 +241,10 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
|
|
|
216
241
|
|
|
217
242
|
{buffering && !manualPlayRequired && (
|
|
218
243
|
<div className="absolute inset-0 z-10 flex items-center justify-center">
|
|
219
|
-
<CircleNotchIcon
|
|
244
|
+
<CircleNotchIcon
|
|
245
|
+
className="size-8 animate-spin text-white/80"
|
|
246
|
+
weight="bold"
|
|
247
|
+
/>
|
|
220
248
|
</div>
|
|
221
249
|
)}
|
|
222
250
|
|
|
@@ -244,54 +272,86 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
|
|
|
244
272
|
)}
|
|
245
273
|
|
|
246
274
|
{showProgress && !controls && (
|
|
247
|
-
<div className="absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent
|
|
248
|
-
<div
|
|
249
|
-
|
|
275
|
+
<div className="absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent">
|
|
276
|
+
<div
|
|
277
|
+
role="slider"
|
|
278
|
+
aria-label="Playback position"
|
|
279
|
+
aria-valuenow={scrubberPercent}
|
|
280
|
+
aria-valuemin={0}
|
|
281
|
+
aria-valuemax={100}
|
|
282
|
+
tabIndex={0}
|
|
283
|
+
ref={trackRef}
|
|
284
|
+
className="relative flex h-4 w-full cursor-pointer items-center"
|
|
285
|
+
onMouseDown={handleTrackPointerDown}
|
|
286
|
+
onTouchStart={handleTrackPointerDown}
|
|
287
|
+
onClick={(e) => e.stopPropagation()}
|
|
288
|
+
onKeyDown={(e) => {
|
|
289
|
+
if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))
|
|
290
|
+
if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))
|
|
291
|
+
}}
|
|
292
|
+
>
|
|
293
|
+
<div className="w-full overflow-hidden rounded-full bg-white/30 h-1">
|
|
294
|
+
<div
|
|
295
|
+
className="h-full rounded-full bg-white"
|
|
296
|
+
style={{ width: `${scrubberPercent}%` }}
|
|
297
|
+
/>
|
|
298
|
+
</div>
|
|
250
299
|
</div>
|
|
251
300
|
</div>
|
|
252
301
|
)}
|
|
253
302
|
|
|
254
|
-
{controls &&
|
|
255
|
-
<
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
303
|
+
{controls && (
|
|
304
|
+
<div className="absolute inset-x-0 bottom-0 flex items-center gap-2 bg-gradient-to-t from-black/60 to-transparent px-3 pb-2.5 pt-6 transition-all duration-200">
|
|
305
|
+
<button
|
|
306
|
+
type="button"
|
|
307
|
+
onClick={(e) => {
|
|
308
|
+
e.stopPropagation()
|
|
309
|
+
setPlaying((p) => !p)
|
|
310
|
+
}}
|
|
311
|
+
className="shrink-0 text-white"
|
|
312
|
+
aria-label={playing ? 'Pause' : 'Play'}
|
|
313
|
+
>
|
|
314
|
+
{playing ? (
|
|
315
|
+
<PauseIcon className="size-5" weight="fill" />
|
|
316
|
+
) : (
|
|
317
|
+
<PlayIcon className="size-5 translate-x-px" weight="fill" />
|
|
318
|
+
)}
|
|
319
|
+
</button>
|
|
266
320
|
|
|
267
|
-
<div
|
|
268
|
-
role="slider"
|
|
269
|
-
aria-label="Playback position"
|
|
270
|
-
aria-valuenow={scrubberPercent}
|
|
271
|
-
aria-valuemin={0}
|
|
272
|
-
aria-valuemax={100}
|
|
273
|
-
tabIndex={0}
|
|
274
|
-
ref={trackRef}
|
|
275
|
-
className="relative flex h-4 w-full cursor-pointer items-center"
|
|
276
|
-
onMouseDown={handleTrackPointerDown}
|
|
277
|
-
onTouchStart={handleTrackPointerDown}
|
|
278
|
-
onClick={(e) => e.stopPropagation()}
|
|
279
|
-
onMouseEnter={() => setScrubberHovered(true)}
|
|
280
|
-
onMouseLeave={() => setScrubberHovered(false)}
|
|
281
|
-
onKeyDown={(e) => {
|
|
282
|
-
if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))
|
|
283
|
-
if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))
|
|
284
|
-
}}
|
|
285
|
-
>
|
|
286
|
-
<div className={`w-full overflow-hidden rounded-full bg-white/30 transition-all duration-200 ${scrubberHovered || seeking ? 'h-1.5' : 'h-1'}`}>
|
|
287
|
-
<div className="h-full rounded-full bg-white" style={{ width: `${scrubberPercent}%` }} />
|
|
288
|
-
</div>
|
|
289
321
|
<div
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
322
|
+
role="slider"
|
|
323
|
+
aria-label="Playback position"
|
|
324
|
+
aria-valuenow={scrubberPercent}
|
|
325
|
+
aria-valuemin={0}
|
|
326
|
+
aria-valuemax={100}
|
|
327
|
+
tabIndex={0}
|
|
328
|
+
ref={trackRef}
|
|
329
|
+
className="relative flex h-4 w-full cursor-pointer items-center"
|
|
330
|
+
onMouseDown={handleTrackPointerDown}
|
|
331
|
+
onTouchStart={handleTrackPointerDown}
|
|
332
|
+
onClick={(e) => e.stopPropagation()}
|
|
333
|
+
onMouseEnter={() => setScrubberHovered(true)}
|
|
334
|
+
onMouseLeave={() => setScrubberHovered(false)}
|
|
335
|
+
onKeyDown={(e) => {
|
|
336
|
+
if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))
|
|
337
|
+
if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))
|
|
338
|
+
}}
|
|
339
|
+
>
|
|
340
|
+
<div
|
|
341
|
+
className={`w-full overflow-hidden rounded-full bg-white/30 transition-all duration-200 ${scrubberHovered || seeking ? 'h-1.5' : 'h-1'}`}
|
|
342
|
+
>
|
|
343
|
+
<div
|
|
344
|
+
className="h-full rounded-full bg-white"
|
|
345
|
+
style={{ width: `${scrubberPercent}%` }}
|
|
346
|
+
/>
|
|
347
|
+
</div>
|
|
348
|
+
<div
|
|
349
|
+
className={`absolute size-3 -translate-x-1/2 rounded-full bg-white shadow transition-[opacity,transform] duration-200 ${scrubberHovered || seeking ? 'scale-100 opacity-100' : 'scale-0 opacity-0'}`}
|
|
350
|
+
style={{ left: `${scrubberPercent}%` }}
|
|
351
|
+
/>
|
|
352
|
+
</div>
|
|
293
353
|
</div>
|
|
294
|
-
|
|
354
|
+
)}
|
|
295
355
|
</div>
|
|
296
356
|
)
|
|
297
357
|
}
|