@ethora/chat-component 26.9.8 → 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 (101) hide show
  1. package/README.md +1 -1
  2. package/dist/{ChatProfileModal-3UH0H5Ec.js → ChatProfileModal-Bf5jGPBZ.js} +44 -44
  3. package/dist/FilePreviewModal-Bwx0RZZw.js +1763 -0
  4. package/dist/{ManageDataModal-BblTuE9g.js → ManageDataModal-Dhkp0LWH.js} +17 -17
  5. package/dist/{MarkdownBody-RMEx8yW2.js → MarkdownBody-_sUhW2O8.js} +1 -1
  6. package/dist/{MessageSearchModal-CrYR2EH8.js → MessageSearchModal-rwwWrILl.js} +40 -40
  7. package/dist/{PublicChatsModal-Bi5r4mrV.js → PublicChatsModal-Byso6_vt.js} +19 -19
  8. package/dist/{SideDrawer-CDAoobvX.js → SideDrawer-CQPOf0ek.js} +35 -35
  9. package/dist/{UserProfileModal-4Frgvam-.js → UserProfileModal-Vj2kICvc.js} +10 -10
  10. package/dist/{UserSettingsModal-C-mb-9cb.js → UserSettingsModal-CioX4ZIV.js} +5 -5
  11. package/dist/{VideoCallOverlay-92dFLb9U.js → VideoCallOverlay-DodAkiam.js} +3824 -3708
  12. package/dist/{VisibilityModal-zIAV6dAP.js → VisibilityModal-CIl7rkBM.js} +11 -11
  13. package/dist/assets/icons.d.ts +2 -3
  14. package/dist/components/Files/fileCategory.d.ts +4 -2
  15. package/dist/components/MainComponents/AlbumGrid.d.ts +22 -0
  16. package/dist/components/MainComponents/AttachmentList.d.ts +6 -6
  17. package/dist/components/MainComponents/ImageUnavailable.d.ts +21 -0
  18. package/dist/components/MainComponents/MediaUploadOverlay.d.ts +31 -0
  19. package/dist/components/MainComponents/MessageContainer.d.ts +3 -0
  20. package/dist/components/MessageBubble/MediaCaption.d.ts +9 -0
  21. package/dist/components/MessageBubble/MessageAvatarPhoto.d.ts +17 -0
  22. package/dist/components/MessageBubble/MessageReaction.d.ts +6 -0
  23. package/dist/components/MessageBubble/QuickReplies.d.ts +2 -0
  24. package/dist/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +8 -10
  25. package/dist/components/Modals/FilePreviewModal/ImageLightbox.d.ts +4 -0
  26. package/dist/components/Modals/FilePreviewModal/PdfView.d.ts +4 -0
  27. package/dist/components/Modals/FilePreviewModal/ViewerChrome.d.ts +64 -0
  28. package/dist/components/RoomComponents/LastMessageItem.d.ts +2 -0
  29. package/dist/components/RoomComponents/styled/LastMessageMedia.d.ts +19 -0
  30. package/dist/components/RoomComponents/styled/LastTextMessage.d.ts +2 -2
  31. package/dist/components/RoomComponents/styled/StyledRoomComponents.d.ts +10 -3
  32. package/dist/components/VideoCalls/VideoCallSession.d.ts +13 -0
  33. package/dist/components/styled/FileCard.d.ts +20 -0
  34. package/dist/components/styled/MediaSurface.d.ts +50 -0
  35. package/dist/components/styled/MessageImage.d.ts +9 -10
  36. package/dist/components/styled/SendInput.d.ts +12 -2
  37. package/dist/components/styled/StyledComponents.d.ts +69 -2
  38. package/dist/components/styled/StyledInputComponents/MediaComponents.d.ts +36 -24
  39. package/dist/components/styled/UnsupportedType.d.ts +1 -0
  40. package/dist/components/styled/VideoMessage.d.ts +11 -6
  41. package/dist/e2ee/callKey.d.ts +32 -0
  42. package/dist/e2ee/fileEnvelope.d.ts +16 -5
  43. package/dist/e2ee/omemo.d.ts +18 -0
  44. package/dist/firebase-messaging-sw.js +20 -3
  45. package/dist/{handleCopyClick-BtXos0AJ.js → handleCopyClick-DGaZhy_u.js} +1 -1
  46. package/dist/helpers/albumLayout.d.ts +53 -0
  47. package/dist/helpers/attachments.d.ts +22 -1
  48. package/dist/helpers/avatarImageCache.d.ts +9 -0
  49. package/dist/helpers/caption.d.ts +63 -0
  50. package/dist/helpers/composerFocus.d.ts +22 -0
  51. package/dist/helpers/createMainMessageForThread.d.ts +1 -1
  52. package/dist/helpers/downloadFile.d.ts +19 -0
  53. package/dist/helpers/fileKind.d.ts +17 -0
  54. package/dist/helpers/lastMessagePreview.d.ts +55 -0
  55. package/dist/helpers/mapWithConcurrency.d.ts +8 -0
  56. package/dist/helpers/mediaBox.d.ts +110 -0
  57. package/dist/helpers/mediaBubble.d.ts +39 -0
  58. package/dist/helpers/mediaLabel.d.ts +10 -0
  59. package/dist/helpers/mediaSendRetry.d.ts +25 -0
  60. package/dist/helpers/messageRuns.d.ts +10 -0
  61. package/dist/helpers/repairFilenameEncoding.d.ts +11 -0
  62. package/dist/helpers/roomImageGallery.d.ts +34 -0
  63. package/dist/helpers/safeUrl.d.ts +15 -0
  64. package/dist/helpers/secureFileUrl.d.ts +4 -1
  65. package/dist/helpers/viewerSender.d.ts +47 -0
  66. package/dist/hooks/useAvatarImage.d.ts +21 -0
  67. package/dist/hooks/useIsMobileViewport.d.ts +5 -0
  68. package/dist/hooks/useMediaProbe.d.ts +40 -0
  69. package/dist/hooks/usePaneWidthVar.d.ts +11 -0
  70. package/dist/hooks/usePdfThumbnail.d.ts +0 -1
  71. package/dist/hooks/usePrefersReducedMotion.d.ts +2 -0
  72. package/dist/hooks/useSendMessage.d.ts +4 -1
  73. package/dist/{main-BnLtessp.js → main-CUB_w8AZ.js} +17712 -14488
  74. package/dist/main.js +10 -10
  75. package/dist/networking/api-requests/auth.api.d.ts +2 -0
  76. package/dist/networking/callKeyStanza.d.ts +7 -0
  77. package/dist/networking/stanzaHandlers.d.ts +4 -2
  78. package/dist/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +2 -0
  79. package/dist/networking/xmpp/sendMediaMessage.xmpp.d.ts +8 -0
  80. package/dist/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +2 -0
  81. package/dist/networking/xmppClient.d.ts +5 -0
  82. package/dist/roomStore/callSlice.d.ts +6 -1
  83. package/dist/roomStore/index.d.ts +10 -0
  84. package/dist/roomStore/roomsSlice.d.ts +18 -3
  85. package/dist/styles/motion.d.ts +22 -2
  86. package/dist/types/models/attachment.model.d.ts +19 -0
  87. package/dist/types/models/config.model.d.ts +28 -2
  88. package/dist/types/models/customComponents.model.d.ts +2 -0
  89. package/dist/types/models/message.model.d.ts +9 -0
  90. package/dist/types/models/modal.model.d.ts +19 -0
  91. package/dist/types/models/room.model.d.ts +16 -0
  92. package/dist/types/models/xmpp.model.d.ts +3 -0
  93. package/dist/utils/messageNotificationContent.d.ts +34 -0
  94. package/dist/version.d.ts +1 -1
  95. package/package.json +1 -1
  96. package/public/firebase-messaging-sw.js +20 -3
  97. package/dist/FilePreviewModal-Cgj1iHry.js +0 -743
  98. package/dist/components/RoomComponents/styled/LastAudioMessage.d.ts +0 -6
  99. package/dist/components/RoomComponents/styled/LastMessageFile.d.ts +0 -6
  100. package/dist/components/RoomComponents/styled/LastMessagePhoto.d.ts +0 -6
  101. package/dist/components/RoomComponents/styled/LastMessageVideo.d.ts +0 -6
@@ -1,7 +1,7 @@
1
1
  import { jsxs as r, jsx as s } from "react/jsx-runtime";
2
2
  import { useState as b, useEffect as x } from "react";
3
- import { x as o, a as L, p as N, u as P, aM as D, aN as z } from "./main-BnLtessp.js";
4
- import { S as I, D as C, a as $, b as k, e as w, f as p } from "./SideDrawer-CDAoobvX.js";
3
+ import { E as o, a as L, x as P, u as R, aR as D, aS as z } from "./main-CUB_w8AZ.js";
4
+ import { S as I, D as C, a as $, b as k, e as S, f as p } from "./SideDrawer-CQPOf0ek.js";
5
5
  o.div``;
6
6
  o.div`
7
7
  font-size: 16px;
@@ -13,7 +13,7 @@ o.p`
13
13
  color: var(--ethora-color-text-muted, #6b7280);
14
14
  margin-bottom: 32px;
15
15
  `;
16
- const O = o.div`
16
+ const w = o.div`
17
17
  display: flex;
18
18
  flex-direction: column;
19
19
  gap: 6px;
@@ -25,7 +25,7 @@ const O = o.div`
25
25
  `, u = o.input`
26
26
  accent-color: ${({ $radioColor: i }) => i || "var(--ethora-color-primary, #0052CD)"};
27
27
  margin: 0px;
28
- `, M = o.div`
28
+ `, N = o.div`
29
29
  padding: 10px 15px;
30
30
  margin-top: 16px;
31
31
  color: ${({ type: i }) => i === "success" ? "#10b981" : "#ef4444"};
@@ -39,12 +39,12 @@ const O = o.div`
39
39
  background: ${({ type: i }) => i === "success" ? "rgba(16, 185, 129, 0.15)" : "rgba(242, 118, 107, 0.15)"};
40
40
  border-color: ${({ type: i }) => i === "success" ? "var(--ethora-color-success, #10b981)" : "var(--ethora-color-danger, #ef4444)"};
41
41
  }
42
- `, B = ({
42
+ `, M = ({
43
43
  handleCloseModal: i
44
44
  }) => {
45
- const S = L(), e = N(), { user: n, config: l } = P(
45
+ const O = L(), e = P(), { user: n, config: l } = R(
46
46
  (t) => t.chatSettingStore
47
- ), g = (t) => S(z(t)), [a, m] = b(n?.isProfileOpen), [c, v] = b(n?.isAssetsOpen), [f, y] = b(null), d = (t, A) => {
47
+ ), g = (t) => O(z(t)), [a, m] = b(n?.isProfileOpen), [c, v] = b(n?.isAssetsOpen), [f, y] = b(null), d = (t, A) => {
48
48
  y({ message: t, type: A }), setTimeout(() => y(null), 3e3);
49
49
  };
50
50
  return x(() => {
@@ -64,7 +64,7 @@ const O = o.div`
64
64
  children: [
65
65
  /* @__PURE__ */ r(C, { children: [
66
66
  /* @__PURE__ */ s($, { children: e("settings.visibility.profileLabel") }),
67
- /* @__PURE__ */ s(k, { children: /* @__PURE__ */ s(w, { children: /* @__PURE__ */ r(O, { children: [
67
+ /* @__PURE__ */ s(k, { children: /* @__PURE__ */ s(S, { children: /* @__PURE__ */ r(w, { children: [
68
68
  /* @__PURE__ */ r(h, { children: [
69
69
  /* @__PURE__ */ s(
70
70
  u,
@@ -97,7 +97,7 @@ const O = o.div`
97
97
  ] }),
98
98
  /* @__PURE__ */ r(C, { children: [
99
99
  /* @__PURE__ */ s($, { children: e("settings.visibility.documentsLabel") }),
100
- /* @__PURE__ */ s(k, { children: /* @__PURE__ */ s(w, { children: /* @__PURE__ */ r(O, { children: [
100
+ /* @__PURE__ */ s(k, { children: /* @__PURE__ */ s(S, { children: /* @__PURE__ */ r(w, { children: [
101
101
  /* @__PURE__ */ r(h, { children: [
102
102
  /* @__PURE__ */ s(
103
103
  u,
@@ -128,11 +128,11 @@ const O = o.div`
128
128
  /* @__PURE__ */ s(p, { children: e("settings.visibility.individualDescription") })
129
129
  ] }) }) })
130
130
  ] }),
131
- f && /* @__PURE__ */ s(M, { type: f.type, children: f.message })
131
+ f && /* @__PURE__ */ s(N, { type: f.type, children: f.message })
132
132
  ]
133
133
  }
134
134
  );
135
135
  };
136
136
  export {
137
- B as default
137
+ M as default
138
138
  };
@@ -148,10 +148,9 @@ export declare const InSendingIcon: ({ fill, color, ...props }: {
148
148
  fill?: string;
149
149
  color?: string;
150
150
  }) => import("react/jsx-runtime").JSX.Element;
151
- export declare const DoubleTick: ({ fill, color, ...props }: {
151
+ export declare const DoubleTick: ({ stroke, ...props }: {
152
152
  [x: string]: any;
153
- fill?: string;
154
- color?: string;
153
+ stroke?: string;
155
154
  }) => import("react/jsx-runtime").JSX.Element;
156
155
  export declare const RedCross: ({ color, ...props }: {
157
156
  [x: string]: any;
@@ -7,7 +7,9 @@ export type FileCategory = 'media' | 'documents' | 'audio';
7
7
  * with thumbnails); audio/* gets its own chip; everything else falls back
8
8
  * to "Documents".
9
9
  */
10
- export declare function getFileCategory(mimetype?: string | null): FileCategory;
11
- export declare function isPreviewable(file: Pick<ApiFile, 'mimetype'>): boolean;
10
+ export declare function getFileCategory(mimetype?: string | null, name?: string | null): FileCategory;
11
+ export declare function isPreviewable(file: Pick<ApiFile, 'mimetype'> & {
12
+ originalname?: string;
13
+ }): boolean;
12
14
  /** Human-readable byte size, e.g. formatBytes(1536) -> "1.5 KB". */
13
15
  export declare function formatBytes(bytes?: number | null): string;
@@ -0,0 +1,22 @@
1
+ import { default as React } from 'react';
2
+ import { IAttachment, ModalFile } from '../../types/types';
3
+ export interface AlbumGridItem {
4
+ attachment: IAttachment;
5
+ /** Position in the message's `attachments`, used for retry. */
6
+ index: number;
7
+ }
8
+ interface AlbumGridProps {
9
+ items: AlbumGridItem[];
10
+ /** Called with the failed tile's index when the user asks to retry it. */
11
+ onRetry?: (index: number) => void;
12
+ /** Who posted the album and when, handed to the viewer header. */
13
+ sender?: ModalFile['sender'];
14
+ date?: string;
15
+ }
16
+ /**
17
+ * Photo/video album for a message with several media files. Layout comes
18
+ * from getAlbumLayout; a tile tap opens that file in the preview modal, and
19
+ * a tile still in flight or failed shows its state over the thumbnail.
20
+ */
21
+ declare const AlbumGrid: React.FC<AlbumGridProps>;
22
+ export default AlbumGrid;
@@ -1,12 +1,12 @@
1
1
  import { default as React } from 'react';
2
- import { IAttachment } from '../../types/types';
2
+ import { IAttachment, ModalFile } from '../../types/types';
3
3
  interface AttachmentListProps {
4
4
  attachments: IAttachment[];
5
- /** See CustomMessageImage's `onUnavailable` - only wired to the full-width
6
- * single-image renderer (AttachmentRow), not the multi-file grid tiles,
7
- * since one dead thumbnail there shouldn't tombstone a message that still
8
- * has other live attachments. */
9
- onUnavailable?: () => void;
5
+ /** Re-sends the file at this index of `attachments` after a failed upload. */
6
+ onRetryAttachment?: (index: number) => void;
7
+ /** Who posted the message and when; the viewer header shows both. */
8
+ sender?: ModalFile['sender'];
9
+ date?: string;
10
10
  }
11
11
  declare const AttachmentList: React.FC<AttachmentListProps>;
12
12
  export default AttachmentList;
@@ -0,0 +1,21 @@
1
+ import { default as React } from 'react';
2
+ export interface ImageUnavailableArtProps {
3
+ /** Rendered width and height in CSS pixels. The viewBox scales crisply. */
4
+ size?: number;
5
+ }
6
+ export declare const ImageUnavailableArt: React.FC<ImageUnavailableArtProps>;
7
+ export interface ImageUnavailableStateProps {
8
+ /**
9
+ * Compact: the glyph only, about 28px, for album grid tiles. Full: the
10
+ * illustration, the caption and a hint, for a solo bubble or the viewer.
11
+ */
12
+ compact?: boolean;
13
+ /**
14
+ * Shows a "Try again" action. The picture sits inside the bubble's open
15
+ * button, so the action is a span with button semantics, not a <button>.
16
+ */
17
+ onRetry?: () => void;
18
+ }
19
+ /** Self-contained "could not load" state that fills its positioned parent. */
20
+ export declare const ImageUnavailableState: React.FC<ImageUnavailableStateProps>;
21
+ export default ImageUnavailableState;
@@ -0,0 +1,31 @@
1
+ import { default as React } from 'react';
2
+ /** How long the scrim takes to fade once the upload is done. */
3
+ export declare const SCRIM_FADE_MS = 180;
4
+ /** The circular-arrow retry mark, shared by the failed tile and the "+N" badge. */
5
+ export declare const RetryIcon: React.FC<{
6
+ size?: number;
7
+ }>;
8
+ /**
9
+ * Thin circular progress ring. The SVG is a fixed 40px square with a
10
+ * viewBox, so it can never stretch; the arc is drawn by moving the dash
11
+ * offset from the full circumference (empty) down to zero (complete).
12
+ */
13
+ export declare const ProgressRing: React.FC<{
14
+ percent: number;
15
+ children?: React.ReactNode;
16
+ }>;
17
+ interface MediaUploadOverlayProps {
18
+ /** `uploading` covers "waiting for the siblings" too; `failed` is a retry prompt. */
19
+ status: 'uploading' | 'failed';
20
+ progress?: number;
21
+ /** Upload is done: fade the scrim out instead of leaving it up. */
22
+ leaving?: boolean;
23
+ }
24
+ /**
25
+ * State layer over an outgoing attachment: a frosted scrim with a progress
26
+ * ring while it goes up, and a tinted scrim with a retry glyph once it has
27
+ * failed. The parent owns the click, so this stays pointer-transparent and
28
+ * can sit inside a button without nesting interactive elements.
29
+ */
30
+ export declare const MediaUploadOverlay: React.FC<MediaUploadOverlayProps>;
31
+ export default MediaUploadOverlay;
@@ -6,6 +6,7 @@ interface MessageContainerProps {
6
6
  isUser: boolean;
7
7
  $isUser?: boolean;
8
8
  isReply: boolean;
9
+ isLastInGroup?: boolean;
9
10
  }>;
10
11
  message: IMessage;
11
12
  activeMessage: IMessage;
@@ -13,6 +14,8 @@ interface MessageContainerProps {
13
14
  xmppUsername: string;
14
15
  isReply: boolean;
15
16
  showDateLabel: boolean;
17
+ /** False when the next row is the same sender's message (a run continues). */
18
+ isLastInGroup?: boolean;
16
19
  className?: string;
17
20
  }
18
21
  export declare const MessageContainer: React.NamedExoticComponent<MessageContainerProps>;
@@ -0,0 +1,9 @@
1
+ import { default as React } from 'react';
2
+ import { MentionClickHandler } from '../../helpers/parseMessageBody';
3
+ interface MediaCaptionProps {
4
+ /** The message: its caption, or the text a legacy sender put in `body`. */
5
+ message: object;
6
+ onMentionClick?: MentionClickHandler;
7
+ }
8
+ declare const MediaCaption: React.FC<MediaCaptionProps>;
9
+ export default MediaCaption;
@@ -0,0 +1,17 @@
1
+ import { default as React, CSSProperties } from 'react';
2
+ interface MessageAvatarPhotoProps {
3
+ /** Sender photo URL; empty renders the initials circle alone. */
4
+ src?: string | null;
5
+ /** Display name, used for the initials. */
6
+ username?: string;
7
+ style?: CSSProperties;
8
+ }
9
+ /**
10
+ * Sender avatar in a message bubble. The initials circle is always rendered
11
+ * (no layout shift, nothing waits on the network); the photo is layered over
12
+ * it and faded in once it has loaded. A photo that fails to load leaves the
13
+ * initials, where the old bare <img> showed a broken-image glyph. A sender
14
+ * with many bubbles shares one load through useAvatarImage's cache.
15
+ */
16
+ export declare const MessageAvatarPhoto: React.FC<MessageAvatarPhotoProps>;
17
+ export {};
@@ -5,6 +5,12 @@ interface MessageReactionProps {
5
5
  reaction: Record<string, ReactionMessage>;
6
6
  changeReaction: (reaction: string) => void;
7
7
  userName?: string;
8
+ /**
9
+ * Reports how far the chip rows hang below the bubble's bottom edge, in px,
10
+ * whenever their rendered height changes (one row hangs REACTION_HANG_PX).
11
+ * The message row uses it to reserve room for every wrapped row.
12
+ */
13
+ onHangChange?: (hangPx: number) => void;
8
14
  }
9
15
  export declare const MessageReaction: FC<MessageReactionProps>;
10
16
  export {};
@@ -1,9 +1,11 @@
1
1
  import { default as React } from 'react';
2
2
  import { QuickReply } from '../../helpers/quickReplies';
3
+ import { ChatColorScheme } from '../../types/types';
3
4
  interface QuickRepliesProps {
4
5
  replies: QuickReply[];
5
6
  messageId: string;
6
7
  accentColor?: string;
8
+ colorScheme?: ChatColorScheme;
7
9
  /** Already answered - the chips are gone for good. */
8
10
  answered?: boolean;
9
11
  onSelect: (reply: QuickReply, questionId: string) => void;
@@ -7,17 +7,15 @@ interface FilePreviewModalProps {
7
7
  *
8
8
  * Images get a real lightbox: previous/next across every image loaded for
9
9
  * the room (see helpers/roomImageGallery for exactly what that set is),
10
- * wheel/pinch zoom with bounded panning, double-click/double-tap to toggle
11
- * fit, arrow-key and swipe navigation. Video, PDF and unsupported files take
12
- * the same paths they always did and get no navigation chrome, so opening a
13
- * PDF is the experience it was before.
10
+ * a thumbnail strip, wheel/pinch zoom with bounded panning, double-click or
11
+ * double-tap to toggle fit, arrow and swipe navigation, and a blurred
12
+ * low-resolution stand-in while the full picture loads. Video, audio, PDF and
13
+ * other files each get their own view; none of them get gallery chrome.
14
14
  *
15
- * Escape, initial focus and focus restore are NOT handled here: the modal
16
- * layer (Modals/Modal/Modal.tsx) already runs `useModalDismiss` around every
17
- * entry in MODAL_COMPONENTS, this one included. Adding a second Escape
18
- * listener would double-handle the key and fight that hook's focus restore,
19
- * so the only key listener below is for the arrows, and it explicitly leaves
20
- * every other key (Escape included) alone.
15
+ * Escape and initial focus are handled by useModalDismiss at the modal layer
16
+ * (Modals/Modal/ModalContent.tsx), which also restores focus to the opener on
17
+ * close. This component adds the Tab trap and the arrow and zoom keys, and it
18
+ * leaves Escape alone so the key is not handled twice.
21
19
  */
22
20
  declare const FilePreviewModal: React.FC<FilePreviewModalProps>;
23
21
  export default FilePreviewModal;
@@ -11,6 +11,10 @@ export interface ImageLightboxHandle {
11
11
  interface ImageLightboxProps {
12
12
  src: string;
13
13
  alt: string;
14
+ /** Low-res stand-in painted blurred until `src` has loaded. */
15
+ previewSrc?: string;
16
+ /** Visually hidden label for the loading spinner (screen readers). */
17
+ loadingLabel?: string;
14
18
  /** Swipe (touch) navigation; also used to report gesture direction. */
15
19
  onSwipeLeft?: () => void;
16
20
  onSwipeRight?: () => void;
@@ -10,6 +10,10 @@ interface PdfViewerProps {
10
10
  * opened was handed to a third-party host - and broke outright whenever that
11
11
  * page changed or was unreachable. Rendering locally keeps the file URL
12
12
  * inside the app and works offline-ish (the PDF itself still has to load).
13
+ *
14
+ * All pages stack in one scroll container. Every page has a placeholder sized
15
+ * from its real aspect, but only the few near the viewport render a canvas,
16
+ * so a 200-page document costs about as much as a 7-page one.
13
17
  */
14
18
  declare const PdfViewer: React.FC<PdfViewerProps>;
15
19
  export default PdfViewer;
@@ -0,0 +1,64 @@
1
+ import { default as React } from 'react';
2
+ export declare const VIEWER_TEXT = "#f5f7fa";
3
+ export declare const VIEWER_MUTED = "rgba(245, 247, 250, 0.68)";
4
+ export declare const VIEWER_SURFACE = "rgba(255, 255, 255, 0.08)";
5
+ export declare const VIEWER_SURFACE_HOVER = "rgba(255, 255, 255, 0.18)";
6
+ export declare const ViewerSurface: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
7
+ $closing: boolean;
8
+ }>> & string;
9
+ export declare const TopBar: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, never>> & string;
10
+ export declare const TopIdentity: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
11
+ export declare const SenderText: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
12
+ export declare const SenderName: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
13
+ export declare const SubLine: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
14
+ export declare const ActionGroup: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
15
+ export declare const IconButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
16
+ export declare const Stage: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
17
+ export declare const MediaFrame: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
18
+ $fit: "media" | "content";
19
+ }>> & string;
20
+ export declare const NavButton: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
21
+ $side: "left" | "right";
22
+ }>> & string;
23
+ export declare const BottomBar: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
24
+ export declare const ThumbStrip: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
25
+ export declare const Thumb: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components/dist/types').Substitute<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
26
+ $active: boolean;
27
+ }>> & string;
28
+ export declare const ThumbImage: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, never>> & string;
29
+ /** Small play triangle over a video's thumbnail. */
30
+ export declare const ThumbPlayBadge: () => import("react/jsx-runtime").JSX.Element;
31
+ /** Stand-in thumbnail for a video that has no poster image. */
32
+ export declare const ThumbVideoGlyph: () => import("react/jsx-runtime").JSX.Element;
33
+ export declare const ControlRow: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
34
+ export declare const Counter: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
35
+ export declare const ZoomGroup: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
36
+ interface ErrorPanelProps {
37
+ onRetry: () => void;
38
+ onDownload: () => void;
39
+ }
40
+ /** Shown in place of an image that cannot be loaded. No remote fallback image. */
41
+ export declare const ErrorPanel: React.FC<ErrorPanelProps>;
42
+ interface FileCardProps {
43
+ fileName: string;
44
+ unsupportedText: string;
45
+ onDownload: () => void;
46
+ }
47
+ /** Large card for files the viewer cannot render (anything but image/video/audio/PDF). */
48
+ export declare const FileCard: React.FC<FileCardProps>;
49
+ interface AudioCardProps {
50
+ fileName: string;
51
+ src: string;
52
+ }
53
+ /** Audio gets a native player inside a card, so it reads as a clip, not a broken image. */
54
+ export declare const AudioCard: React.FC<AudioCardProps>;
55
+ export declare const ExternalLinkGlyph: () => import("react/jsx-runtime").JSX.Element;
56
+ export declare const RetryGlyph: () => import("react/jsx-runtime").JSX.Element;
57
+ export declare const DownloadGlyph: () => import("react/jsx-runtime").JSX.Element;
58
+ export declare const FileGlyph: () => import("react/jsx-runtime").JSX.Element;
59
+ export declare const AudioGlyph: () => import("react/jsx-runtime").JSX.Element;
60
+ /** Format a message timestamp for the viewer header; empty when unknown. */
61
+ export declare const formatViewerDate: (iso?: string) => string;
62
+ /** Returns the URL with a retry marker, so a retry is not served from the failed cache entry. */
63
+ export declare const withRetryMarker: (url: string, attempt: number) => string;
64
+ export {};
@@ -2,6 +2,8 @@ import { FC } from 'react';
2
2
  import { LastMessage } from '../../types/types';
3
3
  interface LastMessageItemProps {
4
4
  lastMessage: LastMessage;
5
+ /** The room is end-to-end encrypted: media shows an icon and label only. */
6
+ sealed?: boolean;
5
7
  }
6
8
  declare const LastMessageItem: FC<LastMessageItemProps>;
7
9
  export default LastMessageItem;
@@ -0,0 +1,19 @@
1
+ import { FC } from 'react';
2
+ import { MediaPreview } from '../../../helpers/lastMessagePreview';
3
+ /** Edge of the thumbnail tile, and so the height of a thumbnail row. */
4
+ export declare const MEDIA_THUMB_PX = 18;
5
+ interface LastMessageMediaProps {
6
+ preview: MediaPreview;
7
+ /** Sender line, already resolved by ChatRoomItem; empty omits it. */
8
+ name?: string;
9
+ }
10
+ /**
11
+ * Room-list preview for a media last message: a thumbnail (images, videos
12
+ * with a poster) or an inline icon, then a localized label. Thumbnails come
13
+ * from the message's own preview URL only, with the viewer's file token
14
+ * appended; a thumbnail that fails (a secure URL that 404s, an expired
15
+ * token) drops to the icon instead of a broken image, and nothing is ever
16
+ * fetched from a placeholder host.
17
+ */
18
+ declare const LastMessageMedia: FC<LastMessageMediaProps>;
19
+ export default LastMessageMedia;
@@ -1,6 +1,6 @@
1
1
  import { FC } from 'react';
2
2
  import { LastMessage } from '../../../types/types';
3
- interface LastMessageEmojiProps extends Pick<LastMessage, 'user' | 'body'> {
3
+ interface LastTextMessageProps extends Pick<LastMessage, 'user' | 'body'> {
4
4
  }
5
- declare const LastTextMessage: FC<LastMessageEmojiProps>;
5
+ declare const LastTextMessage: FC<LastTextMessageProps>;
6
6
  export default LastTextMessage;
@@ -1,9 +1,16 @@
1
1
  import { default as React } from 'react';
2
+ export declare const PREVIEW_NAME_PX = 16;
3
+ export declare const PREVIEW_LINE_PX = 18;
4
+ export declare const PREVIEW_BLOCK_MIN_PX: number;
2
5
  export declare const LastRoomMessageContainer: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
3
- export declare const LastRoomMessageName: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
6
+ export declare const LastRoomMessageName: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
4
7
  export declare const LastRoomMessageText: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
5
- /** Thumbnail/icon + label for a media preview, flowing in the same line. */
6
- export declare const LastRoomMessageMedia: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
8
+ /** Line 2 when it carries an icon or thumbnail next to its label. */
9
+ export declare const LastRoomMessageLine: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
10
+ /** Thumbnail/icon + label for a media preview, on the message line. */
11
+ export declare const LastRoomMessageMedia: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<Omit<import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>, "ref"> & {
12
+ ref?: React.Ref<HTMLDivElement>;
13
+ }, never>> & string;
7
14
  export declare const NewMessageMarker: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
8
15
  export declare const LastMessageImg: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, never>> & string;
9
16
  export declare const ShadeWrapper: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
@@ -20,6 +20,19 @@ interface VideoCallSessionProps {
20
20
  onConnected?: () => void;
21
21
  onError?: (message: string) => void;
22
22
  onHangup: () => void;
23
+ /** Request end-to-end encryption of the media for this call. */
24
+ e2ee?: boolean;
25
+ /** The shared media key (base64), delivered over OMEMO. May arrive late. */
26
+ e2eeKey?: string | null;
27
+ /** Host-supplied factory for the LiveKit E2EE worker (see VideoCallsConfig). */
28
+ e2eeWorkerFactory?: () => Worker;
29
+ /**
30
+ * A remote participant just joined the LiveKit room. The key owner uses this
31
+ * to re-send the E2EE media key over OMEMO: the newcomer is online now, so a
32
+ * peer who missed the ephemeral key at call start (e.g. woken by push) still
33
+ * receives it. See VideoCallOverlay.
34
+ */
35
+ onParticipantJoined?: () => void;
23
36
  }
24
37
  export declare const VideoCallSession: React.FC<VideoCallSessionProps>;
25
38
  export {};
@@ -0,0 +1,20 @@
1
+ import { default as React } from 'react';
2
+ export interface FileCardProps {
3
+ /** Full file name; the card truncates it with an ellipsis. */
4
+ name: string;
5
+ /** Short parts shown under the name, joined with a middle dot. */
6
+ meta: Array<string | undefined>;
7
+ icon: React.ReactNode;
8
+ tone?: 'pdf' | 'neutral';
9
+ compact?: boolean;
10
+ onOpen: () => void;
11
+ title?: string;
12
+ 'aria-label'?: string;
13
+ }
14
+ /**
15
+ * A file that is not an image or video: a tile with the type glyph, the name
16
+ * with an ellipsis, a small meta line and a download affordance. One click
17
+ * opens the file in the preview modal.
18
+ */
19
+ declare const FileCard: React.ForwardRefExoticComponent<FileCardProps & React.RefAttributes<HTMLButtonElement>>;
20
+ export default FileCard;
@@ -0,0 +1,50 @@
1
+ import { default as React } from 'react';
2
+ /** Frosted circle with a play triangle, centred on a video. */
3
+ export declare const PlayBadge: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
4
+ export declare const DurationChip: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
5
+ /** Small "GIF" pill, bottom-left, on an animated picture. */
6
+ export declare const GifChip: import('styled-components/dist/types').IStyledComponentBase<"web", import('styled-components').FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
7
+ export interface MediaSurfaceProps {
8
+ kind: 'image' | 'video';
9
+ /** Full-resolution URL. Empty while an outgoing upload has no URL yet. */
10
+ src: string;
11
+ /** Low-resolution preview, shown blurred until `src` has loaded. */
12
+ previewSrc?: string;
13
+ alt: string;
14
+ /** `fill` covers its positioned parent (album tile); `solo` sizes itself. */
15
+ variant: 'fill' | 'solo';
16
+ /** Natural size recorded on the attachment, when the storage kept it. */
17
+ dims?: {
18
+ width?: unknown;
19
+ height?: unknown;
20
+ };
21
+ /** Duration in seconds, shown as a chip on videos. */
22
+ duration?: string;
23
+ /** Outgoing upload: shimmer while the URL is pending. */
24
+ pending?: boolean;
25
+ /** CSS border-radius for the stage (per corner for album tiles). */
26
+ radius?: string;
27
+ /** Solo only: opens the preview. Omit for tiles, which own the click. */
28
+ onOpen?: () => void;
29
+ /** The opener exists but cannot act yet (no file URL): keeps the element tree stable. */
30
+ openDisabled?: boolean;
31
+ /** Clickable item: zoom cursor and hover zoom. Defaults to `Boolean(onOpen)`. */
32
+ interactive?: boolean;
33
+ /** Blur and dim the picture, used behind the "+N" count. */
34
+ blurred?: boolean;
35
+ /** MIME type of the file; `image/gif` makes the picture animate in place. */
36
+ mimetype?: string;
37
+ /** Show the play badge and duration chip on videos. Defaults to true. */
38
+ chrome?: boolean;
39
+ /** Sender's own picture (blob URL): shown sharp and at once, ahead of `src`. */
40
+ localSrc?: string;
41
+ /** 0 to 100 download progress of `src`, when known; otherwise a quiet sweep. */
42
+ loadProgress?: number;
43
+ }
44
+ /**
45
+ * The in-bubble picture of one media file: a shimmer while it loads, the
46
+ * preview blurred until the full file is decoded, a 180ms fade to the real
47
+ * image, and a self-contained unavailable state when it cannot be shown.
48
+ */
49
+ declare const MediaSurface: React.FC<MediaSurfaceProps>;
50
+ export default MediaSurface;
@@ -4,16 +4,15 @@ interface CustomMessageImageProps {
4
4
  fileName: string;
5
5
  mimetype: string;
6
6
  locationPreview?: string;
7
- /**
8
- * Called only once the server itself says the file is gone (404/410),
9
- * not merely when the <img> failed to load. The only known cause in
10
- * practice is the file having been deleted from the Files panel without
11
- * a matching message found locally to tombstone up front (see
12
- * FilesPanel.tsx's handleDelete) - the caller uses this to flip the
13
- * message to the normal "deleted" placeholder instead of leaving this
14
- * broken-image card on screen.
15
- */
16
- onUnavailable?: () => void;
7
+ /** Natural size from the attachment, when the storage kept it. */
8
+ width?: number;
9
+ height?: number;
10
+ /** Sender's own blob URL, shown at once while the server copy loads. */
11
+ localUrl?: string;
17
12
  }
13
+ /**
14
+ * A single picture in a bubble: its natural aspect ratio, sized to the
15
+ * pane's shared media width. A click opens the preview modal at this file.
16
+ */
18
17
  declare const CustomMessageImage: React.FC<CustomMessageImageProps>;
19
18
  export default CustomMessageImage;
@@ -1,12 +1,15 @@
1
1
  import { default as React } from 'react';
2
2
  import { IConfig, IMentionSpan } from '../../types/types';
3
+ import { CaptionInput } from '../../helpers/caption';
3
4
  export interface SendInputProps {
4
5
  sendMessage: (message: string, mentions?: IMentionSpan[]) => void | Promise<void>;
5
6
  /**
6
7
  * Receives a `File[]` for picked attachments (one message, N files) and a
7
8
  * `Blob` for voice notes. Single files still arrive as a one-element array.
9
+ * Text typed with the files arrives as `caption` and is sent inside that
10
+ * same media message, so it can never land as a separate bubble.
8
11
  */
9
- sendMedia: (data: File[] | File | Blob, type: string) => void | Promise<void>;
12
+ sendMedia: (data: File[] | File | Blob, type: string, caption?: CaptionInput) => void | boolean | Promise<void | boolean>;
10
13
  isLoading: boolean;
11
14
  editMessage?: string;
12
15
  config?: IConfig;
@@ -19,7 +22,7 @@ export interface SendInputProps {
19
22
  showPreview?: boolean;
20
23
  previewParser?: (text: string) => (string | JSX.Element)[];
21
24
  onSendMessage?: (message: string, mentions?: IMentionSpan[]) => void | Promise<void>;
22
- onSendMedia?: (data: File[] | File | Blob, type: string) => void | Promise<void>;
25
+ onSendMedia?: (data: File[] | File | Blob, type: string, caption?: CaptionInput) => void | boolean | Promise<void | boolean>;
23
26
  placeholderText?: string;
24
27
  /** Disables the @-mention autocomplete (e.g. for a composer variant that
25
28
  * doesn't want it). Defaults to enabled. */
@@ -31,6 +34,13 @@ export interface SendInputProps {
31
34
  * live composers would otherwise overwrite each other's text.
32
35
  */
33
36
  disableDrafts?: boolean;
37
+ /**
38
+ * Take focus whenever the room list hands the composer a chat switch (a
39
+ * click on a room row, even one that is already open). Set on the main
40
+ * composer only: a second composer on the same screen must not steal focus.
41
+ * Mobile never requests it, so the keyboard does not pop up uninvited.
42
+ */
43
+ focusOnRoomSwitch?: boolean;
34
44
  }
35
45
  declare const SendInput: React.FC<SendInputProps>;
36
46
  export default SendInput;