@ethora/chat-component 26.9.6 → 26.10.1

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.
Files changed (133) hide show
  1. package/README.md +45 -3
  2. package/dist/{ChatProfileModal-DKuxJsdM.js → ChatProfileModal-Bf5jGPBZ.js} +566 -562
  3. package/dist/FilePreviewModal-Bwx0RZZw.js +1763 -0
  4. package/dist/{ManageDataModal-Dw4dCQll.js → ManageDataModal-Dhkp0LWH.js} +20 -20
  5. package/dist/{MarkdownBody-xtKDMR0h.js → MarkdownBody-_sUhW2O8.js} +1 -1
  6. package/dist/{MessageSearchModal-BVKU6H3v.js → MessageSearchModal-rwwWrILl.js} +106 -114
  7. package/dist/{PublicChatsModal-CscOnVaQ.js → PublicChatsModal-Byso6_vt.js} +13 -13
  8. package/dist/{SideDrawer-WneDrrWG.js → SideDrawer-CQPOf0ek.js} +38 -38
  9. package/dist/{UserProfileModal-CMHFq1I9.js → UserProfileModal-Vj2kICvc.js} +10 -10
  10. package/dist/{UserSettingsModal-BoZXZ0oR.js → UserSettingsModal-CioX4ZIV.js} +5 -5
  11. package/dist/{VideoCallOverlay-CQNi7wp5.js → VideoCallOverlay-DodAkiam.js} +3824 -3708
  12. package/dist/{VisibilityModal-BPsNiMzJ.js → VisibilityModal-CIl7rkBM.js} +12 -12
  13. package/dist/assets/icons.d.ts +2 -3
  14. package/dist/components/Files/fileCategory.d.ts +4 -2
  15. package/dist/components/InputComponents/MentionDropdown.d.ts +2 -0
  16. package/dist/components/MainComponents/AlbumGrid.d.ts +22 -0
  17. package/dist/components/MainComponents/AttachmentList.d.ts +6 -6
  18. package/dist/components/MainComponents/ImageUnavailable.d.ts +21 -0
  19. package/dist/components/MainComponents/MediaUploadOverlay.d.ts +31 -0
  20. package/dist/components/MainComponents/MessageContainer.d.ts +3 -0
  21. package/dist/components/MainComponents/scrollAnchor.d.ts +19 -0
  22. package/dist/components/MainComponents/useJumpToMessage.d.ts +42 -11
  23. package/dist/components/MainComponents/useScrollAnchor.d.ts +29 -0
  24. package/dist/components/MessageBubble/MediaCaption.d.ts +9 -0
  25. package/dist/components/MessageBubble/MessageAvatarPhoto.d.ts +17 -0
  26. package/dist/components/MessageBubble/MessageReaction.d.ts +6 -0
  27. package/dist/components/MessageBubble/QuickReplies.d.ts +2 -0
  28. package/dist/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +8 -10
  29. package/dist/components/Modals/FilePreviewModal/ImageLightbox.d.ts +4 -0
  30. package/dist/components/Modals/FilePreviewModal/PdfView.d.ts +4 -0
  31. package/dist/components/Modals/FilePreviewModal/ViewerChrome.d.ts +64 -0
  32. package/dist/components/Modals/MessageSearchModal/MessageHitResults.d.ts +5 -0
  33. package/dist/components/Modals/styledModalComponents.d.ts +0 -8
  34. package/dist/components/RoomComponents/LastMessageItem.d.ts +2 -0
  35. package/dist/components/RoomComponents/styled/LastMessageMedia.d.ts +19 -0
  36. package/dist/components/RoomComponents/styled/LastTextMessage.d.ts +2 -2
  37. package/dist/components/RoomComponents/styled/StyledRoomComponents.d.ts +10 -3
  38. package/dist/components/VideoCalls/VideoCallSession.d.ts +13 -0
  39. package/dist/components/styled/FileCard.d.ts +20 -0
  40. package/dist/components/styled/MediaSurface.d.ts +50 -0
  41. package/dist/components/styled/MessageImage.d.ts +9 -10
  42. package/dist/components/styled/SendInput.d.ts +12 -2
  43. package/dist/components/styled/StyledComponents.d.ts +69 -2
  44. package/dist/components/styled/StyledInputComponents/MediaComponents.d.ts +36 -24
  45. package/dist/components/styled/UnsupportedType.d.ts +1 -0
  46. package/dist/components/styled/VideoMessage.d.ts +11 -6
  47. package/dist/e2ee/callKey.d.ts +32 -0
  48. package/dist/e2ee/fileEnvelope.d.ts +16 -5
  49. package/dist/e2ee/omemo.d.ts +18 -0
  50. package/dist/firebase-messaging-sw.js +20 -3
  51. package/dist/{handleCopyClick-B70vLjJD.js → handleCopyClick-DGaZhy_u.js} +1 -1
  52. package/dist/helpers/albumLayout.d.ts +53 -0
  53. package/dist/helpers/attachments.d.ts +22 -1
  54. package/dist/helpers/avatarImageCache.d.ts +9 -0
  55. package/dist/helpers/caption.d.ts +63 -0
  56. package/dist/helpers/checkUniqueUsers.d.ts +2 -2
  57. package/dist/helpers/composerFocus.d.ts +22 -0
  58. package/dist/helpers/createMainMessageForThread.d.ts +1 -1
  59. package/dist/helpers/dedupeMembers.d.ts +10 -0
  60. package/dist/helpers/downloadFile.d.ts +19 -0
  61. package/dist/helpers/fileKind.d.ts +17 -0
  62. package/dist/helpers/historyPreloadConfig.d.ts +25 -0
  63. package/dist/helpers/historyPreloadScheduler.d.ts +3 -0
  64. package/dist/helpers/insertMessageWithDelimiter.d.ts +1 -0
  65. package/dist/helpers/isMessageSearchEnabled.d.ts +9 -0
  66. package/dist/helpers/jumpThread.d.ts +56 -0
  67. package/dist/helpers/jumpWindow.d.ts +73 -0
  68. package/dist/helpers/lastMessagePreview.d.ts +55 -0
  69. package/dist/helpers/mapWithConcurrency.d.ts +8 -0
  70. package/dist/helpers/mediaBox.d.ts +110 -0
  71. package/dist/helpers/mediaBubble.d.ts +39 -0
  72. package/dist/helpers/mediaLabel.d.ts +10 -0
  73. package/dist/helpers/mediaSendRetry.d.ts +25 -0
  74. package/dist/helpers/messageRuns.d.ts +10 -0
  75. package/dist/helpers/openThreadForJump.d.ts +26 -0
  76. package/dist/helpers/pdf/loadPdfjs.d.ts +8 -1
  77. package/dist/helpers/repairFilenameEncoding.d.ts +11 -0
  78. package/dist/helpers/roomImageGallery.d.ts +34 -0
  79. package/dist/helpers/roomUserCount.d.ts +19 -0
  80. package/dist/helpers/safeUrl.d.ts +15 -0
  81. package/dist/helpers/secureFileUrl.d.ts +4 -1
  82. package/dist/helpers/userResolver.d.ts +57 -0
  83. package/dist/helpers/viewerSender.d.ts +47 -0
  84. package/dist/helpers/xmppIdShape.d.ts +1 -1
  85. package/dist/hooks/useAvatarImage.d.ts +21 -0
  86. package/dist/hooks/useChatWrapperInit.d.ts +6 -0
  87. package/dist/hooks/useIsMobileViewport.d.ts +5 -0
  88. package/dist/hooks/useMediaProbe.d.ts +40 -0
  89. package/dist/hooks/usePaneWidthVar.d.ts +11 -0
  90. package/dist/hooks/usePdfThumbnail.d.ts +2 -2
  91. package/dist/hooks/usePrefersReducedMotion.d.ts +2 -0
  92. package/dist/hooks/useRoomDirectory.d.ts +11 -0
  93. package/dist/hooks/useSendMessage.d.ts +4 -1
  94. package/dist/{main-rJpE4hh-.js → main-CUB_w8AZ.js} +29136 -24217
  95. package/dist/main.css +1 -1
  96. package/dist/main.js +16 -16
  97. package/dist/networking/api-requests/auth.api.d.ts +2 -0
  98. package/dist/networking/api-requests/roomMembers.api.d.ts +18 -0
  99. package/dist/networking/callKeyStanza.d.ts +7 -0
  100. package/dist/networking/ethoraEvents.d.ts +44 -0
  101. package/dist/networking/stanzaHandlers.d.ts +6 -4
  102. package/dist/networking/xmpp/allRoomPresences.xmpp.d.ts +18 -1
  103. package/dist/networking/xmpp/presenceInRoom.xmpp.d.ts +1 -1
  104. package/dist/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +2 -0
  105. package/dist/networking/xmpp/sendMediaMessage.xmpp.d.ts +8 -0
  106. package/dist/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +2 -0
  107. package/dist/networking/xmppClient.d.ts +61 -2
  108. package/dist/roomStore/Middleware/jumpThreadMiddleware.d.ts +2 -0
  109. package/dist/roomStore/callSlice.d.ts +6 -1
  110. package/dist/roomStore/index.d.ts +22 -0
  111. package/dist/roomStore/roomsSlice.d.ts +51 -4
  112. package/dist/roomStore/safeKey.d.ts +12 -0
  113. package/dist/roomStore/usersSetCap.d.ts +15 -0
  114. package/dist/styles/motion.d.ts +22 -2
  115. package/dist/types/models/attachment.model.d.ts +19 -0
  116. package/dist/types/models/config.model.d.ts +98 -5
  117. package/dist/types/models/customComponents.model.d.ts +2 -0
  118. package/dist/types/models/message.model.d.ts +9 -0
  119. package/dist/types/models/modal.model.d.ts +19 -0
  120. package/dist/types/models/room.model.d.ts +30 -0
  121. package/dist/types/models/xmpp.model.d.ts +24 -1
  122. package/dist/utils/messageNotificationContent.d.ts +34 -0
  123. package/dist/version.d.ts +1 -1
  124. package/package.json +2 -1
  125. package/public/firebase-messaging-sw.js +20 -3
  126. package/dist/FilePreviewModal-BcaSoO3-.js +0 -743
  127. package/dist/components/MainComponents/computeAnchoredScrollTop.d.ts +0 -9
  128. package/dist/components/Modals/NewChatModal/UpdNewChatModal.d.ts +0 -3
  129. package/dist/components/RoomComponents/styled/LastAudioMessage.d.ts +0 -6
  130. package/dist/components/RoomComponents/styled/LastMessageFile.d.ts +0 -6
  131. package/dist/components/RoomComponents/styled/LastMessagePhoto.d.ts +0 -6
  132. package/dist/components/RoomComponents/styled/LastMessageVideo.d.ts +0 -6
  133. package/dist/components/SortDropDown/index.d.ts +0 -8
@@ -0,0 +1,1763 @@
1
+ import { jsx as r, jsxs as b } from "react/jsx-runtime";
2
+ import { b2 as et, b3 as tt, E as f, b4 as yt, x as Pe, b as Et, b5 as kt, b6 as nt, b7 as rt, b8 as ot, b9 as Le, ba as Te, bb as Ce, aJ as $e, K as Ae, bc as Ue, bd as Pt, G as ke, be as St, bf as it, a as Rt, a_ as Lt, u as le, aa as _e, bg as Tt, bh as Ct, bi as Se, bj as Mt, ax as ue, bk as Be, bl as It, bm as $t, bn as At, bo as Dt, bp as Ot, aI as Ne, D as zt, bq as Ut } from "./main-CUB_w8AZ.js";
3
+ import Me, { useState as F, useRef as U, useEffect as M, useMemo as te, useCallback as B, useLayoutEffect as _t } from "react";
4
+ const at = (t, o, i) => {
5
+ const g = document.createElement("a");
6
+ g.href = t, g.setAttribute("download", o), i && (g.target = "_blank", g.rel = "noopener"), g.style.display = "none", document.body.appendChild(g), g.click(), g.remove();
7
+ }, Bt = (t, o) => {
8
+ const i = URL.createObjectURL(t);
9
+ try {
10
+ at(i, o, !1);
11
+ } finally {
12
+ URL.revokeObjectURL(i);
13
+ }
14
+ }, Nt = (t, o) => at(t, o, !0);
15
+ async function Wt(t, o, i = {}) {
16
+ const g = i.fetchImpl ?? fetch, E = i.saveBlob ?? Bt, l = i.saveUrl ?? Nt;
17
+ let w;
18
+ try {
19
+ w = await g(t, { method: "GET" });
20
+ } catch {
21
+ return l(t, o), "direct";
22
+ }
23
+ return w.ok ? (E(new Blob([await w.arrayBuffer()]), o), "blob") : (et(t) && (w.status === 401 || w.status === 403) && tt(), "http-error");
24
+ }
25
+ function We(t, o) {
26
+ let i;
27
+ return (...g) => {
28
+ window.clearTimeout(i), i = window.setTimeout(() => t(...g), o);
29
+ };
30
+ }
31
+ function Xt({ debounce: t, scroll: o, polyfill: i, offsetSize: g } = { debounce: 0, scroll: !1, offsetSize: !1 }) {
32
+ const E = i || (typeof window > "u" ? class {
33
+ } : window.ResizeObserver);
34
+ if (!E) throw new Error("This browser does not support ResizeObserver out of the box. See: https://github.com/react-spring/react-use-measure/#resize-observer-polyfills");
35
+ const [l, w] = F({ left: 0, top: 0, width: 0, height: 0, bottom: 0, right: 0, x: 0, y: 0 }), c = U({ element: null, scrollContainers: null, resizeObserver: null, lastBounds: l, orientationHandler: null }), T = t ? typeof t == "number" ? t : t.scroll : null, m = t ? typeof t == "number" ? t : t.resize : null, v = U(!1);
36
+ M(() => (v.current = !0, () => {
37
+ v.current = !1;
38
+ }));
39
+ const [N, S, x] = te(() => {
40
+ const k = () => {
41
+ if (!c.current.element) return;
42
+ const { left: W, top: V, width: I, height: D, bottom: j, right: R, x: P, y: C } = c.current.element.getBoundingClientRect(), $ = { left: W, top: V, width: I, height: D, bottom: j, right: R, x: P, y: C };
43
+ c.current.element instanceof HTMLElement && g && ($.height = c.current.element.offsetHeight, $.width = c.current.element.offsetWidth), Object.freeze($), v.current && !jt(c.current.lastBounds, $) && w(c.current.lastBounds = $);
44
+ };
45
+ return [k, m ? We(k, m) : k, T ? We(k, T) : k];
46
+ }, [w, g, T, m]);
47
+ function O() {
48
+ c.current.scrollContainers && (c.current.scrollContainers.forEach((k) => k.removeEventListener("scroll", x, !0)), c.current.scrollContainers = null), c.current.resizeObserver && (c.current.resizeObserver.disconnect(), c.current.resizeObserver = null), c.current.orientationHandler && ("orientation" in screen && "removeEventListener" in screen.orientation ? screen.orientation.removeEventListener("change", c.current.orientationHandler) : "onorientationchange" in window && window.removeEventListener("orientationchange", c.current.orientationHandler));
49
+ }
50
+ function A() {
51
+ c.current.element && (c.current.resizeObserver = new E(x), c.current.resizeObserver.observe(c.current.element), o && c.current.scrollContainers && c.current.scrollContainers.forEach((k) => k.addEventListener("scroll", x, { capture: !0, passive: !0 })), c.current.orientationHandler = () => {
52
+ x();
53
+ }, "orientation" in screen && "addEventListener" in screen.orientation ? screen.orientation.addEventListener("change", c.current.orientationHandler) : "onorientationchange" in window && window.addEventListener("orientationchange", c.current.orientationHandler));
54
+ }
55
+ const H = (k) => {
56
+ !k || k === c.current.element || (O(), c.current.element = k, c.current.scrollContainers = st(k), A());
57
+ };
58
+ return Yt(x, !!o), Ft(S), M(() => {
59
+ O(), A();
60
+ }, [o, x, S]), M(() => O, []), [H, l, N];
61
+ }
62
+ function Ft(t) {
63
+ M(() => {
64
+ const o = t;
65
+ return window.addEventListener("resize", o), () => {
66
+ window.removeEventListener("resize", o);
67
+ };
68
+ }, [t]);
69
+ }
70
+ function Yt(t, o) {
71
+ M(() => {
72
+ if (o) {
73
+ const i = t;
74
+ return window.addEventListener("scroll", i, { capture: !0, passive: !0 }), () => {
75
+ window.removeEventListener("scroll", i, !0);
76
+ };
77
+ }
78
+ }, [t, o]);
79
+ }
80
+ function st(t) {
81
+ const o = [];
82
+ if (!t || t === document.body) return o;
83
+ const { overflow: i, overflowX: g, overflowY: E } = window.getComputedStyle(t);
84
+ return [i, g, E].some((l) => l === "auto" || l === "scroll") && o.push(t), [...o, ...st(t.parentElement)];
85
+ }
86
+ const Ht = ["x", "y", "top", "bottom", "left", "right", "width", "height"], jt = (t, o) => Ht.every((i) => t[i] === o[i]), Xe = 0.5, Fe = 3, xe = 1.25, Vt = 2e-3, Ye = 12, He = 16, je = 16, Gt = 72, Ve = 320, Zt = 150, Ge = 4, Kt = 7, qt = "800px 0px", Jt = 2, Qt = 0.9, Ze = { width: 612, height: 792 }, en = f.div`
87
+ display: flex;
88
+ flex-direction: column;
89
+ align-items: center;
90
+ gap: 12px;
91
+ width: 100%;
92
+ height: 100%;
93
+ overflow: auto;
94
+ `, tn = f.div`
95
+ position: relative;
96
+ width: 100%;
97
+ height: 100%;
98
+ min-width: 0;
99
+ min-height: 0;
100
+ `, nn = f.div`
101
+ box-sizing: border-box;
102
+ width: 100%;
103
+ height: 100%;
104
+ overflow: auto;
105
+ overscroll-behavior: contain;
106
+ background-color: #e6e9ee;
107
+ border-radius: var(--ethora-radius-lg, 16px);
108
+ -webkit-overflow-scrolling: touch;
109
+ `, rn = f.div`
110
+ position: relative;
111
+ `, lt = f.div`
112
+ position: absolute;
113
+ box-sizing: border-box;
114
+ overflow: hidden;
115
+ background-color: #fff;
116
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
117
+ ${({ $loading: t }) => t && yt}
118
+ `, on = f.canvas`
119
+ display: ${({ $painted: t }) => t ? "block" : "none"};
120
+ width: 100%;
121
+ height: 100%;
122
+ `, an = f.div`
123
+ position: absolute;
124
+ left: 0;
125
+ right: 0;
126
+ bottom: 16px;
127
+ display: grid;
128
+ grid-template-columns: 1fr auto 1fr;
129
+ align-items: center;
130
+ gap: 8px;
131
+ padding: 0 16px;
132
+ pointer-events: none;
133
+ `, ct = f.div`
134
+ display: inline-flex;
135
+ align-items: center;
136
+ gap: 2px;
137
+ box-sizing: border-box;
138
+ border-radius: 999px;
139
+ background-color: rgba(20, 22, 28, 0.72);
140
+ color: #fff;
141
+ backdrop-filter: blur(8px);
142
+ -webkit-backdrop-filter: blur(8px);
143
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
144
+ font-size: 13px;
145
+ font-variant-numeric: tabular-nums;
146
+ white-space: nowrap;
147
+ pointer-events: auto;
148
+ user-select: none;
149
+ `, sn = f(ct)`
150
+ grid-column: 2;
151
+ justify-self: center;
152
+ padding: 6px 14px;
153
+ `, ln = f(ct)`
154
+ grid-column: 3;
155
+ justify-self: end;
156
+ padding: 3px;
157
+ `, cn = f.span`
158
+ min-width: 44px;
159
+ text-align: center;
160
+ font-size: 12px;
161
+ `, Re = f.button`
162
+ display: inline-flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ width: 30px;
166
+ height: 30px;
167
+ padding: 0;
168
+ border: 0;
169
+ border-radius: 999px;
170
+ background: transparent;
171
+ color: inherit;
172
+ cursor: pointer;
173
+
174
+ &:hover:not(:disabled) {
175
+ background-color: rgba(255, 255, 255, 0.16);
176
+ }
177
+
178
+ &:disabled {
179
+ opacity: 0.4;
180
+ cursor: default;
181
+ }
182
+
183
+ &:focus-visible {
184
+ outline: 2px solid #fff;
185
+ outline-offset: 2px;
186
+ }
187
+ `, dn = f.div`
188
+ display: flex;
189
+ flex-direction: column;
190
+ align-items: center;
191
+ gap: 12px;
192
+ padding: 16px;
193
+ border-radius: var(--ethora-radius-lg, 16px);
194
+ background-color: var(--ethora-color-bg-subtle, #f5f7fa);
195
+ color: var(--ethora-color-text, #141414);
196
+ text-align: center;
197
+
198
+ a {
199
+ color: var(--ethora-color-primary-text, var(--ethora-color-primary, #0052cd));
200
+ }
201
+ `, un = (t, o, i) => Math.min(i, Math.max(o, t)), fn = (t) => {
202
+ const o = t;
203
+ return !o || !o.tagName ? !1 : o.isContentEditable ? !0 : ["INPUT", "TEXTAREA", "SELECT"].includes(o.tagName);
204
+ }, Ke = (t, o, i, g) => {
205
+ const E = t + o;
206
+ let l = 0, w = -1;
207
+ for (let c = 0; c < i.length; c += 1) {
208
+ const T = i[c], m = T + g[c];
209
+ if (m < t) continue;
210
+ if (T > E) break;
211
+ const v = Math.min(m, E) - Math.max(T, t);
212
+ v > w && (l = c, w = v);
213
+ }
214
+ return l + 1;
215
+ }, qe = (t, o) => new Set(
216
+ [...t].sort((i, g) => Math.abs(i - o) - Math.abs(g - o) || i - g).slice(0, Kt)
217
+ ), hn = Me.memo(function({
218
+ pdfDocument: o,
219
+ pageNumber: i,
220
+ width: g,
221
+ height: E,
222
+ top: l,
223
+ left: w,
224
+ active: c
225
+ }) {
226
+ const T = U(null), m = U(null), [v, N] = F(!1);
227
+ return M(() => {
228
+ const S = T.current;
229
+ if (!S) return;
230
+ if (!c || g <= 0) {
231
+ m.current?.cancel(), m.current = null, S.width = 0, S.height = 0, N(!1);
232
+ return;
233
+ }
234
+ let x = !1;
235
+ return (async () => {
236
+ try {
237
+ const O = await o.getPage(i);
238
+ if (x) {
239
+ O.cleanup();
240
+ return;
241
+ }
242
+ const A = O.getViewport({ scale: 1 }), H = Math.min(window.devicePixelRatio || 1, Jt), k = O.getViewport({
243
+ scale: A.width ? g / A.width * H : H
244
+ }), W = S.getContext("2d");
245
+ if (!W) return;
246
+ S.width = Math.max(1, Math.floor(k.width)), S.height = Math.max(1, Math.floor(k.height)), m.current?.cancel();
247
+ const V = O.render({ canvasContext: W, viewport: k });
248
+ m.current = V, await V.promise, x || N(!0), O.cleanup();
249
+ } catch (O) {
250
+ x || console.warn("[Ethora] PDF page render failed:", O);
251
+ }
252
+ })(), () => {
253
+ x = !0, m.current?.cancel(), m.current = null;
254
+ };
255
+ }, [c, o, i, g]), /* @__PURE__ */ r(
256
+ lt,
257
+ {
258
+ "data-pdf-page": i,
259
+ $loading: !v,
260
+ style: { left: w, top: l, width: g, height: E },
261
+ children: /* @__PURE__ */ r(on, { ref: T, $painted: v })
262
+ }
263
+ );
264
+ }), pn = ({ pdfUrl: t }) => {
265
+ const o = Pe(), { config: i } = Et(), [g, E] = Xt(), l = U(null), w = B(
266
+ (d) => {
267
+ l.current = d, g(d);
268
+ },
269
+ [g]
270
+ ), [c, T] = F("loading"), [m, v] = F(null), [N, S] = F([]), [x, O] = F(1), A = U(1), [H, k] = F(0), [W, V] = F(1), I = U(1), [D, j] = F(() => /* @__PURE__ */ new Set()), R = U(null), P = U(null), C = U(null), $ = H > 0 ? H : Ve, Y = m?.numPages ?? 0;
271
+ M(() => {
272
+ let d = !1, n = null, e;
273
+ return T("loading"), v(null), S([]), j(/* @__PURE__ */ new Set()), I.current = 1, V(1), (async () => {
274
+ const a = await kt(i?.pdfPreview?.workerSrc, i?.pdfPreview?.libUrl);
275
+ if (!d) {
276
+ if (!a || !t) {
277
+ T("error");
278
+ return;
279
+ }
280
+ try {
281
+ e = a.getDocument({ url: t, isEvalSupported: !1 });
282
+ const s = await e.promise;
283
+ if (d) {
284
+ s.destroy().catch(() => {
285
+ });
286
+ return;
287
+ }
288
+ if (n = s, s.numPages < 1) {
289
+ T("error");
290
+ return;
291
+ }
292
+ S(Array.from({ length: s.numPages }, () => Ze)), v(s), T("ready");
293
+ } catch (s) {
294
+ d || (console.warn("[Ethora] PDF open failed:", s), T("error"));
295
+ }
296
+ }
297
+ })(), () => {
298
+ d = !0, n?.destroy?.().catch(() => {
299
+ }), e?.destroy?.().catch(() => {
300
+ });
301
+ };
302
+ }, [t, i?.pdfPreview?.workerSrc, i?.pdfPreview?.libUrl]), M(() => {
303
+ if (!m) return;
304
+ let d = !1;
305
+ return (async () => {
306
+ try {
307
+ const n = m.numPages, e = await m.getPage(1), a = e.getViewport({ scale: 1 });
308
+ if (e.cleanup(), d || !a.width) return;
309
+ const s = { width: a.width, height: a.height };
310
+ S(Array.from({ length: n }, () => s));
311
+ for (let u = 2; u <= n; u += Ge) {
312
+ const y = Math.min(n, u + Ge - 1), z = await Promise.all(
313
+ Array.from({ length: y - u + 1 }, async (X, J) => {
314
+ const Q = u + J, se = await m.getPage(Q), pe = se.getViewport({ scale: 1 });
315
+ return se.cleanup(), {
316
+ pageNumber: Q,
317
+ size: { width: pe.width, height: pe.height }
318
+ };
319
+ })
320
+ );
321
+ if (d) return;
322
+ S((X) => {
323
+ if (X.length !== n) return X;
324
+ const J = X.slice();
325
+ return z.forEach(({ pageNumber: Q, size: se }) => {
326
+ J[Q - 1] = se;
327
+ }), J;
328
+ });
329
+ }
330
+ } catch (n) {
331
+ d || console.warn("[Ethora] PDF page measure failed:", n);
332
+ }
333
+ })(), () => {
334
+ d = !0;
335
+ };
336
+ }, [m]);
337
+ const L = te(() => {
338
+ const d = N.length > 0 ? N : [Ze], n = Math.max(1, $ - He * 2) * x, e = Math.max($, n + He * 2), a = [], s = [];
339
+ let u = je;
340
+ d.forEach((z) => {
341
+ const X = n * z.height / (z.width || 1);
342
+ a.push(u), s.push(X), u += X + Ye;
343
+ });
344
+ const y = u - Ye;
345
+ return {
346
+ pageWidth: n,
347
+ stageWidth: e,
348
+ stageHeight: y + Gt,
349
+ left: (e - n) / 2,
350
+ tops: a,
351
+ heights: s
352
+ };
353
+ }, [N, $, x]);
354
+ P.current = L, _t(() => {
355
+ const d = l.current;
356
+ if (!d) return;
357
+ const n = R.current;
358
+ n && (R.current = null, d.scrollLeft = n.fx * d.scrollWidth - n.cx, d.scrollTop = n.fy * d.scrollHeight - n.cy);
359
+ const e = Ke(
360
+ d.scrollTop,
361
+ d.clientHeight,
362
+ L.tops,
363
+ L.heights
364
+ );
365
+ e !== I.current && (I.current = e, V(e));
366
+ }, [L]);
367
+ const K = B((d, n) => {
368
+ const e = l.current;
369
+ if (!e || !e.scrollHeight || !e.scrollWidth) return;
370
+ if (e.scrollTop <= 0 && e.scrollLeft <= 0) {
371
+ R.current = null;
372
+ return;
373
+ }
374
+ const a = d ?? e.clientWidth / 2, s = n ?? e.clientHeight / 2;
375
+ R.current = {
376
+ fx: (e.scrollLeft + a) / e.scrollWidth,
377
+ fy: (e.scrollTop + s) / e.scrollHeight,
378
+ cx: a,
379
+ cy: s
380
+ };
381
+ }, []), _ = B(
382
+ (d, n, e) => {
383
+ const a = un(d, Xe, Fe);
384
+ a !== A.current && (K(n, e), A.current = a, O(a));
385
+ },
386
+ [K]
387
+ ), ee = Math.max(Ve, Math.floor(E.width || 0));
388
+ M(() => {
389
+ if (H === 0) {
390
+ k(ee);
391
+ return;
392
+ }
393
+ if (ee === H) return;
394
+ const d = window.setTimeout(() => {
395
+ K(), k(ee);
396
+ }, Zt);
397
+ return () => window.clearTimeout(d);
398
+ }, [ee, H, K]);
399
+ const ne = typeof IntersectionObserver < "u";
400
+ M(() => {
401
+ !m || ne || j(
402
+ qe(
403
+ Array.from({ length: m.numPages }, (d, n) => n + 1),
404
+ W
405
+ )
406
+ );
407
+ }, [m, W, ne]), M(() => {
408
+ const d = l.current;
409
+ if (!m || !d || typeof IntersectionObserver > "u")
410
+ return;
411
+ const n = /* @__PURE__ */ new Set(), e = new IntersectionObserver(
412
+ (a) => {
413
+ a.forEach((s) => {
414
+ const u = Number(s.target.dataset.pdfPage);
415
+ Number.isFinite(u) && (s.isIntersecting ? n.add(u) : n.delete(u));
416
+ }), j(qe([...n], I.current));
417
+ },
418
+ { root: d, rootMargin: qt }
419
+ );
420
+ return d.querySelectorAll("[data-pdf-page]").forEach((a) => e.observe(a)), () => e.disconnect();
421
+ }, [m]);
422
+ const de = B(() => {
423
+ const d = l.current, n = P.current;
424
+ if (!d || !n) return;
425
+ const e = Ke(
426
+ d.scrollTop,
427
+ d.clientHeight,
428
+ n.tops,
429
+ n.heights
430
+ );
431
+ e !== I.current && (I.current = e, V(e));
432
+ }, []), re = () => {
433
+ C.current === null && (C.current = window.requestAnimationFrame(() => {
434
+ C.current = null, de();
435
+ }));
436
+ };
437
+ if (M(
438
+ () => () => {
439
+ C.current !== null && window.cancelAnimationFrame(C.current);
440
+ },
441
+ []
442
+ ), M(() => {
443
+ const d = l.current;
444
+ if (!d) return;
445
+ const n = (e) => {
446
+ if (!(e.ctrlKey || e.metaKey)) return;
447
+ e.preventDefault();
448
+ const a = d.getBoundingClientRect();
449
+ _(
450
+ A.current * Math.exp(-e.deltaY * Vt),
451
+ e.clientX - a.left,
452
+ e.clientY - a.top
453
+ );
454
+ };
455
+ return d.addEventListener("wheel", n, { passive: !1 }), () => d.removeEventListener("wheel", n);
456
+ }, [c, _]), M(() => {
457
+ const d = (n) => {
458
+ if (n.defaultPrevented || n.altKey || n.ctrlKey || n.metaKey || fn(n.target)) return;
459
+ const e = l.current;
460
+ if (!e) return;
461
+ const a = n.target, s = !!a && e.contains(a), u = !!a && (a.tagName === "BUTTON" || a.tagName === "A");
462
+ switch (n.key) {
463
+ case "+":
464
+ case "=":
465
+ n.preventDefault(), _(A.current * xe);
466
+ return;
467
+ case "-":
468
+ case "_":
469
+ n.preventDefault(), _(A.current / xe);
470
+ return;
471
+ case "0":
472
+ n.preventDefault(), _(1);
473
+ return;
474
+ }
475
+ if (s) return;
476
+ const y = e.clientHeight * Qt;
477
+ switch (n.key) {
478
+ case "PageDown":
479
+ n.preventDefault(), e.scrollTop += y;
480
+ return;
481
+ case "PageUp":
482
+ n.preventDefault(), e.scrollTop -= y;
483
+ return;
484
+ case " ":
485
+ if (u) return;
486
+ n.preventDefault(), e.scrollTop += n.shiftKey ? -y : y;
487
+ return;
488
+ case "Home":
489
+ n.preventDefault(), e.scrollTop = 0;
490
+ return;
491
+ case "End":
492
+ n.preventDefault(), e.scrollTop = e.scrollHeight;
493
+ return;
494
+ default:
495
+ return;
496
+ }
497
+ };
498
+ return document.addEventListener("keydown", d), () => document.removeEventListener("keydown", d);
499
+ }, [_]), c === "error" || c === "ready" && Y === 0)
500
+ return /* @__PURE__ */ r(en, { children: /* @__PURE__ */ b(dn, { children: [
501
+ /* @__PURE__ */ r("span", { children: o("modal.filePreview.pdfUnavailable") }),
502
+ /* @__PURE__ */ r("a", { href: t, target: "_blank", rel: "noopener noreferrer", children: o("modal.filePreview.openExternally") })
503
+ ] }) });
504
+ const oe = Math.round(x * 100);
505
+ return /* @__PURE__ */ b(tn, { children: [
506
+ /* @__PURE__ */ r(
507
+ nn,
508
+ {
509
+ ref: w,
510
+ tabIndex: 0,
511
+ role: "region",
512
+ "aria-label": o("modal.filePreview.pdfPages"),
513
+ onScroll: re,
514
+ "data-testid": "pdf-scroll",
515
+ children: /* @__PURE__ */ r(rn, { style: { width: L.stageWidth, height: L.stageHeight }, children: m ? Array.from({ length: Y }, (d, n) => {
516
+ const e = n + 1;
517
+ return /* @__PURE__ */ r(
518
+ hn,
519
+ {
520
+ pdfDocument: m,
521
+ pageNumber: e,
522
+ width: L.pageWidth,
523
+ height: L.heights[n],
524
+ top: L.tops[n],
525
+ left: L.left,
526
+ active: D.has(e)
527
+ },
528
+ e
529
+ );
530
+ }) : /* @__PURE__ */ r(
531
+ lt,
532
+ {
533
+ $loading: !0,
534
+ "aria-hidden": "true",
535
+ style: {
536
+ left: L.left,
537
+ top: je,
538
+ width: L.pageWidth,
539
+ height: L.heights[0]
540
+ }
541
+ }
542
+ ) })
543
+ }
544
+ ),
545
+ c === "ready" && /* @__PURE__ */ b(an, { children: [
546
+ /* @__PURE__ */ b(sn, { children: [
547
+ W,
548
+ " / ",
549
+ Y
550
+ ] }),
551
+ /* @__PURE__ */ b(ln, { children: [
552
+ /* @__PURE__ */ r(
553
+ Re,
554
+ {
555
+ type: "button",
556
+ onClick: () => _(A.current / xe),
557
+ disabled: x <= Xe,
558
+ "aria-label": o("modal.filePreview.zoomOut"),
559
+ children: /* @__PURE__ */ r(nt, { color: "currentColor" })
560
+ }
561
+ ),
562
+ /* @__PURE__ */ b(cn, { children: [
563
+ oe,
564
+ "%"
565
+ ] }),
566
+ /* @__PURE__ */ r(
567
+ Re,
568
+ {
569
+ type: "button",
570
+ onClick: () => _(A.current * xe),
571
+ disabled: x >= Fe,
572
+ "aria-label": o("modal.filePreview.zoomIn"),
573
+ children: /* @__PURE__ */ r(rt, { color: "currentColor" })
574
+ }
575
+ ),
576
+ /* @__PURE__ */ r(
577
+ Re,
578
+ {
579
+ type: "button",
580
+ onClick: () => _(1),
581
+ disabled: x === 1,
582
+ "aria-label": o("modal.filePreview.resetZoom"),
583
+ children: /* @__PURE__ */ r(ot, { color: "currentColor" })
584
+ }
585
+ )
586
+ ] })
587
+ ] })
588
+ ] });
589
+ }, G = 1, Ie = 6, gn = 2.5, mn = 50, bn = 300, Je = 24, wn = 16e-4, ve = (t, o, i) => Math.min(i, Math.max(o, t)), xn = f.div`
590
+ position: relative;
591
+ /* An explicit height, not flex growth alone: the parent lays its children
592
+ out in a row and centres them, so the viewport would otherwise be sized
593
+ by its content, and the image's own max-height of 100% would resolve
594
+ against that auto height and never fit anything. */
595
+ flex: 1 1 auto;
596
+ width: 100%;
597
+ height: 100%;
598
+ min-height: 0;
599
+ display: flex;
600
+ align-items: center;
601
+ justify-content: center;
602
+ overflow: hidden;
603
+ /* A zoomed image is dragged, not selected, and a two-finger gesture is a
604
+ pinch rather than a page scroll. */
605
+ touch-action: none;
606
+ user-select: none;
607
+ /* The viewer backdrop shows through: the picture sits on the dark chrome. */
608
+ background-color: transparent;
609
+ `, vn = Ae`
610
+ to { transform: rotate(360deg); }
611
+ `, yn = f.div`
612
+ position: absolute;
613
+ top: 50%;
614
+ left: 50%;
615
+ width: 40px;
616
+ height: 40px;
617
+ margin: -20px 0 0 -20px;
618
+ pointer-events: none;
619
+ z-index: 1;
620
+
621
+ svg {
622
+ width: 100%;
623
+ height: 100%;
624
+ display: block;
625
+ animation: ${vn} 900ms linear infinite;
626
+ }
627
+
628
+ @media (prefers-reduced-motion: reduce) {
629
+ svg {
630
+ animation-duration: 2400ms;
631
+ }
632
+ }
633
+ `, En = f.img`
634
+ position: absolute;
635
+ inset: 0;
636
+ width: 100%;
637
+ height: 100%;
638
+ object-fit: contain;
639
+ filter: blur(18px);
640
+ transform: scale(1.04);
641
+ pointer-events: none;
642
+ opacity: ${({ $hidden: t }) => t ? 0 : 1};
643
+ transition: opacity ${Te} ${Ce};
644
+ ${$e}
645
+ `, kn = f.img`
646
+ /* Same box the single-file view always used: fill the stage and let
647
+ object-fit do the letterboxing, so what the viewer sees at scale 1 is
648
+ unchanged. It is also what makes the pan clamp exact, since the painted
649
+ content box is then derived from the natural aspect ratio alone. */
650
+ width: 100%;
651
+ height: 100%;
652
+ object-fit: contain;
653
+ transform-origin: center center;
654
+ will-change: transform;
655
+ cursor: ${({ $grabbing: t, $pannable: o }) => t ? "grabbing" : o ? "grab" : "zoom-in"};
656
+ /* Rounded and lifted off the backdrop. The shadow follows the painted
657
+ pixels (drop-shadow), so a letterboxed picture is not boxed in a card. */
658
+ border-radius: 10px;
659
+ filter: drop-shadow(0 18px 40px rgba(0, 0, 0, 0.45));
660
+ opacity: ${({ $loaded: t }) => t ? 1 : 0};
661
+ transition: ${({ $animate: t }) => t ? `transform ${Te} ${Ce}, ` : ""}opacity ${Te} ${Ce};
662
+ ${$e}
663
+ `, dt = Me.forwardRef(
664
+ ({
665
+ src: t,
666
+ alt: o,
667
+ previewSrc: i,
668
+ loadingLabel: g = "",
669
+ onSwipeLeft: E,
670
+ onSwipeRight: l,
671
+ onError: w,
672
+ onScaleChange: c
673
+ }, T) => {
674
+ const m = U(null), v = U(null), [N, S] = F(!1), [x, O] = F(G), [A, H] = F({ x: 0, y: 0 }), [k, W] = F(!1), [V, I] = F(!1), D = U({ scale: G, offset: { x: 0, y: 0 } });
675
+ D.current = { scale: x, offset: A };
676
+ const j = U(null), R = U(null), P = U(
677
+ null
678
+ ), C = B((n) => {
679
+ const e = m.current, a = v.current;
680
+ if (!e) return { x: 0, y: 0 };
681
+ const s = e.clientWidth, u = e.clientHeight, y = a?.naturalWidth || 0, z = a?.naturalHeight || 0;
682
+ let X = s, J = u;
683
+ if (y > 0 && z > 0 && s > 0 && u > 0) {
684
+ const Q = Math.min(s / y, u / z);
685
+ X = y * Q, J = z * Q;
686
+ }
687
+ return {
688
+ x: Math.max(0, (X * n - s) / 2),
689
+ y: Math.max(0, (J * n - u) / 2)
690
+ };
691
+ }, []), $ = B(
692
+ (n, e, a) => {
693
+ const s = ve(n, G, Ie), u = C(s);
694
+ W(a), O(s), H({
695
+ x: ve(e.x, -u.x, u.x),
696
+ y: ve(e.y, -u.y, u.y)
697
+ });
698
+ },
699
+ [C]
700
+ ), Y = B(
701
+ (n, e, a, s) => {
702
+ const u = D.current, y = ve(n, G, Ie), z = y / u.scale;
703
+ $(
704
+ y,
705
+ {
706
+ x: e - (e - u.offset.x) * z,
707
+ y: a - (a - u.offset.y) * z
708
+ },
709
+ s
710
+ );
711
+ },
712
+ [$]
713
+ ), L = B(() => {
714
+ $(G, { x: 0, y: 0 }, !0);
715
+ }, [$]), K = B(
716
+ (n) => {
717
+ Y(D.current.scale * n, 0, 0, !0);
718
+ },
719
+ [Y]
720
+ );
721
+ Me.useImperativeHandle(
722
+ T,
723
+ () => ({
724
+ zoomIn: () => K(1.5),
725
+ zoomOut: () => K(1 / 1.5),
726
+ reset: L
727
+ }),
728
+ [K, L]
729
+ ), M(() => {
730
+ W(!1), O(G), H({ x: 0, y: 0 });
731
+ }, [t]), M(() => {
732
+ const n = v.current;
733
+ S(!!(n?.complete && n.naturalWidth > 0));
734
+ }, [t]), M(() => {
735
+ c?.(x);
736
+ }, [x, c]), M(() => {
737
+ const n = m.current;
738
+ if (!n) return;
739
+ const e = (a) => {
740
+ a.preventDefault();
741
+ const s = n.getBoundingClientRect(), u = a.clientX - s.left - s.width / 2, y = a.clientY - s.top - s.height / 2, z = Math.exp(-a.deltaY * wn);
742
+ Y(D.current.scale * z, u, y, !1);
743
+ };
744
+ return n.addEventListener("wheel", e, { passive: !1 }), () => n.removeEventListener("wheel", e);
745
+ }, [Y]);
746
+ const _ = B(
747
+ (n, e) => {
748
+ const a = m.current;
749
+ if (!a) return;
750
+ if (D.current.scale > G) {
751
+ L();
752
+ return;
753
+ }
754
+ const s = a.getBoundingClientRect();
755
+ Y(
756
+ gn,
757
+ n - s.left - s.width / 2,
758
+ e - s.top - s.height / 2,
759
+ !0
760
+ );
761
+ },
762
+ [L, Y]
763
+ ), ee = B((n) => {
764
+ n.button === 0 && (D.current.scale <= G || (n.preventDefault(), j.current = { x: n.clientX, y: n.clientY }, I(!0)));
765
+ }, []);
766
+ M(() => {
767
+ if (!V || typeof window > "u") return;
768
+ const n = (a) => {
769
+ const s = j.current;
770
+ if (!s) return;
771
+ const u = D.current;
772
+ $(
773
+ u.scale,
774
+ {
775
+ x: u.offset.x + (a.clientX - s.x),
776
+ y: u.offset.y + (a.clientY - s.y)
777
+ },
778
+ !1
779
+ ), j.current = { x: a.clientX, y: a.clientY };
780
+ }, e = () => {
781
+ j.current = null, I(!1);
782
+ };
783
+ return window.addEventListener("mousemove", n), window.addEventListener("mouseup", e), () => {
784
+ window.removeEventListener("mousemove", n), window.removeEventListener("mouseup", e);
785
+ };
786
+ }, [V, $]);
787
+ const ne = B((n) => {
788
+ if (n.touches.length === 2) {
789
+ const [a, s] = [n.touches[0], n.touches[1]];
790
+ R.current = {
791
+ startX: 0,
792
+ startY: 0,
793
+ lastX: 0,
794
+ lastY: 0,
795
+ pinchDistance: Math.hypot(
796
+ a.clientX - s.clientX,
797
+ a.clientY - s.clientY
798
+ ),
799
+ pinchScale: D.current.scale,
800
+ panning: !1,
801
+ moved: !1
802
+ };
803
+ return;
804
+ }
805
+ const e = n.touches[0];
806
+ e && (R.current = {
807
+ startX: e.clientX,
808
+ startY: e.clientY,
809
+ lastX: e.clientX,
810
+ lastY: e.clientY,
811
+ pinchDistance: 0,
812
+ pinchScale: D.current.scale,
813
+ panning: D.current.scale > G,
814
+ moved: !1
815
+ });
816
+ }, []), de = B(
817
+ (n) => {
818
+ const e = R.current;
819
+ if (!e) return;
820
+ if (n.touches.length === 2 && e.pinchDistance > 0) {
821
+ const [s, u] = [n.touches[0], n.touches[1]], y = Math.hypot(
822
+ s.clientX - u.clientX,
823
+ s.clientY - u.clientY
824
+ ), z = m.current;
825
+ if (!z || y <= 0) return;
826
+ const X = z.getBoundingClientRect(), J = (s.clientX + u.clientX) / 2 - X.left - X.width / 2, Q = (s.clientY + u.clientY) / 2 - X.top - X.height / 2;
827
+ e.moved = !0, Y(
828
+ e.pinchScale * y / e.pinchDistance,
829
+ J,
830
+ Q,
831
+ !1
832
+ );
833
+ return;
834
+ }
835
+ const a = n.touches[0];
836
+ if (a) {
837
+ if ((Math.abs(a.clientX - e.startX) > 6 || Math.abs(a.clientY - e.startY) > 6) && (e.moved = !0), e.panning) {
838
+ const s = D.current;
839
+ $(
840
+ s.scale,
841
+ {
842
+ x: s.offset.x + (a.clientX - e.lastX),
843
+ y: s.offset.y + (a.clientY - e.lastY)
844
+ },
845
+ !1
846
+ );
847
+ }
848
+ e.lastX = a.clientX, e.lastY = a.clientY;
849
+ }
850
+ },
851
+ [$, Y]
852
+ ), re = B(
853
+ (n) => {
854
+ const e = R.current;
855
+ if (!e || n.touches.length > 0) return;
856
+ if (R.current = null, !e.moved && e.pinchDistance === 0) {
857
+ const u = Date.now(), y = P.current;
858
+ if (y && u - y.time < bn && Math.abs(y.x - e.startX) < Je && Math.abs(y.y - e.startY) < Je) {
859
+ P.current = null, _(e.startX, e.startY);
860
+ return;
861
+ }
862
+ P.current = {
863
+ time: u,
864
+ x: e.startX,
865
+ y: e.startY
866
+ };
867
+ return;
868
+ }
869
+ if (e.panning || e.pinchDistance > 0 || D.current.scale > G) return;
870
+ const a = e.lastX - e.startX, s = e.lastY - e.startY;
871
+ Math.abs(a) < mn || Math.abs(a) <= Math.abs(s) || (a < 0 ? E?.() : l?.());
872
+ },
873
+ [E, l, _]
874
+ ), oe = B(
875
+ (n) => {
876
+ _(n.clientX, n.clientY);
877
+ },
878
+ [_]
879
+ ), d = te(
880
+ () => `translate(${A.x}px, ${A.y}px) scale(${x})`,
881
+ [A.x, A.y, x]
882
+ );
883
+ return /* @__PURE__ */ b(
884
+ xn,
885
+ {
886
+ ref: m,
887
+ "data-testid": "image-lightbox-viewport",
888
+ onMouseDown: ee,
889
+ onDoubleClick: oe,
890
+ onTouchStart: ne,
891
+ onTouchMove: de,
892
+ onTouchEnd: re,
893
+ onTouchCancel: re,
894
+ children: [
895
+ i && /* @__PURE__ */ r(
896
+ En,
897
+ {
898
+ src: Le(i),
899
+ alt: "",
900
+ "aria-hidden": "true",
901
+ draggable: !1,
902
+ $hidden: N,
903
+ "data-testid": "image-lightbox-preview"
904
+ }
905
+ ),
906
+ !N && /* @__PURE__ */ b(yn, { role: "status", "data-testid": "image-lightbox-spinner", children: [
907
+ /* @__PURE__ */ r(
908
+ "span",
909
+ {
910
+ style: {
911
+ position: "absolute",
912
+ width: 1,
913
+ height: 1,
914
+ overflow: "hidden",
915
+ clip: "rect(0 0 0 0)",
916
+ whiteSpace: "nowrap"
917
+ },
918
+ children: g
919
+ }
920
+ ),
921
+ /* @__PURE__ */ b("svg", { viewBox: "0 0 40 40", "aria-hidden": "true", children: [
922
+ /* @__PURE__ */ r(
923
+ "circle",
924
+ {
925
+ cx: "20",
926
+ cy: "20",
927
+ r: "16",
928
+ fill: "none",
929
+ stroke: "rgba(255, 255, 255, 0.22)",
930
+ strokeWidth: "3"
931
+ }
932
+ ),
933
+ /* @__PURE__ */ r(
934
+ "circle",
935
+ {
936
+ cx: "20",
937
+ cy: "20",
938
+ r: "16",
939
+ fill: "none",
940
+ stroke: "#ffffff",
941
+ strokeWidth: "3",
942
+ strokeLinecap: "round",
943
+ strokeDasharray: "28 72"
944
+ }
945
+ )
946
+ ] })
947
+ ] }),
948
+ /* @__PURE__ */ r(
949
+ kn,
950
+ {
951
+ ref: v,
952
+ "data-testid": "image-lightbox-image",
953
+ src: Le(t),
954
+ alt: o,
955
+ draggable: !1,
956
+ onLoad: () => S(!0),
957
+ onError: w,
958
+ $grabbing: V,
959
+ $pannable: x > G,
960
+ $animate: k,
961
+ $loaded: N,
962
+ style: { transform: d }
963
+ }
964
+ )
965
+ ]
966
+ }
967
+ );
968
+ }
969
+ );
970
+ dt.displayName = "ImageLightbox";
971
+ const ie = (t) => String(t ?? "").trim(), ye = (t) => [ie(t?.firstName), ie(t?.lastName)].filter(Boolean).join(" "), Ee = (t) => {
972
+ const o = ie(t);
973
+ return o && !Pt(o) ? o : "";
974
+ }, Pn = ({
975
+ sender: t,
976
+ usersSet: o,
977
+ me: i,
978
+ peerRoomName: g
979
+ }) => {
980
+ if (!t) return { name: "" };
981
+ const E = [t.username, t.id].map((v) => Ue(ie(v))).filter(Boolean), l = E.map((v) => o?.[v]).find((v) => v && (ye(v) || v.profileImage)), w = Ue(ie(i?.xmppUsername)), c = !!w && E.includes(w), T = ye(t) || Ee(t.name) || ye(l) || (c ? ye(i) || Ee(i?.name) : "") || E.map(Ee).find(Boolean) || Ee(g) || "", m = ie(t.photo) || ie(l?.profileImage) || (c ? ie(i?.profileImage) : "") || void 0;
982
+ return { name: T, photo: m };
983
+ }, Z = "#f5f7fa", ut = "rgba(245, 247, 250, 0.68)", fe = "rgba(255, 255, 255, 0.08)", ft = "rgba(255, 255, 255, 0.18)", ht = "var(--ethora-color-primary, #0052cd)", Sn = Ae`
984
+ from { opacity: 0; transform: scale(0.98); }
985
+ to { opacity: 1; transform: scale(1); }
986
+ `, Rn = Ae`
987
+ from { opacity: 1; transform: scale(1); }
988
+ to { opacity: 0; transform: scale(0.98); }
989
+ `, Ln = f.div`
990
+ position: fixed;
991
+ top: 0;
992
+ right: 0;
993
+ bottom: 0;
994
+ left: 0;
995
+ z-index: 1001;
996
+ display: flex;
997
+ flex-direction: column;
998
+ box-sizing: border-box;
999
+ color: ${Z};
1000
+ background-color: rgba(10, 12, 18, 0.92);
1001
+ -webkit-backdrop-filter: blur(8px);
1002
+ backdrop-filter: blur(8px);
1003
+ animation: ${({ $closing: t }) => t ? ke`${Rn} 160ms ease-in forwards` : ke`${Sn} 160ms ease-out both`};
1004
+ ${$e}
1005
+
1006
+ /* Without backdrop-filter the translucent colour would sit over the chat
1007
+ and read as a smudge; go solid instead. */
1008
+ @supports not ((backdrop-filter: blur(8px)) or (-webkit-backdrop-filter: blur(8px))) {
1009
+ background-color: #0a0c12;
1010
+ }
1011
+ `, Tn = f.header`
1012
+ display: flex;
1013
+ align-items: center;
1014
+ gap: 12px;
1015
+ flex: 0 0 auto;
1016
+ min-height: 64px;
1017
+ padding: 10px 16px;
1018
+ box-sizing: border-box;
1019
+ `, Cn = f.div`
1020
+ display: flex;
1021
+ align-items: center;
1022
+ gap: 12px;
1023
+ flex: 1 1 auto;
1024
+ min-width: 0;
1025
+ `, Mn = f.div`
1026
+ display: flex;
1027
+ flex-direction: column;
1028
+ min-width: 0;
1029
+ line-height: 1.3;
1030
+ `, In = f.span`
1031
+ font-size: 15px;
1032
+ font-weight: 600;
1033
+ color: ${Z};
1034
+ overflow: hidden;
1035
+ text-overflow: ellipsis;
1036
+ white-space: nowrap;
1037
+ `, $n = f.span`
1038
+ font-size: 13px;
1039
+ color: ${ut};
1040
+ overflow: hidden;
1041
+ text-overflow: ellipsis;
1042
+ white-space: nowrap;
1043
+ `, An = f.div`
1044
+ display: flex;
1045
+ align-items: center;
1046
+ gap: 8px;
1047
+ flex: 0 0 auto;
1048
+ `, ce = f.button`
1049
+ display: inline-flex;
1050
+ align-items: center;
1051
+ justify-content: center;
1052
+ width: 40px;
1053
+ height: 40px;
1054
+ padding: 0;
1055
+ margin: 0;
1056
+ flex: 0 0 auto;
1057
+ border: 0;
1058
+ border-radius: 50%;
1059
+ background-color: ${fe};
1060
+ color: ${Z};
1061
+ cursor: pointer;
1062
+ transition: background-color 150ms ease;
1063
+
1064
+ &:hover:not(:disabled) {
1065
+ background-color: ${ft};
1066
+ }
1067
+
1068
+ &:focus-visible {
1069
+ outline: 2px solid ${Z};
1070
+ outline-offset: 2px;
1071
+ }
1072
+
1073
+ &:disabled {
1074
+ opacity: 0.35;
1075
+ cursor: default;
1076
+ }
1077
+ `, Dn = f.div`
1078
+ position: relative;
1079
+ display: flex;
1080
+ flex: 1 1 0;
1081
+ align-items: center;
1082
+ justify-content: center;
1083
+ min-height: 0;
1084
+ min-width: 0;
1085
+ overflow: hidden;
1086
+ `, On = f.div`
1087
+ position: relative;
1088
+ display: flex;
1089
+ align-items: center;
1090
+ justify-content: center;
1091
+ box-sizing: border-box;
1092
+ min-width: 0;
1093
+ min-height: 0;
1094
+ ${({ $fit: t }) => t === "media" ? ke`
1095
+ width: min(92vw, 100%);
1096
+ height: min(82vh, 100%);
1097
+ ` : ke`
1098
+ max-width: 92vw;
1099
+ max-height: 100%;
1100
+ `}
1101
+ `, Qe = f.button`
1102
+ position: absolute;
1103
+ top: 50%;
1104
+ ${({ $side: t }) => t === "left" ? "left: 12px;" : "right: 12px;"}
1105
+ z-index: 2;
1106
+ display: inline-flex;
1107
+ align-items: center;
1108
+ justify-content: center;
1109
+ width: 44px;
1110
+ height: 44px;
1111
+ padding: 0;
1112
+ margin: 0;
1113
+ transform: translateY(-50%);
1114
+ border: 0;
1115
+ border-radius: 50%;
1116
+ background-color: rgba(10, 12, 18, 0.55);
1117
+ color: ${Z};
1118
+ cursor: pointer;
1119
+ transition: background-color 150ms ease, opacity 150ms ease;
1120
+
1121
+ &:hover:not(:disabled) {
1122
+ background-color: rgba(10, 12, 18, 0.8);
1123
+ }
1124
+
1125
+ &:focus-visible {
1126
+ outline: 2px solid ${Z};
1127
+ outline-offset: 2px;
1128
+ }
1129
+
1130
+ &:disabled {
1131
+ opacity: 0.3;
1132
+ cursor: default;
1133
+ }
1134
+ `, zn = f.div`
1135
+ display: flex;
1136
+ flex-direction: column;
1137
+ gap: 10px;
1138
+ flex: 0 0 auto;
1139
+ padding: 10px 16px 16px;
1140
+ box-sizing: border-box;
1141
+ `, Un = f.div`
1142
+ display: flex;
1143
+ align-items: center;
1144
+ gap: 8px;
1145
+ overflow-x: auto;
1146
+ overscroll-behavior-x: contain;
1147
+ padding: 4px 4px;
1148
+ scrollbar-width: thin;
1149
+ scrollbar-color: ${ft} transparent;
1150
+
1151
+ /* Touch users scroll by swipe; the bar only adds noise there. */
1152
+ @media (pointer: coarse) {
1153
+ scrollbar-width: none;
1154
+ &::-webkit-scrollbar {
1155
+ display: none;
1156
+ }
1157
+ }
1158
+ `, _n = f.button`
1159
+ position: relative;
1160
+ flex: 0 0 auto;
1161
+ width: 48px;
1162
+ height: 48px;
1163
+ padding: 0;
1164
+ margin: 0;
1165
+ overflow: hidden;
1166
+ border: 0;
1167
+ border-radius: 8px;
1168
+ background-color: ${fe};
1169
+ cursor: pointer;
1170
+ opacity: ${({ $active: t }) => t ? 1 : 0.6};
1171
+ box-shadow: ${({ $active: t }) => t ? `0 0 0 2px #0a0c12, 0 0 0 4px ${ht}` : "0 0 0 0 transparent"};
1172
+ transition: opacity 150ms ease, box-shadow 150ms ease;
1173
+
1174
+ &:hover {
1175
+ opacity: 1;
1176
+ }
1177
+
1178
+ &:focus-visible {
1179
+ outline: 2px solid ${Z};
1180
+ outline-offset: 2px;
1181
+ }
1182
+ `, Bn = f.img`
1183
+ display: block;
1184
+ width: 100%;
1185
+ height: 100%;
1186
+ object-fit: cover;
1187
+ pointer-events: none;
1188
+ `, Nn = () => /* @__PURE__ */ r(
1189
+ "span",
1190
+ {
1191
+ "aria-hidden": "true",
1192
+ style: {
1193
+ position: "absolute",
1194
+ inset: 0,
1195
+ display: "flex",
1196
+ alignItems: "center",
1197
+ justifyContent: "center",
1198
+ pointerEvents: "none",
1199
+ color: "#fff",
1200
+ background: "rgba(0, 0, 0, 0.25)"
1201
+ },
1202
+ children: /* @__PURE__ */ r("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ r("path", { d: "M8 5.5v13a1 1 0 0 0 1.5.86l10.5-6.5a1 1 0 0 0 0-1.72L9.5 4.64A1 1 0 0 0 8 5.5z" }) })
1203
+ }
1204
+ ), Wn = () => /* @__PURE__ */ r(
1205
+ "span",
1206
+ {
1207
+ "aria-hidden": "true",
1208
+ style: {
1209
+ display: "block",
1210
+ width: "100%",
1211
+ height: "100%",
1212
+ background: "linear-gradient(135deg, #2a3350, #151a2b)"
1213
+ }
1214
+ }
1215
+ ), Xn = f.div`
1216
+ display: grid;
1217
+ grid-template-columns: 1fr auto 1fr;
1218
+ align-items: center;
1219
+ gap: 8px;
1220
+ `, Fn = f.span`
1221
+ justify-self: center;
1222
+ padding: 6px 14px;
1223
+ border-radius: 999px;
1224
+ background-color: ${fe};
1225
+ color: ${Z};
1226
+ font-size: 13px;
1227
+ font-variant-numeric: tabular-nums;
1228
+ white-space: nowrap;
1229
+ `, Yn = f.div`
1230
+ justify-self: end;
1231
+ display: flex;
1232
+ align-items: center;
1233
+ gap: 6px;
1234
+ `, De = f.div`
1235
+ display: flex;
1236
+ flex-direction: column;
1237
+ align-items: center;
1238
+ justify-content: center;
1239
+ gap: 16px;
1240
+ max-width: min(440px, 92vw);
1241
+ padding: 32px 24px;
1242
+ box-sizing: border-box;
1243
+ text-align: center;
1244
+ border-radius: 16px;
1245
+ background-color: rgba(255, 255, 255, 0.05);
1246
+ color: ${Z};
1247
+ `, Oe = f.h2`
1248
+ margin: 0;
1249
+ font-size: 18px;
1250
+ font-weight: 600;
1251
+ line-height: 1.3;
1252
+ color: ${Z};
1253
+ `, Hn = f.p`
1254
+ margin: 0;
1255
+ font-size: 14px;
1256
+ line-height: 1.5;
1257
+ color: ${ut};
1258
+ overflow-wrap: anywhere;
1259
+ `, jn = f.div`
1260
+ display: flex;
1261
+ flex-wrap: wrap;
1262
+ align-items: center;
1263
+ justify-content: center;
1264
+ gap: 10px;
1265
+ `, pt = f.button`
1266
+ display: inline-flex;
1267
+ align-items: center;
1268
+ justify-content: center;
1269
+ gap: 8px;
1270
+ min-height: 40px;
1271
+ padding: 0 18px;
1272
+ border-radius: 999px;
1273
+ font: inherit;
1274
+ font-size: 14px;
1275
+ font-weight: 600;
1276
+ cursor: pointer;
1277
+ transition: background-color 150ms ease;
1278
+
1279
+ &:focus-visible {
1280
+ outline: 2px solid ${Z};
1281
+ outline-offset: 2px;
1282
+ }
1283
+ `, gt = f(pt)`
1284
+ border: 0;
1285
+ background-color: ${ht};
1286
+ color: #ffffff;
1287
+
1288
+ &:hover {
1289
+ filter: brightness(1.1);
1290
+ }
1291
+ `, Vn = f(pt)`
1292
+ border: 1px solid rgba(255, 255, 255, 0.28);
1293
+ background-color: transparent;
1294
+ color: ${Z};
1295
+
1296
+ &:hover {
1297
+ background-color: ${fe};
1298
+ }
1299
+ `, Gn = f.span`
1300
+ display: inline-flex;
1301
+ --ethora-unavailable-ring: #14171f;
1302
+ --ethora-color-bg: #14171f;
1303
+ --ethora-unavailable-accent: #f5b544;
1304
+ > span {
1305
+ color: #9cc0ff;
1306
+ }
1307
+ `, Zn = ({
1308
+ onRetry: t,
1309
+ onDownload: o
1310
+ }) => {
1311
+ const i = Pe();
1312
+ return /* @__PURE__ */ b(De, { role: "alert", "data-testid": "file-viewer-error", children: [
1313
+ /* @__PURE__ */ r(Gn, { children: /* @__PURE__ */ r(St, { size: 88 }) }),
1314
+ /* @__PURE__ */ r(Oe, { children: i("modal.filePreview.unavailable") }),
1315
+ /* @__PURE__ */ b(jn, { children: [
1316
+ /* @__PURE__ */ b(Vn, { type: "button", onClick: t, children: [
1317
+ /* @__PURE__ */ r(er, {}),
1318
+ i("modal.filePreview.retry")
1319
+ ] }),
1320
+ /* @__PURE__ */ b(gt, { type: "button", onClick: o, children: [
1321
+ /* @__PURE__ */ r(bt, {}),
1322
+ i("modal.filePreview.download")
1323
+ ] })
1324
+ ] })
1325
+ ] });
1326
+ }, Kn = ({
1327
+ fileName: t,
1328
+ unsupportedText: o,
1329
+ onDownload: i
1330
+ }) => {
1331
+ const g = Pe(), E = it(t).toUpperCase();
1332
+ return /* @__PURE__ */ b(De, { "data-testid": "file-viewer-file-card", children: [
1333
+ /* @__PURE__ */ b(mt, { "aria-hidden": "true", children: [
1334
+ /* @__PURE__ */ r(tr, {}),
1335
+ E && /* @__PURE__ */ r(Jn, { children: E })
1336
+ ] }),
1337
+ /* @__PURE__ */ r(Oe, { style: { overflowWrap: "anywhere" }, children: t || g("modal.filePreview.fileLabel") }),
1338
+ /* @__PURE__ */ r(Hn, { children: o }),
1339
+ /* @__PURE__ */ b(gt, { type: "button", onClick: i, children: [
1340
+ /* @__PURE__ */ r(bt, {}),
1341
+ g("modal.filePreview.download")
1342
+ ] })
1343
+ ] });
1344
+ }, qn = ({ fileName: t, src: o }) => /* @__PURE__ */ b(De, { "data-testid": "file-viewer-audio-card", children: [
1345
+ /* @__PURE__ */ r(mt, { "aria-hidden": "true", children: /* @__PURE__ */ r(nr, {}) }),
1346
+ /* @__PURE__ */ r(Oe, { style: { overflowWrap: "anywhere" }, children: t }),
1347
+ /* @__PURE__ */ r(
1348
+ "audio",
1349
+ {
1350
+ controls: !0,
1351
+ preload: "metadata",
1352
+ src: o,
1353
+ style: { width: "100%", maxWidth: 360 }
1354
+ }
1355
+ )
1356
+ ] }), mt = f.div`
1357
+ position: relative;
1358
+ display: flex;
1359
+ align-items: center;
1360
+ justify-content: center;
1361
+ width: 96px;
1362
+ height: 116px;
1363
+ border-radius: 12px;
1364
+ background-color: ${fe};
1365
+ color: ${Z};
1366
+ `, Jn = f.span`
1367
+ position: absolute;
1368
+ bottom: 14px;
1369
+ left: 0;
1370
+ right: 0;
1371
+ font-size: 11px;
1372
+ font-weight: 700;
1373
+ letter-spacing: 0.06em;
1374
+ text-align: center;
1375
+ `, he = {
1376
+ width: 20,
1377
+ height: 20,
1378
+ viewBox: "0 0 24 24",
1379
+ fill: "none",
1380
+ stroke: "currentColor",
1381
+ strokeWidth: 1.6,
1382
+ strokeLinecap: "round",
1383
+ strokeLinejoin: "round",
1384
+ "aria-hidden": !0,
1385
+ focusable: !1
1386
+ }, Qn = () => /* @__PURE__ */ b("svg", { ...he, children: [
1387
+ /* @__PURE__ */ r("path", { d: "M14 4h6v6" }),
1388
+ /* @__PURE__ */ r("path", { d: "M20 4l-9 9" }),
1389
+ /* @__PURE__ */ r("path", { d: "M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5" })
1390
+ ] }), er = () => /* @__PURE__ */ b("svg", { ...he, width: 16, height: 16, children: [
1391
+ /* @__PURE__ */ r("path", { d: "M20 12a8 8 0 1 1-2.34-5.66" }),
1392
+ /* @__PURE__ */ r("path", { d: "M20 4v4h-4" })
1393
+ ] }), bt = () => /* @__PURE__ */ b("svg", { ...he, width: 16, height: 16, children: [
1394
+ /* @__PURE__ */ r("path", { d: "M12 4v11" }),
1395
+ /* @__PURE__ */ r("path", { d: "M7 10l5 5 5-5" }),
1396
+ /* @__PURE__ */ r("path", { d: "M5 20h14" })
1397
+ ] }), tr = () => /* @__PURE__ */ b("svg", { ...he, width: 36, height: 36, strokeWidth: 1.3, children: [
1398
+ /* @__PURE__ */ r("path", { d: "M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z" }),
1399
+ /* @__PURE__ */ r("path", { d: "M14 3v5h5" })
1400
+ ] }), nr = () => /* @__PURE__ */ b("svg", { ...he, width: 36, height: 36, strokeWidth: 1.3, children: [
1401
+ /* @__PURE__ */ r("path", { d: "M9 18V5l11-2v13" }),
1402
+ /* @__PURE__ */ r("circle", { cx: "6", cy: "18", r: "3" }),
1403
+ /* @__PURE__ */ r("circle", { cx: "17", cy: "16", r: "3" })
1404
+ ] }), rr = (t) => {
1405
+ if (!t) return "";
1406
+ const o = new Date(t);
1407
+ if (Number.isNaN(o.getTime())) return "";
1408
+ try {
1409
+ return o.toLocaleString(void 0, {
1410
+ dateStyle: "medium",
1411
+ timeStyle: "short"
1412
+ });
1413
+ } catch {
1414
+ return o.toISOString();
1415
+ }
1416
+ }, or = (t, o) => {
1417
+ if (!t || o <= 0) return t;
1418
+ const i = t.includes("?") ? "&" : "?";
1419
+ return `${t}${i}retry=${o}`;
1420
+ }, ir = (t) => {
1421
+ const o = t, i = o?.tagName;
1422
+ return i === "INPUT" || i === "TEXTAREA" || i === "SELECT" || !!o?.isContentEditable;
1423
+ }, ar = () => typeof window < "u" && typeof window.matchMedia == "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches, sr = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), audio[controls], video[controls], [tabindex]:not([tabindex="-1"])', ur = ({
1424
+ handleCloseModal: t
1425
+ }) => {
1426
+ const o = Rt(), i = Pe(), g = Lt(), { activeFile: E } = le(
1427
+ (h) => h.chatSettingStore
1428
+ ), l = te(
1429
+ () => E ?? { fileName: "", fileURL: "", mimetype: "" },
1430
+ [E]
1431
+ ), w = le(
1432
+ (h) => h.chatSettingStore.user?.fileToken || ""
1433
+ ), c = le(
1434
+ (h) => _e(h)?.messages
1435
+ ), T = le((h) => h.rooms.usersSet), m = le((h) => h.chatSettingStore.user), v = le((h) => {
1436
+ const p = _e(h);
1437
+ return p?.type === "private" ? String(p?.title || p?.name || "") : "";
1438
+ }), N = U(null), S = U(null), x = U([]), [O, A] = F(G), [H, k] = F(null), [W, V] = F(
1439
+ null
1440
+ ), I = Tt(l?.mimetype, l?.fileName), D = te(() => Ct(c), [c]), j = l.siblings, R = te(() => {
1441
+ if (Se(D, l) >= 0) return D;
1442
+ const h = Mt(j);
1443
+ return Se(h, l) >= 0 ? h : D;
1444
+ }, [D, j, l]), P = te(
1445
+ () => I === "image" || I === "video" ? Se(R, l) : -1,
1446
+ [R, l, I]
1447
+ ), C = P >= 0 && R.length > 1, $ = C && P > 0, Y = C && P < R.length - 1, L = P >= 0 ? R[P] : void 0, K = L?.fileName || l.fileName, _ = L?.sender ?? l.sender, ee = te(
1448
+ () => Pn({
1449
+ sender: _,
1450
+ usersSet: T,
1451
+ me: m,
1452
+ peerRoomName: v
1453
+ }),
1454
+ [_, T, m, v]
1455
+ ), ne = ee.name, de = rr(L?.date ?? l.date), re = !!l.fileURL, oe = I === "image" && (!re || H === l.fileURL), d = te(() => {
1456
+ const h = ue(l.fileURL, w);
1457
+ return W?.url === l.fileURL ? or(h, W.count) : h;
1458
+ }, [l.fileURL, w, W]), n = L?.previewURL ? ue(L.previewURL, w) : void 0, e = B(
1459
+ (h) => {
1460
+ const p = R[h];
1461
+ p && o(
1462
+ Be({
1463
+ fileName: p.fileName,
1464
+ fileURL: p.fileURL,
1465
+ mimetype: p.mimetype,
1466
+ // Keep the opener's list so paging never loses it.
1467
+ siblings: j
1468
+ })
1469
+ );
1470
+ },
1471
+ [o, R, j]
1472
+ ), a = B(() => {
1473
+ $ && e(P - 1);
1474
+ }, [e, $, P]), s = B(() => {
1475
+ Y && e(P + 1);
1476
+ }, [e, Y, P]);
1477
+ M(() => {
1478
+ !C || typeof Image > "u" || [P - 1, P + 1].forEach((h) => {
1479
+ const p = R[h];
1480
+ if (!p || p.kind !== "image") return;
1481
+ const q = ue(p.fileURL, w);
1482
+ q && (new Image().src = q);
1483
+ });
1484
+ }, [C, P, R, w]), M(() => {
1485
+ if (!C) return;
1486
+ x.current[P]?.scrollIntoView?.({
1487
+ block: "nearest",
1488
+ inline: "center",
1489
+ behavior: ar() ? "auto" : "smooth"
1490
+ });
1491
+ }, [C, P]), M(() => {
1492
+ if (typeof document > "u") return;
1493
+ const h = document.body.style.overflow;
1494
+ return document.body.style.overflow = "hidden", () => {
1495
+ document.body.style.overflow = h;
1496
+ };
1497
+ }, []), M(() => {
1498
+ if (typeof document > "u") return;
1499
+ const h = (p) => {
1500
+ if (!p.defaultPrevented && !(p.altKey || p.ctrlKey || p.metaKey) && !ir(p.target)) {
1501
+ if (p.key === "ArrowLeft" || p.key === "ArrowRight") {
1502
+ if (!C) return;
1503
+ const q = p.target?.tagName;
1504
+ if (q === "VIDEO" || q === "AUDIO") return;
1505
+ p.preventDefault(), p.key === "ArrowLeft" ? a() : s();
1506
+ return;
1507
+ }
1508
+ I !== "image" || oe || (p.key === "+" || p.key === "=" ? (p.preventDefault(), S.current?.zoomIn()) : p.key === "-" || p.key === "_" ? (p.preventDefault(), S.current?.zoomOut()) : p.key === "0" && (p.preventDefault(), S.current?.reset()));
1509
+ }
1510
+ };
1511
+ return document.addEventListener("keydown", h), () => document.removeEventListener("keydown", h);
1512
+ }, [C, a, s, I, oe]);
1513
+ const u = () => {
1514
+ const q = !!it(l.fileName) ? l.fileName : `MEDIA-ETHORA.${I === "image" ? "png" : I === "video" ? "mp4" : "bin"}`;
1515
+ Wt(Ne(l.fileURL), q).catch((be) => {
1516
+ zt.log(be);
1517
+ });
1518
+ }, y = () => {
1519
+ re && window.open(
1520
+ Ne(l.fileURL),
1521
+ "_blank",
1522
+ "noopener,noreferrer"
1523
+ );
1524
+ }, z = () => {
1525
+ o(Be(void 0)), t?.();
1526
+ }, X = (h) => {
1527
+ h.target === h.currentTarget && z();
1528
+ }, J = () => {
1529
+ et(l.fileURL) && tt(), k(l.fileURL);
1530
+ }, Q = () => {
1531
+ V({
1532
+ url: l.fileURL,
1533
+ count: (W?.url === l.fileURL ? W.count : 0) + 1
1534
+ }), k(null);
1535
+ }, se = (h) => {
1536
+ if (h.key !== "Tab" || !N.current) return;
1537
+ const p = Array.from(
1538
+ N.current.querySelectorAll(sr)
1539
+ ).filter((vt) => !vt.hasAttribute("disabled"));
1540
+ if (p.length === 0) return;
1541
+ const q = p[0], be = p[p.length - 1], we = document.activeElement, ze = !we || !N.current.contains(we);
1542
+ h.shiftKey && (we === q || ze) ? (h.preventDefault(), be.focus()) : !h.shiftKey && (we === be || ze) && (h.preventDefault(), q.focus());
1543
+ }, pe = l.fileName || i("modal.filePreview.imageAlt"), wt = i("modal.filePreview.unsupported"), ge = ue(l.fileURL, w);
1544
+ let ae, me = "media";
1545
+ if (oe)
1546
+ me = "content", ae = /* @__PURE__ */ r(Zn, { onRetry: Q, onDownload: u });
1547
+ else
1548
+ switch (I) {
1549
+ case "image":
1550
+ ae = /* @__PURE__ */ r(
1551
+ dt,
1552
+ {
1553
+ ref: S,
1554
+ src: d,
1555
+ previewSrc: n,
1556
+ alt: pe,
1557
+ loadingLabel: i("modal.filePreview.loading"),
1558
+ onScaleChange: A,
1559
+ onSwipeLeft: s,
1560
+ onSwipeRight: a,
1561
+ onError: J
1562
+ }
1563
+ );
1564
+ break;
1565
+ case "video":
1566
+ ae = /* @__PURE__ */ r(
1567
+ Ut,
1568
+ {
1569
+ src: ge,
1570
+ controls: !0,
1571
+ autoPlay: !1
1572
+ },
1573
+ ge
1574
+ );
1575
+ break;
1576
+ case "audio":
1577
+ me = "content", ae = /* @__PURE__ */ r(qn, { fileName: K, src: ge });
1578
+ break;
1579
+ case "pdf":
1580
+ ae = /* @__PURE__ */ r(pn, { pdfUrl: ge });
1581
+ break;
1582
+ default:
1583
+ me = "content", ae = /* @__PURE__ */ r(
1584
+ Kn,
1585
+ {
1586
+ fileName: K,
1587
+ unsupportedText: wt,
1588
+ onDownload: u
1589
+ }
1590
+ );
1591
+ }
1592
+ const xt = I === "image" && !oe;
1593
+ return /* @__PURE__ */ b(
1594
+ Ln,
1595
+ {
1596
+ ref: N,
1597
+ role: "dialog",
1598
+ "aria-modal": "true",
1599
+ "aria-label": i("modal.filePreview.title"),
1600
+ "data-testid": "file-viewer",
1601
+ $closing: g,
1602
+ onKeyDown: se,
1603
+ children: [
1604
+ /* @__PURE__ */ b(Tn, { children: [
1605
+ /* @__PURE__ */ b(Cn, { children: [
1606
+ _ && /* @__PURE__ */ r(
1607
+ It,
1608
+ {
1609
+ src: ee.photo,
1610
+ username: ne
1611
+ }
1612
+ ),
1613
+ /* @__PURE__ */ b(Mn, { children: [
1614
+ ne && /* @__PURE__ */ r(In, { children: ne }),
1615
+ /* @__PURE__ */ r($n, { children: [de, K].filter(Boolean).join(" · ") || i("modal.filePreview.title") })
1616
+ ] })
1617
+ ] }),
1618
+ /* @__PURE__ */ b(An, { children: [
1619
+ /* @__PURE__ */ r(
1620
+ ce,
1621
+ {
1622
+ type: "button",
1623
+ onClick: u,
1624
+ "aria-label": i("action.save"),
1625
+ title: i("action.save"),
1626
+ children: /* @__PURE__ */ r($t, { color: "currentColor" })
1627
+ }
1628
+ ),
1629
+ /* @__PURE__ */ r(
1630
+ ce,
1631
+ {
1632
+ type: "button",
1633
+ onClick: y,
1634
+ disabled: !re,
1635
+ "aria-label": i("modal.filePreview.openExternally"),
1636
+ title: i("modal.filePreview.openExternally"),
1637
+ children: /* @__PURE__ */ r(Qn, {})
1638
+ }
1639
+ ),
1640
+ /* @__PURE__ */ r(
1641
+ ce,
1642
+ {
1643
+ type: "button",
1644
+ onClick: z,
1645
+ "aria-label": i("modal.filePreview.close"),
1646
+ title: i("modal.filePreview.close"),
1647
+ children: /* @__PURE__ */ r(At, { color: "currentColor", width: 20, height: 20 })
1648
+ }
1649
+ )
1650
+ ] })
1651
+ ] }),
1652
+ /* @__PURE__ */ b(Dn, { onClick: X, "data-testid": "file-viewer-stage", children: [
1653
+ C && /* @__PURE__ */ r(
1654
+ Qe,
1655
+ {
1656
+ type: "button",
1657
+ $side: "left",
1658
+ onClick: a,
1659
+ disabled: !$,
1660
+ "aria-label": i("modal.filePreview.previousItem"),
1661
+ children: /* @__PURE__ */ r(Dt, { color: "currentColor" })
1662
+ }
1663
+ ),
1664
+ /* @__PURE__ */ r(On, { $fit: me, children: ae }),
1665
+ C && /* @__PURE__ */ r(
1666
+ Qe,
1667
+ {
1668
+ type: "button",
1669
+ $side: "right",
1670
+ onClick: s,
1671
+ disabled: !Y,
1672
+ "aria-label": i("modal.filePreview.nextItem"),
1673
+ children: /* @__PURE__ */ r(Ot, { color: "currentColor" })
1674
+ }
1675
+ )
1676
+ ] }),
1677
+ /* @__PURE__ */ b(zn, { children: [
1678
+ C && /* @__PURE__ */ r(
1679
+ Un,
1680
+ {
1681
+ role: "group",
1682
+ "aria-label": i("modal.filePreview.thumbnails"),
1683
+ "data-testid": "file-viewer-thumbnails",
1684
+ children: R.map((h, p) => /* @__PURE__ */ b(
1685
+ _n,
1686
+ {
1687
+ ref: (q) => {
1688
+ x.current[p] = q;
1689
+ },
1690
+ type: "button",
1691
+ $active: p === P,
1692
+ "aria-label": i("modal.filePreview.showItem", {
1693
+ current: p + 1,
1694
+ total: R.length
1695
+ }),
1696
+ "aria-current": p === P ? "true" : void 0,
1697
+ onClick: () => e(p),
1698
+ children: [
1699
+ h.kind === "video" && !h.previewURL ? /* @__PURE__ */ r(Wn, {}) : /* @__PURE__ */ r(
1700
+ Bn,
1701
+ {
1702
+ src: Le(
1703
+ ue(h.previewURL || h.fileURL, w)
1704
+ ),
1705
+ alt: "",
1706
+ loading: "lazy",
1707
+ draggable: !1
1708
+ }
1709
+ ),
1710
+ h.kind === "video" && /* @__PURE__ */ r(Nn, {})
1711
+ ]
1712
+ },
1713
+ h.key
1714
+ ))
1715
+ }
1716
+ ),
1717
+ /* @__PURE__ */ b(Xn, { children: [
1718
+ /* @__PURE__ */ r("span", {}),
1719
+ C ? /* @__PURE__ */ r(Fn, { "data-testid": "lightbox-position", "aria-live": "polite", children: i("modal.filePreview.position", {
1720
+ current: P + 1,
1721
+ total: R.length
1722
+ }) }) : /* @__PURE__ */ r("span", {}),
1723
+ xt ? /* @__PURE__ */ b(Yn, { children: [
1724
+ /* @__PURE__ */ r(
1725
+ ce,
1726
+ {
1727
+ type: "button",
1728
+ onClick: () => S.current?.zoomOut(),
1729
+ disabled: O <= G,
1730
+ "aria-label": i("modal.filePreview.zoomOut"),
1731
+ children: /* @__PURE__ */ r(nt, { color: "currentColor" })
1732
+ }
1733
+ ),
1734
+ /* @__PURE__ */ r(
1735
+ ce,
1736
+ {
1737
+ type: "button",
1738
+ onClick: () => S.current?.zoomIn(),
1739
+ disabled: O >= Ie,
1740
+ "aria-label": i("modal.filePreview.zoomIn"),
1741
+ children: /* @__PURE__ */ r(rt, { color: "currentColor" })
1742
+ }
1743
+ ),
1744
+ /* @__PURE__ */ r(
1745
+ ce,
1746
+ {
1747
+ type: "button",
1748
+ onClick: () => S.current?.reset(),
1749
+ disabled: O <= G,
1750
+ "aria-label": i("modal.filePreview.resetZoom"),
1751
+ children: /* @__PURE__ */ r(ot, { color: "currentColor" })
1752
+ }
1753
+ )
1754
+ ] }) : /* @__PURE__ */ r("span", {})
1755
+ ] })
1756
+ ] })
1757
+ ]
1758
+ }
1759
+ );
1760
+ };
1761
+ export {
1762
+ ur as default
1763
+ };