@linktr.ee/messaging-react 4.4.7 → 4.4.8-rc-1788251276
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/{AttachmentCard-DSekwIOA.js → AttachmentCard-BaZk77fe.js} +136 -125
- package/dist/AttachmentCard-BaZk77fe.js.map +1 -0
- package/dist/AttachmentCard-ZpYg622K.cjs +2 -0
- package/dist/AttachmentCard-ZpYg622K.cjs.map +1 -0
- package/dist/{Card-BS6Fza2a.cjs → Card-4irOjGaI.cjs} +2 -2
- package/dist/{Card-BS6Fza2a.cjs.map → Card-4irOjGaI.cjs.map} +1 -1
- package/dist/{Card-BhwBkgxI.js → Card-BdyQhysm.js} +2 -2
- package/dist/{Card-BhwBkgxI.js.map → Card-BdyQhysm.js.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +915 -907
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/AttachmentCard/MediaPlayer.test.tsx +9 -5
- package/src/components/AttachmentCard/MediaPlayer.tsx +3 -5
- package/src/components/AttachmentCard/Thumbnail.test.tsx +4 -0
- package/src/components/ChannelActionsMenu/ChannelActionsMenu.test.tsx +18 -10
- package/src/components/ChannelActionsMenu/index.tsx +13 -4
- package/src/components/ChannelList/ChannelListContext.test.tsx +7 -5
- package/src/components/ChannelList/CustomChannelPreview.test.tsx +7 -5
- package/src/components/ChannelList/index.test.tsx +1 -0
- package/src/components/ChannelView.test.tsx +20 -13
- package/src/components/CustomLinkPreviewList/CustomLinkPreviewList.test.tsx +4 -3
- package/src/components/CustomMessage/CustomMessage.test.tsx +6 -5
- package/src/components/CustomMessage/MessageTag.test.tsx +6 -0
- package/src/components/CustomMessage/SentMessageDeliveryStatus.test.tsx +19 -9
- package/src/components/CustomMessage/StreamAttachmentMessage.test.tsx +12 -5
- package/src/components/CustomMessage/TipMessage/TipMessage.test.tsx +3 -0
- package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +16 -7
- package/src/components/FaqList/FaqList.test.tsx +20 -12
- package/src/components/LinkAttachment/LinkAttachment.test.tsx +27 -14
- package/src/components/LinkAttachment/components/_shared/BubbleTail.test.tsx +1 -0
- package/src/components/LinkAttachment/components/_shared/CardBody.test.tsx +6 -6
- package/src/components/LinkAttachment/components/_shared/CardCta.test.tsx +8 -5
- package/src/components/LinkAttachment/components/_shared/CardShell.test.tsx +7 -5
- package/src/components/LinkAttachment/components/_shared/CardThumbnail.test.tsx +3 -8
- package/src/components/MessageAttachment/MessageAttachment.behavior.test.tsx +22 -15
- package/src/components/MessageAttachment/MessageAttachment.test.tsx +117 -60
- package/src/components/MessageAttachment/_shared/Bubble.test.tsx +2 -0
- package/src/components/MessageAttachment/_shared/CarouselNav.test.tsx +5 -4
- package/src/components/MessageAttachment/_shared/CompactDocumentRow.test.tsx +4 -3
- package/src/components/MessageAttachment/_shared/DismissButton.test.tsx +4 -3
- package/src/components/MessageAttachment/_shared/DownloadAction.test.tsx +8 -5
- package/src/components/MessageAttachment/_shared/DownloadAction.tsx +4 -10
- package/src/components/MessageAttachment/_shared/ImageViewer.test.tsx +6 -3
- package/src/components/MessageAttachment/_shared/MediaStackGrid.test.tsx +11 -4
- package/src/components/MessageAttachment/_shared/PdfViewer.test.tsx +5 -3
- package/src/components/MessageAttachment/_shared/VideoViewer.test.tsx +12 -3
- package/src/components/MessageAttachment/_shared/ViewerShell.test.tsx +13 -6
- package/src/components/MessageAttachment/_shared/useCarousel.test.tsx +10 -4
- package/src/components/MessageBubble/MessageBubble.test.tsx +8 -0
- package/src/components/RichCard/RichCard.test.tsx +10 -2
- package/src/components/_shared/Spinner.test.tsx +75 -0
- package/src/components/_shared/Spinner.tsx +51 -0
- package/dist/AttachmentCard-BbsjzdLJ.cjs +0 -2
- package/dist/AttachmentCard-BbsjzdLJ.cjs.map +0 -1
- package/dist/AttachmentCard-DSekwIOA.js.map +0 -1
|
@@ -1,34 +1,45 @@
|
|
|
1
1
|
import e, { useCallback as t, useEffect as n, useRef as r, useState as i } from "react";
|
|
2
2
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
3
|
-
import "classnames";
|
|
4
|
-
import { CircleNotchIcon as
|
|
5
|
-
//#region src/
|
|
6
|
-
var
|
|
7
|
-
|
|
3
|
+
import s from "classnames";
|
|
4
|
+
import { CircleNotchIcon as c, FileCsvIcon as l, FileDocIcon as u, FileIcon as d, FileMdIcon as f, FilePdfIcon as p, FilePptIcon as m, FileTextIcon as h, FileXlsIcon as g, FileZipIcon as _, ImageIcon as v, PauseIcon as y, PlayIcon as b, SpeakerHighIcon as x, VideoCameraIcon as S } from "@phosphor-icons/react";
|
|
5
|
+
//#region src/components/_shared/Spinner.tsx
|
|
6
|
+
var C = {
|
|
7
|
+
sm: "size-4",
|
|
8
|
+
md: "size-5",
|
|
9
|
+
lg: "size-8"
|
|
10
|
+
}, w = {
|
|
11
|
+
inherit: void 0,
|
|
12
|
+
"on-media": "text-white/80"
|
|
13
|
+
}, T = ({ size: e = "sm", tone: t = "inherit", icon: n = c, weight: r = "bold", "aria-hidden": i, className: o }) => /* @__PURE__ */ a(n, {
|
|
14
|
+
className: s("animate-spin", C[e], w[t], o),
|
|
15
|
+
weight: r,
|
|
16
|
+
"aria-hidden": i
|
|
17
|
+
}), E = ["linktr.ee"], D = "messaging-attachment-v1_0";
|
|
18
|
+
function O(e) {
|
|
8
19
|
try {
|
|
9
20
|
return new URL(e).hostname.toLowerCase();
|
|
10
21
|
} catch {
|
|
11
22
|
return null;
|
|
12
23
|
}
|
|
13
24
|
}
|
|
14
|
-
function
|
|
15
|
-
return
|
|
25
|
+
function k(e) {
|
|
26
|
+
return E.some((t) => e === t || e.endsWith(`.${t}`));
|
|
16
27
|
}
|
|
17
|
-
function
|
|
28
|
+
function A(e) {
|
|
18
29
|
let t = e?.trim();
|
|
19
30
|
if (!t) return;
|
|
20
|
-
let n =
|
|
21
|
-
if (!n || !
|
|
31
|
+
let n = O(t);
|
|
32
|
+
if (!n || !k(n)) return t;
|
|
22
33
|
let r = new URL(t);
|
|
23
|
-
return r.searchParams.get("io") === "true" && r.searchParams.get("size") ===
|
|
34
|
+
return r.searchParams.get("io") === "true" && r.searchParams.get("size") === D ? t : (r.searchParams.set("io", "true"), r.searchParams.set("size", D), r.toString());
|
|
24
35
|
}
|
|
25
36
|
//#endregion
|
|
26
37
|
//#region src/utils/nativeMediaPlayers.ts
|
|
27
|
-
var
|
|
28
|
-
typeof document > "u" || document.querySelectorAll(`[${
|
|
38
|
+
var j = "data-mes-native-player", M = { [j]: "" }, N = (e) => {
|
|
39
|
+
typeof document > "u" || document.querySelectorAll(`[${j}]`).forEach((t) => {
|
|
29
40
|
t !== e && t.pause();
|
|
30
41
|
});
|
|
31
|
-
},
|
|
42
|
+
}, P = [
|
|
32
43
|
[/pdf/, "pdf"],
|
|
33
44
|
[/wordprocessingml|msword|\.doc/, "doc"],
|
|
34
45
|
[/spreadsheetml|ms-excel|\.xls/, "xls"],
|
|
@@ -38,103 +49,103 @@ var D = "data-mes-native-player", O = { [D]: "" }, k = (e) => {
|
|
|
38
49
|
[/plain|rtf/, "text"],
|
|
39
50
|
[/markdown/, "markdown"]
|
|
40
51
|
];
|
|
41
|
-
function
|
|
52
|
+
function F(e) {
|
|
42
53
|
return e.startsWith("video/") ? "video" : e.startsWith("audio/") ? "audio" : e.startsWith("image/") ? "image" : "document";
|
|
43
54
|
}
|
|
44
|
-
function
|
|
45
|
-
let t =
|
|
55
|
+
function I(e) {
|
|
56
|
+
let t = P.find(([t]) => t.test(e));
|
|
46
57
|
return t ? t[1] : "generic";
|
|
47
58
|
}
|
|
48
59
|
//#endregion
|
|
49
60
|
//#region src/components/AttachmentCard/utils/icons.ts
|
|
50
|
-
var
|
|
51
|
-
video:
|
|
52
|
-
audio:
|
|
53
|
-
image:
|
|
54
|
-
document:
|
|
55
|
-
},
|
|
56
|
-
pdf:
|
|
57
|
-
doc:
|
|
58
|
-
xls:
|
|
59
|
-
csv:
|
|
60
|
-
ppt:
|
|
61
|
-
zip:
|
|
62
|
-
text:
|
|
63
|
-
markdown:
|
|
64
|
-
generic:
|
|
61
|
+
var L = {
|
|
62
|
+
video: S,
|
|
63
|
+
audio: x,
|
|
64
|
+
image: v,
|
|
65
|
+
document: d
|
|
66
|
+
}, R = {
|
|
67
|
+
pdf: p,
|
|
68
|
+
doc: u,
|
|
69
|
+
xls: g,
|
|
70
|
+
csv: l,
|
|
71
|
+
ppt: m,
|
|
72
|
+
zip: _,
|
|
73
|
+
text: h,
|
|
74
|
+
markdown: f,
|
|
75
|
+
generic: d
|
|
65
76
|
};
|
|
66
|
-
function
|
|
67
|
-
let t =
|
|
68
|
-
return t === "document" ?
|
|
77
|
+
function z(e) {
|
|
78
|
+
let t = F(e);
|
|
79
|
+
return t === "document" ? R[I(e)] : L[t];
|
|
69
80
|
}
|
|
70
|
-
function
|
|
71
|
-
let t =
|
|
72
|
-
return t === "document" ?
|
|
81
|
+
function B(e) {
|
|
82
|
+
let t = F(e);
|
|
83
|
+
return t === "document" ? I(e) : t;
|
|
73
84
|
}
|
|
74
|
-
function
|
|
75
|
-
return e.createElement(
|
|
76
|
-
"data-testid": `type-icon-${
|
|
85
|
+
function V(t, n) {
|
|
86
|
+
return e.createElement(z(t), {
|
|
87
|
+
"data-testid": `type-icon-${B(t)}`,
|
|
77
88
|
...n
|
|
78
89
|
});
|
|
79
90
|
}
|
|
80
91
|
//#endregion
|
|
81
92
|
//#region src/utils/isDevBuild.ts
|
|
82
|
-
function
|
|
93
|
+
function H() {
|
|
83
94
|
return !1;
|
|
84
95
|
}
|
|
85
96
|
//#endregion
|
|
86
97
|
//#region src/components/AttachmentCard/MediaPlayer.tsx
|
|
87
|
-
var
|
|
88
|
-
let
|
|
89
|
-
|
|
98
|
+
var U = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.clientX ?? 0 : e.clientX, W = ({ source: e, mimeType: s, poster: c, autoPlay: l = !1, playing: u, loop: d = !1, controls: f = !0, showProgress: p = !1, muted: m = !1, onContainerClick: h }) => {
|
|
99
|
+
let g = F(s), _ = r(null), v = r(null), x = r(null), S = r(u), [C, w] = i(l), [E, D] = i(0), [O, k] = i(!1), [A, j] = i(!1), [N, P] = i(!1), [I, L] = i(!1), [R, z] = i(!0), [B, W] = i(null), G = t(() => {
|
|
100
|
+
P(!1), w(!0);
|
|
90
101
|
}, []), K = t((e) => {
|
|
91
|
-
let t =
|
|
102
|
+
let t = v.current;
|
|
92
103
|
if (!t) return 0;
|
|
93
104
|
let n = t.getBoundingClientRect();
|
|
94
|
-
return Math.max(0, Math.min(1, (
|
|
105
|
+
return Math.max(0, Math.min(1, (U(e) - n.left) / n.width));
|
|
95
106
|
}, []), q = t((e) => {
|
|
96
|
-
let t =
|
|
107
|
+
let t = _.current;
|
|
97
108
|
t && t.duration && (t.currentTime = e * t.duration);
|
|
98
109
|
}, []), J = (e) => {
|
|
99
|
-
e.stopPropagation(),
|
|
110
|
+
e.stopPropagation(), k(!0);
|
|
100
111
|
let t = K(e);
|
|
101
112
|
D(t), q(t);
|
|
102
113
|
}, Y = t((e) => {
|
|
103
114
|
e.key === "ArrowRight" && q(Math.min(1, E + .05)), e.key === "ArrowLeft" && q(Math.max(0, E - .05));
|
|
104
115
|
}, [q, E]);
|
|
105
116
|
n(() => {
|
|
106
|
-
|
|
107
|
-
}, [
|
|
108
|
-
if (!
|
|
109
|
-
|
|
117
|
+
u !== void 0 && u !== S.current && (S.current = u, w(u));
|
|
118
|
+
}, [u]), n(() => {
|
|
119
|
+
if (!C) {
|
|
120
|
+
x.current !== null && (cancelAnimationFrame(x.current), x.current = null);
|
|
110
121
|
return;
|
|
111
122
|
}
|
|
112
123
|
let e = () => {
|
|
113
|
-
let t =
|
|
114
|
-
t && t.duration && !
|
|
124
|
+
let t = _.current;
|
|
125
|
+
t && t.duration && !O && D(t.currentTime / t.duration), x.current = requestAnimationFrame(e);
|
|
115
126
|
};
|
|
116
|
-
return
|
|
117
|
-
|
|
127
|
+
return x.current = requestAnimationFrame(e), () => {
|
|
128
|
+
x.current !== null && cancelAnimationFrame(x.current);
|
|
118
129
|
};
|
|
119
|
-
}, [
|
|
120
|
-
let e =
|
|
121
|
-
e && (
|
|
122
|
-
|
|
130
|
+
}, [C, O]), n(() => {
|
|
131
|
+
let e = _.current;
|
|
132
|
+
e && (C ? e.play().catch((e) => {
|
|
133
|
+
w(!1), P(!0), H() && console.debug("[MediaPlayer] play() failed", e);
|
|
123
134
|
}) : e.pause());
|
|
124
|
-
}, [
|
|
125
|
-
if (!
|
|
135
|
+
}, [C]), n(() => {
|
|
136
|
+
if (!O) return;
|
|
126
137
|
let e = (e) => D(K(e)), t = (e) => {
|
|
127
|
-
|
|
138
|
+
k(!1), q(K(e));
|
|
128
139
|
};
|
|
129
140
|
return window.addEventListener("mousemove", e), window.addEventListener("mouseup", t), window.addEventListener("touchmove", e, { passive: !0 }), window.addEventListener("touchend", t), () => {
|
|
130
141
|
window.removeEventListener("mousemove", e), window.removeEventListener("mouseup", t), window.removeEventListener("touchmove", e), window.removeEventListener("touchend", t);
|
|
131
142
|
};
|
|
132
143
|
}, [
|
|
133
|
-
|
|
144
|
+
O,
|
|
134
145
|
K,
|
|
135
146
|
q
|
|
136
147
|
]);
|
|
137
|
-
let X =
|
|
148
|
+
let X = B ? { aspectRatio: String(B) } : void 0, Z = B ? "" : " aspect-video", Q = Math.round(E * 100);
|
|
138
149
|
return /* @__PURE__ */ o("div", {
|
|
139
150
|
role: "button",
|
|
140
151
|
tabIndex: 0,
|
|
@@ -142,96 +153,96 @@ var z = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.cl
|
|
|
142
153
|
className: `relative cursor-pointer overflow-hidden bg-black ${Z}`,
|
|
143
154
|
style: X,
|
|
144
155
|
onClick: (e) => {
|
|
145
|
-
if (
|
|
146
|
-
|
|
156
|
+
if (h) {
|
|
157
|
+
h(e);
|
|
147
158
|
return;
|
|
148
159
|
}
|
|
149
|
-
|
|
160
|
+
N || f && w((e) => !e);
|
|
150
161
|
},
|
|
151
162
|
onKeyDown: (e) => {
|
|
152
163
|
if (e.key === "Enter" || e.key === " ") {
|
|
153
|
-
if (e.preventDefault(),
|
|
154
|
-
|
|
164
|
+
if (e.preventDefault(), h) {
|
|
165
|
+
h(e);
|
|
155
166
|
return;
|
|
156
167
|
}
|
|
157
|
-
|
|
168
|
+
N || f && w((e) => !e);
|
|
158
169
|
}
|
|
159
170
|
},
|
|
160
171
|
children: [
|
|
161
|
-
|
|
162
|
-
src:
|
|
172
|
+
c && (g === "audio" || R) && /* @__PURE__ */ a("img", {
|
|
173
|
+
src: c,
|
|
163
174
|
alt: "",
|
|
164
175
|
"data-testid": "media-player-poster",
|
|
165
176
|
className: "absolute inset-0 h-full w-full object-cover"
|
|
166
177
|
}),
|
|
167
|
-
!
|
|
178
|
+
!c && (g === "audio" || R) && /* @__PURE__ */ a("div", {
|
|
168
179
|
"data-testid": "media-player-placeholder",
|
|
169
180
|
className: "absolute inset-0 flex items-center justify-center",
|
|
170
|
-
children:
|
|
181
|
+
children: V(s, {
|
|
171
182
|
className: "size-12 text-black/20",
|
|
172
183
|
weight: "regular"
|
|
173
184
|
})
|
|
174
185
|
}),
|
|
175
186
|
/* @__PURE__ */ a("div", {
|
|
176
187
|
className: "absolute inset-0",
|
|
177
|
-
children:
|
|
178
|
-
...
|
|
179
|
-
ref:
|
|
188
|
+
children: g === "audio" ? /* @__PURE__ */ a("audio", {
|
|
189
|
+
...M,
|
|
190
|
+
ref: _,
|
|
180
191
|
"data-testid": "media-player-audio",
|
|
181
192
|
src: e,
|
|
182
|
-
loop:
|
|
183
|
-
muted:
|
|
193
|
+
loop: d,
|
|
194
|
+
muted: m,
|
|
184
195
|
style: {
|
|
185
196
|
width: "100%",
|
|
186
197
|
height: "100%"
|
|
187
198
|
},
|
|
188
|
-
onLoadStart: () =>
|
|
199
|
+
onLoadStart: () => L(!0),
|
|
189
200
|
onCanPlay: () => {
|
|
190
|
-
|
|
201
|
+
L(!1), z(!1);
|
|
191
202
|
},
|
|
192
|
-
onWaiting: () =>
|
|
193
|
-
onPlay: () =>
|
|
203
|
+
onWaiting: () => L(!0),
|
|
204
|
+
onPlay: () => P(!1),
|
|
194
205
|
onEnded: () => {
|
|
195
|
-
|
|
206
|
+
d || (w(!1), D(0));
|
|
196
207
|
},
|
|
197
208
|
children: /* @__PURE__ */ a("track", { kind: "captions" })
|
|
198
209
|
}) : /* @__PURE__ */ a("video", {
|
|
199
|
-
ref:
|
|
210
|
+
ref: _,
|
|
200
211
|
"data-testid": "media-player-video",
|
|
201
212
|
src: e,
|
|
202
|
-
loop:
|
|
203
|
-
muted:
|
|
213
|
+
loop: d,
|
|
214
|
+
muted: m,
|
|
204
215
|
playsInline: !0,
|
|
205
216
|
style: {
|
|
206
217
|
width: "100%",
|
|
207
218
|
height: "100%"
|
|
208
219
|
},
|
|
209
|
-
onLoadStart: () =>
|
|
220
|
+
onLoadStart: () => L(!0),
|
|
210
221
|
onCanPlay: () => {
|
|
211
|
-
|
|
222
|
+
L(!1), z(!1);
|
|
212
223
|
},
|
|
213
|
-
onWaiting: () =>
|
|
214
|
-
onPlay: () =>
|
|
224
|
+
onWaiting: () => L(!0),
|
|
225
|
+
onPlay: () => P(!1),
|
|
215
226
|
onLoadedMetadata: () => {
|
|
216
|
-
let e =
|
|
227
|
+
let e = _.current;
|
|
217
228
|
e instanceof HTMLVideoElement && e.videoWidth && e.videoHeight && W(e.videoWidth / e.videoHeight);
|
|
218
229
|
},
|
|
219
230
|
onEnded: () => {
|
|
220
|
-
|
|
231
|
+
d || (w(!1), D(0));
|
|
221
232
|
},
|
|
222
233
|
children: /* @__PURE__ */ a("track", { kind: "captions" })
|
|
223
234
|
})
|
|
224
235
|
}),
|
|
225
|
-
I && !
|
|
236
|
+
I && !N && /* @__PURE__ */ a("div", {
|
|
226
237
|
role: "status",
|
|
227
238
|
"aria-label": "Loading media",
|
|
228
239
|
className: "absolute inset-0 z-10 flex items-center justify-center",
|
|
229
|
-
children: /* @__PURE__ */ a(
|
|
230
|
-
|
|
231
|
-
|
|
240
|
+
children: /* @__PURE__ */ a(T, {
|
|
241
|
+
size: "lg",
|
|
242
|
+
tone: "on-media"
|
|
232
243
|
})
|
|
233
244
|
}),
|
|
234
|
-
|
|
245
|
+
N && !f && /* @__PURE__ */ a("div", {
|
|
235
246
|
className: "absolute inset-0 z-30 flex cursor-pointer items-center justify-center bg-black/35",
|
|
236
247
|
role: "button",
|
|
237
248
|
tabIndex: 0,
|
|
@@ -244,13 +255,13 @@ var z = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.cl
|
|
|
244
255
|
},
|
|
245
256
|
children: /* @__PURE__ */ a("span", {
|
|
246
257
|
className: "flex size-16 items-center justify-center rounded-full bg-white/20 text-white backdrop-blur-sm",
|
|
247
|
-
children: /* @__PURE__ */ a(
|
|
258
|
+
children: /* @__PURE__ */ a(b, {
|
|
248
259
|
className: "size-9 translate-x-0.5",
|
|
249
260
|
weight: "fill"
|
|
250
261
|
})
|
|
251
262
|
})
|
|
252
263
|
}),
|
|
253
|
-
|
|
264
|
+
p && !f && /* @__PURE__ */ a("div", {
|
|
254
265
|
className: "absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent",
|
|
255
266
|
children: /* @__PURE__ */ a("div", {
|
|
256
267
|
role: "slider",
|
|
@@ -259,7 +270,7 @@ var z = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.cl
|
|
|
259
270
|
"aria-valuemin": 0,
|
|
260
271
|
"aria-valuemax": 100,
|
|
261
272
|
tabIndex: 0,
|
|
262
|
-
ref:
|
|
273
|
+
ref: v,
|
|
263
274
|
className: "relative flex h-4 w-full cursor-pointer items-center",
|
|
264
275
|
onMouseDown: J,
|
|
265
276
|
onTouchStart: J,
|
|
@@ -274,19 +285,19 @@ var z = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.cl
|
|
|
274
285
|
})
|
|
275
286
|
})
|
|
276
287
|
}),
|
|
277
|
-
|
|
288
|
+
f && /* @__PURE__ */ o("div", {
|
|
278
289
|
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",
|
|
279
290
|
children: [/* @__PURE__ */ a("button", {
|
|
280
291
|
type: "button",
|
|
281
292
|
onClick: (e) => {
|
|
282
|
-
e.stopPropagation(),
|
|
293
|
+
e.stopPropagation(), w((e) => !e);
|
|
283
294
|
},
|
|
284
295
|
className: "shrink-0 text-white",
|
|
285
|
-
"aria-label":
|
|
286
|
-
children:
|
|
296
|
+
"aria-label": C ? "Pause" : "Play",
|
|
297
|
+
children: C ? /* @__PURE__ */ a(y, {
|
|
287
298
|
className: "size-5",
|
|
288
299
|
weight: "fill"
|
|
289
|
-
}) : /* @__PURE__ */ a(
|
|
300
|
+
}) : /* @__PURE__ */ a(b, {
|
|
290
301
|
className: "size-5 translate-x-px",
|
|
291
302
|
weight: "fill"
|
|
292
303
|
})
|
|
@@ -297,39 +308,39 @@ var z = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.cl
|
|
|
297
308
|
"aria-valuemin": 0,
|
|
298
309
|
"aria-valuemax": 100,
|
|
299
310
|
tabIndex: 0,
|
|
300
|
-
ref:
|
|
311
|
+
ref: v,
|
|
301
312
|
className: "relative flex h-4 w-full cursor-pointer items-center",
|
|
302
313
|
onMouseDown: J,
|
|
303
314
|
onTouchStart: J,
|
|
304
315
|
onClick: (e) => e.stopPropagation(),
|
|
305
|
-
onMouseEnter: () =>
|
|
306
|
-
onMouseLeave: () =>
|
|
316
|
+
onMouseEnter: () => j(!0),
|
|
317
|
+
onMouseLeave: () => j(!1),
|
|
307
318
|
onKeyDown: Y,
|
|
308
319
|
children: [/* @__PURE__ */ a("div", {
|
|
309
|
-
className: `w-full overflow-hidden rounded-full bg-white/30 transition-all duration-200 ${
|
|
320
|
+
className: `w-full overflow-hidden rounded-full bg-white/30 transition-all duration-200 ${A || O ? "h-1.5" : "h-1"}`,
|
|
310
321
|
children: /* @__PURE__ */ a("div", {
|
|
311
322
|
className: "h-full rounded-full bg-white",
|
|
312
323
|
style: { width: `${Q}%` }
|
|
313
324
|
})
|
|
314
325
|
}), /* @__PURE__ */ a("div", {
|
|
315
326
|
"data-testid": "media-player-scrubber-thumb",
|
|
316
|
-
className: `absolute size-3 -translate-x-1/2 rounded-full bg-white shadow transition-[opacity,transform] duration-200 ${
|
|
327
|
+
className: `absolute size-3 -translate-x-1/2 rounded-full bg-white shadow transition-[opacity,transform] duration-200 ${A || O ? "scale-100 opacity-100" : "scale-0 opacity-0"}`,
|
|
317
328
|
style: { left: `${Q}%` }
|
|
318
329
|
})]
|
|
319
330
|
})]
|
|
320
331
|
})
|
|
321
332
|
]
|
|
322
333
|
});
|
|
323
|
-
},
|
|
324
|
-
let l =
|
|
325
|
-
return t && (l === "video" || l === "audio") ? /* @__PURE__ */ a(
|
|
334
|
+
}, G = (e) => e === "dark" ? "size-12 text-white/20" : "size-12 text-black/20", K = (e) => e === "dark" ? "aspect-video overflow-hidden bg-white/10" : "aspect-video overflow-hidden bg-black/5", q = ({ mimeType: e, sourceUrl: t, thumbnailUrl: n, title: r, variant: o, mediaPlayerProps: s, containedImage: c = !1 }) => {
|
|
335
|
+
let l = F(e), [u, d] = i(!1), f = A(t), p = A(n);
|
|
336
|
+
return t && (l === "video" || l === "audio") ? /* @__PURE__ */ a(W, {
|
|
326
337
|
source: t,
|
|
327
338
|
mimeType: e,
|
|
328
339
|
poster: p,
|
|
329
340
|
controls: !0,
|
|
330
341
|
...s
|
|
331
342
|
}) : t && l === "image" ? c ? /* @__PURE__ */ a("div", {
|
|
332
|
-
className: `relative ${
|
|
343
|
+
className: `relative ${K(o)}`,
|
|
333
344
|
children: /* @__PURE__ */ a("img", {
|
|
334
345
|
src: f ?? t,
|
|
335
346
|
alt: r ?? "",
|
|
@@ -343,7 +354,7 @@ var z = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.cl
|
|
|
343
354
|
className: "block w-full",
|
|
344
355
|
draggable: !1
|
|
345
356
|
}) : t && l === "document" ? n ? c ? /* @__PURE__ */ a("div", {
|
|
346
|
-
className: `relative ${
|
|
357
|
+
className: `relative ${K(o)}`,
|
|
347
358
|
children: /* @__PURE__ */ a("img", {
|
|
348
359
|
src: p ?? n,
|
|
349
360
|
alt: r ?? "",
|
|
@@ -358,12 +369,12 @@ var z = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.cl
|
|
|
358
369
|
draggable: !1
|
|
359
370
|
}) : /* @__PURE__ */ a("div", {
|
|
360
371
|
className: `flex aspect-video w-full items-center justify-center ${o === "dark" ? "bg-white/10" : "bg-black/5"}`,
|
|
361
|
-
children:
|
|
362
|
-
className:
|
|
372
|
+
children: V(e, {
|
|
373
|
+
className: G(o),
|
|
363
374
|
weight: "regular"
|
|
364
375
|
})
|
|
365
376
|
}) : n ? /* @__PURE__ */ a("div", {
|
|
366
|
-
className: `relative ${
|
|
377
|
+
className: `relative ${K(o)}`,
|
|
367
378
|
children: /* @__PURE__ */ a("img", {
|
|
368
379
|
src: p ?? n,
|
|
369
380
|
alt: r ?? "",
|
|
@@ -372,13 +383,13 @@ var z = (e) => "touches" in e ? e.touches[0]?.clientX ?? e.changedTouches[0]?.cl
|
|
|
372
383
|
})
|
|
373
384
|
}) : /* @__PURE__ */ a("div", {
|
|
374
385
|
className: `flex aspect-video w-full items-center justify-center ${o === "dark" ? "bg-white/10" : "bg-black/5"}`,
|
|
375
|
-
children:
|
|
376
|
-
className:
|
|
386
|
+
children: V(e, {
|
|
387
|
+
className: G(o),
|
|
377
388
|
weight: "regular"
|
|
378
389
|
})
|
|
379
390
|
});
|
|
380
391
|
};
|
|
381
392
|
//#endregion
|
|
382
|
-
export {
|
|
393
|
+
export { M as a, T as c, F as i, V as n, N as o, I as r, A as s, q as t };
|
|
383
394
|
|
|
384
|
-
//# sourceMappingURL=AttachmentCard-
|
|
395
|
+
//# sourceMappingURL=AttachmentCard-BaZk77fe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttachmentCard-BaZk77fe.js","names":[],"sources":["../src/components/_shared/Spinner.tsx","../src/utils/cdnImageUrl.ts","../src/utils/nativeMediaPlayers.ts","../src/components/AttachmentCard/utils/mimeType.ts","../src/components/AttachmentCard/utils/icons.ts","../src/utils/isDevBuild.ts","../src/components/AttachmentCard/MediaPlayer.tsx","../src/components/AttachmentCard/Thumbnail.tsx"],"sourcesContent":["import {\n CircleNotchIcon,\n type Icon,\n type IconWeight,\n} from '@phosphor-icons/react'\nimport classNames from 'classnames'\n\nconst sizeClasses = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-8',\n} as const\n\nconst toneClasses = {\n inherit: undefined,\n 'on-media': 'text-white/80',\n} as const\n\nexport interface SpinnerProps {\n /** `sm` = 16px, `md` = 20px, `lg` = 32px. Defaults to `sm`. */\n size?: keyof typeof sizeClasses\n /** `on-media` is the translucent white used over dark media chrome. */\n tone?: keyof typeof toneClasses\n /** Phosphor icon to spin. Defaults to `CircleNotchIcon`. */\n icon?: Icon\n weight?: IconWeight\n 'aria-hidden'?: boolean\n className?: string\n}\n\nconst Spinner = ({\n size = 'sm',\n tone = 'inherit',\n icon: IconComponent = CircleNotchIcon,\n weight = 'bold',\n 'aria-hidden': ariaHidden,\n className,\n}: SpinnerProps) => (\n <IconComponent\n className={classNames(\n 'animate-spin',\n sizeClasses[size],\n toneClasses[tone],\n className\n )}\n weight={weight}\n aria-hidden={ariaHidden}\n />\n)\n\nexport default Spinner\n","const LINKTREE_CDN_HOSTS = ['linktr.ee']\n\nconst ATTACHMENT_IMAGE_SIZE_PRESET = 'messaging-attachment-v1_0'\n\nfunction hostnameFromUrl(url: string): string | null {\n try {\n return new URL(url).hostname.toLowerCase()\n } catch {\n return null\n }\n}\n\nfunction isLinktreeCdnHost(hostname: string): boolean {\n return LINKTREE_CDN_HOSTS.some(\n (host) => hostname === host || hostname.endsWith(`.${host}`)\n )\n}\n\nexport function optimizeMessagingAttachmentUrl(\n url: string | undefined | null\n): string | undefined {\n const trimmed = url?.trim()\n if (!trimmed) return undefined\n\n const hostname = hostnameFromUrl(trimmed)\n if (!hostname || !isLinktreeCdnHost(hostname)) return trimmed\n\n const parsedUrl = new URL(trimmed)\n const isAlreadyMessagingOptimized =\n parsedUrl.searchParams.get('io') === 'true' &&\n parsedUrl.searchParams.get('size') === ATTACHMENT_IMAGE_SIZE_PRESET\n\n if (isAlreadyMessagingOptimized) {\n return trimmed\n }\n\n parsedUrl.searchParams.set('io', 'true')\n parsedUrl.searchParams.set('size', ATTACHMENT_IMAGE_SIZE_PRESET)\n\n return parsedUrl.toString()\n}\n","/**\n * Attribute marking every native `<audio>` / `<video>` the toolkit\n * renders on a message surface, so opening one player can silence the\n * others.\n *\n * stream-chat-react's `AudioPlayerPool` — what `useActiveAudioPlayer()`\n * reads — only knows the players *it* mounts, i.e. voice recordings.\n * Everything the toolkit draws itself is a plain native element that\n * never registers there: `MessageAttachment.Audio`, a playable\n * `LinkAttachment` card, and `AttachmentCard`'s `MediaPlayer`. Pausing\n * the pool alone therefore left thread audio sounding underneath an\n * opened video viewer on the production `StreamAttachmentMessage` path,\n * which is exactly the surface the mutual exclusion exists for\n * (MES-1353).\n */\nexport const NATIVE_PLAYER_ATTRIBUTE = 'data-mes-native-player'\n\n/**\n * Spread onto a native player element to enrol it. Keyed off the\n * constant so the marker and the query below can't drift apart.\n */\nexport const nativePlayerProps = { [NATIVE_PLAYER_ATTRIBUTE]: '' } as const\n\n/**\n * Pauses every enrolled player except `except`.\n *\n * No `paused` check: pausing an already-paused element is a no-op per\n * spec, and reading `paused` first would only add a branch that jsdom\n * answers differently from a browser.\n */\nexport const pauseNativeMediaPlayers = (\n except?: HTMLMediaElement | null\n): void => {\n if (typeof document === 'undefined') return\n\n document\n .querySelectorAll<HTMLMediaElement>(`[${NATIVE_PLAYER_ATTRIBUTE}]`)\n .forEach((player) => {\n if (player !== except) player.pause()\n })\n}\n","export type AttachmentSourceType = 'image' | 'audio' | 'video' | 'document'\n\nexport type DocumentIconType =\n | 'pdf'\n | 'doc'\n | 'xls'\n | 'csv'\n | 'ppt'\n | 'zip'\n | 'text'\n | 'markdown'\n | 'generic'\n\nconst DOCUMENT_ICON_PATTERNS: Array<[RegExp, DocumentIconType]> = [\n [/pdf/, 'pdf'],\n [/wordprocessingml|msword|\\.doc/, 'doc'],\n [/spreadsheetml|ms-excel|\\.xls/, 'xls'],\n [/csv/, 'csv'],\n [/presentationml|ms-powerpoint|\\.ppt/, 'ppt'],\n [/zip|x-rar|x-7z|x-tar|x-gzip/, 'zip'],\n [/plain|rtf/, 'text'],\n [/markdown/, 'markdown'],\n]\n\nexport function getSourceType(mimeType: string): AttachmentSourceType {\n if (mimeType.startsWith('video/')) return 'video'\n if (mimeType.startsWith('audio/')) return 'audio'\n if (mimeType.startsWith('image/')) return 'image'\n return 'document'\n}\n\nexport function getDocumentIconType(mimeType: string): DocumentIconType {\n const match = DOCUMENT_ICON_PATTERNS.find(([pattern]) =>\n pattern.test(mimeType)\n )\n return match ? match[1] : 'generic'\n}\n","import {\n FileIcon,\n FileCsvIcon,\n FileDocIcon,\n FileMdIcon,\n FilePdfIcon,\n FilePptIcon,\n FileTextIcon,\n FileXlsIcon,\n FileZipIcon,\n ImageIcon,\n SpeakerHighIcon,\n VideoCameraIcon,\n IconProps,\n} from '@phosphor-icons/react'\nimport React from 'react'\n\nimport { getDocumentIconType, getSourceType } from './mimeType'\nimport type { AttachmentSourceType } from './mimeType'\n\nconst MEDIA_TYPE_ICON: Record<AttachmentSourceType, React.ElementType> = {\n video: VideoCameraIcon,\n audio: SpeakerHighIcon,\n image: ImageIcon,\n document: FileIcon,\n}\n\nconst DOCUMENT_ICON_COMPONENT = {\n pdf: FilePdfIcon,\n doc: FileDocIcon,\n xls: FileXlsIcon,\n csv: FileCsvIcon,\n ppt: FilePptIcon,\n zip: FileZipIcon,\n text: FileTextIcon,\n markdown: FileMdIcon,\n generic: FileIcon,\n} as const\n\nfunction getTypeIcon(mimeType: string): React.ElementType {\n const sourceType = getSourceType(mimeType)\n if (sourceType !== 'document') return MEDIA_TYPE_ICON[sourceType]\n return DOCUMENT_ICON_COMPONENT[getDocumentIconType(mimeType)]\n}\n\nfunction getTypeIconName(mimeType: string): string {\n const sourceType = getSourceType(mimeType)\n if (sourceType !== 'document') return sourceType\n return getDocumentIconType(mimeType)\n}\n\n/** Use instead of `<TypeIcon />` where TypeIcon = getTypeIcon(mime) to satisfy react-hooks/static-components. */\nexport function renderTypeIcon(\n mimeType: string,\n props: IconProps\n): React.ReactElement {\n // Decorative icons: which one was picked is otherwise only visible in a pixel diff.\n return React.createElement(getTypeIcon(mimeType), {\n 'data-testid': `type-icon-${getTypeIconName(mimeType)}`,\n ...props,\n })\n}\n","/**\n * True in Vite dev builds (`import.meta.env.DEV`). Uses a type assertion so\n * `tsc` does not rely on ambient `ImportMeta` merging (vite/client).\n */\nexport function isDevBuild(): boolean {\n return (\n typeof import.meta !== 'undefined' &&\n (import.meta as unknown as { env?: { DEV?: boolean } }).env?.DEV === true\n )\n}\n","import { PauseIcon, PlayIcon } from '@phosphor-icons/react'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport { isDevBuild } from '../../utils/isDevBuild'\nimport { nativePlayerProps } from '../../utils/nativeMediaPlayers'\nimport Spinner from '../_shared/Spinner'\n\nimport { renderTypeIcon } from './utils/icons'\nimport { getSourceType } from './utils/mimeType'\n\ntype TouchEventUnion =\n MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent\n\nconst getClientXFromEvent = (e: TouchEventUnion): number => {\n if ('touches' in e) {\n return e.touches[0]?.clientX ?? e.changedTouches[0]?.clientX ?? 0\n }\n return e.clientX\n}\n\nexport interface MediaPlayerProps {\n source: string\n mimeType: string\n poster?: string\n autoPlay?: boolean\n /** Controlled playing state. When provided, syncs to internal play/pause. */\n playing?: boolean\n loop?: boolean\n controls?: boolean\n showProgress?: boolean\n /** When true, requests muted playback (helps autoplay policies on video). */\n muted?: boolean\n /**\n * When provided, overrides the default click-to-play-toggle behaviour on the\n * player container. The play/pause button (which calls stopPropagation) is\n * unaffected, so inline playback still works.\n */\n onContainerClick?: (e: React.MouseEvent) => void\n}\n\nconst MediaPlayer: React.FC<MediaPlayerProps> = ({\n source,\n mimeType,\n poster,\n autoPlay = false,\n playing: playingProp,\n loop = false,\n controls = true,\n showProgress = false,\n muted = false,\n onContainerClick,\n}) => {\n // --- Derived ---\n const sourceType = getSourceType(mimeType)\n\n // --- Refs ---\n const playerRef = useRef<HTMLMediaElement>(null)\n const trackRef = useRef<HTMLDivElement>(null)\n const rafRef = useRef<number | null>(null)\n const prevPlayingPropRef = useRef(playingProp)\n\n // --- State: playback ---\n const [playing, setPlaying] = useState(autoPlay)\n const [played, setPlayed] = useState(0)\n const [seeking, setSeeking] = useState(false)\n\n // --- State: UI ---\n const [scrubberHovered, setScrubberHovered] = useState(false)\n /** Set when autoplay/play() was rejected so user can start via gesture (no controls UI). */\n const [manualPlayRequired, setManualPlayRequired] = useState(false)\n\n // --- State: loading ---\n const [buffering, setBuffering] = useState(false)\n /** True until the first canPlay fires for the current source — hides controls/spinner behind poster. */\n const [initialLoad, setInitialLoad] = useState(true)\n const [videoAspect, setVideoAspect] = useState<number | null>(null)\n\n // --- Callbacks ---\n const startPlaybackFromGesture = useCallback(() => {\n setManualPlayRequired(false)\n setPlaying(true)\n }, [])\n\n const getFraction = useCallback((e: TouchEventUnion) => {\n const track = trackRef.current\n if (!track) return 0\n const rect = track.getBoundingClientRect()\n return Math.max(\n 0,\n Math.min(1, (getClientXFromEvent(e) - rect.left) / rect.width)\n )\n }, [])\n\n const seekTo = useCallback((fraction: number) => {\n const el = playerRef.current\n if (el && el.duration) el.currentTime = fraction * el.duration\n }, [])\n\n const handleTrackPointerDown = (\n e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>\n ) => {\n e.stopPropagation()\n setSeeking(true)\n const fraction = getFraction(e)\n setPlayed(fraction)\n seekTo(fraction)\n }\n\n const handleScrubberKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))\n if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))\n },\n [seekTo, played]\n )\n\n // --- Effects ---\n\n // Sync controlled playing prop to internal state\n useEffect(() => {\n if (\n playingProp !== undefined &&\n playingProp !== prevPlayingPropRef.current\n ) {\n prevPlayingPropRef.current = playingProp\n setPlaying(playingProp)\n }\n }, [playingProp])\n\n // RAF-driven progress updates\n useEffect(() => {\n if (!playing) {\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current)\n rafRef.current = null\n }\n return\n }\n const tick = () => {\n const el = playerRef.current\n if (el && el.duration && !seeking) setPlayed(el.currentTime / el.duration)\n rafRef.current = requestAnimationFrame(tick)\n }\n rafRef.current = requestAnimationFrame(tick)\n return () => {\n if (rafRef.current !== null) cancelAnimationFrame(rafRef.current)\n }\n }, [playing, seeking])\n\n // ReactPlayer v3 uses native HTML media elements and does not support a\n // declarative `playing` prop — playback must be driven imperatively.\n useEffect(() => {\n const el = playerRef.current\n if (!el) return\n if (playing) {\n void el.play().catch((err) => {\n setPlaying(false)\n setManualPlayRequired(true)\n if (isDevBuild()) {\n console.debug('[MediaPlayer] play() failed', err)\n }\n })\n } else {\n el.pause()\n }\n }, [playing])\n\n // Global seeking listeners\n useEffect(() => {\n if (!seeking) return\n const onMove = (e: MouseEvent | TouchEvent) => setPlayed(getFraction(e))\n const onUp = (e: MouseEvent | TouchEvent) => {\n setSeeking(false)\n seekTo(getFraction(e))\n }\n window.addEventListener('mousemove', onMove)\n window.addEventListener('mouseup', onUp)\n window.addEventListener('touchmove', onMove, { passive: true })\n window.addEventListener('touchend', onUp)\n return () => {\n window.removeEventListener('mousemove', onMove)\n window.removeEventListener('mouseup', onUp)\n window.removeEventListener('touchmove', onMove)\n window.removeEventListener('touchend', onUp)\n }\n }, [seeking, getFraction, seekTo])\n\n // --- Derived render values ---\n // Use natural aspect ratio once metadata loads, fall back to 16:9 before then.\n const aspectStyle = videoAspect\n ? { aspectRatio: String(videoAspect) }\n : undefined\n const aspectClass = !videoAspect ? ' aspect-video' : ''\n const scrubberPercent = Math.round(played * 100)\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n data-testid=\"media-player\"\n className={`relative cursor-pointer overflow-hidden bg-black ${aspectClass}`}\n style={aspectStyle}\n onClick={(e) => {\n if (onContainerClick) {\n onContainerClick(e)\n return\n }\n if (manualPlayRequired) return\n if (controls) setPlaying((p) => !p)\n }}\n onKeyDown={(e) => {\n if (e.key !== 'Enter' && e.key !== ' ') return\n e.preventDefault()\n if (onContainerClick) {\n onContainerClick(e as unknown as React.MouseEvent)\n return\n }\n if (manualPlayRequired) return\n if (controls) setPlaying((p) => !p)\n }}\n >\n {/* For audio, poster persists as a visual background. For video, hide once loaded. */}\n {poster && (sourceType === 'audio' || initialLoad) && (\n <img\n src={poster}\n alt=\"\"\n data-testid=\"media-player-poster\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n )}\n {!poster && (sourceType === 'audio' || initialLoad) && (\n <div\n data-testid=\"media-player-placeholder\"\n className=\"absolute inset-0 flex items-center justify-center\"\n >\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n <div className=\"absolute inset-0\">\n {sourceType === 'audio' ? (\n <audio\n {...nativePlayerProps}\n ref={playerRef as React.RefObject<HTMLAudioElement>}\n data-testid=\"media-player-audio\"\n src={source}\n loop={loop}\n muted={muted}\n style={{ width: '100%', height: '100%' }}\n onLoadStart={() => setBuffering(true)}\n onCanPlay={() => {\n setBuffering(false)\n setInitialLoad(false)\n }}\n onWaiting={() => setBuffering(true)}\n onPlay={() => setManualPlayRequired(false)}\n onEnded={() => {\n if (!loop) {\n setPlaying(false)\n setPlayed(0)\n }\n }}\n >\n <track kind=\"captions\" />\n </audio>\n ) : (\n <video\n ref={playerRef as React.RefObject<HTMLVideoElement>}\n data-testid=\"media-player-video\"\n src={source}\n loop={loop}\n muted={muted}\n playsInline\n style={{ width: '100%', height: '100%' }}\n onLoadStart={() => setBuffering(true)}\n onCanPlay={() => {\n setBuffering(false)\n setInitialLoad(false)\n }}\n onWaiting={() => setBuffering(true)}\n onPlay={() => setManualPlayRequired(false)}\n onLoadedMetadata={() => {\n const el = playerRef.current\n if (\n el instanceof HTMLVideoElement &&\n el.videoWidth &&\n el.videoHeight\n ) {\n setVideoAspect(el.videoWidth / el.videoHeight)\n }\n }}\n onEnded={() => {\n if (!loop) {\n setPlaying(false)\n setPlayed(0)\n }\n }}\n >\n <track kind=\"captions\" />\n </video>\n )}\n </div>\n\n {buffering && !manualPlayRequired && (\n <div\n role=\"status\"\n aria-label=\"Loading media\"\n className=\"absolute inset-0 z-10 flex items-center justify-center\"\n >\n <Spinner size=\"lg\" tone=\"on-media\" />\n </div>\n )}\n\n {manualPlayRequired && !controls && (\n <div\n className=\"absolute inset-0 z-30 flex cursor-pointer items-center justify-center bg-black/35\"\n role=\"button\"\n tabIndex={0}\n aria-label=\"Play preview\"\n onClick={(e) => {\n e.stopPropagation()\n startPlaybackFromGesture()\n }}\n onKeyDown={(e) => {\n if (e.key !== 'Enter' && e.key !== ' ') return\n e.preventDefault()\n e.stopPropagation()\n startPlaybackFromGesture()\n }}\n >\n <span className=\"flex size-16 items-center justify-center rounded-full bg-white/20 text-white backdrop-blur-sm\">\n <PlayIcon className=\"size-9 translate-x-0.5\" weight=\"fill\" />\n </span>\n </div>\n )}\n\n {showProgress && !controls && (\n <div className=\"absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent\">\n <div\n role=\"slider\"\n aria-label=\"Playback position\"\n aria-valuenow={scrubberPercent}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n ref={trackRef}\n className=\"relative flex h-4 w-full cursor-pointer items-center\"\n onMouseDown={handleTrackPointerDown}\n onTouchStart={handleTrackPointerDown}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={handleScrubberKeyDown}\n >\n <div className=\"w-full overflow-hidden rounded-full bg-white/30 h-1\">\n <div\n className=\"h-full rounded-full bg-white\"\n style={{ width: `${scrubberPercent}%` }}\n />\n </div>\n </div>\n </div>\n )}\n\n {controls && (\n <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\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n setPlaying((p) => !p)\n }}\n className=\"shrink-0 text-white\"\n aria-label={playing ? 'Pause' : 'Play'}\n >\n {playing ? (\n <PauseIcon className=\"size-5\" weight=\"fill\" />\n ) : (\n <PlayIcon className=\"size-5 translate-x-px\" weight=\"fill\" />\n )}\n </button>\n\n <div\n role=\"slider\"\n aria-label=\"Playback position\"\n aria-valuenow={scrubberPercent}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n ref={trackRef}\n className=\"relative flex h-4 w-full cursor-pointer items-center\"\n onMouseDown={handleTrackPointerDown}\n onTouchStart={handleTrackPointerDown}\n onClick={(e) => e.stopPropagation()}\n onMouseEnter={() => setScrubberHovered(true)}\n onMouseLeave={() => setScrubberHovered(false)}\n onKeyDown={handleScrubberKeyDown}\n >\n <div\n className={`w-full overflow-hidden rounded-full bg-white/30 transition-all duration-200 ${scrubberHovered || seeking ? 'h-1.5' : 'h-1'}`}\n >\n <div\n className=\"h-full rounded-full bg-white\"\n style={{ width: `${scrubberPercent}%` }}\n />\n </div>\n <div\n data-testid=\"media-player-scrubber-thumb\"\n 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'}`}\n style={{ left: `${scrubberPercent}%` }}\n />\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default MediaPlayer\n","import React, { useState } from 'react'\n\nimport { optimizeMessagingAttachmentUrl } from '../../utils/cdnImageUrl'\n\nimport MediaPlayer, { type MediaPlayerProps } from './MediaPlayer'\nimport { renderTypeIcon } from './utils/icons'\nimport { getSourceType } from './utils/mimeType'\n\nexport type AttachmentThumbnailVariant = 'light' | 'dark'\n\nexport interface AttachmentThumbnailProps {\n mimeType: string\n sourceUrl?: string\n thumbnailUrl?: string\n title?: string\n variant: AttachmentThumbnailVariant\n /** Extra props passed to MediaPlayer when source is video or audio. */\n mediaPlayerProps?: Partial<\n Pick<\n MediaPlayerProps,\n 'autoPlay' | 'loop' | 'muted' | 'controls' | 'onContainerClick'\n >\n >\n /**\n * When true (Visitor unlocked image/document), use aspect-video + object-contain fade-in.\n */\n containedImage?: boolean\n}\n\nconst placeholderIconClass = (variant: AttachmentThumbnailVariant) =>\n variant === 'dark' ? 'size-12 text-white/20' : 'size-12 text-black/20'\n\nconst posterShellClass = (variant: AttachmentThumbnailVariant) =>\n variant === 'dark'\n ? 'aspect-video overflow-hidden bg-white/10'\n : 'aspect-video overflow-hidden bg-black/5'\n\n/**\n * Renders the media preview area for attachment cards (LockedAttachment, MediaMessage).\n * Overlays (dim, lock, eye toggle) are composed by the parent.\n */\nconst AttachmentThumbnail: React.FC<AttachmentThumbnailProps> = ({\n mimeType,\n sourceUrl,\n thumbnailUrl,\n title,\n variant,\n mediaPlayerProps,\n containedImage = false,\n}) => {\n const sourceType = getSourceType(mimeType)\n const [sourceReady, setSourceReady] = useState(false)\n const optimizedSourceUrl = optimizeMessagingAttachmentUrl(sourceUrl)\n const optimizedThumbnailUrl = optimizeMessagingAttachmentUrl(thumbnailUrl)\n\n if (sourceUrl && (sourceType === 'video' || sourceType === 'audio')) {\n return (\n <MediaPlayer\n source={sourceUrl}\n mimeType={mimeType}\n poster={optimizedThumbnailUrl}\n controls\n {...mediaPlayerProps}\n />\n )\n }\n\n if (sourceUrl && sourceType === 'image') {\n if (containedImage) {\n return (\n <div className={`relative ${posterShellClass(variant)}`}>\n <img\n src={optimizedSourceUrl ?? sourceUrl}\n alt={title ?? ''}\n className={`absolute inset-0 h-full w-full object-contain transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}\n draggable={false}\n onLoad={() => setSourceReady(true)}\n />\n </div>\n )\n }\n return (\n <img\n src={optimizedSourceUrl ?? sourceUrl}\n alt={title ?? ''}\n className=\"block w-full\"\n draggable={false}\n />\n )\n }\n\n if (sourceUrl && sourceType === 'document') {\n if (thumbnailUrl) {\n if (containedImage) {\n return (\n <div className={`relative ${posterShellClass(variant)}`}>\n <img\n src={optimizedThumbnailUrl ?? thumbnailUrl}\n alt={title ?? ''}\n className={`absolute inset-0 h-full w-full object-contain transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}\n draggable={false}\n onLoad={() => setSourceReady(true)}\n />\n </div>\n )\n }\n return (\n <img\n src={optimizedThumbnailUrl ?? thumbnailUrl}\n alt=\"\"\n className=\"block w-full\"\n draggable={false}\n />\n )\n }\n return (\n <div\n className={`flex aspect-video w-full items-center justify-center ${variant === 'dark' ? 'bg-white/10' : 'bg-black/5'}`}\n >\n {renderTypeIcon(mimeType, {\n className: placeholderIconClass(variant),\n weight: 'regular',\n })}\n </div>\n )\n }\n\n // Poster-only or empty (no sourceUrl)\n if (thumbnailUrl) {\n return (\n <div className={`relative ${posterShellClass(variant)}`}>\n <img\n src={optimizedThumbnailUrl ?? thumbnailUrl}\n alt={title ?? ''}\n draggable={false}\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n </div>\n )\n }\n\n return (\n <div\n className={`flex aspect-video w-full items-center justify-center ${variant === 'dark' ? 'bg-white/10' : 'bg-black/5'}`}\n >\n {renderTypeIcon(mimeType, {\n className: placeholderIconClass(variant),\n weight: 'regular',\n })}\n </div>\n )\n}\n\nexport default AttachmentThumbnail\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./rolldown-runtime-BocRIvOZ.cjs");let t=require("react");t=e.t(t,1);let n=require("react/jsx-runtime"),r=require("classnames");r=e.t(r,1);let i=require("@phosphor-icons/react");var a={sm:`size-4`,md:`size-5`,lg:`size-8`},o={inherit:void 0,"on-media":`text-white/80`},s=({size:e=`sm`,tone:t=`inherit`,icon:s=i.CircleNotchIcon,weight:c=`bold`,"aria-hidden":l,className:u})=>(0,n.jsx)(s,{className:(0,r.default)(`animate-spin`,a[e],o[t],u),weight:c,"aria-hidden":l}),c=[`linktr.ee`],l=`messaging-attachment-v1_0`;function u(e){try{return new URL(e).hostname.toLowerCase()}catch{return null}}function d(e){return c.some(t=>e===t||e.endsWith(`.${t}`))}function f(e){let t=e?.trim();if(!t)return;let n=u(t);if(!n||!d(n))return t;let r=new URL(t);return r.searchParams.get(`io`)===`true`&&r.searchParams.get(`size`)===l?t:(r.searchParams.set(`io`,`true`),r.searchParams.set(`size`,l),r.toString())}var p=`data-mes-native-player`,m={[p]:``},h=e=>{typeof document>`u`||document.querySelectorAll(`[${p}]`).forEach(t=>{t!==e&&t.pause()})},g=[[/pdf/,`pdf`],[/wordprocessingml|msword|\.doc/,`doc`],[/spreadsheetml|ms-excel|\.xls/,`xls`],[/csv/,`csv`],[/presentationml|ms-powerpoint|\.ppt/,`ppt`],[/zip|x-rar|x-7z|x-tar|x-gzip/,`zip`],[/plain|rtf/,`text`],[/markdown/,`markdown`]];function _(e){return e.startsWith(`video/`)?`video`:e.startsWith(`audio/`)?`audio`:e.startsWith(`image/`)?`image`:`document`}function v(e){let t=g.find(([t])=>t.test(e));return t?t[1]:`generic`}var y={video:i.VideoCameraIcon,audio:i.SpeakerHighIcon,image:i.ImageIcon,document:i.FileIcon},b={pdf:i.FilePdfIcon,doc:i.FileDocIcon,xls:i.FileXlsIcon,csv:i.FileCsvIcon,ppt:i.FilePptIcon,zip:i.FileZipIcon,text:i.FileTextIcon,markdown:i.FileMdIcon,generic:i.FileIcon};function x(e){let t=_(e);return t===`document`?b[v(e)]:y[t]}function S(e){let t=_(e);return t===`document`?v(e):t}function C(e,n){return t.default.createElement(x(e),{"data-testid":`type-icon-${S(e)}`,...n})}function w(){return!1}var T=e=>`touches`in e?e.touches[0]?.clientX??e.changedTouches[0]?.clientX??0:e.clientX,E=({source:e,mimeType:r,poster:a,autoPlay:o=!1,playing:c,loop:l=!1,controls:u=!0,showProgress:d=!1,muted:f=!1,onContainerClick:p})=>{let h=_(r),g=(0,t.useRef)(null),v=(0,t.useRef)(null),y=(0,t.useRef)(null),b=(0,t.useRef)(c),[x,S]=(0,t.useState)(o),[E,D]=(0,t.useState)(0),[O,k]=(0,t.useState)(!1),[A,j]=(0,t.useState)(!1),[M,N]=(0,t.useState)(!1),[P,F]=(0,t.useState)(!1),[I,L]=(0,t.useState)(!0),[R,z]=(0,t.useState)(null),B=(0,t.useCallback)(()=>{N(!1),S(!0)},[]),V=(0,t.useCallback)(e=>{let t=v.current;if(!t)return 0;let n=t.getBoundingClientRect();return Math.max(0,Math.min(1,(T(e)-n.left)/n.width))},[]),H=(0,t.useCallback)(e=>{let t=g.current;t&&t.duration&&(t.currentTime=e*t.duration)},[]),U=e=>{e.stopPropagation(),k(!0);let t=V(e);D(t),H(t)},W=(0,t.useCallback)(e=>{e.key===`ArrowRight`&&H(Math.min(1,E+.05)),e.key===`ArrowLeft`&&H(Math.max(0,E-.05))},[H,E]);(0,t.useEffect)(()=>{c!==void 0&&c!==b.current&&(b.current=c,S(c))},[c]),(0,t.useEffect)(()=>{if(!x){y.current!==null&&(cancelAnimationFrame(y.current),y.current=null);return}let e=()=>{let t=g.current;t&&t.duration&&!O&&D(t.currentTime/t.duration),y.current=requestAnimationFrame(e)};return y.current=requestAnimationFrame(e),()=>{y.current!==null&&cancelAnimationFrame(y.current)}},[x,O]),(0,t.useEffect)(()=>{let e=g.current;e&&(x?e.play().catch(e=>{S(!1),N(!0),w()&&console.debug(`[MediaPlayer] play() failed`,e)}):e.pause())},[x]),(0,t.useEffect)(()=>{if(!O)return;let e=e=>D(V(e)),t=e=>{k(!1),H(V(e))};return window.addEventListener(`mousemove`,e),window.addEventListener(`mouseup`,t),window.addEventListener(`touchmove`,e,{passive:!0}),window.addEventListener(`touchend`,t),()=>{window.removeEventListener(`mousemove`,e),window.removeEventListener(`mouseup`,t),window.removeEventListener(`touchmove`,e),window.removeEventListener(`touchend`,t)}},[O,V,H]);let G=R?{aspectRatio:String(R)}:void 0,K=R?``:` aspect-video`,q=Math.round(E*100);return(0,n.jsxs)(`div`,{role:`button`,tabIndex:0,"data-testid":`media-player`,className:`relative cursor-pointer overflow-hidden bg-black ${K}`,style:G,onClick:e=>{if(p){p(e);return}M||u&&S(e=>!e)},onKeyDown:e=>{if(e.key===`Enter`||e.key===` `){if(e.preventDefault(),p){p(e);return}M||u&&S(e=>!e)}},children:[a&&(h===`audio`||I)&&(0,n.jsx)(`img`,{src:a,alt:``,"data-testid":`media-player-poster`,className:`absolute inset-0 h-full w-full object-cover`}),!a&&(h===`audio`||I)&&(0,n.jsx)(`div`,{"data-testid":`media-player-placeholder`,className:`absolute inset-0 flex items-center justify-center`,children:C(r,{className:`size-12 text-black/20`,weight:`regular`})}),(0,n.jsx)(`div`,{className:`absolute inset-0`,children:h===`audio`?(0,n.jsx)(`audio`,{...m,ref:g,"data-testid":`media-player-audio`,src:e,loop:l,muted:f,style:{width:`100%`,height:`100%`},onLoadStart:()=>F(!0),onCanPlay:()=>{F(!1),L(!1)},onWaiting:()=>F(!0),onPlay:()=>N(!1),onEnded:()=>{l||(S(!1),D(0))},children:(0,n.jsx)(`track`,{kind:`captions`})}):(0,n.jsx)(`video`,{ref:g,"data-testid":`media-player-video`,src:e,loop:l,muted:f,playsInline:!0,style:{width:`100%`,height:`100%`},onLoadStart:()=>F(!0),onCanPlay:()=>{F(!1),L(!1)},onWaiting:()=>F(!0),onPlay:()=>N(!1),onLoadedMetadata:()=>{let e=g.current;e instanceof HTMLVideoElement&&e.videoWidth&&e.videoHeight&&z(e.videoWidth/e.videoHeight)},onEnded:()=>{l||(S(!1),D(0))},children:(0,n.jsx)(`track`,{kind:`captions`})})}),P&&!M&&(0,n.jsx)(`div`,{role:`status`,"aria-label":`Loading media`,className:`absolute inset-0 z-10 flex items-center justify-center`,children:(0,n.jsx)(s,{size:`lg`,tone:`on-media`})}),M&&!u&&(0,n.jsx)(`div`,{className:`absolute inset-0 z-30 flex cursor-pointer items-center justify-center bg-black/35`,role:`button`,tabIndex:0,"aria-label":`Play preview`,onClick:e=>{e.stopPropagation(),B()},onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),e.stopPropagation(),B())},children:(0,n.jsx)(`span`,{className:`flex size-16 items-center justify-center rounded-full bg-white/20 text-white backdrop-blur-sm`,children:(0,n.jsx)(i.PlayIcon,{className:`size-9 translate-x-0.5`,weight:`fill`})})}),d&&!u&&(0,n.jsx)(`div`,{className:`absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent`,children:(0,n.jsx)(`div`,{role:`slider`,"aria-label":`Playback position`,"aria-valuenow":q,"aria-valuemin":0,"aria-valuemax":100,tabIndex:0,ref:v,className:`relative flex h-4 w-full cursor-pointer items-center`,onMouseDown:U,onTouchStart:U,onClick:e=>e.stopPropagation(),onKeyDown:W,children:(0,n.jsx)(`div`,{className:`w-full overflow-hidden rounded-full bg-white/30 h-1`,children:(0,n.jsx)(`div`,{className:`h-full rounded-full bg-white`,style:{width:`${q}%`}})})})}),u&&(0,n.jsxs)(`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`,children:[(0,n.jsx)(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),S(e=>!e)},className:`shrink-0 text-white`,"aria-label":x?`Pause`:`Play`,children:x?(0,n.jsx)(i.PauseIcon,{className:`size-5`,weight:`fill`}):(0,n.jsx)(i.PlayIcon,{className:`size-5 translate-x-px`,weight:`fill`})}),(0,n.jsxs)(`div`,{role:`slider`,"aria-label":`Playback position`,"aria-valuenow":q,"aria-valuemin":0,"aria-valuemax":100,tabIndex:0,ref:v,className:`relative flex h-4 w-full cursor-pointer items-center`,onMouseDown:U,onTouchStart:U,onClick:e=>e.stopPropagation(),onMouseEnter:()=>j(!0),onMouseLeave:()=>j(!1),onKeyDown:W,children:[(0,n.jsx)(`div`,{className:`w-full overflow-hidden rounded-full bg-white/30 transition-all duration-200 ${A||O?`h-1.5`:`h-1`}`,children:(0,n.jsx)(`div`,{className:`h-full rounded-full bg-white`,style:{width:`${q}%`}})}),(0,n.jsx)(`div`,{"data-testid":`media-player-scrubber-thumb`,className:`absolute size-3 -translate-x-1/2 rounded-full bg-white shadow transition-[opacity,transform] duration-200 ${A||O?`scale-100 opacity-100`:`scale-0 opacity-0`}`,style:{left:`${q}%`}})]})]})]})},D=e=>e===`dark`?`size-12 text-white/20`:`size-12 text-black/20`,O=e=>e===`dark`?`aspect-video overflow-hidden bg-white/10`:`aspect-video overflow-hidden bg-black/5`,k=({mimeType:e,sourceUrl:r,thumbnailUrl:i,title:a,variant:o,mediaPlayerProps:s,containedImage:c=!1})=>{let l=_(e),[u,d]=(0,t.useState)(!1),p=f(r),m=f(i);return r&&(l===`video`||l===`audio`)?(0,n.jsx)(E,{source:r,mimeType:e,poster:m,controls:!0,...s}):r&&l===`image`?c?(0,n.jsx)(`div`,{className:`relative ${O(o)}`,children:(0,n.jsx)(`img`,{src:p??r,alt:a??``,className:`absolute inset-0 h-full w-full object-contain transition-opacity duration-300 ${u?`opacity-100`:`opacity-0`}`,draggable:!1,onLoad:()=>d(!0)})}):(0,n.jsx)(`img`,{src:p??r,alt:a??``,className:`block w-full`,draggable:!1}):r&&l===`document`?i?c?(0,n.jsx)(`div`,{className:`relative ${O(o)}`,children:(0,n.jsx)(`img`,{src:m??i,alt:a??``,className:`absolute inset-0 h-full w-full object-contain transition-opacity duration-300 ${u?`opacity-100`:`opacity-0`}`,draggable:!1,onLoad:()=>d(!0)})}):(0,n.jsx)(`img`,{src:m??i,alt:``,className:`block w-full`,draggable:!1}):(0,n.jsx)(`div`,{className:`flex aspect-video w-full items-center justify-center ${o===`dark`?`bg-white/10`:`bg-black/5`}`,children:C(e,{className:D(o),weight:`regular`})}):i?(0,n.jsx)(`div`,{className:`relative ${O(o)}`,children:(0,n.jsx)(`img`,{src:m??i,alt:a??``,draggable:!1,className:`absolute inset-0 h-full w-full object-cover`})}):(0,n.jsx)(`div`,{className:`flex aspect-video w-full items-center justify-center ${o===`dark`?`bg-white/10`:`bg-black/5`}`,children:C(e,{className:D(o),weight:`regular`})})};Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return k}});
|
|
2
|
+
//# sourceMappingURL=AttachmentCard-ZpYg622K.cjs.map
|